[fine] Improvements to classes
- Classes are defined lazily - Member access is via environment - Member access is just a binary expression with a weird environment - Slot loads look like variable loads now - Associativity in the parser (ugh)
This commit is contained in:
parent
0d48bfb113
commit
2839b43f6d
5 changed files with 286 additions and 123 deletions
|
|
@ -129,6 +129,8 @@ pub enum TreeKind {
|
|||
ConditionalExpression,
|
||||
ExpressionStatement,
|
||||
FieldDecl,
|
||||
FieldList,
|
||||
FieldValue,
|
||||
File,
|
||||
ForStatement,
|
||||
FunctionDecl,
|
||||
|
|
@ -139,18 +141,18 @@ pub enum TreeKind {
|
|||
ListConstructor,
|
||||
ListConstructorElement,
|
||||
LiteralExpression,
|
||||
MemberAccess,
|
||||
NewObjectExpression,
|
||||
ParamList,
|
||||
Parameter,
|
||||
ReturnStatement,
|
||||
ReturnType,
|
||||
SelfParameter,
|
||||
SelfReference,
|
||||
TypeExpression,
|
||||
TypeParameter,
|
||||
TypeParameterList,
|
||||
UnaryExpression,
|
||||
FieldList,
|
||||
NewObjectExpression,
|
||||
FieldValue,
|
||||
MemberAccess,
|
||||
}
|
||||
|
||||
pub struct Tree<'a> {
|
||||
|
|
@ -606,6 +608,8 @@ fn param_list(p: &mut CParser) {
|
|||
while !p.at(TokenKind::RightParen) && !p.eof() {
|
||||
if p.at(TokenKind::Identifier) {
|
||||
parameter(p);
|
||||
} else if p.at(TokenKind::Selff) {
|
||||
self_parameter(p);
|
||||
} else {
|
||||
if p.at_any(PARAM_LIST_RECOVERY) {
|
||||
break;
|
||||
|
|
@ -632,6 +636,21 @@ fn parameter(p: &mut CParser) {
|
|||
p.end(m, TreeKind::Parameter);
|
||||
}
|
||||
|
||||
fn self_parameter(p: &mut CParser) {
|
||||
let m = p.start();
|
||||
|
||||
p.expect_start(TokenKind::Selff);
|
||||
if p.eat(TokenKind::Colon) {
|
||||
p.error("self parameters cannot have explicit types");
|
||||
type_expr(p);
|
||||
}
|
||||
if !p.at(TokenKind::RightParen) {
|
||||
p.expect(TokenKind::Comma, "expected a comma between parameters");
|
||||
}
|
||||
|
||||
p.end(m, TreeKind::SelfParameter);
|
||||
}
|
||||
|
||||
fn return_type(p: &mut CParser) {
|
||||
let m = p.start();
|
||||
|
||||
|
|
@ -780,31 +799,27 @@ fn expression(p: &mut CParser) {
|
|||
expression_with_power(p, 0)
|
||||
}
|
||||
|
||||
// BINDING POWERS. When parsing expressions we only accept expressions that
|
||||
// meet a minimum binding power. (This is like "precedence" but I just super
|
||||
// don't like that terminology.)
|
||||
const ASSIGNMENT_POWER: u8 = 0; // =
|
||||
const OR_POWER: u8 = 1; // or
|
||||
const AND_POWER: u8 = 2; // and
|
||||
const EQUALITY_POWER: u8 = 3; // == !=
|
||||
const COMPARISON_POWER: u8 = 4; // < > <= >=
|
||||
const TERM_POWER: u8 = 5; // + -
|
||||
const FACTOR_POWER: u8 = 6; // * /
|
||||
const UNARY_POWER: u8 = 7; // ! -
|
||||
const UNARY_POWER: u8 = 14;
|
||||
|
||||
// const PRIMARY_POWER: u8 = 9;
|
||||
|
||||
fn token_power<'a>(token: TokenKind) -> Option<u8> {
|
||||
fn infix_power(token: TokenKind) -> Option<(u8, u8)> {
|
||||
// A dumb thing: the pair controls associativity.
|
||||
//
|
||||
// If lhs < rhs then it's left-associative, otherwise it's
|
||||
// right-associative.
|
||||
match token {
|
||||
TokenKind::Equal => Some(ASSIGNMENT_POWER),
|
||||
TokenKind::Or => Some(OR_POWER),
|
||||
TokenKind::And => Some(AND_POWER),
|
||||
TokenKind::EqualEqual | TokenKind::BangEqual => Some(EQUALITY_POWER),
|
||||
TokenKind::Equal => Some((1, 0)),
|
||||
TokenKind::Or => Some((2, 3)),
|
||||
TokenKind::And => Some((4, 5)),
|
||||
TokenKind::EqualEqual | TokenKind::BangEqual => Some((6, 7)),
|
||||
TokenKind::Less | TokenKind::Greater | TokenKind::GreaterEqual | TokenKind::LessEqual => {
|
||||
Some(COMPARISON_POWER)
|
||||
Some((8, 9))
|
||||
}
|
||||
TokenKind::Plus | TokenKind::Minus => Some(TERM_POWER),
|
||||
TokenKind::Star | TokenKind::Slash => Some(FACTOR_POWER),
|
||||
TokenKind::Plus | TokenKind::Minus => Some((10, 11)),
|
||||
TokenKind::Star | TokenKind::Slash => Some((12, 13)),
|
||||
//
|
||||
// UNARY_POWER goes here.
|
||||
//
|
||||
TokenKind::Dot => Some((16, 17)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -818,10 +833,11 @@ fn expression_with_power(p: &mut CParser, minimum_power: u8) {
|
|||
}
|
||||
|
||||
loop {
|
||||
let Some(power) = token_power(p.peek()) else {
|
||||
let token = p.peek();
|
||||
let Some((lp, rp)) = infix_power(token) else {
|
||||
break;
|
||||
};
|
||||
if power < minimum_power {
|
||||
if lp < minimum_power {
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -829,18 +845,15 @@ fn expression_with_power(p: &mut CParser, minimum_power: u8) {
|
|||
// see won't we.
|
||||
let m = p.start_before(expr);
|
||||
p.advance(); // Consume the operator
|
||||
expression_with_power(p, power);
|
||||
expr = p.end(m, TreeKind::BinaryExpression);
|
||||
}
|
||||
|
||||
while p.at(TokenKind::Dot) {
|
||||
let m = p.start_before(expr);
|
||||
p.advance(); // Consume the dot
|
||||
p.expect(
|
||||
TokenKind::Identifier,
|
||||
"expected an identifier for member access",
|
||||
expression_with_power(p, rp);
|
||||
expr = p.end(
|
||||
m,
|
||||
if token == TokenKind::Dot {
|
||||
TreeKind::MemberAccess
|
||||
} else {
|
||||
TreeKind::BinaryExpression
|
||||
},
|
||||
);
|
||||
expr = p.end(m, TreeKind::MemberAccess);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -885,6 +898,7 @@ fn prefix_expression(p: &mut CParser) -> MarkClosed {
|
|||
TokenKind::If => conditional(p),
|
||||
|
||||
TokenKind::Identifier => identifier(p),
|
||||
TokenKind::Selff => self_reference(p),
|
||||
|
||||
TokenKind::LeftBracket => list_constructor(p),
|
||||
|
||||
|
|
@ -946,6 +960,15 @@ fn identifier(p: &mut CParser) -> MarkClosed {
|
|||
p.end(m, TreeKind::Identifier)
|
||||
}
|
||||
|
||||
fn self_reference(p: &mut CParser) -> MarkClosed {
|
||||
assert!(p.at(TokenKind::Selff));
|
||||
let m = p.start();
|
||||
|
||||
p.advance();
|
||||
|
||||
p.end(m, TreeKind::SelfReference)
|
||||
}
|
||||
|
||||
fn list_constructor(p: &mut CParser) -> MarkClosed {
|
||||
let m = p.start();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue