//! # The Abstract Syntax Tree //! Contains definitions of Conlang AST Nodes. //! //! # Notable nodes //! - [Item] and [ItemKind]: Top-level constructs //! - [Stmt] and [StmtKind]: Statements //! - [Expr] and [ExprKind]: Expressions //! - [Assign], [Binary], and [Unary] expressions //! - [AssignKind], [BinaryKind], and [UnaryKind] operators //! - [Ty] and [TyKind]: Type qualifiers //! - [Path]: Path expressions use cl_structures::{intern::interned::Interned, span::*}; pub type Sym = Interned<'static, str>; /// Whether a binding ([Static] or [Let]) or reference is mutable or not #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] pub enum Mutability { #[default] Not, Mut, } /// Whether an [Item] is visible outside of the current [Module] #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] pub enum Visibility { #[default] Private, Public, } // TODO: Capture token? /// A name #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Identifier(pub Sym); /// A [Literal]: 0x42, 1e123, 2.4, "Hello" #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum Literal { Bool(bool), Char(char), Int(u128), String(String), } /// A list of [Item]s #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] pub struct File { pub items: Vec, } // Metadata decorators #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] pub struct Attrs { pub meta: Vec, } /// A metadata decorator #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Meta { pub name: Identifier, pub kind: MetaKind, } /// Information attached to [Meta]data #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum MetaKind { Plain, Equals(Literal), Func(Vec), } // Items /// Anything that can appear at the top level of a [File] #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Item { pub extents: Span, pub attrs: Attrs, pub vis: Visibility, pub kind: ItemKind, } /// What kind of [Item] is this? #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum ItemKind { // TODO: Import declaration ("use") item // TODO: Trait declaration ("trait") item? /// A [module](Module) Module(Module), /// A [type alias](Alias) Alias(Alias), /// An [enumerated type](Enum), with a discriminant and optional data Enum(Enum), /// A [structure](Struct) Struct(Struct), /// A [constant](Const) Const(Const), /// A [static](Static) variable Static(Static), /// A [function definition](Function) Function(Function), /// An [implementation](Impl) Impl(Impl), /// An [import](Use) Use(Use), } /// An alias to another [Ty] #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Alias { pub to: Identifier, pub from: Option>, } /// A compile-time constant #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Const { pub name: Identifier, pub ty: Box, pub init: Box, } /// A `static` variable #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Static { pub mutable: Mutability, pub name: Identifier, pub ty: Box, pub init: Box, } /// An ordered collection of [Items](Item) #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Module { pub name: Identifier, pub kind: ModuleKind, } /// The contents of a [Module], if they're in the same file #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum ModuleKind { Inline(File), Outline, } /// Code, and the interface to that code #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Function { pub name: Identifier, pub sign: TyFn, pub bind: Vec, pub body: Option, } /// A single parameter for a [Function] #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Param { pub mutability: Mutability, pub name: Identifier, } /// A user-defined product type #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Struct { pub name: Identifier, pub kind: StructKind, } /// Either a [Struct]'s [StructMember]s or tuple [Ty]pes, if present. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum StructKind { Empty, Tuple(Vec), Struct(Vec), } /// The [Visibility], [Identifier], and [Ty]pe of a single [Struct] member #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct StructMember { pub vis: Visibility, pub name: Identifier, pub ty: Ty, } /// A user-defined sum type #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Enum { pub name: Identifier, pub kind: EnumKind, } /// An [Enum]'s [Variant]s, if it has a variant block #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum EnumKind { /// Represents an enum with no variants NoVariants, Variants(Vec), } /// A single [Enum] variant #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Variant { pub name: Identifier, pub kind: VariantKind, } /// Whether the [Variant] has a C-like constant value, a tuple, or [StructMember]s #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum VariantKind { Plain, CLike(u128), Tuple(Ty), Struct(Vec), } /// Sub-[items](Item) (associated functions, etc.) for a [Ty] #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Impl { pub target: ImplKind, pub body: File, } // TODO: `impl` Trait for { } #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum ImplKind { Type(Ty), Trait { impl_trait: Path, for_type: Box }, } /// An import of nonlocal [Item]s #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Use { pub absolute: bool, pub tree: UseTree, } /// A tree of [Item] imports #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum UseTree { Tree(Vec), Path(PathPart, Box), Alias(Identifier, Identifier), Name(Identifier), Glob, } /// A type expression #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Ty { pub extents: Span, pub kind: TyKind, } /// Information about a [Ty]pe expression #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum TyKind { Never, Empty, SelfTy, Path(Path), Tuple(TyTuple), Ref(TyRef), Fn(TyFn), // TODO: slice, array types } /// A tuple of [Ty]pes #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct TyTuple { pub types: Vec, } /// A [Ty]pe-reference expression as (number of `&`, [Path]) #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct TyRef { pub mutable: Mutability, pub count: u16, pub to: Path, } /// The args and return value for a function pointer [Ty]pe #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct TyFn { pub args: Box, pub rety: Option>, } /// A path to an [Item] in the [Module] tree #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] pub struct Path { pub absolute: bool, pub parts: Vec, } /// A single component of a [Path] #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum PathPart { SuperKw, SelfKw, Ident(Identifier), } /// An abstract statement, and associated metadata #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Stmt { pub extents: Span, pub kind: StmtKind, pub semi: Semi, } /// Whether the [Stmt] is a [Let], [Item], or [Expr] statement #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum StmtKind { Empty, Local(Let), Item(Box), Expr(Box), } /// Whether or not a [Stmt] is followed by a semicolon #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum Semi { Terminated, Unterminated, } /// A local variable declaration [Stmt] #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Let { pub mutable: Mutability, pub name: Identifier, pub ty: Option>, pub init: Option>, } /// An expression, the beating heart of the language #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Expr { pub extents: Span, pub kind: ExprKind, } /// Any of the different [Expr]essions #[derive(Clone, Default, Debug, PartialEq, Eq, Hash)] pub enum ExprKind { /// An empty expression: `(` `)` #[default] Empty, /// An [Assign]ment expression: [`Expr`] ([`AssignKind`] [`Expr`])\+ Assign(Assign), /// A [Binary] expression: [`Expr`] ([`BinaryKind`] [`Expr`])\+ Binary(Binary), /// A [Unary] expression: [`UnaryKind`]\* [`Expr`] Unary(Unary), /// An Array [Index] expression: a[10, 20, 30] Index(Index), /// A [Struct creation](Structor) expression: [Path] `{` ([Fielder] `,`)* [Fielder]? `}` Structor(Structor), /// A [path expression](Path): `::`? [PathPart] (`::` [PathPart])* Path(Path), /// A [Literal]: 0x42, 1e123, 2.4, "Hello" Literal(Literal), /// An [Array] literal: `[` [`Expr`] (`,` [`Expr`])\* `]` Array(Array), /// An Array literal constructed with [repeat syntax](ArrayRep) /// `[` [Expr] `;` [Literal] `]` ArrayRep(ArrayRep), /// An address-of expression: `&` `mut`? [`Expr`] AddrOf(AddrOf), /// A [Block] expression: `{` [`Stmt`]\* [`Expr`]? `}` Block(Block), /// A [Grouping](Group) expression `(` [`Expr`] `)` Group(Group), /// A [Tuple] expression: `(` [`Expr`] (`,` [`Expr`])+ `)` Tuple(Tuple), /// A [Loop] expression: `loop` [`Block`] Loop(Loop), /// A [While] expression: `while` [`Expr`] [`Block`] [`Else`]? While(While), /// An [If] expression: `if` [`Expr`] [`Block`] [`Else`]? If(If), /// A [For] expression: `for` Pattern `in` [`Expr`] [`Block`] [`Else`]? For(For), /// A [Break] expression: `break` [`Expr`]? Break(Break), /// A [Return] expression `return` [`Expr`]? Return(Return), /// A continue expression: `continue` Continue(Continue), } /// An [Assign]ment expression: [`Expr`] ([`AssignKind`] [`Expr`])\+ #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Assign { pub kind: AssignKind, pub parts: Box<(ExprKind, ExprKind)>, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum AssignKind { /// Standard Assignment with no read-back Plain, And, Or, Xor, Shl, Shr, Add, Sub, Mul, Div, Rem, } /// A [Binary] expression: [`Expr`] ([`BinaryKind`] [`Expr`])\+ #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Binary { pub kind: BinaryKind, pub parts: Box<(ExprKind, ExprKind)>, } /// A [Binary] operator #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum BinaryKind { Lt, LtEq, Equal, NotEq, GtEq, Gt, RangeExc, RangeInc, LogAnd, LogOr, LogXor, BitAnd, BitOr, BitXor, Shl, Shr, Add, Sub, Mul, Div, Rem, Dot, Call, } /// A [Unary] expression: [`UnaryKind`]\* [`Expr`] #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Unary { pub kind: UnaryKind, pub tail: Box, } /// A [Unary] operator #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum UnaryKind { Deref, Neg, Not, /// Unused At, /// Unused Tilde, } /// A repeated [Index] expression: a[10, 20, 30][40, 50, 60] #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Index { pub head: Box, pub indices: Vec, } /// A [Struct creation](Structor) expression: [Path] `{` ([Fielder] `,`)* [Fielder]? `}` #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Structor { pub to: Path, pub init: Vec, } /// A [Struct field initializer] expression: [Identifier] (`=` [Expr])? #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Fielder { pub name: Identifier, pub init: Option>, } /// An [Array] literal: `[` [`Expr`] (`,` [`Expr`])\* `]` #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Array { pub values: Vec, } /// An Array literal constructed with [repeat syntax](ArrayRep) /// `[` [Expr] `;` [Literal] `]` #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct ArrayRep { pub value: Box, pub repeat: Box, } /// An address-of expression: `&` `mut`? [`Expr`] #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct AddrOf { pub count: usize, pub mutable: Mutability, pub expr: Box, } /// A [Block] expression: `{` [`Stmt`]\* [`Expr`]? `}` #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Block { pub stmts: Vec, } /// A [Grouping](Group) expression `(` [`Expr`] `)` #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Group { pub expr: Box, } /// A [Tuple] expression: `(` [`Expr`] (`,` [`Expr`])+ `)` #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Tuple { pub exprs: Vec, } /// A [Loop] expression: `loop` [`Block`] #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Loop { pub body: Box, } /// A [While] expression: `while` [`Expr`] [`Block`] [`Else`]? #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct While { pub cond: Box, pub pass: Box, pub fail: Else, } /// An [If] expression: `if` [`Expr`] [`Block`] [`Else`]? #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct If { pub cond: Box, pub pass: Box, pub fail: Else, } /// A [For] expression: `for` Pattern `in` [`Expr`] [`Block`] [`Else`]? #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct For { pub bind: Identifier, // TODO: Patterns? pub cond: Box, pub pass: Box, pub fail: Else, } /// The (optional) `else` clause of a [While], [If], or [For] expression #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Else { pub body: Option>, } /// A [Break] expression: `break` [`Expr`]? #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Break { pub body: Option>, } /// A [Return] expression `return` [`Expr`]? #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Return { pub body: Option>, } /// A continue expression: `continue` #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] pub struct Continue;