mirror of
https://github.com/exoticorn/curlywas.git
synced 2026-01-20 11:46:43 +01:00
implement some initial f32 support
This commit is contained in:
@@ -87,6 +87,7 @@ pub struct LocalVariable<'a> {
|
|||||||
pub name: &'a str,
|
pub name: &'a str,
|
||||||
pub type_: Option<Type>,
|
pub type_: Option<Type>,
|
||||||
pub value: Option<Expression<'a>>,
|
pub value: Option<Expression<'a>>,
|
||||||
|
pub defer: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -104,6 +105,7 @@ impl<'a> From<Expr<'a>> for Expression<'a> {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Expr<'a> {
|
pub enum Expr<'a> {
|
||||||
I32Const(i32),
|
I32Const(i32),
|
||||||
|
F32Const(f32),
|
||||||
Variable {
|
Variable {
|
||||||
position: Position,
|
position: Position,
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
@@ -129,6 +131,11 @@ pub enum Expr<'a> {
|
|||||||
name: &'a str,
|
name: &'a str,
|
||||||
value: Box<Expression<'a>>,
|
value: Box<Expression<'a>>,
|
||||||
},
|
},
|
||||||
|
Cast {
|
||||||
|
position: Position,
|
||||||
|
value: Box<Expression<'a>>,
|
||||||
|
type_: Type,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
|||||||
@@ -78,14 +78,31 @@ fn fold_expr(expr: &mut ast::Expression) {
|
|||||||
};
|
};
|
||||||
expr.expr = ast::Expr::I32Const(result);
|
expr.expr = ast::Expr::I32Const(result);
|
||||||
}
|
}
|
||||||
|
(&ast::Expr::F32Const(left), &ast::Expr::F32Const(right)) => {
|
||||||
|
use ast::Expr::*;
|
||||||
|
expr.expr = match op {
|
||||||
|
Add => F32Const(left + right),
|
||||||
|
Sub => F32Const(left - right),
|
||||||
|
Mul => F32Const(left * right),
|
||||||
|
Div => F32Const(left / right),
|
||||||
|
Rem | And | Or | Xor => return,
|
||||||
|
Eq => I32Const((left == right) as i32),
|
||||||
|
Ne => I32Const((left != right) as i32),
|
||||||
|
Lt => I32Const((left < right) as i32),
|
||||||
|
Le => I32Const((left <= right) as i32),
|
||||||
|
Gt => I32Const((left > right) as i32),
|
||||||
|
Ge => I32Const((left >= right) as i32),
|
||||||
|
};
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::Expr::I32Const(_) | ast::Expr::Variable { .. } => (),
|
ast::Expr::I32Const(_) | ast::Expr::F32Const(_) | ast::Expr::Variable { .. } => (),
|
||||||
ast::Expr::LocalTee { ref mut value, .. } => fold_expr(value),
|
ast::Expr::LocalTee { ref mut value, .. } => fold_expr(value),
|
||||||
ast::Expr::Loop { ref mut block, .. } => fold_block(block),
|
ast::Expr::Loop { ref mut block, .. } => fold_block(block),
|
||||||
ast::Expr::BranchIf {
|
ast::Expr::BranchIf {
|
||||||
ref mut condition, ..
|
ref mut condition, ..
|
||||||
} => fold_expr(condition),
|
} => fold_expr(condition),
|
||||||
|
ast::Expr::Cast { ref mut value, .. } => fold_expr(value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
55
src/emit.rs
55
src/emit.rs
@@ -111,6 +111,7 @@ struct FunctionContext<'a> {
|
|||||||
globals: &'a HashMap<&'a str, u32>,
|
globals: &'a HashMap<&'a str, u32>,
|
||||||
locals: &'a HashMap<&'a str, u32>,
|
locals: &'a HashMap<&'a str, u32>,
|
||||||
labels: Vec<String>,
|
labels: Vec<String>,
|
||||||
|
deferred_inits: HashMap<&'a str, &'a ast::Expression<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_function(func: &ast::Function, globals: &HashMap<&str, u32>) -> Function {
|
fn emit_function(func: &ast::Function, globals: &HashMap<&str, u32>) -> Function {
|
||||||
@@ -131,6 +132,7 @@ fn emit_function(func: &ast::Function, globals: &HashMap<&str, u32>) -> Function
|
|||||||
globals,
|
globals,
|
||||||
locals: &locals,
|
locals: &locals,
|
||||||
labels: vec![],
|
labels: vec![],
|
||||||
|
deferred_inits: HashMap::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
emit_block(&mut context, &func.body);
|
emit_block(&mut context, &func.body);
|
||||||
@@ -169,7 +171,7 @@ fn collect_locals<'a>(block: &ast::Block<'a>, locals: &mut Vec<(&'a str, ast::Ty
|
|||||||
|
|
||||||
fn collect_locals_expr<'a>(expr: &ast::Expression<'a>, locals: &mut Vec<(&'a str, ast::Type)>) {
|
fn collect_locals_expr<'a>(expr: &ast::Expression<'a>, locals: &mut Vec<(&'a str, ast::Type)>) {
|
||||||
match &expr.expr {
|
match &expr.expr {
|
||||||
ast::Expr::Variable { .. } | ast::Expr::I32Const(_) => (),
|
ast::Expr::Variable { .. } | ast::Expr::I32Const(_) | ast::Expr::F32Const(_) => (),
|
||||||
ast::Expr::BinOp { left, right, .. } => {
|
ast::Expr::BinOp { left, right, .. } => {
|
||||||
collect_locals_expr(left, locals);
|
collect_locals_expr(left, locals);
|
||||||
collect_locals_expr(right, locals);
|
collect_locals_expr(right, locals);
|
||||||
@@ -177,10 +179,11 @@ fn collect_locals_expr<'a>(expr: &ast::Expression<'a>, locals: &mut Vec<(&'a str
|
|||||||
ast::Expr::BranchIf { condition, .. } => collect_locals_expr(condition, locals),
|
ast::Expr::BranchIf { condition, .. } => collect_locals_expr(condition, locals),
|
||||||
ast::Expr::LocalTee { value, .. } => collect_locals_expr(value, locals),
|
ast::Expr::LocalTee { value, .. } => collect_locals_expr(value, locals),
|
||||||
ast::Expr::Loop { block, .. } => collect_locals(block, locals),
|
ast::Expr::Loop { block, .. } => collect_locals(block, locals),
|
||||||
|
ast::Expr::Cast { value, .. } => collect_locals_expr(value, locals),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_block(ctx: &mut FunctionContext, block: &ast::Block) {
|
fn emit_block<'a>(ctx: &mut FunctionContext<'a>, block: &'a ast::Block) {
|
||||||
for stmt in &block.statements {
|
for stmt in &block.statements {
|
||||||
match stmt {
|
match stmt {
|
||||||
ast::Statement::Expression(e) => {
|
ast::Statement::Expression(e) => {
|
||||||
@@ -191,9 +194,13 @@ fn emit_block(ctx: &mut FunctionContext, block: &ast::Block) {
|
|||||||
}
|
}
|
||||||
ast::Statement::LocalVariable(v) => {
|
ast::Statement::LocalVariable(v) => {
|
||||||
if let Some(ref val) = v.value {
|
if let Some(ref val) = v.value {
|
||||||
emit_expression(ctx, val);
|
if v.defer {
|
||||||
ctx.function
|
ctx.deferred_inits.insert(v.name, val);
|
||||||
.instruction(&Instruction::LocalSet(*ctx.locals.get(v.name).unwrap()));
|
} else {
|
||||||
|
emit_expression(ctx, val);
|
||||||
|
ctx.function
|
||||||
|
.instruction(&Instruction::LocalSet(*ctx.locals.get(v.name).unwrap()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::Statement::Poke {
|
ast::Statement::Poke {
|
||||||
@@ -228,7 +235,7 @@ fn emit_block(ctx: &mut FunctionContext, block: &ast::Block) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_expression(ctx: &mut FunctionContext, expr: &ast::Expression) {
|
fn emit_expression<'a>(ctx: &mut FunctionContext<'a>, expr: &'a ast::Expression) {
|
||||||
match &expr.expr {
|
match &expr.expr {
|
||||||
ast::Expr::BinOp {
|
ast::Expr::BinOp {
|
||||||
left, op, right, ..
|
left, op, right, ..
|
||||||
@@ -253,8 +260,19 @@ fn emit_expression(ctx: &mut FunctionContext, expr: &ast::Expression) {
|
|||||||
(I32, Gt) => Instruction::I32GtS,
|
(I32, Gt) => Instruction::I32GtS,
|
||||||
(I32, Ge) => Instruction::I32GeS,
|
(I32, Ge) => Instruction::I32GeS,
|
||||||
|
|
||||||
|
(F32, Add) => Instruction::F32Add,
|
||||||
|
(F32, Sub) => Instruction::F32Sub,
|
||||||
|
(F32, Mul) => Instruction::F32Mul,
|
||||||
|
(F32, Div) => Instruction::F32Div,
|
||||||
|
(F32, Rem | And | Or | Xor) => unreachable!(),
|
||||||
|
(F32, Eq) => Instruction::F32Eq,
|
||||||
|
(F32, Ne) => Instruction::F32Neq,
|
||||||
|
(F32, Lt) => Instruction::F32Lt,
|
||||||
|
(F32, Le) => Instruction::F32Le,
|
||||||
|
(F32, Gt) => Instruction::F32Gt,
|
||||||
|
(F32, Ge) => Instruction::F32Ge,
|
||||||
|
|
||||||
(I64, _) => todo!(),
|
(I64, _) => todo!(),
|
||||||
(F32, _) => todo!(),
|
|
||||||
(F64, _) => todo!(),
|
(F64, _) => todo!(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -275,6 +293,9 @@ fn emit_expression(ctx: &mut FunctionContext, expr: &ast::Expression) {
|
|||||||
ast::Expr::I32Const(v) => {
|
ast::Expr::I32Const(v) => {
|
||||||
ctx.function.instruction(&Instruction::I32Const(*v));
|
ctx.function.instruction(&Instruction::I32Const(*v));
|
||||||
}
|
}
|
||||||
|
ast::Expr::F32Const(v) => {
|
||||||
|
ctx.function.instruction(&Instruction::F32Const(*v));
|
||||||
|
}
|
||||||
ast::Expr::LocalTee { name, value, .. } => {
|
ast::Expr::LocalTee { name, value, .. } => {
|
||||||
emit_expression(ctx, value);
|
emit_expression(ctx, value);
|
||||||
let index = ctx.locals.get(*name).unwrap();
|
let index = ctx.locals.get(*name).unwrap();
|
||||||
@@ -290,13 +311,31 @@ fn emit_expression(ctx: &mut FunctionContext, expr: &ast::Expression) {
|
|||||||
}
|
}
|
||||||
ast::Expr::Variable { name, .. } => {
|
ast::Expr::Variable { name, .. } => {
|
||||||
if let Some(index) = ctx.locals.get(*name) {
|
if let Some(index) = ctx.locals.get(*name) {
|
||||||
ctx.function.instruction(&Instruction::LocalGet(*index));
|
if let Some(expr) = ctx.deferred_inits.remove(*name) {
|
||||||
|
emit_expression(ctx, expr);
|
||||||
|
ctx.function.instruction(&Instruction::LocalTee(*index));
|
||||||
|
} else {
|
||||||
|
ctx.function.instruction(&Instruction::LocalGet(*index));
|
||||||
|
}
|
||||||
} else if let Some(index) = ctx.globals.get(*name) {
|
} else if let Some(index) = ctx.globals.get(*name) {
|
||||||
ctx.function.instruction(&Instruction::GlobalGet(*index));
|
ctx.function.instruction(&Instruction::GlobalGet(*index));
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ast::Expr::Cast { value, type_, .. } => {
|
||||||
|
emit_expression(ctx, value);
|
||||||
|
use ast::Type::*;
|
||||||
|
let inst = match (value.type_.unwrap(), *type_) {
|
||||||
|
(t1, t2) if t1 == t2 => None,
|
||||||
|
(I32, F32) => Some(Instruction::F32ConvertI32S),
|
||||||
|
(F32, I32) => Some(Instruction::I32TruncF32S),
|
||||||
|
_ => todo!(),
|
||||||
|
};
|
||||||
|
if let Some(inst) = inst {
|
||||||
|
ctx.function.instruction(&inst);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use nom::{
|
|||||||
combinator::{self, cut, map, map_res, not, opt, peek, recognize, value},
|
combinator::{self, cut, map, map_res, not, opt, peek, recognize, value},
|
||||||
error::VerboseError,
|
error::VerboseError,
|
||||||
multi::{fold_many0, many0, many1, separated_list0},
|
multi::{fold_many0, many0, many1, separated_list0},
|
||||||
sequence::{delimited, pair, preceded, separated_pair, terminated},
|
sequence::{delimited, pair, preceded, separated_pair, terminated, tuple},
|
||||||
Finish,
|
Finish,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -182,21 +182,25 @@ fn statement(s: &str) -> IResult<ast::Statement> {
|
|||||||
|
|
||||||
fn local_var(s: &str) -> IResult<ast::LocalVariable> {
|
fn local_var(s: &str) -> IResult<ast::LocalVariable> {
|
||||||
let (s, _) = ws(tag("let"))(s)?;
|
let (s, _) = ws(tag("let"))(s)?;
|
||||||
let (s, position) = ws(position)(s)?;
|
cut(move |s| {
|
||||||
let (s, name) = identifier(s)?;
|
let (s, defer) = opt(ws(tag("defer")))(s)?;
|
||||||
let (s, type_) = opt(preceded(ws(char(':')), type_))(s)?;
|
let (s, position) = ws(position)(s)?;
|
||||||
let (s, value) = opt(preceded(ws(char('=')), expression))(s)?;
|
let (s, name) = identifier(s)?;
|
||||||
let (s, _) = ws(char(';'))(s)?;
|
let (s, type_) = opt(preceded(ws(char(':')), type_))(s)?;
|
||||||
|
let (s, value) = opt(preceded(ws(char('=')), expression))(s)?;
|
||||||
|
let (s, _) = ws(char(';'))(s)?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
s,
|
s,
|
||||||
ast::LocalVariable {
|
ast::LocalVariable {
|
||||||
position,
|
position,
|
||||||
name: name,
|
name: name,
|
||||||
type_,
|
type_,
|
||||||
value: value.map(|v| v.into()),
|
value: value.map(|v| v.into()),
|
||||||
},
|
defer: defer.is_some()
|
||||||
))
|
},
|
||||||
|
))
|
||||||
|
})(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mem_location(s: &str) -> IResult<ast::MemoryLocation> {
|
fn mem_location(s: &str) -> IResult<ast::MemoryLocation> {
|
||||||
@@ -236,7 +240,8 @@ fn expression_atom(s: &str) -> IResult<ast::Expr> {
|
|||||||
value: Box::new(value.into()),
|
value: Box::new(value.into()),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
map(integer, |v| ast::Expr::I32Const(v)),
|
map(float, ast::Expr::F32Const),
|
||||||
|
map(integer, ast::Expr::I32Const),
|
||||||
map(ws(pair(position, identifier)), |(position, name)| {
|
map(ws(pair(position, identifier)), |(position, name)| {
|
||||||
ast::Expr::Variable {
|
ast::Expr::Variable {
|
||||||
position,
|
position,
|
||||||
@@ -266,12 +271,25 @@ fn branch_if(s: &str) -> IResult<ast::Expr> {
|
|||||||
})(s)
|
})(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expression_product(s: &str) -> IResult<ast::Expr> {
|
fn expression_cast(s: &str) -> IResult<ast::Expr> {
|
||||||
let (s, mut init) = map(expression_atom, Some)(s)?;
|
let (s, mut init) = map(expression_atom, Some)(s)?;
|
||||||
|
fold_many0(
|
||||||
|
pair(ws(terminated(position, tag("as"))), type_),
|
||||||
|
move || init.take().unwrap(),
|
||||||
|
|value, (position, type_)| ast::Expr::Cast {
|
||||||
|
position,
|
||||||
|
value: Box::new(value.into()),
|
||||||
|
type_,
|
||||||
|
},
|
||||||
|
)(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expression_product(s: &str) -> IResult<ast::Expr> {
|
||||||
|
let (s, mut init) = map(expression_cast, Some)(s)?;
|
||||||
fold_many0(
|
fold_many0(
|
||||||
pair(
|
pair(
|
||||||
ws(pair(position, alt((char('*'), char('/'), char('%'))))),
|
ws(pair(position, alt((char('*'), char('/'), char('%'))))),
|
||||||
expression_atom,
|
expression_cast,
|
||||||
),
|
),
|
||||||
move || init.take().unwrap(),
|
move || init.take().unwrap(),
|
||||||
|left, ((position, op), right)| {
|
|left, ((position, op), right)| {
|
||||||
@@ -407,6 +425,13 @@ fn integer(s: &str) -> IResult<i32> {
|
|||||||
))(s)
|
))(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn float(s: &str) -> IResult<f32> {
|
||||||
|
ws(map_res(
|
||||||
|
recognize(tuple((opt(char('-')), digit1, char('.'), digit1))),
|
||||||
|
|n: &str| n.parse::<f32>(),
|
||||||
|
))(s)
|
||||||
|
}
|
||||||
|
|
||||||
fn type_(s: &str) -> IResult<ast::Type> {
|
fn type_(s: &str) -> IResult<ast::Type> {
|
||||||
ws(alt((
|
ws(alt((
|
||||||
value(ast::Type::I32, tag("i32")),
|
value(ast::Type::I32, tag("i32")),
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ fn tc_block<'a>(context: &mut Context<'a>, block: &mut ast::Block<'a>) -> Result
|
|||||||
fn tc_expression<'a>(context: &mut Context<'a>, expr: &mut ast::Expression<'a>) -> Result<()> {
|
fn tc_expression<'a>(context: &mut Context<'a>, expr: &mut ast::Expression<'a>) -> Result<()> {
|
||||||
expr.type_ = match expr.expr {
|
expr.type_ = match expr.expr {
|
||||||
ast::Expr::I32Const(_) => Some(ast::Type::I32),
|
ast::Expr::I32Const(_) => Some(ast::Type::I32),
|
||||||
|
ast::Expr::F32Const(_) => Some(ast::Type::F32),
|
||||||
ast::Expr::BinOp {
|
ast::Expr::BinOp {
|
||||||
position,
|
position,
|
||||||
op,
|
op,
|
||||||
@@ -213,6 +214,20 @@ fn tc_expression<'a>(context: &mut Context<'a>, expr: &mut ast::Expression<'a>)
|
|||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
ast::Expr::Cast {
|
||||||
|
position,
|
||||||
|
ref mut value,
|
||||||
|
type_,
|
||||||
|
} => {
|
||||||
|
tc_expression(context, value)?;
|
||||||
|
if value.type_.is_none() {
|
||||||
|
return Err(Error {
|
||||||
|
position,
|
||||||
|
message: "Cannot cast void".into(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Some(type_)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
16
warptunnel.hw
Normal file
16
warptunnel.hw
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import "uw8.ram" memory(2);
|
||||||
|
import "uw8.time" global mut time: i32;
|
||||||
|
|
||||||
|
export fn tic() {
|
||||||
|
let i: i32;
|
||||||
|
loop pixels {
|
||||||
|
let defer x = (i % 320) as f32 - 160.1;
|
||||||
|
let defer y = (i / 320 - 128) as f32;
|
||||||
|
let defer dist = 10000.0 / (x*x + y*y);
|
||||||
|
let defer t = time as f32 / 20 as f32;
|
||||||
|
|
||||||
|
i?120 = (x * dist + t) as i32 ^ (y * dist + t) as i32;
|
||||||
|
|
||||||
|
branch_if (i := i + 1) < 320*256: pixels
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user