diff --git a/jolt-core/jolt/analyzer.clj b/jolt-core/jolt/analyzer.clj index d5d016d..d820318 100644 --- a/jolt-core/jolt/analyzer.clj +++ b/jolt-core/jolt/analyzer.clj @@ -15,12 +15,12 @@ declared — the bootstrap compiles forward refs through var cells, but keeping them to one keeps the compiled namespace simple." (:require [jolt.ir :refer [const local var-ref host-ref if-node do-node invoke - def-node let-node fn-node vector-node map-node + def-node let-node fn-node vector-node map-node set-node quote-node throw-node]] [jolt.host :refer [form-sym? form-sym-name form-sym-ns form-list? form-vec? form-map? form-set? form-char? form-literal? form-elements form-vec-items - form-map-pairs form-special? compile-ns + form-map-pairs form-set-items form-special? compile-ns form-macro? form-expand-1 resolve-global form-sym-meta host-intern! form-syntax-quote-lower]])) @@ -207,6 +207,6 @@ (form-map? form) (map-node (mapv (fn [p] [(analyze ctx (first p) env) (analyze ctx (second p) env)]) (form-map-pairs form))) - (form-set? form) (uncompilable "set literal") + (form-set? form) (set-node (mapv #(analyze ctx % env) (form-set-items form))) (form-list? form) (analyze-list ctx form env) :else (uncompilable "unsupported form")))) diff --git a/src/jolt/backend.janet b/src/jolt/backend.janet index d1d1961..fe797cb 100644 --- a/src/jolt/backend.janet +++ b/src/jolt/backend.janet @@ -230,6 +230,12 @@ (array/push args (emit ctx (in p 1)))) (tuple/slice args)) +# A set literal: build (make-phs e1 e2 …) so each element is evaluated at runtime +# then the persistent set is constructed — mirrors compiler.janet's emit-set-expr. +(defn- emit-set [ctx node] + (def items (map |(emit ctx $) (vview (node :items)))) + (tuple/slice (array/concat @[phm/make-phs] items))) + (set emit (fn emit [ctx raw] (def node (norm-node raw)) @@ -259,6 +265,7 @@ :invoke (emit-invoke ctx node) :vector (emit-vector ctx node) :map (emit-map ctx node) + :set (emit-set ctx node) :quote ['quote (node :form)] (error (string "backend: unhandled op " (node :op)))))) diff --git a/test/integration/conformance-test.janet b/test/integration/conformance-test.janet index 81fa206..368d387 100644 --- a/test/integration/conformance-test.janet +++ b/test/integration/conformance-test.janet @@ -50,6 +50,12 @@ ["map as fn default" "99" "({:a 1} :z 99)"] ["set as fn" "2" "(#{1 2 3} 2)"] ["set as fn miss" "nil" "(#{1 2 3} 9)"] + # set literals compile (Stage 1 Task 1): computed elements are each evaluated + # then the persistent set is built, matching the interpreter. + ["set literal computed" "true" "(= #{1 2} #{(inc 0) 2})"] + ["empty set literal" "true" "(empty? #{})"] + ["set literal count" "3" "(count #{1 2 3})"] + ["set literal in let" "true" "(let [x 5] (= #{5 6} #{x (inc x)}))"] ["keyword as fn" "1" "(:a {:a 1})"] ["map fn over coll" "(quote (1 3))" "(map {:a 1 :b 3} [:a :b])"]