Tidy, tidy, tidy.

This commit is contained in:
2025-11-05 21:30:03 -08:00
parent 7bd242a641
commit 05d7284551
8 changed files with 723 additions and 537 deletions

View File

@@ -12,3 +12,4 @@ pub use crate::syntax::error::ParserError;
pub use ast::*; pub use ast::*;
pub use location::{Located, Location}; pub use location::{Located, Location};
pub use name::Name; pub use name::Name;
pub use universe::*;

View File

@@ -27,6 +27,7 @@ pub enum Def {
Structure(StructureDef), Structure(StructureDef),
Function(FunctionDef), Function(FunctionDef),
Value(ValueDef), Value(ValueDef),
Operator(OperatorDef),
} }
impl Located for Def { impl Located for Def {
@@ -36,6 +37,7 @@ impl Located for Def {
Def::Structure(def) => def.location.clone(), Def::Structure(def) => def.location.clone(),
Def::Function(def) => def.location.clone(), Def::Function(def) => def.location.clone(),
Def::Value(def) => def.location.clone(), Def::Value(def) => def.location.clone(),
Def::Operator(def) => def.location.clone(),
} }
} }
} }
@@ -91,6 +93,13 @@ pub struct ValueDef {
pub value: Expression, pub value: Expression,
} }
#[derive(Debug)]
pub struct OperatorDef {
pub operator_name: Name,
pub function_name: Name,
location: Location,
}
#[derive(Debug)] #[derive(Debug)]
pub enum ExportClass { pub enum ExportClass {
Public, Public,
@@ -114,15 +123,45 @@ pub struct BindingStmt {
#[derive(Debug)] #[derive(Debug)]
pub enum Expression { pub enum Expression {
Value(ConstantValue), Value(ConstantValue),
Reference(Name), Reference(Location, Name),
EnumerationValue(Name, Name, Option<Box<Expression>>), Enumeration(EnumerationExpr),
StructureValue(Name, Vec<FieldValue>), Structure(StructureExpr),
Conditional(ConditionalExpr), Conditional(ConditionalExpr),
Match(MatchExpr), Match(MatchExpr),
Call(Box<Expression>, CallKind, Vec<Expression>), Call(Box<Expression>, CallKind, Vec<Expression>),
Block(Location, Vec<Statement>), Block(Location, Vec<Statement>),
} }
impl Located for Expression {
fn location(&self) -> Location {
match self {
Expression::Value(c) => c.location(),
Expression::Reference(l, _) => l.clone(),
Expression::Enumeration(ev) => ev.location.clone(),
Expression::Structure(sv) => sv.location.clone(),
Expression::Conditional(ce) => ce.location.clone(),
Expression::Match(me) => me.location.clone(),
Expression::Call(_, _, _) => unimplemented!(),
Expression::Block(l, _) => l.clone(),
}
}
}
#[derive(Debug)]
pub struct EnumerationExpr {
pub location: Location,
pub type_name: Name,
pub variant_name: Name,
pub argument: Option<Box<Expression>>,
}
#[derive(Debug)]
pub struct StructureExpr {
pub location: Location,
pub type_name: Name,
pub fields: Vec<FieldValue>,
}
#[derive(Debug)] #[derive(Debug)]
pub struct ConditionalExpr { pub struct ConditionalExpr {
pub location: Location, pub location: Location,
@@ -240,6 +279,16 @@ pub enum ConstantValue {
String(Location, String), String(Location, String),
} }
impl Located for ConstantValue {
fn location(&self) -> Location {
match self {
ConstantValue::Integer(l, _) => l.clone(),
ConstantValue::Character(l, _) => l.clone(),
ConstantValue::String(l, _) => l.clone(),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Arbitrary)] #[derive(Clone, Debug, PartialEq, Eq, Arbitrary)]
pub struct IntegerWithBase { pub struct IntegerWithBase {
#[proptest(strategy = "proptest::prop_oneof![ \ #[proptest(strategy = "proptest::prop_oneof![ \

View File

@@ -16,7 +16,7 @@ pub enum ParserError {
#[error("Unacceptable end of file at {file} while {place}")] #[error("Unacceptable end of file at {file} while {place}")]
UnacceptableEof { UnacceptableEof {
file: ArcIntern<PathBuf>, file: ArcIntern<PathBuf>,
place: &'static str, place: String,
}, },
#[error("Unexpected token at {file}: expected {expected}, saw {token}")] #[error("Unexpected token at {file}: expected {expected}, saw {token}")]
@@ -24,7 +24,7 @@ pub enum ParserError {
file: ArcIntern<PathBuf>, file: ArcIntern<PathBuf>,
span: Range<usize>, span: Range<usize>,
token: Token, token: Token,
expected: &'static str, expected: String,
}, },
#[error("Unexpected problem opening file {file}: {error}")] #[error("Unexpected problem opening file {file}: {error}")]

View File

@@ -61,4 +61,8 @@ impl Name {
pub fn bind_to(&mut self, other: &Name) { pub fn bind_to(&mut self, other: &Name) {
self.identifier = other.identifier; self.identifier = other.identifier;
} }
pub fn location(&self) -> Option<&Location> {
self.location.as_ref()
}
} }

File diff suppressed because it is too large Load Diff

View File

@@ -151,7 +151,7 @@ fn type_restrictions() {
matches!(&arguments[0], Type::Variable(_, x) if x.as_printed() == "a") && matches!(&arguments[0], Type::Variable(_, x) if x.as_printed() == "a") &&
matches!(&arguments[1], Type::Variable(_, x) if x.as_printed() == "b")))); matches!(&arguments[1], Type::Variable(_, x) if x.as_printed() == "b"))));
assert!(matches!(parse_tr("restrict(,Cons a b,)"), Err(_))); assert!(parse_tr("restrict(,Cons a b,)").is_err());
assert!(matches!( assert!(matches!(
parse_tr("restrict(Cons a b, Monad m)"), parse_tr("restrict(Cons a b, Monad m)"),
@@ -196,7 +196,7 @@ fn field_definition() {
result.parse_field_definition() result.parse_field_definition()
}; };
assert!(matches!(parse_fd("foo"), Err(_),)); assert!(parse_fd("foo").is_err());
assert!(matches!( assert!(matches!(
parse_fd("foo,"), parse_fd("foo,"),
Ok(Some(StructureField{ name, export: ExportClass::Private, field_type: None, .. })) Ok(Some(StructureField{ name, export: ExportClass::Private, field_type: None, .. }))
@@ -250,10 +250,11 @@ fn structures() {
result.parse_structure() result.parse_structure()
}; };
assert!(matches!(parse_st("structure { }"), Err(_))); assert!(parse_st("structure { }").is_err());
assert!(matches!(parse_st("structure {"), Err(_))); assert!(parse_st("structure {").is_err());
assert!(matches!(parse_st("structure foo {}"), Err(_))); assert!(parse_st("structure foo {}").is_err());
println!("result: {:?}", parse_st("structure Foo {}"));
assert!(matches!( assert!(matches!(
parse_st("structure Foo {}"), parse_st("structure Foo {}"),
Ok(StructureDef { name, fields, .. }) Ok(StructureDef { name, fields, .. })
@@ -264,7 +265,7 @@ fn structures() {
Ok(StructureDef { name, fields, .. }) Ok(StructureDef { name, fields, .. })
if name.as_printed() == "Foo" && if name.as_printed() == "Foo" &&
matches!(fields.as_slice(), &[StructureField { ref name, ref field_type, .. }] matches!(fields.as_slice(), &[StructureField { ref name, ref field_type, .. }]
if name.as_printed() == "bar" && matches!(field_type, None)))); if name.as_printed() == "bar" && field_type.is_none())));
assert!(matches!( assert!(matches!(
parse_st("structure Foo { bar: Word8 }"), parse_st("structure Foo { bar: Word8 }"),
@@ -326,10 +327,10 @@ fn enum_variant() {
result.parse_enum_variant() result.parse_enum_variant()
}; };
assert!(matches!(parse_ev("foo"), Err(_),)); assert!(matches!(parse_ev("foo"), Ok(None)));
assert!(matches!(parse_ev("foo,"), Err(_),)); assert!(matches!(parse_ev("foo,"), Ok(None)));
assert!(matches!(parse_ev("Cons foo,"), Err(_),)); assert!(parse_ev("Cons foo,").is_err());
assert!(matches!(parse_ev(""), Err(_))); assert!(matches!(parse_ev(""), Ok(None)));
assert!(matches!(parse_ev("}"), Ok(None))); assert!(matches!(parse_ev("}"), Ok(None)));
@@ -383,9 +384,9 @@ fn enumerations() {
result.parse_enumeration() result.parse_enumeration()
}; };
assert!(matches!(parse_en("enumeration { }"), Err(_))); assert!(parse_en("enumeration { }").is_err());
assert!(matches!(parse_en("enumeration {"), Err(_))); assert!(parse_en("enumeration {").is_err());
assert!(matches!(parse_en("enumeration"), Err(_))); assert!(parse_en("enumeration").is_err());
assert!(matches!( assert!(matches!(
parse_en("enumeration Empty { }"), parse_en("enumeration Empty { }"),
@@ -419,13 +420,13 @@ fn expressions() {
result.parse_expression() result.parse_expression()
}; };
assert!(matches!(parse_ex(""), Err(_))); assert!(parse_ex("").is_err());
assert!(matches!( assert!(matches!(
parse_ex("x"), parse_ex("x"),
Ok(Expression::Reference(n)) if n.as_printed() == "x")); Ok(Expression::Reference(_,n)) if n.as_printed() == "x"));
assert!(matches!( assert!(matches!(
parse_ex("(x)"), parse_ex("(x)"),
Ok(Expression::Reference(n)) if n.as_printed() == "x")); Ok(Expression::Reference(_,n)) if n.as_printed() == "x"));
assert!(matches!( assert!(matches!(
parse_ex("'c'"), parse_ex("'c'"),
Ok(Expression::Value(ConstantValue::Character(_, _))) Ok(Expression::Value(ConstantValue::Character(_, _)))
@@ -452,17 +453,19 @@ fn enumeration_values() {
result.parse_expression() result.parse_expression()
}; };
assert!(matches!(parse_ex("Hello::world"), Err(_))); assert!(parse_ex("Hello::world").is_err());
assert!(matches!( assert!(matches!(
parse_ex("Hello::World"), parse_ex("Hello::World"),
Ok(Expression::EnumerationValue(t, v, None)) Ok(Expression::Enumeration(ev))
if t.as_printed() == "Hello" && if ev.type_name.as_printed() == "Hello" &&
v.as_printed() == "World")); ev.variant_name.as_printed() == "World" &&
ev.argument.is_none()));
assert!(matches!( assert!(matches!(
parse_ex("Hello::World(a)"), parse_ex("Hello::World(a)"),
Ok(Expression::EnumerationValue(t, v, Some(_))) Ok(Expression::Enumeration(ev))
if t.as_printed() == "Hello" && if ev.type_name.as_printed() == "Hello" &&
v.as_printed() == "World")); ev.variant_name.as_printed() == "World" &&
ev.argument.is_some()));
} }
#[test] #[test]
@@ -473,29 +476,30 @@ fn structure_value() {
result.parse_expression() result.parse_expression()
}; };
assert!(matches!(parse_st("Foo{ , }"), Err(_))); assert!(parse_st("Foo{ , }").is_err());
assert!(matches!(parse_st("Foo{ foo, }"), Err(_))); assert!(parse_st("Foo{ foo, }").is_err());
assert!(matches!(parse_st("Foo{ foo: , }"), Err(_))); assert!(parse_st("Foo{ foo: , }").is_err());
assert!(matches!(parse_st("Foo{ , foo: 1, }"), Err(_))); assert!(parse_st("Foo{ , foo: 1, }").is_err());
println!("result: {:?}", parse_st("Foo{ foo: 1 }"));
assert!(matches!( assert!(matches!(
parse_st("Foo{ foo: 1 }"), parse_st("Foo{ foo: 1 }"),
Ok(Expression::StructureValue(sname, values)) Ok(Expression::Structure(sv))
if sname.as_printed() == "Foo" && if sv.type_name.as_printed() == "Foo" &&
matches!(values.as_slice(), [FieldValue{ field, value }] matches!(sv.fields.as_slice(), [FieldValue{ field, value }]
if field.as_printed() == "foo" && if field.as_printed() == "foo" &&
matches!(value, Expression::Value(ConstantValue::Integer(_,_)))))); matches!(value, Expression::Value(ConstantValue::Integer(_,_))))));
assert!(matches!( assert!(matches!(
parse_st("Foo{ foo: 1, }"), parse_st("Foo{ foo: 1, }"),
Ok(Expression::StructureValue(sname, values)) Ok(Expression::Structure(sv))
if sname.as_printed() == "Foo" && if sv.type_name.as_printed() == "Foo" &&
matches!(values.as_slice(), [FieldValue{ field, value }] matches!(sv.fields.as_slice(), [FieldValue{ field, value }]
if field.as_printed() == "foo" && if field.as_printed() == "foo" &&
matches!(value, Expression::Value(ConstantValue::Integer(_,_)))))); matches!(value, Expression::Value(ConstantValue::Integer(_,_))))));
assert!(matches!( assert!(matches!(
parse_st("Foo{ foo: 1, bar: \"foo\" }"), parse_st("Foo{ foo: 1, bar: \"foo\" }"),
Ok(Expression::StructureValue(sname, values)) Ok(Expression::Structure(sv))
if sname.as_printed() == "Foo" && if sv.type_name.as_printed() == "Foo" &&
matches!(values.as_slice(), [FieldValue{ field: f1, value: v1 }, matches!(sv.fields.as_slice(), [FieldValue{ field: f1, value: v1 },
FieldValue{ field: f2, value: v2 }] FieldValue{ field: f2, value: v2 }]
if f1.as_printed() == "foo" && if f1.as_printed() == "foo" &&
f2.as_printed() == "bar" && f2.as_printed() == "bar" &&
@@ -503,15 +507,15 @@ fn structure_value() {
matches!(v2, Expression::Value(ConstantValue::String(_,_)))))); matches!(v2, Expression::Value(ConstantValue::String(_,_))))));
assert!(matches!( assert!(matches!(
parse_st("Foo{ foo: 1, bar: \"foo\", }"), parse_st("Foo{ foo: 1, bar: \"foo\", }"),
Ok(Expression::StructureValue(sname, values)) Ok(Expression::Structure(sv))
if sname.as_printed() == "Foo" && if sv.type_name.as_printed() == "Foo" &&
matches!(values.as_slice(), [FieldValue{ field: f1, value: v1 }, matches!(sv.fields.as_slice(), [FieldValue{ field: f1, value: v1 },
FieldValue{ field: f2, value: v2 }] FieldValue{ field: f2, value: v2 }]
if f1.as_printed() == "foo" && if f1.as_printed() == "foo" &&
f2.as_printed() == "bar" && f2.as_printed() == "bar" &&
matches!(v1, Expression::Value(ConstantValue::Integer(_,_))) && matches!(v1, Expression::Value(ConstantValue::Integer(_,_))) &&
matches!(v2, Expression::Value(ConstantValue::String(_,_)))))); matches!(v2, Expression::Value(ConstantValue::String(_,_))))));
assert!(matches!(parse_st("Foo{ foo: 1,, bar: \"foo\", }"), Err(_))); assert!(parse_st("Foo{ foo: 1,, bar: \"foo\", }").is_err());
} }
#[test] #[test]
@@ -539,7 +543,7 @@ fn infix_and_precedence() {
assert!(matches!( assert!(matches!(
parse_ex("1 + 2"), parse_ex("1 + 2"),
Ok(Expression::Call(plus, CallKind::Infix, args)) Ok(Expression::Call(plus, CallKind::Infix, args))
if matches!(plus.as_ref(), Expression::Reference(n) if n.as_printed() == "+") && if matches!(plus.as_ref(), Expression::Reference(_,n) if n.as_printed() == "+") &&
matches!(args.as_slice(), [ matches!(args.as_slice(), [
Expression::Value(ConstantValue::Integer(_, IntegerWithBase{ value: v1, .. })), Expression::Value(ConstantValue::Integer(_, IntegerWithBase{ value: v1, .. })),
Expression::Value(ConstantValue::Integer(_, IntegerWithBase{ value: v2, .. })) Expression::Value(ConstantValue::Integer(_, IntegerWithBase{ value: v2, .. }))
@@ -547,12 +551,12 @@ fn infix_and_precedence() {
assert!(matches!( assert!(matches!(
parse_ex("1 + 2 + 3"), parse_ex("1 + 2 + 3"),
Ok(Expression::Call(plus, CallKind::Infix, args)) Ok(Expression::Call(plus, CallKind::Infix, args))
if matches!(plus.as_ref(), Expression::Reference(n) if n.as_printed() == "+") && if matches!(plus.as_ref(), Expression::Reference(_,n) if n.as_printed() == "+") &&
matches!(args.as_slice(), [ matches!(args.as_slice(), [
Expression::Call(innerplus, CallKind::Infix, inner_args), Expression::Call(innerplus, CallKind::Infix, inner_args),
Expression::Value(ConstantValue::Integer(_, IntegerWithBase{ value: v3, .. })) Expression::Value(ConstantValue::Integer(_, IntegerWithBase{ value: v3, .. }))
] if *v3 == 3 && ] if *v3 == 3 &&
matches!(innerplus.as_ref(), Expression::Reference(n) if n.as_printed() == "+") && matches!(innerplus.as_ref(), Expression::Reference(_,n) if n.as_printed() == "+") &&
matches!(inner_args.as_slice(), [ matches!(inner_args.as_slice(), [
Expression::Value(ConstantValue::Integer(_, IntegerWithBase{ value: v1, .. })), Expression::Value(ConstantValue::Integer(_, IntegerWithBase{ value: v1, .. })),
Expression::Value(ConstantValue::Integer(_, IntegerWithBase{ value: v2, .. })) Expression::Value(ConstantValue::Integer(_, IntegerWithBase{ value: v2, .. }))
@@ -560,12 +564,12 @@ fn infix_and_precedence() {
assert!(matches!( assert!(matches!(
parse_ex("1 * 2 * 3"), parse_ex("1 * 2 * 3"),
Ok(Expression::Call(times, CallKind::Infix, args)) Ok(Expression::Call(times, CallKind::Infix, args))
if matches!(times.as_ref(), Expression::Reference(n) if n.as_printed() == "*") && if matches!(times.as_ref(), Expression::Reference(_,n) if n.as_printed() == "*") &&
matches!(args.as_slice(), [ matches!(args.as_slice(), [
Expression::Value(ConstantValue::Integer(_, IntegerWithBase{ value: v1, .. })), Expression::Value(ConstantValue::Integer(_, IntegerWithBase{ value: v1, .. })),
Expression::Call(innertimes, CallKind::Infix, inner_args), Expression::Call(innertimes, CallKind::Infix, inner_args),
] if *v1 == 1 && ] if *v1 == 1 &&
matches!(innertimes.as_ref(), Expression::Reference(n) if n.as_printed() == "*") && matches!(innertimes.as_ref(), Expression::Reference(_,n) if n.as_printed() == "*") &&
matches!(inner_args.as_slice(), [ matches!(inner_args.as_slice(), [
Expression::Value(ConstantValue::Integer(_, IntegerWithBase{ value: v2, .. })), Expression::Value(ConstantValue::Integer(_, IntegerWithBase{ value: v2, .. })),
Expression::Value(ConstantValue::Integer(_, IntegerWithBase{ value: v3, .. })) Expression::Value(ConstantValue::Integer(_, IntegerWithBase{ value: v3, .. }))
@@ -574,19 +578,19 @@ fn infix_and_precedence() {
assert!(matches!( assert!(matches!(
parse_ex("1 + 2 * 3 + 4"), parse_ex("1 + 2 * 3 + 4"),
Ok(Expression::Call(plus_right, CallKind::Infix, outer_args)) if Ok(Expression::Call(plus_right, CallKind::Infix, outer_args)) if
matches!(plus_right.as_ref(), Expression::Reference(n) if n.as_printed() == "+") && matches!(plus_right.as_ref(), Expression::Reference(_,n) if n.as_printed() == "+") &&
matches!(outer_args.as_slice(), [ matches!(outer_args.as_slice(), [
Expression::Call(plus_left, CallKind::Infix, left_args), Expression::Call(plus_left, CallKind::Infix, left_args),
Expression::Value(ConstantValue::Integer(_, v4)) Expression::Value(ConstantValue::Integer(_, v4))
] if ] if
matches!(v4, IntegerWithBase{ value: 4, .. }) && matches!(v4, IntegerWithBase{ value: 4, .. }) &&
matches!(plus_left.as_ref(), Expression::Reference(n) if n.as_printed() == "+") && matches!(plus_left.as_ref(), Expression::Reference(_,n) if n.as_printed() == "+") &&
matches!(left_args.as_slice(), [ matches!(left_args.as_slice(), [
Expression::Value(ConstantValue::Integer(_, v1)), Expression::Value(ConstantValue::Integer(_, v1)),
Expression::Call(times, CallKind::Infix, times_args) Expression::Call(times, CallKind::Infix, times_args)
] if ] if
matches!(v1, IntegerWithBase{ value: 1, .. }) && matches!(v1, IntegerWithBase{ value: 1, .. }) &&
matches!(times.as_ref(), Expression::Reference(n) if n.as_printed() == "*") && matches!(times.as_ref(), Expression::Reference(_,n) if n.as_printed() == "*") &&
matches!(times_args.as_slice(), [ matches!(times_args.as_slice(), [
Expression::Value(ConstantValue::Integer(_, v2)), Expression::Value(ConstantValue::Integer(_, v2)),
Expression::Value(ConstantValue::Integer(_, v3)) Expression::Value(ConstantValue::Integer(_, v3))
@@ -597,13 +601,13 @@ fn infix_and_precedence() {
assert!(matches!( assert!(matches!(
parse_ex("1 * 2 + 3 * 4"), parse_ex("1 * 2 + 3 * 4"),
Ok(Expression::Call(plus, CallKind::Infix, outer_args)) if Ok(Expression::Call(plus, CallKind::Infix, outer_args)) if
matches!(plus.as_ref(), Expression::Reference(n) if n.as_printed() == "+") && matches!(plus.as_ref(), Expression::Reference(_,n) if n.as_printed() == "+") &&
matches!(outer_args.as_slice(), [ matches!(outer_args.as_slice(), [
Expression::Call(left_times, CallKind::Infix, left_args), Expression::Call(left_times, CallKind::Infix, left_args),
Expression::Call(right_times, CallKind::Infix, right_args) Expression::Call(right_times, CallKind::Infix, right_args)
] if ] if
matches!(left_times.as_ref(), Expression::Reference(n) if n.as_printed() == "*") && matches!(left_times.as_ref(), Expression::Reference(_,n) if n.as_printed() == "*") &&
matches!(right_times.as_ref(), Expression::Reference(n) if n.as_printed() == "*") && matches!(right_times.as_ref(), Expression::Reference(_,n) if n.as_printed() == "*") &&
matches!(left_args.as_slice(), [ matches!(left_args.as_slice(), [
Expression::Value(ConstantValue::Integer(_, v1)), Expression::Value(ConstantValue::Integer(_, v1)),
Expression::Value(ConstantValue::Integer(_, v2)), Expression::Value(ConstantValue::Integer(_, v2)),
@@ -631,95 +635,95 @@ fn calls() {
assert!(matches!( assert!(matches!(
parse_ex("f()"), parse_ex("f()"),
Ok(Expression::Call(f, CallKind::Normal, args)) if Ok(Expression::Call(f, CallKind::Normal, args)) if
matches!(f.as_ref(), Expression::Reference(n) if n.as_printed() == "f") && matches!(f.as_ref(), Expression::Reference(_,n) if n.as_printed() == "f") &&
args.is_empty())); args.is_empty()));
assert!(matches!( assert!(matches!(
parse_ex("f(a)"), parse_ex("f(a)"),
Ok(Expression::Call(f, CallKind::Normal, args)) if Ok(Expression::Call(f, CallKind::Normal, args)) if
matches!(f.as_ref(), Expression::Reference(n) if n.as_printed() == "f") && matches!(f.as_ref(), Expression::Reference(_,n) if n.as_printed() == "f") &&
matches!(args.as_slice(), [Expression::Reference(n)] if n.as_printed() == "a"))); matches!(args.as_slice(), [Expression::Reference(_,n)] if n.as_printed() == "a")));
assert!(matches!( assert!(matches!(
parse_ex("f(a,b)"), parse_ex("f(a,b)"),
Ok(Expression::Call(f, CallKind::Normal, args)) if Ok(Expression::Call(f, CallKind::Normal, args)) if
matches!(f.as_ref(), Expression::Reference(n) if n.as_printed() == "f") && matches!(f.as_ref(), Expression::Reference(_,n) if n.as_printed() == "f") &&
matches!(args.as_slice(), [ matches!(args.as_slice(), [
Expression::Reference(a), Expression::Reference(_,a),
Expression::Reference(b), Expression::Reference(_,b),
] if a.as_printed() == "a" && b.as_printed() == "b"))); ] if a.as_printed() == "a" && b.as_printed() == "b")));
assert!(matches!( assert!(matches!(
parse_ex("f(a,b,)"), parse_ex("f(a,b,)"),
Ok(Expression::Call(f, CallKind::Normal, args)) if Ok(Expression::Call(f, CallKind::Normal, args)) if
matches!(f.as_ref(), Expression::Reference(n) if n.as_printed() == "f") && matches!(f.as_ref(), Expression::Reference(_,n) if n.as_printed() == "f") &&
matches!(args.as_slice(), [ matches!(args.as_slice(), [
Expression::Reference(a), Expression::Reference(_,a),
Expression::Reference(b), Expression::Reference(_,b),
] if a.as_printed() == "a" && b.as_printed() == "b"))); ] if a.as_printed() == "a" && b.as_printed() == "b")));
assert!(matches!(parse_ex("f(,a,b,)"), Err(_))); assert!(parse_ex("f(,a,b,)").is_err());
assert!(matches!(parse_ex("f(a,,b,)"), Err(_))); assert!(parse_ex("f(a,,b,)").is_err());
assert!(matches!(parse_ex("f(a,b,,)"), Err(_))); assert!(parse_ex("f(a,b,,)").is_err());
assert!(matches!( assert!(matches!(
parse_ex("f()()"), parse_ex("f()()"),
Ok(Expression::Call(f, CallKind::Normal, args)) if Ok(Expression::Call(f, CallKind::Normal, args)) if
matches!(f.as_ref(), Expression::Call(inner, CallKind::Normal, inner_args) if matches!(f.as_ref(), Expression::Call(inner, CallKind::Normal, inner_args) if
matches!(inner.as_ref(), Expression::Reference(n) if n.as_printed() == "f") && matches!(inner.as_ref(), Expression::Reference(_,n) if n.as_printed() == "f") &&
inner_args.is_empty()) && inner_args.is_empty()) &&
args.is_empty())); args.is_empty()));
assert!(matches!( assert!(matches!(
parse_ex("f() + 1"), parse_ex("f() + 1"),
Ok(Expression::Call(plus, CallKind::Infix, args)) if Ok(Expression::Call(plus, CallKind::Infix, args)) if
matches!(plus.as_ref(), Expression::Reference(n) if n.as_printed() == "+") && matches!(plus.as_ref(), Expression::Reference(_,n) if n.as_printed() == "+") &&
matches!(args.as_slice(), [ matches!(args.as_slice(), [
Expression::Call(subcall, CallKind::Normal, subargs), Expression::Call(subcall, CallKind::Normal, subargs),
Expression::Value(ConstantValue::Integer(_, v1)) Expression::Value(ConstantValue::Integer(_, v1))
] if ] if
matches!(v1, IntegerWithBase{ value: 1, .. }) && matches!(v1, IntegerWithBase{ value: 1, .. }) &&
matches!(subcall.as_ref(), Expression::Reference(n) if n.as_printed() == "f") && matches!(subcall.as_ref(), Expression::Reference(_,n) if n.as_printed() == "f") &&
subargs.is_empty()))); subargs.is_empty())));
assert!(matches!( assert!(matches!(
parse_ex("f(a + b, c*d)"), parse_ex("f(a + b, c*d)"),
Ok(Expression::Call(eff, CallKind::Normal, args)) if Ok(Expression::Call(eff, CallKind::Normal, args)) if
matches!(eff.as_ref(), Expression::Reference(n) if n.as_printed() == "f") && matches!(eff.as_ref(), Expression::Reference(_,n) if n.as_printed() == "f") &&
matches!(args.as_slice(), [ matches!(args.as_slice(), [
Expression::Call(plus, CallKind::Infix, pargs), Expression::Call(plus, CallKind::Infix, pargs),
Expression::Call(times, CallKind::Infix, targs), Expression::Call(times, CallKind::Infix, targs),
] if ] if
matches!(plus.as_ref(), Expression::Reference(n) if n.as_printed() == "+") && matches!(plus.as_ref(), Expression::Reference(_,n) if n.as_printed() == "+") &&
matches!(times.as_ref(), Expression::Reference(n) if n.as_printed() == "*") && matches!(times.as_ref(), Expression::Reference(_,n) if n.as_printed() == "*") &&
matches!(pargs.as_slice(), [ Expression::Reference(a), Expression::Reference(b) ] if matches!(pargs.as_slice(), [ Expression::Reference(_,a), Expression::Reference(_,b) ] if
a.as_printed() == "a" && b.as_printed() == "b") && a.as_printed() == "a" && b.as_printed() == "b") &&
matches!(targs.as_slice(), [ Expression::Reference(c), Expression::Reference(d) ] if matches!(targs.as_slice(), [ Expression::Reference(_,c), Expression::Reference(_,d) ] if
c.as_printed() == "c" && d.as_printed() == "d")))); c.as_printed() == "c" && d.as_printed() == "d"))));
assert!(matches!( assert!(matches!(
parse_ex("f(a + b, c*d,)"), parse_ex("f(a + b, c*d,)"),
Ok(Expression::Call(eff, CallKind::Normal, args)) if Ok(Expression::Call(eff, CallKind::Normal, args)) if
matches!(eff.as_ref(), Expression::Reference(n) if n.as_printed() == "f") && matches!(eff.as_ref(), Expression::Reference(_,n) if n.as_printed() == "f") &&
matches!(args.as_slice(), [ matches!(args.as_slice(), [
Expression::Call(plus, CallKind::Infix, pargs), Expression::Call(plus, CallKind::Infix, pargs),
Expression::Call(times, CallKind::Infix, targs), Expression::Call(times, CallKind::Infix, targs),
] if ] if
matches!(plus.as_ref(), Expression::Reference(n) if n.as_printed() == "+") && matches!(plus.as_ref(), Expression::Reference(_,n) if n.as_printed() == "+") &&
matches!(times.as_ref(), Expression::Reference(n) if n.as_printed() == "*") && matches!(times.as_ref(), Expression::Reference(_,n) if n.as_printed() == "*") &&
matches!(pargs.as_slice(), [ Expression::Reference(a), Expression::Reference(b) ] if matches!(pargs.as_slice(), [ Expression::Reference(_,a), Expression::Reference(_,b) ] if
a.as_printed() == "a" && b.as_printed() == "b") && a.as_printed() == "a" && b.as_printed() == "b") &&
matches!(targs.as_slice(), [ Expression::Reference(c), Expression::Reference(d) ] if matches!(targs.as_slice(), [ Expression::Reference(_,c), Expression::Reference(_,d) ] if
c.as_printed() == "c" && d.as_printed() == "d")))); c.as_printed() == "c" && d.as_printed() == "d"))));
assert!(matches!( assert!(matches!(
parse_ex("3 + f(1 + 2)"), parse_ex("3 + f(1 + 2)"),
Ok(Expression::Call(plus, CallKind::Infix, args)) if Ok(Expression::Call(plus, CallKind::Infix, args)) if
matches!(plus.as_ref(), Expression::Reference(n) if n.as_printed() == "+") && matches!(plus.as_ref(), Expression::Reference(_,n) if n.as_printed() == "+") &&
matches!(args.as_slice(), [ matches!(args.as_slice(), [
Expression::Value(ConstantValue::Integer(_, v3)), Expression::Value(ConstantValue::Integer(_, v3)),
Expression::Call(eff, CallKind::Normal, fargs) Expression::Call(eff, CallKind::Normal, fargs)
] if ] if
matches!(v3, IntegerWithBase{ value: 3, .. }) && matches!(v3, IntegerWithBase{ value: 3, .. }) &&
matches!(eff.as_ref(), Expression::Reference(n) if n.as_printed() == "f") && matches!(eff.as_ref(), Expression::Reference(_,n) if n.as_printed() == "f") &&
matches!(fargs.as_slice(), [Expression::Call(p, CallKind::Infix, pargs)] if matches!(fargs.as_slice(), [Expression::Call(p, CallKind::Infix, pargs)] if
matches!(p.as_ref(), Expression::Reference(n) if n.as_printed() == "+") && matches!(p.as_ref(), Expression::Reference(_,n) if n.as_printed() == "+") &&
matches!(pargs.as_slice(), [Expression::Value(v1), Expression::Value(v2)] if matches!(pargs.as_slice(), [Expression::Value(v1), Expression::Value(v2)] if
matches!(v1, ConstantValue::Integer(_, IntegerWithBase { value: 1, .. })) && matches!(v1, ConstantValue::Integer(_, IntegerWithBase { value: 1, .. })) &&
matches!(v2, ConstantValue::Integer(_, IntegerWithBase { value: 2, .. }))))))); matches!(v2, ConstantValue::Integer(_, IntegerWithBase { value: 2, .. })))))));
@@ -728,11 +732,11 @@ fn calls() {
parse_ex("(f . g)(1 + 2)"), parse_ex("(f . g)(1 + 2)"),
Ok(Expression::Call(fg, CallKind::Normal, args)) if Ok(Expression::Call(fg, CallKind::Normal, args)) if
matches!(fg.as_ref(), Expression::Call(dot, CallKind::Infix, fgargs) if matches!(fg.as_ref(), Expression::Call(dot, CallKind::Infix, fgargs) if
matches!(dot.as_ref(), Expression::Reference(n) if n.as_printed() == ".") && matches!(dot.as_ref(), Expression::Reference(_,n) if n.as_printed() == ".") &&
matches!(fgargs.as_slice(), [Expression::Reference(f), Expression::Reference(g)] if matches!(fgargs.as_slice(), [Expression::Reference(_,f), Expression::Reference(_,g)] if
f.as_printed() == "f" && g.as_printed() == "g")) && f.as_printed() == "f" && g.as_printed() == "g")) &&
matches!(args.as_slice(), [Expression::Call(plus, CallKind::Infix, pargs)] if matches!(args.as_slice(), [Expression::Call(plus, CallKind::Infix, pargs)] if
matches!(plus.as_ref(), Expression::Reference(n) if n.as_printed() == "+") && matches!(plus.as_ref(), Expression::Reference(_,n) if n.as_printed() == "+") &&
matches!(pargs.as_slice(), [Expression::Value(v1), Expression::Value(v2)] if matches!(pargs.as_slice(), [Expression::Value(v1), Expression::Value(v2)] if
matches!(v1, ConstantValue::Integer(_, IntegerWithBase{ value: 1, .. })) && matches!(v1, ConstantValue::Integer(_, IntegerWithBase{ value: 1, .. })) &&
matches!(v2, ConstantValue::Integer(_, IntegerWithBase{ value: 2, .. })))))); matches!(v2, ConstantValue::Integer(_, IntegerWithBase{ value: 2, .. }))))));
@@ -740,19 +744,19 @@ fn calls() {
assert!(matches!( assert!(matches!(
parse_ex("a + b(2 + 3) * c"), parse_ex("a + b(2 + 3) * c"),
Ok(Expression::Call(plus, CallKind::Infix, pargs)) if Ok(Expression::Call(plus, CallKind::Infix, pargs)) if
matches!(plus.as_ref(), Expression::Reference(n) if n.as_printed() == "+") && matches!(plus.as_ref(), Expression::Reference(_,n) if n.as_printed() == "+") &&
matches!(pargs.as_slice(), [ matches!(pargs.as_slice(), [
Expression::Reference(a), Expression::Reference(_,a),
Expression::Call(times, CallKind::Infix, targs) Expression::Call(times, CallKind::Infix, targs)
] if a.as_printed() == "a" && ] if a.as_printed() == "a" &&
matches!(times.as_ref(), Expression::Reference(n) if n.as_printed() == "*") && matches!(times.as_ref(), Expression::Reference(_,n) if n.as_printed() == "*") &&
matches!(targs.as_slice(), [ matches!(targs.as_slice(), [
Expression::Call(b, CallKind::Normal, bargs), Expression::Call(b, CallKind::Normal, bargs),
Expression::Reference(c), Expression::Reference(_,c),
] if c.as_printed() == "c" && ] if c.as_printed() == "c" &&
matches!(b.as_ref(), Expression::Reference(n) if n.as_printed() == "b") && matches!(b.as_ref(), Expression::Reference(_,n) if n.as_printed() == "b") &&
matches!(bargs.as_slice(), [Expression::Call(plus, CallKind::Infix, pargs)] if matches!(bargs.as_slice(), [Expression::Call(plus, CallKind::Infix, pargs)] if
matches!(plus.as_ref(), Expression::Reference(n) if n.as_printed() == "+") && matches!(plus.as_ref(), Expression::Reference(_,n) if n.as_printed() == "+") &&
matches!(pargs.as_slice(), [ matches!(pargs.as_slice(), [
Expression::Value(ConstantValue::Integer(_, IntegerWithBase{ value: 2, .. })), Expression::Value(ConstantValue::Integer(_, IntegerWithBase{ value: 2, .. })),
Expression::Value(ConstantValue::Integer(_, IntegerWithBase{ value: 3, .. })) Expression::Value(ConstantValue::Integer(_, IntegerWithBase{ value: 3, .. }))
@@ -776,56 +780,56 @@ fn prefix_and_postfix() {
assert!(matches!( assert!(matches!(
parse_ex("++a"), parse_ex("++a"),
Ok(Expression::Call(pp, CallKind::Prefix, args)) if Ok(Expression::Call(pp, CallKind::Prefix, args)) if
matches!(pp.as_ref(), Expression::Reference(n) if n.as_printed() == "++") && matches!(pp.as_ref(), Expression::Reference(_,n) if n.as_printed() == "++") &&
matches!(args.as_slice(), [Expression::Reference(n)] if n.as_printed() == "a"))); matches!(args.as_slice(), [Expression::Reference(_,n)] if n.as_printed() == "a")));
assert!(matches!( assert!(matches!(
parse_ex("a--"), parse_ex("a--"),
Ok(Expression::Call(pp, CallKind::Postfix, args)) if Ok(Expression::Call(pp, CallKind::Postfix, args)) if
matches!(pp.as_ref(), Expression::Reference(n) if n.as_printed() == "--") && matches!(pp.as_ref(), Expression::Reference(_,n) if n.as_printed() == "--") &&
matches!(args.as_slice(), [Expression::Reference(n)] if n.as_printed() == "a"))); matches!(args.as_slice(), [Expression::Reference(_,n)] if n.as_printed() == "a")));
// the prefix is weaker than the postfix, so it should be the outside // the prefix is weaker than the postfix, so it should be the outside
// operatotr // operatotr
assert!(matches!( assert!(matches!(
parse_ex("++a--"), parse_ex("++a--"),
Ok(Expression::Call(pp, CallKind::Prefix, args)) if Ok(Expression::Call(pp, CallKind::Prefix, args)) if
matches!(pp.as_ref(), Expression::Reference(n) if n.as_printed() == "++") && matches!(pp.as_ref(), Expression::Reference(_,n) if n.as_printed() == "++") &&
matches!(args.as_slice(), [Expression::Call(mm, CallKind::Postfix, args)] if matches!(args.as_slice(), [Expression::Call(mm, CallKind::Postfix, args)] if
matches!(mm.as_ref(), Expression::Reference(n) if n.as_printed() == "--") && matches!(mm.as_ref(), Expression::Reference(_,n) if n.as_printed() == "--") &&
matches!(args.as_slice(), [Expression::Reference(n)] if n.as_printed() == "a")))); matches!(args.as_slice(), [Expression::Reference(_,n)] if n.as_printed() == "a"))));
// the prefix is stronger than the postfix, so it should be the inside // the prefix is stronger than the postfix, so it should be the inside
// operator // operator
assert!(matches!( assert!(matches!(
parse_ex("--a++"), parse_ex("--a++"),
Ok(Expression::Call(pp, CallKind::Postfix, args)) if Ok(Expression::Call(pp, CallKind::Postfix, args)) if
matches!(pp.as_ref(), Expression::Reference(n) if n.as_printed() == "++") && matches!(pp.as_ref(), Expression::Reference(_,n) if n.as_printed() == "++") &&
matches!(args.as_slice(), [Expression::Call(mm, CallKind::Prefix, args)] if matches!(args.as_slice(), [Expression::Call(mm, CallKind::Prefix, args)] if
matches!(mm.as_ref(), Expression::Reference(n) if n.as_printed() == "--") && matches!(mm.as_ref(), Expression::Reference(_,n) if n.as_printed() == "--") &&
matches!(args.as_slice(), [Expression::Reference(n)] if n.as_printed() == "a")))); matches!(args.as_slice(), [Expression::Reference(_,n)] if n.as_printed() == "a"))));
assert!(matches!( assert!(matches!(
parse_ex("a++ + b"), parse_ex("a++ + b"),
Ok(Expression::Call(p, CallKind::Infix, args)) if Ok(Expression::Call(p, CallKind::Infix, args)) if
matches!(p.as_ref(), Expression::Reference(n) if n.as_printed() == "+") && matches!(p.as_ref(), Expression::Reference(_,n) if n.as_printed() == "+") &&
matches!(args.as_slice(), [ matches!(args.as_slice(), [
Expression::Call(mm, CallKind::Postfix, args), Expression::Call(mm, CallKind::Postfix, args),
Expression::Reference(n) Expression::Reference(_,n)
] if n.as_printed() == "b" && ] if n.as_printed() == "b" &&
matches!(mm.as_ref(), Expression::Reference(n) if n.as_printed() == "++") && matches!(mm.as_ref(), Expression::Reference(_,n) if n.as_printed() == "++") &&
matches!(args.as_slice(), [Expression::Reference(n)] if n.as_printed() == "a")))); matches!(args.as_slice(), [Expression::Reference(_,n)] if n.as_printed() == "a"))));
assert!(matches!( assert!(matches!(
parse_ex("a + ++ b"), parse_ex("a + ++ b"),
Ok(Expression::Call(p, CallKind::Infix, args)) if Ok(Expression::Call(p, CallKind::Infix, args)) if
matches!(p.as_ref(), Expression::Reference(n) if n.as_printed() == "+") && matches!(p.as_ref(), Expression::Reference(_,n) if n.as_printed() == "+") &&
matches!(args.as_slice(), [ matches!(args.as_slice(), [
Expression::Reference(n), Expression::Reference(_,n),
Expression::Call(mm, CallKind::Prefix, args), Expression::Call(mm, CallKind::Prefix, args),
] if n.as_printed() == "a" && ] if n.as_printed() == "a" &&
matches!(mm.as_ref(), Expression::Reference(n) if n.as_printed() == "++") && matches!(mm.as_ref(), Expression::Reference(_,n) if n.as_printed() == "++") &&
matches!(args.as_slice(), [Expression::Reference(n)] if n.as_printed() == "b")))); matches!(args.as_slice(), [Expression::Reference(_,n)] if n.as_printed() == "b"))));
assert!(matches!( assert!(matches!(
parse_ex("a * ++ b"), parse_ex("a * ++ b"),
@@ -846,29 +850,29 @@ fn blocks() {
Ok(Expression::Block(_, void)) if Ok(Expression::Block(_, void)) if
matches!(void.as_slice(), [Statement::Expression(call)] if matches!(void.as_slice(), [Statement::Expression(call)] if
matches!(call, Expression::Call(void, CallKind::Normal, vargs) if matches!(call, Expression::Call(void, CallKind::Normal, vargs) if
matches!(void.as_ref(), Expression::Reference(n) if matches!(void.as_ref(), Expression::Reference(_,n) if
n.as_printed() == "%prim%void") && n.as_printed() == "%prim%void") &&
vargs.is_empty())))); vargs.is_empty()))));
assert!(matches!( assert!(matches!(
parse_ex("{ x }"), parse_ex("{ x }"),
Ok(Expression::Block(_, x)) if Ok(Expression::Block(_, x)) if
matches!(x.as_slice(), [Statement::Expression(Expression::Reference(n))] if matches!(x.as_slice(), [Statement::Expression(Expression::Reference(_,n))] if
n.as_printed() == "x"))); n.as_printed() == "x")));
assert!(matches!( assert!(matches!(
parse_ex("{ x; }"), parse_ex("{ x; }"),
Ok(Expression::Block(_, x)) if Ok(Expression::Block(_, x)) if
matches!(x.as_slice(), [ matches!(x.as_slice(), [
Statement::Expression(Expression::Reference(n)), Statement::Expression(Expression::Reference(_,n)),
Statement::Expression(Expression::Call(primv, CallKind::Normal, vargs)), Statement::Expression(Expression::Call(primv, CallKind::Normal, vargs)),
] if n.as_printed() == "x" && vargs.is_empty() && ] if n.as_printed() == "x" && vargs.is_empty() &&
matches!(primv.as_ref(), Expression::Reference(n) if matches!(primv.as_ref(), Expression::Reference(_,n) if
n.as_printed() == "%prim%void")))); n.as_printed() == "%prim%void"))));
assert!(matches!( assert!(matches!(
parse_ex("{ x; y }"), parse_ex("{ x; y }"),
Ok(Expression::Block(_, x)) if Ok(Expression::Block(_, x)) if
matches!(x.as_slice(), [ matches!(x.as_slice(), [
Statement::Expression(Expression::Reference(x)), Statement::Expression(Expression::Reference(_,x)),
Statement::Expression(Expression::Reference(y)), Statement::Expression(Expression::Reference(_,y)),
] if x.as_printed() == "x" && y.as_printed() == "y"))); ] if x.as_printed() == "x" && y.as_printed() == "y")));
} }
@@ -886,7 +890,7 @@ fn bindings() {
matches!(x.as_slice(), [Statement::Binding(b), Statement::Expression(_)] if matches!(x.as_slice(), [Statement::Binding(b), Statement::Expression(_)] if
!b.mutable && !b.mutable &&
b.variable.as_printed() == "x" && b.variable.as_printed() == "x" &&
matches!(b.value, Expression::Reference(ref n) if n.as_printed() == "y")))); matches!(b.value, Expression::Reference(_,ref n) if n.as_printed() == "y"))));
} }
#[test] #[test]
@@ -900,25 +904,25 @@ fn conditionals() {
assert!(matches!( assert!(matches!(
parse_ex("if x { y } else { z }"), parse_ex("if x { y } else { z }"),
Ok(Expression::Conditional(cond)) if Ok(Expression::Conditional(cond)) if
matches!(cond.test.as_ref(), Expression::Reference(n) if n.as_printed() == "x") && matches!(cond.test.as_ref(), Expression::Reference(_,n) if n.as_printed() == "x") &&
matches!(cond.consequent.as_ref(), Expression::Block(_, cs) if matches!(cond.consequent.as_ref(), Expression::Block(_, cs) if
matches!(cs.as_slice(), [Statement::Expression(Expression::Reference(n))] if matches!(cs.as_slice(), [Statement::Expression(Expression::Reference(_,n))] if
n.as_printed() == "y")) && n.as_printed() == "y")) &&
matches!(cond.alternative.as_ref(), Some(expr) if matches!(cond.alternative.as_ref(), Some(expr) if
matches!(expr.as_ref(), Expression::Block(_, ast) if matches!(expr.as_ref(), Expression::Block(_, ast) if
matches!(ast.as_slice(), [Statement::Expression(Expression::Reference(n))] if matches!(ast.as_slice(), [Statement::Expression(Expression::Reference(_,n))] if
n.as_printed() == "z"))))); n.as_printed() == "z")))));
assert!(matches!( assert!(matches!(
parse_ex("if x { y }"), parse_ex("if x { y }"),
Ok(Expression::Conditional(cond)) if Ok(Expression::Conditional(cond)) if
matches!(cond.test.as_ref(), Expression::Reference(n) if n.as_printed() == "x") && matches!(cond.test.as_ref(), Expression::Reference(_,n) if n.as_printed() == "x") &&
matches!(cond.consequent.as_ref(), Expression::Block(_, cs) if matches!(cond.consequent.as_ref(), Expression::Block(_, cs) if
matches!(cs.as_slice(), [Statement::Expression(Expression::Reference(n))] if matches!(cs.as_slice(), [Statement::Expression(Expression::Reference(_,n))] if
n.as_printed() == "y")) && n.as_printed() == "y")) &&
cond.alternative.is_none())); cond.alternative.is_none()));
assert!(matches!(parse_ex("if x v { z }"), Err(_))); assert!(parse_ex("if x v { z }").is_err());
assert!(matches!( assert!(matches!(
parse_ex("if x + y { z }"), parse_ex("if x + y { z }"),

View File

@@ -27,6 +27,7 @@ pub enum Token {
CloseBrace, CloseBrace,
Semi, Semi,
Colon, Colon,
DoubleColon,
Comma, Comma,
BackTick, BackTick,
Arrow, Arrow,
@@ -61,6 +62,7 @@ impl fmt::Display for Token {
Token::CloseBrace => write!(f, "}}"), Token::CloseBrace => write!(f, "}}"),
Token::Semi => write!(f, ";"), Token::Semi => write!(f, ";"),
Token::Colon => write!(f, ":"), Token::Colon => write!(f, ":"),
Token::DoubleColon => write!(f, "::"),
Token::Comma => write!(f, ","), Token::Comma => write!(f, ","),
Token::BackTick => write!(f, "`"), Token::BackTick => write!(f, "`"),
Token::Arrow => write!(f, "->"), Token::Arrow => write!(f, "->"),
@@ -99,10 +101,7 @@ struct LexerState<'a> {
impl<'a> From<&'a str> for Lexer<'a> { impl<'a> From<&'a str> for Lexer<'a> {
fn from(value: &'a str) -> Self { fn from(value: &'a str) -> Self {
Lexer::Working(LexerState { Lexer::new(value)
stream: value.char_indices(),
buffer: None,
})
} }
} }
@@ -142,8 +141,7 @@ impl<'a> Iterator for Lexer<'a> {
impl<'a> LexerState<'a> { impl<'a> LexerState<'a> {
fn next_char(&mut self) -> Option<(usize, char)> { fn next_char(&mut self) -> Option<(usize, char)> {
let result = self.buffer.take().or_else(|| self.stream.next()); self.buffer.take().or_else(|| self.stream.next())
result
} }
fn stash_char(&mut self, idx: usize, c: char) { fn stash_char(&mut self, idx: usize, c: char) {
@@ -172,7 +170,6 @@ impl<'a> LexerState<'a> {
'{' => return simple_response(Token::OpenBrace), '{' => return simple_response(Token::OpenBrace),
'}' => return simple_response(Token::CloseBrace), '}' => return simple_response(Token::CloseBrace),
';' => return simple_response(Token::Semi), ';' => return simple_response(Token::Semi),
':' => return simple_response(Token::Colon),
',' => return simple_response(Token::Comma), ',' => return simple_response(Token::Comma),
'`' => return simple_response(Token::BackTick), '`' => return simple_response(Token::BackTick),
'\\' => return simple_response(Token::Lambda(false)), '\\' => return simple_response(Token::Lambda(false)),
@@ -182,6 +179,7 @@ impl<'a> LexerState<'a> {
'\'' => return self.starts_with_single(token_start_offset), '\'' => return self.starts_with_single(token_start_offset),
'\"' => return self.starts_with_double(token_start_offset), '\"' => return self.starts_with_double(token_start_offset),
'-' => return self.starts_with_dash(token_start_offset), '-' => return self.starts_with_dash(token_start_offset),
':' => return self.starts_with_colon(token_start_offset),
_ => {} _ => {}
} }
@@ -519,6 +517,31 @@ impl<'a> LexerState<'a> {
} }
} }
} }
fn starts_with_colon(
&mut self,
token_start_offset: usize,
) -> Result<Option<LocatedToken>, LexerError> {
match self.next_char() {
None => Ok(Some(LocatedToken {
token: Token::Colon,
span: token_start_offset..token_start_offset + 1,
})),
Some((pos, ':')) => Ok(Some(LocatedToken {
token: Token::DoubleColon,
span: token_start_offset..pos,
})),
Some((pos, char)) => {
self.stash_char(pos, char);
Ok(Some(LocatedToken {
token: Token::Colon,
span: token_start_offset..token_start_offset + 1,
}))
}
}
}
} }
proptest::proptest! { proptest::proptest! {
@@ -542,7 +565,7 @@ fn parsed_single_token(s: &str) -> Token {
let mut tokens = Lexer::from(s); let mut tokens = Lexer::from(s);
let result = tokens let result = tokens
.next() .next()
.expect(format!("Can get at least one token from {s:?}").as_str()) .unwrap_or_else(|| panic!("Can get at least one token from {s:?}"))
.expect("Can get a valid token.") .expect("Can get a valid token.")
.token; .token;

View File

@@ -6,21 +6,17 @@ use memmap2::Mmap;
use std::collections::HashMap; use std::collections::HashMap;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
#[derive(Default)]
pub struct Universe { pub struct Universe {
pub files: HashMap<PathBuf, Mmap>, pub files: HashMap<PathBuf, Mmap>,
pub modules: HashMap<PathBuf, Module>, pub modules: HashMap<PathBuf, Module>,
} }
impl Default for Universe {
fn default() -> Self {
Universe {
files: HashMap::new(),
modules: HashMap::new(),
}
}
}
impl Universe { impl Universe {
/// Add a file to this universe.
///
/// This may result in other files being loaded on behalf of the file, if
/// (for example) the given file has imports.
pub fn add_file<P: AsRef<Path>>(&mut self, file: P) -> Result<(), ParserError> { pub fn add_file<P: AsRef<Path>>(&mut self, file: P) -> Result<(), ParserError> {
let filename = file.as_ref().to_string_lossy().into_owned(); let filename = file.as_ref().to_string_lossy().into_owned();