From 17593d528bb385ea4856a2672d6757e1c7bee4d1 Mon Sep 17 00:00:00 2001 From: Mauricio Molina Date: Sun, 5 Oct 2014 20:31:26 +0100 Subject: [PATCH] Added subtraction multiplication and division --- project/plugins.sbt | 1 + src/main/scala/calculator/ir/AST.scala | 3 ++ src/main/scala/calculator/ir/sugar.scala | 3 ++ src/main/scala/calculator/parser/Parser.scala | 5 +++ .../calculator/semantics/Interpreter.scala | 3 ++ .../scala/calculator/parser/ParserTest.scala | 36 +++++++++++++++ .../calculator/semantics/SemanticsTest.scala | 45 +++++++++++++++++++ 7 files changed, 96 insertions(+) create mode 100644 project/plugins.sbt diff --git a/project/plugins.sbt b/project/plugins.sbt new file mode 100644 index 0000000..6f4daa6 --- /dev/null +++ b/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.5.0") \ No newline at end of file diff --git a/src/main/scala/calculator/ir/AST.scala b/src/main/scala/calculator/ir/AST.scala index 94f14d0..6c0ed09 100644 --- a/src/main/scala/calculator/ir/AST.scala +++ b/src/main/scala/calculator/ir/AST.scala @@ -18,3 +18,6 @@ sealed abstract class Expr extends AST case class Num(n: Int) extends Expr case class Plus(left: Expr, right: Expr) extends Expr +case class Minus(left: Expr, right: Expr) extends Expr +case class Mult(left: Expr, right: Expr) extends Expr +case class Div(left: Expr, right: Expr) extends Expr diff --git a/src/main/scala/calculator/ir/sugar.scala b/src/main/scala/calculator/ir/sugar.scala index 7e92da9..c4b4caa 100644 --- a/src/main/scala/calculator/ir/sugar.scala +++ b/src/main/scala/calculator/ir/sugar.scala @@ -16,5 +16,8 @@ package object ir { // take the right operand and returns the appropriate Expr implicit class ExprBuilder(val left: Expr) { def |+|(right: Expr) = Plus(left, right) + def |-| (right: Expr) = Minus(left, right) + def |*| (right: Expr) = Mult(left, right) + def |/| (right: Expr) = Div(left, right) } } diff --git a/src/main/scala/calculator/parser/Parser.scala b/src/main/scala/calculator/parser/Parser.scala index 116886c..827046c 100644 --- a/src/main/scala/calculator/parser/Parser.scala +++ b/src/main/scala/calculator/parser/Parser.scala @@ -11,8 +11,13 @@ object CalcParser extends JavaTokenParsers with PackratParsers { // expressions lazy val expr: PackratParser[Expr] = ( expr~"+"~fact ^^ {case l~"+"~r ⇒ l |+| r} + | expr~"-"~fact ^^ {case l~"-"~r ⇒ l |-| r} + | expr~"*"~fact ^^ {case l~"*"~r ⇒ l |*| r} + | expr~"/"~fact ^^ {case l~"/"~r ⇒ l |/| r} | fact ) + + // factors lazy val fact: PackratParser[Expr] = number diff --git a/src/main/scala/calculator/semantics/Interpreter.scala b/src/main/scala/calculator/semantics/Interpreter.scala index c383719..4df59ca 100644 --- a/src/main/scala/calculator/semantics/Interpreter.scala +++ b/src/main/scala/calculator/semantics/Interpreter.scala @@ -6,5 +6,8 @@ package object semantics { def eval(ast: AST): Int = ast match { case Num(i) ⇒ i case Plus(left, right) ⇒ eval(left) + eval(right) + case Minus(left, right) ⇒ eval(left) - eval(right) + case Mult(left, right) ⇒ eval(left) * eval(right) + case Div(left, right) ⇒ eval(left) / eval(right) } } \ No newline at end of file diff --git a/src/test/scala/calculator/parser/ParserTest.scala b/src/test/scala/calculator/parser/ParserTest.scala index 29ed8f3..ed48fb5 100644 --- a/src/test/scala/calculator/parser/ParserTest.scala +++ b/src/test/scala/calculator/parser/ParserTest.scala @@ -42,5 +42,41 @@ class CalcParserTests extends FunSpec with LangParseMatchers[AST] { program("1 + 2 + 100") should parseAs ( (1 |+| 2) |+| 100 ) } + } + + describe("Subtraction") { + + it("can subtract two numbers") { + program("1-1") should parseAs ( 1 |-| 1 ) + } + + it("can be chained (and is left-associative)") { + program("1 - 2 - 100") should parseAs ( (1 |-| 2) |-| 100 ) + } + + } + + describe("Multiplication") { + + it("can multiply two numbers") { + program("1*1") should parseAs ( 1 |*| 1 ) + } + + it("can be chained (and is left-associative)") { + program("1 * 2 * 100") should parseAs ( (1 |*| 2) |*| 100 ) + } + + } + + describe("Division") { + + it("can add divide numbers") { + program("1/1") should parseAs ( 1 |/| 1 ) + } + + it("can be chained (and is left-associative)") { + program("1 / 2 / 100") should parseAs ( (1 |/| 2) |/| 100 ) + } + } } diff --git a/src/test/scala/calculator/semantics/SemanticsTest.scala b/src/test/scala/calculator/semantics/SemanticsTest.scala index fe2fa73..6c1ada5 100644 --- a/src/test/scala/calculator/semantics/SemanticsTest.scala +++ b/src/test/scala/calculator/semantics/SemanticsTest.scala @@ -39,5 +39,50 @@ class NumSemanticsTests extends FunSpec } } + describe("Subtraction") { + it("can subtract two numbers") { + program("1-1") should compute (0) + } + + it("can be chained (and is left-associative)") { + program("100 - 2 - 1") should compute (97) + } + + it("can handle negative numbers") { + program("1 - -1") should compute (2) + } + + } + + describe("Multiplication") { + + it("can add multiply numbers") { + program("3*5") should compute (15) + } + + it("can be chained (and is left-associative)") { + program("1 * 3 * 150") should compute (450) + } + + it("can handle negative numbers") { + program("6 * -1") should compute (-6) + } + + } + describe("Division") { + + it("can add divide numbers") { + program("100/10") should compute (10) + } + + it("can be chained (and is left-associative)") { + program("100/10/2") should compute (5) + } + + it("can handle negative numbers") { + program("60/-5") should compute (-12) + } + + } }