From a06927e356e94145d2c3b9be9d62a2ba765a9fae Mon Sep 17 00:00:00 2001 From: elkowar <5300871+elkowar@users.noreply.github.com> Date: Thu, 1 Jul 2021 20:38:23 +0200 Subject: [PATCH] parser! --- Cargo.lock | 9 +++++ Cargo.toml | 1 + src/config.rs | 87 ++++++++++++++++------------------------------ src/error.rs | 18 ++++++++++ src/main.rs | 58 +++++++++++++++++-------------- src/parser.lalrpop | 23 +++++------- 6 files changed, 99 insertions(+), 97 deletions(-) create mode 100644 src/error.rs diff --git a/Cargo.lock b/Cargo.lock index 5d6f7ea..3cde16d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "aho-corasick" version = "0.7.18" @@ -256,6 +258,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + [[package]] name = "memchr" version = "2.4.0" @@ -276,6 +284,7 @@ dependencies = [ "itertools", "lalrpop", "lalrpop-util", + "maplit", "regex", ] diff --git a/Cargo.toml b/Cargo.toml index 8824444..11018a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ lalrpop-util = "0.19.5" regex = "1" itertools = "0.10" anyhow = "1.0" +maplit = "*" [build-dependencies] lalrpop = "0.19.5" diff --git a/src/config.rs b/src/config.rs index 51c8a27..cb3127b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,7 @@ use std::{collections::HashMap, iter::FromIterator}; use super::*; +use crate::error::*; use anyhow::*; use itertools::Itertools; use std::collections::LinkedList; @@ -9,34 +10,8 @@ type VarName = String; type AttrValue = String; type AttrName = String; -#[derive(Debug, PartialEq, Eq)] -pub enum AstError { - UnexpectedNode, - InvalidDefinition, - WrongExprType(Sp), - MissingNode, -} - -trait OptionAstErrorExt { - fn or_missing(self) -> Result; -} -impl OptionAstErrorExt for Option { - fn or_missing(self) -> Result { - self.ok_or(AstError::MissingNode) - } -} - -impl From for AstError { - fn from(_: WrongExprType) -> Self { - AstError::WrongExprType - } -} - pub trait FromExpr: Sized { fn from_expr(e: Expr) -> Result; - fn from_sp(e: Sp) -> Result { - Self::from_expr(e.1) - } } impl FromExpr for Expr { @@ -51,7 +26,7 @@ pub enum DefType { impl FromExpr for DefType { fn from_expr(e: Expr) -> Result { - if let Expr::Symbol(sym) = e { + if let Expr::Symbol(_, sym) = e { match sym.as_str() { "defwidget" => Ok(DefType::Widget), _ => Err(AstError::InvalidDefinition), @@ -65,20 +40,22 @@ impl FromExpr for DefType { pub struct Definitional { def_type: DefType, name: String, - attrs: HashMap>, + attrs: HashMap, children: Vec, } impl FromExpr for Definitional { fn from_expr(e: Expr) -> Result { - if let Expr::List(list) = e { + if let Expr::List(span, list) = e { let mut iter = itertools::put_back(list.into_iter()); - let def_type = DefType::from_sp(iter.next().or_missing()?)?; - let name = iter.next().or_missing()?.1.str()?; + let def_type = DefType::from_expr(iter.next().or_missing()?)?; + let name = iter.next().or_missing()?.as_str()?; let attrs = parse_key_values(&mut iter); - let children = iter.map(T::from_sp).collect::, AstError>>()?; + let children = iter + .map(T::from_expr) + .collect::, AstError>>()?; Ok(Definitional { def_type, name, @@ -93,16 +70,16 @@ impl FromExpr for Definitional { #[derive(Debug, Eq, PartialEq)] pub struct Element { name: String, - attrs: HashMap>, + attrs: HashMap, children: Vec, } -impl FromExpr for Element> { +impl FromExpr for Element { fn from_expr(e: Expr) -> Result { - if let Expr::List(list) = e { + if let Expr::List(span, list) = e { let mut iter = itertools::put_back(list.into_iter()); - let name = iter.next().or_missing()?.1.str()?; + let name = iter.next().or_missing()?.as_symbol()?; let attrs = parse_key_values(&mut iter); Ok(Element { @@ -116,18 +93,18 @@ impl FromExpr for Element> { } } -fn parse_key_values>>( +fn parse_key_values>( iter: &mut itertools::PutBack, -) -> HashMap> { +) -> HashMap { let mut data = HashMap::new(); loop { match iter.next() { - Some(Sp(l, Expr::Keyword(kw), r)) => match iter.next() { + Some(Expr::Keyword(span, kw)) => match iter.next() { Some(value) => { data.insert(kw, value); } None => { - iter.put_back(Sp(l, Expr::Keyword(kw), r)); + iter.put_back(Expr::Keyword(span, kw)); return data; } }, @@ -149,28 +126,24 @@ mod test { fn test() { let parser = parser::ExprParser::new(); assert_eq!( - Element::>::from_expr( - parser - .parse("(box foo :bar 12 :baz \"hi\" foo (bar))") - .unwrap() + Element::::from_expr( + parser.parse("(box :bar 12 :baz \"hi\" foo (bar))").unwrap() ) .unwrap(), Element { name: "box".to_string(), - children: vec![ - Sp(1, Expr::Symbol("foo".to_string()), 2), - Sp( - 2, - Expr::List(vec![Sp(2, Expr::Symbol("bar".to_string()), 3)]), - 3 - ) - ], - attrs: { - let mut data = HashMap::new(); - data.insert("foo".to_string(), Sp(2, Expr::Number(12), 3)); - data.insert("bar".to_string(), Sp(2, Expr::Str("hi".to_string()), 3)); - data + attrs: maplit::hashmap! { + ":bar".to_string() => Expr::Number(Span(10, 12), 12), + ":baz".to_string() => Expr::Str(Span(18, 22), "hi".to_string()), + }, + children: vec![ + Expr::Symbol(Span(23, 26), "foo".to_string()), + Expr::List( + Span(27, 32), + vec![Expr::Symbol(Span(28, 31), "bar".to_string())] + ), + ], } ); } diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..23948a0 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,18 @@ +use crate::Expr; + +#[derive(Debug, PartialEq, Eq)] +pub enum AstError { + UnexpectedNode, + InvalidDefinition, + WrongExprType(Expr), + MissingNode, +} + +pub trait OptionAstErrorExt { + fn or_missing(self) -> Result; +} +impl OptionAstErrorExt for Option { + fn or_missing(self) -> Result { + self.ok_or(AstError::MissingNode) + } +} diff --git a/src/main.rs b/src/main.rs index 400c56f..7bc52ee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,8 @@ #![allow(unused)] mod config; +mod error; +use error::AstError; use std::ops::Deref; @@ -14,39 +16,43 @@ use lalrpop_util::lalrpop_mod; lalrpop_mod!(pub parser); #[derive(Debug, Eq, PartialEq, Clone, Copy)] -pub struct Sp(pub usize, pub T, pub usize); +pub struct Span(pub usize, pub usize); -impl std::fmt::Display for Sp { +impl std::fmt::Display for Span { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "<{}- {} -{}>", self.0, self.1, self.2) + write!(f, "<{}..{}>", self.0, self.1) } } -#[derive(Debug, Clone)] -pub struct WrongExprType(Sp); - #[derive(Debug, PartialEq, Eq, Clone)] pub enum Expr { - List(Vec>), - Table(Vec<(Sp, Sp)>), - Keyword(String), - Symbol(String), - Str(String), - Number(i32), + List(Span, Vec), + Table(Span, Vec<(Expr, Expr)>), + Keyword(Span, String), + Symbol(Span, String), + Str(Span, String), + Number(Span, i32), Comment, } -impl Expr { - fn str(self) -> Result { - use Expr::*; - match self { - Str(x) => Ok(x), - x => Err(WrongExprType(x)), +macro_rules! as_func { + ($name:ident<$t:ty> = $p:pat => $value:expr) => { + fn $name(self) -> Result<$t, AstError> { + match self { + $p => Ok($value), + x => Err(AstError::WrongExprType(x)), + } } - } + }; +} + +impl Expr { + as_func!(as_str = Expr::Str(_, x) => x); + as_func!(as_symbol = Expr::Symbol(_, x) => x); + fn is_keyword(&self) -> bool { match self { - Expr::Keyword(_) => true, + Expr::Keyword(_, _) => true, _ => false, } } @@ -56,16 +62,16 @@ 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!( + 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), + Keyword(_, x) => write!(f, "{}", x), + Symbol(_, x) => write!(f, "{}", x), + Str(_, x) => write!(f, "{}", x), Comment => write!(f, ""), } } diff --git a/src/parser.lalrpop b/src/parser.lalrpop index 48405fe..050b13b 100644 --- a/src/parser.lalrpop +++ b/src/parser.lalrpop @@ -1,34 +1,29 @@ use std::str::FromStr; //use crate::lexer; use crate::Expr; -use crate::Sp; +use crate::Span; grammar; -Span: Sp = { - <@L> <@R> => Sp(<>) -}; - pub Expr: Expr = { - "(" )>>)+> ")" => Expr::List(elems), + "(" )+> ")" => Expr::List(Span(l, r), elems), - "{" )>> )>>)*> "}" => Expr::Table(elems), + "{" )> <()>)*> "}" => Expr::Table(Span(l, r), elems), => x, => x, - => Expr::Str(x), - => Expr::Number(x), + => Expr::Str(Span(l, r), x), + => Expr::Number(Span(l, r), x), Comment => Expr::Comment, }; -Keyword: Expr = => Expr::Keyword(<>.to_string()); -Symbol: Expr = /.*-+][^\s{}\(\)]*"> => Expr::Symbol(<>.to_string()); +Keyword: Expr = => Expr::Keyword(Span(l, r), x.to_string()); +Symbol: Expr = /.*-+][^\s{}\(\)]*"> => Expr::Symbol(Span(l, r), x.to_string()); StrLit: String = { - r#""(?:[^"\\]|\\.)*""# => { - let val = <>; - val[1..val.len() - 1].to_owned() + => { + x[1..x.len() - 1].to_owned() }, }