let ( let* ) = Result.bind open Expr open Error 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, interpreter_error) result = let pos = expr.pos in match expr.expr with | Literal literal -> Ok (value_of_literal literal) | BinaryExpr { op; left; right } -> ( let* left = interpret_expr left in let* right = interpret_expr 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)) | Number x, Minus, Number y -> Ok (Number (x -. y)) | Number x, Mul, Number y -> Ok (Number (x *. y)) | Number x, Div, Number y -> Ok (Number (x /. y)) | Number x, Equal, Number y -> Ok (Bool (x = y)) | Number x, Greater, Number y -> Ok (Bool (x > y)) | Number x, GreaterEqual, Number y -> Ok (Bool (x >= y)) | Number x, Less, Number y -> Ok (Bool (x < y)) | Number x, LessEqual, Number y -> Ok (Bool (x <= y)) | Bool b, And, Bool c -> Ok (Bool (b && c)) | Bool b, Or, Bool c -> Ok (Bool (b || c)) | _, Equal, _ -> Ok (Bool (left = right)) | _, _, _ -> let msg = Printf.sprintf "Invalid operands of type %s and %s to operator %s" (type_string_of_lox_value left) (type_string_of_lox_value right) (show_binary_op op) in Error (InterpreterError.make pos msg)) | UnaryExpr { op; expr } -> ( let* expr = interpret_expr expr in match (op, expr) with | Neg, Number x -> Ok (Number (-.x)) | Not, Bool b -> Ok (Bool (not b)) | _, _ -> let msg = Printf.sprintf "Invalid operant of type %s to operator %s" (type_string_of_lox_value expr) (show_unary_op op) in Error (InterpreterError.make pos msg))