Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finished the External DSL lab #15

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/main/scala/calculator/calc.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import calculator.semantics.eval
object Calculator extends EvalLoop with App {
override def prompt = "> "

loop { line
loop { line =>
CalcParser(line) match {
case CalcParser.Success(t, _) println(eval(t))
case e: CalcParser.NoSuccess println(e)
case CalcParser.Success(t, _) => println(eval(t))
case e: CalcParser.NoSuccess => println(e)
}
}
}
9 changes: 3 additions & 6 deletions src/main/scala/calculator/ir/AST.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,6 @@ package calculator.ir
* -----------
* Grammar
* -----------
*
* n ∈ 𝒵
*
* e ∈ Expr ::= e + t | e - t | t
* t ∈ Term ::= t * f | t / f | f
* f ∈ Fact ::= n | ( e )
*
*/

Expand All @@ -18,3 +12,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
3 changes: 3 additions & 0 deletions src/main/scala/calculator/ir/sugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
7 changes: 5 additions & 2 deletions src/main/scala/calculator/parser/Parser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@ 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}
| expr~"/"~fact ^^ {case l~"/"~r => l |/| r}
| fact )

// factors
lazy val fact: PackratParser[Expr] =
number

// numbers
def number: Parser[Num] = wholeNumber ^^ {s Num(s.toInt)}
def number: Parser[Num] = wholeNumber ^^ {s => Num(s.toInt)}

}
7 changes: 5 additions & 2 deletions src/main/scala/calculator/semantics/Interpreter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import calculator.ir._

package object semantics {
def eval(ast: AST): Int = ast match {
case Num(i) ⇒ i
case Plus(left, right) ⇒ eval(left) + eval(right)
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)
}
}
37 changes: 37 additions & 0 deletions src/test/scala/calculator/parser/ParserTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,41 @@ class CalcParserTests extends FunSpec with LangParseMatchers[AST] {
}

}

describe("Subtraction") {

it("can subtract two numbers") {
program("2-1") should parseAs ( 2 |-| 1 )
}

it("can be chained (and is left associative)") {
program("3-2-1") should parseAs ( (3 |-| 2) |-| 1 )
}

}

describe("Multiplication") {

it("can multiply two numbers") {
program("6*7") should parseAs ( 6 |*| 7 )
}

it("can be chained (and is left-associative)") {
program("3*4*5") should parseAs ( (3 |*| 4) |*| 5 )
}

}

describe("Division") {

it("can divide two numbers") {
program("64/4") should parseAs ( 64 |/| 4)
}

it ("can be chained (and is left-associative)") {
program("64/4/8") should parseAs ( ( 64 |/| 4 ) |/| 8 )
}

}

}
52 changes: 52 additions & 0 deletions src/test/scala/calculator/semantics/SemanticsTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,57 @@ class NumSemanticsTests extends FunSpec
}

}

describe("Subtraction") {

it("can subtract two numbers") {
program("2-1") should compute (1)
}

it ("can be chained (and is left-associative)") {
program("3-2-1") should compute (0)
}

it ("can handle negative values and answers") {
program("-1-4") should compute(-5)
}

}

describe("Multiplication") {

it("can multiply two numbers") {
program("6*7") should compute (42)
}

it("can be chained (and is left-associative)") {
program("3*4*5") should compute (60)
}

it ("can handle negative values and answers") {
program("2*-3*7") should compute (-42)
}

}

describe("Division") {

it ("can divide two numbers that divide each other") {
program("64/4") should compute (16)
}

it ("will round down when the numbers do not divide evenly") {
program("169/4") should compute (42)
}

it ("can be chained (and is left-associative)") {
program("64/4/8") should compute (2)
}

it ("can handle negative values and answers") {
program("-64/8") should compute (-8)
}

}

}