M src/backend/rust2.rs +5 -7
@@ 12,8 12,6 @@ use std::io::{self, Write};
use log::*;
-use crate::typeck::Tck;
-use crate::types::*;
use crate::*;
/// Compiles a `Type` into a a valid Rust type.
@@ 161,7 159,7 @@ pub(super) fn output(ir: &hir2::Ir) -> V
output
}
-fn compile_import(w: &mut impl Write, ir: &hir2::Import) -> io::Result<()> {
+fn compile_import(_w: &mut impl Write, _ir: &hir2::Import) -> io::Result<()> {
todo!()
}
@@ 421,10 419,10 @@ fn compile_expr(expr: &hir2::ENode) -> S
}
E::Block { body } => format!("{{\n{}\n}}", compile_exprs(body, ";\n")),
E::Let {
- varname,
+ varname: _,
typename: _,
- init,
- mutable,
+ init: _,
+ mutable: _,
} => {
todo!("tck")
/*
@@ 524,7 522,7 @@ fn compile_expr(expr: &hir2::ENode) -> S
// panic!("Should never happen, structs should always be tuples by now!");
format!("{}.{}", compile_expr(expr), elt)
}
- E::TupleRef { expr, elt } => {
+ E::TupleRef { expr: _, elt: _ } => {
todo!("tck")
/*
// We turn our structs into Rust tuples, so we need to
M src/builtins.rs +3 -0
@@ 2,6 2,7 @@
//! instead of having them scattered all over.
use crate::backend::Backend;
+use crate::hir2::{Type as Type2, TypeNode as TN};
use crate::types::*;
use crate::*;
@@ 11,6 12,7 @@ pub struct Builtin {
pub name: Sym,
/// The value's type, used for typechecking
pub sig: Type,
+ pub sig2: hir2::TypeNode,
/// The implmentation of the builtin as raw code for each particular
/// backend.
pub code: BTreeMap<Backend, String>,
@@ 103,6 105,7 @@ fn __{name}_to_u32(x: {name}) -> u32 {{
Builtin {
name: Sym::new(format!("__println_{name}")),
sig: Type::Func(vec![ty.clone()], Box::new(Type::unit()), vec![]),
+ sig2: TN::function(vec![ty.clone()], TN::unit()),
code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, println)]),
},
Builtin {
M src/hir2.rs +139 -0
@@ 62,6 62,145 @@ impl TypeNode {
pub fn get_mangled_name(&self) -> String {
self.t.get_mangled_name()
}
+
+ pub fn struct_(body: BTreeMap<Sym, Self>) -> Self {
+ Self::new(Type::Struct(body))
+ }
+
+ /// Shortcut for getting the type for an unknown int
+ pub fn iunknown() -> Self {
+ Self::new(Type::Prim(PrimType::UnknownInt))
+ }
+
+ /// Shortcut for getting the Type for a signed int of a particular size
+ pub fn isize(size: u8) -> Self {
+ Self::new(Type::Prim(PrimType::Int(size, true)))
+ }
+
+ /// Shortcut for getting the Type for an unsigned signed int of a particular size
+ pub fn usize(size: u8) -> Self {
+ Self::new(Type::Prim(PrimType::Int(size, false)))
+ }
+
+ /// Shortcut for getting the Type for I128
+ pub fn i128() -> Self {
+ Self::isize(16)
+ }
+
+ /// Shortcut for getting the Type for I64
+ pub fn i64() -> Self {
+ Self::isize(8)
+ }
+
+ /// Shortcut for getting the Type for I32
+ pub fn i32() -> Self {
+ Self::isize(4)
+ }
+
+ /// Shortcut for getting the type for I16
+ pub fn i16() -> Self {
+ Self::isize(2)
+ }
+
+ /// Shortcut for getting the type for I8
+ pub fn i8() -> Self {
+ Self::isize(1)
+ }
+
+ /// Shortcut for getting the Type for U128
+ pub fn u128() -> Self {
+ Self::usize(16)
+ }
+
+ /// Shortcut for getting the Type for U64
+ pub fn u64() -> Self {
+ Self::usize(8)
+ }
+
+ /// Shortcut for getting the Type for U32
+ pub fn u32() -> Self {
+ Self::usize(4)
+ }
+
+ /// Shortcut for getting the type for U16
+ pub fn u16() -> Self {
+ Self::usize(2)
+ }
+
+ /// Shortcut for getting the type for U8
+ pub fn u8() -> Self {
+ Self::usize(1)
+ }
+
+ /// Shortcut for getting the type for Bool
+ pub fn bool() -> Self {
+ Self::new(Type::Prim(PrimType::Bool))
+ }
+
+ /// Shortcut for getting the type for Unit
+ pub fn unit() -> Self {
+ Self::new(Type::Tuple(vec![]))
+ }
+
+ /// Shortcut for getting the type for Never
+ pub fn never() -> Self {
+ // Self::new(Named(Sym::new("Never"), vec![])
+ todo!()
+ }
+
+ /// Create a Tuple with the given values
+ pub fn tuple(args: &[Self]) -> Self {
+ Self::new(Type::Tuple(args.to_vec()))
+ }
+
+ /// Used in some tests
+ pub fn array(t: &TypeNode, len: usize) -> Self {
+ Self::new(Type::Array(t.clone(), len))
+ }
+
+ /// Shortcut for a named type with no type params
+ // pub fn named0(s: impl AsRef<str>) -> Self {
+ pub fn named0(_s: Sym) -> Self {
+ // Type::Var(s, vec![])
+ todo!()
+ }
+ pub fn function(params: &[TypeNode], rettype: &Type) -> Self {
+ TypeNode::new(Type::Func(
+ Vec::from(params),
+ TypeNode::new(rettype.clone()),
+ ))
+ }
+
+ pub fn is_func(&self) -> bool {
+ matches!(&*self.t, &Type::Func(_, _))
+ }
+
+ /// Takes a string and matches it against the builtin/
+ /// primitive types, returning the appropriate `TypeDef`
+ ///
+ /// If it is not a built-in type, or is a compound such
+ /// as a tuple or struct, returns None.
+ ///
+ /// The effective inverse of `TypeDef::get_name()`. Compound
+ /// types take more parsing to turn from strings to `TypeDef`'s
+ /// and are handled in `parser::parse_type()`.
+ pub fn get_primitive_type(s: &str) -> Option<Type> {
+ match s {
+ "I8" => Some(Type::i8()),
+ "I16" => Some(Type::i16()),
+ "I32" => Some(Type::i32()),
+ "I64" => Some(Type::i64()),
+ "I128" => Some(Type::i128()),
+ "U8" => Some(Type::u8()),
+ "U16" => Some(Type::u16()),
+ "U32" => Some(Type::u32()),
+ "U64" => Some(Type::u64()),
+ "U128" => Some(Type::u128()),
+ "Bool" => Some(Type::bool()),
+ "Never" => Some(Type::never()),
+ _ => None,
+ }
+ }
}
impl From<&Type> for TypeNode {
M src/nbe.rs +26 -5
@@ 45,7 45,7 @@ pub struct Env {
// figure out around vars and indices before I actually
// switch everything over. This is basically a placeholder
// to make the transition simpler later.
- _vals: Vector<ValBinding>,
+ vals: Vector<ValBinding>,
/// Where we record our association of expressions to their types
/// for type inference/unification. Maybe should be its own type passed
@@ 156,10 156,16 @@ impl Env {
self.types.len()
}
- /// Binds a variable to a name.
+ fn add_binding(&self, vl: ValBinding) -> Self {
+ let mut s = self.clone();
+ s.vals.push_back(vl.clone());
+ s
+ }
+
+ /// Binds a type variable to a name.
/// Not suuuuure yet whether we need to juggle bindings separately
/// from values? Yeah we do.
- fn add_binding(&self, vl: TypeBinding) -> Self {
+ fn add_type_binding(&self, vl: TypeBinding) -> Self {
let mut s = self.clone();
s.types.push_back(vl.clone());
s
@@ 171,7 177,7 @@ impl Env {
fn add_neu_binding(&self, name: Sym, kind: Kind) -> Self {
let varlvl = Lvl(self.size() + 1); // new var is at the top of our bindings env, plus one
let vartype = NType::Neu(Neutral::Var(varlvl, name));
- self.add_binding(TypeBinding::TypeVar(vartype, kind, name))
+ self.add_type_binding(TypeBinding::TypeVar(vartype, kind, name))
}
/// Look up a bound value by de Bruijn index.
@@ 867,6 873,20 @@ impl Env {
self.set_expr_type(e, &res);
Ok(res)
}
+
+ fn add_builtins(&self) -> Self {
+ let mut res = self.clone();
+ for builtin in &*builtins::BUILTINS {
+ let ty = self
+ .eval_type(builtin.sig2.clone())
+ .expect("Builtin has invalid type, shouldn't happen");
+ // let binding = ValBinding::Var(NType::, )
+ // *res = self.add_binding(builtin.)
+ // let ty = tck.insert_known(&builtin.sig);
+ // self.add_var(builtin.name, ty, false);
+ }
+ res
+ }
}
/// Our quote operation that just translates our NbE world back into
@@ 962,7 982,7 @@ pub fn inst(c: Closure, args: &[NType])
// bind the closure's args to the given type variable names, and eval it.
let mut new_env = env;
for ((nm, declared_kind), arg) in nms.into_iter().zip(args) {
- new_env = new_env.add_binding(TypeBinding::TypeVar(
+ new_env = new_env.add_type_binding(TypeBinding::TypeVar(
arg.clone(),
declared_kind.clone(),
nm.clone(),
@@ 1091,6 1111,7 @@ fn predeclare_decls(_env: &mut Env, ir:
/// Or just the part of the Env that
pub fn typecheck(ir: &hir2::Ir) -> Result<(), String> {
let env = &mut Env::default();
+ *env = env.add_builtins();
predeclare_decls(env, &ir)?;
typecheck_typedefs(env, &ir.typedefs)?;
typecheck_consts(env, &ir.consts)?;
M src/simptbl.rs +1 -1
@@ 8,7 8,7 @@
//!
//! Just use this as a piece to build other more complicated operations atop.
-use std::cell::RefCell;
+// use std::cell::RefCell;
use crate::*;
M tests/programs/hello1.gt => tests/programs/test_hello2.gt +0 -0