Add dummy typ values on expressions in the AST

This commit is contained in:
Alex Bethel 2022-08-12 21:23:09 -06:00
parent f870bbe3c7
commit cd0353b31a
2 changed files with 88 additions and 56 deletions

View file

@ -10,7 +10,8 @@ use chumsky::{
}; };
use crate::syntax::{ use crate::syntax::{
ClassMember, Expr, Identifier, Literal, Pattern, Statement, SyntaxTree, Type, TypeConstructor, ClassMember, Expr, ExprKind, Identifier, Literal, Pattern, Statement, SyntaxTree, Type,
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.
@ -330,6 +331,7 @@ fn parse_func_decl<'a>(
name, name,
arguments, arguments,
definition, definition,
typ: None,
}) })
} }
@ -372,15 +374,15 @@ 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| Expr::Application { .reduce(|l, r| {
func: Box::new(l), expr(ExprKind::Application {
argument: Box::new(r), func: Box::new(l),
argument: Box::new(r),
})
}) })
.unwrap() .unwrap()
}); });
// let unary = parse_unary(m, term);
// let unary = term;
let unary = parse_unary(m, application); let unary = parse_unary(m, application);
let binary = (0..=10).rev().fold(unary.boxed(), |p, precedence| { let binary = (0..=10).rev().fold(unary.boxed(), |p, precedence| {
@ -399,10 +401,12 @@ fn parse_unary(
.repeated() .repeated()
.then(base) .then(base)
.map(|(ops, exp)| { .map(|(ops, exp)| {
ops.into_iter().fold(exp, |exp, op| Expr::UnaryOp { ops.into_iter().fold(exp, |exp, op| {
kind: op.to_string(), expr(ExprKind::UnaryOp {
val: Box::new(exp), kind: op.to_string(),
translation: "negate".to_string(), val: Box::new(exp),
translation: "negate".to_string(),
})
}) })
}) })
} }
@ -442,12 +446,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::BinaryOp { expr(ExprKind::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) => {
@ -488,11 +492,13 @@ fn parse_binary<'a>(
others_l others_l
.into_iter() .into_iter()
.rev() .rev()
.fold(last.to_owned(), |r, (l, (op, trans))| Expr::BinaryOp { .fold(last.to_owned(), |r, (l, (op, trans))| {
kind: op.to_string(), expr(ExprKind::BinaryOp {
left: Box::new(l.to_owned()), kind: op.to_string(),
right: Box::new(r), left: Box::new(l.to_owned()),
translation: trans.to_string(), right: Box::new(r),
translation: trans.to_string(),
})
}) })
} }
} }
@ -501,65 +507,71 @@ fn parse_binary<'a>(
fn parse_let_expr( fn parse_let_expr(
m: &ParserMeta, m: &ParserMeta,
base: impl Parser<char, Expr, Error = Simple<char>> + Clone, rec: impl Parser<char, Expr, Error = Simple<char>> + Clone,
) -> impl Parser<char, Expr, Error = Simple<char>> + Clone { ) -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
pad(keyword("let")) pad(keyword("let"))
.ignore_then(parse_pattern(m)) .ignore_then(parse_pattern(m))
.then_ignore(pad(just('='))) .then_ignore(pad(just('=')))
.then(base.clone()) .then(rec.clone())
.then_ignore(pad(keyword("in"))) .then_ignore(pad(keyword("in")))
.then(base) .then(rec)
.map(|((left, right), into)| Expr::Let { .map(|((left, right), into)| {
left, expr(ExprKind::Let {
right: Box::new(right), left,
into: Box::new(into), right: Box::new(right),
into: Box::new(into),
})
}) })
} }
fn parse_match_expr( fn parse_match_expr(
m: &ParserMeta, m: &ParserMeta,
base: impl Parser<char, Expr, Error = Simple<char>> + Clone, rec: impl Parser<char, Expr, Error = Simple<char>> + Clone,
) -> impl Parser<char, Expr, Error = Simple<char>> + Clone { ) -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
pad(keyword("match")) pad(keyword("match"))
.ignore_then(base.clone()) .ignore_then(rec.clone())
.then( .then(
parse_pattern(m) parse_pattern(m)
.then_ignore(pad(just("=>"))) .then_ignore(pad(just("=>")))
.then(base) .then(rec)
.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(|(matcher, cases)| Expr::Match { .map(|(matcher, cases)| {
matcher: Box::new(matcher), expr(ExprKind::Match {
cases, matcher: Box::new(matcher),
cases,
})
}) })
} }
fn parse_record_expr( fn parse_record_expr(
_m: &ParserMeta, _m: &ParserMeta,
base: impl Parser<char, Expr, Error = Simple<char>> + Clone, rec: impl Parser<char, Expr, Error = Simple<char>> + Clone,
) -> impl Parser<char, Expr, Error = Simple<char>> + Clone { ) -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
pad(ident()) pad(ident())
.then_ignore(pad(just(':'))) .then_ignore(pad(just(':')))
.then(base) .then(rec)
.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(Expr::Record) .map(|elems| expr(ExprKind::Record(elems)))
} }
fn parse_lambda_expr( fn parse_lambda_expr(
m: &ParserMeta, m: &ParserMeta,
base: impl Parser<char, Expr, Error = Simple<char>> + Clone, rec: impl Parser<char, Expr, Error = Simple<char>> + Clone,
) -> impl Parser<char, Expr, Error = Simple<char>> + Clone { ) -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
pad(keyword("fn")) pad(keyword("fn"))
.ignore_then(parse_pattern(m).repeated()) .ignore_then(parse_pattern(m).repeated())
.then_ignore(pad(just("->"))) .then_ignore(pad(just("->")))
.then(base) .then(rec)
.map(|(arguments, result)| Expr::Lambda { .map(|(arguments, result)| {
arguments, expr(ExprKind::Lambda {
result: Box::new(result), arguments,
result: Box::new(result),
})
}) })
} }
@ -585,36 +597,38 @@ 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)| match kind { subscripts.into_iter().fold(l, |l, (kind, r)| {
SubscriptKind::Dot => Expr::DotSubscript { expr(match kind {
value: Box::new(l), SubscriptKind::Dot => ExprKind::DotSubscript {
subscript: Box::new(r), value: Box::new(l),
}, subscript: Box::new(r),
SubscriptKind::Bracket => Expr::BracketSubscript { },
value: Box::new(l), SubscriptKind::Bracket => ExprKind::BracketSubscript {
subscript: Box::new(r), value: Box::new(l),
}, subscript: Box::new(r),
},
})
}) })
}) })
} }
fn parse_tuple_expr( fn parse_tuple_expr(
_m: &ParserMeta, _m: &ParserMeta,
base: impl Parser<char, Expr, Error = Simple<char>> + Clone, rec: impl Parser<char, Expr, Error = Simple<char>> + Clone,
) -> impl Parser<char, Expr, Error = Simple<char>> + Clone { ) -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
base.separated_by(pad(just(','))) rec.separated_by(pad(just(',')))
.delimited_by(pad(just('(')), pad(just(')'))) .delimited_by(pad(just('(')), pad(just(')')))
.map(|exprs| { .map(|exprs| {
if exprs.len() == 1 { if exprs.len() == 1 {
exprs.into_iter().next().unwrap() exprs.into_iter().next().unwrap()
} else { } else {
Expr::Tuple(exprs) expr(ExprKind::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(Expr::VariableReference) parse_identifier(m).map(|r| expr(ExprKind::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 {
@ -659,7 +673,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(Expr::Literal) pad(choice((int, float, string))).map(|lit| expr(ExprKind::Literal(lit)))
} }
fn parse_identifier( fn parse_identifier(
@ -797,8 +811,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 { parse_literal(m).map(|e| match e.kind {
Expr::Literal(lit) => Pattern::Literal(lit), ExprKind::Literal(lit) => Pattern::Literal(lit),
_ => unreachable!(), _ => unreachable!(),
}) })
} }
@ -829,6 +843,10 @@ 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

@ -65,6 +65,10 @@ 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<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.
@ -87,9 +91,19 @@ pub struct TypeConstructor {
pub args: Vec<Type>, pub args: Vec<Type>,
} }
/// Expressions. /// An expression.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Expr { 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<Type>,
}
/// The different kinds of expressions.
#[derive(Clone, Debug)]
pub enum ExprKind {
/// Unary operators, e.g., `-5`. /// Unary operators, e.g., `-5`.
UnaryOp { UnaryOp {
/// The text of the operator. /// The text of the operator.