├── .gitattributes ├── .gitignore ├── 101screen.subx ├── 102keyboard.subx ├── 103glyph.subx ├── 104test.subx ├── 105string-equal.subx ├── 106stream.subx ├── 108write.subx ├── 109stream-equal.subx ├── 112read-byte.subx ├── 113write-stream.subx ├── 115write-byte.subx ├── 117write-int-hex.subx ├── 118parse-hex-int.subx ├── 120allocate.subx ├── 121new-stream.subx ├── 123slice.subx ├── 124next-token.subx ├── 126write-int-decimal.subx ├── 127next-word.subx ├── 301array-equal.subx ├── 302stack_allocate.subx ├── 308allocate-array.subx ├── 309stream.subx ├── 310copy-bytes.subx ├── 311decimal-int.subx ├── 312copy.subx ├── 313index-bounds-check.subx ├── 314divide.subx ├── 315stack-debug.subx ├── 316colors.subx ├── 317abort.subx ├── 318debug-counter.subx ├── 319timer.subx ├── 400.mu ├── 403unicode.mu ├── 408float.mu ├── 411string.mu ├── 412render-float-decimal.mu ├── 500fake-screen.mu ├── 501draw-text.mu ├── 502test.mu ├── 503manhattan-line.mu ├── 504test-screen.mu ├── 505colors.mu ├── 506math.mu ├── 507line.mu ├── 508circle.mu ├── 509bezier.mu ├── 510disk.mu ├── 511image.mu ├── 512array.mu ├── 513grapheme-stack.mu ├── 514gap-buffer.mu ├── 515parse-float.mu ├── 516read-line.mu ├── 517random.mu ├── LICENSE.txt ├── README.md ├── apps ├── boot0.hex ├── color-game.mu ├── colors.mu ├── ex1.mu ├── ex10.mu ├── ex11.mu ├── ex12.mu ├── ex13.mu ├── ex14.mu ├── ex15.mu ├── ex2.mu ├── ex3.mu ├── ex4.mu ├── ex5.mu ├── ex6.mu ├── ex7.mu ├── ex8.mu ├── ex9.mu ├── hest-life.mu ├── life.mu ├── mandelbrot-fixed.mu ├── mandelbrot-silhouette.mu ├── mandelbrot.mu ├── rpn.mu ├── tile.mu └── vimrc.vim ├── archive ├── 0.vm.arc │ ├── Readme.md │ ├── blocking.arc.t │ ├── buffered-stdin.mu │ ├── callcc.mu │ ├── channel.mu │ ├── charterm │ │ ├── charterm.rkt │ │ ├── demo.rkt │ │ ├── doc.scrbl │ │ ├── info.rkt │ │ ├── main.rkt │ │ ├── planet-docs │ │ │ └── doc │ │ │ │ ├── index.html │ │ │ │ ├── racket.css │ │ │ │ ├── scribble-common.js │ │ │ │ ├── scribble-style.css │ │ │ │ └── scribble.css │ │ └── test-charterm.rkt │ ├── chessboard.arc.t │ ├── chessboard.mu │ ├── color-repl.mu │ ├── counters.mu │ ├── edit.arc.t │ ├── edit.mu │ ├── exuberant-ctags-rc │ ├── factorial.mu │ ├── fork.mu │ ├── generic.mu │ ├── graphics.mu │ ├── highlights │ ├── load.arc │ ├── mu │ ├── mu.arc │ ├── mu.arc.t │ ├── mu.arc.t.html │ ├── render.vim │ ├── scratch.vim │ ├── stdin.mu │ ├── tangle.mu │ ├── trace.arc.t │ ├── trace.mu │ ├── vimrc.vim │ └── x.mu ├── 1.vm │ ├── 000organization.cc │ ├── 001help.cc │ ├── 002test.cc │ ├── 003trace.cc │ ├── 003trace.test.cc │ ├── 010vm.cc │ ├── 011load.cc │ ├── 012transform.cc │ ├── 013update_operation.cc │ ├── 014literal_string.cc │ ├── 015literal_noninteger.cc │ ├── 016dilated_reagent.cc │ ├── 017parse_tree.cc │ ├── 018constant.cc │ ├── 019type_abbreviations.cc │ ├── 020run.cc │ ├── 021check_instruction.cc │ ├── 022arithmetic.cc │ ├── 023boolean.cc │ ├── 024jump.cc │ ├── 025compare.cc │ ├── 026call.cc │ ├── 027call_ingredient.cc │ ├── 028call_return.cc │ ├── 029tools.cc │ ├── 030container.cc │ ├── 031merge.cc │ ├── 032array.cc │ ├── 033exclusive_container.cc │ ├── 034address.cc │ ├── 035lookup.cc │ ├── 036abandon.cc │ ├── 038new_text.cc │ ├── 040brace.cc │ ├── 041jump_target.cc │ ├── 042name.cc │ ├── 043space.cc │ ├── 044space_surround.cc │ ├── 045closure_name.cc │ ├── 046check_type_by_name.cc │ ├── 050scenario.cc │ ├── 051scenario_test.mu │ ├── 052tangle.cc │ ├── 053recipe_header.cc │ ├── 054static_dispatch.cc │ ├── 055shape_shifting_container.cc │ ├── 056shape_shifting_recipe.cc │ ├── 057immutable.cc │ ├── 058to_text.cc │ ├── 059to_text.mu │ ├── 060rewrite_literal_string.cc │ ├── 061text.mu │ ├── 062convert_ingredients_to_text.cc │ ├── 063array.mu │ ├── 064list.mu │ ├── 065duplex_list.mu │ ├── 066stream.mu │ ├── 067random.cc │ ├── 068random.mu │ ├── 069hash.cc │ ├── 070table.mu │ ├── 072recipe.cc │ ├── 073scheduler.cc │ ├── 074wait.cc │ ├── 075channel.mu │ ├── 076continuation.cc │ ├── 080display.cc │ ├── 081print.mu │ ├── 082scenario_screen.cc │ ├── 083scenario_screen_test.mu │ ├── 084console.mu │ ├── 085scenario_console.cc │ ├── 086scenario_console_test.mu │ ├── 087file.cc │ ├── 088file.mu │ ├── 089scenario_filesystem.cc │ ├── 090scenario_filesystem_test.mu │ ├── 091socket.cc │ ├── 092socket.mu │ ├── 099hardware_checks.cc │ ├── 101run_sandboxed.cc │ ├── 998check_type_pointers.cc │ ├── 999spaces.cc │ ├── Readme.md │ ├── args.mu │ ├── build0 │ ├── build1 │ ├── build2 │ ├── build3 │ ├── build4 │ ├── build_and_test_until │ ├── cannot_write_tests_for │ ├── channel.mu │ ├── chessboard.mu │ ├── clean │ ├── cleave │ │ ├── Readme │ │ └── cleave.cc │ ├── console.mu │ ├── continuation1.mu │ ├── continuation2.mu │ ├── continuation3.mu │ ├── continuation4.mu │ ├── continuation5.mu │ ├── copy_mu │ ├── counters.mu │ ├── display.mu │ ├── edit │ │ ├── 001-editor.mu │ │ ├── 002-typing.mu │ │ ├── 003-shortcuts.mu │ │ ├── 004-programming-environment.mu │ │ ├── 005-sandbox.mu │ │ ├── 006-sandbox-copy.mu │ │ ├── 007-sandbox-delete.mu │ │ ├── 008-sandbox-edit.mu │ │ ├── 009-sandbox-test.mu │ │ ├── 010-sandbox-trace.mu │ │ ├── 011-errors.mu │ │ ├── 012-editor-undo.mu │ │ └── Readme.md │ ├── example1.mu │ ├── exception1.mu │ ├── exception2.mu │ ├── exuberant_ctags_rc │ ├── factorial.mu │ ├── filesystem.mu │ ├── fork.mu │ ├── git_log_filtered │ ├── http-client.mu │ ├── http-server.mu │ ├── immutable-error.mu │ ├── lambda-to-mu.mu │ ├── mu │ ├── mu.vim │ ├── mutable.mu │ ├── new_lesson │ ├── nqueens.mu │ ├── real-files.mu │ ├── relayout │ ├── same-fringe.mu │ ├── sandbox │ │ ├── 001-editor.mu │ │ ├── 002-typing.mu │ │ ├── 003-shortcuts.mu │ │ ├── 004-programming-environment.mu │ │ ├── 005-sandbox.mu │ │ ├── 006-sandbox-copy.mu │ │ ├── 007-sandbox-delete.mu │ │ ├── 008-sandbox-edit.mu │ │ ├── 009-sandbox-test.mu │ │ ├── 010-sandbox-trace.mu │ │ ├── 011-errors.mu │ │ ├── 012-editor-undo.mu │ │ ├── Readme.md │ │ ├── mu_run │ │ └── tmux.conf │ ├── screen.mu │ ├── snapshot_lesson │ ├── static-dispatch.mu │ ├── tangle.mu │ ├── termbox │ │ ├── COPYING │ │ ├── Readme │ │ ├── bytebuffer.inl │ │ ├── input.inl │ │ ├── output.inl │ │ ├── termbox.c │ │ ├── termbox.h │ │ └── utf8.c │ ├── test_layers │ ├── vimrc.vim │ └── x.mu ├── 2.transect │ ├── Readme │ ├── compiler10 │ ├── compiler2 │ ├── compiler3 │ ├── compiler4 │ ├── compiler5 │ ├── compiler6 │ ├── compiler7 │ ├── compiler8 │ ├── compiler9 │ ├── ex3.k2 │ ├── ex4.k2 │ ├── ex5.k2 │ ├── ex6.k2 │ ├── ex7.k2 │ ├── ex8.k2 │ ├── factorial.k2 │ └── vimrc.vim └── Readme.md ├── boot.subx ├── browse-slack ├── README.md ├── convert_slack.py ├── environment.mu ├── main.mu ├── test_data └── vimrc.vim ├── cheatsheet.pdf ├── editor ├── Mu.tmbundle │ ├── Syntaxes │ │ └── Mu.tmLanguage │ └── info.plist ├── README.md ├── VSCode │ ├── .vscode │ │ └── launch.json │ ├── .vscodeignore │ ├── language-configuration.json │ ├── package.json │ └── syntaxes │ │ └── Mu.tmLanguage ├── atom │ ├── README.md │ ├── grammars │ │ └── subx.json │ ├── package.json │ └── styles │ │ └── styles.less ├── editor.md ├── mu.ctags ├── mu.dte ├── mu.nanorc ├── mu.vim ├── mulisp.vim ├── subx.dte ├── subx.el ├── subx.gedit ├── subx.nanorc └── subx.vim ├── font.subx ├── help ├── html ├── 101screen.subx.html ├── 102keyboard.subx.html ├── 103glyph.subx.html ├── 104test.subx.html ├── 105string-equal.subx.html ├── 106stream.subx.html ├── 108write.subx.html ├── 109stream-equal.subx.html ├── 112read-byte.subx.html ├── 113write-stream.subx.html ├── 115write-byte.subx.html ├── 117write-int-hex.subx.html ├── 118parse-hex-int.subx.html ├── 120allocate.subx.html ├── 121new-stream.subx.html ├── 123slice.subx.html ├── 124next-token.subx.html ├── 126write-int-decimal.subx.html ├── 127next-word.subx.html ├── 20210624-shell.png ├── 301array-equal.subx.html ├── 302stack_allocate.subx.html ├── 308allocate-array.subx.html ├── 309stream.subx.html ├── 310copy-bytes.subx.html ├── 311decimal-int.subx.html ├── 312copy.subx.html ├── 313index-bounds-check.subx.html ├── 314divide.subx.html ├── 315stack-debug.subx.html ├── 316colors.subx.html ├── 317abort.subx.html ├── 318counter.subx.html ├── 318debug-counter.subx.html ├── 319timer.subx.html ├── 400.mu.html ├── 403unicode.mu.html ├── 408float.mu.html ├── 411string.mu.html ├── 412render-float-decimal.mu.html ├── 500fake-screen.mu.html ├── 501draw-text.mu.html ├── 502test.mu.html ├── 503manhattan-line.mu.html ├── 504test-screen.mu.html ├── 505colors.mu.html ├── 506math.mu.html ├── 507line.mu.html ├── 508circle.mu.html ├── 509bezier.mu.html ├── 510disk.mu.html ├── 511image.mu.html ├── 512array.mu.html ├── 513grapheme-stack.mu.html ├── 514gap-buffer.mu.html ├── 515parse-float.mu.html ├── 516read-line.mu.html ├── apps │ ├── *.subx.html │ ├── color-game.mu.html │ ├── colors.mu.html │ ├── ex1.mu.html │ ├── ex10.mu.html │ ├── ex11.mu.html │ ├── ex12.mu.html │ ├── ex13.mu.html │ ├── ex14.mu.html │ ├── ex15.mu.html │ ├── ex2.mu.html │ ├── ex3.mu.html │ ├── ex4.mu.html │ ├── ex5.mu.html │ ├── ex6.mu.html │ ├── ex7.mu.html │ ├── ex8.mu.html │ ├── ex9.mu.html │ ├── hest-life.mu.html │ ├── life.mu.html │ ├── mandelbrot-fixed.mu.html │ ├── mandelbrot-silhouette.mu.html │ ├── mandelbrot.mu.html │ ├── rpn.mu.html │ └── tile.mu.html ├── archive │ └── 2.vm │ │ ├── chessboard-test.png │ │ ├── edit.png │ │ ├── example1.png │ │ ├── expected-result.png │ │ ├── f2c-1.mu │ │ ├── f2c-1.png │ │ ├── f2c-2.mu │ │ ├── f2c-2.png │ │ ├── factorial-test.png │ │ ├── factorial.png │ │ ├── fake-console.png │ │ ├── fake-keyboard.png │ │ ├── fork.png │ │ ├── immutable-error.png │ │ ├── mutable.png │ │ ├── resources.mu │ │ ├── resources.png │ │ ├── tangle.png │ │ ├── tmux-vim-sandbox.png │ │ ├── tracing-test.mu │ │ ├── tracing-test.png │ │ └── unexpected-result.png ├── boot.subx.html ├── browse-slack │ ├── environment.mu.html │ └── main.mu.html ├── control0.png ├── control1.png ├── encoding.png ├── ex2.mu.png ├── ex3.png ├── font.subx.html ├── life.png ├── linux │ ├── 000init.subx.html │ ├── 101_write.subx.html │ ├── 102test.subx.html │ ├── 103kernel-string-equal.subx.html │ ├── 104new-segment.subx.html │ ├── 105string-equal.subx.html │ ├── 106stream.subx.html │ ├── 107trace.subx.html │ ├── 108write.subx.html │ ├── 109stream-equal.subx.html │ ├── 110stop.subx.html │ ├── 111read.subx.html │ ├── 112read-byte.subx.html │ ├── 113write-stream.subx.html │ ├── 114error.subx.html │ ├── 115write-byte.subx.html │ ├── 116write-buffered.subx.html │ ├── 117write-int-hex.subx.html │ ├── 118parse-hex-int.subx.html │ ├── 119error-byte.subx.html │ ├── 120allocate.subx.html │ ├── 121new-stream.subx.html │ ├── 122read-line.subx.html │ ├── 123slice.subx.html │ ├── 124next-token.subx.html │ ├── 125write-stream-data.subx.html │ ├── 126write-int-decimal.subx.html │ ├── 127next-word.subx.html │ ├── 128subx-words.subx.html │ ├── 129emit-hex.subx.html │ ├── 130emit.subx.html │ ├── 131table.subx.html │ ├── 132slurp.subx.html │ ├── 133subx-widths.subx.html │ ├── 134emit-hex-array.subx.html │ ├── 135next-word-or-string.subx.html │ ├── 201register-names.subx.html │ ├── 202write-int.subx.html │ ├── 203stack.subx.html │ ├── 301array-equal.subx.html │ ├── 302stack_allocate.subx.html │ ├── 303kernel-string.subx.html │ ├── 304screen.subx.html │ ├── 305keyboard.subx.html │ ├── 306files.subx.html │ ├── 307size.subx.html │ ├── 308allocate-array.subx.html │ ├── 309stream.subx.html │ ├── 310copy-bytes.subx.html │ ├── 311decimal-int.subx.html │ ├── 312copy.subx.html │ ├── 313index-bounds-check.subx.html │ ├── 314divide.subx.html │ ├── 315slice.subx.html │ ├── 400.mu.html │ ├── 401test.mu.html │ ├── 402time.mu.html │ ├── 403unicode.mu.html │ ├── 404stream.mu.html │ ├── 405screen.mu.html │ ├── 406int32.mu.html │ ├── 407right-justify.mu.html │ ├── 408float.mu.html │ ├── 409print-float-hex.mu.html │ ├── 410file.mu.html │ ├── 411string.mu.html │ ├── 412print-float-decimal.mu.html │ ├── apps │ │ ├── advent2017 │ │ │ └── 1a.mu.html │ │ ├── advent2020 │ │ │ ├── 1a.mu.html │ │ │ ├── 1b.mu.html │ │ │ ├── 2a.mu.html │ │ │ ├── 2b.mu.html │ │ │ ├── 3a.mu.html │ │ │ ├── 3b.mu.html │ │ │ ├── 4a.mu.html │ │ │ ├── 4b.mu.html │ │ │ ├── 5a.mu.html │ │ │ └── 5b.mu.html │ │ ├── arith.mu.html │ │ ├── crenshaw2-1.subx.html │ │ ├── crenshaw2-1b.subx.html │ │ ├── ex1.mu.html │ │ ├── ex1.subx.html │ │ ├── ex10.subx.html │ │ ├── ex11.subx.html │ │ ├── ex12.subx.html │ │ ├── ex13.subx.html │ │ ├── ex14.subx.html │ │ ├── ex2.mu.html │ │ ├── ex2.subx.html │ │ ├── ex3.2.mu.html │ │ ├── ex3.mu.html │ │ ├── ex3.subx.html │ │ ├── ex4.subx.html │ │ ├── ex5.subx.html │ │ ├── ex6.subx.html │ │ ├── ex7.subx.html │ │ ├── ex8.subx.html │ │ ├── ex9.subx.html │ │ ├── factorial.mu.html │ │ ├── factorial.subx.html │ │ ├── factorial2.subx.html │ │ ├── factorial3.subx.html │ │ ├── factorial4.subx.html │ │ ├── hello.mu.html │ │ ├── parse-int.mu.html │ │ ├── print-file.mu.html │ │ ├── random.subx.html │ │ ├── raytracing │ │ │ ├── 1.mu.html │ │ │ ├── 2.mu.html │ │ │ ├── 3.mu.html │ │ │ ├── color.mu.html │ │ │ ├── ray.mu.html │ │ │ └── vec.mu.html │ │ ├── rpn.mu.html │ │ ├── texture.mu.html │ │ └── tui.mu.html │ ├── assort.subx.html │ ├── bootstrap │ │ ├── 000organization.cc.html │ │ ├── 001help.cc.html │ │ ├── 002test.cc.html │ │ ├── 003trace.cc.html │ │ ├── 003trace.test.cc.html │ │ ├── 010vm.cc.html │ │ ├── 011run.cc.html │ │ ├── 012elf.cc.html │ │ ├── 013direct_addressing.cc.html │ │ ├── 014indirect_addressing.cc.html │ │ ├── 015immediate_addressing.cc.html │ │ ├── 016index_addressing.cc.html │ │ ├── 017jump_disp8.cc.html │ │ ├── 018jump_disp32.cc.html │ │ ├── 019functions.cc.html │ │ ├── 020byte_addressing.cc.html │ │ ├── 021div.cc.html │ │ ├── 022float.cc.html │ │ ├── 029syscalls.cc.html │ │ ├── 030translate.cc.html │ │ ├── 031transforms.cc.html │ │ ├── 032operands.cc.html │ │ ├── 033check_operands.cc.html │ │ ├── 034check_operand_bounds.cc.html │ │ ├── 035compute_segment_address.cc.html │ │ ├── 036labels.cc.html │ │ ├── 037global_variables.cc.html │ │ ├── 038literal_strings.cc.html │ │ ├── 039debug.cc.html │ │ └── 040tests.cc.html │ ├── braces.subx.html │ ├── branches.mu.html │ ├── calls.subx.html │ ├── dquotes.subx.html │ ├── ex1.subx.html │ ├── ex10.subx.html │ ├── ex11.subx.html │ ├── ex12.subx.html │ ├── ex13.subx.html │ ├── ex14.subx.html │ ├── ex2.subx.html │ ├── ex3.subx.html │ ├── ex4.subx.html │ ├── ex5.subx.html │ ├── ex6.subx.html │ ├── ex7.subx.html │ ├── ex8.subx.html │ ├── ex9.subx.html │ ├── factorial.subx.html │ ├── factorial2.subx.html │ ├── factorial3.subx.html │ ├── factorial4.subx.html │ ├── hex.subx.html │ ├── labels_baremetal.subx.html │ ├── mu-init-test.subx.html │ ├── mu-init.subx.html │ ├── mu.subx.html │ ├── pack.subx.html │ ├── sigils.subx.html │ ├── stack_array.subx.html │ ├── subx-params.subx.html │ ├── survey_baremetal.subx.html │ ├── survey_elf.subx.html │ ├── tests.subx.html │ └── tile │ │ ├── box.mu.html │ │ ├── data.mu.html │ │ ├── environment.mu.html │ │ ├── float-stack.mu.html │ │ ├── gap-buffer.mu.html │ │ ├── grapheme-stack.mu.html │ │ ├── main.mu.html │ │ ├── rpn.mu.html │ │ ├── surface.mu.html │ │ ├── table.mu.html │ │ ├── value-stack.mu.html │ │ ├── value.mu.html │ │ └── word.mu.html ├── mu-init.subx.html ├── mu_instructions.html ├── rpn5.png ├── shell │ ├── cell.mu.html │ ├── data.limg.html │ ├── environment.mu.html │ ├── evaluate.mu.html │ ├── global.mu.html │ ├── infix.mu.html │ ├── int-stack.mu.html │ ├── macroexpand.mu.html │ ├── main.mu.html │ ├── parenthesize.mu.html │ ├── parse.mu.html │ ├── primitives.mu.html │ ├── print.mu.html │ ├── read.mu.html │ ├── sandbox.mu.html │ ├── tokenize.mu.html │ └── trace.mu.html ├── signatures.mu.html ├── trace.png └── vga_palette.html ├── linux ├── 000init.subx ├── 100.txt ├── 101_write.subx ├── 102test.subx ├── 103kernel-string-equal.subx ├── 104new-segment.subx ├── 105string-equal.subx ├── 106stream.subx ├── 107trace.subx ├── 108write.subx ├── 109stream-equal.subx ├── 110stop.subx ├── 111read.subx ├── 112read-byte.subx ├── 113write-stream.subx ├── 114error.subx ├── 115write-byte.subx ├── 116write-buffered.subx ├── 117write-int-hex.subx ├── 118parse-hex-int.subx ├── 119error-byte.subx ├── 120allocate.subx ├── 121new-stream.subx ├── 122read-line.subx ├── 123slice.subx ├── 124next-token.subx ├── 125write-stream-data.subx ├── 126write-int-decimal.subx ├── 127next-word.subx ├── 128subx-words.subx ├── 129emit-hex.subx ├── 130emit.subx ├── 131table.subx ├── 132slurp.subx ├── 133subx-widths.subx ├── 134emit-hex-array.subx ├── 135next-word-or-string.subx ├── 200.txt ├── 201register-names.subx ├── 202write-int.subx ├── 203stack.subx ├── 300.txt ├── 301array-equal.subx ├── 302stack_allocate.subx ├── 303kernel-string.subx ├── 304screen.subx ├── 305keyboard.subx ├── 306files.subx ├── 307size.subx ├── 308allocate-array.subx ├── 309stream.subx ├── 310copy-bytes.subx ├── 311decimal-int.subx ├── 312copy.subx ├── 313index-bounds-check.subx ├── 314divide.subx ├── 315slice.subx ├── 400.mu ├── 401test.mu ├── 402time.mu ├── 403unicode.mu ├── 404stream.mu ├── 405screen.mu ├── 406int32.mu ├── 407right-justify.mu ├── 408float.mu ├── 409print-float-hex.mu ├── 410file.mu ├── 411string.mu ├── 412print-float-decimal.mu ├── README.md ├── apps │ ├── advent2017 │ │ └── 1a.mu │ ├── advent2020 │ │ ├── 1a.mu │ │ ├── 1b.mu │ │ ├── 2a.mu │ │ ├── 2b.mu │ │ ├── 3a.mu │ │ ├── 3b.mu │ │ ├── 4a.mu │ │ ├── 4b.mu │ │ ├── 5a.mu │ │ ├── 5b.mu │ │ └── vimrc.vim │ ├── arith.mu │ ├── ex1.mu │ ├── ex1.subx │ ├── ex10.subx │ ├── ex11.subx │ ├── ex12.subx │ ├── ex13.subx │ ├── ex14.subx │ ├── ex2.mu │ ├── ex2.subx │ ├── ex3.2.mu │ ├── ex3.mu │ ├── ex3.subx │ ├── ex4.subx │ ├── ex5.subx │ ├── ex6.subx │ ├── ex7.subx │ ├── ex8.subx │ ├── ex9.subx │ ├── factorial.mu │ ├── factorial.subx │ ├── factorial2.subx │ ├── factorial3.subx │ ├── factorial4.subx │ ├── hello.mu │ ├── parse-int.mu │ ├── print-file.mu │ ├── random.subx │ ├── raytracing │ │ ├── 1.cc │ │ ├── 1.cc.0 │ │ ├── 1.mu │ │ ├── 1.ppm │ │ ├── 2.mu │ │ ├── 2.ppm │ │ ├── 3.expected.ppm │ │ ├── 3.mu │ │ ├── 3.ppm │ │ ├── README.md │ │ ├── color.h │ │ ├── color.mu │ │ ├── main.cc │ │ ├── ray.h │ │ ├── ray.mu │ │ ├── vec.mu │ │ ├── vec3.h │ │ └── vimrc.vim │ ├── rpn.mu │ ├── texture.mu │ └── tui.mu ├── assort ├── assort.subx ├── bootstrap │ ├── 000organization.cc │ ├── 001help.cc │ ├── 002test.cc │ ├── 003trace.cc │ ├── 003trace.cc.filter │ ├── 003trace.cc.rotate │ ├── 003trace.test.cc │ ├── 010vm.cc │ ├── 011run.cc │ ├── 012elf.cc │ ├── 013direct_addressing.cc │ ├── 014indirect_addressing.cc │ ├── 015immediate_addressing.cc │ ├── 016index_addressing.cc │ ├── 017jump_disp8.cc │ ├── 018jump_disp32.cc │ ├── 019functions.cc │ ├── 020byte_addressing.cc │ ├── 021div.cc │ ├── 022float.cc │ ├── 029syscalls.cc │ ├── 030translate.cc │ ├── 031transforms.cc │ ├── 032operands.cc │ ├── 033check_operands.cc │ ├── 034check_operand_bounds.cc │ ├── 035compute_segment_address.cc │ ├── 036labels.cc │ ├── 037global_variables.cc │ ├── 038literal_strings.cc │ ├── 039debug.cc │ ├── 040tests.cc │ ├── README.md │ ├── bootstrap │ ├── build │ ├── build_and_test_until │ ├── clean │ ├── test_layers │ └── tools │ │ ├── enumerate.cc │ │ ├── tangle.cc │ │ └── tangle.readme.md ├── braces ├── braces.subx ├── branches.mu ├── branches.out ├── browse │ ├── README.md │ ├── main.mu │ ├── paginated-screen.mu │ └── vimrc.vim ├── calls ├── calls.subx ├── dquotes ├── dquotes.subx ├── help ├── hex ├── hex.subx ├── labels_baremetal ├── labels_baremetal.subx ├── mu ├── mu-init-test.subx ├── mu-init.subx ├── mu.subx ├── pack ├── pack.subx ├── sigils ├── sigils.subx ├── stack_array.subx ├── stats.txt ├── subx-params.subx ├── subx_debugging.md ├── survey_baremetal ├── survey_baremetal.subx ├── survey_elf ├── survey_elf.subx ├── test_apps ├── test_apps_emulated ├── tests ├── tests.subx ├── tile │ ├── README.md │ ├── box.mu │ ├── data.mu │ ├── environment.mu │ ├── float-stack.mu │ ├── gap-buffer.mu │ ├── grapheme-stack.mu │ ├── main.mu │ ├── rpn.mu │ ├── surface.mu │ ├── table.mu │ ├── value-stack.mu │ ├── value.mu │ ├── vimrc.vim │ └── word.mu ├── translate ├── translate_debug ├── translate_emulated ├── translate_subx ├── translate_subx_debug ├── translate_subx_emulated ├── vocabulary.md └── x86_approx.md ├── misc_checks ├── misc_checks.subx ├── modrm.pdf ├── mu-init.subx ├── mu.md ├── mu_instructions ├── shell ├── README.md ├── cell.mu ├── data.limg ├── environment.mu ├── evaluate.mu ├── global.mu ├── infix.mu ├── int-stack.mu ├── macroexpand.mu ├── main.mu ├── parenthesize.mu ├── parse.mu ├── primitives.mu ├── print.mu ├── read.mu ├── sandbox.mu ├── tokenize.mu ├── trace.mu └── vimrc.vim ├── sib.pdf ├── signatures.mu ├── subx.md ├── subx_bare.md ├── subx_opcodes ├── tools ├── README.md ├── browse_trace ├── browse_trace.cc ├── browse_trace.readme.md ├── create_container ├── expand_string_handle ├── image-data ├── linkify.cc ├── mu-init-minify.subx ├── regs.mu ├── termbox │ ├── COPYING │ ├── Readme │ ├── bytebuffer.inl │ ├── input.inl │ ├── output.inl │ ├── termbox.c │ ├── termbox.h │ └── utf8.c ├── test_treeshake_translate ├── translate_minified ├── treeshake.cc ├── update_html ├── update_signatures ├── vga_palette ├── vga_palette.c └── vga_palette.png ├── translate ├── translate_emulated ├── tutorial ├── add2.mu ├── c2f.mu ├── converter.html ├── converter.mu ├── converter2.mu ├── counter.mu ├── counter.png ├── index.md ├── task1.mu ├── task1.png ├── task10-hint1.mu ├── task10-hint2.mu ├── task10-hint3.mu ├── task10-solution1.mu ├── task10.mu ├── task11-solution.mu ├── task11.mu ├── task12-solution.mu ├── task12.mu ├── task15.mu ├── task2.mu ├── task2.png ├── task3.png ├── task4-initial.png ├── task4-solution.mu ├── task4.mu ├── task5-solution.mu ├── task5.mu ├── task6-error-runbook.txt ├── task6.mu ├── task7-solution.mu ├── task7.mu ├── task8a.mu ├── task8b.mu ├── task8c.mu ├── task9-solution.mu ├── task9.mu └── vimrc.vim ├── vimrc.vim └── vocabulary.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # hide from GitHub stats 2 | index.html linguist-generated=true 3 | html/** linguist-generated=true 4 | archive/** linguist-generated=true 5 | prototypes/** linguist-generated=true 6 | tools/iso/kernel.soso/** linguist-vendored 7 | # include the bulk of the repo with an approximately-correct language 8 | # just so it seems less like a purely C++ project 9 | # unfortunately Linguist won't accept a spec for my toy languages 10 | *.subx linguist-language=Assembly 11 | *.mu linguist-language=Forth 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | a.* 2 | *.img 3 | labels 4 | -------------------------------------------------------------------------------- /104test.subx: -------------------------------------------------------------------------------- 1 | # Some helpers needed only because Mu doesn't support globals at the moment. 2 | 3 | == code 4 | 5 | count-test-failure: 6 | # . prologue 7 | 55/push-ebp 8 | 89/<- %ebp 4/r32/esp 9 | # 10 | ff 0/subop/increment *Num-test-failures 11 | $count-test-failure:end: 12 | # . epilogue 13 | 89/<- %esp 5/r32/ebp 14 | 5d/pop-to-ebp 15 | c3/return 16 | 17 | num-test-failures: # -> _/eax: int 18 | # . prologue 19 | 55/push-ebp 20 | 89/<- %ebp 4/r32/esp 21 | # 22 | 8b/-> *Num-test-failures 0/r32/eax 23 | $num-test-failures:end: 24 | # . epilogue 25 | 89/<- %esp 5/r32/ebp 26 | 5d/pop-to-ebp 27 | c3/return 28 | 29 | running-tests?: # -> _/eax: int 30 | # . prologue 31 | 55/push-ebp 32 | 89/<- %ebp 4/r32/esp 33 | # 34 | 8b/-> *Running-tests? 0/r32/eax 35 | $running-tests?:end: 36 | # . epilogue 37 | 89/<- %esp 5/r32/ebp 38 | 5d/pop-to-ebp 39 | c3/return 40 | 41 | == data 42 | 43 | Num-test-failures: 44 | 0/imm32 45 | 46 | Running-tests?: 47 | 1/imm32/true 48 | -------------------------------------------------------------------------------- /308allocate-array.subx: -------------------------------------------------------------------------------- 1 | # 2-arg version of allocate-array. 2 | # Really only intended to be called from code generated by mu.subx. 3 | 4 | == code 5 | 6 | allocate-array2: # ad: (addr allocation-descriptor), array-len: int, elem-size: int, out: (addr handle array _) 7 | # . prologue 8 | 55/push-ebp 9 | 89/<- %ebp 4/r32/esp 10 | # . save registers 11 | 50/push-eax 12 | 52/push-edx 13 | # 14 | 8b/-> *(ebp+0xc) 0/r32/eax 15 | f7 4/subop/multiply-into-edx-eax *(ebp+0x10) 16 | # TODO: check edx for overflow 17 | (allocate-array *(ebp+8) %eax *(ebp+0x14)) 18 | $allocate-array2:end: 19 | # . restore registers 20 | 5a/pop-to-edx 21 | 58/pop-to-eax 22 | # . epilogue 23 | 89/<- %esp 5/r32/ebp 24 | 5d/pop-to-ebp 25 | c3/return 26 | -------------------------------------------------------------------------------- /312copy.subx: -------------------------------------------------------------------------------- 1 | == code 2 | 3 | copy-array-object: # src: (addr array T), dest-ah: (addr handle array T) 4 | # . prologue 5 | 55/push-ebp 6 | 89/<- %ebp 4/r32/esp 7 | # 8 | (copy-array Heap *(ebp+8) *(ebp+0xc)) 9 | $copy-array-object:end: 10 | # . epilogue 11 | 89/<- %esp 5/r32/ebp 12 | 5d/pop-to-ebp 13 | c3/return 14 | -------------------------------------------------------------------------------- /314divide.subx: -------------------------------------------------------------------------------- 1 | == code 2 | 3 | integer-divide: # a: int, b: int -> quotient/eax: int, remainder/edx: int 4 | # . prologue 5 | 55/push-ebp 6 | 89/<- %ebp 4/r32/esp 7 | # eax = a 8 | 8b/-> *(ebp+8) 0/r32/eax 9 | # edx = all 0s or all 1s 10 | 99/sign-extend-eax-into-edx 11 | # quotient, remainder = divide eax by b 12 | f7 7/subop/divide-eax-edx-by *(ebp+0xc) 13 | $integer-divide:end: 14 | # . epilogue 15 | 89/<- %esp 5/r32/ebp 16 | 5d/pop-to-ebp 17 | c3/return 18 | -------------------------------------------------------------------------------- /318debug-counter.subx: -------------------------------------------------------------------------------- 1 | # A rudimentary counter that can be called from anywhere. 2 | 3 | == code 4 | 5 | count-event: 6 | # . prologue 7 | 55/push-ebp 8 | 89/<- %ebp 4/r32/esp 9 | # 10 | ff 0/subop/increment *Foo 11 | $count-event:end: 12 | # . epilogue 13 | 89/<- %esp 5/r32/ebp 14 | 5d/pop-to-ebp 15 | c3/return 16 | 17 | count-of-events: # -> _/eax: int 18 | # . prologue 19 | 55/push-ebp 20 | 89/<- %ebp 4/r32/esp 21 | # 22 | 8b/-> *Foo 0/r32/eax 23 | $count-of-events:end: 24 | # . epilogue 25 | 89/<- %esp 5/r32/ebp 26 | 5d/pop-to-ebp 27 | c3/return 28 | 29 | == data 30 | Foo: 31 | 0/imm32 32 | -------------------------------------------------------------------------------- /319timer.subx: -------------------------------------------------------------------------------- 1 | == code 2 | 3 | timer-counter: # -> _/eax: int 4 | # . prologue 5 | 55/push-ebp 6 | 89/<- %ebp 4/r32/esp 7 | # 8 | 8b/-> *Timer-counter 0/r32/eax 9 | $timer-counter:end: 10 | # . epilogue 11 | 89/<- %esp 5/r32/ebp 12 | 5d/pop-to-ebp 13 | c3/return 14 | -------------------------------------------------------------------------------- /408float.mu: -------------------------------------------------------------------------------- 1 | # Some quick-n-dirty ways to create floats. 2 | 3 | fn fill-in-rational _out: (addr float), nr: int, dr: int { 4 | var out/edi: (addr float) <- copy _out 5 | var result/xmm0: float <- convert nr 6 | var divisor/xmm1: float <- convert dr 7 | result <- divide divisor 8 | copy-to *out, result 9 | } 10 | 11 | fn fill-in-sqrt _out: (addr float), n: int { 12 | var out/edi: (addr float) <- copy _out 13 | var result/xmm0: float <- convert n 14 | result <- square-root result 15 | copy-to *out, result 16 | } 17 | 18 | fn rational nr: int, dr: int -> _/xmm0: float { 19 | var result/xmm0: float <- convert nr 20 | var divisor/xmm1: float <- convert dr 21 | result <- divide divisor 22 | return result 23 | } 24 | 25 | # n/m rounded up 26 | fn scale-down-and-round-up n: int, m: int -> _/ecx: int { 27 | var result/ecx: int <- copy n 28 | result <- add m 29 | result <- decrement 30 | var result-f/xmm0: float <- convert result 31 | var m-f/xmm1: float <- convert m 32 | result-f <- divide m-f 33 | result <- truncate result-f 34 | return result 35 | } 36 | -------------------------------------------------------------------------------- /502test.mu: -------------------------------------------------------------------------------- 1 | # print msg to screen if a != b, otherwise print "." 2 | fn check-ints-equal _a: int, b: int, msg: (addr array byte) { 3 | var a/eax: int <- copy _a 4 | compare a, b 5 | { 6 | break-if-!= 7 | draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg=cyan, 0/bg 8 | return 9 | } 10 | draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg=cyan, 0/bg 11 | move-cursor-to-left-margin-of-next-line 0/screen 12 | count-test-failure 13 | } 14 | 15 | fn test-check-ints-equal { 16 | check-ints-equal 0, 0, "abc" 17 | } 18 | 19 | fn check _a: boolean, msg: (addr array byte) { 20 | var a/eax: int <- copy _a 21 | compare a, 0/false 22 | { 23 | break-if-= 24 | draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg=cyan, 0/bg 25 | return 26 | } 27 | draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg=cyan, 0/bg 28 | move-cursor-to-left-margin-of-next-line 0/screen 29 | count-test-failure 30 | } 31 | 32 | fn check-not _a: boolean, msg: (addr array byte) { 33 | var a/eax: int <- copy _a 34 | compare a, 0/false 35 | { 36 | break-if-!= 37 | draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg=cyan, 0/bg 38 | return 39 | } 40 | draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg=cyan, 0/bg 41 | move-cursor-to-left-margin-of-next-line 0/screen 42 | count-test-failure 43 | } 44 | -------------------------------------------------------------------------------- /503manhattan-line.mu: -------------------------------------------------------------------------------- 1 | fn draw-box-on-real-screen x1: int, y1: int, x2: int, y2: int, color: int { 2 | draw-horizontal-line-on-real-screen x1, x2, y1, color 3 | draw-vertical-line-on-real-screen x1, y1, y2, color 4 | draw-horizontal-line-on-real-screen x1, x2, y2, color 5 | draw-vertical-line-on-real-screen x2, y1, y2, color 6 | } 7 | 8 | fn draw-horizontal-line-on-real-screen x1: int, x2: int, y: int, color: int { 9 | var x/eax: int <- copy x1 10 | { 11 | compare x, x2 12 | break-if->= 13 | pixel-on-real-screen x, y, color 14 | x <- increment 15 | loop 16 | } 17 | } 18 | 19 | fn draw-vertical-line-on-real-screen x: int, y1: int, y2: int, color: int { 20 | var y/eax: int <- copy y1 21 | { 22 | compare y, y2 23 | break-if->= 24 | pixel-on-real-screen x, y, color 25 | y <- increment 26 | loop 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /506math.mu: -------------------------------------------------------------------------------- 1 | fn abs n: int -> _/eax: int { 2 | compare n, 0 3 | { 4 | break-if->= 5 | negate n 6 | } 7 | return n 8 | } 9 | 10 | fn sgn n: int -> _/eax: int { 11 | compare n, 0 12 | { 13 | break-if-<= 14 | return 1 15 | } 16 | { 17 | break-if->= 18 | return -1 19 | } 20 | return 0 21 | } 22 | 23 | fn shift-left-by n: int, bits: int -> _/eax: int { 24 | var i/eax: int <- copy bits 25 | { 26 | compare i, 0 27 | break-if-<= 28 | shift-left n, 1 29 | i <- decrement 30 | loop 31 | } 32 | return n 33 | } 34 | 35 | fn shift-right-by n: int, bits: int -> _/eax: int { 36 | var i/eax: int <- copy bits 37 | { 38 | compare i, 0 39 | break-if-<= 40 | shift-right n, 1 41 | i <- decrement 42 | loop 43 | } 44 | return n 45 | } 46 | 47 | fn clear-lowest-bits _n: (addr int), bits: int { 48 | var dest/edi: (addr int) <- copy _n 49 | var n/eax: int <- copy *dest 50 | n <- shift-right-by n, bits 51 | n <- shift-left-by n, bits 52 | copy-to *dest, n 53 | } 54 | -------------------------------------------------------------------------------- /510disk.mu: -------------------------------------------------------------------------------- 1 | fn load-sectors disk: (addr disk), lba: int, n: int, out: (addr stream byte) { 2 | var curr-lba/ebx: int <- copy lba 3 | var remaining/edx: int <- copy n 4 | { 5 | compare remaining, 0 6 | break-if-<= 7 | # sectors = min(remaining, 0x100) 8 | var sectors/eax: int <- copy remaining 9 | compare sectors, 0x100 10 | { 11 | break-if-<= 12 | sectors <- copy 0x100 13 | } 14 | # 15 | read-ata-disk disk, curr-lba, sectors, out 16 | # 17 | remaining <- subtract sectors 18 | curr-lba <- add sectors 19 | loop 20 | } 21 | } 22 | 23 | fn store-sectors disk: (addr disk), lba: int, n: int, in: (addr stream byte) { 24 | var curr-lba/ebx: int <- copy lba 25 | var remaining/edx: int <- copy n 26 | { 27 | compare remaining, 0 28 | break-if-<= 29 | # sectors = min(remaining, 0x100) 30 | var sectors/eax: int <- copy remaining 31 | compare sectors, 0x100 32 | { 33 | break-if-<= 34 | sectors <- copy 0x100 35 | } 36 | # 37 | write-ata-disk disk, curr-lba, sectors, in 38 | # 39 | remaining <- subtract sectors 40 | curr-lba <- add sectors 41 | loop 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /516read-line.mu: -------------------------------------------------------------------------------- 1 | # read line from keyboard into stream while also echoing to screen 2 | # abort on stream overflow 3 | fn read-line-from-keyboard keyboard: (addr keyboard), out: (addr stream byte), screen: (addr screen), fg: int, bg: int { 4 | clear-stream out 5 | $read-line-from-keyboard:loop: { 6 | draw-cursor screen, 0x20/space 7 | var key/eax: byte <- read-key keyboard 8 | compare key, 0xa/newline 9 | break-if-= 10 | compare key, 0 11 | loop-if-= 12 | compare key, 8/backspace 13 | { 14 | break-if-!= 15 | undo-append-byte out 16 | draw-code-point-at-cursor-over-full-screen screen, 0x20/space, fg 0/bg # clear cursor 17 | move-cursor-left screen 18 | move-cursor-left screen 19 | draw-code-point-at-cursor-over-full-screen screen, 0x20/space, fg 0/bg # clear old cursor 20 | move-cursor-left screen 21 | loop $read-line-from-keyboard:loop 22 | } 23 | var key2/eax: int <- copy key 24 | append-byte out, key2 25 | var c/eax: code-point <- copy key2 26 | draw-code-point-at-cursor-over-full-screen screen, c, fg bg 27 | loop 28 | } 29 | # clear cursor 30 | draw-code-point-at-cursor-over-full-screen screen, 0x20/space, fg bg 31 | } 32 | -------------------------------------------------------------------------------- /517random.mu: -------------------------------------------------------------------------------- 1 | fn next-random prev: int -> _/edi: int { 2 | # https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use 3 | var a/ecx: int <- copy 0x4b/75 4 | var c/edx: int <- copy 0x4a/74 5 | var m/ebx: int <- copy 0x10001 6 | var next/eax: int <- copy prev 7 | next <- multiply a 8 | next <- add c 9 | next <- remainder next, m 10 | return next 11 | } 12 | 13 | fn remainder a: int, b: int -> _/eax: int { 14 | var q/eax: int <- copy 0 15 | var r/edx: int <- copy 0 16 | q, r <- integer-divide a, b 17 | return r 18 | } 19 | -------------------------------------------------------------------------------- /apps/ex1.mu: -------------------------------------------------------------------------------- 1 | # The simplest possible bare-metal program. 2 | # 3 | # To build a disk image: 4 | # ./translate apps/ex1.mu # emits code.img 5 | # To run: 6 | # qemu-system-i386 code.img 7 | # 8 | # Expected output: blank screen with no errors 9 | 10 | fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) { 11 | } 12 | -------------------------------------------------------------------------------- /apps/ex10.mu: -------------------------------------------------------------------------------- 1 | # Demo of mouse support. 2 | # 3 | # To build a disk image: 4 | # ./translate apps/ex10.mu # emits code.img 5 | # To run: 6 | # qemu-system-i386 code.img 7 | # 8 | # Expected output: 9 | # Values between -256 and +255 as you move the mouse over the window. 10 | # You might need to click on the window once. 11 | 12 | fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) { 13 | # repeatedly print out mouse driver results if non-zero 14 | $main:event-loop: { 15 | var dx/eax: int <- copy 0 16 | var dy/ecx: int <- copy 0 17 | dx, dy <- read-mouse-event 18 | { 19 | compare dx, 0 20 | break-if-!= 21 | compare dy, 0 22 | break-if-!= 23 | loop $main:event-loop 24 | } 25 | { 26 | var dummy1/eax: int <- copy 0 27 | var dummy2/ecx: int <- copy 0 28 | dummy1, dummy2 <- draw-text-wrapping-right-then-down-over-full-screen screen, " ", 0/x, 0x10/y, 0x31/fg, 0/bg 29 | } 30 | { 31 | var dummy/ecx: int <- copy 0 32 | dx, dummy <- draw-int32-decimal-wrapping-right-then-down-over-full-screen screen, dx, 0/x, 0x10/y, 0x31/fg, 0/bg 33 | } 34 | { 35 | var dummy/eax: int <- copy 0 36 | dummy, dy <- draw-int32-decimal-wrapping-right-then-down-over-full-screen screen, dy, 5/x, 0x10/y, 0x31/fg, 0/bg 37 | } 38 | loop 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /apps/ex12.mu: -------------------------------------------------------------------------------- 1 | # Checking the timer. 2 | # 3 | # To build a disk image: 4 | # ./translate apps/ex12.mu # emits code.img 5 | # To run: 6 | # qemu-system-i386 code.img 7 | # 8 | # Expected output: text with slowly updating colors 9 | 10 | fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) { 11 | var fg/ecx: int <- copy 0 12 | var prev-timer-counter/edx: int <- copy 0 13 | { 14 | var dummy/eax: int <- draw-text-rightward screen, "hello from baremetal Mu!", 0x10/x, 0x400/xmax, 0x10/y, fg, 0/bg 15 | # wait for timer to bump 16 | { 17 | var curr-timer-counter/eax: int <- timer-counter 18 | compare curr-timer-counter, prev-timer-counter 19 | loop-if-= 20 | prev-timer-counter <- copy curr-timer-counter 21 | } 22 | # switch color 23 | fg <- increment 24 | loop 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /apps/ex13.mu: -------------------------------------------------------------------------------- 1 | # Load an image from disk and display it on screen. 2 | # 3 | # Build the code disk: 4 | # $ ./translate apps/ex13.mu # generates code.img 5 | # Load a pbm, pgm or ppm image (no more than 255 levels) in the data disk 6 | # $ dd if=/dev/zero of=data.img count=20160 7 | # $ dd if=___ of=data.img conv=notrunc 8 | # Run: 9 | # $ qemu-system-i386 -hda code.img -hdb data.img 10 | 11 | fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) { 12 | var img-storage: image 13 | var img/esi: (addr image) <- address img-storage 14 | load-image img, data-disk 15 | render-image screen, img, 0/x, 0/y, 0x300/width, 0x300/height 16 | } 17 | 18 | fn load-image self: (addr image), data-disk: (addr disk) { 19 | var s-storage: (stream byte 0x200000) # 512 * 0x1000 sectors 20 | var s/ebx: (addr stream byte) <- address s-storage 21 | load-sectors data-disk, 0/lba, 0x1000/sectors, s 22 | initialize-image self, s 23 | } 24 | -------------------------------------------------------------------------------- /apps/ex14.mu: -------------------------------------------------------------------------------- 1 | # Unicode demo 2 | # 3 | # Mu can't read Unicode from keyboard yet, so we'll read utf-8 from disk and 4 | # print to screen. 5 | # 6 | # Steps for trying it out: 7 | # 1. Translate this example into a disk image code.img. 8 | # ./translate apps/ex14.mu 9 | # 2. Build a second disk image data.img containing some Unicode text. 10 | # dd if=/dev/zero of=data.img count=20160 11 | # echo 'நட' |dd of=data.img conv=notrunc 12 | # 3. Run: 13 | # qemu-system-i386 -hda code.img -hdb data.img 14 | # 15 | # Expected output: 'நட' in green near the top-left corner of screen 16 | 17 | fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) { 18 | var text-storage: (stream byte 0x200) 19 | var text/esi: (addr stream byte) <- address text-storage 20 | load-sectors data-disk, 0/lba, 1/num-sectors, text 21 | var dummy/eax: int <- draw-stream-rightward screen, text, 0/x 0x80/xmax 0/y, 0xa/fg, 0/bg 22 | } 23 | -------------------------------------------------------------------------------- /apps/ex2.mu: -------------------------------------------------------------------------------- 1 | # Test out the video mode by filling in the screen with pixels. 2 | # 3 | # To build a disk image: 4 | # ./translate apps/ex2.mu # emits code.img 5 | # To run: 6 | # qemu-system-i386 code.img 7 | 8 | fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) { 9 | var y/eax: int <- copy 0 10 | { 11 | compare y, 0x300/screen-height=768 12 | break-if->= 13 | var x/edx: int <- copy 0 14 | { 15 | compare x, 0x400/screen-width=1024 16 | break-if->= 17 | var color/ecx: int <- copy x 18 | color <- and 0xff 19 | pixel screen x, y, color 20 | x <- increment 21 | loop 22 | } 23 | y <- increment 24 | loop 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /apps/ex3.mu: -------------------------------------------------------------------------------- 1 | # Draw pixels in response to keyboard events, starting from the top-left 2 | # and in raster order. 3 | # 4 | # To build a disk image: 5 | # ./translate apps/ex3.mu # emits code.img 6 | # To run: 7 | # qemu-system-i386 code.img 8 | # 9 | # Expected output: a new green pixel starting from the top left corner of the 10 | # screen every time you press a key (letter or digit) 11 | 12 | fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) { 13 | var x/ecx: int <- copy 0 14 | var y/edx: int <- copy 0 15 | { 16 | var key/eax: byte <- read-key keyboard 17 | compare key, 0 18 | loop-if-= # busy wait 19 | pixel-on-real-screen x, y, 0x31/green 20 | x <- increment 21 | compare x, 0x400/screen-width=1024 22 | { 23 | break-if-< 24 | y <- increment 25 | x <- copy 0 26 | } 27 | loop 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /apps/ex4.mu: -------------------------------------------------------------------------------- 1 | # Draw a character using the built-in font (GNU unifont) 2 | # 3 | # To build a disk image: 4 | # ./translate apps/ex4.mu # emits code.img 5 | # To run: 6 | # qemu-system-i386 code.img 7 | # 8 | # Expected output: letter 'A' in green near the top-left corner of screen 9 | 10 | fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) { 11 | var dummy/eax: int <- draw-code-point screen, 0x41/A, 2/row, 1/col, 0xa/fg, 0/bg 12 | # wide glyph 13 | #? var dummy/eax: int <- draw-code-point screen, 0x1b/esc, 2/row, 1/col, 0xa/fg, 0/bg 14 | } 15 | -------------------------------------------------------------------------------- /apps/ex5.mu: -------------------------------------------------------------------------------- 1 | # Draw a single line of ASCII text using the built-in font (GNU unifont) 2 | # Also demonstrates bounds-checking _before_ drawing. 3 | # 4 | # To build a disk image: 5 | # ./translate apps/ex5.mu # emits code.img 6 | # To run: 7 | # qemu-system-i386 code.img 8 | # 9 | # Expected output: text in green near the top-left corner of screen 10 | 11 | fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) { 12 | var dummy/eax: int <- draw-text-rightward screen, "hello from baremetal Mu!", 0x10/x, 0x400/xmax, 0x10/y, 0xa/fg, 0/bg 13 | dummy <- draw-text-rightward screen, "you shouldn't see this", 0x10/x, 0xa0/xmax, 0x30/y, 3/fg, 0/bg # xmax is too narrow 14 | } 15 | -------------------------------------------------------------------------------- /apps/ex6.mu: -------------------------------------------------------------------------------- 1 | # Drawing ASCII text incrementally. 2 | # 3 | # To build a disk image: 4 | # ./translate apps/ex6.mu # emits code.img 5 | # To run: 6 | # qemu-system-i386 code.img 7 | # 8 | # Expected output: a box and text that doesn't overflow it 9 | 10 | fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) { 11 | # drawing text within a bounding box 12 | draw-box-on-real-screen 0xf, 0x1f, 0x79, 0x51, 0x4 13 | var x/eax: int <- copy 0x20 14 | var y/ecx: int <- copy 0x20 15 | x, y <- draw-text-wrapping-right-then-down screen, "hello ", 0x10/xmin, 0x20/ymin, 0x78/xmax, 0x50/ymax, x, y, 0xa/fg, 0/bg 16 | x, y <- draw-text-wrapping-right-then-down screen, "from ", 0x10/xmin, 0x20/ymin, 0x78/xmax, 0x50/ymax, x, y, 0xa/fg, 0/bg 17 | x, y <- draw-text-wrapping-right-then-down screen, "baremetal ", 0x10/xmin, 0x20/ymin, 0x78/xmax, 0x50/ymax, x, y, 0xa/fg, 0/bg 18 | x, y <- draw-text-wrapping-right-then-down screen, "Mu!", 0x10/xmin, 0x20/ymin, 0x78/xmax, 0x50/ymax, x, y, 0xa/fg, 0/bg 19 | 20 | # drawing at the cursor in multiple directions 21 | draw-text-wrapping-down-then-right-from-cursor-over-full-screen screen, "abc", 0xa/fg, 0/bg 22 | draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "def", 0xa/fg, 0/bg 23 | 24 | # test drawing near the edge 25 | x <- draw-text-rightward screen, "R", 0x7f/x, 0x80/xmax=screen-width, 0x18/y, 0xa/fg, 0/bg 26 | draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "wrapped from R", 0xa/fg, 0/bg 27 | 28 | x <- draw-text-downward screen, "D", 0x20/x, 0x2f/y, 0x30/ymax=screen-height, 0xa/fg, 0/bg 29 | draw-text-wrapping-down-then-right-from-cursor-over-full-screen screen, "wrapped from D", 0xa/fg, 0/bg 30 | } 31 | -------------------------------------------------------------------------------- /apps/ex7.mu: -------------------------------------------------------------------------------- 1 | # Cursor-based motions. 2 | # 3 | # To build a disk image: 4 | # ./translate apps/ex7.mu # emits code.img 5 | # To run: 6 | # qemu-system-i386 code.img 7 | # 8 | # Expected output: an interactive game a bit like "snakes". Try pressing h, j, 9 | # k, l. 10 | 11 | fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) { 12 | set-cursor-position screen, 0, 0 13 | { 14 | draw-cursor screen, 0x20/space 15 | var key/eax: byte <- read-key keyboard 16 | { 17 | compare key, 0x80/left-arrow 18 | break-if-!= 19 | draw-code-point-at-cursor screen, 0x2d/dash, 0x31/fg, 0/bg 20 | move-cursor-left 0 21 | } 22 | { 23 | compare key, 0x81/down-arrow 24 | break-if-!= 25 | draw-code-point-at-cursor screen, 0x7c/vertical-bar, 0x31/fg, 0/bg 26 | move-cursor-down 0 27 | } 28 | { 29 | compare key, 0x82/up-arrow 30 | break-if-!= 31 | draw-code-point-at-cursor screen, 0x7c/vertical-bar, 0x31/fg, 0/bg 32 | move-cursor-up 0 33 | } 34 | { 35 | compare key, 0x83/right-arrow 36 | break-if-!= 37 | var g/eax: code-point <- copy 0x2d/dash 38 | draw-code-point-at-cursor screen, 0x2d/dash, 0x31/fg, 0/bg 39 | move-cursor-right 0 40 | } 41 | loop 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /apps/ex8.mu: -------------------------------------------------------------------------------- 1 | # Demo of floating-point support. 2 | # 3 | # To build a disk image: 4 | # ./translate apps/ex8.mu # emits code.img 5 | # To run: 6 | # qemu-system-i386 code.img 7 | # You shouldn't see any exceptions. 8 | 9 | fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) { 10 | var n/eax: int <- copy 0 11 | var result/xmm0: float <- convert n 12 | } 13 | -------------------------------------------------------------------------------- /apps/ex9.mu: -------------------------------------------------------------------------------- 1 | # Demo of reading and writing to disk. 2 | # 3 | # Steps for trying it out: 4 | # 1. Translate this example into a disk image code.img. 5 | # ./translate apps/ex9.mu 6 | # 2. Build a second disk image data.img containing some text. 7 | # dd if=/dev/zero of=data.img count=20160 8 | # echo 'abc def ghi' |dd of=data.img conv=notrunc 9 | # 3. Familiarize yourself with how the data disk looks within xxd: 10 | # xxd data.img |head 11 | # 4. Run: 12 | # qemu-system-i386 -hda code.img -hdb data.img 13 | # 5. Exit the emulator. 14 | # 6. Notice that the data disk now contains the word count of the original text. 15 | # xxd data.img |head 16 | 17 | fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) { 18 | var text-storage: (stream byte 0x200) 19 | var text/esi: (addr stream byte) <- address text-storage 20 | load-sectors data-disk, 0/lba, 1/num-sectors, text 21 | 22 | var word-count/eax: int <- word-count text 23 | 24 | var result-storage: (stream byte 0x10) 25 | var result/edi: (addr stream byte) <- address result-storage 26 | write-int32-decimal result, word-count 27 | store-sectors data-disk, 0/lba, 1/num-sectors, result 28 | } 29 | 30 | fn word-count in: (addr stream byte) -> _/eax: int { 31 | var result/edi: int <- copy 0 32 | { 33 | var done?/eax: boolean <- stream-empty? in 34 | compare done?, 0/false 35 | break-if-!= 36 | var g/eax: code-point-utf8 <- read-code-point-utf8 in 37 | { 38 | compare g, 0x20/space 39 | break-if-!= 40 | result <- increment 41 | } 42 | { 43 | compare g, 0xa/newline 44 | break-if-!= 45 | result <- increment 46 | } 47 | loop 48 | } 49 | return result 50 | } 51 | -------------------------------------------------------------------------------- /apps/vimrc.vim: -------------------------------------------------------------------------------- 1 | " when opening files in this directory, load vimrc from cwd (top-level) 2 | source vimrc.vim 3 | -------------------------------------------------------------------------------- /archive/0.vm.arc/Readme.md: -------------------------------------------------------------------------------- 1 | Original prototype, last modified 2015-03-14 2 | 3 | First install [Racket](http://racket-lang.org) (just for this prototype; 4 | last tested with v6.3). Then: 5 | 6 | ```shell 7 | $ cd mu/archives/1.vm 8 | $ git clone http://github.com/arclanguage/anarki 9 | $ cd anarki 10 | $ git checkout d7290130a7 # last compatible snapshot 11 | $ cd .. 12 | $ ./mu test mu.arc.t # run tests 13 | ``` 14 | 15 | Example programs: 16 | 17 | ```shell 18 | $ ./mu factorial.mu # computes factorial of 5 19 | $ ./mu fork.mu # two threads print '33' and '34' forever 20 | $ ./mu channel.mu # two threads in a producer/consumer relationship 21 | ``` 22 | -------------------------------------------------------------------------------- /archive/0.vm.arc/blocking.arc.t: -------------------------------------------------------------------------------- 1 | (selective-load "mu.arc" section-level) 2 | (set allow-raw-addresses*) 3 | 4 | (reset) 5 | (new-trace "blocking-example") 6 | (add-code 7 | '((function reader [ 8 | (default-space:space-address <- new space:literal 30:literal/capacity) 9 | (x:tagged-value 1:channel-address/space:global <- read 1:channel-address/space:global) 10 | ]) 11 | (function main [ 12 | (default-space:space-address <- new space:literal 30:literal/capacity) 13 | (1:channel-address <- init-channel 3:literal) 14 | (2:integer/routine <- fork-helper reader:fn default-space:space-address/globals 50:literal/limit) 15 | ; write nothing to the channel 16 | ;? (sleep until-routine-done:literal 2:integer/routine) 17 | ]))) 18 | ;? (= dump-trace* (obj whitelist '("schedule" "run"))) 19 | (run 'main) 20 | ;? (prn "completed:") 21 | ;? (each r completed-routines* 22 | ;? (prn " " r)) 23 | (when (ran-to-completion 'reader) 24 | (prn "F - reader waits for input")) 25 | 26 | (reset) 27 | -------------------------------------------------------------------------------- /archive/0.vm.arc/buffered-stdin.mu: -------------------------------------------------------------------------------- 1 | ; reads lines, prints them back when you hit 'enter' 2 | ; dies if you wait a while, because so far we never free memory 3 | (function main [ 4 | (default-space:space-address <- new space:literal 30:literal) 5 | (cursor-mode) ;? 1 6 | ; hook up stdin 7 | (stdin:channel-address <- init-channel 1:literal) 8 | (fork-helper send-keys-to-stdin:fn nil:literal/globals nil:literal/limit nil:literal/keyboard stdin:channel-address) 9 | ; buffer stdin 10 | (buffered-stdin:channel-address <- init-channel 1:literal) 11 | (fork-helper buffer-lines:fn nil:literal/globals nil:literal/limit stdin:channel-address buffered-stdin:channel-address) 12 | { begin 13 | ; now read characters from the buffer until 'enter' is typed 14 | (s:string-address <- new "? ") 15 | (print-string nil:literal/terminal s:string-address) 16 | { begin 17 | (x:tagged-value buffered-stdin:channel-address/deref <- read buffered-stdin:channel-address) 18 | (c:character <- maybe-coerce x:tagged-value character:literal) 19 | ;? ($print (("AAA " literal))) ;? 1 20 | ;? ($print c:character) ;? 1 21 | ;? ($print (("\n" literal))) ;? 1 22 | (print-character nil:literal/terminal c:character) 23 | (line-done?:boolean <- equal c:character ((#\newline literal))) 24 | (loop-unless line-done?:boolean) 25 | } 26 | (loop) 27 | } 28 | ]) 29 | -------------------------------------------------------------------------------- /archive/0.vm.arc/callcc.mu: -------------------------------------------------------------------------------- 1 | ; in mu, call-cc (http://en.wikipedia.org/wiki/Call-with-current-continuation) 2 | ; is constructed out of a combination of two primitives: 3 | ; 'current-continuation', which returns a continuation, and 4 | ; 'continue-from', which takes a continuation to 5 | 6 | (function g [ 7 | (c:continuation <- current-continuation) ; <-- loop back to here 8 | (print-character nil:literal/terminal ((#\a literal))) 9 | (reply c:continuation) 10 | ]) 11 | 12 | (function f [ 13 | (c:continuation <- g) 14 | (reply c:continuation) 15 | ]) 16 | 17 | (function main [ 18 | (c:continuation <- f) 19 | (continue-from c:continuation) ; <-- ..when you hit this 20 | ]) 21 | -------------------------------------------------------------------------------- /archive/0.vm.arc/charterm/doc.scrbl: -------------------------------------------------------------------------------- 1 | #lang scribble/manual 2 | @; THIS-FILE-WAS-GENERATED-BY-MCFLY-TOOLS (planet neil/mcfly-tools:1:=12) 3 | @(require (for-syntax racket/base) 4 | (for-template racket/base) 5 | (planet neil/mcfly:1:3/mcfly-scribble) 6 | (planet neil/mcfly:1:3/mcfly-expand)) 7 | @(mcfly-expand "charterm.rkt") 8 | -------------------------------------------------------------------------------- /archive/0.vm.arc/charterm/info.rkt: -------------------------------------------------------------------------------- 1 | #lang setup/infotab 2 | 3 | (define mcfly-planet 'neil/charterm:3:1) 4 | (define name "CharTerm") 5 | (define mcfly-subtitle "Character-cell Terminal Interface in Racket") 6 | (define blurb (list name ": Character-cell Terminal Interface")) 7 | (define homepage "http://www.neilvandyke.org/racket-charterm/") 8 | (define mcfly-author "Neil Van Dyke") 9 | (define repositories '("4.x")) 10 | (define categories '(misc)) 11 | (define can-be-loaded-with 'all) 12 | (define scribblings '(("doc.scrbl" () (library)))) 13 | (define primary-file "main.rkt") 14 | (define mcfly-start "charterm.rkt") 15 | (define mcfly-files '(defaults 16 | "charterm.rkt" 17 | "demo.rkt" 18 | "test-charterm.rkt")) 19 | (define mcfly-license "LGPLv3") 20 | 21 | (define mcfly-legal 22 | "Copyright 2012 -- 2013 Neil Van Dyke. This program is Free Software; you 23 | can redistribute it and/or modify it under the terms of the GNU Lesser General 24 | Public License as published by the Free Software Foundation; either version 3 25 | of the License, or (at your option) any later version. This program is 26 | distributed in the hope that it will be useful, but without any warranty; 27 | without even the implied warranty of merchantability or fitness for a 28 | particular purpose. See http://www.gnu.org/licenses/ for details. For other 29 | licenses and consulting, please contact the author.") 30 | -------------------------------------------------------------------------------- /archive/0.vm.arc/charterm/main.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | (require "charterm.rkt") 3 | (provide (all-from-out "charterm.rkt")) 4 | -------------------------------------------------------------------------------- /archive/0.vm.arc/charterm/planet-docs/doc/scribble-style.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/archive/0.vm.arc/charterm/planet-docs/doc/scribble-style.css -------------------------------------------------------------------------------- /archive/0.vm.arc/charterm/test-charterm.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | ;; For legal info, see file "charterm.rkt". 3 | 4 | ;; (require (planet neil/charterm:1)) 5 | (require "charterm.rkt") 6 | 7 | (with-charterm 8 | (charterm-clear-screen) 9 | (charterm-cursor 10 5) 10 | (charterm-display "Hello, ") 11 | (charterm-bold) 12 | (charterm-display "you") 13 | (charterm-normal) 14 | (charterm-display ".") 15 | (charterm-cursor 1 1) 16 | (charterm-display "Press a key...") 17 | (let ((key (charterm-read-key))) 18 | (charterm-cursor 1 1) 19 | (charterm-clear-line) 20 | (printf "You pressed: ~S\r\n" key))) 21 | -------------------------------------------------------------------------------- /archive/0.vm.arc/counters.mu: -------------------------------------------------------------------------------- 1 | (function init-counter [ 2 | (default-space:space-address <- new space:literal 30:literal) 3 | (n:integer <- next-input) 4 | (reply default-space:space-address) 5 | ]) 6 | 7 | (function increment-counter [ 8 | (default-space:space-address <- new space:literal 30:literal) 9 | (0:space-address/names:init-counter <- next-input) ; setup outer space; it *must* come from 'init-counter' 10 | (x:integer <- next-input) 11 | (n:integer/space:1 <- add n:integer/space:1 x:integer) 12 | (reply n:integer/space:1) 13 | ]) 14 | 15 | (function main [ 16 | (default-space:space-address <- new space:literal 30:literal) 17 | ; counter A 18 | (a:space-address <- init-counter 34:literal) 19 | ; counter B 20 | (b:space-address <- init-counter 23:literal) 21 | ; increment both by 2 but in different ways 22 | (increment-counter a:space-address 1:literal) 23 | (bres:integer <- increment-counter b:space-address 2:literal) 24 | (ares:integer <- increment-counter a:space-address 1:literal) 25 | ; check results 26 | ($print (("Contents of counters a: " literal))) 27 | (print-integer nil:literal/terminal ares:integer) 28 | ($print ((" b: " literal))) 29 | (print-integer nil:literal/terminal bres:integer) 30 | ($print (("\n" literal))) 31 | ]) 32 | 33 | ; compare http://www.paulgraham.com/accgen.html 34 | -------------------------------------------------------------------------------- /archive/0.vm.arc/edit.arc.t: -------------------------------------------------------------------------------- 1 | (selective-load "mu.arc" section-level) 2 | (set allow-raw-addresses*) 3 | 4 | (section 100 5 | 6 | (reset) 7 | (new-trace "new-screen") 8 | (add-code:readfile "edit.mu") 9 | (add-code 10 | '((function test-new-screen [ 11 | (1:screen-address/global <- new-screen 5:literal 5:literal) 12 | ]))) 13 | ;? (each stmt function*!new-screen 14 | ;? (prn stmt)) 15 | (let routine make-routine!test-new-screen 16 | (let before rep.routine!alloc 17 | ;? (= dump-trace* (obj blacklist '("sz" "m" "setm" "addr" "cvt0" "cvt1"))) 18 | (run 'test-new-screen) 19 | ;? (prn memory*) 20 | ;? (prn memory*.2001) 21 | (when (~is (memory* memory*.1) 5) ; number of rows 22 | (prn "F - newly-allocated screen doesn't have the right number of rows: @(memory* memory*!2001)")) 23 | (let row-pointers (let base (+ 1 memory*.1) 24 | (range base (+ base 4))) 25 | ;? (prn row-pointers) 26 | (when (some nil (map memory* row-pointers)) 27 | (prn "F - newly-allocated screen didn't initialize all of its row pointers")) 28 | (when (~all 5 (map memory* (map memory* row-pointers))) 29 | (prn "F - newly-allocated screen didn't initialize all of its row lengths"))))) 30 | 31 | (reset) 32 | 33 | ) ; section 100 for all editor code 34 | -------------------------------------------------------------------------------- /archive/0.vm.arc/edit.mu: -------------------------------------------------------------------------------- 1 | ; a screen is an array of pointers to lines, in turn arrays of characters 2 | 3 | (function new-screen [ 4 | (default-space:space-address <- new space:literal 30:literal) 5 | (nrows:integer <- next-input) 6 | (ncols:integer <- next-input) 7 | (result:screen-address <- new screen:literal nrows:integer) 8 | (rowidx:integer <- copy 0:literal) 9 | { begin 10 | (curr-line-address-address:line-address-address <- index-address result:screen-address/deref rowidx:integer) 11 | (curr-line-address-address:line-address-address/deref <- new line:literal ncols:integer) 12 | (curr-line-address:line-address <- copy curr-line-address-address:line-address-address/deref) 13 | (rowidx:integer <- add rowidx:integer 1:literal) 14 | (x:boolean <- not-equal rowidx:integer nrows:integer) 15 | (loop-if x:boolean) 16 | } 17 | (reply result:screen-address) 18 | ]) 19 | -------------------------------------------------------------------------------- /archive/0.vm.arc/exuberant-ctags-rc: -------------------------------------------------------------------------------- 1 | --langdef=mu 2 | --langmap=mu:.mu 3 | --regex-mu=/^\(function[ \t]+([^ \t\[]+)/\1/d,definition/ 4 | --regex-mu=/^\(recipe[ \t]+([^ \t\[]+)/\1/d,definition/ 5 | --regex-mu=/^\(and-record[ \t]+([^ \t\[]+)/\1/t,type/ 6 | --regex-mu=/^\(address[ \t]+([^ \t\[]+)/\1/t,type/ 7 | --regex-mu=/^\(array[ \t]+([^ \t\[]+)/\1/t,type/ 8 | -------------------------------------------------------------------------------- /archive/0.vm.arc/factorial.mu: -------------------------------------------------------------------------------- 1 | (function factorial [ 2 | (default-space:space-address <- new space:literal 30:literal) 3 | (n:integer <- next-input) 4 | { begin 5 | ; if n=0 return 1 6 | (zero?:boolean <- equal n:integer 0:literal) 7 | (break-unless zero?:boolean) 8 | (reply 1:literal) 9 | } 10 | ; return n*factorial(n-1) 11 | (x:integer <- subtract n:integer 1:literal) 12 | (subresult:integer <- factorial x:integer) 13 | (result:integer <- multiply subresult:integer n:integer) 14 | (reply result:integer) 15 | ]) 16 | 17 | (function main [ 18 | (1:integer <- factorial 5:literal) 19 | ($print (("result: " literal))) 20 | (print-integer nil:literal/terminal 1:integer) 21 | ($print (("\n" literal))) 22 | ]) 23 | -------------------------------------------------------------------------------- /archive/0.vm.arc/fork.mu: -------------------------------------------------------------------------------- 1 | (function main [ 2 | (fork thread2:fn) 3 | (default-space:space-address <- new space:literal 2:literal) 4 | (x:integer <- copy 34:literal) 5 | { begin 6 | (print-integer nil:literal/terminal x:integer) 7 | (loop) 8 | } 9 | ]) 10 | 11 | (function thread2 [ 12 | (default-space:space-address <- new space:literal 2:literal) 13 | (y:integer <- copy 35:literal) 14 | { begin 15 | (print-integer nil:literal/terminal y:integer) 16 | (loop) 17 | } 18 | ]) 19 | -------------------------------------------------------------------------------- /archive/0.vm.arc/generic.mu: -------------------------------------------------------------------------------- 1 | ; To demonstrate generic functions, we'll construct a factorial function with 2 | ; separate base and recursive clauses. Compare factorial.mu. 3 | 4 | ; factorial n = n*factorial(n-1) 5 | (function factorial [ 6 | (default-space:space-address <- new space:literal 30:literal) 7 | (n:integer <- input 0:literal) 8 | (x:integer <- subtract n:integer 1:literal) 9 | (subresult:integer <- factorial x:integer) 10 | (result:integer <- multiply subresult:integer n:integer) 11 | (reply result:integer) 12 | ]) 13 | 14 | ; factorial 0 = 1 15 | (function factorial [ 16 | (default-space:space-address <- new space:literal 30:literal) 17 | (n:integer <- input 0:literal) 18 | { begin 19 | (zero?:boolean <- equal n:integer 0:literal) 20 | (break-unless zero?:boolean) 21 | (reply 1:literal) 22 | } 23 | ]) 24 | 25 | (function main [ 26 | (1:integer <- factorial 5:literal) 27 | ($print (("result: " literal))) 28 | (print-integer nil:literal/terminal 1:integer) 29 | ($print (("\n" literal))) 30 | ]) 31 | -------------------------------------------------------------------------------- /archive/0.vm.arc/graphics.mu: -------------------------------------------------------------------------------- 1 | ; open a viewport, print coordinates of mouse clicks 2 | ; currently need to ctrl-c to exit after closing the viewport 3 | (function main [ 4 | (window-on (("practice" literal)) 300:literal 300:literal) 5 | { begin 6 | (pos:integer-integer-pair click?:boolean <- mouse-position) 7 | (loop-unless click?:boolean) 8 | (x:integer <- get pos:integer-integer-pair 0:offset) 9 | (y:integer <- get pos:integer-integer-pair 1:offset) 10 | ;? ($print (("AAA " literal))) 11 | ;? ($print x:integer) 12 | ;? ($print ((", " literal))) 13 | ;? ($print y:integer) 14 | ;? ($print (("\n" literal))) 15 | (print-integer nil:literal/terminal x:integer) 16 | (print-character nil:literal/terminal ((#\, literal))) 17 | (print-character nil:literal/terminal ((#\space literal))) 18 | (print-integer nil:literal/terminal y:integer) 19 | (print-character nil:literal/terminal ((#\newline literal))) 20 | (loop) 21 | } 22 | (window-off) 23 | ]) 24 | -------------------------------------------------------------------------------- /archive/0.vm.arc/highlights: -------------------------------------------------------------------------------- 1 | " vim: ft=vim 2 | " Data-flow highlighting: http://www.reddit.com/r/programming/comments/1w76um/coding_in_color/cezpios 3 | 4 | highlight highlight_97a5a5e3 ctermfg=205 5 | call matchadd('highlight_97a5a5e3', '\') 6 | highlight highlight_1f88e41c ctermfg=139 7 | call matchadd('highlight_1f88e41c', '\') 8 | highlight highlight_6da20a96 ctermfg=141 9 | call matchadd('highlight_6da20a96', '\') 10 | highlight highlight_ae83eebb ctermfg=149 11 | call matchadd('highlight_ae83eebb', 'curr-line-address-address') 12 | highlight highlight_bb695e14 ctermfg=36 13 | call matchadd('highlight_bb695e14', '\') 14 | highlight highlight_1e44ab4f ctermfg=208 15 | call matchadd('highlight_1e44ab4f', '\') 16 | highlight highlight_3323f077 ctermfg=208 17 | call matchadd('highlight_3323f077', '\') 18 | highlight highlight_74fc42b2 ctermfg=220 19 | call matchadd('highlight_74fc42b2', 'second-arg') 20 | highlight highlight_ff6f0571 ctermfg=220 21 | call matchadd('highlight_ff6f0571', 'second-arg-box') 22 | -------------------------------------------------------------------------------- /archive/0.vm.arc/load.arc: -------------------------------------------------------------------------------- 1 | ; support for dividing arc files into sections of different level, and 2 | ; selectively loading just sections at or less than a given level 3 | 4 | ; usage: 5 | ; load.arc [level] [arc files] -- [mu files] 6 | 7 | (def selective-load (file (o level 999)) 8 | ;? (prn "loading @file at level @level") 9 | (fromfile file 10 | (whilet expr (read) 11 | ;? (prn car.expr) 12 | (if (is 'section expr.0) 13 | (when (<= expr.1 level) 14 | (each x (cut expr 2) 15 | (eval x))) 16 | (eval expr)) 17 | ;? (prn car.expr " done") 18 | ))) 19 | 20 | (= section-level 999) 21 | (point break 22 | (each x (map [fromstring _ (read)] cdr.argv) 23 | (if (isa x 'int) 24 | (= section-level x) 25 | (is '-- x) 26 | (break) ; later args are mu files 27 | :else 28 | (selective-load string.x section-level)))) 29 | -------------------------------------------------------------------------------- /archive/0.vm.arc/mu: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # To run a program: 4 | # $ mu [mu files] 5 | # To run a file of tests (in arc): 6 | # $ mu test [arc files] 7 | # To start an interactive session: 8 | # $ mu repl 9 | # 10 | # To mess with load levels and selectively run parts of the codebase, skip 11 | # this script and call load.arc directly. 12 | 13 | if [[ $1 == "test" ]] 14 | then 15 | shift 16 | ./anarki/arc load.arc "$@" # test currently assumed to be arc files rather than mu files 17 | elif [[ $1 == "repl" ]] 18 | then 19 | if [ "$(type rlwrap)" ] 20 | then 21 | rlwrap -C mu ./anarki/arc mu.arc 22 | else 23 | ./anarki/arc mu.arc 24 | fi 25 | else 26 | ./anarki/arc load.arc mu.arc -- "$@" # mu files from args 27 | fi 28 | -------------------------------------------------------------------------------- /archive/0.vm.arc/scratch.vim: -------------------------------------------------------------------------------- 1 | " random commands used interactively to build mu.arc.t.html 2 | 3 | TOhtml 4 | %s,<.*<-.*,&,gc 5 | %s/Special"></Op">\</g 6 | %s, <-, &,gc 7 | %s/Constant[^>]*>[^>]*>[: ]literal/Mu&/gc 8 | %s/Constant[^>]*>[^>]*>[: ]offset/Mu&/gc 9 | %s,\t literal,gc 10 | %s,\t literal,gc 11 | %s,\,nil:literal,gc 12 | %s,\,t:literal,gc 13 | 14 | map ` :s,[^ ].*,&, 15 | /function.*[ 16 | "b = `/n 17 | map ; @b 18 | /jump 19 | /break 20 | /reply 21 | /loop 22 | /sleep 23 | /fork 24 | /defer 25 | /label1 26 | /before.*[ 27 | /after.*[ 28 | 29 | " supercedes 30 | %s,<.*break.*,&,gc 31 | %s,<.*continue.*,&,gc 32 | %s,<.*reply.*,&,gc 33 | %s,<.*jump.*,&,gc 34 | %s,<.*main.*,&,gc 35 | %s,<.*test1.*,&,gc 36 | %s,<.*test2.*,&,gc 37 | %s,<.*f1.*,&,gc 38 | %s,<.*f2.*,&,gc 39 | 40 | pre { white-space: pre-wrap; font-family: monospace; color: #aaaaaa; background-color: #000000; } 41 | body { font-family: monospace; color: #aaaaaa; background-color: #000000; } 42 | a { color:#4444ff; } 43 | * { font-size: 1em; } 44 | .Constant, .MuConstant { color: #008080; } 45 | .Comment { color: #8080ff; } 46 | .Delimiter { color: #600060; } 47 | .Normal { color: #aaaaaa; } 48 | .Mu, .Mu .Normal, .Mu .Constant { color: #ffffff; } 49 | .Op { color: #ff8888; } 50 | .CommentedCode { color: #666666; } 51 | -------------------------------------------------------------------------------- /archive/0.vm.arc/stdin.mu: -------------------------------------------------------------------------------- 1 | ; reads and prints keys until you hit 'q' 2 | ; no need to hit 'enter', and 'enter' has no special meaning 3 | ; dies if you wait a while, because so far we never free memory 4 | (function main [ 5 | (default-space:space-address <- new space:literal 30:literal) 6 | (cursor-mode) 7 | ; hook up stdin 8 | (stdin:channel-address <- init-channel 1:literal) 9 | ;? ($print (("main: stdin is " literal))) 10 | ;? ($print stdin:channel-address) 11 | ;? ($print (("\n" literal))) 12 | (fork-helper send-keys-to-stdin:fn nil:literal/globals nil:literal/limit nil:literal/keyboard stdin:channel-address) 13 | ; now read characters from stdin until a 'q' is typed 14 | ($print (("? " literal))) 15 | { begin 16 | (x:tagged-value stdin:channel-address/deref <- read stdin:channel-address) 17 | (c:character <- maybe-coerce x:tagged-value character:literal) 18 | ;? ($print (("main: stdin is " literal))) 19 | ;? ($print stdin:channel-address) 20 | ;? ($print (("\n" literal))) 21 | ;? ($print (("check: " literal))) 22 | ;? ($print c:character) 23 | (done?:boolean <- equal c:character ((#\q literal))) 24 | (break-if done?:boolean) 25 | (loop) 26 | } 27 | ]) 28 | -------------------------------------------------------------------------------- /archive/0.vm.arc/tangle.mu: -------------------------------------------------------------------------------- 1 | ; To demonstrate tangle directives, we'll construct a factorial function with 2 | ; separate base and recursive cases. Compare factorial.mu. 3 | ; This isn't a very realistic example, just a simple demonstration of 4 | ; possibilities. 5 | 6 | (function factorial [ 7 | (default-space:space-address <- new space:literal 30:literal) 8 | (n:integer <- next-input) 9 | { begin 10 | base-case 11 | } 12 | recursive-case 13 | ]) 14 | 15 | (after base-case [ 16 | ; if n=0 return 1 17 | (zero?:boolean <- equal n:integer 0:literal) 18 | (break-unless zero?:boolean) 19 | (reply 1:literal) 20 | ]) 21 | 22 | (after recursive-case [ 23 | ; return n*factorial(n-1) 24 | (x:integer <- subtract n:integer 1:literal) 25 | (subresult:integer <- factorial x:integer) 26 | (result:integer <- multiply subresult:integer n:integer) 27 | (reply result:integer) 28 | ]) 29 | 30 | (function main [ 31 | (1:integer <- factorial 5:literal) 32 | ($print (("result: " literal))) 33 | (print-integer nil:literal/terminal 1:integer) 34 | (print-character nil:literal/terminal ((#\newline literal))) 35 | ]) 36 | -------------------------------------------------------------------------------- /archive/0.vm.arc/vimrc.vim: -------------------------------------------------------------------------------- 1 | syntax sync minlines=999 2 | 3 | function! HighlightMuInArc() 4 | set ft=mu 5 | syntax keyword muHack begin | highlight link muHack CommentedCode 6 | syntax match muHack "[()]" | highlight link muHack CommentedCode 7 | endfunction 8 | autocmd BufRead,BufNewFile *.mu call HighlightMuInArc() 9 | -------------------------------------------------------------------------------- /archive/0.vm.arc/x.mu: -------------------------------------------------------------------------------- 1 | (function main [ 2 | (x:integer <- copy 1:literal) 3 | (y:integer <- copy 3:literal) 4 | (z:integer <- add x:integer y:integer) 5 | ($dump-memory) 6 | ]) 7 | -------------------------------------------------------------------------------- /archive/1.vm/013update_operation.cc: -------------------------------------------------------------------------------- 1 | //: Once all code is loaded, save operation ids of instructions and check that 2 | //: nothing's undefined. 3 | 4 | :(before "End Instruction Modifying Transforms") 5 | Transform.push_back(update_instruction_operations); // idempotent 6 | 7 | :(code) 8 | void update_instruction_operations(const recipe_ordinal r) { 9 | trace(101, "transform") << "--- compute instruction operations for recipe " << get(Recipe, r).name << end(); 10 | recipe& caller = get(Recipe, r); 11 | //? cerr << "--- compute instruction operations for recipe " << caller.name << '\n'; 12 | for (int index = 0; index < SIZE(caller.steps); ++index) { 13 | instruction& inst = caller.steps.at(index); 14 | if (inst.is_label) continue; 15 | if (!contains_key(Recipe_ordinal, inst.name)) { 16 | raise << maybe(caller.name) << "instruction '" << inst.name << "' has no recipe in '" << to_original_string(inst) << "'\n" << end(); 17 | continue; 18 | } 19 | inst.operation = get(Recipe_ordinal, inst.name); 20 | // End Instruction Operation Checks 21 | } 22 | } 23 | 24 | // hook to suppress inserting recipe name into errors 25 | string maybe(string recipe_name) { 26 | // End maybe(recipe_name) Special-cases 27 | return recipe_name + ": "; 28 | } 29 | 30 | void test_missing_arrow() { 31 | Hide_errors = true; 32 | transform( 33 | "def main [\n" 34 | " 1:number , copy 0\n" // typo: ',' instead of '<-' 35 | "]\n" 36 | ); 37 | CHECK_TRACE_CONTENTS( 38 | "error: main: instruction '1:number' has no recipe in '1:number copy, 0'\n" 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /archive/1.vm/015literal_noninteger.cc: -------------------------------------------------------------------------------- 1 | //: Support literal non-integers. 2 | 3 | void test_noninteger_literal() { 4 | load( 5 | "def main [\n" 6 | " 1:number <- copy 3.14159\n" 7 | "]\n" 8 | ); 9 | CHECK_TRACE_CONTENTS( 10 | "parse: ingredient: {3.14159: \"literal-fractional-number\"}\n" 11 | ); 12 | } 13 | 14 | :(after "Parsing reagent(string s)") 15 | if (is_noninteger(s)) { 16 | name = s; 17 | type = new type_tree("literal-fractional-number", 0); 18 | set_value(to_double(s)); 19 | return; 20 | } 21 | 22 | :(code) 23 | bool is_noninteger(const string& s) { 24 | return s.find_first_not_of("0123456789-.") == string::npos // no other characters 25 | && s.find_first_of("0123456789") != string::npos // at least one digit 26 | && s.find('-', 1) == string::npos // '-' only at first position 27 | && std::count(s.begin(), s.end(), '.') == 1; // exactly one decimal point 28 | } 29 | 30 | double to_double(string n) { 31 | char* end = NULL; 32 | // safe because string.c_str() is guaranteed to be null-terminated 33 | double result = strtod(n.c_str(), &end); 34 | assert(*end == '\0'); 35 | return result; 36 | } 37 | 38 | void test_is_noninteger() { 39 | CHECK(!is_noninteger("1234")); 40 | CHECK(!is_noninteger("1a2")); 41 | CHECK(is_noninteger("234.0")); 42 | CHECK(!is_noninteger("...")); 43 | CHECK(!is_noninteger(".")); 44 | CHECK(is_noninteger("2.")); 45 | CHECK(is_noninteger(".2")); 46 | CHECK(is_noninteger("-.2")); 47 | CHECK(is_noninteger("-2.")); 48 | CHECK(!is_noninteger("--.2")); 49 | CHECK(!is_noninteger(".-2")); 50 | CHECK(!is_noninteger("..2")); 51 | } 52 | -------------------------------------------------------------------------------- /archive/1.vm/051scenario_test.mu: -------------------------------------------------------------------------------- 1 | # tests for 'scenario' in previous layer 2 | 3 | scenario first_scenario_in_mu [ 4 | run [ 5 | 10:num <- add 2, 2 6 | ] 7 | memory-should-contain [ 8 | 10 <- 4 9 | ] 10 | ] 11 | 12 | scenario scenario_with_comment_in_mu [ 13 | run [ 14 | # comment 15 | 10:num <- add 2, 2 16 | ] 17 | memory-should-contain [ 18 | 10 <- 4 19 | ] 20 | ] 21 | 22 | scenario scenario_with_multiple_comments_in_mu [ 23 | run [ 24 | # comment1 25 | # comment2 26 | 10:num <- add 2, 2 27 | ] 28 | memory-should-contain [ 29 | 10 <- 4 30 | ] 31 | ] 32 | 33 | scenario check_text_in_memory [ 34 | run [ 35 | 10:num <- copy 3 36 | 11:char <- copy 97 # 'a' 37 | 12:char <- copy 98 # 'b' 38 | 13:char <- copy 99 # 'c' 39 | ] 40 | memory-should-contain [ 41 | 10:array:character <- [abc] 42 | ] 43 | ] 44 | 45 | scenario check_trace [ 46 | run [ 47 | 10:num <- add 2, 2 48 | ] 49 | trace-should-contain [ 50 | mem: storing 4 in location 10 51 | ] 52 | ] 53 | 54 | scenario check_trace_negative [ 55 | run [ 56 | 10:num <- add 2, 2 57 | ] 58 | trace-should-not-contain [ 59 | mem: storing 3 in location 10 60 | ] 61 | ] 62 | 63 | scenario check_trace_instruction [ 64 | run [ 65 | trace 1, [foo], [aaa] 66 | ] 67 | trace-should-contain [ 68 | foo: aaa 69 | ] 70 | ] 71 | -------------------------------------------------------------------------------- /archive/1.vm/058to_text.cc: -------------------------------------------------------------------------------- 1 | //: Primitive to convert any type to text (array of characters). 2 | //: Later layers will allow us to override this to do something smarter for 3 | //: specific types. 4 | 5 | :(before "End Primitive Recipe Declarations") 6 | TO_TEXT, 7 | :(before "End Primitive Recipe Numbers") 8 | put(Recipe_ordinal, "to-text", TO_TEXT); 9 | :(before "End Primitive Recipe Checks") 10 | case TO_TEXT: { 11 | if (SIZE(inst.ingredients) != 1) { 12 | raise << maybe(get(Recipe, r).name) << "'to-text' requires a single ingredient, but got '" << to_original_string(inst) << "'\n" << end(); 13 | break; 14 | } 15 | // can handle any type 16 | break; 17 | } 18 | :(before "End Primitive Recipe Implementations") 19 | case TO_TEXT: { 20 | products.resize(1); 21 | products.at(0).push_back(/*alloc id*/0); 22 | products.at(0).push_back(new_mu_text(inspect(current_instruction().ingredients.at(0), ingredients.at(0)))); 23 | break; 24 | } 25 | -------------------------------------------------------------------------------- /archive/1.vm/059to_text.mu: -------------------------------------------------------------------------------- 1 | # A couple of variants of 'to-text' that we'll use implicitly in stashes (see 2 | # later layers). 3 | # 4 | # Mu code might specialize them to be smarter, but I don't anticipate any need 5 | # beyond specializing 'to-text' itself. 6 | 7 | # 'shorter' variant of to-text, when you want to enable some sort of trimming 8 | # define it to be identical to 'to-text' by default 9 | def to-text-line x:_elem -> y:text [ 10 | local-scope 11 | load-inputs 12 | y <- to-text x 13 | ] 14 | 15 | # variant for arrays (since we can't pass them around otherwise) 16 | def array-to-text-line x:&:@:_elem -> y:text [ 17 | local-scope 18 | load-inputs 19 | y <- to-text *x 20 | ] 21 | 22 | scenario to-text-line-early-warning-for-static-dispatch [ 23 | x:text <- to-text-line 34 24 | # just ensure there were no errors 25 | ] 26 | 27 | scenario array-to-text-line-early-warning-for-static-dispatch [ 28 | n:&:@:num <- new number:type, 3 29 | x:text <- array-to-text-line n 30 | # just ensure there were no errors 31 | ] 32 | 33 | # finally, a specialization for single characters 34 | def to-text c:char -> y:text [ 35 | local-scope 36 | load-inputs 37 | y <- new character:type, 1/capacity 38 | *y <- put-index *y, 0, c 39 | ] 40 | 41 | scenario character-to-text [ 42 | 1:char <- copy 111/o 43 | 2:text <- to-text 1:char 44 | 3:@:char <- copy *2:text 45 | memory-should-contain [ 46 | 3:array:character <- [o] 47 | ] 48 | ] 49 | -------------------------------------------------------------------------------- /archive/1.vm/067random.cc: -------------------------------------------------------------------------------- 1 | :(before "End Primitive Recipe Declarations") 2 | REAL_RANDOM, 3 | :(before "End Primitive Recipe Numbers") 4 | put(Recipe_ordinal, "real-random", REAL_RANDOM); 5 | :(before "End Primitive Recipe Checks") 6 | case REAL_RANDOM: { 7 | break; 8 | } 9 | :(before "End Primitive Recipe Implementations") 10 | case REAL_RANDOM: { 11 | // todo: limited range of numbers, might be imperfectly random 12 | // todo: thread state in extra ingredients and products 13 | products.resize(1); 14 | products.at(0).push_back(rand()); 15 | break; 16 | } 17 | 18 | :(before "End Primitive Recipe Declarations") 19 | MAKE_RANDOM_NONDETERMINISTIC, 20 | :(before "End Primitive Recipe Numbers") 21 | put(Recipe_ordinal, "make-random-nondeterministic", MAKE_RANDOM_NONDETERMINISTIC); 22 | :(before "End Primitive Recipe Checks") 23 | case MAKE_RANDOM_NONDETERMINISTIC: { 24 | break; 25 | } 26 | :(before "End Primitive Recipe Implementations") 27 | case MAKE_RANDOM_NONDETERMINISTIC: { 28 | srand(time(NULL)); 29 | break; 30 | } 31 | 32 | // undo non-determinism in later tests 33 | :(before "End Reset") 34 | srand(0); 35 | -------------------------------------------------------------------------------- /archive/1.vm/083scenario_screen_test.mu: -------------------------------------------------------------------------------- 1 | # To check our support for screens in scenarios, rewrite tests from print.mu 2 | 3 | scenario print-character-at-top-left-2 [ 4 | local-scope 5 | assume-screen 3/width, 2/height 6 | run [ 7 | a:char <- copy 97/a 8 | screen <- print screen, a 9 | ] 10 | screen-should-contain [ 11 | .a . 12 | . . 13 | ] 14 | ] 15 | 16 | scenario clear-line-erases-printed-characters-2 [ 17 | local-scope 18 | assume-screen 5/width, 3/height 19 | # print a character 20 | a:char <- copy 97/a 21 | screen <- print screen, a 22 | # move cursor to start of line 23 | screen <- move-cursor screen, 0/row, 0/column 24 | run [ 25 | screen <- clear-line screen 26 | ] 27 | screen-should-contain [ 28 | . . 29 | . . 30 | . . 31 | ] 32 | ] 33 | 34 | scenario scroll-screen [ 35 | local-scope 36 | assume-screen 3/width, 2/height 37 | run [ 38 | a:char <- copy 97/a 39 | move-cursor screen, 1/row, 2/column 40 | screen <- print screen, a 41 | screen <- print screen, a 42 | ] 43 | screen-should-contain [ 44 | . a. 45 | .a . 46 | ] 47 | ] 48 | -------------------------------------------------------------------------------- /archive/1.vm/086scenario_console_test.mu: -------------------------------------------------------------------------------- 1 | # To check our support for consoles in scenarios, rewrite tests from 2 | # scenario_console.mu 3 | # Tests for console interface. 4 | 5 | scenario read-key-in-mu [ 6 | assume-console [ 7 | type [abc] 8 | ] 9 | run [ 10 | 1:char, 2:bool <- read-key console 11 | 3:char, 4:bool <- read-key console 12 | 5:char, 6:bool <- read-key console 13 | 7:char, 8:bool <- read-key console 14 | ] 15 | memory-should-contain [ 16 | 1 <- 97 # 'a' 17 | 2 <- 1 18 | 3 <- 98 # 'b' 19 | 4 <- 1 20 | 5 <- 99 # 'c' 21 | 6 <- 1 22 | 7 <- 0 # eof 23 | 8 <- 1 24 | ] 25 | ] 26 | -------------------------------------------------------------------------------- /archive/1.vm/args.mu: -------------------------------------------------------------------------------- 1 | # To provide commandline args to a Mu program, use '--'. In this case: 2 | # $ ./mu args.mu -- abc 3 | # abc 4 | def main text:text [ 5 | local-scope 6 | load-inputs 7 | $print text 10/newline 8 | ] 9 | -------------------------------------------------------------------------------- /archive/1.vm/build0: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Compile mu from scratch. 3 | 4 | set -v 5 | set -e # stop immediately on error 6 | 7 | cd ../../linux/bootstrap/tools 8 | # auto-generate various lists (ending in '_list' by convention) { 9 | # list of function declarations, so I can define them in any order 10 | grep -h "^[^ #].*) {" tangle.cc |sed 's/ {.*/;/' > tangle.function_list 11 | # list of tests to run 12 | grep -h "^[[:space:]]*void test_" tangle.cc |sed 's/^\s*void \(.*\)() {$/\1,/' > tangle.test_list 13 | grep -h "^\s*void test_" tangle.cc |sed 's/^\s*void \(.*\)() {.*/"\1",/' > tangle.test_name_list 14 | # } 15 | g++ -std=c++98 -g -O3 tangle.cc -o tangle 16 | ./tangle test 17 | cd ../../../archive/1.vm 18 | 19 | cd termbox 20 | gcc -g -O2 -c termbox.c 21 | gcc -g -O2 -c utf8.c 22 | ar rcs libtermbox.a *.o 23 | cd .. 24 | 25 | ../../linux/bootstrap/tools/tangle [0-9]*.cc > mu.cc 26 | # auto-generate function declarations, so I can define them in any order 27 | # functions start out unindented, have all args on the same line, and end in ') {' 28 | # 29 | # \/ ignore struct/class methods 30 | grep -h "^[^[:space:]#].*) {$" mu.cc |grep -v ":.*(" |sed 's/ {.*/;/' > function_list 31 | # auto-generate list of tests to run 32 | grep -h "^\s*void test_" mu.cc |sed 's/^\s*void \(.*\)() {.*/\1,/' > test_list 33 | grep -h "^\s*void test_" mu.cc |sed 's/^\s*void \(.*\)() {.*/"\1",/' > test_name_list 34 | g++ -std=c++98 -g -O2 mu.cc termbox/libtermbox.a -o mu_bin 35 | 36 | cat [0-9]*.mu > core.mu 37 | -------------------------------------------------------------------------------- /archive/1.vm/build_and_test_until: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Run tests for just a subset of layers. 3 | # 4 | # Usage: 5 | # build_and_test_until [file prefix] [test name] 6 | # Provide the second arg to run just a single test. 7 | set -e 8 | 9 | # clean previous builds if they were building until a different layer 10 | touch .until 11 | PREV_UNTIL=`cat .until` 12 | if [ "$PREV_UNTIL" != $1 ] 13 | then 14 | ./clean top-level 15 | echo $1 > .until 16 | fi 17 | 18 | ./build3 --until $1 && ./mu_bin test $2 19 | -------------------------------------------------------------------------------- /archive/1.vm/cannot_write_tests_for: -------------------------------------------------------------------------------- 1 | 0. main's ingredients 2 | 1. assertion failures or errors inside scenarios 3 | 2. screen background color 4 | 3. has-more-events? 5 | 4. hide/show screen 6 | 5. more touch event types 7 | 6. sandbox isolation 8 | 7. errors in reading/writing files (missing directory, others?) 9 | 10 | termbox issues are implementation-specific and not worth testing: 11 | whether we clear junk from other processes 12 | latency in interpreting low-level escape characters 13 | 14 | calls to update-cursor are currently duplicated: 15 | render-all calls update-cursor to simplify testing 16 | event-loop needs to call update-cursor explicitly to backstop branches doing their own minimal rendering 17 | solution: update-cursor after minimal rendering 18 | -------------------------------------------------------------------------------- /archive/1.vm/channel.mu: -------------------------------------------------------------------------------- 1 | # example program: communicating between routines using channels 2 | 3 | def producer sink:&:sink:char -> sink:&:sink:char [ 4 | # produce characters 1 to 5 on a channel 5 | local-scope 6 | load-inputs 7 | # n = 0 8 | n:char <- copy 0 9 | { 10 | done?:bool <- lesser-than n, 5 11 | break-unless done? 12 | # other threads might get between these prints 13 | $print [produce: ], n, [ 14 | ] 15 | sink <- write sink, n 16 | n <- add n, 1 17 | loop 18 | } 19 | close sink 20 | ] 21 | 22 | def consumer source:&:source:char -> source:&:source:char [ 23 | # consume and print integers from a channel 24 | local-scope 25 | load-inputs 26 | { 27 | # read an integer from the channel 28 | n:char, eof?:bool, source <- read source 29 | break-if eof? 30 | # other threads might get between these prints 31 | $print [consume: ], n:char, [ 32 | ] 33 | loop 34 | } 35 | ] 36 | 37 | def main [ 38 | local-scope 39 | source:&:source:char, sink:&:sink:char <- new-channel 3/capacity 40 | # create two background 'routines' that communicate by a channel 41 | routine1:num <- start-running producer, sink 42 | routine2:num <- start-running consumer, source 43 | wait-for-routine routine1 44 | wait-for-routine routine2 45 | ] 46 | -------------------------------------------------------------------------------- /archive/1.vm/clean: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | set -v 5 | rm -rf mu.cc core.mu mu_bin* *_list .build 6 | rm -rf termbox/*.o termbox/libtermbox.a 7 | rm -rf .until .quit 8 | test $# -gt 0 && exit 0 # convenience: 'clean top-level' to leave subsidiary tools alone 9 | rm -rf ../../linux/bootstrap/tools/enumerate ../../linux/bootstrap/tools/tangle ../../linux/bootstrap/tools/*_list cleave/cleave cleave/cleave.dSYM ../../linux/bootstrap/tools/*.dSYM 10 | -------------------------------------------------------------------------------- /archive/1.vm/cleave/Readme: -------------------------------------------------------------------------------- 1 | Tool to construct compilation units out of Mu's layers. 2 | -------------------------------------------------------------------------------- /archive/1.vm/console.mu: -------------------------------------------------------------------------------- 1 | # example program: reading events from keyboard or mouse 2 | # 3 | # Keeps printing 'a' until you press a key or click on the mouse. 4 | 5 | def main [ 6 | local-scope 7 | open-console 8 | { 9 | e:event, found?:bool <- check-for-interaction 10 | break-if found? 11 | print-character-to-display 97, 7/white 12 | loop 13 | } 14 | close-console 15 | $print e, 10/newline 16 | ] 17 | -------------------------------------------------------------------------------- /archive/1.vm/continuation1.mu: -------------------------------------------------------------------------------- 1 | # Example program showing that 'return-continuation-until-mark' can 'pause' a 2 | # function call, returning a continuation, and that calling the continuation 3 | # can 'resume' the paused function call. 4 | # 5 | # To run: 6 | # $ git clone https://github.com/akkartik/mu 7 | # $ cd mu 8 | # $ ./mu continuation1.mu 9 | # 10 | # Expected output: 11 | # 1 12 | 13 | def main [ 14 | local-scope 15 | k:continuation <- call-with-continuation-mark 100/mark, create-yielder 16 | x:num <- call k # should return 1 17 | $print x 10/newline 18 | ] 19 | 20 | def create-yielder -> n:num [ 21 | local-scope 22 | load-inputs 23 | return-continuation-until-mark 100/mark 24 | return 1 25 | ] 26 | -------------------------------------------------------------------------------- /archive/1.vm/continuation2.mu: -------------------------------------------------------------------------------- 1 | # Example program showing that a 'paused' continuation can be 'resumed' 2 | # multiple times from the same point (but with changes to data). 3 | # 4 | # To run: 5 | # $ git clone https://github.com/akkartik/mu 6 | # $ cd mu 7 | # $ ./mu continuation2.mu 8 | # 9 | # Expected output: 10 | # 1 11 | # 2 12 | # 3 13 | 14 | def main [ 15 | local-scope 16 | l:&:list:num <- copy null 17 | l <- push 3, l 18 | l <- push 2, l 19 | l <- push 1, l 20 | k:continuation <- call-with-continuation-mark 100/mark, create-yielder, l 21 | { 22 | x:num, done?:bool <- call k 23 | break-if done? 24 | $print x 10/newline 25 | loop 26 | } 27 | ] 28 | 29 | def create-yielder l:&:list:num -> n:num, done?:bool [ 30 | local-scope 31 | load-inputs 32 | return-continuation-until-mark 100/mark 33 | done? <- equal l, null 34 | return-if done?, 0/dummy 35 | n <- first l 36 | l <- rest l 37 | ] 38 | -------------------------------------------------------------------------------- /archive/1.vm/continuation3.mu: -------------------------------------------------------------------------------- 1 | # Example program showing that a function call can be 'paused' multiple times, 2 | # creating different continuation values. 3 | # 4 | # To run: 5 | # $ git clone https://github.com/akkartik/mu 6 | # $ cd mu 7 | # $ ./mu continuation3.mu 8 | # 9 | # Expected output: 10 | # caller 0 11 | # callee 0 12 | # caller 1 13 | # callee 1 14 | # caller 2 15 | # callee 2 16 | 17 | def main [ 18 | local-scope 19 | $print [caller 0] 10/newline 20 | k:continuation <- call-with-continuation-mark 100/mark, f 21 | $print [caller 1] 10/newline 22 | k <- call k 23 | $print [caller 2] 10/newline 24 | call k 25 | ] 26 | 27 | def f [ 28 | local-scope 29 | $print [callee 0] 10/newline 30 | return-continuation-until-mark 100/mark 31 | $print [callee 1] 10/newline 32 | return-continuation-until-mark 100/mark 33 | $print [callee 2] 10/newline 34 | ] 35 | -------------------------------------------------------------------------------- /archive/1.vm/continuation4.mu: -------------------------------------------------------------------------------- 1 | # Example program showing 'return-continuation-until-mark' return other values 2 | # alongside continuations. 3 | # 4 | # Print out a given list of numbers. 5 | # 6 | # To run: 7 | # $ git clone https://github.com/akkartik/mu 8 | # $ cd mu 9 | # $ ./mu continuation4.mu 10 | # 11 | # Expected output: 12 | # 1 13 | # 2 14 | # 3 15 | 16 | def main [ 17 | local-scope 18 | l:&:list:num <- copy null 19 | l <- push 3, l 20 | l <- push 2, l 21 | l <- push 1, l 22 | k:continuation, x:num, done?:bool <- call-with-continuation-mark 100/mark, create-yielder, l 23 | { 24 | break-if done? 25 | $print x 10/newline 26 | k, x:num, done?:bool <- call k 27 | loop 28 | } 29 | ] 30 | 31 | def create-yielder l:&:list:num -> n:num, done?:bool [ 32 | local-scope 33 | load-inputs 34 | { 35 | done? <- equal l, null 36 | break-if done? 37 | n <- first l 38 | l <- rest l 39 | return-continuation-until-mark 100/mark, n, done? 40 | loop 41 | } 42 | # A function that returns continuations shouldn't get the opportunity to 43 | # return. Calling functions should stop calling its continuation after this 44 | # point. 45 | return-continuation-until-mark 100/mark, -1, done? 46 | assert false, [called too many times, ran out of continuations to return] 47 | ] 48 | -------------------------------------------------------------------------------- /archive/1.vm/continuation5.mu: -------------------------------------------------------------------------------- 1 | # Example program showing that a 'paused' continuation can be 'resumed' with 2 | # inputs. 3 | # 4 | # Print out a list of numbers, first adding 0 to the first, 1 to the second, 2 5 | # to the third, and so on. 6 | # 7 | # To run: 8 | # $ git clone https://github.com/akkartik/mu 9 | # $ cd mu 10 | # $ ./mu continuation5.mu 11 | # 12 | # Expected output: 13 | # 1 14 | # 3 15 | # 5 16 | 17 | def main [ 18 | local-scope 19 | l:&:list:num <- copy null 20 | l <- push 3, l 21 | l <- push 2, l 22 | l <- push 1, l 23 | k:continuation, x:num, done?:bool <- call-with-continuation-mark 100/mark, create-yielder, l 24 | a:num <- copy 1 25 | { 26 | break-if done? 27 | $print x 10/newline 28 | k, x:num, done?:bool <- call k, a # resume; x = a + next l value 29 | a <- add a, 1 30 | loop 31 | } 32 | ] 33 | 34 | def create-yielder l:&:list:num -> n:num, done?:bool [ 35 | local-scope 36 | load-inputs 37 | a:num <- copy 0 38 | { 39 | done? <- equal l, null 40 | break-if done? 41 | n <- first l 42 | l <- rest l 43 | n <- add n, a 44 | a <- return-continuation-until-mark 100/mark, n, done? # pause/resume 45 | loop 46 | } 47 | return-continuation-until-mark 100/mark, -1, done? 48 | assert false, [called too many times, ran out of continuations to return] 49 | ] 50 | -------------------------------------------------------------------------------- /archive/1.vm/copy_mu: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | # Copy binaries across mu directories for different students on a single 3 | # server, so we only need to build them once. 4 | 5 | cp -r $1/enumerate/enumerate $2/enumerate 6 | cp -r $1/cleave/cleave $2/cleave 7 | rm -rf $2/.build 8 | cp -r $1/.build $2 9 | cp -r $1/mu_bin $2 10 | cd $2 11 | ./mu # couple of things still get recompiled, but should now be quick 12 | -------------------------------------------------------------------------------- /archive/1.vm/counters.mu: -------------------------------------------------------------------------------- 1 | # example program: maintain multiple counters with isolated lexical scopes 2 | # (spaces) 3 | 4 | def new-counter n:num -> default-space:space [ 5 | default-space <- new location:type, 30 6 | load-inputs # initialize n 7 | ] 8 | 9 | def increment-counter outer:space/names:new-counter, x:num -> n:num/space:1 [ 10 | local-scope 11 | load-inputs 12 | 0:space/names:new-counter <- copy outer # setup outer space; it *must* come from 'new-counter' 13 | n/space:1 <- add n/space:1, x 14 | ] 15 | 16 | def main [ 17 | local-scope 18 | # counter A 19 | a:space/names:new-counter <- new-counter 34 20 | # counter B 21 | b:space/names:new-counter <- new-counter 23 22 | # increment both by 2 but in different ways 23 | increment-counter a, 1 24 | b-value:num <- increment-counter b, 2 25 | a-value:num <- increment-counter a, 1 26 | # check results 27 | $print [Contents of counters], 10/newline 28 | $print [a: ], a-value, [ b: ], b-value, 10/newline 29 | ] 30 | -------------------------------------------------------------------------------- /archive/1.vm/display.mu: -------------------------------------------------------------------------------- 1 | # example program: managing the display 2 | 3 | def main [ 4 | open-console 5 | clear-display 6 | print-character-to-display 97, 1/red, 2/green 7 | 1:num/raw, 2:num/raw <- cursor-position-on-display 8 | wait-for-some-interaction 9 | clear-line-on-display 10 | move-cursor-on-display 0, 4 11 | print-character-to-display 98 12 | wait-for-some-interaction 13 | move-cursor-on-display 0, 0 14 | clear-line-on-display 15 | wait-for-some-interaction 16 | move-cursor-down-on-display 17 | wait-for-some-interaction 18 | move-cursor-right-on-display 19 | wait-for-some-interaction 20 | move-cursor-left-on-display 21 | wait-for-some-interaction 22 | move-cursor-up-on-display 23 | wait-for-some-interaction 24 | close-console 25 | ] 26 | -------------------------------------------------------------------------------- /archive/1.vm/edit/Readme.md: -------------------------------------------------------------------------------- 1 | Environment for learning programming using Mu: http://akkartik.name/post/mu 2 | 3 | Run it from the `mu` directory: 4 | 5 | ```shell 6 | $ ./mu edit 7 | ``` 8 | 9 | This will load all the `.mu` files in this directory and then run the editor. 10 | Press ctrl-c to quit. Press F4 to save your work (if a lesson/ directory 11 | exists) and to run the contents of the sandbox editor on the right. 12 | 13 | You can also run the tests for the environment: 14 | 15 | ```shell 16 | $ ./mu test edit 17 | ``` 18 | 19 | You can also load the files more explicitly by enumerating them all (in order): 20 | 21 | ```shell 22 | $ ./mu edit/*.mu 23 | ``` 24 | 25 | This is handy if you want to play with simpler versions of the editor that are 26 | easier to understand. Stop loading at any layer to run with a subset of 27 | features: 28 | 29 | ```shell 30 | $ ./mu edit/001*.mu edit/002*.mu # run a simple editor rather than the full environment 31 | ``` 32 | 33 | --- 34 | 35 | Appendix: keyboard shortcuts 36 | 37 | _moving and scrolling_ 38 | - `ctrl-a` or `home`: move cursor to start of line 39 | - `ctrl-e` or `end`: move cursor to end of line 40 | - `ctrl-f` or `page-down`: scroll down by one page 41 | - `ctrl-b` or `page-up`: scroll up by one page 42 | - `ctrl-x`: scroll down by one line 43 | - `ctrl-s`: scroll up by one line 44 | - `ctrl-t`: scroll until current line is at top of screen 45 | 46 | _modifying text_ 47 | - `ctrl-k`: delete text from cursor to end of line 48 | - `ctrl-u`: delete text from start of line until just before cursor 49 | - `ctrl-/`: comment/uncomment current line (using a special leader to ignore real comments https://www.reddit.com/r/vim/comments/4ootmz/_/d4ehmql) 50 | -------------------------------------------------------------------------------- /archive/1.vm/example1.mu: -------------------------------------------------------------------------------- 1 | def main [ 2 | local-scope 3 | a:num <- add 2, 2 4 | a <- multiply a, 3 5 | # uncomment the next line to see the output 6 | # $print a 7 | ] 8 | -------------------------------------------------------------------------------- /archive/1.vm/exuberant_ctags_rc: -------------------------------------------------------------------------------- 1 | --langdef=mu 2 | --langmap=mu:.mu 3 | --regex-mu=/^def[ \t]+([^ \t]*)/\1/d,definition/ 4 | --regex-mu=/^def![ \t]+([^ \t]*)/\1/d,definition/ 5 | --regex-mu=/^recipe[ \t]+([^ \t]*)/\1/d,definition/ 6 | --regex-mu=/^recipe![ \t]+([^ \t]*)/\1/d,definition/ 7 | --regex-mu=/^type[ \t]+([^ \t]*)/\1/t,typeref/ 8 | --regex-mu=/^container[ \t]+([^ \t:]*)/\1/s,struct/ 9 | --regex-mu=/^exclusive-container[ \t]+([^ \t:]*)/\1/u,union/ 10 | --regex-mu=/$x/x/x/e/ --------- next option is for way-points in Mu 11 | --regex-mu=/^[ \t]*(<[^ \t]*>)/\1/d,definition/ 12 | -------------------------------------------------------------------------------- /archive/1.vm/factorial.mu: -------------------------------------------------------------------------------- 1 | # example program: compute the factorial of 5 2 | 3 | def main [ 4 | local-scope 5 | x:num <- factorial 5 6 | $print [result: ], x, [ 7 | ] 8 | ] 9 | 10 | def factorial n:num -> result:num [ 11 | local-scope 12 | load-inputs 13 | { 14 | # if n=0 return 1 15 | zero?:bool <- equal n, 0 16 | break-unless zero? 17 | return 1 18 | } 19 | # return n * factorial(n-1) 20 | x:num <- subtract n, 1 21 | subresult:num <- factorial x 22 | result <- multiply subresult, n 23 | ] 24 | 25 | # unit test 26 | scenario factorial-test [ 27 | run [ 28 | 1:num <- factorial 5 29 | ] 30 | memory-should-contain [ 31 | 1 <- 120 32 | ] 33 | ] 34 | -------------------------------------------------------------------------------- /archive/1.vm/filesystem.mu: -------------------------------------------------------------------------------- 1 | # example program: copy one file into another, character by character 2 | # BEWARE: this will modify your file system 3 | # before running it, put some text into /tmp/mu-x 4 | # after running it, check /tmp/mu-y 5 | 6 | def main [ 7 | local-scope 8 | source-file:&:source:char <- start-reading null/real-filesystem, [/tmp/mu-x] 9 | sink-file:&:sink:char, write-routine:num <- start-writing null/real-filesystem, [/tmp/mu-y] 10 | { 11 | c:char, done?:bool, source-file <- read source-file 12 | break-if done? 13 | sink-file <- write sink-file, c 14 | loop 15 | } 16 | close sink-file 17 | # make sure to wait for the file to be actually written to disk 18 | # (Mu practices structured concurrency: http://250bpm.com/blog:71) 19 | wait-for-routine write-routine 20 | ] 21 | -------------------------------------------------------------------------------- /archive/1.vm/fork.mu: -------------------------------------------------------------------------------- 1 | # example program: running multiple routines 2 | 3 | def main [ 4 | start-running thread2 5 | { 6 | $print 34 7 | loop 8 | } 9 | ] 10 | 11 | def thread2 [ 12 | { 13 | $print 35 14 | loop 15 | } 16 | ] 17 | -------------------------------------------------------------------------------- /archive/1.vm/git_log_filtered: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Show the log while skipping unimportant directories. 3 | # 4 | # I usually run this through an alias local to this repo: 5 | # $ git config alias.ll '!./git_log_filtered' 6 | # $ git ll --stat 7 | set -e 8 | 9 | git log $* -- . ":(exclude)html" 10 | -------------------------------------------------------------------------------- /archive/1.vm/http-client.mu: -------------------------------------------------------------------------------- 1 | # example program: reading a URL over HTTP 2 | 3 | def main [ 4 | local-scope 5 | $print [aaa] 10/newline 6 | google:&:source:char <- start-reading-from-network null/real-resources, [google.com/] 7 | $print [bbb] 10/newline 8 | n:num <- copy 0 9 | buf:&:buffer:char <- new-buffer 30 10 | { 11 | c:char, done?:bool <- read google 12 | break-if done? 13 | n <- add n, 1 14 | buf <- append buf, c 15 | { 16 | _, a:num <- divide-with-remainder n, 100 17 | break-if a 18 | $print n 10/newline 19 | } 20 | loop 21 | } 22 | result:text <- buffer-to-array buf 23 | open-console 24 | clear-screen null/screen # non-scrolling app 25 | len:num <- length *result 26 | print null/real-screen, result 27 | wait-for-some-interaction 28 | close-console 29 | ] 30 | -------------------------------------------------------------------------------- /archive/1.vm/http-server.mu: -------------------------------------------------------------------------------- 1 | # example program: a single-request HTTP server 2 | # listen for connections from clients on a server socket 3 | # when a connection occurs, transfer it to a session socket 4 | # read from it using channels 5 | # write to it directly 6 | # 7 | # After running it, navigate to localhost:8080. Your browser should display 8 | # "SUCCESS!" and the server will terminate after one connection. 9 | 10 | def main [ 11 | local-scope 12 | socket:num <- $open-server-socket 8080/port 13 | $print [Mu socket creation returned ], socket, 10/newline 14 | return-unless socket 15 | session:num <- $accept socket 16 | contents:&:source:char, sink:&:sink:char <- new-channel 30 17 | sink <- start-running receive-from-socket session, sink 18 | query:text <- drain contents 19 | $print [Done reading from socket.], 10/newline 20 | write-to-socket session, [HTTP/1.0 200 OK 21 | Content-type: text/plain 22 | 23 | SUCCESS! 24 | ] 25 | $print 10/newline, [Wrote to and closing socket...], 10/newline 26 | session <- $close-socket session 27 | socket <- $close-socket socket 28 | ] 29 | -------------------------------------------------------------------------------- /archive/1.vm/immutable-error.mu: -------------------------------------------------------------------------------- 1 | # compare mutable.mu 2 | 3 | def main [ 4 | local-scope 5 | x:&:num <- new number:type 6 | foo x 7 | ] 8 | 9 | def foo x:&:num [ 10 | local-scope 11 | load-inputs 12 | *x <- copy 34 # will cause an error because x is immutable in this function 13 | ] 14 | -------------------------------------------------------------------------------- /archive/1.vm/mu: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Run interpreter, first compiling if necessary. 3 | set -e 4 | 5 | ./build3 && ./mu_bin "$@" 6 | 7 | # Scenarios considered: 8 | # ./mu 9 | # ./mu --help 10 | # ./mu test 11 | # ./mu test file1.mu 12 | -------------------------------------------------------------------------------- /archive/1.vm/mutable.mu: -------------------------------------------------------------------------------- 1 | # compare immutable-error.mu 2 | 3 | def main [ 4 | local-scope 5 | x:&:num <- new number:type 6 | foo x 7 | ] 8 | 9 | def foo x:&:num -> x:&:num [ 10 | local-scope 11 | load-inputs 12 | *x <- copy 34 13 | ] 14 | -------------------------------------------------------------------------------- /archive/1.vm/new_lesson: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Run this before running './mu edit' or './mu sandbox' to make sure you don't 3 | # lose any work. 4 | # 5 | # You'll be editing code in lesson/recipes.mu, and any sandboxes you create 6 | # will be in lesson/0, lesson/1, etc., from top to bottom. 7 | 8 | set -e 9 | 10 | mkdir lesson 11 | cd lesson 12 | git init 13 | echo '**/.*.swp' > .gitignore 14 | git add . 15 | git commit -m 0 16 | -------------------------------------------------------------------------------- /archive/1.vm/real-files.mu: -------------------------------------------------------------------------------- 1 | # example program: read a character from one file and write it to another 2 | # BEWARE: this will modify your file system 3 | # before running it, put a character into /tmp/mu-x 4 | # after running it, check /tmp/mu-y 5 | 6 | def main [ 7 | local-scope 8 | f:num/file <- $open-file-for-reading [/tmp/mu-x] 9 | $print [file to read from: ], f, 10/newline 10 | c:char, eof?:bool <- $read-from-file f 11 | $print [copying ], c, 10/newline 12 | f <- $close-file f 13 | $print [file after closing: ], f, 10/newline 14 | f <- $open-file-for-writing [/tmp/mu-y] 15 | $print [file to write to: ], f, 10/newline 16 | $write-to-file f, c 17 | f <- $close-file f 18 | ] 19 | -------------------------------------------------------------------------------- /archive/1.vm/relayout: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Helper to change the numerical prefixes across the repo, say if you want to 3 | # create room between 023 and 024, and so on. 4 | # 5 | # Assumes there's only ever one file with any numeric prefix. If you move 6 | # 003trace.test.cc you might need to do some manual patch-up. 7 | 8 | set -e 9 | 10 | if [[ $# -eq 0 && `git diff HEAD |wc -l` -gt 0 ]] 11 | then 12 | echo "Uncommitted changes" 13 | exit 14 | fi 15 | 16 | if [[ $# -gt 0 ]] # dry run 17 | then 18 | git() { 19 | echo $* 20 | } 21 | fi 22 | 23 | # 24 | 25 | index=0 26 | ls [0-9]* |grep -v "trace.test" |sort -n | 27 | while read file 28 | do 29 | while [[ $file != `printf "%03d" $index`* ]] 30 | do 31 | echo 32 | index=$(($index+1)) 33 | done 34 | echo $file 35 | index=$(($index+1)) 36 | done > .layout 37 | 38 | vim -c "set nu" .layout 39 | 40 | # 41 | 42 | root() { 43 | echo $1 |sed 's/^[0-9]*//' 44 | } 45 | 46 | index=0 47 | cat .layout | 48 | while read file 49 | do 50 | if [ ! -z $file ] 51 | then 52 | newfile=`printf "%03d" $index``root $file` 53 | if [[ $newfile != $file ]] 54 | then 55 | echo git mv $file $newfile 56 | git mv $file $newfile 57 | fi 58 | fi 59 | index=$(($index+1)) 60 | done 61 | 62 | rm .layout 63 | 64 | # Scenarios considered: 65 | # Don't redo the layout if Vim exits with error. 66 | -------------------------------------------------------------------------------- /archive/1.vm/sandbox/Readme.md: -------------------------------------------------------------------------------- 1 | Variant of [the Mu programming environment](../edit) that runs just the sandbox. 2 | 3 | Suitable for people who want to run their favorite terminal-based editor with 4 | Mu. Just run editor and sandbox inside split panes atop tmux. For example, 5 | here's Mu running alongside vim: 6 | 7 | tmux+vim example 8 | 9 | To set this up: 10 | 11 | a) copy the lines in tmux.conf into `$HOME/.tmux.conf`. 12 | 13 | b) copy the file `mu_run` somewhere in your `$PATH`. 14 | 15 | Now when you start tmux, split it into two vertical panes, run `./mu sandbox` 16 | on the right pane and your editor on the left. You should be able to hit F4 in 17 | either side to run the sandbox. 18 | 19 | Known issues: you have to explicitly save inside your editor before hitting 20 | F4, unlike with `./mu edit`. 21 | 22 | --- 23 | 24 | Appendix: keyboard shortcuts 25 | 26 | _moving_ 27 | - `ctrl-a` or `home`: move cursor to start of line 28 | - `ctrl-e` or `end`: move cursor to end of line 29 | 30 | _modifying text_ 31 | - `ctrl-k`: delete text from cursor to end of line 32 | - `ctrl-u`: delete text from start of line until just before cursor 33 | - `ctrl-/`: comment/uncomment current line (using a special leader to ignore real comments https://www.reddit.com/r/vim/comments/4ootmz/_/d4ehmql) 34 | -------------------------------------------------------------------------------- /archive/1.vm/sandbox/mu_run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | # Little bit of glue to support running Mu from Vim over tmux. 3 | 4 | export ALREADY_FOCUSED=0 5 | tmux list-panes |grep "^1.*active" -q && export ALREADY_FOCUSED=1 6 | if [[ $ALREADY_FOCUSED -eq 0 ]] 7 | then 8 | tmux select-pane -t 1 9 | fi 10 | 11 | tmux send-keys 'F4' 12 | 13 | if [[ $ALREADY_FOCUSED -eq 0 ]] 14 | then 15 | tmux last-pane 16 | fi 17 | 18 | exit 0 # avoid spurious error messages under tmux 19 | -------------------------------------------------------------------------------- /archive/1.vm/sandbox/tmux.conf: -------------------------------------------------------------------------------- 1 | # Hotkey for running Mu over tmux 2 | # Assumes exactly two panes, with vim running on the left side and `./mu sandbox` running on the right side. 3 | bind-key -n F4 run mu_run 4 | -------------------------------------------------------------------------------- /archive/1.vm/screen.mu: -------------------------------------------------------------------------------- 1 | # example program: managing the display using 'screen' objects 2 | 3 | # The zero screen below means 'use the real screen'. Tests can also use fake 4 | # screens. 5 | def main [ 6 | open-console 7 | clear-screen null/screen # non-scrolling app 8 | 10:char <- copy 97/a 9 | print null/screen, 10:char/a, 1/red, 2/green 10 | 1:num/raw, 2:num/raw <- cursor-position null/screen 11 | wait-for-event null/console 12 | clear-screen null/screen 13 | move-cursor null/screen, 0/row, 4/column 14 | 10:char <- copy 98/b 15 | print null/screen, 10:char 16 | wait-for-event null/console 17 | move-cursor null/screen, 0/row, 0/column 18 | clear-line null/screen 19 | wait-for-event null/console 20 | cursor-down null/screen 21 | wait-for-event null/console 22 | cursor-right null/screen 23 | wait-for-event null/console 24 | cursor-left null/screen 25 | wait-for-event null/console 26 | cursor-up null/screen 27 | wait-for-event null/console 28 | close-console 29 | ] 30 | -------------------------------------------------------------------------------- /archive/1.vm/snapshot_lesson: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Hacky little helper called from edit/ and sandbox/ apps to save a snapshot 3 | # of lesson/ using git. 4 | set -e 5 | 6 | test -d lesson/.git || exit 0 # give up if it's not a git repo 7 | 8 | cd lesson 9 | # explicitly say '--all' for git 1.9 10 | git add --all . 11 | # bug in git: git diff -q messes up --exit-code 12 | git diff HEAD --exit-code >/dev/null || git commit -a -m . >/dev/null 13 | -------------------------------------------------------------------------------- /archive/1.vm/static-dispatch.mu: -------------------------------------------------------------------------------- 1 | # Example program showing how multiple functions with the same name can 2 | # coexist, and how we select between them. 3 | # 4 | # Expected output: 5 | # 4 6 | # 7 7 | # 7 8 | 9 | def test a:num -> b:num [ 10 | local-scope 11 | load-inputs 12 | b <- add a, 1 13 | ] 14 | 15 | def test a:num, b:num -> c:num [ 16 | local-scope 17 | load-inputs 18 | c <- add a, b 19 | ] 20 | 21 | def main [ 22 | local-scope 23 | a:num <- test 3 # selects single-input version 24 | $print a, 10/newline 25 | b:num <- test 3, 4 # selects double-input version 26 | $print b, 10/newline 27 | c:num <- test 3, 4, 5 # prefers double- to single-input version 28 | $print c, 10/newline 29 | ] 30 | -------------------------------------------------------------------------------- /archive/1.vm/tangle.mu: -------------------------------------------------------------------------------- 1 | # example program: constructing functions out of order 2 | # 3 | # We construct a factorial function with separate base and recursive cases. 4 | # Compare factorial.mu. 5 | # 6 | # This isn't a very tasteful example, just a basic demonstration of 7 | # possibilities. 8 | 9 | def factorial n:num -> result:num [ 10 | local-scope 11 | load-inputs 12 | 13 | ] 14 | 15 | after [ 16 | # if n=0 return 1 17 | return-unless n, 1 18 | ] 19 | 20 | after [ 21 | # return n * factorial(n - 1) 22 | { 23 | break-unless n 24 | x:num <- subtract n, 1 25 | subresult:num <- factorial x 26 | result <- multiply subresult, n 27 | return result 28 | } 29 | ] 30 | 31 | def main [ 32 | 1:num <- factorial 5 33 | # trailing space in next line is to help with syntax highlighting 34 | $print [result: ], 1:num, [ 35 | ] 36 | ] 37 | -------------------------------------------------------------------------------- /archive/1.vm/termbox/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2010-2013 nsf 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /archive/1.vm/termbox/Readme: -------------------------------------------------------------------------------- 1 | Fork of https://github.com/nsf/termbox as of 2015-06-05 2 | git hash 252bef01264a2aeef22ebe5bae0b5893a58947f3 3 | -------------------------------------------------------------------------------- /archive/1.vm/vimrc.vim: -------------------------------------------------------------------------------- 1 | " Highlighting literate directives in C++ sources. 2 | function! HighlightTangledFile() 3 | " Tangled comments only make sense in the sources and are stripped out of 4 | " the generated .cc file. They're highlighted same as regular comments. 5 | syntax match tangledComment /\/\/:.*/ | highlight link tangledComment Comment 6 | syntax match tangledSalientComment /\/\/::.*/ | highlight link tangledSalientComment SalientComment 7 | set comments-=:// 8 | set comments-=n:// 9 | set comments+=n://:,n:// 10 | 11 | " Inside tangle scenarios. 12 | syntax region tangleDirective start=+:(+ skip=+".*"+ end=+)+ 13 | highlight link tangleDirective Delimiter 14 | syntax match traceContains /^+.*/ 15 | highlight traceContains ctermfg=22 16 | syntax match traceAbsent /^-.*/ 17 | highlight traceAbsent ctermfg=darkred 18 | syntax match tangleScenarioSetup /^\s*% .*/ | highlight link tangleScenarioSetup SpecialChar 19 | highlight Special ctermfg=160 20 | endfunction 21 | augroup LocalVimrc 22 | autocmd BufRead,BufNewFile *.cc call HighlightTangledFile() 23 | autocmd BufRead,BufNewFile *.mu set ft=mu 24 | augroup END 25 | 26 | " Scenarios considered: 27 | " opening or starting vim with a new or existing file without an extension (should interpret as C++) 28 | " opening or starting vim with a new or existing file with a .mu extension 29 | " starting vim or opening a buffer without a file name (ok to do nothing) 30 | " opening a second file in a new or existing window (shouldn't mess up existing highlighting) 31 | " reloading an existing file (shouldn't mess up existing highlighting) 32 | -------------------------------------------------------------------------------- /archive/1.vm/x.mu: -------------------------------------------------------------------------------- 1 | # example program: add two numbers 2 | 3 | def main [ 4 | 11:num <- copy 1 5 | 12:num <- copy 3 6 | 13:num <- add 11:num, 12:num 7 | $dump-memory 8 | ] 9 | -------------------------------------------------------------------------------- /archive/2.transect/Readme: -------------------------------------------------------------------------------- 1 | Abortive series of attempts at building a bootstrappable low-level language. 2 | Type-checked, but feasible to implement in some sort of notation for machine 3 | code (like SubX). 4 | 5 | The latest version is in compiler10. But it doesn't account for checking 6 | how programs allocate registers. 7 | -------------------------------------------------------------------------------- /archive/2.transect/compiler2: -------------------------------------------------------------------------------- 1 | to dereference a heap allocation 2 | copy handle to stack 3 | perform lookup to stack 4 | 5 | lookup x in *(ESP+4) of type (handle T) 6 | 7 | reg <- copy *(ESP+5) : (address T stack) 8 | payload alloc id <- copy *reg 9 | address alloc id <- copy *(ESP+4) 10 | compare payload alloc id, address alloc id 11 | jump if not equal to print stack trace and panic 12 | address <- add reg, 1 13 | 14 | types: 15 | 16 | address T reg 17 | address T stack 18 | address T heap 19 | address T global 20 | 21 | copy down this spectrum is not permitted, but up is. 22 | 23 | addresses aren't allowed in types, globals and on the heap. Only handles. 24 | addresses are only for temporary manipulations. 25 | 26 | 27 | *(address T) <- copy T 28 | -------------------------------------------------------------------------------- /archive/2.transect/compiler5: -------------------------------------------------------------------------------- 1 | == Goal 2 | 3 | A memory-safe language with a simple translator to x86 that can be feasibly written in x86. 4 | 5 | == Definitions of terms 6 | 7 | Memory-safe: it should be impossible to: 8 | a) create a pointer out of arbitrary data, or 9 | b) to access heap memory after it's been freed. 10 | 11 | Simple: do all the work in a 2-pass translator: 12 | Pass 1: check each instruction's types in isolation. 13 | Pass 2: emit code for each instruction in isolation. 14 | 15 | == types 16 | 17 | int 18 | char 19 | (address _ t), t ∋ {stack, heap, global} 20 | (array _ t), t ∋ {stack, heap, global} 21 | 22 | stack addresses can't be copied to heap or global 23 | heap addresses can't be copied [1] 24 | global addresses you're free to use anywhere 25 | 26 | [1] (address _ heap) can't be copied or stored, can't be part of a type or 27 | choice. Only thing you can do with it is access it from the register you wrote 28 | it to. And even that not past a call instruction. Important detail: `free()` 29 | is a call. So an address to something on the heap can never be invalid if the 30 | program type-checks. 31 | 32 | : (address T m) <- advance : (array T m), : (index T) 33 | -------------------------------------------------------------------------------- /archive/2.transect/compiler6: -------------------------------------------------------------------------------- 1 | == Goal 2 | 3 | A memory-safe language with a simple translator to x86 that can be feasibly written in x86. 4 | 5 | == Definitions of terms 6 | 7 | Memory-safe: it should be impossible to: 8 | a) create a pointer out of arbitrary data, or 9 | b) to access heap memory after it's been freed. 10 | 11 | Simple: do all the work in a 2-pass translator: 12 | Pass 1: check each instruction's types in isolation. 13 | Pass 2: emit code for each instruction in isolation. 14 | 15 | == types 16 | 17 | int 18 | char 19 | (address _) 20 | (array _ n) 21 | (ref _) 22 | 23 | addresses can't be saved to stack or global, 24 | or included in compound types 25 | or used across a call (to eliminate possibility of free) 26 | 27 | : (address T) <- advance : (array T), : (index T) 28 | 29 | arrays require a size 30 | (ref array _) may not include a size 31 | 32 | == open questions 33 | Is argv an address? 34 | Global variables are easiest to map to addresses. 35 | Ideally we'd represent 'indirect' as a '*' and we could just count to make 36 | sure that an instruction never has more than one '*'. 37 | -------------------------------------------------------------------------------- /archive/2.transect/compiler7: -------------------------------------------------------------------------------- 1 | == Goal 2 | 3 | A memory-safe language with a simple translator to x86 that can be feasibly written in x86. 4 | 5 | == Definitions of terms 6 | 7 | Memory-safe: it should be impossible to: 8 | a) create a pointer out of arbitrary data, or 9 | b) to access heap memory after it's been freed. 10 | 11 | Simple: do all the work in a 2-pass translator: 12 | Pass 1: check each instruction's types in isolation. 13 | Pass 2: emit code for each instruction in isolation. 14 | 15 | == types 16 | 17 | int 18 | char 19 | (address _ stack|heap|global) 20 | (array _ n) # on stack or global 21 | (ref _) 22 | (ref array _) # by definition always on the heap 23 | 24 | addresses to global can be saved and manipulated as usual 25 | addresses on stack can't be saved to heap 26 | addresses on heap can't be saved to global (use ref) 27 | 28 | addresses to stack or heap can't be included in compound types 29 | or used across a call 30 | or used across a label 31 | 32 | : (address T stack|global) <- advance : (array T), : (index T) 33 | : (address T heap) <- advance * : (ref array T), : (index T) 34 | 35 | arrays require a size 36 | (ref array _) may not include a size 37 | 38 | Arguments of type 'address' are required to be on the stack or global. Can't 39 | be on the heap. 40 | 41 | So we need duplication for address and ref arguments? 42 | 43 | Argv has type (array (address (array char) global)) 44 | 45 | variables on stack, heap and global are references. The name points at the 46 | address. Use '*' to get at the value. 47 | -------------------------------------------------------------------------------- /archive/2.transect/compiler8: -------------------------------------------------------------------------------- 1 | == Goal 2 | 3 | A memory-safe language with a simple translator to x86 that can be feasibly written in x86. 4 | 5 | == Definitions of terms 6 | 7 | Memory-safe: it should be impossible to: 8 | a) create a pointer out of arbitrary data, or 9 | b) to access heap memory after it's been freed. 10 | 11 | Simple: do all the work in a 2-pass translator: 12 | Pass 1: check each instruction's types in isolation. 13 | Pass 2: emit code for each instruction in isolation. 14 | 15 | == types 16 | 17 | int 18 | char 19 | (address _) 20 | (array _ n) 21 | (ref _) 22 | 23 | == implications 24 | 25 | addresses can't be saved to stack or global, 26 | or included in compound types 27 | or used across a call (to eliminate possibility of free) 28 | 29 | : (address T) <- advance : (array T), : (index T) 30 | 31 | arrays require a size 32 | (ref array _) may not include a size 33 | 34 | argv has type (array (ref array char)) 35 | 36 | variables on stack, heap and global are references. The name points at the 37 | address. Use '*' to get at the value. 38 | 39 | instructions performing lookups write to register, so that we can reuse the register for temporaries 40 | instructions performing lookups can't read from the register they write to. 41 | But most instructions read from the register they write to?! (in-out params) 42 | 43 | == open questions 44 | 45 | If bounds checks can take multiple instructions, why not perform array 46 | indexing in a single statement in the language? 47 | 48 | But we want addresses as intermediate points to combine instructions with. 49 | 50 | Maybe disallow addresses to function calls, but allow addresses to non-heap 51 | structures to be used spanning function calls and labels. 52 | 53 | That's just for ergonomics. Doesn't add new capability. 54 | -------------------------------------------------------------------------------- /archive/2.transect/ex3.k2: -------------------------------------------------------------------------------- 1 | # add the first 10 numbers, and return the result in the exit code 2 | 3 | fn main [ 4 | var result/EBX : int 5 | result/EBX <- copy 0 6 | var counter/ECX : int 7 | counter/ECX <- copy 1 8 | { 9 | compare counter/ECX, 10 10 | break-if > 11 | result/EBX <- add counter/ECX 12 | counter/ECX <- add 1 13 | loop 14 | } 15 | call exit, 1 16 | ] 17 | 18 | fn exit x : int [ 19 | code/EBX <- copy x 20 | code/EAX <- copy 1/exit 21 | syscall 22 | ] 23 | -------------------------------------------------------------------------------- /archive/2.transect/ex4.k2: -------------------------------------------------------------------------------- 1 | ## read a character from stdin, save it to a global, write it to stdout 2 | 3 | # variables are always references 4 | # read their address with their names: x (can't write to their address) 5 | # read/write their contents with a lookup: *x 6 | var x : char 7 | 8 | fn main [ 9 | call read 0/stdin, x, 1/size 10 | result/EAX <- call write 1/stdout, x, 1/size 11 | call exit, result/EAX 12 | ] 13 | 14 | fn read fd : int, x : (address array byte), size : int [ 15 | EBX <- copy fd 16 | ECX <- copy x 17 | EDX <- copy size 18 | EAX <- copy 3/read 19 | syscall 20 | ] 21 | 22 | fn write fd : int, x : (address array byte), size : int [ 23 | EBX <- copy fd 24 | ECX <- copy x 25 | EDX <- copy size 26 | EAX <- copy 4/write 27 | syscall 28 | ] 29 | 30 | fn exit x : int [ 31 | code/EBX <- copy x 32 | code/EAX <- copy 1/exit 33 | syscall 34 | ] 35 | -------------------------------------------------------------------------------- /archive/2.transect/ex5.k2: -------------------------------------------------------------------------------- 1 | # read a character from stdin, save it to a local on the stack, write it to stdout 2 | 3 | fn main [ 4 | var x : char 5 | call read 0/stdin, x, 1/size 6 | result/EBX <- call write 1/stdout, x, 1/size 7 | call exit-EBX 8 | ] 9 | 10 | fn read fd : int, x : (address array byte), size : int [ 11 | EBX <- copy fd 12 | ECX <- copy x 13 | EDX <- copy size 14 | EAX <- copy 3/read 15 | syscall 16 | ] 17 | 18 | fn write fd : int, x : (address array byte), size : int [ 19 | EBX <- copy fd 20 | ECX <- copy x 21 | EDX <- copy size 22 | EAX <- copy 4/write 23 | syscall 24 | ] 25 | 26 | # like exit, but assumes the code is already in EBX 27 | fn exit-EBX [ 28 | code/EAX <- copy 1/exit 29 | syscall 30 | ] 31 | -------------------------------------------------------------------------------- /archive/2.transect/ex6.k2: -------------------------------------------------------------------------------- 1 | ## print out a (global variable) string to stdout 2 | 3 | var size : int = 14 4 | var x : (array character) = "hello, world!" 5 | 6 | fn main [ 7 | call write 1/stdout, x, size 8 | call exit, 0 9 | ] 10 | 11 | fn write fd : int, x : (address array byte), size : int [ 12 | EBX <- copy fd 13 | ECX <- copy x 14 | EDX <- copy size 15 | EAX <- copy 4/write 16 | syscall 17 | ] 18 | 19 | fn exit x : int [ 20 | code/EBX <- copy x 21 | code/EAX <- copy 1/exit 22 | syscall 23 | ] 24 | -------------------------------------------------------------------------------- /archive/2.transect/ex7.k2: -------------------------------------------------------------------------------- 1 | # example showing file syscalls 2 | # 3 | # Create a file, open it for writing, write a character to it, close it, open 4 | # it for reading, read a character from it, close it, delete it, and return 5 | # the character read. 6 | 7 | var stream : int = 0 8 | var a : char = 97 9 | var b : char = 0 10 | var filename : (array char) = ".foo" 11 | 12 | fn main [ 13 | call create, filename 14 | *stream <- call open, filename, 1/wronly 15 | call write, *stream, a, 1 16 | call close, *stream 17 | stream <- call open, filename, 0/rdonly 18 | call read, *stream, b, 1 19 | call close, *stream 20 | call unlink, filename 21 | var result/EBX : char 22 | result/EBX <- copy b # TODO: copy char to int? 23 | call exit-EBX 24 | ] 25 | 26 | fn read fd : int, x : (address array byte), size : int [ 27 | EBX <- copy fd 28 | ECX <- copy x 29 | EDX <- copy size 30 | EAX <- copy 3/read 31 | syscall 32 | ] 33 | 34 | fn write fd : int, x : (address array byte), size : int [ 35 | EBX <- copy fd 36 | ECX <- copy x 37 | EDX <- copy size 38 | EAX <- copy 4/write 39 | syscall 40 | ] 41 | 42 | fn open name : (address array byte) [ 43 | EBX <- copy name 44 | EAX <- copy 5/open 45 | syscall 46 | ] 47 | 48 | fn close name : (address array byte) [ 49 | EBX <- copy name 50 | EAX <- copy 6/close 51 | syscall 52 | ] 53 | 54 | fn unlink name : (address array byte) [ 55 | EBX <- copy name 56 | EAX <- copy 10/unlink 57 | syscall 58 | ] 59 | 60 | # like exit, but assumes the code is already in EBX 61 | fn exit-EBX [ 62 | code/EAX <- copy 1/exit 63 | syscall 64 | ] 65 | -------------------------------------------------------------------------------- /archive/2.transect/ex8.k2: -------------------------------------------------------------------------------- 1 | # Example reading commandline arguments: compute length of first arg. 2 | 3 | fn main argc : int, argv : (array (ref array char)) -> [ 4 | var tmp : (index char) 5 | tmp <- index 1, %size(ref array char) 6 | var tmp2 : (address (ref array char)) 7 | tmp2 <- advance argv, tmp 8 | var s/EBX : (ref array char) 9 | s/EBX <- copy *tmp2 10 | var result/EAX : int 11 | result/EAX <- ascii_length s/EBX 12 | call exit, result/EAX 13 | ] 14 | 15 | fn ascii_length s : (ref array char) -> result : int [ 16 | var result/EBX : int 17 | result/EBX <- copy 0 18 | { 19 | var tmp0/EDI : (offset char) 20 | tmp0/EDI <- index result/EBX, %size(char) 21 | var tmp/EDX : (address char) 22 | tmp/EDX <- advance *s, tmp0/EDI 23 | var c/ECX : char 24 | c/ECX <- copy *tmp 25 | compare c/ECX, 0 26 | break-if-equal 27 | loop 28 | } 29 | return result/EBX 30 | ] 31 | 32 | fn exit x : int [ 33 | code/EBX <- copy x 34 | code/EAX <- copy 1/exit 35 | syscall 36 | ] 37 | -------------------------------------------------------------------------------- /archive/2.transect/factorial.k2: -------------------------------------------------------------------------------- 1 | # compute the factorial of 5, and return the result in the exit code 2 | 3 | fn factorial n : int -> result/EAX : int [ 4 | result/EAX <- copy 1 5 | { 6 | compare n, 1 7 | break-if <= 8 | var tmp/EBX : int 9 | tmp/EBX <- copy n 10 | tmp/EBX <- subtract 1 11 | var tmp2/EAX : int 12 | tmp2/EAX <- call factorial, tmp/EBX 13 | result/EAX <- multiply tmp2/EAX, n 14 | } 15 | return result/EAX 16 | ] 17 | -------------------------------------------------------------------------------- /archive/Readme.md: -------------------------------------------------------------------------------- 1 | This directory contains earlier prototypes. 2 | 3 | * 0.vm.arc: an early prototype of a statement-oriented interpreted language 4 | built in Arc. Now has its own repo at 5 | [mu0](https://github.com/akkartik/mu0). 6 | 7 | * 1.vm: a statement-oriented interpreted language. Now has its own repo at 8 | [mu1](https://github.com/akkartik/mu1). 9 | 10 | * 2.transect: an abortive design for a safe low-level language with manual 11 | register allocation. 12 | -------------------------------------------------------------------------------- /browse-slack/README.md: -------------------------------------------------------------------------------- 1 | To try it out: 2 | 3 | 1. Import a tiny test Slack archive into the data disk by running: 4 | ``` 5 | tools/image-data 10 < browse-slack/test_data 6 | ``` 7 | 8 | 2. Build the code disk (on Linux; see the top-level Readme for other platforms) 9 | ``` 10 | ./translate browse-slack/*.mu 11 | ``` 12 | 13 | 3. Run the code and data disks: 14 | ``` 15 | qemu-system-i386 -m 2G -hda code.img -hdb path/to/data.img 16 | ``` 17 | 18 | You should now see some text and images in Qemu. For a real Slack archive, 19 | follow the instructions at the top of `browse-slack/convert_slack.py`. You'll 20 | also want to tweak the `sector-count` in browse-slack/main.mu which affects 21 | the number of sectors read from the data disk. 22 | -------------------------------------------------------------------------------- /browse-slack/vimrc.vim: -------------------------------------------------------------------------------- 1 | " when opening files in this directory, load vimrc from cwd (top-level) 2 | source vimrc.vim 3 | -------------------------------------------------------------------------------- /cheatsheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/cheatsheet.pdf -------------------------------------------------------------------------------- /editor/Mu.tmbundle/info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | contactEmailRot13 6 | zh.grkgzngr@nxxnegvx.pbz 7 | contactName 8 | Kartik Agaram 9 | description 10 | Bundle for Mu: https://github.com/akkartik/mu 11 | name 12 | Mu 13 | uuid 14 | 24559A54-666E-40D4-A561-C9A49DD9B675 15 | 16 | 17 | -------------------------------------------------------------------------------- /editor/README.md: -------------------------------------------------------------------------------- 1 | Syntax highlighting configuration for various editors. 2 | -------------------------------------------------------------------------------- /editor/VSCode/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that launches the extension inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "args": [ 13 | "--extensionDevelopmentPath=${workspaceFolder}" 14 | ] 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /editor/VSCode/.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | .gitignore 4 | vsc-extension-quickstart.md 5 | -------------------------------------------------------------------------------- /editor/VSCode/language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "lineComment": "#" 4 | }, 5 | "brackets": [ 6 | ["{", "}"], 7 | ["[", "]"], 8 | ["(", ")"] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /editor/VSCode/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mu", 3 | "displayName": "Mu", 4 | "description": "Syntax Highlighting for the Mu language", 5 | "version": "0.0.1", 6 | "engines": { 7 | "vscode": "^1.62.0" 8 | }, 9 | "categories": [ 10 | "Programming Languages" 11 | ], 12 | "contributes": { 13 | "languages": [{ 14 | "id": "mu", 15 | "aliases": ["Mu", "mu"], 16 | "extensions": [".mu"], 17 | "configuration": "./language-configuration.json" 18 | }], 19 | "grammars": [{ 20 | "language": "mu", 21 | "scopeName": "source.mu", 22 | "path": "./syntaxes/Mu.tmLanguage" 23 | }] 24 | } 25 | } -------------------------------------------------------------------------------- /editor/atom/README.md: -------------------------------------------------------------------------------- 1 | ## Syntax highlighting for the Atom editor 2 | 3 | Copy or symlink this directory into `~/.atom/packages/subx`. 4 | -------------------------------------------------------------------------------- /editor/atom/grammars/subx.json: -------------------------------------------------------------------------------- 1 | { 2 | "scopeName": "source.subx", 3 | "name": "SubX", 4 | "fileTypes": ["subx"], 5 | "patterns": [ 6 | { 7 | "name": "header-comment.subx", 8 | "match": "# - .*" 9 | }, 10 | { 11 | "name": "comment-sub-2.subx", 12 | "match": "# \\. \\. .*" 13 | }, 14 | { 15 | "name": "comment-sub-1.subx", 16 | "match": "# \\. .*" 17 | }, 18 | { 19 | "name": "comment.subx", 20 | "match": "#.*" 21 | }, 22 | { 23 | "name": "strings.subx", 24 | "match": "\"[^\"]*\"" 25 | }, 26 | { 27 | "name": "test.subx", 28 | "match": "^test-[^ ]*:" 29 | }, 30 | { 31 | "name": "global.subx", 32 | "match": "^[A-Z][^ ]*:" 33 | }, 34 | { 35 | "name": "function.subx", 36 | "match": "^[^_$ #][^ ]*:" 37 | }, 38 | { 39 | "name": "label.subx", 40 | "match": "^[_$][^ ]*:" 41 | } 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /editor/atom/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "subx", 3 | "version": "0.0.1", 4 | "description": "Syntax highlighting for SubX files in the Mu computing stack.", 5 | "author": "Kartik Agaram", 6 | "keywords": [ 7 | "language", 8 | "mu", 9 | "syntax", 10 | "highlighting" 11 | ], 12 | "repository": "https://github.com/akkartik/mu", 13 | "engines": { 14 | "atom": ">=1.0.0 <2.0.0" 15 | }, 16 | "dependencies": {} 17 | } 18 | -------------------------------------------------------------------------------- /editor/atom/styles/styles.less: -------------------------------------------------------------------------------- 1 | atom-text-editor.editor { 2 | .syntax--source.syntax--subx { 3 | .syntax--header-comment.syntax--subx { 4 | color: #ccccff; 5 | } 6 | .syntax--comment-sub-1.syntax--subx { 7 | color: #888888; 8 | } 9 | .syntax--comment-sub-2.syntax--subx { 10 | color: #666666; 11 | } 12 | .syntax--comment.syntax--subx { 13 | color: #8888ff; 14 | } 15 | .syntax--strings.syntax--subx { 16 | color: cyan; 17 | } 18 | .syntax--function.syntax--subx { 19 | color: orange; 20 | } 21 | .syntax--global.syntax--subx { 22 | color: red; 23 | } 24 | .syntax--test.syntax--subx { 25 | color: #88ff88; 26 | } 27 | .syntax--label.syntax--subx { 28 | color: #448844; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /editor/editor.md: -------------------------------------------------------------------------------- 1 | ## Getting your editor set up 2 | 3 | If you've read this far, it's time to set up your editor. Mu is really 4 | intended to be read interactively rather than on a browser. 5 | 6 | There is rudimentary syntax highlighting support for Mu and SubX files for 7 | various editors. Look for your editor in `mu.*` and `subx.*`, and follow the 8 | instructions within. 9 | 10 | The Vim files are most developed. In particular, I recommend some optional 11 | setup in subx.vim to use multiple colors for comments. 12 | 13 | If you use [`ctags`](http://ctags.sourceforge.net) for jumping easily 14 | from names to their definitions in your editor, set it up to load `mu.ctags`. 15 | For classic Exuberant Ctags, copy it into `~/.ctags`. For the newer Universal 16 | Ctags, copy it into `~/.ctags.d/mu.ctags`. 17 | 18 | [Here](https://lobste.rs/s/qglfdp/subx_minimalist_assembly_language_for#c_o9ddqk) 19 | are some tips on my setup for quickly finding the right opcode for any 20 | situation from within Vim. 21 | -------------------------------------------------------------------------------- /editor/mu.ctags: -------------------------------------------------------------------------------- 1 | --langdef=mu 2 | --langmap=mu:.mu 3 | --regex-mu=/^fn[ \t]+([^ \t]*)/\1/d,definition/ 4 | --regex-mu=/^type[ \t]+([^ \t]*)/\1/t,typeref/ 5 | 6 | --langdef=subx 7 | --langmap=subx:.subx 8 | --regex-subx=/^([^$ #][^ #]*):/\1/d,definition/ 9 | -------------------------------------------------------------------------------- /editor/mu.dte: -------------------------------------------------------------------------------- 1 | # Syntax highlighting for https://gitlab.com/craigbarnes/dte 2 | # 3 | # To install this file, symlink it to ~/.dte/syntax/mu 4 | # Then add this line to ~/.dte/rc: 5 | # ft mu mu 6 | 7 | syntax mu 8 | 9 | state start code 10 | char # comment 11 | char '"' string 12 | char -b a-z ident 13 | eat this 14 | 15 | state comment 16 | char "\n" start 17 | eat this 18 | 19 | state string 20 | char "\"" start string 21 | eat this 22 | 23 | state ident 24 | char -b a-z this 25 | inlist keyword start 26 | noeat start 27 | 28 | list keyword \ 29 | fn type var 30 | -------------------------------------------------------------------------------- /editor/mu.nanorc: -------------------------------------------------------------------------------- 1 | # include this file in your ~/.nanorc 2 | 3 | syntax "mu" "\.mu$" 4 | # tests 5 | color green "\ 4 | " URL: http://github.com/akkartik/mu 5 | " License: public domain 6 | " 7 | " Copy this file into your ftplugin directory, and add the following to your 8 | " vimrc or to .vim/ftdetect/mulisp.vim: 9 | " autocmd BufReadPost,BufNewFile *.limg set filetype=mulisp 10 | 11 | let s:save_cpo = &cpo 12 | set cpo&vim 13 | 14 | setlocal iskeyword=@,48-57,?,!,_,$ 15 | 16 | " Hack: I define new syntax groups here, and I don't know how to distribute 17 | " colorscheme-independent color suggestions for them. 18 | highlight Normal ctermfg=245 19 | highlight muLispNormal ctermfg=0 20 | highlight muLispOuterKeyword ctermfg=160 21 | highlight link muLispKeyword Type 22 | 23 | syntax region String start=+"+ skip=+\\"+ end=+"+ 24 | 25 | syntax region muLispNormal matchgroup=Normal start=/\[/ end=/\]/ contains=muLispLiteral,muLispComment,muLispDelimiter,muLispKeyword 26 | 27 | syntax match muLispComment /#.*/ contained | highlight link muLispComment Comment 28 | syntax match muLispLiteral /\<[0-9]\+\>/ contained | highlight link muLispLiteral Constant 29 | syntax match muLispLiteral /\[[^\]]*\]/ contained 30 | syntax match muLispDelimiter /[(),@`]/ contained | highlight link muLispDelimiter Delimiter 31 | 32 | syntax keyword muLispOuterKeyword globals sandbox 33 | syntax keyword muLispKeyword fn def mac let if while for 34 | 35 | let &cpo = s:save_cpo 36 | -------------------------------------------------------------------------------- /editor/subx.dte: -------------------------------------------------------------------------------- 1 | # Syntax highlighting for https://gitlab.com/craigbarnes/dte 2 | # 3 | # To install this file, symlink it to ~/.dte/syntax/subx 4 | # Then add this line to ~/.dte/rc: 5 | # ft subx subx 6 | 7 | syntax subx 8 | 9 | # For improved colorization, add lines like these in your ~/.dte/rc (the 10 | # precise colors here assume the default color scheme in a 256-color terminal): 11 | # hi subx.comment0 25 underline 12 | # hi comment 25 13 | # hi subx.comment2 19 14 | # hi subx.comment3 245 15 | default comment subx.comment0 subx.comment2 subx.comment3 16 | 17 | state start code 18 | str "# . ." subx.comment3 19 | str "# ." subx.comment2 20 | str "# -" subx.comment0 21 | char # comment 22 | char '"' string 23 | eat this 24 | 25 | state comment 26 | char "\n" start 27 | eat this 28 | 29 | state subx.comment0 30 | char "\n" start 31 | eat this 32 | 33 | state subx.comment2 34 | char "\n" start 35 | eat this 36 | 37 | state subx.comment3 38 | char "\n" start 39 | eat this 40 | 41 | state string 42 | char "\"" start string 43 | eat this 44 | -------------------------------------------------------------------------------- /editor/subx.el: -------------------------------------------------------------------------------- 1 | ;;; Emacs major mode for editing SubX files. -*- coding: utf-8; lexical-binding: t; -*- 2 | 3 | ;; Author: Kartik Agaram (subx.el@akkartik.com) 4 | ;; Version: 0.0.1 5 | ;; Created: 28 Dec 2019 6 | ;; Keywords: languages 7 | ;; Homepage: https://github.com/akkartik/mu 8 | 9 | ;;; Commentary: 10 | 11 | ;; I don't know how to define new faces in an emacs package, so I'm 12 | ;; cannibalizing existing faces. 13 | ;; 14 | ;; I load this file like so in my .emacs: 15 | ;; (load "/absolute/path/to/subx.el") 16 | ;; (add-to-list 'auto-mode-alist '("\\.subx" . subx-mode)) 17 | ;; 18 | ;; Education on the right way to do this most appreciated. 19 | 20 | (setq subx-font-lock-keywords 21 | '( 22 | ; tests 23 | ("^test-[^ ]*:" . font-lock-type-face) 24 | ; functions 25 | ("^[a-z][^ ]*:" . font-lock-function-name-face) 26 | ; globals 27 | ("^[A-Z][^ ]*:" . font-lock-variable-name-face) 28 | ; minor labels 29 | ("^[^a-zA-Z#( ][^ ]*:" . font-lock-doc-face) 30 | ; string literals 31 | ; ("\"[^\"]*\"" . font-lock-constant-face) ; strings colorized already, albeit buggily 32 | ; 4 colors for comments; ugly but functional 33 | ("# \\. \\. .*" . font-lock-doc-face) 34 | ("# \\. .*" . font-lock-constant-face) 35 | ("# - .*" . font-lock-comment-face) 36 | ("#.*" . font-lock-preprocessor-face) 37 | )) 38 | 39 | (define-derived-mode subx-mode fundamental-mode "subx mode" 40 | "Major mode for editing SubX (Mu project)" 41 | (setq font-lock-defaults '((subx-font-lock-keywords))) 42 | ) 43 | 44 | (provide 'subx-mode) 45 | -------------------------------------------------------------------------------- /editor/subx.gedit: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | text/x-subx;text/x-subxsrc 6 | *.subx 7 | 8 | 9 | 20 | 21 | 49 | 50 | 51 | https://github.com/akkartik/mu/blob/main/apps/*.subx 52 |
53 | 1 
54 | 
55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /html/archive/2.vm/chessboard-test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/archive/2.vm/chessboard-test.png -------------------------------------------------------------------------------- /html/archive/2.vm/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/archive/2.vm/edit.png -------------------------------------------------------------------------------- /html/archive/2.vm/example1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/archive/2.vm/example1.png -------------------------------------------------------------------------------- /html/archive/2.vm/expected-result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/archive/2.vm/expected-result.png -------------------------------------------------------------------------------- /html/archive/2.vm/f2c-1.mu: -------------------------------------------------------------------------------- 1 | # c = (f-32) * 5/9 2 | def fahrenheit-to-celsius f:number -> c:number [ 3 | local-scope 4 | load-ingredients 5 | tmp:number <- subtract f, 32 6 | tmp <- multiply tmp, 5 7 | c <- divide tmp, 9 8 | ] 9 | -------------------------------------------------------------------------------- /html/archive/2.vm/f2c-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/archive/2.vm/f2c-1.png -------------------------------------------------------------------------------- /html/archive/2.vm/f2c-2.mu: -------------------------------------------------------------------------------- 1 | # c = (f-32) * 5/9 2 | def fahrenheit-to-celsius [ 3 | local-scope 4 | f:number <- next-ingredient 5 | tmp:number <- subtract f, 32 6 | tmp <- multiply tmp, 5 7 | c:number <- divide tmp, 9 8 | return c 9 | ] 10 | -------------------------------------------------------------------------------- /html/archive/2.vm/f2c-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/archive/2.vm/f2c-2.png -------------------------------------------------------------------------------- /html/archive/2.vm/factorial-test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/archive/2.vm/factorial-test.png -------------------------------------------------------------------------------- /html/archive/2.vm/factorial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/archive/2.vm/factorial.png -------------------------------------------------------------------------------- /html/archive/2.vm/fake-console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/archive/2.vm/fake-console.png -------------------------------------------------------------------------------- /html/archive/2.vm/fake-keyboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/archive/2.vm/fake-keyboard.png -------------------------------------------------------------------------------- /html/archive/2.vm/fork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/archive/2.vm/fork.png -------------------------------------------------------------------------------- /html/archive/2.vm/immutable-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/archive/2.vm/immutable-error.png -------------------------------------------------------------------------------- /html/archive/2.vm/mutable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/archive/2.vm/mutable.png -------------------------------------------------------------------------------- /html/archive/2.vm/resources.mu: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | assume-resources [ 6 | # contents for a local file 7 | [/foo/bar] <- [ 8 | |def| # lines delimited by '|' 9 | ] 10 | 11 | # contents for a URL 12 | [example.com/foo/bar] <- [ 13 | |abc| 14 | ] 15 | ] 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /html/archive/2.vm/resources.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/archive/2.vm/resources.png -------------------------------------------------------------------------------- /html/archive/2.vm/tangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/archive/2.vm/tangle.png -------------------------------------------------------------------------------- /html/archive/2.vm/tmux-vim-sandbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/archive/2.vm/tmux-vim-sandbox.png -------------------------------------------------------------------------------- /html/archive/2.vm/tracing-test.mu: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run [ 5 | result:boolean <- equal [abc], [abcd] # lengths differ 6 | ] 7 | trace-should-contain [ 8 | equal: comparing lengths 9 | ] 10 | trace-should-not-contain [ 11 | equal: comparing characters 12 | ] 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /html/archive/2.vm/tracing-test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/archive/2.vm/tracing-test.png -------------------------------------------------------------------------------- /html/archive/2.vm/unexpected-result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/archive/2.vm/unexpected-result.png -------------------------------------------------------------------------------- /html/control0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/control0.png -------------------------------------------------------------------------------- /html/control1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/control1.png -------------------------------------------------------------------------------- /html/encoding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/encoding.png -------------------------------------------------------------------------------- /html/ex2.mu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/ex2.mu.png -------------------------------------------------------------------------------- /html/ex3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/ex3.png -------------------------------------------------------------------------------- /html/life.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/life.png -------------------------------------------------------------------------------- /html/rpn5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/rpn5.png -------------------------------------------------------------------------------- /html/trace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/html/trace.png -------------------------------------------------------------------------------- /linux/100.txt: -------------------------------------------------------------------------------- 1 | We're now past C++ bootstrap. 2 | 3 | Layers in the 1xx series are in bare SubX, without any syntax sugar. They are 4 | intended to be used by the phases of the self-hosted translator to replicate 5 | the functionality of the C++ bootstrap: 6 | hex.subx 7 | survey_elf.subx 8 | pack.subx 9 | dquotes.subx 10 | assort.subx 11 | tests.subx 12 | -------------------------------------------------------------------------------- /linux/200.txt: -------------------------------------------------------------------------------- 1 | Layers in the 2xx series are in bare SubX, without any syntax sugar. They are 2 | intended to be used by various syntax-sugar phases: 3 | sigils.subx 4 | calls.subx 5 | braces.subx 6 | -------------------------------------------------------------------------------- /linux/300.txt: -------------------------------------------------------------------------------- 1 | Layers in the 3xx series use all the available syntax sugar for SubX programs. 2 | Functions here can be called from Mu programs if they meet certain criteria: 3 | 4 | - There's a signature for them in 400.mu 5 | - Inouts on the stack, outputs in registers 6 | - Valid Mu types everywhere (Mu's type system isn't expressive enough for 7 | everything SubX does in rare situations.) 8 | - No way to for an `addr` to escape a function. No `(... addr ... addr ...)` 9 | inouts, and no `(... addr ...)` outputs. 10 | 11 | While functions _can_ be called, not all SubX functions meeting these criteria 12 | _should_ be called. In particular, avoid exporting functions that could be 13 | misused. A classic example is trying to add a `size-of` operator. If you're 14 | doing that you're likely going to rely on programmers to use it correctly. Mu 15 | tries to be idiot-proof. Even if SubX requires greater care, using SubX 16 | primitives from Mu should not. 17 | -------------------------------------------------------------------------------- /linux/307size.subx: -------------------------------------------------------------------------------- 1 | # Size of an array in bytes. 2 | 3 | == code 4 | 5 | size: # in: (addr array _) -> result/eax: int 6 | # . prologue 7 | 55/push-ebp 8 | 89/<- %ebp 4/r32/esp 9 | # eax = in 10 | 8b/-> *(ebp+8) 0/r32/eax 11 | # 12 | 8b/-> *eax 0/r32/eax 13 | $size:end: 14 | # . epilogue 15 | 89/<- %esp 5/r32/ebp 16 | 5d/pop-to-ebp 17 | c3/return 18 | -------------------------------------------------------------------------------- /linux/308allocate-array.subx: -------------------------------------------------------------------------------- 1 | # 2-arg version of allocate-array. 2 | # Really only intended to be called from code generated by mu.subx. 3 | 4 | == code 5 | 6 | allocate-array2: # ad: (addr allocation-descriptor), array-len: int, elem-size: int, out: (addr handle array _) 7 | # . prologue 8 | 55/push-ebp 9 | 89/<- %ebp 4/r32/esp 10 | # . save registers 11 | 50/push-eax 12 | 52/push-edx 13 | # 14 | 8b/-> *(ebp+0xc) 0/r32/eax 15 | f7 4/subop/multiply-into-edx-eax *(ebp+0x10) 16 | # TODO: check edx for overflow 17 | (allocate-array *(ebp+8) %eax *(ebp+0x14)) 18 | $allocate-array2:end: 19 | # . restore registers 20 | 5a/pop-to-edx 21 | 58/pop-to-eax 22 | # . epilogue 23 | 89/<- %esp 5/r32/ebp 24 | 5d/pop-to-ebp 25 | c3/return 26 | -------------------------------------------------------------------------------- /linux/314divide.subx: -------------------------------------------------------------------------------- 1 | == code 2 | 3 | integer-divide: # a: int, b: int -> quotient/eax: int, remainder/edx: int 4 | # . prologue 5 | 55/push-ebp 6 | 89/<- %ebp 4/r32/esp 7 | # eax = a 8 | 8b/-> *(ebp+8) 0/r32/eax 9 | # edx = all 0s or all 1s 10 | 99/sign-extend-eax-into-edx 11 | # quotient, remainder = divide eax by b 12 | f7 7/subop/divide-eax-edx-by *(ebp+0xc) 13 | $integer-divide:end: 14 | # . epilogue 15 | 89/<- %esp 5/r32/ebp 16 | 5d/pop-to-ebp 17 | c3/return 18 | -------------------------------------------------------------------------------- /linux/315slice.subx: -------------------------------------------------------------------------------- 1 | == code 2 | 3 | # variant of slice-to-string intended to be called from Mu 4 | # Mu doesn't yet expose allocation-descriptors 5 | _slice-to-string: # in: (addr slice), out: (addr handle array byte) 6 | # . prologue 7 | 55/push-ebp 8 | 89/<- %ebp 4/r32/esp 9 | # 10 | (slice-to-string Heap *(ebp+8) *(ebp+0xc)) 11 | # . epilogue 12 | 89/<- %esp 5/r32/ebp 13 | 5d/pop-to-ebp 14 | c3/return 15 | -------------------------------------------------------------------------------- /linux/401test.mu: -------------------------------------------------------------------------------- 1 | # Some helpers for Mu tests. 2 | 3 | fn check val: boolean, msg: (addr array byte) { 4 | var tmp/eax: int <- copy val 5 | check-ints-equal tmp, 1, msg 6 | } 7 | 8 | fn check-not val: boolean, msg: (addr array byte) { 9 | var tmp/eax: int <- copy val 10 | check-ints-equal tmp, 0, msg 11 | } 12 | -------------------------------------------------------------------------------- /linux/402time.mu: -------------------------------------------------------------------------------- 1 | type timespec { 2 | tv_sec: int 3 | tv_nsec: int 4 | } 5 | 6 | # return time in seconds since epoch 7 | # TODO: y2038 8 | fn time -> _/eax: int { 9 | var t: timespec 10 | var clock/ebx: int <- copy 0/CLOCK_MONOTONIC 11 | var t-addr/ecx: (addr timespec) <- address t 12 | syscall_clock_gettime 13 | var t-secs-addr/ecx: (addr int) <- get t-addr, tv_sec 14 | var secs/eax: int <- copy *t-secs-addr 15 | return secs 16 | } 17 | 18 | # return time in nanoseconds since epoch 19 | fn ntime -> _/eax: int { 20 | var t: timespec 21 | var clock/ebx: int <- copy 0/CLOCK_MONOTONIC 22 | var t-addr/ecx: (addr timespec) <- address t 23 | syscall_clock_gettime 24 | var t-nsecs-addr/ecx: (addr int) <- get t-addr, tv_nsec 25 | var nsecs/eax: int <- copy *t-nsecs-addr 26 | return nsecs 27 | } 28 | 29 | # nsecs must be less than 999999999 or 0x3b9ac9ff nanoseconds 30 | fn sleep secs: int, nsecs: int { 31 | var t: timespec 32 | # initialize t 33 | var tmp/eax: (addr int) <- get t, tv_sec 34 | var tmp2/ecx: int <- copy secs 35 | copy-to *tmp, tmp2 36 | tmp <- get t, tv_nsec 37 | tmp2 <- copy nsecs 38 | copy-to *tmp, tmp2 39 | # perform the syscall 40 | var t-addr/ebx: (addr timespec) <- address t 41 | var rem-addr/ecx: (addr timespec) <- copy 0 42 | syscall_nanosleep 43 | } 44 | -------------------------------------------------------------------------------- /linux/406int32.mu: -------------------------------------------------------------------------------- 1 | # Some slow but convenient helpers 2 | 3 | # slow, iterative shift-left instruction 4 | # preconditions: _nr >= 0, _dr > 0 5 | fn repeated-shift-left nr: int, dr: int -> _/eax: int { 6 | var result/eax: int <- copy nr 7 | { 8 | compare dr, 0 9 | break-if-<= 10 | result <- shift-left 1 11 | decrement dr 12 | loop 13 | } 14 | return result 15 | } 16 | 17 | # slow, iterative shift-right instruction 18 | # preconditions: _nr >= 0, _dr > 0 19 | fn repeated-shift-right nr: int, dr: int -> _/eax: int { 20 | var result/eax: int <- copy nr 21 | { 22 | compare dr, 0 23 | break-if-<= 24 | result <- shift-right 1 25 | decrement dr 26 | loop 27 | } 28 | return result 29 | } 30 | 31 | fn abs n: int -> _/eax: int { 32 | var result/eax: int <- copy n 33 | { 34 | compare n, 0 35 | break-if->= 36 | result <- negate 37 | } 38 | return result 39 | } 40 | -------------------------------------------------------------------------------- /linux/407right-justify.mu: -------------------------------------------------------------------------------- 1 | # print 'n' with enough leading spaces to be right-justified in 'width' 2 | fn print-int32-decimal-right-justified screen: (addr screen), n: int, _width: int { 3 | # tweak things for negative numbers 4 | var n-width/eax: int <- decimal-size n 5 | var width/ecx: int <- copy _width 6 | { 7 | compare n-width, width 8 | break-if->= 9 | print-code-point-utf8 screen, 0x20/space 10 | width <- decrement 11 | loop 12 | } 13 | print-int32-decimal screen, n 14 | } 15 | -------------------------------------------------------------------------------- /linux/408float.mu: -------------------------------------------------------------------------------- 1 | # Some quick-n-dirty ways to create floats. 2 | 3 | fn fill-in-rational _out: (addr float), nr: int, dr: int { 4 | var out/edi: (addr float) <- copy _out 5 | var result/xmm0: float <- convert nr 6 | var divisor/xmm1: float <- convert dr 7 | result <- divide divisor 8 | copy-to *out, result 9 | } 10 | 11 | fn fill-in-sqrt _out: (addr float), n: int { 12 | var out/edi: (addr float) <- copy _out 13 | var result/xmm0: float <- convert n 14 | result <- square-root result 15 | copy-to *out, result 16 | } 17 | 18 | fn rational nr: int, dr: int -> _/xmm0: float { 19 | var result/xmm0: float <- convert nr 20 | var divisor/xmm1: float <- convert dr 21 | result <- divide divisor 22 | return result 23 | } 24 | -------------------------------------------------------------------------------- /linux/410file.mu: -------------------------------------------------------------------------------- 1 | fn read-lines in: (addr buffered-file), out: (addr handle array (handle array byte)) { 2 | var stream: (stream (handle array byte) 0x10) 3 | var stream-a/edi: (addr stream (handle array byte)) <- address stream 4 | var line: (stream byte 0x10) 5 | var line-a/esi: (addr stream byte) <- address line 6 | { 7 | clear-stream line-a 8 | read-line-buffered in, line-a 9 | var done?/eax: boolean <- stream-empty? line-a 10 | compare done?, 0/false 11 | break-if-!= 12 | #? print-string 0, "AAA\n" 13 | var h: (handle array byte) 14 | var ah/eax: (addr handle array byte) <- address h 15 | stream-to-array line-a, ah 16 | write-to-stream stream-a, ah 17 | loop 18 | } 19 | stream-to-array stream-a, out 20 | } 21 | -------------------------------------------------------------------------------- /linux/apps/advent2020/vimrc.vim: -------------------------------------------------------------------------------- 1 | " when opening files in this directory, load vimrc from cwd (top-level) 2 | source vimrc.vim 3 | -------------------------------------------------------------------------------- /linux/apps/ex1.mu: -------------------------------------------------------------------------------- 1 | # First example: return the answer to the Ultimate Question of Life, the 2 | # Universe, and Everything. 3 | # 4 | # Same as https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html 5 | # 6 | # To run: 7 | # $ ./translate apps/ex1.mu 8 | # $ ./a.elf 9 | # Expected result: 10 | # $ echo $? 11 | # 42 12 | 13 | fn main -> _/ebx: int { 14 | return 0x2a # Mu requires hexadecimal 15 | } 16 | -------------------------------------------------------------------------------- /linux/apps/ex1.subx: -------------------------------------------------------------------------------- 1 | # First example: return the answer to the Ultimate Question of Life, the 2 | # Universe, and Everything. 3 | # 4 | # Same as https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html 5 | # 6 | # To run: 7 | # $ ./translate_subx 000init.subx apps/ex1.subx 8 | # $ ./a.elf 9 | # Expected result: 10 | # $ echo $? 11 | # 42 12 | 13 | == code 14 | 15 | Entry: 16 | # exit(42) 17 | bb/copy-to-ebx 0x2a/imm32 # 42 in hex 18 | e8/call syscall_exit/disp32 19 | 20 | # . . vim:nowrap:textwidth=0 21 | -------------------------------------------------------------------------------- /linux/apps/ex12.subx: -------------------------------------------------------------------------------- 1 | # Example showing mmap syscall. 2 | # Create a new segment using mmap, save the address, write to it. 3 | # 4 | # To run: 5 | # $ ./translate_subx 000init.subx apps/ex12.subx 6 | # $ ./a.elf 7 | # You shouldn't get a segmentation fault. 8 | 9 | == code 10 | # instruction effective address register displacement immediate 11 | # . op subop mod rm32 base index scale r32 12 | # . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes 13 | 14 | Entry: 15 | # mmap(Mmap-new-segment->len) 16 | bb/copy-to-ebx Mmap-new-segment/imm32 17 | e8/call syscall_mmap/disp32 18 | 19 | # write to *eax to check that we have access to the newly-allocated segment 20 | c7 0/subop/copy 0/mod/direct 0/rm32/eax . . . . . 0x34/imm32 # copy to *eax 21 | 22 | # exit(eax) 23 | 89/copy 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # copy eax to ebx 24 | e8/call syscall_exit/disp32 25 | 26 | == data 27 | 28 | # various constants used here were found in the Linux sources (search for file mman-common.h) 29 | Mmap-new-segment: # type mmap_arg_struct 30 | # addr 31 | 0/imm32 32 | # len 33 | 0x100/imm32 34 | # protection flags 35 | 3/imm32 # PROT_READ | PROT_WRITE 36 | # sharing flags 37 | 0x22/imm32 # MAP_PRIVATE | MAP_ANONYMOUS 38 | # fd 39 | -1/imm32 # since MAP_ANONYMOUS is specified 40 | # offset 41 | 0/imm32 # since MAP_ANONYMOUS is specified 42 | 43 | # . . vim:nowrap:textwidth=0 44 | -------------------------------------------------------------------------------- /linux/apps/ex13.subx: -------------------------------------------------------------------------------- 1 | # Compare 3 and 3. 2 | # 3 | # To run: 4 | # $ ./translate_subx 000init.subx apps/ex13.subx 5 | # $ ./a.elf 6 | # Expected result: 7 | # $ echo $? 8 | # 1 9 | 10 | == code 11 | # instruction effective address register displacement immediate 12 | # . op subop mod rm32 base index scale r32 13 | # . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes 14 | 15 | Entry: 16 | b8/copy-to-eax 3/imm32 17 | 3d/compare-eax-and 3/imm32 18 | 0f 94/set-if-= 3/mod/direct 3/rm32/ebx . . . . . . # set ebx to ZF 19 | 81 4/subop/and 3/mod/direct 3/rm32/ebx . . . . . 0xff/imm32 # AND with eax 20 | 21 | $exit: 22 | # exit(ebx) 23 | e8/call syscall_exit/disp32 24 | 25 | # . . vim:nowrap:textwidth=0 26 | -------------------------------------------------------------------------------- /linux/apps/ex14.subx: -------------------------------------------------------------------------------- 1 | # Multiply 2 numbers. 2 | # 3 | # To run: 4 | # $ ./translate_subx 000init.subx apps/ex14.subx 5 | # $ ./a.elf 6 | # Expected result: 7 | # $ echo $? 8 | # 6 9 | 10 | == code 11 | # instruction effective address register displacement immediate 12 | # . op subop mod rm32 base index scale r32 13 | # . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes 14 | 15 | Entry: 16 | b8/copy-to-eax 1/imm32 17 | b9/copy-to-ecx 2/imm32 18 | bb/copy-to-ebx 3/imm32 19 | 20 | 69/multiply 3/mod/direct 1/rm32/ecx . . . 3/r32/ebx 3/imm32 # ebx = ecx * 3 21 | 22 | $exit: 23 | # exit(ebx) 24 | e8/call syscall_exit/disp32 25 | 26 | # . . vim:nowrap:textwidth=0 27 | -------------------------------------------------------------------------------- /linux/apps/ex2.mu: -------------------------------------------------------------------------------- 1 | # Add 3 and 4, and return the result in the exit code. 2 | # 3 | # To run: 4 | # $ ./translate apps/ex2.mu 5 | # $ ./a.elf 6 | # Expected result: 7 | # $ echo $? 8 | # 7 9 | 10 | fn main -> _/ebx: int { 11 | var result/eax: int <- do-add 3 4 12 | return result 13 | } 14 | 15 | fn do-add a: int, b: int -> _/eax: int { 16 | var result/ecx: int <- copy a 17 | result <- add b 18 | return result 19 | } 20 | -------------------------------------------------------------------------------- /linux/apps/ex2.subx: -------------------------------------------------------------------------------- 1 | # Add 3 and 4, and return the result in the exit code. 2 | # 3 | # To run: 4 | # $ ./translate_subx 000init.subx apps/ex2.subx 5 | # $ ./a.elf 6 | # Expected result: 7 | # $ echo $? 8 | # 7 9 | 10 | == code 11 | 12 | Entry: 13 | # ebx = 3 14 | bb/copy-to-ebx 3/imm32 15 | # add 4 to ebx 16 | 81 0/subop/add 3/mod/direct 3/rm32/ebx 4/imm32 17 | # exit(ebx) 18 | e8/call syscall_exit/disp32 19 | 20 | # . . vim:nowrap:textwidth=0 21 | -------------------------------------------------------------------------------- /linux/apps/ex3.2.mu: -------------------------------------------------------------------------------- 1 | # Unnecessarily use an array to sum 1..10 2 | # 3 | # To run: 4 | # $ ./translate apps/ex3.2.mu 5 | # $ ./a.elf 6 | # $ echo $? 7 | # 55 8 | 9 | fn main -> _/ebx: int { 10 | # populate a 11 | var a: (array int 0xb) # 11; we waste index 0 12 | var i/ecx: int <- copy 1 13 | { 14 | compare i, 0xb 15 | break-if->= 16 | var x/eax: (addr int) <- index a, i 17 | copy-to *x, i 18 | i <- increment 19 | loop 20 | } 21 | # sum 22 | var result/edx: int <- copy 0 23 | i <- copy 1 24 | { 25 | compare i, 0xb 26 | break-if->= 27 | var x/eax: (addr int) <- index a, i 28 | result <- add *x 29 | i <- increment 30 | loop 31 | } 32 | return result 33 | } 34 | -------------------------------------------------------------------------------- /linux/apps/ex3.mu: -------------------------------------------------------------------------------- 1 | # Add the first 10 numbers, and return the result in the exit code. 2 | # 3 | # To run: 4 | # $ ./translate ex3.mu 5 | # $ ./a.elf 6 | # Expected result: 7 | # $ echo $? 8 | # 55 9 | 10 | fn main -> _/ebx: int { 11 | var result/ebx: int <- copy 0 12 | var i/eax: int <- copy 1 13 | { 14 | compare i, 0xa 15 | break-if-> 16 | result <- add i 17 | i <- increment 18 | loop 19 | } 20 | return result 21 | } 22 | -------------------------------------------------------------------------------- /linux/apps/ex3.subx: -------------------------------------------------------------------------------- 1 | # Add the first 10 numbers, and return the result in the exit code. 2 | # 3 | # To run: 4 | # $ ./translate_subx 000init.subx apps/ex3.subx 5 | # $ ./a.elf 6 | # Expected result: 7 | # $ echo $? 8 | # 55 9 | 10 | == code 11 | # instruction effective address register displacement immediate 12 | # . op subop mod rm32 base index scale r32 13 | # . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes 14 | 15 | Entry: 16 | # result: ebx = 0 17 | bb/copy-to-ebx 0/imm32 18 | # counter: ecx = 1 19 | b9/copy-to-ecx 1/imm32 20 | 21 | $loop: 22 | # if (counter > 10) break 23 | 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0xa/imm32 # compare ecx 24 | 7f/jump-if-> $exit/disp8 25 | # result += counter 26 | 01/add 3/mod/direct 3/rm32/ebx . . . 1/r32/ecx . . # add ecx to ebx 27 | # ++counter 28 | 41/increment-ecx 29 | # loop 30 | eb/jump $loop/disp8 31 | 32 | $exit: 33 | # exit(ebx) 34 | e8/call syscall_exit/disp32 35 | 36 | # . . vim:nowrap:textwidth=0 37 | -------------------------------------------------------------------------------- /linux/apps/ex4.subx: -------------------------------------------------------------------------------- 1 | # Read a character from stdin, save it to a global, write it to stdout. 2 | # 3 | # To run: 4 | # $ ./translate_subx 000init.subx apps/ex4.subx 5 | # $ ./a.elf 6 | 7 | == data 8 | 9 | # the global variable we save to 10 | X: 11 | 0/imm32 # space for read() to write to 12 | 13 | == code 14 | 15 | Entry: 16 | # read(stdin, X, 1) 17 | # . fd = 0 (stdin) 18 | bb/copy-to-ebx 0/imm32 19 | # . data = X (location to write result to) 20 | b9/copy-to-ecx X/imm32 21 | # . size = 1 character 22 | ba/copy-to-edx 1/imm32 23 | # . syscall 24 | e8/call syscall_read/disp32 25 | 26 | # write(stdout, X, 1) 27 | # . fd = 1 (stdout) 28 | bb/copy-to-ebx 1/imm32 29 | # . initialize X (location to read from) 30 | b9/copy-to-ecx X/imm32 31 | # . size = 1 character 32 | ba/copy-to-edx 1/imm32 33 | # . syscall 34 | e8/call syscall_write/disp32 35 | 36 | # exit(ebx) 37 | e8/call syscall_exit/disp32 38 | 39 | # . . vim:nowrap:textwidth=0 40 | -------------------------------------------------------------------------------- /linux/apps/ex5.subx: -------------------------------------------------------------------------------- 1 | # Read a character from stdin, save it to a local on the stack, write it to stdout. 2 | # 3 | # To run: 4 | # $ ./translate_subx 000init.subx apps/ex5.subx 5 | # $ ./a.elf 6 | 7 | == code 8 | # instruction effective address register displacement immediate 9 | # . op subop mod rm32 base index scale r32 10 | # . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes 11 | 12 | Entry: 13 | 14 | # allocate x on the stack 15 | 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # subtract from esp 16 | 17 | # read(stdin, x, 1) 18 | # . fd = 0 (stdin) 19 | bb/copy-to-ebx 0/imm32 20 | # . data = x (location to write result to) 21 | 8d/copy-address 1/mod/*+disp8 4/rm32/sib 4/base/esp 4/index/none 1/r32/ecx 4/disp8 . # copy esp+4 to ecx 22 | # . size = 1 character 23 | ba/copy-to-edx 1/imm32 24 | # . syscall 25 | e8/call syscall_read/disp32 26 | 27 | # syscall_write(stdout, x, 1) 28 | # . fd = 1 (stdout) 29 | bb/copy-to-ebx 1/imm32 30 | # . data = x (location to read from) 31 | 8d/copy-address 1/mod/*+disp8 4/rm32/sib 4/base/esp 4/index/none 1/r32/ecx 4/disp8 . # copy esp+4 to ecx 32 | # . size = 1 character 33 | ba/copy-to-edx 1/imm32 34 | # . syscall 35 | e8/call syscall_write/disp32 36 | 37 | # exit(ebx) 38 | e8/call syscall_exit/disp32 39 | 40 | # . . vim:nowrap:textwidth=0 41 | -------------------------------------------------------------------------------- /linux/apps/ex6.subx: -------------------------------------------------------------------------------- 1 | # Print out a (global variable) string to stdout. 2 | # 3 | # To run: 4 | # $ ./translate_subx 000init.subx apps/ex6.subx 5 | # $ ./a.elf 6 | # Hello, world! 7 | 8 | == code 9 | 10 | # . op subop mod rm32 base index scale r32 11 | # . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes 12 | 13 | Entry: 14 | # write(stdout, X, Size) 15 | # . fd = 1 (stdout) 16 | bb/copy-to-ebx 1/imm32 17 | # . initialize X (location to write result to) 18 | b9/copy-to-ecx X/imm32 19 | # . initialize Size 20 | 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 2/r32/edx Size/disp32 . # copy *Size to edx 21 | # . syscall 22 | e8/call syscall_write/disp32 23 | 24 | # exit(ebx) 25 | e8/call syscall_exit/disp32 26 | 27 | == data 28 | 29 | Size: # size of string 30 | 0x0d/imm32 # 13 31 | X: # string to print 32 | 48 65 6c 6c 6f 20 77 6f 72 6c 64 21 0a 00 33 | # H e l l o ␣ w o r l d ! newline null 34 | 35 | # . . vim:nowrap:textwidth=0 36 | -------------------------------------------------------------------------------- /linux/apps/factorial.mu: -------------------------------------------------------------------------------- 1 | # compute the factorial of 5, and return the result in the exit code 2 | # 3 | # To run: 4 | # $ ./translate apps/factorial.mu 5 | # $ ./a.elf 6 | # $ echo $? 7 | # 120 8 | # 9 | # You can also run the automated test suite: 10 | # $ ./a.elf test 11 | # Expected output: 12 | # ........ 13 | # Every '.' indicates a passing test. Failing tests get a 'F'. 14 | # There's only one test in this file, but you'll also see tests running from 15 | # Mu's standard library. 16 | # 17 | # Compare factorial4.subx 18 | 19 | fn factorial n: int -> _/eax: int { 20 | compare n, 1 21 | # if (n <= 1) return 1 22 | { 23 | break-if-> 24 | return 1 25 | } 26 | # n > 1; return n * factorial(n-1) 27 | var tmp/ecx: int <- copy n 28 | tmp <- decrement 29 | var result/eax: int <- factorial tmp 30 | result <- multiply n 31 | return result 32 | } 33 | 34 | fn test-factorial { 35 | var result/eax: int <- factorial 5 36 | check-ints-equal result, 0x78, "F - test-factorial" 37 | } 38 | 39 | fn main args-on-stack: (addr array addr array byte) -> _/ebx: int { 40 | var args/eax: (addr array addr array byte) <- copy args-on-stack 41 | # len = length(args) 42 | var len/ecx: int <- length args 43 | # if (len <= 1) return factorial(5) 44 | compare len, 1 45 | { 46 | break-if-> 47 | var exit-status/eax: int <- factorial 5 48 | return exit-status 49 | } 50 | # if (args[1] == "test") run-tests() 51 | var tmp2/ecx: (addr addr array byte) <- index args, 1 52 | var tmp3/eax: boolean <- string-equal? *tmp2, "test" 53 | compare tmp3, 0 54 | { 55 | break-if-= 56 | run-tests 57 | # TODO: get at Num-test-failures somehow 58 | } 59 | return 0 60 | } 61 | -------------------------------------------------------------------------------- /linux/apps/hello.mu: -------------------------------------------------------------------------------- 1 | # Meaningless conventional example. 2 | # 3 | # To run: 4 | # $ ./translate apps/hello.mu 5 | # $ ./a.elf 6 | 7 | fn main -> _/ebx: int { 8 | print-string 0/screen, "Hello world!\n" 9 | return 0 10 | } 11 | -------------------------------------------------------------------------------- /linux/apps/parse-int.mu: -------------------------------------------------------------------------------- 1 | # parse a decimal int at the commandline 2 | # 3 | # To run: 4 | # $ ./translate apps/parse-int.mu 5 | # $ ./a.elf 123 6 | # $ echo $? 7 | # 123 8 | 9 | fn main _args: (addr array addr array byte) -> _/ebx: int { 10 | # if no args, print a message and exit 11 | var args/esi: (addr array addr array byte) <- copy _args 12 | var n/ecx: int <- length args 13 | compare n, 1 14 | { 15 | break-if-> 16 | print-string 0/screen, "usage: parse-int \n" 17 | return 1 18 | } 19 | # otherwise parse the first arg as an integer 20 | var in/ecx: (addr addr array byte) <- index args, 1 21 | var out/eax: int <- parse-int *in 22 | return out 23 | } 24 | 25 | fn parse-int _in: (addr array byte) -> _/eax: int { 26 | var in/esi: (addr array byte) <- copy _in 27 | var len/edx: int <- length in 28 | var i/ecx: int <- copy 0 29 | var result/edi: int <- copy 0 30 | { 31 | compare i, len 32 | break-if->= 33 | # result *= 10 34 | var ten/eax: int <- copy 0xa 35 | result <- multiply ten 36 | # c = in[i] 37 | var tmp/ebx: (addr byte) <- index in, i 38 | var c/eax: byte <- copy-byte *tmp 39 | # 40 | var g/eax: code-point-utf8 <- copy c 41 | var digit/eax: int <- to-decimal-digit g 42 | result <- add digit 43 | i <- increment 44 | loop 45 | } 46 | return result 47 | } 48 | -------------------------------------------------------------------------------- /linux/apps/print-file.mu: -------------------------------------------------------------------------------- 1 | # accept a filename on the commandline, read it and print it out to screen 2 | # only ascii right now, just like the rest of Mu 3 | # 4 | # To run: 5 | # $ ./translate apps/print-file.mu 6 | # $ echo abc > x 7 | # $ ./a.elf x 8 | # abc 9 | 10 | fn main _args: (addr array addr array byte) -> _/ebx: int { 11 | var args/eax: (addr array addr array byte) <- copy _args 12 | var n/ecx: int <- length args 13 | compare n, 1 14 | { 15 | break-if-> 16 | print-string 0/screen, "usage: cat \n" 17 | return 0 18 | } 19 | { 20 | break-if-<= 21 | var filename/edx: (addr addr array byte) <- index args 1 22 | var in: (handle buffered-file) 23 | { 24 | var addr-in/eax: (addr handle buffered-file) <- address in 25 | open *filename, 0/read-only, addr-in 26 | } 27 | var _in-addr/eax: (addr buffered-file) <- lookup in 28 | var in-addr/ecx: (addr buffered-file) <- copy _in-addr 29 | { 30 | var c/eax: byte <- read-byte-buffered in-addr 31 | compare c, 0xffffffff/end-of-file 32 | break-if-= 33 | var g/eax: code-point-utf8 <- copy c 34 | print-code-point-utf8 0/screen, g 35 | loop 36 | } 37 | } 38 | return 0 39 | } 40 | -------------------------------------------------------------------------------- /linux/apps/raytracing/1.cc: -------------------------------------------------------------------------------- 1 | // https://raytracing.github.io/books/RayTracingInOneWeekend.html 2 | #include 3 | 4 | int main() { 5 | 6 | // Image 7 | 8 | const int image_width = 256; 9 | const int image_height = 256; 10 | 11 | // Render 12 | 13 | std::cout << "P3\n" << image_width << ' ' << image_height << "\n255\n"; 14 | 15 | for (int j = image_height-1; j >= 0; --j) 16 | for (int i = 0; i < image_width; ++i) 17 | std::cout << i << ' ' << j << " 64\n"; 18 | } 19 | -------------------------------------------------------------------------------- /linux/apps/raytracing/1.cc.0: -------------------------------------------------------------------------------- 1 | // https://raytracing.github.io/books/RayTracingInOneWeekend.html 2 | #include 3 | 4 | int main() { 5 | 6 | // Image 7 | 8 | const int image_width = 256; 9 | const int image_height = 256; 10 | 11 | // Render 12 | 13 | std::cout << "P3\n" << image_width << ' ' << image_height << "\n255\n"; 14 | 15 | for (int j = image_height-1; j >= 0; --j) { 16 | for (int i = 0; i < image_width; ++i) { 17 | auto r = double(i) / (image_width-1); 18 | auto g = double(j) / (image_height-1); 19 | auto b = 0.25; 20 | 21 | int ir = static_cast(255.999 * r); 22 | int ig = static_cast(255.999 * g); 23 | int ib = static_cast(255.999 * b); 24 | 25 | std::cout << ir << ' ' << ig << ' ' << ib << '\n'; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /linux/apps/raytracing/1.mu: -------------------------------------------------------------------------------- 1 | # Listing 1 of https://raytracing.github.io/books/RayTracingInOneWeekend.html 2 | # (simplified) 3 | # 4 | # To run (on Linux): 5 | # $ git clone https://github.com/akkartik/mu 6 | # $ cd mu/linux 7 | # $ ./translate apps/raytracing/1.mu 8 | # $ ./a.elf > 1.ppm 9 | 10 | fn main -> _/ebx: int { 11 | print-string 0, "P3\n256 256\n255\n" 12 | var j/ecx: int <- copy 0xff 13 | { 14 | compare j, 0 15 | break-if-< 16 | var i/eax: int <- copy 0 17 | { 18 | compare i, 0xff 19 | break-if-> 20 | print-int32-decimal 0, i 21 | print-string 0, " " 22 | print-int32-decimal 0, j 23 | print-string 0, " 64\n" 24 | i <- increment 25 | loop 26 | } 27 | j <- decrement 28 | loop 29 | } 30 | return 0 31 | } 32 | -------------------------------------------------------------------------------- /linux/apps/raytracing/README.md: -------------------------------------------------------------------------------- 1 | Exercises from https://raytracing.github.io/books/RayTracingInOneWeekend.html 2 | -------------------------------------------------------------------------------- /linux/apps/raytracing/color.h: -------------------------------------------------------------------------------- 1 | #ifndef COLOR_H 2 | #define COLOR_H 3 | 4 | #include "vec3.h" 5 | 6 | #include 7 | 8 | void write_color(std::ostream &out, color pixel_color) { 9 | // Write the translated [0,255] value of each color component. 10 | out << static_cast(255.999 * pixel_color.x()) << ' ' 11 | << static_cast(255.999 * pixel_color.y()) << ' ' 12 | << static_cast(255.999 * pixel_color.z()) << '\n'; 13 | } 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /linux/apps/raytracing/color.mu: -------------------------------------------------------------------------------- 1 | type rgb { 2 | # components normalized to within [0.0, 1.0] 3 | r: float 4 | g: float 5 | b: float 6 | } 7 | 8 | # print translating to [0, 256) 9 | fn print-rgb screen: (addr screen), _c: (addr rgb) { 10 | var c/esi: (addr rgb) <- copy _c 11 | var xn: float 12 | var xn-addr/ecx: (addr float) <- address xn 13 | fill-in-rational xn-addr, 0x3e7ff, 0x3e8 # 255999 / 1000 14 | # print 255.999 * c->r 15 | var result/xmm0: float <- copy xn 16 | var src-addr/eax: (addr float) <- get c, r 17 | result <- multiply *src-addr 18 | var result-int/edx: int <- truncate result 19 | print-int32-decimal screen, result-int 20 | print-string screen, " " 21 | # print 255.999 * c->g 22 | src-addr <- get c, g 23 | result <- copy xn 24 | result <- multiply *src-addr 25 | result-int <- truncate result 26 | print-int32-decimal screen, result-int 27 | print-string screen, " " 28 | # print 255.999 * c->b 29 | src-addr <- get c, b 30 | result <- copy xn 31 | result <- multiply *src-addr 32 | result-int <- truncate result 33 | print-int32-decimal screen, result-int 34 | print-string screen, "\n" 35 | } 36 | -------------------------------------------------------------------------------- /linux/apps/raytracing/ray.h: -------------------------------------------------------------------------------- 1 | #ifndef RAY_H 2 | #define RAY_H 3 | 4 | #include "vec3.h" 5 | 6 | class ray { 7 | public: 8 | ray() {} 9 | ray(const point3& origin, const vec3& direction) 10 | : orig(origin), dir(direction) 11 | {} 12 | 13 | point3 origin() const { return orig; } 14 | vec3 direction() const { return dir; } 15 | 16 | point3 at(float t) const { 17 | return orig + t*dir; 18 | } 19 | 20 | public: 21 | point3 orig; 22 | vec3 dir; 23 | }; 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /linux/apps/raytracing/ray.mu: -------------------------------------------------------------------------------- 1 | type ray { 2 | orig: vec3 # point 3 | dir: vec3 4 | } 5 | 6 | # A little different from the constructor at https://raytracing.github.io/books/RayTracingInOneWeekend.html 7 | # We immediately normalize the direction vector so we don't have to keep doing 8 | # so. 9 | fn initialize-ray _self: (addr ray), o: (addr vec3), d: (addr vec3) { 10 | var self/esi: (addr ray) <- copy _self 11 | var dest/eax: (addr vec3) <- get self, orig 12 | copy-object o, dest 13 | dest <- get self, dir 14 | vec3-unit d, dest 15 | } 16 | 17 | fn ray-at _self: (addr ray), t: float, out: (addr vec3) { 18 | var self/esi: (addr ray) <- copy _self 19 | var src/eax: (addr vec3) <- get self, dir 20 | copy-object src, out 21 | vec3-scale-up out, t 22 | src <- get self, orig 23 | vec3-add-to out, src 24 | } 25 | -------------------------------------------------------------------------------- /linux/apps/raytracing/vimrc.vim: -------------------------------------------------------------------------------- 1 | " when opening files in this directory, load vimrc from cwd (top-level) 2 | source vimrc.vim 3 | -------------------------------------------------------------------------------- /linux/apps/texture.mu: -------------------------------------------------------------------------------- 1 | # Playing with emitting cool textures. 2 | # 3 | # To run (on Linux): 4 | # $ git clone https://github.com/akkartik/mu 5 | # $ cd mu 6 | # $ ./translate apps/texture.mu 7 | # $ ./a.elf > a.ppm 8 | 9 | fn main -> _/ebx: int { 10 | #? var width/esi: int <- copy 0x190 # 400 11 | #? var height/edi: int <- copy 0xe1 # 225; aspect ratio 16:9 12 | var width/esi: int <- copy 0xff 13 | var height/edi: int <- copy 0xff 14 | print-string 0/screen, "P3\n" 15 | print-int32-decimal 0/screen, width 16 | print-string 0/screen, " " 17 | print-int32-decimal 0/screen, height 18 | print-string 0/screen, "\n" 19 | print-string 0/screen, "255\n" # color depth 20 | var row/ecx: int <- copy 0 21 | { 22 | compare row, height 23 | break-if->= 24 | var col/edx: int <- copy 0 25 | { 26 | compare col, width 27 | break-if->= 28 | # r 29 | var tmp/eax: int <- copy col 30 | tmp <- multiply row 31 | tmp <- and 0x7f 32 | tmp <- add 0x80 33 | tmp <- copy 0xff 34 | print-int32-decimal 0/screen, tmp 35 | print-string 0/screen, " " 36 | # g 37 | tmp <- copy row 38 | tmp <- multiply col 39 | tmp <- and 0x7f 40 | tmp <- add 0x80 41 | #? tmp <- copy 0xcf 42 | print-int32-decimal 0/screen, tmp 43 | print-string 0/screen, " " 44 | # b 45 | tmp <- copy row 46 | tmp <- multiply col 47 | tmp <- and 0x7f 48 | tmp <- add 0x80 49 | print-int32-decimal 0/screen, tmp 50 | print-string 0/screen, "\n" 51 | col <- increment 52 | loop 53 | } 54 | row <- increment 55 | loop 56 | } 57 | return 0 58 | } 59 | -------------------------------------------------------------------------------- /linux/apps/tui.mu: -------------------------------------------------------------------------------- 1 | # Test some primitives for text-mode. 2 | # 3 | # To run: 4 | # $ ./translate apps/tui.mu 5 | # $ ./a.elf 6 | 7 | fn main -> _/ebx: int { 8 | var nrows/eax: int <- copy 0 9 | var ncols/ecx: int <- copy 0 10 | nrows, ncols <- screen-size 0 11 | enable-screen-grid-mode 12 | move-cursor 0/screen, 5/row, 0x22/col 13 | start-color 0/screen, 1/fg, 0x7a/bg 14 | start-blinking 0/screen 15 | print-string 0/screen, "Hello world!" 16 | reset-formatting 0/screen 17 | move-cursor 0/screen, 6/row, 0x22/col 18 | print-string 0/screen, "tty dimensions: " 19 | print-int32-hex 0/screen, nrows 20 | print-string 0/screen, " rows, " 21 | print-int32-hex 0/screen, ncols 22 | print-string 0/screen, " rows\n" 23 | 24 | print-string 0/screen, "press a key to see its code: " 25 | enable-keyboard-immediate-mode 26 | var x/eax: code-point-utf8 <- read-key-from-real-keyboard 27 | enable-keyboard-type-mode 28 | enable-screen-type-mode 29 | print-string 0/screen, "You pressed " 30 | var x-int/eax: int <- copy x 31 | print-int32-hex 0/screen, x-int 32 | print-string 0/screen, "\n" 33 | return 0 34 | } 35 | -------------------------------------------------------------------------------- /linux/assort: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/linux/assort -------------------------------------------------------------------------------- /linux/bootstrap/021div.cc: -------------------------------------------------------------------------------- 1 | //: helper for division operations: sign-extend EAX into EDX 2 | 3 | :(before "End Initialize Op Names") 4 | put_new(Name, "99", "sign-extend EAX into EDX (cdq)"); 5 | 6 | :(code) 7 | void test_cdq() { 8 | Reg[EAX].i = 10; 9 | run( 10 | "== code 0x1\n" 11 | "99\n" 12 | ); 13 | CHECK_TRACE_CONTENTS( 14 | "run: sign-extend EAX into EDX\n" 15 | "run: EDX is now 0x00000000\n" 16 | ); 17 | } 18 | 19 | :(before "End Single-Byte Opcodes") 20 | case 0x99: { // sign-extend EAX into EDX 21 | trace(Callstack_depth+1, "run") << "sign-extend EAX into EDX" << end(); 22 | Reg[EDX].i = (Reg[EAX].i < 0) ? -1 : 0; 23 | trace(Callstack_depth+1, "run") << "EDX is now 0x" << HEXWORD << Reg[EDX].u << end(); 24 | break; 25 | } 26 | 27 | :(code) 28 | void test_cdq_negative() { 29 | Reg[EAX].i = -10; 30 | run( 31 | "== code 0x1\n" 32 | "99\n" 33 | ); 34 | CHECK_TRACE_CONTENTS( 35 | "run: sign-extend EAX into EDX\n" 36 | "run: EDX is now 0xffffffff\n" 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /linux/bootstrap/031transforms.cc: -------------------------------------------------------------------------------- 1 | :(before "End Types") 2 | typedef void (*transform_fn)(program&); 3 | :(before "End Globals") 4 | vector Transform; 5 | 6 | :(before "End transform(program& p)") 7 | for (int t = 0; t < SIZE(Transform); ++t) 8 | (*Transform.at(t))(p); 9 | 10 | :(before "End One-time Setup") 11 | // Begin Transforms 12 | // End Transforms 13 | -------------------------------------------------------------------------------- /linux/bootstrap/README.md: -------------------------------------------------------------------------------- 1 | This tool is 2 things: 2 | 3 | a) An emulator for SubX, the subset of the 32-bit x86 instruction set used by 4 | Mu. 5 | 6 | b) A second translator for SubX programs that emits identical binaries to the 7 | self-hosting versions in the parent directory. Having two diverse compilers 8 | (one in a familiar language, one with minimal syscall surface area) that emit 9 | identical binaries should help gain confidence in Mu. 10 | 11 | ## Running 12 | 13 | `bootstrap` currently has the following sub-commands: 14 | 15 | - `bootstrap help`: some helpful documentation to have at your fingertips. 16 | 17 | - `bootstrap test`: runs all automated tests. 18 | 19 | - `bootstrap translate -o `: translates `.subx` 20 | files into an executable ELF binary. 21 | 22 | - `bootstrap run `: simulates running the ELF binaries emitted 23 | by `bootstrap translate`. Useful for testing and debugging. 24 | 25 | Remember, not all 32-bit Linux binaries are guaranteed to run. I'm not 26 | building general infrastructure here for all of the x86 instruction set. 27 | SubX is about programming with a small, regular subset of 32-bit x86. 28 | 29 | ## Hacking 30 | 31 | This directory is the only C++ code in the project, and has [an unconventional 32 | organization](http://akkartik.name/post/four-repos). 33 | -------------------------------------------------------------------------------- /linux/bootstrap/bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Run SubX VM, first compiling if necessary. 3 | set -e 4 | 5 | $(dirname $0)/build 6 | 7 | $(dirname $0)/bootstrap_bin "$@" 8 | -------------------------------------------------------------------------------- /linux/bootstrap/build_and_test_until: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Run tests for just a subset of layers. 3 | # 4 | # Usage: 5 | # build_and_test_until [file prefix] [test name] 6 | # Provide the second arg to run just a single test. 7 | set -e 8 | 9 | # clean previous builds if they were building until a different layer 10 | touch .until 11 | PREV_UNTIL=`cat .until` 12 | if [ "$PREV_UNTIL" != $1 ] 13 | then 14 | ./clean 15 | echo $1 > .until 16 | fi 17 | 18 | ./build --until $1 && ./bootstrap_bin test $2 19 | -------------------------------------------------------------------------------- /linux/bootstrap/clean: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | set -v 5 | rm -rf bootstrap.cc bootstrap_bin* *_list 6 | rm -rf .until 7 | rm -rf tools/enumerate tools/tangle tools/*_list tools/*.dSYM 8 | -------------------------------------------------------------------------------- /linux/bootstrap/test_layers: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Repeatedly stop building until successive layers, and run all tests built. 3 | # 4 | # Assumes .subx files all come after .cc files. 5 | 6 | set -e 7 | 8 | cd `dirname $0` 9 | # add C++ files one at a time 10 | for f in [0-9]*cc 11 | do 12 | echo "=== bootstrap $f" 13 | ./build_and_test_until $f 14 | done 15 | 16 | # build everything one last time 17 | ./clean 18 | ./build # build optimized since we'll be running it repeatedly below 19 | -------------------------------------------------------------------------------- /linux/bootstrap/tools/enumerate.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using std::vector; 6 | #include 7 | using std::string; 8 | #include 9 | using std::cout; 10 | 11 | int main(int argc, const char* argv[]) { 12 | assert(argc == 3); 13 | assert(string(argv[1]) == "--until"); 14 | string last_file(argv[2]); 15 | 16 | dirent** files; 17 | int num_files = scandir(".", &files, NULL, alphasort); 18 | for (int i = 0; i < num_files; ++i) { 19 | string curr_file = files[i]->d_name; 20 | if (!isdigit(curr_file.at(0))) continue; 21 | if (!last_file.empty() && curr_file > last_file) break; 22 | cout << curr_file << '\n'; 23 | } 24 | // don't bother freeing files 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /linux/braces: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/linux/braces -------------------------------------------------------------------------------- /linux/branches.mu: -------------------------------------------------------------------------------- 1 | fn foo { 2 | $foo: { 3 | break-if-= 4 | break-if-= $foo 5 | break-if-!= 6 | break-if-!= $foo 7 | break-if-<= 8 | break-if-<= $foo 9 | break-if->= 10 | break-if->= $foo 11 | break-if-< 12 | break-if-< $foo 13 | break-if-> 14 | break-if-> $foo 15 | break-if-carry 16 | break-if-carry $foo 17 | break-if-overflow 18 | break-if-overflow $foo 19 | loop-if-= 20 | loop-if-= $foo 21 | loop-if-!= 22 | loop-if-!= $foo 23 | loop-if-<= 24 | loop-if-<= $foo 25 | loop-if->= 26 | loop-if->= $foo 27 | loop-if-< 28 | loop-if-< $foo 29 | loop-if-> 30 | loop-if-> $foo 31 | loop-if-carry 32 | loop-if-carry $foo 33 | loop-if-not-carry 34 | loop-if-not-carry $foo 35 | loop-if-overflow 36 | loop-if-overflow $foo 37 | loop-if-not-overflow 38 | loop-if-not-overflow $foo 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /linux/browse/README.md: -------------------------------------------------------------------------------- 1 | Render a subset of Markdown. 2 | 3 | To run: 4 | 5 | ``` 6 | $ cd linux 7 | $ ./translate browse.mu 8 | $ ./a.elf __text_file__ 9 | ``` 10 | 11 | Press 'q' to quit. All other keys scroll down. 12 | 13 | ## Format restrictions 14 | 15 | This is a fairly tiny subset of GitHub-Flavored Markdown. Things supported so 16 | far: 17 | 18 | * Newlines are mostly ignored. Double newlines are rendered (paragraphs). 19 | Newlines followed by indentation are rendered. 20 | * Paragraphs starting with runs of `#` represent headings. 21 | * Within a line, characters between `*`s or `_`s represent bolded text. No 22 | italics. 23 | -------------------------------------------------------------------------------- /linux/browse/vimrc.vim: -------------------------------------------------------------------------------- 1 | " when opening files in this directory, load vimrc from cwd (top-level) 2 | source vimrc.vim 3 | -------------------------------------------------------------------------------- /linux/calls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/linux/calls -------------------------------------------------------------------------------- /linux/dquotes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/linux/dquotes -------------------------------------------------------------------------------- /linux/help: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Some minimal online help. 3 | 4 | linux/bootstrap/bootstrap help $* 5 | -------------------------------------------------------------------------------- /linux/hex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/linux/hex -------------------------------------------------------------------------------- /linux/labels_baremetal: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/linux/labels_baremetal -------------------------------------------------------------------------------- /linux/mu: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/linux/mu -------------------------------------------------------------------------------- /linux/mu-init-test.subx: -------------------------------------------------------------------------------- 1 | # Just a test stub for mu-init.subx 2 | # 3 | # Try it out like this: 4 | # $ ./translate_subx init.linux [0-9]*.subx mu-init.subx mu-init-test.subx 5 | # $ ./a.elf # should run all tests 6 | 7 | main: # args: (addr array (addr array byte)) -> result/ebx: int 8 | # . prologue 9 | 55/push-ebp 10 | 89/<- %ebp 4/r32/esp 11 | # . save registers 12 | 50/push-eax 13 | 56/push-esi 14 | # esi = args 15 | 8b/-> *(ebp+8) 6/r32/esi 16 | { 17 | # if (argc <= 1) break 18 | 81 7/subop/compare *esi 4/imm32 19 | 7e/jump-if-<= break/disp8 20 | # if (argv[1] != "test") break 21 | (string-equal? *(esi+8) "test") # => eax 22 | 3d/compare-eax-and 0/imm32 23 | 74/jump-if-= break/disp8 24 | # 25 | (run-tests) 26 | # return *Num-test-failures 27 | 8b/-> *Num-test-failures 3/r32/ebx 28 | eb/jump $main:end/disp8 29 | } 30 | $main:end: 31 | # . restore registers 32 | 5e/pop-to-esi 33 | 58/pop-to-eax 34 | # . epilogue 35 | 89/<- %esp 5/r32/ebp 36 | 5d/pop-to-ebp 37 | c3/return 38 | -------------------------------------------------------------------------------- /linux/pack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/linux/pack -------------------------------------------------------------------------------- /linux/sigils: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/linux/sigils -------------------------------------------------------------------------------- /linux/subx-params.subx: -------------------------------------------------------------------------------- 1 | # Various knobs for translating SubX programs using SubX. 2 | 3 | == data 4 | 5 | # largest segment that can be translated 6 | Segment-size: 7 | 0x300000/imm32/3MB 8 | 9 | # maximum size of input textual stream (spanning all segments) 10 | Input-size: 11 | 0x600000/imm32/6MB 12 | 13 | # number of labels we can translate to addresses 14 | Max-labels: 15 | 0x60000/imm32/16K-labels/384KB 16 | 17 | # capacity of trace-stream 18 | Trace-size: 19 | 0x200000/imm32/2MB 20 | -------------------------------------------------------------------------------- /linux/survey_baremetal: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/linux/survey_baremetal -------------------------------------------------------------------------------- /linux/survey_elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/linux/survey_elf -------------------------------------------------------------------------------- /linux/tests: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/linux/tests -------------------------------------------------------------------------------- /linux/tile/README.md: -------------------------------------------------------------------------------- 1 | A programming environment that tries to [“stop drawing dead fish”](http://worrydream.com/#!/StopDrawingDeadFish). 2 | 3 | screenshot 4 | 5 | To run: 6 | 7 | ``` 8 | $ cd linux 9 | $ ./translate tile/*.mu 10 | $ ./a.elf screen 11 | ``` 12 | 13 | To run tests: 14 | 15 | ``` 16 | $ ./a.elf test 17 | ``` 18 | 19 | To run a conventional REPL (for debugging): 20 | 21 | ``` 22 | $ ./a.elf type 23 | ``` 24 | 25 | ## hacking 26 | 27 | This is just a prototype. There are no tests. 28 | 29 | To add a new primitive you'll need to hard-code it into the `evaluate` 30 | function (linux/tile/rpn.mu). 31 | 32 | There's also a second place you'll want to teach about predefined primitives: 33 | `bound-function?` (linux/tile/environment.mu) 34 | -------------------------------------------------------------------------------- /linux/tile/vimrc.vim: -------------------------------------------------------------------------------- 1 | " when opening files in this directory, load vimrc from cwd (top-level) 2 | source vimrc.vim 3 | -------------------------------------------------------------------------------- /linux/translate: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Translate a given Mu program into an ELF binary on Linux. 3 | 4 | set -e 5 | 6 | cat $* [0-9]*.mu |./mu > a.subx 7 | 8 | ./translate_subx [0-9]*.subx mu-init.subx a.subx 9 | -------------------------------------------------------------------------------- /linux/translate_debug: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Translate given Mu files with debug information on Linux. 3 | # 4 | # (You _could_ do something similar on other platforms using emulation. But I 5 | # often find that to be too slow.) 6 | 7 | set -e 8 | 9 | cat $* [0-9]*.mu |./mu > a.subx 10 | 11 | ./translate_subx_debug [0-9]*.subx mu-init.subx a.subx 12 | -------------------------------------------------------------------------------- /linux/translate_emulated: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Translate a Mu program using emulated mode on Linux or BSD or Mac. 3 | 4 | set -e 5 | set -v 6 | 7 | cat $* [0-9]*.mu |bootstrap/bootstrap run ./mu > a.subx 8 | 9 | ./translate_subx_emulated [0-9]*.subx mu-init.subx a.subx 10 | -------------------------------------------------------------------------------- /linux/translate_subx: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Translate given SubX files by running the self-hosted translator natively on 3 | # Linux. 4 | 5 | set -e 6 | 7 | cat $* |./braces > a.braces 8 | 9 | cat a.braces |./calls > a.calls 10 | 11 | cat a.calls |./sigils > a.sigils 12 | 13 | cat a.sigils |./tests > a.tests 14 | 15 | cat a.tests |./assort > a.assort 16 | 17 | cat a.assort |./dquotes > a.dquotes 18 | 19 | # A little hack. We want translate_subx to always emit identical binaries to 20 | # the C++ translator. The C++ translator assorts segments before it processes 21 | # string literals, so we follow the same order above. 22 | # 23 | # However, dquotes currently emits a separate data segment for string literals. 24 | # So we need to run assort a second time to clean up after it. 25 | # 26 | # Potential solutions: 27 | # a) modify C++ translator to process string literals before assorting. 28 | # b) clean up dquotes to assume assorted segments, and append to the 29 | # existing data segment. 30 | cat a.dquotes |./assort > a.assort2 31 | 32 | cat a.assort2 |./pack > a.pack 33 | 34 | cat a.pack |./survey_elf > a.survey 35 | 36 | cat a.survey |./hex > a.elf 37 | 38 | chmod +x a.elf 39 | -------------------------------------------------------------------------------- /linux/translate_subx_debug: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Translate given SubX files with debug information on Linux. 3 | # 4 | # Mu provides 3 canonical ways to translate unsafe SubX programs: 5 | # 0. The C++ translator 'bootstrap translate' can generate traces for 6 | # debugging on Linux or BSD or Mac, but doesn't support any syntax sugar. 7 | # 1. The self-hosted translator can be run natively on Linux using 8 | # 'translate_subx'. It is fast and supports all syntax sugar, but you get no 9 | # trace for debugging. 10 | # 2. The self-hosted translator can be run emulated on Linux or BSD or Mac 11 | # using 'translate_subx_emulated'. It supports all syntax sugar. However, it 12 | # can be slow if you generate traces. 13 | # 14 | # This script fills in the gap above by stitching together aspects from 15 | # multiple approaches. It translates syntax sugar natively, but emulates lower 16 | # levels using the C++ translator. The result is complete and relatively fast 17 | # even when generating traces. 18 | # 19 | # The cost: it needs Linux. There is no script to generate traces while 20 | # running emulated on BSD or Mac. That's often impractically slow. 21 | 22 | set -e 23 | 24 | cat $* |./braces > a.braces 25 | cat a.braces |./calls > a.calls 26 | cat a.calls |./sigils > a.sigils 27 | 28 | bootstrap/bootstrap --debug translate a.sigils -o a.elf 29 | 30 | chmod +x a.elf 31 | -------------------------------------------------------------------------------- /linux/translate_subx_emulated: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Translate given SubX files by running the self-hosted translator in emulated 3 | # mode on Linux or BSD or Mac. 4 | # 5 | # We _could_ generate traces here, but that's often extremely slow. 6 | 7 | set -e 8 | set -v 9 | 10 | cat $* |bootstrap/bootstrap run ./braces > a.braces 11 | cat a.braces |bootstrap/bootstrap run ./calls > a.calls 12 | cat a.calls |bootstrap/bootstrap run ./sigils > a.sigils 13 | cat a.sigils |bootstrap/bootstrap run ./tests > a.tests 14 | cat a.tests |bootstrap/bootstrap run ./assort > a.assort 15 | cat a.assort |bootstrap/bootstrap run ./dquotes > a.dquotes 16 | cat a.dquotes |bootstrap/bootstrap run ./assort > a.assort2 17 | cat a.assort2 |bootstrap/bootstrap run ./pack > a.pack 18 | cat a.pack |bootstrap/bootstrap run ./survey_elf > a.survey 19 | cat a.survey |bootstrap/bootstrap run ./hex > a.elf 20 | 21 | chmod +x a.elf 22 | -------------------------------------------------------------------------------- /misc_checks: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Hackily check for certain kinds of errors. 3 | # 4 | # We still rely exclusively on linux/bootstrap/bootstrap for some static 5 | # checks on bare SubX code that aren't implemented yet in the self-hosted 6 | # translator phases. 7 | # 8 | # However, boot.subx uses instructions that bootstrap doesn't recognize. So we 9 | # won't check it. 10 | 11 | set -e 12 | 13 | cat $* [0-9]*.mu |linux/mu > a.subx 14 | 15 | cat misc_checks.subx mu-init.subx [0-9]*.subx a.subx |linux/braces > a.braces 16 | cat a.braces |linux/calls > a.calls 17 | cat a.calls |linux/sigils > a.sigils 18 | 19 | CXXFLAGS=-g linux/bootstrap/bootstrap --debug translate a.sigils -o a.elf 20 | # Translation will never succeed, 21 | # but if we get to "missing reference to global" errors, they're expected and 22 | # we've gotten to the end of what bootstrap can check for us. 23 | -------------------------------------------------------------------------------- /misc_checks.subx: -------------------------------------------------------------------------------- 1 | == code 0x00000000 2 | 3 | == data 0x80000000 4 | -------------------------------------------------------------------------------- /modrm.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/modrm.pdf -------------------------------------------------------------------------------- /mu-init.subx: -------------------------------------------------------------------------------- 1 | # Initialize the minimal runtime for Mu programs. 2 | # 3 | # See translate for how this file is used. 4 | # 5 | # Mu programs start at a function called 'main' with this signature: 6 | # fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) 7 | # 8 | # All tests must pass first (the "power-on unit test"). 9 | 10 | == code 11 | 12 | Entry: 13 | # initialize stack 14 | bd/copy-to-ebp 0/imm32 15 | # 16 | #? (main 0 0 Primary-bus-secondary-drive) 17 | # always first run tests 18 | (run-tests) 19 | (num-test-failures) # => eax 20 | # call main if tests all passed 21 | { 22 | 3d/compare-eax-and 0/imm32 23 | 75/jump-if-!= break/disp8 24 | c7 0/subop/copy *Running-tests? 0/imm32/false 25 | (clear-real-screen) 26 | c7 0/subop/copy *Real-screen-cursor-x 0/imm32 27 | c7 0/subop/copy *Real-screen-cursor-y 0/imm32 28 | (main 0 0 Primary-bus-secondary-drive) 29 | } 30 | 31 | # hang indefinitely 32 | { 33 | eb/jump loop/disp8 34 | } 35 | -------------------------------------------------------------------------------- /shell/main.mu: -------------------------------------------------------------------------------- 1 | # Experimental Mu shell 2 | # Currently based on Lisp. 3 | 4 | fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) { 5 | var env-storage: environment 6 | var env/esi: (addr environment) <- address env-storage 7 | initialize-environment env, 0x20/fake-screen-width, 8/fake-screen-height 8 | load-state env, data-disk 9 | { 10 | render-environment screen, env 11 | # no way to quit right now; just reboot 12 | { 13 | var key/eax: byte <- read-key keyboard 14 | compare key, 0 15 | loop-if-= 16 | var key/eax: code-point-utf8 <- copy key 17 | edit-environment env, key, data-disk 18 | } 19 | loop 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /shell/read.mu: -------------------------------------------------------------------------------- 1 | fn read-cell in: (addr gap-buffer), out: (addr handle cell), trace: (addr trace) { 2 | # eagerly tokenize everything so that the phases are easier to see in the trace 3 | var tokens-storage: (stream token 0x10000) 4 | var tokens/edx: (addr stream token) <- address tokens-storage 5 | tokenize in, tokens, trace 6 | var error?/eax: boolean <- has-errors? trace 7 | compare error?, 0/false 8 | { 9 | break-if-= 10 | return 11 | } 12 | # insert more parens based on indentation 13 | var parenthesized-tokens-storage: (stream token 0x10000) 14 | var parenthesized-tokens/ecx: (addr stream token) <- address parenthesized-tokens-storage 15 | parenthesize tokens, parenthesized-tokens, trace 16 | var error?/eax: boolean <- has-errors? trace 17 | compare error?, 0/false 18 | { 19 | break-if-= 20 | return 21 | } 22 | parse-input parenthesized-tokens, out, trace 23 | transform-infix out, trace 24 | } 25 | -------------------------------------------------------------------------------- /shell/vimrc.vim: -------------------------------------------------------------------------------- 1 | " when opening files in this directory, load vimrc from cwd (top-level) 2 | source vimrc.vim 3 | -------------------------------------------------------------------------------- /sib.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/sib.pdf -------------------------------------------------------------------------------- /tools/README.md: -------------------------------------------------------------------------------- 1 | Run all these from the top-level `mu/` directory. 2 | 3 | ### Some tools for Mu's build process 4 | 5 | These are built automatically. 6 | 7 | * `enumerate`: list numeric files in current directory, optionally `--until` 8 | some prefix. 9 | 10 | 11 | ### Miscellaneous odds and ends 12 | 13 | These are built lazily. 14 | 15 | * `browse_trace`: debugging tool. See `browse_trace.readme.md` for details. 16 | 17 | * `linkify`: inserts hyperlinks from variables to definitions in Mu's html 18 | sources. Hacky; just see the number of tests. Invoked by `update_html`. 19 | 20 | * `treeshake_all`: rebuild SubX binaries without tests and unused functions. 21 | Hacky; just helps estimate the code needed to perform various tasks. 22 | ``` 23 | tools/treeshake_all 24 | ``` 25 | 26 | ### Notes to self: constraints on the tools/ directory 27 | * Don't overwhelm the initial view of the project with lots of crap in the 28 | root directory. 29 | * Directories go up top in the github view, so too many sub-directories are 30 | also overwhelming. 31 | * Don't increase increase build time too much; everything in `tools/` shouldn't 32 | be automatically built. 33 | * stuff needed all the time is built from root directory. 34 | * `tools/` contains many independent things; don't make it hard to see 35 | boundaries. Ideally just one source file per tool. If not, give related 36 | files similar name prefixes. 37 | -------------------------------------------------------------------------------- /tools/browse_trace: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | test "$CXX" || export CXX=c++ 5 | test "$CC" || export CC=cc 6 | test "$CFLAGS" || export CFLAGS="-g -O2" 7 | export CFLAGS="$CFLAGS -Wall -Wextra -ftrapv -fno-strict-aliasing" 8 | 9 | # build if doesn't exist 10 | [ ! -f `dirname $0`/browse_trace_bin ] && ( 11 | cd `dirname $0` 12 | [ ! -f termbox/libtermbox.a ] && ( 13 | cd termbox 14 | $CC $CFLAGS -c utf8.c 15 | $CC $CFLAGS -c termbox.c 16 | ar rcs libtermbox.a *.o 17 | ) 18 | $CXX $CFLAGS browse_trace.cc termbox/libtermbox.a -o browse_trace_bin 19 | ) 20 | 21 | `dirname $0`/browse_trace_bin $* 22 | -------------------------------------------------------------------------------- /tools/create_container: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Start a Linux container containing the mu/ directory. 3 | # Useful on non-Linux platforms. 4 | # Run it from the top-level mu/ directory. 5 | 6 | docker run -it --name mu -v `pwd`:/mu abyssos/abyss:dev 7 | 8 | # On the first startup, you'll need to run the following commands: 9 | # apk add git nano libcxx-dev 10 | # cd /mu 11 | 12 | # Leaving this container will stop it. 13 | # Restart it with: 14 | # docker start mu 15 | # 16 | # Now you can connect to it anytime with: 17 | # docker exec -it mu sh 18 | # cd /mu 19 | # 20 | # Quite slow, though. Docker has to run a VM on other platforms. 21 | -------------------------------------------------------------------------------- /tools/expand_string_handle: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Expand syntax sugar for SubX string literals and show the corresponding handle definition. 3 | # 4 | # The handle has a fake alloc-id; we're never going to try to reclaim global 5 | # variables, we just sometimes need handles in them to satisfy type constraints. 6 | 7 | INPUT=$(cat) 8 | echo " 0x11/imm32/alloc-id:fake:payload" 9 | echo " # \"$INPUT\"" 10 | 11 | # print length in bytes 12 | printf " 0x%x/imm32/size\n" $(echo -n $INPUT |wc -c) 13 | 14 | # print ascii codes for each character in hex 15 | echo -n " " 16 | for c in $(echo "$INPUT" |sed -e 's/./& /g') 17 | do 18 | echo -n " 0x$(printf '%x' "'$c")/$c" 19 | done 20 | echo 21 | -------------------------------------------------------------------------------- /tools/image-data: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Create a disk image containing some (text) data. 3 | 4 | if [ $# -eq 0 ] 5 | then 6 | echo "Fill disk of some capacity (in ~1 MB units) from stdin" 7 | echo "usage: image-data capacity" 8 | exit 1 9 | fi 10 | 11 | dd if=/dev/zero of=data.img count=$(($1*2016)) # 32 tracks * 63 sectors/track of 512-byte sectors 12 | dd of=data.img conv=notrunc 13 | -------------------------------------------------------------------------------- /tools/mu-init-minify.subx: -------------------------------------------------------------------------------- 1 | # Initialize the minimal runtime for Mu programs without any tests. 2 | # 3 | # See translate_min for how this file is used. 4 | # 5 | # Mu programs start at a function called 'main' with this signature: 6 | # fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) 7 | 8 | == code 9 | 10 | Entry: 11 | # initialize stack 12 | bd/copy-to-ebp 0/imm32 13 | # 14 | (main 0 0 Primary-bus-secondary-drive) 15 | 16 | # hang indefinitely 17 | { 18 | eb/jump loop/disp8 19 | } 20 | -------------------------------------------------------------------------------- /tools/regs.mu: -------------------------------------------------------------------------------- 1 | type bar { 2 | x: int 3 | y: boolean 4 | } 5 | 6 | fn foo { 7 | var a/eax: int <- copy 0 8 | var a/ecx: int <- copy 0 9 | var a/edx: int <- copy 0 10 | var a/ebx: int <- copy 0 11 | var a/esi: int <- copy 0 12 | var a/edi: int <- copy 0 13 | } 14 | -------------------------------------------------------------------------------- /tools/termbox/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2010-2013 nsf 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /tools/termbox/Readme: -------------------------------------------------------------------------------- 1 | Fork of https://github.com/nsf/termbox as of 2015-06-05 2 | git hash 252bef01264a2aeef22ebe5bae0b5893a58947f3 3 | -------------------------------------------------------------------------------- /tools/test_treeshake_translate: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Translate SubX programs using a minified translator. 3 | # Based on ntranslate. 4 | 5 | set -e 6 | 7 | ./build 8 | 9 | cat $* |apps/braces.treeshake.bin > a.braces 10 | 11 | cat a.braces |apps/calls.treeshake.bin > a.calls 12 | 13 | cat a.calls |apps/sigils.treeshake.bin > a.sigils 14 | 15 | cat a.sigils |apps/tests.treeshake.bin > a.tests 16 | 17 | cat a.tests |apps/assort.treeshake.bin > a.assort 18 | 19 | cat a.assort |apps/dquotes.treeshake.bin > a.dquotes 20 | 21 | cat a.dquotes |apps/assort.treeshake.bin > a.assort2 22 | 23 | cat a.assort2 |apps/pack.treeshake.bin > a.pack 24 | 25 | cat a.pack |apps/survey.treeshake.bin > a.survey 26 | 27 | cat a.survey |apps/hex.treeshake.bin > a.elf 28 | 29 | chmod +x a.elf 30 | -------------------------------------------------------------------------------- /tools/update_signatures: -------------------------------------------------------------------------------- 1 | grep -h '^sig \|^fn ' [0-9]*.mu |grep -v 'fn test-' |sed 's/^fn /sig /' |sed 's/ {$//' > signatures.mu 2 | -------------------------------------------------------------------------------- /tools/vga_palette.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/tools/vga_palette.png -------------------------------------------------------------------------------- /tutorial/add2.mu: -------------------------------------------------------------------------------- 1 | fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) { 2 | var result/eax: int <- do-add 3, 4 3 | draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, result, 3/fg=cyan 0/bg 4 | } 5 | 6 | fn do-add a: int, b: int -> _/eax: int { 7 | var result/eax: int <- copy a 8 | result <- add b 9 | return result 10 | } 11 | 12 | fn test-do-add { 13 | var observed/eax: int <- do-add 0, 0 14 | check-ints-equal observed, 0, "F - 0+0" 15 | observed <- do-add 3, 0 16 | check-ints-equal observed, 3, "F - 3+0" 17 | observed <- do-add 3, 2 18 | check-ints-equal observed, 5, "F - 3+2" 19 | } 20 | -------------------------------------------------------------------------------- /tutorial/c2f.mu: -------------------------------------------------------------------------------- 1 | fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) { 2 | var result/eax: int <- do-add 3, 4 3 | draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, result, 3/fg=cyan 0/bg 4 | } 5 | 6 | fn do-add a: int, b: int -> _/eax: int { 7 | var result/eax: int <- copy a 8 | result <- add b 9 | return result 10 | } 11 | 12 | fn test-do-add { 13 | var observed/eax: int <- do-add 0, 0 14 | check-ints-equal observed, 0, "F - 0+0" 15 | observed <- do-add 3, 0 16 | check-ints-equal observed, 3, "F - 3+0" 17 | observed <- do-add 3, 2 18 | check-ints-equal observed, 5, "F - 3+2" 19 | } 20 | -------------------------------------------------------------------------------- /tutorial/converter.html: -------------------------------------------------------------------------------- 1 | 11 | 12 |
13 | = 14 |
15 | 16 | -------------------------------------------------------------------------------- /tutorial/counter.mu: -------------------------------------------------------------------------------- 1 | # Counter app 2 | # https://eugenkiss.github.io/7guis/tasks/#counter 3 | # 4 | # To build: 5 | # $ ./translate counter.mu 6 | # To run: 7 | # $ qemu-system-i386 code.img 8 | 9 | fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) { 10 | var count/ecx: int <- copy 0 11 | # widget title 12 | set-cursor-position screen, 0x1f/x 0xe/y 13 | draw-text-rightward-from-cursor-over-full-screen screen, " Counter ", 0xf/fg 0x16/bg 14 | # event loop 15 | { 16 | # draw current state to screen 17 | clear-rect screen, 0x1f/xmin 0xf/ymin, 0x40/xmax 0x14/ymax, 0xc5/color 18 | set-cursor-position screen, 0x20/x 0x10/y 19 | draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, count, 7/fg 0xc5/bg 20 | # render a menu bar 21 | set-cursor-position screen, 0x24/x 0x12/y 22 | draw-text-rightward-from-cursor-over-full-screen screen, " enter ", 0/fg 0x5c/bg=highlight 23 | draw-text-rightward-from-cursor-over-full-screen screen, " increment ", 7/fg 0xc5/bg 24 | # process a single keystroke 25 | { 26 | var key/eax: byte <- read-key keyboard 27 | compare key, 0 28 | loop-if-= 29 | compare key, 0xa/newline 30 | break-if-!= 31 | count <- increment 32 | } 33 | loop 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tutorial/counter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/tutorial/counter.png -------------------------------------------------------------------------------- /tutorial/task1.mu: -------------------------------------------------------------------------------- 1 | # Draw a single line of ASCII text. 2 | # 3 | # To build a disk image: 4 | # ./translate tutorial/task1.mu # emits code.img 5 | # To run: 6 | # qemu-system-i386 code.img 7 | 8 | fn main screen: (addr screen) { 9 | var dummy/eax: int <- draw-text-rightward screen, "hello from baremetal Mu!", 0x10/x, 0x400/xmax, 0x10/y, 0xa/fg, 0/bg 10 | } 11 | -------------------------------------------------------------------------------- /tutorial/task1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/tutorial/task1.png -------------------------------------------------------------------------------- /tutorial/task11-solution.mu: -------------------------------------------------------------------------------- 1 | fn difference a: int, b: int -> _/eax: int { 2 | var result/eax: int <- copy a 3 | result <- subtract b 4 | compare result, 0 5 | { 6 | break-if->= 7 | result <- negate 8 | } 9 | return result 10 | } 11 | 12 | fn test-difference { 13 | var result/eax: int <- difference 5, 3 14 | check-ints-equal result, 2, "F - difference works" 15 | result <- difference 3, 5 16 | check-ints-equal result, 2, "F - difference is always positive" 17 | result <- difference 6, 6 18 | check-ints-equal result, 0, "F - difference can be 0" 19 | } 20 | 21 | fn main screen: (addr screen) { 22 | } 23 | -------------------------------------------------------------------------------- /tutorial/task11.mu: -------------------------------------------------------------------------------- 1 | fn difference a: int, b: int -> _/eax: int { 2 | } 3 | 4 | fn test-difference { 5 | var result/eax: int <- difference 5, 3 6 | check-ints-equal result, 2, "F - difference works" 7 | result <- difference 3, 5 8 | check-ints-equal result, 2, "F - difference is always positive" 9 | result <- difference 6, 6 10 | check-ints-equal result, 0, "F - difference can be 0" 11 | } 12 | 13 | fn main screen: (addr screen) { 14 | } 15 | -------------------------------------------------------------------------------- /tutorial/task12-solution.mu: -------------------------------------------------------------------------------- 1 | # Here's one way to draw a rectangle from the top-left corner of screen. 2 | # Lots of other solutions are possible. 3 | fn main screen: (addr screen) { 4 | draw-line screen, 1/x1 1/y1, 0x300/x2 1/y2, 3/color=green 5 | draw-line screen, 1/x1 0x200/y1, 0x300/x2 0x200/y2, 3/color=green 6 | draw-line screen, 1/x1 1/y1, 1/x2 0x200/y2, 3/color=green 7 | draw-line screen, 0x300/x1 1/y1, 0x300/x2 0x200/y2, 3/color=green 8 | } 9 | -------------------------------------------------------------------------------- /tutorial/task12.mu: -------------------------------------------------------------------------------- 1 | fn main screen: (addr screen) { 2 | draw-line screen, 0x100/x1 0x100/y1, 0x300/x2 0x100/y2, 3/color=green 3 | draw-line screen, 0x100/x1 0x200/y1, 0x300/x2 0x200/y2, 3/color=green 4 | draw-line screen, 0x100/x1 0x100/y1, 0x100/x2 0x200/y2, 3/color=green 5 | draw-line screen, 0x300/x1 0x100/y1, 0x300/x2 0x200/y2, 3/color=green 6 | } 7 | -------------------------------------------------------------------------------- /tutorial/task15.mu: -------------------------------------------------------------------------------- 1 | fn main screen: (addr screen) { 2 | var y/eax: int <- copy 0 3 | { 4 | compare y, 0x300/screen-height=768 5 | break-if->= 6 | var x/edx: int <- copy 0 7 | { 8 | compare x, 0x400/screen-width=1024 9 | break-if->= 10 | var color/ecx: int <- copy x 11 | pixel screen x, y, color 12 | x <- increment 13 | loop 14 | } 15 | y <- increment 16 | loop 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tutorial/task2.mu: -------------------------------------------------------------------------------- 1 | fn test-1 { 2 | check-ints-equal 1, 2, "F - test-1" 3 | } 4 | 5 | fn main { 6 | # do nothing 7 | } 8 | -------------------------------------------------------------------------------- /tutorial/task2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/tutorial/task2.png -------------------------------------------------------------------------------- /tutorial/task3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/tutorial/task3.png -------------------------------------------------------------------------------- /tutorial/task4-initial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akkartik/mu/50d6c374de23adebc7a3a2742c6c20dfd87010fb/tutorial/task4-initial.png -------------------------------------------------------------------------------- /tutorial/task4-solution.mu: -------------------------------------------------------------------------------- 1 | fn the-answer -> _/eax: int { 2 | var result/eax: int <- copy 0 3 | # insert your statement below { 4 | result <- copy 0x2a 5 | # } 6 | return result 7 | } 8 | 9 | fn test-the-answer { 10 | var result/eax: int <- the-answer 11 | check-ints-equal result, 0x2a, "F - the-answer should return 42, but didn't." 12 | } 13 | 14 | fn main { 15 | } 16 | -------------------------------------------------------------------------------- /tutorial/task4.mu: -------------------------------------------------------------------------------- 1 | fn the-answer -> _/eax: int { 2 | var result/eax: int <- copy 0 3 | # insert your statement below { 4 | 5 | # } 6 | return result 7 | } 8 | 9 | fn test-the-answer { 10 | var result/eax: int <- the-answer 11 | check-ints-equal result, 0x2a, "F - the-answer should return 42, but didn't" 12 | } 13 | 14 | fn main { 15 | } 16 | -------------------------------------------------------------------------------- /tutorial/task5-solution.mu: -------------------------------------------------------------------------------- 1 | fn foo -> _/eax: int { 2 | var x: int 3 | # statement 1: store 3 in x 4 | copy-to x, 3 5 | # statement 2: define a new variable 'y' in register eax and store 4 in it 6 | var y/eax: int <- copy 4 7 | # statement 3: add y to x, storing the result in x 8 | add-to x, y 9 | return x 10 | } 11 | 12 | fn test-foo { 13 | var result/eax: int <- foo 14 | check-ints-equal result, 7, "F - foo should return 7, but didn't" 15 | } 16 | 17 | fn main { 18 | } 19 | -------------------------------------------------------------------------------- /tutorial/task5.mu: -------------------------------------------------------------------------------- 1 | fn foo -> _/eax: int { 2 | var x: int 3 | # statement 1: store 3 in x 4 | # statement 2: define a new variable 'y' in register eax and store 4 in it 5 | # statement 3: add y to x, storing the result in x 6 | return x 7 | } 8 | 9 | fn test-foo { 10 | var result/eax: int <- foo 11 | check-ints-equal result, 7, "F - foo should return 7, but didn't" 12 | } 13 | 14 | fn main { 15 | } 16 | -------------------------------------------------------------------------------- /tutorial/task6-error-runbook.txt: -------------------------------------------------------------------------------- 1 | If I encounter an error that looks like this: 2 | fn main: stmt copy: output 'm' not in a register 3 | 4 | then I should do the following: 5 | - find the function mentioned (here `main`); 6 | - look for a statement that contains the mentioned output (here `m`) before 7 | the `<-`; and 8 | - replace the statement with a version of the same instruction that writes 9 | to an inout in memory. (Here, replace `m <- copy` with `copy-to m`.) 10 | 11 | === 12 | 13 | If I encounter an error that looks like this: 14 | label table: get-slice: key not found: copy-to 15 | 16 | then I should do the following: 17 | - look for a statement with the same instruction (here `copy-to`) whose 18 | first inout is not a variable stored in memory; and 19 | - email Kartik (http://akkartik.name/contact) to ask why this message is so 20 | much less helpful then the previous one. 21 | -------------------------------------------------------------------------------- /tutorial/task6.mu: -------------------------------------------------------------------------------- 1 | fn main { 2 | var m: int 3 | var r/edx: int <- copy 0 4 | # insert a single statement below 5 | 6 | } 7 | -------------------------------------------------------------------------------- /tutorial/task7-solution.mu: -------------------------------------------------------------------------------- 1 | fn foo -> _/eax: int { 2 | var x/edx: int <- copy 0 3 | # statement 1: store 3 in x 4 | x <- copy 3 5 | # statement 2: define a new variable 'y' in register eax and store 4 in it 6 | var y/eax: int <- copy 4 7 | # statement 3: add y to x, storing the result in x 8 | x <- add y 9 | return x 10 | } 11 | 12 | fn test-foo { 13 | var result/eax: int <- foo 14 | check-ints-equal result, 7, "F - foo should return 7, but didn't" 15 | } 16 | 17 | fn main { 18 | } 19 | -------------------------------------------------------------------------------- /tutorial/task7.mu: -------------------------------------------------------------------------------- 1 | fn foo -> _/eax: int { 2 | var x/edx: int <- copy 0 3 | # statement 1: store 3 in x 4 | copy-to x, 3 5 | # statement 2: define a new variable 'y' in register eax and store 4 in it 6 | var y/eax: int <- copy 4 7 | # statement 3: add y to x, storing the result in x 8 | add-to x, y 9 | return x 10 | } 11 | 12 | fn test-foo { 13 | var result/eax: int <- foo 14 | check-ints-equal result, 7, "F - foo should return 7, but didn't" 15 | } 16 | 17 | fn main { 18 | } 19 | -------------------------------------------------------------------------------- /tutorial/task8a.mu: -------------------------------------------------------------------------------- 1 | fn f a: int { 2 | } 3 | 4 | fn main { 5 | f 0 6 | var r/eax: int <- copy 3 7 | f r 8 | var m: int 9 | f m 10 | } 11 | -------------------------------------------------------------------------------- /tutorial/task8b.mu: -------------------------------------------------------------------------------- 1 | fn f -> _/eax: int { 2 | var result/ecx: int <- copy 0 3 | return result 4 | } 5 | 6 | fn main { 7 | var x/eax: int <- f 8 | } 9 | -------------------------------------------------------------------------------- /tutorial/task8c.mu: -------------------------------------------------------------------------------- 1 | fn f -> _/eax: int { 2 | return 3 3 | } 4 | 5 | fn main { 6 | var x/ecx: int <- f 7 | } 8 | -------------------------------------------------------------------------------- /tutorial/task9-solution.mu: -------------------------------------------------------------------------------- 1 | fn f -> _/eax: int { 2 | return 2 3 | } 4 | 5 | fn g -> _/eax: int { 6 | return 3 7 | } 8 | 9 | fn add-f-and-g -> _/eax: int { 10 | var _x/eax: int <- f 11 | var x/ecx: int <- copy _x 12 | var y/eax: int <- g 13 | x <- add y 14 | return x 15 | } 16 | 17 | fn test-add-f-and-g { 18 | var result/eax: int <- add-f-and-g 19 | check-ints-equal result, 5, "F - test-add-f-and-g\n" 20 | } 21 | 22 | fn main { 23 | } 24 | -------------------------------------------------------------------------------- /tutorial/task9.mu: -------------------------------------------------------------------------------- 1 | fn f -> _/eax: int { 2 | return 2 3 | } 4 | 5 | fn g -> _/eax: int { 6 | return 3 7 | } 8 | 9 | fn add-f-and-g -> _/eax: int { 10 | var x/eax: int <- f 11 | var y/eax: int <- g 12 | x <- add y 13 | return x 14 | } 15 | 16 | fn test-add-f-and-g { 17 | var result/eax: int <- add-f-and-g 18 | check-ints-equal result, 5, "F - test-add-f-and-g\n" 19 | } 20 | 21 | fn main { 22 | } 23 | -------------------------------------------------------------------------------- /tutorial/vimrc.vim: -------------------------------------------------------------------------------- 1 | " when opening files in this directory, load vimrc from cwd (top-level) 2 | source vimrc.vim 3 | --------------------------------------------------------------------------------