// ================================================================
// LEXER

!whitespace : ' ' | '\t' | '\n' | '\r' ;
!comment : '#'  {.} '\n' ;

_letter : 'a'-'z' | 'A'-'Z' ;
_decdig : '0'-'9' ;
_idchar : _letter | _decdig | '_' ;

emit : 'e' 'm' 'i' 't' ;

// ================================================================
// IMPORT

<< import "miller/src/dsl" >>

// ================================================================
// PARSER

// ----------------------------------------------------------------
Root
  : EmitStatement
   << dsl.NewAST($0) >>
;

// ----------------------------------------------------------------
// Examples:
//   emit @a
//   emit (@a, @b)
//   emit @a, "x", "y"
//   emit (@a, @b), "x", "y"
// First argument (single or in parentheses) must be non-indexed
// oosvar/localvar/fieldname, so we can use their names as keys in the emitted
// record.  These restrictions are enforced in the CST logic, to keep this
// parser/AST logic simpler.
EmitStatement
  : emit Rvalue
    << dsl.NewASTNodeUnary($0, $1, dsl.NodeTypeEmitStatement) >>

  | emit Rvalue "," EmitArgs
    << dsl.NewASTNodeBinary($0, $1, $3, dsl.NodeTypeEmitStatement) >>

  | emit "(" EmitArgs ")"
    << dsl.NewASTNodeUnary($0, $2, dsl.NodeTypeEmitStatement) >>

  | emit "(" EmitArgs ")" "," EmitArgs
    << dsl.NewASTNodeBinary($0, $2, $5, dsl.NodeTypeEmitStatement) >>
;

// ----------------------------------------------------------------
EmitArgs
  : Rvalue
    << dsl.NewASTNodeUnary(
      nil,
      $0,
      dsl.NodeTypeFunctionCallsite,
    ) >>

  | Rvalue "," EmitArgs
    << dsl.PrependChild(
      $2,
      $0,
    ) >>
;

// ----------------------------------------------------------------
FcnArgs
  : Rvalue
    << dsl.NewASTNodeUnary(
      nil,
      $0,
      dsl.NodeTypeFunctionCallsite,
    ) >>

  // Allow trailing final comma, especially for multiline statements
  | Rvalue ","
    << dsl.NewASTNodeUnary(
      nil,
      $0,
      dsl.NodeTypeFunctionCallsite,
    ) >>

  // Allow trailing final comma, especially for multiline statements
  | Rvalue "," FcnArgs
    << dsl.PrependChild(
      $2,
      $0,
    ) >>
;


// ----------------------------------------------------------------
Rvalue
  : Literal
  | "(" Literal ")"
;

Literal
  : "x" << dsl.NewASTNodeZary($0, dsl.NodeTypeStringLiteral) >>
  | "y" << dsl.NewASTNodeZary($0, dsl.NodeTypeStringLiteral) >>
  | "z" << dsl.NewASTNodeZary($0, dsl.NodeTypeStringLiteral) >>
;
