Start of expression parsing

This commit is contained in:
2023-07-04 02:49:29 -05:00
parent 2a9bfb342b
commit 2aac110900
3 changed files with 276 additions and 7 deletions
+72
View File
@@ -53,3 +53,75 @@ pub struct Argname {
pub name: String,
pub typename: Option<String>,
}
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct Block {
pub statements: Vec<Statement>,
}
#[derive(Eq, PartialEq, Clone, Debug)]
pub enum Statement {
Return(Return),
Assignment(Assignment),
Call(Call),
VarDecl(VarDecl),
Conditional(Conditional),
WhileLoop(WhileLoop),
RepeatLoop(RepeatLoop),
}
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct Return {}
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct Assignment {}
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct Call {}
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct VarDecl {}
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct Conditional {}
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct WhileLoop {}
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct RepeatLoop {}
/// One of the five arithmetical operators
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Operator {
Add,
Sub,
Mul,
Div,
Mod,
}
#[derive(PartialEq, Clone, Debug)]
pub enum Node {
Number(i32),
Call(Call),
ArrayRef(ArrayRef),
Name(String),
Address(String),
Expr(Box<Node>, Vec<(Operator, Node)>),
}
impl From<i32> for Node {
fn from(val: i32) -> Self {
Self::Number(val)
}
}
impl From<&str> for Node {
fn from(s: &str) -> Self {
Self::Name(String::from(s))
}
}
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct ArrayRef {}
+5 -7
View File
@@ -31,17 +31,16 @@ val = { // These are what get evaluated and left on the stack:
// (call, or pointer arithmetic, since ids all reference addresses)
// (multiple calls / subscripts aren't allowed; use CALL or collapse to one
// subscript)
call | arrayref | name |
//(name ~ (arglist | subscript)?) |
("&" ~ name) } // The address for an name
call | arrayref | name | address }
address = { "&" ~ name } // The address for a name
arrayref = { name ~ subscript } // Subscripting is only literal IDs. Anything else can be pointer arithmetic
call = { name ~ arglist } // Call syntax is only literal IDs. Calling things dynamically is done with a builtin; CALL(foo[3], 1, 2, 3)
arg = { expr | string }
arglist = { "(" ~ (arg ~ ("," ~ arg)*)? ~ ")" }
subscript = { "[" ~ expr ~ "]" }
statement = { ((return_stmt | assignment | call | var_decl) ~ ";") | conditional | loop_stmt }
statement = { ((return_stmt | assignment | call | var_decl) ~ ";") | conditional | while_loop | repeat_loop }
block = { "{" ~ statement* ~ "}" }
@@ -60,9 +59,8 @@ program = { (COMMENT | WHITESPACE)? ~ declaration* ~ EOI }
return_stmt = { "return" ~ expr }
conditional = { "if" ~ "(" ~ expr ~ ")" ~ block ~ ("else" ~ block)? }
loop_stmt = { while_stmt | repeat }
while_stmt = { "while" ~ "(" ~ expr ~ ")" ~ block }
repeat = { "repeat" ~ "(" ~ expr ~ ")" ~ name ~ block }
while_loop = { "while" ~ "(" ~ expr ~ ")" ~ block }
repeat_loop = { "repeat" ~ "(" ~ expr ~ ")" ~ name ~ block }
var_decl = { "var" ~ name ~ varinfo ~ ("=" ~ expr)? }
global = { "global" ~ name ~ varinfo ~ ";" }
typename = { ":" ~ name }
+199
View File
@@ -281,6 +281,153 @@ impl AstNode for Argname {
///////////////////////////////////////////////////////////////////////////////////////////
impl AstNode for Statement {
const RULE: Rule = Rule::declaration;
fn from_pair(pair: Pair) -> Self {
match pair.as_rule() {
Rule::return_stmt => Self::Return(Return::from_pair(pair)),
Rule::assignment => Self::Assignment(Assignment::from_pair(pair)),
Rule::call => Self::Call(Call::from_pair(pair)),
Rule::var_decl => Self::VarDecl(VarDecl::from_pair(pair)),
Rule::conditional => Self::Conditional(Conditional::from_pair(pair)),
Rule::while_loop => Self::WhileLoop(WhileLoop::from_pair(pair)),
Rule::repeat_loop => Self::RepeatLoop(RepeatLoop::from_pair(pair)),
_ => todo!(),
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////
impl AstNode for Return {
const RULE: Rule = Rule::return_stmt;
fn from_pair(pair: Pair) -> Self {
todo!()
}
}
///////////////////////////////////////////////////////////////////////////////////////////
impl AstNode for Assignment {
const RULE: Rule = Rule::assignment;
fn from_pair(pair: Pair) -> Self {
todo!()
}
}
///////////////////////////////////////////////////////////////////////////////////////////
impl AstNode for Call {
const RULE: Rule = Rule::call;
fn from_pair(pair: Pair) -> Self {
todo!()
}
}
///////////////////////////////////////////////////////////////////////////////////////////
impl AstNode for VarDecl {
const RULE: Rule = Rule::var_decl;
fn from_pair(pair: Pair) -> Self {
todo!()
}
}
///////////////////////////////////////////////////////////////////////////////////////////
impl AstNode for Conditional {
const RULE: Rule = Rule::conditional;
fn from_pair(pair: Pair) -> Self {
todo!()
}
}
///////////////////////////////////////////////////////////////////////////////////////////
impl AstNode for WhileLoop {
const RULE: Rule = Rule::while_loop;
fn from_pair(pair: Pair) -> Self {
todo!()
}
}
///////////////////////////////////////////////////////////////////////////////////////////
impl AstNode for RepeatLoop {
const RULE: Rule = Rule::repeat_loop;
fn from_pair(pair: Pair) -> Self {
todo!()
}
}
///////////////////////////////////////////////////////////////////////////////////////////
impl AstNode for Node {
const RULE: Rule = Rule::expr; // Also used for vals / terms / the whole tree
fn from_pair(pair: Pair) -> Self {
let expr = match pair.as_rule() {
Rule::val => Node::from_pair(pair.first()),
Rule::number => Node::Number(pair.into_number()),
Rule::name => Node::Name(String::from(pair.as_str())),
Rule::call => todo!(),
Rule::arrayref => todo!(),
Rule::address => todo!(),
Rule::expr | Rule::term => {
let mut children = pair.into_inner();
let car = Node::from_pair(children.next().unwrap());
Node::Expr(Box::new(car), parse_expr(children))
}
_ => unreachable!(),
};
shake_expr(expr)
}
}
fn parse_expr(mut cdr: Pairs) -> Vec<(Operator, Node)> {
let mut terms = Vec::new();
while let Some(operator) = cdr.next() {
let rhs = cdr.next().unwrap();
let rhs_r = rhs.as_rule();
let rhs = Node::from_pair(rhs);
let op = Operator::from_pair(operator);
terms.push((op, rhs));
}
terms
}
fn shake_expr(node: Node) -> Node {
match node {
Node::Expr(car, cdr) => {
let shaken_car = shake_expr(*car);
if cdr.is_empty() {
shaken_car
} else {
let shaken_cdr = cdr.into_iter().map(|(op, n)| (op, shake_expr(n))).collect();
Node::Expr(Box::from(shaken_car), shaken_cdr)
}
}
_ => node,
}
}
///////////////////////////////////////////////////////////////////////////////////////////
impl AstNode for Operator {
const RULE: Rule = Rule::sign; // also term_op
fn from_pair(pair: Pair) -> Self {
match pair.as_str() {
"+" => Self::Add,
"-" => Self::Sub,
"*" => Self::Mul,
"/" => Self::Div,
"%" => Self::Mod,
_ => unreachable!(),
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////
#[cfg(test)]
mod test {
use super::*;
@@ -480,4 +627,56 @@ mod test {
})
);
}
#[test]
fn parse_exprs() {
use Node::*;
use Operator::*;
// A very, very basic expression
assert_eq!(Node::parse("23"), Ok(Number(23)));
// Two vals with an operator
assert_eq!(
Node::parse("23 + 5"),
Ok(Expr(Number(23).into(), vec![(Add, Number(5))]))
);
// Multiple terms at the same precedence level
assert_eq!(
Node::parse("1 + 2 + 3"),
Ok(Expr(
Number(1).into(),
vec![(Add, 2.into()), (Add, 3.into())]
))
);
// Higher precedence levels
assert_eq!(
Node::parse("1 + 2 * 3"),
Ok(Node::Expr(
Number(1).into(),
vec![(Add, Expr(Number(2).into(), vec![(Mul, 3.into())]))]
))
);
assert_eq!(
Node::parse("2 * 3"),
Ok(Expr(Number(2).into(), vec![(Mul, 3.into())]))
);
assert_eq!(
Node::parse("2 * 3 + 4"),
Ok(Expr(
Expr(Number(2).into(), vec![(Mul, 3.into())]).into(),
vec![(Add, 4.into())]
))
);
// Parens
assert_eq!(
Node::parse("(1 + 2) * 3"),
Ok(Node::Expr(
Expr(Number(1).into(), vec![(Add, 2.into())]).into(),
vec![(Mul, 3.into())]
))
);
}
}