summaryrefslogtreecommitdiffstats
path: root/src/forth
diff options
context:
space:
mode:
Diffstat (limited to 'src/forth')
-rw-r--r--src/forth/parser.rs83
1 files changed, 50 insertions, 33 deletions
diff --git a/src/forth/parser.rs b/src/forth/parser.rs
index 1eb93df..c934c4a 100644
--- a/src/forth/parser.rs
+++ b/src/forth/parser.rs
@@ -27,6 +27,14 @@ impl std::error::Error for ParseError {}
type ParseResult<T> = Result<T, ParseError>;
+// todo: the annotations should be directly tied to the wordlist so
+// they can't get out of sync.
+#[derive(Debug)]
+pub struct Annotation {
+ // (start, end) index in program text
+ pub loc: (usize, usize),
+}
+
#[derive(Debug)]
pub struct WordCatalog<'a>(pub(super) HashMap<&'a str, usize>);
@@ -44,6 +52,7 @@ pub struct Parser<'a> {
// routine is always in the first entry.
// todo: don't be pub, have a method to extract a wordlist
pub wordlist: WordList,
+ pub annotations: Vec<Vec<Annotation>>,
// catalog of word to word index in `wordlist`
pub wordalog: WordCatalog<'a>,
// holds a stack of indices into `wordlist` that are currently
@@ -52,7 +61,7 @@ pub struct Parser<'a> {
defstack: Vec<usize>,
// number of clauses currently being defined for a particular ‘if’
// construct. a stack is needed in order to allow for nesting.
- if_stack: Vec<IfClauses>,
+ if_stack: Vec<(IfClauses, Annotation)>,
}
impl<'a> Parser<'a> {
@@ -64,6 +73,7 @@ impl<'a> Parser<'a> {
text,
enumerator: text.chars().enumerate(),
wordlist: WordList(wl),
+ annotations: vec![vec![]],
wordalog: WordCatalog(HashMap::new()),
defstack: vec![],
if_stack: vec![],
@@ -93,21 +103,25 @@ impl<'a> Parser<'a> {
&self.wordlist.0[*word_index]
}
+ fn anno_mut(&mut self) -> &mut Vec<Annotation> {
+ let word_index = self.defstack.last().unwrap_or(&0);
+ &mut self.annotations[*word_index]
+ }
+
// push `op` onto the currently building bytecode, as determined
// by the top of the `namestack`.
- fn bc_push(&mut self, op: OpCode) -> ParseResult<()> {
- // let word_index = self.defstack.last().unwrap_or(&0);
- // self.wordlist.0[*word_index].0.push(op);
+ fn bc_push(&mut self, op: OpCode, anno: Annotation) {
self.bc_mut().0.push(op);
- Ok(())
+ self.anno_mut().push(anno);
}
pub fn parse(&mut self) -> ParseResult<()> {
- while let Some((word, _start, end)) = self.next_word() {
+ while let Some((word, start, end)) = self.next_word() {
+ let anno = Annotation { loc: (start, end) };
if let Ok(i) = word.parse::<i32>() {
- self.bc_push(OpCode::Num(i))?;
+ self.bc_push(OpCode::Num(i), anno);
} else if let Some(i) = self.wordalog.0.get(word) {
- self.bc_push(OpCode::Call(*i))?;
+ self.bc_push(OpCode::Call(*i), anno);
} else {
match word {
r#"s""# => {
@@ -115,13 +129,14 @@ impl<'a> Parser<'a> {
self.enumerator
.find(|(_i, c)| return *c == '"')
.ok_or(ParseError::MissingQuote)?;
- self.bc_push(OpCode::Str(end+1, s_end))?;
+ self.bc_push(OpCode::Str(end+1, s_end), anno);
},
":" => {
let (name, _, _) = self.next_word().ok_or(ParseError::EOF)?;
self.wordalog.0.insert(name, self.wordlist.0.len());
self.defstack.push(self.wordlist.0.len());
self.wordlist.0.push(ByteCode(vec![]));
+ self.annotations.push(vec![]);
},
";" => {
match self.bc().0.last() {
@@ -136,59 +151,61 @@ impl<'a> Parser<'a> {
self.bc_mut().0.pop();
self.bc_mut().0.push(OpCode::TIf(t, f));
// technically only needed if ‘f’ is None, but whatever.
- self.bc_mut().0.push(OpCode::Ret);
+ self.bc_push(OpCode::Ret, anno);
},
- _ => self.bc_push(OpCode::Ret)?,
+ _ => self.bc_push(OpCode::Ret, anno),
}
self.defstack.pop().ok_or(ParseError::DefStackEmpty)?;
},
"if" => {
let i = self.wordlist.0.len();
self.wordlist.0.push(ByteCode(vec![]));
+ self.annotations.push(vec![]);
self.defstack.push(i);
- self.if_stack.push(IfClauses::True(i));
+ self.if_stack.push((IfClauses::True(i), anno));
},
"else" => {
- self.bc_push(OpCode::Ret)?;
+ self.bc_push(OpCode::Ret, anno);
self.defstack.pop();
let i = self.wordlist.0.len();
self.wordlist.0.push(ByteCode(vec![]));
+ self.annotations.push(vec![]);
self.defstack.push(i);
- let true_clause = match self.if_stack.pop() {
+ let (true_clause, anno) = match self.if_stack.pop() {
None => return Err(ParseError::MissingIf),
- Some(IfClauses::TrueFalse(_, _)) => return Err(ParseError::MissingIf),
- Some(IfClauses::True(cl)) => cl,
+ Some((IfClauses::TrueFalse(_, _), _)) => return Err(ParseError::MissingIf),
+ Some((IfClauses::True(cl), anno)) => (cl, anno),
};
- self.if_stack.push(IfClauses::TrueFalse(true_clause, i));
+ self.if_stack.push((IfClauses::TrueFalse(true_clause, i), anno));
},
"then" => {
- self.bc_push(OpCode::Ret)?;
+ self.bc_push(OpCode::Ret, anno);
self.defstack.pop();
match self.if_stack.pop() {
None => return Err(ParseError::MissingIf),
- Some(IfClauses::True(true_clause)) => {
- self.bc_push(OpCode::If(true_clause, None))?;
+ Some((IfClauses::True(true_clause), anno)) => {
+ self.bc_push(OpCode::If(true_clause, None), anno);
},
- Some(IfClauses::TrueFalse(true_clause, false_clause)) => {
- self.bc_push(OpCode::If(true_clause, Some(false_clause)))?;
+ Some((IfClauses::TrueFalse(true_clause, false_clause), anno)) => {
+ self.bc_push(OpCode::If(true_clause, Some(false_clause)), anno);
}
}
},
- "+" => self.bc_push(OpCode::Add)?,
- "-" => self.bc_push(OpCode::Sub)?,
- "*" => self.bc_push(OpCode::Mul)?,
- "/" => self.bc_push(OpCode::Div)?,
- "dup" => self.bc_push(OpCode::Dup)?,
- "drop" => self.bc_push(OpCode::Drop)?,
- "=" => self.bc_push(OpCode::EQ)?,
- ">" => self.bc_push(OpCode::GT)?,
- ">=" => self.bc_push(OpCode::GTE)?,
- "<" => self.bc_push(OpCode::LT)?,
- "<=" => self.bc_push(OpCode::LTE)?,
+ "+" => self.bc_push(OpCode::Add, anno),
+ "-" => self.bc_push(OpCode::Sub, anno),
+ "*" => self.bc_push(OpCode::Mul, anno),
+ "/" => self.bc_push(OpCode::Div, anno),
+ "dup" => self.bc_push(OpCode::Dup, anno),
+ "drop" => self.bc_push(OpCode::Drop, anno),
+ "=" => self.bc_push(OpCode::EQ, anno),
+ ">" => self.bc_push(OpCode::GT, anno),
+ ">=" => self.bc_push(OpCode::GTE, anno),
+ "<" => self.bc_push(OpCode::LT, anno),
+ "<=" => self.bc_push(OpCode::LTE, anno),
other => return Err(ParseError::UnknownWord(String::from(other))),
}
}