package fr.celticinfo.lox import fr.celticinfo.lox.TokenType.* /** * The Parser class is responsible for parsing the tokens produced by the Scanner into an abstract syntax tree (AST). * It is a recursive descent parser that uses a series of methods to parse different parts of the grammar. */ class Parser(private val tokens: List) { private var current = 0 fun parse(): List { val statements: MutableList = ArrayList() while (!isAtEnd()) { statements.add(declaration()) } return statements } private fun declaration(): Stmt? { return try { when { match(CLASS) -> classDeclaration() match(FUN) -> function("function") match(VAR) -> varDeclaration() else -> statement() } } catch (error: ParseError) { synchronize() return null } } private fun classDeclaration(): ClassStmt { val name = consume(IDENTIFIER, "Expect class name.") consume(LEFT_BRACE, "Expect '{' before class body.") val methods: MutableList = ArrayList() while (!check(RIGHT_BRACE) && !isAtEnd()) { methods.add(function("method")) } consume(RIGHT_BRACE, "Expect '}' after class body.") return ClassStmt(name, methods) } private fun function(kind: String): Function { val name = consume(IDENTIFIER, "Expect $kind name.") consume(LEFT_PAREN, "Expect '(' after $kind name.") val parameters: MutableList = ArrayList() if (!check(RIGHT_PAREN)) { do { if (parameters.size >= 255) { error(peek(), "Cannot have more than 255 parameters.") } parameters.add(consume(IDENTIFIER, "Expect parameter name.")) } while (match(COMMA)) } consume(RIGHT_PAREN, "Expect ')' after parameters.") consume(LEFT_BRACE, "Expect '{' before $kind body.") val body = blockStatement() return Function(name, parameters, body) } private fun varDeclaration(): Var { val name = consume(IDENTIFIER, "Expect variable name.") var initializer: Expr? = null if (match(EQUAL)) { initializer = expression() } consume(SEMICOLON, "Expect ';' after variable declaration.") return Var(name, initializer) } private fun whileStatement(): While { consume(LEFT_PAREN, "Expect '(' after 'while'.") val condition = expression() consume(RIGHT_PAREN, "Expect ')' after condition.") val body = statement() return While(condition, body) } private fun statement(): Stmt { return when { match(FOR) -> forStatement() match(IF) -> ifStatement() match(PRINT) -> printStatement() match(RETURN) -> returnStatement() match(WHILE) -> whileStatement() match(LEFT_BRACE) -> Block(blockStatement()) else -> expressionStatement() } } private fun forStatement(): Stmt { consume(LEFT_PAREN, "Expect '(' after 'for'.") val initializer = when { match(SEMICOLON) -> null match(VAR) -> varDeclaration() else -> expressionStatement() } val condition = when { !check(SEMICOLON) -> expression() else -> Literal(true) } consume(SEMICOLON, "Expect ';' after loop condition.") val increment = when { !check(RIGHT_PAREN) -> expression() else -> null } consume(RIGHT_PAREN, "Expect ')' after for clauses.") var body = statement() if (increment != null) { body = Block(listOf(body, Expression(increment))) } body = While(condition, body) if (initializer != null) { body = Block(listOf(initializer, body)) } return body } private fun ifStatement(): If { consume(LEFT_PAREN, "Expect '(' after 'if'.") val condition = expression() consume(RIGHT_PAREN, "Expect ')' after if condition.") val thenBranch = statement() var elseBranch: Stmt? = null if (match(ELSE)) { elseBranch = statement() } return If(condition, thenBranch, elseBranch) } private fun printStatement(): Print { val value = expression() consume(SEMICOLON, "Expect ';' after value.") return Print(value) } private fun returnStatement(): Return { val keyword = previous() val value = if (!check(SEMICOLON)) expression() else null consume(SEMICOLON, "Expect ';' after return value.") return Return(keyword, value) } private fun expressionStatement(): Expression { val value = expression() consume(SEMICOLON, "Expect ';' after expression.") return Expression(value) } private fun blockStatement(): List { val statements: MutableList = ArrayList() while (!check(RIGHT_BRACE) && !isAtEnd()) { statements.add(declaration()) } consume(RIGHT_BRACE, "Expect '}' after block.") return statements } private fun expression(): Expr { return assignment() } private fun assignment(): Expr { val expr = or() if (match(EQUAL)) { val equals = previous() val value = assignment() if (expr is Variable) { val name = expr.name return Assign(name, value) } else if (expr is Get) { return Set(expr.obj, expr.name, value) } error(equals, "Invalid assignment target.") } return expr } private fun or(): Expr { var expr = and() while (match(OR)) { val operator = previous() val right = and() expr = Logical(expr, operator, right) } return expr } private fun and(): Expr { var expr = equality() while (match(AND)) { val operator = previous() val right = equality() expr = Logical(expr, operator, right) } return expr } private fun equality(): Expr { var expr = comparison() while (match(BANG_EQUAL, EQUAL_EQUAL)) { val operator = previous() val right = comparison() expr = Binary(expr, operator, right) } return expr } private fun comparison(): Expr { var expr = term() while (match(GREATER, GREATER_EQUAL, LESS, LESS_EQUAL)) { val operator = previous() val right = term() expr = Binary(expr, operator, right) } return expr } private fun term(): Expr { var expr = factor() while (match(MINUS, PLUS)) { val operator = previous() val right = factor() expr = Binary(expr, operator, right) } return expr } private fun factor(): Expr { var expr = unary() while (match(SLASH, STAR)) { val operator = previous() val right = unary() expr = Binary(expr, operator, right) } return expr } private fun unary(): Expr { if (match(BANG, MINUS)) { val operator = previous() val right = unary() return Unary(operator, right) } return call() } private fun match(vararg types: TokenType): Boolean { for (type in types) { if (check(type)) { advance() return true } } return false } private fun call(): Expr { var expr = primary() while (true) { if (match(LEFT_PAREN)) { expr = finishCall(expr) } else if (match(DOT)) { val name = consume(IDENTIFIER, "Expect property name after '.'.") expr = Get(expr, name) } else { break } } return expr } private fun finishCall(callee: Expr): Expr { val arguments: MutableList = ArrayList() if (!check(RIGHT_PAREN)) { do { if (arguments.size >= 255) { error(peek(), "Cannot have more than 255 arguments.") } arguments.add(expression()) } while (match(COMMA)) } val paren = consume(RIGHT_PAREN, "Expect ')' after arguments.") return Call(callee, paren, arguments) } private fun primary(): Expr { when { match(FALSE) -> return Literal(false) match(TRUE) -> return Literal(true) match(NIL) -> return Literal(null) match(NUMBER, STRING) -> return Literal(previous().literal) match(IDENTIFIER) -> return Variable(previous()) match(LEFT_PAREN) -> { val expr = expression() consume(RIGHT_PAREN, "Expect ')' after expression.") return Grouping(expr) } else -> throw error(peek(), "Expect expression.") } } private fun check(type: TokenType): Boolean { if (isAtEnd()) return false return peek().type == type } private fun advance(): Token { if (!isAtEnd()) current++ return previous() } private fun isAtEnd(): Boolean { return peek().type == EOF } private fun peek(): Token { return tokens[current] } private fun previous(): Token { return tokens[current - 1] } private fun consume(type: TokenType, message: String): Token { if (check(type)) return advance() throw error(peek(), message) } private fun error(token: Token, message: String): ParseError { Lox.error(token, message) return ParseError() } private fun synchronize() { advance() while (!isAtEnd()) { if (previous().type == SEMICOLON) return when (peek().type) { CLASS, FUN, VAR, FOR, IF, WHILE, PRINT, RETURN -> return else -> advance() } } } class ParseError: RuntimeException() }