ast: allow definitions in loop head
This is a rather bad hack, but it makes parsing a lot easier, so i'll allow it for now.
This commit is contained in:
parent
57e74ab52a
commit
ec8c8916b7
3 changed files with 37 additions and 11 deletions
|
@ -17,6 +17,7 @@ enum Scope {
|
||||||
SourceList,
|
SourceList,
|
||||||
Function,
|
Function,
|
||||||
Loop,
|
Loop,
|
||||||
|
ForLoopHead,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Parser {
|
struct Parser {
|
||||||
|
@ -243,6 +244,7 @@ impl Parser {
|
||||||
self.lexer.expect_kind(token::Kind::OParen)?;
|
self.lexer.expect_kind(token::Kind::OParen)?;
|
||||||
let terminators = [token::Kind::Semi, token::Kind::Semi, token::Kind::CParen];
|
let terminators = [token::Kind::Semi, token::Kind::Semi, token::Kind::CParen];
|
||||||
let mut exprs = Vec::new();
|
let mut exprs = Vec::new();
|
||||||
|
self.scope.push(Scope::ForLoopHead);
|
||||||
for i in 0..3 {
|
for i in 0..3 {
|
||||||
exprs.push(if self.lexer.next_if(terminators[i]).is_some() {
|
exprs.push(if self.lexer.next_if(terminators[i]).is_some() {
|
||||||
None
|
None
|
||||||
|
@ -250,6 +252,7 @@ impl Parser {
|
||||||
Some(self.parse_expr(&terminators[i..=i])?)
|
Some(self.parse_expr(&terminators[i..=i])?)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
self.scope.pop();
|
||||||
let body = self.parse_block_stmt()?;
|
let body = self.parse_block_stmt()?;
|
||||||
self.scope.pop();
|
self.scope.pop();
|
||||||
let exec = exprs.pop().unwrap();
|
let exec = exprs.pop().unwrap();
|
||||||
|
@ -330,10 +333,15 @@ impl Parser {
|
||||||
self.assert_scope(Scope::File)?;
|
self.assert_scope(Scope::File)?;
|
||||||
let expr = if let Some(result) = self.lexer.peek() {
|
let expr = if let Some(result) = self.lexer.peek() {
|
||||||
let token = result?;
|
let token = result?;
|
||||||
if !token.kind.is_start_of_expr() {
|
match token.kind {
|
||||||
self.syntax_error(String::from("Expected an expression"), &token)
|
k if k.is_start_of_expr() => self.parse_assignment_expr_or_higher(terminators),
|
||||||
} else {
|
// special case: when we are in a for loop header, we allow
|
||||||
self.parse_assignment_expr_or_higher(terminators)
|
// declaration statements (this is technically a bug and we're
|
||||||
|
// only doing it because it makes parsing everything easier)
|
||||||
|
token::Kind::VarKeyword if self.is_scope(Scope::ForLoopHead) => {
|
||||||
|
self.parse_decl_stmt()
|
||||||
|
}
|
||||||
|
_ => self.syntax_error(String::from("Expected an expression"), &token),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.syntax_error(
|
self.syntax_error(
|
||||||
|
@ -707,6 +715,10 @@ impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_scope(&self, scope: Scope) -> bool {
|
||||||
|
self.assert_scope(scope).is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
/// Ensure that the `scope` stack does not contain a certain scope.
|
/// Ensure that the `scope` stack does not contain a certain scope.
|
||||||
fn assert_scope_not(&self, scope: Scope) -> Result<(), Error> {
|
fn assert_scope_not(&self, scope: Scope) -> Result<(), Error> {
|
||||||
if self.scope.contains(&scope) {
|
if self.scope.contains(&scope) {
|
||||||
|
|
13
src/main.rs
13
src/main.rs
|
@ -3,20 +3,29 @@ mod error;
|
||||||
mod lex;
|
mod lex;
|
||||||
mod rt;
|
mod rt;
|
||||||
|
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
use ast::parse;
|
use ast::parse;
|
||||||
use rt::exec;
|
use rt::exec;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
let start_time = Instant::now();
|
||||||
let result = parse(String::from("test.gaybuild")).unwrap();
|
let result = parse(String::from("test.gaybuild")).unwrap();
|
||||||
|
let duration = start_time.elapsed();
|
||||||
match result {
|
match result {
|
||||||
Ok(tree) => {
|
Ok(tree) => {
|
||||||
println!("=== begin tree ===");
|
println!("=== begin tree ===");
|
||||||
tree.walk(|n, d| println!("{}{}", " ".repeat(d as usize), n));
|
tree.walk(|n, d| println!("{}{}", " ".repeat(d as usize), n));
|
||||||
println!("=== end tree ===\n");
|
println!("=== end tree ===");
|
||||||
|
println!("parsing took {:?}\n", duration);
|
||||||
println!("=== begin eval ===");
|
println!("=== begin eval ===");
|
||||||
match exec(&tree) {
|
let start_time = Instant::now();
|
||||||
|
let result = exec(&tree);
|
||||||
|
let duration = start_time.elapsed();
|
||||||
|
match result {
|
||||||
Ok(val) => {
|
Ok(val) => {
|
||||||
println!("=== end eval ===");
|
println!("=== end eval ===");
|
||||||
|
println!("evaluation took {:?}", duration);
|
||||||
println!("evaluation returned {}", val)
|
println!("evaluation returned {}", val)
|
||||||
}
|
}
|
||||||
Err(e) => println!("{:?}", e),
|
Err(e) => println!("{:?}", e),
|
||||||
|
|
|
@ -31,7 +31,7 @@ target kern {
|
||||||
print("2 <= 3");
|
print("2 <= 3");
|
||||||
}
|
}
|
||||||
# ... so do while loops ...
|
# ... so do while loops ...
|
||||||
y = 0;
|
var y = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
print(y);
|
print(y);
|
||||||
y += 1;
|
y += 1;
|
||||||
|
@ -40,19 +40,24 @@ target kern {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# ... and even for loops
|
# ... and even for loops
|
||||||
for (x = 0; x < 10; x += 1) {
|
for (var x = 0; x < 10; x += 1) {
|
||||||
print(x);
|
print(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
# functions are first-class citizens; they can be defined as inline
|
# functions are first-class citizens; they can be defined as inline
|
||||||
# anonymous functions that you can treat like any other value
|
# anonymous functions that you can treat like any other value
|
||||||
fn_with_callback(fn(a, b) { return a + b; });
|
var captured_val = "-.-";
|
||||||
|
fn_with_callback(fn(a, b) {
|
||||||
|
captured_val = "OwO";
|
||||||
|
return a + b;
|
||||||
|
});
|
||||||
|
print(captured_val);
|
||||||
(fn(a, b) { return a + b; })(1, 2);
|
(fn(a, b) { return a + b; })(1, 2);
|
||||||
|
|
||||||
# math works exactly as you would expect it to
|
# math works exactly as you would expect it to
|
||||||
owo = 1 + 2 * 3 * 4 - 5;
|
var owo = 1 + 2 * 3 * 4 - 5;
|
||||||
# and, naturally, there are also all the bitwise goodies
|
# and, naturally, there are also all the bitwise goodies
|
||||||
bitmask = 1 << 2 | 1 << 8 ^ get_bit() & 1;
|
var bitmask = 1 << 2 | 1 << 8 ^ get_bit() & 1;
|
||||||
# this is exactly equal to the above, but with added
|
# this is exactly equal to the above, but with added
|
||||||
# parentheses to make the operator precedences clear
|
# parentheses to make the operator precedences clear
|
||||||
bitmask = (1 << 2) | ((1 << 8) ^ (get_bit() & 1));
|
bitmask = (1 << 2) | ((1 << 8) ^ (get_bit() & 1));
|
||||||
|
|
Loading…
Reference in a new issue