diff --git a/examples/microw8/random.cwa b/examples/microw8/random.cwa index 3e41ad0..b5d3e7d 100644 --- a/examples/microw8/random.cwa +++ b/examples/microw8/random.cwa @@ -9,14 +9,14 @@ fn random() -> i32 { fn random64() -> i64 { let state: i64; randomState = (state := ( - state := randomState ^ (randomState >> 12i64) + state := randomState ^ (randomState #>> 12i64) ) ^ (state << 25i64) - ) ^ (state >> 27i64); + ) ^ (state #>> 27i64); randomState * 2685821657736338717i64 } fn randomf() -> f32 { - f32.reinterpret_i32(1065353216 | (random() >> 9)) - 1 as f32 + f32.reinterpret_i32(1065353216 | (random() #>> 9)) - 1 as f32 } fn seed(s: i32) { @@ -28,8 +28,8 @@ fn seed(s: i32) { export fn tic(time: i32) { let i: i32; loop pixels { - seed(i + (time / 100) * 320); - i?120 = (randomf() * 256 as f32 + time as f32 / 10 as f32) as i32; + seed(i + (time / 10) * 320); + i?120 = (randomf() * 256 as f32 + time as f32 / 10 as f32) as i32 & 128; branch_if (i := i + 1) < 320*256: pixels } } diff --git a/examples/wasm4/skipahead.cwa b/examples/wasm4/skipahead.cwa index af980fc..8c8596a 100644 --- a/examples/wasm4/skipahead.cwa +++ b/examples/wasm4/skipahead.cwa @@ -14,7 +14,7 @@ global mut s: f32 = 0.0; global mut f: f32 = 0.0; fn rng(state: i32) -> i32 { - 94614859 * (state ^ (state >> 17)) + 94614859 * (state ^ (state #>> 17)) } fn set_color(color: i32) -> i32 { @@ -35,7 +35,7 @@ export fn update() { loop lines { ?(8003-y) = (score := score / 10) % 10 + 48; let defer z = (4000 / (y := y + 1) + pz) / 20; - let defer x = (rng(rng(rng(rng(z)))) >>> 30) as f32 - px; + let defer x = (rng(rng(rng(rng(z)))) >> 30) as f32 - px; let defer w = 9 as f32 / sqrt(z as f32); let defer rx = 80 + (y as f32 * x) as i32; let defer rw = (y as f32 * w) as i32; @@ -47,10 +47,10 @@ export fn update() { if y == 120 & py > zero { if x < -w | x > zero { - if pad & 2 { // (*) - pz = 30; // (*) - px = zero; // (*) - } // (*) + if pad & 2 { + pz = 30; + px = zero; + } return; } py = zero; diff --git a/src/ast.rs b/src/ast.rs index 9dd4455..26e6048 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -170,19 +170,25 @@ pub enum BinOp { Sub, Mul, Div, + DivU, Rem, + RemU, And, Or, Xor, Eq, Ne, Gt, + GtU, Ge, + GeU, Lt, + LtU, Le, - Lsl, - Lsr, - Asr, + LeU, + Shl, + ShrU, + ShrS, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/src/constfold.rs b/src/constfold.rs index 86aba5c..8cc3fce 100644 --- a/src/constfold.rs +++ b/src/constfold.rs @@ -18,13 +18,16 @@ fn fold_mem_location(mem_location: &mut ast::MemoryLocation) { fn fold_expr(expr: &mut ast::Expression) { use ast::BinOp::*; match expr.expr { - ast::Expr::Block { ref mut statements, ref mut final_expression} => { + ast::Expr::Block { + ref mut statements, + ref mut final_expression, + } => { for stmt in statements { fold_expr(stmt); } if let Some(ref mut expr) = final_expression { fold_expr(expr); - } + } } ast::Expr::Let { ref mut value, .. } => { if let Some(ref mut expr) = value { @@ -43,13 +46,25 @@ fn fold_expr(expr: &mut ast::Expression) { ast::Expr::UnaryOp { op, ref mut value } => { fold_expr(value); let result = match (op, &value.expr) { - (ast::UnaryOp::Negate, ast::Expr::I32Const(value)) => Some(ast::Expr::I32Const(-*value)), - (ast::UnaryOp::Negate, ast::Expr::I64Const(value)) => Some(ast::Expr::I64Const(-*value)), - (ast::UnaryOp::Negate, ast::Expr::F32Const(value)) => Some(ast::Expr::F32Const(-*value)), - (ast::UnaryOp::Negate, ast::Expr::F64Const(value)) => Some(ast::Expr::F64Const(-*value)), - (ast::UnaryOp::Not, ast::Expr::I32Const(value)) => Some(ast::Expr::I32Const((*value == 0) as i32)), - (ast::UnaryOp::Not, ast::Expr::I64Const(value)) => Some(ast::Expr::I32Const((*value == 0) as i32)), - _ => None + (ast::UnaryOp::Negate, ast::Expr::I32Const(value)) => { + Some(ast::Expr::I32Const(-*value)) + } + (ast::UnaryOp::Negate, ast::Expr::I64Const(value)) => { + Some(ast::Expr::I64Const(-*value)) + } + (ast::UnaryOp::Negate, ast::Expr::F32Const(value)) => { + Some(ast::Expr::F32Const(-*value)) + } + (ast::UnaryOp::Negate, ast::Expr::F64Const(value)) => { + Some(ast::Expr::F64Const(-*value)) + } + (ast::UnaryOp::Not, ast::Expr::I32Const(value)) => { + Some(ast::Expr::I32Const((*value == 0) as i32)) + } + (ast::UnaryOp::Not, ast::Expr::I64Const(value)) => { + Some(ast::Expr::I32Const((*value == 0) as i32)) + } + _ => None, }; if let Some(result) = result { expr.expr = result; @@ -76,6 +91,13 @@ fn fold_expr(expr: &mut ast::Expression) { return; } } + DivU => { + if let Some(result) = (left as u32).checked_div(right as u32) { + result as i32 + } else { + return; + } + } Rem => { if let Some(result) = left.checked_rem(right) { result @@ -83,24 +105,35 @@ fn fold_expr(expr: &mut ast::Expression) { return; } } + RemU => { + if let Some(result) = (left as u32).checked_rem(right as u32) { + result as i32 + } else { + return; + } + } And => left & right, Or => left | right, Xor => left ^ right, Eq => (left == right) as i32, Ne => (left != right) as i32, Lt => (left < right) as i32, + LtU => ((left as u32) < (right as u32)) as i32, Le => (left <= right) as i32, + LeU => ((left as u32) <= (right as u32)) as i32, Gt => (left > right) as i32, + GtU => ((left as u32) > (right as u32)) as i32, Ge => (left >= right) as i32, - Lsl => left << right, - Lsr => ((left as u32) >> right) as i32, - Asr => left >> right + GeU => ((left as u32) >= (right as u32)) as i32, + Shl => left << right, + ShrU => ((left as u32) >> right) as i32, + ShrS => left >> right, }; expr.expr = ast::Expr::I32Const(result); } (&ast::Expr::I64Const(left), &ast::Expr::I64Const(right)) => { use ast::Expr::*; - expr.expr = match op { + expr.expr = match op { Add => I64Const(left.wrapping_add(right)), Sub => I64Const(left.wrapping_sub(right)), Mul => I64Const(left.wrapping_mul(right)), @@ -111,6 +144,13 @@ fn fold_expr(expr: &mut ast::Expression) { return; } } + DivU => { + if let Some(result) = (left as u64).checked_div(right as u64) { + I64Const(result as i64) + } else { + return; + } + } Rem => { if let Some(result) = left.checked_rem(right) { I64Const(result) @@ -118,18 +158,29 @@ fn fold_expr(expr: &mut ast::Expression) { return; } } + RemU => { + if let Some(result) = (left as u64).checked_rem(right as u64) { + I64Const(result as i64) + } else { + return; + } + } And => I64Const(left & right), Or => I64Const(left | right), Xor => I64Const(left ^ right), Eq => I32Const((left == right) as i32), Ne => I32Const((left != right) as i32), Lt => I32Const((left < right) as i32), + LtU => I32Const(((left as u64) < (right as u64)) as i32), Le => I32Const((left <= right) as i32), + LeU => I32Const(((left as u64) <= (right as u64)) as i32), Gt => I32Const((left > right) as i32), + GtU => I32Const(((left as u64) > (right as u64)) as i32), Ge => I32Const((left >= right) as i32), - Lsl => I64Const(left << right), - Lsr => I64Const(((left as u64) >> right) as i64), - Asr => I64Const(left >> right) + GeU => I32Const(((left as u64) >= (right as u64)) as i32), + Shl => I64Const(left << right), + ShrU => I64Const(((left as u64) >> right) as i64), + ShrS => I64Const(left >> right), }; } (&ast::Expr::F32Const(left), &ast::Expr::F32Const(right)) => { @@ -139,7 +190,8 @@ fn fold_expr(expr: &mut ast::Expression) { Sub => F32Const(left - right), Mul => F32Const(left * right), Div => F32Const(left / right), - Rem | And | Or | Xor | Lsl | Lsr | Asr => return, + Rem | And | Or | Xor | Shl | ShrU | ShrS | DivU | RemU | LtU | LeU + | GtU | GeU => return, Eq => I32Const((left == right) as i32), Ne => I32Const((left != right) as i32), Lt => I32Const((left < right) as i32), @@ -155,7 +207,8 @@ fn fold_expr(expr: &mut ast::Expression) { Sub => F64Const(left - right), Mul => F64Const(left * right), Div => F64Const(left / right), - Rem | And | Or | Xor | Lsl | Lsr | Asr => return, + Rem | And | Or | Xor | Shl | ShrU | ShrS | DivU | RemU | LtU | LeU + | GtU | GeU => return, Eq => I32Const((left == right) as i32), Ne => I32Const((left != right) as i32), Lt => I32Const((left < right) as i32), @@ -167,7 +220,11 @@ fn fold_expr(expr: &mut ast::Expression) { _ => (), } } - ast::Expr::I32Const(_) | ast::Expr::I64Const(_) | ast::Expr::F32Const(_) | ast::Expr::F64Const(_) | ast::Expr::Variable { .. } => (), + ast::Expr::I32Const(_) + | ast::Expr::I64Const(_) + | ast::Expr::F32Const(_) + | ast::Expr::F64Const(_) + | ast::Expr::Variable { .. } => (), ast::Expr::Assign { ref mut value, .. } => fold_expr(value), ast::Expr::LocalTee { ref mut value, .. } => fold_expr(value), ast::Expr::Loop { ref mut block, .. } => fold_expr(block), @@ -202,7 +259,9 @@ fn fold_expr(expr: &mut ast::Expression) { fold_expr(if_false); } ast::Expr::If { - ref mut condition, ref mut if_true, ref mut if_false + ref mut condition, + ref mut if_true, + ref mut if_false, } => { fold_expr(condition); fold_expr(if_true); @@ -210,12 +269,17 @@ fn fold_expr(expr: &mut ast::Expression) { fold_expr(if_false); } } - ast::Expr::Return { value: Some(ref mut value) } => fold_expr(value), + ast::Expr::Return { + value: Some(ref mut value), + } => fold_expr(value), ast::Expr::Return { value: None } => (), - ast::Expr::First { ref mut value, ref mut drop } => { + ast::Expr::First { + ref mut value, + ref mut drop, + } => { fold_expr(value); fold_expr(drop); } - ast::Expr::Error => unreachable!() + ast::Expr::Error => unreachable!(), } } diff --git a/src/emit.rs b/src/emit.rs index d283236..217a19f 100644 --- a/src/emit.rs +++ b/src/emit.rs @@ -413,43 +413,58 @@ fn emit_expression<'a>(ctx: &mut FunctionContext<'a>, expr: &'a ast::Expression) (I32, Sub) => Instruction::I32Sub, (I32, Mul) => Instruction::I32Mul, (I32, Div) => Instruction::I32DivS, + (I32, DivU) => Instruction::I32DivU, (I32, Rem) => Instruction::I32RemS, + (I32, RemU) => Instruction::I32RemU, (I32, And) => Instruction::I32And, (I32, Or) => Instruction::I32Or, (I32, Xor) => Instruction::I32Xor, (I32, Eq) => Instruction::I32Eq, (I32, Ne) => Instruction::I32Neq, (I32, Lt) => Instruction::I32LtS, + (I32, LtU) => Instruction::I32LtU, (I32, Le) => Instruction::I32LeS, + (I32, LeU) => Instruction::I32LeU, (I32, Gt) => Instruction::I32GtS, + (I32, GtU) => Instruction::I32GtU, (I32, Ge) => Instruction::I32GeS, - (I32, Lsl) => Instruction::I32Shl, - (I32, Lsr) => Instruction::I32ShrU, - (I32, Asr) => Instruction::I32ShrS, + (I32, GeU) => Instruction::I32GeU, + (I32, Shl) => Instruction::I32Shl, + (I32, ShrU) => Instruction::I32ShrU, + (I32, ShrS) => Instruction::I32ShrS, (I64, Add) => Instruction::I64Add, (I64, Sub) => Instruction::I64Sub, (I64, Mul) => Instruction::I64Mul, (I64, Div) => Instruction::I64DivS, + (I64, DivU) => Instruction::I64DivU, (I64, Rem) => Instruction::I64RemS, + (I64, RemU) => Instruction::I64RemU, (I64, And) => Instruction::I64And, (I64, Or) => Instruction::I64Or, (I64, Xor) => Instruction::I64Xor, (I64, Eq) => Instruction::I64Eq, (I64, Ne) => Instruction::I64Neq, (I64, Lt) => Instruction::I64LtS, + (I64, LtU) => Instruction::I64LtU, (I64, Le) => Instruction::I64LeS, + (I64, LeU) => Instruction::I64LeU, (I64, Gt) => Instruction::I64GtS, + (I64, GtU) => Instruction::I64GtU, (I64, Ge) => Instruction::I64GeS, - (I64, Lsl) => Instruction::I64Shl, - (I64, Lsr) => Instruction::I64ShrU, - (I64, Asr) => Instruction::I64ShrS, + (I64, GeU) => Instruction::I64GeU, + (I64, Shl) => Instruction::I64Shl, + (I64, ShrU) => Instruction::I64ShrU, + (I64, ShrS) => Instruction::I64ShrS, (F32, Add) => Instruction::F32Add, (F32, Sub) => Instruction::F32Sub, (F32, Mul) => Instruction::F32Mul, (F32, Div) => Instruction::F32Div, - (F32, Rem | And | Or | Xor | Lsl | Lsr | Asr) => unreachable!(), + ( + F32, + DivU | Rem | RemU | And | Or | Xor | Shl | ShrU | ShrS | LtU | LeU | GtU | GeU, + ) => unreachable!(), (F32, Eq) => Instruction::F32Eq, (F32, Ne) => Instruction::F32Neq, (F32, Lt) => Instruction::F32Lt, @@ -461,7 +476,10 @@ fn emit_expression<'a>(ctx: &mut FunctionContext<'a>, expr: &'a ast::Expression) (F64, Sub) => Instruction::F64Sub, (F64, Mul) => Instruction::F64Mul, (F64, Div) => Instruction::F64Div, - (F64, Rem | And | Or | Xor | Lsl | Lsr | Asr) => unreachable!(), + ( + F64, + DivU | Rem | RemU | And | Or | Xor | Shl | ShrU | ShrS | LtU | LeU | GtU | GeU, + ) => unreachable!(), (F64, Eq) => Instruction::F64Eq, (F64, Ne) => Instruction::F64Neq, (F64, Lt) => Instruction::F64Lt, diff --git a/src/parser.rs b/src/parser.rs index e8516d0..31ff9ba 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -192,7 +192,7 @@ fn lexer() -> impl Parser, Error = Simple> { .collect::() .map(Token::Str); - let op = one_of("+-*/%&^|<=>".chars()) + let op = one_of("+-*/%&^|<=>#".chars()) .repeated() .at_least(1) .or(just(':').chain(just('='))) @@ -574,7 +574,9 @@ fn script_parser() -> impl Parser> + C just(Token::Op("*".to_string())) .to(ast::BinOp::Mul) .or(just(Token::Op("/".to_string())).to(ast::BinOp::Div)) + .or(just(Token::Op("#/".to_string())).to(ast::BinOp::DivU)) .or(just(Token::Op("%".to_string())).to(ast::BinOp::Rem)) + .or(just(Token::Op("#%".to_string())).to(ast::BinOp::RemU)) .then(memory_op.clone()) .repeated(), ) @@ -613,9 +615,9 @@ fn script_parser() -> impl Parser> + C .clone() .then( just(Token::Op("<<".to_string())) - .to(ast::BinOp::Lsl) - .or(just(Token::Op(">>".to_string())).to(ast::BinOp::Lsr)) - .or(just(Token::Op(">>>".to_string())).to(ast::BinOp::Asr)) + .to(ast::BinOp::Shl) + .or(just(Token::Op("#>>".to_string())).to(ast::BinOp::ShrU)) + .or(just(Token::Op(">>".to_string())).to(ast::BinOp::ShrS)) .then(op_sum.clone()) .repeated(), ) @@ -637,9 +639,13 @@ fn script_parser() -> impl Parser> + C .to(ast::BinOp::Eq) .or(just(Token::Op("!=".to_string())).to(ast::BinOp::Ne)) .or(just(Token::Op("<".to_string())).to(ast::BinOp::Lt)) + .or(just(Token::Op("#<".to_string())).to(ast::BinOp::LtU)) .or(just(Token::Op("<=".to_string())).to(ast::BinOp::Le)) + .or(just(Token::Op("#<=".to_string())).to(ast::BinOp::LeU)) .or(just(Token::Op(">".to_string())).to(ast::BinOp::Gt)) + .or(just(Token::Op("#>".to_string())).to(ast::BinOp::GtU)) .or(just(Token::Op(">=".to_string())).to(ast::BinOp::Ge)) + .or(just(Token::Op("#>=".to_string())).to(ast::BinOp::GeU)) .then(op_shift.clone()) .repeated(), ) diff --git a/src/typecheck.rs b/src/typecheck.rs index 1095821..c31ef6a 100644 --- a/src/typecheck.rs +++ b/src/typecheck.rs @@ -429,7 +429,7 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() use ast::BinOp::*; match op { Add | Sub | Mul | Div => left.type_, - Rem | And | Or | Xor | Lsl | Lsr | Asr => { + Rem | And | Or | Xor | Shl | ShrU | ShrS | DivU | RemU => { if left.type_ != Some(I32) && left.type_ != Some(I64) { return type_mismatch( Some(I32), @@ -443,6 +443,19 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() } } Eq | Ne | Lt | Le | Gt | Ge => Some(I32), + LtU | LeU | GtU | GeU => { + if left.type_ != Some(I32) && left.type_ != Some(I64) { + return type_mismatch( + Some(I32), + &left.span, + left.type_, + &left.span, + context.source, + ); + } else { + Some(I32) + } + } } } ast::Expr::Variable(ref name) => { @@ -687,7 +700,10 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() } None } - ast::Expr::First { ref mut value, ref mut drop } => { + ast::Expr::First { + ref mut value, + ref mut drop, + } => { tc_expression(context, value)?; tc_expression(context, drop)?; value.type_