From 7b89f4c10cbae465cf3bc54e9d65d2829f4cdd93 Mon Sep 17 00:00:00 2001 From: darcy Date: Wed, 4 Dec 2024 21:32:50 +1100 Subject: [PATCH] feat: parse `eval` instruction --- src/debugger/eval.rs | 30 +++++++++++++++++++++ src/debugger/mod.rs | 5 ++-- src/parser.rs | 64 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 src/debugger/eval.rs diff --git a/src/debugger/eval.rs b/src/debugger/eval.rs new file mode 100644 index 0000000..aeb0ca5 --- /dev/null +++ b/src/debugger/eval.rs @@ -0,0 +1,30 @@ +use miette::Result; + +use crate::{ + air::AirStmt, + lexer::{cursor::Cursor, TokenKind}, + runtime::RunState, + symbol::InstrKind, + AsmParser, +}; + +pub fn run(state: &mut RunState, line: String) { + let stmt = parse(line); + + println!("{:#?}", stmt); + + todo!(); +} + +fn parse(line: String) -> Result { + // TODO(fix): This is a TERRIBLE solution. Ideally cursor doesn't take &'static str ?? + let line = Box::leak(line.into_boxed_str()); + + let mut parser = AsmParser::new_simple(line)?; + + let stmt = parser.parse_simple()?; + + println!("{:#?}", stmt); + + todo!(); +} diff --git a/src/debugger/mod.rs b/src/debugger/mod.rs index 10e8aba..83269a9 100644 --- a/src/debugger/mod.rs +++ b/src/debugger/mod.rs @@ -1,4 +1,5 @@ mod command; +mod eval; mod parse; mod source; @@ -339,8 +340,8 @@ impl Debugger { Command::Eval { instruction } => { self.was_pc_changed = true; - dprintln!(Always, "<{}>", instruction); - dprintln!(Always, "unimplemented: eval") + dprintln!(Always, "Eval: <{}>", instruction); + eval::run(state, instruction); } Command::BreakAdd { location } => { diff --git a/src/parser.rs b/src/parser.rs index 15e5e48..7489377 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -81,6 +81,33 @@ pub fn preprocess(src: &'static str) -> Result> { Ok(res) } +fn preprocess_simple(src: &'static str) -> Result> { + let mut res: Vec = Vec::new(); + let mut cur = Cursor::new(src); + + loop { + let token = cur.advance_real()?; + match token.kind { + TokenKind::Instr(_) | TokenKind::Trap(_) => res.push(token), + + TokenKind::Comment | TokenKind::Whitespace => continue, + TokenKind::Eof => break, + + TokenKind::Dir(_) + | TokenKind::Label + | TokenKind::Lit(_) + | TokenKind::Reg(_) + | TokenKind::Byte(_) + | TokenKind::Breakpoint => { + // TODO(feat): Handle error + panic!("unexpected token `{:?}`", token.kind); + } + } + } + + Ok(res) +} + fn unescape(s: &str) -> Cow { if s.find('\\').is_none() { return Cow::Borrowed(s); @@ -137,6 +164,16 @@ impl AsmParser { }) } + pub fn new_simple(src: &'static str) -> Result { + let toks = preprocess_simple(src)?; + Ok(AsmParser { + src, + toks: toks.into_iter().peekable(), + air: Air::new(), + line: 1, + }) + } + fn get_span(&self, span: Span) -> &str { &self.src[span.offs()..span.end()] } @@ -200,6 +237,31 @@ impl AsmParser { Ok(self.air) } + pub fn parse_simple(&mut self) -> Result { + let Some(tok) = self.toks.next() else { + // TODO(feat): Handle error + panic!("unexpected eof (possibly unreachable)"); + }; + + match tok.kind { + TokenKind::Instr(instr_kind) => self.parse_instr(instr_kind), + TokenKind::Trap(trap_kind) => self.parse_trap(trap_kind), + + // Does not exist in preprocessed token stream + TokenKind::Comment + | TokenKind::Whitespace + | TokenKind::Eof + | TokenKind::Dir(_) + | TokenKind::Label + | TokenKind::Lit(_) + | TokenKind::Reg(_) + | TokenKind::Byte(_) + | TokenKind::Breakpoint => { + unreachable!("Found invalid token kind in preprocessed stream"); + } + } + } + /// Return label or leave iter untouched and return None fn optional_label(&mut self) -> Option { match self.toks.peek() { @@ -209,7 +271,7 @@ impl AsmParser { } /// Process several tokens to form valid AIR statement - fn parse_instr(&mut self, kind: InstrKind) -> Result { + pub fn parse_instr(&mut self, kind: InstrKind) -> Result { use crate::symbol::InstrKind; match kind { InstrKind::Push => {