Initial commit: Jolt — Clojure interpreter on Janet
- PEG-based Clojure reader (symbols, keywords, numbers, strings, lists, vectors, maps, sets, quote forms, reader macros, metadata) - Tree-walking evaluator (quote, do, if, def, fn*, let*, loop*/recur, syntax-quote/unquote/unquote-splicing, macro system, ns/require/in-ns) - 95+ clojure.core functions (predicates, math, collections, seq ops, higher-order, atoms, I/O) - Public API (init, eval-string, eval-string*) - REPL (jolt/main.janet) - 7 test suites, all green - MIT license
This commit is contained in:
commit
cdcf569506
16 changed files with 2696 additions and 0 deletions
132
test/reader-test.janet
Normal file
132
test/reader-test.janet
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
(use ../src/jolt/reader)
|
||||
|
||||
# Helper: create a symbol
|
||||
(defn sym [name]
|
||||
(let [slash (string/find "/" name)]
|
||||
(if slash
|
||||
{:jolt/type :symbol
|
||||
:ns (string/slice name 0 slash)
|
||||
:name (string/slice name (+ slash 1))}
|
||||
{:jolt/type :symbol
|
||||
:ns nil
|
||||
:name name})))
|
||||
|
||||
# Symbols
|
||||
(assert (deep= (sym "foo") (parse-string "foo"))
|
||||
"bare symbol")
|
||||
(assert (deep= (sym "foo/bar") (parse-string "foo/bar"))
|
||||
"namespaced symbol")
|
||||
(assert (deep= (sym "+") (parse-string "+"))
|
||||
"operator symbol")
|
||||
(assert (deep= (sym "->foo") (parse-string "->foo"))
|
||||
"arrow symbol")
|
||||
|
||||
# Keywords
|
||||
(assert (= :foo (parse-string ":foo"))
|
||||
"bare keyword")
|
||||
(assert (= :foo/bar (parse-string "::foo/bar"))
|
||||
"auto-resolved keyword")
|
||||
(assert (= :foo/bar (parse-string ":foo/bar"))
|
||||
"namespaced keyword")
|
||||
|
||||
# Numbers
|
||||
(assert (= 1 (parse-string "1"))
|
||||
"integer")
|
||||
(assert (= -42 (parse-string "-42"))
|
||||
"negative integer")
|
||||
(assert (= 3.14 (parse-string "3.14"))
|
||||
"float")
|
||||
|
||||
# Strings
|
||||
(assert (= "hello" (parse-string "\"hello\""))
|
||||
"simple string")
|
||||
|
||||
# Nil, booleans
|
||||
(assert (= nil (parse-string "nil"))
|
||||
"nil")
|
||||
(assert (= true (parse-string "true"))
|
||||
"true")
|
||||
(assert (= false (parse-string "false"))
|
||||
"false")
|
||||
|
||||
# Lists → Janet arrays (to distinguish from vectors)
|
||||
(assert (array? (parse-string "(1 2 3)"))
|
||||
"list produces array")
|
||||
(assert (deep= @[1 2 3] (parse-string "(1 2 3)"))
|
||||
"simple list")
|
||||
|
||||
# Vectors → Janet tuples
|
||||
(assert (tuple? (parse-string "[1 2 3]"))
|
||||
"vector produces tuple")
|
||||
(assert (deep= [1 2 3] (parse-string "[1 2 3]"))
|
||||
"simple vector")
|
||||
|
||||
# Maps → Janet structs
|
||||
(let [m (parse-string "{:a 1 :b 2}")]
|
||||
(assert (struct? m) "map is struct")
|
||||
(assert (= 1 (m :a)) "map key lookup"))
|
||||
|
||||
# Sets → tagged with :jolt/set
|
||||
(let [form (parse-string "#{1 2 3}")]
|
||||
(assert (struct? form) "set is struct")
|
||||
(assert (= :jolt/set (form :jolt/type)) "set type tag"))
|
||||
|
||||
# Quote and shorthand
|
||||
(assert (deep= @[(sym "quote") (sym "x")] (parse-string "'x"))
|
||||
"quote shorthand")
|
||||
(assert (deep= @[(sym "syntax-quote") (sym "x")] (parse-string "`x"))
|
||||
"syntax-quote")
|
||||
(assert (deep= @[(sym "unquote") (sym "x")] (parse-string "~x"))
|
||||
"unquote")
|
||||
(assert (deep= @[(sym "unquote-splicing") (sym "x")] (parse-string "~@x"))
|
||||
"unquote-splicing")
|
||||
(assert (deep= @[(sym "deref") (sym "x")] (parse-string "@x"))
|
||||
"deref shorthand")
|
||||
|
||||
# Metadata
|
||||
(let [form (parse-string "^:meta x")]
|
||||
(assert (array? form) "metadata is array")
|
||||
(assert (deep= @[(sym "with-meta") (sym "x") :meta] form)
|
||||
"metadata form"))
|
||||
|
||||
# Comments (skip to end of line)
|
||||
(assert (= 42 (parse-string "; comment\n42"))
|
||||
"comment then form")
|
||||
|
||||
# Discard #_
|
||||
(assert (= 42 (parse-string "#_ (ignored 1 2) 42"))
|
||||
"discard skips next form")
|
||||
|
||||
# Anonymous function #()
|
||||
(let [form (parse-string "#(+ %1 %2)")]
|
||||
(assert (array? form) "fn form is array")
|
||||
(assert (deep= (sym "fn*") (in form 0)) "first element is fn*"))
|
||||
|
||||
# Nested forms
|
||||
(let [form (parse-string "(+ 1 (* 2 3))")]
|
||||
(assert (array? form) "outer list is array")
|
||||
(assert (deep= (sym "+") (in form 0)) "+ is first")
|
||||
(assert (= 1 (in form 1)) "1 is second")
|
||||
(assert (array? (in form 2)) "nested list is array"))
|
||||
|
||||
# Multiple forms: parse-next
|
||||
(let [[form1 rest-str] (parse-next "(1 2) [3 4]")]
|
||||
(assert (deep= @[1 2] form1) "first form is list")
|
||||
(let [[form2 _] (parse-next rest-str)]
|
||||
(assert (deep= [3 4] form2) "second form is vector")))
|
||||
|
||||
# Reader conditional (basic #? support)
|
||||
(let [form (parse-string "#?(:clj 1 :cljs 2)")]
|
||||
(assert (struct? form) "reader conditional")
|
||||
(assert (= :jolt/reader-conditional (form :jolt/type)) "correct type"))
|
||||
|
||||
# Characters
|
||||
(let [form (parse-string "\\newline")]
|
||||
(assert (struct? form) "char is struct")
|
||||
(assert (= :char (form :jolt/type)) "char type")
|
||||
(assert (= "newline" (form :name)) "char name"))
|
||||
|
||||
(let [form (parse-string "\\a")]
|
||||
(assert (= "a" (form :name)) "simple char name"))
|
||||
|
||||
(print "All reader tests passed!")
|
||||
Loading…
Add table
Add a link
Reference in a new issue