implement some initial f32 support

This commit is contained in:
2021-10-27 20:03:23 +02:00
parent 7f5dd9aa80
commit 23d926dbb3
6 changed files with 146 additions and 27 deletions

View File

@@ -87,6 +87,7 @@ pub struct LocalVariable<'a> {
pub name: &'a str, pub name: &'a str,
pub type_: Option<Type>, pub type_: Option<Type>,
pub value: Option<Expression<'a>>, pub value: Option<Expression<'a>>,
pub defer: bool
} }
#[derive(Debug)] #[derive(Debug)]
@@ -104,6 +105,7 @@ impl<'a> From<Expr<'a>> for Expression<'a> {
#[derive(Debug)] #[derive(Debug)]
pub enum Expr<'a> { pub enum Expr<'a> {
I32Const(i32), I32Const(i32),
F32Const(f32),
Variable { Variable {
position: Position, position: Position,
name: &'a str, name: &'a str,
@@ -129,6 +131,11 @@ pub enum Expr<'a> {
name: &'a str, name: &'a str,
value: Box<Expression<'a>>, value: Box<Expression<'a>>,
}, },
Cast {
position: Position,
value: Box<Expression<'a>>,
type_: Type,
},
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]

View File

@@ -78,14 +78,31 @@ fn fold_expr(expr: &mut ast::Expression) {
}; };
expr.expr = ast::Expr::I32Const(result); 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::LocalTee { ref mut value, .. } => fold_expr(value),
ast::Expr::Loop { ref mut block, .. } => fold_block(block), ast::Expr::Loop { ref mut block, .. } => fold_block(block),
ast::Expr::BranchIf { ast::Expr::BranchIf {
ref mut condition, .. ref mut condition, ..
} => fold_expr(condition), } => fold_expr(condition),
ast::Expr::Cast { ref mut value, .. } => fold_expr(value),
} }
} }

View File

@@ -111,6 +111,7 @@ struct FunctionContext<'a> {
globals: &'a HashMap<&'a str, u32>, globals: &'a HashMap<&'a str, u32>,
locals: &'a HashMap<&'a str, u32>, locals: &'a HashMap<&'a str, u32>,
labels: Vec<String>, labels: Vec<String>,
deferred_inits: HashMap<&'a str, &'a ast::Expression<'a>>,
} }
fn emit_function(func: &ast::Function, globals: &HashMap<&str, u32>) -> Function { 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, globals,
locals: &locals, locals: &locals,
labels: vec![], labels: vec![],
deferred_inits: HashMap::new(),
}; };
emit_block(&mut context, &func.body); 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)>) { fn collect_locals_expr<'a>(expr: &ast::Expression<'a>, locals: &mut Vec<(&'a str, ast::Type)>) {
match &expr.expr { match &expr.expr {
ast::Expr::Variable { .. } | ast::Expr::I32Const(_) => (), ast::Expr::Variable { .. } | ast::Expr::I32Const(_) | ast::Expr::F32Const(_) => (),
ast::Expr::BinOp { left, right, .. } => { ast::Expr::BinOp { left, right, .. } => {
collect_locals_expr(left, locals); collect_locals_expr(left, locals);
collect_locals_expr(right, 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::BranchIf { condition, .. } => collect_locals_expr(condition, locals),
ast::Expr::LocalTee { value, .. } => collect_locals_expr(value, locals), ast::Expr::LocalTee { value, .. } => collect_locals_expr(value, locals),
ast::Expr::Loop { block, .. } => collect_locals(block, 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 { for stmt in &block.statements {
match stmt { match stmt {
ast::Statement::Expression(e) => { ast::Statement::Expression(e) => {
@@ -191,11 +194,15 @@ fn emit_block(ctx: &mut FunctionContext, block: &ast::Block) {
} }
ast::Statement::LocalVariable(v) => { ast::Statement::LocalVariable(v) => {
if let Some(ref val) = v.value { if let Some(ref val) = v.value {
if v.defer {
ctx.deferred_inits.insert(v.name, val);
} else {
emit_expression(ctx, val); emit_expression(ctx, val);
ctx.function ctx.function
.instruction(&Instruction::LocalSet(*ctx.locals.get(v.name).unwrap())); .instruction(&Instruction::LocalSet(*ctx.locals.get(v.name).unwrap()));
} }
} }
}
ast::Statement::Poke { ast::Statement::Poke {
mem_location, mem_location,
value, value,
@@ -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 { match &expr.expr {
ast::Expr::BinOp { ast::Expr::BinOp {
left, op, right, .. left, op, right, ..
@@ -253,8 +260,19 @@ fn emit_expression(ctx: &mut FunctionContext, expr: &ast::Expression) {
(I32, Gt) => Instruction::I32GtS, (I32, Gt) => Instruction::I32GtS,
(I32, Ge) => Instruction::I32GeS, (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!(), (I64, _) => todo!(),
(F32, _) => todo!(),
(F64, _) => todo!(), (F64, _) => todo!(),
}); });
} }
@@ -275,6 +293,9 @@ fn emit_expression(ctx: &mut FunctionContext, expr: &ast::Expression) {
ast::Expr::I32Const(v) => { ast::Expr::I32Const(v) => {
ctx.function.instruction(&Instruction::I32Const(*v)); ctx.function.instruction(&Instruction::I32Const(*v));
} }
ast::Expr::F32Const(v) => {
ctx.function.instruction(&Instruction::F32Const(*v));
}
ast::Expr::LocalTee { name, value, .. } => { ast::Expr::LocalTee { name, value, .. } => {
emit_expression(ctx, value); emit_expression(ctx, value);
let index = ctx.locals.get(*name).unwrap(); let index = ctx.locals.get(*name).unwrap();
@@ -290,13 +311,31 @@ fn emit_expression(ctx: &mut FunctionContext, expr: &ast::Expression) {
} }
ast::Expr::Variable { name, .. } => { ast::Expr::Variable { name, .. } => {
if let Some(index) = ctx.locals.get(*name) { if let Some(index) = ctx.locals.get(*name) {
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)); ctx.function.instruction(&Instruction::LocalGet(*index));
}
} else if let Some(index) = ctx.globals.get(*name) { } else if let Some(index) = ctx.globals.get(*name) {
ctx.function.instruction(&Instruction::GlobalGet(*index)); ctx.function.instruction(&Instruction::GlobalGet(*index));
} else { } else {
unreachable!() 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);
}
}
} }
} }

View File

@@ -6,7 +6,7 @@ use nom::{
combinator::{self, cut, map, map_res, not, opt, peek, recognize, value}, combinator::{self, cut, map, map_res, not, opt, peek, recognize, value},
error::VerboseError, error::VerboseError,
multi::{fold_many0, many0, many1, separated_list0}, multi::{fold_many0, many0, many1, separated_list0},
sequence::{delimited, pair, preceded, separated_pair, terminated}, sequence::{delimited, pair, preceded, separated_pair, terminated, tuple},
Finish, Finish,
}; };
@@ -182,6 +182,8 @@ fn statement(s: &str) -> IResult<ast::Statement> {
fn local_var(s: &str) -> IResult<ast::LocalVariable> { fn local_var(s: &str) -> IResult<ast::LocalVariable> {
let (s, _) = ws(tag("let"))(s)?; let (s, _) = ws(tag("let"))(s)?;
cut(move |s| {
let (s, defer) = opt(ws(tag("defer")))(s)?;
let (s, position) = ws(position)(s)?; let (s, position) = ws(position)(s)?;
let (s, name) = identifier(s)?; let (s, name) = identifier(s)?;
let (s, type_) = opt(preceded(ws(char(':')), type_))(s)?; let (s, type_) = opt(preceded(ws(char(':')), type_))(s)?;
@@ -195,8 +197,10 @@ fn local_var(s: &str) -> IResult<ast::LocalVariable> {
name: name, name: name,
type_, type_,
value: value.map(|v| v.into()), value: value.map(|v| v.into()),
defer: defer.is_some()
}, },
)) ))
})(s)
} }
fn mem_location(s: &str) -> IResult<ast::MemoryLocation> { 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()), 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)| { map(ws(pair(position, identifier)), |(position, name)| {
ast::Expr::Variable { ast::Expr::Variable {
position, position,
@@ -266,12 +271,25 @@ fn branch_if(s: &str) -> IResult<ast::Expr> {
})(s) })(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)?; 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( fold_many0(
pair( pair(
ws(pair(position, alt((char('*'), char('/'), char('%'))))), ws(pair(position, alt((char('*'), char('/'), char('%'))))),
expression_atom, expression_cast,
), ),
move || init.take().unwrap(), move || init.take().unwrap(),
|left, ((position, op), right)| { |left, ((position, op), right)| {
@@ -407,6 +425,13 @@ fn integer(s: &str) -> IResult<i32> {
))(s) ))(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> { fn type_(s: &str) -> IResult<ast::Type> {
ws(alt(( ws(alt((
value(ast::Type::I32, tag("i32")), value(ast::Type::I32, tag("i32")),

View File

@@ -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<()> { fn tc_expression<'a>(context: &mut Context<'a>, expr: &mut ast::Expression<'a>) -> Result<()> {
expr.type_ = match expr.expr { expr.type_ = match expr.expr {
ast::Expr::I32Const(_) => Some(ast::Type::I32), ast::Expr::I32Const(_) => Some(ast::Type::I32),
ast::Expr::F32Const(_) => Some(ast::Type::F32),
ast::Expr::BinOp { ast::Expr::BinOp {
position, position,
op, op,
@@ -213,6 +214,20 @@ fn tc_expression<'a>(context: &mut Context<'a>, expr: &mut ast::Expression<'a>)
} }
None 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(()) Ok(())
} }

16
warptunnel.hw Normal file
View 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
}
}