Compare commits
No commits in common. "01a6a5bbbaa9b5a5bfe75b8557ccbbfd80b9cc47" and "f870bbe3c752f50f1c12211a9582aa43ba7c4205" have entirely different histories.
01a6a5bbba
...
f870bbe3c7
|
@ -2,13 +2,13 @@
|
|||
|
||||
use std::{error::Error, fmt::Display, fs::File, io::Write, process::exit, str::FromStr};
|
||||
|
||||
use clap::Parser;
|
||||
use drimc_rs::{
|
||||
ast2ir::ast2ir,
|
||||
backends,
|
||||
parser::{parser, ParserError, ParserMeta},
|
||||
typeck::typeck,
|
||||
};
|
||||
use clap::Parser;
|
||||
|
||||
/// Optimization levels.
|
||||
#[derive(Debug)]
|
||||
|
@ -256,7 +256,7 @@ fn main() {
|
|||
let source = std::fs::read_to_string(&args.source_file)?;
|
||||
let meta = ParserMeta::default();
|
||||
let ast = chumsky::Parser::parse(&parser(&meta), source).map_err(ParserError)?;
|
||||
let ast = typeck(ast)?;
|
||||
typeck(&ast)?;
|
||||
|
||||
let ir = ast2ir(ast);
|
||||
|
||||
|
|
|
@ -10,8 +10,7 @@ use chumsky::{
|
|||
};
|
||||
|
||||
use crate::syntax::{
|
||||
ClassMember, Expr, ExprKind, Identifier, Literal, Pattern, Statement, SyntaxTree, Type,
|
||||
TypeConstructor,
|
||||
ClassMember, Expr, Identifier, Literal, Pattern, Statement, SyntaxTree, Type, TypeConstructor,
|
||||
};
|
||||
|
||||
/// Adapter to make `chumsky`'s parser errors usable as standard Rust errors.
|
||||
|
@ -331,7 +330,6 @@ fn parse_func_decl<'a>(
|
|||
name,
|
||||
arguments,
|
||||
definition,
|
||||
typ: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -374,15 +372,15 @@ fn parse_expression<'a>(
|
|||
let application = term.repeated().at_least(1).map(|exprs| {
|
||||
exprs
|
||||
.into_iter()
|
||||
.reduce(|l, r| {
|
||||
expr(ExprKind::Application {
|
||||
func: Box::new(l),
|
||||
argument: Box::new(r),
|
||||
})
|
||||
.reduce(|l, r| Expr::Application {
|
||||
func: Box::new(l),
|
||||
argument: Box::new(r),
|
||||
})
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
// let unary = parse_unary(m, term);
|
||||
// let unary = term;
|
||||
let unary = parse_unary(m, application);
|
||||
|
||||
let binary = (0..=10).rev().fold(unary.boxed(), |p, precedence| {
|
||||
|
@ -401,12 +399,10 @@ fn parse_unary(
|
|||
.repeated()
|
||||
.then(base)
|
||||
.map(|(ops, exp)| {
|
||||
ops.into_iter().fold(exp, |exp, op| {
|
||||
expr(ExprKind::UnaryOp {
|
||||
kind: op.to_string(),
|
||||
val: Box::new(exp),
|
||||
translation: "negate".to_string(),
|
||||
})
|
||||
ops.into_iter().fold(exp, |exp, op| Expr::UnaryOp {
|
||||
kind: op.to_string(),
|
||||
val: Box::new(exp),
|
||||
translation: "negate".to_string(),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -446,12 +442,12 @@ fn parse_binary<'a>(
|
|||
others
|
||||
.into_iter()
|
||||
.fold(first, |left, (op_name, _assoc, translation, right)| {
|
||||
expr(ExprKind::BinaryOp {
|
||||
Expr::BinaryOp {
|
||||
kind: op_name.to_owned(),
|
||||
left: Box::new(left),
|
||||
right: Box::new(right),
|
||||
translation: translation.to_string(),
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
Some(Associativity::Right) => {
|
||||
|
@ -492,13 +488,11 @@ fn parse_binary<'a>(
|
|||
others_l
|
||||
.into_iter()
|
||||
.rev()
|
||||
.fold(last.to_owned(), |r, (l, (op, trans))| {
|
||||
expr(ExprKind::BinaryOp {
|
||||
kind: op.to_string(),
|
||||
left: Box::new(l.to_owned()),
|
||||
right: Box::new(r),
|
||||
translation: trans.to_string(),
|
||||
})
|
||||
.fold(last.to_owned(), |r, (l, (op, trans))| Expr::BinaryOp {
|
||||
kind: op.to_string(),
|
||||
left: Box::new(l.to_owned()),
|
||||
right: Box::new(r),
|
||||
translation: trans.to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -507,71 +501,65 @@ fn parse_binary<'a>(
|
|||
|
||||
fn parse_let_expr(
|
||||
m: &ParserMeta,
|
||||
rec: impl Parser<char, Expr, Error = Simple<char>> + Clone,
|
||||
base: impl Parser<char, Expr, Error = Simple<char>> + Clone,
|
||||
) -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
|
||||
pad(keyword("let"))
|
||||
.ignore_then(parse_pattern(m))
|
||||
.then_ignore(pad(just('=')))
|
||||
.then(rec.clone())
|
||||
.then(base.clone())
|
||||
.then_ignore(pad(keyword("in")))
|
||||
.then(rec)
|
||||
.map(|((left, right), into)| {
|
||||
expr(ExprKind::Let {
|
||||
left,
|
||||
right: Box::new(right),
|
||||
into: Box::new(into),
|
||||
})
|
||||
.then(base)
|
||||
.map(|((left, right), into)| Expr::Let {
|
||||
left,
|
||||
right: Box::new(right),
|
||||
into: Box::new(into),
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_match_expr(
|
||||
m: &ParserMeta,
|
||||
rec: impl Parser<char, Expr, Error = Simple<char>> + Clone,
|
||||
base: impl Parser<char, Expr, Error = Simple<char>> + Clone,
|
||||
) -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
|
||||
pad(keyword("match"))
|
||||
.ignore_then(rec.clone())
|
||||
.ignore_then(base.clone())
|
||||
.then(
|
||||
parse_pattern(m)
|
||||
.then_ignore(pad(just("=>")))
|
||||
.then(rec)
|
||||
.then(base)
|
||||
.separated_by(pad(just(",")))
|
||||
.allow_trailing()
|
||||
.delimited_by(pad(just('{')), pad(just('}'))),
|
||||
)
|
||||
.map(|(matcher, cases)| {
|
||||
expr(ExprKind::Match {
|
||||
matcher: Box::new(matcher),
|
||||
cases,
|
||||
})
|
||||
.map(|(matcher, cases)| Expr::Match {
|
||||
matcher: Box::new(matcher),
|
||||
cases,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_record_expr(
|
||||
_m: &ParserMeta,
|
||||
rec: impl Parser<char, Expr, Error = Simple<char>> + Clone,
|
||||
base: impl Parser<char, Expr, Error = Simple<char>> + Clone,
|
||||
) -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
|
||||
pad(ident())
|
||||
.then_ignore(pad(just(':')))
|
||||
.then(rec)
|
||||
.then(base)
|
||||
.separated_by(pad(just(',')))
|
||||
.allow_trailing()
|
||||
.delimited_by(pad(just('{')), pad(just('}')))
|
||||
.map(|elems| expr(ExprKind::Record(elems)))
|
||||
.map(Expr::Record)
|
||||
}
|
||||
|
||||
fn parse_lambda_expr(
|
||||
m: &ParserMeta,
|
||||
rec: impl Parser<char, Expr, Error = Simple<char>> + Clone,
|
||||
base: impl Parser<char, Expr, Error = Simple<char>> + Clone,
|
||||
) -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
|
||||
pad(keyword("fn"))
|
||||
.ignore_then(parse_pattern(m).repeated())
|
||||
.then_ignore(pad(just("->")))
|
||||
.then(rec)
|
||||
.map(|(arguments, result)| {
|
||||
expr(ExprKind::Lambda {
|
||||
arguments,
|
||||
result: Box::new(result),
|
||||
})
|
||||
.then(base)
|
||||
.map(|(arguments, result)| Expr::Lambda {
|
||||
arguments,
|
||||
result: Box::new(result),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -597,38 +585,36 @@ fn parse_subscript_expr(
|
|||
.repeated(),
|
||||
)
|
||||
.map(|(l, subscripts): (Expr, Vec<(SubscriptKind, Expr)>)| {
|
||||
subscripts.into_iter().fold(l, |l, (kind, r)| {
|
||||
expr(match kind {
|
||||
SubscriptKind::Dot => ExprKind::DotSubscript {
|
||||
value: Box::new(l),
|
||||
subscript: Box::new(r),
|
||||
},
|
||||
SubscriptKind::Bracket => ExprKind::BracketSubscript {
|
||||
value: Box::new(l),
|
||||
subscript: Box::new(r),
|
||||
},
|
||||
})
|
||||
subscripts.into_iter().fold(l, |l, (kind, r)| match kind {
|
||||
SubscriptKind::Dot => Expr::DotSubscript {
|
||||
value: Box::new(l),
|
||||
subscript: Box::new(r),
|
||||
},
|
||||
SubscriptKind::Bracket => Expr::BracketSubscript {
|
||||
value: Box::new(l),
|
||||
subscript: Box::new(r),
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_tuple_expr(
|
||||
_m: &ParserMeta,
|
||||
rec: impl Parser<char, Expr, Error = Simple<char>> + Clone,
|
||||
base: impl Parser<char, Expr, Error = Simple<char>> + Clone,
|
||||
) -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
|
||||
rec.separated_by(pad(just(',')))
|
||||
base.separated_by(pad(just(',')))
|
||||
.delimited_by(pad(just('(')), pad(just(')')))
|
||||
.map(|exprs| {
|
||||
if exprs.len() == 1 {
|
||||
exprs.into_iter().next().unwrap()
|
||||
} else {
|
||||
expr(ExprKind::Tuple(exprs))
|
||||
Expr::Tuple(exprs)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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(Expr::VariableReference)
|
||||
}
|
||||
|
||||
fn parse_literal(_m: &ParserMeta) -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
|
||||
|
@ -673,7 +659,7 @@ fn parse_literal(_m: &ParserMeta) -> impl Parser<char, Expr, Error = Simple<char
|
|||
.map(|(l, r)| (l + "." + &r).parse().unwrap())
|
||||
.map(Literal::Float);
|
||||
|
||||
pad(choice((int, float, string))).map(|lit| expr(ExprKind::Literal(lit)))
|
||||
pad(choice((int, float, string))).map(Expr::Literal)
|
||||
}
|
||||
|
||||
fn parse_identifier(
|
||||
|
@ -811,8 +797,8 @@ fn parse_record_pattern(
|
|||
|
||||
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.
|
||||
parse_literal(m).map(|e| match e.kind {
|
||||
ExprKind::Literal(lit) => Pattern::Literal(lit),
|
||||
parse_literal(m).map(|e| match e {
|
||||
Expr::Literal(lit) => Pattern::Literal(lit),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
|
@ -843,10 +829,6 @@ fn ident() -> impl Parser<char, String, Error = Simple<char>> + Clone {
|
|||
})
|
||||
}
|
||||
|
||||
fn expr(e: ExprKind) -> Expr {
|
||||
Expr { kind: e, typ: None }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
use num_bigint::BigUint;
|
||||
|
||||
use crate::typeck;
|
||||
|
||||
/// 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
|
||||
/// completely using the syntax tree.
|
||||
|
@ -67,10 +65,6 @@ pub enum ClassMember {
|
|||
|
||||
/// The definition of the function.
|
||||
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.
|
||||
|
@ -93,19 +87,9 @@ pub struct TypeConstructor {
|
|||
pub args: Vec<Type>,
|
||||
}
|
||||
|
||||
/// An expression.
|
||||
/// Expressions.
|
||||
#[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.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ExprKind {
|
||||
pub enum Expr {
|
||||
/// Unary operators, e.g., `-5`.
|
||||
UnaryOp {
|
||||
/// The text of the operator.
|
||||
|
@ -268,7 +252,7 @@ pub enum Pattern {
|
|||
}
|
||||
|
||||
/// Namespaced identifiers.
|
||||
#[derive(Clone, Debug, Hash, PartialEq)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Identifier {
|
||||
/// The elements of the identifier; there must be at least one of these.
|
||||
pub elems: Vec<String>,
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
//! Type checker.
|
||||
|
||||
use std::{collections::BTreeMap, error::Error, fmt::Display};
|
||||
use std::{error::Error, fmt::Display};
|
||||
|
||||
use num_bigint::BigInt;
|
||||
|
||||
use crate::syntax::{Identifier, SyntaxTree};
|
||||
use crate::syntax::SyntaxTree;
|
||||
|
||||
/// A compile-time type error from the user's source code.
|
||||
#[derive(Debug)]
|
||||
|
@ -18,39 +16,7 @@ impl Display for TypeError {
|
|||
|
||||
impl Error for TypeError {}
|
||||
|
||||
/// A type known at compile time. While this resembles the AST `Type` structure, this enum is
|
||||
/// optimized for unifying types against one another and representing compiler-generated types
|
||||
/// rather than strictly representing named types.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Type {
|
||||
/// `Foo`
|
||||
Named(Identifier),
|
||||
|
||||
/// `List Int`
|
||||
Application {
|
||||
/// The function being applied. This must be a generic type.
|
||||
function: Box<Type>,
|
||||
|
||||
/// The type given as an argument to the type.
|
||||
expression: Box<Type>,
|
||||
},
|
||||
|
||||
/// `(a, b)`
|
||||
Tuple(Vec<Type>),
|
||||
|
||||
/// `{ a: x, b: y }`
|
||||
Record(BTreeMap<String, Type>),
|
||||
|
||||
/// Compiler-internal type representing an arbitrary-precision integer whose value is known at
|
||||
/// compile time. This is the default type of integer literals. A `CompInt` can be converted to
|
||||
/// an actual integer type via implicit application of the `fromCompInt` generic function.
|
||||
CompInt(BigInt),
|
||||
|
||||
/// Compiler-internal type representing a string literal. See `CompInt`.
|
||||
CompString(String),
|
||||
}
|
||||
|
||||
/// Type-checks the syntax tree.
|
||||
pub fn typeck(_: SyntaxTree) -> Result<SyntaxTree, TypeError> {
|
||||
pub fn typeck(_: &SyntaxTree) -> Result<(), TypeError> {
|
||||
todo!()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue