├── .config ├── cspell.jsonc └── custom-dictionary.txt ├── .editorconfig ├── .github └── workflows │ ├── gh_pages.yml │ ├── pr_benchmarks.yml │ └── rust.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Justfile ├── LICENSE ├── README.md ├── bridge_adapters ├── Cargo.toml └── src │ ├── lib.rs │ ├── lisp_adapters.rs │ └── lisp_adapters │ ├── collections.rs │ ├── numbers.rs │ ├── primitives.rs │ └── text.rs ├── bridge_macros ├── Cargo.toml ├── README.md └── src │ └── lib.rs ├── bridge_types ├── Cargo.toml └── src │ └── lib.rs ├── builtins ├── Cargo.toml ├── src │ ├── bridge_macro_tests.rs │ ├── collections.rs │ ├── conversions.rs │ ├── fs_meta.rs │ ├── fs_temp.rs │ ├── io.rs │ ├── lib.rs │ ├── math.rs │ ├── print.rs │ ├── rand.rs │ └── string.rs ├── tests │ ├── MACRO_HELP.md │ ├── convert_primitives_pass.rs │ ├── convert_string_pass.rs │ ├── optional_args_pass.rs │ ├── simple_proc_macro_pass.rs │ └── var_args_pass.rs └── trybuild │ └── tests │ ├── borrow_checker_two_mut_fail.rs │ ├── borrow_checker_two_mut_fail.stderr │ ├── enforce_return_fail.rs │ ├── enforce_return_fail.stderr │ ├── too_many_generics_fail.rs │ └── too_many_generics_fail.stderr ├── compile_state ├── Cargo.toml └── src │ ├── lib.rs │ └── state.rs ├── compiler ├── Cargo.toml ├── build.rs ├── src │ ├── backquote.rs │ ├── compile.rs │ ├── compile │ │ ├── compile_call.rs │ │ ├── compile_cond.rs │ │ ├── compile_fn.rs │ │ ├── compile_let.rs │ │ ├── compile_math.rs │ │ ├── compile_seq.rs │ │ ├── compile_store.rs │ │ ├── compile_tests.rs │ │ ├── destructure.rs │ │ └── util.rs │ ├── config.rs │ ├── lib.rs │ ├── load_eval.rs │ ├── pass1.rs │ ├── reader.rs │ └── test_utils.rs └── test_utils │ ├── Cargo.toml │ └── src │ └── lib.rs ├── doc ├── .gitignore ├── README.md ├── book.toml ├── list-slosh-doc-exemptions.sh ├── list-slosh-forms.sh ├── mdbook-slosh-eval │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ └── main.rs ├── mk-site.slosh ├── search-hack-patch.sh └── src │ ├── .gitignore │ ├── SUMMARY.md │ ├── containers.md │ ├── debugger.md │ ├── end_to_end.md │ ├── equality.md │ ├── errors.md │ ├── faq.md │ ├── generated-sections │ └── .gitignore │ ├── iterators.md │ ├── let.md │ ├── namespaces.md │ ├── overview.md │ ├── section-docs │ ├── conditional.md │ └── hashmap.md │ ├── shell-redirects.md │ ├── shell-vs-lisp.md │ ├── sl-sh-forms.md │ ├── syntax-and-macros.md │ └── welcome.md ├── init.slosh ├── legacy ├── .github │ └── workflows │ │ └── rust.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── LICENSE ├── README.md ├── benches │ ├── start.lisp │ ├── start_benchmark.rs │ └── start_script.rs ├── build.rs ├── contrib │ ├── gpwclark │ │ └── slshrc │ ├── old-seq.lisp │ ├── reader_macro_vec.lisp │ └── sls │ │ ├── class-tst.lisp │ │ └── seq2.lisp ├── docs │ ├── .gitignore │ ├── .gitlab-ci.yml │ ├── 404.html │ ├── 404.md │ ├── Dockerfile │ ├── Gemfile │ ├── README.docker │ ├── _config.yml │ ├── _data │ │ ├── alerts.yml │ │ ├── samplelist.yml │ │ ├── sidebars │ │ │ ├── home_sidebar.yml │ │ │ ├── other.yml │ │ │ ├── product1_sidebar.yml │ │ │ └── product2_sidebar.yml │ │ ├── strings.yml │ │ ├── tags.yml │ │ ├── terms.yml │ │ └── topnav.yml │ ├── _drafts │ │ └── evalable-2020-05-14-file-io-forms.md │ ├── _evalable_pages │ │ └── mydoc │ │ │ ├── mydoc_documentation.md │ │ │ ├── mydoc_namespaces.md │ │ │ ├── mydoc_reader.md │ │ │ └── mydoc_shellreader.md │ ├── _includes │ │ ├── archive.html │ │ ├── callout.html │ │ ├── custom │ │ │ ├── getting_started_series.html │ │ │ ├── getting_started_series_next.html │ │ │ ├── series_acme.html │ │ │ ├── series_acme_next.html │ │ │ ├── usermap.html │ │ │ └── usermapcomplex.html │ │ ├── feedback.html │ │ ├── footer.html │ │ ├── google_analytics.html │ │ ├── head.html │ │ ├── head_print.html │ │ ├── image.html │ │ ├── important.html │ │ ├── initialize_shuffle.html │ │ ├── inline_image.html │ │ ├── links.html │ │ ├── note.html │ │ ├── sidebar.html │ │ ├── taglogic.html │ │ ├── tip.html │ │ ├── toc.html │ │ ├── topnav.html │ │ └── warning.html │ ├── _layouts │ │ ├── default.html │ │ ├── default_print.html │ │ ├── none.html │ │ ├── page.html │ │ ├── page_print.html │ │ └── post.html │ ├── _posts │ │ └── 2021-03-01-sl-sh-gets-new-docs-site.md │ ├── _tooltips │ │ ├── baseball.html │ │ ├── basketball.html │ │ ├── football.html │ │ └── soccer.html │ ├── _user_config.yml │ ├── closure.lisp │ ├── createtag │ ├── css │ │ ├── bootstrap.min.css │ │ ├── boxshadowproperties.css │ │ ├── customstyles.css │ │ ├── font-awesome.min.css │ │ ├── fonts │ │ │ ├── FontAwesome.otf │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.svg │ │ │ ├── fontawesome-webfont.ttf │ │ │ ├── fontawesome-webfont.woff │ │ │ └── fontawesome-webfont.woff2 │ │ ├── modern-business.css │ │ ├── printstyles.css │ │ ├── syntax.css │ │ ├── theme-blue.css │ │ └── theme-green.css │ ├── docify.lisp │ ├── docstrings-to-md.lisp │ ├── docstruct.lisp │ ├── feed.xml │ ├── fonts │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ ├── images │ │ ├── androidsdkmanagericon.png │ │ ├── authorizegithubscreen2.png │ │ ├── authorizeongithub.png │ │ ├── company_logo.png │ │ ├── company_logo_big.png │ │ ├── favicon.ico │ │ ├── helpapi-01.png │ │ ├── helpapi.svg │ │ ├── illustratoroptions.png │ │ ├── itermexample.png │ │ ├── jekyll.png │ │ ├── killalljekyll.png │ │ ├── liningup.png │ │ ├── sl-sh-ascii-logo.png │ │ ├── sl-sh-icon.png │ │ └── workflowarrow.png │ ├── index.md │ ├── jekyll.sh │ ├── js │ │ ├── customscripts.js │ │ ├── jekyll-search.js │ │ ├── jquery.ba-throttle-debounce.min.js │ │ ├── jquery.navgoco.min.js │ │ ├── jquery.shuffle.min.js │ │ └── toc.js │ ├── licenses │ │ ├── LICENSE │ │ └── LICENSE-BSD-NAVGOCO.txt │ ├── mk-docs.lisp │ ├── mk-post.lisp │ ├── mk-sidebar.lisp │ ├── pages │ │ ├── mydoc │ │ │ ├── mydoc_blockers_1_0.md │ │ │ ├── mydoc_endfix.md │ │ │ ├── mydoc_faq.md │ │ │ ├── mydoc_files.md │ │ │ ├── mydoc_introduction.md │ │ │ ├── mydoc_pipes.md │ │ │ ├── mydoc_pull_requests.md │ │ │ ├── mydoc_scripting.md │ │ │ ├── mydoc_slshrc.md │ │ │ └── mydoc_support.md │ │ └── news │ │ │ ├── news.html │ │ │ └── news_archive.html │ ├── pdf-all.sh │ ├── pdf-mydoc.sh │ ├── pdf │ │ ├── mydoc.pdf │ │ ├── product1.pdf │ │ └── product2.pdf │ ├── pdfconfigs │ │ ├── config_mydoc_pdf.yml │ │ ├── titlepage.html │ │ └── tocpage.html │ ├── search.json │ ├── serve-local-docs.lisp │ ├── sitemap.xml │ ├── tooltips.html │ ├── tooltips.json │ ├── update.sh │ └── var │ │ └── build.sh ├── lisp │ ├── collection.lisp │ ├── core.lisp │ ├── getopts.lisp │ ├── iterator.lisp │ ├── lib.lisp │ ├── seq.lisp │ ├── shell-read.lisp │ ├── shell.lisp │ ├── slsh-std.lisp │ ├── slshrc │ ├── struct.lisp │ └── test.lisp ├── list-globals.lisp ├── run-tests.lisp ├── slshrc.example ├── src │ ├── analyze.rs │ ├── backquote.rs │ ├── builtins.rs │ ├── builtins_bind.rs │ ├── builtins_edit.rs │ ├── builtins_file.rs │ ├── builtins_hashmap.rs │ ├── builtins_io.rs │ ├── builtins_math.rs │ ├── builtins_namespace.rs │ ├── builtins_pair.rs │ ├── builtins_rand.rs │ ├── builtins_regex.rs │ ├── builtins_stats.rs │ ├── builtins_str.rs │ ├── builtins_system.rs │ ├── builtins_types.rs │ ├── builtins_util.rs │ ├── builtins_values.rs │ ├── builtins_vector.rs │ ├── completions.rs │ ├── config.rs │ ├── environment.rs │ ├── eval.rs │ ├── interner.rs │ ├── lib.rs │ ├── main.rs │ ├── pretty_print.rs │ ├── process.rs │ ├── reader.rs │ ├── shell.rs │ ├── signals.rs │ ├── symbols.rs │ ├── types.rs │ ├── umask_util.rs │ └── unix.rs └── tests │ ├── backquote.lisp │ ├── getopts.lisp │ ├── scopes.lisp │ ├── seq.lisp │ ├── shell-read-test.lisp │ └── string_interpolation.lisp ├── lisp ├── core.slosh ├── iterator.slosh ├── sh-color.slosh └── test.slosh ├── scripts └── check-clippy-version.sh ├── shell ├── Cargo.toml ├── build.rs └── src │ ├── bin │ └── shell.rs │ ├── builtins.rs │ ├── command_data.rs │ ├── config.rs │ ├── glob.rs │ ├── jobs.rs │ ├── lib.rs │ ├── parse.rs │ ├── platform.rs │ ├── platform │ ├── unix.rs │ └── unix │ │ └── umask.rs │ ├── run.rs │ └── signals.rs ├── slosh ├── Cargo.toml ├── bench_utils │ ├── Cargo.toml │ ├── benches │ │ ├── bench.slosh │ │ ├── float-bench.slosh │ │ └── vec-search-bench.slosh │ └── src │ │ └── lib.rs ├── benches │ ├── criterion.rs │ └── iai.rs ├── build.rs ├── src │ ├── config.rs │ └── main.rs └── tests │ ├── divide-by-zero_fail.slosh │ ├── equality.slosh │ ├── hello.slosh │ └── lisp-scripts.rs ├── slosh_lib ├── Cargo.toml └── src │ ├── completions.rs │ ├── debug.rs │ ├── lib.rs │ ├── liner_rules.rs │ └── shell_builtins.rs ├── slosh_test ├── Cargo.toml ├── README.md ├── build.rs ├── run-tests.slosh ├── src │ └── main.rs └── tests │ └── slosh-tests.rs ├── slosh_test_lib ├── Cargo.toml ├── README.md └── src │ ├── docs.rs │ ├── docs │ └── legacy.rs │ └── lib.rs ├── vim └── slosh.vim └── vm ├── Cargo.toml ├── LICENSE ├── README.md └── src ├── bin ├── disassemble.rs └── testpol.rs ├── chunk.rs ├── chunk └── disassemble.rs ├── error.rs ├── float ├── float_32.rs ├── float_56.rs └── mod.rs ├── fxhasher.rs ├── heap.rs ├── heap ├── bits.rs ├── handle.rs ├── io.rs ├── storage.rs └── vm_hashmap.rs ├── interner.rs ├── lib.rs ├── opcodes.rs ├── value.rs ├── vm.rs └── vm ├── call.rs ├── call_collection.rs ├── cons.rs ├── exec_loop.rs ├── macros.rs └── storage.rs /.config/cspell.jsonc: -------------------------------------------------------------------------------- 1 | // https://github.com/streetsidesoftware/cspell 2 | // This is the configuration file for cspell, a spellchecker for code. 3 | // There is a vscode extension https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker 4 | // you can run cspell from the command line with `npx cspell .` 5 | // you can check which dictionary has a word with `npx cspell trace yourWord` 6 | { 7 | "version": "0.2", 8 | "ignorePaths": ["target", "legacy", "**/*.lock"], 9 | "useGitignore": false, 10 | "enableFiletypes": ["*", "Vimscript"], 11 | "dictionaryDefinitions": [ 12 | { 13 | "name": "custom-dictionary", 14 | "path": "./custom-dictionary.txt", 15 | "addWords": true 16 | } 17 | ], 18 | "dictionaries": ["custom-dictionary", "rust", "makefile", "softwareTerms"], 19 | "words": [], 20 | "flagWords": [], 21 | "ignoreWords": ["Emmmmm", "atwo", "btwo", "ctwo", "dtwo", "hexy"], 22 | "import": [] 23 | } 24 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | # copied from the rust project https://github.com/rust-lang/rust 6 | 7 | root = true 8 | 9 | [*] 10 | end_of_line = lf 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | indent_style = space 15 | indent_size = 4 16 | 17 | [*.rs] 18 | max_line_length = 100 19 | 20 | [*.md] 21 | # double whitespace at end of line 22 | # denotes a line break in Markdown 23 | trim_trailing_whitespace = false 24 | 25 | [*.yml] 26 | indent_size = 2 27 | 28 | [Makefile] 29 | indent_style = tab 30 | -------------------------------------------------------------------------------- /.github/workflows/gh_pages.yml: -------------------------------------------------------------------------------- 1 | name: GitHub Pages 2 | on: 3 | push: 4 | branches: 5 | - main 6 | - 'user-docs/**' 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | permissions: 12 | contents: write # To push a branch 13 | pull-requests: write # To create a PR from that branch 14 | steps: 15 | - uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 18 | - name: Deploy GitHub Pages 19 | run: | 20 | cargo build --bin slosh 21 | export PATH="$PATH:$PWD/target/debug/" 22 | cargo install --force mdbook 23 | # change to documentation directory 24 | cd doc 25 | # mk-site.sh writes the static site to the book directory 26 | ./mk-site.slosh build 27 | git worktree add gh-pages 28 | git config user.name "Deploy from CI" 29 | git config user.email "" 30 | cd gh-pages 31 | # Delete the ref to avoid keeping history. 32 | git update-ref -d refs/heads/gh-pages 33 | rm -rf * 34 | mv ../book/* . 35 | git add . 36 | git commit -m "Deploy $GITHUB_SHA to gh-pages" 37 | git push --force --set-upstream origin gh-pages 38 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | env: 8 | RUSTFLAGS: -Dwarnings 9 | CARGO_TERM_COLOR: always 10 | RUST_BACKTRACE: 1 11 | 12 | jobs: 13 | build-linux: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Format 20 | run: | 21 | cargo version 22 | rustc --version 23 | cargo fmt --verbose -- --check 24 | - name: Clippy 25 | run: | 26 | cargo version 27 | rustc --version 28 | cargo clippy --verbose -- -D warnings 29 | - name: Build 30 | run: | 31 | cargo version 32 | rustc --version 33 | cargo build --workspace --verbose 34 | - name: Run rust tests 35 | run: cargo test --verbose 36 | - name: Run lisp integration tests 37 | run: cargo test --workspace 38 | 39 | 40 | build-macos: 41 | 42 | runs-on: macos-latest 43 | 44 | steps: 45 | - uses: actions/checkout@v2 46 | - name: Build 47 | run: | 48 | cargo version 49 | rustc --version 50 | cargo build --workspace --verbose 51 | - name: Run rust tests 52 | run: cargo test --verbose 53 | - name: Run lisp integration tests 54 | run: cargo test --workspace 55 | 56 | # if this gets too slow consider 57 | # https://github.com/Swatinem/rust-cache 58 | # along with 59 | # - name: Compile rust tests 60 | # run: cargo test --no-run 61 | # in linux AND macos tests 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | #Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | .idea 13 | **.iml 14 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | resolver = "2" 4 | 5 | members = [ 6 | "slosh", 7 | "slosh_lib", 8 | "compiler", 9 | "vm", 10 | "builtins", 11 | "compile_state", 12 | "shell", 13 | "bridge_macros", 14 | "bridge_types", 15 | "bridge_adapters", 16 | "slosh_test", 17 | "slosh_test_lib", 18 | ] 19 | 20 | exclude = ["legacy"] 21 | 22 | [profile.release] 23 | lto = true 24 | codegen-units = 1 25 | #opt-level = 'z' 26 | #debug = true 27 | panic = "abort" 28 | 29 | [profile.bench] 30 | debug = true 31 | 32 | [workspace.package] 33 | version = "0.11.0" 34 | 35 | [workspace.dependencies] 36 | bridge_types = { path = "bridge_types" } 37 | compile_state = { path = "compile_state" } 38 | sl-compiler = { path = "compiler" } 39 | compiler_test_utils = { path = "compiler/test_utils" } 40 | slvm = { path = "vm" } 41 | shell = { path = "shell" } 42 | regex = "1" 43 | lazy_static = "1" 44 | mdbook = "0.4.37" 45 | 46 | unicode-width = "0.2" 47 | unicode_reader = "1" 48 | unicode-segmentation = "1.12" 49 | glob = "0.3" 50 | cfg-if = "1.0" 51 | nix = "0.29" 52 | chrono = "0.4.38" 53 | 54 | static_assertions = "1.1.0" 55 | rand = "0.8.5" 56 | walkdir = "2.5.0" 57 | same-file = "1.0.6" 58 | trybuild = "1.0.101" 59 | tempfile = "3" 60 | temp-env = "0.3.6" 61 | syn = "1.0.109" 62 | quote = "1.0.37" 63 | env_logger = "0.11.5" 64 | criterion = "0.5" 65 | iai-callgrind = "0.14" 66 | -------------------------------------------------------------------------------- /Justfile: -------------------------------------------------------------------------------- 1 | # Justfile 2 | # 'just' is a command runner, like a modern 'make' 3 | # Install instructions at https://github.com/casey/just?tab=readme-ov-file#installation 4 | # Usage is as simple as 'just test' to run all the tests we care about. 5 | 6 | # The default recipe that runs if you type 'just' with no arguments 7 | # List available commands 8 | default: 9 | @just --list --unsorted 10 | 11 | # Run all the necessary tests: clippy, unit tests, and integration tests 12 | test: 13 | sh scripts/check-clippy-version.sh 14 | cargo fmt 15 | cargo clippy 16 | cargo test --workspace 17 | 18 | # Generate and open the slosh docs 19 | sloshdoc: 20 | cd doc && ./mk-site.sh 21 | open doc/book/index.html 22 | 23 | # Generate and open the rust docs 24 | rustdoc: 25 | cargo doc --workspace --no-deps --open 26 | 27 | 28 | # The remaining commands in the project are less commonly used 29 | 30 | # These tests are a subset of 'cargo test --workspace' 31 | # It runs ./slosh_test/tests/slosh-tests.rs which loads /slosh_test/run-tests.slosh which loads up all the globals and executes the Example block of each docstring 32 | # Test docstring examples of slosh globals defined with add_builtin or add_special 33 | test-globals: 34 | cargo test --package slosh_test --test slosh-tests run_slosh_tests -- --exact --nocapture 35 | 36 | # These tests are a subset of 'cargo test --workspace' 37 | # Test slosh tests defined in /slosh/tests/*.slosh 38 | test-lisp: 39 | cargo test --package slosh --test lisp-scripts -- --nocapture 40 | 41 | # Run the most recently built slosh executable 42 | slosh: 43 | @if [ -f ./target/debug/slosh ] && [ -f ./target/release/slosh ]; then \ 44 | if [ ./target/debug/slosh -nt ./target/release/slosh ]; then \ 45 | ./target/debug/slosh; \ 46 | else \ 47 | ./target/release/slosh; \ 48 | fi; \ 49 | elif [ -f ./target/debug/slosh ]; then \ 50 | ./target/debug/slosh; \ 51 | elif [ -f ./target/release/slosh ]; then \ 52 | ./target/release/slosh; \ 53 | else \ 54 | cargo build && ./target/debug/slosh; \ 55 | fi 56 | 57 | # Using `npx` requires installing `npm` which comes with `nodejs` from https://nodejs.org/en/download/ 58 | # Use javascript cspell tool to spellcheck the codebase 59 | spellcheck: 60 | npx cspell . 61 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Steven Stanfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bridge_adapters/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bridge_adapters" 3 | version.workspace = true 4 | edition = "2021" 5 | 6 | [dependencies] 7 | slvm = { workspace = true } 8 | compile_state = { workspace = true } 9 | bridge_types = { workspace = true } 10 | -------------------------------------------------------------------------------- /bridge_adapters/src/lib.rs: -------------------------------------------------------------------------------- 1 | use compile_state::state::{CompileEnvironment, SloshVm, SloshVmTrait}; 2 | use slvm::CallFuncSig; 3 | 4 | pub mod lisp_adapters; 5 | 6 | pub fn add_builtin( 7 | env: &mut SloshVm, 8 | name: &str, 9 | func: CallFuncSig, 10 | doc_string: &str, 11 | ) { 12 | let si = env.set_global_builtin(name, func); 13 | let key = env.intern("doc-string"); 14 | let s = env.alloc_string(doc_string.to_string()); 15 | env.set_global_property(si, key, s); 16 | } 17 | -------------------------------------------------------------------------------- /bridge_adapters/src/lisp_adapters/collections.rs: -------------------------------------------------------------------------------- 1 | use crate::lisp_adapters::{SlFromRef, SlFromRefMut}; 2 | use bridge_types::ErrorStrings; 3 | use compile_state::state::SloshVm; 4 | use slvm::vm_hashmap::VMHashMap; 5 | use slvm::{VMError, VMResult, Value, ValueType}; 6 | 7 | impl<'a> SlFromRef<'a, Value> for &'a VMHashMap { 8 | fn sl_from_ref(value: Value, vm: &'a SloshVm) -> VMResult { 9 | match value { 10 | Value::Map(h) => Ok(vm.get_map(h)), 11 | _ => Err(VMError::new_conversion( 12 | ErrorStrings::fix_me_mismatched_type( 13 | <&'static str>::from(ValueType::Map), 14 | value.display_type(vm), 15 | ), 16 | )), 17 | } 18 | } 19 | } 20 | 21 | impl<'a> SlFromRefMut<'a, Value> for &'a mut VMHashMap { 22 | fn sl_from_ref_mut(value: Value, vm: &'a mut SloshVm) -> VMResult { 23 | match value { 24 | Value::Map(h) => Ok(vm.get_map_mut(h)?), 25 | _ => Err(VMError::new_conversion( 26 | ErrorStrings::fix_me_mismatched_type( 27 | <&'static str>::from(ValueType::Map), 28 | value.display_type(vm), 29 | ), 30 | )), 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /bridge_macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bridge_macros" 3 | version.workspace = true 4 | edition = "2021" 5 | 6 | 7 | [lib] 8 | proc-macro = true 9 | 10 | [dependencies] 11 | syn = { workspace = true, features = ["full"] } 12 | quote = { workspace = true } 13 | static_assertions = { workspace = true } 14 | bridge_types = { workspace = true } 15 | slvm = { workspace = true } 16 | 17 | [dev-dependencies] 18 | trybuild = { workspace = true } 19 | -------------------------------------------------------------------------------- /bridge_types/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bridge_types" 3 | version.workspace = true 4 | edition = "2021" 5 | -------------------------------------------------------------------------------- /builtins/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "builtins" 3 | version.workspace = true 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | slvm = { workspace = true } 10 | compile_state = { workspace = true } 11 | shell = { workspace = true } 12 | sl-compiler = { workspace = true } 13 | bridge_adapters = { path = "../bridge_adapters" } 14 | unicode-segmentation = { workspace = true } 15 | unicode_reader = { workspace = true } 16 | bridge_types = { workspace = true } 17 | bridge_macros = { path = "../bridge_macros" } 18 | static_assertions = { workspace = true } 19 | rand = { workspace = true } 20 | walkdir = { workspace = true } 21 | same-file = { workspace = true } 22 | glob = { workspace = true } 23 | 24 | [dev-dependencies] 25 | trybuild = { workspace = true } 26 | -------------------------------------------------------------------------------- /builtins/src/bridge_macro_tests.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn macro_passing_tests() { 5 | let t = trybuild::TestCases::new(); 6 | t.pass("tests/*.rs"); 7 | } 8 | 9 | #[test] 10 | fn macro_failing_tests() { 11 | let t = trybuild::TestCases::new(); 12 | t.compile_fail("trybuild/tests/*fail.rs"); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /builtins/tests/MACRO_HELP.md: -------------------------------------------------------------------------------- 1 | To get macro expansion output for a given test 2 | 3 | `cargo expand --test ` 4 | 5 | e.g. 6 | `cargo expand --test special_args_pass` 7 | 8 | If macro expansion for the test/trybuild/ is needed it is a little more complicated. 9 | 10 | Why? well, if you put failing tests in `/tests/` then cargo tests fails so you 11 | can't do that. But `cargo expand --test` relies on finding modules in a test directory 12 | so, you can move a test from trybuild up one directory but move it back b/c 13 | otherwise `cargo test` will fail and CI won't pass. 14 | 15 | because `/trybuild` 16 | -------------------------------------------------------------------------------- /builtins/tests/convert_string_pass.rs: -------------------------------------------------------------------------------- 1 | use bridge_macros::sl_sh_fn; 2 | use bridge_types::{LooseString, SloshChar}; 3 | use compile_state::state::new_slosh_vm; 4 | use slvm::{VMResult, Value}; 5 | use std::borrow::Cow; 6 | 7 | pub fn main() { 8 | let mut vm = new_slosh_vm(); 9 | let args = vec![]; 10 | let expected = "return_string".to_string(); 11 | 12 | match parse_return_string(&mut vm, args.as_slice()).unwrap() { 13 | Value::String(h) => { 14 | let s = vm.get_string(h).to_string(); 15 | assert_eq!(expected, s); 16 | } 17 | _ => { 18 | panic!("Expected Value::String") 19 | } 20 | } 21 | assert_eq!(expected, return_string().unwrap()); 22 | 23 | match parse_return_loose_string(&mut vm, args.as_slice()).unwrap() { 24 | Value::String(h) => { 25 | let s = vm.get_string(h).to_string(); 26 | assert_eq!(expected, s); 27 | } 28 | _ => { 29 | panic!("Expected Value::String") 30 | } 31 | } 32 | assert_eq!(LooseString::Owned(expected), return_string().unwrap()); 33 | 34 | let expected = "a"; 35 | match parse_return_slosh_char(&mut vm, args.as_slice()).unwrap() { 36 | Value::String(h) => { 37 | let s = vm.get_string(h); 38 | assert_eq!(expected, s); 39 | } 40 | _ => { 41 | panic!("Expected Value::String") 42 | } 43 | } 44 | assert_eq!( 45 | SloshChar::String(Cow::Borrowed(expected)), 46 | return_slosh_char().unwrap() 47 | ); 48 | } 49 | 50 | /// obligatory doc 51 | #[sl_sh_fn(fn_name = "return_string")] 52 | pub fn return_string() -> VMResult { 53 | Ok("return_string".to_string()) 54 | } 55 | 56 | //TODO PC document use of generics in return parameters and limitations, 57 | /// obligatory doc 58 | #[sl_sh_fn(fn_name = "return_loose_string")] 59 | pub fn return_loose_string<'a>() -> VMResult> { 60 | Ok(LooseString::Owned("return_string".to_string())) 61 | } 62 | /// obligatory doc 63 | #[sl_sh_fn(fn_name = "return_slosh_char")] 64 | pub fn return_slosh_char<'a>() -> VMResult> { 65 | Ok(SloshChar::String(Cow::Borrowed("a"))) 66 | } 67 | 68 | /// obligatory doc 69 | #[sl_sh_fn(fn_name = "accept_str")] 70 | pub fn accept_str(_s: &str) {} 71 | 72 | /// obligatory doc 73 | #[sl_sh_fn(fn_name = "accept_str_mut")] 74 | pub fn accept_str_mut(_s: &mut String) {} 75 | 76 | //TODO #220 return &mut String? 77 | // require attribute? 78 | 79 | ///// obligatory doc 80 | //#[sl_sh_fn(fn_name = "accept_str_and_ret")] 81 | //pub fn accept_str_return_str(s: &str) -> &str { 82 | // s 83 | //} 84 | -------------------------------------------------------------------------------- /builtins/tests/optional_args_pass.rs: -------------------------------------------------------------------------------- 1 | use bridge_macros::sl_sh_fn; 2 | use compile_state::state::new_slosh_vm; 3 | use slvm::{VMResult, Value}; 4 | 5 | pub fn main() { 6 | let mut vm = new_slosh_vm(); 7 | 8 | let args = vec![Value::CodePoint('a')]; 9 | assert!(parse_accept_option(&mut vm, args.as_slice()).is_ok()); 10 | let args = vec![]; 11 | assert!(parse_accept_option(&mut vm, args.as_slice()).is_ok()); 12 | 13 | let no_args = vec![]; 14 | assert!(parse_accept_mult_option(&mut vm, no_args.as_slice()).is_ok()); 15 | let one_arg = vec![Value::CodePoint('a')]; 16 | assert!(parse_accept_mult_option(&mut vm, one_arg.as_slice()).is_ok()); 17 | let two_args = vec![Value::CodePoint('a'), Value::CodePoint('a')]; 18 | assert!(parse_accept_mult_option(&mut vm, two_args.as_slice()).is_ok()); 19 | let three_args = vec![ 20 | Value::CodePoint('a'), 21 | Value::CodePoint('a'), 22 | Value::CodePoint('a'), 23 | ]; 24 | assert!(parse_accept_mult_option(&mut vm, three_args.as_slice()).is_err()); 25 | } 26 | 27 | /// obligatory doc 28 | #[sl_sh_fn(fn_name = "accept_option")] 29 | pub fn accept_option(_opt: Option) -> VMResult<()> { 30 | Ok(()) 31 | } 32 | 33 | /// obligatory doc 34 | #[sl_sh_fn(fn_name = "accept_mult_option")] 35 | pub fn accept_mult_option(_opt1: Option, _opt2: Option) -> VMResult<()> { 36 | Ok(()) 37 | } 38 | -------------------------------------------------------------------------------- /builtins/tests/simple_proc_macro_pass.rs: -------------------------------------------------------------------------------- 1 | use bridge_macros::sl_sh_fn; 2 | use compile_state::state::new_slosh_vm; 3 | use slvm::{VMResult, Value}; 4 | 5 | pub fn main() { 6 | let mut vm = new_slosh_vm(); 7 | let args = vec![]; 8 | assert_eq!( 9 | Value::Nil, 10 | parse_return_nil(&mut vm, args.as_slice()).unwrap() 11 | ); 12 | assert_eq!((), return_nil().unwrap()); 13 | assert_eq!( 14 | Value::Nil, 15 | parse_return_nil2(&mut vm, args.as_slice()).unwrap() 16 | ); 17 | assert_eq!((), return_nil2()); 18 | assert_eq!( 19 | Value::Nil, 20 | parse_return_option(&mut vm, args.as_slice()).unwrap() 21 | ); 22 | assert_eq!((), return_option().unwrap()); 23 | 24 | assert_eq!( 25 | Value::Nil, 26 | parse_return_option_none(&mut vm, args.as_slice()).unwrap() 27 | ); 28 | assert_eq!((), return_option().unwrap()); 29 | } 30 | 31 | /// obligatory doc 32 | #[sl_sh_fn(fn_name = "return_nil")] 33 | pub fn return_nil() -> VMResult<()> { 34 | Ok(()) 35 | } 36 | 37 | /// obligatory doc 38 | #[sl_sh_fn(fn_name = "return_nil2")] 39 | pub fn return_nil2() {} 40 | 41 | /// obligatory doc 42 | #[sl_sh_fn(fn_name = "return_option")] 43 | pub fn return_option() -> Option<()> { 44 | Some(()) 45 | } 46 | 47 | /// obligatory doc 48 | #[sl_sh_fn(fn_name = "return_option_none")] 49 | pub fn return_option_none() -> Option<()> { 50 | None 51 | } 52 | -------------------------------------------------------------------------------- /builtins/trybuild/tests/borrow_checker_two_mut_fail.rs: -------------------------------------------------------------------------------- 1 | use compile_state::state::new_slosh_vm; 2 | use slvm::Value; 3 | 4 | pub fn main() {} 5 | fn borrow_check() { 6 | let mut vm = new_slosh_vm(); 7 | let dest = vm.alloc_string("XXX".to_string()); 8 | let dest2 = vm.alloc_string("YYY".to_string()); 9 | match dest { 10 | Value::String(d) => { 11 | let d = vm.get_string_mut(d).unwrap(); 12 | match dest2 { 13 | Value::String(d2) => { 14 | let d2 = vm.get_string_mut(d2).unwrap(); 15 | println!("x: {}", d); 16 | println!("y: {}", d2); 17 | } 18 | _ => { 19 | panic!("failed"); 20 | } 21 | } 22 | } 23 | _ => { 24 | panic!("failed"); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /builtins/trybuild/tests/borrow_checker_two_mut_fail.stderr: -------------------------------------------------------------------------------- 1 | error[E0499]: cannot borrow `vm` as mutable more than once at a time 2 | --> trybuild/tests/borrow_checker_two_mut_fail.rs:14:30 3 | | 4 | 11 | let d = vm.get_string_mut(d).unwrap(); 5 | | -- first mutable borrow occurs here 6 | ... 7 | 14 | let d2 = vm.get_string_mut(d2).unwrap(); 8 | | ^^ second mutable borrow occurs here 9 | 15 | println!("x: {}", d); 10 | | - first borrow later used here 11 | -------------------------------------------------------------------------------- /builtins/trybuild/tests/enforce_return_fail.rs: -------------------------------------------------------------------------------- 1 | use bridge_macros::sl_sh_fn; 2 | 3 | pub fn main() {} 4 | 5 | /// obligatory doc 6 | #[sl_sh_fn(fn_name = "invalid_return")] 7 | pub fn invalid_return() -> Result<(), ()> { 8 | Ok(()) 9 | } 10 | -------------------------------------------------------------------------------- /builtins/trybuild/tests/enforce_return_fail.stderr: -------------------------------------------------------------------------------- 1 | error: Functions can only return GenericArguments of type ["VMResult", "Option"], try wrapping this value in Option or VMResult. 2 | --> trybuild/tests/enforce_return_fail.rs:7:28 3 | | 4 | 7 | pub fn invalid_return() -> Result<(), ()> { 5 | | ^^^^^^ 6 | -------------------------------------------------------------------------------- /builtins/trybuild/tests/too_many_generics_fail.rs: -------------------------------------------------------------------------------- 1 | use bridge_macros::sl_sh_fn; 2 | 3 | pub fn main() {} 4 | 5 | /// obligatory doc 6 | #[sl_sh_fn(fn_name = "too_many_generics")] 7 | pub fn too_many_generics<'a, 'b>(a: &'a str, b: &'b str) -> &'a str { 8 | println!("{}", b); // prevent warning about unused variable 9 | a 10 | } 11 | -------------------------------------------------------------------------------- /builtins/trybuild/tests/too_many_generics_fail.stderr: -------------------------------------------------------------------------------- 1 | error: sl_sh_fn only supports functions with 0 or 1 generic lifetime parameters. 2 | --> trybuild/tests/too_many_generics_fail.rs:7:25 3 | | 4 | 7 | pub fn too_many_generics<'a, 'b>(a: &'a str, b: &'b str) -> &'a str { 5 | | ^ 6 | -------------------------------------------------------------------------------- /compile_state/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "compile_state" 3 | version.workspace = true 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | slvm = { workspace = true } 10 | -------------------------------------------------------------------------------- /compile_state/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod state; 2 | -------------------------------------------------------------------------------- /compiler/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sl-compiler" 3 | version.workspace = true 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | unicode-segmentation = { workspace = true } 10 | unicode_reader = { workspace = true } 11 | slvm = { workspace = true } 12 | compile_state = { workspace = true } 13 | 14 | [dev-dependencies] 15 | compiler_test_utils = { workspace = true } 16 | 17 | [build-dependencies] 18 | chrono = { workspace = true } 19 | -------------------------------------------------------------------------------- /compiler/build.rs: -------------------------------------------------------------------------------- 1 | use std::env::consts::{ARCH, OS}; 2 | use std::process::Command; 3 | 4 | use chrono::prelude::Utc; 5 | 6 | #[cfg(debug_assertions)] 7 | const BUILD_TYPE: &str = "debug"; 8 | #[cfg(not(debug_assertions))] 9 | const BUILD_TYPE: &str = "release"; 10 | 11 | fn main() { 12 | let version_string = if have_git() { 13 | format!( 14 | "{} {} ({}:{}{}, {BUILD_TYPE} build, {OS} [{ARCH}], {} UTC [{}])", 15 | env!("CARGO_PKG_NAME"), 16 | env!("CARGO_PKG_VERSION"), 17 | get_branch_name(), 18 | get_commit_hash(), 19 | if is_working_tree_clean() { "" } else { "+" }, 20 | Utc::now().format("%b %d %Y, %T"), 21 | get_rustc_version(), 22 | ) 23 | } else { 24 | format!( 25 | "{} {} ({BUILD_TYPE} build, {OS} [{ARCH}], {} UTC [{}])", 26 | env!("CARGO_PKG_NAME"), 27 | env!("CARGO_PKG_VERSION"), 28 | Utc::now().format("%b %d %Y, %T"), 29 | get_rustc_version(), 30 | ) 31 | }; 32 | 33 | println!("cargo:rustc-env=VERSION_STRING={version_string}"); 34 | } 35 | 36 | fn have_git() -> bool { 37 | Command::new("git") 38 | .arg("--version") 39 | .current_dir(env!("CARGO_MANIFEST_DIR")) 40 | .output() 41 | .is_ok() 42 | } 43 | 44 | fn get_commit_hash() -> String { 45 | let output = Command::new("git") 46 | .arg("log") 47 | .arg("-1") 48 | .arg("--pretty=format:%h") // Abbreviated commit hash 49 | // .arg("--pretty=format:%H") // Full commit hash 50 | .current_dir(env!("CARGO_MANIFEST_DIR")) 51 | .output() 52 | .unwrap(); 53 | 54 | assert!(output.status.success()); 55 | 56 | String::from_utf8_lossy(&output.stdout).to_string() 57 | } 58 | 59 | fn get_branch_name() -> String { 60 | let output = Command::new("git") 61 | .arg("rev-parse") 62 | .arg("--abbrev-ref") 63 | .arg("HEAD") 64 | .current_dir(env!("CARGO_MANIFEST_DIR")) 65 | .output() 66 | .unwrap(); 67 | 68 | assert!(output.status.success()); 69 | 70 | String::from_utf8_lossy(&output.stdout) 71 | .trim_end() 72 | .to_string() 73 | } 74 | 75 | fn is_working_tree_clean() -> bool { 76 | let status = Command::new("git") 77 | .arg("diff") 78 | .arg("--quiet") 79 | .arg("--exit-code") 80 | .current_dir(env!("CARGO_MANIFEST_DIR")) 81 | .status() 82 | .unwrap(); 83 | 84 | status.code().unwrap() == 0 85 | } 86 | 87 | fn get_rustc_version() -> String { 88 | let output = Command::new("rustc") 89 | .arg("--version") 90 | .current_dir(env!("CARGO_MANIFEST_DIR")) 91 | .output() 92 | .unwrap(); 93 | 94 | assert!(output.status.success()); 95 | 96 | String::from_utf8_lossy(&output.stdout) 97 | .trim_end() 98 | .to_string() 99 | } 100 | -------------------------------------------------------------------------------- /compiler/src/compile/util.rs: -------------------------------------------------------------------------------- 1 | use crate::SloshVm; 2 | use slvm::{VMError, VMResult, Value}; 3 | 4 | pub(crate) fn get_args_iter<'vm>( 5 | env: &'vm SloshVm, 6 | args: Value, 7 | name: &str, 8 | ) -> VMResult + 'vm>> { 9 | match args { 10 | Value::Pair(_) | Value::List(_, _) | Value::Nil => Ok(args.iter(env)), 11 | _ => Err(VMError::new_compile(format!("{name}, invalid args"))), 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /compiler/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod reader; 2 | 3 | pub use crate::reader::*; 4 | 5 | pub use compile_state::state::*; 6 | 7 | pub mod config; 8 | pub use crate::config::*; 9 | 10 | pub mod backquote; 11 | pub use crate::backquote::*; 12 | 13 | pub mod compile; 14 | pub mod pass1; 15 | 16 | pub mod load_eval; 17 | #[cfg(test)] 18 | pub mod test_utils; 19 | 20 | pub use crate::compile::*; 21 | -------------------------------------------------------------------------------- /compiler/src/pass1.rs: -------------------------------------------------------------------------------- 1 | use crate::compile_fn::mk_state; 2 | use crate::{CompileState, SloshVm}; 3 | use slvm::{from_i56, VMResult, Value}; 4 | 5 | pub fn pass1(env: &mut SloshVm, state: &mut CompileState, exp: Value) -> VMResult<()> { 6 | let fn_ = env.intern("fn"); 7 | let mac_ = env.intern("macro"); 8 | match exp { 9 | Value::Pair(_) | Value::List(_, _) => { 10 | let (car, cdr) = exp.get_pair(env).expect("Pair/List not a Pair or List?"); 11 | // Do an extra pass1 on lambda's so we can get all captures upfront. 12 | if let Value::Symbol(i) = car { 13 | if i == fn_ || i == mac_ { 14 | // XXX boo on this collect. 15 | let cdr = cdr.iter(env).collect::>(); 16 | if !cdr.is_empty() { 17 | let (mut new_state, _, _) = mk_state(env, state, cdr[0])?; 18 | for r in cdr[1..].iter() { 19 | pass1(env, &mut new_state, *r)?; 20 | } 21 | } 22 | return Ok(()); 23 | } 24 | } 25 | // XXX boo on this collect. 26 | for r in exp.iter(env).collect::>() { 27 | pass1(env, state, r)?; 28 | } 29 | } 30 | Value::Symbol(i) => { 31 | if state.get_symbol(i).is_none() && state.symbols.borrow().can_capture(i) { 32 | state.symbols.borrow_mut().insert_capture(env, i); 33 | if let Some(dbg_args) = state.chunk.dbg_args.as_mut() { 34 | dbg_args.push(i); 35 | } 36 | } 37 | } 38 | Value::True => {} 39 | Value::False => {} 40 | Value::Nil => {} 41 | Value::Undefined => {} 42 | Value::Byte(_) => {} 43 | Value::Int(i) => { 44 | let i = from_i56(&i); 45 | if i < 0 || i > u16::MAX as i64 { 46 | env.heap_immutable(exp); 47 | state.add_constant(exp); 48 | } 49 | } 50 | Value::String(_) => {} 51 | Value::Bytes(_) => {} 52 | Value::Lambda(_) => {} 53 | Value::Closure(_) => {} 54 | Value::Continuation(_) => {} 55 | Value::CallFrame(_) => {} 56 | Value::Value(_) => {} 57 | 58 | _ => { 59 | env.heap_immutable(exp); 60 | state.add_constant(exp); 61 | } 62 | } 63 | Ok(()) 64 | } 65 | -------------------------------------------------------------------------------- /compiler/test_utils/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "compiler_test_utils" 3 | version = "0.1.0" 4 | edition = "2021" 5 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 6 | 7 | [dependencies] 8 | sl-compiler = { workspace = true } 9 | slvm = { workspace = true } 10 | compile_state = { workspace = true } 11 | -------------------------------------------------------------------------------- /doc/.gitignore: -------------------------------------------------------------------------------- 1 | book 2 | slosh-rust-docs 3 | all-rust-docs 4 | legacy 5 | -------------------------------------------------------------------------------- /doc/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["gpwclark", "sstanfield"] 3 | language = "en" 4 | multilingual = false 5 | src = "src" 6 | title = "Slosh Documentation" 7 | 8 | [preprocessor.slosh-eval] 9 | after = ["links"] 10 | doc-supplementary = true 11 | code-block-label = "slosh" 12 | 13 | [preprocessor.slosh-eval.doc-forms] 14 | std-lib = true 15 | user = true 16 | user-doc-files = [] 17 | user-doc-load-paths = [] 18 | -------------------------------------------------------------------------------- /doc/list-slosh-doc-exemptions.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env slosh_test 2 | 3 | (pr (loop (lst i output) ((get-exemptions) 0 "") 4 | (if (>= (+ i 1) (len lst)) 5 | (break output) 6 | (recur lst (inc! i) (str output lst.~i ",\n"))))) 7 | -------------------------------------------------------------------------------- /doc/list-slosh-forms.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env slosh_test 2 | 3 | (pr (loop (lst i output) ((get-globals-sorted) 0 "") 4 | (if (>= (+ i 1) (len lst)) 5 | (break output) 6 | (recur lst (inc! i) (str output lst.~i ",\n"))))) 7 | -------------------------------------------------------------------------------- /doc/mdbook-slosh-eval/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /doc/mdbook-slosh-eval/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mdbook-slosh-eval" 3 | version = "0.1.0" 4 | edition = "2021" 5 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 6 | 7 | [dependencies] 8 | clap = "*" 9 | semver = "*" 10 | mdbook = "*" 11 | anyhow = "*" 12 | serde_json = "*" 13 | env_logger = "*" 14 | log = "*" 15 | pulldown-cmark = "0.10.2" 16 | pulldown-cmark-to-cmark = "13.0.0" 17 | slosh_lib = { path = "../../slosh_lib" } 18 | slosh_test_lib = { path = "../../slosh_test_lib" } 19 | builtins = { path = "../../builtins" } 20 | compile_state = { path = "../../compile_state" } 21 | bridge_adapters = { path = "../../bridge_adapters" } 22 | slvm = { path = "../../vm" } 23 | sl-compiler = { path = "../../compiler" } 24 | toml = "=0.5.11" 25 | 26 | [build-dependencies] 27 | chrono = "0.4.38" 28 | 29 | [workspace] 30 | -------------------------------------------------------------------------------- /doc/search-hack-patch.sh: -------------------------------------------------------------------------------- 1 | ############################################################## 2 | # Hack to get mdbook to allow searching for symbols like `%` # 3 | ############################################################## 4 | # Path to the searcher.js file 5 | SEARCHER_JS="./book/searcher.js" 6 | # Line to find 7 | SEARCH_LINE=' searchindex = elasticlunr.Index.load(config.index);' 8 | # Lines to insert after the found line 9 | INSERT_LINES='\ 10 | // Hack to allow searching for symbols like `%` \ 11 | // Related discussion at https://github.com/weixsong/elasticlunr.js/issues/53 \ 12 | // and https://github.com/rust-lang/mdBook/issues/2393 \ 13 | // where people are trying to get mdbook and elasticlunr.js to handle Chinese and its non-English characters \ 14 | // Removing the trimmer makes sense, and perhaps there is another place to remove it more elegantly \ 15 | searchindex.pipeline.remove(elasticlunr.trimmer); \ 16 | // Perhaps because we are removing the trimmer at the wrong spot \ 17 | // We also have to re-add everything to the index \ 18 | // This might double the memory usage \ 19 | let temp = Object.values(searchindex.documentStore.docs); \ 20 | temp.forEach((d) => searchindex.addDoc(d)); \ 21 | // End of Hack to allow searching for symbols like `%` \ 22 | ' 23 | # Use awk to find the line and insert the new lines after it 24 | awk -v search="$SEARCH_LINE" -v insert="$INSERT_LINES" ' 25 | { 26 | print 27 | if ($0 == search) { 28 | print insert 29 | } 30 | }' "$SEARCHER_JS" > "${SEARCHER_JS}.tmp" && mv "${SEARCHER_JS}.tmp" "$SEARCHER_JS" 31 | -------------------------------------------------------------------------------- /doc/src/.gitignore: -------------------------------------------------------------------------------- 1 | # copied from the gh repo, ephermeral 2 | legacy/ 3 | 4 | # generated by cargo doc 5 | all-rust-docs/ 6 | slosh-rust-docs/ 7 | -------------------------------------------------------------------------------- /doc/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | # Basics 4 | - [Welcome](./welcome.md) 5 | - [Overview](./overview.md) 6 | 7 | # Shell Basics 8 | - [Shell Commands in Lisp](./shell-vs-lisp.md) 9 | - [Shell Redirects](./shell-redirects.md) 10 | 11 | # Language Basics 12 | - [Data Types in Slosh](./containers.md) 13 | - [Equality](./equality.md) 14 | - [Errors](./errors.md) 15 | - [Syntax and Macros](./syntax-and-macros.md) 16 | - [Iterators](./iterators.md) 17 | - [Debugger](./debugger.md) 18 | 19 | # General 20 | 21 | - [Let Bindings and Destructuring](./let.md) 22 | - [Namespaces](./namespaces.md) 23 | - [Examples](./end_to_end.md) 24 | - [FAQ](./faq.md) 25 | -------------------------------------------------------------------------------- /doc/src/debugger.md: -------------------------------------------------------------------------------- 1 | # Simple Lisp Debugger 2 | 3 | - `:abort` 4 | - exit the debugger. 5 | - `:globals` 6 | - prints all the globals 7 | - `:dasm` 8 | - show the bytecode 9 | - `:regs` 10 | - show stack that's available, e.g. the view of the stack your function has 11 | - `:stack` 12 | - show call stack 13 | - `:regs-raw` 14 | - TODO sls fix me 15 | -------------------------------------------------------------------------------- /doc/src/end_to_end.md: -------------------------------------------------------------------------------- 1 | # End to End example of Slosh execution 2 | 3 | 1. Start with the lisp program `(1.1)` 4 | 2. In `reader.rs` 5 | 6 | - The `read_inner` function controls most parsing. 7 | - Numeric parsing happens at the end in the catch-all of the match statement. 8 | - The `do_atom` function attempts to parse 1.1 as an i64 and fails, so it parses it as f64 and then calls `.into()` to convert to a `Value` 9 | 10 | 3. In `main.rs` 11 | 12 | - The `exec_expression` function calls `pass1` 13 | - And then it calls `compile` 14 | 15 | 4. In `pass1.rs` 16 | 17 | - The `pass1` function initially operates on (1.1) as a pair or list 18 | - It iterates over each element of the list and recursively calls `pass1` on each element 19 | - So then `pass1` is called on 1.1 which is then handled in the catch-all of the match statement 20 | - and this is where we add 1.1 to the heap and add it is a constant to the vm 21 | 22 | 5. In `state.rs` 23 | 24 | - `add_constant` is called which inserts the `Value` of 1.1 into `pub struct CompileState`'s `pub constants: HashMap` 25 | - Since constants are stored in a hashmap, if two different numeric constants hash to the same thing, they will be stored as the same constant 26 | 27 | 6. In `float_56.rs` 28 | 29 | - `F56` impl's the `Hash` trait and has a custom implementation of `hash` that converts the `F56` to a `u64` and then hashes the result 30 | 31 | 7. In `compile.rs` 32 | 33 | - Recall that `exec_expression` called `compile` after `pass1` 34 | - calls to `compile` trickle down into `compile_list`, `compile_special`, `compile_math`, and others. 35 | - `compile_list` handles a single value like this and the match statement catch-all prints Boo and the value itself 36 | -------------------------------------------------------------------------------- /doc/src/errors.md: -------------------------------------------------------------------------------- 1 | # ERRORS 2 | 3 | ## Error Type 4 | The error type consists of an identifying keyword and a data/payload value. This 5 | value is typically a string but can be any valid value. 6 | 7 | (type [error]) returns :Error 8 | The form (car [error]) returns the keyword identifying this error. 9 | The form (cdr [error]) returns the data value for the error. 10 | Note the use of car/cdr to pull apart an error even though it is not of the pair type. 11 | Use (mk-err :[ID] value) to create an error type or (err :[ID] value) to "raise" an error (see below). 12 | 13 | ## Raising an error 14 | Runtime errors will be "raised". This means the program execution will halt and the debugger will be entered. Currently this only allows examining the running state but will eventually include the ability to modify state and restart as other Lisps allow. Code can raise an error with the err form, for instance (err :some-error-type "This is my error") will raise an error and interrupt the program. 15 | 16 | Note, the (get-error FORM+) form can be used to programmatically return a raised error instead of breaking to the debugger. 17 | 18 | ## Returning an error 19 | Code can return an error instead of breaking into the debugger. Use the (mk-err :[ERROR ID] vallue) to create an error and then use it as any other value (return it from a function for instance). This may be appropriate for a common error that does not warrent breaking to the debugger. 20 | 21 | ## References 22 | See the docs string for: 23 | - err 24 | - mk-err 25 | - err? 26 | - ok? 27 | - get-error 28 | -------------------------------------------------------------------------------- /doc/src/faq.md: -------------------------------------------------------------------------------- 1 | # FAQ 2 | 3 | 4 |
5 | Does the syntax on the CLI differ from bash that much if at all? 6 |

7 | No, not really. 8 |

9 |
10 | 11 |
12 | Will sl-sh be supported on windows? 13 |

14 | Work is being done in sl-liner and sl-console to make this possible but currently it is not supported. 15 |

16 |
17 | 18 |
19 | Is it any good? 20 |

21 | Yes 22 |

23 |
24 | -------------------------------------------------------------------------------- /doc/src/generated-sections/.gitignore: -------------------------------------------------------------------------------- 1 | **.md 2 | -------------------------------------------------------------------------------- /doc/src/iterators.md: -------------------------------------------------------------------------------- 1 | # Iterators 2 | 3 | # TODO PC/sls docs 4 | [this is the PR where iterators first went in to slosh](https://github.com/sl-sh-dev/sl-sh/pull/181) 5 | [inspiration for our iterators](https://www.tfeb.org/fragments/2024/05/15/an-iteration-construct-for-common-lisp/) 6 | -------------------------------------------------------------------------------- /doc/src/namespaces.md: -------------------------------------------------------------------------------- 1 | # Namespaces 2 | 3 | ## Description 4 | 5 | Namespaces are compiler bookkeeping for organizing global symbols. When in a namespace then any symbols that are defined will have the current NAMESPACE:: prepended to the symbol. When symbols are resolved the compiler will also try to prepend the current namespace first in order to find the symbol. 6 | 7 | ## Entering a namespace 8 | 9 | From code use the `with-ns` form. 10 | 11 | ```slosh 12 | (doc 'with-ns) 13 | ``` 14 | 15 | From the top-level REPL you can use 'ns'. 16 | ```slosh 17 | (doc 'ns) 18 | ``` 19 | 20 | This is an open-ended namespace change intended for the repl, prefer with-ns for a scoped namespace in code. 21 | 22 | ## Imports 23 | 24 | Other namespaces can be imported to allow its symbols to be accessed in a shorter form. Use the 'import' form for this . 25 | ```slosh 26 | (doc 'import) 27 | ``` 28 | For instance using ```(import iter)``` will allow any symbols in the iter namespace to be used without prepending 'iter::'. You can also use the ```(import iter :as i)```, the :as form allows the namespace to be given a different name. In this case the iter namespace could be replaced with 'i', (i::for ...) instead of (iter::for ...) for example. Imports are resolved in the order they are compiled in case of conflict (i.e. the first import that resolves a symbol wins). Imports are attached to the current namespace, changing namespaces will clear imports (note that 'with-ns' saves and restores the previous namespace with imports). 29 | 30 | ## Loading code 31 | 32 | To load new code into your environment use load or run-script. 33 | 34 | ### Load 35 | 36 | The load form should generally be preferred. It will compile the code at compile time (vs runtime) and execute it at runtime. This means: 37 | - The path parameter has to be known at compile time: a string const, defined global or form that does not need local inputs. 38 | - Any symbols defined in the loaded code will be known to the compiler at compile time and available for use. 39 | 40 | ```slosh 41 | (doc 'load) 42 | ``` 43 | 44 | ### Run Script 45 | The run-script form loads each form in the file, compiles and executes it at runtime. This means: 46 | - It can take any parameter since it is resolved at runtime. 47 | - Globals it defines will NOT be known until after it runs at runtime. 48 | 49 | ```slosh 50 | (doc 'run-script) 51 | ``` 52 | -------------------------------------------------------------------------------- /doc/src/overview.md: -------------------------------------------------------------------------------- 1 | # The Readme 2 | 3 | {{#include ../../README.md}} 4 | -------------------------------------------------------------------------------- /doc/src/section-docs/conditional.md: -------------------------------------------------------------------------------- 1 | **For additional notes on conditionals involving equality see [documentation site's equality section](../equality.md)** 2 | -------------------------------------------------------------------------------- /doc/src/section-docs/hashmap.md: -------------------------------------------------------------------------------- 1 | Hashmaps as a collection benefit from the same syntactic sugar provided by the 2 | reader macro with the added support of some generic collection functions, `get`, 3 | `set!`, and `clear!`. 4 | 5 | For retrieving items from a hashmap prefer the reader syntax (.) or use the `get` 6 | function. 7 | ```slosh 8 | (def m {:one "one", :two "two", "three" 3}) 9 | (and (= "one" m.:one) 10 | (= "two" m.:two) 11 | (= 3 (get m "three"))) 12 | ``` 13 | For setting key/value pairs on an existing hashmap prefer the reader syntax 14 | with the `set!` function or pass it the output of `get`. 15 | ```slosh 16 | (def m {:one "one", :two "two", "three" 3, :four 4}) 17 | (set! m.:one "changed1") 18 | (set! m.:two "changed2") 19 | (set! (get m "three") "changed3") 20 | (and (= "changed1" m.:one) 21 | (= "changed2" m.:two) 22 | (= "changed3" (get m "three"))) 23 | 24 | (def four :four) 25 | (set! m.~four "changed4") 26 | (= "changed4" (get m :four)) 27 | ``` 28 | 29 | 30 | 31 | Clearing all keys is done with the `clear!` function. 32 | ```slosh 33 | (def m {:one "one", :two "two", "three" 3}) 34 | (clear! m) 35 | (= (make-hash) m) 36 | ``` 37 | ** Hashmap keys that are not keyword types (not prefixed by a colon) can not be 38 | used with the reader syntax, which is why in the example the key "three" was 39 | used with the `get` function each time instead of using the reader syntax. 40 | 41 | -------------------------------------------------------------------------------- /doc/src/shell-redirects.md: -------------------------------------------------------------------------------- 1 | Still figuring this out currently allows things like this (syntax will probably change): 2 | 3 | Current iteration uses :< (same as :0<) to connect a file stdin and :> (same as :1>) to connect a file to stdout. These can also be used with file descriptors (for example :2> will connect a file to stderr). They can be mixed with other shell redirects and will just become part of the redirect stack. Each lisp redirect will return a file in a list (first element will be the PID of the final process). 4 | 5 | Examples: 6 | (let ([pid, out] (sh "ls" :>)) (iter::for l in (iter::iter out) (pr l))) 7 | 8 | (let ([pid, out, er] (sh "ls vm/src/ sdsdf" :> :2>))(prn "PID: " pid) (iter::for l in (iter::iter out)(pr "from out: " l))(iter::for l in (iter::iter er)(pr "from err: " l) 9 | 10 | Set the lisp pipe then use a shell redirect to also send stderr to the same pipe: 11 | (let ([pid, out] (sh "ls vm/src/ sdsdf" :> "2>&1"))(prn "PID: " pid) (iter::for l in (iter::iter out)(pr "from grep: " l))) 12 | 13 | (let ([pid, in, out] (sh :< "grep XX" :>))(prn "PID: " pid) (fprn in "XXsls")(fprn in "sls")(fprn in "dfdXX")(fclose in)(iter::for l in (iter::iter out)(pr "from grep: " l))) 14 | 15 | (same as above but include a pipe between shell commands) 16 | (let ([pid, in, out] (sh :< "grep XX | cat -" :>)) (fprn in "XXsls")(fprn in "sls")(fprn in "dfdXX")(fclose in)(iter::for l in (iter::iter out)(pr l))) 17 | -------------------------------------------------------------------------------- /doc/src/shell-vs-lisp.md: -------------------------------------------------------------------------------- 1 | # Using shell commands in lisp 2 | 3 | Slosh can easily be used to launch processes in lisp mode (e.g. in a script). 4 | Interacting with the input and output of those programs can be done in a variety 5 | of ways. 6 | 7 | 8 | ## Two main flavors of starting shell processes 9 | 10 | 1. *The $sh variety* which is a little clunky as you directly pass it a string, as seen in the let binding. 11 | 2. *The $ reader macro* which treats everything as a string but allows escaping slosh variables 12 | directly in the shell with macro-like syntax `~` 13 | ``` 14 | (defn parse-git-branch () (let (branch ($sh "git rev-parse --abbrev-ref HEAD 2>/dev/null")) 15 | (if (= branch "") 16 | (str "") 17 | (do $(export BRANCH_NAME=~branch) 18 | (str "(" branch ")"))))) 19 | ``` 20 | ~ under construction ~ 21 | 22 | instead of (sh "wc" "-l") 23 | we have $(wc -l) 24 | (def v "foo") 25 | $(echo ~foo) 26 | $(echo ~v) 27 | 28 | 29 | ## calling shell commands in lisp code 30 | ### 3 ways 31 | - $() - reader-macro - convenient because it interprets everything as a string - can be used with macro like ~ 32 | - (sh "") - regular function, but you have to pass it a string 33 | ** $() & (sh) are very similar. 34 | 35 | - ($sh ) - like backticks, call to shell, and get back a slosh string, e.g. run this command and give me the output 36 | but we do not have a reader macro yet. 37 | - this is not implemented w/ a reader macro but could be something like $(( )) except that might be ugly 38 | - ($sh "git rev-parse --abbrev-ref HEAD 2>/dev/null") 39 | - this returns a string, does more work for you 40 | - (sh "git rev-parse --abbrev-ref HEAD 2>/dev/null") 41 | - Returns the exit status if foreground and the PID if background. Add the '&' to the string to background it. 42 | 43 | ``` 44 | NOTE: 45 | on the CLI typing $() directly on the REPL, but if you wrapped it in say a (do $()) it would work, REPL isn't smart enough yet to 46 | pass the $() to the LISP repl 47 | ``` 48 | 49 | ### bash precedent 50 | - diff <(echo "1\n2\n3") <(echo "echo 1\n\1\n3") 51 | - https://www.gnu.org/software/bash/manual/html_node/Process-Substitution.html#Process-Substitution 52 | -------------------------------------------------------------------------------- /doc/src/welcome.md: -------------------------------------------------------------------------------- 1 | # Welcome 2 | 3 | This is a real shell and scripting language that at least two people really 4 | use each day. They really use it on the CLI and they really use it to write 5 | scripts because they want to use a real language in the terminal and they want 6 | that same language to be available for scripting. There's one huge and 7 | wonderful catch, it's a lisp! 8 | 9 | # As a shell 10 | As a shell slosh does not differ much from bash at all. It supports pipes, 11 | redirects, ... etc. You could replace your grandmother's shell with slosh and 12 | as long as you ported her prompt verbatim she probably would not notice. 13 | 14 | 15 | # As a language 16 | Slosh is inspired by clojure and scheme. It is a type 1 lisp. 17 | 18 | 19 | # Motivation 20 | 21 | Lisp is a truly novel family of languages. Every year new developers 22 | discover [what many people have discovered long before 23 | them](https://xkcd.com/297/). 24 | 25 | Some of them go on to realize that using a lisp regularly in the terminal could 26 | not only enhance their skills as a developer but potentially open them up to a 27 | whole world of automation and fun by interacting with software that sparks joy. 28 | This could result in a renaissance of custom functionality spread lovingly throughout 29 | their systems. Despite its portability, we do not believe we should write any 30 | more bash code because it has never, and will never, result in "library" code; 31 | it's been decades! This means everything you do with it is a dead-end. There 32 | is no momentum, and no standing on the shoulders of those that came before you. 33 | Over time, we hope to change that. 34 | 35 | The docs are heavily under development as we transition from our old legacy 36 | tree based interpreter (sl-sh) to the register based virtual machine 37 | implementation of the language (slosh). 38 | 39 | 40 | 41 | # DOCS todos 42 | 43 | [wiki of under construction / todo docs](https://github.com/sl-sh-dev/sl-sh/wiki/) 44 | 45 | -------------------------------------------------------------------------------- /init.slosh: -------------------------------------------------------------------------------- 1 | (prn (version)) 2 | 3 | (prn "Using default slshrc written to \"~/.config/slosh/init.slosh\".") 4 | (prn "Edit this file to remove this message and customize your shell") 5 | 6 | (defn parse-git-branch () (let (branch ($sh "git rev-parse --abbrev-ref HEAD 2>/dev/null")) 7 | (if (= branch "") 8 | (str "") 9 | (str "(" branch ")")))) 10 | 11 | (defn get-pwd () 12 | (str-replace (env 'PWD) (env 'HOME) "~")) 13 | 14 | (defn set-prompt-tail (last-status) 15 | (let ( 16 | debug (if (str-contains (version) "debug") "[DEBUG]" "") 17 | status (if (= last-status 0) "" (str "\x1b[31m(" last-status ")\x1b[39m")) 18 | ) 19 | (if (= *euid* 0) 20 | (str "\x1b[31m" status "\n\x1b[31m" debug "λ #\x1b[39m ") 21 | (str "\x1b[32m" status "\n\x1b[32m" debug "λ >\x1b[39m ")))) 22 | 23 | (defn __prompt () 24 | (str "\x1b[32m[" *ns* "]:" (env "HOST") ":\x1b[34m" (str-trim! (get-pwd)) "/\x1b[37m" (parse-git-branch) (set-prompt-tail *last-status*))) 25 | 26 | (sh "alias ls='/bin/ls --color -F'") 27 | (sh "alias ll='/bin/ls --color -Falh'") 28 | (sh "alias vi=nvim") 29 | (sh "alias vim=nvim") 30 | 31 | (sh "export PATH=/bin:/usr/bin:/usr/local/bin:~/bin:~/.cargo/bin") 32 | 33 | (sh "export LC_ALL=en_US.UTF-8") 34 | 35 | ; load and activate syntax highlighting on the prompt 36 | (load "sh-color.slosh") 37 | (syntax-on) 38 | 39 | 40 | ;; i'm fun {{{ 41 | (prn " ██╗") 42 | (prn " ██║") 43 | (prn " ██║") 44 | (prn " ██████████████████████████████████╗ ██║") 45 | (prn " ██╔═════════════════════════════██║ ██║") 46 | (prn " ██║ ██║ ██║") 47 | (prn "███████╗██╗ ███████╗██╗ ██╗ ██║ ██║") 48 | (prn "██╔════╝██║ ██╔════╝██║ ██║ ██║ ██║") 49 | (prn "███████╗██║█████╗███████╗███████║ ██║ ██║") 50 | (prn "╚════██║██║╚════╝╚════██║██╔══██║ ██║ ██║") 51 | (prn "███████║███████╗ ███████║██║ ██║ ██║ ██║") 52 | (prn "╚══════╝╚══════╝ ╚══════╝╚═╝ ╚═╝ ██║ ╚═╝") 53 | (prn " ██╗ ██║ ██║") 54 | (prn " ██║ ██████████████████████████████████║") 55 | (prn " ██║ ╚═════════════════════════════════╝") 56 | (prn " ██║") 57 | (prn " ██║ ████████████████████████████████████████████╗") 58 | (prn " ██║ ╚═══════════════════════════════════════════╝") 59 | (prn " ██║") 60 | (prn " ╚═╝") 61 | 62 | (prn " Hey, hey, hey. Don't be mean.") 63 | (prn " We don't have to be mean because,") 64 | (prn " remember, no matter where you go,") 65 | (prn " there you are.") 66 | (prn " - Buckaroo Banzai") 67 | 68 | ;; }}} 69 | -------------------------------------------------------------------------------- /legacy/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | .idea/** 4 | docs/Gemfile.lock 5 | docs/pages/mydoc/mydoc_shellreader.md 6 | docs/pages/mydoc/mydoc_reader.md 7 | docs/_data/sidebars/mydoc_sidebar.yml 8 | docs/pages/mydoc/mydoc_api.md 9 | docs/pages/mydoc/mydoc_namespaces.md 10 | docs/pages/mydoc/mydoc_documentation.md 11 | -------------------------------------------------------------------------------- /legacy/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sl-sh" 3 | version = "0.9.70" 4 | authors = ["Steven Stanfield "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | cfg-if = "1.0" 11 | sl-liner = { git = "https://github.com/sl-sh-dev/sl-liner.git" } 12 | #sl-liner = { path = "../sl-liner" } 13 | glob = "0.3" 14 | nix = "0.23.1" 15 | unicode-segmentation = "1.7.1" 16 | unicode_reader = "1" 17 | unicode-width = "0.1" 18 | rand = "0.8.3" 19 | walkdir = "2" 20 | same-file = "1.0.6" 21 | remove_dir_all = "0.8" 22 | #jemallocator = "0.3.2" 23 | regex = "1.5" 24 | sl-sh-proc-macros = { git = "https://github.com/sl-sh-dev/sl-sh-proc-macros.git" } 25 | #sl-sh-proc-macros = { path = "../sl-sh-proc-macros" } 26 | static_assertions = "1" 27 | 28 | [build-dependencies] 29 | chrono = "0.4.7" 30 | 31 | [profile.release] 32 | lto = true 33 | #codegen-units = 1 34 | #opt-level = 'z' 35 | #debug = true 36 | panic = "abort" 37 | 38 | [dev-dependencies] 39 | criterion = "0.3" 40 | 41 | [[bench]] 42 | name = "start_benchmark" 43 | harness = false 44 | 45 | [[bench]] 46 | name = "start_script" 47 | harness = false 48 | 49 | -------------------------------------------------------------------------------- /legacy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.52.1 2 | 3 | WORKDIR /usr/src/sl-sh 4 | 5 | RUN rustup target add x86_64-unknown-linux-musl 6 | 7 | COPY . . 8 | RUN cargo install --path . 9 | 10 | CMD ["sl-sh"] 11 | -------------------------------------------------------------------------------- /legacy/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 sstanfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /legacy/benches/start.lisp: -------------------------------------------------------------------------------- 1 | (exit) 2 | -------------------------------------------------------------------------------- /legacy/benches/start_benchmark.rs: -------------------------------------------------------------------------------- 1 | use ::sl_sh::shell::*; 2 | use criterion::{criterion_group, criterion_main, Criterion}; 3 | 4 | pub fn criterion_benchmark(c: &mut Criterion) { 5 | let command_args: Vec = Vec::new(); 6 | c.bench_function("startup", |b| { 7 | b.iter(|| run_one_command("exit", &command_args)) 8 | }); 9 | } 10 | 11 | criterion_group!(benches, criterion_benchmark); 12 | criterion_main!(benches); 13 | -------------------------------------------------------------------------------- /legacy/benches/start_script.rs: -------------------------------------------------------------------------------- 1 | use ::sl_sh::shell::*; 2 | use criterion::{criterion_group, criterion_main, Criterion}; 3 | 4 | pub fn criterion_benchmark(c: &mut Criterion) { 5 | let command_args: Vec = Vec::new(); 6 | c.bench_function("start script", |b| { 7 | b.iter(|| run_one_script("benches/start.lisp", &command_args)) 8 | }); 9 | } 10 | 11 | criterion_group!(benches, criterion_benchmark); 12 | criterion_main!(benches); 13 | -------------------------------------------------------------------------------- /legacy/contrib/reader_macro_vec.lisp: -------------------------------------------------------------------------------- 1 | (defn reader_macro_vec (stream ch) (progn 2 | (def 'ret (vec)) 3 | (loop (val) ((read stream)) 4 | (progn 5 | (vec-push! ret val) 6 | (if (and (not (str-iter-empty? stream))(not (= (str-iter-peek stream) #\]))) 7 | (recur (read stream))))) 8 | (if (not (= #\] (next! stream))) (err "Malformed []")) 9 | ret)) 10 | 11 | (def '*read-table* (make-hash '((#\[ . reader_macro_vec)))) 12 | (def '*read-table-end-char* (make-hash '((#\[ . #\])))) 13 | -------------------------------------------------------------------------------- /legacy/docs/.gitignore: -------------------------------------------------------------------------------- 1 | _site/ 2 | .sass-cache/ 3 | .jekyll-metadata 4 | .jekyll-cache 5 | _pdf 6 | .DS_Store 7 | .idea 8 | .vendor/ 9 | .vscode/ 10 | .bundle/ 11 | -------------------------------------------------------------------------------- /legacy/docs/.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: ruby:2.3 2 | 3 | variables: 4 | JEKYLL_ENV: production 5 | 6 | test: 7 | stage: test 8 | script: 9 | - sh ./var/build.sh 10 | - bundle exec jekyll build -d test 11 | artifacts: 12 | paths: 13 | - test 14 | except: 15 | - master 16 | 17 | pages: 18 | stage: deploy 19 | script: 20 | - sh ./var/build.sh 21 | - bundle exec jekyll build -d public 22 | artifacts: 23 | paths: 24 | - public 25 | only: 26 | - master 27 | -------------------------------------------------------------------------------- /legacy/docs/404.html: -------------------------------------------------------------------------------- 1 | --- 2 | permalink: /404.html 3 | layout: default 4 | --- 5 | 6 | 19 | 20 |
21 |

404

22 | 23 |

Page not found :(

24 |

The requested page could not be found.

25 |
26 | -------------------------------------------------------------------------------- /legacy/docs/404.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Page Not Found" 3 | search: exclude 4 | --- 5 | 6 | Sorry, but the page you were trying to view does not exist. Try searching for it or looking at the URL to see if it looks correct. 7 | -------------------------------------------------------------------------------- /legacy/docs/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG RUBY=2.7.1 2 | FROM ruby:$RUBY 3 | 4 | EXPOSE 4000 5 | 6 | RUN apt-get update 7 | RUN apt-get install -y \ 8 | git \ 9 | locales \ 10 | make \ 11 | nodejs 12 | 13 | RUN gem update system 14 | 15 | COPY Gemfile /tmp/ 16 | RUN bundle config local.ghpages /tmp/ && NOKOGIRI_USE_SYSTEM_LIBRARIES=true bundle install --gemfile=/tmp/Gemfile 17 | 18 | RUN echo "en_US UTF-8" > /etc/locale.gen && locale-gen en-US.UTF-8 19 | ENV LANG en_US.UTF-8 20 | ENV LANGUAGE en_US.UTF-8 21 | ENV LC_ALL en_US.UTF-8 22 | 23 | WORKDIR /tmp/ 24 | COPY . /tmp/ 25 | ENTRYPOINT ["jekyll", "serve", "--config", "/tmp/_config.yml,/tmp/_user_config.yml", "--livereload", "-H", "0.0.0.0", "-p", "4000"] 26 | -------------------------------------------------------------------------------- /legacy/docs/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | gem 'github-pages', group: :jekyll_plugins 3 | -------------------------------------------------------------------------------- /legacy/docs/README.docker: -------------------------------------------------------------------------------- 1 | # to build 2 | ``` 3 | docker build -t jekyll . 4 | ``` 5 | 6 | # to run 7 | ``` 8 | docker run --rm --name jekyll -it -p 4000:4000 -v $PWD:/tmp jekyll 9 | ``` 10 | # to run forever (make sure this command is run in the docs/ subdirectory 11 | docker run -d --restart=always -it -p 4000:4000 --name jekyll -v $PWD:/tmp jekyll 12 | 13 | # to view 14 | in browser visit localhost:4000 15 | 16 | # to view state of jekyll watcher to check for reload times or errors 17 | docker logs -f 18 | 19 | # to auto reload when certain files change. 20 | (loop () () (do $(inotifywait -e close_write ...) $(sl-sh docify.lisp) (recur))) 21 | -------------------------------------------------------------------------------- /legacy/docs/_config.yml: -------------------------------------------------------------------------------- 1 | # TODO 2 | # 1. Fix tag or remove them and make note they exist if I'm not using them. 3 | repository: sl-sh-dev/sl-sh 4 | description: documentation for Simple Lisp SHell 5 | title: sl-sh documentation 6 | output: web 7 | topnav_title: sl-sh documentation 8 | site_title: sl-sh documentation 9 | company_name: sl-sh 10 | baseurl: "/sl-sh" # the subpath of your site, e.g. /blog 11 | url: "https://sl-sh-dev.github.io" # the base hostname & protocol for your site, e.g. http://example.com 12 | exclude: 13 | - .idea/ 14 | - .gitignore 15 | - vendor 16 | # these are the files and directories that jekyll will exclude from the build 17 | feedback_disable: true 18 | highlighter: rouge 19 | # library used for syntax highlighting 20 | markdown: kramdown 21 | kramdown: 22 | input: GFM 23 | auto_ids: true 24 | # filter used to process markdown. note that kramdown differs from github-flavored markdown in some subtle ways 25 | collections: 26 | tooltips: 27 | output: false 28 | # collections are declared here. this renders the content in _tooltips and processes it, but doesn't output it as actual files in the output unless you change output to true 29 | defaults: 30 | - 31 | scope: 32 | path: "" 33 | type: "pages" 34 | values: 35 | layout: "page" 36 | search: true 37 | sidebar: home_sidebar 38 | topnav: topnav 39 | - 40 | scope: 41 | path: "" 42 | type: "tooltips" 43 | values: 44 | layout: "page" 45 | search: true 46 | tooltip: true 47 | - 48 | scope: 49 | path: "" 50 | type: "posts" 51 | values: 52 | layout: "post" 53 | search: true 54 | sidebar: home_sidebar 55 | topnav: topnav 56 | 57 | # these are defaults used for the frontmatter for these file types 58 | sidebars: 59 | - home_sidebar 60 | - mydoc_sidebar 61 | - other 62 | 63 | # needed for sitemap.xml file only 64 | # url: http://idratherbewriting.com 65 | # baseurl: /documentation-theme-jekyll 66 | 67 | 68 | github: [metadata] 69 | -------------------------------------------------------------------------------- /legacy/docs/_data/alerts.yml: -------------------------------------------------------------------------------- 1 | tip: '