Added break statements
This commit is contained in:
@@ -62,6 +62,7 @@ pub enum Macro {
|
||||
Until,
|
||||
Do,
|
||||
End,
|
||||
Break,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
|
||||
@@ -69,7 +69,7 @@ org_directive = { label_def? ~ ".org" ~ expr }
|
||||
equ_directive = { label_def ~ ".equ" ~ expr }
|
||||
|
||||
include = { "include" ~ string }
|
||||
control = { "if" | "unless" | "while" | "until" | "do" | "else" | "end" }
|
||||
control = { "if" | "unless" | "while" | "until" | "do" | "else" | "end" | "break" }
|
||||
preprocessor = {"#" ~ (control | include) }
|
||||
|
||||
blank = { WHITESPACE? ~ COMMENT? }
|
||||
|
||||
@@ -208,6 +208,7 @@ fn parse_macro(line: Pair) -> Macro {
|
||||
"until" => Macro::Until,
|
||||
"do" => Macro::Do,
|
||||
"end" => Macro::End,
|
||||
"break" => Macro::Break,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Rule::include => Macro::Include(create_string(pre.only())),
|
||||
|
||||
@@ -81,7 +81,10 @@ impl<T: IntoIterator<Item = String>, F: Fn(String) -> Result<T, AssembleError>>
|
||||
|
||||
// It's a macro, so do it and then try again
|
||||
Ok(VASMLine::Macro(mac)) => {
|
||||
self.handle_macro(mac);
|
||||
match self.handle_macro(mac) {
|
||||
None => {}
|
||||
Some(err) => return Some(Err(err))
|
||||
}
|
||||
self.next()
|
||||
}
|
||||
|
||||
@@ -214,6 +217,20 @@ impl<T: IntoIterator<Item = String>, F: Fn(String) -> Result<T, AssembleError>>
|
||||
}
|
||||
_ => return Some(AssembleError::MacroError(self.current_location())),
|
||||
},
|
||||
|
||||
Macro::Break => {
|
||||
let innermost_loop = self.control_stack.iter().rev().find(|cs| {
|
||||
match cs {
|
||||
ControlStructure::LoopDo(_, _) => true,
|
||||
_ => false
|
||||
}
|
||||
});
|
||||
if let Some(ControlStructure::LoopDo(_, after)) = innermost_loop {
|
||||
self.emit(format!("jmpr @{}", after));
|
||||
} else {
|
||||
return Some(AssembleError::MacroError(self.current_location()))
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -227,10 +244,18 @@ mod tests {
|
||||
|
||||
fn lines_for(source: Vec<String>) -> Vec<VASMLine> {
|
||||
let include = |_name: String| panic!();
|
||||
let src = LineSource::new("blah", source, include);
|
||||
let src = LineSource::new("<none>", source, include);
|
||||
src.map(|line| line.unwrap().line).collect()
|
||||
}
|
||||
|
||||
fn error_for(source: Vec<String>) -> Option<AssembleError> {
|
||||
let include = |_name: String| panic!();
|
||||
for line in LineSource::new("<none>", source, include) {
|
||||
if line.is_err() { return line.err() }
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn stringify(a: Vec<&str>) -> Vec<String> {
|
||||
a.into_iter().map(String::from).collect()
|
||||
}
|
||||
@@ -325,4 +350,40 @@ mod tests {
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_preprocess_break() {
|
||||
// First a working one
|
||||
assert_eq!(
|
||||
lines_for(stringify(vec!["#while", "#do", "#break", "#end"])),
|
||||
vec![
|
||||
VASMLine::LabelDef(Label("__gensym_1".to_string())),
|
||||
VASMLine::Instruction(
|
||||
None,
|
||||
Brz,
|
||||
Some(Node::RelativeLabel("__gensym_2".to_string()))
|
||||
),
|
||||
VASMLine::Instruction(
|
||||
None,
|
||||
Jmpr,
|
||||
Some(Node::RelativeLabel("__gensym_2".to_string()))
|
||||
),
|
||||
VASMLine::Instruction(
|
||||
None,
|
||||
Jmpr,
|
||||
Some(Node::RelativeLabel("__gensym_1".to_string()))
|
||||
),
|
||||
VASMLine::LabelDef(Label::from("__gensym_2"))
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_malformed_break() {
|
||||
// Malformed one
|
||||
assert_eq!(
|
||||
error_for(stringify(vec!["#while", "#break"])),
|
||||
Some(AssembleError::MacroError(Location::from(2)))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user