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:
parent
01a6a5bbba
commit
99daf682cd
|
@ -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!()
|
|
||||||
}
|
|
|
@ -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!()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
//! Intermediate code representation.
|
|
||||||
|
|
||||||
/// The IR tree representing the whole program.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct IR;
|
|
|
@ -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;
|
||||||
|
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,11 +372,9 @@ 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,12 +397,10 @@ 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(),
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -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,13 +486,11 @@ 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,12 +507,10 @@ 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),
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -538,11 +528,9 @@ 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,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,11 +555,9 @@ 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),
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -597,17 +583,15 @@ 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 => Expr::BracketSubscript {
|
||||||
SubscriptKind::Bracket => ExprKind::BracketSubscript {
|
value: Box::new(l),
|
||||||
value: Box::new(l),
|
subscript: Box::new(r),
|
||||||
subscript: Box::new(r),
|
},
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -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::*;
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in a new issue