mirror of
https://github.com/exoticorn/curlywas.git
synced 2026-01-20 11:46:43 +01:00
add support for (void) block expression
This commit is contained in:
20
examples/microw8/circles.cwa
Normal file
20
examples/microw8/circles.cwa
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -155,6 +155,10 @@ pub enum Expr {
|
||||
label: String,
|
||||
block: Box<Expression>,
|
||||
},
|
||||
LabelBlock {
|
||||
label: String,
|
||||
block: Box<Expression>,
|
||||
},
|
||||
Branch(String),
|
||||
BranchIf {
|
||||
condition: Box<Expression>,
|
||||
|
||||
@@ -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, ..
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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<char, Vec<(Token, Span)>, Error = Simple<char>> {
|
||||
"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<Token, ast::Script, Error = Simple<Token>> + 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<Token, ast::Script, Error = Simple<Token>> + 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<Token, ast::Script, Error = Simple<Token>> + 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<Token, ast::Script, Error = Simple<Token>> + 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<Token, ast::Script, Error = Simple<Token>> + 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<Token, ast::Script, Error = Simple<Token>> + 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<Token, ast::Script, Error = Simple<Token>> + 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(')')),
|
||||
)
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user