Fix parser for index and call exprs, remove old test that didn't work, add visitor pattern

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-09-03 18:32:22 -07:00
parent 2fd340a688
commit f8819279f8
6 changed files with 325 additions and 65 deletions

View File

@@ -1,17 +1,125 @@
use crate::syn::visit::*;
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum Stmt { pub enum Stmt {
Expr(Expr), Expr(Expr),
Assign, Assign(AssignStmt),
} }
//
// impl Accept for Stmt
//
impl<V: Visit> Accept<V> for Stmt {
fn accept(&self, visitor: &mut V) -> V::Out {
visitor.visit_stmt(self)
}
}
//
// impl DefaultAccept for Stmt
//
impl<V: Visit> DefaultAccept<V> for Stmt {
fn default_accept(&self, visitor: &mut V) -> V::Out {
match self {
Stmt::Expr(e) => e.accept(visitor),
Stmt::Assign(a) => a.accept(visitor),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AssignStmt {
pub lhs: LhsExpr,
pub rhs: Expr,
}
//
// impl Accept for AssignStmt
//
impl<V: Visit> Accept<V> for AssignStmt {
fn accept(&self, visitor: &mut V) -> V::Out {
visitor.visit_assign_stmt(self)
}
}
//
// impl DefaultAccept for AssignStmt
//
impl<V: Visit<Out=()>> DefaultAccept<V> for AssignStmt {
fn default_accept(&self, visitor: &mut V) -> V::Out {
self.lhs.accept(visitor);
self.rhs.accept(visitor);
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum LhsExpr {
SetAttr(AccessExpr),
Local(String),
}
//
// impl Accept for LhsExpr
//
impl<V: Visit> Accept<V> for LhsExpr {
fn accept(&self, visitor: &mut V) -> V::Out {
visitor.visit_lhs_expr(self)
}
}
//
// impl DefaultAccept for LhsExpr
//
impl<V: Visit<Out=()>> DefaultAccept<V> for LhsExpr {
fn default_accept(&self, visitor: &mut V) -> V::Out {
match self {
LhsExpr::SetAttr(a) => a.accept(visitor),
LhsExpr::Local(_) => {},
}
}
}
//
// struct Expr
//
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum Expr { pub enum Expr {
Atom(Atom), Atom(Atom),
Bin(Box<BinExpr>), Bin(Box<BinExpr>),
Un(Box<UnExpr>), Un(Box<UnExpr>),
Access(Box<AccessExpr>), Access(Box<AccessExpr>),
Call(Box<CallExpr>),
Index(Box<IndexExpr>),
} }
//
// impl Accept for Expr
//
impl<V: Visit> Accept<V> for Expr {
fn accept(&self, visitor: &mut V) -> V::Out {
visitor.visit_expr(self)
}
}
//
// impl DefaultAccept for Expr
//
impl<V: Visit> DefaultAccept<V> for Expr {
fn default_accept(&self, visitor: &mut V) -> V::Out {
match self {
Expr::Atom(a) => a.accept(visitor),
Expr::Bin(b) => b.accept(visitor),
Expr::Un(u) => u.accept(visitor),
Expr::Access(a) => a.accept(visitor),
Expr::Call(c) => c.accept(visitor),
Expr::Index(i) => i.accept(visitor),
}
}
}
//
// impl From<T> for Expr
//
impl From<Atom> for Expr { impl From<Atom> for Expr {
fn from(other: Atom) -> Self { fn from(other: Atom) -> Self {
Expr::Atom(other) Expr::Atom(other)
@@ -36,6 +144,18 @@ impl From<AccessExpr> for Expr {
} }
} }
impl From<CallExpr> for Expr {
fn from(other: CallExpr) -> Self {
Expr::Call(other.into())
}
}
impl From<IndexExpr> for Expr {
fn from(other: IndexExpr) -> Self {
Expr::Index(other.into())
}
}
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum BinOp { pub enum BinOp {
Plus, Plus,
@@ -52,6 +172,9 @@ pub enum BinOp {
Or, Or,
} }
//
// struct BinExpr
//
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct BinExpr { pub struct BinExpr {
pub lhs: Expr, pub lhs: Expr,
@@ -65,12 +188,34 @@ impl BinExpr {
} }
} }
//
// impl Accept for BinExpr
//
impl<V: Visit> Accept<V> for BinExpr {
fn accept(&self, visitor: &mut V) -> V::Out {
visitor.visit_bin_expr(self)
}
}
//
// impl DefaultAccept for BinExpr
//
impl<V: Visit<Out=()>> DefaultAccept<V> for BinExpr {
fn default_accept(&self, visitor: &mut V) -> V::Out {
visitor.visit_expr(&self.lhs);
visitor.visit_expr(&self.rhs);
}
}
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum UnOp { pub enum UnOp {
Plus, Plus,
Minus, Minus,
} }
//
// struct UnExpr
//
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnExpr { pub struct UnExpr {
pub op: UnOp, pub op: UnOp,
@@ -83,28 +228,124 @@ impl UnExpr {
} }
} }
//
// impl Accept for UnExpr
//
impl<V: Visit> Accept<V> for UnExpr {
fn accept(&self, visitor: &mut V) -> V::Out {
visitor.visit_un_expr(self)
}
}
//
// impl DefaultAccept for UnExpr
//
impl<V: Visit> DefaultAccept<V> for UnExpr {
fn default_accept(&self, visitor: &mut V) -> V::Out {
visitor.visit_expr(&self.expr)
}
}
//
// struct CallExpr
//
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CallExpr {
pub expr: Expr,
pub args: Vec<Expr>,
}
impl CallExpr {
pub fn new_expr(expr: Expr, args: Vec<Expr>) -> Expr {
Self { expr, args }.into()
}
}
//
// impl Accept for CallExpr
//
impl<V: Visit> Accept<V> for CallExpr {
fn accept(&self, visitor: &mut V) -> V::Out {
visitor.visit_call_expr(self)
}
}
//
// impl DefaultAccept for CallExpr
//
impl<V: Visit<Out=()>> DefaultAccept<V> for CallExpr {
fn default_accept(&self, visitor: &mut V) -> V::Out {
visitor.visit_expr(&self.expr);
self.args.iter()
.for_each(|arg| visitor.visit_expr(arg));
}
}
//
// struct IndexExpr
//
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IndexExpr {
pub expr: Expr,
pub index: Expr,
}
impl IndexExpr {
pub fn new_expr(expr: Expr, index: Expr) -> Expr {
Self { expr, index, }.into()
}
}
//
// impl Accept for IndexExpr
//
impl<V: Visit> Accept<V> for IndexExpr {
fn accept(&self, visitor: &mut V) -> V::Out {
visitor.visit_index_expr(self)
}
}
//
// impl DefaultAccept for IndexExpr
//
impl<V: Visit<Out=()>> DefaultAccept<V> for IndexExpr {
fn default_accept(&self, visitor: &mut V) -> V::Out {
visitor.visit_expr(&self.expr);
visitor.visit_expr(&self.index);
}
}
//
// struct AccessExpr
//
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct AccessExpr { pub struct AccessExpr {
pub expr: Expr, pub expr: Expr,
pub access: Vec<Access>, pub access: String,
} }
impl AccessExpr { impl AccessExpr {
pub fn new_expr(expr: Expr, access: Vec<Access>) -> Expr { pub fn new_expr(expr: Expr, access: String) -> Expr {
Self { expr, access, }.into() Self { expr, access, }.into()
} }
} }
#[derive(Debug, Clone, PartialEq, Eq)] //
pub struct Access { // impl Accept for AccessExpr
pub access: String, //
pub trailing: Vec<ExprTrail>, impl<V: Visit> Accept<V> for AccessExpr {
fn accept(&self, visitor: &mut V) -> V::Out {
visitor.visit_access_expr(self)
}
} }
#[derive(Debug, Clone, PartialEq, Eq)] //
pub enum ExprTrail { // impl DefaultAccept for AccessExpr
Call(Vec<Expr>), //
Index(Expr), impl<V: Visit> DefaultAccept<V> for AccessExpr {
fn default_accept(&self, visitor: &mut V) -> V::Out {
visitor.visit_expr(&self.expr)
}
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
@@ -115,6 +356,16 @@ pub enum Atom {
String(String), String(String),
} }
impl<V: Visit> Accept<V> for Atom {
fn accept(&self, visitor: &mut V) -> V::Out {
visitor.visit_atom(self)
}
}
impl<V: Visit<Out=()>> DefaultAccept<V> for Atom {
fn default_accept(&self, _visitor: &mut V) -> V::Out { }
}
pub fn parse(text: &str) -> Result<Option<Vec<Stmt>>, Vec<String>> { pub fn parse(text: &str) -> Result<Option<Vec<Stmt>>, Vec<String>> {
use crate::syn::{lexer, parser}; use crate::syn::{lexer, parser};
let lexerdef = lexer::lexerdef(); let lexerdef = lexer::lexerdef();
@@ -129,36 +380,3 @@ pub fn parse(text: &str) -> Result<Option<Vec<Stmt>>, Vec<String>> {
Ok(res.transpose().unwrap()) Ok(res.transpose().unwrap())
} }
#[cfg(test)]
mod test {
use super::*;
fn parse_expr(text: &str) -> Expr {
let mut body = parse(text)
.unwrap()
.unwrap();
assert!(body.len() == 1);
let stmt = body.pop().unwrap();
if let Stmt::Expr(expr) = stmt {
expr
} else {
panic!("{:?} parses to {:?} which is not a Stmt::Expr", text, stmt);
}
}
#[test]
fn access() {
assert_eq!(
parse_expr("a.b.c()"),
AccessExpr::new_expr(
Atom::Ident("a".to_string()).into(),
vec![
Access { access: "b".to_string(), trailing: vec![], },
Access { access: "c".to_string(), trailing: vec![ExprTrail::Call(vec![])], },
]
)
);
}
}

View File

@@ -5,6 +5,7 @@
[0-9]+ "NUM" [0-9]+ "NUM"
"([^"]|\\[rnt"'\\])+"|'([^"]|\\[rnt"'\\])+' "STRING" "([^"]|\\[rnt"'\\])+"|'([^"]|\\[rnt"'\\])+' "STRING"
= "="
\|\| "||" \|\| "||"
&& "&&" && "&&"
< "<" < "<"

10
src/syn/macros.rs Normal file
View File

@@ -0,0 +1,10 @@
#[macro_export]
macro_rules! accept_default {
($visitor:ty, $acceptor:ty) => {
impl $crate::syn::visit::Accept for $acceptor<$visitor> {
fn accept(&self, visitor: &mut $visitor) -> $visitor::Out {
$crate::syn::visit::DefaultAccept::default_accept(self, visitor)
}
}
};
}

View File

@@ -1,4 +1,6 @@
#![macro_use] mod macros;
pub mod ast; pub mod ast;
pub mod visit;
pub mod lexer { pub mod lexer {
lrlex_mod!("syn/lexer.l"); lrlex_mod!("syn/lexer.l");

View File

@@ -19,6 +19,7 @@ Body -> Result<Vec<Stmt>>:
Stmt -> Result<Stmt>: Stmt -> Result<Stmt>:
Expr { Ok(Stmt::Expr($1?)) } Expr { Ok(Stmt::Expr($1?)) }
//| Assign { todo!() }
; ;
Expr -> Result<Expr>: BinExpr { $1 }; Expr -> Result<Expr>: BinExpr { $1 };
@@ -42,31 +43,24 @@ BinExpr -> Result<Expr>:
UnExpr -> Result<Expr>: UnExpr -> Result<Expr>:
'+' UnExpr { Ok(UnExpr::new_expr(UnOp::Plus, $2?)) } '+' UnExpr { Ok(UnExpr::new_expr(UnOp::Plus, $2?)) }
| '-' UnExpr { Ok(UnExpr::new_expr(UnOp::Minus, $2?)) } | '-' UnExpr { Ok(UnExpr::new_expr(UnOp::Minus, $2?)) }
| CallIndexExpr { $1 }
;
// TODO - add CallExpr and IndexExpr, allow them to nest
// - UnExpr will point to CallIndexExpr
// - Call/Index exprs are based on an AccessExpr
// - AccessExpr will retain ExprTrailing in between its items, but should end in a .ident
CallIndexExpr -> Result<Expr>:
IndexExpr { $1 }
| CallExpr { $1 }
| AccessExpr { $1 } | AccessExpr { $1 }
; ;
AccessExpr -> Result<Expr>: CallExpr -> Result<Expr>:
AtomExpr AccessExprTail { CallIndexExpr '(' FunArgs ')' {
Ok(AccessExpr::new_expr($1?, $2?)) Ok(CallExpr::new_expr($1?, $3?))
} }
| AtomExpr {
Ok(AccessExpr::new_expr($1?, Default::default()))
}
;
AccessExprTail -> Result<Vec<Access>>:
AccessExprTail '.' Ident ExprTrailing {
flatten($1, Ok(Access { access: $3?, trailing: $4? }))
}
| '.' Ident ExprTrailing {
Ok(vec![Access { access: $2?, trailing: $3? }])
}
;
ExprTrailing -> Result<Vec<ExprTrail>>:
ExprTrailing '(' FunArgs ')' { flatten($1, Ok(ExprTrail::Call($3?))) }
| ExprTrailing '[' Expr ']' { flatten($1, Ok(ExprTrail::Index($3?))) }
| { Ok(Vec::new()) }
; ;
FunArgs -> Result<Vec<Expr>>: FunArgs -> Result<Vec<Expr>>:
@@ -79,6 +73,17 @@ FunArgsTail -> Result<Vec<Expr>>:
| Expr { Ok(vec![$1?]) } | Expr { Ok(vec![$1?]) }
; ;
IndexExpr -> Result<Expr>:
CallIndexExpr '[' Expr ']' {
Ok(IndexExpr::new_expr($1?, $3?))
}
;
AccessExpr -> Result<Expr>:
AtomExpr { $1 }
| CallIndexExpr '.' Ident { Ok(AccessExpr::new_expr($1?, $3?)) }
;
AtomExpr -> Result<Expr>: AtomExpr -> Result<Expr>:
Atom { $1.map(Expr::Atom) } Atom { $1.map(Expr::Atom) }
| '(' Expr ')' { $2 } | '(' Expr ')' { $2 }

24
src/syn/visit.rs Normal file
View File

@@ -0,0 +1,24 @@
use crate::syn::ast::*;
pub trait Accept<V: Visit + ?Sized> {
fn accept(&self, visitor: &mut V) -> V::Out;
}
pub trait DefaultAccept<V: Visit + ?Sized> {
fn default_accept(&self, visitor: &mut V) -> V::Out;
}
pub trait Visit {
type Out;
fn visit_stmt(&mut self, stmt: &Stmt) -> Self::Out;
fn visit_assign_stmt(&mut self, assign: &AssignStmt) -> Self::Out;
fn visit_lhs_expr(&mut self, lhs_expr: &LhsExpr) -> Self::Out;
fn visit_expr(&mut self, expr: &Expr) -> Self::Out;
fn visit_bin_expr(&mut self, expr: &BinExpr) -> Self::Out;
fn visit_un_expr(&mut self, expr: &UnExpr) -> Self::Out;
fn visit_call_expr(&mut self, expr: &CallExpr) -> Self::Out;
fn visit_index_expr(&mut self, expr: &IndexExpr) -> Self::Out;
fn visit_access_expr(&mut self, expr: &AccessExpr) -> Self::Out;
fn visit_atom(&mut self, atom: &Atom) -> Self::Out;
}