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);
export fn tic(time: i32) {
cls(0);
cls(32);
let i: i32;
loop outer {
let lazy fi = i as f32 / 4 as f32;

View File

@@ -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;

View File

@@ -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<Type>,

View File

@@ -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<u8> {
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<u8> {
module.section(&global_section);
}
module.section(&exports);
if let Some(function_index) = start_index {
module.section(&StartSection { function_index });
}
module.section(&code);
}
@@ -613,7 +623,8 @@ fn emit_expression<'a>(ctx: &mut FunctionContext<'a>, expr: &'a ast::Expression)
}
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);

View File

@@ -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<char, Vec<(Token, Span)>, Error = Simple<char>> {
}
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<char, Vec<(Token, Span)>, Error = Simple<char>> {
"if" => Token::If,
"else" => Token::Else,
"return" => Token::Return,
"data" => Token::Data,
_ => 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 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<Token, ast::Script, Error = Simple<Token>> + 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<Token, ast::Script, Error = Simple<Token>> + 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<Token, ast::Script, Error = Simple<Token>> + 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<Token, ast::Script, Error = Simple<Token>> + 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

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