# PEG grammar for pattern matching and extracting

module Fear::Extractor

grammar Grammar
  rule matcher
    identified_matcher / anonymous_matcher
  end

  rule identified_matcher
    identifier space '@' space anonymous_matcher <IdentifiedMatcher>
  end

  rule anonymous_matcher
    array / literal / identifier / extractor / type
  end

  rule array
    '[' (non_empty_array / array_splat / empty_array) ']' <ArrayLiteral>
  end

  rule empty_array
    '' <EmptyArray>
  end

  rule non_empty_array
    array_head (array_tail / empty_array) <NonEmptyArray>
  end

  rule array_tail
    ',' (non_empty_array / array_splat) <ArrayTail>
  end

  rule array_splat
    space? (named_array_splat / anonymous_array_splat) space? <ArraySplat>
  end

  rule array_splat_identifier
    space? anonymous_array_splat space? <ArraySplat>
  end

  rule anonymous_array_splat
    '*' '_'? <AnonymousArraySplat>
  end

  rule named_array_splat
    '*' [a-z] [a-z0-9_]* <NamedArraySplat>
  end

  rule array_head
    space? anonymous_matcher space? <ArrayHead>
  end

  rule space
    [\s]+
  end

  rule any
    '_' <AnyIdentifier>
  end

  rule variable_identifier
    [a-z_] [a-z0-9_]* <Identifier>
  end

  rule identifier
    typed_identifier / any / variable_identifier
  end

  rule typed_identifier
    (any / variable_identifier) ' : ' type <TypedIdentifier>
  end

  rule literal
    nil / true / false / number / string / symbol
  end

  rule number
    float / integer
  end

  rule integer
    ('+' / '-')? [0-9]+ <IntegerLiteral>
  end

  rule float
    ('+' / '-')? [0-9]+ '.' [0-9]+ <FloatLiteral>
  end

  rule symbol
    ':' (string / any / variable_identifier) <SymbolLiteral>
  end

  rule string
    double_quoted_string / single_quoted_string
  end

  rule double_quoted_string
    '"' ([^"\\] / '\\' . )* '"' <DoubleQuotedStringLiteral>
  end

  rule single_quoted_string
    "'" ([^'\\] / '\\' . )* "'" <StringLiteral>
  end

  rule true
    'true' <TrueLiteral>
  end

  rule false
    'false' <FalseLiteral>
  end

  rule nil
    'nil' <NilLiteral>
  end

  rule extractor
    type '(' non_empty_array? ')' <ExtractorLiteral>
  end

  rule type
    constant ('::' constant)* <TypeLiteral>
  end

  rule constant
    [A-Z] [a-zA-Z0-9_]*
  end
end

end