diff --git a/src/jolt/backend.janet b/src/jolt/backend.janet index 7cea92c..ddac7a8 100644 --- a/src/jolt/backend.janet +++ b/src/jolt/backend.janet @@ -230,11 +230,25 @@ # core fn. Matches numeric semantics; relaxes the non-number checks (a documented # perf-mode divergence, same as the bootstrap's core-renames). (def- native-ops - {"+" '+ "-" '- "*" '* "<" '< ">" '> "<=" '<= ">=" '>= "inc" '++ "dec" '--}) + {"+" '+ "-" '- "*" '* "/" '/ "<" '< ">" '> "<=" '<= ">=" '>= + "inc" '++ "dec" '-- + # verified semantic parity with the jolt fns (incl. negative operands): + # mod is floored, rem (janet %) truncates, / is variadic with (/ x) -> 1/x. + # quot is deliberately ABSENT: janet div floors where Clojure truncates. + "mod" 'mod "rem" '% + # jolt's bit fns are 2-arg (unlike Clojure's variadic), so these emit native + # only at exactly the arity the interpreted fn accepts; bit-not is unary. + "bit-and" 'band "bit-or" 'bor "bit-xor" 'bxor + "bit-shift-left" 'blshift "bit-shift-right" 'brshift "bit-not" 'bnot}) + +(def- unary-ops {'++ true '-- true 'bnot true}) +(def- binary-ops {'mod true '% true 'band true 'bor true 'bxor true + 'blshift true 'brshift true}) (defn- native-op "If fnode is a clojure.core ref (or host ref) to a native-op primitive, return - the Janet op symbol, else nil. inc/dec are unary so only at arity 1." + the Janet op symbol, else nil — only at an arity where the janet op and the + jolt fn agree." [fnode nargs] (def nm (case (fnode :op) :var (when (= "clojure.core" (fnode :ns)) (fnode :name)) @@ -243,7 +257,8 @@ (def op (and nm (get native-ops nm))) (cond (nil? op) nil - (and (or (= op '++) (= op '--)) (not= nargs 1)) nil + (and (get unary-ops op) (not= nargs 1)) nil + (and (get binary-ops op) (not= nargs 2)) nil op)) (defn- emit-invoke [ctx node] diff --git a/test/integration/conformance-test.janet b/test/integration/conformance-test.janet index b9a63d4..a9507a6 100644 --- a/test/integration/conformance-test.janet +++ b/test/integration/conformance-test.janet @@ -119,6 +119,16 @@ ["update-in fnil" "{:a {:b 1}}" "(update-in {} [:a :b] (fnil inc 0))"] ["get-in" "1" "(get-in {:a {:b {:c 1}}} [:a :b :c])"] + ### ---- native-op parity (compile emits janet ops at guarded arities) ---- + ["native mod floored" "2" "(mod -7 3)"] + ["native rem truncated" "-1" "(rem -7 3)"] + ["native unary div" "0.5" "(/ 2)"] + ["native chained div" "1" "(/ 6 3 2)"] + ["native bit-and" "8" "(bit-and 12 10)"] + ["native bit-xor" "6" "(bit-xor 12 10)"] + ["native bit-not" "-6" "(bit-not 5)"] + ["native shifts" "[16 2]" "[(bit-shift-left 4 2) (bit-shift-right 8 2)]"] + ### ---- HIGH: str semantics ---- ["str nil empty" "\"\"" "(str nil)"] ["str concat nil" "\"a1\"" "(str \"a\" 1 nil)"]