implement support for start function

This commit is contained in:
2021-11-13 22:27:07 +01:00
parent 29b8c04700
commit e23b98c1ab
6 changed files with 53 additions and 22 deletions

View File

@@ -5,7 +5,7 @@ import "env.sin" fn sin(f32) -> f32;
import "env.cls" fn cls(i32); import "env.cls" fn cls(i32);
export fn tic(time: i32) { export fn tic(time: i32) {
cls(0); cls(32);
let i: i32; let i: i32;
loop outer { loop outer {
let lazy fi = i as f32 / 4 as f32; let lazy fi = i as f32 / 4 as f32;

View File

@@ -1,6 +1,5 @@
import "env.memory" memory(4); import "env.memory" memory(4);
import "env.sin" fn sin(f32) -> f32; import "env.sin" fn sin(f32) -> f32;
import "env.atan2" fn atan2(f32, f32) -> f32;
export fn tic(time: i32) { export fn tic(time: i32) {
let i: i32; let i: i32;

View File

@@ -53,6 +53,7 @@ pub struct GlobalVar {
pub struct Function { pub struct Function {
pub span: Span, pub span: Span,
pub export: bool, pub export: bool,
pub start: bool,
pub name: String, pub name: String,
pub params: Vec<(String, Type)>, pub params: Vec<(String, Type)>,
pub type_: Option<Type>, pub type_: Option<Type>,

View File

@@ -3,7 +3,7 @@ use std::collections::HashMap;
use wasm_encoder::{ use wasm_encoder::{
BlockType, CodeSection, DataSection, EntityType, Export, ExportSection, Function, BlockType, CodeSection, DataSection, EntityType, Export, ExportSection, Function,
FunctionSection, GlobalSection, GlobalType, ImportSection, Instruction, MemArg, MemoryType, FunctionSection, GlobalSection, GlobalType, ImportSection, Instruction, MemArg, MemoryType,
Module, TypeSection, ValType, Module, StartSection, TypeSection, ValType,
}; };
use crate::{ast, intrinsics::Intrinsics}; use crate::{ast, intrinsics::Intrinsics};
@@ -94,9 +94,14 @@ pub fn emit(script: &ast::Script) -> Vec<u8> {
let mut exports = ExportSection::new(); let mut exports = ExportSection::new();
let mut code = CodeSection::new(); let mut code = CodeSection::new();
let mut start_index = None;
let intrinsics = Intrinsics::new(); let intrinsics = Intrinsics::new();
for func in script.functions.iter() { 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); function_map.insert(func.name.clone(), function_map.len() as u32);
} }
@@ -118,6 +123,11 @@ pub fn emit(script: &ast::Script) -> Vec<u8> {
module.section(&global_section); module.section(&global_section);
} }
module.section(&exports); module.section(&exports);
if let Some(function_index) = start_index {
module.section(&StartSection { function_index });
}
module.section(&code); module.section(&code);
} }
@@ -613,7 +623,8 @@ fn emit_expression<'a>(ctx: &mut FunctionContext<'a>, expr: &'a ast::Expression)
} }
ast::Expr::LabelBlock { label, block } => { ast::Expr::LabelBlock { label, block } => {
ctx.labels.push(label.to_string()); 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); emit_expression(ctx, block);
ctx.labels.pop(); ctx.labels.pop();
ctx.function.instruction(&Instruction::End); ctx.function.instruction(&Instruction::End);

View File

@@ -6,11 +6,8 @@ use std::fmt;
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
enum Token { enum Token {
Import,
Export,
Fn, Fn,
Let, Let,
Memory,
Global, Global,
Mut, Mut,
Loop, Loop,
@@ -24,7 +21,6 @@ enum Token {
If, If,
Else, Else,
Return, Return,
Data,
Ident(String), Ident(String),
Str(String), Str(String),
Int(i32), Int(i32),
@@ -38,11 +34,8 @@ enum Token {
impl fmt::Display for Token { impl fmt::Display for Token {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
Token::Import => write!(f, "import"),
Token::Export => write!(f, "export"),
Token::Fn => write!(f, "fn"), Token::Fn => write!(f, "fn"),
Token::Let => write!(f, "let"), Token::Let => write!(f, "let"),
Token::Memory => write!(f, "memory"),
Token::Global => write!(f, "global"), Token::Global => write!(f, "global"),
Token::Mut => write!(f, "mut"), Token::Mut => write!(f, "mut"),
Token::Loop => write!(f, "loop"), Token::Loop => write!(f, "loop"),
@@ -56,7 +49,6 @@ impl fmt::Display for Token {
Token::If => write!(f, "if"), Token::If => write!(f, "if"),
Token::Else => write!(f, "else"), Token::Else => write!(f, "else"),
Token::Return => write!(f, "return"), Token::Return => write!(f, "return"),
Token::Data => write!(f, "data"),
Token::Ident(s) => write!(f, "{}", s), Token::Ident(s) => write!(f, "{}", s),
Token::Str(s) => write!(f, "{:?}", s), Token::Str(s) => write!(f, "{:?}", s),
Token::Int(v) => write!(f, "{}", v), Token::Int(v) => write!(f, "{}", v),
@@ -231,11 +223,8 @@ fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = Simple<char>> {
} }
let ident = ident().map(|ident: String| match ident.as_str() { let ident = ident().map(|ident: String| match ident.as_str() {
"import" => Token::Import,
"export" => Token::Export,
"fn" => Token::Fn, "fn" => Token::Fn,
"let" => Token::Let, "let" => Token::Let,
"memory" => Token::Memory,
"global" => Token::Global, "global" => Token::Global,
"mut" => Token::Mut, "mut" => Token::Mut,
"loop" => Token::Loop, "loop" => Token::Loop,
@@ -249,7 +238,6 @@ fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = Simple<char>> {
"if" => Token::If, "if" => Token::If,
"else" => Token::Else, "else" => Token::Else,
"return" => Token::Return, "return" => Token::Return,
"data" => Token::Data,
_ => Token::Ident(ident), _ => Token::Ident(ident),
}); });
@@ -755,7 +743,7 @@ fn script_parser() -> impl Parser<Token, ast::Script, Error = Simple<Token>> + C
let expression = expression_out.unwrap(); let expression = expression_out.unwrap();
let top_level_item = { let top_level_item = {
let import_memory = just(Token::Memory) let import_memory = just(Token::Ident("memory".to_string()))
.ignore_then( .ignore_then(
integer integer
.clone() .clone()
@@ -795,7 +783,7 @@ fn script_parser() -> impl Parser<Token, ast::Script, Error = Simple<Token>> + C
}) })
.boxed(); .boxed();
let import = just(Token::Import) let import = just(Token::Ident("import".to_string()))
.ignore_then(string.clone()) .ignore_then(string.clone())
.then(import_memory.or(import_global).or(import_function)) .then(import_memory.or(import_global).or(import_function))
.then_ignore(just(Token::Ctrl(';'))) .then_ignore(just(Token::Ctrl(';')))
@@ -814,8 +802,9 @@ fn script_parser() -> impl Parser<Token, ast::Script, Error = Simple<Token>> + C
.then(type_parser()) .then(type_parser())
.boxed(); .boxed();
let function = just(Token::Export) let function = just(Token::Ident("export".to_string()))
.or_not() .or_not()
.then(just(Token::Ident("start".to_string())).or_not())
.then_ignore(just(Token::Fn)) .then_ignore(just(Token::Fn))
.then(identifier.clone()) .then(identifier.clone())
.then( .then(
@@ -829,11 +818,12 @@ fn script_parser() -> impl Parser<Token, ast::Script, Error = Simple<Token>> + C
.or_not(), .or_not(),
) )
.then(block.clone()) .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 { ast::TopLevelItem::Function(ast::Function {
span, span,
params, params,
export: export.is_some(), export: export.is_some(),
start: start.is_some(),
name, name,
type_, type_,
body, body,
@@ -875,7 +865,7 @@ fn script_parser() -> impl Parser<Token, ast::Script, Error = Simple<Token>> + C
let data_string = string.map(|s| ast::DataValues::String(s)); 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()) .ignore_then(expression.clone())
.then( .then(
data_i8 data_i8

View File

@@ -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 { for data in &mut script.data {
tc_const(&mut data.offset, source)?; tc_const(&mut data.offset, source)?;
if data.offset.type_ != Some(I32) { if data.offset.type_ != Some(I32) {