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.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "0.7.18"
|
version = "0.7.18"
|
||||||
|
@ -256,6 +258,12 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "maplit"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.4.0"
|
version = "2.4.0"
|
||||||
|
@ -276,6 +284,7 @@ dependencies = [
|
||||||
"itertools",
|
"itertools",
|
||||||
"lalrpop",
|
"lalrpop",
|
||||||
"lalrpop-util",
|
"lalrpop-util",
|
||||||
|
"maplit",
|
||||||
"regex",
|
"regex",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ lalrpop-util = "0.19.5"
|
||||||
regex = "1"
|
regex = "1"
|
||||||
itertools = "0.10"
|
itertools = "0.10"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
|
maplit = "*"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
lalrpop = "0.19.5"
|
lalrpop = "0.19.5"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::{collections::HashMap, iter::FromIterator};
|
use std::{collections::HashMap, iter::FromIterator};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::error::*;
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use std::collections::LinkedList;
|
use std::collections::LinkedList;
|
||||||
|
@ -9,34 +10,8 @@ type VarName = String;
|
||||||
type AttrValue = String;
|
type AttrValue = String;
|
||||||
type AttrName = 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 {
|
pub trait FromExpr: Sized {
|
||||||
fn from_expr(e: Expr) -> Result<Self, AstError>;
|
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 {
|
impl FromExpr for Expr {
|
||||||
|
@ -51,7 +26,7 @@ pub enum DefType {
|
||||||
|
|
||||||
impl FromExpr for DefType {
|
impl FromExpr for DefType {
|
||||||
fn from_expr(e: Expr) -> Result<Self, AstError> {
|
fn from_expr(e: Expr) -> Result<Self, AstError> {
|
||||||
if let Expr::Symbol(sym) = e {
|
if let Expr::Symbol(_, sym) = e {
|
||||||
match sym.as_str() {
|
match sym.as_str() {
|
||||||
"defwidget" => Ok(DefType::Widget),
|
"defwidget" => Ok(DefType::Widget),
|
||||||
_ => Err(AstError::InvalidDefinition),
|
_ => Err(AstError::InvalidDefinition),
|
||||||
|
@ -65,20 +40,22 @@ impl FromExpr for DefType {
|
||||||
pub struct Definitional<T> {
|
pub struct Definitional<T> {
|
||||||
def_type: DefType,
|
def_type: DefType,
|
||||||
name: String,
|
name: String,
|
||||||
attrs: HashMap<AttrName, Sp<Expr>>,
|
attrs: HashMap<AttrName, Expr>,
|
||||||
children: Vec<T>,
|
children: Vec<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: FromExpr> FromExpr for Definitional<T> {
|
impl<T: FromExpr> FromExpr for Definitional<T> {
|
||||||
fn from_expr(e: Expr) -> Result<Self, AstError> {
|
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 mut iter = itertools::put_back(list.into_iter());
|
||||||
|
|
||||||
let def_type = DefType::from_sp(iter.next().or_missing()?)?;
|
let def_type = DefType::from_expr(iter.next().or_missing()?)?;
|
||||||
let name = iter.next().or_missing()?.1.str()?;
|
let name = iter.next().or_missing()?.as_str()?;
|
||||||
let attrs = parse_key_values(&mut iter);
|
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 {
|
Ok(Definitional {
|
||||||
def_type,
|
def_type,
|
||||||
name,
|
name,
|
||||||
|
@ -93,16 +70,16 @@ impl<T: FromExpr> FromExpr for Definitional<T> {
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub struct Element<T> {
|
pub struct Element<T> {
|
||||||
name: String,
|
name: String,
|
||||||
attrs: HashMap<AttrName, Sp<Expr>>,
|
attrs: HashMap<AttrName, Expr>,
|
||||||
children: Vec<T>,
|
children: Vec<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromExpr for Element<Sp<Expr>> {
|
impl FromExpr for Element<Expr> {
|
||||||
fn from_expr(e: Expr) -> Result<Self, AstError> {
|
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 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);
|
let attrs = parse_key_values(&mut iter);
|
||||||
|
|
||||||
Ok(Element {
|
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>,
|
iter: &mut itertools::PutBack<I>,
|
||||||
) -> HashMap<String, Sp<Expr>> {
|
) -> HashMap<String, Expr> {
|
||||||
let mut data = HashMap::new();
|
let mut data = HashMap::new();
|
||||||
loop {
|
loop {
|
||||||
match iter.next() {
|
match iter.next() {
|
||||||
Some(Sp(l, Expr::Keyword(kw), r)) => match iter.next() {
|
Some(Expr::Keyword(span, kw)) => match iter.next() {
|
||||||
Some(value) => {
|
Some(value) => {
|
||||||
data.insert(kw, value);
|
data.insert(kw, value);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
iter.put_back(Sp(l, Expr::Keyword(kw), r));
|
iter.put_back(Expr::Keyword(span, kw));
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -149,28 +126,24 @@ mod test {
|
||||||
fn test() {
|
fn test() {
|
||||||
let parser = parser::ExprParser::new();
|
let parser = parser::ExprParser::new();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Element::<Sp<Expr>>::from_expr(
|
Element::<Expr>::from_expr(
|
||||||
parser
|
parser.parse("(box :bar 12 :baz \"hi\" foo (bar))").unwrap()
|
||||||
.parse("(box foo :bar 12 :baz \"hi\" foo (bar))")
|
|
||||||
.unwrap()
|
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
Element {
|
Element {
|
||||||
name: "box".to_string(),
|
name: "box".to_string(),
|
||||||
children: vec![
|
attrs: maplit::hashmap! {
|
||||||
Sp(1, Expr::Symbol("foo".to_string()), 2),
|
":bar".to_string() => Expr::Number(Span(10, 12), 12),
|
||||||
Sp(
|
":baz".to_string() => Expr::Str(Span(18, 22), "hi".to_string()),
|
||||||
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
|
|
||||||
},
|
},
|
||||||
|
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)]
|
#![allow(unused)]
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
|
mod error;
|
||||||
|
use error::AstError;
|
||||||
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
@ -14,39 +16,43 @@ use lalrpop_util::lalrpop_mod;
|
||||||
lalrpop_mod!(pub parser);
|
lalrpop_mod!(pub parser);
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
|
#[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 {
|
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)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
List(Vec<Sp<Expr>>),
|
List(Span, Vec<Expr>),
|
||||||
Table(Vec<(Sp<Expr>, Sp<Expr>)>),
|
Table(Span, Vec<(Expr, Expr)>),
|
||||||
Keyword(String),
|
Keyword(Span, String),
|
||||||
Symbol(String),
|
Symbol(Span, String),
|
||||||
Str(String),
|
Str(Span, String),
|
||||||
Number(i32),
|
Number(Span, i32),
|
||||||
Comment,
|
Comment,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expr {
|
macro_rules! as_func {
|
||||||
fn str(self) -> Result<String, WrongExprType> {
|
($name:ident<$t:ty> = $p:pat => $value:expr) => {
|
||||||
use Expr::*;
|
fn $name(self) -> Result<$t, AstError> {
|
||||||
match self {
|
match self {
|
||||||
Str(x) => Ok(x),
|
$p => Ok($value),
|
||||||
x => Err(WrongExprType(x)),
|
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 {
|
fn is_keyword(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Expr::Keyword(_) => true,
|
Expr::Keyword(_, _) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,16 +62,16 @@ impl std::fmt::Display for Expr {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
use Expr::*;
|
use Expr::*;
|
||||||
match self {
|
match self {
|
||||||
Number(x) => write!(f, "{}", x),
|
Number(_, x) => write!(f, "{}", x),
|
||||||
List(x) => write!(f, "({})", x.iter().map(|e| format!("{}", e)).join(" ")),
|
List(_, x) => write!(f, "({})", x.iter().map(|e| format!("{}", e)).join(" ")),
|
||||||
Table(x) => write!(
|
Table(_, x) => write!(
|
||||||
f,
|
f,
|
||||||
"{{{}}}",
|
"{{{}}}",
|
||||||
x.iter().map(|(k, v)| format!("{} {}", k, v)).join(" ")
|
x.iter().map(|(k, v)| format!("{} {}", k, v)).join(" ")
|
||||||
),
|
),
|
||||||
Keyword(x) => write!(f, "{}", x),
|
Keyword(_, x) => write!(f, "{}", x),
|
||||||
Symbol(x) => write!(f, "{}", x),
|
Symbol(_, x) => write!(f, "{}", x),
|
||||||
Str(x) => write!(f, "{}", x),
|
Str(_, x) => write!(f, "{}", x),
|
||||||
Comment => write!(f, ""),
|
Comment => write!(f, ""),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,34 +1,29 @@
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
//use crate::lexer;
|
//use crate::lexer;
|
||||||
use crate::Expr;
|
use crate::Expr;
|
||||||
use crate::Sp;
|
use crate::Span;
|
||||||
|
|
||||||
grammar;
|
grammar;
|
||||||
|
|
||||||
|
|
||||||
Span<T>: Sp<T> = {
|
|
||||||
<@L> <T> <@R> => Sp(<>)
|
|
||||||
};
|
|
||||||
|
|
||||||
pub Expr: Expr = {
|
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:Keyword> => x,
|
||||||
<x:Symbol> => x,
|
<x:Symbol> => x,
|
||||||
<x:StrLit> => Expr::Str(x),
|
<l:@L> <x:StrLit> <r:@R> => Expr::Str(Span(l, r), x),
|
||||||
<x:Num> => Expr::Number(x),
|
<l:@L> <x:Num> <r:@R> => Expr::Number(Span(l, r), x),
|
||||||
Comment => Expr::Comment,
|
Comment => Expr::Comment,
|
||||||
};
|
};
|
||||||
|
|
||||||
Keyword: Expr = <r":[^\s]+"> => Expr::Keyword(<>.to_string());
|
Keyword: Expr = <l:@L> <x:r":[^\s]+"> <r:@R> => Expr::Keyword(Span(l, r), x.to_string());
|
||||||
Symbol: Expr = <r"[a-zA-Z_!\?<>/.*-+][^\s{}\(\)]*"> => Expr::Symbol(<>.to_string());
|
Symbol: Expr = <l:@L> <x:r"[a-zA-Z_!\?<>/.*-+][^\s{}\(\)]*"> <r:@R> => Expr::Symbol(Span(l, r), x.to_string());
|
||||||
|
|
||||||
StrLit: String = {
|
StrLit: String = {
|
||||||
r#""(?:[^"\\]|\\.)*""# => {
|
<x:r#""(?:[^"\\]|\\.)*""#> => {
|
||||||
let val = <>;
|
x[1..x.len() - 1].to_owned()
|
||||||
val[1..val.len() - 1].to_owned()
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue