parser!
This commit is contained in:
parent
e21983f92d
commit
a06927e356
6 changed files with 99 additions and 97 deletions
9
Cargo.lock
generated
9
Cargo.lock
generated
|
@ -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",
|
||||
]
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ lalrpop-util = "0.19.5"
|
|||
regex = "1"
|
||||
itertools = "0.10"
|
||||
anyhow = "1.0"
|
||||
maplit = "*"
|
||||
|
||||
[build-dependencies]
|
||||
lalrpop = "0.19.5"
|
||||
|
|
|
@ -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<Expr>),
|
||||
MissingNode,
|
||||
}
|
||||
|
||||
trait OptionAstErrorExt<T> {
|
||||
fn or_missing(self) -> Result<T, AstError>;
|
||||
}
|
||||
impl<T> OptionAstErrorExt<T> for Option<T> {
|
||||
fn or_missing(self) -> Result<T, AstError> {
|
||||
self.ok_or(AstError::MissingNode)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WrongExprType> for AstError {
|
||||
fn from(_: WrongExprType) -> Self {
|
||||
AstError::WrongExprType
|
||||
}
|
||||
}
|
||||
|
||||
pub trait FromExpr: Sized {
|
||||
fn from_expr(e: Expr) -> Result<Self, AstError>;
|
||||
fn from_sp(e: Sp<Expr>) -> Result<Self, AstError> {
|
||||
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<Self, AstError> {
|
||||
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<T> {
|
||||
def_type: DefType,
|
||||
name: String,
|
||||
attrs: HashMap<AttrName, Sp<Expr>>,
|
||||
attrs: HashMap<AttrName, Expr>,
|
||||
children: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T: FromExpr> FromExpr for Definitional<T> {
|
||||
fn from_expr(e: Expr) -> Result<Self, AstError> {
|
||||
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::<Result<Vec<_>, AstError>>()?;
|
||||
let children = iter
|
||||
.map(T::from_expr)
|
||||
.collect::<Result<Vec<_>, AstError>>()?;
|
||||
Ok(Definitional {
|
||||
def_type,
|
||||
name,
|
||||
|
@ -93,16 +70,16 @@ impl<T: FromExpr> FromExpr for Definitional<T> {
|
|||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct Element<T> {
|
||||
name: String,
|
||||
attrs: HashMap<AttrName, Sp<Expr>>,
|
||||
attrs: HashMap<AttrName, Expr>,
|
||||
children: Vec<T>,
|
||||
}
|
||||
|
||||
impl FromExpr for Element<Sp<Expr>> {
|
||||
impl FromExpr for Element<Expr> {
|
||||
fn from_expr(e: Expr) -> Result<Self, AstError> {
|
||||
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<Sp<Expr>> {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_key_values<I: Iterator<Item = Sp<Expr>>>(
|
||||
fn parse_key_values<I: Iterator<Item = Expr>>(
|
||||
iter: &mut itertools::PutBack<I>,
|
||||
) -> HashMap<String, Sp<Expr>> {
|
||||
) -> HashMap<String, Expr> {
|
||||
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::<Sp<Expr>>::from_expr(
|
||||
parser
|
||||
.parse("(box foo :bar 12 :baz \"hi\" foo (bar))")
|
||||
.unwrap()
|
||||
Element::<Expr>::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())]
|
||||
),
|
||||
],
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
18
src/error.rs
Normal file
18
src/error.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
use crate::Expr;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum AstError {
|
||||
UnexpectedNode,
|
||||
InvalidDefinition,
|
||||
WrongExprType(Expr),
|
||||
MissingNode,
|
||||
}
|
||||
|
||||
pub trait OptionAstErrorExt<T> {
|
||||
fn or_missing(self) -> Result<T, AstError>;
|
||||
}
|
||||
impl<T> OptionAstErrorExt<T> for Option<T> {
|
||||
fn or_missing(self) -> Result<T, AstError> {
|
||||
self.ok_or(AstError::MissingNode)
|
||||
}
|
||||
}
|
58
src/main.rs
58
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<T>(pub usize, pub T, pub usize);
|
||||
pub struct Span(pub usize, pub usize);
|
||||
|
||||
impl<T: std::fmt::Display> std::fmt::Display for Sp<T> {
|
||||
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<Expr>);
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum Expr {
|
||||
List(Vec<Sp<Expr>>),
|
||||
Table(Vec<(Sp<Expr>, Sp<Expr>)>),
|
||||
Keyword(String),
|
||||
Symbol(String),
|
||||
Str(String),
|
||||
Number(i32),
|
||||
List(Span, Vec<Expr>),
|
||||
Table(Span, Vec<(Expr, Expr)>),
|
||||
Keyword(Span, String),
|
||||
Symbol(Span, String),
|
||||
Str(Span, String),
|
||||
Number(Span, i32),
|
||||
Comment,
|
||||
}
|
||||
|
||||
impl Expr {
|
||||
fn str(self) -> Result<String, WrongExprType> {
|
||||
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<String> = Expr::Str(_, x) => x);
|
||||
as_func!(as_symbol<String> = 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, ""),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,34 +1,29 @@
|
|||
use std::str::FromStr;
|
||||
//use crate::lexer;
|
||||
use crate::Expr;
|
||||
use crate::Sp;
|
||||
use crate::Span;
|
||||
|
||||
grammar;
|
||||
|
||||
|
||||
Span<T>: Sp<T> = {
|
||||
<@L> <T> <@R> => Sp(<>)
|
||||
};
|
||||
|
||||
pub Expr: Expr = {
|
||||
"(" <elems:(<Span<(<Expr>)>>)+> ")" => Expr::List(elems),
|
||||
<l:@L> "(" <elems:(<Expr>)+> ")" <r:@R> => Expr::List(Span(l, r), elems),
|
||||
|
||||
"{" <elems:(<Span<(<Expr>)>> <Span<(<Expr>)>>)*> "}" => Expr::Table(elems),
|
||||
<l:@L> "{" <elems:(<(<Expr>)> <(<Expr>)>)*> "}" <r:@R> => Expr::Table(Span(l, r), elems),
|
||||
|
||||
<x:Keyword> => x,
|
||||
<x:Symbol> => x,
|
||||
<x:StrLit> => Expr::Str(x),
|
||||
<x:Num> => Expr::Number(x),
|
||||
<l:@L> <x:StrLit> <r:@R> => Expr::Str(Span(l, r), x),
|
||||
<l:@L> <x:Num> <r:@R> => Expr::Number(Span(l, r), x),
|
||||
Comment => Expr::Comment,
|
||||
};
|
||||
|
||||
Keyword: Expr = <r":[^\s]+"> => Expr::Keyword(<>.to_string());
|
||||
Symbol: Expr = <r"[a-zA-Z_!\?<>/.*-+][^\s{}\(\)]*"> => Expr::Symbol(<>.to_string());
|
||||
Keyword: Expr = <l:@L> <x:r":[^\s]+"> <r:@R> => Expr::Keyword(Span(l, r), x.to_string());
|
||||
Symbol: Expr = <l:@L> <x:r"[a-zA-Z_!\?<>/.*-+][^\s{}\(\)]*"> <r:@R> => Expr::Symbol(Span(l, r), x.to_string());
|
||||
|
||||
StrLit: String = {
|
||||
r#""(?:[^"\\]|\\.)*""# => {
|
||||
let val = <>;
|
||||
val[1..val.len() - 1].to_owned()
|
||||
<x:r#""(?:[^"\\]|\\.)*""#> => {
|
||||
x[1..x.len() - 1].to_owned()
|
||||
},
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue