diff --git a/src/syntax.rs b/src/syntax.rs index a4701b6..3b40648 100644 --- a/src/syntax.rs +++ b/src/syntax.rs @@ -48,10 +48,12 @@ impl Location { } } +#[derive(Debug)] pub struct Module { definitions: Vec, } +#[derive(Debug)] pub struct Definition { location: Location, export: ExportClass, @@ -59,6 +61,7 @@ pub struct Definition { definition: Def, } +#[derive(Debug)] pub enum Def { Enumeration(EnumerationDef), Structure(StructureDef), @@ -77,28 +80,33 @@ impl Def { } } +#[derive(Debug)] pub struct EnumerationDef { location: Location, options: Vec, } +#[derive(Debug)] pub struct EnumerationVariant { location: Location, name: String, arguments: Vec, } +#[derive(Debug)] pub struct StructureDef { name: String, location: Location, fields: Vec, } +#[derive(Debug)] pub struct StructureField { name: String, field_type: Type, } +#[derive(Debug)] pub struct FunctionDef { name: String, location: Location, @@ -107,26 +115,31 @@ pub struct FunctionDef { body: Vec, } +#[derive(Debug)] pub struct FunctionArg { name: String, arg_type: Option, } +#[derive(Debug)] pub struct ValueDef { name: String, location: Location, value: Value, } +#[derive(Debug)] pub enum ExportClass { Public, Private, } +#[derive(Debug)] pub enum Statement { Binding(BindingStmt), } +#[derive(Debug)] pub struct BindingStmt { location: Location, mutable: bool, @@ -134,10 +147,12 @@ pub struct BindingStmt { value: Expression, } +#[derive(Debug)] pub enum Expression { Value(Value), } +#[derive(Debug)] pub struct TypeRestrictions { restrictions: Vec, } @@ -150,24 +165,28 @@ impl TypeRestrictions { } } +#[derive(Debug)] pub struct TypeRestriction { location: Location, class: String, variables: Vec, } +#[derive(Debug)] pub enum Type { Constructor(Location, String), Variable(Location, String), Primitive(Location, String), Application(Box, Vec), - Function(Vec, Box), + Function(Box, Box), } +#[derive(Debug)] pub enum Value { Constant(ConstantValue), } +#[derive(Debug)] pub enum ConstantValue { Integer(Location, IntegerWithBase), Character(Location, char), @@ -249,3 +268,58 @@ fn can_parse_constants() { Ok(ConstantValue::Character(_, 'f')) )); } + +#[test] +fn can_parse_types() { + let parse_type = |str| { + let lexer = Lexer::from(str).map(|item| { + item.map_err(|e| ParserError::LexerError { + file_id: 0, + error: e, + }) + }); + let result = TypeParser::new().parse(0, lexer); + result + }; + + println!("cons result: {:?}", parse_type("Cons")); + assert!(matches!( + parse_type("Cons"), + Ok(Type::Application(cons, empty)) if + matches!(cons.as_ref(), Type::Constructor(_, c) if c == "Cons") && + empty.is_empty() + )); + assert!(matches!( + parse_type("cons"), + Ok(Type::Variable(_, c)) if c == "cons" + )); + assert!(matches!( + parse_type("Cons a b"), + Ok(Type::Application(a, b)) + if matches!(a.as_ref(), Type::Constructor(_, c) if c == "Cons") && + matches!(b.as_slice(), [Type::Variable(_, b1), Type::Variable(_, b2)] + if b1 == "a" && b2 == "b") + )); + assert!(matches!( + parse_type("a -> z"), + Ok(Type::Function(a, z)) + if matches!(a.as_slice(), [Type::Variable(_, a1)] if a1 == "a") && + matches!(z.as_ref(), Type::Variable(_, z1) if z1 == "z") + )); + assert!(matches!( + parse_type("a b -> z"), + Ok(Type::Function(a, z)) + if matches!(a.as_slice(), [Type::Variable(_, a1), Type::Variable(_, b1)] + if a1 == "a" && b1 == "b") && + matches!(z.as_ref(), Type::Variable(_, z1) if z1 == "z") + )); + assert!(matches!( + parse_type("Cons a b -> z"), + Ok(Type::Function(a, z)) + if matches!(a.as_slice(), [Type::Application(cons, appargs)] + if matches!(cons.as_ref(), Type::Constructor(_, c) if c == "Cons") && + matches!(appargs.as_slice(), [Type::Variable(_, b1), Type::Variable(_, b2)] + if b1 == "a" && b2 == "b")) && + matches!(z.as_ref(), Type::Variable(_, z1) if z1 == "z") + )); +}