From 10a7dc8823c8cecab2a4d0d7b66ef1f52a6dffbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Przemys=C5=82aw=20Pluta?= Date: Wed, 11 Mar 2020 22:58:28 +0100 Subject: [PATCH] Migrate import evaluator to Kotlin --- .../io/smnp/runtime/model/CallStackFrame.kt | 2 +- .../io/smnp/dsl/ast/parser/ImportParser.kt | 3 +- .../io/smnp/dsl/ast/parser/RootParser.kt | 3 +- .../evaluation/evaluator/ImportEvaluator.kt | 39 +++++++++++++++++++ .../evaluation/evaluator/RootEvaluator.kt | 4 +- .../kotlin/io/smnp/interpreter/Interpreter.kt | 28 ++++++++----- 6 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 app/src/main/kotlin/io/smnp/evaluation/evaluator/ImportEvaluator.kt diff --git a/api/src/main/kotlin/io/smnp/runtime/model/CallStackFrame.kt b/api/src/main/kotlin/io/smnp/runtime/model/CallStackFrame.kt index c75f4cf..a65302c 100644 --- a/api/src/main/kotlin/io/smnp/runtime/model/CallStackFrame.kt +++ b/api/src/main/kotlin/io/smnp/runtime/model/CallStackFrame.kt @@ -24,7 +24,7 @@ data class CallStackFrame( } fun getVariable(name: String): Value { - return scopes.lastOrNull { it.containsKey(name) }?.get(name) ?: throw RuntimeException("Variable `$name` not found") + return scopes.lastOrNull { it.containsKey(name) }?.get(name) ?: throw RuntimeException("Undefined variable `$name`") } fun prettyScope() { diff --git a/app/src/main/kotlin/io/smnp/dsl/ast/parser/ImportParser.kt b/app/src/main/kotlin/io/smnp/dsl/ast/parser/ImportParser.kt index c98e937..e583cb0 100644 --- a/app/src/main/kotlin/io/smnp/dsl/ast/parser/ImportParser.kt +++ b/app/src/main/kotlin/io/smnp/dsl/ast/parser/ImportParser.kt @@ -9,8 +9,7 @@ class ImportParser : Parser() { override fun tryToParse(input: TokenList): ParserOutput { val pathParser = oneOf( UnitParser(), - SimpleIdentifierParser(), - StringLiteralParser() + SimpleIdentifierParser() ) return allOf( diff --git a/app/src/main/kotlin/io/smnp/dsl/ast/parser/RootParser.kt b/app/src/main/kotlin/io/smnp/dsl/ast/parser/RootParser.kt index c53fead..ca8eea0 100644 --- a/app/src/main/kotlin/io/smnp/dsl/ast/parser/RootParser.kt +++ b/app/src/main/kotlin/io/smnp/dsl/ast/parser/RootParser.kt @@ -3,12 +3,13 @@ package io.smnp.dsl.ast.parser import io.smnp.dsl.ast.model.entity.ParserOutput import io.smnp.dsl.ast.model.node.RootNode import io.smnp.dsl.token.model.entity.TokenList +import io.smnp.dsl.token.model.enumeration.TokenType class RootParser : Parser() { override fun tryToParse(input: TokenList): ParserOutput { return repeat( oneOf( - ImportParser(), + allOf(ImportParser(), optional(terminal(TokenType.SEMICOLON))) { (import, _) -> import }, FunctionDefinitionParser(), ExtendParser(), StatementParser() diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/ImportEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/ImportEvaluator.kt new file mode 100644 index 0000000..a3758ab --- /dev/null +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/ImportEvaluator.kt @@ -0,0 +1,39 @@ +package io.smnp.evaluation.evaluator + +import io.smnp.dsl.ast.model.node.AccessOperatorNode +import io.smnp.dsl.ast.model.node.IdentifierNode +import io.smnp.dsl.ast.model.node.ImportNode +import io.smnp.dsl.ast.model.node.Node +import io.smnp.environment.Environment +import io.smnp.error.ShouldNeverReachThisLineException +import io.smnp.evaluation.model.entity.EvaluatorOutput + +class ImportEvaluator : Evaluator() { + override fun supportedNodes() = listOf(ImportNode::class) + + override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { + val path = when (val pathNode = (node as ImportNode).path) { + is AccessOperatorNode -> complexPath(pathNode).joinToString(".") + is IdentifierNode -> pathNode.token.rawValue + else -> throw ShouldNeverReachThisLineException() + } + + environment.loadModule(path) + + return EvaluatorOutput.ok() + } + + private fun complexPath(segment: AccessOperatorNode): List { + val segments = mutableListOf() + val (lhs, _, rhs) = segment + + segments.add((rhs as IdentifierNode).token.rawValue) + + when(lhs) { + is AccessOperatorNode -> segments.addAll(complexPath(lhs)) + is IdentifierNode -> segments.add(lhs.token.rawValue) + } + + return segments.reversed() + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/RootEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/RootEvaluator.kt index ea95e19..24d9c1a 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/RootEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/RootEvaluator.kt @@ -11,8 +11,10 @@ class RootEvaluator : Evaluator() { override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput { val evaluator = oneOf( + ImportEvaluator(), ExpressionEvaluator(), - FunctionDefinitionEvaluator() + FunctionDefinitionEvaluator(), + DefaultEvaluator() ) for(child in node.children) { diff --git a/app/src/main/kotlin/io/smnp/interpreter/Interpreter.kt b/app/src/main/kotlin/io/smnp/interpreter/Interpreter.kt index c1948dc..eed06a8 100644 --- a/app/src/main/kotlin/io/smnp/interpreter/Interpreter.kt +++ b/app/src/main/kotlin/io/smnp/interpreter/Interpreter.kt @@ -2,30 +2,38 @@ package io.smnp.interpreter import io.smnp.dsl.ast.parser.RootParser import io.smnp.dsl.token.tokenizer.DefaultTokenizer +import io.smnp.environment.DefaultEnvironment +import io.smnp.environment.Environment +import io.smnp.evaluation.evaluator.RootEvaluator import java.io.File class Interpreter { - fun run(code: String) { - val tokenizer = DefaultTokenizer() - val parser = RootParser() + private val tokenizer = DefaultTokenizer() + private val parser = RootParser() + private val evaluator = RootEvaluator() + fun run(code: String) { val lines = code.split("\n") val tokens = tokenizer.tokenize(lines) val ast = parser.parse(tokens) - ast.node.pretty() - println(tokens) + val environment = createEnvironment() + evaluator.evaluate(ast.node, environment) + } + + private fun createEnvironment(): Environment { + val environment = DefaultEnvironment() + environment.loadModule("smnp.lang") + + return environment } fun run(file: File) { - val tokenizer = DefaultTokenizer() - val parser = RootParser() - val lines = file.readLines() val tokens = tokenizer.tokenize(lines) val ast = parser.parse(tokens) - ast.node.pretty() - println(tokens) + val environment = createEnvironment() + evaluator.evaluate(ast.node, environment) } } \ No newline at end of file