Last active
June 6, 2017 00:34
-
-
Save Barakat/3a1cab5478c1ac13c9bfb2ba311e7639 to your computer and use it in GitHub Desktop.
Mini-programming language in pure-Kotlin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import java.io.ByteArrayInputStream | |
| import java.io.InputStream | |
| import java.io.PrintStream | |
| import java.util.* | |
| import java.util.concurrent.Callable | |
| enum class Token constructor(val symbol: String) { | |
| IF("if"), | |
| ELSE("else"), | |
| WHILE("while"), | |
| TRUE("true"), | |
| FALSE("false"), | |
| BREAK("break"), | |
| CONTINUE("continue"), | |
| SEMICOLON(";"), | |
| COMMA(","), | |
| OP("("), | |
| CP(")"), | |
| OB("{"), | |
| CB("}"), | |
| NAME("NAME"), | |
| NUMBER("NUMBER"), | |
| STRING("STRING"), | |
| ASS("="), | |
| EQ("=="), | |
| NOT("!"), | |
| NE("!="), | |
| ADD("+"), | |
| SUB("-"), | |
| MUL("*"), | |
| LT("<"), | |
| LTE("<="), | |
| GT(">"), | |
| GTE(">="), | |
| DIV("/"), | |
| EOF("EOF"), | |
| INVALID("INVALID"); | |
| override fun toString() = symbol | |
| val binaryOperator get() = this in arrayOf(ASS, EQ, NE, LT, LTE, GT, GTE, ADD, SUB, MUL, DIV) | |
| val precedence get() = when (this) { | |
| EQ, NE -> 1 | |
| LT, LTE, GT, GTE -> 2 | |
| ADD, SUB -> 3 | |
| MUL, DIV -> 4 | |
| else -> 0 | |
| } | |
| } | |
| class Lexer constructor(val inputStream: InputStream) { | |
| var ready = false | |
| var eof = false | |
| var char = '\u0000' | |
| fun next(): Pair<Token, Any?> { | |
| if (!ready) { | |
| nextChar() | |
| ready = true | |
| } | |
| while (true) { | |
| while (!eof && char.isWhitespace()) | |
| nextChar() | |
| if (eof) | |
| return Pair(Token.EOF, null) | |
| else if (char.isJavaIdentifierStart()) { | |
| val buffer = StringBuffer() | |
| do { | |
| buffer.append(char) | |
| nextChar() | |
| } while (char.isJavaIdentifierPart()) | |
| val name = buffer.toString() | |
| when (name) { | |
| "if" -> return Pair(Token.IF, null) | |
| "else" -> return Pair(Token.ELSE, null) | |
| "while" -> return Pair(Token.WHILE, null) | |
| "break" -> return Pair(Token.BREAK, null) | |
| "continue" -> return Pair(Token.CONTINUE, null) | |
| "true" -> return Pair(Token.TRUE, null) | |
| "false" -> return Pair(Token.FALSE, null) | |
| } | |
| return Pair(Token.NAME, name) | |
| } else if (char.isDigit()) { | |
| val buffer = StringBuffer() | |
| do { | |
| buffer.append(char) | |
| nextChar() | |
| } while (char.isDigit()) | |
| return Pair(Token.NUMBER, buffer.toString().toInt()) | |
| } else if (char == '"') { | |
| nextChar() | |
| val buffer = StringBuffer() | |
| while (char != '"') { | |
| buffer.append(char) | |
| nextChar() | |
| } | |
| nextChar() | |
| return Pair(Token.STRING, buffer.toString()) | |
| } | |
| val token = when (char) { | |
| ';' -> Pair(Token.SEMICOLON, null) | |
| ',' -> Pair(Token.COMMA, null) | |
| '(' -> Pair(Token.OP, null) | |
| ')' -> Pair(Token.CP, null) | |
| '{' -> Pair(Token.OB, null) | |
| '}' -> Pair(Token.CB, null) | |
| '+' -> Pair(Token.ADD, null) | |
| '-' -> Pair(Token.SUB, null) | |
| '*' -> Pair(Token.MUL, null) | |
| '/' -> Pair(Token.DIV, null) | |
| '=' -> { | |
| nextChar() | |
| if (char == '=') { | |
| nextChar() | |
| Pair(Token.EQ, null) | |
| } else { | |
| Pair(Token.ASS, null) | |
| } | |
| } | |
| '<' -> { | |
| nextChar() | |
| if (char == '=') { | |
| nextChar() | |
| Pair(Token.LTE, null) | |
| } else { | |
| Pair(Token.LT, null) | |
| } | |
| } | |
| '>' -> { | |
| nextChar() | |
| if (char == '=') { | |
| nextChar() | |
| Pair(Token.GT, null) | |
| } else { | |
| Pair(Token.GTE, null) | |
| } | |
| } | |
| '!' -> { | |
| nextChar() | |
| if (char == '=') { | |
| nextChar() | |
| Pair(Token.NE, null) | |
| } else | |
| Pair(Token.NOT, null) | |
| } | |
| else -> Pair(Token.INVALID, null) | |
| } | |
| if (token.first !in arrayOf(Token.ASS, Token.NOT)) | |
| nextChar() | |
| return token | |
| } | |
| } | |
| private fun nextChar() { | |
| val current = inputStream.read() | |
| eof = current == -1 | |
| char = current.toChar() | |
| } | |
| } | |
| class Parser constructor(val lexer: Lexer) { | |
| var current: Pair<Token, Any?>? = null | |
| var next: Pair<Token, Any?>? = null | |
| var panic = false | |
| fun parse(): Unit { | |
| if (current == null) | |
| nextToken() | |
| val unit = Unit() | |
| while (current!!.first != Token.EOF) | |
| unit.statement.add(parseStatement()) | |
| return unit | |
| } | |
| private fun nextToken() { | |
| current = next ?: lexer.next() | |
| next = lexer.next() | |
| } | |
| private fun expect(token: Token) { | |
| val currentToken = current!!.second ?: current!!.first | |
| if (currentToken != token) { | |
| panic("Expect $token got '$currentToken'") | |
| sync() | |
| } | |
| nextToken() | |
| } | |
| private fun panic(error: String) { | |
| System.out.println(error) | |
| panic = true | |
| } | |
| private fun sync() { | |
| while (current!!.first !in arrayOf(Token.EOF, Token.SEMICOLON)) | |
| nextToken() | |
| panic = true | |
| } | |
| private fun parseStatement(): Statement { | |
| val token = current!!.first | |
| if (token == Token.WHILE) | |
| return parseWhileStatement() | |
| else if (token == Token.IF) | |
| return parseIfStatement() | |
| else if (token == Token.BREAK) { | |
| nextToken() | |
| expect(Token.SEMICOLON) | |
| return BreakStatement | |
| } else if (token == Token.CONTINUE) { | |
| nextToken() | |
| expect(Token.SEMICOLON) | |
| return ContinueStatement | |
| } | |
| val expression = parseExpression() | |
| val expressionStatement = ExpressionStatement(expression) | |
| expect(Token.SEMICOLON) | |
| return expressionStatement | |
| } | |
| private fun parseWhileStatement(): WhileStatement { | |
| expect(Token.WHILE) | |
| val expression = parseExpression() | |
| expect(Token.OB) | |
| val unit = Unit() | |
| while (current!!.first != Token.CB) | |
| unit.statement.add(parseStatement()) | |
| nextToken() | |
| return WhileStatement(expression, unit) | |
| } | |
| private fun parseIfStatement(): IfStatement { | |
| expect(Token.IF) | |
| val expression = parseExpression() | |
| expect(Token.OB) | |
| val unit = Unit() | |
| while (current!!.first != Token.CB) | |
| unit.statement.add(parseStatement()) | |
| nextToken() | |
| val elseIfClauses = arrayListOf<ElseIfClause>() | |
| while (current!!.first == Token.ELSE && next!!.first == Token.IF) { | |
| nextToken() | |
| nextToken() | |
| val elseIfExpression = parseExpression() | |
| expect(Token.OB) | |
| val elseIfUnit = Unit() | |
| while (current!!.first != Token.CB) | |
| elseIfUnit.statement.add(parseStatement()) | |
| nextToken() | |
| elseIfClauses.add(ElseIfClause(elseIfExpression, elseIfUnit)) | |
| } | |
| var elseClause: Unit? = null | |
| if (current!!.first == Token.ELSE) { | |
| nextToken() | |
| expect(Token.OB) | |
| elseClause = Unit() | |
| while (current!!.first != Token.CB) | |
| elseClause.statement.add(parseStatement()) | |
| expect(Token.CB) | |
| } | |
| return IfStatement(expression, unit, elseIfClauses, elseClause) | |
| } | |
| private fun parseExpression(): Expression = parseExpression(-1) | |
| private fun parseExpression(prevPrecedence: Int): Expression { | |
| val left = parseTerm() | |
| while (current!!.first.binaryOperator && current!!.first.precedence >= prevPrecedence) { | |
| val operator = current!!.first | |
| nextToken() | |
| val right = parseExpression(current!!.first.precedence) | |
| when (operator) { | |
| Token.ASS -> return Assignment(left, right) | |
| Token.EQ -> return Equals(left, right) | |
| Token.NE -> return NotEquals(left, right) | |
| Token.LT -> return LessThan(left, right) | |
| Token.LTE -> return LessThanEquals(left, right) | |
| Token.GT -> return GreaterThan(left, right) | |
| Token.GTE -> return GreaterThanEquals(left, right) | |
| Token.ADD -> return Addition(left, right) | |
| Token.SUB -> return Subtraction(left, right) | |
| Token.MUL -> return Multiplication(left, right) | |
| Token.DIV -> return Division(left, right) | |
| else -> TODO("Not implemented binary operator") | |
| } | |
| } | |
| return left | |
| } | |
| private fun parseTerm(): Expression { | |
| val value = current!!.second | |
| when (current!!.first) { | |
| Token.NUMBER -> { | |
| nextToken() | |
| return IntegerAtom(value as Int) | |
| } | |
| Token.TRUE -> { | |
| nextToken() | |
| return TrueAtom | |
| } | |
| Token.FALSE -> { | |
| nextToken() | |
| return FalseAtom | |
| } | |
| Token.STRING -> { | |
| nextToken() | |
| return StringAtom(value as String) | |
| } | |
| Token.NAME -> { | |
| nextToken() | |
| if (current!!.first == Token.OP) { | |
| nextToken() | |
| val name = value as String | |
| val arguments = mutableListOf<Expression>() | |
| while (current!!.first != Token.CP) { | |
| arguments.add(parseExpression()) | |
| if (current!!.first == Token.COMMA) | |
| nextToken() | |
| } | |
| nextToken() | |
| return FunctionCall(name, arguments) | |
| } | |
| return SymbolAtom(value as String) | |
| } | |
| Token.OP -> { | |
| nextToken() | |
| val expression = parseExpression() | |
| expect(Token.CP) | |
| return expression | |
| } | |
| Token.SUB -> { | |
| nextToken() | |
| val expression = parseTerm() | |
| return Negative(expression) | |
| } | |
| else -> panic("Unexpected term ${current!!.first}") | |
| } | |
| return BadExpression() | |
| } | |
| } | |
| interface Node { | |
| fun accept(visitor: Visitor) | |
| } | |
| interface Statement : Node | |
| interface Expression : Node | |
| data class ExpressionStatement constructor(val expression: Expression) : Statement { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| data class WhileStatement constructor(val expression: Expression, val unit: Unit) : Statement { | |
| override fun accept(visitor: Visitor): kotlin.Unit { | |
| visitor.visit(this) | |
| } | |
| } | |
| object BreakStatement : Statement { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| object ContinueStatement : Statement { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| data class ElseIfClause constructor(val expression: Expression, val unit: Unit) | |
| data class IfStatement constructor(val expression: Expression, val unit: Unit, val elseIfClauses: MutableList<ElseIfClause> = arrayListOf(), val elseClause: Unit? = null) : Statement { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| class Unit constructor(val statement: MutableList<Statement> = mutableListOf<Statement>()) : Node { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| interface BinaryExpression : Expression { | |
| val left: Expression | |
| val right: Expression | |
| val precedence: Int | |
| } | |
| data class Assignment constructor(override val left: Expression, override val right: Expression, override val precedence: Int = Token.ASS.precedence) : BinaryExpression { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| data class LessThan constructor(override val left: Expression, override val right: Expression, override val precedence: Int = Token.LT.precedence) : BinaryExpression { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| data class LessThanEquals constructor(override val left: Expression, override val right: Expression, override val precedence: Int = Token.LTE.precedence) : BinaryExpression { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| data class GreaterThan constructor(override val left: Expression, override val right: Expression, override val precedence: Int = Token.GT.precedence) : BinaryExpression { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| data class GreaterThanEquals constructor(override val left: Expression, override val right: Expression, override val precedence: Int = Token.GTE.precedence) : BinaryExpression { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| data class Equals constructor(override val left: Expression, override val right: Expression, override val precedence: Int = Token.EQ.precedence) : BinaryExpression { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| data class NotEquals constructor(override val left: Expression, override val right: Expression, override val precedence: Int = Token.NE.precedence) : BinaryExpression { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| data class Addition constructor(override val left: Expression, override val right: Expression, override val precedence: Int = Token.ADD.precedence) : BinaryExpression { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| data class Subtraction constructor(override val left: Expression, override val right: Expression, override val precedence: Int = Token.SUB.precedence) : BinaryExpression { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| data class Multiplication constructor(override val left: Expression, override val right: Expression, override val precedence: Int = Token.MUL.precedence) : BinaryExpression { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| data class Division constructor(override val left: Expression, override val right: Expression, override val precedence: Int = Token.DIV.precedence) : BinaryExpression { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| interface UnaryExpression : Expression | |
| interface Atom : UnaryExpression | |
| data class IntegerAtom constructor(val int: Int) : Atom { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| data class StringAtom constructor(val string: String) : Atom { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| data class SymbolAtom constructor(val symbol: String) : Atom { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| object TrueAtom : Atom { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| object FalseAtom : Atom { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| data class Negative constructor(val expression: Expression) : UnaryExpression { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| data class FunctionCall constructor(val name: String, val arguments: List<Expression>) : UnaryExpression { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| class BadExpression : Expression { | |
| override fun accept(visitor: Visitor) = visitor.visit(this) | |
| } | |
| interface Visitor { | |
| fun visit(unit: Unit) | |
| fun visit(expressionStatement: ExpressionStatement) | |
| fun visit(assignment: Assignment) | |
| fun visit(equals: Equals) | |
| fun visit(notEquals: NotEquals) | |
| fun visit(lessThan: LessThan) | |
| fun visit(lessThanEquals: LessThanEquals) | |
| fun visit(greaterThan: GreaterThan) | |
| fun visit(greaterThanEquals: GreaterThanEquals) | |
| fun visit(addition: Addition) | |
| fun visit(subtraction: Subtraction) | |
| fun visit(multiplication: Multiplication) | |
| fun visit(division: Division) | |
| fun visit(badExpression: BadExpression) | |
| fun visit(integerAtom: IntegerAtom) | |
| fun visit(symbolAtom: SymbolAtom) | |
| fun visit(negative: Negative) | |
| fun visit(whileStatement: WhileStatement) | |
| fun visit(continueStatement: ContinueStatement) | |
| fun visit(breakStatement: BreakStatement) | |
| fun visit(ifStatement: IfStatement) | |
| fun visit(functionCall: FunctionCall) | |
| fun visit(stringAtom: StringAtom) | |
| fun visit(trueAtom: TrueAtom) | |
| fun visit(falseAtom: FalseAtom) | |
| } | |
| class PrettyPrintVisitor constructor(val printStream: PrintStream, private val tabSize: Int = 4) : Visitor { | |
| private var level = 0 | |
| override fun visit(unit: Unit) = unit.statement.forEach { | |
| it.accept(this) | |
| } | |
| override fun visit(expressionStatement: ExpressionStatement) { | |
| printInlineIndent("") | |
| expressionStatement.expression.accept(this) | |
| printStream.println(';') | |
| } | |
| override fun visit(whileStatement: WhileStatement) { | |
| printInlineIndent("while ") | |
| whileStatement.expression.accept(this) | |
| printStream.println(" {") | |
| enterBlock() | |
| whileStatement.unit.accept(this) | |
| exitBlock() | |
| printIndent("}") | |
| } | |
| override fun visit(breakStatement: BreakStatement) = printIndent("break") | |
| override fun visit(continueStatement: ContinueStatement) = printIndent("continue") | |
| override fun visit(ifStatement: IfStatement) { | |
| printInlineIndent("if ") | |
| ifStatement.expression.accept(this) | |
| printStream.println(" {") | |
| enterBlock() | |
| ifStatement.unit.accept(this) | |
| exitBlock() | |
| printIndent("}") | |
| ifStatement.elseIfClauses.forEach { | |
| printInlineIndent("else if ") | |
| it.expression.accept(this) | |
| printStream.println(" {") | |
| enterBlock() | |
| it.unit.accept(this) | |
| exitBlock() | |
| printIndent("}") | |
| } | |
| if (ifStatement.elseClause != null) { | |
| printIndent("else {") | |
| enterBlock() | |
| ifStatement.elseClause.statement.forEach { | |
| it.accept(this) | |
| } | |
| exitBlock() | |
| printIndent("}") | |
| } | |
| } | |
| override fun visit(assignment: Assignment) = visitBinary(assignment, "=") | |
| override fun visit(equals: Equals) = visitBinary(equals, "==") | |
| override fun visit(lessThan: LessThan) = visitBinary(lessThan, "<") | |
| override fun visit(lessThanEquals: LessThanEquals) = visitBinary(lessThanEquals, "<=") | |
| override fun visit(greaterThan: GreaterThan) = visitBinary(greaterThan, ">") | |
| override fun visit(greaterThanEquals: GreaterThanEquals) = visitBinary(greaterThanEquals, ">=") | |
| override fun visit(notEquals: NotEquals) = visitBinary(notEquals, "!=") | |
| override fun visit(addition: Addition) = visitBinary(addition, "+") | |
| override fun visit(subtraction: Subtraction) = visitBinary(subtraction, "-") | |
| override fun visit(multiplication: Multiplication) = visitBinary(multiplication, "*") | |
| override fun visit(division: Division) = visitBinary(division, "/") | |
| override fun visit(badExpression: BadExpression) = Unit | |
| override fun visit(integerAtom: IntegerAtom) = printStream.print(integerAtom.int) | |
| override fun visit(stringAtom: StringAtom) { | |
| printStream.print('"') | |
| printStream.print(stringAtom.string) | |
| printStream.print('"') | |
| } | |
| override fun visit(symbolAtom: SymbolAtom) = printStream.print(symbolAtom.symbol) | |
| override fun visit(trueAtom: TrueAtom) = printStream.print("true") | |
| override fun visit(falseAtom: FalseAtom) = printStream.print("false") | |
| override fun visit(negative: Negative) { | |
| printStream.print("-") | |
| if (negative.expression !is Atom) | |
| printStream.print('(') | |
| negative.expression.accept(this) | |
| if (negative.expression !is Atom) | |
| printStream.print(')') | |
| } | |
| override fun visit(functionCall: FunctionCall) { | |
| printStream.print(functionCall.name) | |
| printStream.print('(') | |
| functionCall.arguments.forEachIndexed { index, argument -> | |
| argument.accept(this) | |
| if (index != functionCall.arguments.size - 1) | |
| printStream.print(", ") | |
| } | |
| printStream.print(')') | |
| } | |
| private fun visitBinary(binaryExpression: BinaryExpression, operator: String) { | |
| val encloseLeft = binaryExpression.left is BinaryExpression && | |
| (binaryExpression.left as BinaryExpression).precedence < binaryExpression.precedence | |
| if (encloseLeft) | |
| printStream.print('(') | |
| binaryExpression.left.accept(this) | |
| if (encloseLeft) | |
| printStream.print(')') | |
| printStream.print(" $operator ") | |
| binaryExpression.right.accept(this) | |
| } | |
| private fun printInlineIndent(string: String) { | |
| printStream.print(" ".repeat(level * tabSize) + string) | |
| } | |
| private fun printIndent(string: String) { | |
| printStream.println(" ".repeat(level * tabSize) + string) | |
| } | |
| private fun enterBlock() { | |
| ++level | |
| } | |
| private fun exitBlock() { | |
| --level | |
| } | |
| } | |
| class EvaluationVisitor : Visitor { | |
| val functions = HashMap<String, Pair<Int, Callable<Any>>>() | |
| val scope = HashMap<String, Any>() | |
| var stack: Deque<Any> = LinkedList() | |
| var whileBlocksCounter = 0 | |
| var breakVisited = false | |
| var continueVisited = false | |
| init { | |
| functions.put("print", Pair(1, Callable<Any> { | |
| val argument = stack.pop() | |
| println(argument) | |
| Unit | |
| })) | |
| functions.put("read", Pair(0, Callable<Any> { | |
| readLine() | |
| })) | |
| functions.put("pow", Pair(1, Callable<Any> { | |
| val argument = stack.pop() | |
| argument as Int * argument | |
| })) | |
| } | |
| override fun visit(unit: Unit) { | |
| for (statement in unit.statement) { | |
| breakVisited = false | |
| continueVisited = false | |
| statement.accept(this) | |
| if (continueVisited || breakVisited) | |
| break | |
| } | |
| } | |
| override fun visit(expressionStatement: ExpressionStatement) { | |
| expressionStatement.expression.accept(this) | |
| if (expressionStatement.expression !is Assignment) | |
| stack.pop() | |
| } | |
| override fun visit(assignment: Assignment) { | |
| if (assignment.left !is SymbolAtom) { | |
| throw Exception("Expect name on the left side of an assignment") | |
| } | |
| assignment.right.accept(this) | |
| scope.put(assignment.left.symbol, stack.pop()) | |
| } | |
| override fun visit(equals: Equals) { | |
| equals.left.accept(this) | |
| equals.right.accept(this) | |
| val right = stack.pop() | |
| val left = stack.pop() | |
| stack.push(left == right) | |
| } | |
| override fun visit(notEquals: NotEquals) { | |
| notEquals.left.accept(this) | |
| notEquals.right.accept(this) | |
| val right = stack.pop() | |
| val left = stack.pop() | |
| stack.push(left != right) | |
| } | |
| override fun visit(lessThan: LessThan) { | |
| lessThan.left.accept(this) | |
| lessThan.right.accept(this) | |
| val right = stack.pop() | |
| val left = stack.pop() | |
| when (left) { | |
| is String -> stack.push(left < right as String) | |
| is Int -> stack.push(left < right as Int) | |
| else -> throw Exception("Can not apply operator '<' for type $left with $right") | |
| } | |
| } | |
| override fun visit(lessThanEquals: LessThanEquals) { | |
| lessThanEquals.left.accept(this) | |
| lessThanEquals.right.accept(this) | |
| val right = stack.pop() | |
| val left = stack.pop() | |
| when (left) { | |
| is String -> stack.push(left <= right as String) | |
| is Int -> stack.push(left <= right as Int) | |
| else -> throw Exception("Can not apply operator '<=' for type $left with $right") | |
| } | |
| } | |
| override fun visit(greaterThan: GreaterThan) { | |
| greaterThan.left.accept(this) | |
| greaterThan.right.accept(this) | |
| val right = stack.pop() | |
| val left = stack.pop() | |
| when (left) { | |
| is String -> stack.push(left > right as String) | |
| is Int -> stack.push(left > right as Int) | |
| else -> throw Exception("Can not apply operator '>' for type $left with $right") | |
| } | |
| } | |
| override fun visit(greaterThanEquals: GreaterThanEquals) { | |
| greaterThanEquals.left.accept(this) | |
| greaterThanEquals.right.accept(this) | |
| val right = stack.pop() | |
| val left = stack.pop() | |
| when (left) { | |
| is String -> stack.push(left >= right as String) | |
| is Int -> stack.push(left >= right as Int) | |
| else -> throw Exception("Can not apply operator '>=' for type $left with $right") | |
| } | |
| } | |
| override fun visit(addition: Addition) { | |
| addition.left.accept(this) | |
| addition.right.accept(this) | |
| val right = stack.pop() | |
| val left = stack.pop() | |
| when (left) { | |
| is String -> stack.push(left + right) | |
| is Int -> stack.push(left + right as Int) | |
| else -> throw Exception("Can not apply operator '+' for type $left with $right") | |
| } | |
| } | |
| override fun visit(subtraction: Subtraction) { | |
| subtraction.left.accept(this) | |
| subtraction.right.accept(this) | |
| val right = stack.pop() | |
| val left = stack.pop() | |
| when (left) { | |
| is Int -> stack.push(left - right as Int) | |
| else -> throw Exception("Can not apply operator '-' for type $left with $right") | |
| } | |
| } | |
| override fun visit(multiplication: Multiplication) { | |
| multiplication.left.accept(this) | |
| multiplication.right.accept(this) | |
| val right = stack.pop() | |
| val left = stack.pop() | |
| when (left) { | |
| is Int -> stack.push(left * right as Int) | |
| else -> throw Exception("Can not apply operator '*' for type $left with $right") | |
| } | |
| } | |
| override fun visit(division: Division) { | |
| division.left.accept(this) | |
| division.right.accept(this) | |
| val right = stack.pop() | |
| val left = stack.pop() | |
| when (left) { | |
| is Int -> stack.push(left / right as Int) | |
| else -> throw Exception("Can not apply operator '*' for type $left with $right") | |
| } | |
| } | |
| override fun visit(badExpression: BadExpression) { | |
| throw Exception("Syntax error") | |
| } | |
| override fun visit(integerAtom: IntegerAtom) { | |
| stack.push(integerAtom.int) | |
| } | |
| override fun visit(symbolAtom: SymbolAtom) { | |
| stack.push(scope[symbolAtom.symbol]) | |
| } | |
| override fun visit(negative: Negative) { | |
| negative.expression.accept(this) | |
| stack.push(-(stack.pop() as Int)) | |
| } | |
| override fun visit(whileStatement: WhileStatement) { | |
| ++whileBlocksCounter | |
| while (true) { | |
| whileStatement.expression.accept(this) | |
| val expression = stack.pop() as Boolean | |
| continueVisited = false | |
| if (!expression) | |
| break | |
| whileStatement.unit.accept(this) | |
| if (continueVisited || breakVisited) | |
| break | |
| } | |
| --whileBlocksCounter | |
| breakVisited = false | |
| continueVisited = false | |
| } | |
| override fun visit(breakStatement: BreakStatement) { | |
| if (whileBlocksCounter <= 0) | |
| throw Exception("break is used outside a loop") | |
| breakVisited = true | |
| } | |
| override fun visit(continueStatement: ContinueStatement) { | |
| if (whileBlocksCounter <= 0) | |
| throw Exception("continue is used outside a loop") | |
| continueVisited = true | |
| } | |
| override fun visit(ifStatement: IfStatement) { | |
| ifStatement.expression.accept(this) | |
| val ifCondition = stack.pop() as Boolean | |
| if (ifCondition) | |
| ifStatement.unit.accept(this) | |
| else { | |
| var evaluatedElse = true | |
| for ((expression, unit) in ifStatement.elseIfClauses) { | |
| expression.accept(this) | |
| evaluatedElse = stack.pop() as Boolean | |
| if (evaluatedElse) { | |
| unit.accept(this) | |
| break | |
| } | |
| } | |
| if (!evaluatedElse && ifStatement.elseClause != null) | |
| ifStatement.elseClause.accept(this) | |
| } | |
| } | |
| override fun visit(functionCall: FunctionCall) { | |
| val (numberOfArguments, function) = functions.getValue(functionCall.name) | |
| if (functionCall.arguments.size != numberOfArguments) | |
| throw Exception("Function'${functionCall.name}' takes $numberOfArguments argument(s), got ${functionCall.arguments.size} argument(s)") | |
| functionCall.arguments.forEach { | |
| it.accept(this) | |
| } | |
| stack.push(function.call()) | |
| } | |
| override fun visit(stringAtom: StringAtom) { | |
| stack.push(stringAtom.string) | |
| } | |
| override fun visit(trueAtom: TrueAtom) { | |
| stack.push(true) | |
| } | |
| override fun visit(falseAtom: FalseAtom) { | |
| stack.push(false) | |
| } | |
| } | |
| fun main(args: Array<String>) { | |
| val lexer = Lexer(ByteArrayInputStream(""" | |
| print(-2 * 5); | |
| print(6 / 3); | |
| print("C"); | |
| print("Enter your name"); | |
| name = read(); | |
| print("Hello " + name + "!"); | |
| c = pow(1); | |
| if c == 1 { | |
| x = 1; | |
| while x <= 5 { | |
| print(x); | |
| if x == 3 { | |
| break; | |
| print("Three"); | |
| } | |
| x = x + 1; | |
| } | |
| x = 1; | |
| while x <= 5 { | |
| print(x * 111); | |
| if x == 3 { | |
| print("Three hundred thirty three"); | |
| } | |
| x = x + 1; | |
| } | |
| } else if c == 2 { | |
| print("Just two"); | |
| } else { | |
| print("Don't now"); | |
| } | |
| """.toByteArray())) | |
| val parser = Parser(lexer) | |
| val unit = parser.parse() | |
| if (!parser.panic) | |
| unit.accept(EvaluationVisitor()) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment