-
Notifications
You must be signed in to change notification settings - Fork 43
Language Reference
Leon supports two kinds of top-level declarations:
-
ADT definitions in the form of an abstract class and case classes/objects
abstract class Foo case class Bar(a: Int) extends Foo case object Gee extends Foo
-
Objects/modules, for grouping classes and functions
object Specs { def foo(a: Int) = { a + 1 } case class Foo(a: Int) }
## Algebraic Data Types
### Abstract classes
ADT roots need to be defined as abstract, unless the ADT is defined with only one case class/object. Unlike in Scala, abstract classes cannot define fields or constructor arguments.
```scala
abstract class MyType
This abstract root can be extended by a case-class, defining several fields:
case class MyCase1(f: Type, f2: MyType) extends MyType
case class MyCase2(f: Int) extends MyTypeIt is also possible to defined case objects, without fields:
case object BaseCase extends MyTypeNote: You can also define single case-classes:
case class MySingleCase(f: Int)
## Generics
Leon supports type parameters for classes and functions.
```scala
object Test {
abstract class List[T]
case class Cons[T](hd: T, tl: List[T]) extends List[T]
case class Nil[T]() extends List[T]
def contains[T](l: List[T], el: T) = { ... }
}
Note: Type parameters are always invariant. It is not possible to define ADTs like:
abstract class List[T] case class Cons[T](hd: T, tl: List[T]) extends List[T] case object Nil extends List[Nothing]
> Leon in fact restricts type parameters to "simple hierarchies", where subclasses define the same type parameters in the same order.
## Methods
You can currently define methods in ADT roots:
```scala
abstract class List[T] {
def contains(e: T) = { .. }
}
case class Cons[T](hd: T, tl: List[T]) extends List[T]
case object Nil extends List[Nothing]
def test(a: List[Int]) = a.contains(42)
Leon supports two kinds of specifications to functions and methods:
Preconditions constraint the argument and is expressed using require. It should hold for all calls to the function.
def foo(a: Int, b: Int) = {
require(a > b)
...
}Postconditions constraint the resulting value, and is expressed using ensuring:
def foo(a: Int): Int = {
a + 1
} ensuring { res => res > a }Leon supports most purely-functional Scala expressions:
... match {
// Simple (nested) patterns:
case CaseClass( .. , .. , ..) => ...
case v @ CaseClass( .. , .. , ..) => ...
case v : CaseClass => ...
case (t1, t2) => ...
case _ => ...
// can also be guarded, e.g.
case CaseClass(a, b, c) if a > b => ...
}val x = ...val (x, y) = ...def foo(x: Int) = {
val y = x + 1
def bar(z: Int) = {
z + y
}
bar(42)
}val x = (1,2,3)
val x = 1 -> 2 // alternative Scala syntax for Tuple2
x._1 // 1a && ba || b-
a == b(If and only if) !a
a + ba - b-aa * ba / b-
a % b(a modulo b) a < ba <= ba > ba >= ba == b
Note: Integers are treated as mathematical integers (arbitrary size, no overflow).
val s1 = Set(1,2,3,1)
val s2 = Set[Int](1,2)-
s1 ++ s2(Set union) -
s1 & s2(Set intersection) -
s1 -- s2(Set difference) s1 subsetOf s2s1 contains 42
val a = Array(1,2,3)-
a(index)(Array access) -
a.apply(index)(Array access) -
a.updated(index, value)(Returns new updated array) -
a.length(Array size)
val m = Map[Int, Boolean](42 -> false)-
m(index)(Map access) -
m.apply(index)(Map access) m isDefinedAt indexm contains index-
m.updated(index, value)(Returns the new updated map)