summaryrefslogtreecommitdiff
path: root/src/nibble/cst.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/nibble/cst.rs')
-rw-r--r--src/nibble/cst.rs111
1 files changed, 95 insertions, 16 deletions
diff --git a/src/nibble/cst.rs b/src/nibble/cst.rs
index 2b52678..f6fa51b 100644
--- a/src/nibble/cst.rs
+++ b/src/nibble/cst.rs
@@ -4,14 +4,14 @@ use syn::{
ext::IdentExt,
parenthesized,
parse::{Parse, ParseStream},
- punctuated::Punctuated,
+ punctuated::{Pair, Punctuated},
token::{Bracket, Comma, Let, Match, Paren},
LitStr, Token,
};
-use crate::chomp::ast;
+use crate::chomp::{Name, ast};
-use super::convert::{Context, Convert};
+use super::convert::{Context, Convert, ConvertError};
pub type Epsilon = Token![_];
@@ -134,6 +134,19 @@ pub enum Term {
Parens(ParenExpression),
}
+impl Term {
+ pub fn span(&self) -> Option<Span> {
+ match self {
+ Self::Epsilon(e) => Some(e.span),
+ Self::Ident(i) => Some(i.span()),
+ Self::Literal(l) => Some(l.span()),
+ Self::Call(c) => c.span(),
+ Self::Fix(f) => f.span(),
+ Self::Parens(p) => Some(p.paren_token.span),
+ }
+ }
+}
+
impl Parse for Term {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let lookahead = input.lookahead1();
@@ -169,8 +182,74 @@ impl Parse for Cat {
}
}
+impl Cat {
+ pub fn span(&self) -> Option<Span> {
+ let mut iter = self.0.pairs();
+ let span = match iter.next()? {
+ Pair::Punctuated(t, p) => t.span().and_then(|s| s.join(p.span)),
+ Pair::End(t) => t.span(),
+ }?;
+
+ iter.try_fold(span, |span, pair| match pair {
+ Pair::Punctuated(t, p) => t
+ .span()
+ .and_then(|s| span.join(s))
+ .and_then(|s| s.join(p.span)),
+ Pair::End(t) => t.span().and_then(|s| span.join(s)),
+ })
+ }
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct Label {
+ colon_tok: Token![:],
+ pub label: Ident,
+}
+
+impl Label {
+ pub fn span(&self) -> Option<Span> {
+ self.colon_tok.span.join(self.label.span())
+ }
+}
+
+impl Parse for Label {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let colon_tok = input.parse()?;
+ let label = input.call(Ident::parse_any)?;
+ Ok(Self { colon_tok, label })
+ }
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct Labelled {
+ pub cat: Cat,
+ pub label: Option<Label>,
+}
+
+impl Labelled {
+ pub fn span(&self) -> Option<Span> {
+ self.cat.span().and_then(|s| {
+ self.label
+ .as_ref()
+ .and_then(|l| l.span().and_then(|t| s.join(t)))
+ })
+ }
+}
+
+impl Parse for Labelled {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let cat = input.parse()?;
+ let label = if input.peek(Token![:]) {
+ Some(input.parse()?)
+ } else {
+ None
+ };
+ Ok(Self { cat, label })
+ }
+}
+
#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct Alt(pub Punctuated<Cat, Token![|]>);
+pub struct Alt(pub Punctuated<Labelled, Token![|]>);
impl Parse for Alt {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
@@ -248,28 +327,28 @@ pub struct File {
}
impl File {
- pub fn convert(self) -> Option<(Vec<ast::Function>, ast::Expression)> {
+ pub fn convert(self) -> Result<(Vec<ast::Function>, ast::NamedExpression), ConvertError> {
let mut names = Vec::new();
let mut map = Vec::new();
for stmt in self.lets {
- let count = stmt.args.as_ref().map(ArgList::len).unwrap_or_default();
let span = stmt.span();
- let mut context = Context::new(
- &names,
- stmt.args.into_iter().flat_map(|args| args.into_iter()),
- );
+ let params = stmt.args.into_iter().flat_map(|args| args.into_iter());
+ let mut context = Context::new(&names, params.clone());
names.push(stmt.name.clone());
- map.push(ast::Function::new(
- stmt.name.into(),
- count,
- stmt.expr.convert(&mut context)?,
+ let mut expr = stmt.expr.convert(&mut context)?;
+ let name: Name = stmt.name.into();
+ expr.name = Some(name.clone());
+ map.push(ast::Function {
+ name,
+ params: params.map(|name| Some(name.into())).collect(),
+ expr,
span,
- ));
+ });
}
let mut context = Context::new(&names, Vec::new());
let goal = self.goal.expr.convert(&mut context)?;
- Some((map, goal))
+ Ok((map, goal))
}
}