From 0c5955d095ed6760d7f73437799500ff2b9f8d42 Mon Sep 17 00:00:00 2001 From: Melvic Ybanez Date: Mon, 30 Oct 2023 01:41:09 +0800 Subject: [PATCH] WIP: Scaffolding dictionary implementation --- README.md | 4 +- src/main/scala/com/melvic/dry/Token.scala | 1 + src/main/scala/com/melvic/dry/ast/Expr.scala | 25 ++++++++-- .../dry/interpreter/eval/EvalExpr.scala | 3 ++ .../dry/interpreter/values/DDictionary.scala | 10 ++++ .../melvic/dry/interpreter/values/DList.scala | 6 +-- .../scala/com/melvic/dry/lexer/Lexer.scala | 1 + .../com/melvic/dry/parsers/DeclParser.scala | 16 +++---- .../com/melvic/dry/parsers/ExprParser.scala | 48 ++++++++++++++++--- .../com/melvic/dry/parsers/ParseResult.scala | 3 ++ .../scala/com/melvic/dry/parsers/Parser.scala | 44 ++++++++++++----- .../com/melvic/dry/parsers/StmtParser.scala | 26 +++++----- .../com/melvic/dry/resolver/Resolve.scala | 3 ++ .../scala/com/melvic/dry/result/Failure.scala | 12 ++--- 14 files changed, 149 insertions(+), 53 deletions(-) create mode 100644 src/main/scala/com/melvic/dry/interpreter/values/DDictionary.scala diff --git a/README.md b/README.md index 1f86cb0..48fd9d5 100644 --- a/README.md +++ b/README.md @@ -212,7 +212,9 @@ The syntax of Dry should be familiar to Python and Scala developers. Here's the ::= ("/" | "*" | "%" )* ::= ("!" | "-" | "+" | "not") | ::= "false" | "true" | "none" | | - | "self" | | "(" ")" + | "self" | | | | "(" ")" + ::= "{" ( ("," )*)? "}" + ::= ( | ) ":" ::= ?(".")? ::= "-" | "+" ::= '"'(.?"\n"?)*'"' diff --git a/src/main/scala/com/melvic/dry/Token.scala b/src/main/scala/com/melvic/dry/Token.scala index 5523645..026dca6 100644 --- a/src/main/scala/com/melvic/dry/Token.scala +++ b/src/main/scala/com/melvic/dry/Token.scala @@ -23,6 +23,7 @@ object Token { case object Comma extends TokenType case object Dot extends TokenType case object Semicolon extends TokenType + case object Colon extends TokenType case object Eof extends TokenType } diff --git a/src/main/scala/com/melvic/dry/ast/Expr.scala b/src/main/scala/com/melvic/dry/ast/Expr.scala index e3082ef..ce73665 100644 --- a/src/main/scala/com/melvic/dry/ast/Expr.scala +++ b/src/main/scala/com/melvic/dry/ast/Expr.scala @@ -1,5 +1,6 @@ package com.melvic.dry.ast +import com.melvic.dry.ast.Expr.Literal.Str import com.melvic.dry.ast.Stmt.BlockStmt import com.melvic.dry.aux.Show.ShowInterpolator import com.melvic.dry.aux.implicits.ListOps @@ -42,6 +43,23 @@ object Expr { final case class Self(keyword: Token) extends Expr + final case class Dictionary(table: Map[Either[Str, Variable], Expr]) extends Expr + + object Dictionary { + def show: Show[Dictionary] = { case Dictionary(table) => + def fieldKeyToString(key: Either[Str, Variable]): String = + key match { + case Left(fieldName) => show""""$fieldName"""" + case Right(variable) => Expr.show(variable) + } + + def fieldToString(field: (Either[Str, Variable], Expr)): String = + show"${fieldKeyToString(field._1)}: ${Expr.show(field._2)}" + + show"{ ${table.map(fieldToString).mkString(", ")} }" + } + } + def show: Show[Expr] = { case literal: Literal => Literal.show(literal) case Grouping(expr) => show"($expr)" @@ -53,8 +71,9 @@ object Expr { case Call(callee, arguments, _) => show"$callee(${arguments.map(Expr.show).toCsv})" case Lambda(params, body) => show"lambda(${params.map(Token.show).toCsv}) ${BlockStmt.fromDecls(body: _*)}" - case Get(obj, name) => show"$obj.$name" - case Self(_) => "self" - case Set(obj, name, value) => show"$obj.$name = $value" + case Get(obj, name) => show"$obj.$name" + case Self(_) => "self" + case Set(obj, name, value) => show"$obj.$name = $value" + case dictionary: Dictionary => Dictionary.show(dictionary) } } diff --git a/src/main/scala/com/melvic/dry/interpreter/eval/EvalExpr.scala b/src/main/scala/com/melvic/dry/interpreter/eval/EvalExpr.scala index ea9110e..25fe4a7 100644 --- a/src/main/scala/com/melvic/dry/interpreter/eval/EvalExpr.scala +++ b/src/main/scala/com/melvic/dry/interpreter/eval/EvalExpr.scala @@ -33,6 +33,7 @@ private[eval] trait EvalExpr { case get: Get => Evaluate.get(get) case set: Set => Evaluate.set(set) case self: Self => Evaluate.self(self) + case dictionary: Dictionary => Evaluate.dictionary(dictionary) } def lambda(implicit context: Context[Lambda]): Out = @@ -203,6 +204,8 @@ private[eval] trait EvalExpr { def self(implicit context: Context[Self]): Out = varLookup(node.keyword, node) + def dictionary(implicit context: Context[Dictionary]): Out = ??? + private def varLookup(name: Token, expr: Expr)(implicit context: Context[Expr]): Out = locals .get(LocalExprKey(expr)) diff --git a/src/main/scala/com/melvic/dry/interpreter/values/DDictionary.scala b/src/main/scala/com/melvic/dry/interpreter/values/DDictionary.scala new file mode 100644 index 0000000..0cbd161 --- /dev/null +++ b/src/main/scala/com/melvic/dry/interpreter/values/DDictionary.scala @@ -0,0 +1,10 @@ +package com.melvic.dry.interpreter.values +import com.melvic.dry.interpreter.Env + +import scala.collection.mutable + +final case class DDictionary(table: Map[String, Value], env: Env) extends DObject { + override def klass: Metaclass = DClass("Dictionary", Map.empty, env) + + override def fields: mutable.Map[String, Value] = mutable.Map.empty +} diff --git a/src/main/scala/com/melvic/dry/interpreter/values/DList.scala b/src/main/scala/com/melvic/dry/interpreter/values/DList.scala index eee677e..00d5e67 100644 --- a/src/main/scala/com/melvic/dry/interpreter/values/DList.scala +++ b/src/main/scala/com/melvic/dry/interpreter/values/DList.scala @@ -10,18 +10,18 @@ import scala.collection.mutable.ListBuffer import scala.util.chaining.scalaUtilChainingOps final case class DList(elems: ListBuffer[Value], env: Env) extends DObject { - type AddProperties = Map[String, Value] => Map[String, Value] + private type AddProperties = Map[String, Value] => Map[String, Value] override def klass: Metaclass = DClass("List", Map.empty, env) override val fields: mutable.Map[String, Value] = - addIndexFields + addIndexFields() .pipe(addAtMethod) .pipe(addSizeMethod) .pipe(addAddMethod) .to(mutable.Map) - private def addIndexFields = + private def addIndexFields() = elems.zipWithIndex .map { case (elem, i) => ("_" + i) -> elem } .to(Map) diff --git a/src/main/scala/com/melvic/dry/lexer/Lexer.scala b/src/main/scala/com/melvic/dry/lexer/Lexer.scala index 4789fe0..1351f95 100644 --- a/src/main/scala/com/melvic/dry/lexer/Lexer.scala +++ b/src/main/scala/com/melvic/dry/lexer/Lexer.scala @@ -40,6 +40,7 @@ final case class Lexer( case '%' => lexer.addToken(TokenType.Modulo).ok case '-' => lexer.addToken(TokenType.Minus).ok case ';' => lexer.addToken(TokenType.Semicolon).ok + case ':' => lexer.addToken(TokenType.Colon).ok case '!' => lexer.addTokenOrElse('=', TokenType.NotEqual, TokenType.Not) case '=' => lexer.addTokenOrElse('=', TokenType.EqualEqual, TokenType.Equal) case '&' => lexer.addToken(TokenType.BAnd).ok diff --git a/src/main/scala/com/melvic/dry/parsers/DeclParser.scala b/src/main/scala/com/melvic/dry/parsers/DeclParser.scala index 7483ea7..b40afd8 100644 --- a/src/main/scala/com/melvic/dry/parsers/DeclParser.scala +++ b/src/main/scala/com/melvic/dry/parsers/DeclParser.scala @@ -33,9 +33,9 @@ private[parsers] trait DeclParser extends StmtParser { _: Parser => */ def letDecl: ParseResult[Let] = { def consumeSemicolon(parser: Parser): ParseResult[Token] = - parser.consume(TokenType.Semicolon, ";", "let") + parser.consumeAfter(TokenType.Semicolon, ";", "let") - consume(TokenType.Identifier, "identifier", "let").flatMap { case Step(name, parser) => + consumeAfter(TokenType.Identifier, "identifier", "let").flatMap { case Step(name, parser) => parser .matchAny(TokenType.Equal) .fold[ParseResult[Let]](consumeSemicolon(parser).mapValue(_ => LetDecl(name))) { parser => @@ -51,14 +51,14 @@ private[parsers] trait DeclParser extends StmtParser { _: Parser => */ def defDecl(kind: String): ParseResult[Def] = for { - name <- consume(TokenType.Identifier, "identifier", s"'${Lexemes.Def}' keyword") + name <- consumeAfter(TokenType.Identifier, "identifier", s"'${Lexemes.Def}' keyword") params <- name.params body <- params.functionBody(kind) } yield Step(Def(name.value, params.value, body.value.declarations), body.next) private[parsers] def functionBody(kind: String): ParseResult[BlockStmt] = for { - leftBrace <- consume(TokenType.LeftBrace, "{", kind + " signature") + leftBrace <- consumeAfter(TokenType.LeftBrace, "{", kind + " signature") body <- leftBrace.block } yield body @@ -67,10 +67,10 @@ private[parsers] trait DeclParser extends StmtParser { _: Parser => */ def classDecl: ParseResult[ClassDecl] = for { - name <- consume(TokenType.Identifier, "identifier", s"'${Lexemes.Class}' keyword") - leftBrace <- name.consume(TokenType.LeftBrace, "{", "class name") + name <- consumeAfter(TokenType.Identifier, "identifier", s"'${Lexemes.Class}' keyword") + leftBrace <- name.consumeAfter(TokenType.LeftBrace, "{", "class name") methods <- leftBrace.methods - rightBrace <- methods.consume(TokenType.RightBrace, "}", "class body") + rightBrace <- methods.consumeAfter(TokenType.RightBrace, "}", "class body") } yield Step(ClassDecl(name.value, methods.value), rightBrace.next) protected def methods: ParseResult[List[Def]] = { @@ -78,7 +78,7 @@ private[parsers] trait DeclParser extends StmtParser { _: Parser => if (parser.check(TokenType.RightBrace) || parser.isAtEnd) ParseResult.succeed(acc.reverse, parser) else for { - method <- parser.consume(TokenType.Def, Lexemes.Def, "{ in class") + method <- parser.consumeAfter(TokenType.Def, Lexemes.Def, "{ in class") function <- method.defDecl("method") result <- recurse(function.next, function.value :: acc) } yield result diff --git a/src/main/scala/com/melvic/dry/parsers/ExprParser.scala b/src/main/scala/com/melvic/dry/parsers/ExprParser.scala index 1ad0970..2efdd04 100644 --- a/src/main/scala/com/melvic/dry/parsers/ExprParser.scala +++ b/src/main/scala/com/melvic/dry/parsers/ExprParser.scala @@ -118,6 +118,7 @@ private[parsers] trait ExprParser { _: Parser => * {{{ ::= ("(" * ")" | "." )}}} */ def call: ParseResult[Expr] = { + // TODO: see if we can refactor this using the `sequence` utility from `Parser` def parenCall(callee: Expr, parser: Parser): ParseResult[Expr] = { def recurse(args: List[Expr], parser: Parser): ParseResult[List[Expr]] = parser @@ -135,7 +136,7 @@ private[parsers] trait ExprParser { _: Parser => resultForArgs.flatMap { case Step(_, next) => next - .consume(TokenType.RightParen, ")", "function call arguments") + .consumeAfter(TokenType.RightParen, ")", "function call arguments") .flatMap(step => resultForArgs.mapValue(callOrLambda(callee, _, step.value)).mapParser(_ => step.next) ) @@ -146,7 +147,7 @@ private[parsers] trait ExprParser { _: Parser => // Recursively checks if the expression is being called, or a property access is being invoked def checkForCalls(step: Step[Expr]): ParseResult[Expr] = { def propAccess(expr: Expr, next: Parser) = - next.consume(TokenType.Identifier, "property name", ".").mapValue(Get(expr, _)) + next.consumeAfter(TokenType.Identifier, "property name", ".").mapValue(Get(expr, _)) def checkForPropAccess = step.next .matchAny(TokenType.Dot) @@ -226,14 +227,47 @@ private[parsers] trait ExprParser { _: Parser => .orElse(matchAny(TokenType.Identifier).map(p => Step(Variable(p.previousToken), p))) .map(_.toParseResult) .getOrElse( - matchAny(TokenType.LeftParen) - .fold[ParseResult[Expr]](ParseResult.fail(ParseError.expected(peek, "expression", "("), this)) { - _.expression.flatMap { case Step(expr, newParser) => - newParser.consume(TokenType.RightParen, ")", "expression").mapValue(_ => Grouping(expr)) + dictionary.orElse( + matchAny(TokenType.LeftParen) + .fold[ParseResult[Expr]](ParseResult.fail(ParseError.expected(peek, "expression", "("), this)) { + _.expression.flatMap { case Step(expr, newParser) => + newParser.consumeAfter(TokenType.RightParen, ")", "expression").mapValue(_ => Grouping(expr)) + } } - } + ) ) + /** + * {{{ + * ::= "{" ( ("," )*)? "}" + * ::= ( | ) ":" + * }}} + */ + def dictionary: ParseResult[Expr] = + sequence[(Either[Literal.Str, Variable], Expr)]( + TokenType.LeftBrace, + "{", + TokenType.RightBrace, + "}", + "at the start of dictionary", + "dictionary elements" + )(_.matchAnyWith { + case TokenType.Str(_) => true + case TokenType.Identifier => true + }.flatMap { next => + @nowarn + val key = next.previousToken match { + case Token(TokenType.Str(string), _, _) => Left(Literal.Str(string)) + case token @ Token(TokenType.Identifier, _, _) => Right(Variable(token)) + } + next + .consumeAfter(TokenType.Colon, ":", "dictionary key") + .flatMap { case Step(_, next) => + next.expression.map(_.map((key, _))) + } + .fold[Option[Step[(Either[Literal.Str, Variable], Expr)]]]((_, _) => None)(Some(_)) + }).mapValue(elements => Dictionary(elements.toMap)) + /** * Like [[leftAssocBinaryWith]], but is specific to non-logical binary operators. */ diff --git a/src/main/scala/com/melvic/dry/parsers/ParseResult.scala b/src/main/scala/com/melvic/dry/parsers/ParseResult.scala index b7cfb0e..95d025c 100644 --- a/src/main/scala/com/melvic/dry/parsers/ParseResult.scala +++ b/src/main/scala/com/melvic/dry/parsers/ParseResult.scala @@ -44,6 +44,9 @@ final case class ParseResult[+A](result: Result[A], parser: Parser) { case Left(errors) => ifError(errors, parser) case Right(value) => ifSuccess(Step(value, parser)) } + + def orElse[B >: A](alternative: => ParseResult[B]): ParseResult[B] = + fold((_, _) => alternative)(_ => this) } object ParseResult { diff --git a/src/main/scala/com/melvic/dry/parsers/Parser.scala b/src/main/scala/com/melvic/dry/parsers/Parser.scala index ac0fa35..8ced911 100644 --- a/src/main/scala/com/melvic/dry/parsers/Parser.scala +++ b/src/main/scala/com/melvic/dry/parsers/Parser.scala @@ -60,9 +60,12 @@ final case class Parser(tokens: List[Token], current: Int) extends ExprParser wi Step(parser.previousToken, parser) } - def consume(tokenType: TokenType, expected: String, after: String): ParseResult[Token] = + def consumeAfter(tokenType: TokenType, expected: String, after: String): ParseResult[Token] = + consume(tokenType, expected, "after " + after) + + def consume(tokenType: TokenType, expected: String, at: String): ParseResult[Token] = if (check(tokenType)) advance.toParseResult - else ParseResult.fail(ParseError.expected(peek, expected, after), this) + else ParseResult.fail(ParseError.expected(peek, expected, at), this) def isAtEnd: Boolean = peek.tokenType == TokenType.Eof @@ -94,25 +97,42 @@ final case class Parser(tokens: List[Token], current: Int) extends ExprParser wi } /** - * {{{ ::= "(" * ")"}}} + * {{{ ::= "(" ( | ("," )*)? ")"}}} */ def params: ParseResult[List[Token]] = + sequence[Token]( + TokenType.LeftParen, + "(", + TokenType.RightParen, + ")", + "after function name", + "parameters" + )(_.matchAny(TokenType.Identifier).map(next => Step(next.previousToken, next))) + + private[parsers] def sequence[A]( + openingTokenType: TokenType, + openingLexeme: String, + closingTokenType: TokenType, + closingLexeme: String, + openingErrorLabel: String, + // e.g. parameters, list elements, dict elements + elementsLabel: String + )(parseElement: Parser => Option[Step[A]]): ParseResult[List[A]] = for { - afterLeftParen <- consume(TokenType.LeftParen, "(", "function name") + afterOpening <- consume(openingTokenType, openingLexeme, openingErrorLabel) params <- { - def parseWhileNextIsComma(params: List[Token], parser: Parser): ParseResult[List[Token]] = - parser - .matchAny(TokenType.Identifier) - .fold(ParseResult.succeed(params, parser)) { next => - val newParams = next.previousToken :: params + def parseWhileThereIsComma(elements: List[A], parser: Parser): ParseResult[List[A]] = + parseElement(parser) + .fold(ParseResult.succeed(elements, parser)) { case Step(element, next) => + val newElements = element :: elements next .matchAny(TokenType.Comma) - .fold(ParseResult.succeed(newParams, next))(parseWhileNextIsComma(newParams, _)) + .fold(ParseResult.succeed(newElements, next))(parseWhileThereIsComma(newElements, _)) } - parseWhileNextIsComma(Nil, afterLeftParen) + parseWhileThereIsComma(Nil, afterOpening) .mapValue(_.reverse) - .flatMapParser(_.consume(TokenType.RightParen, ")", "parameters")) + .flatMapParser(_.consumeAfter(closingTokenType, closingLexeme, elementsLabel)) } } yield params } diff --git a/src/main/scala/com/melvic/dry/parsers/StmtParser.scala b/src/main/scala/com/melvic/dry/parsers/StmtParser.scala index 407dadd..0d6c246 100644 --- a/src/main/scala/com/melvic/dry/parsers/StmtParser.scala +++ b/src/main/scala/com/melvic/dry/parsers/StmtParser.scala @@ -32,7 +32,7 @@ private[parsers] trait StmtParser { _: Parser with DeclParser => def expressionStatement: ParseResult[Stmt] = for { expr <- expression - semicolon <- expr.consume(TokenType.Semicolon, ";", "statement") + semicolon <- expr.consumeAfter(TokenType.Semicolon, ";", "statement") } yield Step(ExprStmt(expr.value), semicolon.next) /** @@ -54,7 +54,7 @@ private[parsers] trait StmtParser { _: Parser with DeclParser => } recurse(ParseResult.succeed(Nil, this)).flatMap { case Step(decls, parser) => - parser.consume(TokenType.RightBrace, "}", "block").mapValue(_ => BlockStmt(decls)) + parser.consumeAfter(TokenType.RightBrace, "}", "block").mapValue(_ => BlockStmt(decls)) } } @@ -63,9 +63,9 @@ private[parsers] trait StmtParser { _: Parser with DeclParser => */ def ifStatement: ParseResult[Stmt] = for { - leftParen <- consume(TokenType.LeftParen, "(", "if") + leftParen <- consumeAfter(TokenType.LeftParen, "(", "if") cond <- leftParen.expression - rightParen <- cond.consume(TokenType.RightParen, ")", "if condition") + rightParen <- cond.consumeAfter(TokenType.RightParen, ")", "if condition") thenBranch <- rightParen.statement ifStmt <- thenBranch .matchAny(TokenType.Else) @@ -83,9 +83,9 @@ private[parsers] trait StmtParser { _: Parser with DeclParser => */ def whileStatement: ParseResult[While] = for { - leftParen <- consume(TokenType.LeftParen, "(", "while") + leftParen <- consumeAfter(TokenType.LeftParen, "(", "while") condition <- leftParen.expression - rightParen <- condition.consume(TokenType.RightParen, ")", "while condition") + rightParen <- condition.consumeAfter(TokenType.RightParen, ")", "while condition") body <- rightParen.statement } yield Step(While(condition.value, body.value), body.next) @@ -97,7 +97,7 @@ private[parsers] trait StmtParser { _: Parser with DeclParser => * }}} */ def forStatement: ParseResult[Stmt] = { - val initializer = consume(TokenType.LeftParen, "(", "for").flatMap { case Step(_, next) => + val initializer = consumeAfter(TokenType.LeftParen, "(", "for").flatMap { case Step(_, next) => next .matchAny(TokenType.Semicolon) .fold( @@ -112,7 +112,7 @@ private[parsers] trait StmtParser { _: Parser with DeclParser => if (parser.check(delimiter)) ParseResult.succeed(Literal.None, parser) else parser.expression - clauseExpr.flatMapParser(_.consume(delimiter, consume, after)) + clauseExpr.flatMapParser(_.consumeAfter(delimiter, consume, after)) } def condition(parser: Parser) = clause(parser, TokenType.Semicolon, ";", "for loop condition") @@ -146,8 +146,8 @@ private[parsers] trait StmtParser { _: Parser with DeclParser => val keyword = previousToken val expr = if (check(TokenType.Semicolon)) - consume(TokenType.Semicolon, ";", "return value").mapValue(_ => Literal.None) - else expression.flatMapParser(_.consume(TokenType.Semicolon, ";", "return value")) + consumeAfter(TokenType.Semicolon, ";", "return value").mapValue(_ => Literal.None) + else expression.flatMapParser(_.consumeAfter(TokenType.Semicolon, ";", "return value")) expr.mapValue(ReturnStmt(keyword, _)) } @@ -157,15 +157,15 @@ private[parsers] trait StmtParser { _: Parser with DeclParser => def importStatement: ParseResult[Stmt] = { def parseComponents(parser: Parser, components: List[Token]): ParseResult[List[Token]] = parser.matchAny(TokenType.Dot).fold(ParseResult.succeed(components.reverse, parser)) { next => - next.consume(TokenType.Identifier, "identifier", "import").flatMap { case Step(component, next) => + next.consumeAfter(TokenType.Identifier, "identifier", "import").flatMap { case Step(component, next) => parseComponents(next, component :: components) } } for { - firstComponent <- consume(TokenType.Identifier, "identifier", "import") + firstComponent <- consumeAfter(TokenType.Identifier, "identifier", "import") allComponents <- parseComponents(firstComponent.next, firstComponent.value :: Nil) - semicolon <- allComponents.consume(TokenType.Semicolon, ";", "import path") + semicolon <- allComponents.consumeAfter(TokenType.Semicolon, ";", "import path") } yield Step(Import(allComponents.value), semicolon.next) } } diff --git a/src/main/scala/com/melvic/dry/resolver/Resolve.scala b/src/main/scala/com/melvic/dry/resolver/Resolve.scala index 37b9330..67b530c 100644 --- a/src/main/scala/com/melvic/dry/resolver/Resolve.scala +++ b/src/main/scala/com/melvic/dry/resolver/Resolve.scala @@ -78,6 +78,7 @@ object Resolve { case Get(obj, _) => Resolve.expr(obj) case Set(obj, _, value) => Resolve.expr(value) >=> Resolve.expr(obj) case self: Self => Resolve.self(self) + case dict: Dictionary => Resolve.dictionary(dict) } def variable: Variable => Resolve = { case expr @ Variable(name) => @@ -147,6 +148,8 @@ object Resolve { } } + def dictionary: Dictionary => Resolve = ??? + private def exprWithDepth(depth: Int): Expr => Resolve = expr => context => context.copy(locals = context.locals + (LocalExprKey(expr) -> depth)).ok diff --git a/src/main/scala/com/melvic/dry/result/Failure.scala b/src/main/scala/com/melvic/dry/result/Failure.scala index 50abede..4896ecb 100644 --- a/src/main/scala/com/melvic/dry/result/Failure.scala +++ b/src/main/scala/com/melvic/dry/result/Failure.scala @@ -42,19 +42,19 @@ object Failure { sealed trait ParseError extends Failure object ParseError { - final case class Expected(start: Token, expected: String, where: String, after: String) extends ParseError + final case class Expected(start: Token, expected: String, where: String, at: String) extends ParseError final case class InvalidAssignmentTarget(assignment: Token) extends ParseError - def expected(start: Token, end: String, after: String): ParseError = - if (start.tokenType == TokenType.Eof) Expected(start, end, "at end", after) - else Expected(start, end, s"at '${start.lexeme}'", after) + def expected(start: Token, end: String, at: String): ParseError = + if (start.tokenType == TokenType.Eof) Expected(start, end, "at end", at) + else Expected(start, end, s"at '${start.lexeme}'", at) def invalidAssignmentTarget(assignment: Token): ParseError = InvalidAssignmentTarget(assignment) def show: Show[ParseError] = { - case Expected(start, expected, where, after) => - showFullLine(start.line, where, s"Expected '$expected' after $after.") + case Expected(start, expected, where, at) => + showFullLine(start.line, where, s"Expected '$expected' $at.") case InvalidAssignmentTarget(assignment) => showLineAndMessage(assignment.line, "Parser Error: Invalid assignment target") }