Our types

enum ASTNodeType {
  Program = 'Program',
  Literal = 'Literal',
  String = 'String',
  Assignment = 'Assignment',
  Log = 'Log'
}

interface ASTValueNode<T extends ASTNodeType, K> {
  type: T,
  value: K
}

interface ASTProgramNode {
  type: ASTNodeType.Program,
  children: ASTNode[]
}

interface ASTAssignmentNode {
  type: ASTNodeType.Assignment,
  name: string,
  value: ASTNode
}

interface ASTLogNode {
  type: ASTNodeType.Log,
  children: ASTNode[]
}

type ASTNode =
  ASTValueNode<ASTNodeType.String, string> |
  ASTValueNode<ASTNodeType.Literal, string> |
  ASTProgramNode |
  ASTAssignmentNode |
  ASTLogNode

These types are very similar to our lexer types, so we'll only go over these briefly.

ASTNodeType

Another enum which would contain our possible AST node types.

Like our lexer, this contains both String and Literal entries, as well as other types.

ASTValueNode

The AST equivalent of TokenValueNode. Used for strings and literals to capture values.

ASTProgramNode

Here we define our Program node, this shall be the root node in whatever AST we return.

It contains an array of children, which are other AST nodes, sequenced in execution order.

ASTAssignmentNode

This is the resulting AST entry for when we parse an assignment.

It will capture both VariableDeclaration and an AssignmentOperator converting these into a single node format.

ASTLogNode

Like our Log token, this will contain necessary information around what we're actually going to log.

ASTNode

A union of all the above types, so we have a single reference.