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 type_: Option<Type>,
|
||||
pub value: Option<Expression<'a>>,
|
||||
pub defer: bool
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -104,6 +105,7 @@ impl<'a> From<Expr<'a>> for Expression<'a> {
|
||||
#[derive(Debug)]
|
||||
pub enum Expr<'a> {
|
||||
I32Const(i32),
|
||||
F32Const(f32),
|
||||
Variable {
|
||||
position: Position,
|
||||
name: &'a str,
|
||||
@@ -129,6 +131,11 @@ pub enum Expr<'a> {
|
||||
name: &'a str,
|
||||
value: Box<Expression<'a>>,
|
||||
},
|
||||
Cast {
|
||||
position: Position,
|
||||
value: Box<Expression<'a>>,
|
||||
type_: Type,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
|
||||
@@ -78,14 +78,31 @@ fn fold_expr(expr: &mut ast::Expression) {
|
||||
};
|
||||
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::Loop { ref mut block, .. } => fold_block(block),
|
||||
ast::Expr::BranchIf {
|
||||
ref mut 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>,
|
||||
locals: &'a HashMap<&'a str, u32>,
|
||||
labels: Vec<String>,
|
||||
deferred_inits: HashMap<&'a str, &'a ast::Expression<'a>>,
|
||||
}
|
||||
|
||||
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,
|
||||
locals: &locals,
|
||||
labels: vec![],
|
||||
deferred_inits: HashMap::new(),
|
||||
};
|
||||
|
||||
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)>) {
|
||||
match &expr.expr {
|
||||
ast::Expr::Variable { .. } | ast::Expr::I32Const(_) => (),
|
||||
ast::Expr::Variable { .. } | ast::Expr::I32Const(_) | ast::Expr::F32Const(_) => (),
|
||||
ast::Expr::BinOp { left, right, .. } => {
|
||||
collect_locals_expr(left, 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::LocalTee { value, .. } => collect_locals_expr(value, 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 {
|
||||
match stmt {
|
||||
ast::Statement::Expression(e) => {
|
||||
@@ -191,9 +194,13 @@ fn emit_block(ctx: &mut FunctionContext, block: &ast::Block) {
|
||||
}
|
||||
ast::Statement::LocalVariable(v) => {
|
||||
if let Some(ref val) = v.value {
|
||||
emit_expression(ctx, val);
|
||||
ctx.function
|
||||
.instruction(&Instruction::LocalSet(*ctx.locals.get(v.name).unwrap()));
|
||||
if v.defer {
|
||||
ctx.deferred_inits.insert(v.name, val);
|
||||
} else {
|
||||
emit_expression(ctx, val);
|
||||
ctx.function
|
||||
.instruction(&Instruction::LocalSet(*ctx.locals.get(v.name).unwrap()));
|
||||
}
|
||||
}
|
||||
}
|
||||
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 {
|
||||
ast::Expr::BinOp {
|
||||
left, op, right, ..
|
||||
@@ -253,8 +260,19 @@ fn emit_expression(ctx: &mut FunctionContext, expr: &ast::Expression) {
|
||||
(I32, Gt) => Instruction::I32GtS,
|
||||
(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!(),
|
||||
(F32, _) => todo!(),
|
||||
(F64, _) => todo!(),
|
||||
});
|
||||
}
|
||||
@@ -275,6 +293,9 @@ fn emit_expression(ctx: &mut FunctionContext, expr: &ast::Expression) {
|
||||
ast::Expr::I32Const(v) => {
|
||||
ctx.function.instruction(&Instruction::I32Const(*v));
|
||||
}
|
||||
ast::Expr::F32Const(v) => {
|
||||
ctx.function.instruction(&Instruction::F32Const(*v));
|
||||
}
|
||||
ast::Expr::LocalTee { name, value, .. } => {
|
||||
emit_expression(ctx, value);
|
||||
let index = ctx.locals.get(*name).unwrap();
|
||||
@@ -290,13 +311,31 @@ fn emit_expression(ctx: &mut FunctionContext, expr: &ast::Expression) {
|
||||
}
|
||||
ast::Expr::Variable { 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) {
|
||||
ctx.function.instruction(&Instruction::GlobalGet(*index));
|
||||
} else {
|
||||
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},
|
||||
error::VerboseError,
|
||||
multi::{fold_many0, many0, many1, separated_list0},
|
||||
sequence::{delimited, pair, preceded, separated_pair, terminated},
|
||||
sequence::{delimited, pair, preceded, separated_pair, terminated, tuple},
|
||||
Finish,
|
||||
};
|
||||
|
||||
@@ -182,21 +182,25 @@ fn statement(s: &str) -> IResult<ast::Statement> {
|
||||
|
||||
fn local_var(s: &str) -> IResult<ast::LocalVariable> {
|
||||
let (s, _) = ws(tag("let"))(s)?;
|
||||
let (s, position) = ws(position)(s)?;
|
||||
let (s, name) = identifier(s)?;
|
||||
let (s, type_) = opt(preceded(ws(char(':')), type_))(s)?;
|
||||
let (s, value) = opt(preceded(ws(char('=')), expression))(s)?;
|
||||
let (s, _) = ws(char(';'))(s)?;
|
||||
cut(move |s| {
|
||||
let (s, defer) = opt(ws(tag("defer")))(s)?;
|
||||
let (s, position) = ws(position)(s)?;
|
||||
let (s, name) = identifier(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((
|
||||
s,
|
||||
ast::LocalVariable {
|
||||
position,
|
||||
name: name,
|
||||
type_,
|
||||
value: value.map(|v| v.into()),
|
||||
},
|
||||
))
|
||||
Ok((
|
||||
s,
|
||||
ast::LocalVariable {
|
||||
position,
|
||||
name: name,
|
||||
type_,
|
||||
value: value.map(|v| v.into()),
|
||||
defer: defer.is_some()
|
||||
},
|
||||
))
|
||||
})(s)
|
||||
}
|
||||
|
||||
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()),
|
||||
},
|
||||
),
|
||||
map(integer, |v| ast::Expr::I32Const(v)),
|
||||
map(float, ast::Expr::F32Const),
|
||||
map(integer, ast::Expr::I32Const),
|
||||
map(ws(pair(position, identifier)), |(position, name)| {
|
||||
ast::Expr::Variable {
|
||||
position,
|
||||
@@ -266,12 +271,25 @@ fn branch_if(s: &str) -> IResult<ast::Expr> {
|
||||
})(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)?;
|
||||
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(
|
||||
pair(
|
||||
ws(pair(position, alt((char('*'), char('/'), char('%'))))),
|
||||
expression_atom,
|
||||
expression_cast,
|
||||
),
|
||||
move || init.take().unwrap(),
|
||||
|left, ((position, op), right)| {
|
||||
@@ -407,6 +425,13 @@ fn integer(s: &str) -> IResult<i32> {
|
||||
))(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> {
|
||||
ws(alt((
|
||||
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<()> {
|
||||
expr.type_ = match expr.expr {
|
||||
ast::Expr::I32Const(_) => Some(ast::Type::I32),
|
||||
ast::Expr::F32Const(_) => Some(ast::Type::F32),
|
||||
ast::Expr::BinOp {
|
||||
position,
|
||||
op,
|
||||
@@ -213,6 +214,20 @@ fn tc_expression<'a>(context: &mut Context<'a>, expr: &mut ast::Expression<'a>)
|
||||
}
|
||||
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(())
|
||||
}
|
||||
|
||||
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