diff --git a/Makefile.impls b/Makefile.impls index 6ac35b23e5..9485863b9d 100644 --- a/Makefile.impls +++ b/Makefile.impls @@ -34,7 +34,7 @@ wasm_MODE = wasmtime # Implementation specific settings # -IMPLS = ada ada.2 awk bash basic bbc-basic c c.2 chuck clojure coffee common-lisp cpp crystal cs d dart \ +IMPLS = ada ada.2 awk bash basic bbc-basic bqn c c.2 chuck clojure coffee common-lisp cpp crystal cs d dart \ elisp elixir elm erlang es6 factor fantom fennel forth fsharp go groovy gnu-smalltalk \ guile haskell haxe hy io janet java java-truffle js jq julia kotlin livescript logo lua make mal \ matlab miniMAL nasm nim objc objpascal ocaml perl perl6 php picolisp pike plpgsql \ @@ -110,6 +110,7 @@ awk_STEP_TO_PROG = impls/awk/$($(1)).awk bash_STEP_TO_PROG = impls/bash/$($(1)).sh basic_STEP_TO_PROG = $(basic_STEP_TO_PROG_$(basic_MODE)) bbc-basic_STEP_TO_PROG = impls/bbc-basic/$($(1)).bas +bqn_STEP_TO_PROG = impls/bqn/$($(1)).bqn c_STEP_TO_PROG = impls/c/$($(1)) c.2_STEP_TO_PROG = impls/c.2/$($(1)) chuck_STEP_TO_PROG = impls/chuck/$($(1)).ck diff --git a/README.md b/README.md index 3fa1c13df2..01a5a1d3d9 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ FAQ](docs/FAQ.md) where I attempt to answer some common questions. | [Bash 4](#bash-4) | [Joel Martin](https://github.com/kanaka) | | [BASIC](#basic-c64-and-qbasic) (C64 & QBasic) | [Joel Martin](https://github.com/kanaka) | | [BBC BASIC V](#bbc-basic-v) | [Ben Harris](https://github.com/bjh21) | +| [BQN](#bqn) | [Hannu Hartikainen](https://github.com/dancek) | | [C](#c) | [Joel Martin](https://github.com/kanaka) | | [C #2](#c2) | [Duncan Watts](https://github.com/fungiblecog) | | [C++](#c-1) | [Stephen Thirlwall](https://github.com/sdt) | @@ -289,6 +290,17 @@ Or in ARM BBC BASIC V under RISC OS 3 or later: *Run stepX_YYY ``` +### BQN + +The BQN implementation requires [CBQN](https://github.com/dzaima/CBQN) as the non-standard system values `•_while_`, `•GetLine` and `•term.OutRaw` are used. Removing them would be easy, though -- they're just for convenience and REPL usability. + +There are no releases of CBQN at the time of writing, but any version from mid 2022 should work. Specifically, commit `88f6585` is known to work. + +``` +cd impls/bqn +./run +``` + ### C The C implementation of mal requires the following libraries (lib and diff --git a/impls/bqn/Dockerfile b/impls/bqn/Dockerfile new file mode 100644 index 0000000000..068d8622bf --- /dev/null +++ b/impls/bqn/Dockerfile @@ -0,0 +1,12 @@ +FROM ubuntu:22.04 + +RUN apt-get update && \ + apt-get install -qqy git clang build-essential python3 python-is-python3 +RUN git clone https://github.com/dzaima/CBQN.git && \ + cd CBQN && \ + git reset --hard 88f65850fa6ac28bc50886c5942652f21d5be924 && \ + make && \ + make install && \ + ln -s bqn /usr/local/bin/BQN +RUN mkdir /mal +WORKDIR /mal diff --git a/impls/bqn/Makefile b/impls/bqn/Makefile new file mode 100644 index 0000000000..7af3113c71 --- /dev/null +++ b/impls/bqn/Makefile @@ -0,0 +1,3 @@ +all: + +clean: diff --git a/impls/bqn/core.bqn b/impls/bqn/core.bqn new file mode 100644 index 0000000000..34741457ab --- /dev/null +++ b/impls/bqn/core.bqn @@ -0,0 +1,118 @@ +⟨Atom,nil,Err,_chk,_chks⟩ ← •Import "globals.bqn" +⟨Env⟩ ← •Import "env.bqn" +⟨PrStr,PrStrR⟩ ← •Import "printer.bqn" +⟨ReadStr⟩ ← •Import "reader.bqn" + +Q ← {∾´'"'∾𝕩∾'"'} +J ← {0=≠𝕩 ? "" ; + 1=≠𝕩 ? ⊑𝕩 ; + ∾´(⊑𝕩)∾𝕨∾𝕨J 1↓𝕩} +E ← {𝕊 ⟨t‿a,s‿b⟩: + {(⊑t∊3‿4) ∧ ⊑s∊3‿4 ? + {(≠a)=≠b ? ∧´a E¨b ; 0}; + (t≡s)∧a≡b} ; + {2<≠𝕩 ? ∧´E´˘2↕𝕩 ; 1}𝕩} + +ns ← ⟨ + "+"‿{1∾+´1⊏˘>𝕩} + "-"‿{1∾-´1⊏˘>𝕩} + "*"‿{1∾×´1⊏˘>𝕩} + "/"‿{1∾⌊∘÷´1⊏˘>𝕩} + + "="‿{7∾E𝕩} + "<"‿{7∾∧´<´˘2↕1⊸⊑¨𝕩} + "<="‿{7∾∧´≤´˘2↕1⊸⊑¨𝕩} + ">"‿{7∾∧´>´˘2↕1⊸⊑¨𝕩} + ">="‿{7∾∧´≥´˘2↕1⊸⊑¨𝕩} + + "empty?"‿{7∾0=≠1⊑⊑𝕩} + "count"‿{1∾≠1⊑⊑𝕩} + + "bqn-show"‿{•Show ⊑ 𝕩} + "pr-str"‿{2∾<" "J PrStrR¨𝕩} + "str"‿{2∾<""J PrStr¨𝕩} + "prn"‿{•Out " "J PrStrR¨𝕩 ⋄ nil} + "println"‿{•Out " "J PrStr¨𝕩 ⋄ nil} + + "read-string"‿{ReadStr 1⊑⊑𝕩} + "slurp"‿{2∾<•FChars 1⊑⊑𝕩} + + "atom"‿{11∾Atom ⊑𝕩} + "atom?"‿{7∾11=⊑⊑𝕩} + "deref"‿{𝕊 ⟨11‿a⟩: a.Deref@; Err "deref: not an atom"} + "reset!"‿{ + 𝕊 ⟨11‿a,v⟩: a.Reset v; + Err "reset!: not an atom"} + "swap!"‿{ + ⟨t‿a,fn⟩ ← 2↑𝕩 + args ← ( " + line ← •GetLine 0 + •Out Rep line + 𝕊𝕩 +} @ diff --git a/impls/bqn/step1_read_print.bqn b/impls/bqn/step1_read_print.bqn new file mode 100644 index 0000000000..e30134b0c4 --- /dev/null +++ b/impls/bqn/step1_read_print.bqn @@ -0,0 +1,14 @@ +⟨ReadStr⟩ ← •Import "reader.bqn" +⟨PrStrR⟩ ← •Import "printer.bqn" + +READ ← ReadStr +EVAL ← ⊢ +PRINT ← PrStrR +Rep ← PRINT∘EVAL∘READ + +{ + •Out "user> " + line ← •GetLine 0 + •Out Rep line + 𝕊𝕩 +}@ diff --git a/impls/bqn/step2_eval.bqn b/impls/bqn/step2_eval.bqn new file mode 100644 index 0000000000..6f227d59d3 --- /dev/null +++ b/impls/bqn/step2_eval.bqn @@ -0,0 +1,41 @@ +⟨ReadStr⟩ ← •Import "reader.bqn" +⟨PrStrR⟩ ← •Import "printer.bqn" + +replEnv ← >⟨ + "+"‿1‿(+´) + "-"‿1‿(-´) + "*"‿1‿(×´) + "/"‿1‿(÷´) +⟩ +Undef ← {@‿¯1‿(<"undefined: "∾𝕩)} + +EvalAst ← {env 𝕊 t‿v: + {0: idx ← ⊑((⊏˘env)⊐( " + line ← •GetLine 0 + •Out Rep line + 𝕊𝕩 +}@ diff --git a/impls/bqn/step3_env.bqn b/impls/bqn/step3_env.bqn new file mode 100644 index 0000000000..437370d674 --- /dev/null +++ b/impls/bqn/step3_env.bqn @@ -0,0 +1,48 @@ +⟨Env⟩ ← •Import "env.bqn" +⟨ReadStr⟩ ← •Import "reader.bqn" +⟨PrStr⟩ ← •Import "printer.bqn" + +ns ← Env@ +ns.Set "+"‿{1∾+´1⊏˘>𝕩} +ns.Set "-"‿{1∾-´1⊏˘>𝕩} +ns.Set "*"‿{1∾×´1⊏˘>𝕩} +ns.Set "/"‿{1∾⌊∘÷´1⊏˘>𝕩} + +EvalAst ← {env 𝕊 t‿v: + {0: env.Get v ; + 3: env⊸EVAL¨v ; + t‿v + }t +} + +READ ← ReadStr +PRINT ← PrStr +EVAL ← { + env 𝕊 3‿⟨⟩: 3‿⟨⟩ ; + env 𝕊 3‿⟨0‿"def!",0‿k,x⟩: + v ← env EVAL x + {¯1:@;env.Set ( " + line ← •GetLine 0 + •Out Rep line + 𝕊𝕩 +}@ diff --git a/impls/bqn/step4_if_fn_do.bqn b/impls/bqn/step4_if_fn_do.bqn new file mode 100644 index 0000000000..d95d778cb5 --- /dev/null +++ b/impls/bqn/step4_if_fn_do.bqn @@ -0,0 +1,70 @@ +⟨nil⟩ ← •Import "globals.bqn" +⟨Env⟩ ← •Import "env.bqn" +⟨ReadStr⟩ ← •Import "reader.bqn" +⟨PrStrR⟩ ← •Import "printer.bqn" +⟨core⟩ ← •Import "core.bqn" + +EvalAst ← {env 𝕊 t‿v: + {0: env.Get v ; + 3: env⊸EVAL¨v ; + t‿v + }t +} + +READ ← ReadStr +PRINT ← PrStrR +EVAL ← { + # builtin special forms + env 𝕊 3‿⟨0‿"def!",0‿k,x⟩: + v ← env EVAL x + {¯1:@;env.Set ( " + line ← •GetLine 0 + •Out Rep line + 𝕊𝕩 +}@ diff --git a/impls/bqn/step5_tco.bqn b/impls/bqn/step5_tco.bqn new file mode 100644 index 0000000000..08172c8c82 --- /dev/null +++ b/impls/bqn/step5_tco.bqn @@ -0,0 +1,89 @@ +⟨nil⟩ ← •Import "globals.bqn" +⟨Env⟩ ← •Import "env.bqn" +⟨ReadStr⟩ ← •Import "reader.bqn" +⟨PrStrR⟩ ← •Import "printer.bqn" +⟨core⟩ ← •Import "core.bqn" + +EvalAst ← {env 𝕊 t‿v: + {0: env.Get v ; + 3: env⊸EVAL¨v ; + t‿v + }t +} + +SetParams ← {env 𝕊 args‿xs: + {𝕊 + {0‿"&": env.Set (<1⊑1⊑args)∾<3∾ " + line ← •GetLine 0 + •Out Rep line + 𝕊𝕩 +}@ diff --git a/impls/bqn/step6_file.bqn b/impls/bqn/step6_file.bqn new file mode 100644 index 0000000000..5a6fbe5ffd --- /dev/null +++ b/impls/bqn/step6_file.bqn @@ -0,0 +1,94 @@ +⟨nil⟩ ← •Import "globals.bqn" +⟨Env⟩ ← •Import "env.bqn" +⟨ReadStr⟩ ← •Import "reader.bqn" +⟨PrStrR⟩ ← •Import "printer.bqn" +⟨core⟩ ← •Import "core.bqn" + +EvalAst ← {env 𝕊 t‿v: + {0: env.Get v ; + 3: env⊸EVAL¨v ; + t‿v + }t +} + +SetParams ← {env 𝕊 args‿xs: + {𝕊 + {0‿"&": env.Set (<1⊑1⊑args)∾<3∾ " + line ← •GetLine 0 + •Out Rep line + 𝕊𝕩 + }@ ; + core.Set "*ARGV*"‿(3∾<2∾⟜<¨1↓•args) + Rep "(load-file """∾(⊑•args)∾""")" +} diff --git a/impls/bqn/step7_quote.bqn b/impls/bqn/step7_quote.bqn new file mode 100644 index 0000000000..54ef88e903 --- /dev/null +++ b/impls/bqn/step7_quote.bqn @@ -0,0 +1,109 @@ +⟨nil⟩ ← •Import "globals.bqn" +⟨Env⟩ ← •Import "env.bqn" +⟨ReadStr⟩ ← •Import "reader.bqn" +⟨PrStrR⟩ ← •Import "printer.bqn" +⟨core⟩ ← •Import "core.bqn" + +EvalAst ← {env 𝕊 t‿v: + {0: env.Get v ; + 3: env⊸EVAL¨v ; + t‿v + }t +} + +SetParams ← {env 𝕊 args‿xs: + {𝕊 + {0‿"&": env.Set (<1⊑1⊑args)∾<3∾ " + line ← •GetLine 0 + •Out Rep line + 𝕊𝕩 +}@ diff --git a/impls/bqn/step8_macros.bqn b/impls/bqn/step8_macros.bqn new file mode 100644 index 0000000000..eaceb714bf --- /dev/null +++ b/impls/bqn/step8_macros.bqn @@ -0,0 +1,133 @@ +⟨nil⟩ ← •Import "globals.bqn" +⟨Env⟩ ← •Import "env.bqn" +⟨ReadStr⟩ ← •Import "reader.bqn" +⟨PrStrR⟩ ← •Import "printer.bqn" +⟨core⟩ ← •Import "core.bqn" + +EvalAst ← { + env 𝕊 t‿v: + {0: env.Get v ; + 3: env⊸EVAL¨v ; + t‿v + }t ; + 𝕩 +} + +SetParams ← {env 𝕊 args‿xs: + {𝕊 + {0‿"&": env.Set (<1⊑1⊑args)∾<3∾ (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw ""odd number of forms to cond"")) (cons 'cond (rest (rest xs)))))))" + +{ + •Out "user> " + line ← •GetLine 0 + •Out Rep line + 𝕊𝕩 +}@ diff --git a/impls/bqn/step9_try.bqn b/impls/bqn/step9_try.bqn new file mode 100644 index 0000000000..da30e4752a --- /dev/null +++ b/impls/bqn/step9_try.bqn @@ -0,0 +1,137 @@ +⟨Err,nil,_chk,_chks⟩ ← •Import "globals.bqn" +⟨Env⟩ ← •Import "env.bqn" +⟨ReadStr⟩ ← •Import "reader.bqn" +⟨PrStrR⟩ ← •Import "printer.bqn" +⟨core⟩ ← •Import "core.bqn" + +EvalAst ← { + env 𝕊 t‿v: + {0: env.Get v ; + 3: env⊸EVAL¨v ; + t‿v + }t ; + 𝕩 +} + +SetParams ← {env 𝕊 args‿xs: + {𝕊 + {0‿"&": env.Set (<1⊑1⊑args)∾<3∾ (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw ""odd number of forms to cond"")) (cons 'cond (rest (rest xs)))))))" + +{ + •Out "user> " + line ← •GetLine 0 + •Out Rep line + 𝕊𝕩 +}@ diff --git a/impls/bqn/stepA_mal.bqn b/impls/bqn/stepA_mal.bqn new file mode 100644 index 0000000000..884be542b4 --- /dev/null +++ b/impls/bqn/stepA_mal.bqn @@ -0,0 +1,142 @@ +⟨Err,nil,_chk,_chks⟩ ← •Import "globals.bqn" +⟨Env⟩ ← •Import "env.bqn" +⟨ReadStr⟩ ← •Import "reader.bqn" +⟨PrStrR⟩ ← •Import "printer.bqn" +⟨core⟩ ← •Import "core.bqn" + +EvalAst ← { + env 𝕊 t‿v: + {0: env.Get v ; + 3: env⊸EVAL¨v ; + t‿v + }t ; + 𝕩 +} + +SetParams ← {env 𝕊 args‿xs: + {𝕊 + {0‿"&": env.Set (<1⊑1⊑args)∾<3∾ (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw ""odd number of forms to cond"")) (cons 'cond (rest (rest xs)))))))" + +{0=≠•args ? + Rep "(println (str ""Mal ["" *host-language* ""]""))" + { + •term.OutRaw "user> " + line ← •GetLine 0 + •Out Rep line + 𝕊𝕩 + }@ ; + core.Set "*ARGV*"‿(3∾<2∾⟜<¨1↓•args) + Rep "(load-file """∾(⊑•args)∾""")" +}