Parser - Support for getters and setters

This commit is contained in:
Emmanuel BENOîT 2023-01-14 17:01:17 +01:00
parent 3d55901c51
commit 680c4b249d

View file

@ -162,10 +162,10 @@ impl Parser {
self.current -= 1; self.current -= 1;
self.parse_expression_stmt() self.parse_expression_stmt()
} else { } else {
self.parse_function(FunctionKind::Function) self.parse_function()
} }
} else if self.expect(&[TokenType::LeftBrace]).is_some() { } else if self.expect(&[TokenType::LeftBrace]).is_some() {
self.parse_block() self.parse_block_contents()
} else if self.expect(&[TokenType::Address]).is_some() { } else if self.expect(&[TokenType::Address]).is_some() {
self.parse_labelled_loop() self.parse_labelled_loop()
} else if self.expect(&[TokenType::If]).is_some() { } else if self.expect(&[TokenType::If]).is_some() {
@ -218,8 +218,10 @@ impl Parser {
/// Parse the following rules: /// Parse the following rules:
/// ``` /// ```
/// class := IDENTIFIER "{" member* "}" /// class := IDENTIFIER "{" member* "}"
/// member := "static" function /// member := "static"? gen_member
/// member := function /// gen_member := IDENTIFIER function_info
/// gen_member := IDENTIFIER ">" block
/// gen_member := IDENTIFIER "<" block
/// ``` /// ```
fn parse_class(&mut self) -> SloxResult<StmtNode> { fn parse_class(&mut self) -> SloxResult<StmtNode> {
let name = self.consume_identifier("expected class name")?; let name = self.consume_identifier("expected class name")?;
@ -227,26 +229,32 @@ impl Parser {
let mut members = Vec::new(); let mut members = Vec::new();
while !self.check(&TokenType::RightBrace) && !self.is_at_end() { while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
let static_token = self.expect(&[TokenType::Static]); let static_token = self.expect(&[TokenType::Static]);
match self.parse_function(FunctionKind::Method)? { let identifier = self.consume_identifier("member identifier expected")?;
StmtNode::FunDecl(d) => { let accessor = self.expect(&[TokenType::Less, TokenType::Greater]);
if let Some(tok) = &static_token { let (kind, params, body) = if let Some(acc_token) = accessor {
if d.name.lexeme == "init" { let body = self
return Err(SloxError::with_token( .parse_block("'{{' expected before accessor body")?
ErrorKind::Parse, .extract_block_statements();
tok, let (kind, params) = match acc_token.token_type {
"initializer cannot be declared static".to_owned(), TokenType::Greater => (ClassMemberKind::Getter, vec![]),
)); TokenType::Less => (ClassMemberKind::Setter, vec![identifier.clone()]),
} _ => panic!("unexpected accessor token {:?}", acc_token),
} };
(kind, params, body)
} else {
let (params, body) = self.parse_function_info(FunctionKind::Method)?;
(ClassMemberKind::Method, params, body)
};
members.push(ClassMemberDecl { members.push(ClassMemberDecl {
kind: ClassMemberKind::Method, kind,
is_static: static_token.is_some(), is_static: static_token.is_some(),
fun_decl: d, fun_decl: FunDecl {
name: identifier,
params,
body,
},
}); });
} }
_ => panic!("Function declaration expected"),
}
}
self.consume(&TokenType::RightBrace, "'}' expected")?; self.consume(&TokenType::RightBrace, "'}' expected")?;
Ok(StmtNode::ClassDecl(ClassDecl { name, members })) Ok(StmtNode::ClassDecl(ClassDecl { name, members }))
@ -257,9 +265,9 @@ impl Parser {
/// 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_function(&mut self, kind: FunctionKind) -> SloxResult<StmtNode> { fn parse_function(&mut self) -> SloxResult<StmtNode> {
let name = self.consume_identifier(&format!("expected {} name", kind.name()))?; let name = self.consume_identifier("expected function name")?;
let (params, block) = self.parse_function_info(kind)?; let (params, block) = self.parse_function_info(FunctionKind::Function)?;
Ok(StmtNode::FunDecl(FunDecl { Ok(StmtNode::FunDecl(FunDecl {
name, name,
params, params,
@ -307,24 +315,27 @@ impl Parser {
} }
// Read the function's body // Read the function's body
self.consume( let block = self.parse_block(&format!("'{{' expected before {} body", kind.name()))?;
&TokenType::LeftBrace,
&format!("'{{' expected before {} body", kind.name()),
)?;
let block = {
self.loop_state.push(LoopParsingState::None);
let result = self.parse_block();
self.loop_state.pop();
result?
};
Ok((params, block.extract_block_statements())) Ok((params, block.extract_block_statements()))
} }
/// Parse the following rule: /// Parse the following rule:
/// ``` /// ```
/// block := "{" statement* "}" /// block := "{" block_contents
/// ``` /// ```
fn parse_block(&mut self) -> SloxResult<StmtNode> { fn parse_block(&mut self, err_string: &str) -> Result<StmtNode, SloxError> {
self.consume(&TokenType::LeftBrace, &err_string)?;
self.loop_state.push(LoopParsingState::None);
let result = self.parse_block_contents();
self.loop_state.pop();
result
}
/// Parse the following rule:
/// ```
/// block_contents := statement* "}"
/// ```
fn parse_block_contents(&mut self) -> SloxResult<StmtNode> {
let mut stmts: Vec<StmtNode> = Vec::new(); let mut stmts: Vec<StmtNode> = Vec::new();
while !(self.check(&TokenType::RightBrace) || self.is_at_end()) { while !(self.check(&TokenType::RightBrace) || self.is_at_end()) {
stmts.push(self.parse_statement()?); stmts.push(self.parse_statement()?);