✍️ Switch to a handwritten lexer and parser. #1
@@ -232,6 +232,10 @@ impl TypeRestrictions {
|
|||||||
restrictions: vec![],
|
restrictions: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.restrictions.is_empty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|||||||
@@ -261,6 +261,15 @@ impl<'lexer> Parser<'lexer> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
fn print_next_token(&mut self, comment: &str) {
|
||||||
|
let token = self.next().expect("can get token");
|
||||||
|
println!("[{comment}] next token will be {:?}", token.as_ref().map(|x| x.token.clone()));
|
||||||
|
if let Some(token) = token {
|
||||||
|
self.save(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse a definition in a file (structure, enumeration, value, etc.).
|
/// Parse a definition in a file (structure, enumeration, value, etc.).
|
||||||
///
|
///
|
||||||
/// This will read a definition. If there's an error, it's very likely the
|
/// This will read a definition. If there's an error, it's very likely the
|
||||||
@@ -394,6 +403,7 @@ impl<'lexer> Parser<'lexer> {
|
|||||||
let next = self
|
let next = self
|
||||||
.next()?
|
.next()?
|
||||||
.ok_or_else(|| self.bad_eof("looking for definition body"))?;
|
.ok_or_else(|| self.bad_eof("looking for definition body"))?;
|
||||||
|
self.save(next.clone());
|
||||||
|
|
||||||
if let Ok(structure) = self.parse_structure() {
|
if let Ok(structure) = self.parse_structure() {
|
||||||
return Ok(Def::Structure(structure));
|
return Ok(Def::Structure(structure));
|
||||||
|
|||||||
@@ -1001,3 +1001,86 @@ fn patterns() {
|
|||||||
type_name.as_printed() == "Enumeration" &&
|
type_name.as_printed() == "Enumeration" &&
|
||||||
variant_name.as_printed() == "Value"))));
|
variant_name.as_printed() == "Value"))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn definitions() {
|
||||||
|
let parse_def = |str| {
|
||||||
|
let lexer = Lexer::from(str);
|
||||||
|
let mut result = Parser::new("test", lexer);
|
||||||
|
result.parse_definition()
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
parse_def("x = 1;"),
|
||||||
|
Ok(Definition { export: ExportClass::Private, type_restrictions, definition, .. }) if
|
||||||
|
type_restrictions.is_empty() &&
|
||||||
|
matches!(&definition, Def::Value(ValueDef { name, mtype: None, value, .. }) if
|
||||||
|
name.as_printed() == "x" &&
|
||||||
|
matches!(value, Expression::Value(ConstantValue::Integer(_, iwb)) if
|
||||||
|
iwb.value == 1))));
|
||||||
|
assert!(parse_def("x = 1").is_err());
|
||||||
|
assert!(matches!(
|
||||||
|
parse_def("x: Integer = 1;"),
|
||||||
|
Ok(Definition { export: ExportClass::Private, type_restrictions, definition, .. }) if
|
||||||
|
type_restrictions.is_empty() &&
|
||||||
|
matches!(&definition, Def::Value(ValueDef { name, mtype: Some(_), value, .. }) if
|
||||||
|
name.as_printed() == "x" &&
|
||||||
|
matches!(value, Expression::Value(ConstantValue::Integer(_, iwb)) if
|
||||||
|
iwb.value == 1))));
|
||||||
|
assert!(matches!(
|
||||||
|
parse_def("export x: Integer = 1;"),
|
||||||
|
Ok(Definition { export: ExportClass::Public, type_restrictions, definition, .. }) if
|
||||||
|
type_restrictions.is_empty() &&
|
||||||
|
matches!(&definition, Def::Value(ValueDef { name, mtype: Some(_), value, .. }) if
|
||||||
|
name.as_printed() == "x" &&
|
||||||
|
matches!(value, Expression::Value(ConstantValue::Integer(_, iwb)) if
|
||||||
|
iwb.value == 1))));
|
||||||
|
assert!(matches!(
|
||||||
|
parse_def("export restrict() x: Integer = 1;"),
|
||||||
|
Ok(Definition { export: ExportClass::Public, type_restrictions, definition, .. }) if
|
||||||
|
type_restrictions.is_empty() &&
|
||||||
|
matches!(&definition, Def::Value(ValueDef { name, mtype: Some(_), value, .. }) if
|
||||||
|
name.as_printed() == "x" &&
|
||||||
|
matches!(value, Expression::Value(ConstantValue::Integer(_, iwb)) if
|
||||||
|
iwb.value == 1))));
|
||||||
|
assert!(matches!(
|
||||||
|
parse_def("export restrict(Numeric a) x: a = 1;"),
|
||||||
|
Ok(Definition { export: ExportClass::Public, type_restrictions, definition, .. }) if
|
||||||
|
matches!(&type_restrictions, TypeRestrictions { restrictions } if
|
||||||
|
restrictions.len() == 1 &&
|
||||||
|
matches!(restrictions.first(), Some(TypeRestriction{ constructor, arguments }) if
|
||||||
|
matches!(constructor, Type::Constructor(_, n) if n.as_printed() == "Numeric") &&
|
||||||
|
matches!(arguments.as_slice(), [Type::Variable(_, n)] if n.as_printed() == "a"))) &&
|
||||||
|
matches!(&definition, Def::Value(ValueDef { name, mtype: Some(t), value, .. }) if
|
||||||
|
name.as_printed() == "x" &&
|
||||||
|
matches!(t, Type::Variable(_, n) if n.as_printed() == "a") &&
|
||||||
|
matches!(value, Expression::Value(ConstantValue::Integer(_, iwb)) if
|
||||||
|
iwb.value == 1))));
|
||||||
|
assert!(matches!(
|
||||||
|
parse_def("function() { }"),
|
||||||
|
Ok(Definition { export: ExportClass::Private, type_restrictions, definition, .. }) if
|
||||||
|
type_restrictions.is_empty() &&
|
||||||
|
matches!(&definition, Def::Function(FunctionDef { name, arguments, return_type, body, .. }) if
|
||||||
|
name.as_printed() == "function" &&
|
||||||
|
arguments.is_empty() &&
|
||||||
|
return_type.is_none() &&
|
||||||
|
body.len() == 1)));
|
||||||
|
assert!(matches!(
|
||||||
|
parse_def("function() { 1 }"),
|
||||||
|
Ok(Definition { export: ExportClass::Private, type_restrictions, definition, .. }) if
|
||||||
|
type_restrictions.is_empty() &&
|
||||||
|
matches!(&definition, Def::Function(FunctionDef { name, arguments, return_type, body, .. }) if
|
||||||
|
name.as_printed() == "function" &&
|
||||||
|
arguments.is_empty() &&
|
||||||
|
return_type.is_none() &&
|
||||||
|
body.len() == 1)));
|
||||||
|
assert!(matches!(
|
||||||
|
parse_def("function(): Integer { 1 }"),
|
||||||
|
Ok(Definition { export: ExportClass::Private, type_restrictions, definition, .. }) if
|
||||||
|
type_restrictions.is_empty() &&
|
||||||
|
matches!(&definition, Def::Function(FunctionDef { name, arguments, return_type, body, .. }) if
|
||||||
|
name.as_printed() == "function" &&
|
||||||
|
arguments.is_empty() &&
|
||||||
|
return_type.is_some() &&
|
||||||
|
body.len() == 1)));
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user