Initial commit

Includes: runtime base from a previous project, syn(tax) module with
parser and lexer

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-09-01 17:32:48 -07:00
commit 178ed4a952
24 changed files with 1139 additions and 0 deletions

162
src/syn/ast.rs Normal file
View File

@@ -0,0 +1,162 @@
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Stmt {
Expr(Expr),
Assign,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Expr {
Atom(Atom),
Bin(Box<BinExpr>),
Un(Box<UnExpr>),
Access(Box<AccessExpr>),
}
impl From<Atom> for Expr {
fn from(other: Atom) -> Self {
Expr::Atom(other)
}
}
impl From<BinExpr> for Expr {
fn from(other: BinExpr) -> Self {
Expr::Bin(other.into())
}
}
impl From<UnExpr> for Expr {
fn from(other: UnExpr) -> Self {
Expr::Un(other.into())
}
}
impl From<AccessExpr> for Expr {
fn from(other: AccessExpr) -> Self {
Expr::Access(other.into())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BinOp {
Plus,
Minus,
Times,
Div,
Eq,
Neq,
Lt,
Le,
Gt,
Ge,
And,
Or,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BinExpr {
pub lhs: Expr,
pub op: BinOp,
pub rhs: Expr,
}
impl BinExpr {
pub fn new_expr(lhs: Expr, op: BinOp, rhs: Expr) -> Expr {
Self { lhs, op, rhs, }.into()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum UnOp {
Plus,
Minus,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnExpr {
pub op: UnOp,
pub expr: Expr,
}
impl UnExpr {
pub fn new_expr(op: UnOp, expr: Expr) -> Expr {
Self { op, expr }.into()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AccessExpr {
pub expr: Expr,
pub access: Vec<Access>,
}
impl AccessExpr {
pub fn new_expr(expr: Expr, access: Vec<Access>) -> Expr {
Self { expr, access, }.into()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Access {
pub access: String,
pub trailing: Vec<ExprTrail>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ExprTrail {
Call(Vec<Expr>),
Index(Expr),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Atom {
Ident(String),
Sym(String),
Num(i64),
String(String),
}
pub fn parse(text: &str) -> Result<Option<Vec<Stmt>>, Vec<lrpar::LexParseError<u32>>> {
use crate::syn::{lexer, parser};
let lexerdef = lexer::lexerdef();
let lexer = lexerdef.lexer(text);
let (res, errors) = parser::parse(&lexer);
if !errors.is_empty() {
return Err(errors)
}
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![])], },
]
)
);
}
}

27
src/syn/lexer.l Normal file
View File

@@ -0,0 +1,27 @@
%%
[\n;]+ "EOL"
[a-zA-Z_][a-zA-Z0-9_]* "IDENT"
:[a-zA-Z_][a-zA-Z0-9_]* "SYM"
[0-9]+ "NUM"
"([^"]|\\[rnt"'\\])+"|'([^"]|\\[rnt"'\\])+' "STRING"
\|\| "||"
&& "&&"
< "<"
> ">"
<= "<="
>= ">="
!= "!="
== "=="
\+ "+"
\* "*"
/ "/"
- "-"
\( "("
\) ")"
\[ "["
\] "]"
\. "."
, ","
[\t ]+ ;

17
src/syn/mod.rs Normal file
View File

@@ -0,0 +1,17 @@
pub mod ast;
pub mod lexer {
lrlex_mod!("syn/lexer.l");
use lrlex::lrlex_mod;
pub use self::lexer_l::*;
}
pub mod parser {
lrpar_mod!("syn/parser.y");
use lrpar::lrpar_mod;
pub use self::parser_y::*;
}
//pub use lexer_l as lexer;
//pub use parser_y as parser;

144
src/syn/parser.y Normal file
View File

@@ -0,0 +1,144 @@
%start Body
%left '||'
%left '&&'
%left '<' '>' '<=' '>=' '==' '!='
%left '*' '/'
%left '+' '-'
%%
Body -> Result<Vec<Stmt>>:
Body 'EOL' Stmt {
flatten($1, $3)
}
| Stmt { Ok(vec![$1?]) }
| { Ok(Vec::new()) }
;
Stmt -> Result<Stmt>:
Expr { Ok(Stmt::Expr($1?)) }
;
Expr -> Result<Expr>: BinExpr { $1 };
BinExpr -> Result<Expr>:
UnExpr '||' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Or, $3?)) }
| UnExpr '&&' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::And, $3?)) }
| UnExpr '<' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Lt, $3?)) }
| UnExpr '>' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Gt, $3?)) }
| UnExpr '<=' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Le, $3?)) }
| UnExpr '>=' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Ge, $3?)) }
| UnExpr '==' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Eq, $3?)) }
| UnExpr '!=' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Neq, $3?)) }
| UnExpr '*' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Times, $3?)) }
| UnExpr '/' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Div, $3?)) }
| UnExpr '+' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Plus, $3?)) }
| UnExpr '-' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Plus, $3?)) }
| UnExpr { $1 }
;
UnExpr -> Result<Expr>:
'+' UnExpr { Ok(UnExpr::new_expr(UnOp::Plus, $2?)) }
| '-' UnExpr { Ok(UnExpr::new_expr(UnOp::Minus, $2?)) }
| AccessExpr { $1 }
;
AccessExpr -> Result<Expr>:
AtomExpr AccessExprTail {
Ok(AccessExpr::new_expr($1?, $2?))
}
;
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>>:
FunArgsTail { $1 }
| { Ok(Vec::new()) }
;
FunArgsTail -> Result<Vec<Expr>>:
FunArgsTail ',' Expr { flatten($1, $3) }
| Expr { Ok(vec![$1?]) }
;
AtomExpr -> Result<Expr>:
Atom { $1.map(Expr::Atom) }
| '(' Expr ')' { $2 }
;
Atom -> Result<Atom>:
Ident { Ok(Atom::Ident($1?)) }
| 'SYM' {
let v = $1.map_err(|_| ())?;
let sym = &$lexer.span_str(v.span())[1..];
Ok(Atom::Sym(sym.to_string()))
}
| 'NUM' {
let v = $1.map_err(|_| ())?;
let num_text = &$lexer.span_str(v.span());
Ok(Atom::Num(num_text.parse().unwrap()))
}
| 'STRING' {
let v = $1.map_err(|_| ())?;
let string = &$lexer.span_str(v.span())[1..];
Ok(Atom::String(parse_string(string)))
}
;
Ident -> Result<String>:
'IDENT' {
let v = $1.map_err(|_| ())?;
let ident = $lexer.span_str(v.span()).to_string();
Ok(ident)
}
;
%%
use crate::syn::ast::*;
type Result<T> = std::result::Result<T, ()>;
fn flatten<T>(head: Result<Vec<T>>, tail: Result<T>) -> Result<Vec<T>> {
let mut head = head?;
let tail = tail?;
head.push(tail);
Ok(head)
}
fn parse_string(input: &str) -> String {
let mut s = String::new();
let input = &input[1..input.bytes().len() - 1];
let mut chars = input.chars();
while let Some(c) = chars.next() {
if c == '\\' {
let next = chars.next().unwrap();
let c = match next {
'\\' => '\\',
'\'' => '\'',
'"' => '"',
'n' => '\n',
't' => '\t',
_ => unreachable!(),
};
s.push(c);
} else {
s.push(c);
}
}
s
}