From e23b98c1abf207a8fcf283a27e1089b34aeadc19 Mon Sep 17 00:00:00 2001 From: Dennis Ranke Date: Sat, 13 Nov 2021 22:27:07 +0100 Subject: [PATCH] implement support for start function --- examples/microw8/circles.cwa | 2 +- examples/microw8/technotunnel.cwa | 1 - src/ast.rs | 1 + src/emit.rs | 17 ++++++++++++++--- src/parser.rs | 24 +++++++----------------- src/typecheck.rs | 30 ++++++++++++++++++++++++++++++ 6 files changed, 53 insertions(+), 22 deletions(-) diff --git a/examples/microw8/circles.cwa b/examples/microw8/circles.cwa index 483e9be..bf5a3b4 100644 --- a/examples/microw8/circles.cwa +++ b/examples/microw8/circles.cwa @@ -5,7 +5,7 @@ import "env.sin" fn sin(f32) -> f32; import "env.cls" fn cls(i32); export fn tic(time: i32) { - cls(0); + cls(32); let i: i32; loop outer { let lazy fi = i as f32 / 4 as f32; diff --git a/examples/microw8/technotunnel.cwa b/examples/microw8/technotunnel.cwa index a7ac6b2..99e10d3 100644 --- a/examples/microw8/technotunnel.cwa +++ b/examples/microw8/technotunnel.cwa @@ -1,6 +1,5 @@ import "env.memory" memory(4); import "env.sin" fn sin(f32) -> f32; -import "env.atan2" fn atan2(f32, f32) -> f32; export fn tic(time: i32) { let i: i32; diff --git a/src/ast.rs b/src/ast.rs index 81f68d2..afb35a0 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -53,6 +53,7 @@ pub struct GlobalVar { pub struct Function { pub span: Span, pub export: bool, + pub start: bool, pub name: String, pub params: Vec<(String, Type)>, pub type_: Option, diff --git a/src/emit.rs b/src/emit.rs index 643d044..fd22731 100644 --- a/src/emit.rs +++ b/src/emit.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use wasm_encoder::{ BlockType, CodeSection, DataSection, EntityType, Export, ExportSection, Function, FunctionSection, GlobalSection, GlobalType, ImportSection, Instruction, MemArg, MemoryType, - Module, TypeSection, ValType, + Module, StartSection, TypeSection, ValType, }; use crate::{ast, intrinsics::Intrinsics}; @@ -94,9 +94,14 @@ pub fn emit(script: &ast::Script) -> Vec { let mut exports = ExportSection::new(); let mut code = CodeSection::new(); + let mut start_index = None; + let intrinsics = Intrinsics::new(); for func in script.functions.iter() { + if func.start { + start_index = Some(function_map.len() as u32); + } function_map.insert(func.name.clone(), function_map.len() as u32); } @@ -118,6 +123,11 @@ pub fn emit(script: &ast::Script) -> Vec { module.section(&global_section); } module.section(&exports); + + if let Some(function_index) = start_index { + module.section(&StartSection { function_index }); + } + module.section(&code); } @@ -611,9 +621,10 @@ 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 } => { + ast::Expr::LabelBlock { label, block } => { ctx.labels.push(label.to_string()); - ctx.function.instruction(&Instruction::Block(map_block_type(block.type_))); + ctx.function + .instruction(&Instruction::Block(map_block_type(block.type_))); emit_expression(ctx, block); ctx.labels.pop(); ctx.function.instruction(&Instruction::End); diff --git a/src/parser.rs b/src/parser.rs index c7779c8..b95fc94 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -6,11 +6,8 @@ use std::fmt; #[derive(Clone, Debug, PartialEq, Eq, Hash)] enum Token { - Import, - Export, Fn, Let, - Memory, Global, Mut, Loop, @@ -24,7 +21,6 @@ enum Token { If, Else, Return, - Data, Ident(String), Str(String), Int(i32), @@ -38,11 +34,8 @@ enum Token { impl fmt::Display for Token { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Token::Import => write!(f, "import"), - Token::Export => write!(f, "export"), Token::Fn => write!(f, "fn"), Token::Let => write!(f, "let"), - Token::Memory => write!(f, "memory"), Token::Global => write!(f, "global"), Token::Mut => write!(f, "mut"), Token::Loop => write!(f, "loop"), @@ -56,7 +49,6 @@ impl fmt::Display for Token { Token::If => write!(f, "if"), Token::Else => write!(f, "else"), Token::Return => write!(f, "return"), - Token::Data => write!(f, "data"), Token::Ident(s) => write!(f, "{}", s), Token::Str(s) => write!(f, "{:?}", s), Token::Int(v) => write!(f, "{}", v), @@ -231,11 +223,8 @@ fn lexer() -> impl Parser, Error = Simple> { } let ident = ident().map(|ident: String| match ident.as_str() { - "import" => Token::Import, - "export" => Token::Export, "fn" => Token::Fn, "let" => Token::Let, - "memory" => Token::Memory, "global" => Token::Global, "mut" => Token::Mut, "loop" => Token::Loop, @@ -249,7 +238,6 @@ fn lexer() -> impl Parser, Error = Simple> { "if" => Token::If, "else" => Token::Else, "return" => Token::Return, - "data" => Token::Data, _ => Token::Ident(ident), }); @@ -755,7 +743,7 @@ fn script_parser() -> impl Parser> + C let expression = expression_out.unwrap(); let top_level_item = { - let import_memory = just(Token::Memory) + let import_memory = just(Token::Ident("memory".to_string())) .ignore_then( integer .clone() @@ -795,7 +783,7 @@ fn script_parser() -> impl Parser> + C }) .boxed(); - let import = just(Token::Import) + let import = just(Token::Ident("import".to_string())) .ignore_then(string.clone()) .then(import_memory.or(import_global).or(import_function)) .then_ignore(just(Token::Ctrl(';'))) @@ -814,8 +802,9 @@ fn script_parser() -> impl Parser> + C .then(type_parser()) .boxed(); - let function = just(Token::Export) + let function = just(Token::Ident("export".to_string())) .or_not() + .then(just(Token::Ident("start".to_string())).or_not()) .then_ignore(just(Token::Fn)) .then(identifier.clone()) .then( @@ -829,11 +818,12 @@ fn script_parser() -> impl Parser> + C .or_not(), ) .then(block.clone()) - .map_with_span(|((((export, name), params), type_), body), span| { + .map_with_span(|(((((export, start), name), params), type_), body), span| { ast::TopLevelItem::Function(ast::Function { span, params, export: export.is_some(), + start: start.is_some(), name, type_, body, @@ -875,7 +865,7 @@ fn script_parser() -> impl Parser> + C let data_string = string.map(|s| ast::DataValues::String(s)); - let data = just(Token::Data) + let data = just(Token::Ident("data".to_string())) .ignore_then(expression.clone()) .then( data_i8 diff --git a/src/typecheck.rs b/src/typecheck.rs index f62a4d7..61917f4 100644 --- a/src/typecheck.rs +++ b/src/typecheck.rs @@ -150,6 +150,36 @@ pub fn tc_script(script: &mut ast::Script, source: &str) -> Result<()> { } } + let mut start_function: Option<&ast::Function> = None; + for f in &script.functions { + if f.start { + if !f.params.is_empty() || f.type_.is_some() { + Report::build(ReportKind::Error, (), f.span.start) + .with_message("Start function can't have params or a return value") + .with_label( + Label::new(f.span.clone()) + .with_message("Start function can't have params or a return value") + .with_color(Color::Red), + ) + .finish() + .eprint(Source::from(source)) + .unwrap(); + + result = Err(()); + } + if let Some(prev) = start_function { + result = report_duplicate_definition( + "Start function already defined", + &f.span, + &prev.span, + source, + ); + } else { + start_function = Some(f); + } + } + } + for data in &mut script.data { tc_const(&mut data.offset, source)?; if data.offset.type_ != Some(I32) {