Files
rose-ash/lib/ocaml/baseline/calc.ml
giles ffa74399fd
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 54s
ocaml: phase 5.1 calc.ml baseline (11/11 pass) + inline let-rec-and parser fix
Recursive-descent calculator parses '(1 + 2) * 3 + 4' = 13. Two parser
bugs fixed:

1. parse-let now handles inline 'let rec a () = ... and b () = ... in
   body' via new (:let-rec-mut BINDINGS BODY) and (:let-mut BINDINGS
   BODY) AST shapes; eval handles both.

2. has-matching-in? lookahead no longer stops at 'and' — 'and' is
   internal to let-rec, not a decl boundary. Without this fix, the
   inner 'let rec a () = ... and b () = ...' inside a let-decl rhs
   would have been treated as the start of a new top-level decl.

Baseline exercises mutually-recursive functions, while-loops, ref-cell
imperative parsing, and ADT-based AST construction.
2026-05-08 16:53:44 +00:00

77 lines
1.7 KiB
OCaml

(* Baseline: recursive-descent calculator for "+", "*", parens, ints. *)
type expr =
| Lit of int
| Add of expr * expr
| Mul of expr * expr
;;
let parse_input src =
let pos = ref 0 in
let peek () = if !pos < String.length src then String.get src !pos else "" in
let advance () = pos := !pos + 1 in
let skip_ws () =
while !pos < String.length src && peek () = " " do advance () done
in
let rec parse_atom () =
skip_ws () ;
if peek () = "(" then begin
advance () ;
let e = parse_expr () in
skip_ws () ;
advance () ; (* consume ')' *)
e
end
else
let start = !pos in
let rec digits () =
if !pos < String.length src then
let c = peek () in
if c >= "0" && c <= "9" then begin advance () ; digits () end
else ()
in
digits () ;
let n = Int.of_string (String.sub src start (!pos - start)) in
Lit n
and parse_term () =
skip_ws () ;
let lhs = ref (parse_atom ()) in
let rec loop () =
skip_ws () ;
if peek () = "*" then begin
advance () ;
lhs := Mul (!lhs, parse_atom ()) ;
loop ()
end
in
loop () ;
!lhs
and parse_expr () =
skip_ws () ;
let lhs = ref (parse_term ()) in
let rec loop () =
skip_ws () ;
if peek () = "+" then begin
advance () ;
lhs := Add (!lhs, parse_term ()) ;
loop ()
end
in
loop () ;
!lhs
in
parse_expr ()
;;
let rec eval e =
match e with
| Lit n -> n
| Add (a, b) -> eval a + eval b
| Mul (a, b) -> eval a * eval b
;;
(* (1 + 2) * 3 + 4 = 9 + 4 = 13 *)
eval (parse_input "(1 + 2) * 3 + 4")