mirror of
https://github.com/exoticorn/curlywas.git
synced 2026-01-20 11:46:43 +01:00
implement unsigned operators
This commit is contained in:
12
src/ast.rs
12
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)]
|
||||
|
||||
110
src/constfold.rs
110
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!(),
|
||||
}
|
||||
}
|
||||
|
||||
34
src/emit.rs
34
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,
|
||||
|
||||
@@ -192,7 +192,7 @@ fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = Simple<char>> {
|
||||
.collect::<String>()
|
||||
.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<Token, ast::Script, Error = Simple<Token>> + 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<Token, ast::Script, Error = Simple<Token>> + 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<Token, ast::Script, Error = Simple<Token>> + 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(),
|
||||
)
|
||||
|
||||
@@ -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_
|
||||
|
||||
Reference in New Issue
Block a user