From 388641da167b7a4bee4fd939e8c64b1352733ad8 Mon Sep 17 00:00:00 2001 From: Shane Date: Sat, 29 Jun 2024 20:21:25 -0400 Subject: [PATCH] Consistency with calling and auto-calling (#59) This is NOT a code-consistency or refactor PR. This is just to get the following working: - [x] Make lists be lists (no auto-calling for them anymore) - [x] Add a method to `Engine` specifically for calling an Expr, like a list or function - [x] Make s-expressions be auto-called just like functions --- stack-core/src/engine.rs | 34 +++++++++++++++++------- stack-core/src/intrinsic.rs | 6 ++--- stack-core/tests/intrinsics/pop.stack | 2 +- stack-core/tests/intrinsics/push.stack | 2 +- stack-core/tests/intrinsics/record.stack | 2 +- 5 files changed, 30 insertions(+), 16 deletions(-) diff --git a/stack-core/src/engine.rs b/stack-core/src/engine.rs index 4408b0fd..5ea96cf6 100644 --- a/stack-core/src/engine.rs +++ b/stack-core/src/engine.rs @@ -99,7 +99,18 @@ impl Engine { Ok(context) } - #[allow(clippy::only_used_in_recursion)] + pub fn call_expr( + &self, + mut context: Context, + expr: Expr, + ) -> Result { + let expr = context.scan_expr(expr)?; + match expr.kind { + ExprKind::List(exprs) => self.run(context, exprs), + _ => self.run_expr(context, expr), + } + } + pub fn run_expr( &self, mut context: Context, @@ -122,6 +133,7 @@ impl Engine { | ExprKind::Integer(_) | ExprKind::Float(_) | ExprKind::String(_) + | ExprKind::List(_) | ExprKind::Record(_) => { context.stack_push(expr)?; Ok(context) @@ -179,6 +191,9 @@ impl Engine { CallResult::None => unreachable!(), } } + } + if let ExprKind::SExpr { .. } = item.kind { + self.call_expr(context, item) } else { if let Some(journal) = context.journal_mut() { journal.push_op(JournalOp::Call(expr.clone())); @@ -202,7 +217,6 @@ impl Engine { context.stack_push(*x)?; Ok(context) } - ExprKind::List(ref x) => self.run(context, x.to_vec()), ExprKind::Function { ref scope, ref body, @@ -451,7 +465,7 @@ mod tests { // TODO: Move test for lets into a better place? #[test] fn can_use_lets() { - let source = Source::new("", "10 2 '[a b -] '[a b] let"); + let source = Source::new("", "10 2 [a b -] [a b] let"); let mut lexer = Lexer::new(source); let exprs = crate::parser::parse(&mut lexer).unwrap(); @@ -471,7 +485,7 @@ mod tests { #[test] fn lets_take_precedence_over_scope() { - let source = Source::new("", "0 'a def 1 '[a] '[a] let"); + let source = Source::new("", "0 'a def 1 [a] [a] let"); let mut lexer = Lexer::new(source); let exprs = crate::parser::parse(&mut lexer).unwrap(); @@ -491,7 +505,7 @@ mod tests { #[test] fn lets_do_not_act_as_overlays() { - let source = Source::new("", "0 'a def 1 '[a 2 'a def a] '[a] let a"); + let source = Source::new("", "0 'a def 1 [a 2 'a def a] [a] let a"); let mut lexer = Lexer::new(source); let exprs = crate::parser::parse(&mut lexer).unwrap(); @@ -515,7 +529,7 @@ mod tests { #[test] fn functions_work_in_lets() { - let source = Source::new("", "0 'a def 1 '[(fn a 2 'a def a)] '[a] let a"); + let source = Source::new("", "0 'a def 1 [(fn a 2 'a def a)] [a] let a"); let mut lexer = Lexer::new(source); let exprs = crate::parser::parse(&mut lexer).unwrap(); @@ -542,9 +556,9 @@ mod tests { let source = Source::new( "", "0 'a def - 1 '[a] '[a] let - 1 '[(fn! a)] '[a] let - 1 '[(fn a)] '[a] let + 1 [a] [a] let + 1 [(fn! a)] [a] let + 1 [(fn a)] [a] let a", ); let mut lexer = Lexer::new(source); @@ -571,7 +585,7 @@ mod tests { #[test] fn lets_can_set() { - let source = Source::new("", "1 '[a 2 'a set a] '[a] let"); + let source = Source::new("", "1 [a 2 'a set a] [a] let"); let mut lexer = Lexer::new(source); let exprs = crate::parser::parse(&mut lexer).unwrap(); diff --git a/stack-core/src/intrinsic.rs b/stack-core/src/intrinsic.rs index 7d6a43c7..3411d452 100644 --- a/stack-core/src/intrinsic.rs +++ b/stack-core/src/intrinsic.rs @@ -797,7 +797,7 @@ impl Intrinsic { let cond = context.stack_pop(&expr)?; if cond.kind.is_truthy() { - context = engine.run_expr(context, body)?; + context = engine.call_expr(context, body)?; } Ok(context) @@ -812,7 +812,7 @@ impl Intrinsic { // MARK: Call Self::Call => { let item = context.stack_pop(&expr)?; - engine.run_expr(context, item) + engine.call_expr(context, item) } // MARK: Let @@ -851,7 +851,7 @@ impl Intrinsic { } context.push_scope(scope); - context = engine.run_expr(context, body)?; + context = engine.call_expr(context, body)?; context.pop_scope(); if let Some(journal) = context.journal_mut() { diff --git a/stack-core/tests/intrinsics/pop.stack b/stack-core/tests/intrinsics/pop.stack index 3b246dc0..b61016ee 100644 --- a/stack-core/tests/intrinsics/pop.stack +++ b/stack-core/tests/intrinsics/pop.stack @@ -1,2 +1,2 @@ -(pop '[1 2 3]) +(pop [1 2 3]) (pop "he") diff --git a/stack-core/tests/intrinsics/push.stack b/stack-core/tests/intrinsics/push.stack index 8dec7a49..9c150680 100644 --- a/stack-core/tests/intrinsics/push.stack +++ b/stack-core/tests/intrinsics/push.stack @@ -1,4 +1,4 @@ -'[] +[] (push _ 1) (push _ 2) diff --git a/stack-core/tests/intrinsics/record.stack b/stack-core/tests/intrinsics/record.stack index abe5f7a8..e0e1d505 100644 --- a/stack-core/tests/intrinsics/record.stack +++ b/stack-core/tests/intrinsics/record.stack @@ -6,7 +6,7 @@ drop ;; Test casting -(cast '[["name" "john"] ["type" "person"]] "record") +(cast [["name" "john"] ["type" "person"]] "record") (= "john" (prop _ "name")) swap (= "person" (prop _ "type")) swap