mirror of
https://github.com/exoticorn/curlywas.git
synced 2026-01-20 11:46:43 +01:00
implement support for start function
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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>,
|
||||||
|
|||||||
17
src/emit.rs
17
src/emit.rs
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -611,9 +621,10 @@ fn emit_expression<'a>(ctx: &mut FunctionContext<'a>, expr: &'a ast::Expression)
|
|||||||
ctx.labels.pop();
|
ctx.labels.pop();
|
||||||
ctx.function.instruction(&Instruction::End);
|
ctx.function.instruction(&Instruction::End);
|
||||||
}
|
}
|
||||||
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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user