diff --git a/README.md b/README.md index f39cd10b..cd9d4195 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,8 @@ to _some_ safe and clear syntax with as few layers of translation as possible. The emphasis is on internal consistency at any point in time rather than compatibility with the past. ([More details.](http://akkartik.name/akkartik-convivial-20200607.pdf)) -Currently Mu requires a 32-bit x86 processor and Linux kernel. +Currently Mu requires a 32-bit x86 processor. Generated programs require just +a Linux kernel and nothing else. ## Goals @@ -67,12 +68,20 @@ The Mu stack consists of: - _bare_ SubX, a more rudimentary form of SubX without certain syntax sugar. All Mu programs get translated through these layers into tiny zero-dependency -ELF binaries. The translators for most levels are built out of lower levels. -The translator from Mu to SubX is written in SubX, and the translator from -SubX to bare SubX is built in bare SubX. +ELF binaries that run natively on Linux. The translators for most levels are +built out of lower levels. The translator from Mu to SubX is written in SubX, +and the translator from SubX to bare SubX is built in bare SubX. -Mu programs can be run in emulated mode to emit traces, which permit time-travel -debugging. ([More details.](subx_debugging.md)) +There's an emulator for running Mu binaries (more slowly) on other Unix-like +systems. + +```sh +$ ./translate_mu_emulated apps/ex2.mu # emit a.elf using the emulator +$ ./bootstrap run ./a.elf # run in the emulator +$ echo $? +``` + +The emulator is also useful for [debugging](subx_debugging.md). ### incomplete tools diff --git a/subx_debugging.md b/subx_debugging.md index 27b98774..acd6f88d 100644 --- a/subx_debugging.md +++ b/subx_debugging.md @@ -27,28 +27,16 @@ rudimentary but hopefully still workable toolkit: mode (`bootstrap run`): ``` - $ ./bootstrap translate input.subx -o binary - $ ./bootstrap --trace run binary arg1 arg2 2>trace + $ ./translate_subx_debug file1.subx file2.subx ... # generating a.elf + $ ./bootstrap --trace run a.elf arg1 arg2 + saving trace to 'last_run' ``` The ability to generate a trace is the essential reason for the existence of `bootstrap run` mode. It gives far better visibility into program internals than running natively. -- As a further refinement, it is possible to render label names in the trace - by adding a second flag to the `bootstrap translate` command: - - ``` - $ ./bootstrap --debug translate input.subx -o binary - $ ./bootstrap --trace run binary arg1 arg2 2>trace - ``` - - `bootstrap --debug translate` emits a mapping from label to address in a file - called `labels`. `bootstrap --trace run` reads in the `labels` file if - it exists and prints out any matching label name as it traces each instruction - executed. - - Here's a sample of what a trace looks like, with a few boxes highlighted: + Here's a sample of the contents of `last_run`, with a few boxes highlighted: trace example @@ -60,10 +48,10 @@ rudimentary but hopefully still workable toolkit: address `0x0900005e` maps to label `$loop` and presumably marks the start of some loop. Function names get similar `run: == label` lines. -- One trick when emitting traces with labels: +- One quick trick when scanning a trace for the first time: ``` - $ grep label trace + $ grep label last_run ``` This is useful for quickly showing you the control flow for the run, and the @@ -115,11 +103,21 @@ rudimentary but hopefully still workable toolkit: `./translate_subx_debug`, and then running: ``` - ./bootstrap --trace --dump run a.elf test 2>&1 |grep 'label test' + grep 'label test-' |tail ``` Just read out the last test printed out before the segfault. + Even outside of tests, I can often quickly debug an error just by scanning + the end of a trace for labels: + + ``` + $ grep label last_run |tail + ``` + + Knowing _where_ the error occurred is often enough to put me on the right + track to debugging an error. + Hopefully these hints are enough to get you started. The main thing to remember is to not be afraid of modifying the sources. A good debugging session gets into a nice rhythm of generating a trace, staring at it for a diff --git a/test_apps b/test_apps index 129e429c..8f6253ba 100755 --- a/test_apps +++ b/test_apps @@ -1,180 +1,171 @@ #!/bin/sh -# Build and test all included SubX programs: +# Build and test all included SubX programs on Linux: # translate them into ELF binaries # compare the generated binaries with what's already in git -# run/test the ELF binaries in emulated mode (unless $NO_EMULATION) -# run/test the ELF binaries in native mode (if on Linux) +# run/test the ELF binaries in emulated mode +# run/test the ELF binaries in native mode # # Example usage: -# test_apps # compare generated binaries, run them in emulated and native mode -# test_apps record # run binaries in emulated and native mode -# NO_EMULATION=1 test_apps # compare generated binaries, run them in native mode -# NO_EMULATION=1 test_apps record # run binaries just in native mode +# test_apps +# test_apps record # don't compare with what's in git set -e cd `dirname $0` -test $NO_EMULATION || EMULATED=1 -test $EMULATED && echo 'testing emulated runs' -test `uname` = 'Linux' && NATIVE=1 -test $NATIVE && echo 'testing native runs' - ./build -export OS=${OS:-linux} - -echo "== translating and running using C++" +echo "== translating using the bootstrap C++ translator" # example programs echo ex1 -./bootstrap translate init.$OS apps/ex1.subx -o apps/ex1 +./bootstrap_bin translate init.linux apps/ex1.subx -o apps/ex1 test "$1" = 'record' || git diff --exit-code apps/ex1 -test $EMULATED && { - ./bootstrap run apps/ex1 || ret=$? +{ + ./bootstrap_bin run apps/ex1 || ret=$? test $ret -eq 42 # life, the universe and everything } -test $NATIVE && { +{ apps/ex1 || ret=$? test $ret -eq 42 # life, the universe and everything } echo ex2 -./bootstrap translate init.$OS apps/ex2.subx -o apps/ex2 +./bootstrap_bin translate init.linux apps/ex2.subx -o apps/ex2 test "$1" = 'record' || git diff --exit-code apps/ex2 -test $EMULATED && { - ./bootstrap run apps/ex2 || ret=$? +{ + ./bootstrap_bin run apps/ex2 || ret=$? test $ret -eq 7 # 3 + 4 } -test $NATIVE && { +{ apps/ex2 || ret=$? test $ret -eq 7 # 3 + 4 } echo ex3 -./bootstrap translate init.$OS apps/ex3.subx -o apps/ex3 +./bootstrap_bin translate init.linux apps/ex3.subx -o apps/ex3 test "$1" = 'record' || git diff --exit-code apps/ex3 -test $EMULATED && { - ./bootstrap run apps/ex3 || ret=$? +{ + ./bootstrap_bin run apps/ex3 || ret=$? test $ret -eq 55 # 1 + 2 + ... + 10 } -test $NATIVE && { +{ apps/ex3 || ret=$? test $ret -eq 55 # 1 + 2 + ... + 10 } echo ex4 -./bootstrap translate init.$OS apps/ex4.subx -o apps/ex4 +./bootstrap_bin translate init.linux apps/ex4.subx -o apps/ex4 test "$1" = 'record' || git diff --exit-code apps/ex4 -test $EMULATED && { - echo a | ./bootstrap run apps/ex4 >ex4.out || true +{ + echo a | ./bootstrap_bin run apps/ex4 >ex4.out || true test `cat ex4.out` = 'a' } -test $NATIVE && { +{ echo a | apps/ex4 >ex4.out || true test `cat ex4.out` = 'a' } echo ex5 -./bootstrap translate init.$OS apps/ex5.subx -o apps/ex5 +./bootstrap_bin translate init.linux apps/ex5.subx -o apps/ex5 test "$1" = 'record' || git diff --exit-code apps/ex5 -test $EMULATED && { - echo a | ./bootstrap run apps/ex5 >ex5.out || true +{ + echo a | ./bootstrap_bin run apps/ex5 >ex5.out || true test `cat ex5.out` = 'a' } -test $NATIVE && { +{ echo a | apps/ex5 >ex5.out || true test `cat ex5.out` = 'a' } echo ex6 -./bootstrap translate init.$OS apps/ex6.subx -o apps/ex6 +./bootstrap_bin translate init.linux apps/ex6.subx -o apps/ex6 test "$1" = 'record' || git diff --exit-code apps/ex6 -test $EMULATED && { - ./bootstrap run apps/ex6 >ex6.out || true +{ + ./bootstrap_bin run apps/ex6 >ex6.out || true test "`cat ex6.out`" = 'Hello, world!' } -test $NATIVE && { +{ apps/ex6 >ex6.out || true test "`cat ex6.out`" = 'Hello, world!' } echo ex7 -./bootstrap translate init.$OS apps/ex7.subx -o apps/ex7 +./bootstrap_bin translate init.linux apps/ex7.subx -o apps/ex7 test "$1" = 'record' || git diff --exit-code apps/ex7 -test $EMULATED && { - ./bootstrap run apps/ex7 || ret=$? +{ + ./bootstrap_bin run apps/ex7 || ret=$? test $ret -eq 97 # 'a' } -test $NATIVE && { +{ apps/ex7 || ret=$? test $ret -eq 97 # 'a' } echo ex8 -./bootstrap translate init.$OS apps/ex8.subx -o apps/ex8 +./bootstrap_bin translate init.linux apps/ex8.subx -o apps/ex8 test "$1" = 'record' || git diff --exit-code apps/ex8 -test $EMULATED && { - ./bootstrap run apps/ex8 abcd || ret=$? +{ + ./bootstrap_bin run apps/ex8 abcd || ret=$? test $ret -eq 4 # length('abcd') } -test $NATIVE && { +{ apps/ex8 abcd || ret=$? test $ret -eq 4 # length('abcd') } echo ex9 -./bootstrap translate init.$OS apps/ex9.subx -o apps/ex9 +./bootstrap_bin translate init.linux apps/ex9.subx -o apps/ex9 test "$1" = 'record' || git diff --exit-code apps/ex9 -test $EMULATED && { - ./bootstrap run apps/ex9 z x || ret=$? +{ + ./bootstrap_bin run apps/ex9 z x || ret=$? test $ret -eq 2 # 'z' - 'x' } -test $NATIVE && { +{ apps/ex9 z x || ret=$? test $ret -eq 2 # 'z' - 'x' } echo ex10 -./bootstrap translate init.$OS apps/ex10.subx -o apps/ex10 +./bootstrap_bin translate init.linux apps/ex10.subx -o apps/ex10 test "$1" = 'record' || git diff --exit-code apps/ex10 -test $EMULATED && { - ./bootstrap run apps/ex10 abc abc || ret=$? +{ + ./bootstrap_bin run apps/ex10 abc abc || ret=$? test $ret -eq 1 # equal - ./bootstrap run apps/ex10 abc abcd # 0; not equal + ./bootstrap_bin run apps/ex10 abc abcd # 0; not equal } -test $NATIVE && { +{ apps/ex10 abc abc || ret=$? test $ret -eq 1 # equal apps/ex10 abc abcd # 0; not equal } echo ex11 -./bootstrap translate init.$OS apps/ex11.subx -o apps/ex11 +./bootstrap_bin translate init.linux apps/ex11.subx -o apps/ex11 test "$1" = 'record' || git diff --exit-code apps/ex11 -test $EMULATED && { - ./bootstrap run apps/ex11 +{ + ./bootstrap_bin run apps/ex11 echo } -test $NATIVE && { +{ apps/ex11 echo } echo ex12 -./bootstrap translate init.$OS apps/ex12.subx -o apps/ex12 +./bootstrap_bin translate init.linux apps/ex12.subx -o apps/ex12 test "$1" = 'record' || git diff --exit-code apps/ex12 -test $EMULATED && ./bootstrap run apps/ex12 # final byte of mmap'd address is well-nigh guaranteed to be 0 +test $EMULATED && ./bootstrap_bin run apps/ex12 # final byte of mmap'd address is well-nigh guaranteed to be 0 test $NATIVE && apps/ex12 echo ex13 -./bootstrap translate init.$OS apps/ex13.subx -o apps/ex13 +./bootstrap_bin translate init.linux apps/ex13.subx -o apps/ex13 test "$1" = 'record' || git diff --exit-code apps/ex13 -test $EMULATED && { - ./bootstrap run apps/ex13 || ret=$? +{ + ./bootstrap_bin run apps/ex13 || ret=$? test $ret -eq 1 # 3 == 3 } -test $NATIVE && { +{ apps/ex13 || ret=$? test $ret -eq 1 # 3 == 3 } @@ -182,15 +173,15 @@ test $NATIVE && { # Larger apps that use the standard library. echo factorial -./bootstrap translate init.$OS [01]*.subx apps/factorial.subx -o apps/factorial +./bootstrap_bin translate init.linux [01]*.subx apps/factorial.subx -o apps/factorial test "$1" = 'record' || git diff --exit-code apps/factorial -test $EMULATED && { - ./bootstrap run apps/factorial || ret=$? +{ + ./bootstrap_bin run apps/factorial || ret=$? test $ret -eq 120 # factorial(5) - ./bootstrap run apps/factorial test + ./bootstrap_bin run apps/factorial test echo } -test $NATIVE && { +{ apps/factorial || ret=$? test $ret -eq 120 # factorial(5) apps/factorial test @@ -198,25 +189,25 @@ test $NATIVE && { } echo crenshaw2-1 -./bootstrap translate init.$OS [01]*.subx apps/crenshaw2-1.subx -o apps/crenshaw2-1 +./bootstrap_bin translate init.linux [01]*.subx apps/crenshaw2-1.subx -o apps/crenshaw2-1 test "$1" = 'record' || git diff --exit-code apps/crenshaw2-1 -test $EMULATED && { - ./bootstrap run apps/crenshaw2-1 test +{ + ./bootstrap_bin run apps/crenshaw2-1 test echo } -test $NATIVE && { +{ apps/crenshaw2-1 test echo } echo crenshaw2-1b -./bootstrap translate init.$OS [01]*.subx apps/crenshaw2-1b.subx -o apps/crenshaw2-1b +./bootstrap_bin translate init.linux [01]*.subx apps/crenshaw2-1b.subx -o apps/crenshaw2-1b test "$1" = 'record' || git diff --exit-code apps/crenshaw2-1b -test $EMULATED && { - ./bootstrap run apps/crenshaw2-1b test +{ + ./bootstrap_bin run apps/crenshaw2-1b test echo } -test $NATIVE && { +{ apps/crenshaw2-1b test echo } @@ -226,13 +217,13 @@ test $NATIVE && { for phase in hex survey pack assort dquotes tests do echo $phase - ./bootstrap translate init.$OS [01]*.subx apps/subx-params.subx apps/$phase.subx -o apps/$phase + ./bootstrap_bin translate init.linux [01]*.subx apps/subx-params.subx apps/$phase.subx -o apps/$phase test "$1" = 'record' || git diff --exit-code apps/$phase - test $EMULATED && { - ./bootstrap run apps/$phase test + { + ./bootstrap_bin run apps/$phase test echo } - test $NATIVE && { + { apps/$phase test echo } @@ -241,70 +232,67 @@ done # Higher-level syntax. # Certain phases of translation run native beyond this point. We're starting -# to go beyond functionality of the C++ bootstrap. +# to go beyond functionality of the C++ bootstrap_bin. echo sigils -./bootstrap translate init.$OS [012]*.subx apps/subx-params.subx apps/sigils.subx -o apps/sigils +./bootstrap_bin translate init.linux [012]*.subx apps/subx-params.subx apps/sigils.subx -o apps/sigils test "$1" = 'record' || git diff --exit-code apps/sigils -test $EMULATED && { - ./bootstrap run apps/sigils test +{ + ./bootstrap_bin run apps/sigils test echo } -test $NATIVE && { +{ apps/sigils test echo } -test $NATIVE || { echo 'there are more tests, but you need Linux to run them'; exit 0; } - echo calls -cat init.$OS [012]*.subx apps/subx-params.subx apps/calls.subx | apps/sigils > a.sigils -./bootstrap translate a.sigils -o apps/calls +cat init.linux [012]*.subx apps/subx-params.subx apps/calls.subx | apps/sigils > a.sigils +./bootstrap_bin translate a.sigils -o apps/calls test "$1" = 'record' || git diff --exit-code apps/calls -test $EMULATED && { - ./bootstrap run apps/calls test +{ + ./bootstrap_bin run apps/calls test echo } -test $NATIVE && { +{ apps/calls test echo } echo braces -cat init.$OS [012]*.subx apps/subx-params.subx apps/braces.subx | apps/calls | apps/sigils > a.sigils -./bootstrap translate a.sigils -o apps/braces +cat init.linux [012]*.subx apps/subx-params.subx apps/braces.subx | apps/calls | apps/sigils > a.sigils +./bootstrap_bin translate a.sigils -o apps/braces test "$1" = 'record' || git diff --exit-code apps/braces -test $EMULATED && { - ./bootstrap run apps/braces test +{ + ./bootstrap_bin run apps/braces test echo } -test $NATIVE && { +{ apps/braces test echo } echo mu -cat init.$OS [0-2]*.subx apps/mu.subx | apps/braces | apps/calls | apps/sigils > a.sigils -./bootstrap translate a.sigils -o apps/mu +cat init.linux [0-2]*.subx apps/mu.subx | apps/braces | apps/calls | apps/sigils > a.sigils +./bootstrap_bin translate a.sigils -o apps/mu test "$1" = 'record' || git diff --exit-code apps/mu -test $EMULATED && { - ./bootstrap run apps/mu test +{ + ./bootstrap_bin run apps/mu test echo } -test $NATIVE && { +{ apps/mu test echo } -test $NATIVE || exit 0 -echo "== translating using SubX (native only)" +echo "== translating using the self-hosted translator" # example programs for n in `seq 1 12` do echo ex$n - ./translate_subx init.$OS apps/ex$n.subx + ./translate_subx init.linux apps/ex$n.subx diff apps/ex$n a.elf done @@ -313,7 +301,7 @@ done for app in factorial crenshaw2-1 crenshaw2-1b do echo $app - ./translate_subx init.$OS [01]*.subx apps/$app.subx + ./translate_subx init.linux [01]*.subx apps/$app.subx diff apps/$app a.elf done @@ -322,77 +310,77 @@ done for app in hex survey pack assort dquotes tests do echo $app - ./translate_subx init.$OS [01]*.subx apps/subx-params.subx apps/$app.subx + ./translate_subx init.linux [01]*.subx apps/subx-params.subx apps/$app.subx diff apps/$app a.elf done for app in sigils calls braces do echo $app - ./translate_subx init.$OS [012]*.subx apps/subx-params.subx apps/$app.subx + ./translate_subx init.linux [012]*.subx apps/subx-params.subx apps/$app.subx diff apps/$app a.elf done # Mu translator echo mu -./translate_subx init.$OS [0-2]*.subx apps/mu.subx +./translate_subx init.linux [0-2]*.subx apps/mu.subx diff apps/mu a.elf # Mu programs echo ex1.mu ./translate_mu apps/ex1.mu -test $EMULATED && { - ./bootstrap run a.elf || ret=$? +{ + ./bootstrap_bin run a.elf || ret=$? test $ret -eq 42 # life, the universe and everything } -test $NATIVE && { +{ ./a.elf || ret=$? test $ret -eq 42 # life, the universe and everything } echo ex2.mu ./translate_mu apps/ex2.mu -test $EMULATED && { - ./bootstrap run a.elf || ret=$? +{ + ./bootstrap_bin run a.elf || ret=$? test $ret -eq 7 } -test $NATIVE && { +{ ./a.elf || ret=$? test $ret -eq 7 } echo ex3.mu ./translate_mu apps/ex3.mu -test $EMULATED && { - ./bootstrap run a.elf || ret=$? +{ + ./bootstrap_bin run a.elf || ret=$? test $ret -eq 55 } -test $NATIVE && { +{ ./a.elf || ret=$? test $ret -eq 55 } echo ex3.2.mu ./translate_mu apps/ex3.2.mu -test $EMULATED && { - ./bootstrap run a.elf || ret=$? +{ + ./bootstrap_bin run a.elf || ret=$? test $ret -eq 55 } -test $NATIVE && { +{ ./a.elf || ret=$? test $ret -eq 55 } echo factorial.mu ./translate_mu apps/factorial.mu -test $EMULATED && { - ./bootstrap run a.elf || ret=$? +{ + ./bootstrap_bin run a.elf || ret=$? test $ret -eq 120 - ./bootstrap run a.elf test + ./bootstrap_bin run a.elf test echo } -test $NATIVE && { +{ ./a.elf || ret=$? test $ret -eq 120 ./a.elf test diff --git a/test_apps_emulated b/test_apps_emulated new file mode 100755 index 00000000..d70c8341 --- /dev/null +++ b/test_apps_emulated @@ -0,0 +1,286 @@ +#!/bin/sh +# Build and test all included SubX programs on non-Linux platforms: +# translate them into ELF binaries +# compare the generated binaries with what's already in git +# run/test the ELF binaries in emulated mode +# +# Example usage: +# test_apps_emulated +# test_apps_emulated record # don't compare with what's in git +# +# This script is slow. 20+ times slower than running natively on Linux. + +set -e +cd `dirname $0` + +./build + +echo "== translating using the bootstrap C++ translator" + +# example programs + +echo ex1 +./bootstrap_bin translate init.linux apps/ex1.subx -o apps/ex1 +test "$1" = 'record' || git diff --exit-code apps/ex1 +{ + ./bootstrap_bin run apps/ex1 || ret=$? + test $ret -eq 42 # life, the universe and everything +} + +echo ex2 +./bootstrap_bin translate init.linux apps/ex2.subx -o apps/ex2 +test "$1" = 'record' || git diff --exit-code apps/ex2 +{ + ./bootstrap_bin run apps/ex2 || ret=$? + test $ret -eq 7 # 3 + 4 +} + +echo ex3 +./bootstrap_bin translate init.linux apps/ex3.subx -o apps/ex3 +test "$1" = 'record' || git diff --exit-code apps/ex3 +{ + ./bootstrap_bin run apps/ex3 || ret=$? + test $ret -eq 55 # 1 + 2 + ... + 10 +} + +echo ex4 +./bootstrap_bin translate init.linux apps/ex4.subx -o apps/ex4 +test "$1" = 'record' || git diff --exit-code apps/ex4 +{ + echo a | ./bootstrap_bin run apps/ex4 >ex4.out || true + test `cat ex4.out` = 'a' +} + +echo ex5 +./bootstrap_bin translate init.linux apps/ex5.subx -o apps/ex5 +test "$1" = 'record' || git diff --exit-code apps/ex5 +{ + echo a | ./bootstrap_bin run apps/ex5 >ex5.out || true + test `cat ex5.out` = 'a' +} + +echo ex6 +./bootstrap_bin translate init.linux apps/ex6.subx -o apps/ex6 +test "$1" = 'record' || git diff --exit-code apps/ex6 +{ + ./bootstrap_bin run apps/ex6 >ex6.out || true + test "`cat ex6.out`" = 'Hello, world!' +} + +echo ex7 +./bootstrap_bin translate init.linux apps/ex7.subx -o apps/ex7 +test "$1" = 'record' || git diff --exit-code apps/ex7 +{ + ./bootstrap_bin run apps/ex7 || ret=$? + test $ret -eq 97 # 'a' +} + +echo ex8 +./bootstrap_bin translate init.linux apps/ex8.subx -o apps/ex8 +test "$1" = 'record' || git diff --exit-code apps/ex8 +{ + ./bootstrap_bin run apps/ex8 abcd || ret=$? + test $ret -eq 4 # length('abcd') +} + +echo ex9 +./bootstrap_bin translate init.linux apps/ex9.subx -o apps/ex9 +test "$1" = 'record' || git diff --exit-code apps/ex9 +{ + ./bootstrap_bin run apps/ex9 z x || ret=$? + test $ret -eq 2 # 'z' - 'x' +} + +echo ex10 +./bootstrap_bin translate init.linux apps/ex10.subx -o apps/ex10 +test "$1" = 'record' || git diff --exit-code apps/ex10 +{ + ./bootstrap_bin run apps/ex10 abc abc || ret=$? + test $ret -eq 1 # equal + ./bootstrap_bin run apps/ex10 abc abcd # 0; not equal +} + +echo ex11 +./bootstrap_bin translate init.linux apps/ex11.subx -o apps/ex11 +test "$1" = 'record' || git diff --exit-code apps/ex11 +{ + ./bootstrap_bin run apps/ex11 + echo +} + +echo ex12 +./bootstrap_bin translate init.linux apps/ex12.subx -o apps/ex12 +test "$1" = 'record' || git diff --exit-code apps/ex12 +test $EMULATED && ./bootstrap_bin run apps/ex12 # final byte of mmap'd address is well-nigh guaranteed to be 0 +test $NATIVE && apps/ex12 + +echo ex13 +./bootstrap_bin translate init.linux apps/ex13.subx -o apps/ex13 +test "$1" = 'record' || git diff --exit-code apps/ex13 +{ + ./bootstrap_bin run apps/ex13 || ret=$? + test $ret -eq 1 # 3 == 3 +} + +# Larger apps that use the standard library. + +echo factorial +./bootstrap_bin translate init.linux [01]*.subx apps/factorial.subx -o apps/factorial +test "$1" = 'record' || git diff --exit-code apps/factorial +{ + ./bootstrap_bin run apps/factorial || ret=$? + test $ret -eq 120 # factorial(5) + ./bootstrap_bin run apps/factorial test + echo +} + +echo crenshaw2-1 +./bootstrap_bin translate init.linux [01]*.subx apps/crenshaw2-1.subx -o apps/crenshaw2-1 +test "$1" = 'record' || git diff --exit-code apps/crenshaw2-1 +{ + ./bootstrap_bin run apps/crenshaw2-1 test + echo +} + +echo crenshaw2-1b +./bootstrap_bin translate init.linux [01]*.subx apps/crenshaw2-1b.subx -o apps/crenshaw2-1b +test "$1" = 'record' || git diff --exit-code apps/crenshaw2-1b +{ + ./bootstrap_bin run apps/crenshaw2-1b test + echo +} + +# Phases of the self-hosted SubX translator. + +for phase in hex survey pack assort dquotes tests +do + echo $phase + ./bootstrap_bin translate init.linux [01]*.subx apps/subx-params.subx apps/$phase.subx -o apps/$phase + test "$1" = 'record' || git diff --exit-code apps/$phase + { + ./bootstrap_bin run apps/$phase test + echo + } +done + +# Higher-level syntax. + +# Certain phases of translation run native beyond this point. We're starting +# to go beyond functionality of the C++ bootstrap_bin. + +echo sigils +./bootstrap_bin translate init.linux [012]*.subx apps/subx-params.subx apps/sigils.subx -o apps/sigils +test "$1" = 'record' || git diff --exit-code apps/sigils +{ + ./bootstrap_bin run apps/sigils test + echo +} + +echo calls +cat init.linux [012]*.subx apps/subx-params.subx apps/calls.subx | ./bootstrap_bin run apps/sigils > a.sigils +./bootstrap_bin translate a.sigils -o apps/calls +test "$1" = 'record' || git diff --exit-code apps/calls +{ + ./bootstrap_bin run apps/calls test + echo +} + +echo braces +cat init.linux [012]*.subx apps/subx-params.subx apps/braces.subx | ./bootstrap_bin run apps/calls | ./bootstrap_bin run apps/sigils > a.sigils +./bootstrap_bin translate a.sigils -o apps/braces +test "$1" = 'record' || git diff --exit-code apps/braces +{ + ./bootstrap_bin run apps/braces test + echo +} + +echo mu +cat init.linux [0-2]*.subx apps/mu.subx | ./bootstrap_bin run apps/braces | ./bootstrap_bin run apps/calls | ./bootstrap_bin run apps/sigils > a.sigils +./bootstrap_bin translate a.sigils -o apps/mu +test "$1" = 'record' || git diff --exit-code apps/mu +{ + ./bootstrap_bin run apps/mu test + echo +} + +echo "== translating using the self-hosted translator" + +# example programs + +for n in `seq 1 12` +do + echo ex$n + ./translate_subx_emulated init.linux apps/ex$n.subx + diff apps/ex$n a.elf +done + +# Larger apps that use the standard library. + +for app in factorial crenshaw2-1 crenshaw2-1b +do + echo $app + ./translate_subx_emulated init.linux [01]*.subx apps/$app.subx + diff apps/$app a.elf +done + +# Phases of the self-hosted SubX translator. + +for app in hex survey pack assort dquotes tests +do + echo $app + ./translate_subx_emulated init.linux [01]*.subx apps/subx-params.subx apps/$app.subx + diff apps/$app a.elf +done + +for app in sigils calls braces +do + echo $app + ./translate_subx_emulated init.linux [012]*.subx apps/subx-params.subx apps/$app.subx + diff apps/$app a.elf +done + +# Mu translator +echo mu +./translate_subx_emulated init.linux [0-2]*.subx apps/mu.subx +diff apps/mu a.elf + +# Mu programs + +echo ex1.mu +./translate_mu_emulated apps/ex1.mu +{ + ./bootstrap_bin run a.elf || ret=$? + test $ret -eq 42 # life, the universe and everything +} + +echo ex2.mu +./translate_mu_emulated apps/ex2.mu +{ + ./bootstrap_bin run a.elf || ret=$? + test $ret -eq 7 +} + +echo ex3.mu +./translate_mu_emulated apps/ex3.mu +{ + ./bootstrap_bin run a.elf || ret=$? + test $ret -eq 55 +} + +echo ex3.2.mu +./translate_mu_emulated apps/ex3.2.mu +{ + ./bootstrap_bin run a.elf || ret=$? + test $ret -eq 55 +} + +echo factorial.mu +./translate_mu_emulated apps/factorial.mu +{ + ./bootstrap_bin run a.elf || ret=$? + test $ret -eq 120 + ./bootstrap_bin run a.elf test + echo +} + +exit 0 diff --git a/translate_mu b/translate_mu index 77098093..b4806bc5 100755 --- a/translate_mu +++ b/translate_mu @@ -1,6 +1,5 @@ #!/bin/sh -# Translate given Mu programs into ELF binaries. -# Linux only for now. +# Translate a given Mu program into an ELF binary on Linux. set -e diff --git a/translate_mu_debug b/translate_mu_debug index b6176a82..8bee3906 100755 --- a/translate_mu_debug +++ b/translate_mu_debug @@ -1,5 +1,8 @@ #!/bin/sh -# Translate Mu programs with debug information on Linux. +# Translate given Mu files with debug information on Linux. +# +# (You _could_ do something similar on other platforms using emulation. But I +# often find that to be too slow.) set -e diff --git a/translate_mu_emulated b/translate_mu_emulated new file mode 100755 index 00000000..7a305b96 --- /dev/null +++ b/translate_mu_emulated @@ -0,0 +1,10 @@ +#!/bin/sh +# Translate a Mu program using emulated mode on Linux or BSD or Mac. + +set -e + +./build + +cat $* [0-9]*.mu |./bootstrap_bin run apps/mu > a.subx + +./translate_subx_emulated init.linux [0-9]*.subx mu-init.subx a.subx diff --git a/translate_subx b/translate_subx index ba36986a..ebde020a 100755 --- a/translate_subx +++ b/translate_subx @@ -1,19 +1,6 @@ #!/bin/sh -# Translate SubX by running the self-hosted translator natively on Linux. -# -# Possible knobs: -# Whether to run a phase natively or in emulated mode. -# This script is for running natively. -# Whether to stop after a phase. -# This script assumes inputs are already working so doesn't easily show -# which phase an error happens in. -# Whether to trace a phase. Whether to always trace or rerun with tracing -# enabled after an error. -# Leave tracing to other scripts. We save intermediate files so it's easy -# to rerun a single phase afterwards. -# Whether to run a phase with debug information. (Need to juggle multiple -# sets of debug files.) -# Again, that's for subsequent scripts. +# Translate given SubX files by running the self-hosted translator natively on +# Linux. set -e diff --git a/translate_subx_debug b/translate_subx_debug index 021de0a4..7f558fc9 100755 --- a/translate_subx_debug +++ b/translate_subx_debug @@ -1,28 +1,32 @@ #!/bin/sh -# Translate SubX files with debug information on Linux. +# Translate given SubX files with debug information on Linux. # -# Mu's core tooling has a gap: -# 0. The C++ translator 'subx translate' can generate debug information on -# Linux or BSD or Mac, but doesn't support any syntax sugar. -# 1. The self-hosted translator 'translate' runs in emulated mode and can -# run on Linux or BSD or Mac. However, syntax sugar passes (sigils and -# calls) can be very slow to run emulated. -# 2. The self-hosted translator 'translate_subx' runs natively on Linux. It is -# fast, but you get no trace for runs and zero error-checking on the code -# emitted by sigils and calls. Which could still be buggy. +# Mu provides 3 canonical ways to translate unsafe SubX programs: +# 0. The C++ translator 'bootstrap translate' can generate traces for +# debugging on Linux or BSD or Mac, but doesn't support any syntax sugar. +# 1. The self-hosted translator can be run natively on Linux using +# 'translate_subx'. It is fast and supports all syntax sugar, but you get no +# trace for debugging. +# 2. The self-hosted translator can be run emulated on Linux or BSD or Mac +# using 'translate_subx_emulated'. It supports all syntax sugar. However, it +# can be slow if you generate traces. # -# This script is a hack to get the best of all worlds. We run natively what we -# must, and leverage as much debug information as possible. This arrangement -# is snappy but requires Linux just like 'translate_subx'. You also are on your -# own to mentally map desugared instructions in traces and error messages back -# to the original sources. +# This script fills in the gap above by stitching together aspects from +# multiple approaches. It translates syntax sugar natively, but emulates lower +# levels using the C++ translator. The result is complete and relatively fast +# even when generating traces. +# +# The cost: it needs Linux. There is no script to generate traces while +# running emulated on BSD or Mac. That's often impractically slow. set -e +./build + cat $* |apps/braces > a.braces cat a.braces |apps/calls > a.calls cat a.calls |apps/sigils > a.sigils -./bootstrap --debug translate a.sigils -o a.elf +./bootstrap_bin --debug translate a.sigils -o a.elf chmod +x a.elf diff --git a/translate_subx_emulated b/translate_subx_emulated index 0f013dfc..4a75c03b 100755 --- a/translate_subx_emulated +++ b/translate_subx_emulated @@ -1,20 +1,8 @@ #!/bin/sh -# Translate SubX by running the self-hosted translator in emulated mode on -# Linux or BSD or Mac. +# Translate given SubX files by running the self-hosted translator in emulated +# mode on Linux or BSD or Mac. # -# Possible knobs: -# Whether to run a phase natively or in emulated mode. -# Just always emulate for now since we debug on non-Linux. -# Whether to stop after a phase. -# Just always run all phases, but print out phases so it's clear where an -# error happens. -# Whether to trace a phase. Whether to always trace or rerun with tracing -# enabled after an error. -# Leave tracing to other scripts. We save intermediate files so it's easy -# to rerun a single phase afterwards. -# Whether to run a phase with debug information. (Need to juggle multiple -# sets of debug files.) -# Again, that's for subsequent scripts. +# We _could_ generate traces here, but that's often extremely slow. set -e @@ -24,9 +12,10 @@ cat $* |./bootstrap_bin run apps/braces > a.braces cat a.braces |./bootstrap_bin run apps/calls > a.calls cat a.calls |./bootstrap_bin run apps/sigils > a.sigils cat a.sigils |./bootstrap_bin run apps/tests > a.tests -cat a.tests |./bootstrap_bin run apps/dquotes > a.dquotes -cat a.dquotes |./bootstrap_bin run apps/assort > a.assort -cat a.assort |./bootstrap_bin run apps/pack > a.pack +cat a.tests |./bootstrap_bin run apps/assort > a.assort +cat a.assort |./bootstrap_bin run apps/dquotes > a.dquotes +cat a.dquotes |./bootstrap_bin run apps/assort > a.assort2 +cat a.assort2 |./bootstrap_bin run apps/pack > a.pack cat a.pack |./bootstrap_bin run apps/survey > a.survey cat a.survey |./bootstrap_bin run apps/hex > a.elf