mirror of
https://github.com/exoticorn/curlywas.git
synced 2026-01-20 11:46:43 +01:00
got trainride working
This commit is contained in:
11
src/ast.rs
11
src/ast.rs
@@ -136,6 +136,17 @@ pub enum Expr<'a> {
|
|||||||
value: Box<Expression<'a>>,
|
value: Box<Expression<'a>>,
|
||||||
type_: Type,
|
type_: Type,
|
||||||
},
|
},
|
||||||
|
FuncCall {
|
||||||
|
position: Position,
|
||||||
|
name: &'a str,
|
||||||
|
params: Vec<Expression<'a>>
|
||||||
|
},
|
||||||
|
Select {
|
||||||
|
position: Position,
|
||||||
|
condition: Box<Expression<'a>>,
|
||||||
|
if_true: Box<Expression<'a>>,
|
||||||
|
if_false: Box<Expression<'a>>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
|||||||
@@ -104,5 +104,25 @@ fn fold_expr(expr: &mut ast::Expression) {
|
|||||||
ref mut condition, ..
|
ref mut condition, ..
|
||||||
} => fold_expr(condition),
|
} => fold_expr(condition),
|
||||||
ast::Expr::Cast { ref mut value, .. } => fold_expr(value),
|
ast::Expr::Cast { ref mut value, .. } => fold_expr(value),
|
||||||
|
ast::Expr::FuncCall {
|
||||||
|
name,
|
||||||
|
ref mut params,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
for param in params.iter_mut() {
|
||||||
|
fold_expr(param);
|
||||||
|
}
|
||||||
|
use ast::Expr::*;
|
||||||
|
let params: Vec<_> = params.iter().map(|e| &e.expr).collect();
|
||||||
|
expr.expr = match (name, params.as_slice()) {
|
||||||
|
("sqrt", [F32Const(v)]) if *v >= 0.0 => F32Const(v.sqrt()),
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
ast::Expr::Select { ref mut condition, ref mut if_true, ref mut if_false, .. } => {
|
||||||
|
fold_expr(condition);
|
||||||
|
fold_expr(if_true);
|
||||||
|
fold_expr(if_false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
45
src/emit.rs
45
src/emit.rs
@@ -180,6 +180,21 @@ fn collect_locals_expr<'a>(expr: &ast::Expression<'a>, locals: &mut Vec<(&'a str
|
|||||||
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),
|
ast::Expr::Cast { value, .. } => collect_locals_expr(value, locals),
|
||||||
|
ast::Expr::FuncCall { params, .. } => {
|
||||||
|
for param in params {
|
||||||
|
collect_locals_expr(param, locals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::Expr::Select {
|
||||||
|
condition,
|
||||||
|
if_true,
|
||||||
|
if_false,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
collect_locals_expr(condition, locals);
|
||||||
|
collect_locals_expr(if_true, locals);
|
||||||
|
collect_locals_expr(if_false, locals);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,6 +351,26 @@ fn emit_expression<'a>(ctx: &mut FunctionContext<'a>, expr: &'a ast::Expression)
|
|||||||
ctx.function.instruction(&inst);
|
ctx.function.instruction(&inst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ast::Expr::FuncCall { name, params, .. } => {
|
||||||
|
let mut types = vec![];
|
||||||
|
for param in params {
|
||||||
|
types.push(param.type_.unwrap());
|
||||||
|
emit_expression(ctx, param);
|
||||||
|
}
|
||||||
|
ctx.function
|
||||||
|
.instruction(&builtin_function(name, &types).unwrap());
|
||||||
|
}
|
||||||
|
ast::Expr::Select {
|
||||||
|
condition,
|
||||||
|
if_true,
|
||||||
|
if_false,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
emit_expression(ctx, if_true);
|
||||||
|
emit_expression(ctx, if_false);
|
||||||
|
emit_expression(ctx, condition);
|
||||||
|
ctx.function.instruction(&Instruction::Select);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,3 +390,13 @@ fn map_block_type(t: Option<ast::Type>) -> BlockType {
|
|||||||
BlockType::Empty
|
BlockType::Empty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn builtin_function(name: &str, params: &[ast::Type]) -> Option<Instruction<'static>> {
|
||||||
|
use ast::Type::*;
|
||||||
|
let inst = match (name, params) {
|
||||||
|
("sqrt", &[F32]) => Instruction::F32Sqrt,
|
||||||
|
("abs", &[F32]) => Instruction::F32Abs,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
Some(inst)
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,7 +28,14 @@ fn main() -> Result<()> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
constfold::fold_script(&mut script);
|
constfold::fold_script(&mut script);
|
||||||
typecheck::tc_script(&mut script).unwrap();
|
if let Err(err) = typecheck::tc_script(&mut script) {
|
||||||
|
let line = input[..(input.len() - err.position.0)]
|
||||||
|
.chars()
|
||||||
|
.filter(|c| *c == '\n')
|
||||||
|
.count()
|
||||||
|
+ 1;
|
||||||
|
bail!("{} in line {}", err.message, line);
|
||||||
|
}
|
||||||
let wasm = emit::emit(&script);
|
let wasm = emit::emit(&script);
|
||||||
|
|
||||||
wasmparser::validate(&wasm)?;
|
wasmparser::validate(&wasm)?;
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ fn statement(s: &str) -> IResult<ast::Statement> {
|
|||||||
terminated(
|
terminated(
|
||||||
pair(
|
pair(
|
||||||
mem_location,
|
mem_location,
|
||||||
ws(pair(position, preceded(char('='), expression))),
|
cut(ws(pair(position, preceded(char('='), expression)))),
|
||||||
),
|
),
|
||||||
ws(char(';')),
|
ws(char(';')),
|
||||||
),
|
),
|
||||||
@@ -197,7 +197,7 @@ 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()
|
defer: defer.is_some(),
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
})(s)
|
})(s)
|
||||||
@@ -225,7 +225,7 @@ fn mem_location(s: &str) -> IResult<ast::MemoryLocation> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn expression(s: &str) -> IResult<ast::Expr> {
|
fn expression(s: &str) -> IResult<ast::Expr> {
|
||||||
expression_cmp(s)
|
expression_bit(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expression_atom(s: &str) -> IResult<ast::Expr> {
|
fn expression_atom(s: &str) -> IResult<ast::Expr> {
|
||||||
@@ -242,6 +242,36 @@ fn expression_atom(s: &str) -> IResult<ast::Expr> {
|
|||||||
),
|
),
|
||||||
map(float, ast::Expr::F32Const),
|
map(float, ast::Expr::F32Const),
|
||||||
map(integer, ast::Expr::I32Const),
|
map(integer, ast::Expr::I32Const),
|
||||||
|
map(
|
||||||
|
tuple((
|
||||||
|
terminated(ws(position), tag("select")),
|
||||||
|
preceded(ws(char('(')), expression),
|
||||||
|
preceded(ws(char(',')), expression),
|
||||||
|
delimited(ws(char(',')), expression, ws(char(')'))),
|
||||||
|
)),
|
||||||
|
|(position, condition, if_true, if_false)| ast::Expr::Select {
|
||||||
|
position,
|
||||||
|
condition: Box::new(condition.into()),
|
||||||
|
if_true: Box::new(if_true.into()),
|
||||||
|
if_false: Box::new(if_false.into()),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
map(
|
||||||
|
tuple((
|
||||||
|
ws(position),
|
||||||
|
identifier,
|
||||||
|
delimited(
|
||||||
|
ws(char('(')),
|
||||||
|
separated_list0(ws(char(',')), expression),
|
||||||
|
ws(char(')')),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
|(position, name, params)| ast::Expr::FuncCall {
|
||||||
|
position,
|
||||||
|
name,
|
||||||
|
params: params.into_iter().map(|p| p.into()).collect(),
|
||||||
|
},
|
||||||
|
),
|
||||||
map(ws(pair(position, identifier)), |(position, name)| {
|
map(ws(pair(position, identifier)), |(position, name)| {
|
||||||
ast::Expr::Variable {
|
ast::Expr::Variable {
|
||||||
position,
|
position,
|
||||||
@@ -333,33 +363,8 @@ fn expression_sum(s: &str) -> IResult<ast::Expr> {
|
|||||||
)(s)
|
)(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expression_bit(s: &str) -> IResult<ast::Expr> {
|
|
||||||
let (s, mut init) = map(expression_sum, Some)(s)?;
|
|
||||||
fold_many0(
|
|
||||||
pair(
|
|
||||||
ws(pair(position, alt((char('&'), char('|'), char('^'))))),
|
|
||||||
expression_sum,
|
|
||||||
),
|
|
||||||
move || init.take().unwrap(),
|
|
||||||
|left, ((position, op), right)| {
|
|
||||||
let op = match op {
|
|
||||||
'&' => ast::BinOp::And,
|
|
||||||
'|' => ast::BinOp::Or,
|
|
||||||
'^' => ast::BinOp::Xor,
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
ast::Expr::BinOp {
|
|
||||||
position,
|
|
||||||
op,
|
|
||||||
left: Box::new(left.into()),
|
|
||||||
right: Box::new(right.into()),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expression_cmp(s: &str) -> IResult<ast::Expr> {
|
fn expression_cmp(s: &str) -> IResult<ast::Expr> {
|
||||||
let (s, mut init) = map(expression_bit, Some)(s)?;
|
let (s, mut init) = map(expression_sum, Some)(s)?;
|
||||||
fold_many0(
|
fold_many0(
|
||||||
pair(
|
pair(
|
||||||
ws(pair(
|
ws(pair(
|
||||||
@@ -373,7 +378,7 @@ fn expression_cmp(s: &str) -> IResult<ast::Expr> {
|
|||||||
tag(">"),
|
tag(">"),
|
||||||
)),
|
)),
|
||||||
)),
|
)),
|
||||||
expression_bit,
|
expression_sum,
|
||||||
),
|
),
|
||||||
move || init.take().unwrap(),
|
move || init.take().unwrap(),
|
||||||
|left, ((position, op), right)| {
|
|left, ((position, op), right)| {
|
||||||
@@ -396,6 +401,31 @@ fn expression_cmp(s: &str) -> IResult<ast::Expr> {
|
|||||||
)(s)
|
)(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn expression_bit(s: &str) -> IResult<ast::Expr> {
|
||||||
|
let (s, mut init) = map(expression_cmp, Some)(s)?;
|
||||||
|
fold_many0(
|
||||||
|
pair(
|
||||||
|
ws(pair(position, alt((char('&'), char('|'), char('^'))))),
|
||||||
|
expression_cmp,
|
||||||
|
),
|
||||||
|
move || init.take().unwrap(),
|
||||||
|
|left, ((position, op), right)| {
|
||||||
|
let op = match op {
|
||||||
|
'&' => ast::BinOp::And,
|
||||||
|
'|' => ast::BinOp::Or,
|
||||||
|
'^' => ast::BinOp::Xor,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
ast::Expr::BinOp {
|
||||||
|
position,
|
||||||
|
op,
|
||||||
|
left: Box::new(left.into()),
|
||||||
|
right: Box::new(right.into()),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)(s)
|
||||||
|
}
|
||||||
|
|
||||||
fn block_expression(s: &str) -> IResult<ast::Expr> {
|
fn block_expression(s: &str) -> IResult<ast::Expr> {
|
||||||
loop_(s)
|
loop_(s)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ fn tc_expression<'a>(context: &mut Context<'a>, expr: &mut ast::Expression<'a>)
|
|||||||
} else {
|
} else {
|
||||||
return Err(Error {
|
return Err(Error {
|
||||||
position,
|
position,
|
||||||
message: "Variable not found".into(),
|
message: format!("Variable '{}' not found", name),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,6 +228,73 @@ fn tc_expression<'a>(context: &mut Context<'a>, expr: &mut ast::Expression<'a>)
|
|||||||
}
|
}
|
||||||
Some(type_)
|
Some(type_)
|
||||||
}
|
}
|
||||||
|
ast::Expr::FuncCall {
|
||||||
|
position,
|
||||||
|
name,
|
||||||
|
ref mut params,
|
||||||
|
} => {
|
||||||
|
if let Some((ptypes, rtype)) = builtin_function_types(name) {
|
||||||
|
if params.len() != ptypes.len() {
|
||||||
|
return Err(Error {
|
||||||
|
position,
|
||||||
|
message: format!(
|
||||||
|
"Expected {} parameters but found {}",
|
||||||
|
ptypes.len(),
|
||||||
|
params.len()
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (index, (ptype, param)) in ptypes.iter().zip(params.iter_mut()).enumerate() {
|
||||||
|
tc_expression(context, param)?;
|
||||||
|
if param.type_.is_none() || param.type_.unwrap() != *ptype {
|
||||||
|
return Err(Error {
|
||||||
|
position,
|
||||||
|
message: format!(
|
||||||
|
"Param {} is {:?} but should be {:?}",
|
||||||
|
index + 1,
|
||||||
|
param.type_,
|
||||||
|
ptype
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rtype
|
||||||
|
} else {
|
||||||
|
return Err(Error {
|
||||||
|
position,
|
||||||
|
message: format!("Unknown function '{}'", name),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::Expr::Select {
|
||||||
|
position,
|
||||||
|
ref mut condition,
|
||||||
|
ref mut if_true,
|
||||||
|
ref mut if_false,
|
||||||
|
} => {
|
||||||
|
tc_expression(context, condition)?;
|
||||||
|
tc_expression(context, if_true)?;
|
||||||
|
tc_expression(context, if_false)?;
|
||||||
|
if condition.type_ != Some(ast::Type::I32) {
|
||||||
|
return Err(Error {
|
||||||
|
position,
|
||||||
|
message: "Condition of select has to be of type i32".into(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if if_true.type_ != if_false.type_ {
|
||||||
|
return Err(Error {
|
||||||
|
position,
|
||||||
|
message: "Types of select branches differ".into(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if if_true.type_.is_none() {
|
||||||
|
return Err(Error {
|
||||||
|
position,
|
||||||
|
message: "Types of select branches cannot be void".into(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if_true.type_
|
||||||
|
}
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -246,3 +313,13 @@ fn tc_mem_location<'a>(
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn builtin_function_types(name: &str) -> Option<(&'static [ast::Type], Option<ast::Type>)> {
|
||||||
|
use ast::Type::*;
|
||||||
|
let types: (&'static [ast::Type], Option<ast::Type>) = match name {
|
||||||
|
"sqrt" => (&[F32], Some(F32)),
|
||||||
|
"abs" => (&[F32], Some(F32)),
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
Some(types)
|
||||||
|
}
|
||||||
|
|||||||
26
trainride.hw
Normal file
26
trainride.hw
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import "uw8.ram" memory(2);
|
||||||
|
import "uw8.time" global mut time: i32;
|
||||||
|
|
||||||
|
export fn tic() {
|
||||||
|
let i: i32;
|
||||||
|
let defer t = time as f32 / 1000 as f32;
|
||||||
|
loop pixels {
|
||||||
|
let defer x = (i % 320 - 160) as f32;
|
||||||
|
let defer y = (i / 320) as f32 - 128.5;
|
||||||
|
let defer z = t + 20 as f32 / sqrt(x*x + y*y);
|
||||||
|
let defer z_int = z as i32;
|
||||||
|
let defer q = select(z_int % 9 >= 6, z, (z_int - z_int % 9 + 6) as f32);
|
||||||
|
let defer w = 9 as f32 / y + t;
|
||||||
|
let defer s = q - t;
|
||||||
|
let defer m = x * s / 50 as f32;
|
||||||
|
|
||||||
|
i?120 = select(y > 0 as f32 & w < q,
|
||||||
|
select(abs(x * (w - t)) < 9 as f32, 15, 7) - w as i32 % 2,
|
||||||
|
select(y * s > -99 as f32 / (m * m + 1 as f32),
|
||||||
|
select(q == z, z_int % 2, 3),
|
||||||
|
12 + (y / 23 as f32) as i32
|
||||||
|
)
|
||||||
|
) * 16;
|
||||||
|
branch_if (i := i + 1) < 320*256: pixels;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user