Recover agent-loop progress: lua/prolog/forth/erlang/haskell phases 1-2
Salvaged from worktree-agent-* branches killed during sx-tree MCP outage: - lua: tokenizer + parser + phase-2 transpile (~157 tests) - prolog: tokenizer + parser + unification (72 tests, plan update lost to WIP) - forth: phase-1 reader/interpreter + phase-2 colon/VARIABLE (134 tests) - erlang: tokenizer + parser (114 tests) - haskell: tokenizer + parse tests (43 tests) Cherry-picked file contents only, not branch history, to avoid pulling in unrelated ocaml-vm merge commits that were in those branches' bases.
This commit is contained in:
215
lib/prolog/tests/parse.sx
Normal file
215
lib/prolog/tests/parse.sx
Normal file
@@ -0,0 +1,215 @@
|
||||
;; lib/prolog/tests/parse.sx — parser unit tests
|
||||
;;
|
||||
;; Run: bash lib/prolog/tests/run-parse.sh
|
||||
;; Or via sx-server: (load "lib/prolog/tokenizer.sx") (load "lib/prolog/parser.sx")
|
||||
;; (load "lib/prolog/tests/parse.sx") (pl-parse-tests-run!)
|
||||
|
||||
(define pl-test-count 0)
|
||||
(define pl-test-pass 0)
|
||||
(define pl-test-fail 0)
|
||||
(define pl-test-failures (list))
|
||||
|
||||
(define
|
||||
pl-test!
|
||||
(fn
|
||||
(name got expected)
|
||||
(do
|
||||
(set! pl-test-count (+ pl-test-count 1))
|
||||
(if
|
||||
(= got expected)
|
||||
(set! pl-test-pass (+ pl-test-pass 1))
|
||||
(do
|
||||
(set! pl-test-fail (+ pl-test-fail 1))
|
||||
(append!
|
||||
pl-test-failures
|
||||
(str name "\n expected: " expected "\n got: " got)))))))
|
||||
|
||||
;; Atoms & variables
|
||||
(pl-test!
|
||||
"atom fact"
|
||||
(pl-parse "foo.")
|
||||
(list (list "clause" (list "atom" "foo") (list "atom" "true"))))
|
||||
|
||||
(pl-test! "number literal" (pl-parse-goal "42") (list "num" 42))
|
||||
|
||||
(pl-test!
|
||||
"negative number — not supported yet (parsed as op atom + num)"
|
||||
(pl-parse-goal "-5")
|
||||
(list "atom" "-"))
|
||||
|
||||
(pl-test! "variable" (pl-parse-goal "X") (list "var" "X"))
|
||||
|
||||
(pl-test!
|
||||
"underscore variable"
|
||||
(pl-parse-goal "_Ignored")
|
||||
(list "var" "_Ignored"))
|
||||
|
||||
(pl-test! "anonymous variable" (pl-parse-goal "_") (list "var" "_"))
|
||||
|
||||
(pl-test!
|
||||
"compound 1-arg"
|
||||
(pl-parse-goal "foo(a)")
|
||||
(list "compound" "foo" (list (list "atom" "a"))))
|
||||
|
||||
(pl-test!
|
||||
"compound 3-args mixed"
|
||||
(pl-parse-goal "p(X, 1, hello)")
|
||||
(list
|
||||
"compound"
|
||||
"p"
|
||||
(list (list "var" "X") (list "num" 1) (list "atom" "hello"))))
|
||||
|
||||
(pl-test!
|
||||
"nested compound"
|
||||
(pl-parse-goal "f(g(X), h(Y, Z))")
|
||||
(list
|
||||
"compound"
|
||||
"f"
|
||||
(list
|
||||
(list "compound" "g" (list (list "var" "X")))
|
||||
(list "compound" "h" (list (list "var" "Y") (list "var" "Z"))))))
|
||||
|
||||
;; Lists
|
||||
(pl-test! "empty list" (pl-parse-goal "[]") (list "atom" "[]"))
|
||||
|
||||
(pl-test!
|
||||
"single-element list"
|
||||
(pl-parse-goal "[a]")
|
||||
(list "compound" "." (list (list "atom" "a") (list "atom" "[]"))))
|
||||
|
||||
(pl-test!
|
||||
"three-element list"
|
||||
(pl-parse-goal "[1, 2, 3]")
|
||||
(list
|
||||
"compound"
|
||||
"."
|
||||
(list
|
||||
(list "num" 1)
|
||||
(list
|
||||
"compound"
|
||||
"."
|
||||
(list
|
||||
(list "num" 2)
|
||||
(list "compound" "." (list (list "num" 3) (list "atom" "[]"))))))))
|
||||
|
||||
(pl-test!
|
||||
"head-tail list"
|
||||
(pl-parse-goal "[H|T]")
|
||||
(list "compound" "." (list (list "var" "H") (list "var" "T"))))
|
||||
|
||||
(pl-test!
|
||||
"two-head-tail list"
|
||||
(pl-parse-goal "[A, B|T]")
|
||||
(list
|
||||
"compound"
|
||||
"."
|
||||
(list
|
||||
(list "var" "A")
|
||||
(list "compound" "." (list (list "var" "B") (list "var" "T"))))))
|
||||
|
||||
;; Clauses
|
||||
(pl-test!
|
||||
"fact"
|
||||
(pl-parse "parent(tom, bob).")
|
||||
(list
|
||||
(list
|
||||
"clause"
|
||||
(list
|
||||
"compound"
|
||||
"parent"
|
||||
(list (list "atom" "tom") (list "atom" "bob")))
|
||||
(list "atom" "true"))))
|
||||
|
||||
(pl-test!
|
||||
"rule with single-goal body"
|
||||
(pl-parse "q(X) :- p(X).")
|
||||
(list
|
||||
(list
|
||||
"clause"
|
||||
(list "compound" "q" (list (list "var" "X")))
|
||||
(list "compound" "p" (list (list "var" "X"))))))
|
||||
|
||||
(pl-test!
|
||||
"rule with conjunctive body"
|
||||
(pl-parse "r(X, Y) :- p(X), q(Y).")
|
||||
(list
|
||||
(list
|
||||
"clause"
|
||||
(list "compound" "r" (list (list "var" "X") (list "var" "Y")))
|
||||
(list
|
||||
"compound"
|
||||
","
|
||||
(list
|
||||
(list "compound" "p" (list (list "var" "X")))
|
||||
(list "compound" "q" (list (list "var" "Y"))))))))
|
||||
|
||||
;; Cut in body
|
||||
(pl-test!
|
||||
"cut in body"
|
||||
(pl-parse "foo(X) :- p(X), !, q(X).")
|
||||
(list
|
||||
(list
|
||||
"clause"
|
||||
(list "compound" "foo" (list (list "var" "X")))
|
||||
(list
|
||||
"compound"
|
||||
","
|
||||
(list
|
||||
(list "compound" "p" (list (list "var" "X")))
|
||||
(list
|
||||
"compound"
|
||||
","
|
||||
(list
|
||||
(list "cut")
|
||||
(list "compound" "q" (list (list "var" "X"))))))))))
|
||||
|
||||
;; Symbolic-atom compound terms (phase 1 form)
|
||||
(pl-test!
|
||||
"= as compound"
|
||||
(pl-parse-goal "=(X, 5)")
|
||||
(list "compound" "=" (list (list "var" "X") (list "num" 5))))
|
||||
|
||||
(pl-test!
|
||||
"is with +"
|
||||
(pl-parse-goal "is(Y, +(X, 1))")
|
||||
(list
|
||||
"compound"
|
||||
"is"
|
||||
(list
|
||||
(list "var" "Y")
|
||||
(list "compound" "+" (list (list "var" "X") (list "num" 1))))))
|
||||
|
||||
;; Strings
|
||||
(pl-test!
|
||||
"double-quoted string"
|
||||
(pl-parse-goal "\"hello\"")
|
||||
(list "str" "hello"))
|
||||
|
||||
;; Single-quoted atom
|
||||
(pl-test!
|
||||
"quoted atom"
|
||||
(pl-parse-goal "'Hello World'")
|
||||
(list "atom" "Hello World"))
|
||||
|
||||
;; Multi-clause program
|
||||
(pl-test!
|
||||
"append program"
|
||||
(len
|
||||
(pl-parse "append([], L, L).\nappend([H|T], L, [H|R]) :- append(T, L, R).\n"))
|
||||
2)
|
||||
|
||||
;; Comments
|
||||
(pl-test!
|
||||
"line comment ignored"
|
||||
(pl-parse "foo.\n% this is a comment\nbar.")
|
||||
(list
|
||||
(list "clause" (list "atom" "foo") (list "atom" "true"))
|
||||
(list "clause" (list "atom" "bar") (list "atom" "true"))))
|
||||
|
||||
(pl-test!
|
||||
"block comment ignored"
|
||||
(pl-parse "/* hello */\nfoo.")
|
||||
(list (list "clause" (list "atom" "foo") (list "atom" "true"))))
|
||||
|
||||
;; ── Runner ───────────────────────────────────────────────────────
|
||||
(define pl-parse-tests-run! (fn () {:failed pl-test-fail :passed pl-test-pass :total pl-test-count :failures pl-test-failures}))
|
||||
Reference in New Issue
Block a user