[fine] WIP: Classes
This commit is contained in:
parent
e6c96fde38
commit
0ee89bf26b
7 changed files with 370 additions and 59 deletions
|
|
@ -125,8 +125,10 @@ pub enum TreeKind {
|
|||
BinaryExpression,
|
||||
Block,
|
||||
CallExpression,
|
||||
ClassDecl,
|
||||
ConditionalExpression,
|
||||
ExpressionStatement,
|
||||
FieldDecl,
|
||||
File,
|
||||
ForStatement,
|
||||
FunctionDecl,
|
||||
|
|
@ -145,6 +147,9 @@ pub enum TreeKind {
|
|||
TypeParameter,
|
||||
TypeParameterList,
|
||||
UnaryExpression,
|
||||
FieldList,
|
||||
NewObjectExpression,
|
||||
FieldValue,
|
||||
}
|
||||
|
||||
pub struct Tree<'a> {
|
||||
|
|
@ -183,14 +188,17 @@ impl<'a> Tree<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn children_of_kind<'b>(
|
||||
&'b self,
|
||||
s: &'b SyntaxTree,
|
||||
kind: TreeKind,
|
||||
) -> impl Iterator<Item = TreeRef> + 'b {
|
||||
self.child_trees()
|
||||
.filter_map(move |t| if s[t].kind == kind { Some(t) } else { None })
|
||||
}
|
||||
|
||||
pub fn child_of_kind(&self, s: &SyntaxTree, kind: TreeKind) -> Option<TreeRef> {
|
||||
self.children
|
||||
.iter()
|
||||
.filter_map(|c| match c {
|
||||
Child::Tree(t) => Some(*t),
|
||||
_ => None,
|
||||
})
|
||||
.find(|c| s[*c].kind == kind)
|
||||
self.children_of_kind(&s, kind).next()
|
||||
}
|
||||
|
||||
pub fn child_tree_of_kind<'b>(
|
||||
|
|
@ -400,6 +408,10 @@ impl<'a> CParser<'a> {
|
|||
self.error(error);
|
||||
}
|
||||
|
||||
fn expect_start(&mut self, kind: TokenKind) {
|
||||
assert!(self.eat(kind));
|
||||
}
|
||||
|
||||
fn advance_with_error<T>(&mut self, error: T) -> MarkClosed
|
||||
where
|
||||
T: Into<String>,
|
||||
|
|
@ -498,6 +510,7 @@ fn file(p: &mut CParser) {
|
|||
while !p.eof() {
|
||||
match p.peek() {
|
||||
TokenKind::Fun => function(p),
|
||||
TokenKind::Class => class(p),
|
||||
_ => statement(p),
|
||||
}
|
||||
}
|
||||
|
|
@ -505,10 +518,9 @@ fn file(p: &mut CParser) {
|
|||
}
|
||||
|
||||
fn function(p: &mut CParser) {
|
||||
assert!(p.at(TokenKind::Fun));
|
||||
let m = p.start();
|
||||
|
||||
p.expect(TokenKind::Fun, "expected a function to start with 'fun'");
|
||||
p.expect_start(TokenKind::Fun);
|
||||
p.expect(TokenKind::Identifier, "expected a function name");
|
||||
if p.at(TokenKind::LeftParen) {
|
||||
param_list(p);
|
||||
|
|
@ -523,11 +535,40 @@ fn function(p: &mut CParser) {
|
|||
p.end(m, TreeKind::FunctionDecl);
|
||||
}
|
||||
|
||||
fn param_list(p: &mut CParser) {
|
||||
assert!(p.at(TokenKind::LeftParen));
|
||||
fn class(p: &mut CParser) {
|
||||
let m = p.start();
|
||||
|
||||
p.expect(TokenKind::LeftParen, "expect '(' to start a parameter list");
|
||||
p.expect_start(TokenKind::Class);
|
||||
p.expect(TokenKind::Identifier, "expected a class name");
|
||||
if p.eat(TokenKind::LeftBrace) {
|
||||
while !p.at(TokenKind::RightBrace) && !p.eof() {
|
||||
field_decl(p);
|
||||
}
|
||||
}
|
||||
p.expect(TokenKind::RightBrace, "expected a class to end with a '}'");
|
||||
|
||||
p.end(m, TreeKind::ClassDecl);
|
||||
}
|
||||
|
||||
fn field_decl(p: &mut CParser) {
|
||||
let m = p.start();
|
||||
|
||||
p.expect(TokenKind::Identifier, "expected a field name");
|
||||
if p.eat(TokenKind::Colon) {
|
||||
type_expr(p);
|
||||
}
|
||||
p.expect(
|
||||
TokenKind::Semicolon,
|
||||
"expect a ';' after field declarations",
|
||||
);
|
||||
|
||||
p.end(m, TreeKind::FieldDecl);
|
||||
}
|
||||
|
||||
fn param_list(p: &mut CParser) {
|
||||
let m = p.start();
|
||||
|
||||
p.expect_start(TokenKind::LeftParen);
|
||||
while !p.at(TokenKind::RightParen) && !p.eof() {
|
||||
if p.at(TokenKind::Identifier) {
|
||||
parameter(p);
|
||||
|
|
@ -541,12 +582,9 @@ fn param_list(p: &mut CParser) {
|
|||
}
|
||||
|
||||
fn parameter(p: &mut CParser) {
|
||||
assert!(p.at(TokenKind::Identifier));
|
||||
let m = p.start();
|
||||
p.expect(
|
||||
TokenKind::Identifier,
|
||||
"expected an identifier for a parameter name",
|
||||
);
|
||||
|
||||
p.expect_start(TokenKind::Identifier);
|
||||
if p.eat(TokenKind::Colon) {
|
||||
type_expr(p);
|
||||
}
|
||||
|
|
@ -558,13 +596,9 @@ fn parameter(p: &mut CParser) {
|
|||
}
|
||||
|
||||
fn return_type(p: &mut CParser) {
|
||||
assert!(p.at(TokenKind::Arrow));
|
||||
let m = p.start();
|
||||
|
||||
p.expect(
|
||||
TokenKind::Arrow,
|
||||
"function return type starts with an arrow",
|
||||
);
|
||||
p.expect_start(TokenKind::Arrow);
|
||||
type_expr(p);
|
||||
|
||||
p.end(m, TreeKind::ReturnType);
|
||||
|
|
@ -584,10 +618,9 @@ fn type_expr(p: &mut CParser) {
|
|||
}
|
||||
|
||||
fn type_parameter_list(p: &mut CParser) {
|
||||
assert!(p.at(TokenKind::Less));
|
||||
let m = p.start();
|
||||
|
||||
p.expect(TokenKind::Less, "expected < to start type parameter list");
|
||||
p.expect_start(TokenKind::Less);
|
||||
while !p.at(TokenKind::Greater) && !p.eof() {
|
||||
if p.at(TokenKind::Identifier) {
|
||||
type_parameter(p);
|
||||
|
|
@ -613,10 +646,9 @@ fn type_parameter(p: &mut CParser) {
|
|||
}
|
||||
|
||||
fn block(p: &mut CParser) {
|
||||
assert!(p.at(TokenKind::LeftBrace));
|
||||
let m = p.start();
|
||||
|
||||
p.expect(TokenKind::LeftBrace, "expect '{' to start a block");
|
||||
p.expect_start(TokenKind::LeftBrace);
|
||||
while !p.at(TokenKind::RightBrace) && !p.eof() {
|
||||
statement(p);
|
||||
}
|
||||
|
|
@ -650,10 +682,9 @@ fn statement_if(p: &mut CParser) {
|
|||
}
|
||||
|
||||
fn statement_let(p: &mut CParser) {
|
||||
assert!(p.at(TokenKind::Let));
|
||||
let m = p.start();
|
||||
|
||||
p.expect(TokenKind::Let, "expect 'let' to start a let statement");
|
||||
p.expect_start(TokenKind::Let);
|
||||
p.expect(TokenKind::Identifier, "expected a name for the variable");
|
||||
p.expect(TokenKind::Equal, "expected a '=' after the variable name");
|
||||
expression(p);
|
||||
|
|
@ -665,13 +696,9 @@ fn statement_let(p: &mut CParser) {
|
|||
}
|
||||
|
||||
fn statement_return(p: &mut CParser) {
|
||||
assert!(p.at(TokenKind::Return));
|
||||
let m = p.start();
|
||||
|
||||
p.expect(
|
||||
TokenKind::Return,
|
||||
"expect 'return' to start a return statement",
|
||||
);
|
||||
p.expect_start(TokenKind::Return);
|
||||
expression(p);
|
||||
if !p.at(TokenKind::RightBrace) {
|
||||
p.expect(TokenKind::Semicolon, "expect ';' to end a return statement");
|
||||
|
|
@ -681,10 +708,9 @@ fn statement_return(p: &mut CParser) {
|
|||
}
|
||||
|
||||
fn statement_for(p: &mut CParser) {
|
||||
assert!(p.at(TokenKind::For));
|
||||
let m = p.start();
|
||||
|
||||
p.expect(TokenKind::For, "expect a for to start a for loop");
|
||||
p.expect_start(TokenKind::For);
|
||||
p.expect(
|
||||
TokenKind::Identifier,
|
||||
"expected an identifier for the loop variable",
|
||||
|
|
@ -771,13 +797,9 @@ fn expression_with_power(p: &mut CParser, minimum_power: u8) {
|
|||
}
|
||||
|
||||
fn argument_list(p: &mut CParser) {
|
||||
assert!(p.at(TokenKind::LeftParen));
|
||||
let m = p.start();
|
||||
|
||||
p.expect(
|
||||
TokenKind::LeftParen,
|
||||
"expect an argument list to start with '('",
|
||||
);
|
||||
p.expect_start(TokenKind::LeftParen);
|
||||
while !p.at(TokenKind::RightParen) && !p.eof() {
|
||||
argument(p);
|
||||
}
|
||||
|
|
@ -818,6 +840,8 @@ fn prefix_expression(p: &mut CParser) -> MarkClosed {
|
|||
|
||||
TokenKind::LeftBracket => list_constructor(p),
|
||||
|
||||
TokenKind::New => object_constructor(p),
|
||||
|
||||
_ => p.advance_with_error("expected an expression"),
|
||||
}
|
||||
}
|
||||
|
|
@ -829,10 +853,9 @@ fn literal(p: &mut CParser) -> MarkClosed {
|
|||
}
|
||||
|
||||
fn grouping(p: &mut CParser) -> MarkClosed {
|
||||
assert!(p.at(TokenKind::LeftParen));
|
||||
let m = p.start();
|
||||
|
||||
p.expect(TokenKind::LeftParen, "expected '(' to start grouping");
|
||||
p.expect_start(TokenKind::LeftParen);
|
||||
expression(p);
|
||||
p.expect(TokenKind::RightParen, "unmatched parentheses in expression");
|
||||
|
||||
|
|
@ -849,10 +872,9 @@ fn unary(p: &mut CParser) -> MarkClosed {
|
|||
}
|
||||
|
||||
fn conditional(p: &mut CParser) -> MarkClosed {
|
||||
assert!(p.at(TokenKind::If));
|
||||
let m = p.start();
|
||||
|
||||
p.expect(TokenKind::If, "expected conditional to start with 'if'");
|
||||
p.expect_start(TokenKind::If);
|
||||
expression(p);
|
||||
block(p);
|
||||
if p.eat(TokenKind::Else) {
|
||||
|
|
@ -877,13 +899,9 @@ fn identifier(p: &mut CParser) -> MarkClosed {
|
|||
}
|
||||
|
||||
fn list_constructor(p: &mut CParser) -> MarkClosed {
|
||||
assert!(p.at(TokenKind::LeftBracket));
|
||||
let m = p.start();
|
||||
|
||||
p.expect(
|
||||
TokenKind::LeftBracket,
|
||||
"expect a list constructor to start with [",
|
||||
);
|
||||
p.expect_start(TokenKind::LeftBracket);
|
||||
while !p.at(TokenKind::RightBracket) && !p.eof() {
|
||||
list_constructor_element(p);
|
||||
}
|
||||
|
|
@ -909,6 +927,49 @@ fn list_constructor_element(p: &mut CParser) {
|
|||
p.end(m, TreeKind::ListConstructorElement);
|
||||
}
|
||||
|
||||
fn object_constructor(p: &mut CParser) -> MarkClosed {
|
||||
let m = p.start();
|
||||
|
||||
p.expect_start(TokenKind::New);
|
||||
type_expr(p);
|
||||
if p.at(TokenKind::LeftBrace) {
|
||||
field_list(p);
|
||||
} else {
|
||||
p.error("expected a '{' to start the field list after the class type");
|
||||
}
|
||||
|
||||
p.end(m, TreeKind::NewObjectExpression)
|
||||
}
|
||||
|
||||
fn field_list(p: &mut CParser) {
|
||||
let m = p.start();
|
||||
|
||||
p.expect_start(TokenKind::LeftBrace);
|
||||
while !p.at(TokenKind::RightBrace) && !p.eof() {
|
||||
field_value(p);
|
||||
}
|
||||
p.expect(
|
||||
TokenKind::RightBrace,
|
||||
"expected the field list to end with '}'",
|
||||
);
|
||||
|
||||
p.end(m, TreeKind::FieldList);
|
||||
}
|
||||
|
||||
fn field_value(p: &mut CParser) {
|
||||
let m = p.start();
|
||||
|
||||
p.expect(TokenKind::Identifier, "expected a field name");
|
||||
if p.eat(TokenKind::Colon) {
|
||||
expression(p);
|
||||
}
|
||||
if !p.at(TokenKind::RightBrace) {
|
||||
p.expect(TokenKind::Comma, "expect a ',' between fields");
|
||||
}
|
||||
|
||||
p.end(m, TreeKind::FieldValue);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue