From 86c02e86bbf5ac34780c39105775075665bc2bb6 Mon Sep 17 00:00:00 2001 From: elkowar <5300871+elkowar@users.noreply.github.com> Date: Fri, 2 Jul 2021 22:00:03 +0200 Subject: [PATCH] cleanup --- src/config.rs | 74 +++++++------------ src/error.rs | 4 +- src/expr.rs | 173 +++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 104 +-------------------------- src/parser.lalrpop | 3 +- 5 files changed, 203 insertions(+), 155 deletions(-) create mode 100644 src/expr.rs diff --git a/src/config.rs b/src/config.rs index 2efca23..3b9b104 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,9 +1,14 @@ -use std::{collections::HashMap, iter::FromIterator}; - -use super::*; -use crate::error::*; +use crate::{ + error::*, + expr::{Expr, ExprIterator, ExprType, Span}, + parser, spanned, +}; use itertools::Itertools; -use std::collections::LinkedList; +use std::{ + collections::{HashMap, LinkedList}, + iter::FromIterator, + str::FromStr, +}; type VarName = String; type AttrValue = String; @@ -24,15 +29,13 @@ pub enum DefType { Widget, } -impl FromExpr for DefType { - fn from_expr(e: Expr) -> AstResult { - if let Expr::Symbol(span, sym) = e { - match sym.as_str() { - "defwidget" => Ok(DefType::Widget), - _ => Err(AstError::InvalidDefinition(Some(span))), - } - } else { - Err(AstError::WrongExprType(Some(e.span()), ExprType::Symbol, e)) +impl FromStr for DefType { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "defwidget" => Ok(DefType::Widget), + _ => Err(()), } } } @@ -51,13 +54,13 @@ impl FromExpr for Definitional { let span = e.span(); spanned!(e.span(), { let list = e.as_list()?; - let mut iter = itertools::put_back(list.into_iter()); + let mut iter = ExprIterator::new(list.into_iter()); + let (span, def_type) = iter.next_symbol()?; + let def_type = def_type.parse().map_err(|_| AstError::InvalidDefinition(Some(span)))?; - let def_type = DefType::from_expr(iter.next().or_missing(ExprType::Symbol)?)?; - let name = iter.next().or_missing(ExprType::Symbol)?.as_symbol()?; - let attrs = parse_key_values(&mut iter)?; + let (_, name) = iter.next_symbol()?; + let attrs = iter.key_values()?; let children = iter.map(|x| C::from_expr(x)).collect::>>()?; - Definitional { span, def_type, name, attrs, children } }) } @@ -76,40 +79,15 @@ impl FromExpr for Element { let span = e.span(); spanned!(e.span(), { let list = e.as_list()?; - let mut iter = itertools::put_back(list.into_iter()); - - let name = iter.next().or_missing(ExprType::Str)?.as_symbol()?; - let attrs = parse_key_values(&mut iter)?; - let children = iter.map(C::from_expr).collect::>>()?; - + let mut iter = ExprIterator::new(list.into_iter()); + let (_, name) = iter.next_symbol()?; + let attrs = iter.key_values()?; + let children = iter.map(|x| C::from_expr(x)).collect::>>()?; Element { span, name, attrs, children } }) } } -/// Parse consecutive `:keyword value` pairs from an expression iterator into a HashMap. Transforms the keys using the FromExpr trait. -fn parse_key_values>(iter: &mut itertools::PutBack) -> AstResult> { - let mut data = HashMap::new(); - loop { - match iter.next() { - Some(Expr::Keyword(span, kw)) => match iter.next() { - Some(value) => { - data.insert(kw, T::from_expr(value)?); - } - None => { - iter.put_back(Expr::Keyword(span, kw)); - return Ok(data); - } - }, - Some(expr) => { - iter.put_back(expr); - return Ok(data); - } - None => return Ok(data), - } - } -} - #[cfg(test)] mod test { diff --git a/src/error.rs b/src/error.rs index e472763..82a722c 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,4 @@ -use crate::{Expr, ExprType, Span}; +use crate::expr::{Expr, ExprType, Span}; use thiserror::Error; pub type AstResult = Result; @@ -10,7 +10,7 @@ pub enum AstError { #[error("Expected a {1}, but got nothing")] MissingNode(Option, ExprType), #[error("Wrong type of expression: Expected {1} but got {2}")] - WrongExprType(Option, ExprType, Expr), + WrongExprType(Option, ExprType, ExprType), } pub fn spanned(span: Span, err: impl Into) -> AstError { diff --git a/src/expr.rs b/src/expr.rs new file mode 100644 index 0000000..099b5e2 --- /dev/null +++ b/src/expr.rs @@ -0,0 +1,173 @@ +use itertools::Itertools; +use std::collections::HashMap; + +use crate::{config::FromExpr, error::*}; +use std::fmt::Display; + +#[derive(Eq, PartialEq, Clone, Copy)] +pub struct Span(pub usize, pub usize); + +impl std::fmt::Display for Span { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}..{}", self.0, self.1) + } +} + +impl std::fmt::Debug for Span { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self) + } +} + +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum ExprType { + List, + Table, + Keyword, + Symbol, + Str, + Number, + Comment, +} + +impl Display for ExprType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum Expr { + List(Span, Vec), + Table(Span, Vec<(Expr, Expr)>), + Keyword(Span, String), + Symbol(Span, String), + Str(Span, String), + Number(Span, i32), + Comment(Span), +} + +macro_rules! as_func { + ($exprtype:expr, $name:ident < $t:ty > = $p:pat => $value:expr) => { + pub fn $name(self) -> Result<$t, AstError> { + match self { + $p => Ok($value), + x => Err(AstError::WrongExprType(Some(x.span()), $exprtype, x.expr_type())), + } + } + }; +} + +impl Expr { + as_func!(ExprType::Str, as_str = Expr::Str(_, x) => x); + + as_func!(ExprType::Symbol, as_symbol = Expr::Symbol(_, x) => x); + + as_func!(ExprType::List, as_list> = Expr::List(_, x) => x); + + pub fn expr_type(&self) -> ExprType { + match self { + Expr::List(..) => ExprType::List, + Expr::Table(..) => ExprType::Table, + Expr::Keyword(..) => ExprType::Keyword, + Expr::Symbol(..) => ExprType::Symbol, + Expr::Str(..) => ExprType::Str, + Expr::Number(..) => ExprType::Number, + Expr::Comment(_) => ExprType::Number, + } + } + + pub fn span(&self) -> Span { + match self { + Expr::List(span, _) => *span, + Expr::Table(span, _) => *span, + Expr::Keyword(span, _) => *span, + Expr::Symbol(span, _) => *span, + Expr::Str(span, _) => *span, + Expr::Number(span, _) => *span, + Expr::Comment(span) => *span, + } + } +} + +impl std::fmt::Display for Expr { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use Expr::*; + match self { + Number(_, x) => write!(f, "{}", x), + List(_, x) => write!(f, "({})", x.iter().map(|e| format!("{}", e)).join(" ")), + Table(_, x) => write!(f, "{{{}}}", x.iter().map(|(k, v)| format!("{} {}", k, v)).join(" ")), + Keyword(_, x) => write!(f, "{}", x), + Symbol(_, x) => write!(f, "{}", x), + Str(_, x) => write!(f, "{}", x), + Comment(_) => write!(f, ""), + } + } +} + +pub struct ExprIterator> { + iter: itertools::PutBack, +} + +macro_rules! return_or_put_back { + ($name:ident, $expr_type:expr, $t:ty = $p:pat => $ret:expr) => { + pub fn $name(&mut self) -> AstResult<$t> { + let expr_type = $expr_type; + match self.next() { + Some($p) => Ok($ret), + Some(other) => { + let span = other.span(); + let actual_type = other.expr_type(); + self.iter.put_back(other); + Err(AstError::WrongExprType(Some(span), expr_type, actual_type)) + } + None => Err(AstError::MissingNode(None, expr_type)), + } + } + }; +} + +impl> ExprIterator { + return_or_put_back!(next_symbol, ExprType::Symbol, (Span, String) = Expr::Symbol(span, x) => (span, x)); + + return_or_put_back!(next_string, ExprType::Str, (Span, String) = Expr::Str(span, x) => (span, x)); + + pub fn new(iter: I) -> Self { + ExprIterator { iter: itertools::put_back(iter) } + } + + pub fn key_values(&mut self) -> AstResult> { + parse_key_values(&mut self.iter) + } +} + +impl> Iterator for ExprIterator { + type Item = Expr; + + fn next(&mut self) -> Option { + self.iter.next() + } +} + +/// Parse consecutive `:keyword value` pairs from an expression iterator into a HashMap. Transforms the keys using the FromExpr trait. +fn parse_key_values>(iter: &mut itertools::PutBack) -> AstResult> { + let mut data = HashMap::new(); + loop { + match iter.next() { + Some(Expr::Keyword(span, kw)) => match iter.next() { + Some(value) => { + data.insert(kw, T::from_expr(value)?); + } + None => { + iter.put_back(Expr::Keyword(span, kw)); + return Ok(data); + } + }, + Some(expr) => { + iter.put_back(expr); + return Ok(data); + } + None => return Ok(data), + } + } +} diff --git a/src/main.rs b/src/main.rs index 2d03ab2..1462fac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ mod config; mod error; +mod expr; use error::AstError; use std::{fmt::Display, ops::Deref}; @@ -16,109 +17,6 @@ use lalrpop_util::lalrpop_mod; lalrpop_mod!(pub parser); -#[derive(Eq, PartialEq, Clone, Copy)] -pub struct Span(pub usize, pub usize); - -impl std::fmt::Display for Span { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}..{}", self.0, self.1) - } -} - -impl std::fmt::Debug for Span { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self) - } -} - -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub enum ExprType { - List, - Table, - Keyword, - Symbol, - Str, - Number, - Comment, -} - -impl Display for ExprType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Expr { - List(Span, Vec), - Table(Span, Vec<(Expr, Expr)>), - Keyword(Span, String), - Symbol(Span, String), - Str(Span, String), - Number(Span, i32), - Comment(Span), -} - -impl From for ExprType { - fn from(x: Expr) -> Self { - match x { - Expr::List(..) => ExprType::List, - Expr::Table(..) => ExprType::Table, - Expr::Keyword(..) => ExprType::Keyword, - Expr::Symbol(..) => ExprType::Symbol, - Expr::Str(..) => ExprType::Str, - Expr::Number(..) => ExprType::Number, - Expr::Comment(_) => ExprType::Number, - } - } -} - -macro_rules! as_func { - ($exprtype:expr, $name:ident < $t:ty > = $p:pat => $value:expr) => { - fn $name(self) -> Result<$t, AstError> { - match self { - $p => Ok($value), - x => Err(AstError::WrongExprType(Some(x.span()), $exprtype, x)), - } - } - }; -} - -impl Expr { - as_func!(ExprType::Str, as_str = Expr::Str(_, x) => x); - - as_func!(ExprType::Symbol, as_symbol = Expr::Symbol(_, x) => x); - - as_func!(ExprType::List, as_list> = Expr::List(_, x) => x); - - pub fn span(&self) -> Span { - match self { - Expr::List(span, _) => *span, - Expr::Table(span, _) => *span, - Expr::Keyword(span, _) => *span, - Expr::Symbol(span, _) => *span, - Expr::Str(span, _) => *span, - Expr::Number(span, _) => *span, - Expr::Comment(span) => *span, - } - } -} - -impl std::fmt::Display for Expr { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - use Expr::*; - match self { - Number(_, x) => write!(f, "{}", x), - List(_, x) => write!(f, "({})", x.iter().map(|e| format!("{}", e)).join(" ")), - Table(_, x) => write!(f, "{{{}}}", x.iter().map(|(k, v)| format!("{} {}", k, v)).join(" ")), - Keyword(_, x) => write!(f, "{}", x), - Symbol(_, x) => write!(f, "{}", x), - Str(_, x) => write!(f, "{}", x), - Comment(_) => write!(f, ""), - } - } -} - fn main() {} #[allow(unused_macros)] diff --git a/src/parser.lalrpop b/src/parser.lalrpop index 99e511c..c306776 100644 --- a/src/parser.lalrpop +++ b/src/parser.lalrpop @@ -1,7 +1,6 @@ use std::str::FromStr; //use crate::lexer; -use crate::Expr; -use crate::Span; +use crate::expr::{Expr, Span}; grammar;