use crate::tokens::Token; /* --------- * * AST nodes * * --------- */ /// The AST node for the program #[derive(Default, Debug, Clone)] pub struct ProgramNode(pub Vec<StmtNode>); /// A function declaration. #[derive(Debug, Clone)] pub struct FunDecl { pub name: Token, pub params: Vec<Token>, pub body: Vec<StmtNode>, } /// The declaration of a class member. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ClassMemberKind { Method, Getter, Setter, } /// The declaration of a class member. #[derive(Debug, Clone)] pub struct ClassMemberDecl { pub kind: ClassMemberKind, pub is_static: bool, pub fun_decl: FunDecl, } /// A class declaration. #[derive(Debug, Clone)] pub struct ClassDecl { /// The token that represents the name of the class. pub name: Token, /// The token indicating the name of the parent class, if any. pub superclass: Option<Token>, /// The list of class members. pub members: Vec<ClassMemberDecl>, } /// An AST node that represents a statement. #[derive(Debug, Clone)] pub enum StmtNode { /// A variable declaration VarDecl(Token, Option<ExprNode>), /// A function declaration FunDecl(FunDecl), /// A class declaration ClassDecl(ClassDecl), /// An single expression Expression(ExprNode), /// The print statement Print(ExprNode), /// A block containing multiple statements. Block(Vec<StmtNode>), /// A conditional statement. If { condition: ExprNode, then_branch: Box<StmtNode>, else_branch: Option<Box<StmtNode>>, }, /// Loop statement. Loop { label: Option<Token>, condition: ExprNode, body: Box<StmtNode>, after_body: Option<Box<StmtNode>>, }, /// Break or continue statement. LoopControl { is_break: bool, loop_name: Option<Token>, }, /// Return statement. Return { token: Token, value: Option<ExprNode>, }, } impl StmtNode { /// Extract the list of statements from a block. Panic if the statement /// is not a block. pub fn extract_block_statements(self) -> Vec<StmtNode> { match self { Self::Block(stmts) => stmts, _ => panic!("Statement is not a block"), } } } /// A getter expression. #[derive(Debug, Clone)] pub struct GetExpr { /// The instance being accessed. pub instance: Box<ExprNode>, /// The name of the property. pub name: Token, } /// A setter expression. #[derive(Debug, Clone)] pub struct SetExpr { /// The instance being accessed. pub instance: Box<ExprNode>, /// The name of the property. pub name: Token, /// The value to set pub value: Box<ExprNode>, } /// A binary expression. #[derive(Debug, Clone)] pub struct BinaryExpr { /// The left side expression pub left: Box<ExprNode>, /// The operator pub operator: Token, /// The right side expression pub right: Box<ExprNode>, } /// A variable reference expression. #[derive(Debug, Clone)] pub struct VariableExpr { /// The name of the variable, or the "this" keyword. pub token: Token, /// Identifier used for variable resolution. pub id: usize, } /// An AST node that represents an expression. #[derive(Debug, Clone)] pub enum ExprNode { /// Assignment to a variable. Assignment { name: Token, value: Box<ExprNode>, /// Identifier used for variable resolution. id: usize, }, /// Logical binary expression. Logical(BinaryExpr), /// Binary expression. Binary(BinaryExpr), /// Unary expression. Unary { operator: Token, right: Box<ExprNode>, }, /// Grouping expression, containing a sub-expression. Grouping { expression: Box<ExprNode> }, /// A litteral value, represented by the corresponding token. Litteral { value: Token }, /// A reference to a variable. Variable(VariableExpr), /// The "this" keyword. This(VariableExpr), /// A lambda function. Lambda { params: Vec<Token>, body: Vec<StmtNode>, }, /// A function call. Call { /// Expression that corresponds to the callable. callee: Box<ExprNode>, /// Right parenthesis that closes the list of arguments. Used to /// report errors. right_paren: Token, /// The list of function arguments. arguments: Vec<ExprNode>, }, /// A get expression. Get(GetExpr), /// A set expression. Set(SetExpr), }