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:
Emmanuel BENOîT 2023-01-07 14:05:17 +01:00
parent 36026681f7
commit 5702abe44d

View file

@ -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,12 +133,13 @@ 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 := "class" class ";"
/// statement := block /// statement := block
/// statement := labelled_loop /// statement := labelled_loop
/// statement := if_statement /// statement := if_statement
@ -144,13 +151,15 @@ impl Parser {
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(),