A big refactor, step 2
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
use crate::ast::{Const, Expr};
|
||||
use crate::parser::{AstNode, Pair, PairExt, PestRule};
|
||||
|
||||
impl AstNode for Const {
|
||||
const RULE: PestRule = PestRule::const_decl;
|
||||
fn from_pair(pair: Pair) -> Self {
|
||||
let mut inner = pair.into_inner();
|
||||
let name = String::from(inner.next().unwrap().as_str());
|
||||
let value = inner.next().unwrap();
|
||||
match value.as_rule() {
|
||||
PestRule::string => Const {
|
||||
name,
|
||||
string: Some(value.into_quoted_string()),
|
||||
value: None,
|
||||
},
|
||||
PestRule::expr => Const {
|
||||
name,
|
||||
string: None,
|
||||
value: Some(Expr::from_pair(value)),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::parser::Parseable;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parse_decimal_consts() {
|
||||
assert_eq!(
|
||||
Const::from_str("const a = 123;"),
|
||||
Ok(Const {
|
||||
name: "a".into(),
|
||||
value: Some(123.into()),
|
||||
string: None,
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_hex() {
|
||||
assert_eq!(
|
||||
Const::from_str("const a = 0xaa;"),
|
||||
Ok(Const {
|
||||
name: "a".into(),
|
||||
value: Some(0xaa.into()),
|
||||
string: None,
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_negative() {
|
||||
assert_eq!(
|
||||
Const::from_str("const a = -7;"),
|
||||
Ok(Const {
|
||||
name: "a".into(),
|
||||
value: Some(Expr::Neg(7.into()).into()),
|
||||
string: None,
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_string() {
|
||||
assert_eq!(
|
||||
Const::from_str("const a = \"foo bar\";"),
|
||||
Ok(Const {
|
||||
name: "a".into(),
|
||||
value: None,
|
||||
string: Some("foo bar".into()),
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use crate::ast::{Const, Declaration, Function, FunctionPrototype, Global};
|
||||
use crate::parser::{AstNode, Pair, PestRule, PairExt};
|
||||
|
||||
impl AstNode for Declaration {
|
||||
const RULE: PestRule = PestRule::declaration;
|
||||
fn from_pair(pair: Pair) -> Self {
|
||||
let pair = pair.first();
|
||||
match pair.as_rule() {
|
||||
PestRule::function => Self::Function(Function::from_pair(pair)),
|
||||
PestRule::global => Self::Global(Global::from_pair(pair)),
|
||||
PestRule::const_decl => Self::Const(Const::from_pair(pair)),
|
||||
PestRule::function_prototype => Self::Prototype(FunctionPrototype::from_pair(pair)),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
use crate::ast::{Block, Function};
|
||||
use crate::parser::{AstNode, Pair, PestRule};
|
||||
|
||||
impl AstNode for Function {
|
||||
const RULE: PestRule = PestRule::function;
|
||||
fn from_pair(pair: Pair<'_>) -> Self {
|
||||
let mut inner = pair.into_inner().peekable();
|
||||
let name = String::from(inner.next().unwrap().as_str());
|
||||
let args: Vec<_> = inner
|
||||
.next()
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
.map(|p| String::from(p.as_str()))
|
||||
.collect();
|
||||
|
||||
let body = Block::from_pair(inner.next().unwrap());
|
||||
|
||||
Self { name, args, body }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::parser::Parseable;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parse_function_headers() {
|
||||
assert_eq!(
|
||||
Function::from_str("fn foo() {}"),
|
||||
Ok(Function {
|
||||
name: "foo".into(),
|
||||
args: vec![],
|
||||
body: Block(vec![]),
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_fns_with_args() {
|
||||
assert_eq!(
|
||||
Function::from_str("fn foo(a, b) {}"),
|
||||
Ok(Function {
|
||||
name: "foo".into(),
|
||||
args: vec!["a".into(), "b".into()],
|
||||
body: Block(vec![]),
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
use crate::ast::{Expr, Global};
|
||||
use crate::parser::{AstNode, Pair, PestRule};
|
||||
|
||||
impl AstNode for Global {
|
||||
const RULE: PestRule = PestRule::global;
|
||||
fn from_pair(pair: Pair) -> Self {
|
||||
let mut inner = pair.into_inner().peekable();
|
||||
let name = String::from(inner.next().unwrap().as_str());
|
||||
let size = inner.next().map(Expr::from_pair);
|
||||
|
||||
Global { name, size }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::parser::Parseable;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parse_globals() {
|
||||
assert_eq!(
|
||||
Global::from_str("global foo;"),
|
||||
Ok(Global {
|
||||
name: "foo".into(),
|
||||
size: None,
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_global_arrays() {
|
||||
assert_eq!(
|
||||
Global::from_str("global foo[10];"),
|
||||
Ok(Global {
|
||||
name: "foo".into(),
|
||||
size: Some(10.into()),
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
pub mod declaration;
|
||||
mod global;
|
||||
mod r#const;
|
||||
mod function;
|
||||
+44
-252
@@ -28,94 +28,20 @@ lazy_static::lazy_static! {
|
||||
};
|
||||
}
|
||||
|
||||
/// Expose Pest's generated `Rule` type so other things can see it.
|
||||
/// Make some Pest types a little more ergonomic to refer to, especially outside this file:
|
||||
pub type PestRule = Rule;
|
||||
|
||||
use crate::ast::*;
|
||||
use std::iter::Peekable;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub(crate) type Pair<'a> = pest::iterators::Pair<'a, Rule>;
|
||||
pub(crate) type Pairs<'i, R = Rule> = pest::iterators::Pairs<'i, R>;
|
||||
|
||||
trait PairExt {
|
||||
fn first(self) -> Self;
|
||||
fn first_as_string(self) -> String;
|
||||
fn only(self) -> Self;
|
||||
fn into_number(self) -> i32;
|
||||
|
||||
/// Create a String containing the string represented by a given pair. Since the pair will
|
||||
/// reference bytes containing escape sequences, this isn't the same as an &str to the
|
||||
/// original code; this is a new string translating those escape sequences to their actual
|
||||
/// bytes.
|
||||
fn into_quoted_string(self) -> String;
|
||||
}
|
||||
|
||||
impl<'a> PairExt for Pair<'a> {
|
||||
fn first(self) -> Self {
|
||||
self.into_inner().next().unwrap()
|
||||
}
|
||||
|
||||
fn first_as_string(self) -> String {
|
||||
String::from(self.first().as_str())
|
||||
}
|
||||
|
||||
fn only(self) -> Pair<'a> {
|
||||
let mut iter = self.into_inner();
|
||||
let child = iter.next().unwrap();
|
||||
debug_assert_eq!(iter.next(), None);
|
||||
child
|
||||
}
|
||||
|
||||
fn into_number(self) -> i32 {
|
||||
let first = self.into_inner().next().unwrap();
|
||||
match first.as_rule() {
|
||||
Rule::dec_number | Rule::dec_zero => i32::from_str(first.as_str()).unwrap(),
|
||||
Rule::hex_number => i32::from_str_radix(first.as_str().get(2..).unwrap(), 16).unwrap(),
|
||||
Rule::bin_number => i32::from_str_radix(first.as_str().get(2..).unwrap(), 2).unwrap(),
|
||||
Rule::oct_number => i32::from_str_radix(first.as_str().get(2..).unwrap(), 8).unwrap(),
|
||||
_ => panic!("Expected a number, got {}", first.as_str()),
|
||||
}
|
||||
}
|
||||
|
||||
fn into_quoted_string(self) -> String {
|
||||
let mut string = String::with_capacity(self.as_str().len());
|
||||
for inner in self.into_inner() {
|
||||
let string_inner = inner.as_str();
|
||||
match string_inner {
|
||||
"\\t" => string.push('\t'),
|
||||
"\\r" => string.push('\r'),
|
||||
"\\n" => string.push('\n'),
|
||||
"\\0" => string.push('\0'),
|
||||
"\\\\" => string.push('\\'),
|
||||
"\\\"" => string.push('\"'),
|
||||
_ => string.push_str(string_inner),
|
||||
}
|
||||
}
|
||||
string
|
||||
}
|
||||
}
|
||||
|
||||
trait PairsExt {
|
||||
fn next_if_rule(&mut self, rule: Rule) -> Option<Pair>;
|
||||
fn first(&mut self) -> Pair;
|
||||
}
|
||||
|
||||
impl PairsExt for Peekable<Pairs<'_>> {
|
||||
fn next_if_rule(&mut self, rule: Rule) -> Option<Pair> {
|
||||
self.next_if(|p| p.as_rule() == rule)
|
||||
}
|
||||
|
||||
fn first(&mut self) -> Pair {
|
||||
self.next().unwrap().first()
|
||||
}
|
||||
}
|
||||
|
||||
mod parse_error;
|
||||
mod pairs_ext;
|
||||
|
||||
use crate::ast::*;
|
||||
pub use pairs_ext::*;
|
||||
pub use parse_error::ParseError;
|
||||
|
||||
/// A trait that represents something that can be parsed into an AST node: impl this to turn
|
||||
/// a pair into your node, by from_pair-ing child nodes.
|
||||
trait AstNode: Sized {
|
||||
const RULE: Rule;
|
||||
fn from_pair(pair: Pair) -> Self;
|
||||
@@ -128,6 +54,9 @@ trait AstNode: Sized {
|
||||
}
|
||||
}
|
||||
|
||||
/// A companion trait to AstNode: Parseable things can be parsed from strings, and Parseable
|
||||
/// AstNodes have a default way of doing that (using the ForgeParser to make a pair and then
|
||||
/// from_pair-ing it
|
||||
trait Parseable: Sized {
|
||||
fn from_str(src: &str) -> Result<Self, ParseError>;
|
||||
}
|
||||
@@ -142,87 +71,24 @@ impl<T: AstNode> Parseable for T {
|
||||
}
|
||||
}
|
||||
|
||||
/// Try and parse a program into an AST node. A convenience method (since Program is both
|
||||
/// Parseable and an AstNode) but also the outside entry point into this whole module.
|
||||
pub fn parse(src: &str) -> Result<Program, ParseError> {
|
||||
Program::from_str(src)
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl AstNode for Declaration {
|
||||
const RULE: Rule = Rule::declaration;
|
||||
fn from_pair(pair: Pair) -> Self {
|
||||
let pair = pair.first();
|
||||
match pair.as_rule() {
|
||||
Rule::function => Self::Function(Function::from_pair(pair)),
|
||||
Rule::global => Self::Global(Global::from_pair(pair)),
|
||||
Rule::const_decl => Self::Const(Const::from_pair(pair)),
|
||||
Rule::function_prototype => Self::Prototype(FunctionPrototype::from_pair(pair)),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
mod ast_nodes;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl AstNode for Global {
|
||||
const RULE: Rule = Rule::global;
|
||||
fn from_pair(pair: Pair) -> Self {
|
||||
let mut inner = pair.into_inner().peekable();
|
||||
let name = String::from(inner.next().unwrap().as_str());
|
||||
let size = inner.next().map(Expr::from_pair);
|
||||
|
||||
Global { name, size }
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl AstNode for Const {
|
||||
const RULE: Rule = Rule::const_decl;
|
||||
fn from_pair(pair: Pair) -> Self {
|
||||
let mut inner = pair.into_inner();
|
||||
let name = String::from(inner.next().unwrap().as_str());
|
||||
let value = inner.next().unwrap();
|
||||
match value.as_rule() {
|
||||
Rule::string => Const {
|
||||
name,
|
||||
string: Some(value.into_quoted_string()),
|
||||
value: None,
|
||||
},
|
||||
Rule::expr => Const {
|
||||
name,
|
||||
string: None,
|
||||
value: Some(Expr::from_pair(value)),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl AstNode for Function {
|
||||
const RULE: Rule = Rule::function;
|
||||
fn from_pair(pair: Pair<'_>) -> Self {
|
||||
let mut inner = pair.into_inner().peekable();
|
||||
let name = String::from(inner.next().unwrap().as_str());
|
||||
let args: Vec<_> = inner
|
||||
.next()
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
.map(|p| String::from(p.as_str()))
|
||||
.collect();
|
||||
|
||||
let body = Block::from_pair(inner.next().unwrap());
|
||||
|
||||
Self { name, args, body }
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl AstNode for FunctionPrototype {
|
||||
const RULE: Rule = Rule::function_prototype;
|
||||
const RULE: PestRule = PestRule::function_prototype;
|
||||
fn from_pair(pair: Pair<'_>) -> Self {
|
||||
let mut inner = pair.into_inner().peekable();
|
||||
let name = String::from(inner.next().unwrap().as_str());
|
||||
@@ -240,18 +106,18 @@ impl AstNode for FunctionPrototype {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl AstNode for Statement {
|
||||
const RULE: Rule = Rule::statement;
|
||||
const RULE: PestRule = PestRule::statement;
|
||||
fn from_pair(pair: Pair) -> Self {
|
||||
let pair = pair.first();
|
||||
match pair.as_rule() {
|
||||
Rule::return_stmt => Self::Return(Return::from_pair(pair)),
|
||||
Rule::assignment => Self::Assignment(Assignment::from_pair(pair)),
|
||||
Rule::expr => Self::Expr(Expr::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)),
|
||||
Rule::asm => Self::Asm(Asm::from_pair(pair)),
|
||||
PestRule::return_stmt => Self::Return(Return::from_pair(pair)),
|
||||
PestRule::assignment => Self::Assignment(Assignment::from_pair(pair)),
|
||||
PestRule::expr => Self::Expr(Expr::from_pair(pair)),
|
||||
PestRule::var_decl => Self::VarDecl(VarDecl::from_pair(pair)),
|
||||
PestRule::conditional => Self::Conditional(Conditional::from_pair(pair)),
|
||||
PestRule::while_loop => Self::WhileLoop(WhileLoop::from_pair(pair)),
|
||||
PestRule::repeat_loop => Self::RepeatLoop(RepeatLoop::from_pair(pair)),
|
||||
PestRule::asm => Self::Asm(Asm::from_pair(pair)),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
@@ -260,14 +126,14 @@ impl AstNode for Statement {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl AstNode for Asm {
|
||||
const RULE: Rule = Rule::asm;
|
||||
const RULE: PestRule = PestRule::asm;
|
||||
fn from_pair(pair: Pair) -> Self {
|
||||
let mut args = Vec::new();
|
||||
let mut body = None;
|
||||
for p in pair.into_inner() {
|
||||
match p.as_rule() {
|
||||
Rule::expr => args.push(Expr::from_pair(p).into()),
|
||||
Rule::asm_body => body = Some(String::from(p.as_str().trim())),
|
||||
PestRule::expr => args.push(Expr::from_pair(p).into()),
|
||||
PestRule::asm_body => body = Some(String::from(p.as_str().trim())),
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
@@ -278,7 +144,7 @@ impl AstNode for Asm {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl AstNode for Return {
|
||||
const RULE: Rule = Rule::return_stmt;
|
||||
const RULE: PestRule = PestRule::return_stmt;
|
||||
fn from_pair(pair: Pair) -> Self {
|
||||
pair.into_inner()
|
||||
.next()
|
||||
@@ -289,7 +155,7 @@ impl AstNode for Return {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl AstNode for Assignment {
|
||||
const RULE: Rule = Rule::assignment;
|
||||
const RULE: PestRule = PestRule::assignment;
|
||||
fn from_pair(pair: Pair) -> Self {
|
||||
let mut pairs = pair.into_inner();
|
||||
let lvalue = Expr::from_pair(pairs.next().unwrap()).into();
|
||||
@@ -301,7 +167,7 @@ impl AstNode for Assignment {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl AstNode for VarDecl {
|
||||
const RULE: Rule = Rule::var_decl;
|
||||
const RULE: PestRule = PestRule::var_decl;
|
||||
fn from_pair(pair: Pair) -> Self {
|
||||
let mut inner = pair.into_inner();
|
||||
let name = String::from(inner.next().unwrap().as_str());
|
||||
@@ -310,8 +176,8 @@ impl AstNode for VarDecl {
|
||||
|
||||
for p in inner {
|
||||
match p.as_rule() {
|
||||
Rule::size => { size = Some(Expr::from_pair(p.first())) }
|
||||
Rule::expr => { initial = Some(Expr::from_pair(p)) }
|
||||
PestRule::size => { size = Some(Expr::from_pair(p.first())) }
|
||||
PestRule::expr => { initial = Some(Expr::from_pair(p)) }
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
@@ -323,7 +189,7 @@ impl AstNode for VarDecl {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl AstNode for Block {
|
||||
const RULE: Rule = Rule::block;
|
||||
const RULE: PestRule = PestRule::block;
|
||||
|
||||
fn from_pair(pair: Pair) -> Self {
|
||||
Self(pair.into_inner().map(Statement::from_pair_located).collect())
|
||||
@@ -333,7 +199,7 @@ impl AstNode for Block {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl AstNode for Conditional {
|
||||
const RULE: Rule = Rule::conditional;
|
||||
const RULE: PestRule = PestRule::conditional;
|
||||
fn from_pair(pair: Pair) -> Self {
|
||||
let mut inner = pair.into_inner();
|
||||
let condition = Expr::from_pair(inner.next().unwrap());
|
||||
@@ -350,7 +216,7 @@ impl AstNode for Conditional {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl AstNode for WhileLoop {
|
||||
const RULE: Rule = Rule::while_loop;
|
||||
const RULE: PestRule = PestRule::while_loop;
|
||||
fn from_pair(pair: Pair) -> Self {
|
||||
let mut inner = pair.into_inner();
|
||||
Self {
|
||||
@@ -363,12 +229,12 @@ impl AstNode for WhileLoop {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl AstNode for RepeatLoop {
|
||||
const RULE: Rule = Rule::repeat_loop;
|
||||
const RULE: PestRule = PestRule::repeat_loop;
|
||||
fn from_pair(pair: Pair) -> Self {
|
||||
let mut inner = pair.into_inner().peekable();
|
||||
let count = Expr::from_pair(inner.next().unwrap());
|
||||
let name = inner
|
||||
.next_if_rule(Rule::name)
|
||||
.next_if_rule(PestRule::name)
|
||||
.map(|p| String::from(p.as_str()));
|
||||
let body = Block::from_pair(inner.next().unwrap());
|
||||
Self { count, name, body }
|
||||
@@ -378,7 +244,7 @@ impl AstNode for RepeatLoop {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl AstNode for Expr {
|
||||
const RULE: Rule = Rule::expr;
|
||||
const RULE: PestRule = PestRule::expr;
|
||||
fn from_pair(pair: Pair) -> Self {
|
||||
// The way this works is, the rule has to be of the form:
|
||||
// expr = { prefix* ~ val ~ suffix* ~ (operator ~ prefix* ~ val ~ suffix*)* }
|
||||
@@ -393,10 +259,10 @@ impl AstNode for Expr {
|
||||
// various forms.
|
||||
PRATT_PARSER
|
||||
.map_primary(|term| match term.as_rule() {
|
||||
Rule::number => Expr::Number(term.into_number()),
|
||||
Rule::name => Expr::Name(String::from(term.as_str())),
|
||||
Rule::expr => Expr::from_pair(term),
|
||||
Rule::string => Self::String(term.into_quoted_string()),
|
||||
PestRule::number => Expr::Number(term.into_number()),
|
||||
PestRule::name => Expr::Name(String::from(term.as_str())),
|
||||
PestRule::expr => Expr::from_pair(term),
|
||||
PestRule::string => Self::String(term.into_quoted_string()),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.map_infix(|lhs, op, rhs| Expr::Infix(lhs.into(), Operator::from_pair(op), rhs.into()))
|
||||
@@ -408,13 +274,13 @@ impl AstNode for Expr {
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.map_postfix(|expr, suffix| match suffix.as_rule() {
|
||||
Rule::arglist => Expr::Call(
|
||||
PestRule::arglist => Expr::Call(
|
||||
Call {
|
||||
target: expr.into(),
|
||||
args: suffix.into_inner().map(Expr::from_pair).collect(),
|
||||
}
|
||||
),
|
||||
Rule::subscript => {
|
||||
PestRule::subscript => {
|
||||
Expr::Subscript(expr.into(), Expr::from_pair(suffix.first()).into())
|
||||
}
|
||||
_ => unreachable!(),
|
||||
@@ -432,7 +298,7 @@ impl Expr {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl AstNode for Operator {
|
||||
const RULE: Rule = Rule::operator;
|
||||
const RULE: PestRule = PestRule::operator;
|
||||
fn from_pair(pair: Pair) -> Self {
|
||||
match pair.as_str() {
|
||||
"+" => Self::Add,
|
||||
@@ -461,13 +327,13 @@ impl AstNode for Operator {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl AstNode for Program {
|
||||
const RULE: Rule = Rule::program;
|
||||
const RULE: PestRule = PestRule::program;
|
||||
fn from_pair(pair: Pair) -> Self {
|
||||
// Program captures EOI, to make sure that it's parsing the entire stream. We need to
|
||||
// ignore that though:
|
||||
Self(
|
||||
pair.into_inner()
|
||||
.filter(|p| p.as_rule() != Rule::EOI)
|
||||
.filter(|p| p.as_rule() != PestRule::EOI)
|
||||
.map(Declaration::from_pair_located)
|
||||
.collect(),
|
||||
)
|
||||
@@ -480,80 +346,6 @@ impl AstNode for Program {
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parse_globals() {
|
||||
assert_eq!(
|
||||
Global::from_str("global foo;"),
|
||||
Ok(Global {
|
||||
name: "foo".into(),
|
||||
size: None,
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
Global::from_str("global foo[10];"),
|
||||
Ok(Global {
|
||||
name: "foo".into(),
|
||||
size: Some(10.into()),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_consts() {
|
||||
assert_eq!(
|
||||
Const::from_str("const a = 123;"),
|
||||
Ok(Const {
|
||||
name: "a".into(),
|
||||
value: Some(123.into()),
|
||||
string: None,
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
Const::from_str("const a = 0xaa;"),
|
||||
Ok(Const {
|
||||
name: "a".into(),
|
||||
value: Some(0xaa.into()),
|
||||
string: None,
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
Const::from_str("const a = -7;"),
|
||||
Ok(Const {
|
||||
name: "a".into(),
|
||||
value: Some(Expr::Neg(7.into()).into()),
|
||||
string: None,
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
Const::from_str("const a = \"foo bar\";"),
|
||||
Ok(Const {
|
||||
name: "a".into(),
|
||||
value: None,
|
||||
string: Some("foo bar".into()),
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_function_headers() {
|
||||
assert_eq!(
|
||||
Function::from_str("fn foo() {}"),
|
||||
Ok(Function {
|
||||
name: "foo".into(),
|
||||
args: vec![],
|
||||
body: Block(vec![]),
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
Function::from_str("fn foo(a, b) {}"),
|
||||
Ok(Function {
|
||||
name: "foo".into(),
|
||||
args: vec!["a".into(), "b".into()],
|
||||
body: Block(vec![]),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_exprs() {
|
||||
use Expr::Infix;
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::str::FromStr;
|
||||
use crate::parser::{Pair, Pairs, PestRule};
|
||||
|
||||
/// Some handy utility methods to extend Pair with
|
||||
trait PairExt {
|
||||
pub trait PairExt {
|
||||
/// Go down one level in the AST, return the first node. Assumes the first node exists
|
||||
fn first(self) -> Self;
|
||||
|
||||
@@ -71,7 +71,7 @@ impl<'a> PairExt for Pair<'a> {
|
||||
}
|
||||
|
||||
/// Some handy utility methods to extend Pairs with
|
||||
trait PairsExt {
|
||||
pub trait PairsExt {
|
||||
/// Peek the next sibling but only if it matches a given rule: used for things
|
||||
/// with optional modifiers following
|
||||
fn next_if_rule(&mut self, rule: PestRule) -> Option<Pair>;
|
||||
|
||||
Reference in New Issue
Block a user