ocaml: phase 4 basic labeled / optional argument syntax (label dropped) (+3 tests, 562 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 26s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 26s
Three parser changes:
1. at-app-start? returns true on op '~' or '?' so the app loop
keeps consuming labeled args.
2. The app arg parser handles:
~name:VAL drop label, parse VAL as the arg
?name:VAL same
~name punning -- treat as (:var name)
?name same
3. try-consume-param! drops '~' or '?' and treats the following
ident as a regular positional param name.
Caveats:
- Order in the call must match definition order; we don't reorder
by label name.
- Optional args don't auto-wrap in Some, so the function body sees
the raw value for ?x:V.
Lets us write idiomatic-looking OCaml even though the runtime is
positional underneath:
let f ~x ~y = x + y in f ~x:3 ~y:7 = 10
let x = 4 in let y = 5 in f ~x ~y = 20 (punning)
let f ?x ~y = x + y in f ?x:1 ~y:2 = 3
This commit is contained in:
@@ -353,6 +353,15 @@
|
||||
(advance-tok!)
|
||||
(set-nth! wild-counter 0 (+ (nth wild-counter 0) 1))
|
||||
(str "__wild_" (nth wild-counter 0))))
|
||||
;; ~name / ?name labeled/optional param — drop the label
|
||||
;; prefix and treat as a positional ident name. Optional
|
||||
;; default `?(name = default)` is not handled here yet.
|
||||
((and (or (at-op? "~") (at-op? "?"))
|
||||
(= (ocaml-tok-type (peek-tok-at 1)) "ident"))
|
||||
(begin
|
||||
(advance-tok!) ;; ~ or ?
|
||||
(let ((nm (ocaml-tok-value (peek-tok))))
|
||||
(begin (advance-tok!) nm))))
|
||||
((check-tok? "ident" nil)
|
||||
(let ((nm (ocaml-tok-value (peek-tok))))
|
||||
(begin (advance-tok!) nm)))
|
||||
@@ -565,6 +574,9 @@
|
||||
((and (= tt "keyword") (or (= tv "true") (= tv "false") (= tv "begin")))
|
||||
true)
|
||||
((and (= tt "op") (or (= tv "(") (= tv "[") (= tv "{") (= tv "!"))) true)
|
||||
;; ~name or ?name (labeled/optional arg) — drop the
|
||||
;; label prefix and use the value as a positional arg.
|
||||
((and (= tt "op") (or (= tv "~") (= tv "?"))) true)
|
||||
(else false)))))
|
||||
(define parse-atom-postfix
|
||||
(fn ()
|
||||
@@ -637,6 +649,20 @@
|
||||
((at-op? "!")
|
||||
(begin (advance-tok!)
|
||||
(list :deref (parse-atom-postfix))))
|
||||
;; Labeled/optional arg ~name[:VAL] or ?name[:VAL]
|
||||
;; — drop the label prefix. With colon, parse VAL
|
||||
;; as the arg. Without, the variable named `name`
|
||||
;; (punning) becomes the arg.
|
||||
((or (at-op? "~") (at-op? "?"))
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(let ((nm (ocaml-tok-value
|
||||
(consume! "ident" nil))))
|
||||
(cond
|
||||
((at-op? ":")
|
||||
(begin (advance-tok!)
|
||||
(parse-atom-postfix)))
|
||||
(else (list :var nm))))))
|
||||
(else (parse-atom-postfix)))))
|
||||
(begin (set! head (list :app head arg)) (loop))))))
|
||||
(loop)
|
||||
|
||||
@@ -1396,6 +1396,14 @@ cat > "$TMPFILE" << 'EPOCHS'
|
||||
(epoch 5142)
|
||||
(eval "(ocaml-run-program \"let h (a, b) (c, d) = a * b + c * d ;; h (1, 2) (3, 4)\")")
|
||||
|
||||
;; ── Labeled / optional args (label dropped) ──────────────────
|
||||
(epoch 5150)
|
||||
(eval "(ocaml-run \"let f ~x ~y = x + y in f ~x:3 ~y:7\")")
|
||||
(epoch 5151)
|
||||
(eval "(ocaml-run \"let f ~x ~y = x * y in let x = 4 in let y = 5 in f ~x ~y\")")
|
||||
(epoch 5152)
|
||||
(eval "(ocaml-run \"let f ?x ~y = x + y in f ?x:1 ~y:2\")")
|
||||
|
||||
EPOCHS
|
||||
|
||||
OUTPUT=$(timeout 360 "$SX_SERVER" < "$TMPFILE" 2>/dev/null)
|
||||
@@ -2219,6 +2227,11 @@ check 5140 "top let f (a, b) = a+b" '10'
|
||||
check 5141 "top let g x (a, b) mixed" '6'
|
||||
check 5142 "top let h (a, b) (c, d)" '14'
|
||||
|
||||
# ── Labeled / optional args (label dropped, positional) ─────────
|
||||
check 5150 "f ~x:3 ~y:7 sum" '10'
|
||||
check 5151 "f ~x ~y punning" '20'
|
||||
check 5152 "f ?x:1 ~y:2 (no Some wrap)" '3'
|
||||
|
||||
TOTAL=$((PASS + FAIL))
|
||||
if [ $FAIL -eq 0 ]; then
|
||||
echo "ok $PASS/$TOTAL OCaml-on-SX tests passed"
|
||||
|
||||
Reference in New Issue
Block a user