Tear out the IR and type checking systems

I'm gonna re-do type checking so it's not done at the AST level, but
instead the AST generates a high-level IR that then gets type-checked
to a lower-level IR.
This commit is contained in:
Alex Bethel 2022-08-22 20:00:34 -06:00
parent 01a6a5bbba
commit 99daf682cd
7 changed files with 44 additions and 121 deletions

View file

@ -1,10 +0,0 @@
//! Conversion of AST to intermediate representation.
use crate::ir::IR;
use crate::syntax::SyntaxTree;
/// Compiles an abstract syntax tree into intermediate representation; this assumes the code already
/// type-checks, and emits unoptimized IR.
pub fn ast2ir(_: SyntaxTree) -> IR {
todo!()
}

View file

@ -1,9 +1,7 @@
//! Backend for direct generation of C code. //! Backend for direct generation of C code.
use crate::ir::IR;
/// Generates C code with the same semantics as the intermediate representation. Returns the C /// Generates C code with the same semantics as the intermediate representation. Returns the C
/// source code as a string. /// source code as a string.
pub fn generate_c(_ir: &IR) -> String { pub fn generate_c(_ir: &()) -> String {
todo!() todo!()
} }

View file

@ -1,5 +0,0 @@
//! Intermediate code representation.
/// The IR tree representing the whole program.
#[derive(Debug)]
pub struct IR;

View file

@ -5,9 +5,7 @@
#![deny(missing_docs)] #![deny(missing_docs)]
pub mod ast2ir;
pub mod backends; pub mod backends;
pub mod ir;
pub mod parser; pub mod parser;
pub mod syntax; pub mod syntax;
pub mod typeck; pub mod typeck;

View file

@ -1,11 +1,9 @@
//! Drim compiler CLI. //! Drim compiler CLI.
use std::{error::Error, fmt::Display, fs::File, io::Write, process::exit, str::FromStr}; use std::{error::Error, fmt::Display, process::exit, str::FromStr};
use clap::Parser; use clap::Parser;
use drimc_rs::{ use drimc_rs::{
ast2ir::ast2ir,
backends,
parser::{parser, ParserError, ParserMeta}, parser::{parser, ParserError, ParserMeta},
typeck::typeck, typeck::typeck,
}; };
@ -258,27 +256,7 @@ fn main() {
let ast = chumsky::Parser::parse(&parser(&meta), source).map_err(ParserError)?; let ast = chumsky::Parser::parse(&parser(&meta), source).map_err(ParserError)?;
let ast = typeck(ast)?; let ast = typeck(ast)?;
let ir = ast2ir(ast); println!("{ast:?}");
match args.target {
Target::CSource => {
let c = backends::c::generate_c(&ir);
let mut out_file = File::create("out.c")?;
write!(out_file, "{}", c)?;
}
Target::Assembly => todo!(),
Target::ObjectFile => todo!(),
Target::Executable => todo!(),
Target::SharedObject => todo!(),
Target::Spirv => todo!(),
Target::Wat => todo!(),
Target::Wasm => todo!(),
Target::Lua => todo!(),
Target::Python => todo!(),
Target::Go => todo!(),
Target::Ada => todo!(),
}
Ok(()) Ok(())
} }

View file

@ -10,8 +10,7 @@ use chumsky::{
}; };
use crate::syntax::{ use crate::syntax::{
ClassMember, Expr, ExprKind, Identifier, Literal, Pattern, Statement, SyntaxTree, Type, ClassMember, Expr, Identifier, Literal, Pattern, Statement, SyntaxTree, Type, TypeConstructor,
TypeConstructor,
}; };
/// Adapter to make `chumsky`'s parser errors usable as standard Rust errors. /// Adapter to make `chumsky`'s parser errors usable as standard Rust errors.
@ -331,7 +330,6 @@ fn parse_func_decl<'a>(
name, name,
arguments, arguments,
definition, definition,
typ: None,
}) })
} }
@ -374,12 +372,10 @@ fn parse_expression<'a>(
let application = term.repeated().at_least(1).map(|exprs| { let application = term.repeated().at_least(1).map(|exprs| {
exprs exprs
.into_iter() .into_iter()
.reduce(|l, r| { .reduce(|l, r| Expr::Application {
expr(ExprKind::Application {
func: Box::new(l), func: Box::new(l),
argument: Box::new(r), argument: Box::new(r),
}) })
})
.unwrap() .unwrap()
}); });
@ -401,14 +397,12 @@ fn parse_unary(
.repeated() .repeated()
.then(base) .then(base)
.map(|(ops, exp)| { .map(|(ops, exp)| {
ops.into_iter().fold(exp, |exp, op| { ops.into_iter().fold(exp, |exp, op| Expr::UnaryOp {
expr(ExprKind::UnaryOp {
kind: op.to_string(), kind: op.to_string(),
val: Box::new(exp), val: Box::new(exp),
translation: "negate".to_string(), translation: "negate".to_string(),
}) })
}) })
})
} }
fn parse_binary<'a>( fn parse_binary<'a>(
@ -446,12 +440,12 @@ fn parse_binary<'a>(
others others
.into_iter() .into_iter()
.fold(first, |left, (op_name, _assoc, translation, right)| { .fold(first, |left, (op_name, _assoc, translation, right)| {
expr(ExprKind::BinaryOp { Expr::BinaryOp {
kind: op_name.to_owned(), kind: op_name.to_owned(),
left: Box::new(left), left: Box::new(left),
right: Box::new(right), right: Box::new(right),
translation: translation.to_string(), translation: translation.to_string(),
}) }
}) })
} }
Some(Associativity::Right) => { Some(Associativity::Right) => {
@ -492,14 +486,12 @@ fn parse_binary<'a>(
others_l others_l
.into_iter() .into_iter()
.rev() .rev()
.fold(last.to_owned(), |r, (l, (op, trans))| { .fold(last.to_owned(), |r, (l, (op, trans))| Expr::BinaryOp {
expr(ExprKind::BinaryOp {
kind: op.to_string(), kind: op.to_string(),
left: Box::new(l.to_owned()), left: Box::new(l.to_owned()),
right: Box::new(r), right: Box::new(r),
translation: trans.to_string(), translation: trans.to_string(),
}) })
})
} }
} }
}) })
@ -515,13 +507,11 @@ fn parse_let_expr(
.then(rec.clone()) .then(rec.clone())
.then_ignore(pad(keyword("in"))) .then_ignore(pad(keyword("in")))
.then(rec) .then(rec)
.map(|((left, right), into)| { .map(|((left, right), into)| Expr::Let {
expr(ExprKind::Let {
left, left,
right: Box::new(right), right: Box::new(right),
into: Box::new(into), into: Box::new(into),
}) })
})
} }
fn parse_match_expr( fn parse_match_expr(
@ -538,12 +528,10 @@ fn parse_match_expr(
.allow_trailing() .allow_trailing()
.delimited_by(pad(just('{')), pad(just('}'))), .delimited_by(pad(just('{')), pad(just('}'))),
) )
.map(|(matcher, cases)| { .map(|(matcher, cases)| Expr::Match {
expr(ExprKind::Match {
matcher: Box::new(matcher), matcher: Box::new(matcher),
cases, cases,
}) })
})
} }
fn parse_record_expr( fn parse_record_expr(
@ -556,7 +544,7 @@ fn parse_record_expr(
.separated_by(pad(just(','))) .separated_by(pad(just(',')))
.allow_trailing() .allow_trailing()
.delimited_by(pad(just('{')), pad(just('}'))) .delimited_by(pad(just('{')), pad(just('}')))
.map(|elems| expr(ExprKind::Record(elems))) .map(|elems| Expr::Record(elems))
} }
fn parse_lambda_expr( fn parse_lambda_expr(
@ -567,12 +555,10 @@ fn parse_lambda_expr(
.ignore_then(parse_pattern(m).repeated()) .ignore_then(parse_pattern(m).repeated())
.then_ignore(pad(just("->"))) .then_ignore(pad(just("->")))
.then(rec) .then(rec)
.map(|(arguments, result)| { .map(|(arguments, result)| Expr::Lambda {
expr(ExprKind::Lambda {
arguments, arguments,
result: Box::new(result), result: Box::new(result),
}) })
})
} }
fn parse_subscript_expr( fn parse_subscript_expr(
@ -597,19 +583,17 @@ fn parse_subscript_expr(
.repeated(), .repeated(),
) )
.map(|(l, subscripts): (Expr, Vec<(SubscriptKind, Expr)>)| { .map(|(l, subscripts): (Expr, Vec<(SubscriptKind, Expr)>)| {
subscripts.into_iter().fold(l, |l, (kind, r)| { subscripts.into_iter().fold(l, |l, (kind, r)| match kind {
expr(match kind { SubscriptKind::Dot => Expr::DotSubscript {
SubscriptKind::Dot => ExprKind::DotSubscript {
value: Box::new(l), value: Box::new(l),
subscript: Box::new(r), subscript: Box::new(r),
}, },
SubscriptKind::Bracket => ExprKind::BracketSubscript { SubscriptKind::Bracket => Expr::BracketSubscript {
value: Box::new(l), value: Box::new(l),
subscript: Box::new(r), subscript: Box::new(r),
}, },
}) })
}) })
})
} }
fn parse_tuple_expr( fn parse_tuple_expr(
@ -622,13 +606,13 @@ fn parse_tuple_expr(
if exprs.len() == 1 { if exprs.len() == 1 {
exprs.into_iter().next().unwrap() exprs.into_iter().next().unwrap()
} else { } else {
expr(ExprKind::Tuple(exprs)) Expr::Tuple(exprs)
} }
}) })
} }
fn parse_var_ref_expr(m: &ParserMeta) -> impl Parser<char, Expr, Error = Simple<char>> + Clone { fn parse_var_ref_expr(m: &ParserMeta) -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
parse_identifier(m).map(|r| expr(ExprKind::VariableReference(r))) parse_identifier(m).map(|r| Expr::VariableReference(r))
} }
fn parse_literal(_m: &ParserMeta) -> impl Parser<char, Expr, Error = Simple<char>> + Clone { fn parse_literal(_m: &ParserMeta) -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
@ -673,7 +657,7 @@ fn parse_literal(_m: &ParserMeta) -> impl Parser<char, Expr, Error = Simple<char
.map(|(l, r)| (l + "." + &r).parse().unwrap()) .map(|(l, r)| (l + "." + &r).parse().unwrap())
.map(Literal::Float); .map(Literal::Float);
pad(choice((int, float, string))).map(|lit| expr(ExprKind::Literal(lit))) pad(choice((int, float, string))).map(|lit| Expr::Literal(lit))
} }
fn parse_identifier( fn parse_identifier(
@ -811,8 +795,8 @@ fn parse_record_pattern(
fn parse_literal_pattern(m: &ParserMeta) -> impl Parser<char, Pattern, Error = Simple<char>> { fn parse_literal_pattern(m: &ParserMeta) -> impl Parser<char, Pattern, Error = Simple<char>> {
// TODO: factor out literal parsing so we don't have to do this ugly `unreachable` stuff. // TODO: factor out literal parsing so we don't have to do this ugly `unreachable` stuff.
parse_literal(m).map(|e| match e.kind { parse_literal(m).map(|e| match e {
ExprKind::Literal(lit) => Pattern::Literal(lit), Expr::Literal(lit) => Pattern::Literal(lit),
_ => unreachable!(), _ => unreachable!(),
}) })
} }
@ -843,10 +827,6 @@ fn ident() -> impl Parser<char, String, Error = Simple<char>> + Clone {
}) })
} }
fn expr(e: ExprKind) -> Expr {
Expr { kind: e, typ: None }
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View file

@ -2,8 +2,6 @@
use num_bigint::BigUint; use num_bigint::BigUint;
use crate::typeck;
/// A concrete syntax tree. This represents the full content of a Drim program, including all /// A concrete syntax tree. This represents the full content of a Drim program, including all
/// whitespace, comments, and tokens: the source code of the original program can be recovered /// whitespace, comments, and tokens: the source code of the original program can be recovered
/// completely using the syntax tree. /// completely using the syntax tree.
@ -67,10 +65,6 @@ pub enum ClassMember {
/// The definition of the function. /// The definition of the function.
definition: Option<Expr>, definition: Option<Expr>,
/// The type of the overall function; this is filled in by the typechecker, and is left
/// blank by the parser.
typ: Option<typeck::Type>,
}, },
/// Declaration of a type that is a literal alias for another type. /// Declaration of a type that is a literal alias for another type.
@ -93,19 +87,9 @@ pub struct TypeConstructor {
pub args: Vec<Type>, pub args: Vec<Type>,
} }
/// An expression.
#[derive(Clone, Debug)]
pub struct Expr {
/// The contents of the expression.
pub kind: ExprKind,
/// An optional type signature, left as `None` by the parser and added by the type checker.
pub typ: Option<typeck::Type>,
}
/// The different kinds of expressions. /// The different kinds of expressions.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum ExprKind { pub enum Expr {
/// Unary operators, e.g., `-5`. /// Unary operators, e.g., `-5`.
UnaryOp { UnaryOp {
/// The text of the operator. /// The text of the operator.