use crate::syntax::location::{Located, Location}; use crate::syntax::name::Name; use proptest_derive::Arbitrary; #[derive(Debug)] pub struct Module { pub definitions: Vec, } #[derive(Debug)] pub struct Definition { pub location: Location, pub export: ExportClass, pub type_restrictions: TypeRestrictions, pub definition: Def, } impl Located for Definition { fn location(&self) -> Location { self.location.clone() } } #[derive(Debug)] pub enum Def { Enumeration(EnumerationDef), Structure(StructureDef), Function(FunctionDef), Value(ValueDef), Operator(OperatorDef), } impl Located for Def { fn location(&self) -> Location { match self { Def::Enumeration(def) => def.location.clone(), Def::Structure(def) => def.location.clone(), Def::Function(def) => def.location.clone(), Def::Value(def) => def.location.clone(), Def::Operator(def) => def.location.clone(), } } } #[derive(Debug)] pub struct EnumerationDef { pub name: Name, pub location: Location, pub variants: Vec, } #[derive(Debug)] pub struct EnumerationVariant { pub location: Location, pub name: Name, pub argument: Option, } #[derive(Debug)] pub struct StructureDef { pub name: Name, pub location: Location, pub fields: Vec, } #[derive(Debug)] pub struct StructureField { pub location: Location, pub export: ExportClass, pub name: Name, pub field_type: Option, } #[derive(Debug)] pub struct FunctionDef { pub name: Name, pub location: Location, pub arguments: Vec, pub return_type: Option, pub body: Vec, } #[derive(Debug)] pub struct FunctionArg { pub name: Name, pub arg_type: Option, } #[derive(Debug)] pub struct ValueDef { pub name: Name, pub location: Location, pub mtype: Option, pub value: Expression, } #[derive(Debug)] pub struct OperatorDef { pub operator_name: Name, pub location: Location, pub function_name: Name, } #[derive(Debug)] pub enum ExportClass { Public, Private, } #[derive(Debug)] pub enum Statement { Binding(BindingStmt), Expression(Expression), } #[derive(Debug)] pub struct BindingStmt { pub location: Location, pub mutable: bool, pub variable: Name, pub value: Expression, } #[derive(Debug)] pub enum Expression { Value(ConstantValue), Reference(Location, Name), Enumeration(EnumerationExpr), Structure(StructureExpr), Conditional(ConditionalExpr), Match(MatchExpr), Call(Box, CallKind, Vec), Block(Location, Vec), } 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>, } #[derive(Debug)] pub struct StructureExpr { pub location: Location, pub type_name: Name, pub fields: Vec, } #[derive(Debug)] pub struct ConditionalExpr { pub location: Location, pub test: Box, pub consequent: Box, pub alternative: Option>, } #[derive(Debug)] pub struct MatchExpr { pub location: Location, pub value: Box, pub cases: Vec, } #[derive(Debug)] pub struct MatchCase { pub pattern: Pattern, pub consequent: Expression, } #[derive(Debug)] pub enum Pattern { Constant(ConstantValue), Variable(Name), EnumerationValue(EnumerationPattern), Structure(StructurePattern), } #[derive(Debug)] pub struct EnumerationPattern { pub location: Location, pub type_name: Name, pub variant_name: Name, pub argument: Option>, } #[derive(Debug)] pub struct StructurePattern { pub location: Location, pub type_name: Name, pub fields: Vec<(Name, Option)>, } #[derive(Debug)] pub enum CallKind { Infix, Normal, Postfix, Prefix, } #[derive(Debug)] pub struct FieldValue { pub field: Name, pub value: Expression, } #[derive(Debug)] pub struct TypeRestrictions { pub restrictions: Vec, } impl TypeRestrictions { pub fn empty() -> Self { TypeRestrictions { restrictions: vec![], } } pub fn is_empty(&self) -> bool { self.restrictions.is_empty() } } #[derive(Debug)] pub struct TypeRestriction { pub constructor: Type, pub arguments: Vec, } #[derive(Clone, Debug)] pub enum Type { Constructor(Location, Name), Variable(Location, Name), Primitive(Location, Name), Application(Box, Vec), Function(Vec, Box), } impl PartialEq for Type { fn eq(&self, other: &Self) -> bool { match self { Type::Constructor(_, x) => matches!(other, Type::Constructor(_, y) if x == y), Type::Variable(_, x) => matches!(other, Type::Variable(_, y) if x == y), Type::Primitive(_, x) => matches!(other, Type::Primitive(_, y) if x == y), Type::Application(con1, args1) => { matches!(other, Type::Application(con2, args2) if con1 == con2 && args1 == args2) } Type::Function(args1, ret1) => { matches!(other, Type::Function(args2, ret2) if args1 == args2 && ret1 == ret2) } } } } impl Located for Type { fn location(&self) -> Location { match self { Type::Constructor(l, _) => l.clone(), Type::Variable(l, _) => l.clone(), Type::Primitive(l, _) => l.clone(), Type::Application(t1, ts) => { let mut result = t1.location(); if let Some(last) = ts.last() { result = result.extend_to(&last.location()); } result } Type::Function(args, ret) => { if let Some(first) = args.first() { first.location().extend_to(&ret.location()) } else { ret.location() } } } } } #[derive(Clone, Debug)] pub enum ConstantValue { Integer(Location, IntegerWithBase), Character(Location, char), 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(), } } } impl PartialEq for ConstantValue { fn eq(&self, other: &Self) -> bool { match self { ConstantValue::Character(_, x) => { matches!(other, ConstantValue::Character(_, y) if x == y) } ConstantValue::String(_, x) => matches!(other, ConstantValue::String(_, y) if x == y), ConstantValue::Integer(_, x) => matches!(other, ConstantValue::Integer(_, y) if x == y), } } } #[derive(Clone, Debug, PartialEq, Eq, Arbitrary)] pub struct IntegerWithBase { #[proptest(strategy = "proptest::prop_oneof![ \ proptest::strategy::Just(None), \ proptest::strategy::Just(Some(2)), \ proptest::strategy::Just(Some(8)), \ proptest::strategy::Just(Some(10)), \ proptest::strategy::Just(Some(16)), \ ]")] pub base: Option, pub value: u64, }