aboutsummaryrefslogtreecommitdiff
path: root/lib/xixanta/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/xixanta/src')
-rw-r--r--lib/xixanta/src/assembler.rs43
-rw-r--r--lib/xixanta/src/node.rs6
-rw-r--r--lib/xixanta/src/opcodes.rs10
-rw-r--r--lib/xixanta/src/parser.rs28
4 files changed, 49 insertions, 38 deletions
diff --git a/lib/xixanta/src/assembler.rs b/lib/xixanta/src/assembler.rs
index 5c43387..cb992d4 100644
--- a/lib/xixanta/src/assembler.rs
+++ b/lib/xixanta/src/assembler.rs
@@ -855,7 +855,20 @@ impl<'a> Assembler<'a> {
errors.append(&mut ers);
}
}
-
+ NodeType::Fallthrough => {
+ // We don't do much other than pushing a fake PendingNode with a
+ // 'bundle_index' value that will point to the next node.
+ let current = &mut self.mappings[self.current_mapping];
+ self.pending.push(PendingNode {
+ mapping: self.current_mapping,
+ segment: self.current_segment,
+ context: self.context.name().to_string(),
+ bundle_index: current.segments[self.current_segment].bundles.len(),
+ node: node.to_owned(),
+ labels_seen: self.context.labels_seen(),
+ macro_context: self.macro_context.clone(),
+ });
+ }
_ => {}
}
@@ -890,10 +903,7 @@ impl<'a> Assembler<'a> {
//
// NOTE: this has to happen with a context switch, otherwise the
// name resolution won't be accurate.
- if matches!(
- pn.node.node_type,
- NodeType::Control(ControlType::Fallthrough)
- ) {
+ if matches!(pn.node.node_type, NodeType::Fallthrough) {
if let Err(e) = self.fallthrough(&pn) {
errors.push(e);
}
@@ -970,16 +980,14 @@ impl<'a> Assembler<'a> {
// If we are not in 'crunch' mode, then it's a bug.
assert_eq!(self.stage, Stage::Crunching);
- let node = pn.node.left.as_ref().unwrap();
-
// If there was no "argument", then skip things altogether. The
// programmer opted for an explicit fallthrough without further checks.
- if node.value.is_empty() {
+ if pn.node.value.is_empty() {
return Ok(());
}
// If there is an argument, it has to be a valid address identifier.
- if let Err(message) = node.value.is_valid_identifier(false) {
+ if let Err(message) = pn.node.value.is_valid_identifier(false) {
return Err(Error {
line: pn.node.value.line,
message,
@@ -995,7 +1003,7 @@ impl<'a> Assembler<'a> {
// from the 'bundle_index' from the PendingNode, as it was pushed while
// pointing to the "next" bundle. Hence, we just fetch that bundle and
// get its address.
- let target_address = self.evaluate_variable(node)?.value() as usize;
+ let target_address = self.evaluate_variable(&pn.node)?.value() as usize;
let current = &self.mappings[pn.mapping].segments[pn.segment];
let Some(effective) = current.bundles.get(pn.bundle_index) else {
return Err(Error {
@@ -1935,21 +1943,6 @@ impl<'a> Assembler<'a> {
NodeType::Control(ControlType::EndIf) => Ok(()),
NodeType::Control(ControlType::IncludeSource) => Ok(()),
NodeType::Control(ControlType::Echo(_)) => Ok(()),
- NodeType::Control(ControlType::Fallthrough) => {
- // We don't do much other than pushing a fake PendingNode with a
- // 'bundle_index' value that will point to the next node.
- let current = &mut self.mappings[self.current_mapping];
- self.pending.push(PendingNode {
- mapping: self.current_mapping,
- segment: self.current_segment,
- context: self.context.name().to_string(),
- bundle_index: current.segments[self.current_segment].bundles.len(),
- node: node.to_owned(),
- labels_seen: self.context.labels_seen(),
- macro_context: self.macro_context.clone(),
- });
- Ok(())
- }
_ => Err(Error {
line: node.value.line,
message: format!(
diff --git a/lib/xixanta/src/node.rs b/lib/xixanta/src/node.rs
index 9fbe34c..5093ab3 100644
--- a/lib/xixanta/src/node.rs
+++ b/lib/xixanta/src/node.rs
@@ -166,7 +166,6 @@ pub enum ControlType {
EndIf,
Defined,
Echo(EchoKind),
- Fallthrough,
}
impl fmt::Display for ControlType {
@@ -202,7 +201,6 @@ impl fmt::Display for ControlType {
EchoKind::Warning => write!(f, ".warning"),
EchoKind::Error => write!(f, ".error"),
},
- ControlType::Fallthrough => write!(f, ".fallthrough"),
}
}
}
@@ -319,6 +317,9 @@ pub enum NodeType {
/// A comment which is relevant for the current session.
Comment(CommentType),
+
+ /// Fallthrough pseudo-instruction.
+ Fallthrough,
}
impl fmt::Display for NodeType {
@@ -333,6 +334,7 @@ impl fmt::Display for NodeType {
NodeType::Literal => write!(f, "literal"),
NodeType::Label => write!(f, "label"),
NodeType::Call => write!(f, "call"),
+ NodeType::Fallthrough => write!(f, "fallthrough"),
NodeType::Operation(op) => match op {
OperationType::Add => write!(f, "addition"),
OperationType::Sub => write!(f, "subtraction"),
diff --git a/lib/xixanta/src/opcodes.rs b/lib/xixanta/src/opcodes.rs
index bd3c207..48e4fca 100644
--- a/lib/xixanta/src/opcodes.rs
+++ b/lib/xixanta/src/opcodes.rs
@@ -1999,16 +1999,6 @@ pub static CONTROL_FUNCTIONS: LazyLock<HashMap<String, Control>> = LazyLock::new
only_string: true,
},
);
- functions.insert(
- String::from(".fallthrough"),
- Control {
- control_type: ControlType::Fallthrough,
- has_identifier: Some(false),
- required_args: Some((0, 0)),
- touches_context: false,
- only_string: false,
- },
- );
functions
});
diff --git a/lib/xixanta/src/parser.rs b/lib/xixanta/src/parser.rs
index 7a7e3f0..e2e31dc 100644
--- a/lib/xixanta/src/parser.rs
+++ b/lib/xixanta/src/parser.rs
@@ -766,9 +766,12 @@ impl Parser {
// Parse statements which are neither an instruction nor an assignment. This
// includes stuff like control statements or macro calls.
fn parse_other(&mut self, line: &str, id: PString) -> Result<(), Vec<Error>> {
- // This is either a control statement (i.e. starts with '.') or a macro call.
+ // This is either a control statement (i.e. starts with '.'), a
+ // __fallthrough__, or a macro call.
let node = if id.value.starts_with('.') {
self.parse_control(id, line, 0)?
+ } else if id.value == "__fallthrough__" {
+ self.parse_fallthrough(line)?
} else {
let args = self.parse_arguments(line, 0)?;
PNode {
@@ -1642,6 +1645,29 @@ impl Parser {
})
}
+ // Parse a fallthrough statement.
+ fn parse_fallthrough(&mut self, line: &str) -> Result<PNode, Error> {
+ // Skip whitespaces and fetch the identifier.
+ self.skip_whitespace(line);
+ let identifier = self.parse_identifier(line, false)?.0;
+
+ // If there was something else other than the identifier, it's a parsing
+ // error.
+ let rest = line.get(self.offset..).unwrap_or("").trim();
+ if !rest.is_empty() {
+ return Err(self.parser_error("too many arguments for __fallthrough__"));
+ }
+
+ Ok(PNode {
+ node_type: NodeType::Fallthrough,
+ value: identifier,
+ left: None,
+ right: None,
+ args: None,
+ source: self.current_source,
+ })
+ }
+
// Returns a NodeType::Literal node with whatever could be parsed
// considering the given `line` which starts with the given `symbol`. The
// recursivity `level` is also provided as it will call again