Abstract Syntax Tree
Abstract Syntax Tree
Abstract Syntax Tree
Letlang source files SHOULD be parsed into the following Abstract Syntax Tree:
unit = CompilationUnit(path: identifier+, body: statement*)
statement =
| Import(path: identifier+, alias?: identifier)
| EffectDeclaration(
is_public: bool,
symbol_name: identifier,
call_params: call_param*,
return_type: typeref,
)
| ClassDeclaration(
is_public: bool,
symbol_name: identifier,
type_params: type_param*,
cons_param: cons_param,
constraints?: proposition+,
)
| FunctionDeclaration(
is_public: bool,
symbol_name: identifier,
type_params: type_param*,
call_params: call_param*,
return_type: typeref,
body: proposition+,
)
| TailRecursiveFunctionDeclaration(
is_public: bool,
symbol_name: identifier,
type_params: type_param*,
call_params: call_param*,
return_type: typeref,
body: proposition+,
)
type_param = TypeParam(param_name: identifier)
call_param = CallParam(param_name: identifier, param_type: typeref)
cons_param = ConsParam(param_name: identifier, param_type: typeref)
typeref =
| TypeValue(val: literal)
| TypeName(symbol: identifier+, type_params: type_param*)
| StructDefinition(members: typeref_struct_member*)
| TupleDefinition(members: typeref*)
| FunctionSignature(params: typeref*, return_type: typeref)
| OneOf(alternatives: typeref*)
| AllOf(alternatives: typeref*)
| Not(typeref: typeref)
typeref_struct_member = StructMemberDefinition(name: identifier, typeref: typeref)
proposition =
| Evaluation(expr: expression)
| Constraint(symbol_name: identifier, symbol_type: typeref, checks: expression*)
expression =
| Symbol(path: identifier+)
| Literal(val: literal)
| Structure(members: expression_struct_member*)
| Tuple(members: expression*)
| List(items: expression*)
| EffectCall(name: identifier+, params: expression*)
| FunctionCall(func: expression, params: expression*)
| SpawnCall(func: expression, params: expression*)
| GenericResolve(val: expression, type_params: typeref+)
| MemberAccess(lhs: expression, rhs: identifier)
| TypeCheck(lhs: expression, rhs: typeref, negate: bool)
| UnaryOperation(op: unary_operator, expr: expression)
| BinaryOperation(lhs: expression, op: binary_operator, rhs: expression)
| PatternMatch(lhs: pattern, rhs: expression)
| TailRecFinal(val: expression)
| TailRecRecurse(args: expression*)
| MatchBranching(expr: expression, cases: match_branch+)
| ConditionalBranching(cases: cond_branch*, else_case: proposition+)
| Receive(cases: receive_branch+, after?: receive_timeout_branch)
unary_operator = ...
binary_operator = ...
match_branch = MatchBranch(pattern: pattern, body: proposition+)
cond_branch = ConditionalBranch(cond: expression, body: proposition+)
receive_branch = ReceiveBranch(pattern: pattern, body: proposition+)
receive_timeout_branch = ReceiveTimeoutBranch(timeout: expression, body: proposition+)
pattern =
| VariableBinding(symbol_name: identifier)
| ValuePattern(val: expression)
| LiteralPattern(val: literal)
| TuplePattern(members: pattern*)
| StructPattern(members: pattern_struct_member*)
| ListPattern(items: pattern*)
| ListHeadTailPattern(head: pattern, tail: pattern)
pattern_struct_member = StructMemberPattern(name: identifier, pattern: pattern)
literal =
| BooleanLiteral(val: bool)
| NumberLiteral(val: f64)
| AtomLiteral(repr: string)
| StringLiteral(val: string)
identifier = /[_a-zA-Z][_0-9a-zA-Z]*/
The following nodes MUST create a new scope:
CompilationUnit
ClassDeclaration
FunctionDeclaration
TailRecursiveFunctionDeclaration
MatchBranch
ConditionalBranch
ReceiveBranch
ReceiveTimeoutBranch
The following nodes MUST create a new symbol in the current scope:
Import
EffectDeclaration
ClassDeclaration
FunctionDeclaration
TailRecursiveFunctionDeclaration
TypeParam
CallParam
ConsParam
VariableBinding
The compiler MUST ensure that Symbol
, TypeName
and EffectCall
nodes
point to a symbol that exists in the current scope.
The compiler MUST ensure that symbols are used in the right context:
ClassDeclaration
nodes MUST be used only in a TypeName
nodeTypeParam
nodes MUST be used only in a TypeName
nodeFunctionDeclaration
nodes MUST be used only in a Symbol
nodeTailRecursiveFunctionDeclaration
nodes MUST be used only in a Symbol
nodeEffectDeclaration
nodes MUST be used only in a EffectCall
nodeThe compiler MUST ensure that GenericResolve
nodes are only applied to
symbols having at least one type parameter.
The compiler MUST ensure that the val
field of a GenericResolve
node is
a Symbol
node.
The compiler MUST ensure that every Import
nodes point to an existing
Letlang module.