aboutsummaryrefslogtreecommitdiff
path: root/lib/xixanta/src/parser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'lib/xixanta/src/parser.rs')
-rw-r--r--lib/xixanta/src/parser.rs98
1 files changed, 94 insertions, 4 deletions
diff --git a/lib/xixanta/src/parser.rs b/lib/xixanta/src/parser.rs
index 8429c2e..c171624 100644
--- a/lib/xixanta/src/parser.rs
+++ b/lib/xixanta/src/parser.rs
@@ -1,6 +1,7 @@
use crate::errors::ParseError;
use crate::node::{NodeBodyType, NodeType, OperationType, PNode, PString};
use crate::opcodes::{CONTROL_FUNCTIONS, INSTRUCTIONS};
+use rand::distributions::{Alphanumeric, DistString};
use std::cmp::Ordering;
use std::io::{self, BufRead, Read};
@@ -82,8 +83,10 @@ impl Parser {
}
}
+ /// Returns the first layer of nodes that have been parsed. Note that this
+ /// function only makes sense to be called whenever parsing is done,
+ /// otherwise results will be incomplete in (most probably) unexpected ways.
pub fn nodes(&self) -> Vec<PNode> {
- // println!("{:#?}", self.nodes);
self.nodes.first().unwrap().to_vec()
}
@@ -916,6 +919,11 @@ impl Parser {
}
}
+ // Generate a unique identifier with the given prefix.
+ fn unique_identifier(&self, prefix: String) -> String {
+ prefix + &String::from("-") + &Alphanumeric.sample_string(&mut rand::thread_rng(), 16)
+ }
+
// Returns a NodeType::Control node with whatever could be parsed
// considering the given `id` and rest of the `line`.
fn parse_control(&mut self, id: PString, line: &str) -> Result<PNode, ParseError> {
@@ -933,11 +941,21 @@ impl Parser {
// If this control function has an identifier (e.g. `.macro
// Identifier(args...)`), let's parse it now.
- if control.has_identifier {
+ if control.has_identifier.is_some() {
self.skip_whitespace(line);
left = Some(Box::new(PNode {
node_type: NodeType::Value,
- value: self.parse_identifier(line)?.0,
+ // The identifier is actually there or does it have to be generated?
+ value: if control.has_identifier.unwrap() {
+ PString {
+ value: self.unique_identifier(control.control_type.to_string()),
+ line: self.line,
+ start: id.start,
+ end: id.end,
+ }
+ } else {
+ self.parse_identifier(line)?.0
+ },
left: None,
right: None,
args: None,
@@ -950,7 +968,7 @@ impl Parser {
// required by the function.
let args = self.parse_arguments(line)?;
if let Some(args_required) = control.required_args {
- if args.len() != args_required {
+ if args.len() < args_required.0 || args.len() > args_required.1 {
return Err(self.parser_error(
format!("wrong number of arguments for function '{}'", id.value).as_str(),
));
@@ -2153,6 +2171,78 @@ inc $20
}
#[test]
+ fn parse_repeat_control() {
+ let mut parser = Parser::default();
+ let err = parser.parse(".repeat\n.endrepeat".as_bytes()).unwrap_err();
+ assert_eq!(
+ err.first().unwrap().message,
+ "wrong number of arguments for function '.repeat'"
+ );
+
+ let mut parser = Parser::default();
+ let err = parser
+ .parse(".repeat 1, 2, 3\n.endrepeat".as_bytes())
+ .unwrap_err();
+ assert_eq!(
+ err.first().unwrap().message,
+ "wrong number of arguments for function '.repeat'"
+ );
+
+ // Minimum required argument.
+
+ parser = Parser::default();
+ let mut line = ".repeat 2\n.endrepeat";
+
+ assert!(parser.parse(line.as_bytes()).is_ok());
+ let mut control = parser.nodes.last().unwrap().first().unwrap();
+ assert_node(
+ control,
+ NodeType::Control(ControlType::StartRepeat),
+ line,
+ ".repeat",
+ );
+ assert!(control
+ .left
+ .as_ref()
+ .unwrap()
+ .value
+ .value
+ .starts_with(".repeat-"));
+ assert!(control.right.is_some());
+
+ let mut args = control.args.clone().unwrap();
+ assert_eq!(args.len(), 1);
+ assert_node(args.first().unwrap(), NodeType::Value, line, "2");
+
+ // Maximum allowed arguments.
+
+ parser = Parser::default();
+ line = ".repeat 2, I\n.endrepeat";
+
+ assert!(parser.parse(line.as_bytes()).is_ok());
+ control = parser.nodes.last().unwrap().first().unwrap();
+ assert_node(
+ control,
+ NodeType::Control(ControlType::StartRepeat),
+ line,
+ ".repeat",
+ );
+ assert!(control
+ .left
+ .as_ref()
+ .unwrap()
+ .value
+ .value
+ .starts_with(".repeat-"));
+ assert!(control.right.is_some());
+
+ args = control.args.clone().unwrap();
+ assert_eq!(args.len(), 2);
+ assert_node(args.first().unwrap(), NodeType::Value, line, "2");
+ assert_node(args.last().unwrap(), NodeType::Value, line, "I");
+ }
+
+ #[test]
fn parse_unknown_control() {
let mut parser = Parser::default();
let mut err = parser.parse(".".as_bytes()).unwrap_err();