From cfa199e81e382b4e1cf2d7a2eab2e996617b9ea3 Mon Sep 17 00:00:00 2001 From: Ryan Chandler Date: Tue, 19 Jul 2022 12:04:40 +0100 Subject: [PATCH] parser: class methods with visibility --- trunk_lexer/src/lexer.rs | 4 ++- trunk_lexer/src/token.rs | 1 + trunk_parser/src/ast.rs | 4 +-- trunk_parser/src/parser.rs | 66 ++++++++++++++++++++++++++++++++++++-- 4 files changed, 69 insertions(+), 6 deletions(-) diff --git a/trunk_lexer/src/lexer.rs b/trunk_lexer/src/lexer.rs index 725e2bd..e1b87c9 100644 --- a/trunk_lexer/src/lexer.rs +++ b/trunk_lexer/src/lexer.rs @@ -238,6 +238,7 @@ fn identifier_to_keyword(ident: &str) -> Option { "public" => TokenKind::Public, "protected" => TokenKind::Protected, "private" => TokenKind::Private, + "static" => TokenKind::Static, _ => return None, }) } @@ -290,7 +291,7 @@ mod tests { #[test] fn keywords() { - assert_tokens(" for Param { } #[derive(Debug, Clone, PartialEq)] -pub enum MethodFlags { +pub enum MethodFlag { Public, Protected, Private, @@ -55,7 +55,7 @@ pub enum Statement { name: Identifier, params: Vec, body: Block, - flags: Vec, + flags: Vec, }, If { condition: Expression, diff --git a/trunk_parser/src/parser.rs b/trunk_parser/src/parser.rs index 9326dd5..49479e9 100644 --- a/trunk_parser/src/parser.rs +++ b/trunk_parser/src/parser.rs @@ -1,7 +1,7 @@ -use std::vec::IntoIter; +use std::{vec::IntoIter}; use std::iter::Peekable; use trunk_lexer::{Token, TokenKind}; -use crate::{Program, Statement, Block, Expression}; +use crate::{Program, Statement, Block, Expression, ast::MethodFlag}; macro_rules! expect { ($actual:expr, $expected:pat, $out:expr, $message:literal) => { @@ -81,6 +81,7 @@ impl Parser { Statement::Function { name, params, body } => { Statement::Method { name, params, body, flags: vec![] } }, + s @ Statement::Method { .. } => s, _ => return Err(ParseError::InvalidClassStatement(format!("Classes can only contain properties, constants and methods."))) }; @@ -148,6 +149,22 @@ impl Parser { Statement::Function { name: name.into(), params, body } }, + _ if is_method_visibility_modifier(&t.kind) => { + let mut flags = vec![visibility_token_to_flag(&t.kind)]; + + while let Some(t) = tokens.peek() && is_method_visibility_modifier(&t.kind) { + let next = tokens.next().unwrap(); + + flags.push(visibility_token_to_flag(&next.kind)); + } + + match self.statement(tokens.next().unwrap(), tokens)? { + Statement::Function { name, params, body } => { + Statement::Method { name, params, body, flags } + }, + _ => return Err(ParseError::InvalidClassStatement("Classes can only contain properties, constants and methods.".into())) + } + }, _ => todo!("unhandled token: {:?}", t) }) } @@ -226,6 +243,20 @@ impl Parser { } } +fn is_method_visibility_modifier(kind: &TokenKind) -> bool { + [TokenKind::Public, TokenKind::Protected, TokenKind::Private, TokenKind::Static].contains(kind) +} + +fn visibility_token_to_flag(kind: &TokenKind) -> MethodFlag { + match kind { + TokenKind::Public => MethodFlag::Public, + TokenKind::Protected => MethodFlag::Protected, + TokenKind::Private => MethodFlag::Private, + TokenKind::Static => MethodFlag::Static, + _ => unreachable!() + } +} + fn infix(lhs: Expression, op: TokenKind, rhs: Expression) -> Expression { Expression::Infix(Box::new(lhs), op.into(), Box::new(rhs)) } @@ -255,7 +286,7 @@ pub enum ParseError { #[cfg(test)] mod tests { use trunk_lexer::Lexer; - use crate::{Statement, Block, Param, Expression, ast::InfixOp}; + use crate::{Statement, Block, Param, Expression, ast::{InfixOp, MethodFlag}}; use super::Parser; macro_rules! function { @@ -403,6 +434,35 @@ mod tests { ]); } + #[test] + fn class_with_method_visibility() { + assert_ast("\ +