The Acorn language allows users to combine numeric and Boolean values using standard arithmetic and logical operators.
The Expression-Value Duality is expressed as two traits. Literal extends both. Numbers and Booles are traits that encapsulate Scala Doubles and Booleans, respectively:
Here are all of the Expression classes that must be implemented and tested:
Like many Expression classes, Sum has two Expression fields:
Scala doesn't have interfaces, instead it has traits:
trait Value
trait Expression {
def
execute: Value
}
Unlike interfaces, traits may include implemented methods.
A class, trait, or object may extends several traits:
class Literal extends Expression with Value {
def
execute = this
}
The following declaration demonstrates: overriding methods, companion objects, operator overloading, the apply method,
class Number(val value: Double) extends Literal {
def
+(other: Number) = Number(this.value
+ other.value)
def
*(other: Number) = Number(this.value
* other.value)
def
-(other: Number) = Number(this.value
- other.value)
def
/(other: Number) = Number(this.value
/ other.value)
def
<(other: Number) = Boole(this.value
< other.value)
def
==(other: Number) = Boole(this.value
== other.value)
override
def toString = value.toString
}
object Number {
def
apply(value: Double) = new
Number(value)
}
Notice what happens if val is removed.
class Sum(val operand1: Expression, val operand2: Expression) extends Expression {
def
execute() = {
val value1 = operand1.execute
val
value2 = operand2.execute
if (!value1.isInstanceOf[Number] || !value2.isInstanceOf[Number])
throw new Exception("type
mismatch: only numbers can be added")
else {
val num1 = value1.asInstanceOf[Number]
val num2 = value2.asInstanceOf[Number]
num1 + num2
}
}
override
def toString = "(" +
operand1.toString + " + " + operand2.toString + ")"
}
object Sum {
def
apply(operand1: Expression, operand2: Expression) =
new Sum(operand1, operand2)
}
object AcornTest extends
App {
def execute(exp:
Expression) {
try {
print(exp.toString
+ " = ")
val value = exp.execute
println(value.toString)
} catch {
case e: Exception => println(e)
}
}
execute(Sum(Number(3.1), Number(4.2)))
execute(And(Boole(true), Boole.TRUE))
execute(And(Boole.FALSE,
Number(3.1)))
execute(And(Number(3.1), Boole.FALSE))
execute(Sum(Number(3.1), Boole.FALSE))
execute(Sum(Sum(Number(3.1), Number(4.2)),
Sum(Number(3.5), Number(2.8))))
//execute(Less(Product(Number(10),
Sum(Number(3), Number(5)))))
// etc.
}