From 23d926dbb3ad17859a4f3e165bc617ce3083eb75 Mon Sep 17 00:00:00 2001 From: Dennis Ranke Date: Wed, 27 Oct 2021 20:03:23 +0200 Subject: [PATCH] implement some initial f32 support --- src/ast.rs | 7 ++++++ src/constfold.rs | 19 ++++++++++++++- src/emit.rs | 55 ++++++++++++++++++++++++++++++++++++------- src/parser.rs | 61 ++++++++++++++++++++++++++++++++++-------------- src/typecheck.rs | 15 ++++++++++++ warptunnel.hw | 16 +++++++++++++ 6 files changed, 146 insertions(+), 27 deletions(-) create mode 100644 warptunnel.hw diff --git a/src/ast.rs b/src/ast.rs index a9a27a9..dc52134 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -87,6 +87,7 @@ pub struct LocalVariable<'a> { pub name: &'a str, pub type_: Option, pub value: Option>, + pub defer: bool } #[derive(Debug)] @@ -104,6 +105,7 @@ impl<'a> From> 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>, }, + Cast { + position: Position, + value: Box>, + type_: Type, + }, } #[derive(Debug, Clone, Copy)] diff --git a/src/constfold.rs b/src/constfold.rs index 2a2756b..fd2c216 100644 --- a/src/constfold.rs +++ b/src/constfold.rs @@ -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), } } diff --git a/src/emit.rs b/src/emit.rs index dbb3ba4..9e2974c 100644 --- a/src/emit.rs +++ b/src/emit.rs @@ -111,6 +111,7 @@ struct FunctionContext<'a> { globals: &'a HashMap<&'a str, u32>, locals: &'a HashMap<&'a str, u32>, labels: Vec, + 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); + } + } } } diff --git a/src/parser.rs b/src/parser.rs index a7e14ef..14b28fe 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -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 { fn local_var(s: &str) -> IResult { 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 { @@ -236,7 +240,8 @@ fn expression_atom(s: &str) -> IResult { 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 { })(s) } -fn expression_product(s: &str) -> IResult { +fn expression_cast(s: &str) -> IResult { 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 { + 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 { ))(s) } +fn float(s: &str) -> IResult { + ws(map_res( + recognize(tuple((opt(char('-')), digit1, char('.'), digit1))), + |n: &str| n.parse::(), + ))(s) +} + fn type_(s: &str) -> IResult { ws(alt(( value(ast::Type::I32, tag("i32")), diff --git a/src/typecheck.rs b/src/typecheck.rs index 8f25431..a239082 100644 --- a/src/typecheck.rs +++ b/src/typecheck.rs @@ -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(()) } diff --git a/warptunnel.hw b/warptunnel.hw new file mode 100644 index 0000000..c31f9c9 --- /dev/null +++ b/warptunnel.hw @@ -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 + } +} \ No newline at end of file