Parser - Parse classes
* New FunctionKind value for methods (with only 254 arguments) * Class parsing * Some minor refactoring of function parsing
This commit is contained in:
parent
36026681f7
commit
5702abe44d
1 changed files with 49 additions and 17 deletions
|
@ -1,7 +1,7 @@
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{ExprNode, FunDecl, ProgramNode, StmtNode},
|
ast::{ClassDecl, ExprNode, FunDecl, ProgramNode, StmtNode},
|
||||||
errors::{ErrorHandler, ErrorKind, SloxError, SloxResult},
|
errors::{ErrorHandler, ErrorKind, SloxError, SloxResult},
|
||||||
tokens::{Token, TokenType},
|
tokens::{Token, TokenType},
|
||||||
};
|
};
|
||||||
|
@ -38,12 +38,14 @@ impl From<&Option<Token>> for LoopParsingState {
|
||||||
enum FunctionKind {
|
enum FunctionKind {
|
||||||
Function,
|
Function,
|
||||||
Lambda,
|
Lambda,
|
||||||
|
Method,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionKind {
|
impl FunctionKind {
|
||||||
/// The name of this kind.
|
/// The name of this kind.
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
|
Self::Method => "method",
|
||||||
Self::Function => "function",
|
Self::Function => "function",
|
||||||
Self::Lambda => "lambda",
|
Self::Lambda => "lambda",
|
||||||
}
|
}
|
||||||
|
@ -52,6 +54,7 @@ impl FunctionKind {
|
||||||
/// The string that designates what can be found before the parameters
|
/// The string that designates what can be found before the parameters
|
||||||
fn before_params(&self) -> &'static str {
|
fn before_params(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
|
Self::Method => "method name",
|
||||||
Self::Function => "function name",
|
Self::Function => "function name",
|
||||||
Self::Lambda => "'fun' keyword",
|
Self::Lambda => "'fun' keyword",
|
||||||
}
|
}
|
||||||
|
@ -59,7 +62,10 @@ impl FunctionKind {
|
||||||
|
|
||||||
/// The maximal amount of explicit parameters for a function of this kind.
|
/// The maximal amount of explicit parameters for a function of this kind.
|
||||||
fn max_params(&self) -> usize {
|
fn max_params(&self) -> usize {
|
||||||
255
|
match self {
|
||||||
|
Self::Method => 254,
|
||||||
|
_ => 255,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,30 +133,33 @@ impl Parser {
|
||||||
ProgramNode(stmts)
|
ProgramNode(stmts)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse the following rule:
|
/// Parse the following rules:
|
||||||
/// ```
|
/// ```
|
||||||
/// statement := expression ";"
|
/// statement := expression ";"
|
||||||
/// statement := "print" expression ";"
|
/// statement := "print" expression ";"
|
||||||
/// statement := var_declaration ";"
|
/// statement := var_declaration ";"
|
||||||
/// statement := fun_declaration ";"
|
/// statement := "fun" function ";"
|
||||||
/// statement := block
|
/// statement := "class" class ";"
|
||||||
/// statement := labelled_loop
|
/// statement := block
|
||||||
/// statement := if_statement
|
/// statement := labelled_loop
|
||||||
/// statement := while_statement
|
/// statement := if_statement
|
||||||
/// statement := for_statement
|
/// statement := while_statement
|
||||||
/// statement := loop_control_statement
|
/// statement := for_statement
|
||||||
/// statement := return_statement
|
/// statement := loop_control_statement
|
||||||
|
/// statement := return_statement
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_statement(&mut self) -> SloxResult<StmtNode> {
|
fn parse_statement(&mut self) -> SloxResult<StmtNode> {
|
||||||
if self.expect(&[TokenType::Var]).is_some() {
|
if self.expect(&[TokenType::Var]).is_some() {
|
||||||
self.parse_var_declaration()
|
self.parse_var_declaration()
|
||||||
|
} else if self.expect(&[TokenType::Class]).is_some() {
|
||||||
|
self.parse_class()
|
||||||
} else if self.expect(&[TokenType::Fun]).is_some() {
|
} else if self.expect(&[TokenType::Fun]).is_some() {
|
||||||
if self.check(&TokenType::LeftParen) {
|
if self.check(&TokenType::LeftParen) {
|
||||||
// This is a lambda.
|
// This is a lambda.
|
||||||
self.current -= 1;
|
self.current -= 1;
|
||||||
self.parse_expression_stmt()
|
self.parse_expression_stmt()
|
||||||
} else {
|
} else {
|
||||||
self.parse_fun_declaration(FunctionKind::Function)
|
self.parse_function(FunctionKind::Function)
|
||||||
}
|
}
|
||||||
} else if self.expect(&[TokenType::LeftBrace]).is_some() {
|
} else if self.expect(&[TokenType::LeftBrace]).is_some() {
|
||||||
self.parse_block()
|
self.parse_block()
|
||||||
|
@ -208,11 +217,34 @@ impl Parser {
|
||||||
|
|
||||||
/// Parse the following rule:
|
/// Parse the following rule:
|
||||||
/// ```
|
/// ```
|
||||||
/// fun_declaration := "fun" function
|
/// class := IDENTIFIER "{" function* "}"
|
||||||
|
/// ```
|
||||||
|
fn parse_class(&mut self) -> SloxResult<StmtNode> {
|
||||||
|
// Read the name
|
||||||
|
let name = match self.peek().token_type {
|
||||||
|
TokenType::Identifier(_) => self.advance().clone(),
|
||||||
|
_ => return self.error("class name expected"),
|
||||||
|
};
|
||||||
|
// Read the body
|
||||||
|
self.consume(&TokenType::LeftBrace, "'{' expected")?;
|
||||||
|
let mut methods = Vec::new();
|
||||||
|
while !self.check(&TokenType::LeftBrace) && !self.is_at_end() {
|
||||||
|
match self.parse_function(FunctionKind::Method)? {
|
||||||
|
StmtNode::FunDecl(d) => methods.push(d),
|
||||||
|
_ => panic!("Function declaration expected"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.consume(&TokenType::RightBrace, "'}' expected")?;
|
||||||
|
|
||||||
|
Ok(StmtNode::ClassDecl(ClassDecl { name, methods }))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse the following rule:
|
||||||
|
/// ```
|
||||||
/// function := IDENTIFIER function_info
|
/// function := IDENTIFIER function_info
|
||||||
/// ```
|
/// ```
|
||||||
/// The `kind` parameter is used to generate error messages.
|
/// The `kind` parameter is used to generate error messages.
|
||||||
fn parse_fun_declaration(&mut self, kind: FunctionKind) -> SloxResult<StmtNode> {
|
fn parse_function(&mut self, kind: FunctionKind) -> SloxResult<StmtNode> {
|
||||||
// Read the name
|
// Read the name
|
||||||
let name = match self.peek().token_type {
|
let name = match self.peek().token_type {
|
||||||
TokenType::Identifier(_) => self.advance().clone(),
|
TokenType::Identifier(_) => self.advance().clone(),
|
||||||
|
|
Loading…
Reference in a new issue