diff --git a/crsn/src/asm/parse/parse_instr.rs b/crsn/src/asm/parse/parse_instr.rs index 8f24234..8dfff40 100644 --- a/crsn/src/asm/parse/parse_instr.rs +++ b/crsn/src/asm/parse/parse_instr.rs @@ -1,4 +1,4 @@ -use sexp::{Sexp, SourcePosition}; +use sexp::{Sexp, SourcePosition, Atom}; use crate::asm::error::CrsnError; use crate::asm::instr::{Flatten, InstrWithBranches}; @@ -25,6 +25,7 @@ pub fn parse_instructions(items: impl Iterator, pos: &SourcePosition, continue; } + // Let extensions parse custom syntax let mut token_parser = TokenParser::new(toki.collect(), &listpos, pcx); for p in pcx.parsers { token_parser = match p.parse_syntax(pos, &name, token_parser) { @@ -43,12 +44,25 @@ pub fn parse_instructions(items: impl Iterator, pos: &SourcePosition, } // Get back the original iterator - let toki = token_parser.into_iter(); + let token_count = token_parser.len(); + let toki : std::vec::IntoIter = token_parser.into_iter(); - let arg_tokens = TokenParser::new(toki.clone().take_while(|e| e.is_atom()).collect(), &listpos, pcx); - let branch_tokens = toki - .skip_while(|e| e.is_atom()) - .take_while(|e| e.is_list()); + let branch_tokens = toki.clone().rev() + .take_while(|e| { + if let Sexp::List(ref items, _) = e { + if items.len() > 1 { + if let Sexp::Atom(Atom::S(ref kw), _) = items[0] { + if kw.ends_with('?') { + return true; + } + } + } + } + false + }) + .collect::>(); + + let arg_tokens = TokenParser::new(toki.take(token_count - branch_tokens.len()).collect(), &listpos, pcx); let branches = { let mut branches = vec![]; diff --git a/crsn/src/builtin/defs.rs b/crsn/src/builtin/defs.rs index 6c01f63..2769b9c 100644 --- a/crsn/src/builtin/defs.rs +++ b/crsn/src/builtin/defs.rs @@ -15,6 +15,21 @@ pub enum Barrier { Standalone, } +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum SleepUnit { + Usec, Msec, Sec +} + +impl SleepUnit { + pub fn micros(self) -> u64 { + match self { + SleepUnit::Usec => 1, + SleepUnit::Msec => 1000, + SleepUnit::Sec => 1000000, + } + } +} + #[derive(Debug)] pub enum BuiltinOp { /// Do nothing (costs one cycle) @@ -23,7 +38,8 @@ pub enum BuiltinOp { Halt, /// Sleep Sleep { - micros: Rd, + count: Rd, + unit_us: SleepUnit, }, /// Mark a jump target. Label(Label), @@ -57,9 +73,9 @@ pub enum BuiltinOp { /// Copy value Move { dst: Wr, src: Rd }, /// Store runtime status to a register - StoreStatus { dst: Wr }, + StoreFlags { dst: Wr }, /// Load runtime status from a register - LoadStatus { src: Rd }, + LoadFlags { src: Rd }, } impl BuiltinOp { diff --git a/crsn/src/builtin/exec.rs b/crsn/src/builtin/exec.rs index ff2861b..a3ad142 100644 --- a/crsn/src/builtin/exec.rs +++ b/crsn/src/builtin/exec.rs @@ -109,16 +109,16 @@ impl OpTrait for BuiltinOp { state.update_status(val); state.write(*dst, val)?; } - BuiltinOp::StoreStatus { dst } => { + BuiltinOp::StoreFlags { dst } => { let packed = state.frame.status.store(); state.write(*dst, packed)?; } - BuiltinOp::LoadStatus { src } => { + BuiltinOp::LoadFlags { src } => { let x = state.read(*src)?; state.frame.status.load(x); } - BuiltinOp::Sleep { micros } => { - std::thread::sleep(Duration::from_micros(state.read(*micros)?)) + BuiltinOp::Sleep { count: micros, unit_us } => { + std::thread::sleep(Duration::from_micros(state.read(*micros)? * unit_us.micros())) } BuiltinOp::Delete(obj) => { let x = state.read(Rd::new(RdData::Register(obj.reg())))?; diff --git a/crsn/src/builtin/parse.rs b/crsn/src/builtin/parse.rs index 9a62adb..445f2f2 100644 --- a/crsn/src/builtin/parse.rs +++ b/crsn/src/builtin/parse.rs @@ -8,7 +8,7 @@ use crate::asm::parse::arg_parser::TokenParser; use crate::asm::parse::parse_data::{parse_constant_name, parse_label, parse_label_str, parse_rd, parse_reg_alias, parse_value}; use crate::asm::parse::sexp_expect::{expect_any_string_atom}; use crate::asm::patches::ErrWithPos; -use crate::builtin::defs::{Barrier, BuiltinOp}; +use crate::builtin::defs::{Barrier, BuiltinOp, SleepUnit}; use crate::module::ParseRes; use crate::utils::A; @@ -24,9 +24,24 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok BuiltinOp::Halt } - "sleep" => { + "uslp" => { BuiltinOp::Sleep { - micros: args.next_rd()?, + count: args.next_rd()?, + unit_us: SleepUnit::Usec, + } + } + + "mslp" => { + BuiltinOp::Sleep { + count: args.next_rd()?, + unit_us: SleepUnit::Msec, + } + } + + "sslp" => { + BuiltinOp::Sleep { + count: args.next_rd()?, + unit_us: SleepUnit::Sec, } } @@ -126,7 +141,7 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok BuiltinOp::Routine(parse_routine_name(name.0, &name.1)?) } - "skip" => { + "s" => { BuiltinOp::Skip(args.next_rd()?) } @@ -168,14 +183,14 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok } } - "sst" => { - BuiltinOp::StoreStatus { + "stf" => { + BuiltinOp::StoreFlags { dst: args.next_wr()?, } } - "sld" => { - BuiltinOp::LoadStatus { + "ldf" => { + BuiltinOp::LoadFlags { src: args.next_rd()?, } } @@ -224,7 +239,9 @@ pub(crate) fn to_sexp(op: &BuiltinOp) -> Sexp { match op { BuiltinOp::Nop => sexp::list(&[A("nop")]), BuiltinOp::Halt => sexp::list(&[A("halt")]), - BuiltinOp::Sleep { micros } => sexp::list(&[A("sleep"), A(micros)]), + BuiltinOp::Sleep { count: micros, unit_us: SleepUnit::Sec } => sexp::list(&[A("sslp"), A(micros)]), + BuiltinOp::Sleep { count: micros, unit_us: SleepUnit::Msec } => sexp::list(&[A("mslp"), A(micros)]), + BuiltinOp::Sleep { count: micros, unit_us: SleepUnit::Usec } => sexp::list(&[A("uslp"), A(micros)]), BuiltinOp::Label(label) => sexp::list(&[A(label)]), BuiltinOp::Jump(label) => sexp::list(&[A("j"), A(label)]), BuiltinOp::FarLabel(label) => sexp::list(&[A("far"), A(label)]), @@ -248,7 +265,7 @@ pub(crate) fn to_sexp(op: &BuiltinOp) -> Sexp { } } BuiltinOp::Routine(name) => sexp::list(&[A("routine"), A(name)]), - BuiltinOp::Skip(n) => sexp::list(&[A("skip"), A(n)]), + BuiltinOp::Skip(n) => sexp::list(&[A("s"), A(n)]), BuiltinOp::Barrier { kind, msg } => { let mut inner = vec![]; match kind { @@ -279,8 +296,8 @@ pub(crate) fn to_sexp(op: &BuiltinOp) -> Sexp { } BuiltinOp::Delete(obj) => sexp::list(&[A("del"), A(obj)]), BuiltinOp::Move { dst, src } => sexp::list(&[A("ld"), A(dst), A(src)]), - BuiltinOp::StoreStatus { dst } => sexp::list(&[A("sst"), A(dst)]), - BuiltinOp::LoadStatus { src } => sexp::list(&[A("sld"), A(src)]) + BuiltinOp::StoreFlags { dst } => sexp::list(&[A("stf"), A(dst)]), + BuiltinOp::LoadFlags { src } => sexp::list(&[A("ldf"), A(src)]) } } @@ -302,26 +319,28 @@ mod test { // jump is translated to a skip ("(nop)", "(nop)"), ("(halt)", "(halt)"), - ("(sleep 1000)", "(sleep 1000)"), - ("(sleep 1_0_0_0)", "(sleep 1000)"), - ("(sleep ' ')", "(sleep 32)"), - ("(sleep '\\n')", "(sleep 10)"), - ("(sleep 0b111)", "(sleep 7)"), - ("(sleep 0xab_cd)", "(sleep 43981)"), - ("(sleep #ab_cd)", "(sleep 43981)"), + ("(uslp 1000)", "(uslp 1000)"), + ("(uslp 1_0_0_0)", "(uslp 1000)"), + ("(uslp ' ')", "(uslp 32)"), + ("(uslp '\\n')", "(uslp 10)"), + ("(uslp 0b111)", "(uslp 7)"), + ("(uslp 0xab_cd)", "(uslp 43981)"), + ("(uslp #ab_cd)", "(uslp 43981)"), + ("(mslp 1000)", "(mslp 1000)"), + ("(sslp 1000)", "(sslp 1000)"), ("(:x)", "(:x)"), ("(j :x)", "(j :x)"), ("(:#7)", "(:#7)"), ("(j :#7)", "(j :#7)"), ("(fj :x)", "(fj :x)"), - ("(skip 0)", "(skip 0)"), - ("(skip r0)", "(skip r0)"), - ("(sym banana r0)(unsym banana)(sym banana r1)(skip banana)", "(skip r1)"), - ("(def foo 123)(skip foo)", "(skip 123)"), - ("(def foo 123)(undef foo)(def foo 444)(skip foo)", "(skip 444)"), - ("(def foo -777)(def bar foo)(skip bar)", "(skip -777)"), - ("(skip -10)", "(skip -10)"), - ("(skip -10000)", "(skip -10000)"), + ("(s 0)", "(s 0)"), + ("(s r0)", "(s r0)"), + ("(sym banana r0)(unsym banana)(sym banana r1)(s banana)", "(s r1)"), + ("(def foo 123)(s foo)", "(s 123)"), + ("(def foo 123)(undef foo)(def foo 444)(s foo)", "(s 444)"), + ("(def foo -777)(def bar foo)(s bar)", "(s -777)"), + ("(s -10)", "(s -10)"), + ("(s -10000)", "(s -10000)"), ("(call funcname)", "(call funcname)"), ("(call funcname 13)", "(call funcname 13)"), ("(sym haf r0)\ @@ -348,8 +367,8 @@ mod test { ("(ld r0 r0)", "(ld r0 r0)"), ("(ld r0 156)", "(ld r0 156)"), ("(ld _ -32767)", "(ld _ -32767)"), - ("(sst r0)", "(sst r0)"), - ("(sld r0)", "(sld r0)"), + ("(stf r0)", "(stf r0)"), + ("(ldf r0)", "(ldf r0)"), ("(far :label)", "(far :label)"), ("(del @r5)", "(del @r5)"), ("(sym cat r0)(del @cat)", "(del @r0)"), diff --git a/crsn/src/module/mod.rs b/crsn/src/module/mod.rs index 3d2e672..8ea65c7 100644 --- a/crsn/src/module/mod.rs +++ b/crsn/src/module/mod.rs @@ -82,7 +82,7 @@ pub trait CrsnExtension: Debug + Send + Sync + 'static { /// pcx is available on the arg_tokens parser fn parse_op<'a>(&self, pos: &SourcePosition, keyword: &str, arg_tokens: TokenParser<'a>) -> Result, CrsnError>; - /// Parse a generic S-expression (non-op) + /// Parse a generic S-expression (non-op) that started with the given keyword /// /// pcx is available on the arg_tokens parser fn parse_syntax<'a>(&self, pos: &SourcePosition, keyword: &str, tokens: TokenParser<'a>) diff --git a/crsn_buf/src/defs.rs b/crsn_buf/src/defs.rs index 7a72cd1..d397ad9 100644 --- a/crsn_buf/src/defs.rs +++ b/crsn_buf/src/defs.rs @@ -1,5 +1,4 @@ use crsn::asm::data::{Rd, RdObj, Wr}; -use crsn::asm::data::literal::Value; #[derive(Clone, Debug, PartialEq)] pub enum BufValue { diff --git a/crsn_buf/src/exec.rs b/crsn_buf/src/exec.rs index 5c2281f..1ba3d18 100644 --- a/crsn_buf/src/exec.rs +++ b/crsn_buf/src/exec.rs @@ -1,6 +1,5 @@ use std::collections::{HashMap, VecDeque}; -use crsn::asm::data::{Rd, RdObj, Wr}; use crsn::asm::data::literal::Value; use crsn::asm::instr::Cond; use crsn::module::{EvalRes, OpTrait}; diff --git a/crsn_buf/src/parse.rs b/crsn_buf/src/parse.rs index e51dc45..336be9c 100644 --- a/crsn_buf/src/parse.rs +++ b/crsn_buf/src/parse.rs @@ -6,7 +6,6 @@ use crsn::sexp::{SourcePosition, Sexp, Atom}; use crate::defs::{BufOps, BufValue}; use crsn::asm::data::Rd; -use crsn::sexp; use crsn::asm::parse::parse_data::parse_rd; pub(crate) fn parse<'a>(_pos: &SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result, CrsnError> { diff --git a/examples/mouse.csn b/examples/mouse.csn index 96cebd2..b4a4d2f 100644 --- a/examples/mouse.csn +++ b/examples/mouse.csn @@ -16,7 +16,7 @@ (call draw_box x y) (:next) - (sleep 500) + (uslp 500) (j :loop) (proc draw_box x y diff --git a/examples/number_array.csn b/examples/number_array.csn new file mode 100644 index 0000000..17e594b --- /dev/null +++ b/examples/number_array.csn @@ -0,0 +1,8 @@ +( + (ld r0 65) + (sym buf r7) + (mkbfv buf (r0 66 67 68 '\n')) + + (bfrpop @stdout @buf) + (s.nem -1) +)