global and local variables with scope

also reworked arg parsing, now has --debug flag
This commit is contained in:
Moritz Gmeiner 2024-08-26 01:58:03 +02:00
commit 77e57cd8c2
8 changed files with 341 additions and 95 deletions

View file

@ -1,20 +1,36 @@
let ( let* ) = Result.bind
open Expr
open Environment
open Error
open Expr
open Stmt
open Value
let value_of_literal (literal : literal) : Value.lox_value =
match literal with String s -> String s | Number x -> Number x | Bool b -> Bool b | Nil -> Nil
let rec interpret_expr (expr : expr_node) : (lox_value, runtime_error) result =
let rec interpret_expr (env : environment) (expr : expr_node) : (lox_value, runtime_error) result =
let { pos; expr } = expr in
match expr with
| Literal literal -> Ok (value_of_literal literal)
| Variable name -> (
let value_opt = Env.get env name in
match value_opt with
| Some x -> Ok x
| None ->
let msg = Printf.sprintf "name \"%s\" is not defined" name in
Error (RuntimeError.make pos msg))
| Assignment { name; expr } ->
if not (Env.is_defined env name) then
let msg = Printf.sprintf "tried to assign to undefined variable %s" name in
Error (RuntimeError.make pos msg)
else
let* value = interpret_expr env expr in
Env.update env name value;
Ok value
| BinaryExpr { op; left; right } -> (
let* left = interpret_expr left in
let* right = interpret_expr right in
let* left = interpret_expr env left in
let* right = interpret_expr env right in
match (left, op, right) with
| String a, Plus, String b -> Ok (String (a ^ b))
| Number x, Plus, Number y -> Ok (Number (x +. y))
@ -43,7 +59,7 @@ let rec interpret_expr (expr : expr_node) : (lox_value, runtime_error) result =
in
Error { pos; msg })
| UnaryExpr { op; expr } -> (
let* expr = interpret_expr expr in
let* expr = interpret_expr env expr in
match (op, expr) with
| Neg, Number x -> Ok (Number (-.x))
| Not, Bool b -> Ok (Bool (not b))
@ -54,14 +70,31 @@ let rec interpret_expr (expr : expr_node) : (lox_value, runtime_error) result =
in
Error (RuntimeError.make pos msg))
let interpret_stmt (stmt : stmt_node) : (unit, runtime_error) result =
let rec interpret_stmt (env : environment) (stmt : stmt_node) : (unit, runtime_error) result =
let { pos; stmt } = stmt in
ignore pos;
match stmt with
| Expr expr ->
let* _ = interpret_expr env expr in
Ok ()
| Print expr ->
let* value = interpret_expr expr in
let* value = interpret_expr env expr in
print_endline (Value.string_of_lox_value value);
Ok ()
| Expr expr ->
let* _ = interpret_expr expr in
Ok ()
| VarDecl { name; init } ->
let* init = Option.map (interpret_expr env) init |> Option.value ~default:(Ok Nil) in
let success = Env.define env name init in
if success then Ok ()
else
let msg = Printf.sprintf "Tried to define %s, but was already defined" name in
Error (RuntimeError.make pos msg)
| Block stmts ->
let env = Env.enter env in
let rec _interpret stmts =
match stmts with
| stmt :: tail ->
let* _ = interpret_stmt env stmt in
_interpret tail
| [] -> Ok ()
in
_interpret stmts