Parser - Some refactoring of code that handles identifiers

This commit is contained in:
Emmanuel BENOîT 2023-01-08 11:31:02 +01:00
parent e006a12c80
commit 334dc99752

View file

@ -200,10 +200,7 @@ impl Parser {
/// var_declaration := "var" IDENTIFIER "=" expression ";" /// var_declaration := "var" IDENTIFIER "=" expression ";"
/// ``` /// ```
fn parse_var_declaration(&mut self) -> SloxResult<StmtNode> { fn parse_var_declaration(&mut self) -> SloxResult<StmtNode> {
let name = match self.peek().token_type { let name = self.consume_identifier("expected variable name")?;
TokenType::Identifier(_) => self.advance().clone(),
_ => return self.error("expected variable name"),
};
let initializer: Option<ExprNode> = match self.expect(&[TokenType::Equal]) { let initializer: Option<ExprNode> = match self.expect(&[TokenType::Equal]) {
Some(_) => Some(self.parse_expression()?), Some(_) => Some(self.parse_expression()?),
None => None, None => None,
@ -220,12 +217,7 @@ impl Parser {
/// class := IDENTIFIER "{" function* "}" /// class := IDENTIFIER "{" function* "}"
/// ``` /// ```
fn parse_class(&mut self) -> SloxResult<StmtNode> { fn parse_class(&mut self) -> SloxResult<StmtNode> {
// Read the name let name = self.consume_identifier("expected class 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")?; self.consume(&TokenType::LeftBrace, "'{' expected")?;
let mut methods = Vec::new(); let mut methods = Vec::new();
while !self.check(&TokenType::RightBrace) && !self.is_at_end() { while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
@ -245,11 +237,7 @@ impl Parser {
/// ``` /// ```
/// 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, kind: FunctionKind) -> SloxResult<StmtNode> {
// Read the name let name = self.consume_identifier(&format!("expected {} name", kind.name()))?;
let name = match self.peek().token_type {
TokenType::Identifier(_) => self.advance().clone(),
_ => return self.error_mv(format!("expected {} name", kind.name())),
};
let (params, block) = self.parse_function_info(kind)?; let (params, block) = self.parse_function_info(kind)?;
Ok(StmtNode::FunDecl(FunDecl { Ok(StmtNode::FunDecl(FunDecl {
name, name,
@ -284,15 +272,12 @@ impl Parser {
kind.max_params() kind.max_params()
)); ));
} }
if let TokenType::Identifier(name) = &self.peek().token_type { let name = self.consume_identifier("parameter name expected")?;
if names.contains(name) { if names.contains(&name.lexeme) {
return self.error_mv(format!("duplicate {} parameter", kind.name())); return self.error_mv(format!("duplicate {} parameter", kind.name()));
} }
names.insert(name.to_owned()); names.insert(name.lexeme);
params.push(self.advance().clone()); params.push(self.advance().clone());
} else {
return self.error("parameter name expected");
}
if self.expect(&[TokenType::Comma]).is_none() { if self.expect(&[TokenType::Comma]).is_none() {
break; break;
} }
@ -357,11 +342,7 @@ impl Parser {
/// labelled_loop := "@" IDENTIFIER for_statement /// labelled_loop := "@" IDENTIFIER for_statement
/// ``` /// ```
fn parse_labelled_loop(&mut self) -> SloxResult<StmtNode> { fn parse_labelled_loop(&mut self) -> SloxResult<StmtNode> {
let name_token = match self.peek().token_type { let name_token = self.consume_identifier("identifier expected after '@'")?;
TokenType::Identifier(_) => self.advance().clone(),
_ => return self.error("identifier expected after '@'"),
};
if self.expect(&[TokenType::While]).is_some() { if self.expect(&[TokenType::While]).is_some() {
self.parse_while_statement(Some(name_token)) self.parse_while_statement(Some(name_token))
} else if self.expect(&[TokenType::For]).is_some() { } else if self.expect(&[TokenType::For]).is_some() {
@ -478,7 +459,7 @@ impl Parser {
)); ));
} }
let loop_name = if let TokenType::Identifier(_) = self.peek().token_type { let loop_name = if self.peek().is_identifier() {
let name_token = self.advance().clone(); let name_token = self.advance().clone();
if !self.find_named_loop(&name_token.lexeme) { if !self.find_named_loop(&name_token.lexeme) {
self.expect(&[TokenType::Semicolon]); self.expect(&[TokenType::Semicolon]);
@ -817,6 +798,17 @@ impl Parser {
self.previous() self.previous()
} }
/// Advance if the current token is an identifier, returning a clone of
/// the token. If it isn't, an error with the specified message is
/// returned instead.
fn consume_identifier(&mut self, message: &str) -> SloxResult<Token> {
if self.peek().is_identifier() {
Ok(self.advance().clone())
} else {
self.error(message)
}
}
/// Check whether the end of token stream has been reached by checking /// Check whether the end of token stream has been reached by checking
/// for the `EOF` token. /// for the `EOF` token.
fn is_at_end(&self) -> bool { fn is_at_end(&self) -> bool {