use crate::util::BoolAsOption;
use crate::common::{ Identifier, Primary, OperatorType, KeywordType, OverloadableOperatorType, MaybeIgnore };
use crate::tracking::{ Source, SourceRegion };
pub trait ASTNode {
type Data;
fn get_data (&self) -> &Self::Data;
fn get_data_mut (&mut self) -> &mut Self::Data;
fn get_source (&self) -> SourceRegion;
}
macro_rules! impl_ASTNode {
($vty: ident => $dty: ident) => {
impl ASTNode for $vty {
type Data = $dty;
fn get_data (&self) -> &Self::Data { &self.data }
fn get_data_mut (&mut self) -> &mut Self::Data { &mut self.data }
fn get_source (&self) -> SourceRegion { self.source }
}
impl std::fmt::Display for $vty {
fn fmt (&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}::{:#?}", stringify!($vty), self.get_data())?;
Ok(())
}
}
impl_Debug_from_Display!($vty);
};
($( $vty: ident => $dty: ident ),* $(,)?) => {
$( impl_ASTNode!($vty => $dty); ) *
};
}
#[derive(Debug, Clone)]
pub struct StructField {
pub name: Identifier,
pub ty: TypeExpression,
}
#[derive(Debug, Clone)]
pub struct EnumField {
pub name: Identifier,
pub value: Option<Expression>,
}
#[derive(Debug, Clone)]
pub enum TypeExpressionData {
Identifier(Identifier),
Pointer { mutable: bool, value_ty: Box<TypeExpression> },
Array { element_count: Option<Box<Expression>>, element_ty: Box<TypeExpression> },
Tuple(Vec<TypeExpression>),
Struct(Vec<StructField>),
Union(Vec<StructField>),
Enum { backing_ty: Option<Box<TypeExpression>>, fields: Vec<EnumField> },
Sum(Vec<StructField>),
Function { parameter_tys: Vec<TypeExpression>, return_ty: Option<Box<TypeExpression>> },
}
impl TypeExpressionData {
pub fn is_identifier (&self) -> bool {
match self {
TypeExpressionData::Identifier(_) => true,
_ => false
}
}
pub fn is_pointer (&self) -> bool {
match self {
TypeExpressionData::Pointer { .. } => true,
_ => false
}
}
pub fn is_array (&self) -> bool {
match self {
TypeExpressionData::Array { .. } => true,
_ => false
}
}
pub fn is_tuple (&self) -> bool {
match self {
TypeExpressionData::Tuple(_) => true,
_ => false
}
}
pub fn is_struct (&self) -> bool {
match self {
TypeExpressionData::Struct(_) => true,
_ => false
}
}
pub fn is_union (&self) -> bool {
match self {
TypeExpressionData::Union(_) => true,
_ => false
}
}
pub fn is_enum (&self) -> bool {
match self {
TypeExpressionData::Enum { .. } => true,
_ => false
}
}
pub fn is_sum (&self) -> bool {
match self {
TypeExpressionData::Sum(_) => true,
_ => false
}
}
pub fn is_function (&self) -> bool {
match self {
TypeExpressionData::Function { .. } => true,
_ => false
}
}
}
#[derive(Clone)]
pub struct TypeExpression {
pub data: TypeExpressionData,
pub source: SourceRegion,
}
#[derive(Debug, Clone)]
pub struct CompoundField {
pub name: Option<Identifier>,
pub value: Expression
}
#[derive(Debug, Clone)]
pub enum ExpressionData {
Primary(Primary),
AddressOf { mutable: bool, value: Box<Expression> },
Unary { op: OperatorType, operand: Box<Expression> },
Binary { op: OperatorType, left: Box<Expression>, right: Box<Expression> },
MatchExpression { left: Box<Expression>, right: Box<Expression> },
Member { operand: Box<Expression>, member_name: Identifier },
Subscript { operand: Box<Expression>, subscript: Box<Expression> },
Call { callee: Box<Expression>, parameters: Vec<Expression> },
Cast { operand: Box<Expression>, as_ty: Option<Box<TypeExpression>> },
Compound { value_ty: Option<Box<TypeExpression>>, fields: Vec<CompoundField> },
Block(Box<Block>),
Conditional(Box<ConditionalBlock>),
Match(Box<MatchBlock>),
}
impl ExpressionData {
pub fn is_primary (&self) -> bool {
match self {
ExpressionData::Primary(_) => true,
_ => false
}
}
pub fn is_unary (&self) -> bool {
match self {
ExpressionData::Unary { .. } => true,
_ => false
}
}
pub fn is_binary (&self) -> bool {
match self {
ExpressionData::Binary { .. } => true,
_ => false
}
}
pub fn is_member (&self) -> bool {
match self {
ExpressionData::Member { .. } => true,
_ => false
}
}
pub fn is_subscript (&self) -> bool {
match self {
ExpressionData::Subscript { .. } => true,
_ => false
}
}
pub fn is_call (&self) -> bool {
match self {
ExpressionData::Call { .. } => true,
_ => false
}
}
pub fn is_cast (&self) -> bool {
match self {
ExpressionData::Cast { .. } => true,
_ => false
}
}
pub fn is_compound (&self) -> bool {
match self {
ExpressionData::Compound { .. } => true,
_ => false
}
}
pub fn is_block (&self) -> bool {
match self {
ExpressionData::Block(_) => true,
_ => false
}
}
pub fn is_conditional (&self) -> bool {
match self {
ExpressionData::Conditional(_) => true,
_ => false
}
}
pub fn is_match (&self) -> bool {
match self {
ExpressionData::Match(_) => true,
_ => false
}
}
}
#[derive(Clone)]
pub struct Expression {
pub data: ExpressionData,
pub source: SourceRegion,
}
#[derive(Debug, Clone)]
pub enum StructPatternFieldData {
Terminal { alias: Option<MaybeIgnore<Identifier>>, value: Option<Expression> },
Subpattern(Pattern),
}
impl StructPatternFieldData {
pub fn is_terminal (&self) -> bool {
match self {
StructPatternFieldData::Terminal { .. } => true,
_ => false
}
}
pub fn is_subpattern (&self) -> bool {
match self {
StructPatternFieldData::Subpattern(_) => true,
_ => false
}
}
pub fn empty () -> StructPatternFieldData {
StructPatternFieldData::Terminal {
alias: None,
value: None
}
}
pub fn set_alias (&mut self, ident: MaybeIgnore<Identifier>) {
match self {
StructPatternFieldData::Terminal { alias, value: _ } => *alias = Some(ident),
_ => panic!("Cannot set Terminal alias on StructPatternFieldData type {:?}", self)
}
}
pub fn set_value (&mut self, expr: Expression) {
match self {
StructPatternFieldData::Terminal { alias: _, value } => *value = Some(expr),
_ => panic!("Cannot set Terminal value on StructPatternFieldData type {:?}", self)
}
}
}
#[derive(Debug, Clone)]
pub struct StructPatternField {
pub name: Identifier,
pub data: StructPatternFieldData,
}
#[derive(Debug, Clone)]
pub enum NamedExpressionPattern {
Pattern(Pattern),
NamedExpression { name: Identifier, expression: Expression },
}
impl NamedExpressionPattern {
pub fn is_pattern (&self) -> bool {
match self {
NamedExpressionPattern::Pattern(_) => true,
_ => false
}
}
pub fn is_expression (&self) -> bool {
match self {
NamedExpressionPattern::NamedExpression { .. } => true,
_ => false
}
}
}
#[derive(Debug, Clone)]
pub enum PatternData {
Ignore,
Identifier(Identifier),
IdentifierChain(Vec<Identifier>),
Expression(Expression),
Tuple(Vec<NamedExpressionPattern>),
NamedTuple { identifier_chain: Vec<Identifier>, fields: Vec<NamedExpressionPattern> },
Struct { identifier_chain: Vec<Identifier>, fields: Vec<StructPatternField> },
Else { left: Box<Pattern>, right: Box<Pattern> },
Enums { identifier_chain: Vec<Identifier>, expression: Expression },
}
impl PatternData {
pub fn is_ignore (&self) -> bool {
match self {
PatternData::Ignore => true,
_ => false
}
}
pub fn is_ident (&self) -> bool {
match self {
PatternData::Identifier(_) => true,
_ => false
}
}
pub fn is_ident_chain (&self) -> bool {
match self {
PatternData::IdentifierChain(_) => true,
_ => false
}
}
pub fn is_ident_or_chain (&self) -> bool {
match self {
PatternData::Identifier(_) | PatternData::IdentifierChain(_) => true,
_ => false
}
}
pub fn is_expression (&self) -> bool {
match self {
PatternData::Expression(_) => true,
_ => false
}
}
pub fn is_tuple (&self) -> bool {
match self {
PatternData::Tuple(_) => true,
_ => false
}
}
pub fn is_named_tuple (&self) -> bool {
match self {
PatternData::NamedTuple { .. } => true,
_ => false
}
}
pub fn is_struct (&self) -> bool {
match self {
PatternData::Struct { .. } => true,
_ => false
}
}
pub fn is_else (&self) -> bool {
match self {
PatternData::Else { .. } => true,
_ => false
}
}
pub fn extract_ident_or_chain (self) -> Vec<Identifier> {
match self {
PatternData::IdentifierChain(chain) => chain,
PatternData::Identifier(ident) => vec! [ ident ],
_ => panic!("Cannot extract ident chain from pattern type: {:?}", self)
}
}
pub fn extract_tuple_fields (self) -> Vec<NamedExpressionPattern> {
if let PatternData::Tuple(fields) = self {
fields
} else {
panic!("Cannot extract tuple fields from pattern type: {:?}", self)
}
}
}
#[derive(Clone)]
pub struct Pattern {
pub data: PatternData,
pub source: SourceRegion,
}
#[derive(Debug, Clone, Copy)]
pub enum FunctionIdentifier {
Name(Identifier),
Operator(OverloadableOperatorType),
}
impl FunctionIdentifier {
pub fn is_name (&self) -> bool {
match self {
FunctionIdentifier::Name(_) => true,
_ => false
}
}
pub fn is_operator (&self) -> bool {
match self {
FunctionIdentifier::Operator(_) => true,
_ => false
}
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, FromPrimitive, ToPrimitive)]
pub enum LoopControlType {
Break,
Continue,
}
impl LoopControlType {
pub fn from_kw (kw: KeywordType) -> LoopControlType {
match kw {
KeywordType::Break => LoopControlType::Break,
KeywordType::Continue => LoopControlType::Continue,
_ => panic!("Cannot convert KeywordType {} to LoopControlType", kw.as_text())
}
}
}
#[derive(Debug, Clone)]
pub struct FunctionParameter {
pub pattern: Pattern,
pub ty: TypeExpression
}
#[derive(Debug, Clone)]
pub struct Block {
pub statements: Vec<Statement>,
pub terminator: Option<Expression>,
}
impl Block {
pub fn evaluates_to_expression (&self) -> bool {
self.terminator.is_some()
}
}
#[derive(Debug, Clone)]
pub struct ConditionalBranch {
pub condition: Expression,
pub body: Block,
}
impl ConditionalBranch {
pub fn evaluates_to_expression (&self) -> bool {
self.body.evaluates_to_expression()
}
}
#[derive(Debug, Clone)]
pub struct ConditionalBlock {
pub if_branch: ConditionalBranch,
pub else_if_branches: Vec<ConditionalBranch>,
pub else_branch: Option<Block>,
}
impl ConditionalBlock {
pub fn evaluates_to_expression (&self) -> bool {
self.if_branch.evaluates_to_expression()
}
}
#[derive(Debug, Clone)]
pub struct MatchBranch {
pub condition: NamedExpressionPattern,
pub body: Statement,
}
impl MatchBranch {
pub fn evaluates_to_expression (&self) -> bool {
self.body.evaluates_to_expression()
}
}
#[derive(Debug, Clone)]
pub struct MatchBlock {
pub operand: Expression,
pub branches: Vec<MatchBranch>,
}
impl MatchBlock {
pub fn evaluates_to_expression (&self) -> bool {
if let Some(first_branch) = self.branches.first() {
first_branch.evaluates_to_expression()
} else {
false
}
}
}
#[derive(Debug, Clone)]
pub enum StatementData {
Block(Block),
Module { name: Identifier, body: Option<Block> },
Import { path: String, alias: Option<Identifier> },
Export(Box<Statement>),
Use { identifier_chain: Vec<Identifier>, alias: Option<Identifier> },
TypeAlias { name: Identifier, ty: TypeExpression },
Struct { name: Identifier, fields: Option<Vec<StructField>> },
Union { name: Identifier, fields: Option<Vec<StructField>> },
Enum { name: Identifier, backing_ty: Option<TypeExpression>, fields: Option<Vec<EnumField>> },
Sum { name: Identifier, fields: Option<Vec<StructField>> },
Impl { operand: TypeExpression, body: Block },
Function { name: FunctionIdentifier, parameters: Vec<FunctionParameter>, return_ty: Option<TypeExpression>, body: Option<Block> },
Declaration { pattern: Pattern, explicit_ty: Option<TypeExpression>, initial_value: Option<Expression> },
Assignment { target: Expression, value: Expression },
ModAssignment { target: Expression, op: OperatorType, value: Expression },
LoopControl { ty: LoopControlType, label: Option<Identifier> },
Return(Option<Expression>),
Conditional(ConditionalBlock),
Match(MatchBlock),
For { label: Option<Identifier>, iter_pattern: Pattern, iter: Expression, body: Block },
While { label: Option<Identifier>, condition: Expression, body: Block },
Loop { label: Option<Identifier>, body: Block, until_condition: Option<Expression> },
Expression(Expression),
}
impl StatementData {
pub fn requires_semi (&self) -> bool {
match self {
StatementData::Block(block) => block.evaluates_to_expression(),
StatementData::Module { body, .. } => body.is_none(),
StatementData::Export(stmt) => stmt.requires_semi(),
StatementData::Conditional(conditional_block) => conditional_block.evaluates_to_expression(),
StatementData::Match(match_block) => match_block.evaluates_to_expression(),
StatementData::Struct { fields, .. } => fields.is_none(),
StatementData::Union { fields, .. } => fields.is_none(),
StatementData::Enum { fields, .. } => fields.is_none(),
StatementData::Sum { fields, .. } => fields.is_none(),
StatementData::Function { body, .. } => body.is_none(),
StatementData::Impl { .. } |
StatementData::For { .. } |
StatementData::While { .. } |
StatementData::Loop { .. } => false,
_ => true,
}
}
pub fn evaluates_to_expression (&self) -> bool {
match self {
StatementData::Expression(_) => true,
StatementData::Block(block) => block.evaluates_to_expression(),
StatementData::Conditional(conditional_block) => conditional_block.evaluates_to_expression(),
StatementData::Match(match_block) => match_block.evaluates_to_expression(),
_ => false
}
}
pub fn is_block (&self) -> bool {
match self {
StatementData::Block(_) => true,
_ => false
}
}
pub fn is_module (&self) -> bool {
match self {
StatementData::Module { .. } => true,
_ => false
}
}
pub fn is_import (&self) -> bool {
match self {
StatementData::Import { .. } => true,
_ => false
}
}
pub fn is_export (&self) -> bool {
match self {
StatementData::Export(_) => true,
_ => false
}
}
pub fn is_use (&self) -> bool {
match self {
StatementData::Use { .. } => true,
_ => false
}
}
pub fn is_type_alias (&self) -> bool {
match self {
StatementData::TypeAlias { .. } => true,
_ => false
}
}
pub fn is_struct (&self) -> bool {
match self {
StatementData::Struct { .. } => true,
_ => false
}
}
pub fn is_union (&self) -> bool {
match self {
StatementData::Union { .. } => true,
_ => false
}
}
pub fn is_enum (&self) -> bool {
match self {
StatementData::Enum { .. } => true,
_ => false
}
}
pub fn is_sum (&self) -> bool {
match self {
StatementData::Sum { .. } => true,
_ => false
}
}
pub fn is_impl (&self) -> bool {
match self {
StatementData::Impl { .. } => true,
_ => false
}
}
pub fn is_function (&self) -> bool {
match self {
StatementData::Function { .. } => true,
_ => false
}
}
pub fn is_declaration (&self) -> bool {
match self {
StatementData::Declaration { .. } => true,
_ => false
}
}
pub fn is_assignment (&self) -> bool {
match self {
StatementData::Assignment { .. } => true,
_ => false
}
}
pub fn is_loop_control (&self) -> bool {
match self {
StatementData::LoopControl { .. } => true,
_ => false
}
}
pub fn is_return (&self) -> bool {
match self {
StatementData::Return(_) => true,
_ => false
}
}
pub fn is_conditional (&self) -> bool {
match self {
StatementData::Conditional { .. } => true,
_ => false
}
}
pub fn is_for (&self) -> bool {
match self {
StatementData::For { .. } => true,
_ => false
}
}
pub fn is_while (&self) -> bool {
match self {
StatementData::While { .. } => true,
_ => false
}
}
pub fn is_loop (&self) -> bool {
match self {
StatementData::Loop { .. } => true,
_ => false
}
}
pub fn is_match (&self) -> bool {
match self {
StatementData::Match { .. } => true,
_ => false
}
}
pub fn is_expression (&self) -> bool {
match self {
StatementData::Expression { .. } => true,
_ => false
}
}
}
#[derive(Clone)]
pub struct Statement {
pub data: StatementData,
pub source: SourceRegion,
}
impl Statement {
pub fn requires_semi (&self) -> bool {
self.data.requires_semi()
}
pub fn evaluates_to_expression (&self) -> bool {
self.data.evaluates_to_expression()
}
pub fn convert_to_expression (self) -> ExpressionStatement {
ExpressionStatement::Expression(Expression {
data: match self.data {
StatementData::Expression(expr) => expr.data,
StatementData::Block(block) if block.terminator.is_some() => ExpressionData::Block(Box::new(block)),
StatementData::Conditional(conditional_block) if conditional_block.if_branch.body.terminator.is_some() => ExpressionData::Conditional(Box::new(conditional_block)),
StatementData::Match(match_block) if match_block.branches.first().and_then(|branch| branch.body.data.evaluates_to_expression().as_option()).is_some() => ExpressionData::Match(Box::new(match_block)),
_ => return ExpressionStatement::Statement(self)
},
source: self.source
})
}
}
#[derive(Debug, Clone)]
pub enum ExpressionStatement {
Expression(Expression),
Statement(Statement),
}
impl ExpressionStatement {
pub fn get_source (&self) -> SourceRegion {
match self {
ExpressionStatement::Expression(expr) => expr.source,
ExpressionStatement::Statement(stmt) => stmt.source
}
}
pub fn as_statement (self) -> Statement {
match self {
ExpressionStatement::Expression(expr) => {
let source = expr.source;
Statement {
data: StatementData::Expression(expr),
source
}
},
ExpressionStatement::Statement(stmt) => stmt
}
}
pub fn as_expression (self) -> Option<Expression> {
match self {
ExpressionStatement::Expression(expr) => Some(expr),
ExpressionStatement::Statement(stmt) => match stmt.convert_to_expression() {
ExpressionStatement::Expression(expr) => Some(expr),
ExpressionStatement::Statement(_) => None
}
}
}
}
impl_ASTNode! [
Expression => ExpressionData,
TypeExpression => TypeExpressionData,
Pattern => PatternData,
Statement => StatementData
];
pub struct AST {
pub top_level: Vec<Statement>,
pub source: Source,
}
impl std::fmt::Display for AST {
fn fmt (&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
for s in &self.top_level {
write!(f, "{:?}", s)?;
}
Ok(())
}
}
impl_Debug_from_Display!(AST);