namespace fbast;

union MonoType {
  NamedType,
  TvarType,
  ArrayType,
  DictType,
  RecordType,
  FunctionType,
}

table NamedType {
  base_node:BaseNode;
  id:Identifier;
}

table TvarType {
  base_node:BaseNode;
  id:Identifier;
}

table ArrayType {
  base_node:BaseNode;
  element:MonoType;
}

table DictType {
  base_node:BaseNode;
  key:MonoType;
  val:MonoType;
}

table PropertyType {
  base_node:BaseNode;
  id:Identifier;
  monotype:MonoType;
}

table RecordType {
  base_node:BaseNode;
  properties:[PropertyType];
  tvar:Identifier;
}

enum ParameterKind : byte {
  Required,
  Optional,
  Pipe,
}

table ParameterType {
  base_node:BaseNode;
  id:Identifier;
  monotype:MonoType;
  kind:ParameterKind;
}

table FunctionType {
  base_node:BaseNode;
  parameters:[ParameterType];
  monotype:MonoType;
}

table TypeConstraint {
  base_node:BaseNode;
  tvar:Identifier;
  kinds:[Identifier];
}

table TypeExpression {
  base_node:BaseNode;
  monotype:MonoType;
  constraints:[TypeConstraint];
}

union Statement {
  BadStatement,
  VariableAssignment,
  MemberAssignment,
  ExpressionStatement,
  ReturnStatement,
  OptionStatement,
  BuiltinStatement,
  TestStatement,
  TestCaseStatement,
}

union Assignment {
  MemberAssignment,
  VariableAssignment,
}

union Expression {
  StringExpression,
  ParenExpression,
  ArrayExpression,
  DictExpression,
  FunctionExpression,
  BinaryExpression,
  BooleanLiteral,
  CallExpression,
  ConditionalExpression,
  DateTimeLiteral,
  DurationLiteral,
  FloatLiteral,
  Identifier,
  IntegerLiteral,
  LogicalExpression,
  MemberExpression,
  IndexExpression,
  ObjectExpression,
  PipeExpression,
  PipeLiteral,
  RegexpLiteral,
  StringLiteral,
  UnaryExpression,
  UnsignedIntegerLiteral,
  BadExpression,
}

struct Position {
  line:int;
  column:int;
}

table SourceLocation {
  file:string;
  start:Position;
  end:Position;
  source:string;
}

table Comment {
  text:string;
}

table BaseNode {
  loc:SourceLocation;
  errors:[string];
  comments:[Comment];
}

table Package {
  base_node:BaseNode;
  path:string;
  package:string;
  files:[File];
}

table File {
  base_node:BaseNode;
  name:string;
  metadata:string;
  package:PackageClause;
  imports:[ImportDeclaration];
  body:[WrappedStatement];
}

table PackageClause {
  base_node:BaseNode;
  name:Identifier;
}

table ImportDeclaration {
  base_node:BaseNode;
  as:Identifier;
  path:StringLiteral;
}

// Statements

// Unions cannot be vector elements,
// so wrap the union in a table.
table WrappedStatement {
  statement:Statement;
}

table BadStatement {
  base_node:BaseNode;
  text:string;
}

table VariableAssignment {
  base_node:BaseNode;
  id:Identifier;
  // Calling the below "init" creates errors in generated Go code
  init_:Expression;
}

table MemberAssignment {
  base_node:BaseNode;
  member:MemberExpression;
  // Calling the below "init" creates errors in generated Go code
  init_:Expression;
}

table ExpressionStatement {
  base_node:BaseNode;
  expression:Expression;
}

table ReturnStatement {
  base_node:BaseNode;
  argument:Expression;
}

table OptionStatement {
  base_node:BaseNode;
  assignment:Assignment;
}

table BuiltinStatement {
  base_node:BaseNode;
  id:Identifier;
}

table TestStatement {
  base_node:BaseNode;
  assignment:Assignment;
}

table TestCaseStatement {
  base_node:BaseNode;
  id:Identifier;
  extends:StringLiteral;
  block:Block;
}

// Expressions

// Unions cannot appear in vectors or other unions,
// so provide a wrapped version where needed.
table WrappedExpression {
  expr:Expression;
}

enum Operator : byte {
  InvalidOperator,
  MultiplicationOperator,
  DivisionOperator,
  ModuloOperator,
  PowerOperator,
  AdditionOperator,
  SubtractionOperator,
  LessThanEqualOperator,
  LessThanOperator,
  GreaterThanEqualOperator,
  GreaterThanOperator,
  StartsWithOperator,
  InOperator,
  NotOperator,
  ExistsOperator,
  NotEmptyOperator,
  EmptyOperator,
  EqualOperator,
  NotEqualOperator,
  RegexpMatchOperator,
  NotRegexpMatchOperator,
}

enum LogicalOperator : byte {
  AndOperator,
  OrOperator,
}

enum TimeUnit : byte {
  y,
  mo,
  w,
  d,
  h,
  m,
  s,
  ms,
  us,
  ns,
}

table BinaryExpression {
  base_node:BaseNode;
  operator:Operator;
  left:Expression;
  right:Expression;
}

table LogicalExpression {
  base_node:BaseNode;
  operator:LogicalOperator;
  left:Expression;
  right:Expression;
}

table UnaryExpression {
  base_node:BaseNode;
  operator:Operator;
  argument:Expression;
}

table BooleanLiteral {
  base_node:BaseNode;
  value:bool;
}

table DateTimeLiteral {
  base_node:BaseNode;
  secs:int64;
  nsecs:uint32;
  offset:int32;
}

table DurationLiteral {
  base_node:BaseNode;
  values:[Duration];
}

table Duration {
  magnitude:int64;
  unit:TimeUnit;
}

table FloatLiteral {
  base_node:BaseNode;
  value:float64;
}

table IntegerLiteral {
  base_node:BaseNode;
  value:int64;
}

table PipeLiteral {
  base_node:BaseNode;
}

table RegexpLiteral {
  base_node:BaseNode;
  value:string;
}

table StringLiteral {
  base_node:BaseNode;
  value:string;
}

table UnsignedIntegerLiteral {
  base_node:BaseNode;
  value:uint64;
}

table Identifier {
  base_node:BaseNode;
  name:string;
}

table StringExpression {
  base_node:BaseNode;
  parts:[StringExpressionPart];
}

table StringExpressionPart {
  base_node:BaseNode;
  // Following two fields are mutually exclusive:
  text_value:string; // for TextPart
  interpolated_expression:Expression; // for InterpolatedPart
}

table ParenExpression {
  base_node:BaseNode;
  expression:Expression;
}

table ArrayExpression {
  base_node:BaseNode;
  elements:[WrappedExpression];
}

table DictExpression {
  base_node:BaseNode;
  elements:[DictItem];
}

table DictItem {
  key:Expression;
  val:Expression;
}

union ExpressionOrBlock {
  Block,
  WrappedExpression,
}

table FunctionExpression {
  base_node:BaseNode;
  params:[Property];
  body:ExpressionOrBlock;
}

table Block {
  base_node:BaseNode;
  body:[WrappedStatement];
}

table CallExpression {
  base_node:BaseNode;
  callee:Expression;
  arguments:ObjectExpression;
}

table ConditionalExpression {
  base_node:BaseNode;
  test:Expression;
  consequent:Expression;
  alternate:Expression;
}

union PropertyKey {
  Identifier,
  StringLiteral,
}

table Property {
  base_node:BaseNode;
  key:PropertyKey;
  value:Expression;
}

table MemberExpression {
  base_node:BaseNode;
  object:Expression;
  property:PropertyKey;
}

table IndexExpression {
  base_node:BaseNode;
  array:Expression;
  index:Expression;
}

table ObjectExpression {
  base_node:BaseNode;
  with:Identifier;
  properties:[Property];
}

table PipeExpression {
  base_node:BaseNode;
  argument:Expression;
  call:CallExpression;
}

table BadExpression {
  base_node:BaseNode;
  text:string;
  expression:Expression;
}

root_type Package;
