M src/backend/rust.rs +3 -4
@@ 1,8 1,7 @@
//! Compile our HIR to Rust.
//! This is kinda silly, but hey why not.
//!
-//!
-//! Potential improvements:
+//! Potential optimizations:
//! * Use something smarter than strings to collect output -- could just
//! output to a stream like the formatter does. This is a little weird though 'cause
//! we often want to build pieces of code, and then combine them together at the end.
@@ 96,7 95,7 @@ fn compile_typename(t: &Type) -> Cow<'st
// }
// accm += ")";
// accm.into()
- passes::generate_type_name(t).into()
+ passes::mangled_type_name(t).into()
}
Enum(_things) => {
// Construct names for anonymous enums by concat'ing the member
@@ 109,7 108,7 @@ fn compile_typename(t: &Type) -> Cow<'st
// accm += &*nm.val();
// }
// accm.into()
- passes::generate_type_name(t).into()
+ passes::mangled_type_name(t).into()
}
Generic(s) => mangle_name(&s.val()).into(),
Array(t, len) => format!("[{};{}]", compile_typename(t), len).into(),
M src/bin/garnetfmt.rs +1 -0
@@ 1,4 1,5 @@
//! A code formatter.
+//! Very simple and dumb.
use std::io::{self, Cursor};
use std::path::PathBuf;
M src/builtins.rs +0 -3
@@ 1,8 1,5 @@
//! A place for us to stick compiler builtins and the metadata they need,
//! instead of having them scattered all over.
-//!
-//! TODO: We would really benefit from having a function that can take in a single
-//! number type and output all the math/binary/logic ops for that number.
use std::collections::BTreeMap;
M src/hir.rs +10 -9
@@ 288,6 288,8 @@ impl Expr {
Self::TupleCtor { body: vec![] }
}
+ /// Write the given HIR expr as a slightly-jank sexpr-y format.
+ /// It's not too pretty, but is way easier to eyeball than derive(Debug) output.
pub fn write(&self, indent: usize, f: &mut dyn fmt::Write) -> fmt::Result {
use Expr::*;
for _ in 0..(indent * 2) {
@@ 483,23 485,20 @@ impl Expr {
impl ExprNode {
/// Shortcut function for making literal bools
pub fn bool(b: bool) -> Self {
- Self::new(Expr::Lit {
- val: Literal::Bool(b),
- })
+ Self::new(Expr::bool(b))
}
/// Shortcut function for making literal integers
pub fn int(i: i128) -> Self {
- Self::new(Expr::Lit {
- val: Literal::Integer(i),
- })
+ Self::new(Expr::int(i))
}
/// Shortcut function for making literal unit
pub fn unit() -> Self {
- Self::new(Expr::TupleCtor { body: vec![] })
+ Self::new(Expr::unit())
}
}
+
/// A top-level declaration in the source file.
/// Like ExprNode, contains a type annotation.
#[derive(Debug, Clone, PartialEq)]
@@ 618,7 617,7 @@ fn lower_expr(expr: &ast::Expr) -> ExprN
}
E::If { cases, falseblock } => {
// One of the actual transformations, this makes all if/else statements
- // into essentially a switch: `if ... else if ... else if ... else if true ... end`
+ // into essentially a cond: `if ... else if ... else if ... else if true ... end`
// This is more consistent and easier to handle for typechecking.
assert!(!cases.is_empty(), "Should never happen");
let mut cases: Vec<_> = cases
@@ 644,7 643,7 @@ fn lower_expr(expr: &ast::Expr) -> ExprN
}
E::While { cond, body } => {
// While loops just get turned into a Loop containing
- // if not cond then break end
+ // `if not cond then break end`
let inverted_cond = E::UniOp {
op: UOp::Not,
rhs: cond.clone(),
@@ 742,6 741,7 @@ fn lower_expr(expr: &ast::Expr) -> ExprN
fn lower_exprs(exprs: &[ast::Expr]) -> Vec<ExprNode> {
exprs.iter().map(lower_expr).collect()
}
+
fn lower_typedef(accm: &mut Vec<Decl>, name: Sym, ty: &Type, params: &[Sym]) {
use Decl::*;
match ty {
@@ 785,6 785,7 @@ fn lower_typedef(accm: &mut Vec<Decl>, n
};
accm.push(new_constdef);
}
+
// For `type Foo = sum X {}, Y Thing end`
// synthesize
// const Foo = {
M src/lib.rs +3 -3
@@ 1,4 1,4 @@
-//! Garnet compiler guts.
+//! Garnet compiler driver functions and utility funcs.
//#![deny(missing_docs)]
@@ 66,7 66,7 @@ impl PrimType {
///
/// TODO someday: We should make a consistent and very good
/// name-mangling scheme for types, will make some backend stuff
-/// simpler.
+/// simpler. Also see passes::generate_type_name.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Type {
/// Primitive type with no subtypes
@@ 609,7 609,7 @@ impl Cx {
/// Main driver function.
/// Compile a given source string to Rust source code, or return an error.
-/// TODO: Better parser errors with locations
+/// TODO: Better errors with locations
///
/// Parse -> lower to IR -> run transformation passes
/// -> typecheck -> more passes -> codegen
M src/passes.rs +12 -10
@@ 86,7 86,7 @@ fn id<T>(thing: T) -> T {
///
/// To handle multiple expressions this will turn more into a fold()
/// than a map(), it will take an accumulator that gets threaded through
-/// everything... That gets *very weird* though and I manage to pour
+/// everything... That gets *very weird* though and I managed to pour
/// my coffee on my cat this morning so let's give that a miss for now.
/// As it is, this can only transform subtrees into other subtrees.
///
@@ 389,7 389,9 @@ fn signature_map(sig: hir::Signature, f:
}
}
-pub fn generate_type_name(typ: &Type) -> String {
+/// Generates a mangled type name for the given type that is unique (hopefully) and
+/// printable. See also TODO on crate::Type.
+pub fn mangled_type_name(typ: &Type) -> String {
match typ {
Type::Enum(fields) => {
let fieldnames: Vec<_> = fields
@@ 400,17 402,17 @@ pub fn generate_type_name(typ: &Type) ->
format!("__Enum{}", fieldstr)
}
Type::Func(params, rettype, typeparams) => {
- let paramnames: Vec<String> = params.iter().map(generate_type_name).collect();
+ let paramnames: Vec<String> = params.iter().map(mangled_type_name).collect();
let paramstr = paramnames.join("_");
- let retname = generate_type_name(rettype);
- let tparamnames: Vec<String> = typeparams.iter().map(generate_type_name).collect();
+ let retname = mangled_type_name(rettype);
+ let tparamnames: Vec<String> = typeparams.iter().map(mangled_type_name).collect();
let tparamstr = tparamnames.join("_");
format!("__Func__{}__{}_{}", paramstr, retname, tparamstr)
}
Type::Struct(body, _) => {
let fieldnames: Vec<_> = body
.iter()
- .map(|(nm, ty)| format!("{}_{}", nm, generate_type_name(ty)))
+ .map(|(nm, ty)| format!("{}_{}", nm, mangled_type_name(ty)))
.collect();
let fieldstr = fieldnames.join("_");
format!("__Struct__{}", fieldstr)
@@ 418,7 420,7 @@ pub fn generate_type_name(typ: &Type) ->
Type::Sum(body, _) => {
let fieldnames: Vec<_> = body
.iter()
- .map(|(nm, ty)| format!("{}_{}", nm, generate_type_name(ty)))
+ .map(|(nm, ty)| format!("{}_{}", nm, mangled_type_name(ty)))
.collect();
let fieldstr = fieldnames.join("_");
format!("__Sum__{}", fieldstr)
@@ 427,17 429,17 @@ pub fn generate_type_name(typ: &Type) ->
format!("__G{}", name)
}
Type::Named(name, fields) => {
- let field_names: Vec<_> = fields.iter().map(generate_type_name).collect();
+ let field_names: Vec<_> = fields.iter().map(mangled_type_name).collect();
let field_str = field_names.join("_");
format!("__Named{}__{}", name, field_str)
}
Type::Prim(p) => p.get_name().into_owned(),
Type::Never => format!("!"),
Type::Array(t, len) => {
- format!("__Arr{}__{}", generate_type_name(t), len)
+ format!("__Arr{}__{}", mangled_type_name(t), len)
}
Type::Uniq(t) => {
- format!("__Uniq__{}", generate_type_name(t))
+ format!("__Uniq__{}", mangled_type_name(t))
}
}
}
M src/passes/double_typeck.rs +3 -0
@@ 2,6 2,9 @@
//! Doesn't actually change anything, just walks through
//! the entire IR tree and makes sure that every expression
//! has a real type.
+//!
+//! Technically unnecessary but occasionally useful for
+//! debugging stuff.
use crate::hir::*;
use crate::passes::*;
M src/typeck.rs +8 -10
@@ 130,7 130,7 @@ pub enum TypeError {
},
TypeListMismatch {
// We can't necessarily display TypeId's sensibly, so I guess
- // we haven to turn them into strings
+ // we have to turn them into strings
expected: String,
got: String,
},
@@ 216,7 216,9 @@ impl std::fmt::Display for TypeError {
}
impl TypeError {
- /// TODO: This should just be turned into the Display impl
+ /// TODO: This should just be turned into the Display impl.
+ /// But we might need access to the Tck sometimes? Do we make
+ /// it so that has to happen when the error is created? I guess so
pub fn format(&self) -> String {
match self {
TypeError::UnknownVar(sym) => format!("Unknown var: {}", sym.val()),
@@ 358,6 360,7 @@ impl Tck {
)
})
}
+
/// Save the type variable associated with the given expr.
/// Panics if it is redefining the expr's type.
fn set_expr_type(&mut self, expr: &hir::ExprNode, ty: TypeId) {
@@ 483,15 486,10 @@ impl Tck {
}
/// Same as `get_struct_field_type()` but takes a tuple type and an integer.
- pub fn get_tuple_field_type(
- &mut self,
- symtbl: &Symtbl,
- tuple_type: TypeId,
- n: usize,
- ) -> TypeId {
+ pub fn get_tuple_field_type(&mut self, tuple_type: TypeId, n: usize) -> TypeId {
use TypeInfo::*;
match self.get(&tuple_type).clone() {
- Ref(t) => self.get_tuple_field_type(symtbl, t, n),
+ Ref(t) => self.get_tuple_field_type(t, n),
Named(nm, tys) if &*nm.val() == "Tuple" => tys.get(n).cloned().unwrap_or_else(|| {
panic!("Tuple has no field {}, valid fields are: {:#?}", n, tys)
}),
@@ 1356,7 1354,7 @@ fn typecheck_expr(
TupleRef { expr: e, elt } => {
typecheck_expr(tck, symtbl, func_rettype, e)?;
let tuple_type = tck.get_expr_type(e);
- let field_type = tck.get_tuple_field_type(symtbl, tuple_type, *elt);
+ let field_type = tck.get_tuple_field_type(tuple_type, *elt);
trace!(
"Heckin tuple ref... Type of {:?}.{} is {:?}",
e,