diff --git a/ast/src/main/ast/pork.yml b/ast/src/main/ast/pork.yml index 87d1cac..461abc2 100644 --- a/ast/src/main/ast/pork.yml +++ b/ast/src/main/ast/pork.yml @@ -41,6 +41,20 @@ types: type: Symbol - name: value type: Expression + VarAssignment: + parent: Expression + values: + - name: symbol + type: Symbol + - name: value + type: Expression + SetAssignment: + parent: Expression + values: + - name: symbol + type: Symbol + - name: value + type: Expression InfixOperator: values: - name: token @@ -70,6 +84,18 @@ types: - name: Remainder values: token: "rem" + - name: Lesser + values: + token: "<" + - name: Greater + values: + token: ">" + - name: GreaterEqual + values: + token: ">=" + - name: LesserEqual + values: + token: "<=" InfixOperation: parent: Expression values: diff --git a/ast/src/main/graph/types.dot b/ast/src/main/graph/types.dot index 68bc44e..2fd7de9 100644 --- a/ast/src/main/graph/types.dot +++ b/ast/src/main/graph/types.dot @@ -8,6 +8,8 @@ digraph A { type_Block [shape=box,label="Block"] type_CompilationUnit [shape=box,label="CompilationUnit"] type_LetAssignment [shape=box,label="LetAssignment"] + type_VarAssignment [shape=box,label="VarAssignment"] + type_SetAssignment [shape=box,label="SetAssignment"] type_InfixOperator [shape=box,label="InfixOperator"] type_InfixOperation [shape=box,label="InfixOperation"] type_BooleanLiteral [shape=box,label="BooleanLiteral"] @@ -35,6 +37,8 @@ digraph A { type_Node -> type_CompilationUnit type_Node -> type_Native type_Expression -> type_LetAssignment + type_Expression -> type_VarAssignment + type_Expression -> type_SetAssignment type_Expression -> type_InfixOperation type_Expression -> type_BooleanLiteral type_Expression -> type_FunctionCall @@ -58,6 +62,10 @@ digraph A { type_CompilationUnit -> type_Definition [style=dotted] type_LetAssignment -> type_Symbol [style=dotted] type_LetAssignment -> type_Expression [style=dotted] + type_VarAssignment -> type_Symbol [style=dotted] + type_VarAssignment -> type_Expression [style=dotted] + type_SetAssignment -> type_Symbol [style=dotted] + type_SetAssignment -> type_Expression [style=dotted] type_InfixOperation -> type_Expression [style=dotted] type_InfixOperation -> type_InfixOperator [style=dotted] type_FunctionCall -> type_Symbol [style=dotted] diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/InfixOperator.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/InfixOperator.kt index 0425918..1901a62 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/InfixOperator.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/InfixOperator.kt @@ -14,5 +14,9 @@ enum class InfixOperator(val token: String) { Equals("=="), NotEquals("!="), EuclideanModulo("mod"), - Remainder("rem") + Remainder("rem"), + Lesser("<"), + Greater(">"), + GreaterEqual(">="), + LesserEqual("<=") } diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/NodeCoalescer.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/NodeCoalescer.kt index 7632418..a434cbd 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/NodeCoalescer.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/NodeCoalescer.kt @@ -53,6 +53,9 @@ class NodeCoalescer(val handler: (Node) -> Unit) : NodeVisitor { override fun visitPrefixOperation(node: PrefixOperation): Unit = handle(node) + override fun visitSetAssignment(node: SetAssignment): Unit = + handle(node) + override fun visitStringLiteral(node: StringLiteral): Unit = handle(node) @@ -62,6 +65,9 @@ class NodeCoalescer(val handler: (Node) -> Unit) : NodeVisitor { override fun visitSymbolReference(node: SymbolReference): Unit = handle(node) + override fun visitVarAssignment(node: VarAssignment): Unit = + handle(node) + override fun visitWhile(node: While): Unit = handle(node) diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/NodeType.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/NodeType.kt index 4edc284..eb7b914 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/NodeType.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/NodeType.kt @@ -23,8 +23,10 @@ enum class NodeType(val parent: NodeType? = null) { Native(Node), Parentheses(Expression), PrefixOperation(Expression), + SetAssignment(Expression), StringLiteral(Expression), Symbol(Node), SymbolReference(Expression), + VarAssignment(Expression), While(Expression) } diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/NodeVisitor.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/NodeVisitor.kt index 22eb6c1..75a85d3 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/NodeVisitor.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/NodeVisitor.kt @@ -36,11 +36,15 @@ interface NodeVisitor { fun visitPrefixOperation(node: PrefixOperation): T + fun visitSetAssignment(node: SetAssignment): T + fun visitStringLiteral(node: StringLiteral): T fun visitSymbol(node: Symbol): T fun visitSymbolReference(node: SymbolReference): T + fun visitVarAssignment(node: VarAssignment): T + fun visitWhile(node: While): T } diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/NodeVisitorExtensions.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/NodeVisitorExtensions.kt index e68e4e4..bebdb9a 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/NodeVisitorExtensions.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/NodeVisitorExtensions.kt @@ -7,6 +7,8 @@ fun NodeVisitor.visit(node: Node): T = is Block -> visitBlock(node) is CompilationUnit -> visitCompilationUnit(node) is LetAssignment -> visitLetAssignment(node) + is VarAssignment -> visitVarAssignment(node) + is SetAssignment -> visitSetAssignment(node) is InfixOperation -> visitInfixOperation(node) is BooleanLiteral -> visitBooleanLiteral(node) is FunctionCall -> visitFunctionCall(node) diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/SetAssignment.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/SetAssignment.kt new file mode 100644 index 0000000..30c39c4 --- /dev/null +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/SetAssignment.kt @@ -0,0 +1,29 @@ +// GENERATED CODE FROM PORK AST CODEGEN +package gay.pizza.pork.ast + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +@SerialName("setAssignment") +class SetAssignment(val symbol: Symbol, val value: Expression) : Expression() { + override val type: NodeType = NodeType.SetAssignment + + override fun visitChildren(visitor: NodeVisitor): List = + visitor.visitNodes(symbol, value) + + override fun visit(visitor: NodeVisitor): T = + visitor.visitSetAssignment(this) + + override fun equals(other: Any?): Boolean { + if (other !is SetAssignment) return false + return other.symbol == symbol && other.value == value + } + + override fun hashCode(): Int { + var result = symbol.hashCode() + result = 31 * result + value.hashCode() + result = 31 * result + type.hashCode() + return result + } +} diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/VarAssignment.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/VarAssignment.kt new file mode 100644 index 0000000..b705fff --- /dev/null +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/VarAssignment.kt @@ -0,0 +1,29 @@ +// GENERATED CODE FROM PORK AST CODEGEN +package gay.pizza.pork.ast + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +@SerialName("varAssignment") +class VarAssignment(val symbol: Symbol, val value: Expression) : Expression() { + override val type: NodeType = NodeType.VarAssignment + + override fun visitChildren(visitor: NodeVisitor): List = + visitor.visitNodes(symbol, value) + + override fun visit(visitor: NodeVisitor): T = + visitor.visitVarAssignment(this) + + override fun equals(other: Any?): Boolean { + if (other !is VarAssignment) return false + return other.symbol == symbol && other.value == value + } + + override fun hashCode(): Int { + var result = symbol.hashCode() + result = 31 * result + value.hashCode() + result = 31 * result + type.hashCode() + return result + } +} diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt index 2b6f132..9a3dc16 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt @@ -26,13 +26,19 @@ class EvaluationVisitor(root: Scope) : NodeVisitor { override fun visitLetAssignment(node: LetAssignment): Any { val value = node.value.visit(this) - currentScope.define(node.symbol.id, value) + currentScope.define(node.symbol.id, value, ValueStoreType.Let) return value } override fun visitSymbolReference(node: SymbolReference): Any = currentScope.value(node.symbol.id) + override fun visitVarAssignment(node: VarAssignment): Any { + val value = node.value.visit(this) + currentScope.define(node.symbol.id, value, type = ValueStoreType.Var) + return value + } + override fun visitWhile(node: While): Any { val blockFunction = node.block.visit(this) as BlockFunction var result: Any? = null @@ -68,6 +74,12 @@ class EvaluationVisitor(root: Scope) : NodeVisitor { } } + override fun visitSetAssignment(node: SetAssignment): Any { + val value = node.value.visit(this) + currentScope.set(node.symbol.id, value) + return value + } + override fun visitIf(node: If): Any { val condition = node.condition.visit(this) return if (condition == true) { @@ -108,7 +120,11 @@ class EvaluationVisitor(root: Scope) : NodeVisitor { multiply = { a, b -> a * b }, divide = { a, b -> a / b }, euclideanModulo = { _, _ -> throw RuntimeException("Can't perform integer modulo between floating point types") }, - remainder = { _, _ -> throw RuntimeException("Can't perform integer remainder between floating point types") } + remainder = { _, _ -> throw RuntimeException("Can't perform integer remainder between floating point types") }, + lesser = { a, b -> a < b }, + greater = { a, b -> a > b }, + lesserEqual = { a, b -> a <= b }, + greaterEqual = { a, b -> a >= b } ) } @@ -123,7 +139,11 @@ class EvaluationVisitor(root: Scope) : NodeVisitor { multiply = { a, b -> a * b }, divide = { a, b -> a / b }, euclideanModulo = { _, _ -> throw RuntimeException("Can't perform integer modulo between floating point types") }, - remainder = { _, _ -> throw RuntimeException("Can't perform integer remainder between floating point types") } + remainder = { _, _ -> throw RuntimeException("Can't perform integer remainder between floating point types") }, + lesser = { a, b -> a < b }, + greater = { a, b -> a > b }, + lesserEqual = { a, b -> a <= b }, + greaterEqual = { a, b -> a >= b } ) } @@ -138,7 +158,11 @@ class EvaluationVisitor(root: Scope) : NodeVisitor { multiply = { a, b -> a * b }, divide = { a, b -> a / b }, euclideanModulo = { x, d -> (x % d).let { q -> if (q < 0) q + abs(d) else q } }, - remainder = { x, d -> x % d } + remainder = { x, d -> x % d }, + lesser = { a, b -> a < b }, + greater = { a, b -> a > b }, + lesserEqual = { a, b -> a <= b }, + greaterEqual = { a, b -> a >= b } ) } @@ -153,7 +177,11 @@ class EvaluationVisitor(root: Scope) : NodeVisitor { multiply = { a, b -> a * b }, divide = { a, b -> a / b }, euclideanModulo = { x, d -> (x % d).let { q -> if (q < 0) q + abs(d) else q } }, - remainder = { x, d -> x % d } + remainder = { x, d -> x % d }, + lesser = { a, b -> a < b }, + greater = { a, b -> a > b }, + lesserEqual = { a, b -> a <= b }, + greaterEqual = { a, b -> a >= b } ) } @@ -170,8 +198,12 @@ class EvaluationVisitor(root: Scope) : NodeVisitor { multiply: (T, T) -> T, divide: (T, T) -> T, euclideanModulo: (T, T) -> T, - remainder: (T, T) -> T - ): T { + remainder: (T, T) -> T, + lesser: (T, T) -> Boolean, + greater: (T, T) -> Boolean, + lesserEqual: (T, T) -> Boolean, + greaterEqual: (T, T) -> Boolean + ): Any { return when (op) { InfixOperator.Plus -> add(convert(left), convert(right)) InfixOperator.Minus -> subtract(convert(left), convert(right)) @@ -179,6 +211,10 @@ class EvaluationVisitor(root: Scope) : NodeVisitor { InfixOperator.Divide -> divide(convert(left), convert(right)) InfixOperator.EuclideanModulo -> euclideanModulo(convert(left), convert(right)) InfixOperator.Remainder -> remainder(convert(left), convert(right)) + InfixOperator.Lesser -> lesser(convert(left), convert(right)) + InfixOperator.Greater -> greater(convert(left), convert(right)) + InfixOperator.LesserEqual -> lesserEqual(convert(left), convert(right)) + InfixOperator.GreaterEqual -> greaterEqual(convert(left), convert(right)) else -> throw RuntimeException("Unable to handle operation $op") } } diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Scope.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Scope.kt index b65f444..b581f25 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Scope.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Scope.kt @@ -6,43 +6,55 @@ class Scope( val name: String? = null ) { private val inherited = inherits.toMutableList() - private val variables = mutableMapOf() + private val variables = mutableMapOf() - fun define(name: String, value: Any) { - val previous = variables.put(name, value) + fun define(name: String, value: Any, type: ValueStoreType = ValueStoreType.Let) { + val previous = variables.put(name, ValueStore(value, type)) if (previous != null) { variables[name] = previous throw RuntimeException("Variable '${name}' is already defined") } } - fun value(name: String): Any { - val value = valueOrNotFound(name) - if (value === NotFound) { + fun set(name: String, value: Any) { + val holder = valueHolderOrNotFound(name) + if (holder.type == ValueStoreType.Let) { + throw RuntimeException("Variable '${name}' is already defined") + } + + if (holder === NotFound.Holder) { throw RuntimeException("Variable '${name}' not defined") } - return value + holder.value = value } - private fun valueOrNotFound(name: String): Any { - val value = variables[name] - if (value == null) { + fun value(name: String): Any { + val holder = valueHolderOrNotFound(name) + if (holder === NotFound.Holder) { + throw RuntimeException("Variable '${name}' not defined") + } + return holder.value + } + + private fun valueHolderOrNotFound(name: String): ValueStore { + val holder = variables[name] + if (holder == null) { if (parent != null) { - val parentMaybeFound = parent.valueOrNotFound(name) - if (parentMaybeFound !== NotFound) { + val parentMaybeFound = parent.valueHolderOrNotFound(name) + if (parentMaybeFound !== NotFound.Holder) { return parentMaybeFound } } for (inherit in inherited) { - val inheritMaybeFound = inherit.valueOrNotFound(name) - if (inheritMaybeFound !== NotFound) { + val inheritMaybeFound = inherit.valueHolderOrNotFound(name) + if (inheritMaybeFound !== NotFound.Holder) { return inheritMaybeFound } } - return NotFound + return NotFound.Holder } - return value + return holder } fun fork(name: String? = null): Scope = @@ -80,5 +92,7 @@ class Scope( } } - private object NotFound + private object NotFound { + val Holder = ValueStore(NotFound, ValueStoreType.Let) + } } diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ValueStore.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ValueStore.kt new file mode 100644 index 0000000..d5cfbc3 --- /dev/null +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ValueStore.kt @@ -0,0 +1,5 @@ +package gay.pizza.pork.evaluator + +class ValueStore(var value: Any, val type: ValueStoreType) { + override fun toString(): String = "${type.name}: $value" +} \ No newline at end of file diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ValueStoreType.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ValueStoreType.kt new file mode 100644 index 0000000..0db02e6 --- /dev/null +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ValueStoreType.kt @@ -0,0 +1,6 @@ +package gay.pizza.pork.evaluator + +enum class ValueStoreType { + Let, + Var +} diff --git a/examples/count.pork b/examples/count.pork new file mode 100644 index 0000000..6aa1a33 --- /dev/null +++ b/examples/count.pork @@ -0,0 +1,7 @@ +export func main() { + var x = 1 + while x <= 5 { + println(x) + x = x + 1 + } +} diff --git a/parser/src/main/kotlin/gay/pizza/pork/parser/DiscardNodeAttribution.kt b/parser/src/main/kotlin/gay/pizza/pork/parser/DiscardNodeAttribution.kt index 6875f5e..b3de15e 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/DiscardNodeAttribution.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/DiscardNodeAttribution.kt @@ -5,5 +5,6 @@ import gay.pizza.pork.ast.Node object DiscardNodeAttribution : NodeAttribution { override fun enter() {} override fun push(token: Token) {} + override fun adopt(node: T) {} override fun exit(node: T): T = node } diff --git a/parser/src/main/kotlin/gay/pizza/pork/parser/NodeAttribution.kt b/parser/src/main/kotlin/gay/pizza/pork/parser/NodeAttribution.kt index 864afc2..ba11e8f 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/NodeAttribution.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/NodeAttribution.kt @@ -5,5 +5,6 @@ import gay.pizza.pork.ast.Node interface NodeAttribution { fun enter() fun push(token: Token) + fun adopt(node: T) fun exit(node: T): T } diff --git a/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt b/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt index 11d6661..71da253 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt @@ -45,6 +45,14 @@ class Parser(source: PeekableSource, val attribution: NodeAttribution) { LetAssignment(symbol, value) } + private fun readVarAssignment(): VarAssignment = within { + expect(TokenType.Var) + val symbol = readSymbolRaw() + expect(TokenType.Equals) + val value = readExpression() + VarAssignment(symbol, value) + } + private fun readSymbolRaw(): Symbol = within { expect(TokenType.Symbol) { Symbol(it.text) } } @@ -123,6 +131,10 @@ class Parser(source: PeekableSource, val attribution: NodeAttribution) { readLetAssignment() } + TokenType.Var -> { + readVarAssignment() + } + TokenType.Symbol -> { readSymbolCases() } @@ -161,6 +173,15 @@ class Parser(source: PeekableSource, val attribution: NodeAttribution) { } } + if (expression is SymbolReference && peek(TokenType.Equals)) { + return within { + attribution.adopt(expression) + expect(TokenType.Equals) + val value = readExpression() + SetAssignment(expression.symbol, value) + } + } + return if (peek( TokenType.Plus, TokenType.Minus, @@ -169,7 +190,11 @@ class Parser(source: PeekableSource, val attribution: NodeAttribution) { TokenType.Equality, TokenType.Inequality, TokenType.Mod, - TokenType.Rem + TokenType.Rem, + TokenType.Lesser, + TokenType.Greater, + TokenType.LesserEqual, + TokenType.GreaterEqual ) ) { within { @@ -268,6 +293,10 @@ class Parser(source: PeekableSource, val attribution: NodeAttribution) { TokenType.Inequality -> InfixOperator.NotEquals TokenType.Mod -> InfixOperator.EuclideanModulo TokenType.Rem -> InfixOperator.Remainder + TokenType.Lesser -> InfixOperator.Lesser + TokenType.Greater -> InfixOperator.Greater + TokenType.LesserEqual -> InfixOperator.LesserEqual + TokenType.GreaterEqual -> InfixOperator.GreaterEqual else -> throw RuntimeException("Unknown Infix Operator") } diff --git a/parser/src/main/kotlin/gay/pizza/pork/parser/Printer.kt b/parser/src/main/kotlin/gay/pizza/pork/parser/Printer.kt index 7a4836b..31f9443 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/Printer.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/Printer.kt @@ -95,6 +95,13 @@ class Printer(buffer: StringBuilder) : NodeVisitor { visit(node.symbol) } + override fun visitVarAssignment(node: VarAssignment) { + append("var ") + visit(node.symbol) + append(" = ") + visit(node.value) + } + override fun visitWhile(node: While) { append("while ") visit(node.condition) @@ -113,6 +120,12 @@ class Printer(buffer: StringBuilder) : NodeVisitor { visit(node.expression) } + override fun visitSetAssignment(node: SetAssignment) { + visit(node.symbol) + append(" = ") + visit(node.value) + } + override fun visitIf(node: If) { append("if ") visit(node.condition) diff --git a/parser/src/main/kotlin/gay/pizza/pork/parser/TokenNodeAttribution.kt b/parser/src/main/kotlin/gay/pizza/pork/parser/TokenNodeAttribution.kt index 36abdc0..2de962d 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/TokenNodeAttribution.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/TokenNodeAttribution.kt @@ -22,6 +22,15 @@ class TokenNodeAttribution : NodeAttribution { store.add(token) } + override fun adopt(node: T) { + val tokens = nodes.remove(node) + if (tokens != null) { + for (token in tokens) { + push(token) + } + } + } + override fun exit(node: T): T { val store = stack.removeLast() nodes[node] = store diff --git a/parser/src/main/kotlin/gay/pizza/pork/parser/TokenType.kt b/parser/src/main/kotlin/gay/pizza/pork/parser/TokenType.kt index 709b78e..5ad74bb 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/TokenType.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/TokenType.kt @@ -19,6 +19,10 @@ enum class TokenType(vararg properties: TokenTypeProperty) { Minus(SingleChar('-'), OperatorFamily), Multiply(SingleChar('*'), OperatorFamily), Divide(SingleChar('/'), OperatorFamily), + LesserEqual(OperatorFamily), + GreaterEqual(OperatorFamily), + Lesser(SingleChar('<'), OperatorFamily, Promotion('=', LesserEqual)), + Greater(SingleChar('>'), OperatorFamily, Promotion('=', GreaterEqual)), LeftCurly(SingleChar('{')), RightCurly(SingleChar('}')), LeftBracket(SingleChar('[')), @@ -42,6 +46,7 @@ enum class TokenType(vararg properties: TokenTypeProperty) { Func(Keyword("func"), KeywordFamily), Native(Keyword("native"), KeywordFamily), Let(Keyword("let"), KeywordFamily), + Var(Keyword("var"), KeywordFamily), Whitespace(CharConsumer { it == ' ' || it == '\r' || it == '\n' || it == '\t' }), BlockComment(CommentFamily), LineComment(CommentFamily),