implement unsigned operators

This commit is contained in:
2021-11-11 23:04:41 +01:00
parent d3e882cba0
commit 51cf8a8d28
7 changed files with 161 additions and 51 deletions

View File

@@ -9,14 +9,14 @@ fn random() -> i32 {
fn random64() -> i64 { fn random64() -> i64 {
let state: i64; let state: i64;
randomState = (state := ( randomState = (state := (
state := randomState ^ (randomState >> 12i64) state := randomState ^ (randomState #>> 12i64)
) ^ (state << 25i64) ) ^ (state << 25i64)
) ^ (state >> 27i64); ) ^ (state #>> 27i64);
randomState * 2685821657736338717i64 randomState * 2685821657736338717i64
} }
fn randomf() -> f32 { 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) { fn seed(s: i32) {
@@ -28,8 +28,8 @@ fn seed(s: i32) {
export fn tic(time: i32) { export fn tic(time: i32) {
let i: i32; let i: i32;
loop pixels { loop pixels {
seed(i + (time / 100) * 320); seed(i + (time / 10) * 320);
i?120 = (randomf() * 256 as f32 + time as f32 / 10 as f32) as i32; i?120 = (randomf() * 256 as f32 + time as f32 / 10 as f32) as i32 & 128;
branch_if (i := i + 1) < 320*256: pixels branch_if (i := i + 1) < 320*256: pixels
} }
} }

View File

@@ -14,7 +14,7 @@ global mut s: f32 = 0.0;
global mut f: f32 = 0.0; global mut f: f32 = 0.0;
fn rng(state: i32) -> i32 { fn rng(state: i32) -> i32 {
94614859 * (state ^ (state >> 17)) 94614859 * (state ^ (state #>> 17))
} }
fn set_color(color: i32) -> i32 { fn set_color(color: i32) -> i32 {
@@ -35,7 +35,7 @@ export fn update() {
loop lines { loop lines {
?(8003-y) = (score := score / 10) % 10 + 48; ?(8003-y) = (score := score / 10) % 10 + 48;
let defer z = (4000 / (y := y + 1) + pz) / 20; 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 w = 9 as f32 / sqrt(z as f32);
let defer rx = 80 + (y as f32 * x) as i32; let defer rx = 80 + (y as f32 * x) as i32;
let defer rw = (y as f32 * w) as i32; let defer rw = (y as f32 * w) as i32;
@@ -47,10 +47,10 @@ export fn update() {
if y == 120 & py > zero { if y == 120 & py > zero {
if x < -w | x > zero { if x < -w | x > zero {
if pad & 2 { // (*) if pad & 2 {
pz = 30; // (*) pz = 30;
px = zero; // (*) px = zero;
} // (*) }
return; return;
} }
py = zero; py = zero;

View File

@@ -170,19 +170,25 @@ pub enum BinOp {
Sub, Sub,
Mul, Mul,
Div, Div,
DivU,
Rem, Rem,
RemU,
And, And,
Or, Or,
Xor, Xor,
Eq, Eq,
Ne, Ne,
Gt, Gt,
GtU,
Ge, Ge,
GeU,
Lt, Lt,
LtU,
Le, Le,
Lsl, LeU,
Lsr, Shl,
Asr, ShrU,
ShrS,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]

View File

@@ -18,7 +18,10 @@ fn fold_mem_location(mem_location: &mut ast::MemoryLocation) {
fn fold_expr(expr: &mut ast::Expression) { fn fold_expr(expr: &mut ast::Expression) {
use ast::BinOp::*; use ast::BinOp::*;
match expr.expr { 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 { for stmt in statements {
fold_expr(stmt); fold_expr(stmt);
} }
@@ -43,13 +46,25 @@ fn fold_expr(expr: &mut ast::Expression) {
ast::Expr::UnaryOp { op, ref mut value } => { ast::Expr::UnaryOp { op, ref mut value } => {
fold_expr(value); fold_expr(value);
let result = match (op, &value.expr) { let result = match (op, &value.expr) {
(ast::UnaryOp::Negate, ast::Expr::I32Const(value)) => Some(ast::Expr::I32Const(-*value)), (ast::UnaryOp::Negate, ast::Expr::I32Const(value)) => {
(ast::UnaryOp::Negate, ast::Expr::I64Const(value)) => Some(ast::Expr::I64Const(-*value)), Some(ast::Expr::I32Const(-*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::Negate, ast::Expr::I64Const(value)) => {
(ast::UnaryOp::Not, ast::Expr::I32Const(value)) => Some(ast::Expr::I32Const((*value == 0) as i32)), Some(ast::Expr::I64Const(-*value))
(ast::UnaryOp::Not, ast::Expr::I64Const(value)) => Some(ast::Expr::I32Const((*value == 0) as i32)), }
_ => None (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 { if let Some(result) = result {
expr.expr = result; expr.expr = result;
@@ -76,6 +91,13 @@ fn fold_expr(expr: &mut ast::Expression) {
return; return;
} }
} }
DivU => {
if let Some(result) = (left as u32).checked_div(right as u32) {
result as i32
} else {
return;
}
}
Rem => { Rem => {
if let Some(result) = left.checked_rem(right) { if let Some(result) = left.checked_rem(right) {
result result
@@ -83,18 +105,29 @@ fn fold_expr(expr: &mut ast::Expression) {
return; return;
} }
} }
RemU => {
if let Some(result) = (left as u32).checked_rem(right as u32) {
result as i32
} else {
return;
}
}
And => left & right, And => left & right,
Or => left | right, Or => left | right,
Xor => left ^ right, Xor => left ^ right,
Eq => (left == right) as i32, Eq => (left == right) as i32,
Ne => (left != right) as i32, Ne => (left != right) as i32,
Lt => (left < right) as i32, Lt => (left < right) as i32,
LtU => ((left as u32) < (right as u32)) as i32,
Le => (left <= right) as i32, Le => (left <= right) as i32,
LeU => ((left as u32) <= (right as u32)) as i32,
Gt => (left > right) as i32, Gt => (left > right) as i32,
GtU => ((left as u32) > (right as u32)) as i32,
Ge => (left >= right) as i32, Ge => (left >= right) as i32,
Lsl => left << right, GeU => ((left as u32) >= (right as u32)) as i32,
Lsr => ((left as u32) >> right) as i32, Shl => left << right,
Asr => left >> right ShrU => ((left as u32) >> right) as i32,
ShrS => left >> right,
}; };
expr.expr = ast::Expr::I32Const(result); expr.expr = ast::Expr::I32Const(result);
} }
@@ -111,6 +144,13 @@ fn fold_expr(expr: &mut ast::Expression) {
return; return;
} }
} }
DivU => {
if let Some(result) = (left as u64).checked_div(right as u64) {
I64Const(result as i64)
} else {
return;
}
}
Rem => { Rem => {
if let Some(result) = left.checked_rem(right) { if let Some(result) = left.checked_rem(right) {
I64Const(result) I64Const(result)
@@ -118,18 +158,29 @@ fn fold_expr(expr: &mut ast::Expression) {
return; return;
} }
} }
RemU => {
if let Some(result) = (left as u64).checked_rem(right as u64) {
I64Const(result as i64)
} else {
return;
}
}
And => I64Const(left & right), And => I64Const(left & right),
Or => I64Const(left | right), Or => I64Const(left | right),
Xor => I64Const(left ^ right), Xor => I64Const(left ^ right),
Eq => I32Const((left == right) as i32), Eq => I32Const((left == right) as i32),
Ne => I32Const((left != right) as i32), Ne => I32Const((left != right) as i32),
Lt => 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), Le => I32Const((left <= right) as i32),
LeU => I32Const(((left as u64) <= (right as u64)) as i32),
Gt => I32Const((left > right) as i32), Gt => I32Const((left > right) as i32),
GtU => I32Const(((left as u64) > (right as u64)) as i32),
Ge => I32Const((left >= right) as i32), Ge => I32Const((left >= right) as i32),
Lsl => I64Const(left << right), GeU => I32Const(((left as u64) >= (right as u64)) as i32),
Lsr => I64Const(((left as u64) >> right) as i64), Shl => I64Const(left << right),
Asr => I64Const(left >> right) ShrU => I64Const(((left as u64) >> right) as i64),
ShrS => I64Const(left >> right),
}; };
} }
(&ast::Expr::F32Const(left), &ast::Expr::F32Const(right)) => { (&ast::Expr::F32Const(left), &ast::Expr::F32Const(right)) => {
@@ -139,7 +190,8 @@ fn fold_expr(expr: &mut ast::Expression) {
Sub => F32Const(left - right), Sub => F32Const(left - right),
Mul => F32Const(left * right), Mul => F32Const(left * right),
Div => 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), Eq => I32Const((left == right) as i32),
Ne => I32Const((left != right) as i32), Ne => I32Const((left != right) as i32),
Lt => 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), Sub => F64Const(left - right),
Mul => F64Const(left * right), Mul => F64Const(left * right),
Div => 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), Eq => I32Const((left == right) as i32),
Ne => I32Const((left != right) as i32), Ne => I32Const((left != right) as i32),
Lt => 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::Assign { ref mut value, .. } => fold_expr(value),
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_expr(block), ast::Expr::Loop { ref mut block, .. } => fold_expr(block),
@@ -202,7 +259,9 @@ fn fold_expr(expr: &mut ast::Expression) {
fold_expr(if_false); fold_expr(if_false);
} }
ast::Expr::If { 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(condition);
fold_expr(if_true); fold_expr(if_true);
@@ -210,12 +269,17 @@ fn fold_expr(expr: &mut ast::Expression) {
fold_expr(if_false); 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::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(value);
fold_expr(drop); fold_expr(drop);
} }
ast::Expr::Error => unreachable!() ast::Expr::Error => unreachable!(),
} }
} }

View File

@@ -413,43 +413,58 @@ fn emit_expression<'a>(ctx: &mut FunctionContext<'a>, expr: &'a ast::Expression)
(I32, Sub) => Instruction::I32Sub, (I32, Sub) => Instruction::I32Sub,
(I32, Mul) => Instruction::I32Mul, (I32, Mul) => Instruction::I32Mul,
(I32, Div) => Instruction::I32DivS, (I32, Div) => Instruction::I32DivS,
(I32, DivU) => Instruction::I32DivU,
(I32, Rem) => Instruction::I32RemS, (I32, Rem) => Instruction::I32RemS,
(I32, RemU) => Instruction::I32RemU,
(I32, And) => Instruction::I32And, (I32, And) => Instruction::I32And,
(I32, Or) => Instruction::I32Or, (I32, Or) => Instruction::I32Or,
(I32, Xor) => Instruction::I32Xor, (I32, Xor) => Instruction::I32Xor,
(I32, Eq) => Instruction::I32Eq, (I32, Eq) => Instruction::I32Eq,
(I32, Ne) => Instruction::I32Neq, (I32, Ne) => Instruction::I32Neq,
(I32, Lt) => Instruction::I32LtS, (I32, Lt) => Instruction::I32LtS,
(I32, LtU) => Instruction::I32LtU,
(I32, Le) => Instruction::I32LeS, (I32, Le) => Instruction::I32LeS,
(I32, LeU) => Instruction::I32LeU,
(I32, Gt) => Instruction::I32GtS, (I32, Gt) => Instruction::I32GtS,
(I32, GtU) => Instruction::I32GtU,
(I32, Ge) => Instruction::I32GeS, (I32, Ge) => Instruction::I32GeS,
(I32, Lsl) => Instruction::I32Shl, (I32, GeU) => Instruction::I32GeU,
(I32, Lsr) => Instruction::I32ShrU, (I32, Shl) => Instruction::I32Shl,
(I32, Asr) => Instruction::I32ShrS, (I32, ShrU) => Instruction::I32ShrU,
(I32, ShrS) => Instruction::I32ShrS,
(I64, Add) => Instruction::I64Add, (I64, Add) => Instruction::I64Add,
(I64, Sub) => Instruction::I64Sub, (I64, Sub) => Instruction::I64Sub,
(I64, Mul) => Instruction::I64Mul, (I64, Mul) => Instruction::I64Mul,
(I64, Div) => Instruction::I64DivS, (I64, Div) => Instruction::I64DivS,
(I64, DivU) => Instruction::I64DivU,
(I64, Rem) => Instruction::I64RemS, (I64, Rem) => Instruction::I64RemS,
(I64, RemU) => Instruction::I64RemU,
(I64, And) => Instruction::I64And, (I64, And) => Instruction::I64And,
(I64, Or) => Instruction::I64Or, (I64, Or) => Instruction::I64Or,
(I64, Xor) => Instruction::I64Xor, (I64, Xor) => Instruction::I64Xor,
(I64, Eq) => Instruction::I64Eq, (I64, Eq) => Instruction::I64Eq,
(I64, Ne) => Instruction::I64Neq, (I64, Ne) => Instruction::I64Neq,
(I64, Lt) => Instruction::I64LtS, (I64, Lt) => Instruction::I64LtS,
(I64, LtU) => Instruction::I64LtU,
(I64, Le) => Instruction::I64LeS, (I64, Le) => Instruction::I64LeS,
(I64, LeU) => Instruction::I64LeU,
(I64, Gt) => Instruction::I64GtS, (I64, Gt) => Instruction::I64GtS,
(I64, GtU) => Instruction::I64GtU,
(I64, Ge) => Instruction::I64GeS, (I64, Ge) => Instruction::I64GeS,
(I64, Lsl) => Instruction::I64Shl, (I64, GeU) => Instruction::I64GeU,
(I64, Lsr) => Instruction::I64ShrU, (I64, Shl) => Instruction::I64Shl,
(I64, Asr) => Instruction::I64ShrS, (I64, ShrU) => Instruction::I64ShrU,
(I64, ShrS) => Instruction::I64ShrS,
(F32, Add) => Instruction::F32Add, (F32, Add) => Instruction::F32Add,
(F32, Sub) => Instruction::F32Sub, (F32, Sub) => Instruction::F32Sub,
(F32, Mul) => Instruction::F32Mul, (F32, Mul) => Instruction::F32Mul,
(F32, Div) => Instruction::F32Div, (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, Eq) => Instruction::F32Eq,
(F32, Ne) => Instruction::F32Neq, (F32, Ne) => Instruction::F32Neq,
(F32, Lt) => Instruction::F32Lt, (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, Sub) => Instruction::F64Sub,
(F64, Mul) => Instruction::F64Mul, (F64, Mul) => Instruction::F64Mul,
(F64, Div) => Instruction::F64Div, (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, Eq) => Instruction::F64Eq,
(F64, Ne) => Instruction::F64Neq, (F64, Ne) => Instruction::F64Neq,
(F64, Lt) => Instruction::F64Lt, (F64, Lt) => Instruction::F64Lt,

View File

@@ -192,7 +192,7 @@ fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = Simple<char>> {
.collect::<String>() .collect::<String>()
.map(Token::Str); .map(Token::Str);
let op = one_of("+-*/%&^|<=>".chars()) let op = one_of("+-*/%&^|<=>#".chars())
.repeated() .repeated()
.at_least(1) .at_least(1)
.or(just(':').chain(just('='))) .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())) just(Token::Op("*".to_string()))
.to(ast::BinOp::Mul) .to(ast::BinOp::Mul)
.or(just(Token::Op("/".to_string())).to(ast::BinOp::Div)) .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::Rem))
.or(just(Token::Op("#%".to_string())).to(ast::BinOp::RemU))
.then(memory_op.clone()) .then(memory_op.clone())
.repeated(), .repeated(),
) )
@@ -613,9 +615,9 @@ fn script_parser() -> impl Parser<Token, ast::Script, Error = Simple<Token>> + C
.clone() .clone()
.then( .then(
just(Token::Op("<<".to_string())) just(Token::Op("<<".to_string()))
.to(ast::BinOp::Lsl) .to(ast::BinOp::Shl)
.or(just(Token::Op(">>".to_string())).to(ast::BinOp::Lsr)) .or(just(Token::Op("#>>".to_string())).to(ast::BinOp::ShrU))
.or(just(Token::Op(">>>".to_string())).to(ast::BinOp::Asr)) .or(just(Token::Op(">>".to_string())).to(ast::BinOp::ShrS))
.then(op_sum.clone()) .then(op_sum.clone())
.repeated(), .repeated(),
) )
@@ -637,9 +639,13 @@ fn script_parser() -> impl Parser<Token, ast::Script, Error = Simple<Token>> + C
.to(ast::BinOp::Eq) .to(ast::BinOp::Eq)
.or(just(Token::Op("!=".to_string())).to(ast::BinOp::Ne)) .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::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::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::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::Ge))
.or(just(Token::Op("#>=".to_string())).to(ast::BinOp::GeU))
.then(op_shift.clone()) .then(op_shift.clone())
.repeated(), .repeated(),
) )

View File

@@ -429,7 +429,7 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<()
use ast::BinOp::*; use ast::BinOp::*;
match op { match op {
Add | Sub | Mul | Div => left.type_, 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) { if left.type_ != Some(I32) && left.type_ != Some(I64) {
return type_mismatch( return type_mismatch(
Some(I32), 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), 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) => { ast::Expr::Variable(ref name) => {
@@ -687,7 +700,10 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<()
} }
None 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, value)?;
tc_expression(context, drop)?; tc_expression(context, drop)?;
value.type_ value.type_