diff --git a/.gitignore b/.gitignore index 9eec3c9..033927e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ -bin -doc/repl/glj.wasm +/bin +/doc/repl/glj.wasm +/report.html .direnv # useful to symlink in for context diff --git a/Makefile b/Makefile index aa24e0f..9824bc4 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,29 @@ - -CLOJURE_STDLIB_VERSION := clojure-1.12.1 -STDLIB_ORIGINALS_DIR := scripts/rewrite-core/originals -STDLIB_ORIGINALS := $(shell find $(STDLIB_ORIGINALS_DIR) -name '*.clj') -STDLIB := $(STDLIB_ORIGINALS:scripts/rewrite-core/originals/%=%) -STDLIB_ORIGINALS := $(addprefix scripts/rewrite-core/originals/,$(STDLIB)) -STDLIB_TARGETS := $(addprefix pkg/stdlib/clojure/,$(STDLIB:.clj=.glj)) +# Usage: +# make clean all test GO-VERSION=1.25.1 + +SHELL := bash + +GO-VERSION ?= 1.19.3 +CLOJURE-VERSION ?= 1.12.1 + +CLOJURE-STDLIB-VERSION := clojure-$(CLOJURE-VERSION) +STDLIB-ORIGINALS-DIR := scripts/rewrite-core/originals +STDLIB-ORIGINALS := $(wildcard $(STDLIB-ORIGINALS-DIR)/*.clj) +STDLIB-NAMES := $(STDLIB-ORIGINALS:scripts/rewrite-core/originals/%=%) +STDLIB-ORIGINALS := $(STDLIB-NAMES:%=scripts/rewrite-core/originals/,%) +STDLIB-TARGETS := $(addprefix pkg/stdlib/clojure/,$(STDLIB-NAMES:.clj=.glj)) + +AOT-NAMESPACES := \ + clojure.core \ + clojure.core.async \ + clojure.string \ + clojure.template \ + clojure.test \ + clojure.uuid \ + clojure.walk \ + glojure.go.io \ + glojure.go.types \ + $(EXTRA-AOT-NAMESPACES) OS-TYPE := $(shell bash -c 'echo $$OSTYPE') OS-NAME := \ @@ -23,88 +42,142 @@ OA-linux-arm64 := linux_arm64 OA-linux-int64 := linux_amd64 OA-macos-arm64 := darwin_arm64 OA-macos-int64 := darwin_amd64 -OA := $(OA-$(OS-ARCH)) -GLJ := bin/$(OA)/glj +GLJ-CMD := bin/$(OA-$(OS-ARCH))/glj endif endif -TEST_FILES := $(shell find ./test -name '*.glj' | sort) -TEST_TARGETS := $(addsuffix .test,$(TEST_FILES)) +TEST-GLJ-DIR := test/glojure +TEST-GLJ-FILES := $(shell find $(TEST-GLJ-DIR) -name '*.glj' | sort) +TEST-GLJ-TARGETS := $(addsuffix .test,$(TEST-GLJ-FILES)) +TEST-SUITE-DIR := test/clojure-test-suite +TEST-SUITE-FILE := test-glojure.glj + +GO-PLATFORMS := \ + darwin_arm64 \ + darwin_amd64 \ + linux_arm64 \ + linux_amd64 \ + windows_arm \ + windows_amd64 \ + js_wasm \ + $(EXTRA-GO-PLATFORMS) + +GLJ-IMPORTS=$(foreach platform,$(GO-PLATFORMS) \ + ,pkg/gen/gljimports/gljimports_$(platform).go) -GOPLATFORMS := darwin_arm64 darwin_amd64 linux_arm64 linux_amd64 windows_amd64 windows_arm js_wasm -GLJIMPORTS=$(foreach platform,$(GOPLATFORMS),pkg/gen/gljimports/gljimports_$(platform).go) # wasm should have .wasm suffix; others should not -BINS=$(foreach platform,$(GOPLATFORMS),bin/$(platform)/glj$(if $(findstring wasm,$(platform)),.wasm,)) +GLJ-BINS=$(foreach platform,$(GO-PLATFORMS) \ + ,bin/$(platform)/glj$(if $(findstring wasm,$(platform)),.wasm,)) + +GO-CMD := go$(GO-VERSION) + +ALL-TARGETS := \ + $(if $(force),update-clojure-sources) \ + stdlib-targets \ + generate \ + aot \ + glj-imports \ + glj-bins \ -# eventually, support multiple minor versions -GO_VERSION := 1.19.3 -GO_CMD := go$(GO_VERSION) +#------------------------------------------------------------------------------- +default: all -.PHONY: all -all: gocmd $(STDLIB_TARGETS) go-generate aot $(GLJIMPORTS) $(BINS) +# Dummy target for commands like: +# make all force=1 +# make stdlib-targets force=1 +force: + +all: $(ALL-TARGETS) -.PHONY: gocmd gocmd: - @$(GO_CMD) version 2>&1 > /dev/null || \ - (go install "golang.org/dl/$(GO_CMD)@latest" && \ - $(GO_CMD) download > /dev/null && $(GO_CMD) version > /dev/null) + @$(GO-CMD) version &> /dev/null || { \ + (go install "golang.org/dl/$(GO-CMD)@latest" && \ + $(GO-CMD) download > /dev/null && \ + $(GO-CMD) version > /dev/null); } + +stdlib-targets: $(STDLIB-TARGETS) -.PHONY: go-generate generate: - @go generate ./... + go generate ./... -.PHONY: aot -aot: gocmd $(STDLIB_TARGETS) - @echo "(map compile '[clojure.core clojure.core.async clojure.string clojure.template clojure.test clojure.uuid clojure.walk glojure.go.types glojure.go.io])" | \ - GLOJURE_USE_AOT=false GLOJURE_STDLIB_PATH=./pkg/stdlib $(GO_CMD) run -tags glj_no_aot_stdlib ./cmd/glj +aot: gocmd $(STDLIB-TARGETS) + GLOJURE_USE_AOT=false \ + GLOJURE_STDLIB_PATH=./pkg/stdlib \ + $(GO-CMD) run -tags glj_no_aot_stdlib ./cmd/glj \ + <<<"(map compile '[$(AOT-NAMESPACES)])" -.PHONY: build -build: $(GLJ) +glj-imports: $(GLJ-IMPORTS) -.PHONY: clean -clean: - $(RM) -r bin/ +glj-bins: $(GLJ-BINS) -pkg/gen/gljimports/gljimports_%.go: ./scripts/gen-gljimports.sh ./cmd/gen-import-interop/main.go ./internal/genpkg/genpkg.go \ - $(wildcard ./pkg/lang/*.go) $(wildcard ./pkg/runtime/*.go) +build: $(GLJ-CMD) + +clean: + $(RM) report.html + $(RM) -r bin/ scripts/rewrite-core/.cpcache/ + +pkg/gen/gljimports/gljimports_%.go: \ + ./scripts/gen-gljimports.sh \ + ./cmd/gen-import-interop/main.go \ + ./internal/genpkg/genpkg.go \ + $(wildcard ./pkg/lang/*.go) \ + $(wildcard ./pkg/runtime/*.go) \ + $(if $(force),force) @echo "Generating $@" - @./scripts/gen-gljimports.sh $@ $* $(GO_CMD) + ./scripts/gen-gljimports.sh $@ $* $(GO-CMD) -pkg/stdlib/clojure/%.glj: scripts/rewrite-core/originals/%.clj scripts/rewrite-core/run.sh scripts/rewrite-core/rewrite.clj +pkg/stdlib/clojure/%.glj: \ + scripts/rewrite-core/originals/%.clj \ + scripts/rewrite-core/run.sh \ + scripts/rewrite-core/rewrite.clj \ + $(if $(force),force) @echo "Rewriting $< to $@" @mkdir -p $(dir $@) - @scripts/rewrite-core/run.sh $< > $@ + scripts/rewrite-core/run.sh $< > $@ -bin/%/glj: generate $(wildcard ./cmd/glj/*.go) $(wildcard ./pkg/**/*.go) $(wildcard ./internal/**/*.go) +bin/%/glj: generate \ + $(wildcard ./cmd/glj/*.go) \ + $(wildcard ./pkg/**/*.go) \ + $(wildcard ./internal/**/*.go) \ + $(if $(force),force) @echo "Building $@" @mkdir -p $(dir $@) - @scripts/build-glj.sh $@ $* + scripts/build-glj.sh $@ $* -bin/%/glj.wasm: $(wildcard ./cmd/glj/*.go) $(wildcard ./pkg/**/*.go) $(wildcard ./internal/**/*.go) +bin/%/glj.wasm: \ + $(wildcard ./cmd/glj/*.go) \ + $(wildcard ./pkg/**/*.go) \ + $(wildcard ./internal/**/*.go) \ + $(if $(force),force) @echo "Building $@" @mkdir -p $(dir $@) - @scripts/build-glj.sh $@ $* + scripts/build-glj.sh $@ $* -.PHONY: vet vet: - @go vet ./... - -.PHONY: $(TEST_TARGETS) -$(TEST_TARGETS): gocmd $(GLJ) - @$(GLJ) $(basename $@) + go vet ./... .PHONY: test -test: $(TEST_TARGETS) # vet - vet is disabled until we fix errors in generated code - @cd test/clojure-test-suite && \ - ../../$(GLJ) test-glojure.glj --expect-failures 38 --expect-errors 151 2>/dev/null +# vet is disabled until we fix errors in generated code +test: test-glj test-suite # vet + +test-glj: $(TEST-GLJ-TARGETS) + +test-suite: $(GLJ-CMD) + cd $(TEST-SUITE-DIR) && \ + $(abspath $<) $(TEST-SUITE-FILE) \ + --expect-failures 38 \ + --expect-errors 151 \ + 2>/dev/null + +$(TEST-GLJ-TARGETS): $(GLJ-CMD) + $< $(basename $@) -.PHONY: format format: @if go fmt ./... | grep -q ''; then \ echo "Files were formatted. Please commit the changes."; \ exit 1; \ fi -.PHONY: update-clojure-sources update-clojure-sources: - @scripts/rewrite-core/update-clojure-sources.sh $(CLOJURE_STDLIB_VERSION) + scripts/rewrite-core/update-clojure-sources.sh \ + $(CLOJURE-STDLIB-VERSION) diff --git a/pkg/ast/ast.go b/pkg/ast/ast.go index 343d7d7..2586f48 100644 --- a/pkg/ast/ast.go +++ b/pkg/ast/ast.go @@ -190,21 +190,21 @@ type ( } CaseNode struct { - Test *Node // The expression to test - Shift int64 // Bit shift for hash compaction - Mask int64 // Bit mask for hash compaction - TestType interface{} // Keyword: :int, :hash-identity, or :hash-equiv - SwitchType interface{} // Keyword: :compact or :sparse - Default *Node // Default expression - Entries []CaseEntry // Case entries - SkipCheck map[int64]bool // Set of keys with collisions + Test *Node // The expression to test + Shift int64 // Bit shift for hash compaction + Mask int64 // Bit mask for hash compaction + TestType interface{} // Keyword: :int, :hash-identity, or :hash-equiv + SwitchType interface{} // Keyword: :compact or :sparse + Default *Node // Default expression + Entries []CaseEntry // Case entries + SkipCheck map[int64]bool // Set of keys with collisions } CaseEntry struct { - Key int64 // Map key (int value or shifted/masked hash) - TestConstant *Node // Original test constant (nil for collisions) - ResultExpr *Node // Result expression or condp for collisions - HasCollision bool // Whether this is a collision case + Key int64 // Map key (int value or shifted/masked hash) + TestConstant *Node // Original test constant (nil for collisions) + ResultExpr *Node // Result expression or condp for collisions + HasCollision bool // Whether this is a collision case } TheVarNode struct { diff --git a/pkg/stdlib/clojure/walk/loader.go b/pkg/stdlib/clojure/walk/loader.go index f31bd0e..b8a8fed 100644 --- a/pkg/stdlib/clojure/walk/loader.go +++ b/pkg/stdlib/clojure/walk/loader.go @@ -191,7 +191,7 @@ func LoadNS() { _ = v5 var tmp6 any { // let - // let binding "vec__1061" + // let binding "vec__1089" var v7 any = v5 _ = v7 // let binding "k" @@ -539,7 +539,7 @@ func LoadNS() { _ = v5 var tmp6 any { // let - // let binding "vec__1065" + // let binding "vec__1093" var v7 any = v5 _ = v7 // let binding "k" diff --git a/pkg/stdlib/glojure/go/io/loader.go b/pkg/stdlib/glojure/go/io/loader.go index ac5e80b..021f9df 100644 --- a/pkg/stdlib/glojure/go/io/loader.go +++ b/pkg/stdlib/glojure/go/io/loader.go @@ -285,7 +285,7 @@ func LoadNS() { tmp8 := lang.Apply(tmp7, nil) var v9 any = tmp8 _ = v9 - // let binding "vec__1098" + // let binding "vec__1123" var tmp10 any tmp11 := checkDerefVar(var_clojure_DOT_core_vector_QMARK_) tmp12 := lang.Apply(tmp11, []any{v9}) @@ -312,22 +312,22 @@ func LoadNS() { } var v23 any = tmp10 _ = v23 - // let binding "vec__1101" + // let binding "vec__1126" tmp24 := checkDerefVar(var_clojure_DOT_core_nth) tmp25 := lang.Apply(tmp24, []any{v23, int64(0), nil}) var v26 any = tmp25 _ = v26 - // let binding "seq__1102" + // let binding "seq__1127" tmp27 := checkDerefVar(var_clojure_DOT_core_seq) tmp28 := lang.Apply(tmp27, []any{v26}) var v29 any = tmp28 _ = v29 - // let binding "first__1103" + // let binding "first__1128" tmp30 := checkDerefVar(var_clojure_DOT_core_first) tmp31 := lang.Apply(tmp30, []any{v29}) var v32 any = tmp31 _ = v32 - // let binding "seq__1102" + // let binding "seq__1127" tmp33 := checkDerefVar(var_clojure_DOT_core_next) tmp34 := lang.Apply(tmp33, []any{v29}) var v35 any = tmp34 @@ -380,7 +380,7 @@ func LoadNS() { tmp7 := lang.Apply(tmp6, nil) var v8 any = tmp7 _ = v8 - // let binding "vec__1092" + // let binding "vec__1117" var tmp9 any tmp10 := checkDerefVar(var_clojure_DOT_core_vector_QMARK_) tmp11 := lang.Apply(tmp10, []any{v8}) @@ -407,22 +407,22 @@ func LoadNS() { } var v22 any = tmp9 _ = v22 - // let binding "vec__1095" + // let binding "vec__1120" tmp23 := checkDerefVar(var_clojure_DOT_core_nth) tmp24 := lang.Apply(tmp23, []any{v22, int64(0), nil}) var v25 any = tmp24 _ = v25 - // let binding "seq__1096" + // let binding "seq__1121" tmp26 := checkDerefVar(var_clojure_DOT_core_seq) tmp27 := lang.Apply(tmp26, []any{v25}) var v28 any = tmp27 _ = v28 - // let binding "first__1097" + // let binding "first__1122" tmp29 := checkDerefVar(var_clojure_DOT_core_first) tmp30 := lang.Apply(tmp29, []any{v28}) var v31 any = tmp30 _ = v31 - // let binding "seq__1096" + // let binding "seq__1121" tmp32 := checkDerefVar(var_clojure_DOT_core_next) tmp33 := lang.Apply(tmp32, []any{v28}) var v34 any = tmp33 @@ -534,7 +534,7 @@ func LoadNS() { tmp14 := lang.Apply(http7.NewRequest, []any{http7.MethodGet, tmp13, nil}) var v15 any = tmp14 _ = v15 - // let binding "vec__1071" + // let binding "vec__1096" var tmp16 any tmp17 := checkDerefVar(var_clojure_DOT_core_vector_QMARK_) tmp18 := lang.Apply(tmp17, []any{v15}) @@ -561,22 +561,22 @@ func LoadNS() { } var v29 any = tmp16 _ = v29 - // let binding "vec__1074" + // let binding "vec__1099" tmp30 := checkDerefVar(var_clojure_DOT_core_nth) tmp31 := lang.Apply(tmp30, []any{v29, int64(0), nil}) var v32 any = tmp31 _ = v32 - // let binding "seq__1075" + // let binding "seq__1100" tmp33 := checkDerefVar(var_clojure_DOT_core_seq) tmp34 := lang.Apply(tmp33, []any{v32}) var v35 any = tmp34 _ = v35 - // let binding "first__1076" + // let binding "first__1101" tmp36 := checkDerefVar(var_clojure_DOT_core_first) tmp37 := lang.Apply(tmp36, []any{v35}) var v38 any = tmp37 _ = v38 - // let binding "seq__1075" + // let binding "seq__1100" tmp39 := checkDerefVar(var_clojure_DOT_core_next) tmp40 := lang.Apply(tmp39, []any{v35}) var v41 any = tmp40 @@ -627,7 +627,7 @@ func LoadNS() { tmp15 := lang.Apply(tmp14, []any{v12}) var v16 any = tmp15 _ = v16 - // let binding "vec__1077" + // let binding "vec__1102" var tmp17 any tmp18 := checkDerefVar(var_clojure_DOT_core_vector_QMARK_) tmp19 := lang.Apply(tmp18, []any{v16}) @@ -654,22 +654,22 @@ func LoadNS() { } var v30 any = tmp17 _ = v30 - // let binding "vec__1080" + // let binding "vec__1105" tmp31 := checkDerefVar(var_clojure_DOT_core_nth) tmp32 := lang.Apply(tmp31, []any{v30, int64(0), nil}) var v33 any = tmp32 _ = v33 - // let binding "seq__1081" + // let binding "seq__1106" tmp34 := checkDerefVar(var_clojure_DOT_core_seq) tmp35 := lang.Apply(tmp34, []any{v33}) var v36 any = tmp35 _ = v36 - // let binding "first__1082" + // let binding "first__1107" tmp37 := checkDerefVar(var_clojure_DOT_core_first) tmp38 := lang.Apply(tmp37, []any{v36}) var v39 any = tmp38 _ = v39 - // let binding "seq__1081" + // let binding "seq__1106" tmp40 := checkDerefVar(var_clojure_DOT_core_next) tmp41 := lang.Apply(tmp40, []any{v36}) var v42 any = tmp41 @@ -779,7 +779,7 @@ func LoadNS() { _ = v2 var tmp3 any { // let - // let binding "vec__1083" + // let binding "vec__1108" tmp4 := lang.Apply(url5.ParseRequestURI, []any{v1}) var v5 any = tmp4 _ = v5 @@ -802,7 +802,7 @@ func LoadNS() { tmp15 := lang.Apply(os6.Open, []any{v1}) var v16 any = tmp15 _ = v16 - // let binding "vec__1086" + // let binding "vec__1111" var tmp17 any tmp18 := checkDerefVar(var_clojure_DOT_core_vector_QMARK_) tmp19 := lang.Apply(tmp18, []any{v16}) @@ -829,22 +829,22 @@ func LoadNS() { } var v30 any = tmp17 _ = v30 - // let binding "vec__1089" + // let binding "vec__1114" tmp31 := checkDerefVar(var_clojure_DOT_core_nth) tmp32 := lang.Apply(tmp31, []any{v30, int64(0), nil}) var v33 any = tmp32 _ = v33 - // let binding "seq__1090" + // let binding "seq__1115" tmp34 := checkDerefVar(var_clojure_DOT_core_seq) tmp35 := lang.Apply(tmp34, []any{v33}) var v36 any = tmp35 _ = v36 - // let binding "first__1091" + // let binding "first__1116" tmp37 := checkDerefVar(var_clojure_DOT_core_first) tmp38 := lang.Apply(tmp37, []any{v36}) var v39 any = tmp38 _ = v39 - // let binding "seq__1090" + // let binding "seq__1115" tmp40 := checkDerefVar(var_clojure_DOT_core_next) tmp41 := lang.Apply(tmp40, []any{v36}) var v42 any = tmp41 @@ -1496,7 +1496,7 @@ func LoadNS() { tmp10 := lang.Apply(io4.Copy, []any{v7, v6}) var v11 any = tmp10 _ = v11 - // let binding "vec__1104" + // let binding "vec__1129" var tmp12 any tmp13 := checkDerefVar(var_clojure_DOT_core_vector_QMARK_) tmp14 := lang.Apply(tmp13, []any{v11}) @@ -1523,22 +1523,22 @@ func LoadNS() { } var v25 any = tmp12 _ = v25 - // let binding "vec__1107" + // let binding "vec__1132" tmp26 := checkDerefVar(var_clojure_DOT_core_nth) tmp27 := lang.Apply(tmp26, []any{v25, int64(0), nil}) var v28 any = tmp27 _ = v28 - // let binding "seq__1108" + // let binding "seq__1133" tmp29 := checkDerefVar(var_clojure_DOT_core_seq) tmp30 := lang.Apply(tmp29, []any{v28}) var v31 any = tmp30 _ = v31 - // let binding "first__1109" + // let binding "first__1134" tmp32 := checkDerefVar(var_clojure_DOT_core_first) tmp33 := lang.Apply(tmp32, []any{v31}) var v34 any = tmp33 _ = v34 - // let binding "seq__1108" + // let binding "seq__1133" tmp35 := checkDerefVar(var_clojure_DOT_core_next) tmp36 := lang.Apply(tmp35, []any{v31}) var v37 any = tmp36 diff --git a/pkg/stdlib/glojure/go/types/loader.go b/pkg/stdlib/glojure/go/types/loader.go index 57e20e3..efa2f24 100644 --- a/pkg/stdlib/glojure/go/types/loader.go +++ b/pkg/stdlib/glojure/go/types/loader.go @@ -1144,7 +1144,7 @@ func LoadNS() { _ = tmp3 var tmp9 any { // let - // let binding "vec__1068" + // let binding "vec__1135" tmp10 := lang.Apply(parser5.ParseExpr, []any{v2}) var v11 any = tmp10 _ = v11