From 6d2925984fb24810c4255de0d7c6eb9fe0028fa2 Mon Sep 17 00:00:00 2001 From: Ava Affine Date: Wed, 10 Jul 2024 13:22:28 -0700 Subject: [PATCH] Big project dir refactor * split into multi member workspace in preparation for a no_std core * env and posix stuff neatly crammed into a seperate shell project * some pokes at interactive-devel.f * updated ci * removed 'l' shortcut for 'load' and update docs * remove out of date readme content * updated tests * more sensible cond implementation and extra tests * substr stdlib function with tests Signed-off-by: Ava Affine --- .cargo/config.toml | 2 + .gitlab-ci.yml | 23 ++-- Cargo.toml | 31 +---- Readme.org | 44 +------ Shell.org | 26 ++-- core/Cargo.toml | 17 +++ {src => core/src}/error.rs | 0 {src => core/src}/eval.rs | 0 {src => core/src}/lex.rs | 37 +++--- {src => core/src}/lib.rs | 29 +---- {src => core/src}/segment.rs | 5 +- core/src/stl.rs | 41 ++++++ {src => core/src}/stl/append.rs | 0 {src => core/src}/stl/boolean.rs | 0 {src => core/src}/stl/control.rs | 0 {src => core/src}/stl/decl.rs | 110 ++++------------ {src => core/src}/stl/file.rs | 0 {src => core/src}/stl/math.rs | 0 {src => core/src}/stl/strings.rs | 92 +++++++++++++- {src => core/src}/sym.rs | 10 +- {tests => core/tests}/test_eval.rs | 14 +- {tests => core/tests}/test_func.rs | 4 +- {tests => core/tests}/test_lex.rs | 20 +-- {tests => core/tests}/test_lib_append.rs | 39 +++--- {tests => core/tests}/test_lib_bools.rs | 43 ++----- {tests => core/tests}/test_lib_control.rs | 69 ++++------ {tests => core/tests}/test_lib_decl.rs | 69 ++++------ {tests => core/tests}/test_lib_file.rs | 18 +-- {tests => core/tests}/test_lib_math.rs | 77 +++-------- {tests => core/tests}/test_lib_str.rs | 148 +++++++++++++++++----- shell/Cargo.toml | 26 ++++ src/bin/flesh.rs => shell/src/main.rs | 58 +++++---- {src/stl => shell/src}/posix.rs | 134 ++++++++++++++++---- {src => shell/src}/run.rs | 9 +- {src => shell/src}/stl.rs | 89 ++++++------- shell/src/store.rs | 53 ++++++++ shell/src/window.rs | 110 ++++++++++++++++ snippets/avas-laptop-prompt.f | 24 ++-- snippets/genbind.f | 2 +- snippets/interactive-devel-tests.f | 20 +++ snippets/interactive-devel.f | 24 +++- snippets/userlib-tests.f | 45 ++++--- snippets/userlib.f | 81 ++++++------ tests/test_lib_posix.rs | 103 --------------- 44 files changed, 967 insertions(+), 779 deletions(-) create mode 100644 .cargo/config.toml create mode 100644 core/Cargo.toml rename {src => core/src}/error.rs (100%) rename {src => core/src}/eval.rs (100%) rename {src => core/src}/lex.rs (90%) rename {src => core/src}/lib.rs (61%) rename {src => core/src}/segment.rs (98%) create mode 100644 core/src/stl.rs rename {src => core/src}/stl/append.rs (100%) rename {src => core/src}/stl/boolean.rs (100%) rename {src => core/src}/stl/control.rs (100%) rename {src => core/src}/stl/decl.rs (87%) rename {src => core/src}/stl/file.rs (100%) rename {src => core/src}/stl/math.rs (100%) rename {src => core/src}/stl/strings.rs (76%) rename {src => core/src}/sym.rs (98%) rename {tests => core/tests}/test_eval.rs (89%) rename {tests => core/tests}/test_func.rs (99%) rename {tests => core/tests}/test_lex.rs (87%) rename {tests => core/tests}/test_lib_append.rs (89%) rename {tests => core/tests}/test_lib_bools.rs (87%) rename {tests => core/tests}/test_lib_control.rs (78%) rename {tests => core/tests}/test_lib_decl.rs (82%) rename {tests => core/tests}/test_lib_file.rs (78%) rename {tests => core/tests}/test_lib_math.rs (88%) rename {tests => core/tests}/test_lib_str.rs (57%) create mode 100644 shell/Cargo.toml rename src/bin/flesh.rs => shell/src/main.rs (96%) rename {src/stl => shell/src}/posix.rs (92%) rename {src => shell/src}/run.rs (95%) rename {src => shell/src}/stl.rs (89%) create mode 100644 shell/src/store.rs create mode 100644 shell/src/window.rs create mode 100644 snippets/interactive-devel-tests.f delete mode 100644 tests/test_lib_posix.rs diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..bf2c7be --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[env] +POSIX_LOAD_NAME = "load" \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6a193d8..2af54da 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,25 +6,30 @@ stages: - test - release -compile-with-posix-features: +compile-shell-with-posix-features: stage: build script: - - cargo build + - cargo build -p flesh-shell -F posix -compile-without-posix-features: +compile-shell-without-posix-features: stage: build script: - - cargo build --no-default-features + - cargo build -p flesh-shell --no-default-features -compile-implicit-load: +compile-core: stage: build script: - - cargo build -F implicit-load + - cargo build -p flesh-core -unit-tests: +unit-test-shell: stage: test script: - - cargo test + - cargo test -p flesh-shell + +unit-test-core: + stage: test + script: + - cargo test -p flesh-core userlib-tests: stage: test @@ -34,7 +39,7 @@ userlib-tests: prepare-release: stage: release script: - - cargo build -F implicit-load --release + - cargo build --release - | tar -czf flesh-$CI_COMMIT_TAG.tar.gz \ --xform='s,target/release/,,' \ diff --git a/Cargo.toml b/Cargo.toml index ec592cd..bf5c65e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,25 +1,6 @@ -[package] -name = "flesh" -version = "0.4.0" -authors = ["Ava "] -edition = "2021" - -[dependencies] -# used in config (src/run.rs) -dirs = "3.0" -# these two are used in src/bin/relish.rs to manage a prompt -nu-ansi-term = "0.47.0" -reedline = "0.17.0" -# used by main shell to update console dimensions -termion = "2.0.1" -# these two used in posix shell layer (src/stl/posix.rs) -nix = { version = "0.26.2", optional = true } -libc = { version = "0.2.144", optional = true } -# this one provides a global constant lookup table for simple -# string escaping in the lexer -phf = { version = "0.11", default-features = false, features = ["macros"] } - -[features] -default = ["posix"] -posix = ["dep:nix", "dep:libc"] -implicit-load = ["posix"] +[workspace] +resolver = "2" +members = [ + "shell", + "core" +] \ No newline at end of file diff --git a/Readme.org b/Readme.org index 52648c3..0b8f20b 100644 --- a/Readme.org +++ b/Readme.org @@ -92,13 +92,13 @@ For installation, consider adding the following to your ~\~/.emacs~: * Compilation Compiling Flesh is as simple as kicking off a build with Cargo. #+BEGIN_EXAMPLE sh - cargo build + cargo build -p flesh-shell #+END_EXAMPLE This will produce a binary at [[file:target/debug/flesh][target/debug/flesh]] which includes all of the features flesh has to offer. This provides a REPL with a full interactive shell that also can manage variables in the Unix environment. It is possible to compile a smaller REPL that does not interact with environment variables and does not offer any shell features. Simply pass the ~--no-default-features~ flag to cargo: #+BEGIN_EXAMPLE sh - cargo build --no-default-features + cargo build -p flesh-shell --no-default-features #+END_EXAMPLE In order to run Flesh it is recommended to run the resulting binary at [[file:target/debug/flesh][target/debug/flesh]]. @@ -114,46 +114,6 @@ Userlib tests can be triggered by loading the userlib as well as its test suite cargo run snippets/userlib.f snippets/userlib-tests.f #+END_EXAMPLE -* The codebase -** The [[file:tests][tests directory]] -Start here if you are new. -*** [[file:tests/test_eval.rs][Eval tests]] -These are particularly easy to read and write tests. -They primarily cover execution paths in the evaluation process. -*** [[file:tests/test_func.rs][Func tests]] -These tests extend the eval tests to cover the co-recursive nature between eval and func calls. -*** [[file:tests/test_lex.rs][Lex tests]] -These tests verify the handling of syntax. -*** Lib tests: (tests/test_lib*) -These tests are unique per stdlib module and work to prove the functionality of builtin functions in the language. -** [[file:src][Source directory]] -This directory contains all of the user facing code in flesh. -Just a few entries of note: -*** [[file:src/segment.rs][Segment module]] -This file lays out the data structures that the interpreter operates on. -Representation of code trees, traversals, and type annotations all live here. -It provides the core representation of data used in Flesh, and could provide supplementary refrence material for users seeking a deeper understanding of how their code is stored in memory. -*** [[file:src/lib.rs][lib.rs]] -This defines a library that can be included to provide an interpreter interface within any Rust project. -The components defined here can certainly be used to support language development for other LISP (or non LISP) langauges. An external project may use or not use any number of these components. -*** [[file:src/sym.rs][Symbol module]] -This file contains all code related to symbol expansion and function calling. -The types defined in this file include SymTable, Args, Symbol, and more. -Code to call Lambda functions also exists in here. -*** [[file:src/run.rs][Run module]] -This file contains functions which load and run the configuration file script. -For more information see the configuraiton section above in this Readme. -*** [[file:src/stl.rs][Standard library module]] -This defines the ~static_stdlib~ function and the ~dynamic_stdlib~ function. -The ~static_stdlib~ function loads all symbols in the standard library which do not need further configuration into the symbol table. -The ~dynamic_stdlib~ function loads all symbols in the standard library which *do* need configuration into the symbol table. -The ~dynamic_stdlib~ function uses variables saved in the symbol table to configure the functions and variables it loads. -This module also contains definitions for the default configuration values. -Any new addition to the stdlib must make its way here to be included in the main shell (and any other shell using the included stdlib functions). -You may choose to override these functions if you would like to include your own special functions in your own special interpreter, or if you would like to pare down the stdlib to a lighter subet of what it is. -You can view the code for standard library functions in [[file:src/stl/][the standard library directory]]. -*** [[file:src/bin/][binary directory]] -This contains any executable target of this project. Notably [[file:src/bin/flesh.rs][the main shell]]. * Current Status / TODO list Note: this section will not show the status of each item unless you are viewing it with a proper orgmode viewer. Note: this section only tracks the state of incomplete TODO items. Having everything on here would be cluttered. diff --git a/Shell.org b/Shell.org index 303d90f..799477e 100644 --- a/Shell.org +++ b/Shell.org @@ -10,24 +10,24 @@ This document outlines the ways that Flesh can be used as a shell for daily admi For the most common uses (executing shell commands) a function is provided to find and load binaries from entries in the ~PATH~ variable. This function may be called either with ~load~ or ~l~. #+BEGIN_SRC lisp (load htop) ;; executes the htop binary, if htop is found on the users PATH - (l emacs) ;; executes the emacs binary, if emacs is found on the users PATH + (load emacs) ;; executes the emacs binary, if emacs is found on the users PATH #+END_SRC The load command takes an infinite number of arguments and uses the following rules to construct a shell command from them: + symbols that are not set are taken as strings #+BEGIN_SRC lisp - (l emacs -nw) ;; 'emacs' and '-nw' not defined + (load emacs -nw) ;; 'emacs' and '-nw' not defined #+END_SRC + symbols that are set are replaced by their values #+BEGIN_SRC lisp - (l ls -la HOME) + (load ls -la HOME) (let ((ping-count 4) (domain "sunnypup.io")) - (l ping -c ping-count domain) + (load ping -c ping-count domain) #+END_SRC + nested forms are evaluated #+BEGIN_SRC lisp - (l cat (concat HOME "/notes.txt")) + (load cat (concat HOME "/notes.txt")) #+END_SRC Shell command evaluation rules apply to the following functions: @@ -53,9 +53,9 @@ In a shell such as Bash or Zsh, commands can be chained with the ~&&~ operator: In these chains, if one command fails the next one(s) are not run. Colloquially, the command short-circuits. A similar construct is offered in Flesh called ~circuit~. Circuit will evaluate one or more forms (all expected to evaluate to either an integer (shell command) or a boolean (more general form). If a form returns false (or non-zero) no other forms are evaluated. The printed error message will identify where in the sequence evaluation was halted. #+BEGIN_EXAMPLE lisp (circuit - (l apt update) ;; if this fails, no upgrade is made - (l apt upgrade) ;; if this fails, "Success!" is not printed - (l echo "Success!")) + (load apt update) ;; if this fails, no upgrade is made + (load apt upgrade) ;; if this fails, "Success!" is not printed + (load echo "Success!")) #+END_EXAMPLE *** Command piping @@ -129,7 +129,7 @@ To launch a background process use the ~bg~ function: To get all jobs in your shell use the system ~ps~ binary: #+BEGIN_EXAMPLE lisp -(l ps) +(load ps) #+END_EXAMPLE To foreground a background process use the ~fg~ function: @@ -156,7 +156,7 @@ Daily Flesh users will long for first class shell commands that are accounted fo A simple solution: #+BEGIN_EXAMPLE lisp (def lis 'shortcut for ls -la' - (lambda (dir) (l ls -la dir))) + (lambda (dir) (load ls -la dir))) (lis HOME) #+END_EXAMPLE @@ -196,8 +196,4 @@ With the ~implicit load~ feature any call to an undefined function will trigger ...... (redacted directory list) ..... #+END_EXAMPLE -Implicit load can be used by building flesh with the following command: - -#+BEGIN_EXAMPLE -cargo build -F implicit-load -#+END_EXAMPLE +Implicit load is now enabled by default on any 1.0 build of flesh. diff --git a/core/Cargo.toml b/core/Cargo.toml new file mode 100644 index 0000000..81e3f4a --- /dev/null +++ b/core/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "flesh-core" +version = "0.4.0" +authors = ["Ava "] +edition = "2021" + +[dependencies] +# this one provides a global constant lookup table for simple +# string escaping in the lexer +phf = { version = "0.11", default-features = false, features = ["macros"] } + +[lib] +name = "flesh" + +# only turn this on if you set POSIX_LOAD_NAME at build time +[features] +implicit-load = [] \ No newline at end of file diff --git a/src/error.rs b/core/src/error.rs similarity index 100% rename from src/error.rs rename to core/src/error.rs diff --git a/src/eval.rs b/core/src/eval.rs similarity index 100% rename from src/eval.rs rename to core/src/eval.rs diff --git a/src/lex.rs b/core/src/lex.rs similarity index 90% rename from src/lex.rs rename to core/src/lex.rs index 3c057c2..4623256 100644 --- a/src/lex.rs +++ b/core/src/lex.rs @@ -63,13 +63,13 @@ fn process(document: &String) -> Result, String> { } /* State variables - * TODO: describe all of them */ let mut is_str = false; let mut ign = false; let mut token = String::new(); let mut delim_stack = Vec::new(); let mut ref_stack = vec![]; + let mut cursor = 0; /* Iterate over document * Manage currently sought delimiter @@ -78,6 +78,8 @@ fn process(document: &String) -> Result, String> { let mut needs_alloc = false; let mut alloc_list = false; let delim: char; + cursor += 1; + if let Some(d) = delim_stack.last() { delim = *d; @@ -116,7 +118,8 @@ fn process(document: &String) -> Result, String> { } // try to generalize all whitespace if !needs_alloc && char::is_whitespace(c) && !is_str { - // dont make empty tokens just because the document has consecutive whitespace + // dont make empty tokens just because the document + // has consecutive whitespace if token.is_empty() { continue; } @@ -126,30 +129,24 @@ fn process(document: &String) -> Result, String> { if !needs_alloc { match c { // add a new Seg reference to the stack - '(' => { - if is_str { - token.push(c); - continue; - } - - if !token.is_empty() { - return Err("list started in middle of another token".to_string()); - } - + '(' if !is_str && token.is_empty() => { + let mut s = Seg::new(); ref_stack.push(Seg::new()); delim_stack.push(')'); } + // specific error case + '(' if !is_str && !token.is_empty() => { + return Err( + format!("list started in middle of another token: {}", token) + ) + } // begin parsing a string - '"' | '\'' | '`' if !is_str => { + '"' | '`' if !is_str => { is_str = true; delim_stack.push(c); } // eat the whole line - '#' | ';' => { - if is_str { - token.push(c); - continue; - } + '#' | ';' if !is_str => { ign = true; delim_stack.push('\n'); } @@ -176,6 +173,7 @@ fn process(document: &String) -> Result, String> { return_singlet = true; Seg::new() }); + let obj; if is_str { obj = Box::from(Ctr::String(token)); @@ -194,7 +192,7 @@ fn process(document: &String) -> Result, String> { } else if let Some(s) = tok_is_symbol(&token) { obj = Box::from(Ctr::Symbol(s)); } else { - return Err(format!("Unparsable token: {}", token)); + return Err(format!("Unparsable token \"{}\" at char {}", token, cursor)); } token = String::new(); @@ -202,6 +200,7 @@ fn process(document: &String) -> Result, String> { } if alloc_list || return_singlet { + // return if we have finished the document if ref_stack.is_empty() { return Ok(Box::new(current_seg)); diff --git a/src/lib.rs b/core/src/lib.rs similarity index 61% rename from src/lib.rs rename to core/src/lib.rs index 579373c..6edb8dc 100644 --- a/src/lib.rs +++ b/core/src/lib.rs @@ -15,7 +15,8 @@ * along with this program. If not, see . */ -mod run; +//#![no_std] + mod eval; mod lex; mod segment; @@ -24,7 +25,6 @@ mod sym; mod error; pub mod ast { - pub use crate::run::run; pub use crate::eval::eval; pub use crate::lex::lex; pub use crate::segment::{Ctr, Seg, Type}; @@ -34,28 +34,9 @@ pub mod ast { pub mod stdlib { pub use crate::stl::{ - dynamic_stdlib, static_stdlib, - load_defaults, load_environment, - CONSOLE_XDIM_VNAME, - CONSOLE_YDIM_VNAME, - POSIX_CFG_VNAME, - MODENV_CFG_VNAME, - L_PROMPT_VNAME, - R_PROMPT_VNAME, - PROMPT_DELIM_VNAME, + static_stdlib, CFG_FILE_VNAME, - FLESH_DEFAULT_CONS_HEIGHT, - FLESH_DEFAULT_CONS_WIDTH, + decl::STORE_DOCSTRING, + decl::store_callback, }; } - -pub mod aux { - #[cfg(feature="posix")] - pub use crate::stl::posix::args_from_ast; - #[cfg(feature="posix")] - pub use crate::stl::posix::ShellState; - #[cfg(feature="posix")] - pub use crate::stl::posix::check_jobs; - #[cfg(feature="posix")] - pub use crate::stl::posix::POSIX_LOAD_NAME; -} diff --git a/src/segment.rs b/core/src/segment.rs similarity index 98% rename from src/segment.rs rename to core/src/segment.rs index f46db4e..3aea7c8 100644 --- a/src/segment.rs +++ b/core/src/segment.rs @@ -92,9 +92,6 @@ impl Ctr { impl Seg { /* recurs over tree assumed to be list in standard form * appends object to end of list - * - * TODO: figure out how not to call CLONE on a CTR via obj arg - * TODO: return result */ pub fn append(&mut self, obj: Box) { if let Ctr::None = &*(self.car) { @@ -254,7 +251,7 @@ impl fmt::Display for Ctr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Ctr::Symbol(s) => write!(f, "{}", s), - Ctr::String(s) => write!(f, "\'{}\'", s), + Ctr::String(s) => write!(f, "\"{}\"", s), Ctr::Integer(s) => write!(f, "{}", s), Ctr::Float(s) => write!(f, "{}", s), Ctr::Bool(s) => { diff --git a/core/src/stl.rs b/core/src/stl.rs new file mode 100644 index 0000000..c67fdf9 --- /dev/null +++ b/core/src/stl.rs @@ -0,0 +1,41 @@ +/* Flesh: Flexible Shell + * Copyright (C) 2021 Ava Affine + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +use crate::sym::SymTable; + +pub mod append; +pub mod boolean; +pub mod control; +pub mod decl; +pub mod math; +pub mod strings; +pub mod file; + +pub const CFG_FILE_VNAME: &str = "FLESH_CFG_FILE"; + +/// static_stdlib +/// inserts all stdlib functions that can be inserted without +/// any kind of further configuration data into a symtable +pub fn static_stdlib(syms: &mut SymTable) { + append::add_list_lib(syms); + strings::add_string_lib(syms); + decl::add_decl_lib_static(syms); + control::add_control_lib(syms); + boolean::add_bool_lib(syms); + math::add_math_lib(syms); + file::add_file_lib(syms); +} diff --git a/src/stl/append.rs b/core/src/stl/append.rs similarity index 100% rename from src/stl/append.rs rename to core/src/stl/append.rs diff --git a/src/stl/boolean.rs b/core/src/stl/boolean.rs similarity index 100% rename from src/stl/boolean.rs rename to core/src/stl/boolean.rs diff --git a/src/stl/control.rs b/core/src/stl/control.rs similarity index 100% rename from src/stl/control.rs rename to core/src/stl/control.rs diff --git a/src/stl/decl.rs b/core/src/stl/decl.rs similarity index 87% rename from src/stl/decl.rs rename to core/src/stl/decl.rs index 8478306..26c020c 100644 --- a/src/stl/decl.rs +++ b/core/src/stl/decl.rs @@ -18,9 +18,7 @@ use crate::eval::eval; use crate::error::{Traceback, start_trace}; use crate::segment::{Ctr, Seg, Type}; -use crate::stdlib::{CONSOLE_XDIM_VNAME, FLESH_DEFAULT_CONS_WIDTH}; use crate::sym::{SymTable, Symbol, UserFn, ValueType, Args}; -use std::env; use std::rc::Rc; const QUOTE_DOCSTRING: &str = "takes a single unevaluated tree and returns it as it is: unevaluated."; @@ -132,20 +130,6 @@ fn isset_callback(ast: &Seg, syms: &mut SymTable) -> Result { const ENV_DOCSTRING: &str = "takes no arguments prints out all available symbols and their associated values"; fn env_callback(_ast: &Seg, syms: &mut SymTable) -> Result { - // get width of current output - let xdim: i128; - if let Ctr::Integer(dim) = *syms - .call_symbol(&CONSOLE_XDIM_VNAME.to_string(), &Seg::new(), true) - .unwrap_or_else(|_: Traceback| Box::new(Ctr::None)) { - xdim = dim; - } else { - println!("{} contains non integer value, defaulting to {}", - CONSOLE_XDIM_VNAME, FLESH_DEFAULT_CONS_WIDTH); - xdim = FLESH_DEFAULT_CONS_WIDTH as i128; - } - - let mut v_col_len = 0; - let mut f_col_len = 0; let mut functions = vec![]; let mut variables = vec![]; for (name, val) in syms.iter() { @@ -156,51 +140,19 @@ fn env_callback(_ast: &Seg, syms: &mut SymTable) -> Result { _ => format!("{}: {}", name, val.value), }; - if token.len() > v_col_len && token.len() < xdim as usize { - v_col_len = token.len(); - } - variables.push(token); } else { - if f_col_len < name.len() && name.len() < xdim as usize { - f_col_len = name.len(); - } functions.push(name.clone()); } } - let mut n_v_cols = xdim / v_col_len as i128; - // now decrement to make sure theres room for two spaces of padding - while n_v_cols > 1 && xdim % (v_col_len as i128) < (2 * n_v_cols) { - n_v_cols -= 1; - } - // again for functions - let mut n_f_cols = xdim / f_col_len as i128; - while n_f_cols > 1 && xdim & (f_col_len as i128) < (2 * n_f_cols) { - n_f_cols -= 1; - } - - let mut col_iter = 0; println!("VARIABLES:"); for var in variables { - print!("{:v_col_len$}", var); - col_iter += 1; - if col_iter % n_v_cols == 0 { - println!(); - } else { - print!(" "); - } + println!("{}", var) } println!("\nFUNCTIONS:"); - col_iter = 0; for func in functions { - print!("{:f_col_len$}", func); - col_iter += 1; - if col_iter % n_f_cols == 0 { - println!(); - } else { - print!(" "); - } + println!("{}", func); } Ok(Ctr::None) } @@ -307,7 +259,7 @@ fn setdoc_callback(ast: &Seg, syms: &mut SymTable) -> Result { } } -const STORE_DOCSTRING: &str = "allows user to define functions and variables. +pub const STORE_DOCSTRING: &str = "allows user to define functions and variables. A call may take one of three forms: 1. variable declaration: Takes a name, doc string, and a value. @@ -321,8 +273,10 @@ const STORE_DOCSTRING: &str = "allows user to define functions and variables. (def useless-var) Additionally, passing a tree as a name will trigger def to evaluate the tree and try to derive -a value from it. If it does not return a "; -fn store_callback(ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result { +a value from it. If it does not return a String or a Symbol this will result in a failure. + +The name of the symbol operated on is returned (as a string)."; +pub fn store_callback(ast: &Seg, syms: &mut SymTable) -> Result { let is_var = ast.len() == 3; let name: String; let docs: String; @@ -350,11 +304,8 @@ fn store_callback(ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result 4 { return Err(start_trace(("def", "expected 3 or 4 inputs").into())) } @@ -426,20 +377,7 @@ fn store_callback(ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result {}, - Type::Seg => {}, - _ => { - let mut s = var_val.to_string(); - if let Ctr::String(tok) = var_val { - s = tok; - } - env::set_var(name.clone(), s); - } - } - } - return Ok(Ctr::None) + return Ok(Ctr::String(name)) } let mut arg_list = vec![]; @@ -468,7 +406,7 @@ fn store_callback(ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result Result { - store_callback(ast, syms, env) + store_callback(ast, syms) }, )), ..Default::default() diff --git a/src/stl/file.rs b/core/src/stl/file.rs similarity index 100% rename from src/stl/file.rs rename to core/src/stl/file.rs diff --git a/src/stl/math.rs b/core/src/stl/math.rs similarity index 100% rename from src/stl/math.rs rename to core/src/stl/math.rs diff --git a/src/stl/strings.rs b/core/src/stl/strings.rs similarity index 76% rename from src/stl/strings.rs rename to core/src/stl/strings.rs index b0fb109..fc670fe 100644 --- a/src/stl/strings.rs +++ b/core/src/stl/strings.rs @@ -93,7 +93,9 @@ fn strcast_callback(ast: &Seg, _syms: &mut SymTable) -> Result { } const SUBSTR_DOCSTRING: &str = - "Takes two strings. Returns true if string1 contains at least one instance of string2"; + "Takes a string and two integers (arg1, arg2 and arg3 respectively). +Returns the substring of arg1 starting at arg2 and ending at arg3. +Returns error if arg2 or arg3 are negative, and if arg3 is larger than the length of arg1."; fn substr_callback(ast: &Seg, _syms: &mut SymTable) -> Result { let parent_str: String; if let Ctr::String(ref s) = *ast.car { @@ -104,13 +106,84 @@ fn substr_callback(ast: &Seg, _syms: &mut SymTable) -> Result { .into())) } + let second_arg_obj: &Ctr; + let third_arg_obj: &Ctr; + let start: usize; + if let Ctr::Seg(ref s) = *ast.cdr { + second_arg_obj = &*s.car; + third_arg_obj = &*s.cdr; + } else { + return Err(start_trace( + ("substr", "expected three inputs") + .into())) + } + + if let Ctr::Integer(i) = &*second_arg_obj { + if i < &0 { + return Err(start_trace(("substr", "start index cannot be negative").into())) + } + start = i.clone() as usize; + } else { + return Err(start_trace( + ("substr", "expected second input to be an integer") + .into())) + } + + if start > parent_str.len() { + return Err(start_trace(("substr", "start index larger than source string").into())) + } + + let end: usize; + let third_arg_inner: &Ctr; + if let Ctr::Seg(ref s) = *third_arg_obj { + third_arg_inner = &*s.car; + } else { + return Err(start_trace( + ("substr", "expected three inputs") + .into())) + } + + if let Ctr::Integer(i) = &*third_arg_inner { + if i < &0 { + return Err(start_trace(("substr", "end index cannot be negative").into())) + } + end = i.clone() as usize; + } else { + return Err(start_trace( + ("substr", "expected third input to be an integer") + .into())) + } + + if end > parent_str.len() { + return Err(start_trace(("substr", "end index larger than source string").into())) + } + + if end <= start { + return Err(start_trace(("substr", "end index must be larger than start index").into())) + } + + Ok(Ctr::String(parent_str[start..end].to_string())) +} + +const IS_SUBSTR_DOCSTRING: &str = + "Takes two strings. Returns true if string1 contains at least one instance of string2"; +fn is_substr_callback(ast: &Seg, _syms: &mut SymTable) -> Result { + let parent_str: String; + if let Ctr::String(ref s) = *ast.car { + parent_str = s.to_string(); + } else { + return Err(start_trace( + ("substr?", "expected first input to be a string") + .into())) + } + let second_arg_obj: &Ctr; let child_str: String; if let Ctr::Seg(ref s) = *ast.cdr { second_arg_obj = &*s.car; } else { return Err(start_trace( - ("substr", "expected two inputs") + ("substr?", "expected two inputs") .into())) } @@ -118,7 +191,7 @@ fn substr_callback(ast: &Seg, _syms: &mut SymTable) -> Result { child_str = s.clone(); } else { return Err(start_trace( - ("substr", "expected second input to be a string") + ("substr?", "expected second input to be a string") .into())) } @@ -212,6 +285,19 @@ pub fn add_string_lib(syms: &mut SymTable) { name: String::from("substr?"), args: Args::Strict(vec![Type::String, Type::String]), conditional_branches: false, + docs: IS_SUBSTR_DOCSTRING.to_string(), + value: ValueType::Internal(Rc::new(is_substr_callback)), + optimizable: true, + ..Default::default() + }, + ); + + syms.insert( + "substr".to_string(), + Symbol { + name: String::from("substr"), + args: Args::Strict(vec![Type::String, Type::Integer, Type::Integer]), + conditional_branches: false, docs: SUBSTR_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(substr_callback)), optimizable: true, diff --git a/src/sym.rs b/core/src/sym.rs similarity index 98% rename from src/sym.rs rename to core/src/sym.rs index 6a2d968..4c480c2 100644 --- a/src/sym.rs +++ b/core/src/sym.rs @@ -18,8 +18,6 @@ use crate::eval::eval; use crate::error::{Traceback, start_trace}; use crate::segment::{Ctr, Seg, Type}; -#[cfg(feature="implicit-load")] -use crate::stl::posix::POSIX_LOAD_NAME; use std::collections::HashMap; use std::fmt; use std::rc::Rc; @@ -146,9 +144,9 @@ impl SymTable { * assume a shell command is being run */ #[cfg(feature="implicit-load")] - None if call_func => match self.remove(&POSIX_LOAD_NAME.to_string()) { + None if call_func => match self.remove(&env!("POSIX_LOAD_NAME").to_string()) { Some(s) => { - name_token = String::from(POSIX_LOAD_NAME); + name_token = String::from(env!("POSIX_LOAD_NAME").to_string()); /* highly unfortunate circumstance * we must now rebuild the original ast * costs a whole clone of the args @@ -167,7 +165,9 @@ impl SymTable { }, None => return Err( Traceback::new() - .with_trace(("(implicit load)", "(load function not found)").into()) + .with_trace(( + &format!("(implicit load ({}))", name), + "(load function not found)").into()) ) }, diff --git a/tests/test_eval.rs b/core/tests/test_eval.rs similarity index 89% rename from tests/test_eval.rs rename to core/tests/test_eval.rs index 51be613..36cc32b 100644 --- a/tests/test_eval.rs +++ b/core/tests/test_eval.rs @@ -1,7 +1,7 @@ mod eval_tests { use flesh::ast::{eval, lex, SymTable}; use flesh::ast::{Args, Ctr, Seg, Symbol, UserFn, ValueType}; - use flesh::stdlib::{dynamic_stdlib, static_stdlib}; + use flesh::stdlib::static_stdlib; #[test] fn eval_simple() { @@ -23,8 +23,8 @@ mod eval_tests { #[test] fn eval_function_call() { - let test_doc = "('one' (echo 'unwrap_me'))".to_string(); - let output = "('one' 'unwrap_me')"; + let test_doc = "(\"one\" (echo \"unwrap_me\"))".to_string(); + let output = "(\"one\" \"unwrap_me\")"; let mut syms = SymTable::new(); let test_external_func: Symbol = Symbol { @@ -50,8 +50,8 @@ mod eval_tests { #[test] fn eval_embedded_func_calls() { - let test_doc = "('one' (echo (echo 'unwrap_me')))".to_string(); - let output = "('one' 'unwrap_me')"; + let test_doc = "(\"one\" (echo (echo \"unwrap_me\")))".to_string(); + let output = "(\"one\" \"unwrap_me\")"; let mut syms = SymTable::new(); let test_external_func: Symbol = Symbol { @@ -75,6 +75,7 @@ mod eval_tests { assert_eq!(reduced.to_string(), output); } + #[cfg(not(feature = "implicit-load"))] #[test] fn eval_bad_syms() { let test_doc = "(undefined)".to_string(); @@ -96,13 +97,12 @@ mod eval_tests { #[test] fn func_lambda_equivalency() { - let comparator = "(def apply 'applicator' (fn x) (fn x))"; + let comparator = "(def apply \"applicator\" (fn x) (fn x))"; let lh_doc = "(apply car (1 2 3))"; let rh_doc = "(apply (lambda (x) (car x)) (1 2 3))"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); eval(&lex(&comparator.to_string()).unwrap(), &mut syms).unwrap(); assert_eq!( diff --git a/tests/test_func.rs b/core/tests/test_func.rs similarity index 99% rename from tests/test_func.rs rename to core/tests/test_func.rs index 06ed4e1..cfd748f 100644 --- a/tests/test_func.rs +++ b/core/tests/test_func.rs @@ -91,7 +91,7 @@ mod func_tests { .call_symbol(&"echo_2".to_string(), &args, true) .unwrap() .to_string(), - "'test'".to_string() + "\"test\"".to_string() ); } @@ -140,7 +140,7 @@ mod func_tests { syms.call_symbol(&"test_outer".to_string(), &args, true) .unwrap() .to_string(), - "'test'".to_string() + "\"test\"".to_string() ); } diff --git a/tests/test_lex.rs b/core/tests/test_lex.rs similarity index 87% rename from tests/test_lex.rs rename to core/tests/test_lex.rs index 8166ec7..71d023e 100644 --- a/tests/test_lex.rs +++ b/core/tests/test_lex.rs @@ -3,44 +3,44 @@ mod lex_tests { #[test] fn test_lex_basic_pair() { - let document = String::from("(hello 'world')"); + let document = String::from("(hello \"world\")"); assert_eq!(lex(&document).unwrap().to_string(), document); } #[test] fn test_lex_basic_list() { - let document = String::from("(hello 'world' 1 2 3)"); + let document = String::from("(hello \"world\" 1 2 3)"); assert_eq!(lex(&document).unwrap().to_string(), document); } #[test] fn test_bad_symbol() { let document = String::from("(as@dd)"); - let output: &str = "Problem lexing document: \"Unparsable token: as@dd\""; + let output: &str = "Problem lexing document: \"Unparsable token \\\"as@dd\\\" at char 7\""; assert_eq!(lex(&document).err().unwrap().0.first().unwrap().message, output.to_string(),); } #[test] fn test_lex_complex_list() { - let document = String::from("(hello 'world' (1 2 (1 2 3)) 1 2 3)"); + let document = String::from("(hello \"world\" (1 2 (1 2 3)) 1 2 3)"); assert_eq!(lex(&document).unwrap().to_string(), document); } #[test] fn test_list_delim_in_str() { - let document = String::from("('(')"); + let document = String::from("(\"(\")"); assert_eq!(lex(&document).unwrap().to_string(), document); } #[test] fn test_comment_delim_in_str() { - let document = String::from("('#')"); + let document = String::from("(\"#\")"); assert_eq!(lex(&document).unwrap().to_string(), document); } #[test] fn test_empty_string() { - let document = String::from("('')"); + let document = String::from("(\"\")"); assert_eq!(lex(&document).unwrap().to_string(), document); } @@ -75,8 +75,8 @@ mod lex_tests { #[test] fn test_postline_comment_1() { let document = - String::from("#!/bin/flesh\n((one two)# another doc comment\n('three' four))"); - let output: &str = "((one two) ('three' four))"; + String::from("#!/bin/flesh\n((one two)# another doc comment\n(\"three\" four))"); + let output: &str = "((one two) (\"three\" four))"; assert_eq!(lex(&document).unwrap().to_string(), output.to_string(),); } @@ -105,7 +105,7 @@ mod lex_tests { #[test] fn test_bad_token_list() { let document = String::from("(one t(wo)"); - let output: &str = "Problem lexing document: \"list started in middle of another token\""; + let output: &str = "Problem lexing document: \"list started in middle of another token: t\""; assert_eq!(lex(&document).err().unwrap().0.first().unwrap().message, output.to_string(),); } } diff --git a/tests/test_lib_append.rs b/core/tests/test_lib_append.rs similarity index 89% rename from tests/test_lib_append.rs rename to core/tests/test_lib_append.rs index b9db2a2..e82471e 100644 --- a/tests/test_lib_append.rs +++ b/core/tests/test_lib_append.rs @@ -1,6 +1,6 @@ mod append_lib_tests { use flesh::ast::{eval, lex, SymTable}; - use flesh::stdlib::{dynamic_stdlib, static_stdlib}; + use flesh::stdlib::static_stdlib; #[test] fn test_cons_to_empty_list() { @@ -18,8 +18,8 @@ mod append_lib_tests { #[test] fn test_multi_cons_to_empty_list() { - let document = "(cons () 1 'two' 3.4)"; - let result = "(1 'two' 3.4)"; + let document = "(cons () 1 \"two\" 3.4)"; + let result = "(1 \"two\" 3.4)"; let mut syms = SymTable::new(); static_stdlib(&mut syms); @@ -63,8 +63,8 @@ mod append_lib_tests { #[test] fn test_cons_no_list() { - let document = "(cons 'test' 1 2 3)"; - let result = "('test' 1 2 3)"; + let document = "(cons \"test\" 1 2 3)"; + let result = "(\"test\" 1 2 3)"; let mut syms = SymTable::new(); static_stdlib(&mut syms); @@ -176,7 +176,7 @@ mod append_lib_tests { #[test] fn test_pop() { - let document = "(def test '' (pop (1 2 3)))"; + let document = "(def test \"\" (pop (1 2 3)))"; let check1 = "(car test)"; let result1 = "1"; let check2 = "(cdr test)"; @@ -184,7 +184,7 @@ mod append_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); + eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap(); let ch1 = lex(&check1.to_string()).unwrap(); let ch2 = lex(&check2.to_string()).unwrap(); @@ -202,7 +202,7 @@ mod append_lib_tests { #[test] fn test_pop_mono() { - let document = "(def test '' (pop (1)))"; + let document = "(def test \"\" (pop (1)))"; let check1 = "(car test)"; let result1 = "1"; let check2 = "(cdr test)"; @@ -210,7 +210,7 @@ mod append_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); + eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap(); let ch1 = lex(&check1.to_string()).unwrap(); let ch2 = lex(&check2.to_string()).unwrap(); @@ -228,7 +228,7 @@ mod append_lib_tests { #[test] fn test_dq() { - let document = "(def test '' (dq (1 2 3)))"; + let document = "(def test \"\" (dq (1 2 3)))"; let check1 = "(car test)"; let result1 = "3"; let check2 = "(cdr test)"; @@ -236,7 +236,7 @@ mod append_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); + eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap(); let ch1 = lex(&check1.to_string()).unwrap(); let ch2 = lex(&check2.to_string()).unwrap(); @@ -254,7 +254,7 @@ mod append_lib_tests { #[test] fn test_dq_mono() { - let document = "(def test '' (dq (1)))"; + let document = "(def test \"\" (dq (1)))"; let check1 = "(car test)"; let result1 = "1"; let check2 = "(cdr test)"; @@ -262,7 +262,7 @@ mod append_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); + eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap(); let ch1 = lex(&check1.to_string()).unwrap(); let ch2 = lex(&check2.to_string()).unwrap(); @@ -280,12 +280,11 @@ mod append_lib_tests { #[test] fn test_reverse() { - let document = "(reverse ('test' 1 2 3))"; - let result = "(3 2 1 'test')"; + let document = "(reverse (\"test\" 1 2 3))"; + let result = "(3 2 1 \"test\")"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) @@ -297,12 +296,11 @@ mod append_lib_tests { #[test] fn test_reverse_mono() { - let document = "(reverse ('test'))"; - let result = "('test')"; + let document = "(reverse (\"test\"))"; + let result = "(\"test\")"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) @@ -319,7 +317,6 @@ mod append_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) @@ -336,7 +333,6 @@ mod append_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) @@ -353,7 +349,6 @@ mod append_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) diff --git a/tests/test_lib_bools.rs b/core/tests/test_lib_bools.rs similarity index 87% rename from tests/test_lib_bools.rs rename to core/tests/test_lib_bools.rs index f20d479..c55a4d0 100644 --- a/tests/test_lib_bools.rs +++ b/core/tests/test_lib_bools.rs @@ -1,6 +1,6 @@ mod bool_lib_tests { use flesh::ast::{eval, lex, Ctr, SymTable}; - use flesh::stdlib::{dynamic_stdlib, static_stdlib}; + use flesh::stdlib::static_stdlib; #[test] fn test_and_true_chain() { @@ -8,7 +8,6 @@ mod bool_lib_tests { let result = "true"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -23,7 +22,6 @@ mod bool_lib_tests { let result = "false"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -38,7 +36,6 @@ mod bool_lib_tests { let result = "false"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -53,7 +50,6 @@ mod bool_lib_tests { let result = "true"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -68,7 +64,6 @@ mod bool_lib_tests { let result = "true"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -83,7 +78,6 @@ mod bool_lib_tests { let result = "false"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -98,7 +92,6 @@ mod bool_lib_tests { let result = "false"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -109,13 +102,12 @@ mod bool_lib_tests { #[test] fn test_toggle_a_bool() { - let document = "(def tester '' true)"; + let document = "(def tester \"\" true)"; let change = "(toggle tester)"; let check = "(tester)"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); let doc_tree = lex(&document.to_string()).unwrap(); let change_tree = lex(&change.to_string()).unwrap(); @@ -148,13 +140,12 @@ mod bool_lib_tests { #[test] fn test_toggle_errors_dont_lose_vars() { - let document = "(def tester '' 'oops')"; + let document = "(def tester \"\" \"oops\")"; let change = "(toggle tester)"; let check = "(tester)"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); let doc_tree = lex(&document.to_string()).unwrap(); let change_tree = lex(&change.to_string()).unwrap(); @@ -168,7 +159,7 @@ mod bool_lib_tests { ); let intermediate = *eval(&check_tree, &mut syms).unwrap(); if let Ctr::Seg(ref s) = intermediate { - assert_eq!(s.to_string(), "('oops')".to_string()); + assert_eq!(s.to_string(), "(\"oops\")".to_string()); } else { eprintln!("did not expect: {}", intermediate); panic!() @@ -181,13 +172,12 @@ mod bool_lib_tests { #[test] fn test_toggle_errors_dont_lose_funcs() { - let document = "(def tester '' (oops) oops)"; + let document = "(def tester \"\" (oops) oops)"; let change = "(toggle tester)"; - let check = "(tester '1')"; + let check = "(tester \"1\")"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); let doc_tree = lex(&document.to_string()).unwrap(); let change_tree = lex(&change.to_string()).unwrap(); @@ -217,7 +207,6 @@ mod bool_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); if let Ctr::Bool(b) = *eval(&test, &mut syms).unwrap() { assert!(b) @@ -233,7 +222,6 @@ mod bool_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); if let Ctr::Bool(b) = *eval(&test, &mut syms).unwrap() { assert!(!b) @@ -249,7 +237,6 @@ mod bool_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); if let Ctr::Bool(b) = *eval(&test, &mut syms).unwrap() { assert!(!b) @@ -265,7 +252,6 @@ mod bool_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); if let Ctr::Bool(b) = *eval(&test, &mut syms).unwrap() { assert!(!b) @@ -276,12 +262,11 @@ mod bool_lib_tests { #[test] fn test_iseq_long_t_str() { - let document = "(eq? '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '1')"; + let document = "(eq? \"1\" \"1\" \"1\" \"1\" \"1\" \"1\" \"1\" \"1\" \"1\" \"1\" \"1\")"; let test = lex(&document.to_string()).unwrap(); let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); if let Ctr::Bool(b) = *eval(&test, &mut syms).unwrap() { assert!(b) @@ -297,7 +282,6 @@ mod bool_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); if let Ctr::Bool(b) = *eval(&test, &mut syms).unwrap() { assert!(b) @@ -308,12 +292,11 @@ mod bool_lib_tests { #[test] fn test_iseq_f_wrong_type() { - let document = "(eq? 1 '1')"; + let document = "(eq? 1 \"1\")"; let test = lex(&document.to_string()).unwrap(); let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); if let Ctr::Bool(b) = *eval(&test, &mut syms).unwrap() { assert!(!b) @@ -324,12 +307,11 @@ mod bool_lib_tests { #[test] fn test_boolcast_str_t() { - let document = "(bool 'true')"; + let document = "(bool \"true\")"; let test = lex(&document.to_string()).unwrap(); let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); if let Ctr::Bool(b) = *eval(&test, &mut syms).unwrap() { assert!(b) @@ -340,12 +322,11 @@ mod bool_lib_tests { #[test] fn test_boolcast_str_f() { - let document = "(bool 'false')"; + let document = "(bool \"false\")"; let test = lex(&document.to_string()).unwrap(); let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); if let Ctr::Bool(b) = *eval(&test, &mut syms).unwrap() { assert!(!b) @@ -361,7 +342,6 @@ mod bool_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); if let Ctr::Bool(b) = *eval(&test, &mut syms).unwrap() { assert!(b) @@ -377,7 +357,6 @@ mod bool_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); if let Ctr::Bool(b) = *eval(&test, &mut syms).unwrap() { assert!(!b) @@ -393,7 +372,6 @@ mod bool_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); if let Ctr::Bool(b) = *eval(&test, &mut syms).unwrap() { assert!(b) @@ -409,7 +387,6 @@ mod bool_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); if let Ctr::Bool(b) = *eval(&test, &mut syms).unwrap() { assert!(!b) diff --git a/tests/test_lib_control.rs b/core/tests/test_lib_control.rs similarity index 78% rename from tests/test_lib_control.rs rename to core/tests/test_lib_control.rs index cf6db8d..790466f 100644 --- a/tests/test_lib_control.rs +++ b/core/tests/test_lib_control.rs @@ -1,13 +1,12 @@ mod control_lib_tests { use flesh::ast::{eval, lex, SymTable}; - use flesh::stdlib::{dynamic_stdlib, static_stdlib}; + use flesh::stdlib::static_stdlib; #[test] fn test_assert_t() { let document = "(assert true)"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap(); } @@ -16,7 +15,6 @@ mod control_lib_tests { let document = "(assert false)"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert!(eval(&lex(&document.to_string()).unwrap(), &mut syms).is_err()) } @@ -26,7 +24,6 @@ mod control_lib_tests { let result = 1; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -41,7 +38,6 @@ mod control_lib_tests { let result = 2; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -56,7 +52,6 @@ mod control_lib_tests { let result = "(1)"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -68,13 +63,12 @@ mod control_lib_tests { #[test] fn test_let_multiphase_locals() { let document = "(let ( - (temp '1') - (temp (cons () temp '2'))) + (temp \"1\") + (temp (cons () temp \"2\"))) temp)"; - let result = "('1' '2')"; + let result = "(\"1\" \"2\")"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -86,14 +80,13 @@ mod control_lib_tests { #[test] fn test_let_def_escapes_locals() { let document1 = "(let ( - (temp 'hello') - (temp (concat temp ' ' 'world'))) - (def global '' temp))"; + (temp \"hello\") + (temp (concat temp \" \" \"world\"))) + (def global \"\" temp))"; let document2 = "global"; - let result = "('hello world')"; + let result = "(\"hello world\")"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); eval(&lex(&document1.to_string()).unwrap(), &mut syms).unwrap(); assert_eq!( *eval(&lex(&document2.to_string()).unwrap(), &mut syms) @@ -105,11 +98,10 @@ mod control_lib_tests { #[test] fn test_let_multibody_evals() { - let document = "(let ((temp '1')) temp (cons () temp '2'))"; - let result = "('1' '2')"; + let document = "(let ((temp \"1\")) temp (cons () temp \"2\"))"; + let result = "(\"1\" \"2\")"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -121,15 +113,14 @@ mod control_lib_tests { #[test] fn test_let_multiphase_local_multibody_evals() { let document = "(let ( - (temp '1') - (temp (cons () temp '2'))) - (echo 'first body') - (cons temp '3'))"; + (temp \"1\") + (temp (cons () temp \"2\"))) + (echo \"first body\") + (cons temp \"3\"))"; - let result = "('1' '2' '3')"; + let result = "(\"1\" \"2\" \"3\")"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -140,15 +131,15 @@ mod control_lib_tests { #[test] fn test_while_basic() { - let switch_dec = "(def switch '' true)"; + let switch_dec = "(def switch \"\" true)"; // if prev is true, switch looped once and only once // else prev will have a problematic type let while_loop = " (while switch - (def prev '' switch) + (def prev \"\" switch) (toggle switch) (if switch - (def '' prev) + (def \"\" prev) ()))"; let test_check = "prev"; @@ -158,7 +149,6 @@ mod control_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); eval(&switch_tree, &mut syms).unwrap(); eval(&while_tree, &mut syms).unwrap(); @@ -167,15 +157,15 @@ mod control_lib_tests { #[test] fn test_while_eval_cond() { - let switch_dec = "(def switch '' true)"; + let switch_dec = "(def switch \"\" true)"; // if prev is true, switch looped once and only once // else prev will have a problematic type let while_loop = " (while (or switch switch) - (def prev '' switch) + (def prev \"\" switch) (toggle switch) (if switch - (def '' prev) + (def \"\" prev) ()))"; let test_check = "prev"; @@ -185,7 +175,6 @@ mod control_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); eval(&switch_tree, &mut syms).unwrap(); eval(&while_tree, &mut syms).unwrap(); @@ -194,15 +183,15 @@ mod control_lib_tests { #[test] fn test_while_2_iter() { - let additional = "(def sw1 '' true)"; - let switch_dec = "(def sw2 '' true)"; + let additional = "(def sw1 \"\" true)"; + let switch_dec = "(def sw2 \"\" true)"; // while should loop twice and define result let while_loop = " (while sw1 (toggle sw2) (if (and sw1 sw2) - (def sw1 '' false) - (def result '' 'yay')))"; + (def sw1 \"\" false) + (def result \"\" \"yay\")))"; let test_check = "result"; let another_tree = lex(&additional.to_string()).unwrap(); @@ -212,7 +201,6 @@ mod control_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); eval(&another_tree, &mut syms).unwrap(); eval(&switch_tree, &mut syms).unwrap(); @@ -222,7 +210,7 @@ mod control_lib_tests { #[test] fn test_circuit_basic() { - let document = "(if (circuit true (and true true) 0 true) (def result '' 'passed') ())"; + let document = "(if (circuit true (and true true) 0 true) (def result \"\" \"passed\") ())"; let test = "result"; let doc_tree = lex(&document.to_string()).unwrap(); @@ -230,16 +218,16 @@ mod control_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); eval(&doc_tree, &mut syms).unwrap(); let res = eval(&test_tree, &mut syms); res.unwrap(); } + #[cfg(not(feature = "implicit-load"))] #[test] fn test_circuit_fail() { - let document = "(if (circuit true (and false true) true) (def result '' 'passed') ())"; + let document = "(if (circuit true (and false true) true) (def result \"\" \"passed\") ())"; let test = "result"; let doc_tree = lex(&document.to_string()).unwrap(); @@ -247,7 +235,6 @@ mod control_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); eval(&doc_tree, &mut syms).unwrap(); assert_eq!( diff --git a/tests/test_lib_decl.rs b/core/tests/test_lib_decl.rs similarity index 82% rename from tests/test_lib_decl.rs rename to core/tests/test_lib_decl.rs index 166020c..f53051a 100644 --- a/tests/test_lib_decl.rs +++ b/core/tests/test_lib_decl.rs @@ -1,16 +1,15 @@ mod decl_lib_tests { use flesh::ast::{eval, lex, Ctr, SymTable}; - use flesh::stdlib::{dynamic_stdlib, static_stdlib}; + use flesh::stdlib::static_stdlib; #[test] fn test_variable_def_and_lookup() { - let doc1 = "(def test 'my test var' 1)"; + let doc1 = "(def test \"my test var\" 1)"; let doc2 = "test"; let result = "(1)"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); eval(&lex(&doc1.to_string()).unwrap(), &mut syms).unwrap(); let res = *eval(&lex(&doc2.to_string()).unwrap(), &mut syms).unwrap(); @@ -19,13 +18,12 @@ mod decl_lib_tests { #[test] fn test_variable_def_and_lookup_list() { - let doc1 = "(def test 'my test var' (1))"; + let doc1 = "(def test \"my test var\" (1))"; let doc2 = "test"; let result = "((1))"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); eval(&lex(&doc1.to_string()).unwrap(), &mut syms).unwrap(); let res = *eval(&lex(&doc2.to_string()).unwrap(), &mut syms).unwrap(); @@ -34,13 +32,12 @@ mod decl_lib_tests { #[test] fn test_func_def_and_lookup() { - let doc1 = "(def test 'my test func' (hello) hello)"; + let doc1 = "(def test \"my test func\" (hello) hello)"; let doc2 = "(test 1)"; let result = "1"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); eval(&lex(&doc1.to_string()).unwrap(), &mut syms).unwrap(); let res = *eval(&lex(&doc2.to_string()).unwrap(), &mut syms).unwrap(); @@ -49,14 +46,13 @@ mod decl_lib_tests { #[test] fn test_variable_def_redef_and_lookup() { - let doc1 = "(def test 'my test var' 1)"; - let doc2 = "(def test 'my test var' '2')"; + let doc1 = "(def test \"my test var\" 1)"; + let doc2 = "(def test \"my test var\" \"2\")"; let doc3 = "(test)"; - let result = "('2')"; + let result = "(\"2\")"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); eval(&lex(&doc1.to_string()).unwrap(), &mut syms).unwrap(); eval(&lex(&doc2.to_string()).unwrap(), &mut syms).unwrap(); @@ -64,15 +60,15 @@ mod decl_lib_tests { assert_eq!(res.to_string(), result); } + #[cfg(not(feature = "implicit-load"))] #[test] fn test_variable_def_undef_and_lookup_fail() { - let doc1 = "(def test 'my test var' 1)"; + let doc1 = "(def test \"my test var\" 1)"; let doc2 = "(def test)"; let doc3 = "(test)"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); eval(&lex(&doc1.to_string()).unwrap(), &mut syms).unwrap(); eval(&lex(&doc2.to_string()).unwrap(), &mut syms).unwrap(); @@ -90,17 +86,16 @@ mod decl_lib_tests { #[test] fn test_variable_def_redef_via_reference_and_lookup() { - let doc1 = "(def test 'my test var' 1)"; - let doc2 = "(def ref 'references test' (quote test))"; - let doc3 = "(def ref 'my test var' '2')"; + let doc1 = "(def test \"my test var\" 1)"; + let doc2 = "(def ref \"references test\" (quote test))"; + let doc3 = "(def ref \"my test var\" \"2\")"; let test = "(test)"; let res1 = "(1)"; - let doc4 = "(def (eval ref) 'my test var' '2')"; - let res2 = "('2')"; + let doc4 = "(def (eval ref) \"my test var\" \"2\")"; + let res2 = "(\"2\")"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); eval(&lex(&doc1.to_string()).unwrap(), &mut syms).unwrap(); eval(&lex(&doc2.to_string()).unwrap(), &mut syms).unwrap(); @@ -115,15 +110,14 @@ mod decl_lib_tests { #[test] fn test_variable_doc_dynamic() { - let doc1 = "(def test-doc 'docs for test' 'test tests tests test')"; - let doc2 = "(def test test-doc 'one')"; + let doc1 = "(def test-doc \"docs for test\" \"test tests tests test\")"; + let doc2 = "(def test test-doc \"one\")"; let doc3 = "(eq? (and (eq? (get-doc (quote test)) test-doc) - (eq? test 'one')))"; + (eq? test \"one\")))"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); eval(&lex(&doc1.to_string()).unwrap(), &mut syms).unwrap(); eval(&lex(&doc2.to_string()).unwrap(), &mut syms).unwrap(); @@ -136,13 +130,12 @@ mod decl_lib_tests { #[test] fn test_func_def_no_args() { - let doc1 = "(def test 'my test func' () 1)"; + let doc1 = "(def test \"my test func\" () 1)"; let doc2 = "(test)"; let result = "1"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); eval(&lex(&doc1.to_string()).unwrap(), &mut syms).unwrap(); let res = *eval(&lex(&doc2.to_string()).unwrap(), &mut syms).unwrap(); @@ -151,12 +144,11 @@ mod decl_lib_tests { #[test] fn test_isset_true() { - let doc1 = "(def test '' 1)"; + let doc1 = "(def test \"\" 1)"; let doc2 = "(set? test)"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); let def_tree = lex(&doc1.to_string()).unwrap(); let set_tree = lex(&doc2.to_string()).unwrap(); @@ -171,7 +163,6 @@ mod decl_lib_tests { let doc = "(set? test)"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); let set_tree = lex(&doc.to_string()).unwrap(); if let Ctr::Bool(b) = *eval(&set_tree, &mut syms).unwrap() { assert!(!b); @@ -180,12 +171,11 @@ mod decl_lib_tests { #[test] fn test_env_doesnt_lose_elements() { - let doc1 = "(def t '' 1)"; + let doc1 = "(def t \"\" 1)"; let doc2 = "(env)"; let doc3 = "t"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); let set_tree = lex(&doc1.to_string()).unwrap(); let env_tree = lex(&doc2.to_string()).unwrap(); let tst_tree = lex(&doc3.to_string()).unwrap(); @@ -200,7 +190,6 @@ mod decl_lib_tests { let result = "(add 1 2)"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -217,7 +206,6 @@ mod decl_lib_tests { let result = "3"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -232,7 +220,6 @@ mod decl_lib_tests { let result = "(1 2 3)"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -246,7 +233,6 @@ mod decl_lib_tests { let document = "(lambda (x y) (add x y))"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -260,7 +246,6 @@ mod decl_lib_tests { let document = "(lambda () (add 1 2))"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -274,7 +259,6 @@ mod decl_lib_tests { let document = "((lambda (x y) (add x y)) 1 2)"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); let it = *eval( &lex(&document.to_string()).unwrap(), &mut syms).unwrap(); @@ -291,7 +275,6 @@ mod decl_lib_tests { (adder 1 2))"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); let it = *eval( &lex(&document.to_string()).unwrap(), &mut syms).unwrap(); @@ -305,11 +288,10 @@ mod decl_lib_tests { #[test] fn test_lambda_var_bound_call() { let document = "(let (()) - (def adder 'my adder' (lambda (x y) (add x y))) + (def adder \"my adder\" (lambda (x y) (add x y))) (adder 1 2))"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); let it = *eval( &lex(&document.to_string()).unwrap(), &mut syms).unwrap(); @@ -323,12 +305,11 @@ mod decl_lib_tests { #[test] fn test_lambda_arg_call() { let document = "(let (()) - (def appl '' (func item) (func item)) - (def adder 'my adder' (lambda (x) (add x 1))) + (def appl \"\" (func item) (func item)) + (def adder \"my adder\" (lambda (x) (add x 1))) (appl adder 2))"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); let it = *eval( &lex(&document.to_string()).unwrap(), &mut syms).unwrap(); @@ -342,11 +323,10 @@ mod decl_lib_tests { #[test] fn test_setget_doc_string() { - let highly_inadvisable = "(set-doc (q help) 'help')"; + let highly_inadvisable = "(set-doc (q help) \"help\")"; let document = "(get-doc (q help))"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); let _ = *eval( &lex(&highly_inadvisable.to_string()).unwrap(), &mut syms).unwrap(); @@ -365,7 +345,6 @@ mod decl_lib_tests { let doc = "(eval (quote (add 1 1)))"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&doc.to_string()).unwrap(), &mut syms).unwrap().to_string(), 2.to_string() diff --git a/tests/test_lib_file.rs b/core/tests/test_lib_file.rs similarity index 78% rename from tests/test_lib_file.rs rename to core/tests/test_lib_file.rs index 6d979a9..729d5ad 100644 --- a/tests/test_lib_file.rs +++ b/core/tests/test_lib_file.rs @@ -1,15 +1,14 @@ mod file_lib_tests { use flesh::ast::{eval, lex, SymTable}; - use flesh::stdlib::{dynamic_stdlib, static_stdlib}; + use flesh::stdlib::static_stdlib; #[test] fn test_fexists() { - let document = "(exists? '/tmp')"; + let document = "(exists? \"/tmp\")"; let result = "true"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -20,12 +19,11 @@ mod file_lib_tests { #[test] fn test_fexists_doesnt() { - let document = "(exists? 'cargo.timtam')"; + let document = "(exists? \"cargo.timtam\")"; let result = "false"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -37,8 +35,8 @@ mod file_lib_tests { #[test] fn test_write_file() { let document = " - (let ((s 'test') - (t '/tmp/flesh-lib-test-file-1')) + (let ((s \"test\") + (t \"/tmp/flesh-lib-test-file-1\")) (write-file t s) (echo (read-file t)) (eq? (read-file t) s))"; @@ -46,7 +44,6 @@ mod file_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -58,8 +55,8 @@ mod file_lib_tests { #[test] fn test_append_file() { let document = " - (let ((s 'test') - (t '/tmp/flesh-lib-test-file-2')) + (let ((s \"test\") + (t \"/tmp/flesh-lib-test-file-2\")) (write-file t s) (append-file t s) (eq? (read-file t) @@ -68,7 +65,6 @@ mod file_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() diff --git a/tests/test_lib_math.rs b/core/tests/test_lib_math.rs similarity index 88% rename from tests/test_lib_math.rs rename to core/tests/test_lib_math.rs index 0637e3f..33e3cba 100644 --- a/tests/test_lib_math.rs +++ b/core/tests/test_lib_math.rs @@ -1,6 +1,6 @@ mod math_lib_tests { use flesh::ast::{eval, lex, Ctr, SymTable}; - use flesh::stdlib::{dynamic_stdlib, static_stdlib}; + use flesh::stdlib::static_stdlib; #[test] fn test_add_chain() { @@ -9,7 +9,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -25,7 +24,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -41,7 +39,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -57,7 +54,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -73,7 +69,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -89,7 +84,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -100,12 +94,11 @@ mod math_lib_tests { #[test] fn test_string_to_int() { - let document = "(int '10')"; + let document = "(int \"10\")"; let result = "10"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -121,7 +114,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -132,12 +124,11 @@ mod math_lib_tests { #[test] fn test_string_to_float() { - let document = "(float '10.3')"; + let document = "(float \"10.3\")"; let result = "10.3"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -153,7 +144,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -169,7 +159,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -185,7 +174,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -201,7 +189,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -212,7 +199,7 @@ mod math_lib_tests { #[test] fn test_ii_mod() { - let document = "(def test '' (mod 7 3))"; + let document = "(def test \"\" (mod 7 3))"; let check1 = "(car test)"; let result1 = "2"; let check2 = "(cdr test)"; @@ -220,7 +207,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); let _ = *eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap(); assert_eq!( *eval(&lex(&check1.to_string()).unwrap(), &mut syms) @@ -238,13 +224,12 @@ mod math_lib_tests { #[test] fn test_if_mod() { - let document = "(def test '' (mod 7 3.3))"; + let document = "(def test \"\" (mod 7 3.3))"; let check1 = "(car test)"; let result1 = "2"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); let _ = *eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap(); assert_eq!( *eval(&lex(&check1.to_string()).unwrap(), &mut syms) @@ -256,12 +241,11 @@ mod math_lib_tests { #[test] fn test_fi_mod() { - let document = "(def test '' (mod 7.2 2))"; + let document = "(def test \"\" (mod 7.2 2))"; let check1 = "(car test)"; let result1 = "3"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); let _ = *eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap(); assert_eq!( *eval(&lex(&check1.to_string()).unwrap(), &mut syms) @@ -273,13 +257,12 @@ mod math_lib_tests { #[test] fn test_ff_mod() { - let document = "(def test '' (mod 7.2 3.3))"; + let document = "(def test \"\" (mod 7.2 3.3))"; let check1 = "(car test)"; let result1 = "2"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); let _ = *eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap(); assert_eq!( *eval(&lex(&check1.to_string()).unwrap(), &mut syms) @@ -296,7 +279,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -312,7 +294,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -328,7 +309,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -344,7 +324,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -360,7 +339,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -376,7 +354,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -392,7 +369,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -408,7 +384,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -424,7 +399,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -440,7 +414,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -456,7 +429,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -472,7 +444,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -488,7 +459,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -504,7 +474,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -520,7 +489,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -536,7 +504,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -552,7 +519,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -568,7 +534,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -584,7 +549,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -600,7 +564,6 @@ mod math_lib_tests { let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -611,13 +574,12 @@ mod math_lib_tests { #[test] fn test_inc() { - let document = "(def tester '' 1)"; + let document = "(def tester \"\" 1)"; let change = "(inc tester)"; let check = "(tester)"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); let doc_tree = lex(&document.to_string()).unwrap(); let change_tree = lex(&change.to_string()).unwrap(); @@ -650,13 +612,12 @@ mod math_lib_tests { #[test] fn test_inc_errors_dont_lose_vars() { - let document = "(def tester '' 'oops')"; + let document = "(def tester \"\" \"oops\")"; let change = "(inc tester)"; let check = "(tester)"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); let doc_tree = lex(&document.to_string()).unwrap(); let change_tree = lex(&change.to_string()).unwrap(); @@ -670,7 +631,7 @@ mod math_lib_tests { ); let intermediate = *eval(&check_tree, &mut syms).unwrap(); if let Ctr::Seg(ref s) = intermediate { - assert_eq!(s.to_string(), "('oops')".to_string()); + assert_eq!(s.to_string(), "(\"oops\")".to_string()); } else { eprintln!("did not expect: {}", intermediate); panic!() @@ -683,13 +644,12 @@ mod math_lib_tests { #[test] fn test_inc_errors_dont_lose_funcs() { - let document = "(def tester '' (oops) oops)"; + let document = "(def tester \"\" (oops) oops)"; let change = "(inc tester)"; - let check = "(tester '1')"; + let check = "(tester \"1\")"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); let doc_tree = lex(&document.to_string()).unwrap(); let change_tree = lex(&change.to_string()).unwrap(); @@ -714,13 +674,12 @@ mod math_lib_tests { #[test] fn test_dec() { - let document = "(def tester '' 1)"; + let document = "(def tester \"\" 1)"; let change = "(dec tester)"; let check = "(tester)"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); let doc_tree = lex(&document.to_string()).unwrap(); let change_tree = lex(&change.to_string()).unwrap(); @@ -753,13 +712,12 @@ mod math_lib_tests { #[test] fn test_dec_errors_dont_lose_vars() { - let document = "(def tester '' 'oops')"; + let document = "(def tester \"\" \"oops\")"; let change = "(dec tester)"; let check = "(tester)"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); let doc_tree = lex(&document.to_string()).unwrap(); let change_tree = lex(&change.to_string()).unwrap(); @@ -773,7 +731,7 @@ mod math_lib_tests { ); let intermediate = *eval(&check_tree, &mut syms).unwrap(); if let Ctr::Seg(ref s) = intermediate { - assert_eq!(s.to_string(), "('oops')".to_string()); + assert_eq!(s.to_string(), "(\"oops\")".to_string()); } else { eprintln!("did not expect: {}", intermediate); panic!() @@ -786,13 +744,12 @@ mod math_lib_tests { #[test] fn test_dec_errors_dont_lose_funcs() { - let document = "(def tester '' (oops) oops)"; + let document = "(def tester \"\" (oops) oops)"; let change = "(dec tester)"; - let check = "(tester '1')"; + let check = "(tester \"1\")"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); let doc_tree = lex(&document.to_string()).unwrap(); let change_tree = lex(&change.to_string()).unwrap(); diff --git a/tests/test_lib_str.rs b/core/tests/test_lib_str.rs similarity index 57% rename from tests/test_lib_str.rs rename to core/tests/test_lib_str.rs index acc869a..98ea328 100644 --- a/tests/test_lib_str.rs +++ b/core/tests/test_lib_str.rs @@ -1,14 +1,13 @@ mod str_lib_tests { use flesh::ast::{eval, lex, SymTable}; - use flesh::stdlib::{dynamic_stdlib, static_stdlib}; + use flesh::stdlib::static_stdlib; #[test] fn test_simple_concat() { - let document = "(concat 'test')"; - let result = "'test'"; + let document = "(concat \"test\")"; + let result = "\"test\""; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -19,11 +18,10 @@ mod str_lib_tests { #[test] fn test_poly_concat() { - let document = "(concat 'test' 1 2 3)"; - let result = "'test123'"; + let document = "(concat \"test\" 1 2 3)"; + let result = "\"test123\""; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -35,10 +33,9 @@ mod str_lib_tests { #[test] fn test_empty_concat() { let document = "(concat)"; - let result = "''"; + let result = "\"\""; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -49,11 +46,10 @@ mod str_lib_tests { #[test] fn test_strlen_str() { - let document = "(strlen 'test')"; + let document = "(strlen \"test\")"; let result = 4; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -68,7 +64,6 @@ mod str_lib_tests { let result = 4; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -83,7 +78,6 @@ mod str_lib_tests { let result = 4; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -98,7 +92,6 @@ mod str_lib_tests { let result = 7; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -113,7 +106,6 @@ mod str_lib_tests { let result = 4; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -125,10 +117,9 @@ mod str_lib_tests { #[test] fn test_strcast_i() { let document = "(string 4)"; - let result = "'4'"; + let result = "\"4\""; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -140,10 +131,9 @@ mod str_lib_tests { #[test] fn test_strcast_seg() { let document = "(string (1 2 3))"; - let result = "'(1 2 3)'"; + let result = "\"(1 2 3)\""; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -154,11 +144,10 @@ mod str_lib_tests { #[test] fn test_contains() { - let document = "(substr? 'bigger' 'ger')"; + let document = "(substr? \"bigger\" \"ger\")"; let result = "true"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -169,11 +158,10 @@ mod str_lib_tests { #[test] fn test_doesnt_contain() { - let document = "(substr? 'smaller' 'ger')"; + let document = "(substr? \"smaller\" \"ger\")"; let result = "false"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -184,11 +172,10 @@ mod str_lib_tests { #[test] fn test_split() { - let document = "(split 'one.two.three' '.')"; - let result = "('one' 'two' 'three')"; + let document = "(split \"one.two.three\" \".\")"; + let result = "(\"one\" \"two\" \"three\")"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -199,11 +186,10 @@ mod str_lib_tests { #[test] fn test_split_big_delim() { - let document = "(split 'one:d:two:d:three' ':d:')"; - let result = "('one' 'two' 'three')"; + let document = "(split \"one:d:two:d:three\" \":d:\")"; + let result = "(\"one\" \"two\" \"three\")"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -214,11 +200,10 @@ mod str_lib_tests { #[test] fn test_splitnt() { - let document = "(split 'one.two.three' '-')"; - let result = "('one.two.three')"; + let document = "(split \"one.two.three\" \"-\")"; + let result = "(\"one.two.three\")"; let mut syms = SymTable::new(); static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); assert_eq!( *eval(&lex(&document.to_string()).unwrap(), &mut syms) .unwrap() @@ -226,4 +211,103 @@ mod str_lib_tests { result.to_string(), ); } + + #[test] + fn test_substr_valid() { + let document = "(substr \"test\" 0 4)"; + let result = "\"test\""; + let mut syms = SymTable::new(); + static_stdlib(&mut syms); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } + + #[test] + fn test_substr_start_neg() { + let document = "(substr \"test\" -1 3)"; + let result = "start index cannot be negative"; + let mut syms = SymTable::new(); + static_stdlib(&mut syms); + let doc_res= eval(&lex(&document.to_string()).unwrap(), &mut syms); + if let Err(e) = doc_res { + assert_eq!( + e.0.first().unwrap().message, + result.to_string(), + ); + } else { + assert!(false); + } + } + + #[test] + fn test_substr_end_neg() { + let document = "(substr \"test\" 1 -3)"; + let result = "end index cannot be negative"; + let mut syms = SymTable::new(); + static_stdlib(&mut syms); + let doc_res= eval(&lex(&document.to_string()).unwrap(), &mut syms); + if let Err(e) = doc_res { + assert_eq!( + e.0.first().unwrap().message, + result.to_string(), + ); + } else { + assert!(false); + } + } + + #[test] + fn test_substr_start_out_of_bounds() { + let document = "(substr \"test\" 5 3)"; + let result = "start index larger than source string"; + let mut syms = SymTable::new(); + static_stdlib(&mut syms); + let doc_res= eval(&lex(&document.to_string()).unwrap(), &mut syms); + if let Err(e) = doc_res { + assert_eq!( + e.0.first().unwrap().message, + result.to_string(), + ); + } else { + assert!(false); + } + } + + #[test] + fn test_substr_end_out_of_bounds() { + let document = "(substr \"test\" 1 5)"; + let result = "end index larger than source string"; + let mut syms = SymTable::new(); + static_stdlib(&mut syms); + let doc_res= eval(&lex(&document.to_string()).unwrap(), &mut syms); + if let Err(e) = doc_res { + assert_eq!( + e.0.first().unwrap().message, + result.to_string(), + ); + } else { + assert!(false); + } + } + + #[test] + fn test_substr_index_order() { + let document = "(substr \"test\" 3 2)"; + let result = "end index must be larger than start index"; + let mut syms = SymTable::new(); + static_stdlib(&mut syms); + let doc_res= eval(&lex(&document.to_string()).unwrap(), &mut syms); + if let Err(e) = doc_res { + assert_eq!( + e.0.first().unwrap().message, + result.to_string(), + ); + } else { + assert!(false); + } + } } diff --git a/shell/Cargo.toml b/shell/Cargo.toml new file mode 100644 index 0000000..f75a96f --- /dev/null +++ b/shell/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "flesh-shell" +version = "0.4.0" +authors = ["Ava Affine "] +edition = "2021" + +[[bin]] +name = "flesh" +path = "src/main.rs" + +[dependencies] +# used in config (src/run.rs) +dirs = "3.0" +# these two are used in src/bin/relish.rs to manage a prompt +nu-ansi-term = "0.47.0" +reedline = "0.17.0" +# used by main shell to update console dimensions +termion = "2.0.1" +# these two used in posix shell layer (src/stl/posix.rs) +nix = { version = "0.26.2", optional = true } +libc = { version = "0.2.144", optional = true } +flesh-core = { path = "../core", features = ["implicit-load"]} + +[features] +default = ["posix"] +posix = ["dep:nix", "dep:libc"] \ No newline at end of file diff --git a/src/bin/flesh.rs b/shell/src/main.rs similarity index 96% rename from src/bin/flesh.rs rename to shell/src/main.rs index 4ca41be..5edc17a 100644 --- a/src/bin/flesh.rs +++ b/shell/src/main.rs @@ -15,17 +15,26 @@ * along with this program. If not, see . */ +#[cfg(feature="posix")] +mod posix; + +mod run; +mod stl; + use { flesh::{ ast::{ - eval, lex, run, + eval, lex, Ctr, Seg, SymTable, Symbol, Traceback, }, - stdlib::{ - static_stdlib, dynamic_stdlib, load_defaults, - load_environment, - CONSOLE_XDIM_VNAME, CONSOLE_YDIM_VNAME, CFG_FILE_VNAME, + stdlib::CFG_FILE_VNAME, + }, + crate::{ + run::run, + stl::{ + load_environment, static_stdlib_overwrites, load_defaults, + CONSOLE_XDIM_VNAME, CONSOLE_YDIM_VNAME, L_PROMPT_VNAME, R_PROMPT_VNAME, PROMPT_DELIM_VNAME, }, }, @@ -51,7 +60,9 @@ use { }; #[cfg(feature="posix")] -use flesh::aux::{ShellState, check_jobs}; +use crate::stl::dynamic_stdlib; +#[cfg(feature="posix")] +use posix::{ShellState, check_jobs}; #[cfg(feature="posix")] use nix::unistd; @@ -94,7 +105,7 @@ impl Prompt for CustomPrompt { }; Cow::Owned(format!( - "({}reverse-search: {}) ", + "({}search: {}) ", prefix, history_search.term )) } @@ -239,7 +250,7 @@ fn incomplete_brackets(line: &str) -> bool { for c in line.chars() { match c { - c if ['"', '`', '\''].contains(&c) => { + c if ['"', '`'].contains(&c) => { match within_string { Some(w) if c == w => { balance.pop(); @@ -300,7 +311,7 @@ fn main() { let mut syms = SymTable::new(); load_defaults(&mut syms); load_environment(&mut syms); - static_stdlib(&mut syms); + static_stdlib_overwrites(&mut syms); #[cfg(feature="posix")] let prompt_ss: Rc>; @@ -317,22 +328,6 @@ fn main() { dynamic_stdlib(&mut syms, Some(shell_state_bindings)); } - // reload this later with the state bindings - #[cfg(not(feature="posix"))] - dynamic_stdlib(&mut syms); - - // if there are args those are scripts, run them and exit - if env::args().count() > 1 { - let mut iter = env::args(); - iter.next(); - for i in iter { - run(i, &mut syms).unwrap(); - } - - return - } - - // this is a user shell. attempt to load configuration { // scope the below borrow of syms let cfg_file = env::var(CFG_FILE_VNAME).unwrap_or(cfg_file_name); @@ -345,6 +340,19 @@ fn main() { dynamic_stdlib(&mut syms, Some(prompt_ss.clone())); } + // if there are args those are scripts, run them and exit + if env::args().count() > 1 { + let mut iter = env::args(); + iter.next(); + for i in iter { + if let Err(e) = run(i, &mut syms) { + eprintln!("{}", e) + } + } + + return + } + // setup readline let completion_menu = Box::new(ColumnarMenu::default().with_name("completion_menu")); let mut keybindings = default_emacs_keybindings(); diff --git a/src/stl/posix.rs b/shell/src/posix.rs similarity index 92% rename from src/stl/posix.rs rename to shell/src/posix.rs index 8c76d66..c2cd249 100644 --- a/src/stl/posix.rs +++ b/shell/src/posix.rs @@ -16,20 +16,12 @@ */ use { - crate::{ - segment::{ - Ctr, Seg, Type - }, - sym::{ - SymTable, ValueType, - Symbol, Args, - }, - error::{ - Traceback, start_trace, - }, - eval::eval, - run, + flesh::ast::{ + eval, start_trace, + Ctr, Seg, Type, SymTable, ValueType, + Symbol, Args, Traceback, }, + crate::run, libc::{ sigaddset, sigemptyset, sigprocmask, exit, SIGINT, SIGCHLD, SIGTTOU, SIGTTIN, SIGQUIT, SIGTSTP, @@ -62,7 +54,7 @@ use { }, }; -pub const POSIX_LOAD_NAME: &str = "load"; +pub const POSIX_LOAD_NAME: &str = env!("POSIX_LOAD_NAME"); pub const CD_USER_CB: &str = "CFG_FLESH_CD_CB"; pub struct ShellState { @@ -847,20 +839,6 @@ pub fn load_posix_shell(syms: &mut SymTable, shell_state: Rc ign_sigs(); - syms.insert( - String::from("l"), - Symbol { - name: String::from(POSIX_LOAD_NAME), - args: Args::Infinite, - conditional_branches: true, - docs: String::from(LOAD_DOCSTRING), - value: ValueType::Internal(Rc::new(move |ast: &Seg, symtable: &mut SymTable| -> Result { - load_callback(ast, symtable, &mut shell_state.borrow_mut()) - })), - ..Default::default() - }, - ); - syms.insert( String::from(POSIX_LOAD_NAME), Symbol { @@ -995,3 +973,103 @@ pub fn load_posix_shell(syms: &mut SymTable, shell_state: Rc }, ); } + +#[cfg(test)] +mod tests { + use super::*; + use flesh::ast::{lex, eval, SymTable}; + use flesh::stdlib::static_stdlib; + + #[test] + fn test_cmd_singlet() { + let document = "(binary)"; + let result = vec!["binary"]; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms); + + if let Ok(ref s) = lex(&document.to_string()) { + assert_eq!( + args_from_ast(s, &mut syms), + result + ) + } else { + panic!() + } + } + + #[test] + fn test_cmd_list() { + let document = "(binary --flag=1 122 \"yeet\" true)"; + let result = vec!["binary", "--flag=1", "122", "yeet", "true"]; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms); + + if let Ok(ref s) = lex(&document.to_string()) { + assert_eq!( + args_from_ast(s, &mut syms), + result + ) + } else { + panic!() + } + } + + #[test] + fn test_cmd_syms_undef() { + let document = "(binary --flag=1 122 \"yeet\" true syms)"; + let result = vec!["binary", "--flag=1", "122", "yeet", "true", "syms"]; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms); + + if let Ok(ref s) = lex(&document.to_string()) { + assert_eq!( + args_from_ast(s, &mut syms), + result + ) + } else { + panic!() + } + } + + #[test] + fn test_cmd_syms_unwrap_simple() { + let decl = "(def syms \"\" 1)"; + let document = "(binary --flag=1 122 \"yeet\" true syms)"; + let result = vec!["binary", "--flag=1", "122", "yeet", "true", "1"]; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms); + + eval(&lex(&decl.to_string()).unwrap(), &mut syms).unwrap(); + + if let Ok(ref s) = lex(&document.to_string()) { + assert_eq!( + args_from_ast(s, &mut syms), + result + ) + } else { + panic!() + } + } + + #[test] + fn test_cmd_syms_unwrap_eval() { + let document = "(binary --flag=1 122 \"yeet\" true (add 1 2))"; + let result = vec!["binary", "--flag=1", "122", "yeet", "true", "3"]; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms); + + if let Ok(ref s) = lex(&document.to_string()) { + assert_eq!( + args_from_ast(s, &mut syms), + result + ) + } else { + panic!() + } + } +} diff --git a/src/run.rs b/shell/src/run.rs similarity index 95% rename from src/run.rs rename to shell/src/run.rs index 08285d3..977142a 100644 --- a/src/run.rs +++ b/shell/src/run.rs @@ -15,11 +15,10 @@ * along with this program. If not, see . */ -use crate::eval::eval; -use crate::lex::lex; -use crate::error::{Traceback, start_trace}; -use crate::segment::{Ctr, Seg}; -use crate::sym::SymTable; +use flesh::ast::{ + eval, lex, start_trace, + Ctr, Seg, SymTable, Traceback, +}; use std::path::Path; use std::fs; use std::iter::FromIterator; diff --git a/src/stl.rs b/shell/src/stl.rs similarity index 89% rename from src/stl.rs rename to shell/src/stl.rs index 2e73dd6..3f1669a 100644 --- a/src/stl.rs +++ b/shell/src/stl.rs @@ -15,24 +15,24 @@ * along with this program. If not, see . */ -use crate::segment::{Ctr, Seg, Type}; +use flesh::{ + ast::{Ctr, Seg, Type, Args, SymTable, Symbol, ValueType, Traceback}, + stdlib::{STORE_DOCSTRING, static_stdlib}, +}; + use crate::run::{run_callback, RUN_DOCSTRING}; -use crate::sym::{Args, SymTable, Symbol, ValueType}; -use crate::error::Traceback; + use std::rc::Rc; use std::cell::RefCell; use std::env::vars; #[cfg(feature = "posix")] -pub mod posix; +use crate::posix; -pub mod append; -pub mod boolean; -pub mod control; -pub mod decl; -pub mod math; -pub mod strings; -pub mod file; +#[path = "window.rs"] +mod window; +#[path = "store.rs"] +mod store; pub const CONSOLE_XDIM_VNAME: &str = "_FLESH_WIDTH"; pub const CONSOLE_YDIM_VNAME: &str = "_FLESH_HEIGHT"; @@ -41,10 +41,10 @@ pub const MODENV_CFG_VNAME: &str = "CFG_FLESH_ENV"; pub const L_PROMPT_VNAME: &str = "CFG_FLESH_L_PROMPT"; pub const R_PROMPT_VNAME: &str = "CFG_FLESH_R_PROMPT"; pub const PROMPT_DELIM_VNAME: &str = "CFG_FLESH_PROMPT_DELIMITER"; -pub const CFG_FILE_VNAME: &str = "FLESH_CFG_FILE"; pub const FLESH_DEFAULT_CONS_HEIGHT: i16 = 24; pub const FLESH_DEFAULT_CONS_WIDTH: i16 = 80; + fn l_prompt_default_callback(_: &Seg, _: &mut SymTable) -> Result { Ok(Ctr::String(">".to_string())) } @@ -60,14 +60,9 @@ fn prompt_delimiter_default_callback(_: &Seg, _: &mut SymTable) -> Result>>) { - // get CFG_FLESH_ENV from syms let env_cfg_user_form = syms .call_symbol(&MODENV_CFG_VNAME.to_string(), &Seg::new(), true) .unwrap_or_else(|_: Traceback| Box::new(Ctr::None)) .to_string() .eq("true"); - decl::add_decl_lib_dynamic(syms, env_cfg_user_form); + if env_cfg_user_form { + syms.insert( + "def".to_string(), + Symbol { + name: String::from("define"), + args: Args::Infinite, + conditional_branches: true, + docs: STORE_DOCSTRING.to_string(), + value: ValueType::Internal(Rc::new( + store::store_callback_with_env_integration + )), + ..Default::default() + } + ); + } if let Some(shell_state) = shell { let posix_cfg_user_form = syms @@ -108,27 +116,6 @@ pub fn dynamic_stdlib(syms: &mut SymTable, shell: Option. + */ + +use std::env; +use flesh::ast::{Ctr, Traceback, Seg, SymTable, Type, ValueType}; +use flesh::stdlib::store_callback; + +pub fn store_callback_with_env_integration( + ast: &Seg, + syms: &mut SymTable +) -> Result { + let name = store_callback(ast, syms)?; + if let Ctr::String(n) = &name { + match ast.len() { + 1 => { + env::remove_var(n); + }, + 3 if syms.contains_key(&n) => { + if let ValueType::VarForm(val) = &syms.get(&n).unwrap().value { + match val.to_type() { + Type::Lambda => {}, + Type::Seg => {}, + _ => { + let mut s = val.to_string(); + // eat printed quotes on a string val + if let Ctr::String(tok) = &**val { + s = tok.to_string(); + } + env::set_var(n.clone(), s); + } + } + } + }, + _ => {} + } + } + + Ok(name) +} diff --git a/shell/src/window.rs b/shell/src/window.rs new file mode 100644 index 0000000..51385b8 --- /dev/null +++ b/shell/src/window.rs @@ -0,0 +1,110 @@ +/* Flesh: Flexible Shell + * Copyright (C) 2021 Ava Hahn + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +use flesh::ast::{Traceback, Ctr, Symbol, Args, ValueType, Seg, SymTable, Type}; +use crate::stl::{CONSOLE_XDIM_VNAME, FLESH_DEFAULT_CONS_WIDTH}; +use std::rc::Rc; + +pub fn add_window_lib_funcs(syms: &mut SymTable) { + syms.insert( + "env".to_string(), + Symbol { + name: String::from("env"), + args: Args::None, + conditional_branches: false, + docs: ENV_DOCSTRING.to_string(), + value: ValueType::Internal(Rc::new(env_callback)), + ..Default::default() + }, + ); +} + +const ENV_DOCSTRING: &str = "takes no arguments +prints out all available symbols and their associated values"; +fn env_callback(_ast: &Seg, syms: &mut SymTable) -> Result { + // get width of current output + let xdim: i128; + if let Ctr::Integer(dim) = *syms + .call_symbol(&CONSOLE_XDIM_VNAME.to_string(), &Seg::new(), true) + .unwrap_or_else(|_: Traceback| Box::new(Ctr::None)) { + xdim = dim; + } else { + println!("{} contains non integer value, defaulting to {}", + CONSOLE_XDIM_VNAME, FLESH_DEFAULT_CONS_WIDTH); + xdim = FLESH_DEFAULT_CONS_WIDTH as i128; + } + + let mut v_col_len = 0; + let mut f_col_len = 0; + let mut functions = vec![]; + let mut variables = vec![]; + for (name, val) in syms.iter() { + if let ValueType::VarForm(l) = &val.value { + let token: String = match l.to_type() { + Type::Lambda => format!("{}: ", name), + Type::Seg => format!("{}:
", name), + _ => format!("{}: {}", name, val.value), + }; + + if token.len() > v_col_len && token.len() < xdim as usize { + v_col_len = token.len(); + } + + variables.push(token); + } else { + if f_col_len < name.len() && name.len() < xdim as usize { + f_col_len = name.len(); + } + functions.push(name.clone()); + } + } + + let mut n_v_cols = xdim / v_col_len as i128; + // now decrement to make sure theres room for two spaces of padding + while n_v_cols > 1 && xdim % (v_col_len as i128) < (2 * n_v_cols) { + n_v_cols -= 1; + } + // again for functions + let mut n_f_cols = xdim / f_col_len as i128; + while n_f_cols > 1 && xdim & (f_col_len as i128) < (2 * n_f_cols) { + n_f_cols -= 1; + } + + let mut col_iter = 0; + println!("VARIABLES:"); + for var in variables { + print!("{:v_col_len$}", var); + col_iter += 1; + if col_iter % n_v_cols == 0 { + println!(); + } else { + print!(" "); + } + } + println!("\nFUNCTIONS:"); + col_iter = 0; + for func in functions { + print!("{:f_col_len$}", func); + col_iter += 1; + if col_iter % n_f_cols == 0 { + println!(); + } else { + print!(" "); + } + } + Ok(Ctr::None) +} diff --git a/snippets/avas-laptop-prompt.f b/snippets/avas-laptop-prompt.f index 94c0247..277d99e 100644 --- a/snippets/avas-laptop-prompt.f +++ b/snippets/avas-laptop-prompt.f @@ -21,9 +21,9 @@ ;; username, and percentages for all batteries on the system. ;; -> requires CFG_FLESH_POSIX=true and userlib. -(def _batteries 'paths to batteries powering system' +(def _batteries "paths to batteries powering system" (lambda () - (let ((power-srcs-dir '/sys/class/power_supply') + (let ((power-srcs-dir "/sys/class/power_supply") (power-srcs (split (load-to-string find /sys/class/power_supply -printf "%p ") " ")) @@ -39,7 +39,7 @@ (set (q pwr-iter) (pop rem)))) pwr-list))) -(def display-batteries 'display battery capacity' +(def display-batteries "display battery capacity" (lambda () (let ((bat-iter (pop (_batteries))) (display "")) @@ -53,14 +53,14 @@ (set (q bat-iter) (pop rem)))) display))) -(def CFG_FLESH_R_PROMPT 'display battery info' +(def CFG_FLESH_R_PROMPT "display battery info" () (display-batteries)) -(def _fancy-cwd 'prints (up to) last three segments of current path' +(def _fancy-cwd "prints (up to) last three segments of current path" () (let ((cdir (load-to-string pwd)) - (dir-segs (split cdir '/')) + (dir-segs (split cdir "/")) (dir-iter (dq dir-segs)) (i 0)) (if (lte? (len dir-segs) 4) @@ -73,14 +73,14 @@ (concat "..." final))))) (def in-a-git-repo? -'returns true or false depending on if currently in a git repo' +"returns true or false depending on if currently in a git repo" () (eq? (load-to-string git rev-parse --is-inside-work-tree) "true")) (def git-repo-is-dirty? -'returns true or false depending on if current dir is a dirty git repo' - () (not (eq? (load-to-string git diff '--stat') ""))) +"returns true or false depending on if current dir is a dirty git repo" + () (not (eq? (load-to-string git diff "--stat") ""))) -(def git-status 'returns "(git:{!,})" if dir is in a git repository' +(def git-status "returns '(git:{!,})' if dir is in a git repository" () (if (in-a-git-repo?) (concat @@ -90,9 +90,9 @@ "!" "") ")") - '')) + "")) -(def CFG_FLESH_L_PROMPT 'display user and dir (git info in future)' +(def CFG_FLESH_L_PROMPT "display user and dir (git info in future)" () (concat "[" USER "]" "\t" diff --git a/snippets/genbind.f b/snippets/genbind.f index df7d21f..667e2a1 100644 --- a/snippets/genbind.f +++ b/snippets/genbind.f @@ -52,6 +52,6 @@ Or, a more advanced use: (cons while (cons gt? (cons len (q arg-iter)) 1) (cons set (cons q (q func-call)) (cons cons (q func-call) (cons car (q arg-iter)))) (cons set (cons q (q arg-iter)) (cons pop (cons cdr (q arg-iter))))) - (cons echo '+ ' (cons cdr (cons pop (q func-call)))) + (cons echo "+ " (cons cdr (cons pop (q func-call)))) (cons eval (q func-call)))))) (eval lam))) diff --git a/snippets/interactive-devel-tests.f b/snippets/interactive-devel-tests.f new file mode 100644 index 0000000..2786d5b --- /dev/null +++ b/snippets/interactive-devel-tests.f @@ -0,0 +1,20 @@ +#!/bin/flesh + +;; Flesh: Flexible Shell +;; Copyright (C) 2021 Ava Affine +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;; INTERACTIVE DEVELOPMENT TESTS +;; This file contains test cases for interactive-devel.f diff --git a/snippets/interactive-devel.f b/snippets/interactive-devel.f index d9291ac..6ccecdd 100644 --- a/snippets/interactive-devel.f +++ b/snippets/interactive-devel.f @@ -18,19 +18,31 @@ ;; INTERACTIVE DEVELOPMENT ;; This file contains features that help you develop new features at the REPL +;; TODO: Need an is_symbol impl or some way to reflect + +;; lib setup +(if (not (set? reduce)) + ((echo "need map. Include userlib.f") + (exit -1))) ;; basic goals -;; (def get-sym-deps -;; 'gets all global symbols referenced by the definition of a symbol' -;; (sym) ;; probably just iter over and call 'set?' on symbols -;; ()) ;; then return a stack of symbols +;; (def get-tree-deps +;; 'Gets all global symbols referenced by the definition of a symbol. +;; assumes symbol is passed in quoted. Essentially this function expects +;; a tree.' +;; (sym) +;; (reduce (lambda (res elem) (cond ((sym? elem) ;; symbol case +;; () +;; ((list? elem) ;; list case +;; (extend results (get-tree-deps (eval elem))))))) +;; sym)) ;; then return a stack of symbols -;; (def dump-sym +;; (def dump-tree ;; 'writes a symbol to a library file' ;; (sym lib) ;; check if lib exists ;; ()) ;; write to lib -;; (def dump-sym-with-deps +;; (def dump-tree-with-deps ;; 'writes a symbol, with all its dependencies, to a file' ;; (sym lib) ;; make a list of sym and all its deps ;; ()) ;; iterate over that list and add new elements that are deps of iter diff --git a/snippets/userlib-tests.f b/snippets/userlib-tests.f index f2d8019..a0aa4c0 100644 --- a/snippets/userlib-tests.f +++ b/snippets/userlib-tests.f @@ -20,44 +20,44 @@ ;; this file implements unit tests for handwritten userlib functions (def passed -'prints if a test has passed' +"prints if a test has passed" (test) (echo (concat "PASSED: " test))) (def failed -'prints if a test has failed' +"prints if a test has failed" (test) (let (()) (echo (concat "FAILED: " test)) (exit 1))) -(def test-cases 'all test cases' - (('set updates var' +(def test-cases "all test cases" + (("set updates var" (quote (let ((test-val 0)) (set (q test-val) 3) (eq? test-val 3)))) - ('prepend prepends to list' + ("prepend prepends to list" (quote (let ((list (2 3 4)) (list (prepend 1 list)) (list-head (pop list))) (eq? (car list-head) 1)))) - ('map applies function across list' + ("map applies function across list" (quote (let ((list (1 2 3)) (adder (lambda (x) (add 1 x)))) (eq? (map adder list) (2 3 4))))) - ('reduce function adds numbers' + ("reduce function adds numbers" (quote (let ((list (1 2 3)) (adder (lambda (x y) (add x y)))) (eq? (reduce adder list) (add 1 2 3))))) - ('cond evaluates the first branch that returns true' + ("cond evaluates the first branch that returns true" (quote (let ((switch-one false) (switch-two false) @@ -68,7 +68,7 @@ (true (toggle switch-three))))) (and (not switch-one) switch-two (not switch-three))))) - ('cond doesnt do anything if all the branches are false' + ("cond doesnt do anything if all the branches are false" (quote (let ((switch-one false) (switch-two false) @@ -79,27 +79,32 @@ (false (toggle switch-three))))) (and (not switch-one) (not switch-two) (not switch-three))))) - ('cond returns the result of the branch that is evaluated' + ("cond returns the result of the branch that is evaluated" (quote - (let ((variable false)) + (let ((variable "2")) (set (q variable) (cond (q - ((true true))))) - variable))) + ((true "1"))))) + (eq? variable "1")))) - ('contains? finds elem in list' + ("cond does not choke on nil evaluated result" + (quote + (cdr ((cond (q ((true (assert true))))) + true)))) + + ("contains? finds elem in list" (quote (contains? (1 2 3) 1))) - ('contains? finds last elem in list' + ("contains? finds last elem in list" (quote (contains? (1 2 3) 3))) - ('contains? doesnt find elem not in list' + ("contains? doesnt find elem not in list" (quote (not (contains? (1 2 3) 4)))) - ('get-paths properly splits path into segments' + ("get-paths properly splits path into segments" (quote (let ((PATH "/seg1:/seg2") (split-path (get-paths))) @@ -107,20 +112,20 @@ (contains? split-path "/seg1") (contains? split-path "/seg2"))))) - ('add-path properly adds a new path segment to PATH' + ("add-path properly adds a new path segment to PATH" (quote (let ((PATH "/seg1:/seg2") (new-path "/seg3")) (add-path new-path) (contains? (get-paths) new-path)))) - ('join operates as expected' + ("join operates as expected" (quote (let ((l ("1" 2 (3)))) (eq? (join l ".") "1.2.(3)")))) - ('extend extends sets' + ("extend extends sets" (quote (let ((s1 (1 2 3)) (s2 (4 5 6))) diff --git a/snippets/userlib.f b/snippets/userlib.f index c54167c..4d07d56 100644 --- a/snippets/userlib.f +++ b/snippets/userlib.f @@ -36,13 +36,13 @@ ;; this would be way faster as code in stl ;; but stl already suffers scope creep (def prepend -'takes a list and appends an element to the back of it. - returns prepended list' +"takes a list and appends an element to the back of it. + returns prepended list" (elem list) (reverse (cons (reverse list) elem))) (def set -'sets an existing variable without touching its docstring. +"sets an existing variable without touching its docstring. WARNING: If you find yourself struggling to debug a complex error in state access, @@ -56,89 +56,90 @@ A cozy script in flesh is one where each root level form (or eval at repl) is self contained, and does not permanently modify any other one. - See the userlib tests for an easy to follow example of this.' + See the userlib tests for an easy to follow example of this." (var val) (let ((doc (get-doc var))) (def (eval var) doc val))) (def map -'Takes two arguments: a function and a list. +"Takes two arguments: a function and a list. for each element in the list, the function is applied and the -result is added to a new list. Returns the new list.' +result is added to a new list. Returns the new list." (func list) (let ((list-iter (pop list)) (result ())) (while (gt? (len list-iter) 1) - (let ((current (car list-iter)) - (remaining (cdr list-iter)) + (let ((current (car list-iter)) + (remaining (cdr list-iter)) (current-res (func current))) - (set (q result) (cons result current-res)) + (set (q result) (cons result current-res)) (set (q list-iter) (pop remaining)))) result)) (def reduce -'Takes two arguments: a function and a list. +"Takes two arguments: a function and a list. The function is expected to take two arguments: * the current list item * the previous result Initially the function will take element1 and element2, outputting result1. Then the function will take result1 and element3, outputting result2. -this will continue iuntil the list is exhausted.' +this will continue iuntil the list is exhausted." (func list) (let ((list-iter (pop list)) - (result (car list-iter))) + (result (car list-iter))) (set (q list-iter) (pop (cdr list-iter))) (if (lt? (len list) 2) (echo "list too short!") (while (gt? (len list-iter) 1) - (let ((current (car list-iter)) + (let ((current (car list-iter)) (remaining (cdr list-iter))) - (set (q result) (func result current)) + (set (q result) (func result current)) (set (q list-iter) (pop remaining))))) result)) (def cond -'Takes one argument: a list of pairs consisting of a form returning a bool and a form to execute -The function iterates over the list checking if the first form of a pair evaluates to true, in which -case it will execute the second form of the pair, returning its result, and stop the loop.' +"Takes one argument: a list of pairs consisting of a form containing a bool and a form to execute +The function iterates over the list checking if the first element of each form evaluates to true, if so it will execute the second form of the pair, returning its result, and stop the loop." (list) - (let ((iter list)) - (while (gt? (len iter) 0) - (let ((current (car iter)) - (remaining (pop iter))) - (if (eval (car current)) - (car (pop ((set (q iter) ()) - (eval (cdr current))))) - (set (q iter) (cdr remaining))))))) +(let ((iter list)) + (while (gt? (len iter) 0) + (let ((current (car iter)) + (remaining (pop iter))) + (if (eval (car current)) + (let ((res (eval (cdr current)))) + (set (q iter) ()) + res) + (set (q iter) (cdr remaining))))))) + (def contains? -'Takes two arguments: a list and an element. -Returns true if the list contains the element.' +"Takes two arguments: a list and an element. +Returns true if the list contains the element." (list elem) -(let ((found false) +(let ((found false) (list-iter (pop list))) (while (and (gt? (len list-iter) 1) (not found)) - (let ((current (car list-iter)) + (let ((current (car list-iter)) (remaining (cdr list-iter))) (if (eq? current elem) - (set (q found) true) + (set (q found) true) (set (q list-iter) (pop remaining))))) found)) (def get-paths -'returns each individual directory in PATH' -() (split PATH ':')) +"returns each individual directory in PATH" +() (split PATH ":")) (def add-path -'Takes one argument. -adds a directory to PATH' +"Takes one argument. +adds a directory to PATH" (path) (set (q PATH) - (concat PATH ':' path))) + (concat PATH ":" path))) (def display-paths -'prints out each element of $PATH one by one' +"prints out each element of $PATH one by one" () (let ((path-iter (pop (get-paths)))) (while (gt? (len path-iter) 1) @@ -148,17 +149,17 @@ adds a directory to PATH' (set (q path-iter) (pop rem)))))) (def join -'concatenates list elements into a string, while -interspersing a provided delimiter in between elements' +"concatenates list elements into a string, while +interspersing a provided delimiter in between elements" (list delim) (reduce (lambda (res elem) (if (eq? (strlen res) 0) - (string elem) + (string elem) (concat res delim elem))) list)) (def extend -'adds all elements in set2 to set1' +"adds all elements in set2 to set1" (set1 set2) (reduce (lambda (res elem) (cons res elem)) (prepend set1 set2))) diff --git a/tests/test_lib_posix.rs b/tests/test_lib_posix.rs deleted file mode 100644 index 295767d..0000000 --- a/tests/test_lib_posix.rs +++ /dev/null @@ -1,103 +0,0 @@ -mod posix_tests { - use flesh::aux::args_from_ast; - use flesh::stdlib::{dynamic_stdlib, static_stdlib}; - use flesh::ast::{lex, eval, SymTable}; - - #[test] - fn test_cmd_singlet() { - let document = "(binary)"; - let result = vec!["binary"]; - - let mut syms = SymTable::new(); - static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); - - if let Ok(ref s) = lex(&document.to_string()) { - assert_eq!( - args_from_ast(s, &mut syms), - result - ) - } else { - panic!() - } - } - - #[test] - fn test_cmd_list() { - let document = "(binary --flag=1 122 'yeet' true)"; - let result = vec!["binary", "--flag=1", "122", "yeet", "true"]; - - let mut syms = SymTable::new(); - static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); - - if let Ok(ref s) = lex(&document.to_string()) { - assert_eq!( - args_from_ast(s, &mut syms), - result - ) - } else { - panic!() - } - } - - #[test] - fn test_cmd_syms_undef() { - let document = "(binary --flag=1 122 'yeet' true syms)"; - let result = vec!["binary", "--flag=1", "122", "yeet", "true", "syms"]; - - let mut syms = SymTable::new(); - static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); - - if let Ok(ref s) = lex(&document.to_string()) { - assert_eq!( - args_from_ast(s, &mut syms), - result - ) - } else { - panic!() - } - } - - #[test] - fn test_cmd_syms_unwrap_simple() { - let decl = "(def syms '' 1)"; - let document = "(binary --flag=1 122 'yeet' true syms)"; - let result = vec!["binary", "--flag=1", "122", "yeet", "true", "1"]; - - let mut syms = SymTable::new(); - static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); - - eval(&lex(&decl.to_string()).unwrap(), &mut syms).unwrap(); - - if let Ok(ref s) = lex(&document.to_string()) { - assert_eq!( - args_from_ast(s, &mut syms), - result - ) - } else { - panic!() - } - } - - #[test] - fn test_cmd_syms_unwrap_eval() { - let document = "(binary --flag=1 122 'yeet' true (add 1 2))"; - let result = vec!["binary", "--flag=1", "122", "yeet", "true", "3"]; - - let mut syms = SymTable::new(); - static_stdlib(&mut syms); - dynamic_stdlib(&mut syms, None); - - if let Ok(ref s) = lex(&document.to_string()) { - assert_eq!( - args_from_ast(s, &mut syms), - result - ) - } else { - panic!() - } - } -}