Module Fang_tiger.Analysis
Parameters
Signature
Building analyzers
include TIGER with type 'a t := 'a t
Expressions
val arith : oper -> expr t -> expr t -> tag -> expr t
Arithmetic on
int
.For example,
23 * (5 + 3)
is
arith `Multiply (int 23L) (arith `Add (int 5L) (int 3L))
val neg : expr t -> tag -> expr t
Negate an
int
.For example,
-(3 + 5)
is
neg (arith `Add (int 3L) (int 5L))
val cmp : rel -> expr t -> expr t -> tag -> expr t
Compare two values.
For example,
"foo" = "bar"
is
cmp `Equal (string "foo") (string "bar")
Only values of compatible type can be compared.
Allowed comparisons:
int
: Allstring
: All (lexicographic)- arrays: equality (by reference)
- records: equality (by reference)
val value : target t -> tag -> expr t
The value of a target.
For example,
x + 3
is
arith `Add (value (name "x")) (int 3L)
val if_ : condition:expr t -> yes:expr t -> ?no:expr t -> tag -> expr t
Conditional values.
There are two forms of
if
statements. In both cases,condition
must be of typeint
.The first is for conditionally performing an effect. In this case, the affirmative branch is of type
unit
.For example,
if a < 10 then print("yes")
is
if_ ~condition:(cmp `Less_than (value (name "a")) (int 10L)) ~yes:(call "print" [string "yes"])
When a negative branch is included (
no
), both branches must evaluate to values of compatible types.For example,
if a < 10 then a + 1 else 100
is
if_ ~condition:(cmp `Less_than (value (name "a")) (int 10L)) ~yes:(arith `Add (value (name "a")) (int 1L)) ~no:(int 100L)
val while_ : condition:expr t -> body:expr t -> tag -> expr t
Conditional repeated execution.
The
condition
must be of typeint
and thebody
must be of typeunit
.For example,
while x >= 10 do x := x - 5
is
while_ ~condition:(cmp `Greater_or_equal (value (name "x")) (int 10L)) ~body: (assign (name "x") (arith `Subtract (value (name "x")) (int 5L)))
val for_ : string -> initial:expr t -> final:expr t -> body:expr t -> tag -> expr t
The
for
loop we know and love.initial
andfinal
must be of typeint
. The variable takes on the values fromintial, initial + 1, ..., value
inclusive and is not defined outside the body of the loop.The body must be of type
unit
.For example,
for i := 1 to 10 do print_int(i + 1)
is
for_ "i" ~initial:(int 1L) ~final:(int 10) ~body:(call "print_int" [arith `Add (value (name "i")) (int 1L)])
val break : tag -> expr t
Break out of a loop.
For example,
while 1 do break
is
while_ ~condition:(int 1L) ~body:break
val seq : expr t list -> tag -> expr t
Sequence multiple expressions.
The result is the last value in the sequence.
For example,
(print("foo"); 10; 20)
is
seq [call "print" [string "foo"]; int 10L; int 20L]
val call : string -> expr t list -> tag -> expr t
Invoke a function.
For example,
concat(s, "foo")
is
call "concat" [value (name "s"); string "foo"]
val uniform_array : string -> size:expr t -> initial:expr t -> tag -> expr t
A new array filled with a uniform value.
size
must be of typeint
.For example,
people["Sally"] of 100
(an array of 100 people named Sally) is
uniform_array "people" ~size:(int 100L) ~initial:(string "Sally")
val array : string -> expr t list -> tag -> expr t
An array literal.
For example,
people of ["Joe", "Sally", "Bob"]
is
array "people" [string "Joe"; string "Sally"; string "Bob"]
val size : expr t -> tag -> expr t
The number of items in an array value.
For example,
size numbers
is
size (value (name "numbers"))
val record : string -> (string * expr t) list -> tag -> expr t
Create a new record value.
The record fields can be specified in any order.
For example,
person {name="Joe", age=11}
is
record "person" [("name", string "Joe"); ("age", int 11L)]
val scope : decl t list -> expr t -> tag -> expr t
Define a new scope.
The expression is evaluated based on the new declarations. After, the declarations no longer apply.
For example,
let var x := 10 var y := x + 1 in x - y end
is
scope [var "x" (int 10L); var "y" (arith `Add (value (name "x")) (int 1L))] (arith `Subtract (value (name "x")) (value (name "y")))
Targets
Declarations
val var : string -> ?type_name:string -> expr t -> tag -> decl t
Variable declaration.
In most cases, the type of a variable can be inferred from the value it is assigned.
For example,
var x := 10
is
var "x" (int 10L)
The type can be also supplied explicitly, like
var y: int := 20
which is
var "y" ~type_name:"int" (int 20L)
When a variable is initialized to
nil
, the type must be included:var p: person := nil
val fns : fn t list -> tag -> decl t
A mutually-recursive group of function definitions.
For example,
function is_even(x: int): int = if x = 0 then 1 else is_odd(x - 1) and function is_odd(x: int): int = if x = 0 then 0 else is_even(x - 1)
is
fns [ fn "is_even" [(param "x", "int")] ~type_name:"int" (if_ ~condition:(cmp `Equal (value (name "x")) (int 0L)) ~yes:(int 1L) ~no: (call "is_odd" [arith `Subtract (value (name "x")) (int 1L)]) ) ; fn "is_odd" [(param "x", "int")] ~type_name:"int" (if_ ~condition:(cmp `Equal (value (name "x")) (int 0L)) ~yes:(int 0L) ~no: (call "is_even" [arith `Subtract (value (name "x")) (int 1L)] ) ) ]
Functions
val fn : string -> (param t * string) list -> ?type_name:string -> expr t -> tag -> fn t
Function definition.
When
type_name
is not provided, the function body must be of typeunit
.For example,
function greet() = print("Hi!")
is
fn "greet" [] (call "print" [string "Hi!"])
and
function add(x: int, y: int): int = x + y
is
fn "add" [(param "x", "int"); (param "y", "int")] ~type_name:"int" (arith `Add (value (name "x")) (value (name "y")))
Function parameter names
Types
val alias_type : name:string -> target:string -> tag -> typ t
Define a type alias.
For example,
type age = int
is
alias_type ~name:"age" ~target:"int"