From 252ed1c9253866e1560228257b2fa99c20e52501 Mon Sep 17 00:00:00 2001 From: Gleb Koval Date: Mon, 27 Jan 2025 14:47:57 +0000 Subject: [PATCH 1/5] refactor: use scalafmt to format code --- .editorconfig | 12 ++++++++++++ .scalafmt.conf | 2 ++ src/main/wacc/Main.scala | 17 +++++++++-------- src/main/wacc/lexer.scala | 14 +++++++------- src/main/wacc/parser.scala | 18 +++++++++--------- 5 files changed, 39 insertions(+), 24 deletions(-) create mode 100644 .editorconfig create mode 100644 .scalafmt.conf diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f0e0cf3 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true + +[Makefile] +indent_style = tab +indent_size = 4 + diff --git a/.scalafmt.conf b/.scalafmt.conf new file mode 100644 index 0000000..4d4a975 --- /dev/null +++ b/.scalafmt.conf @@ -0,0 +1,2 @@ +version = 3.8.6 +runner.dialect = scala36 diff --git a/src/main/wacc/Main.scala b/src/main/wacc/Main.scala index 898b5f8..a4c9fd7 100644 --- a/src/main/wacc/Main.scala +++ b/src/main/wacc/Main.scala @@ -3,13 +3,14 @@ package wacc import parsley.{Success, Failure} def main(args: Array[String]): Unit = { - println("hello WACC!") + println("hello WACC!") - args.headOption match { - case Some(expr) => parser.parse(expr) match { - case Success(x) => println(s"$expr = $x") - case Failure(msg) => println(msg) - } - case None => println("please enter an expression") - } + args.headOption match { + case Some(expr) => + parser.parse(expr) match { + case Success(x) => println(s"$expr = $x") + case Failure(msg) => println(msg) + } + case None => println("please enter an expression") + } } diff --git a/src/main/wacc/lexer.scala b/src/main/wacc/lexer.scala index 7a1872f..f633bf6 100644 --- a/src/main/wacc/lexer.scala +++ b/src/main/wacc/lexer.scala @@ -5,12 +5,12 @@ import parsley.token.Lexer import parsley.token.descriptions.* object lexer { - private val desc = LexicalDesc.plain.copy( - // your configuration goes here - ) - private val lexer = Lexer(desc) + private val desc = LexicalDesc.plain.copy( + // your configuration goes here + ) + private val lexer = Lexer(desc) - val integer = lexer.lexeme.integer.decimal - val implicits = lexer.lexeme.symbol.implicits - def fully[A](p: Parsley[A]): Parsley[A] = lexer.fully(p) + val integer = lexer.lexeme.integer.decimal + val implicits = lexer.lexeme.symbol.implicits + def fully[A](p: Parsley[A]): Parsley[A] = lexer.fully(p) } diff --git a/src/main/wacc/parser.scala b/src/main/wacc/parser.scala index 083a8d0..370f8aa 100644 --- a/src/main/wacc/parser.scala +++ b/src/main/wacc/parser.scala @@ -7,14 +7,14 @@ import lexer.implicits.implicitSymbol import lexer.{integer, fully} object parser { - def parse(input: String): Result[String, BigInt] = parser.parse(input) - private val parser = fully(expr) - - private val add = (x: BigInt, y: BigInt) => x + y - private val sub = (x: BigInt, y: BigInt) => x - y + def parse(input: String): Result[String, BigInt] = parser.parse(input) + private val parser = fully(expr) - private lazy val expr: Parsley[BigInt] = - chain.left1(integer | "(" ~> expr <~ ")")( - ("+" as add) | ("-" as sub) - ) + private val add = (x: BigInt, y: BigInt) => x + y + private val sub = (x: BigInt, y: BigInt) => x - y + + private lazy val expr: Parsley[BigInt] = + chain.left1(integer | "(" ~> expr <~ ")")( + ("+" as add) | ("-" as sub) + ) } From a52b384782515565611f8ae0524f9661e22bcdd9 Mon Sep 17 00:00:00 2001 From: Gleb Koval Date: Mon, 27 Jan 2025 14:52:51 +0000 Subject: [PATCH 2/5] ci: check_format, check_commits, compile_jvm and test_jvm steps --- .commitlintrc.yml | 1 + .gitlab-ci.yml | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 .commitlintrc.yml create mode 100644 .gitlab-ci.yml diff --git a/.commitlintrc.yml b/.commitlintrc.yml new file mode 100644 index 0000000..175ef04 --- /dev/null +++ b/.commitlintrc.yml @@ -0,0 +1 @@ +extends: "@commitlint/config-conventional" diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..dead37e --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,40 @@ +stages: + - check + - compile + - test + +default: + image: gumjoe/wacc-ci-scala:slim + +check_format: + stage: check + before_script: + - cs install scalafmt + script: + - scalafmt --check . || echo "Run 'scala format' to fix formatting issues." + +check_commits: + stage: check + image: node:lts-alpine + before_script: + - apk add git + - npm install -g @commitlint/cli @commitlint/config-conventional + - git pull origin master + script: + - npx commitlint --from origin/master --to HEAD --verbose + +compile_jvm: + stage: compile + script: + - scala compile --platform jvm -Werror . + artifacts: + paths: + - .bsp/ + - .scala-build/ + +test_jvm: + stage: test + dependencies: + - compile_jvm + script: + - scala test --platform jvm . From 6c166e4f76e1c51caa2512af103a1ed8a56f3375 Mon Sep 17 00:00:00 2001 From: Gleb Koval Date: Mon, 27 Jan 2025 15:57:35 +0000 Subject: [PATCH 3/5] ci: runner compile immediately --- .gitlab-ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dead37e..ce35a58 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -8,6 +8,7 @@ default: check_format: stage: check + needs: [] before_script: - cs install scalafmt script: @@ -15,6 +16,7 @@ check_format: check_commits: stage: check + needs: [] image: node:lts-alpine before_script: - apk add git @@ -25,6 +27,7 @@ check_commits: compile_jvm: stage: compile + needs: [] script: - scala compile --platform jvm -Werror . artifacts: @@ -34,7 +37,6 @@ compile_jvm: test_jvm: stage: test - dependencies: - - compile_jvm + needs: [ compile_jvm ] script: - scala test --platform jvm . From 56aa2210d8eabd4ca138935b23ca1f9c75d9c768 Mon Sep 17 00:00:00 2001 From: Gleb Koval Date: Mon, 27 Jan 2025 16:00:26 +0000 Subject: [PATCH 4/5] docs: add contributing section to README --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 954e909..b9daa80 100644 --- a/README.md +++ b/README.md @@ -33,3 +33,10 @@ builds your WACC compiler. Currently running 'make' will call `wacc-compiler` in the root directory of the project. If this doesn't work for whatever reason, there are a few different alternatives you can try in the makefile. **Do not use the makefile as you're working, it's for labts/CI!** + +# Contributing + +- All commit messages must follow the [conventional commits spec](https://www.conventionalcommits.org/en/v1.0.0/). + - **This includes merge request titles**. +- All scala code must be formated with `scala format`. +- All scala code must compile without errors OR WARNINGS. From cb89bb54b675fdf576af3ff49f36643e8f523520 Mon Sep 17 00:00:00 2001 From: Gleb Koval Date: Mon, 27 Jan 2025 19:23:35 +0000 Subject: [PATCH 5/5] test: test against wacc-examples repo --- .gitignore | 1 + .gitlab-ci.yml | 10 +++- src/test/wacc/examples.scala | 92 ++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 src/test/wacc/examples.scala diff --git a/.gitignore b/.gitignore index c3923f1..64ecf6a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .bsp/ .scala-build/ .vscode/ +wacc-examples/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ce35a58..760b3d3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,7 +12,7 @@ check_format: before_script: - cs install scalafmt script: - - scalafmt --check . || echo "Run 'scala format' to fix formatting issues." + - scalafmt --check . check_commits: stage: check @@ -37,6 +37,12 @@ compile_jvm: test_jvm: stage: test - needs: [ compile_jvm ] + # Use our own runner (not cloud VM or shared) to ensure we have multiple cores. + tags: [ large ] + # This is expensive, so do use `dependencies` instead of `needs` to + # ensure all previous stages pass. + dependencies: [ compile_jvm ] + before_script: + - git clone https://$EXAMPLES_AUTH@gitlab.doc.ic.ac.uk/lab2425_spring/wacc-examples.git script: - scala test --platform jvm . diff --git a/src/test/wacc/examples.scala b/src/test/wacc/examples.scala new file mode 100644 index 0000000..6400646 --- /dev/null +++ b/src/test/wacc/examples.scala @@ -0,0 +1,92 @@ +package wacc + +import org.scalatest.{ParallelTestExecution, BeforeAndAfterAll} +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.Inspectors.forEvery +import parsley.{Success, Failure} + +class ParallelExamplesSpec + extends AnyFlatSpec + with BeforeAndAfterAll + with ParallelTestExecution { + val files = + allWaccFiles("wacc-examples/valid").map { p => + (p.toString, (_: Int) == 0) + } ++ + allWaccFiles("wacc-examples/invalid/syntaxErr").map { p => + (p.toString, (_: Int) == 100) + } ++ + allWaccFiles("wacc-examples/invalid/semanticErr").map { p => + (p.toString, (_: Int) == 200) + } ++ + allWaccFiles("wacc-examples/invalid/whack").map { p => + (p.toString, List(0, 100, 200).contains) + } + + // tests go here + forEvery(files.filter { (filename, _) => + !fileIsDissallowed(filename) + }) { (filename, expectedResult) => + s"$filename" should "be parsed with correct result" in { + val contents = os.read(os.Path(filename)) + parser.parse(contents) match { + case Success(x) => assert(expectedResult(x.toInt)) + case Failure(msg) => fail(msg) + } + } + } + + def allWaccFiles(dir: String): IndexedSeq[os.Path] = + val d = java.io.File(dir) + os.walk(os.Path(d.getAbsolutePath)).filter { _.ext == "wacc" } + + def fileIsDissallowed(filename: String): Boolean = + Seq( + "wacc-examples/valid/advanced", + "wacc-examples/valid/array", + "wacc-examples/valid/basic/exit", + "wacc-examples/valid/basic/skip", + "wacc-examples/valid/expressions", + "wacc-examples/valid/function/nested_functions", + "wacc-examples/valid/function/simple_functions", + "wacc-examples/valid/if", + "wacc-examples/valid/IO/print", + "wacc-examples/valid/IO/read", + "wacc-examples/valid/IO/IOLoop.wacc", + "wacc-examples/valid/IO/IOSequence.wacc", + "wacc-examples/valid/pairs", + "wacc-examples/valid/runtimeErr", + "wacc-examples/valid/scope", + "wacc-examples/valid/sequence", + "wacc-examples/valid/variables", + "wacc-examples/valid/while", + // invalid (syntax) + "wacc-examples/invalid/syntaxErr/array", + "wacc-examples/invalid/syntaxErr/basic", + "wacc-examples/invalid/syntaxErr/expressions", + "wacc-examples/invalid/syntaxErr/function", + "wacc-examples/invalid/syntaxErr/if", + "wacc-examples/invalid/syntaxErr/literals", + "wacc-examples/invalid/syntaxErr/pairs", + "wacc-examples/invalid/syntaxErr/print", + "wacc-examples/invalid/syntaxErr/sequence", + "wacc-examples/invalid/syntaxErr/variables", + "wacc-examples/invalid/syntaxErr/while", + // invalid (semantic) + "wacc-examples/invalid/semanticErr/array", + "wacc-examples/invalid/semanticErr/exit", + "wacc-examples/invalid/semanticErr/expressions", + "wacc-examples/invalid/semanticErr/function", + "wacc-examples/invalid/semanticErr/if", + "wacc-examples/invalid/semanticErr/IO", + "wacc-examples/invalid/semanticErr/multiple", + "wacc-examples/invalid/semanticErr/pairs", + "wacc-examples/invalid/semanticErr/print", + "wacc-examples/invalid/semanticErr/read", + "wacc-examples/invalid/semanticErr/scope", + "wacc-examples/invalid/semanticErr/variables", + "wacc-examples/invalid/semanticErr/while", + // invalid (whack) + "wacc-examples/invalid/whack" + ).find(filename.contains).isDefined +}