Skip to content

Commit

Permalink
finally move builtin types into builtin.rs
Browse files Browse the repository at this point in the history
  • Loading branch information
jmgrosen committed Jun 8, 2024
1 parent 0867ccb commit 6dca254
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 88 deletions.
91 changes: 71 additions & 20 deletions src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,63 +5,114 @@ use string_interner::DefaultStringInterner;
use crate::expr::Symbol;
use crate::ir1::{DebruijnIndex, Op};
use crate::ir2;
use crate::typing::{Clock, Kind, Type};

type BuiltinTypeFn = fn(&mut DefaultStringInterner) -> Type;

#[derive(Clone, Copy, Debug)]
pub struct Builtin {
pub struct Builtin<Ty> {
pub n_args: usize,
// there's gotta be a better way to do this
pub type_: Ty,
pub ir2_expr: &'static ir2::Expr<'static>,
}

impl Builtin {
const fn new(n_args: usize, ir2_expr: &'static ir2::Expr<'static>) -> Builtin {
Builtin { n_args, ir2_expr }
impl<Ty> Builtin<Ty> {
const fn new(n_args: usize, type_: Ty, ir2_expr: &'static ir2::Expr<'static>) -> Builtin<Ty> {
Builtin { n_args, type_, ir2_expr }
}
}

macro_rules! builtins {
( $($name:ident [ $nargs:literal ] [ $ir2e:expr ] ),* $(,)? ) => {
const BUILTINS: &[(&'static str, Builtin)] = &[
( $($name:ident [ $nargs:literal ] { $interner:pat => $type_expr:expr } [ $ir2e:expr ] ),* $(,)? ) => {
mod builtin_types {
use super::*;

$(
(stringify!($name), Builtin::new($nargs, $ir2e)),
pub fn $name($interner: &mut DefaultStringInterner) -> Type {
$type_expr
}
)*
}
const BUILTINS: &[(&'static str, Builtin<BuiltinTypeFn>)] = &[
$(
(stringify!($name), Builtin::new($nargs, builtin_types::$name, $ir2e)),
)*
];
}
}

fn g(interner: &mut DefaultStringInterner, name: &'static str) -> Symbol {
interner.get_or_intern_static(name)
}

builtins!(
pi[0]
{ _ => Type::Sample }
[ &ir2::Expr::Op(Op::Pi, &[]) ],
sin[1]
{ _ => Type::Function(Type::Sample.into(), Type::Sample.into()) }
[ &ir2::Expr::Op(Op::Sin, &[&ir2::Expr::Var(DebruijnIndex(0))]) ],
cos[1]
{ _ => Type::Function(Type::Sample.into(), Type::Sample.into()) }
[ &ir2::Expr::Op(Op::Cos, &[&ir2::Expr::Var(DebruijnIndex(0))]) ],
add[2]
[ &ir2::Expr::Op(Op::FAdd, &[&ir2::Expr::Var(DebruijnIndex(0)), &ir2::Expr::Var(DebruijnIndex(1))]) ],
sub[2]
// TODO: make sure this order is correct?
[ &ir2::Expr::Op(Op::FSub, &[&ir2::Expr::Var(DebruijnIndex(0)), &ir2::Expr::Var(DebruijnIndex(1))]) ],
mul[2]
[ &ir2::Expr::Op(Op::FMul, &[&ir2::Expr::Var(DebruijnIndex(0)), &ir2::Expr::Var(DebruijnIndex(1))]) ],
div[2]
[ &ir2::Expr::Op(Op::FDiv, &[&ir2::Expr::Var(DebruijnIndex(0)), &ir2::Expr::Var(DebruijnIndex(1))]) ],
addone[1]
[ &ir2::Expr::Op(Op::FAdd, &[&ir2::Expr::Var(DebruijnIndex(0)), &ir2::Expr::Op(Op::Const(crate::ir1::Value::Sample(1.0)), &[])]) ],
reinterpi[1]
{ _ => Type::Function(Type::Index.into(), Type::Sample.into()) }
[ &ir2::Expr::Op(Op::ReinterpI2F, &[&ir2::Expr::Var(DebruijnIndex(0))]) ],
reinterpf[1]
{ _ => Type::Function(Type::Sample.into(), Type::Index.into()) }
[ &ir2::Expr::Op(Op::ReinterpF2I, &[&ir2::Expr::Var(DebruijnIndex(0))]) ],
cast[1]
{ _ => Type::Function(Type::Index.into(), Type::Sample.into()) }
[ &ir2::Expr::Op(Op::CastI2F, &[&ir2::Expr::Var(DebruijnIndex(0))]) ],
since_tick[1]
{ i => Type::Forall(g(i, "c"), Kind::Clock, Type::Stream(Clock::from_var(g(i, "c")), Type::Sample.into()).into()) }
[ &ir2::Expr::Op(Op::SinceLastTickStream, &[&ir2::Expr::Var(DebruijnIndex(0))]) ],
wait[1]
{ i => Type::Forall(g(i, "c"), Kind::Clock, Type::Later(Clock::from_var(g(i, "c")), Type::Unit.into()).into()) }
[ &ir2::Expr::Op(Op::Wait, &[&ir2::Expr::Var(DebruijnIndex(0))]) ],
sched[3]
{ i =>
Type::Forall(g(i, "a"), Kind::Type, Box::new(
Type::Forall(g(i, "c"), Kind::Clock, Box::new(
Type::Forall(g(i, "d"), Kind::Clock, Box::new(
Type::Function(Box::new(
Type::Later(Clock::from_var(g(i, "c")), Box::new(Type::TypeVar(g(i, "a"))))
), Box::new(
Type::Later(Clock::from_var(g(i, "d")), Box::new(
Type::Sum(Box::new(
Type::Unit
), Box::new(
Type::TypeVar(g(i, "a"))
))
))
))
))
))
))
}
[ &ir2::Expr::Op(Op::Schedule, &[&ir2::Expr::Var(DebruijnIndex(2)), &ir2::Expr::Var(DebruijnIndex(1)), &ir2::Expr::Var(DebruijnIndex(0))]) ],
);

pub type BuiltinsMap = HashMap<Symbol, Builtin>;
pub type BuiltinsMap = HashMap<Symbol, Builtin<Type>>;

pub fn make_builtins(interner: &mut DefaultStringInterner) -> BuiltinsMap {
BUILTINS.iter().map(|&(name, builtin)| (interner.get_or_intern_static(name), builtin)).collect()
BUILTINS.iter().map(|&(name, builtin)| {
let builtin_constructed = Builtin {
n_args: builtin.n_args,
type_: (builtin.type_)(interner),
ir2_expr: builtin.ir2_expr,
};
(interner.get_or_intern_static(name), builtin_constructed)
}).collect()
}

// TODO: need to synchronize the order of these with the
// runtime. maybe we could fetch these from the runtime somehow? hmmmm
const BUILTIN_CLOCKS: &[&'static str] = &[
"audio",
];

pub fn make_builtin_clocks(interner: &mut DefaultStringInterner) -> Vec<Symbol> {
BUILTIN_CLOCKS.iter().map(|&name| interner.get_or_intern_static(name)).collect()
}
85 changes: 19 additions & 66 deletions src/toplevel.rs
Original file line number Diff line number Diff line change
@@ -1,82 +1,35 @@
use std::fmt;
use std::error::Error;
use std::iter;
use std::collections::{HashMap, HashSet};
use std::collections::HashMap;

use crate::expr::{Expr, Symbol, TopLevelDefBody};
use string_interner::{StringInterner, DefaultStringInterner};

use typed_arena::Arena;

use crate::builtin::make_builtins;
use crate::builtin::{make_builtin_clocks, make_builtins, BuiltinsMap};
use crate::parse::{self, Parser};
use crate::typing::{self, Globals, Typechecker};
use crate::{ir1, ir2, wasm, util};

use crate::typing::{Type, Kind, Clock};
use crate::typing::Type;

pub struct TopLevel<'a> {
pub interner: DefaultStringInterner,
pub arena: &'a Arena<Expr<'a, tree_sitter::Range>>,
pub builtins: BuiltinsMap,
pub globals: Globals,
pub global_clocks: HashSet<Symbol>,
pub global_clocks: Vec<Symbol>,
}

impl<'a> TopLevel<'a> {
pub fn new(arena: &'a Arena<Expr<'a, tree_sitter::Range>>) -> TopLevel<'a> {
let mut interner = StringInterner::new();
let mut globals: Globals = HashMap::new();
let builtins = make_builtins(&mut interner);
let globals = builtins.iter().map(|(&name, builtin)| (name, builtin.type_.clone())).collect();
let builtin_clocks = make_builtin_clocks(&mut interner);

// TODO: move this to the builtins themselves
let add = interner.get_or_intern_static("add");
let div = interner.get_or_intern_static("div");
let mul = interner.get_or_intern_static("mul");
let pi = interner.get_or_intern_static("pi");
let sin = interner.get_or_intern_static("sin");
let addone = interner.get_or_intern_static("addone");
let reinterpi = interner.get_or_intern_static("reinterpi");
let reinterpf = interner.get_or_intern_static("reinterpf");
let cast = interner.get_or_intern_static("cast");
globals.insert(add, typing::Type::Function(Box::new(typing::Type::Sample), Box::new(typing::Type::Function(Box::new(typing::Type::Sample), Box::new(typing::Type::Sample)))));
globals.insert(div, typing::Type::Function(Box::new(typing::Type::Sample), Box::new(typing::Type::Function(Box::new(typing::Type::Sample), Box::new(typing::Type::Sample)))));
globals.insert(mul, typing::Type::Function(Box::new(typing::Type::Sample), Box::new(typing::Type::Function(Box::new(typing::Type::Sample), Box::new(typing::Type::Sample)))));
globals.insert(pi, typing::Type::Sample);
globals.insert(sin, typing::Type::Function(Box::new(typing::Type::Sample), Box::new(typing::Type::Sample)));
globals.insert(addone, typing::Type::Function(Box::new(typing::Type::Sample), Box::new(typing::Type::Sample)));
globals.insert(reinterpi, typing::Type::Function(Box::new(typing::Type::Index), Box::new(typing::Type::Sample)));
globals.insert(reinterpf, typing::Type::Function(Box::new(typing::Type::Sample), Box::new(typing::Type::Index)));
globals.insert(cast, typing::Type::Function(Box::new(typing::Type::Index), Box::new(typing::Type::Sample)));
let since_tick = interner.get_or_intern_static("since_tick");
let c = interner.get_or_intern_static("c");
globals.insert(since_tick, typing::Type::Forall(c, Kind::Clock, Box::new(typing::Type::Stream(typing::Clock::from_var(c), Box::new(typing::Type::Sample)))));
let wait = interner.get_or_intern_static("wait");
globals.insert(wait, typing::Type::Forall(c, Kind::Clock, Box::new(typing::Type::Later(Clock::from_var(c), Box::new(typing::Type::Unit)))));
let sched = interner.get_or_intern_static("sched");
let a = interner.get_or_intern_static("a");
let d = interner.get_or_intern_static("d");
globals.insert(sched, typing::Type::Forall(a, Kind::Type, Box::new(
typing::Type::Forall(c, Kind::Clock, Box::new(
typing::Type::Forall(d, Kind::Clock, Box::new(
typing::Type::Function(Box::new(
typing::Type::Later(Clock::from_var(c), Box::new(Type::TypeVar(a)))
), Box::new(
typing::Type::Later(Clock::from_var(d), Box::new(
Type::Sum(Box::new(
Type::Unit
), Box::new(
Type::TypeVar(a)
))
))
))
))
))
)));

let mut global_clock_names = HashSet::new();
let audio = interner.get_or_intern_static("audio");
global_clock_names.insert(audio);

TopLevel { arena, interner, globals, global_clocks: global_clock_names }
TopLevel { arena, interner, builtins, globals, global_clocks: builtin_clocks }
}

pub fn make_parser<'b>(&'b mut self) -> Parser<'b, 'a> {
Expand Down Expand Up @@ -164,10 +117,9 @@ pub fn compile<'a>(toplevel: &mut TopLevel<'a>, code: String) -> TopLevelResult<

let defs = elabbed_file.defs;

let builtins = make_builtins(&mut toplevel.interner);
let mut builtin_globals = HashMap::new();
let mut global_defs = Vec::new();
for (name, builtin) in builtins.into_iter() {
for (&name, builtin) in toplevel.builtins.iter() {
builtin_globals.insert(name, ir1::Global(global_defs.len() as u32));
global_defs.push(ir2::GlobalDef::Func {
rec: false,
Expand All @@ -178,11 +130,12 @@ pub fn compile<'a>(toplevel: &mut TopLevel<'a>, code: String) -> TopLevelResult<
}

let mut global_clocks = HashMap::new();
let audio = toplevel.interner.get_or_intern_static("audio");
global_clocks.insert(audio, ir1::Global(global_defs.len() as u32));
global_defs.push(ir2::GlobalDef::ClosedExpr {
body: &ir2::Expr::Var(ir1::DebruijnIndex(0)),
});
for &name in toplevel.global_clocks.iter() {
global_clocks.insert(name, ir1::Global(global_defs.len() as u32));
global_defs.push(ir2::GlobalDef::ClosedExpr {
body: &ir2::Expr::Var(ir1::DebruijnIndex(0)),
});
}
for def in defs.iter() {
match def.body {
TopLevelDefBody::Def { .. } => {
Expand All @@ -205,11 +158,11 @@ pub fn compile<'a>(toplevel: &mut TopLevel<'a>, code: String) -> TopLevelResult<


let mut main = None;
let defs_ir1: HashMap<Name, &ir1::Expr<'_>> = iter::once({
let defs_ir1: HashMap<Name, &ir1::Expr<'_>> = toplevel.global_clocks.iter().enumerate().map(|(i, &name)| {
let clock_expr = &*expr_under_arena.alloc(
ir1::Expr::Op(ir1::Op::GetClock(0), &[])
ir1::Expr::Op(ir1::Op::GetClock(i as u32), &[])
);
(Name::Clock(audio), clock_expr)
(Name::Clock(name), clock_expr)
}).chain(defs.iter().map(|def| {
match def.body {
TopLevelDefBody::Def { expr, .. } => {
Expand Down
4 changes: 2 additions & 2 deletions src/typing.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use core::fmt;
use std::collections::{HashMap, HashSet};
use std::collections::HashMap;
use std::cmp::Ordering;
use std::rc::Rc;
use std::fmt::Write;
Expand Down Expand Up @@ -771,7 +771,7 @@ impl<'a> fmt::Display for PrettyTypeError<'a, tree_sitter::Range> {

pub struct Typechecker<'a, 'b, R> {
pub globals: &'a mut Globals,
pub global_clocks: &'a HashSet<Symbol>,
pub global_clocks: &'a [Symbol],
pub interner: &'a mut DefaultStringInterner,
pub arena: &'b Arena<Expr<'b, R>>,
}
Expand Down

0 comments on commit 6dca254

Please sign in to comment.