Parse lambdas, records, indexing
This commit is contained in:
parent
8331e4f341
commit
a28cce5b63
1
axc/foo.axs
Normal file
1
axc/foo.axs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
def a (x: String) = 2 + a::b["xyz"] + fn x y -> x + y + {a : b};
|
|
@ -3,7 +3,7 @@
|
||||||
use std::{error::Error, fmt::Display};
|
use std::{error::Error, fmt::Display};
|
||||||
|
|
||||||
use chumsky::{
|
use chumsky::{
|
||||||
prelude::{choice, end, just, none_of, one_of, Simple},
|
prelude::{choice, end, just, none_of, one_of, todo, Simple},
|
||||||
recursive::recursive,
|
recursive::recursive,
|
||||||
text::{ident, int, keyword, whitespace},
|
text::{ident, int, keyword, whitespace},
|
||||||
Parser,
|
Parser,
|
||||||
|
@ -331,11 +331,22 @@ fn parse_class_def<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_expression<'a>(m: &'a ParserMeta) -> impl Parser<char, Expr, Error = Simple<char>> + 'a {
|
fn parse_expression<'a>(m: &'a ParserMeta) -> impl Parser<char, Expr, Error = Simple<char>> + 'a {
|
||||||
(0..=10)
|
recursive(|full_expr| {
|
||||||
.rev()
|
let lambda = parse_lambda_expr(m, full_expr.clone());
|
||||||
.fold(parse_unary(m, parse_literal(m)).boxed(), |p, precedence| {
|
let record = parse_record_expr(m, full_expr.clone());
|
||||||
|
|
||||||
|
let base = choice((parse_literal(m), parse_var_ref_expr(m)));
|
||||||
|
let subscript = parse_subscript_expr(m, base);
|
||||||
|
let term = choice((lambda, record, subscript));
|
||||||
|
|
||||||
|
let unary = parse_unary(m, term);
|
||||||
|
|
||||||
|
let binary = (0..=10).rev().fold(unary.boxed(), |p, precedence| {
|
||||||
parse_binary(m, precedence, p).boxed()
|
parse_binary(m, precedence, p).boxed()
|
||||||
})
|
});
|
||||||
|
|
||||||
|
binary
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_unary(
|
fn parse_unary(
|
||||||
|
@ -435,6 +446,79 @@ fn parse_binary<'a>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_record_expr(
|
||||||
|
_m: &ParserMeta,
|
||||||
|
base: impl Parser<char, Expr, Error = Simple<char>> + Clone,
|
||||||
|
) -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
|
||||||
|
ident()
|
||||||
|
.then_ignore(whitespace())
|
||||||
|
.then_ignore(just(':'))
|
||||||
|
.then_ignore(whitespace())
|
||||||
|
.then(base)
|
||||||
|
.separated_by(just(',').then(whitespace()))
|
||||||
|
.allow_trailing()
|
||||||
|
.delimited_by(just('{').then(whitespace()), just('}').then(whitespace()))
|
||||||
|
.map(Expr::Record)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_lambda_expr(
|
||||||
|
m: &ParserMeta,
|
||||||
|
base: impl Parser<char, Expr, Error = Simple<char>> + Clone,
|
||||||
|
) -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
|
||||||
|
keyword("fn")
|
||||||
|
.then(whitespace())
|
||||||
|
.ignore_then(parse_pattern(m).repeated())
|
||||||
|
.then_ignore(just("->").then(whitespace()))
|
||||||
|
.then(base)
|
||||||
|
.map(|(arguments, result)| Expr::Lambda {
|
||||||
|
arguments,
|
||||||
|
result: Box::new(result),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_subscript_expr(
|
||||||
|
_m: &ParserMeta,
|
||||||
|
base: impl Parser<char, Expr, Error = Simple<char>> + Clone,
|
||||||
|
) -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
|
||||||
|
enum SubscriptKind {
|
||||||
|
Dot,
|
||||||
|
Bracket,
|
||||||
|
}
|
||||||
|
|
||||||
|
base.clone()
|
||||||
|
.then(
|
||||||
|
choice((
|
||||||
|
just('.')
|
||||||
|
.ignore_then(whitespace())
|
||||||
|
.ignore_then(base.clone())
|
||||||
|
.map(|e| (SubscriptKind::Dot, e)),
|
||||||
|
base.clone()
|
||||||
|
.delimited_by(just('[').then(whitespace()), just(']').then(whitespace()))
|
||||||
|
.map(|e| (SubscriptKind::Bracket, e)),
|
||||||
|
))
|
||||||
|
.repeated(),
|
||||||
|
)
|
||||||
|
.map(|(l, subscripts): (Expr, Vec<(SubscriptKind, Expr)>)| {
|
||||||
|
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_var_ref_expr(m: &ParserMeta) -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
|
||||||
|
ident()
|
||||||
|
.then_ignore(whitespace())
|
||||||
|
.separated_by(just("::").then(whitespace()))
|
||||||
|
.map(Expr::VariableReference)
|
||||||
|
}
|
||||||
|
|
||||||
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 {
|
||||||
let string_char = none_of("\"\\").or(just('\\').ignore_then(choice((
|
let string_char = none_of("\"\\").or(just('\\').ignore_then(choice((
|
||||||
just('n').to('\n'),
|
just('n').to('\n'),
|
||||||
|
@ -540,7 +624,7 @@ fn parse_record_type(
|
||||||
.map(Type::Record)
|
.map(Type::Record)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_pattern(m: &ParserMeta) -> impl Parser<char, Pattern, Error = Simple<char>> {
|
fn parse_pattern(m: &ParserMeta) -> impl Parser<char, Pattern, Error = Simple<char>> + Clone {
|
||||||
recursive(|rec| {
|
recursive(|rec| {
|
||||||
choice((
|
choice((
|
||||||
parse_ignore_pattern(m),
|
parse_ignore_pattern(m),
|
||||||
|
|
|
@ -143,10 +143,7 @@ pub enum Expr {
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Record initialization, e.g., `{ pointer: xyz, length: 12 }`.
|
/// Record initialization, e.g., `{ pointer: xyz, length: 12 }`.
|
||||||
Record {
|
Record(Vec<(String, Expr)>),
|
||||||
/// The elements of the record.
|
|
||||||
elements: Vec<(String, Expr)>,
|
|
||||||
},
|
|
||||||
|
|
||||||
/// Anonymous functions, e.g., `fn x -> x + 1`.
|
/// Anonymous functions, e.g., `fn x -> x + 1`.
|
||||||
Lambda {
|
Lambda {
|
||||||
|
@ -158,16 +155,13 @@ pub enum Expr {
|
||||||
result: Box<Expr>,
|
result: Box<Expr>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Variable references, possibly namespaced, e.g., `foo::bar::baz`.
|
|
||||||
VariableReference(Vec<String>),
|
|
||||||
|
|
||||||
/// Dot subscripts, e.g., `foo.bar`.
|
/// Dot subscripts, e.g., `foo.bar`.
|
||||||
DotSubscript {
|
DotSubscript {
|
||||||
/// The left side of the subscript.
|
/// The left side of the subscript.
|
||||||
value: Box<Expr>,
|
value: Box<Expr>,
|
||||||
|
|
||||||
/// The right side of the subscript; this is only allowed to be a single word.
|
/// The right side of the subscript; semantically, this is only allowed to be a single word.
|
||||||
subscript: String,
|
subscript: Box<Expr>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Bracket subscripts, e.g., `foo[bar]`.
|
/// Bracket subscripts, e.g., `foo[bar]`.
|
||||||
|
@ -179,6 +173,9 @@ pub enum Expr {
|
||||||
subscript: Box<Expr>,
|
subscript: Box<Expr>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Variable references, possibly namespaced, e.g., `foo::bar::baz`.
|
||||||
|
VariableReference(Vec<String>),
|
||||||
|
|
||||||
/// Literal tokens, e.g., strings and numbers.
|
/// Literal tokens, e.g., strings and numbers.
|
||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue