Module type Fang_translate.TRANSLATE

type _ t

A translator from Tiger to IR.

type _ ir

An IR interpreter.

Executing translations

val translate : ?⁠safe:bool -> analysis -> expr t -> (value ir * frame_ptr) fragment iter * string fragment iter

Translate a Tiger value into IR.

If safe is false (it's default value is true) then potentially memory-unsafe operations will be permitted: accessing a nil record value and accessing an array outside of its bounds. Unsafe code is faster.

The result is a pair of iterators.

The first iterates over all the subroutines necessary for implementing the Tiger fragment and the frame pointer requirement for each.

The second iterates over all necessary string constants.

Building translators

include TIGER with type 'a t := 'a t
type _ t

A Tiger fragment.

Expressions

val int : int64 -> tag -> expr t

A 64 bit integer literal.

val string : string -> tag -> expr t

A string literal.

val nil : tag -> expr t

The empty record value.

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: All
  • string: 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 type int.

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 type int and the body must be of type unit.

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 and final must be of type int. The variable takes on the values from intial, 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 type int.

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")))
val assign : target t -> expr t -> tag -> expr t

Assign a value to a target.

The type of the target must be compatible with the type of the value to be assigned.

The result is a value of type unit.

For example,

person.name := "Joe"

is

assign (access (name "person") "name") (string "Joe") 

Targets

val name : string -> tag -> target t

The name of a variable.

For example,

my_var

is

name "my_var" 
val index : target t -> expr t -> tag -> target t

An indexed location in an array.

The index value must of be type int.

For example,

numbers[3]

is

index (name "numbers") (int 3L) 
val access : target t -> string -> tag -> target t

A record field.

For example,

person.age

is

access (name "person") "age" 

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)] ) ) ]
val types : typ t list -> tag -> decl t

A mutually-recursive group of type definitions.

For example,

type participants = array of person
and type person = string

is

types
  [ array_type ~name:"participants" ~item:"person"
  ; alias_type ~name:"person" ~target:"string" ]

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 type unit.

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

val param : string -> tag -> param t

A function parameter name.

For example, in the function definition

function add(x: int, y: int): int = x + y

both x and y are parameters.

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" 
val array_type : name:string -> item:string -> tag -> typ t

Define an array type.

For example,

type numbers = array of int

is

array_type ~name:"numbers" ~item:"int" 
val record_type : string -> (string * string) list -> tag -> typ t

Define a record type.

For example,

type person = {name: string, age: int}

is

record_type "person" [("name", "string"); ("age", "int")]