From 0689bdbea01542928160801343f2cb0b29d3653b Mon Sep 17 00:00:00 2001 From: TudbuT Date: Fri, 7 Apr 2023 22:03:36 +0200 Subject: [PATCH] add postfix argument notation --- src/lexer.rs | 24 ++++++++++++++++++++---- src/main.rs | 8 ++++++-- src/runtime.rs | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/src/lexer.rs b/src/lexer.rs index 251aee5..2633fd1 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -10,6 +10,7 @@ pub enum LexerError { InvalidInclude, InvalidConstructBlock, InvalidNumber(String), + ArgsWithoutCall, } pub fn lex(input: String) -> Result { @@ -65,6 +66,24 @@ fn read_block(str_words: &[String], isfn: bool) -> Result<(Option, Words, u name: "dyn".to_owned(), })))) } + "<{" => { + let block = read_block(&str_words[i + 1..], false)?; + i += block.2 + 1; + let mut block = block.1.words; + match words.remove(words.len() - 1) { + Word::Call(a, b, c) => { + words.append(&mut block); + words.push(Word::Call(a, b, c)); + } + Word::ObjCall(a, b, c) => { + words.push(Word::Key(Keyword::ObjPush)); + words.append(&mut block); + words.push(Word::Key(Keyword::ObjPop)); + words.push(Word::ObjCall(a, b, c)); + } + _ => return Err(LexerError::ArgsWithoutCall), + } + } "construct" => { let name = str_words[i + 1].to_owned(); let is_namespace = if str_words[i + 2] == "namespace" { @@ -190,10 +209,7 @@ fn read_block(str_words: &[String], isfn: bool) -> Result<(Option, Words, u ))); } x => { - let mut word = x - .split(':') - .next() - .unwrap(); // SAFETY: One item always exists after a split. + let mut word = x.split(':').next().unwrap(); // SAFETY: One item always exists after a split. if !word.is_empty() { let mut ra = 0; while word.starts_with('&') { diff --git a/src/main.rs b/src/main.rs index e3f2d1b..d9a0d3b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,13 @@ -use spl::{start_file, find_in_splpath}; +use spl::{find_in_splpath, start_file}; use std::env::args; fn main() { - if let Err(x) = start_file(&args().nth(1).unwrap_or_else(|| find_in_splpath("repl.spl").expect("no file to be run"))) { + if let Err(x) = start_file( + &args() + .nth(1) + .unwrap_or_else(|| find_in_splpath("repl.spl").expect("no file to be run")), + ) { println!("{x:?}"); } } diff --git a/src/runtime.rs b/src/runtime.rs index ad7cbe3..07b06ae 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -358,6 +358,7 @@ impl Frame { pub struct Stack { frames: Vec>, object_stack: Vec, + objcall_stack: Vec, files: Vec, pub return_accumultor: u32, } @@ -393,6 +394,7 @@ impl Stack { let mut r = Stack { frames: vec![o.clone()], object_stack: Vec::new(), + objcall_stack: Vec::new(), files: Vec::new(), return_accumultor: 0, }; @@ -409,6 +411,7 @@ impl Stack { let mut r = Stack { frames: vec![o.clone()], object_stack: Vec::new(), + objcall_stack: Vec::new(), files: Vec::new(), return_accumultor: 0, }; @@ -663,6 +666,20 @@ pub enum Keyword { /// encountered and the error is of (or, if no type is specified, any error). /// equivalent to \[ ["" <...>] \] { | } { | } dyn-catch Catch(Vec, Words, Words), + /// + /// + /// Used by `object:method <{ arg1 arg2 }` syntax. Generates as: + /// - CALL object + /// - OBJPUSH + /// - CALL arg1 + /// - CALL arg2 + /// - OBJPOP + /// - OBJCALL method + ObjPush, + /// + /// + /// see [Keyword::ObjPush] + ObjPop, } /// Any SPL value that is not a construct. @@ -840,7 +857,10 @@ impl Type { q.append(&mut VecDeque::from(t.lock_ro().parents.clone())); } for property in to_apply.into_iter().rev() { - object.property_map.entry(property).or_insert_with(|| Value::Null.spl()); + object + .property_map + .entry(property) + .or_insert_with(|| Value::Null.spl()); } } @@ -1199,6 +1219,17 @@ impl Words { stack.set_var(var, obj)?; } } + Keyword::ObjPush => { + let o = stack.pop(); + stack.objcall_stack.push(o); + } + Keyword::ObjPop => { + let o = stack + .objcall_stack + .pop() + .expect("invalid word generation. objpop without objpush!"); + stack.push(o); + } }, Word::Const(x) => { if option_env!("SPLDEBUG").is_some() {