From 2abfb0adbc9884364e312f4c9f8aeb7a56d03a9b Mon Sep 17 00:00:00 2001 From: Leonardo Lucena Date: Mon, 12 Dec 2022 20:43:56 +0000 Subject: [PATCH] Update Scala version to 3.2.1 --- .gitignore | 6 ++ .vscode/settings.json | 5 ++ README.md | 9 ++- build.sbt | 4 +- grammar.md | 3 +- interpreter.md | 130 +++++++++++++++++++++------------------ project/assembly.sbt | 2 +- project/build.properties | 2 +- project/metals.sbt | 6 ++ 9 files changed, 96 insertions(+), 71 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 project/metals.sbt diff --git a/.gitignore b/.gitignore index a181f2b..3d27007 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,9 @@ project/plugins/project/ # Metals *.metals/ +project/project/metals.sbt +project/project/project/metals.sbt + +.bloop/ +*.interp +*.antlr diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..32cfc61 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.watcherExclude": { + "**/target": true + } +} \ No newline at end of file diff --git a/README.md b/README.md index 6201c9b..75e5df7 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ The language is implemented in two ways: Parser Rules - + Listener (59 lines)
Abstract Syntax (23 lines) @@ -53,8 +53,8 @@ The language is implemented in two ways: Total - 190 lines - 190 lines + 190 lines + 190 lines @@ -107,7 +107,7 @@ statement: ID ':=' expression # attrib | 'if' bool 'then' statement 'else' statement # if | 'while' bool 'do' statement # while | 'print' Text # print - | 'write' expression # write + | 'print' expression # write | '{' seqStatement '}' # block ; @@ -130,7 +130,6 @@ bool: ('true'|'false') # boolean INT: ('0'..'9')+ ; ID: ('a'..'z')+; Text: '"' .*? '"'; - Space: [ \t\n\r] -> skip; ```` --- diff --git a/build.sbt b/build.sbt index 3daec06..9724aee 100644 --- a/build.sbt +++ b/build.sbt @@ -1,6 +1,6 @@ -ThisBuild / scalaVersion := "3.2.0" +ThisBuild / scalaVersion := "3.2.1" ThisBuild / organization := "com.github.lrlucena" -ThisBuild / version := "1.2" +ThisBuild / version := "1.2.1" enablePlugins(Antlr4Plugin) diff --git a/grammar.md b/grammar.md index 2d40dbf..ee1f7b9 100644 --- a/grammar.md +++ b/grammar.md @@ -12,7 +12,7 @@ statement: ID ':=' expression # attrib | 'if' bool 'then' statement 'else' statement # if | 'while' bool 'do' statement # while | 'print' Text # print - | 'write' expression # write + | 'print' expression # write | '{' seqStatement '}' # block ; @@ -35,6 +35,5 @@ bool: ('true'|'false') # boolean INT: ('0'..'9')+ ; ID: ('a'..'z')+; Text: '"' .*? '"'; - Space: [ \t\n\r] -> skip; ``` diff --git a/interpreter.md b/interpreter.md index d92e939..d210983 100644 --- a/interpreter.md +++ b/interpreter.md @@ -63,19 +63,23 @@ sbt> runMain whilelang.interpreter.main sum.while ## Parser Rules ````scala -package whilelang.interpreter +package whilelang.parser import scala.jdk.CollectionConverters._ import scala.language.implicitConversions -import whilelang.interpreter.Language._ -import whilelang.parser.{Antlr2Scala, WhilelangBaseListener} +import whilelang.parser.WhilelangBaseListener import whilelang.parser.WhilelangParser._ +import whilelang.util.Antlr2Scala +import Statement._ +import Expression._ +import Bool._ -class MyListener extends WhilelangBaseListener with Antlr2Scala[Any] { +class MyListener extends WhilelangBaseListener with Antlr2Scala[Any]: var program: Program = _ override def exitProgram(ctx: ProgramContext) = - program = Program(ctx.seqStatement.value) + ctx.value = Program(ctx.seqStatement.value) + program = ctx.value override def exitSeqStatement(ctx: SeqStatementContext) = ctx.value = SeqStatement(ctx.statement.asScala.toList.map { _.value[Statement] }) @@ -96,7 +100,7 @@ class MyListener extends WhilelangBaseListener with Antlr2Scala[Any] { ctx.value = Print(ctx.Text.text.drop(1).dropRight(1)) override def exitWrite(ctx: WriteContext) = - ctx.value = Write(ctx.expression.value[Expression]) + ctx.value = Write(ctx.expression.value) override def exitBlock(ctx: BlockContext) = ctx.value = ctx.seqStatement.value @@ -114,10 +118,12 @@ class MyListener extends WhilelangBaseListener with Antlr2Scala[Any] { ctx.value = Integer(ctx.text.toInt) override def exitBinOp(ctx: BinOpContext) = + val lhs: Expression = ctx.expression(0).value + val rhs: Expression = ctx.expression(1).value ctx.value = ctx(1).text match - case "*" => ExpMult(ctx(0).value, ctx(2).value) - case "-" => ExpSub(ctx(0).value, ctx(2).value) - case "+" | _ => ExpSum(ctx(0).value, ctx(2).value) + case "*" => ExpMult(lhs, rhs) + case "-" => ExpSub(lhs, rhs) + case "+" | _ => ExpSum(lhs, rhs) override def exitNot(ctx: NotContext) = ctx.value = Not(ctx.bool.value) @@ -126,48 +132,47 @@ class MyListener extends WhilelangBaseListener with Antlr2Scala[Any] { ctx.value = Boole(ctx.text == "true") override def exitAnd(ctx: AndContext) = - ctx.value = And(ctx(0).value, ctx(2).value) + ctx.value = And(ctx.bool(0).value, ctx.bool(1).value) override def exitBoolParen(ctx: BoolParenContext) = ctx.value = ctx.bool.value override def exitRelOp(ctx: RelOpContext) = + val lhs: Expression = ctx.expression(0).value + val rhs: Expression = ctx.expression(1).value ctx.value = ctx(1).text match - case "=" => ExpEqual(ctx.expression(0).value, ctx.expression(1).value) - case "<=" | _ => ExpLessOrEqualThan(ctx.expression(0).value, ctx.expression(1).value) -} + case "=" => ExpEq(lhs, rhs) + case "<=" | _ => ExpLe(lhs, rhs) ```` ## Abstract Syntax ````scala -package whilelang.interpreter +package whilelang.parser -object Language { - sealed trait Statement { def execute() = Semantics.execute(this) } - case object Skip extends Statement - case class If(condition: Bool, thenSmt: Statement, elseSmt: Statement) extends Statement - case class Write(exp: Expression) extends Statement - case class While(condition: Bool, doSmt: Statement) extends Statement - case class Print(text: String) extends Statement - case class SeqStatement(statements: List[Statement]) extends Statement - case class Attrib(id: String, exp: Expression) extends Statement - case class Program(statements: SeqStatement) extends Statement - - sealed trait Expression { def value() = Semantics.value(this) } - case object Read extends Expression - case class Id(id: String) extends Expression - case class Integer(exp: Int) extends Expression - case class ExpSum(lhs: Expression, rhs: Expression) extends Expression - case class ExpSub(lhs: Expression, rhs: Expression) extends Expression - case class ExpMult(lhs: Expression, rhs: Expression) extends Expression - - sealed trait Bool { def value() = Semantics.value(this) } - case class Boole(b: Boolean) extends Bool - case class ExpEqual(lhs: Expression, rhs: Expression) extends Bool - case class ExpLessOrEqualThan(lhs: Expression, rhs: Expression) extends Bool - case class Not(b: Bool) extends Bool - case class And(lhs: Bool, rhs: Bool) extends Bool -} +enum Statement: + case Skip + case If(condition: Bool, thenSmt: Statement, elseSmt: Statement) + case Write(exp: Expression) + case While(condition: Bool, doSmt: Statement) + case Print(text: String) + case SeqStatement(statements: List[Statement]) + case Attrib(id: String, exp: Expression) + case Program(statements: SeqStatement) + +enum Expression: + case Read + case Id(id: String) + case Integer(exp: Int) + case ExpSum(lhs: Expression, rhs: Expression) + case ExpSub(lhs: Expression, rhs: Expression) + case ExpMult(lhs: Expression, rhs: Expression) + +enum Bool: + case Boole(b: Boolean) + case ExpEq(lhs: Expression, rhs: Expression) + case ExpLe(lhs: Expression, rhs: Expression) + case Not(b: Bool) + case And(lhs: Bool, rhs: Bool) ```` ## Semantics @@ -212,45 +217,50 @@ object Semantics { ### Walker ````scala -package whilelang.parser +package whilelang.util import scala.util.Try import org.antlr.v4.runtime.{BaseErrorListener, CharStream, CharStreams, CommonTokenStream, RecognitionException, Recognizer } import org.antlr.v4.runtime.misc.ParseCancellationException import org.antlr.v4.runtime.tree.ParseTreeWalker +import whilelang.parser._ +import whilelang.interpreter._ -object ThrowingErrorListener extends BaseErrorListener { +object ThrowingErrorListener extends BaseErrorListener: override def syntaxError(r: Recognizer[_, _], off: Any, line: Int, col: Int, msg: String, e: RecognitionException) = - throw new ParseCancellationException(s"line $line:$col $msg") -} + throw ParseCancellationException(s"line $line:$col $msg") -object Walker { - def walk(source: String)(implicit listener: WhilelangListener) = Try { - val addListener = (r: Recognizer[_, _]) => - r.removeErrorListeners() - r.addErrorListener(ThrowingErrorListener) - val lexer = new WhilelangLexer(CharStreams.fromString(source)) { addListener(this) } - val parser = new WhilelangParser(new CommonTokenStream(lexer)) { addListener(this) } +object Walker: + def sourceCode(file: String): Try[String] = Try { + io.Source.fromFile(file).getLines().mkString("\n") + } + + def addListener(r: Recognizer[_, _]*) = r.map( r => + r.removeErrorListeners() + r.addErrorListener(ThrowingErrorListener)) - new ParseTreeWalker().walk(listener, parser.program) + def walk(source: String)(implicit listener: MyListener): Try[Statement.Program] = Try { + val lexer = WhilelangLexer(CharStreams.fromString(source)) + val parser = WhilelangParser(CommonTokenStream(lexer)) + addListener(lexer, parser) + ParseTreeWalker().walk(listener, parser.program) + listener.program } -} ```` ### Antlr2Scala ````scala -package whilelang.parser +package whilelang.util -import org.antlr.v4.runtime.tree.{ ParseTree, ParseTreeProperty } +import org.antlr.v4.runtime.tree.{ParseTree, ParseTreeProperty} + +trait Antlr2Scala[T]: + private val values = ParseTreeProperty[T] -trait Antlr2Scala[T] { - private[Antlr2Scala] val values = new ParseTreeProperty[T] given Conversion[ParseTree, Tree2Scala] = Tree2Scala(_) - private[Antlr2Scala] case class Tree2Scala(tree: ParseTree) { + private[Antlr2Scala] case class Tree2Scala(tree: ParseTree): def apply(i: Int) = tree.getChild(i) def text = tree.getText def value[E]: E = values.get(tree).asInstanceOf[E] def value_=(v: T) = values.put(tree, v) - } -} ```` diff --git a/project/assembly.sbt b/project/assembly.sbt index fdd8358..979a942 100644 --- a/project/assembly.sbt +++ b/project/assembly.sbt @@ -1 +1 @@ -addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.2.0") +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.1.0") diff --git a/project/build.properties b/project/build.properties index 22af262..8b9a0b0 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.7.1 +sbt.version=1.8.0 diff --git a/project/metals.sbt b/project/metals.sbt new file mode 100644 index 0000000..e9e7b54 --- /dev/null +++ b/project/metals.sbt @@ -0,0 +1,6 @@ +// DO NOT EDIT! This file is auto-generated. + +// This file enables sbt-bloop to create bloop config files. + +addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.5.4") +