Compare commits

..

No commits in common. "b5b56b49a90a1a605a959935144912e9eecee98c" and "afa481207494c7dcf5d70eb8f463b12bd743b6a1" have entirely different histories.

6 changed files with 31 additions and 158 deletions

View file

@ -155,9 +155,6 @@ pub enum TreeKind {
TypeParameter, TypeParameter,
TypeParameterList, TypeParameterList,
UnaryExpression, UnaryExpression,
IsExpression,
VariableBinding,
} }
pub struct Tree<'a> { pub struct Tree<'a> {
@ -321,7 +318,6 @@ struct MarkClosed {
struct CParser<'a> { struct CParser<'a> {
tokens: Tokens<'a>, tokens: Tokens<'a>,
current: Token<'a>, current: Token<'a>,
next: Token<'a>,
fuel: Cell<u32>, fuel: Cell<u32>,
events: Vec<ParseEvent<'a>>, events: Vec<ParseEvent<'a>>,
panic: bool, panic: bool,
@ -332,13 +328,11 @@ impl<'a> CParser<'a> {
let mut parser = CParser { let mut parser = CParser {
tokens, tokens,
current: Token::new(TokenKind::EOF, 0, ""), current: Token::new(TokenKind::EOF, 0, ""),
next: Token::new(TokenKind::EOF, 0, ""),
fuel: Cell::new(256), fuel: Cell::new(256),
events: Vec::new(), events: Vec::new(),
panic: false, panic: false,
}; };
parser.current = parser.tokens.next(); parser.current = parser.tokens.next();
parser.next = parser.tokens.next();
parser.skip_ephemera(); parser.skip_ephemera();
parser parser
} }
@ -377,18 +371,14 @@ impl<'a> CParser<'a> {
self.events.push(ParseEvent::Advance { self.events.push(ParseEvent::Advance {
token: self.current.clone(), token: self.current.clone(),
}); });
// Move next into current (and current into next but who cares, thanks rust.) self.current = self.tokens.next();
std::mem::swap(&mut self.current, &mut self.next);
self.next = self.tokens.next();
self.skip_ephemera(); self.skip_ephemera();
} }
fn skip_ephemera(&mut self) { fn skip_ephemera(&mut self) {
while self.current.kind == TokenKind::Whitespace || self.current.kind == TokenKind::Comment while self.current.kind == TokenKind::Whitespace || self.current.kind == TokenKind::Comment
{ {
// Move next into current (and current into next but who cares, thanks rust.) self.current = self.tokens.next();
std::mem::swap(&mut self.current, &mut self.next);
self.next = self.tokens.next();
} }
} }
@ -407,17 +397,6 @@ impl<'a> CParser<'a> {
self.current.kind self.current.kind
} }
fn peek_next(&self) -> TokenKind {
if self.fuel.get() == 0 {
panic!(
"parser is stuck at '{}' ({})!",
self.current, self.current.start
);
}
self.fuel.set(self.fuel.get() - 1);
self.next.kind
}
// fn trace(&self, msg: &str) { // fn trace(&self, msg: &str) {
// eprintln!("{}: {}: {}", self.current.start, self.current, msg); // eprintln!("{}: {}: {}", self.current.start, self.current, msg);
// } // }
@ -908,7 +887,7 @@ fn expression(p: &mut CParser) {
expression_with_power(p, 0) expression_with_power(p, 0)
} }
const UNARY_POWER: u8 = 16; const UNARY_POWER: u8 = 14;
fn infix_power(token: TokenKind) -> Option<(u8, u8)> { fn infix_power(token: TokenKind) -> Option<(u8, u8)> {
// A dumb thing: the pair controls associativity. // A dumb thing: the pair controls associativity.
@ -918,18 +897,17 @@ fn infix_power(token: TokenKind) -> Option<(u8, u8)> {
match token { match token {
TokenKind::Equal => Some((1, 0)), TokenKind::Equal => Some((1, 0)),
TokenKind::Or => Some((2, 3)), TokenKind::Or => Some((2, 3)),
TokenKind::Is => Some((4, 5)), TokenKind::And => Some((4, 5)),
TokenKind::And => Some((6, 7)), TokenKind::EqualEqual | TokenKind::BangEqual => Some((6, 7)),
TokenKind::EqualEqual | TokenKind::BangEqual => Some((8, 9)),
TokenKind::Less | TokenKind::Greater | TokenKind::GreaterEqual | TokenKind::LessEqual => { TokenKind::Less | TokenKind::Greater | TokenKind::GreaterEqual | TokenKind::LessEqual => {
Some((10, 11)) Some((8, 9))
} }
TokenKind::Plus | TokenKind::Minus => Some((12, 13)), TokenKind::Plus | TokenKind::Minus => Some((10, 11)),
TokenKind::Star | TokenKind::Slash => Some((14, 15)), TokenKind::Star | TokenKind::Slash => Some((12, 13)),
// //
// UNARY_POWER goes here. // UNARY_POWER goes here.
// //
TokenKind::Dot => Some((18, 19)), TokenKind::Dot => Some((16, 17)),
_ => None, _ => None,
} }
} }
@ -953,56 +931,20 @@ fn expression_with_power(p: &mut CParser, minimum_power: u8) {
break; break;
} }
expr = match token { // TODO: I don't think this works for other "infix" types, but we'll
TokenKind::Dot => member_access(p, expr, rp), // see won't we.
TokenKind::Is => is_expression(p, expr, rp), let m = p.start_before(expr);
_ => binary_expression(p, expr, rp),
};
}
}
fn member_access(p: &mut CParser, left: MarkClosed, right_power: u8) -> MarkClosed {
let m = p.start_before(left);
p.advance(); // Consume the operator p.advance(); // Consume the operator
expression_with_power(p, right_power); expression_with_power(p, rp);
p.end(m, TreeKind::MemberAccess) expr = p.end(
} m,
if token == TokenKind::Dot {
fn binary_expression(p: &mut CParser, left: MarkClosed, right_power: u8) -> MarkClosed { TreeKind::MemberAccess
let m = p.start_before(left);
p.advance(); // Consume the operator
expression_with_power(p, right_power);
p.end(m, TreeKind::BinaryExpression)
}
fn is_expression(p: &mut CParser, left: MarkClosed, right_power: u8) -> MarkClosed {
let m = p.start_before(left);
p.advance(); // Consume the operator
// This is hard to do with just, like, no lookahead.
if p.peek() == TokenKind::Identifier && p.peek_next() == TokenKind::Colon {
// This is a variable binding.
variable_binding(p);
} else { } else {
type_expr(p); TreeKind::BinaryExpression
},
);
} }
// Additional predicates go into the right-hand-side.
if p.eat(TokenKind::And) {
expression_with_power(p, right_power);
}
p.end(m, TreeKind::IsExpression)
}
fn variable_binding(p: &mut CParser) {
let m = p.start();
p.expect_start(TokenKind::Identifier);
p.expect_start(TokenKind::Colon);
type_expr(p);
p.end(m, TreeKind::VariableBinding);
} }
fn argument_list(p: &mut CParser) { fn argument_list(p: &mut CParser) {
@ -1183,14 +1125,7 @@ fn field_list(p: &mut CParser) {
p.expect_start(TokenKind::LeftBrace); p.expect_start(TokenKind::LeftBrace);
while !p.at(TokenKind::RightBrace) && !p.eof() { while !p.at(TokenKind::RightBrace) && !p.eof() {
if p.at(TokenKind::Identifier) {
field_value(p); field_value(p);
} else {
if p.at_any(STATEMENT_RECOVERY) {
break;
}
p.advance_with_error("expected an identifier in a field list");
}
} }
p.expect( p.expect(
TokenKind::RightBrace, TokenKind::RightBrace,
@ -1203,7 +1138,7 @@ fn field_list(p: &mut CParser) {
fn field_value(p: &mut CParser) { fn field_value(p: &mut CParser) {
let m = p.start(); let m = p.start();
p.expect_start(TokenKind::Identifier); p.expect(TokenKind::Identifier, "expected a field name");
if p.eat(TokenKind::Colon) { if p.eat(TokenKind::Colon) {
expression(p); expression(p);
} }

View file

@ -604,13 +604,14 @@ impl<'a> Semantics<'a> {
}; };
let result = match tree.kind { let result = match tree.kind {
TreeKind::IsExpression => self.environment_of_is_expression(parent, tree),
TreeKind::Block => self.environment_of_block(parent, tree),
TreeKind::File => self.environment_of_file(parent, tree),
TreeKind::ForStatement => self.environment_of_for(parent, tree),
TreeKind::LetStatement => self.environment_of_let(parent, tree), TreeKind::LetStatement => self.environment_of_let(parent, tree),
TreeKind::MemberAccess => self.environment_of_member_access(tree),
TreeKind::ParamList => self.environment_of_paramlist(parent, tree), TreeKind::ParamList => self.environment_of_paramlist(parent, tree),
TreeKind::File => self.environment_of_file(parent, tree),
TreeKind::Block => self.environment_of_block(parent, tree),
TreeKind::ForStatement => self.environment_of_for(parent, tree),
TreeKind::MemberAccess => self.environment_of_member_access(tree),
_ => parent, _ => parent,
}; };
@ -818,24 +819,6 @@ impl<'a> Semantics<'a> {
} }
} }
fn environment_of_is_expression(&self, parent: EnvironmentRef, tree: &Tree) -> EnvironmentRef {
assert_eq!(tree.kind, TreeKind::IsExpression);
let Some(binding) = tree.child_tree_of_kind(self.syntax_tree, TreeKind::VariableBinding)
else {
return parent;
};
let Some(variable) = binding.nth_token(0) else {
return Environment::error();
};
let Some(type_expr) = binding.nth_tree(2) else {
return Environment::error();
};
let mut env = Environment::new(Some(parent), Location::Local);
env.insert(variable, type_expr);
return EnvironmentRef::new(env);
}
pub fn class_of(&self, t: TreeRef) -> ClassRef { pub fn class_of(&self, t: TreeRef) -> ClassRef {
{ {
// I want to make sure that this borrow is dropped after this block. // I want to make sure that this borrow is dropped after this block.
@ -985,9 +968,6 @@ impl<'a> Semantics<'a> {
(Type::Error, _) => true, (Type::Error, _) => true,
(_, Type::Error) => true, (_, Type::Error) => true,
// Can... I... convert unreachable always? Is this sound?
(Type::Unreachable, _) => true,
// TODO: Unification on type variables! :D // TODO: Unification on type variables! :D
(_, _) => false, (_, _) => false,
} }
@ -1030,7 +1010,6 @@ impl<'a> Semantics<'a> {
TreeKind::GroupingExpression => self.type_of_grouping(tree), TreeKind::GroupingExpression => self.type_of_grouping(tree),
TreeKind::Identifier => self.type_of_identifier(t, tree), TreeKind::Identifier => self.type_of_identifier(t, tree),
TreeKind::IfStatement => self.type_of_if_statement(tree), TreeKind::IfStatement => self.type_of_if_statement(tree),
TreeKind::IsExpression => Some(Type::Bool),
TreeKind::LetStatement => Some(Type::Nothing), TreeKind::LetStatement => Some(Type::Nothing),
TreeKind::ListConstructor => self.type_of_list_constructor(t, tree), TreeKind::ListConstructor => self.type_of_list_constructor(t, tree),
TreeKind::ListConstructorElement => self.type_of_list_constructor_element(tree), TreeKind::ListConstructorElement => self.type_of_list_constructor_element(tree),
@ -1875,9 +1854,6 @@ pub fn check(s: &Semantics) {
TreeKind::FieldValue => {} TreeKind::FieldValue => {}
TreeKind::SelfParameter => {} TreeKind::SelfParameter => {}
TreeKind::SelfReference => {} TreeKind::SelfReference => {}
TreeKind::IsExpression => check_is_expression(s, tree),
TreeKind::VariableBinding => check_variable_binding(s, tree),
} }
} }
} }
@ -2053,14 +2029,6 @@ fn check_class_declaration(s: &Semantics, tree: &Tree) {
} }
} }
fn check_is_expression(_s: &Semantics, _tree: &Tree) {
// TODO
}
fn check_variable_binding(_s: &Semantics, _tree: &Tree) {
// TODO
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View file

@ -48,7 +48,6 @@ pub enum TokenKind {
If, If,
Import, Import,
In, In,
Is,
Let, Let,
New, New,
Or, Or,
@ -298,9 +297,6 @@ impl<'a> Tokens<'a> {
if ident == "in" { if ident == "in" {
return TokenKind::In; return TokenKind::In;
} }
if ident == "is" {
return TokenKind::Is;
}
} }
'l' => { 'l' => {
if ident == "let" { if ident == "let" {
@ -597,8 +593,6 @@ mod tests {
(58, New, "new") (58, New, "new")
); );
test_tokens!(more_more_keywords, "in is", (0, In, "in"), (3, Is, "is"));
test_tokens!( test_tokens!(
strings, strings,
r#"'this is a string that\'s great!\r\n' "foo's" 'bar"s' "#, r#"'this is a string that\'s great!\r\n' "foo's" 'bar"s' "#,

View file

@ -33,7 +33,7 @@ class Monster {
fun print(x:string) {} fun print(x:string) {}
fun in_range(weapon: MeleeWeapon or RangedWeapon, distance: f64) { fun in_range(weapon: MeleeWeapon or RangedWeapon, distance: f64) {
match weapon { weapon match {
w:RangedWeapon -> distance >= w.minRange and distance <= w.maxRange, w:RangedWeapon -> distance >= w.minRange and distance <= w.maxRange,
_ -> distance == 1 _ -> distance == 1
} }

View file

@ -1,18 +0,0 @@
class Foo {
a: f64;
}
fun test() -> f64 {
let b = new Foo { a : 23 };
let result = 0;
if b is c:Foo and c.a == 23 {
result = result + 1;
}
if b is c:Foo and c.a == 24 {
result = result + 1;
}
result
}
// @no-errors

View file

@ -1,6 +0,0 @@
fun explicit_return() -> f64 {
return 10.0;
// No error: after this point code is unreachable.
}
// @no-errors