Difficult ownership questions

This commit is contained in:
2022-05-30 05:21:00 +02:00
parent 1e8aa45176
commit ec1734e113
15 changed files with 441 additions and 89 deletions

View File

@@ -6,63 +6,76 @@ use super::number;
use super::misc;
use super::name;
#[derive(Debug)]
/// An S-expression as read from a source file
#[derive(Debug, Clone)]
pub enum Expr {
Num(f64),
Int(u64),
Char(char),
Str(String),
Name(String),
Name(Vec<String>),
S(Vec<Expr>),
Lambda(String, Option<Box<Expr>>, Vec<Expr>),
Auto(Option<String>, Option<Box<Expr>>, Vec<Expr>),
Typed(Box<Expr>, Box<Expr>)
}
/// Parse a type annotation
fn typed_parser<'a>(
expr: Recursive<'a, char, Expr, Simple<char>>,
ops: &'a [String]
expr: Recursive<'a, char, Expr, Simple<char>>
) -> impl Parser<char, Expr, Error = Simple<char>> + 'a {
just(':').ignore_then(expr)
}
/// Parse an expression without a type annotation
fn untyped_xpr_parser<'a>(
expr: Recursive<'a, char, Expr, Simple<char>>,
ops: &'a [String]
ops: &[&'a str]
) -> impl Parser<char, Expr, Error = Simple<char>> + 'a {
let lambda = just('\\')
.ignore_then(name::name_parser(ops))
.then(typed_parser(expr.clone(), ops).or_not())
.then_ignore(just('.'))
.then(expr.clone().repeated().at_least(1))
.map(|((name, t), body)| Expr::Lambda(name, t.map(Box::new), body));
let auto = just('@')
.ignore_then(name::name_parser(ops).or_not())
.then(typed_parser(expr.clone(), ops).or_not())
.then_ignore(just('.'))
.then(expr.clone().repeated().at_least(1))
.map(|((name, t), body)| Expr::Auto(name, t.map(Box::new), body));
// basic S-expression rule
let sexpr = expr.clone()
.repeated()
.delimited_by(just('('), just(')'))
.map(Expr::S);
// Blocks
// can and therefore do match everything up to the closing paren
// \name. body
// \name:type. body
let lambda = just('\\')
.ignore_then(text::ident())
.then(typed_parser(expr.clone()).or_not())
.then_ignore(just('.'))
.then(expr.clone().repeated().at_least(1))
.map(|((name, t), body)| Expr::Lambda(name, t.map(Box::new), body));
// @name. body
// @name:type. body
// @:type. body
let auto = just('@')
.ignore_then(text::ident().or_not())
.then(typed_parser(expr.clone()).or_not())
.then_ignore(just('.'))
.then(expr.clone().repeated().at_least(1))
.map(|((name, t), body)| Expr::Auto(name, t.map(Box::new), body));
choice((
number::int_parser().map(Expr::Int), // all ints are valid floats so it takes precedence
number::float_parser().map(Expr::Num),
number::int_parser().map(Expr::Int),
string::char_parser().map(Expr::Char),
string::str_parser().map(Expr::Str),
name::name_parser(ops).map(Expr::Name),
name::name_parser(ops).map(Expr::Name), // includes namespacing
sexpr,
lambda,
auto
)).padded()
}
pub fn expression_parser(ops: &[String]) -> impl Parser<char, Expr, Error = Simple<char>> + '_ {
/// Parse any expression with a type annotation, surrounded by comments
pub fn expression_parser<'a>(ops: &[&'a str]) -> impl Parser<char, Expr, Error = Simple<char>> + 'a {
// This approach to parsing comments is ugly and error-prone,
// but I don't have a lot of other ideas
return recursive(|expr| {
return misc::comment_parser().or_not().ignore_then(
untyped_xpr_parser(expr.clone(), &ops)
.then(typed_parser(expr, ops).or_not())
.then(typed_parser(expr).or_not())
.map(|(val, t)| match t {
Some(typ) => Expr::Typed(Box::new(val), Box::new(typ)),
None => val