switched to lrpar parser generator
This commit is contained in:
@@ -1,3 +0,0 @@
|
||||
pub trait ASTNode {
|
||||
fn repr_c(&self) -> String;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
use crate::ast::expression::Expression;
|
||||
@@ -1,6 +0,0 @@
|
||||
use crate::ast::literal::Literal;
|
||||
use crate::ast::ast_node::ASTNode;
|
||||
|
||||
pub enum Expression {
|
||||
Literal(Literal),
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
#[derive(Debug)]
|
||||
pub enum Literal {
|
||||
Int(i64),
|
||||
Float(f64),
|
||||
Bool(bool),
|
||||
}
|
||||
|
||||
@@ -1,6 +1,49 @@
|
||||
mod ast_node;
|
||||
pub mod literal;
|
||||
pub mod expression;
|
||||
pub mod logical;
|
||||
mod comparison;
|
||||
mod operators;
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Literal {
|
||||
Int(i64),
|
||||
Float(f64),
|
||||
Bool(bool),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Expression {
|
||||
Lit(Literal),
|
||||
Ident(String),
|
||||
Add(Box<Expression>, Box<Expression>),
|
||||
Sub(Box<Expression>, Box<Expression>),
|
||||
Mul(Box<Expression>, Box<Expression>),
|
||||
Div(Box<Expression>, Box<Expression>),
|
||||
Mod(Box<Expression>, Box<Expression>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Definition {
|
||||
Binding {
|
||||
identifier_info: TypedIdentifier,
|
||||
value: Expression,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct TypedIdentifier {
|
||||
identifier_uuid: usize,
|
||||
|
||||
id: String,
|
||||
type_arg: TypeArg,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum TypeArg {
|
||||
Rank0(AST_TypeId),
|
||||
RankN {
|
||||
from: Box<TypeArg>,
|
||||
to: Box<TypeArg>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct AST_TypeId {
|
||||
type_uuid: usize,
|
||||
|
||||
string_repr: String,
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
use crate::ast::expression::Expression;
|
||||
|
||||
pub enum Operator {
|
||||
Unary(UnaryOperator),
|
||||
Binary(BinaryOperator),
|
||||
}
|
||||
|
||||
pub enum UnaryOperator {
|
||||
Minus,
|
||||
Not,
|
||||
Reference,
|
||||
Dereference,
|
||||
}
|
||||
|
||||
pub enum BinaryOperator {
|
||||
Plus,
|
||||
Minus,
|
||||
Multiply,
|
||||
Divide,
|
||||
Modulo,
|
||||
And,
|
||||
Or,
|
||||
Xor,
|
||||
Equal,
|
||||
NotEqual,
|
||||
Greater,
|
||||
GreaterEqual,
|
||||
Less,
|
||||
LessEqual,
|
||||
}
|
||||
19
src/errors.rs
Normal file
19
src/errors.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
use std::error::Error;
|
||||
use std::fmt::{Debug, Display, Formatter, Pointer};
|
||||
|
||||
pub struct CLIArgumentError(pub &'static str);
|
||||
|
||||
|
||||
impl Display for CLIArgumentError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for CLIArgumentError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for CLIArgumentError {}
|
||||
9
src/grammar.l
Normal file
9
src/grammar.l
Normal file
@@ -0,0 +1,9 @@
|
||||
%%
|
||||
[1-9][0-9]* "LITINT"
|
||||
[-+]?([0-9]*[.][0-9]+|[0-9]*([.][0-9]+)?[Ee][-+]?[1-9][0-9]*) "LITFLOAT"
|
||||
[_a-zA-Z][_0-9a-zA-Z]* "IDENT"
|
||||
\+ "ADD"
|
||||
\* "MUL"
|
||||
\( "("
|
||||
\) ")"
|
||||
[\t ]+ ;
|
||||
52
src/grammar.y
Normal file
52
src/grammar.y
Normal file
@@ -0,0 +1,52 @@
|
||||
%start Expr
|
||||
%%
|
||||
Expr -> Result<Expression, () >:
|
||||
Expr "ADD" MulExpr { Ok(Expression::Add(Box::new( $1? ), Box::new( $3? ))) }
|
||||
| MulExpr { $1 }
|
||||
;
|
||||
|
||||
MulExpr -> Result<Expression, () >:
|
||||
MulExpr "MUL" ConstExpr { Ok( Expression::Mul(Box::new($1?), Box::new($3?)) ) }
|
||||
| ConstExpr { $1 }
|
||||
;
|
||||
|
||||
ConstExpr -> Result<Expression, () >:
|
||||
'(' Expr ')' { $2 }
|
||||
| 'LITINT' {
|
||||
let v = $1.map_err( | _| ())?;
|
||||
Ok(Expression::Lit(Literal::Int(parse_int( $lexer.span_str(v.span()))?)))
|
||||
}
|
||||
| "LITFLOAT" {
|
||||
let v = $1.map_err( | _| ())?;
|
||||
Ok(Expression::Lit(Literal::Float(parse_float( $lexer.span_str(v.span()))?)))
|
||||
}
|
||||
| "IDENT" {
|
||||
let v = $1.map_err( | _| ())?;
|
||||
Ok(Expression::Ident(String::from( $lexer.span_str(v.span()))))
|
||||
}
|
||||
;
|
||||
%%
|
||||
// Any functions here are in scope for all the grammar actions above.
|
||||
|
||||
fn parse_int(s: &str) -> Result<i64, ()> {
|
||||
match s.parse::<i64>() {
|
||||
Ok(val) => Ok(val),
|
||||
Err(_) => {
|
||||
eprintln!("{} cannot be represented as a i64", s);
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_float(s: &str) -> Result<f64, ()> {
|
||||
match s.parse::<f64>() {
|
||||
Ok(val) => Ok(val),
|
||||
Err(_) => {
|
||||
eprintln!("{} cannot be represented as a f64", s);
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
use crate::ast::{Literal, Expression};
|
||||
35
src/main.rs
35
src/main.rs
@@ -1,10 +1,37 @@
|
||||
use lalrpop_util::lalrpop_mod;
|
||||
use crate::errors::CLIArgumentError;
|
||||
use lrlex::lrlex_mod;
|
||||
use lrpar::lrpar_mod;
|
||||
use std::error::Error;
|
||||
use std::fmt::{Display, format};
|
||||
use std::io;
|
||||
use std::io::ErrorKind::InvalidInput;
|
||||
|
||||
mod ast;
|
||||
mod errors;
|
||||
mod optimising;
|
||||
mod tests;
|
||||
|
||||
lalrpop_mod!(pub expressions);
|
||||
lrlex_mod!("grammar.l");
|
||||
lrpar_mod!("grammar.y");
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let src_path = std::env::args()
|
||||
.nth(1)
|
||||
.ok_or(Box::new(CLIArgumentError("Source File Not Provided")))?;
|
||||
let src_string = std::fs::read_to_string(&src_path)?;
|
||||
|
||||
let lexerdef = grammar_l::lexerdef();
|
||||
|
||||
let lexer = lexerdef.lexer((src_string.as_str()));
|
||||
let (res, errs) = grammar_y::parse(&lexer);
|
||||
if let Some(Ok(res)) = res {
|
||||
println!("{:#?}", res);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// fn main() {
|
||||
// if let Err(ref e) = main_() {
|
||||
// return e.fmt()
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
mod constfolding;
|
||||
mod constfolding;
|
||||
|
||||
@@ -13,4 +13,4 @@
|
||||
// assert!(IdentParser::new().parse("0").is_err());
|
||||
// assert!(IdentParser::new().parse("0123456").is_err());
|
||||
// assert!(IdentParser::new().parse("0aaaa").is_err());
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -1,80 +1,54 @@
|
||||
use crate::ast::literal::Literal;
|
||||
use crate::expressions::AtomParser as Parser;
|
||||
use lrlex::lrlex_mod;
|
||||
use lrpar::lrpar_mod;
|
||||
|
||||
#[test]
|
||||
fn int_literals() {
|
||||
let parser = Parser::new();
|
||||
let valid_ints = vec!["1234567890", "(1234567890)", "((((1))))"];
|
||||
let invalid_ints = vec!["01", "(1", "6543)", "((987652345)"];
|
||||
use crate::ast::{Expression, Literal};
|
||||
|
||||
assert!(valid_ints.into_iter().all(|s| parser.parse(s).is_ok()));
|
||||
assert!(invalid_ints.into_iter().all(|s| parser.parse(s).is_err()));
|
||||
lrlex_mod!("grammar.l");
|
||||
lrpar_mod!("grammar.y");
|
||||
|
||||
macro_rules! test_literal_list {
|
||||
|
||||
|
||||
($f:ident, $string:literal) => {
|
||||
assert!($f($string))
|
||||
};
|
||||
|
||||
($f:ident, $first:literal, $($rest:literal),*) => {
|
||||
test_literal_list!($f, $first);
|
||||
test_literal_list!($f, $($rest),*);
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_float_dots() {
|
||||
let valid_floats = vec![
|
||||
"0.0",
|
||||
"-0.0",
|
||||
"3.141592653589793",
|
||||
"-1.123456765432123456789",
|
||||
];
|
||||
assert!(Parser::new().parse("1.1").is_ok());
|
||||
assert!(Parser::new().parse("-1.1").is_ok());
|
||||
assert!(Parser::new().parse(".1").is_ok());
|
||||
assert!(Parser::new().parse("-.1").is_ok());
|
||||
fn parse_str(input: &str) -> Result<Expression, ()> {
|
||||
let lexerdef = grammar_l::lexerdef();
|
||||
let lexer = lexerdef.lexer(&input);
|
||||
let (res, errs) = grammar_y::parse(&lexer);
|
||||
if let Some(parsed_res) = res {
|
||||
parsed_res
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_float_exps() {
|
||||
let parser = crate::expressions::FloatParser::new();
|
||||
|
||||
let valid_float_exps: Vec<&str> = vec![
|
||||
"1e1", "-1e1", "1e-1", "-1e-1", "1.1e1", "1.1e-1", "-1.1e1", "-1.1e-1", ".1e1", "-.1e1",
|
||||
"-.1e-1", "1E1", "-1E1", "1E-1", "-1E-1", "1.1E1", "1.1E-1", "-1.1E1", "-1.1E-1", ".1E1",
|
||||
"-.1E1", "-.1E-1",
|
||||
];
|
||||
fn test_int_literal() {
|
||||
let lexer = grammar_l::lexerdef();
|
||||
let valid_ints = vec!["1", "1", "100000000000000000", "1234567890", "1234567890"];
|
||||
let invalid_ints = vec!["01", "AAAAAAAAAAAAAAA", "-1"];
|
||||
|
||||
let invalid_float_exps: Vec<&str> = vec![
|
||||
"AAAAAAAAAAAAAAA",
|
||||
"1.e1",
|
||||
"1e1.1",
|
||||
"1.1e1.1",
|
||||
"-1e1.1",
|
||||
"1e-1.1",
|
||||
];
|
||||
let matches_parsed_int = |s: &str| match parse_str(s) {
|
||||
Ok(i) => matches!(i, Expression::Lit(Literal::Int(_))),
|
||||
Err(_) => false,
|
||||
};
|
||||
|
||||
assert!(
|
||||
valid_float_exps
|
||||
.into_iter()
|
||||
.all(|s| parser.parse(s).is_ok())
|
||||
);
|
||||
assert!(
|
||||
invalid_float_exps
|
||||
.into_iter()
|
||||
.all(|s| parser.parse(s).is_err())
|
||||
test_literal_list!(
|
||||
matches_parsed_int,
|
||||
"1",
|
||||
"1",
|
||||
"100000000000000000",
|
||||
"1234567890",
|
||||
"1234567890"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_atom_parser() {
|
||||
use crate::ast::literal::Literal;
|
||||
let parser = crate::expressions::AtomParser::new();
|
||||
|
||||
let parsed_int_atom = parser.parse("123");
|
||||
assert!(matches!(parsed_int_atom, Ok(Literal::Int(_))));
|
||||
|
||||
let parsed_int_atom = parser.parse("-1.12345");
|
||||
assert!(matches!(parsed_int_atom, Ok(Literal::Float(_))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_expr_parser() {
|
||||
let parser = crate::expressions::ASTExpressionParser::new();
|
||||
|
||||
let parsed_int_expr = parser.parse("123");
|
||||
assert!(matches!(parsed_int_expr, Ok(Literal::Int(_))));
|
||||
|
||||
let parsed_int_expr = parser.parse("-4.20E-69");
|
||||
assert!(matches!(parsed_int_expr, Ok(Literal::Float(_))));
|
||||
|
||||
// test_literal_list!(parse_str, "01", "AAAAAAAAAAAAAAA", "-1");
|
||||
}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
mod literals;
|
||||
mod expressions;
|
||||
mod literals;
|
||||
|
||||
Reference in New Issue
Block a user