From 29b8c0470053cb2ac58cf13b3ed7578854147270 Mon Sep 17 00:00:00 2001 From: Dennis Ranke Date: Sat, 13 Nov 2021 17:43:04 +0100 Subject: [PATCH] add support for (void) block expression --- examples/microw8/circles.cwa | 20 ++++++++++ src/ast.rs | 4 ++ src/constfold.rs | 1 + src/emit.rs | 8 ++++ src/parser.rs | 71 +++++++++++++++++++----------------- src/typecheck.rs | 13 +++++++ 6 files changed, 84 insertions(+), 33 deletions(-) create mode 100644 examples/microw8/circles.cwa diff --git a/examples/microw8/circles.cwa b/examples/microw8/circles.cwa new file mode 100644 index 0000000..483e9be --- /dev/null +++ b/examples/microw8/circles.cwa @@ -0,0 +1,20 @@ +import "env.memory" memory(4); + +import "env.circle" fn circle(f32, f32, f32, i32); +import "env.sin" fn sin(f32) -> f32; +import "env.cls" fn cls(i32); + +export fn tic(time: i32) { + cls(0); + let i: i32; + loop outer { + let lazy fi = i as f32 / 4 as f32; + let lazy t = time as f32 / 5000 as f32; + circle( + (sin(fi / 2 as f32 + t * 5 as f32) + 1 as f32) * 160 as f32, + (sin(fi / 3 as f32 + t * 4 as f32) + 1 as f32) * 128 as f32, + (sin(t * 17 as f32 + fi * 2 as f32) + 2 as f32) * 16 as f32, i * 2 + 63); + + branch_if (i := i + 1) < 63: outer + } +} \ No newline at end of file diff --git a/src/ast.rs b/src/ast.rs index ece3ad1..81f68d2 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -155,6 +155,10 @@ pub enum Expr { label: String, block: Box, }, + LabelBlock { + label: String, + block: Box, + }, Branch(String), BranchIf { condition: Box, diff --git a/src/constfold.rs b/src/constfold.rs index faafd95..9a8e47a 100644 --- a/src/constfold.rs +++ b/src/constfold.rs @@ -242,6 +242,7 @@ fn fold_expr(expr: &mut ast::Expression) { ast::Expr::Assign { ref mut value, .. } => fold_expr(value), ast::Expr::LocalTee { ref mut value, .. } => fold_expr(value), ast::Expr::Loop { ref mut block, .. } => fold_expr(block), + ast::Expr::LabelBlock { ref mut block, .. } => fold_expr(block), ast::Expr::Branch(_) => (), ast::Expr::BranchIf { ref mut condition, .. diff --git a/src/emit.rs b/src/emit.rs index 25c4586..643d044 100644 --- a/src/emit.rs +++ b/src/emit.rs @@ -316,6 +316,7 @@ fn collect_locals_expr<'a>(expr: &ast::Expression, locals: &mut Vec<(String, ast ast::Expr::Assign { value, .. } => collect_locals_expr(value, locals), ast::Expr::LocalTee { value, .. } => collect_locals_expr(value, locals), ast::Expr::Loop { block, .. } => collect_locals_expr(block, locals), + ast::Expr::LabelBlock { block, .. } => collect_locals_expr(block, locals), ast::Expr::Cast { value, .. } => collect_locals_expr(value, locals), ast::Expr::FuncCall { params, .. } => { for param in params { @@ -610,6 +611,13 @@ fn emit_expression<'a>(ctx: &mut FunctionContext<'a>, expr: &'a ast::Expression) ctx.labels.pop(); ctx.function.instruction(&Instruction::End); } + ast::Expr::LabelBlock {label, block } => { + ctx.labels.push(label.to_string()); + ctx.function.instruction(&Instruction::Block(map_block_type(block.type_))); + emit_expression(ctx, block); + ctx.labels.pop(); + ctx.function.instruction(&Instruction::End); + } ast::Expr::Variable(name) => { if let Some(index) = ctx.locals.get(name) { if let Some((expr, let_type)) = ctx.let_values.get(name.as_str()) { diff --git a/src/parser.rs b/src/parser.rs index c2caf75..c7779c8 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -14,6 +14,7 @@ enum Token { Global, Mut, Loop, + Block, Branch, BranchIf, Lazy, @@ -45,6 +46,7 @@ impl fmt::Display for Token { Token::Global => write!(f, "global"), Token::Mut => write!(f, "mut"), Token::Loop => write!(f, "loop"), + Token::Block => write!(f, "block"), Token::Branch => write!(f, "branch"), Token::BranchIf => write!(f, "branch_if"), Token::Lazy => write!(f, "lazy"), @@ -237,6 +239,7 @@ fn lexer() -> impl Parser, Error = Simple> { "global" => Token::Global, "mut" => Token::Mut, "loop" => Token::Loop, + "block" => Token::Block, "branch" => Token::Branch, "branch_if" => Token::BranchIf, "lazy" => Token::Lazy, @@ -333,39 +336,31 @@ fn script_parser() -> impl Parser> + C let loop_expr = just(Token::Loop) .ignore_then(identifier) - .then( - block - .clone() - .delimited_by(Token::Ctrl('{'), Token::Ctrl('}')), - ) + .then(block.clone()) .map(|(label, block)| ast::Expr::Loop { label, block: Box::new(block), }); + let label_block_expr = just(Token::Block) + .ignore_then(identifier) + .then(block.clone()) + .map(|(label, block)| ast::Expr::LabelBlock { + label, + block: Box::new(block), + }); + let if_expr = just(Token::If) .ignore_then(expression.clone()) - .then( - block - .clone() - .delimited_by(Token::Ctrl('{'), Token::Ctrl('}')), - ) - .then( - just(Token::Else) - .ignore_then( - block - .clone() - .delimited_by(Token::Ctrl('{'), Token::Ctrl('}')), - ) - .or_not(), - ) + .then(block.clone()) + .then(just(Token::Else).ignore_then(block.clone()).or_not()) .map(|((condition, if_true), if_false)| ast::Expr::If { condition: Box::new(condition), if_true: Box::new(if_true), if_false: if_false.map(Box::new), }); - let block_expr = loop_expr.or(if_expr).boxed(); + let block_expr = loop_expr.or(label_block_expr).or(if_expr).boxed(); block_expression = Some(block_expr.clone()); @@ -475,6 +470,7 @@ fn script_parser() -> impl Parser> + C .or(expression .clone() .delimited_by(Token::Ctrl('('), Token::Ctrl(')'))) + .or(block) .recover_with(nested_delimiters( Token::Ctrl('('), Token::Ctrl(')'), @@ -570,7 +566,8 @@ fn script_parser() -> impl Parser> + C } else { make_memory_op(left, vec![(size, right)], None) } - }).clone(); + }) + .clone(); let memory_op = op_cast .clone() @@ -732,17 +729,27 @@ fn script_parser() -> impl Parser> + C expression .clone() - .then_ignore(just(Token::Ctrl(';'))) - .or(block_expression.map_with_span(|expr, span| expr.with_span(span))) + .then(just(Token::Ctrl(';')).to(false)) + .or(block_expression.map_with_span(|expr, span| (expr.with_span(span), true))) .repeated() .then(expression.clone().or_not()) - .map_with_span(|(statements, final_expression), span| { + .map_with_span(|(mut statements, mut final_expression), span| { + if final_expression.is_none() + && statements + .last() + .map(|(_, block_expr)| *block_expr) + .unwrap_or(false) + { + final_expression = statements.pop().map(|(expr, _)| expr); + } ast::Expr::Block { - statements, + statements: statements.into_iter().map(|(expr, _)| expr).collect(), final_expression: final_expression.map(|e| Box::new(e)), } .with_span(span) - }).boxed() + }) + .delimited_by(Token::Ctrl('{'), Token::Ctrl('}')) + .boxed() }); let expression = expression_out.unwrap(); @@ -821,11 +828,7 @@ fn script_parser() -> impl Parser> + C .ignore_then(type_parser()) .or_not(), ) - .then( - block - .clone() - .delimited_by(Token::Ctrl('{'), Token::Ctrl('}')), - ) + .then(block.clone()) .map_with_span(|((((export, name), params), type_), body), span| { ast::TopLevelItem::Function(ast::Function { span, @@ -852,7 +855,8 @@ fn script_parser() -> impl Parser> + C mutable: mutable.is_some(), span, }) - }).boxed(); + }) + .boxed(); let data_i8 = just(Token::Ident("i8".to_string())) .to(ast::DataType::I8) @@ -862,7 +866,8 @@ fn script_parser() -> impl Parser> + C .or(just(Token::Ident("f32".to_string())).to(ast::DataType::F32)) .or(just(Token::Ident("f64".to_string())).to(ast::DataType::F64)) .then( - expression.clone() + expression + .clone() .separated_by(just(Token::Ctrl(','))) .delimited_by(Token::Ctrl('('), Token::Ctrl(')')), ) diff --git a/src/typecheck.rs b/src/typecheck.rs index 6811c76..f62a4d7 100644 --- a/src/typecheck.rs +++ b/src/typecheck.rs @@ -577,6 +577,19 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() context.block_stack.pop(); block.type_ } + ast::Expr::LabelBlock { + ref label, + ref mut block, + } => { + context.block_stack.push(label.clone()); + tc_expression(context, block)?; + context.block_stack.pop(); + if block.type_ != None { + // TODO: implement, requires branches to optionally provide values + return type_mismatch(None, &expr.span, block.type_, &block.span, context.source); + } + None + } ast::Expr::Branch(ref label) => { if !context.block_stack.contains(label) { return missing_label(&expr.span, context.source);