Parser - Support for getters and setters
This commit is contained in:
parent
3d55901c51
commit
680c4b249d
1 changed files with 50 additions and 39 deletions
|
@ -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()?);
|
||||||
|
|
Loading…
Reference in a new issue