From 2cd5016c1d1a910c379c92249ba43ebcc65c18a1 Mon Sep 17 00:00:00 2001 From: Ava Hahn Date: Tue, 20 Jun 2023 01:25:19 +0000 Subject: [PATCH] Assert, Exit builtins * Builtins for assert and exit are added * Tests for assert are added * file operations from previous MR are added to documents * assert and exit are added to documents --- Readme.org | 3 -- Writing.org | 58 +++++++++++++++++++------------------- snippets/userlib-tests.rls | 4 ++- snippets/userlib.rls | 14 +++++++++ src/stl/control.rs | 56 +++++++++++++++++++++++++++++++++++- tests/test_lib_control.rs | 18 ++++++++++++ 6 files changed, 119 insertions(+), 34 deletions(-) diff --git a/Readme.org b/Readme.org index 0ce26e6..0d8d505 100644 --- a/Readme.org +++ b/Readme.org @@ -156,12 +156,9 @@ Note: this section only tracks the state of incomplete TODO items. Having everyt (See tag: v0.3.0) ** TODO v1.0 tasks - islist type query -- assert function - set library - Can pass args to relish scripts (via interpreter) - Can pass args to relish scripts (via command line) -- File operations - - (add this all to the readme) - finish basic goals in the [[file:snippets/interactive-devel.rls][interactive development library]] - Release CI - Rename to Flesh diff --git a/Writing.org b/Writing.org index 18c193a..91c826c 100644 --- a/Writing.org +++ b/Writing.org @@ -283,35 +283,35 @@ The following table is up to date as of Relish 0.3.0. For latest information try - Call ~env~ from a fresh shell: ~(env)~ This will output all variables and functions defined - Read the [[file:src/stl.rs][std library declaration code]] -| *Control Flow* | *Declaration* | *Shell* | *List* | *Math* | *Strings* | *Boolean* | *Userlib* | *Misc* | -|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------| -| if | lambda | pipe | car | float | strlen | toggle | reduce | call | -|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------| -| let | q / quote | load-to-string | len | sub | substr? | bool | prepend | help | -|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------| -| circuit | def | load / l | cons | mul | echo | and | add-path | env | -|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------| -| while | get-doc | load-with | cdr | inc | split | eq? | set | eval | -|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------| -| | set-doc | cd | reverse | dec | input | not | map | | -|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------| -| | set? | fg | dq | div | concat | or | get-paths | | -|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------| -| | | | pop | gte? | string | | cond | | -|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------| -| | | | | int | | | | | -|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------| -| | | | | mod | | | | | -|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------| -| | | | | exp | | | | | -|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------| -| | | | | lt? | | | | | -|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------| -| | | | | gt? | | | | | -|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------| -| | | | | add | | | | | -|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------| -| | | | | lte? | | | | | +| *Control Flow* | *Declaration* | *Shell* | *List* | *Math* | *Strings* | *Boolean* | *Userlib* | *Misc* | *Files* | +|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------+-------------| +| if | lambda | pipe | car | float | strlen | toggle | reduce | call | read-file | +|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------+-------------| +| let | q / quote | load-to-string | len | sub | substr? | bool | prepend | help | append-file | +|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------+-------------| +| circuit | def | load / l | cons | mul | echo | and | add-path | env | write-file | +|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------+-------------| +| while | get-doc | load-with | cdr | inc | split | eq? | set | eval | exists? | +|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------+-------------| +| assert | set-doc | cd | reverse | dec | input | not | map | | | +|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------+-------------| +| exit | set? | fg | dq | div | concat | or | get-paths | | | +|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------+-------------| +| | | | pop | gte? | string | | cond | | | +|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------+-------------| +| | | | | int | | | | | | +|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------+-------------| +| | | | | mod | | | | | | +|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------+-------------| +| | | | | exp | | | | | | +|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------+-------------| +| | | | | lt? | | | | | | +|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------+-------------| +| | | | | gt? | | | | | | +|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------+-------------| +| | | | | add | | | | | | +|----------------+---------------+----------------+---------+--------+-----------+-----------+-----------+--------+-------------| +| | | | | lte? | | | | | | To learn how to use a given function use the ~help~ command. See the Documentation section for more information. diff --git a/snippets/userlib-tests.rls b/snippets/userlib-tests.rls index 93ed8f8..ed07796 100644 --- a/snippets/userlib-tests.rls +++ b/snippets/userlib-tests.rls @@ -27,7 +27,9 @@ (def failed 'prints if a test has failed' (test) - (echo (concat "FAILED: " test))) + (let (()) + (echo (concat "FAILED: " test)) + (exit 1))) (def test-cases 'all test cases' (('set updates var' diff --git a/snippets/userlib.rls b/snippets/userlib.rls index 16d8a5f..f9cfb81 100644 --- a/snippets/userlib.rls +++ b/snippets/userlib.rls @@ -18,6 +18,20 @@ ;; USERLIB ;; This file contains useful features that are not shipped in the STL +;; TODO +;; dir-path +;; abs-path +;; rel-path +;; unique (make set) +;; set add +;; set del +;; superset +;; common-set +;; make-map +;; ins-mapping +;; del-mapping +;; get-mapping +;; mapped? ;; this would be way faster as code in stl ;; but stl already suffers scope creep diff --git a/src/stl/control.rs b/src/stl/control.rs index 5f76992..d751e98 100644 --- a/src/stl/control.rs +++ b/src/stl/control.rs @@ -17,9 +17,10 @@ use crate::eval::eval; use crate::error::{Traceback, start_trace}; -use crate::segment::{Ctr, Seg}; +use crate::segment::{Ctr, Seg, Type}; use crate::sym::{SymTable, Symbol, ValueType, Args}; use std::rc::Rc; +use std::process; const IF_DOCSTRING: &str = "accepts three bodies, a condition, an unevaluated consequence, and an alternative consequence. @@ -381,7 +382,60 @@ fn circuit_callback(ast: &Seg, syms: &mut SymTable) -> Result { } } +const ASSERT_DOCSTRING: &str = "Takes one input: a boolean (or form that evaluates to a boolean). +If input is false, a traceback is started and code throws an error. +Otherwise, if input is true, returns None."; +fn assert_callback(ast: &Seg, _syms: &mut SymTable) -> Result { + if let Ctr::Bool(b) = *ast.car { + if b { + Ok(Ctr::None) + } else { + Err(start_trace(("assert", "assertion failed").into())) + } + } else { + Err(start_trace(("assert", "impossible arg").into())) + } +} + +const EXIT_DOCSTRING: &str = "Takes on input: an integer used as an exit code. +Entire REPL process quits with exit code."; +fn exit_callback(ast: &Seg, _syms: &mut SymTable) -> Result { + if let Ctr::Integer(i) = *ast.car { + if i > 2 ^ 32 { + panic!("argument to exit too large!") + } else { + process::exit(i as i32); + } + } else { + panic!("impossible argument to exit") + } +} + pub fn add_control_lib(syms: &mut SymTable) { + syms.insert( + "exit".to_string(), + Symbol { + name: String::from("exit"), + args: Args::Strict(vec![Type::Integer]), + conditional_branches: false, + docs: EXIT_DOCSTRING.to_string(), + value: ValueType::Internal(Rc::new(exit_callback)), + ..Default::default() + }, + ); + + syms.insert( + "assert".to_string(), + Symbol { + name: String::from("assert"), + args: Args::Strict(vec![Type::Bool]), + conditional_branches: false, + docs: ASSERT_DOCSTRING.to_string(), + value: ValueType::Internal(Rc::new(assert_callback)), + ..Default::default() + }, + ); + syms.insert( "if".to_string(), Symbol { diff --git a/tests/test_lib_control.rs b/tests/test_lib_control.rs index 5a513fa..1474716 100644 --- a/tests/test_lib_control.rs +++ b/tests/test_lib_control.rs @@ -2,6 +2,24 @@ mod control_lib_tests { use relish::ast::{eval, lex, SymTable}; use relish::stdlib::{dynamic_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(); + } + + #[test] + fn test_assert_f() { + 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()) + } + #[test] fn test_if_first_case_singlet() { let document = "(if true 1 2)";