#![allow(clippy::upper_case_acronyms)] #![allow(clippy::enum_variant_names)] use std::{ convert::{AsRef, From}, fmt, rc::Rc, }; mod operators; mod visitor; mod visualize; pub use operators::{BinOp, PrefixOp}; pub use visitor::*; use crate::{ derivative::Derivative, identifier::{define_id_kind, Id}, parsing::Location, }; define_id_kind!(ASTItem); pub type ItemId = Id; #[derive(Derivative, Debug)] #[derivative(PartialEq)] pub struct AST { #[derivative(PartialEq = "ignore")] pub id: ItemId, pub statements: Block, } impl fmt::Display for AST { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", visualize::render_ast(self)) } } #[derive(Derivative, Debug, Clone)] #[derivative(PartialEq)] pub struct Statement { #[derivative(PartialEq = "ignore")] pub id: ItemId, #[derivative(PartialEq = "ignore")] pub location: Location, pub kind: StatementKind, } #[derive(Debug, PartialEq, Clone)] pub enum StatementKind { Expression(Expression), Declaration(Declaration), Import(ImportSpecifier), Flow(FlowControl), } #[derive(Debug, Clone, PartialEq)] pub enum FlowControl { Continue, Break, Return(Option), } #[derive(Debug, Clone, PartialEq, Default)] pub struct Block { pub statements: Vec, } impl From> for Block { fn from(statements: Vec) -> Self { Self { statements } } } impl From for Block { fn from(statement: Statement) -> Self { Self { statements: vec![statement] } } } impl AsRef<[Statement]> for Block { fn as_ref(&self) -> &[Statement] { self.statements.as_ref() } } pub type ParamName = Rc; #[derive(Debug, Derivative, Clone)] #[derivative(PartialEq)] pub struct QualifiedName { #[derivative(PartialEq = "ignore")] pub id: ItemId, pub components: Vec>, } impl fmt::Display for QualifiedName { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match &self.components[..] { [] => write!(f, "[]"), [name] => write!(f, "{}", name), [name, rest @ ..] => { write!(f, "{}", name)?; for c in rest { write!(f, "::{}", c)?; } Ok(()) } } } } #[derive(Debug, PartialEq, Clone)] pub struct FormalParam { pub name: ParamName, pub default: Option, pub anno: Option, } #[derive(Debug, PartialEq, Clone)] pub enum Declaration { FuncSig(Signature), FuncDecl(Signature, Block), TypeDecl { name: TypeSingletonName, body: TypeBody, mutable: bool }, //TODO TypeAlias `original` needs to be a more complex type definition TypeAlias { alias: Rc, original: Rc }, Binding { name: Rc, constant: bool, type_anno: Option, expr: Expression }, Impl { type_name: TypeIdentifier, interface_name: Option, block: Vec }, Interface { name: Rc, signatures: Vec }, //TODO need to limit the types of statements that can be annotated Annotation { name: Rc, arguments: Vec, inner: Box }, Module { name: Rc, items: Block }, } #[derive(Debug, PartialEq, Clone)] pub struct Signature { pub name: Rc, pub operator: bool, pub params: Vec, pub type_anno: Option, } //TODO I can probably get rid of TypeBody #[derive(Debug, PartialEq, Clone)] pub enum TypeBody { Variants(Vec), ImmediateRecord(ItemId, Vec<(Rc, TypeIdentifier)>), } #[derive(Debug, Derivative, Clone)] #[derivative(PartialEq)] pub struct Variant { #[derivative(PartialEq = "ignore")] pub id: ItemId, pub name: Rc, pub kind: VariantKind, } #[derive(Debug, PartialEq, Clone)] pub enum VariantKind { UnitStruct, TupleStruct(Vec), Record(Vec<(Rc, TypeIdentifier)>), } #[derive(Debug, Derivative, Clone)] #[derivative(PartialEq)] pub struct Expression { #[derivative(PartialEq = "ignore")] pub id: ItemId, pub kind: ExpressionKind, //TODO this should only allow singletons, not tuples pub type_anno: Option, } impl Expression { pub fn new(id: ItemId, kind: ExpressionKind) -> Expression { Expression { id, kind, type_anno: None } } } #[derive(Debug, PartialEq, Clone)] pub enum TypeIdentifier { Tuple(Vec), Singleton(TypeSingletonName), } #[derive(Debug, PartialEq, Clone)] pub struct TypeSingletonName { pub name: Rc, pub params: Vec, } #[derive(Debug, PartialEq, Clone)] pub enum ExpressionKind { NatLiteral(u64), FloatLiteral(f64), //TODO StringLiteral variant needs to support prefixes StringLiteral(Rc), BoolLiteral(bool), BinExp(BinOp, Box, Box), PrefixExp(PrefixOp, Box), TupleLiteral(Vec), Value(QualifiedName), NamedStruct { name: QualifiedName, fields: Vec<(Rc, Expression)> }, Call { f: Box, arguments: Vec }, Index { indexee: Box, indexers: Vec }, IfExpression { discriminator: Option>, body: Box }, WhileExpression { condition: Option>, body: Block }, ForExpression { enumerators: Vec, body: Box }, Lambda { params: Vec, type_anno: Option, body: Block }, Access { name: Rc, expr: Box }, ListLiteral(Vec), } #[derive(Debug, PartialEq, Clone)] pub enum InvocationArgument { Positional(Expression), Keyword { name: Rc, expr: Expression }, Ignored, } #[derive(Debug, PartialEq, Clone)] pub enum IfExpressionBody { SimpleConditional { then_case: Block, else_case: Option }, SimplePatternMatch { pattern: Pattern, then_case: Block, else_case: Option }, CondList(Vec), } #[derive(Debug, PartialEq, Clone)] pub struct ConditionArm { pub condition: Condition, pub guard: Option, pub body: Block, } #[derive(Debug, PartialEq, Clone)] pub enum Condition { Pattern(Pattern), TruncatedOp(BinOp, Expression), //Expression(Expression), //I'm pretty sure I don't actually want this Else, } #[derive(Debug, PartialEq, Clone)] pub enum Pattern { Ignored, TuplePattern(Vec), Literal(PatternLiteral), TupleStruct(QualifiedName, Vec), Record(QualifiedName, Vec<(Rc, Pattern)>), VarOrName(QualifiedName), } #[derive(Debug, PartialEq, Clone)] pub enum PatternLiteral { NumPattern { neg: bool, num: ExpressionKind }, StringPattern(Rc), BoolPattern(bool), } #[derive(Debug, PartialEq, Clone)] pub struct Enumerator { pub id: Rc, //TODO rename this field pub generator: Expression, } #[derive(Debug, PartialEq, Clone)] pub enum ForBody { MonadicReturn(Expression), StatementBlock(Block), } #[derive(Debug, Derivative, Clone)] #[derivative(PartialEq)] pub struct ImportSpecifier { #[derivative(PartialEq = "ignore")] pub id: ItemId, pub path_components: Vec>, pub imported_names: ImportedNames, } #[derive(Debug, PartialEq, Clone)] pub enum ImportedNames { All, LastOfPath, List(Vec>), } #[derive(Debug, PartialEq, Clone)] pub struct ModuleSpecifier { pub name: Rc, pub contents: Block, }