Skip to content

Commit

Permalink
Implemented let expressions.
Browse files Browse the repository at this point in the history
  • Loading branch information
artob committed Nov 17, 2020
1 parent 90dc9fd commit 3fac8f2
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 6 deletions.
47 changes: 41 additions & 6 deletions lib/Clar2EVM/compile.ml
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
(* This is free and unencumbered software released into the public domain. *)

type context =
{ vars: string list;
funs: string list; }
{ global_vars: string list;
global_funs: string list;
local_vars: (string * int) list; }

let make_context global_vars global_funs local_vars =
{ global_vars; global_funs; local_vars; }

let extend_context context local_vars =
{ global_vars = context.global_vars;
global_funs = context.global_funs;
local_vars = local_vars @ context.local_vars; }

let _dump_context context =
let dump_local_var (n, i) = Printf.eprintf "\t(%s, %d)" n i in
Printf.eprintf "local_vars=%d\t" (List.length context.local_vars);
List.iter dump_local_var context.local_vars

let unimplemented_function name type' =
unimplemented (Printf.sprintf "(%s %s)" name (Clarity.type_to_string type'))
Expand Down Expand Up @@ -42,12 +56,12 @@ let rec compile_contract ?(features=[]) program =
match only_function with
| Some fn ->
let funs = funs |> List.filter (fun f -> fn = name_of f) in
let globals = { vars = List.map name_of vars; funs = List.map name_of funs; } in
let globals = make_context (List.map name_of vars) (List.map name_of funs) [] in
let program = compile_program features globals funs in
let payload = link_program program in
([], payload)
| None ->
let globals = { vars = List.map name_of vars; funs = List.map name_of funs; } in
let globals = make_context (List.map name_of vars) (List.map name_of funs) [] in
let dispatcher = compile_dispatcher funs in
let program = compile_program features globals funs in
let payload = link_program (dispatcher @ program) in
Expand Down Expand Up @@ -207,6 +221,14 @@ and compile_expression env = function
let b = compile_expression env b in
EVM.gt a b (* TODO: signed vs unsigned *)

| Identifier id -> (* _dump_context env; *)
begin match List.find_opt (fun (name, _) -> name = id) env.local_vars with
| None -> failwith (Printf.sprintf "unbound variable: %s" id)
| Some (_, local_var_index) ->
let stack_slot = (List.length env.local_vars) - local_var_index in
EVM.dup stack_slot
end

| If (cond_expr, then_branch, else_branch) ->
begin match type_of_expression cond_expr with
| Bool ->
Expand Down Expand Up @@ -261,6 +283,19 @@ and compile_expression env = function
| t -> unsupported_function "len" t
end

| Let (bindings, body) ->
let local_var_count = List.length env.local_vars in
let compile_binding_index index (name, _) = (name, local_var_count + index) in
let compile_binding_expr (_, expr) = compile_expression env expr in
let env = extend_context env (List.mapi compile_binding_index bindings) in
let last_body_index = (List.length body) - 1 in
let compile_body_expr index expr =
compile_expression env expr @
if index < last_body_index then EVM.pop1 else []
in
List.map compile_binding_expr bindings @
List.mapi compile_body_expr body |> List.concat

| ListExpression xs ->
List.concat_map (compile_expression env) xs @ [EVM.from_int (List.length xs)]

Expand Down Expand Up @@ -596,12 +631,12 @@ and mangle_name = function
String.uncapitalize_ascii (String.concat "" words)

and lookup_variable_slot env symbol =
match lookup_symbol env.vars symbol with
match lookup_symbol env.global_vars symbol with
| None -> failwith (Printf.sprintf "unknown variable: %s" symbol)
| Some index -> index

and lookup_function_block env symbol =
match lookup_symbol env.funs symbol with
match lookup_symbol env.global_funs symbol with
| None -> failwith (Printf.sprintf "unknown function: %s" symbol)
| Some index -> 1 + index

Expand Down
31 changes: 31 additions & 0 deletions test/operators.t
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,37 @@ impl-trait: Not implemented yet.

let:

$ clarc -t opcode -f only-function=test <<EOF
> (define-read-only (test) (let ((x 7)) x))
> EOF
PUSH1 0x07 DUP1 PUSH1 0x00 MSTORE PUSH1 0x20 PUSH1 0x00 RETURN STOP

$ clarc -t opcode -f only-function=test <<EOF
> (define-read-only (test) (let ((x 7) (y 9)) x))
> EOF
PUSH1 0x07 PUSH1 0x09 DUP2 PUSH1 0x00 MSTORE PUSH1 0x20 PUSH1 0x00 RETURN
STOP

$ clarc -t opcode -f only-function=test <<EOF
> (define-read-only (test) (let ((x 7) (y 9)) y))
> EOF
PUSH1 0x07 PUSH1 0x09 DUP1 PUSH1 0x00 MSTORE PUSH1 0x20 PUSH1 0x00 RETURN
STOP

$ clarc -t opcode -f only-function=test <<EOF
> (define-read-only (test) (let ((x 7)) (let ((x 9)) x)))
> EOF
PUSH1 0x07 PUSH1 0x09 DUP1 PUSH1 0x00 MSTORE PUSH1 0x20 PUSH1 0x00 RETURN
STOP

$ clarc -t opcode -f only-function=test <<EOF
> (define-read-only (test) (let ((x 7)) y))
> EOF
clarc: internal error, uncaught exception:
Failure("unbound variable: y")

[125]

match:

$ clarc -t opcode -f only-function=test <<EOF
Expand Down

0 comments on commit 3fac8f2

Please sign in to comment.