rust-crafting-interpreters-.../src/ast.rs

192 lines
4.5 KiB
Rust

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),
}