{
package parser

// DO NOT EDIT: This file is auto generated by the pigeon PEG parser generator.

}

Start
  = __ program:Program __ EOF {
      return program, nil
    }

Program
  = body:SourceElements {
      return program(body, c.text, c.pos)
    }

SourceElements
  = head:SourceElement tail:(__ SourceElement __)* {
      return srcElems(head, tail)
    }

SourceElement
  = Statement

Statement
  = VariableStatement
  / ReturnStatement
  / ExpressionStatement
  / BlockStatement


VariableStatement
  = declaration:VariableDeclaration  {
      return varstmt(declaration, c.text, c.pos)
    }

ReturnStatement
  = "return" __ argument:Expr {
      return returnstmt(argument, c.text, c.pos)
    }

ExpressionStatement
  = expr:Expr {
        return exprstmt(expr, c.text, c.pos)
    }

BlockStatement
  = "{" __ body:( __ Statement __ )* __ "}" {
      return blockstmt(body, c.text, c.pos)
    }

VariableDeclaration
  = id:Identifier __ "=" __ init:Expr {
      return vardecl(id, init, c.text, c.pos)
    }


MemberExpressions
  = head:Identifier // TODO: should be primary
    tail:(
         __ property:MemberExpressionProperty {
          return property, nil
        }
    )*
    {
      return memberexprs(head, tail, c.text, c.pos)
    }

MemberExpressionProperty
  = "." __ property:Identifier {
      return property, nil
    }
    / "[" __ property:Primary __ "]" __ {
      return property, nil
    }

CallExpression
  = head:(
      callee:MemberExpressions __ args:Arguments {
        return callexpr(callee, args, c.text, c.pos)
      }
    )
    tail:(
        __ args:Arguments {
          return callexpr(nil, args, c.text, c.pos)
        }
      /  __ property:MemberExpressionProperty {
          return memberexpr(nil, property, c.text, c.pos)
        }
    )*
    {
      return callexprs(head, tail, c.text, c.pos)
    }

PipeExpression
  = head:PipeExpressionHead __ tail:(__ PipeExpressionPipe __)+ {
      return pipeExprs(head, tail, c.text, c.pos)
    }

PipeExpressionHead
  = CallExpression // TODO(nathanielc): Allow for more expressions as pipe heads. Cannot use Expr because it causes infinite left recursion.
  / Literal
  / Array
  / MemberExpressions
  / Identifier
  / ObjectExpression
  / ArrowFunctionExpression
  / Parens

PipeExpressionPipe
  = "|>" __ call:CallExpression {
      return incompletePipeExpr(call, c.text, c.pos)
    }

Arguments
  = "(" __ args:(ObjectProperties)? __ ")" {
      return args, nil
    }

ArrowFunctionExpression
  = "(" __ params:ArrowFunctionParams? __ ")" __ "=>" __ body:ArrowFunctionBody __ {
      return arrowfunc(params, body, c.text, c.pos), nil
    }

ArrowFunctionParams
  = first:ArrowFunctionParam __ rest:ArrowFunctionParamsRest* ","?  {
      return append([]interface{}{first}, toIfaceSlice(rest)...), nil
    }

ArrowFunctionParamsRest
  = "," __  arg:ArrowFunctionParam __ {
      return arg, nil
    }

ArrowFunctionParam
  = key:Identifier __ "=" __ value:Primary  __ {
      return property(key, value, c.text, c.pos)
    }
  / key:Identifier __  {
      return property(key, nil, c.text, c.pos)
    }


ArrowFunctionBody
  = body:Expr {
      return body, nil
    }
  / body:BlockStatement {
    return body, nil
  }

ObjectExpression
  = "{" __ object:(ObjectProperties)? __ "}" {
    return object, nil
  }

ObjectProperties
  = first:Property __ rest:PropertiesRest* __ ","? {
      return objectexpr(first, rest, c.text, c.pos)
    }

PropertiesRest
  = "," __  arg:Property {
      return arg, nil
    }

Property
  = key:Identifier __  ":" __ value:Expr {
      return property(key, value, c.text, c.pos)
    }

// + -
// <= < >= > startsWith IN NOT EMPTY EMPTY
// == !=
// and or
// Lowest to Highest Priority.
// Highest Priority includes the valid primary
// primary contains the Lowest Priority
Expr
  = LogicalExpression

LogicalOperators
  = ("or"i / "and"i) {
        return logicalOp(c.text)
      }

LogicalExpression
  = head:Equality tail:( __  LogicalOperators __  Equality )* {
      return logicalExpression(head, tail, c.text, c.pos)
    }

EqualityOperators
  = ("==" / "!=" / "=~" / "!~") {
      return operator(c.text)
    }

Equality
  = head:Relational tail:( __ EqualityOperators __ Relational )* {
      return binaryExpression(head, tail, c.text, c.pos)
    }

RelationalOperators
  = (   "<="
      / "<"
      / ">="
      / ">"
      / "startswith"i
      / "in"i
      / "not empty"i
      / "empty"i
    ) {
        return operator(c.text)
      }

Relational
  = head:Additive tail:( __ RelationalOperators __ Additive )* {
      return binaryExpression(head, tail, c.text, c.pos)
    }

AdditiveOperator
  = ("+" / "-") {
        return operator(c.text)
      }

Additive
  = head:Multiplicative tail:( __ AdditiveOperator __ Multiplicative )* {
      return binaryExpression(head, tail, c.text, c.pos)
    }

MultiplicativeOperator
  = ("*" / "/") {
      return operator(c.text)
    }

Multiplicative
  = head:UnaryExpression tail:( __ MultiplicativeOperator __ UnaryExpression )* {
      return binaryExpression(head, tail, c.text, c.pos)
    }

UnaryOperator
  = ("-" / "not") {
      return operator(c.text)
    }

UnaryExpression
  = __ op:UnaryOperator __ argument:Primary __ {
      return unaryExpression(op, argument, c.text, c.pos)
    }
  / Primary

Primary
  = PipeExpression
  / Array
  / Literal
  / CallExpression
  / MemberExpressions
  / Identifier
  / ObjectExpression
  / ArrowFunctionExpression
  / Parens

Literal
  = StringLiteral
  / BooleanLiteral
  / RegexpLiteral
  / PipeLiteral
  / DurationLiteral
  / DateTimeLiteral
  / NumberLiteral
  / IntegerLiteral

Parens
  = "(" __ expr:Expr __ ")" {
      return expr, nil
    }

Array
  = "[" __ elements:ArrayElements? __ "]" {
      return elements, nil
    }

ArrayElements
  = first:Primary __ rest:ArrayRest* {
      return array(first, rest, c.text, c.pos), nil
    }

ArrayRest
  = "," __ element:Primary {
      return element, nil
    }

DateFullYear
  = Digit Digit Digit Digit

DateMonth
  // 01-12
  = Digit Digit

DateMDay
  // 01-28, 01-29, 01-30, 01-31 based on
  // month/year
  = Digit Digit

TimeHour
  // 00-23
  = Digit Digit

TimeMinute
  // 00-59
  = Digit Digit

TimeSecond
  // 00-58, 00-59, 00-60 based on leap second
  // rules
  = Digit Digit

TimeSecFrac
  = "." Digit+

TimeNumOffset
  = ("+" / "-") TimeHour ":" TimeMinute

TimeOffset
  = ("Z" / TimeNumOffset)

PartialTime
  = TimeHour ":" TimeMinute ":" TimeSecond TimeSecFrac?

FullDate
  = DateFullYear "-" DateMonth "-" DateMDay

FullTime
  = PartialTime TimeOffset

DateTimeLiteral
  = FullDate "T" FullTime {
      return datetime(c.text, c.pos)
    }

NanoSecondUnits
  = "ns"

MicroSecondUnits
  = ("us" / "µs" / "μs")

MilliSecondUnits
  = "ms"

SecondUnits
  = "s"

MinuteUnits
  = "m"

HourUnits
  = "h"

DurationUnits
  = (
        NanoSecondUnits
      / MicroSecondUnits
      / MilliSecondUnits
      / SecondUnits
      / MinuteUnits
      / HourUnits
    )

SingleDuration
  = Integer DurationUnits

DurationLiteral
  = SingleDuration+ {
      return durationLiteral(c.text, c.pos)
    }

StringLiteral
  = ( '"' DoubleStringChar* '"' ) {
      return stringLiteral(c.text, c.pos)
    }
  / ( '"' DoubleStringChar* ( EOL / EOF ) ) {
      return "", errors.New("string literal not terminated")
    }

DoubleStringChar
  = !( '"' / "\\" / EOL ) SourceChar
  / "\\" DoubleStringEscape

DoubleStringEscape
  = '"'
  / ( SourceChar / EOL / EOF ) {
      return nil, errors.New("invalid escape character")
    }


RegexpLiteral
  = "/" pattern:RegexpBody "/" {
        return pattern, nil
      }

RegexpBody
  = chars:RegexpChar+ {
      return regexLiteral(chars, c.text, c.pos)
    }

RegexpChar
  = ![\\/] re:RegexpNonTerminator {
      return re, nil
    }
  / RegexpBackslashSequence

RegexpBackslashSequence
  = "\\/" {
      return []byte{'/'}, nil
    }
  / "\\" RegexpNonTerminator {
      return c.text, nil
    }

RegexpNonTerminator
  = !LineTerminator SourceChar {
      return c.text, nil
    }

BooleanLiteral
  = __ "true" __ {
      return booleanLiteral(true, c.text, c.pos)
    }
  / __ "false" __ {
      return booleanLiteral(false, c.text, c.pos)
    }

NumberLiteral
  = Integer "." Digit+ {
      return numberLiteral(c.text, c.pos)
   }

Integer
  = ("0" / NonZeroDigit Digit*)

IntegerLiteral
  = Integer {
      return integerLiteral(c.text, c.pos)
    }

NonZeroDigit
  = [1-9]

Digit
  = [0-9]

PipeLiteral
  = "<-" {
        return pipeLiteral(c.text, c.pos), nil
      }


Identifier
  // Allow any unicode letter possibly followed by any number of unicode letters, underscores and numbers.
  = [_\pL][_0-9\pL]* {
      return identifier(c.text, c.pos)
    }


SourceChar
  = .
__
  = ( ws / EOL / Comment )*

Comment
  = "//" [^\r\n]* EOL

ws
  = [ \t\r\n]

LineTerminator
  = [\n\r]

EOL
  = "\n"

EOF
  = !.
