ast: fn main
, structification
parser: unified post/infix, context-full grammar repl: modes
This commit is contained in:
parent
434fa225e7
commit
8640ec4261
76
src/ast.rs
76
src/ast.rs
@ -58,7 +58,7 @@ pub struct MakeArm<A: Annotation = Span>(pub String, pub Option<Anno<Expr<A>, A>
|
|||||||
/// (Pat |)* Pat? => Expr
|
/// (Pat |)* Pat? => Expr
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct MatchArm<A: Annotation = Span>(pub Vec<Pat>, pub Anno<Expr<A>, A>);
|
pub struct MatchArm<A: Annotation = Span>(pub Pat, pub Anno<Expr<A>, A>);
|
||||||
|
|
||||||
/// In-universe types
|
/// In-universe types
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
@ -77,6 +77,22 @@ pub enum Ty {
|
|||||||
Fn(Vec<Ty>),
|
Fn(Vec<Ty>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A `const` binding (which defines its name before executing)
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct Const<A: Annotation = Span>(pub Pat, pub Anno<Expr<A>, A>);
|
||||||
|
|
||||||
|
/// A function definition `fn Ident? (Pat,*) Expr`
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct Fn<A: Annotation = Span>(pub Option<String>, pub Pat, pub Anno<Expr<A>, A>);
|
||||||
|
|
||||||
|
/// A `let` binding: `let Pat (= Expr)?`
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct Let<A: Annotation = Span>(pub Pat, pub Option<Anno<Expr<A>, A>>);
|
||||||
|
|
||||||
|
/// `match Expr { MatchArm,* }``
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct Match<A: Annotation = Span>(pub Anno<Expr<A>, A>, pub Vec<MatchArm<A>>);
|
||||||
|
|
||||||
/// Expressions: The beating heart of Dough
|
/// Expressions: The beating heart of Dough
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Expr<A: Annotation = Span> {
|
pub enum Expr<A: Annotation = Span> {
|
||||||
@ -87,15 +103,15 @@ pub enum Expr<A: Annotation = Span> {
|
|||||||
/// A literal bool, string, char, or int
|
/// A literal bool, string, char, or int
|
||||||
Lit(Literal),
|
Lit(Literal),
|
||||||
/// let Pat<NoTopAlt> = expr
|
/// let Pat<NoTopAlt> = expr
|
||||||
Let(Pat, Option<Box<Anno<Self, A>>>),
|
Let(Box<Let<A>>),
|
||||||
/// `const Pat<NoTopAlt> (= Expr)?` (Basically let rec)
|
/// `const Pat<NoTopAlt> (= Expr)?` (Basically let rec)
|
||||||
Const(Pat, Box<Anno<Self, A>>),
|
Const(Box<Const<A>>),
|
||||||
/// `| Pat<Tuple> | Expr` | `|| Expr` | `fn (Pat,*) Expr`
|
/// `| Pat<Tuple> | Expr` | `|| Expr` | `fn Ident? (Pat,*) Expr`
|
||||||
Fn(Pat, Box<Anno<Self, A>>),
|
Fn(Box<Fn<A>>),
|
||||||
/// Expr { (Ident (: Expr)?),* }
|
/// Expr { (Ident (: Expr)?),* }
|
||||||
Make(Box<Anno<Self, A>>, Vec<MakeArm<A>>),
|
Make(Box<Anno<Self, A>>, Vec<MakeArm<A>>),
|
||||||
/// match Expr { MatchArm,* }
|
/// match Expr { MatchArm,* }
|
||||||
Match(Box<Anno<Self, A>>, Vec<MatchArm<A>>),
|
Match(Box<Match<A>>),
|
||||||
/// Op Expr | Expr Op | Expr (Op Expr)+ | Op Expr Expr else Expr
|
/// Op Expr | Expr Op | Expr (Op Expr)+ | Op Expr Expr else Expr
|
||||||
Op(Op, Vec<Anno<Self, A>>),
|
Op(Op, Vec<Anno<Self, A>>),
|
||||||
}
|
}
|
||||||
@ -205,22 +221,52 @@ impl<T: Display + Annotation, A: Annotation> Display for Anno<T, A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<A: Annotation> Display for Const<A> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let Self(pat, expr) = self;
|
||||||
|
write!(f, "const {pat} = {expr}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Annotation> Display for Fn<A> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self(Some(name), pat, expr) => write!(f, "fn {name} {pat} {expr}"),
|
||||||
|
Self(None, pat, expr) => write!(f, "|{pat}| {expr}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Annotation> Display for Let<A> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self(pat, Some(expr)) => write!(f, "let {pat} = {expr}"),
|
||||||
|
Self(pat, None) => write!(f, "let ({pat})"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Annotation> Display for Match<A> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let Self(expr, match_arms) = self;
|
||||||
|
f.delimit_indented(fmt!("match {expr} {{"), "}")
|
||||||
|
.list_wrap("\n", match_arms, ",\n", ",\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<A: Annotation> Display for Expr<A> {
|
impl<A: Annotation> Display for Expr<A> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Id(id) => id.fmt(f),
|
Self::Id(id) => id.fmt(f),
|
||||||
Self::MetId(id) => write!(f, "`{id}"),
|
Self::MetId(id) => write!(f, "`{id}"),
|
||||||
Self::Lit(literal) => literal.fmt(f),
|
Self::Lit(literal) => literal.fmt(f),
|
||||||
Self::Let(pat, Some(expr)) => write!(f, "let {pat} = {expr}"),
|
Self::Let(v) => v.fmt(f),
|
||||||
Self::Let(pat, None) => write!(f, "let ({pat})"),
|
Self::Const(v) => v.fmt(f),
|
||||||
Self::Const(pat, expr) => write!(f, "const {pat} = {expr}"),
|
|
||||||
Self::Make(expr, make_arms) => {
|
Self::Make(expr, make_arms) => {
|
||||||
f.delimit(fmt!("({expr} {{"), "})").list(make_arms, ", ")
|
f.delimit(fmt!("({expr} {{"), "})").list(make_arms, ", ")
|
||||||
}
|
}
|
||||||
Self::Match(expr, match_arms) => f
|
Self::Match(v) => v.fmt(f),
|
||||||
.delimit_indented(fmt!("match {expr} {{"), "}")
|
Self::Fn(v) => v.fmt(f),
|
||||||
.list_wrap("\n", match_arms, ",\n", ",\n"),
|
|
||||||
Self::Fn(pat, expr) => write!(f, "fn {pat} {expr}"),
|
|
||||||
|
|
||||||
Self::Op(op @ (Op::If | Op::While), exprs) => match exprs.as_slice() {
|
Self::Op(op @ (Op::If | Op::While), exprs) => match exprs.as_slice() {
|
||||||
[cond, pass, fail] => write!(f, "{op}{cond} {pass} else {fail}"),
|
[cond, pass, fail] => write!(f, "{op}{cond} {pass} else {fail}"),
|
||||||
@ -315,8 +361,8 @@ impl<A: Annotation> Display for MakeArm<A> {
|
|||||||
|
|
||||||
impl<A: Annotation> Display for MatchArm<A> {
|
impl<A: Annotation> Display for MatchArm<A> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let Self(pats, expr) = self;
|
let Self(pat, expr) = self;
|
||||||
f.delimit("", fmt!(" => {expr}")).list(pats, " | ")
|
write!(f, "{pat} => {expr}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,6 +78,60 @@ impl<M: Match<A> + Annotation, A: Annotation> Match<A> for Anno<M, A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<A: Annotation> Match<A> for Const<A> {
|
||||||
|
fn recurse(sub: &mut Subst<A>, pat: &Self, expr: &Self) -> bool {
|
||||||
|
let (Self(pat_pat, pat_expr), Self(expr_pat, expr_expr)) = (pat, expr);
|
||||||
|
Match::recurse(sub, pat_pat, expr_pat) && Match::recurse(sub, pat_expr, expr_expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(&mut self, sub: &Subst<A>) {
|
||||||
|
let Self(pat, expr) = self;
|
||||||
|
pat.apply(sub);
|
||||||
|
expr.apply(sub);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Annotation> Match<A> for Fn<A> {
|
||||||
|
fn recurse(sub: &mut Subst<A>, pat: &Self, expr: &Self) -> bool {
|
||||||
|
let (Self(pat_id, pat_arg, pat_body), Self(expr_id, expr_arg, expr_body)) = (pat, expr);
|
||||||
|
pat_id == expr_id
|
||||||
|
&& Match::recurse(sub, pat_arg, expr_arg)
|
||||||
|
&& Match::recurse(sub, pat_body, expr_body)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(&mut self, sub: &Subst<A>) {
|
||||||
|
let Self(_, pat, body) = self;
|
||||||
|
pat.apply(sub);
|
||||||
|
body.apply(sub);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Annotation> Match<A> for Let<A> {
|
||||||
|
fn recurse(sub: &mut Subst<A>, pat: &Self, expr: &Self) -> bool {
|
||||||
|
let (Self(pat_pat, pat_expr), Self(expr_pat, expr_expr)) = (pat, expr);
|
||||||
|
Match::recurse(sub, pat_pat, expr_pat) && Match::recurse(sub, pat_expr, expr_expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(&mut self, sub: &Subst<A>) {
|
||||||
|
let Self(pat, expr) = self;
|
||||||
|
pat.apply(sub);
|
||||||
|
expr.apply(sub);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Annotation> Match<A> for crate::ast::Match<A> {
|
||||||
|
fn recurse(sub: &mut Subst<A>, pat: &Self, expr: &Self) -> bool {
|
||||||
|
let (Self(pat_expr, pat_arms), Self(expr_expr, expr_arms)) = (pat, expr);
|
||||||
|
Match::recurse(sub, pat_expr, expr_expr) && Match::recurse(sub, pat_arms, expr_arms)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(&mut self, sub: &Subst<A>) {
|
||||||
|
let Self(pat, expr) = self;
|
||||||
|
pat.apply(sub);
|
||||||
|
expr.apply(sub);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<A: Annotation> Match<A> for Expr<A> {
|
impl<A: Annotation> Match<A> for Expr<A> {
|
||||||
fn recurse(sub: &mut Subst<A>, pat: &Self, expr: &Self) -> bool {
|
fn recurse(sub: &mut Subst<A>, pat: &Self, expr: &Self) -> bool {
|
||||||
match (pat, expr) {
|
match (pat, expr) {
|
||||||
@ -87,25 +141,17 @@ impl<A: Annotation> Match<A> for Expr<A> {
|
|||||||
(Expr::Id(_), _) => false,
|
(Expr::Id(_), _) => false,
|
||||||
(Expr::Lit(pat), Expr::Lit(expr)) => pat == expr,
|
(Expr::Lit(pat), Expr::Lit(expr)) => pat == expr,
|
||||||
(Expr::Lit(_), _) => false,
|
(Expr::Lit(_), _) => false,
|
||||||
(Expr::Let(pat_pat, pat_expr), Expr::Let(expr_pat, expr_expr)) => {
|
(Expr::Let(pat), Expr::Let(expr)) => Match::recurse(sub, pat, expr),
|
||||||
Match::recurse(sub, pat_pat, expr_pat) && Match::recurse(sub, pat_expr, expr_expr)
|
|
||||||
}
|
|
||||||
(Expr::Let(..), _) => false,
|
(Expr::Let(..), _) => false,
|
||||||
(Expr::Const(pat_pat, pat_expr), Expr::Const(expr_pat, expr_expr)) => {
|
(Expr::Const(pat), Expr::Const(expr)) => Match::recurse(sub, pat, expr),
|
||||||
Match::recurse(sub, pat_pat, expr_pat) && Match::recurse(sub, pat_expr, expr_expr)
|
|
||||||
}
|
|
||||||
(Expr::Const(..), _) => false,
|
(Expr::Const(..), _) => false,
|
||||||
(Expr::Make(pat, pat_arms), Expr::Make(expr, expr_arms)) => {
|
(Expr::Make(pat, pat_arms), Expr::Make(expr, expr_arms)) => {
|
||||||
Match::recurse(sub, pat, expr) && Match::recurse(sub, pat_arms, expr_arms)
|
Match::recurse(sub, pat, expr) && Match::recurse(sub, pat_arms, expr_arms)
|
||||||
}
|
}
|
||||||
(Expr::Make(..), _) => false,
|
(Expr::Make(..), _) => false,
|
||||||
(Expr::Match(pat, pat_arms), Expr::Match(expr, expr_arms)) => {
|
(Expr::Match(pat), Expr::Match(expr)) => Match::recurse(sub, pat, expr),
|
||||||
Match::recurse(sub, pat, expr) && Match::recurse(sub, pat_arms, expr_arms)
|
|
||||||
}
|
|
||||||
(Expr::Match(..), _) => false,
|
(Expr::Match(..), _) => false,
|
||||||
(Expr::Fn(pat_pats, pat_expr), Expr::Fn(expr_pats, expr_expr)) => {
|
(Expr::Fn(pat), Expr::Fn(expr)) => Match::recurse(sub, pat, expr),
|
||||||
Match::recurse(sub, pat_pats, expr_pats) && Match::recurse(sub, pat_expr, expr_expr)
|
|
||||||
}
|
|
||||||
(Expr::Fn(..), _) => false,
|
(Expr::Fn(..), _) => false,
|
||||||
(Expr::Op(pat_op, pat_exprs), Expr::Op(expr_op, expr_exprs)) => {
|
(Expr::Op(pat_op, pat_exprs), Expr::Op(expr_op, expr_exprs)) => {
|
||||||
Match::recurse(sub, pat_op, expr_op) && Match::recurse(sub, pat_exprs, expr_exprs)
|
Match::recurse(sub, pat_op, expr_op) && Match::recurse(sub, pat_exprs, expr_exprs)
|
||||||
@ -122,24 +168,20 @@ impl<A: Annotation> Match<A> for Expr<A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Id(_) | Expr::Lit(_) => {}
|
Expr::Id(_) | Expr::Lit(_) => {}
|
||||||
Expr::Let(pat, expr) => {
|
Expr::Let(expr) => {
|
||||||
pat.apply(sub);
|
|
||||||
expr.apply(sub);
|
expr.apply(sub);
|
||||||
}
|
}
|
||||||
Expr::Const(pat, expr) => {
|
Expr::Const(expr) => {
|
||||||
pat.apply(sub);
|
|
||||||
expr.apply(sub);
|
expr.apply(sub);
|
||||||
}
|
}
|
||||||
Expr::Make(expr, make_arms) => {
|
Expr::Make(expr, make_arms) => {
|
||||||
expr.apply(sub);
|
expr.apply(sub);
|
||||||
make_arms.apply(sub);
|
make_arms.apply(sub);
|
||||||
}
|
}
|
||||||
Expr::Match(expr, match_arms) => {
|
Expr::Match(expr) => {
|
||||||
expr.apply(sub);
|
expr.apply(sub);
|
||||||
match_arms.apply(sub);
|
|
||||||
}
|
}
|
||||||
Expr::Fn(pats, expr) => {
|
Expr::Fn(expr) => {
|
||||||
pats.apply(sub);
|
|
||||||
expr.apply(sub);
|
expr.apply(sub);
|
||||||
}
|
}
|
||||||
Expr::Op(op, exprs) => {
|
Expr::Op(op, exprs) => {
|
||||||
|
87
src/main.rs
87
src/main.rs
@ -1,4 +1,8 @@
|
|||||||
//! Tests the lexer
|
//! Tests the lexer
|
||||||
|
use doughlang::{
|
||||||
|
ast::{Anno, Pat},
|
||||||
|
parser::PPrec,
|
||||||
|
};
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use doughlang::{
|
use doughlang::{
|
||||||
ast::{
|
ast::{
|
||||||
@ -25,7 +29,19 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
print!("\x1b[H\x1b[2J");
|
print!("\x1b[H\x1b[2J");
|
||||||
Ok(Response::Deny)
|
Ok(Response::Deny)
|
||||||
}
|
}
|
||||||
|
"lex" => {
|
||||||
|
lex()?;
|
||||||
|
Ok(Response::Deny)
|
||||||
|
}
|
||||||
|
"expr" => {
|
||||||
|
exprs()?;
|
||||||
|
Ok(Response::Deny)
|
||||||
|
}
|
||||||
"pat" => {
|
"pat" => {
|
||||||
|
pats()?;
|
||||||
|
Ok(Response::Deny)
|
||||||
|
}
|
||||||
|
"macro" => {
|
||||||
if let Err(e) = subst() {
|
if let Err(e) = subst() {
|
||||||
println!("\x1b[31m{e}\x1b[0m");
|
println!("\x1b[31m{e}\x1b[0m");
|
||||||
}
|
}
|
||||||
@ -38,28 +54,79 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
})?;
|
})?;
|
||||||
} else {
|
} else {
|
||||||
let doc = std::io::read_to_string(stdin())?;
|
let doc = std::io::read_to_string(stdin())?;
|
||||||
lex(&doc);
|
// lex(&doc);
|
||||||
parse(&doc);
|
parse(&doc);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lex(document: &str) {
|
fn lex() -> Result<(), Box<dyn Error>> {
|
||||||
let mut lexer = Lexer::new(document);
|
read_and("\x1b[93m", " >", "?>", |line| {
|
||||||
|
let mut lexer = Lexer::new(line);
|
||||||
|
if line.trim().is_empty() {
|
||||||
|
return Ok(Response::Break);
|
||||||
|
}
|
||||||
loop {
|
loop {
|
||||||
match lexer.scan() {
|
match lexer.scan() {
|
||||||
Ok(Token { lexeme, kind, span: Span { head, tail } }) => {
|
Err(LexError { res: "EOF", .. }) => {
|
||||||
println!(
|
break Ok(Response::Accept);
|
||||||
"{kind:?}\x1b[11G {head:<4} {tail:<4} {}",
|
|
||||||
lexeme.escape_debug()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("{e}");
|
println!("\x1b[31m{e}\x1b[0m");
|
||||||
break;
|
break Ok(Response::Deny);
|
||||||
|
}
|
||||||
|
Ok(Token { lexeme, kind, span: Span { head, tail } }) => println!(
|
||||||
|
"{kind:?}\x1b[11G {head:<4} {tail:<4} {}",
|
||||||
|
lexeme.escape_debug()
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exprs() -> Result<(), Box<dyn Error>> {
|
||||||
|
read_and("\x1b[93m", " >", "?>", |line| {
|
||||||
|
let mut parser = Parser::new(Lexer::new(line));
|
||||||
|
if line.trim().is_empty() {
|
||||||
|
return Ok(Response::Break);
|
||||||
}
|
}
|
||||||
|
loop {
|
||||||
|
match parser.parse::<Anno<Expr>>(0) {
|
||||||
|
Err(ParseError::FromLexer(LexError { res: "EOF", .. })) => {
|
||||||
|
break Ok(Response::Accept);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("\x1b[31m{e}\x1b[0m");
|
||||||
|
break Ok(Response::Deny);
|
||||||
|
}
|
||||||
|
Ok(v) => println!("{v}\n{v:#?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pats() -> Result<(), Box<dyn Error>> {
|
||||||
|
read_and("\x1b[94m", " >", "?>", |line| {
|
||||||
|
let mut parser = Parser::new(Lexer::new(line));
|
||||||
|
if line.trim().is_empty() {
|
||||||
|
return Ok(Response::Break);
|
||||||
|
}
|
||||||
|
loop {
|
||||||
|
match parser.parse::<Pat>(PPrec::Max) {
|
||||||
|
Err(ParseError::FromLexer(LexError { res: "EOF", .. })) => {
|
||||||
|
break Ok(Response::Accept);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("\x1b[31m{e}\x1b[0m");
|
||||||
|
break Ok(Response::Deny);
|
||||||
|
}
|
||||||
|
Ok(v) => println!("{v}\n{v:#?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subst() -> Result<(), Box<dyn Error>> {
|
fn subst() -> Result<(), Box<dyn Error>> {
|
||||||
|
234
src/parser.rs
234
src/parser.rs
@ -121,6 +121,7 @@ impl<'t> Parser<'t> {
|
|||||||
sep: TKind,
|
sep: TKind,
|
||||||
end: TKind,
|
end: TKind,
|
||||||
) -> PResult<Vec<P>> {
|
) -> PResult<Vec<P>> {
|
||||||
|
// TODO: This loses lexer errors
|
||||||
while self.peek_if(end).is_none() {
|
while self.peek_if(end).is_none() {
|
||||||
elems.push(self.parse(level)?);
|
elems.push(self.parse(level)?);
|
||||||
if self.next_if(sep).is_err() {
|
if self.next_if(sep).is_err() {
|
||||||
@ -167,6 +168,11 @@ impl<'t> Parser<'t> {
|
|||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn consume_if(&mut self, next: TKind) -> PResult<&mut Self> {
|
||||||
|
self.next_if(next)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
/// Consumes the currently peeked token without returning it.
|
/// Consumes the currently peeked token without returning it.
|
||||||
pub fn consume(&mut self) -> &mut Self {
|
pub fn consume(&mut self) -> &mut Self {
|
||||||
self.next_tok = None;
|
self.next_tok = None;
|
||||||
@ -217,6 +223,18 @@ pub enum PPrec {
|
|||||||
Max,
|
Max,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PPrec {
|
||||||
|
fn next(self) -> Self {
|
||||||
|
match self {
|
||||||
|
Self::Min => Self::Min,
|
||||||
|
Self::Typed => Self::Min,
|
||||||
|
Self::Tuple => Self::Typed,
|
||||||
|
Self::Alt => Self::Tuple,
|
||||||
|
Self::Max => Self::Alt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'t> Parse<'t> for Pat {
|
impl<'t> Parse<'t> for Pat {
|
||||||
type Prec = PPrec;
|
type Prec = PPrec;
|
||||||
fn parse(p: &mut Parser<'t>, level: PPrec) -> PResult<Self> {
|
fn parse(p: &mut Parser<'t>, level: PPrec) -> PResult<Self> {
|
||||||
@ -240,13 +258,13 @@ impl<'t> Parse<'t> for Pat {
|
|||||||
TKind::LParen => {
|
TKind::LParen => {
|
||||||
Pat::Tuple(
|
Pat::Tuple(
|
||||||
p.consume()
|
p.consume()
|
||||||
.list(vec![], PPrec::Tuple, TKind::Comma, TKind::RParen)?,
|
.list(vec![], PPrec::Max, TKind::Comma, TKind::RParen)?,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
TKind::LBrack => {
|
TKind::LBrack => {
|
||||||
Pat::Slice(
|
Pat::Slice(
|
||||||
p.consume()
|
p.consume()
|
||||||
.list(vec![], PPrec::Tuple, TKind::Comma, TKind::RBrack)?,
|
.list(vec![], PPrec::Max, TKind::Comma, TKind::RBrack)?,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => Err(ParseError::NotPattern(tok.kind, tok.span))?,
|
_ => Err(ParseError::NotPattern(tok.kind, tok.span))?,
|
||||||
@ -257,14 +275,16 @@ impl<'t> Parse<'t> for Pat {
|
|||||||
let kind = tok.kind;
|
let kind = tok.kind;
|
||||||
|
|
||||||
head = match kind {
|
head = match kind {
|
||||||
TKind::Colon if level > PPrec::Typed => {
|
TKind::Colon if level >= PPrec::Typed => {
|
||||||
Pat::Typed(head.into(), p.consume().parse(())?)
|
Pat::Typed(head.into(), p.consume().parse(())?)
|
||||||
}
|
}
|
||||||
TKind::Comma if level > PPrec::Tuple => {
|
TKind::Comma if level >= PPrec::Tuple => Pat::Tuple(p.consume().list_bare(
|
||||||
Pat::Tuple(p.consume().list_bare(vec![head], PPrec::Tuple, kind)?)
|
vec![head],
|
||||||
}
|
PPrec::Tuple.next(),
|
||||||
TKind::Bar if level > PPrec::Alt => {
|
kind,
|
||||||
Pat::Alt(p.consume().list_bare(vec![head], PPrec::Alt, kind)?)
|
)?),
|
||||||
|
TKind::Bar if level >= PPrec::Alt => {
|
||||||
|
Pat::Alt(p.consume().list_bare(vec![head], PPrec::Alt.next(), kind)?)
|
||||||
}
|
}
|
||||||
_ => break,
|
_ => break,
|
||||||
}
|
}
|
||||||
@ -305,32 +325,9 @@ impl<'t> Parse<'t> for Ty {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t> Parse<'t> for MatchArm {
|
|
||||||
type Prec = usize;
|
|
||||||
fn parse(p: &mut Parser<'t>, level: usize) -> PResult<Self> {
|
|
||||||
p.next_if(TKind::Bar).ok();
|
|
||||||
Ok(MatchArm(
|
|
||||||
p.list(vec![], PPrec::Max, TKind::Bar, TKind::FatArrow)?,
|
|
||||||
p.parse(level)?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'t> Parse<'t> for MakeArm {
|
|
||||||
type Prec = ();
|
|
||||||
fn parse(p: &mut Parser<'t>, _level: ()) -> PResult<Self> {
|
|
||||||
Ok(MakeArm(p.next_if(TKind::Identifier)?.lexeme, {
|
|
||||||
p.next_if(TKind::Colon)
|
|
||||||
.ok()
|
|
||||||
.map(|_| p.parse(Prec::Min.value()))
|
|
||||||
.transpose()?
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Organizes the precedence hierarchy for syntactic elements
|
/// Organizes the precedence hierarchy for syntactic elements
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
enum Prec {
|
pub enum Prec {
|
||||||
Min,
|
Min,
|
||||||
/// The Semicolon Operator gets its own precedence level
|
/// The Semicolon Operator gets its own precedence level
|
||||||
Do,
|
Do,
|
||||||
@ -462,7 +459,7 @@ fn from_infix(token: &Token) -> PResult<(Ps, Prec)> {
|
|||||||
TKind::Question => (Ps::Op(Op::Try), Prec::Unary),
|
TKind::Question => (Ps::Op(Op::Try), Prec::Unary),
|
||||||
TKind::LParen => (Ps::Op(Op::Call), Prec::Extend),
|
TKind::LParen => (Ps::Op(Op::Call), Prec::Extend),
|
||||||
TKind::LBrack => (Ps::Op(Op::Index), Prec::Extend),
|
TKind::LBrack => (Ps::Op(Op::Index), Prec::Extend),
|
||||||
// TKind::LCurly => (Ps::Make, Prec::Make),
|
TKind::LCurly => (Ps::Make, Prec::Make),
|
||||||
TKind::RParen | TKind::RBrack | TKind::RCurly => (Ps::End, Prec::Max),
|
TKind::RParen | TKind::RBrack | TKind::RCurly => (Ps::End, Prec::Max),
|
||||||
TKind::Eq => (Ps::Op(Op::Set), Prec::Assign),
|
TKind::Eq => (Ps::Op(Op::Set), Prec::Assign),
|
||||||
TKind::XorXor => (Ps::Op(Op::LogXor), Prec::Logical),
|
TKind::XorXor => (Ps::Op(Op::LogXor), Prec::Logical),
|
||||||
@ -488,13 +485,79 @@ fn from_infix(token: &Token) -> PResult<(Ps, Prec)> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::match_single_binding, unused)]
|
impl<'t> Parse<'t> for Const {
|
||||||
fn from_postfix(token: &Token) -> PResult<(Ps, Prec)> {
|
type Prec = ();
|
||||||
Ok(match token.kind {
|
|
||||||
TKind::LCurly => (Ps::Make, Prec::Make),
|
fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult<Self> {
|
||||||
kind => Err(ParseError::NotPostfix(kind, token.span))?,
|
Ok(Self(
|
||||||
// _ => (Ps::End, Prec::Max),
|
p.consume().parse(PPrec::Alt)?,
|
||||||
})
|
p.consume_if(TKind::Eq)?.parse(Prec::Tuple.value())?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'t> Parse<'t> for Fn {
|
||||||
|
type Prec = ();
|
||||||
|
|
||||||
|
fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult<Self> {
|
||||||
|
Ok(Self(
|
||||||
|
p.consume()
|
||||||
|
.next_if(TKind::Identifier)
|
||||||
|
.map(|id| id.lexeme)
|
||||||
|
.ok(),
|
||||||
|
Pat::Tuple(p.consume_if(TKind::LParen)?.list(
|
||||||
|
vec![],
|
||||||
|
PPrec::Tuple,
|
||||||
|
TKind::Comma,
|
||||||
|
TKind::RParen,
|
||||||
|
)?),
|
||||||
|
p.parse(Prec::Body.next())?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'t> Parse<'t> for Let {
|
||||||
|
type Prec = ();
|
||||||
|
|
||||||
|
fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult<Self> {
|
||||||
|
Ok(Self(
|
||||||
|
p.consume().parse(PPrec::Alt)?,
|
||||||
|
p.opt_if(Prec::Tuple.value(), TKind::Eq)?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'t> Parse<'t> for Match {
|
||||||
|
type Prec = ();
|
||||||
|
|
||||||
|
fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult<Self> {
|
||||||
|
Ok(Self(p.consume().parse(Prec::Logical.value())?, {
|
||||||
|
p.next_if(TKind::LCurly)?;
|
||||||
|
p.list(vec![], Prec::Body.next(), TKind::Comma, TKind::RCurly)?
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'t> Parse<'t> for MatchArm {
|
||||||
|
type Prec = usize;
|
||||||
|
fn parse(p: &mut Parser<'t>, level: usize) -> PResult<Self> {
|
||||||
|
p.next_if(TKind::Bar).ok();
|
||||||
|
Ok(MatchArm(
|
||||||
|
p.parse(PPrec::Max)?,
|
||||||
|
p.consume_if(TKind::FatArrow)?.parse(level)?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'t> Parse<'t> for MakeArm {
|
||||||
|
type Prec = ();
|
||||||
|
fn parse(p: &mut Parser<'t>, _level: ()) -> PResult<Self> {
|
||||||
|
Ok(MakeArm(p.next_if(TKind::Identifier)?.lexeme, {
|
||||||
|
p.next_if(TKind::Colon)
|
||||||
|
.ok()
|
||||||
|
.map(|_| p.parse(Prec::Body.value()))
|
||||||
|
.transpose()?
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t> Parse<'t> for Expr {
|
impl<'t> Parse<'t> for Expr {
|
||||||
@ -520,14 +583,8 @@ impl<'t> Parse<'t> for Expr {
|
|||||||
Ps::Id => Expr::Id(p.take_lexeme().expect("should have ident")),
|
Ps::Id => Expr::Id(p.take_lexeme().expect("should have ident")),
|
||||||
Ps::Mid => Expr::MetId(p.consume().next()?.lexeme),
|
Ps::Mid => Expr::MetId(p.consume().next()?.lexeme),
|
||||||
Ps::Lit => Expr::Lit(p.parse(())?),
|
Ps::Lit => Expr::Lit(p.parse(())?),
|
||||||
Ps::Let => Expr::Let(
|
Ps::Let => Expr::Let(p.parse(())?),
|
||||||
p.consume().parse(PPrec::Alt)?,
|
Ps::Const => Expr::Const(p.parse(())?),
|
||||||
p.opt_if(prec.value(), TKind::Eq)?,
|
|
||||||
),
|
|
||||||
Ps::Const => Expr::Const(p.consume().parse(PPrec::Tuple)?, {
|
|
||||||
p.next_if(TKind::Eq)?;
|
|
||||||
p.parse(prec.next())?
|
|
||||||
}),
|
|
||||||
Ps::Op(Op::Macro) => Expr::Op(
|
Ps::Op(Op::Macro) => Expr::Op(
|
||||||
Op::Macro,
|
Op::Macro,
|
||||||
vec![p.consume().parse(prec.next())?, {
|
vec![p.consume().parse(prec.next())?, {
|
||||||
@ -535,10 +592,7 @@ impl<'t> Parse<'t> for Expr {
|
|||||||
p.parse(prec.next())?
|
p.parse(prec.next())?
|
||||||
}],
|
}],
|
||||||
),
|
),
|
||||||
Ps::Match => Expr::Match(p.consume().parse(Prec::Logical.value())?, {
|
Ps::Match => Expr::Match(p.parse(())?),
|
||||||
p.next_if(TKind::LCurly)?;
|
|
||||||
p.list(vec![], prec.next(), TKind::Comma, TKind::RCurly)?
|
|
||||||
}),
|
|
||||||
Ps::Op(Op::Block) => Expr::Op(
|
Ps::Op(Op::Block) => Expr::Op(
|
||||||
Op::Block,
|
Op::Block,
|
||||||
p.consume().opt(MIN, TKind::RCurly)?.into_iter().collect(),
|
p.consume().opt(MIN, TKind::RCurly)?.into_iter().collect(),
|
||||||
@ -564,27 +618,17 @@ impl<'t> Parse<'t> for Expr {
|
|||||||
];
|
];
|
||||||
Expr::Op(op, exprs)
|
Expr::Op(op, exprs)
|
||||||
}
|
}
|
||||||
Ps::Fn => {
|
Ps::Fn => Expr::Fn(p.parse(())?),
|
||||||
// TODO: move this to 'item' parsing
|
Ps::Lambda => Expr::Fn(Box::new(Fn(
|
||||||
p.consume().next_if(TKind::LParen)?;
|
None,
|
||||||
Expr::Fn(
|
|
||||||
Pat::Tuple(p.consume().list(
|
|
||||||
vec![],
|
|
||||||
PPrec::Tuple,
|
|
||||||
TKind::Comma,
|
|
||||||
TKind::RParen,
|
|
||||||
)?),
|
|
||||||
p.parse(prec.next())?,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Ps::Lambda => Expr::Fn(
|
|
||||||
Pat::Tuple(
|
|
||||||
p.consume()
|
p.consume()
|
||||||
.list(vec![], PPrec::Tuple, TKind::Comma, TKind::Bar)?,
|
.opt(PPrec::Tuple, TKind::Bar)?
|
||||||
),
|
.unwrap_or(Pat::Tuple(vec![])),
|
||||||
p.parse(Prec::Body.next())?,
|
p.parse(Prec::Body.next())?,
|
||||||
),
|
))),
|
||||||
Ps::Lambda0 => Expr::Fn(Pat::Tuple(vec![]), p.consume().parse(Prec::Body.next())?),
|
Ps::Lambda0 => Expr::Fn(Box::new(Fn(None, Pat::Tuple(vec![]), {
|
||||||
|
p.consume().parse(Prec::Body.next())?
|
||||||
|
}))),
|
||||||
Ps::DoubleRef => Expr::Op(
|
Ps::DoubleRef => Expr::Op(
|
||||||
Op::Refer,
|
Op::Refer,
|
||||||
vec![Expr::Op(Op::Refer, vec![p.consume().parse(prec.next())?]).anno(span)],
|
vec![Expr::Op(Op::Refer, vec![p.consume().parse(prec.next())?]).anno(span)],
|
||||||
@ -594,25 +638,7 @@ impl<'t> Parse<'t> for Expr {
|
|||||||
_ => unimplemented!("prefix {op:?}"),
|
_ => unimplemented!("prefix {op:?}"),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Postfix
|
// Infix and Postfix
|
||||||
while let Ok(tok) = p.peek()
|
|
||||||
&& let Ok((op, prec)) = from_postfix(tok)
|
|
||||||
&& level <= prec.prev()
|
|
||||||
&& op != Ps::End
|
|
||||||
{
|
|
||||||
// let kind = tok.kind;
|
|
||||||
let span = span.merge(p.span());
|
|
||||||
// p.consume();
|
|
||||||
head = match (op, &head) {
|
|
||||||
(Ps::Make, Expr::Op(Op::Path, _) | Expr::Id(_) | Expr::MetId(_)) => Expr::Make(
|
|
||||||
head.anno(span).into(),
|
|
||||||
p.consume().list(vec![], (), TKind::Comma, TKind::RCurly)?,
|
|
||||||
),
|
|
||||||
_ => break,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Infix
|
|
||||||
while let Ok(tok) = p.peek()
|
while let Ok(tok) = p.peek()
|
||||||
&& let Ok((op, prec)) = from_infix(tok)
|
&& let Ok((op, prec)) = from_infix(tok)
|
||||||
&& level <= prec.prev()
|
&& level <= prec.prev()
|
||||||
@ -621,26 +647,37 @@ impl<'t> Parse<'t> for Expr {
|
|||||||
let kind = tok.kind;
|
let kind = tok.kind;
|
||||||
let span = span.merge(p.span());
|
let span = span.merge(p.span());
|
||||||
|
|
||||||
p.consume();
|
|
||||||
|
|
||||||
head = match op {
|
head = match op {
|
||||||
Ps::Make => Expr::Make(
|
// Make (structor expressions) are context-sensitive
|
||||||
|
Ps::Make => match &head {
|
||||||
|
Expr::Op(Op::Path, _) | Expr::Id(_) | Expr::MetId(_) => Expr::Make(
|
||||||
head.anno(span).into(),
|
head.anno(span).into(),
|
||||||
p.consume().list(vec![], (), TKind::Comma, TKind::RCurly)?,
|
p.consume().list(vec![], (), TKind::Comma, TKind::RCurly)?,
|
||||||
),
|
),
|
||||||
|
_ => break,
|
||||||
|
},
|
||||||
Ps::Op(Op::Index) => Expr::Op(
|
Ps::Op(Op::Index) => Expr::Op(
|
||||||
Op::Index,
|
Op::Index,
|
||||||
p.list(vec![head.anno(span)], 0, TKind::Comma, TKind::RBrack)?,
|
p.consume()
|
||||||
|
.list(vec![head.anno(span)], 0, TKind::Comma, TKind::RBrack)?,
|
||||||
),
|
),
|
||||||
Ps::Op(Op::Call) => Expr::Op(
|
Ps::Op(Op::Call) => Expr::Op(
|
||||||
Op::Call,
|
Op::Call,
|
||||||
p.list(vec![head.anno(span)], 0, TKind::Comma, TKind::RParen)?,
|
p.consume()
|
||||||
|
.list(vec![head.anno(span)], 0, TKind::Comma, TKind::RParen)?,
|
||||||
),
|
),
|
||||||
Ps::Op(op @ (Op::Do | Op::Tuple | Op::Dot | Op::Path | Op::LogAnd | Op::LogOr)) => {
|
Ps::Op(op @ (Op::Do | Op::Tuple | Op::Dot | Op::Path | Op::LogAnd | Op::LogOr)) => {
|
||||||
Expr::Op(op, p.list_bare(vec![head.anno(span)], prec.next(), kind)?)
|
Expr::Op(
|
||||||
|
op,
|
||||||
|
p.consume()
|
||||||
|
.list_bare(vec![head.anno(span)], prec.next(), kind)?,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Ps::Op(op @ Op::Try) => Expr::Op(op, vec![head.anno(span)]),
|
Ps::Op(op @ Op::Try) => {
|
||||||
Ps::Op(op) => Expr::Op(op, vec![head.anno(span), p.parse(prec.next())?]),
|
p.consume();
|
||||||
|
Expr::Op(op, vec![head.anno(span)])
|
||||||
|
}
|
||||||
|
Ps::Op(op) => Expr::Op(op, vec![head.anno(span), p.consume().parse(prec.next())?]),
|
||||||
_ => unimplemented!("infix {op:?}"),
|
_ => unimplemented!("infix {op:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -655,7 +692,6 @@ impl<'t, P: Parse<'t> + Annotation> Parse<'t> for Anno<P> {
|
|||||||
where Self: Sized {
|
where Self: Sized {
|
||||||
let start = p.span();
|
let start = p.span();
|
||||||
let anno = Anno(p.parse(level)?, start.merge(p.span()));
|
let anno = Anno(p.parse(level)?, start.merge(p.span()));
|
||||||
println!("{}:\t{anno}", anno.1);
|
|
||||||
Ok(anno)
|
Ok(anno)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user