346 lines
8.6 KiB
Rust
346 lines
8.6 KiB
Rust
#![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,
|
|
util::delim_wrapped,
|
|
};
|
|
|
|
define_id_kind!(ASTItem);
|
|
|
|
pub type ItemId = Id<ASTItem>;
|
|
|
|
#[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<K> {
|
|
#[derivative(PartialEq = "ignore")]
|
|
pub id: ItemId,
|
|
#[derivative(PartialEq = "ignore")]
|
|
pub location: Location,
|
|
pub kind: K,
|
|
}
|
|
|
|
#[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<Expression>),
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Default)]
|
|
pub struct Block {
|
|
pub statements: Vec<Statement<StatementKind>>,
|
|
}
|
|
|
|
impl From<Vec<Statement<StatementKind>>> for Block {
|
|
fn from(statements: Vec<Statement<StatementKind>>) -> Self {
|
|
Self { statements }
|
|
}
|
|
}
|
|
|
|
impl From<Statement<StatementKind>> for Block {
|
|
fn from(statement: Statement<StatementKind>) -> Self {
|
|
Self { statements: vec![statement] }
|
|
}
|
|
}
|
|
|
|
impl AsRef<[Statement<StatementKind>]> for Block {
|
|
fn as_ref(&self) -> &[Statement<StatementKind>] {
|
|
self.statements.as_ref()
|
|
}
|
|
}
|
|
|
|
pub type ParamName = Rc<String>;
|
|
|
|
#[derive(Debug, Derivative, Clone)]
|
|
#[derivative(PartialEq)]
|
|
pub struct QualifiedName {
|
|
#[derivative(PartialEq = "ignore")]
|
|
pub id: ItemId,
|
|
pub components: Vec<Rc<String>>,
|
|
}
|
|
|
|
impl fmt::Display for QualifiedName {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
match &self.components[..] {
|
|
[] => write!(f, "[<empty>]"),
|
|
[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<Expression>,
|
|
pub anno: Option<TypeIdentifier>,
|
|
}
|
|
|
|
#[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<String>,
|
|
original: Rc<String>,
|
|
},
|
|
Binding {
|
|
name: Rc<String>,
|
|
constant: bool,
|
|
type_anno: Option<TypeIdentifier>,
|
|
expr: Expression,
|
|
},
|
|
Impl {
|
|
type_name: TypeIdentifier,
|
|
interface_name: Option<TypeSingletonName>,
|
|
block: Vec<Statement<Declaration>>,
|
|
},
|
|
Interface {
|
|
name: Rc<String>,
|
|
signatures: Vec<Signature>,
|
|
},
|
|
//TODO need to limit the types of statements that can be annotated
|
|
Annotation {
|
|
name: Rc<String>,
|
|
arguments: Vec<Expression>,
|
|
inner: Box<Statement<StatementKind>>,
|
|
},
|
|
Module {
|
|
name: Rc<String>,
|
|
items: Block,
|
|
},
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub struct Signature {
|
|
pub name: Rc<String>,
|
|
pub operator: bool,
|
|
pub params: Vec<FormalParam>,
|
|
pub type_anno: Option<TypeIdentifier>,
|
|
}
|
|
|
|
//TODO I can probably get rid of TypeBody
|
|
#[derive(Debug, Derivative, Clone)]
|
|
#[derivative(PartialEq)]
|
|
pub enum TypeBody {
|
|
Variants(Vec<Variant>),
|
|
ImmediateRecord {
|
|
#[derivative(PartialEq = "ignore")]
|
|
id: ItemId,
|
|
fields: Vec<(Rc<String>, TypeIdentifier)>,
|
|
},
|
|
}
|
|
|
|
#[derive(Debug, Derivative, Clone)]
|
|
#[derivative(PartialEq)]
|
|
pub struct Variant {
|
|
#[derivative(PartialEq = "ignore")]
|
|
pub id: ItemId,
|
|
pub name: Rc<String>,
|
|
pub kind: VariantKind,
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub enum VariantKind {
|
|
UnitStruct,
|
|
TupleStruct(Vec<TypeIdentifier>),
|
|
Record(Vec<(Rc<String>, 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<TypeIdentifier>,
|
|
}
|
|
|
|
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<TypeIdentifier>),
|
|
Singleton(TypeSingletonName),
|
|
}
|
|
|
|
impl fmt::Display for TypeIdentifier {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
match self {
|
|
TypeIdentifier::Tuple(items) =>
|
|
write!(f, "{}", delim_wrapped('(', ')', items.iter().map(|item| item.to_string()))),
|
|
TypeIdentifier::Singleton(tsn) => {
|
|
write!(f, "{}", tsn.name)?;
|
|
if !tsn.params.is_empty() {
|
|
write!(f, "{}", delim_wrapped('<', '>', tsn.params.iter().map(|item| item.to_string())))?;
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub struct TypeSingletonName {
|
|
pub name: Rc<String>,
|
|
pub params: Vec<TypeIdentifier>,
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub enum ExpressionKind {
|
|
NatLiteral(u64),
|
|
FloatLiteral(f64),
|
|
StringLiteral { prefix: Option<Rc<String>>, s: Rc<String> },
|
|
BoolLiteral(bool),
|
|
BinExp(BinOp, Box<Expression>, Box<Expression>),
|
|
PrefixExp(PrefixOp, Box<Expression>),
|
|
TupleLiteral(Vec<Expression>),
|
|
Value(QualifiedName),
|
|
SelfValue,
|
|
NamedStruct { name: QualifiedName, fields: Vec<(Rc<String>, Expression)> },
|
|
Call { f: Box<Expression>, arguments: Vec<InvocationArgument> },
|
|
Index { indexee: Box<Expression>, indexers: Vec<Expression> },
|
|
IfExpression { discriminator: Option<Box<Expression>>, body: Box<IfExpressionBody> },
|
|
WhileExpression { condition: Option<Box<Expression>>, body: Block },
|
|
ForExpression { enumerators: Vec<Enumerator>, body: Box<ForBody> },
|
|
Lambda { params: Vec<FormalParam>, type_anno: Option<TypeIdentifier>, body: Block },
|
|
Access { name: Rc<String>, expr: Box<Expression> },
|
|
ListLiteral(Vec<Expression>),
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub enum InvocationArgument {
|
|
Positional(Expression),
|
|
Keyword { name: Rc<String>, expr: Expression },
|
|
Ignored,
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub enum IfExpressionBody {
|
|
SimpleConditional { then_case: Block, else_case: Option<Block> },
|
|
SimplePatternMatch { pattern: Pattern, then_case: Block, else_case: Option<Block> },
|
|
CondList(Vec<ConditionArm>),
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub struct ConditionArm {
|
|
pub condition: Condition,
|
|
pub guard: Option<Expression>,
|
|
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<Pattern>),
|
|
Literal(PatternLiteral),
|
|
TupleStruct(QualifiedName, Vec<Pattern>),
|
|
Record(QualifiedName, Vec<(Rc<String>, Pattern)>),
|
|
VarOrName(QualifiedName),
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub enum PatternLiteral {
|
|
NumPattern { neg: bool, num: ExpressionKind },
|
|
StringPattern(Rc<String>),
|
|
BoolPattern(bool),
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub struct Enumerator {
|
|
pub identifier: Rc<String>,
|
|
pub generator: Expression,
|
|
pub assignment: bool, //true if `=`, false if `<-`
|
|
}
|
|
|
|
#[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<Rc<String>>,
|
|
pub imported_names: ImportedNames,
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub enum ImportedNames {
|
|
All,
|
|
LastOfPath,
|
|
List(Vec<Rc<String>>),
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub struct ModuleSpecifier {
|
|
pub name: Rc<String>,
|
|
pub contents: Block,
|
|
}
|