implement const

This commit is contained in:
2022-02-26 11:46:38 +01:00
parent b41b7f250c
commit e608d3bb4b
7 changed files with 190 additions and 88 deletions

View File

@@ -1,29 +1,8 @@
import "env.memory" memory(4); include "uw8.cwa"
import "env.pow" fn pow(f32, f32) -> f32; const SWEETY = PALETTE + 192 * 4;
import "env.sin" fn sin(f32) -> f32;
import "env.cos" fn cos(f32) -> f32;
import "env.atan2" fn atan2(f32, f32) -> f32;
import "env.tan" fn tan(f32) -> f32;
import "env.atan" fn atan(f32) -> f32;
import "env.rectangle" fn rect(f32, f32, f32, f32, i32);
//export fn tic(time: i32) { export fn upd() {
// let i: i32;
// loop pixels {
// let lazy x = (i % 320) as f32 - 160.5;
// let lazy y = (i / 320 - 120) as f32;
//
// let lazy dist = 4000 as f32 / sqrt(x*x + y*y + 10 as f32);
// let lazy angle = atan2(x, y) * (64.0 / 3.141);
//
// i?120 = ((((dist + time as f32 / 63 as f32) as i32 ^ angle as i32) #% 32 + 32) >> ((dist as i32 - i % 7 * 3) / 40)) + 192;
//
// branch_if (i := i + 1) < 320*240: pixels;
// }
//}
export fn tic(time: i32) {
let i: i32; let i: i32;
loop colors { loop colors {
rect((i % 16 * 15) as f32, (i / 16 * 15) as f32, 15 as f32, 15 as f32, i); rect((i % 16 * 15) as f32, (i / 16 * 15) as f32, 15 as f32, 15 as f32, i);
@@ -43,7 +22,7 @@ start fn gen_palette() {
let lazy a = max(llimit, min(ulimit, c)) * (scale + 0.05); let lazy a = max(llimit, min(ulimit, c)) * (scale + 0.05);
let lazy b = scale * scale * 0.8; let lazy b = scale * scale * 0.8;
let inline v = (select(i < 11*16*3, max(0 as f32, min(a + b - a * b, 1 as f32)), scale) * 255 as f32) as i32; let inline v = (select(i < 11*16*3, max(0 as f32, min(a + b - a * b, 1 as f32)), scale) * 255 as f32) as i32;
(i%3 + i/3*4)?(120+320*240) = v; (i%3 + i/3*4)?(PALETTE) = v;
avg = (avg + c) * 0.5; avg = (avg + c) * 0.5;
branch_if i := i - 1: gradients; branch_if i := i - 1: gradients;
@@ -56,15 +35,15 @@ start fn gen_palette() {
let lazy first_step = index >= 32; let lazy first_step = index >= 32;
let inline src1 = select(first_step, index % 32 / 2, index * 2); let inline src1 = select(first_step, index % 32 / 2, index * 2);
let inline src2 = select(first_step, (index + 1) % 32 / 2, index * 2 + 1); let inline src2 = select(first_step, (index + 1) % 32 / 2, index * 2 + 1);
let inline c1 = (src1 * 4 + channel)?(120+320*240+192*4); let inline c1 = (src1 * 4 + channel)?SWEETY;
let inline c2 = (src2 * 4 + channel)?(120+320*240+192*4); let inline c2 = (src2 * 4 + channel)?SWEETY;
i?(120+320*240+192*4) = (c1 + c2) * (3 + first_step) / 8; i?(SWEETY) = (c1 + c2) * (3 + first_step) / 8;
branch_if (i := i - 1) >= 0: expand_sweetie; branch_if (i := i - 1) >= 0: expand_sweetie;
} }
} }
data 120+320*240+192*4 { data SWEETY {
i32( i32(
0x2c1c1a, 0x2c1c1a,
0x5d275d, 0x5d275d,

13
examples/microw8/uw8.cwa Normal file
View File

@@ -0,0 +1,13 @@
import "env.memory" memory(4);
import "env.pow" fn pow(f32, f32) -> f32;
import "env.sin" fn sin(f32) -> f32;
import "env.cos" fn cos(f32) -> f32;
import "env.atan2" fn atan2(f32, f32) -> f32;
import "env.tan" fn tan(f32) -> f32;
import "env.atan" fn atan(f32) -> f32;
import "env.rectangle" fn rect(f32, f32, f32, f32, i32);
const FRAMEBUFFER = 120;
const PALETTE = 0x13000;
const FONT = 0x13400;

View File

@@ -8,7 +8,8 @@ pub struct Script {
pub global_vars: Vec<GlobalVar>, pub global_vars: Vec<GlobalVar>,
pub functions: Vec<Function>, pub functions: Vec<Function>,
pub data: Vec<Data>, pub data: Vec<Data>,
pub includes: Vec<Include> pub includes: Vec<Include>,
pub consts: Vec<GlobalConst>,
} }
impl Script { impl Script {
@@ -17,6 +18,7 @@ impl Script {
self.global_vars.append(&mut other.global_vars); self.global_vars.append(&mut other.global_vars);
self.functions.append(&mut other.functions); self.functions.append(&mut other.functions);
self.data.append(&mut other.data); self.data.append(&mut other.data);
self.consts.append(&mut other.consts);
assert!(other.includes.is_empty()); assert!(other.includes.is_empty());
} }
} }
@@ -27,7 +29,8 @@ pub enum TopLevelItem {
GlobalVar(GlobalVar), GlobalVar(GlobalVar),
Function(Function), Function(Function),
Data(Data), Data(Data),
Include(Include) Include(Include),
Const(GlobalConst),
} }
#[derive(Debug)] #[derive(Debug)]
@@ -67,6 +70,14 @@ pub struct GlobalVar {
pub mutable: bool, pub mutable: bool,
} }
#[derive(Debug)]
pub struct GlobalConst {
pub span: Span,
pub name: String,
pub value: Expression,
pub type_: Option<Type>,
}
#[derive(Debug)] #[derive(Debug)]
pub struct Function { pub struct Function {
pub span: Span, pub span: Span,
@@ -170,7 +181,7 @@ pub enum DataType {
F64, F64,
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct MemoryLocation { pub struct MemoryLocation {
pub span: Span, pub span: Span,
pub size: MemSize, pub size: MemSize,
@@ -178,7 +189,7 @@ pub struct MemoryLocation {
pub right: Box<Expression>, pub right: Box<Expression>,
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Expression { pub struct Expression {
pub type_: Option<Type>, pub type_: Option<Type>,
pub expr: Expr, pub expr: Expr,
@@ -213,9 +224,16 @@ impl Expression {
_ => panic!("Expected F64Const"), _ => panic!("Expected F64Const"),
} }
} }
pub fn is_const(&self) -> bool {
match self.expr {
Expr::I32Const(_) | Expr::I64Const(_) | Expr::F32Const(_) | Expr::F64Const(_) => true,
_ => false,
}
}
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum Expr { pub enum Expr {
Block { Block {
statements: Vec<Expression>, statements: Vec<Expression>,
@@ -355,7 +373,7 @@ pub enum BinOp {
pub enum MemSize { pub enum MemSize {
Byte, Byte,
Word, Word,
Float Float,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]

View File

@@ -1,35 +1,103 @@
use crate::ast; use std::collections::HashMap;
use crate::{
ast,
parser::{Sources, Span},
typecheck::{report_duplicate_definition, report_error},
};
type Result<T> = std::result::Result<T, ()>;
pub fn fold_script(script: &mut ast::Script, sources: &Sources) -> Result<()> {
let mut context = Context {
consts: HashMap::new(),
sources,
};
fold_consts(&mut context, &mut script.consts)?;
pub fn fold_script(script: &mut ast::Script) {
for var in &mut script.global_vars { for var in &mut script.global_vars {
fold_expr(&mut var.value); fold_expr(&context, &mut var.value);
} }
for func in &mut script.functions { for func in &mut script.functions {
fold_expr(&mut func.body); fold_expr(&context, &mut func.body);
} }
for data in &mut script.data { for data in &mut script.data {
fold_expr(&mut data.offset); fold_expr(&context, &mut data.offset);
for values in &mut data.data { for values in &mut data.data {
match values { match values {
ast::DataValues::Array { values, .. } => { ast::DataValues::Array { values, .. } => {
for value in values { for value in values {
fold_expr(value); fold_expr(&context, value);
} }
} }
ast::DataValues::String(_) | ast::DataValues::File { .. } => (), ast::DataValues::String(_) | ast::DataValues::File { .. } => (),
} }
} }
} }
Ok(())
} }
fn fold_mem_location(mem_location: &mut ast::MemoryLocation) { struct Context<'a> {
fold_expr(&mut mem_location.left); consts: HashMap<String, ast::Expr>,
fold_expr(&mut mem_location.right); sources: &'a Sources,
} }
fn fold_expr(expr: &mut ast::Expression) { fn fold_consts(context: &mut Context, consts: &mut [ast::GlobalConst]) -> Result<()> {
let mut spans: HashMap<&str, Span> = HashMap::new();
for cnst in consts.iter_mut() {
if let Some(prev_span) = spans.insert(&cnst.name, cnst.span.clone()) {
report_duplicate_definition(
"Const already defined",
&cnst.span,
&prev_span,
context.sources,
)?;
}
}
while context.consts.len() < consts.len() {
let mut making_progress = false;
for cnst in consts.iter_mut() {
if !context.consts.contains_key(&cnst.name) {
fold_expr(context, &mut cnst.value);
if cnst.value.is_const() {
context
.consts
.insert(cnst.name.clone(), cnst.value.expr.clone());
making_progress = true;
}
}
}
if !making_progress {
break;
}
}
let mut result = Ok(());
for cnst in consts {
if !context.consts.contains_key(&cnst.name) {
result = report_error(
&format!("Failed to fold const '{}'", cnst.name),
&cnst.span,
context.sources,
);
}
}
result
}
fn fold_mem_location(context: &Context, mem_location: &mut ast::MemoryLocation) {
fold_expr(context, &mut mem_location.left);
fold_expr(context, &mut mem_location.right);
}
fn fold_expr(context: &Context, expr: &mut ast::Expression) {
use ast::BinOp::*; use ast::BinOp::*;
match expr.expr { match expr.expr {
ast::Expr::Block { ast::Expr::Block {
@@ -37,15 +105,15 @@ fn fold_expr(expr: &mut ast::Expression) {
ref mut final_expression, ref mut final_expression,
} => { } => {
for stmt in statements { for stmt in statements {
fold_expr(stmt); fold_expr(context, stmt);
} }
if let Some(ref mut expr) = final_expression { if let Some(ref mut expr) = final_expression {
fold_expr(expr); fold_expr(context, expr);
} }
} }
ast::Expr::Let { ref mut value, .. } => { ast::Expr::Let { ref mut value, .. } => {
if let Some(ref mut expr) = value { if let Some(ref mut expr) = value {
fold_expr(expr); fold_expr(context, expr);
} }
} }
ast::Expr::Poke { ast::Expr::Poke {
@@ -53,12 +121,12 @@ fn fold_expr(expr: &mut ast::Expression) {
ref mut value, ref mut value,
.. ..
} => { } => {
fold_mem_location(mem_location); fold_mem_location(context, mem_location);
fold_expr(value); fold_expr(context, value);
} }
ast::Expr::Peek(ref mut mem_location) => fold_mem_location(mem_location), ast::Expr::Peek(ref mut mem_location) => fold_mem_location(context, mem_location),
ast::Expr::UnaryOp { op, ref mut value } => { ast::Expr::UnaryOp { op, ref mut value } => {
fold_expr(value); fold_expr(context, value);
let result = match (op, &value.expr) { let result = match (op, &value.expr) {
(ast::UnaryOp::Negate, ast::Expr::I32Const(value)) => { (ast::UnaryOp::Negate, ast::Expr::I32Const(value)) => {
Some(ast::Expr::I32Const(-*value)) Some(ast::Expr::I32Const(-*value))
@@ -90,8 +158,8 @@ fn fold_expr(expr: &mut ast::Expression) {
ref mut right, ref mut right,
.. ..
} => { } => {
fold_expr(left); fold_expr(context, left);
fold_expr(right); fold_expr(context, right);
match (&left.expr, &right.expr) { match (&left.expr, &right.expr) {
(&ast::Expr::I32Const(left), &ast::Expr::I32Const(right)) => { (&ast::Expr::I32Const(left), &ast::Expr::I32Const(right)) => {
let result = match op { let result = match op {
@@ -237,24 +305,28 @@ fn fold_expr(expr: &mut ast::Expression) {
ast::Expr::I32Const(_) ast::Expr::I32Const(_)
| ast::Expr::I64Const(_) | ast::Expr::I64Const(_)
| ast::Expr::F32Const(_) | ast::Expr::F32Const(_)
| ast::Expr::F64Const(_) | ast::Expr::F64Const(_) => (),
| ast::Expr::Variable { .. } => (), ast::Expr::Variable { ref name, .. } => {
ast::Expr::Assign { ref mut value, .. } => fold_expr(value), if let Some(value) = context.consts.get(name) {
ast::Expr::LocalTee { ref mut value, .. } => fold_expr(value), expr.expr = value.clone();
ast::Expr::Loop { ref mut block, .. } => fold_expr(block), }
ast::Expr::LabelBlock { ref mut block, .. } => fold_expr(block), }
ast::Expr::Assign { ref mut value, .. } => fold_expr(context, value),
ast::Expr::LocalTee { ref mut value, .. } => fold_expr(context, value),
ast::Expr::Loop { ref mut block, .. } => fold_expr(context, block),
ast::Expr::LabelBlock { ref mut block, .. } => fold_expr(context, block),
ast::Expr::Branch(_) => (), ast::Expr::Branch(_) => (),
ast::Expr::BranchIf { ast::Expr::BranchIf {
ref mut condition, .. ref mut condition, ..
} => fold_expr(condition), } => fold_expr(context, condition),
ast::Expr::Cast { ref mut value, .. } => fold_expr(value), ast::Expr::Cast { ref mut value, .. } => fold_expr(context, value),
ast::Expr::FuncCall { ast::Expr::FuncCall {
ref name, ref name,
ref mut params, ref mut params,
.. ..
} => { } => {
for param in params.iter_mut() { for param in params.iter_mut() {
fold_expr(param); fold_expr(context, param);
} }
use ast::Expr::*; use ast::Expr::*;
let params: Vec<_> = params.iter().map(|e| &e.expr).collect(); let params: Vec<_> = params.iter().map(|e| &e.expr).collect();
@@ -269,31 +341,31 @@ fn fold_expr(expr: &mut ast::Expression) {
ref mut if_false, ref mut if_false,
.. ..
} => { } => {
fold_expr(condition); fold_expr(context, condition);
fold_expr(if_true); fold_expr(context, if_true);
fold_expr(if_false); fold_expr(context, if_false);
} }
ast::Expr::If { ast::Expr::If {
ref mut condition, ref mut condition,
ref mut if_true, ref mut if_true,
ref mut if_false, ref mut if_false,
} => { } => {
fold_expr(condition); fold_expr(context, condition);
fold_expr(if_true); fold_expr(context, if_true);
if let Some(ref mut if_false) = if_false { if let Some(ref mut if_false) = if_false {
fold_expr(if_false); fold_expr(context, if_false);
} }
} }
ast::Expr::Return { ast::Expr::Return {
value: Some(ref mut value), value: Some(ref mut value),
} => fold_expr(value), } => fold_expr(context, value),
ast::Expr::Return { value: None } => (), ast::Expr::Return { value: None } => (),
ast::Expr::First { ast::Expr::First {
ref mut value, ref mut value,
ref mut drop, ref mut drop,
} => { } => {
fold_expr(value); fold_expr(context, value);
fold_expr(drop); fold_expr(context, drop);
} }
ast::Expr::Error => unreachable!(), ast::Expr::Error => unreachable!(),
} }

View File

@@ -1,7 +1,7 @@
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use parser::Sources;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::path::Path; use std::path::Path;
use parser::Sources;
mod ast; mod ast;
mod constfold; mod constfold;
@@ -40,7 +40,10 @@ pub fn compile_file<P: AsRef<Path>>(path: P, options: Options) -> Result<Vec<u8>
includes::resolve_includes(&mut new_script, &path)?; includes::resolve_includes(&mut new_script, &path)?;
for include in std::mem::take(&mut new_script.includes) { for include in std::mem::take(&mut new_script.includes) {
let mut path = path.parent().expect("Script path has no parent").to_path_buf(); let mut path = path
.parent()
.expect("Script path has no parent")
.to_path_buf();
path.push(include.path); path.push(include.path);
pending_files.push((path, Some(include.span))); pending_files.push((path, Some(include.span)));
} }
@@ -59,8 +62,9 @@ pub fn compile_file<P: AsRef<Path>>(path: P, options: Options) -> Result<Vec<u8>
} }
} }
if constfold::fold_script(&mut script, &sources).is_err() {
constfold::fold_script(&mut script); bail!("Constant folding failed");
}
if typecheck::tc_script(&mut script, &sources).is_err() { if typecheck::tc_script(&mut script, &sources).is_err() {
bail!("Type check failed"); bail!("Type check failed");
} }

View File

@@ -925,6 +925,21 @@ fn script_parser() -> impl Parser<Token, ast::Script, Error = ScriptError> + Clo
}) })
.boxed(); .boxed();
let global_const = just(Token::Ident("const".to_string()))
.ignore_then(identifier)
.then(just(Token::Ctrl(':')).ignore_then(type_parser()).or_not())
.then(just(Token::Op("=".to_string())).ignore_then(expression.clone()))
.then_ignore(just(Token::Ctrl(';')))
.map_with_span(|((name, type_), value), span| {
ast::TopLevelItem::Const(ast::GlobalConst {
name,
type_,
value,
span,
})
})
.boxed();
let data_i8 = just(Token::Ident("i8".to_string())) let data_i8 = just(Token::Ident("i8".to_string()))
.to(ast::DataType::I8) .to(ast::DataType::I8)
.or(just(Token::Ident("i16".to_string())).to(ast::DataType::I16)) .or(just(Token::Ident("i16".to_string())).to(ast::DataType::I16))
@@ -975,17 +990,17 @@ fn script_parser() -> impl Parser<Token, ast::Script, Error = ScriptError> + Clo
|path, span| ast::TopLevelItem::Include(ast::Include { span, path }), |path, span| ast::TopLevelItem::Include(ast::Include { span, path }),
)); ));
import.or(function).or(global).or(data).or(include).boxed() import
.or(function)
.or(global)
.or(data)
.or(include)
.or(global_const)
.boxed()
}; };
top_level_item.repeated().then_ignore(end()).map(|items| { top_level_item.repeated().then_ignore(end()).map(|items| {
let mut script = ast::Script { let mut script = ast::Script::default();
imports: Vec::new(),
global_vars: Vec::new(),
functions: Vec::new(),
data: Vec::new(),
includes: Vec::new(),
};
for item in items { for item in items {
match item { match item {
ast::TopLevelItem::Import(i) => script.imports.push(i), ast::TopLevelItem::Import(i) => script.imports.push(i),
@@ -993,6 +1008,7 @@ fn script_parser() -> impl Parser<Token, ast::Script, Error = ScriptError> + Clo
ast::TopLevelItem::Function(f) => script.functions.push(f), ast::TopLevelItem::Function(f) => script.functions.push(f),
ast::TopLevelItem::Data(d) => script.data.push(d), ast::TopLevelItem::Data(d) => script.data.push(d),
ast::TopLevelItem::Include(i) => script.includes.push(i), ast::TopLevelItem::Include(i) => script.includes.push(i),
ast::TopLevelItem::Const(c) => script.consts.push(c),
} }
} }
script script

View File

@@ -298,7 +298,7 @@ impl LocalVars {
} }
} }
fn report_duplicate_definition( pub fn report_duplicate_definition(
msg: &str, msg: &str,
span: &Span, span: &Span,
prev_span: &Span, prev_span: &Span,