From dc10a278cca74d737e4af0fe034a1caa8abb291d Mon Sep 17 00:00:00 2001 From: Greg Brown Date: Wed, 6 Jan 2021 14:56:11 +0000 Subject: Restructure code base to separate compilation phases. --- src/nibble/cst.rs | 294 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 294 insertions(+) create mode 100644 src/nibble/cst.rs (limited to 'src/nibble/cst.rs') diff --git a/src/nibble/cst.rs b/src/nibble/cst.rs new file mode 100644 index 0000000..383eae9 --- /dev/null +++ b/src/nibble/cst.rs @@ -0,0 +1,294 @@ +use proc_macro2::Span; +use syn::{ + bracketed, + ext::IdentExt, + parenthesized, + parse::{Parse, ParseStream}, + punctuated::Punctuated, + token::{Bracket, Comma, Let, Match, Paren}, + LitStr, Token, +}; + +use crate::chomp::ast; + +use super::convert::{Context, Convert}; + +pub type Epsilon = Token![_]; + +pub type Ident = syn::Ident; + +pub type Literal = LitStr; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ArgList { + paren_token: Paren, + args: Punctuated, +} + +impl ArgList { + pub fn span(&self) -> Span { + self.paren_token.span + } + + pub fn len(&self) -> usize { + self.args.len() + } + + pub fn is_empty(&self) -> bool { + self.args.is_empty() + } +} + +impl IntoIterator for ArgList { + type Item = T; + + type IntoIter = as IntoIterator>::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.args.into_iter() + } +} + +impl Parse for ArgList { + fn parse(input: ParseStream<'_>) -> syn::Result { + let args; + let paren_token = parenthesized!(args in input); + let args = args.call(Punctuated::parse_terminated)?; + Ok(Self { paren_token, args }) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Call { + pub name: Ident, + pub args: ArgList, +} + +impl Call { + pub fn span(&self) -> Option { + self.name.span().join(self.args.span()) + } +} + +impl Parse for Call { + fn parse(input: ParseStream<'_>) -> syn::Result { + let name = input.call(Ident::parse_any)?; + let args = input.parse()?; + Ok(Self { name, args }) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Fix { + bracket_token: Bracket, + pub arg: Ident, + paren_token: Paren, + pub expr: Expression, +} + +impl Fix { + pub fn span(&self) -> Option { + self.bracket_token.span.join(self.paren_token.span) + } +} + +impl Parse for Fix { + fn parse(input: ParseStream<'_>) -> syn::Result { + let arg; + let bracket_token = bracketed!(arg in input); + let arg = arg.call(Ident::parse_any)?; + let expr; + let paren_token = parenthesized!(expr in input); + let expr = expr.parse()?; + Ok(Self { + bracket_token, + arg, + paren_token, + expr, + }) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ParenExpression { + paren_token: Paren, + pub expr: Expression, +} + +impl Parse for ParenExpression { + fn parse(input: ParseStream<'_>) -> syn::Result { + let expr; + let paren_token = parenthesized!(expr in input); + let expr = expr.parse()?; + Ok(Self { paren_token, expr }) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum Term { + Epsilon(Epsilon), + Ident(Ident), + Literal(Literal), + Call(Call), + Fix(Fix), + Parens(ParenExpression), +} + +impl Parse for Term { + fn parse(input: ParseStream<'_>) -> syn::Result { + let lookahead = input.lookahead1(); + + if lookahead.peek(Token![_]) { + input.parse().map(Self::Epsilon) + } else if lookahead.peek(LitStr) { + input.parse().map(Self::Literal) + } else if lookahead.peek(Bracket) { + input.parse().map(Self::Fix) + } else if lookahead.peek(Paren) { + input.parse().map(Self::Parens) + } else if lookahead.peek(Ident::peek_any) { + let name = input.call(Ident::parse_any)?; + + if input.peek(Paren) { + input.parse().map(|args| Self::Call(Call { name, args })) + } else { + Ok(Self::Ident(name)) + } + } else { + Err(lookahead.error()) + } + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Cat(pub Punctuated); + +impl Parse for Cat { + fn parse(input: ParseStream<'_>) -> syn::Result { + input.call(Punctuated::parse_separated_nonempty).map(Self) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Alt(pub Punctuated); + +impl Parse for Alt { + fn parse(input: ParseStream<'_>) -> syn::Result { + input.call(Punctuated::parse_separated_nonempty).map(Self) + } +} + +pub type Expression = Alt; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct LetStatement { + let_token: Token![let], + name: Ident, + args: Option>, + eq_token: Token![=], + expr: Expression, + semi_token: Token![;], +} + +impl LetStatement { + pub fn span(&self) -> Option { + self.let_token.span.join(self.semi_token.span) + } +} + +impl Parse for LetStatement { + fn parse(input: ParseStream<'_>) -> syn::Result { + let let_token = input.parse()?; + let name = input.call(Ident::parse_any)?; + let args = if input.peek(Paren) { + Some(input.parse()?) + } else { + None + }; + let eq_token = input.parse()?; + let expr = input.parse()?; + let semi_token = input.parse()?; + + Ok(Self { + let_token, + name, + args, + eq_token, + expr, + semi_token, + }) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct GoalStatement { + match_token: Token![match], + expr: Expression, + semi_token: Token![;], +} + +impl Parse for GoalStatement { + fn parse(input: ParseStream<'_>) -> syn::Result { + let match_token = input.parse()?; + let expr = input.parse()?; + let semi_token = input.parse()?; + + Ok(Self { + match_token, + expr, + semi_token, + }) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct File { + lets: Vec, + goal: GoalStatement, +} + +impl File { + pub fn convert(self) -> Option<(Vec, ast::Expression)> { + 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()), + ); + names.push(stmt.name.clone()); + map.push(ast::Function::new( + stmt.name.clone(), + count, + stmt.expr.convert(&mut context)?, + span, + )); + } + + let mut context = Context::new(&names, Vec::new()); + let goal = self.goal.expr.convert(&mut context)?; + Some((map, goal)) + } +} + +impl Parse for File { + fn parse(input: ParseStream<'_>) -> syn::Result { + let mut lets = Vec::new(); + let mut lookahead = input.lookahead1(); + + while lookahead.peek(Let) { + lets.push(input.parse()?); + lookahead = input.lookahead1(); + } + + let goal = if lookahead.peek(Match) { + input.parse()? + } else { + return Err(lookahead.error()); + }; + + Ok(Self { lets, goal }) + } +} -- cgit v1.2.3