Skip to content

Commit

Permalink
Version 1.2.0: shrinks, nbb/shadow-cljs, cleanups
Browse files Browse the repository at this point in the history
All:
- Implements a number of miscellaneous shrinks across all three
  implementations.
- Change "ARGS" command line parameter variable to "argv"
- Remove "load" definition and use "slurp -> read -> eval" instead (more
  efficient compressing)
- Update copyrights to 2024.

cljs:
- Drop lumo support and use nbb instead.
- Switch cljs full compilation mode to use shadow-cljs.
    - Add cljs/shadow-cljs.edn with builds for all steps.
    - By default use release mode in the Makefile which compiles into
      a standalone *.js file (although it's quite slow to build).
- add babashka vs shadow-cljs reader macros for core ns hoisting. During
  shrinking (which is only for nbb mode) sed out the regular :cljs
  reader macro.
- use nbb from cljs/node_modules (and 'npm install' during build if
  needed)

js:
- Remove JS jscrush rules (regpack is sufficient)
- Fix regpack node_module make dep
  • Loading branch information
kanaka committed Mar 15, 2024
1 parent 9e2b81d commit 3de0209
Show file tree
Hide file tree
Showing 58 changed files with 1,178 additions and 1,055 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ notes
*.pyc
*.pyz
*-minipy.py
cljs/.shadow-cljs
cljs/build
cljs/src-min
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (C) 2017 Joel Martin <github@martintribe.org>
Copyright (C) 2024 Joel Martin <github@martintribe.org>

miniMAL is licensed under the MPL 2.0 (Mozilla Public License 2.0).
The text of the MPL 2.0 license is included below and can be found at
Expand Down
91 changes: 64 additions & 27 deletions cljs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,83 @@ STEPS = step0_repl step1_read_print step2_eval step3_env \
step4_if_fn_do step5_tco step6_file step7_interop \
step8_macros step9_try stepA_miniMAL

MIN_FILES = src/miniMAL/miniMAL.cljs miniMAL
MIN_FILES = $(foreach S,$(STEPS),src-min/miniMAL/$(S).cljc) miniMAL
BUILD_FILES = $(foreach S,$(STEPS),build/$(S).js) miniMAL.js

all: $(MIN_FILES)
.SECONDARY:

src/miniMAL/miniMAL.cljs: src/miniMAL/stepA_miniMAL.cljs
all: $(MIN_FILES) $(BUILD_FILES)

#
# Compressed
#
src-min/miniMAL/%.cljc: src/miniMAL/%.cljc
@echo "Compressing $@"
@mkdir -p src-min/miniMAL/
@cat $< \
| egrep -v "^ *$$|^ *;" \
| sed 's/^ *//' \
| tr '\n' ' ' \
| sed 's/ *(/(/g' \
| sed 's/) */)/g' \
| sed 's/ *"/"/g' \
| sed 's/ *\[/[/g' \
| sed 's/] */]/g' \
| sed 's/" *\([^n]\)/"\1/g' \
| sed 's/\<ast\>/A/g' \
| sed 's/\<env\>/E/g' \
| sed 's/\<a0\>/a/g' \
| sed 's/\<a1\>/b/g' \
| sed 's/\<a2\>/c/g' \
| sed 's/\<a3\>/d/g' \
| sed 's/stepA-miniMAL/miniMAL/' \
| sed 's/\<EVAL\>/X/g' \
| sed 's/\<eval-ast\>/Y/g' \
| sed 's/\<new-env\>/Z/g' \
| sed \
-e 's/ *(/(/g' \
-e 's/) */)/g' \
-e 's/ *"/"/g' \
-e 's/ *\[/[/g' \
-e 's/] */]/g' \
-e 's/ *{/{/g' \
-e 's/" *\([^n]\)/"\1/g' \
-e 's/\<new-env\>/Y/g' \
-e 's/\([^-]\)\<env\>/\1E/g' \
-e 's/\<ast\>/A/g' \
-e 's/\<EVAL\>/X/g' \
-e 's/\<a0\>/a/g' \
-e 's/\<a1\>/b/g' \
-e 's/\<a2\>/c/g' \
-e 's/\<a3\>/d/g' \
-e 's/\<rest\>/R/g' \
-e 's/\((ns [^)]*)\)/\1(def R rest)/' \
-e 's/\<js\/JSON.parse\>/P/g' \
-e 's/\((ns [^)]*)\)/\1(def P js\/JSON.parse)/' \
-e 's/ *#?(:org.babashka\/nbb *\(.*\) *#_nbb-end */\1/' \
-e 's/ *:cljs *\(.*\)) *#_cljs-end *//' \
> $@

miniMAL: src/miniMAL/miniMAL.cljs
@echo "#!/usr/bin/lumo -q" > $@
@cat $< \
| sed "s/(ns.*:require\([^)]*)\))/(require \'\1/" \
| sed 's/defn -main\[& args\]/let [args (seq (.slice js\/process.argv 4))]/' \
miniMAL: src-min/miniMAL/stepA_miniMAL.cljc
echo "Compressing $@"
echo "#!/usr/bin/env nbb" > $@
cat $< \
| sed "s/(ns [^)]*)//" \
| sed 's/defn -main\[& args\]/let [args (seq (.slice js\/process.argv 3))]/' \
>> $@
@chmod +x $@
chmod +x $@

node_modules/.bin/shadow-cljs:
npm install

# Full ClojureScript Compiled
build/%.js: node_modules/.bin/shadow-cljs src/miniMAL/%.cljc
node_modules/.bin/shadow-cljs release $*
chmod +x $@

.PHONY: clean
miniMAL.js: node_modules/shadow-cljs src/miniMAL/stepA_miniMAL.cljc
node_modules/.bin/shadow-cljs release miniMAL
chmod +x $@

stats: $(foreach S,$(STEPS),src/miniMAL/$(S).cljs) $(MIN_FILES)
#
# Stats
#
stats^%: src/miniMAL/%.cljc src-min/miniMAL/%.cljc
@wc $^ | grep -v "total"


.PHONY: clean stats

stats: $(foreach s,$(STEPS),stats^$(s)) miniMAL core.json
@wc miniMAL core.json | grep -v "total"

clean:
rm -f $(MIN_FILES)
rm -f $(BUILD_FILES)
rm -fr build/cljs-runtime
rmdir -p build || true
rmdir -p src-min/miniMAL || true
6 changes: 3 additions & 3 deletions cljs/core.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@
["interpose", "b",
["map", ["fn", ["x"],
["if", "c",
["print", "x"],
["pr*", "x"],
["if", ["string?", "x"],
"x",
["print", "x"]]]],
["pr*", "x"]]]],
"a"]]]]],
["def", "pr-str", ["fn", ["&", "a"],
["pr-list*", "a", ["`", " "], true]]],
Expand All @@ -47,7 +47,7 @@
["do", ["clj-println", ["pr-list*", "a", ["`", " "], false]], null]]],

["def", "list?", ["fn", ["a"],
["if", ["clj-list?", "a"], true, ["array?", "a"]]]],
["if", ["sequential?", "a"], true, ["array?", "a"]]]],
["def", "contains?", ["fn", ["a", "b"],
["if", ["object?", "a"],
["not", ["undefined?", ["aget", "a", "b"]]],
Expand Down
8 changes: 8 additions & 0 deletions cljs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"dependencies": {
"nbb": "^0.1.9"
},
"devDependencies": {
"shadow-cljs": "^2.27.5"
}
}
3 changes: 2 additions & 1 deletion cljs/run
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#!/bin/bash
STEP=${STEP:-stepA_miniMAL}
exec lumo -c $(dirname $0)/src -m miniMAL.${STEP//_/-} "${@}"
exec $(dirname $0)/node_modules/.bin/nbb -cp $(dirname $0)/src -m miniMAL.${STEP//_/-} "${@}"
#exec $(dirname $0)/node_modules/.bin/nbb -cp $(dirname $0)/src-min -m miniMAL.${STEP//_/-} "${@}"
26 changes: 26 additions & 0 deletions cljs/shadow-cljs.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
;; shadow-cljs configuration
{:source-paths
["src/"]

:build-defaults {:output-dir "build/"
;; Don't try and connect back to shadow-cljs process
:devtools {:enabled false :console-support false}
:compiler-options
{:optimizations :simple
:source-map-use-fs-paths true}}

:builds
{:step0_repl {:target :node-script :main miniMAL.step0-repl/-main :output-to "build/step0_repl.js"}
:step1_read_print {:target :node-script :main miniMAL.step1-read-print/-main :output-to "build/step1_read_print.js"}
:step2_eval {:target :node-script :main miniMAL.step2-eval/-main :output-to "build/step2_eval.js"}
:step3_env {:target :node-script :main miniMAL.step3-env/-main :output-to "build/step3_env.js"}
:step4_if_fn_do {:target :node-script :main miniMAL.step4-if-fn-do/-main :output-to "build/step4_if_fn_do.js"}
:step5_tco {:target :node-script :main miniMAL.step5-tco/-main :output-to "build/step5_tco.js"}
:step6_file {:target :node-script :main miniMAL.step6-file/-main :output-to "build/step6_file.js"}
:step7_interop {:target :node-script :main miniMAL.step7-interop/-main :output-to "build/step7_interop.js"}
:step8_macros {:target :node-script :main miniMAL.step8-macros/-main :output-to "build/step8_macros.js"}
:step9_try {:target :node-script :main miniMAL.step9-try/-main :output-to "build/step9_try.js"}
:stepA_miniMAL {:target :node-script :main miniMAL.stepA-miniMAL/-main :output-to "build/stepA_miniMAL.js"}
:miniMAL {:target :node-script :main miniMAL.stepA-miniMAL/-main :output-to "miniMAL.js"}}

}
11 changes: 6 additions & 5 deletions cljs/src/miniMAL/step1_read_print.cljc
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
(ns miniMAL.step1-read-print)

(defn EVAL [ast env]
ast)
ast)

(defn -main [& args]
(let [efn #(%4 nil (js/JSON.stringify (EVAL (js/JSON.parse %1) {})))]
(.start
(js/require "repl")
(clj->js {:eval efn :writer identity :terminal 0}))))
(.start
(js/require "repl")
(clj->js {:eval #(%4 0 (EVAL (js->clj (js/JSON.parse %1)) {}))
:writer #(js/JSON.stringify (clj->js %))}))
nil)
47 changes: 27 additions & 20 deletions cljs/src/miniMAL/step2_eval.cljc
Original file line number Diff line number Diff line change
@@ -1,27 +1,34 @@
(ns miniMAL.step2-eval)

(declare EVAL)
(defn EVAL [ast env & [sq]]
;;(prn :EVAL :ast ast :sq sq)
(cond
sq
(map #(EVAL % env) ast)

(defn eval-ast [ast env]
(cond (array? ast) (map #(EVAL % env) ast)
(and (string? ast) (contains? env ast)) (get env ast)
(string? ast) (throw (str ast " not found"))
:else ast))
(and (string? ast) (contains? env ast))
(env ast)

(defn EVAL [ast env]
;(prn :EVAL :ast ast)
(if (not (or (array? ast) (seq? ast)))
(eval-ast ast env)
(let [[f & el] (eval-ast ast env)]
(apply f el))))
(string? ast)
(throw (str ast " not found"))

(def E {"+" +
"-" -
"*" *
"/" /})
(sequential? ast)
(let [[f & el] (EVAL ast env 1)]
(apply f el))

:else
ast))

(def E
{"+" +
"-" -
"*" *
"/" /
})

(defn -main [& args]
(let [efn #(%4 nil (js/JSON.stringify (EVAL (js/JSON.parse %1) E)))]
(.start
(js/require "repl")
(clj->js {:eval efn :writer identity :terminal 0}))))
(.start
(js/require "repl")
(clj->js {:eval #(%4 0 (EVAL (js->clj (js/JSON.parse %1)) E))
:writer #(js/JSON.stringify (clj->js %))}))
nil)
68 changes: 39 additions & 29 deletions cljs/src/miniMAL/step3_env.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,44 @@
(defn new-env [& [d B E]]
(atom (js/Object.create d)))

(declare EVAL)
(defn eval-ast [ast env]
(cond (or (array? ast) (seq? ast)) (doall (map #(EVAL % env) ast))
(and (string? ast) (contains? @env ast)) (get @env ast)
(string? ast) (throw (str ast " not found"))
:else ast))

(defn EVAL [ast env]
;(prn :EVAL :ast ast)
(if (not (or (array? ast) (seq? ast)))
(eval-ast ast env)
(let [[a0 a1 a2 a3] ast]
(condp = a0
"def" (let [x (EVAL a2 env)] (swap! env assoc a1 x) x)
"let" (let [env (new-env @env)]
(doseq [[s v] (partition 2 a1)]
(swap! env assoc s (EVAL v env)))
(EVAL a2 env))
(let [[f & el] (eval-ast ast env)]
(apply f el))))))

(def E (new-env {"+" +
"-" -
"*" *
"/" /}))
(defn EVAL [ast env & [sq]]
;;(prn :EVAL :ast ast :sq sq)
(cond
sq
(map #(EVAL % env) ast)

(and (string? ast) (contains? @env ast))
(@env ast)

(string? ast)
(throw (str ast " not found"))

(sequential? ast)
(let [[a0 a1 a2 a3] ast]
(condp = a0
"def" (let [x (EVAL a2 env)]
(swap! env assoc a1 x) x)
"let" (let [env (new-env @env)]
(doseq [[s v] (partition 2 a1)]
(swap! env assoc s (EVAL v env)))
(EVAL a2 env))
(let [[f & el] (EVAL ast env 1)]
(apply f el))))

:else
ast))

(def E
(new-env
{"+" +
"-" -
"*" *
"/" /
}))

(defn -main [& args]
(let [efn #(%4 nil (js/JSON.stringify (EVAL (js/JSON.parse %1) E)))]
(.start
(js/require "repl")
(clj->js {:eval efn :writer identity :terminal 0}))))
(.start
(js/require "repl")
(clj->js {:eval #(%4 0 (EVAL (js->clj (js/JSON.parse %1)) E))
:writer #(js/JSON.stringify (clj->js %))}))
nil)
Loading

0 comments on commit 3de0209

Please sign in to comment.