add loops

main
anna 2 years ago
parent a86c2ec584
commit d9df6df402
Signed by: fef
GPG Key ID: EC22E476DC2D3D84

@ -16,6 +16,7 @@ enum Scope {
DepList,
SourceList,
Function,
Loop,
}
struct Parser {
@ -79,19 +80,33 @@ impl Parser {
fn parse_stmt(&mut self) -> Result<tree::Node, Error> {
let token = self.lexer.peek_or_err()?;
match token.kind {
token::Kind::BreakKeyword => self.parse_break_stmt(),
token::Kind::DependKeyword => self.parse_depend_stmt(),
token::Kind::FnKeyword => self.parse_fn(false),
token::Kind::ForKeyword => self.parse_for_stmt(),
token::Kind::IfKeyword => self.parse_if_stmt(),
token::Kind::ReturnKeyword => self.parse_return_stmt(),
token::Kind::SetKeyword => self.parse_set_stmt(),
token::Kind::SourceKeyword => self.parse_source_stmt(),
token::Kind::TargetKeyword => self.parse_target_stmt(),
token::Kind::TypeKeyword => self.parse_type_stmt(),
token::Kind::WhileKeyword => self.parse_while_stmt(),
k if k.is_start_of_expr() => self.parse_expr_stmt(),
_ => self.syntax_error(format!("Unexpected token {}", token), &token),
}
}
/// ```notrust
/// BreakStatement
/// : "break" ";"
/// ```
fn parse_break_stmt(&mut self) -> Result<tree::Node, Error> {
self.lexer.expect_kind(token::Kind::BreakKeyword)?;
self.assert_scope(Scope::Loop)?;
self.lexer.expect_kind(token::Kind::Semi)?;
Ok(tree::Node::Break)
}
/// ```notrust
/// BlockStatement
/// : "{" [ StatementList ] "}"
@ -182,6 +197,50 @@ impl Parser {
})
}
/// ```notrust
/// WhileStatement
/// : "while" "(" Expression ")" BlockStatement
/// ```
fn parse_while_stmt(&mut self) -> Result<tree::Node, Error> {
self.lexer.expect_kind(token::Kind::WhileKeyword)?;
self.scope.push(Scope::Loop);
self.lexer.expect_kind(token::Kind::OParen)?;
let condition = self.parse_expr(&[token::Kind::CParen])?;
let block = self.parse_block_stmt()?;
self.scope.pop();
Ok(tree::Node::WhileStmt {
condition: Box::new(condition),
block: Box::new(block),
})
}
/// ```notrust
/// ForStatement
/// : "for" "(" [ Expression ] ";" [ Expression ] ";" [ Expression ] ")" BlockStatement
/// ```
fn parse_for_stmt(&mut self) -> Result<tree::Node, Error> {
self.lexer.expect_kind(token::Kind::ForKeyword)?;
self.scope.push(Scope::Loop);
self.lexer.expect_kind(token::Kind::OParen)?;
let terminators = [token::Kind::Semi, token::Kind::Semi, token::Kind::CParen];
let mut exprs = Vec::new();
for i in 0..3 {
exprs.push(if self.lexer.next_if(terminators[i]) {
None
} else {
Some(Box::new(self.parse_expr(&terminators[i..=i])?))
});
}
let body = self.parse_block_stmt()?;
self.scope.pop();
Ok(tree::Node::ForStmt {
exec: exprs.pop().unwrap(),
condition: exprs.pop().unwrap(),
setup: exprs.pop().unwrap(),
body: Box::new(body),
})
}
/// ```notrust
/// SetStatement
/// : "set" AssignmentExpression ";"
@ -213,8 +272,8 @@ impl Parser {
/// : "type" Expression ";"
/// ```
fn parse_type_stmt(&mut self) -> Result<tree::Node, Error> {
self.assert_scope(Scope::Target)?;
self.lexer.expect_kind(token::Kind::TypeKeyword)?;
self.assert_scope(Scope::Target)?;
let expr = self.parse_expr(&[token::Kind::Semi])?;
Ok(tree::Node::TypeExpr(Box::new(expr)))
}
@ -224,8 +283,8 @@ impl Parser {
/// : "source" Expression ";"
/// ```
fn parse_source_stmt(&mut self) -> Result<tree::Node, Error> {
self.assert_scope(Scope::Target)?;
self.lexer.expect_kind(token::Kind::SourceKeyword)?;
self.assert_scope(Scope::Target)?;
self.scope.push(Scope::SourceList);
let source = self.parse_expr(&[token::Kind::Semi])?;
self.scope.pop();

@ -8,6 +8,7 @@ use crate::lex::token::Token;
#[derive(Debug)]
pub enum Node {
Break,
Ident(String),
DepList(Box<Node>),
SourceList(Box<Node>),
@ -37,6 +38,16 @@ pub enum Node {
else_block: Option<Box<Node>>,
},
ReturnStmt(Box<Node>),
ForStmt {
setup: Option<Box<Node>>,
condition: Option<Box<Node>>,
exec: Option<Box<Node>>,
body: Box<Node>,
},
WhileStmt {
condition: Box<Node>,
block: Box<Node>,
},
UnaryExpr {
op: Operator,
node: Box<Node>,
@ -146,6 +157,22 @@ impl Node {
eb.visit(cb, depth);
}
}
Node::ForStmt { setup, condition, exec, body } => {
if let Some(s) = setup {
s.visit(cb, depth);
}
if let Some(c) = condition {
c.visit(cb, depth);
}
if let Some(e) = exec {
e.visit(cb, depth);
}
body.visit(cb, depth);
}
Node::WhileStmt { condition, block } => {
condition.visit(cb, depth);
block.visit(cb, depth);
}
Node::ReturnStmt(node) => node.visit(cb, depth),
Node::UnaryExpr { op, node } => node.visit(cb, depth),
Node::BinaryExpr { op, lhs, rhs } => {
@ -178,6 +205,7 @@ impl fmt::Display for Node {
f,
"{}",
match self {
Node::Break => "<break>",
Node::Ident(name) => name.as_str(),
Node::Bool(b) => {
tmp = format!("{}", b);
@ -201,6 +229,8 @@ impl fmt::Display for Node {
then_block,
else_block,
} => "<if>",
Node::ForStmt { setup, condition, exec, body } => "<for>",
Node::WhileStmt { condition, block } => "<while>",
Node::UnaryExpr { op, node } => op.raw(),
Node::BinaryExpr { op, lhs, rhs } => op.raw(),
Node::TypeExpr(_) => "type",

@ -35,11 +35,13 @@ const fn kw(raw: &'static str, kind: token::Kind) -> KeywordMap {
KeywordMap { raw, kind }
}
static KEYWORDS: [KeywordMap; 12] = [
static KEYWORDS: [KeywordMap; 15] = [
kw("break", token::Kind::BreakKeyword),
kw("depend", token::Kind::DependKeyword),
kw("else", token::Kind::ElseKeyword),
kw("false", token::Kind::FalseKeyword),
kw("fn", token::Kind::FnKeyword),
kw("for", token::Kind::ForKeyword),
kw("if", token::Kind::IfKeyword),
kw("include", token::Kind::IncludeKeyword),
kw("return", token::Kind::ReturnKeyword),
@ -48,6 +50,7 @@ static KEYWORDS: [KeywordMap; 12] = [
kw("target", token::Kind::TargetKeyword),
kw("true", token::Kind::TrueKeyword),
kw("type", token::Kind::TypeKeyword),
kw("while", token::Kind::WhileKeyword),
];
impl Iterator for Lexer {
@ -206,6 +209,17 @@ impl Lexer {
}
}
pub fn next_if(&mut self, kind: token::Kind) -> bool {
if let Some(Ok(token)) = self.peek() {
if token.kind == kind {
self.next();
return true;
}
}
false
}
pub fn require_next(&mut self) -> Result<Token, Error> {
match self.next() {
Some(t) => t,

@ -68,10 +68,12 @@ pub enum Kind {
Percent,
PercentEq,
BreakKeyword,
DependKeyword,
ElseKeyword,
FalseKeyword,
FnKeyword,
ForKeyword,
IfKeyword,
IncludeKeyword,
ReturnKeyword,
@ -80,6 +82,7 @@ pub enum Kind {
TargetKeyword,
TrueKeyword,
TypeKeyword,
WhileKeyword,
StringLiteral,
IntLiteral,
@ -215,10 +218,12 @@ impl fmt::Display for Kind {
Kind::Percent => "percent",
Kind::PercentEq => "percenteq",
Kind::BreakKeyword => "keyword",
Kind::DependKeyword => "keyword",
Kind::ElseKeyword => "keyword",
Kind::FalseKeyword => "keyword",
Kind::FnKeyword => "keyword",
Kind::ForKeyword => "keyword",
Kind::IfKeyword => "keyword",
Kind::IncludeKeyword => "keyword",
Kind::ReturnKeyword => "keyword",
@ -227,6 +232,7 @@ impl fmt::Display for Kind {
Kind::TargetKeyword => "keyword",
Kind::TrueKeyword => "keyword",
Kind::TypeKeyword => "keyword",
Kind::WhileKeyword => "keyword",
Kind::StringLiteral => "string",
Kind::IntLiteral => "int",

@ -16,18 +16,38 @@ fn hello(p1, p2) {
# a target is a single component.
# targets can depend on other targets.
target kern {
# if statements work just like you expect them to ...
if (2 > 3) {
print("2 > 3");
} else {
print("2 <= 3");
}
# ... so do while loops ...
x = 0;
while (true) {
print(x);
x += 1;
if (x == 10) {
break;
}
}
# ... and even for loops
for (x = 0; x < 10; x += 1) {
print(x);
}
# functions are first-class citizens; they can be defined as inline
# anonymous functions that you can treat like any other value
fn_with_callback(fn(a, b) { return a + b; });
(fn(a, b) { return a + b; })(1, 2);
# math works exactly as you would expect it to
owo = 1 + 2 * 3 * 4 - 5;
# and, naturally, there are also all the bitwise goodies
bitmask = 1 << 2 | 1 << 8 ^ get_bit() & 1;
# this is exactly equal to the above, but with added
# parentheses to make the operator precedences clear
bitmask = (1 << 2) | ((1 << 8) ^ (get_bit() & 1));
# the type keyword defines whether the target is supposed to be
# compiled into an executable binary (exe) or a library (lib).

Loading…
Cancel
Save