New grammar, sort of working

This commit is contained in:
2023-08-02 21:56:26 -05:00
parent ba4f98e2a5
commit e8940feea7
5 changed files with 701 additions and 660 deletions
Generated
+85 -82
View File
@@ -83,25 +83,13 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
[[package]] [[package]]
name = "block-buffer" name = "block-buffer"
version = "0.7.3" version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [ dependencies = [
"block-padding",
"byte-tools",
"byteorder",
"generic-array", "generic-array",
] ]
[[package]]
name = "block-padding"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
dependencies = [
"byte-tools",
]
[[package]] [[package]]
name = "bstr" name = "bstr"
version = "0.2.17" version = "0.2.17"
@@ -117,12 +105,6 @@ version = "3.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
[[package]]
name = "byte-tools"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]] [[package]]
name = "bytemuck" name = "bytemuck"
version = "1.9.1" version = "1.9.1"
@@ -196,7 +178,7 @@ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.92",
] ]
[[package]] [[package]]
@@ -337,6 +319,25 @@ dependencies = [
"objc", "objc",
] ]
[[package]]
name = "cpufeatures"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
dependencies = [
"libc",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]] [[package]]
name = "cty" name = "cty"
version = "0.2.2" version = "0.2.2"
@@ -375,7 +376,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"strsim", "strsim",
"syn", "syn 1.0.92",
] ]
[[package]] [[package]]
@@ -386,16 +387,17 @@ checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"quote", "quote",
"syn", "syn 1.0.92",
] ]
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.8.1" version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [ dependencies = [
"generic-array", "block-buffer",
"crypto-common",
] ]
[[package]] [[package]]
@@ -419,12 +421,6 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
[[package]]
name = "fake-simd"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@@ -450,6 +446,7 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
name = "forge_core" name = "forge_core"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"lazy_static",
"pest", "pest",
"pest_derive", "pest_derive",
"vcore", "vcore",
@@ -466,11 +463,12 @@ dependencies = [
[[package]] [[package]]
name = "generic-array" name = "generic-array"
version = "0.12.4" version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [ dependencies = [
"typenum", "typenum",
"version_check",
] ]
[[package]] [[package]]
@@ -700,12 +698,6 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "maplit"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.5.0" version = "2.5.0"
@@ -798,7 +790,7 @@ checksum = "dd3dfb62b95873e3d7aa9a691905287992628e3c10cadce5ed88f15134e3b0ce"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.92",
] ]
[[package]] [[package]]
@@ -863,7 +855,7 @@ dependencies = [
"proc-macro-crate", "proc-macro-crate",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.92",
] ]
[[package]] [[package]]
@@ -931,7 +923,7 @@ dependencies = [
"proc-macro-crate", "proc-macro-crate",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.92",
] ]
[[package]] [[package]]
@@ -959,12 +951,6 @@ version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
[[package]]
name = "opaque-debug"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
[[package]] [[package]]
name = "os_str_bytes" name = "os_str_bytes"
version = "6.4.1" version = "6.4.1"
@@ -1004,18 +990,19 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]] [[package]]
name = "pest" name = "pest"
version = "2.1.3" version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" checksum = "0d2d1d55045829d65aad9d389139882ad623b33b904e7c9f1b10c5b8927298e5"
dependencies = [ dependencies = [
"thiserror",
"ucd-trie", "ucd-trie",
] ]
[[package]] [[package]]
name = "pest_derive" name = "pest_derive"
version = "2.1.0" version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" checksum = "5f94bca7e7a599d89dea5dfa309e217e7906c3c007fb9c3299c40b10d6a315d3"
dependencies = [ dependencies = [
"pest", "pest",
"pest_generator", "pest_generator",
@@ -1023,26 +1010,26 @@ dependencies = [
[[package]] [[package]]
name = "pest_generator" name = "pest_generator"
version = "2.1.3" version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" checksum = "99d490fe7e8556575ff6911e45567ab95e71617f43781e5c05490dc8d75c965c"
dependencies = [ dependencies = [
"pest", "pest",
"pest_meta", "pest_meta",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.27",
] ]
[[package]] [[package]]
name = "pest_meta" name = "pest_meta"
version = "2.1.3" version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" checksum = "2674c66ebb4b4d9036012091b537aae5878970d6999f81a265034d85b136b341"
dependencies = [ dependencies = [
"maplit", "once_cell",
"pest", "pest",
"sha-1", "sha2",
] ]
[[package]] [[package]]
@@ -1096,7 +1083,7 @@ dependencies = [
"proc-macro-error-attr", "proc-macro-error-attr",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.92",
"version_check", "version_check",
] ]
@@ -1113,11 +1100,11 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.37" version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
dependencies = [ dependencies = [
"unicode-xid", "unicode-ident",
] ]
[[package]] [[package]]
@@ -1128,9 +1115,9 @@ checksum = "9145ac0af1d93c638c98c40cf7d25665f427b2a44ad0a99b1dccf3e2f25bb987"
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.18" version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@@ -1273,7 +1260,7 @@ checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.92",
] ]
[[package]] [[package]]
@@ -1288,15 +1275,14 @@ dependencies = [
] ]
[[package]] [[package]]
name = "sha-1" name = "sha2"
version = "0.8.2" version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
dependencies = [ dependencies = [
"block-buffer", "cfg-if 1.0.0",
"cpufeatures",
"digest", "digest",
"fake-simd",
"opaque-debug",
] ]
[[package]] [[package]]
@@ -1360,6 +1346,17 @@ dependencies = [
"unicode-xid", "unicode-xid",
] ]
[[package]]
name = "syn"
version = "2.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]] [[package]]
name = "termcolor" name = "termcolor"
version = "1.1.3" version = "1.1.3"
@@ -1377,22 +1374,22 @@ checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d"
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.31" version = "1.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.31" version = "1.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.27",
] ]
[[package]] [[package]]
@@ -1412,9 +1409,9 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
[[package]] [[package]]
name = "ucd-trie" name = "ucd-trie"
version = "0.1.3" version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
[[package]] [[package]]
name = "ultraviolet" name = "ultraviolet"
@@ -1425,6 +1422,12 @@ dependencies = [
"wide", "wide",
] ]
[[package]]
name = "unicode-ident"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
[[package]] [[package]]
name = "unicode-width" name = "unicode-width"
version = "0.1.9" version = "0.1.9"
@@ -1551,7 +1554,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.92",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@@ -1585,7 +1588,7 @@ checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.92",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
+92 -42
View File
@@ -12,14 +12,14 @@ pub enum Declaration {
#[derive(PartialEq, Clone, Debug, Default)] #[derive(PartialEq, Clone, Debug, Default)]
pub struct Varinfo { pub struct Varinfo {
pub typename: Option<String>, pub typename: Option<String>,
pub size: Option<Node>, pub size: Option<Expr>,
} }
#[derive(PartialEq, Clone, Debug)] #[derive(PartialEq, Clone, Debug)]
pub struct Global { pub struct Global {
pub name: String, pub name: String,
pub typename: Option<String>, pub typename: Option<String>,
pub size: Option<Node>, pub size: Option<Expr>,
} }
#[derive(PartialEq, Clone, Debug)] #[derive(PartialEq, Clone, Debug)]
@@ -32,13 +32,13 @@ pub struct Struct {
pub struct Member { pub struct Member {
pub name: String, pub name: String,
pub typename: Option<String>, pub typename: Option<String>,
pub size: Option<Node>, pub size: Option<Expr>,
} }
#[derive(PartialEq, Clone, Debug)] #[derive(PartialEq, Clone, Debug)]
pub struct Const { pub struct Const {
pub name: String, pub name: String,
pub value: Option<Node>, pub value: Option<Expr>,
pub string: Option<String>, pub string: Option<String>,
} }
@@ -48,9 +48,6 @@ pub struct Block(pub Vec<Statement>);
#[derive(PartialEq, Clone, Debug)] #[derive(PartialEq, Clone, Debug)]
pub struct Function { pub struct Function {
pub name: String, pub name: String,
pub org: Option<i32>,
pub typename: Option<String>,
pub inline: bool,
pub args: Vec<Argname>, pub args: Vec<Argname>,
pub body: Block, pub body: Block,
} }
@@ -65,7 +62,7 @@ pub struct Argname {
pub enum Statement { pub enum Statement {
Return(Return), Return(Return),
Assignment(Assignment), Assignment(Assignment),
Call(Call), Expr(Expr),
VarDecl(VarDecl), VarDecl(VarDecl),
Conditional(Conditional), Conditional(Conditional),
WhileLoop(WhileLoop), WhileLoop(WhileLoop),
@@ -73,7 +70,7 @@ pub enum Statement {
} }
#[derive(PartialEq, Clone, Debug)] #[derive(PartialEq, Clone, Debug)]
pub struct Return(pub Option<Node>); pub struct Return(pub Option<Expr>);
#[derive(PartialEq, Clone, Debug)] #[derive(PartialEq, Clone, Debug)]
pub struct Assignment { pub struct Assignment {
@@ -81,12 +78,6 @@ pub struct Assignment {
pub rvalue: Rvalue, pub rvalue: Rvalue,
} }
#[derive(PartialEq, Clone, Debug)]
pub struct Call {
pub name: String,
pub args: Vec<Rvalue>,
}
#[derive(PartialEq, Clone, Debug)] #[derive(PartialEq, Clone, Debug)]
pub enum Lvalue { pub enum Lvalue {
ArrayRef(ArrayRef), ArrayRef(ArrayRef),
@@ -95,7 +86,7 @@ pub enum Lvalue {
#[derive(PartialEq, Clone, Debug)] #[derive(PartialEq, Clone, Debug)]
pub enum Rvalue { pub enum Rvalue {
Expr(Node), Expr(Expr),
String(String), String(String),
} }
@@ -103,26 +94,26 @@ pub enum Rvalue {
pub struct VarDecl { pub struct VarDecl {
pub name: String, pub name: String,
pub typename: Option<String>, pub typename: Option<String>,
pub size: Option<Node>, pub size: Option<Expr>,
pub initial: Option<Node>, pub initial: Option<Expr>,
} }
#[derive(PartialEq, Clone, Debug)] #[derive(PartialEq, Clone, Debug)]
pub struct Conditional { pub struct Conditional {
pub condition: Node, pub condition: Expr,
pub body: Block, pub body: Block,
pub alternative: Option<Block>, pub alternative: Option<Block>,
} }
#[derive(PartialEq, Clone, Debug)] #[derive(PartialEq, Clone, Debug)]
pub struct WhileLoop { pub struct WhileLoop {
pub condition: Node, pub condition: Expr,
pub body: Block, pub body: Block,
} }
#[derive(PartialEq, Clone, Debug)] #[derive(PartialEq, Clone, Debug)]
pub struct RepeatLoop { pub struct RepeatLoop {
pub count: Node, pub count: Expr,
pub name: Option<String>, pub name: Option<String>,
pub body: Block, pub body: Block,
} }
@@ -154,55 +145,114 @@ pub enum Operator {
pub enum Prefix { pub enum Prefix {
Neg, Neg,
Not, Not,
Address
}
#[derive(Debug, PartialEq, Clone)]
pub enum Suffix {
Subscript(Expr),
Arglist(Vec<Rvalue>),
Member(String),
} }
#[derive(PartialEq, Clone, Debug)] #[derive(PartialEq, Clone, Debug)]
pub enum Node { pub struct Expr {
Number(i32), pub lhs: Val,
Call(Call), pub op: Option<Operator>,
ArrayRef(ArrayRef), pub rhs: Option<BoxExpr>,
Name(String),
Address(String),
Expr(BoxNode, Operator, BoxNode),
Prefix(Prefix, BoxNode),
} }
impl From<i32> for Node { #[derive(PartialEq, Clone, Debug)]
pub enum Val {
Number(i32, Vec<Prefix>, Vec<Suffix>),
Name(String, Vec<Prefix>, Vec<Suffix>),
Expr(BoxExpr, Vec<Prefix>, Vec<Suffix>),
}
impl Val {
pub fn is_simple(&self) -> bool {
if let Self::Expr(expr, pre, suf) = &self {
pre.is_empty() && suf.is_empty() && expr.0.op.is_none()
} else {
false
}
}
pub fn inner_expr(self) -> Option<Expr> {
if let Self::Expr(expr, _, _) = self {
Some(expr.into())
} else { None }
}
}
impl From<i32> for Val {
fn from(val: i32) -> Self { fn from(val: i32) -> Self {
Self::Number(val) Self::Number(val, vec![], vec![])
} }
} }
impl From<&str> for Node { impl From<&str> for Val {
fn from(s: &str) -> Self { fn from(s: &str) -> Self {
Self::Name(String::from(s)) Self::Name(String::from(s), vec![], vec![])
}
}
impl From<Expr> for Val {
fn from(value: Expr) -> Self {
Self::Expr(value.into(), vec![], vec![])
}
}
impl From<BoxExpr> for Val {
fn from(value: BoxExpr) -> Self {
Self::Expr(value, vec![], vec![])
} }
} }
#[repr(transparent)] #[repr(transparent)]
#[derive(PartialEq, Clone, Debug)] #[derive(PartialEq, Clone, Debug)]
pub struct BoxNode(pub Box<Node>); pub struct BoxExpr(pub Box<Expr>);
impl From<i32> for BoxNode { impl From<Val> for Expr {
fn from(value: Val) -> Self {
Self {
lhs: value,
op: None,
rhs: None
}
}
}
impl From<i32> for BoxExpr {
fn from(val: i32) -> Self { fn from(val: i32) -> Self {
BoxNode(Box::from(Node::Number(val))) BoxExpr(Box::from(Expr::from(Val::from(val))))
} }
} }
impl From<Node> for BoxNode { impl From<Expr> for BoxExpr {
fn from(val: Node) -> Self { fn from(val: Expr) -> Self {
BoxNode(Box::from(val)) BoxExpr(Box::from(val))
} }
} }
impl From<BoxNode> for Node { impl From<BoxExpr> for Expr {
fn from(val: BoxNode) -> Self { fn from(val: BoxExpr) -> Self {
*(val.0) *(val.0)
} }
} }
impl From<i32> for Expr {
fn from(value: i32) -> Self {
Self {
lhs: Val::Number(value, vec![], vec![]),
op: None,
rhs: None
}
}
}
#[derive(PartialEq, Clone, Debug)] #[derive(PartialEq, Clone, Debug)]
pub struct ArrayRef { pub struct ArrayRef {
pub name: String, pub name: String,
pub subscript: BoxNode, pub subscript: BoxExpr,
} }
+222 -233
View File
@@ -193,13 +193,6 @@ impl Compilable for Declaration {
impl Compilable for Function { impl Compilable for Function {
fn process(self, state: &mut State, _: Option<&mut Signature>) -> Result<(), CompileError> { fn process(self, state: &mut State, _: Option<&mut Signature>) -> Result<(), CompileError> {
if self.typename.is_some() {
todo!("Structs are not yet supported")
}
if self.org.is_some() || self.inline {
todo!("Attributes are not yet supported")
}
// The signature for this function, which will eventually get added to the state // The signature for this function, which will eventually get added to the state
let mut sig = Signature { let mut sig = Signature {
label: state.gensym(), label: state.gensym(),
@@ -227,12 +220,13 @@ impl Compilable for Function {
match stmt { match stmt {
Statement::Return(_) => {} Statement::Return(_) => {}
Statement::Assignment(assign) => assign.process(state, Some(&mut sig))?, Statement::Assignment(assign) => assign.process(state, Some(&mut sig))?,
Statement::Call(call) => { Statement::Expr(expr) => {
call.process(state, Some(&mut sig))?; todo!();
// Every call leaves a single-word return value on the stack. In an rvalue this // expr.process(state, Some(&mut sig))?;
// is useful but in a statement it's garbage (because nothing else is about to // // Every expr leaves a single-word return value on the stack. In an rvalue this
// pick it up) so, drop it: // // is useful but in a statement it's garbage (because nothing else is about to
sig.emit("pop") // // pick it up) so, drop it:
// sig.emit("pop")
} }
Statement::VarDecl(vardecl) => vardecl.process(state, Some(&mut sig))?, Statement::VarDecl(vardecl) => vardecl.process(state, Some(&mut sig))?,
Statement::Conditional(_) | Statement::WhileLoop(_) | Statement::RepeatLoop(_) => { Statement::Conditional(_) | Statement::WhileLoop(_) | Statement::RepeatLoop(_) => {
@@ -268,13 +262,13 @@ impl Compilable for Assignment {
// For a normal expr, eval and leave on the stack; for a string literal, add it to // For a normal expr, eval and leave on the stack; for a string literal, add it to
// the str table and push the label's address // the str table and push the label's address
match rvalue { // match rvalue {
Rvalue::Expr(rvalue) => rvalue.process(state, Some(sig))?, // Rvalue::Expr(rvalue) => rvalue.process(state, Some(sig))?,
Rvalue::String(string) => { // Rvalue::String(string) => {
let label = state.add_string(&string); // let label = state.add_string(&string);
sig.emit_arg("push", label); // sig.emit_arg("push", label);
} // }
} // }
// Then process the lvalue and storew // Then process the lvalue and storew
lvalue.process(state, Some(sig))?; lvalue.process(state, Some(sig))?;
@@ -285,36 +279,27 @@ impl Compilable for Assignment {
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
impl Compilable for Call {
fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> {
// todo arity check
todo!()
}
}
///////////////////////////////////////////////////////////
impl Compilable for VarDecl { impl Compilable for VarDecl {
fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> { fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> {
let mut sig = sig.expect("Var declaration outside function"); todo!();
if self.typename.is_some() || self.size.is_some() { // let mut sig = sig.expect("Var declaration outside function");
todo!("Structs and arrays are not yet supported") // if self.typename.is_some() || self.size.is_some() {
} // todo!("Structs and arrays are not yet supported")
if let Some(initial) = self.initial { // }
// If it's got an initial value, we have to compile that before we add // if let Some(initial) = self.initial {
// the name to scope, or else UB will ensue if it refers to itself: // // If it's got an initial value, we have to compile that before we add
initial.process(state, Some(sig))?; // // the name to scope, or else UB will ensue if it refers to itself:
// But then add it to scope and assign: // initial.process(state, Some(sig))?;
sig.add_local(&self.name)?; // // But then add it to scope and assign:
// We'll just whip up an lvalue real quick... // sig.add_local(&self.name)?;
Lvalue::Name(self.name).process(state, Some(sig))?; // // We'll just whip up an lvalue real quick...
sig.emit("storew"); // And store the initial value there // Lvalue::Name(self.name).process(state, Some(sig))?;
} else { // sig.emit("storew"); // And store the initial value there
// Otherwise, just add it to scope and leave garbage in there: // } else {
sig.add_local(&self.name)?; // // Otherwise, just add it to scope and leave garbage in there:
} // sig.add_local(&self.name)?;
Ok(()) // }
// Ok(())
} }
} }
@@ -363,119 +348,120 @@ impl Compilable for Lvalue {
/// Evaluate an expression in the context of a local scope. The runtime brother to eval_const. /// Evaluate an expression in the context of a local scope. The runtime brother to eval_const.
/// This recursively evaluates a Node and leaves its value on the stack. /// This recursively evaluates a Node and leaves its value on the stack.
impl Compilable for Node { impl Compilable for Expr {
fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> { fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> {
let mut sig = sig.expect("Non-const expression outside a function"); todo!();
let global_scope = &state.global_scope; // let mut sig = sig.expect("Non-const expression outside a function");
// let global_scope = &state.global_scope;
// First, a sanity check: try and eval_const this. If it's something incredibly basic //
// that just becomes an i32, then we don't need to do anything else: // // First, a sanity check: try and eval_const this. If it's something incredibly basic
if let Ok(val) = eval_const(self.clone(), &state.global_scope) { // // that just becomes an i32, then we don't need to do anything else:
sig.emit_arg("push", val); // if let Ok(val) = eval_const(self.clone(), &state.global_scope) {
return Ok(()); // sig.emit_arg("push", val);
} // return Ok(());
// }
// Okay, looks like we need something that's in scope. Let's recurse: //
match self { // // Okay, looks like we need something that's in scope. Let's recurse:
Node::Number(n) => { // match self.val {
// Numbers are just pushed as literals // Val::Number(n) => {
sig.body.push(format!("push {}", n)); // // Numbers are just pushed as literals
Ok(()) // sig.body.push(format!("push {}", n));
} // Ok(())
Node::Call(_) | Node::ArrayRef(_) | Node::Address(_) => todo!(), // }
Node::Name(name) => match lookup(&name, global_scope, &sig.local_scope) { // Val::Name(name) => match lookup(&name, global_scope, &sig.local_scope) {
// Names are treated differently depending on what they are // // Names are treated differently depending on what they are
Some(Variable::Literal(val)) => { // Some(Variable::Literal(val)) => {
// Names of constants are just that number // // Names of constants are just that number
sig.emit_arg("push", *val); // sig.emit_arg("push", *val);
Ok(()) // Ok(())
} // }
Some(Variable::IndirectLabel(label)) => { // Some(Variable::IndirectLabel(label)) => {
// Names pointing at labels are loaded (rvalue; for lvalues they aren't) // // Names pointing at labels are loaded (rvalue; for lvalues they aren't)
// Indirect labels are the address of where the value is stored (a var, .db) // // Indirect labels are the address of where the value is stored (a var, .db)
sig.emit_arg("loadw", label.clone()); // sig.emit_arg("loadw", label.clone());
Ok(()) // Ok(())
} // }
Some(Variable::DirectLabel(label)) => { // Some(Variable::DirectLabel(label)) => {
// Direct labels are like functions, the label itself is the value, so just // // Direct labels are like functions, the label itself is the value, so just
// push it: // // push it:
sig.emit_arg("push", label.clone()); // sig.emit_arg("push", label.clone());
Ok(()) // Ok(())
} // }
Some(Variable::Local(offset)) => { // Some(Variable::Local(offset)) => {
// Names of locals are added from the frame pointer // // Names of locals are added from the frame pointer
let offset = *offset; // let offset = *offset;
sig.emit("loadw frame"); // sig.emit("loadw frame");
if offset > 0 { // if offset > 0 {
sig.emit_arg("add", offset); // sig.emit_arg("add", offset);
sig.emit("loadw"); // sig.emit("loadw");
} // }
Ok(()) // Ok(())
} // }
None => Err(CompileError(0, 0, format!("Unknown name {}", name))), // None => Err(CompileError(0, 0, format!("Unknown name {}", name))),
}, // },
Node::Expr(lhs, op, rhs) => { // Val::Expr(node) => {
// Recurse on expressions, handling operators // todo!();
lhs.0.process(state, Some(&mut sig))?; // // // Recurse on expressions, handling operators
rhs.0.process(state, Some(&mut sig))?; // // lhs.0.process(state, Some(&mut sig))?;
match op { // // rhs.0.process(state, Some(&mut sig))?;
// Basic math // // match op {
Operator::Add => sig.emit("add"), // // // Basic math
Operator::Sub => sig.emit("sub"), // // Operator::Add => sig.emit("add"),
Operator::Mul => sig.emit("mul"), // // Operator::Sub => sig.emit("sub"),
Operator::Div => sig.emit("div"), // // Operator::Mul => sig.emit("mul"),
Operator::Mod => sig.emit("mod"), // // Operator::Div => sig.emit("div"),
Operator::And => { // // Operator::Mod => sig.emit("mod"),
// Vulcan "and" is bitwise, so we need to flag-ify both args to make it logical // // Operator::And => {
sig.emit("gt 0"); // // // Vulcan "and" is bitwise, so we need to flag-ify both args to make it logical
sig.emit("swap"); // // sig.emit("gt 0");
sig.emit("gt 0"); // // sig.emit("swap");
sig.emit("and"); // // sig.emit("gt 0");
} // // sig.emit("and");
Operator::Or => { // // }
// Same as and, flag-ify both args // // Operator::Or => {
sig.emit("gt 0"); // // // Same as and, flag-ify both args
sig.emit("swap"); // // sig.emit("gt 0");
sig.emit("gt 0"); // // sig.emit("swap");
sig.emit("or"); // // sig.emit("gt 0");
} // // sig.emit("or");
Operator::BitAnd => sig.emit("and"), // // }
Operator::BitOr => sig.emit("or"), // // Operator::BitAnd => sig.emit("and"),
Operator::Xor => sig.emit("xor"), // // Operator::BitOr => sig.emit("or"),
Operator::Lt => sig.emit("alt"), // // Operator::Xor => sig.emit("xor"),
Operator::Le => { // // Operator::Lt => sig.emit("alt"),
// LE and GE are the inverses of GT and LT (arithmetic versions) // // Operator::Le => {
sig.emit("agt"); // // // LE and GE are the inverses of GT and LT (arithmetic versions)
sig.emit("not"); // // sig.emit("agt");
} // // sig.emit("not");
Operator::Gt => sig.emit("agt"), // // }
Operator::Ge => { // // Operator::Gt => sig.emit("agt"),
sig.emit("alt"); // // Operator::Ge => {
sig.emit("not"); // // sig.emit("alt");
} // // sig.emit("not");
Operator::Eq => { // // }
sig.emit("xor"); // // Operator::Eq => {
sig.emit("not"); // // sig.emit("xor");
} // // sig.emit("not");
Operator::Ne => sig.emit("xor"), // // }
Operator::Lshift => sig.emit("lshift"), // // Operator::Ne => sig.emit("xor"),
Operator::Rshift => sig.emit("arshift"), // // Operator::Lshift => sig.emit("lshift"),
} // // Operator::Rshift => sig.emit("arshift"),
Ok(()) // // }
} // // Ok(())
Node::Prefix(prefix, node) => { // }
node.0.process(state, Some(sig))?; // // Node::Prefix(prefix, node) => {
match prefix { // // node.0.process(state, Some(sig))?;
Prefix::Neg => { // // match prefix {
// To arithmetically negate something, invert and increment (2s complement) // // Prefix::Neg => {
sig.emit("xor -1"); // // // To arithmetically negate something, invert and increment (2s complement)
sig.emit("add 1"); // // sig.emit("xor -1");
} // // sig.emit("add 1");
Prefix::Not => sig.emit("not"), // // }
} // // Prefix::Not => sig.emit("not"),
Ok(()) // // }
} // // Ok(())
} // // }
// }
} }
} }
@@ -494,17 +480,18 @@ impl Compilable for Global {
impl Compilable for Const { impl Compilable for Const {
fn process(self, state: &mut State, _: Option<&mut Signature>) -> Result<(), CompileError> { fn process(self, state: &mut State, _: Option<&mut Signature>) -> Result<(), CompileError> {
let var = if self.string.is_some() { todo!()
// If it's a string, add it to the string table // let var = if self.string.is_some() {
Variable::DirectLabel(state.add_string(&self.string.unwrap())) // // If it's a string, add it to the string table
} else if let Some(expr) = self.value { // Variable::DirectLabel(state.add_string(&self.string.unwrap()))
// Otherwise eval_const it // } else if let Some(expr) = self.value {
Variable::Literal(eval_const(expr, &state.global_scope)?) // // Otherwise eval_const it
} else { // Variable::Literal(eval_const(expr, &state.global_scope)?)
unreachable!() // } else {
}; // unreachable!()
// Add it to the global namespace // };
state.add_global(&self.name, |_| var.clone()) // // Add it to the global namespace
// state.add_global(&self.name, |_| var.clone())
} }
} }
@@ -519,61 +506,63 @@ fn to_flag(val: bool) -> i32 {
} }
/// Evaluate a node in a static context, for const definitions and array sizes, that sort of thing. /// Evaluate a node in a static context, for const definitions and array sizes, that sort of thing.
pub fn eval_const(expr: Node, scope: &Scope) -> Result<i32, CompileError> { pub fn eval_const(expr: Expr, scope: &Scope) -> Result<i32, CompileError> {
match expr { todo!()
Node::Number(n) => Ok(n), // match expr.lhs {
Node::Address(_) | Node::ArrayRef(_) | Node::Call(_) => Err(CompileError( // Val::Number(n) => Ok(n),
0, // // Node::Address(_) | Node::ArrayRef(_) | Node::Call(_) => Err(CompileError(
0, // // 0,
String::from("Constants must be statically defined"), // // 0,
)), // // String::from("Constants must be statically defined"),
// // )),
Node::Name(n) => { //
if let Some(Variable::Literal(val)) = scope.get(&n) { // Val::Name(n) => {
Ok(*val) // if let Some(Variable::Literal(val)) = scope.get(&n) {
} else { // Ok(*val)
Err(CompileError(0, 0, format!("Unknown const {}", n))) // } else {
} // Err(CompileError(0, 0, format!("Unknown const {}", n)))
} // }
// }
Node::Expr(lhs, op, rhs) => { //
let lhs = eval_const(lhs.into(), scope)?; // Val::Expr(node) => {
let rhs = eval_const(rhs.into(), scope)?; // todo!()
match op { // // let lhs = eval_const(lhs.into(), scope)?;
Operator::Add => Ok(lhs + rhs), // // let rhs = eval_const(rhs.into(), scope)?;
Operator::Sub => Ok(lhs - rhs), // // match op {
Operator::Mul => Ok(lhs * rhs), // // Operator::Add => Ok(lhs + rhs),
Operator::Div => Ok(lhs / rhs), // // Operator::Sub => Ok(lhs - rhs),
Operator::Mod => Ok(lhs % rhs), // // Operator::Mul => Ok(lhs * rhs),
Operator::And => Ok(to_flag(lhs != 0 && rhs != 0)), // // Operator::Div => Ok(lhs / rhs),
Operator::Or => Ok(to_flag(lhs != 0 || rhs != 0)), // // Operator::Mod => Ok(lhs % rhs),
Operator::BitAnd => Ok(lhs & rhs), // // Operator::And => Ok(to_flag(lhs != 0 && rhs != 0)),
Operator::BitOr => Ok(lhs | rhs), // // Operator::Or => Ok(to_flag(lhs != 0 || rhs != 0)),
Operator::Xor => Ok(lhs ^ rhs), // // Operator::BitAnd => Ok(lhs & rhs),
Operator::Lt => Ok(to_flag(lhs < rhs)), // // Operator::BitOr => Ok(lhs | rhs),
Operator::Le => Ok(to_flag(lhs <= rhs)), // // Operator::Xor => Ok(lhs ^ rhs),
Operator::Gt => Ok(to_flag(lhs > rhs)), // // Operator::Lt => Ok(to_flag(lhs < rhs)),
Operator::Ge => Ok(to_flag(lhs >= rhs)), // // Operator::Le => Ok(to_flag(lhs <= rhs)),
Operator::Eq => Ok(to_flag(lhs == rhs)), // // Operator::Gt => Ok(to_flag(lhs > rhs)),
Operator::Ne => Ok(to_flag(lhs != rhs)), // // Operator::Ge => Ok(to_flag(lhs >= rhs)),
Operator::Lshift => Ok(lhs << rhs), // // Operator::Eq => Ok(to_flag(lhs == rhs)),
Operator::Rshift => Ok(lhs >> rhs), // // Operator::Ne => Ok(to_flag(lhs != rhs)),
} // // Operator::Lshift => Ok(lhs << rhs),
} // // Operator::Rshift => Ok(lhs >> rhs),
Node::Prefix(p, child) => { // // }
let val = eval_const(child.into(), scope)?; // }
match p { // // Node::Prefix(p, child) => {
Prefix::Neg => Ok(-val), // // let val = eval_const(child.into(), scope)?;
Prefix::Not => { // // match p {
if val == 0 { // // Prefix::Neg => Ok(-val),
Ok(1) // // Prefix::Not => {
} else { // // if val == 0 {
Ok(0) // // Ok(1)
} // // } else {
} // // Ok(0)
} // // }
} // // }
} // // }
// // }
// }
} }
#[cfg(test)] #[cfg(test)]
@@ -584,12 +573,12 @@ mod test {
#[test] #[test]
fn test_eval_const() { fn test_eval_const() {
let empty_scope = Scope::new(); let empty_scope = Scope::new();
let to_node = |s| Node::parse(s).unwrap(); let to_expr = |s| Expr::parse(s).unwrap();
// Basic arithmetic // Basic arithmetic
assert_eq!(eval_const(to_node("2 * 3 + 4"), &empty_scope), Ok(10)); assert_eq!(eval_const(to_expr("2 * 3 + 4"), &empty_scope), Ok(10));
assert_eq!(eval_const(to_node("1 + -2"), &empty_scope), Ok(-1)); assert_eq!(eval_const(to_expr("1 + -2"), &empty_scope), Ok(-1));
assert_eq!(eval_const(to_node("1 << 3"), &empty_scope), Ok(8)); assert_eq!(eval_const(to_expr("1 << 3"), &empty_scope), Ok(8));
// Names // Names
let scope: Scope = [ let scope: Scope = [
@@ -597,12 +586,12 @@ mod test {
("bar".into(), Variable::Literal(5)), ("bar".into(), Variable::Literal(5)),
] ]
.into(); .into();
assert_eq!(eval_const(to_node("foo + 5"), &scope), Ok(15)); assert_eq!(eval_const(to_expr("foo + 5"), &scope), Ok(15));
assert_eq!(eval_const(to_node("bar * foo"), &scope), Ok(50)); assert_eq!(eval_const(to_expr("bar * foo"), &scope), Ok(50));
// Error // Error
assert_eq!( assert_eq!(
eval_const(to_node("nope"), &scope), eval_const(to_expr("nope"), &scope),
Err(CompileError(0, 0, String::from("Unknown const nope"))) Err(CompileError(0, 0, String::from("Unknown const nope")))
); );
} }
+239 -229
View File
@@ -2,7 +2,7 @@ use pest::pratt_parser::PrattParser;
use pest::Parser; use pest::Parser;
#[derive(Parser)] #[derive(Parser)]
#[grammar = "forge.pest"] #[grammar = "new.pest"]
struct ForgeParser; struct ForgeParser;
lazy_static::lazy_static! { lazy_static::lazy_static! {
@@ -30,6 +30,7 @@ use crate::ast::*;
use pest::error::{Error, LineColLocation}; use pest::error::{Error, LineColLocation};
use std::iter::Peekable; use std::iter::Peekable;
use std::str::FromStr; use std::str::FromStr;
use crate::ast::Suffix::{Arglist, Subscript};
pub(crate) type Pair<'a> = pest::iterators::Pair<'a, Rule>; pub(crate) type Pair<'a> = pest::iterators::Pair<'a, Rule>;
pub(crate) type Pairs<'i, R = Rule> = pest::iterators::Pairs<'i, R>; pub(crate) type Pairs<'i, R = Rule> = pest::iterators::Pairs<'i, R>;
@@ -179,7 +180,7 @@ impl AstNode for Varinfo {
.map(|t| String::from(t.first().as_str())); .map(|t| String::from(t.first().as_str()));
let size = children let size = children
.next_if_rule(Rule::size) .next_if_rule(Rule::size)
.map(|s| Node::from_pair(s.first())); .map(|s| Expr::from_pair(s.first()));
Self { typename, size } Self { typename, size }
} }
} }
@@ -246,7 +247,7 @@ impl AstNode for Const {
Rule::expr => Const { Rule::expr => Const {
name, name,
string: None, string: None,
value: Some(Node::from_pair(value)), value: Some(Expr::from_pair(value)),
}, },
_ => unreachable!(), _ => unreachable!(),
} }
@@ -260,20 +261,6 @@ impl AstNode for Function {
fn from_pair(pair: Pair<'_>) -> Self { fn from_pair(pair: Pair<'_>) -> Self {
let mut inner = pair.into_inner().peekable(); let mut inner = pair.into_inner().peekable();
let name = String::from(inner.next().unwrap().as_str()); let name = String::from(inner.next().unwrap().as_str());
let mut inline = false;
let mut org = None;
let mut typename = None;
if let Some(annotations) = inner.next_if_rule(Rule::annotations) {
for annotation in annotations.into_inner() {
let annotation = annotation.first();
match annotation.as_rule() {
Rule::inline_annotation => inline = true,
Rule::org_annotation => org = Some(annotation.first().into_number()),
Rule::type_annotation => typename = Some(annotation.first_as_string()),
_ => unreachable!(),
}
}
}
let args: Vec<_> = inner let args: Vec<_> = inner
.next() .next()
.unwrap() .unwrap()
@@ -285,9 +272,6 @@ impl AstNode for Function {
Self { Self {
name, name,
org,
typename,
inline,
args, args,
body, body,
} }
@@ -313,7 +297,7 @@ impl AstNode for Statement {
match pair.as_rule() { match pair.as_rule() {
Rule::return_stmt => Self::Return(Return::from_pair(pair)), Rule::return_stmt => Self::Return(Return::from_pair(pair)),
Rule::assignment => Self::Assignment(Assignment::from_pair(pair)), Rule::assignment => Self::Assignment(Assignment::from_pair(pair)),
Rule::call => Self::Call(Call::from_pair(pair)), Rule::expr => Self::Expr(Expr::from_pair(pair)),
Rule::var_decl => Self::VarDecl(VarDecl::from_pair(pair)), Rule::var_decl => Self::VarDecl(VarDecl::from_pair(pair)),
Rule::conditional => Self::Conditional(Conditional::from_pair(pair)), Rule::conditional => Self::Conditional(Conditional::from_pair(pair)),
Rule::while_loop => Self::WhileLoop(WhileLoop::from_pair(pair)), Rule::while_loop => Self::WhileLoop(WhileLoop::from_pair(pair)),
@@ -330,7 +314,7 @@ impl AstNode for Return {
fn from_pair(pair: Pair) -> Self { fn from_pair(pair: Pair) -> Self {
pair.into_inner() pair.into_inner()
.next() .next()
.map_or(Self(None), |expr| Self(Some(Node::from_pair(expr)))) .map_or(Self(None), |expr| Self(Some(Expr::from_pair(expr))))
} }
} }
@@ -342,7 +326,7 @@ impl AstNode for Assignment {
let mut pairs = pair.into_inner(); let mut pairs = pair.into_inner();
let lvalue_pair = pairs.next().unwrap().first(); let lvalue_pair = pairs.next().unwrap().first();
let lvalue = match lvalue_pair.as_rule() { let lvalue = match lvalue_pair.as_rule() {
Rule::arrayref => Lvalue::ArrayRef(ArrayRef::from_pair(lvalue_pair)), //Rule::arrayref => Lvalue::ArrayRef(ArrayRef::from_pair(lvalue_pair)),
Rule::name => Lvalue::Name(String::from(lvalue_pair.as_str())), Rule::name => Lvalue::Name(String::from(lvalue_pair.as_str())),
_ => unreachable!(), _ => unreachable!(),
}; };
@@ -360,7 +344,7 @@ impl AstNode for Rvalue {
let pair = pair.first(); let pair = pair.first();
match pair.as_rule() { match pair.as_rule() {
Rule::string => Self::String(pair.into_quoted_string()), Rule::string => Self::String(pair.into_quoted_string()),
Rule::expr => Self::Expr(Node::from_pair(pair)), Rule::expr => Self::Expr(Expr::from_pair(pair)),
_ => unreachable!(), _ => unreachable!(),
} }
} }
@@ -368,26 +352,13 @@ impl AstNode for Rvalue {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
impl AstNode for Call {
const RULE: Rule = Rule::call;
fn from_pair(pair: Pair) -> Self {
let mut inner = pair.into_inner();
let name = String::from(inner.next().unwrap().as_str());
let arg_pairs = inner.next().unwrap().into_inner();
let args: Vec<Rvalue> = arg_pairs.map(Rvalue::from_pair).collect();
Self { name, args }
}
}
///////////////////////////////////////////////////////////////////////////////////////////
impl AstNode for VarDecl { impl AstNode for VarDecl {
const RULE: Rule = Rule::var_decl; const RULE: Rule = Rule::var_decl;
fn from_pair(pair: Pair) -> Self { fn from_pair(pair: Pair) -> Self {
let mut inner = pair.into_inner(); let mut inner = pair.into_inner();
let name = String::from(inner.next().unwrap().as_str()); let name = String::from(inner.next().unwrap().as_str());
let Varinfo { typename, size } = Varinfo::from_pair(inner.next().unwrap()); let Varinfo { typename, size } = Varinfo::from_pair(inner.next().unwrap());
let initial = inner.next().map(Node::from_pair); let initial = inner.next().map(Expr::from_pair);
Self { Self {
name, name,
typename, typename,
@@ -413,7 +384,7 @@ impl AstNode for Conditional {
const RULE: Rule = Rule::conditional; const RULE: Rule = Rule::conditional;
fn from_pair(pair: Pair) -> Self { fn from_pair(pair: Pair) -> Self {
let mut inner = pair.into_inner(); let mut inner = pair.into_inner();
let condition = Node::from_pair(inner.next().unwrap()); let condition = Expr::from_pair(inner.next().unwrap());
let body = Block::from_pair(inner.next().unwrap()); let body = Block::from_pair(inner.next().unwrap());
let alternative = inner.next().map(Block::from_pair); let alternative = inner.next().map(Block::from_pair);
Self { Self {
@@ -431,7 +402,7 @@ impl AstNode for WhileLoop {
fn from_pair(pair: Pair) -> Self { fn from_pair(pair: Pair) -> Self {
let mut inner = pair.into_inner(); let mut inner = pair.into_inner();
Self { Self {
condition: Node::from_pair(inner.next().unwrap()), condition: Expr::from_pair(inner.next().unwrap()),
body: Block::from_pair(inner.next().unwrap()), body: Block::from_pair(inner.next().unwrap()),
} }
} }
@@ -443,7 +414,7 @@ impl AstNode for RepeatLoop {
const RULE: Rule = Rule::repeat_loop; const RULE: Rule = Rule::repeat_loop;
fn from_pair(pair: Pair) -> Self { fn from_pair(pair: Pair) -> Self {
let mut inner = pair.into_inner().peekable(); let mut inner = pair.into_inner().peekable();
let count = Node::from_pair(inner.next().unwrap()); let count = Expr::from_pair(inner.next().unwrap());
let name = inner let name = inner
.next_if_rule(Rule::name) .next_if_rule(Rule::name)
.map(|p| String::from(p.as_str())); .map(|p| String::from(p.as_str()));
@@ -454,29 +425,28 @@ impl AstNode for RepeatLoop {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
impl AstNode for Node { impl AstNode for Expr {
const RULE: Rule = Rule::expr; // Also used for vals / terms / the whole tree const RULE: Rule = Rule::expr;
fn from_pair(pair: Pair) -> Self { fn from_pair(pair: Pair) -> Self {
PRATT_PARSER PRATT_PARSER
.map_primary(|val| { .map_primary(|val| {
let primary = val.first(); Expr {
match primary.as_rule() { lhs: Val::from_pair(val),
Rule::number => Node::Number(primary.into_number()), op: None,
Rule::name => Node::Name(String::from(primary.as_str())), rhs: None
Rule::call => Node::Call(Call::from_pair(primary)),
Rule::arrayref => Node::ArrayRef(ArrayRef::from_pair(primary)),
Rule::address => Node::Address(primary.first_as_string()),
Rule::expr => Node::from_pair(primary),
rule => unreachable!("Expr::parse expected atom, found {:?}", rule),
} }
}) })
.map_prefix(|op, rhs| Node::Prefix(Prefix::from_pair(op), rhs.into())) .map_infix(|lhs, op, rhs|
.map_infix(|lhs, op, rhs| Node::Expr(lhs.into(), Operator::from_pair(op), rhs.into())) Expr {
lhs: Val::from(lhs),
op: Some(Operator::from_pair(op)),
rhs: Some(rhs.into()),
})
.parse(pair.into_inner()) .parse(pair.into_inner())
} }
} }
impl Node { impl Expr {
pub(crate) fn parse(src: &str) -> Result<Self, ParseError> { pub(crate) fn parse(src: &str) -> Result<Self, ParseError> {
Self::from_str(src) Self::from_str(src)
} }
@@ -485,7 +455,8 @@ impl Node {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
impl AstNode for Operator { impl AstNode for Operator {
const RULE: Rule = Rule::operator; // also term_op const RULE: Rule = Rule::operator;
// also term_op
fn from_pair(pair: Pair) -> Self { fn from_pair(pair: Pair) -> Self {
match pair.as_str() { match pair.as_str() {
"+" => Self::Add, "+" => Self::Add,
@@ -518,6 +489,7 @@ impl AstNode for Prefix {
match pair.as_str() { match pair.as_str() {
"!" => Self::Not, "!" => Self::Not,
"-" => Self::Neg, "-" => Self::Neg,
"&" => Self::Address,
_ => unreachable!(), _ => unreachable!(),
} }
} }
@@ -525,16 +497,16 @@ impl AstNode for Prefix {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
impl AstNode for ArrayRef { impl AstNode for Suffix {
const RULE: Rule = Rule::arrayref; const RULE: Rule = Rule::suffix;
fn from_pair(pair: Pair) -> Self { fn from_pair(pair: Pair) -> Self {
let mut inner = pair.into_inner(); let first = pair.first();
let name = String::from(inner.next().unwrap().as_str()); match first.as_rule() {
let subscript = Node::from_pair(inner.next().unwrap().first()); Rule::subscript => Subscript(Expr::from_pair(first.first())),
Self { Rule::member => Self::Member(first.first_as_string()),
name, Rule::arglist => Arglist(first.into_inner().map(Rvalue::from_pair).collect()),
subscript: subscript.into(), _ => unreachable!()
} }
} }
} }
@@ -557,10 +529,61 @@ impl AstNode for Program {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
impl AstNode for Val {
const RULE: Rule = Rule::val;
fn from_pair(pair: Pair) -> Self {
let mut suffix = vec![];
let mut prefix = vec![];
let mut val = None;
for child in pair.into_inner() {
match child.as_rule() {
Rule::prefix => prefix.push(Prefix::from_pair(child)),
Rule::suffix => suffix.push(Suffix::from_pair(child)),
Rule::number | Rule::name | Rule::expr => val = Some(child),
_ => unreachable!()
}
}
let val = val.unwrap();
match val.as_rule() {
Rule::number => Self::Number(val.into_number(), prefix, suffix),
Rule::name => Self::Name(String::from(val.as_str()), prefix, suffix),
Rule::expr => Self::Expr(Expr::from_pair(val).into(), prefix, suffix),
_ => unreachable!()
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
#[test]
fn parse_vals() {
// Basic vals with no extras:
assert_eq!(Val::from_str("10"), Ok(10.into()));
assert_eq!(Val::from_str("blah"), Ok(Val::Name("blah".into(), vec![], vec![])));
// Simple prefix
assert_eq!(Val::from_str("-5"),
Ok(Val::Number(5, vec![Prefix::Neg], vec![])));
// Multiple prefixes
assert_eq!(Val::from_str("!&foo"),
Ok(Val::Name("foo".into(), vec![Prefix::Not, Prefix::Address], vec![])));
// Simple suffix
assert_eq!(Val::from_str("foo[10]"),
Ok(Val::Name("foo".into(), vec![], vec![Suffix::Subscript(10.into())])));
// Multi-suffix
assert_eq!(Val::from_str("foo[10].bar"),
Ok(Val::Name("foo".into(), vec![], vec![Suffix::Subscript(10.into()), Suffix::Member("bar".into())])));
}
#[test] #[test]
fn parse_globals() { fn parse_globals() {
assert_eq!( assert_eq!(
@@ -568,7 +591,7 @@ mod test {
Ok(Global { Ok(Global {
name: "foo".into(), name: "foo".into(),
typename: None, typename: None,
size: None size: None,
}) })
); );
assert_eq!( assert_eq!(
@@ -576,7 +599,7 @@ mod test {
Ok(Global { Ok(Global {
name: "foo".into(), name: "foo".into(),
typename: Some("Thing".into()), typename: Some("Thing".into()),
size: None size: None,
}) })
); );
assert_eq!( assert_eq!(
@@ -584,7 +607,7 @@ mod test {
Ok(Global { Ok(Global {
name: "foo".into(), name: "foo".into(),
typename: Some("Thing".into()), typename: Some("Thing".into()),
size: Some(Node::Number(10)) size: Some(10.into()),
}) })
); );
assert_eq!( assert_eq!(
@@ -592,7 +615,7 @@ mod test {
Ok(Global { Ok(Global {
name: "foo".into(), name: "foo".into(),
typename: None, typename: None,
size: Some(Node::Number(10)) size: Some(10.into()),
}) })
); );
} }
@@ -603,27 +626,24 @@ mod test {
Const::from_str("const a = 123;"), Const::from_str("const a = 123;"),
Ok(Const { Ok(Const {
name: "a".into(), name: "a".into(),
value: Some(Node::Number(123)), value: Some(123.into()),
string: None string: None,
}) })
); );
assert_eq!( assert_eq!(
Const::from_str("const a = 0xaa;"), Const::from_str("const a = 0xaa;"),
Ok(Const { Ok(Const {
name: "a".into(), name: "a".into(),
value: Some(Node::Number(0xaa)), value: Some(0xaa.into()),
string: None string: None,
}) })
); );
assert_eq!( assert_eq!(
Const::from_str("const a = -7;"), Const::from_str("const a = -7;"),
Ok(Const { Ok(Const {
name: "a".into(), name: "a".into(),
value: Some(Node::Prefix( value: Some(Val::Number(7, vec![Prefix::Neg], vec![]).into()),
crate::ast::Prefix::Neg, string: None,
Node::Number(7).into()
)),
string: None
}) })
); );
assert_eq!( assert_eq!(
@@ -631,7 +651,7 @@ mod test {
Ok(Const { Ok(Const {
name: "a".into(), name: "a".into(),
value: None, value: None,
string: Some("foo bar".into()) string: Some("foo bar".into()),
}) })
) )
} }
@@ -646,14 +666,14 @@ mod test {
Member { Member {
name: "x".into(), name: "x".into(),
typename: None, typename: None,
size: None size: None,
}, },
Member { Member {
name: "y".into(), name: "y".into(),
typename: None, typename: None,
size: None size: None,
}, },
] ],
}) })
); );
@@ -664,8 +684,8 @@ mod test {
members: vec![Member { members: vec![Member {
name: "bar".into(), name: "bar".into(),
typename: None, typename: None,
size: Some(Node::Number(100)) size: Some(100.into()),
},] }, ],
}) })
); );
@@ -676,8 +696,8 @@ mod test {
members: vec![Member { members: vec![Member {
name: "bar".into(), name: "bar".into(),
typename: Some("Thing".into()), typename: Some("Thing".into()),
size: Some(Node::Number(100)) size: Some(100.into()),
},] }, ],
}) })
); );
} }
@@ -688,9 +708,6 @@ mod test {
Function::from_str("fn foo() {}"), Function::from_str("fn foo() {}"),
Ok(Function { Ok(Function {
name: "foo".into(), name: "foo".into(),
inline: false,
org: None,
typename: None,
args: vec![], args: vec![],
body: Block(vec![]), body: Block(vec![]),
}) })
@@ -699,18 +716,15 @@ mod test {
Function::from_str("fn foo(a, b) {}"), Function::from_str("fn foo(a, b) {}"),
Ok(Function { Ok(Function {
name: "foo".into(), name: "foo".into(),
inline: false,
org: None,
typename: None,
args: vec![ args: vec![
Argname { Argname {
name: "a".into(), name: "a".into(),
typename: None typename: None,
}, },
Argname { Argname {
name: "b".into(), name: "b".into(),
typename: None typename: None,
} },
], ],
body: Block(vec![]), body: Block(vec![]),
}) })
@@ -719,18 +733,15 @@ mod test {
Function::from_str("fn foo(a:Blah, b) {}"), Function::from_str("fn foo(a:Blah, b) {}"),
Ok(Function { Ok(Function {
name: "foo".into(), name: "foo".into(),
inline: false,
org: None,
typename: None,
args: vec![ args: vec![
Argname { Argname {
name: "a".into(), name: "a".into(),
typename: Some("Blah".into()) typename: Some("Blah".into()),
}, },
Argname { Argname {
name: "b".into(), name: "b".into(),
typename: None typename: None,
} },
], ],
body: Block(vec![]), body: Block(vec![]),
}) })
@@ -738,9 +749,6 @@ mod test {
let func = Function { let func = Function {
name: "foo".into(), name: "foo".into(),
inline: true,
org: Some(0x400),
typename: None,
args: vec![Argname { args: vec![Argname {
name: "a".into(), name: "a".into(),
typename: None, typename: None,
@@ -760,23 +768,24 @@ mod test {
#[test] #[test]
fn parse_exprs() { fn parse_exprs() {
use Node::*;
use Operator::*; use Operator::*;
// A very, very basic expression // A very, very basic expression
assert_eq!(Node::from_str("23"), Ok(Number(23))); // For the rest of these we'll .into() stuff for brevity
//Some(assert_eq!(Expr::from_str("23"), Ok(Expr { lhs: Val::Number(23, vec![], vec![]), op: None, rhs: None })));
// Two vals with an operator // Two vals with an operator
assert_eq!( assert_eq!(
Node::from_str("23 + 5"), Expr::from_str("23 + 5"),
Ok(Expr(23.into(), Add, Number(5).into())) Ok(Expr { lhs: 23.into(), op: Some(Add), rhs: Some(5.into()) })
); );
// Multiple terms at the same precedence level // Multiple terms at the same precedence level
assert_eq!( assert_eq!(
Node::from_str("1 + 2 + 3"), Expr::from_str("1 + 2 + 3"),
Ok(Expr(Expr(1.into(), Add, 2.into()).into(), Add, 3.into())) Ok(Expr { lhs: 1.into(), op: Some(Add), rhs: Some(Expr { lhs: 2.into(), op: Some(Add), rhs: Some(3.into()) }.into()) })
); );
/*
// Higher precedence levels // Higher precedence levels
assert_eq!( assert_eq!(
Node::from_str("1 + 2 * 3"), Node::from_str("1 + 2 * 3"),
@@ -847,92 +856,93 @@ mod test {
Node::from_str("(1 + 2) * 3"), Node::from_str("(1 + 2) * 3"),
Ok(Expr(Expr(1.into(), Add, 2.into()).into(), Mul, 3.into())) Ok(Expr(Expr(1.into(), Add, 2.into()).into(), Mul, 3.into()))
); );
*/
} }
#[test] #[test]
fn parse_arrayrefs() { fn parse_arrayrefs() {
use crate::ast::ArrayRef as AR; // use crate::ast::ArrayRef as AR;
use Node::*; // use Val::*;
use Operator::*; // use Operator::*;
//
// Normal numbers // // Normal numbers
assert_eq!( // assert_eq!(
AR::from_str("foo[7]"), // AR::from_str("foo[7]"),
Ok(AR { // Ok(AR {
name: "foo".into(), // name: "foo".into(),
subscript: Number(7).into() // subscript: Number(7).into()
}) // })
); // );
//
// Full exprs (this is the last one of these; the full expr test above covers it // // Full exprs (this is the last one of these; the full expr test above covers it
assert_eq!( // assert_eq!(
AR::from_str("foo[7+x]"), // AR::from_str("foo[7+x]"),
Ok(AR { // Ok(AR {
name: "foo".into(), // name: "foo".into(),
subscript: Node::from_str("7+x").unwrap().into() // subscript: Node::from_str("7+x").unwrap().into()
}) // })
); // );
// Exprs that are actually arrayrefs // Exprs that are actually arrayrefs
assert_eq!( // assert_eq!(
Node::from_str("foo[7]"), // Node::from_str("foo[7]"),
Ok(ArrayRef(AR { // Ok(ArrayRef(AR {
name: "foo".into(), // name: "foo".into(),
subscript: Number(7).into() // subscript: Number(7).into()
})) // }))
); // );
} }
#[test] #[test]
fn parse_addresses() { fn parse_addresses() {
assert_eq!(Node::from_str("&foo"), Ok(Node::Address("foo".into()))); // assert_eq!(Node::from_str("&foo"), Ok(Node::Address("foo".into())));
} }
#[test] // #[test]
fn parse_calls() { // fn parse_calls() {
use Node::Number; // use Val::Number;
//
let blah = Call { // let blah = Call {
name: "blah".into(), // name: "blah".into(),
args: vec![], // args: vec![],
}; // };
//
// Can Node parse a call? // // Can Node parse a call?
assert_eq!(Node::from_str("blah()"), Ok(Node::Call(blah.clone()))); // assert_eq!(Node::from_str("blah()"), Ok(Node::Call(blah.clone())));
//
// Can Statement parse a call? // // Can Statement parse a call?
assert_eq!(Statement::from_str("blah();"), Ok(Statement::Call(blah))); // assert_eq!(Statement::from_str("blah();"), Ok(Statement::Call(blah)));
//
// Calls with args // // Calls with args
assert_eq!( // // assert_eq!(
Call::from_str("blah(1, 2)"), // // Call::from_str("blah(1, 2)"),
Ok(Call { // // Ok(Call {
name: "blah".into(), // // name: "blah".into(),
args: vec![Rvalue::Expr(Number(1)), Rvalue::Expr(Number(2))] // // args: vec![Rvalue::Expr(Number(1)), Rvalue::Expr(Number(2))]
}) // // })
); // // );
//
// Calls with strings // // Calls with strings
assert_eq!( // // assert_eq!(
Call::from_str("blah(\"foo\", 2)"), // // Call::from_str("blah(\"foo\", 2)"),
Ok(Call { // // Ok(Call {
name: "blah".into(), // // name: "blah".into(),
args: vec![Rvalue::String("foo".into()), Rvalue::Expr(Number(2))] // // args: vec![Rvalue::String("foo".into()), Rvalue::Expr(Number(2))]
}) // // })
); // // );
} // }
#[test] #[test]
fn parse_return() { fn parse_return() {
assert_eq!( // assert_eq!(
Statement::from_str("return;"), // Statement::from_str("return;"),
Ok(Statement::Return(Return(None))) // Ok(Statement::Return(Return(None)))
); // );
//
assert_eq!( // assert_eq!(
Statement::from_str("return 17;"), // Statement::from_str("return 17;"),
Ok(Statement::Return(Return(Some(Node::Number(17))))) // Ok(Statement::Return(Return(Some(Node::Number(17)))))
); // );
} }
#[test] #[test]
@@ -941,7 +951,7 @@ mod test {
Statement::from_str("foo = 7;"), Statement::from_str("foo = 7;"),
Ok(Statement::Assignment(Assignment { Ok(Statement::Assignment(Assignment {
lvalue: Lvalue::Name("foo".into()), lvalue: Lvalue::Name("foo".into()),
rvalue: Rvalue::Expr(Node::Number(7)) rvalue: Rvalue::Expr(7.into()),
})) }))
); );
@@ -950,9 +960,9 @@ mod test {
Ok(Assignment { Ok(Assignment {
lvalue: Lvalue::ArrayRef(ArrayRef { lvalue: Lvalue::ArrayRef(ArrayRef {
name: "foo".into(), name: "foo".into(),
subscript: Node::Number(45).into(), subscript: 45.into(),
}), }),
rvalue: Rvalue::Expr(Node::Number(7)) rvalue: Rvalue::Expr(7.into()),
}) })
); );
} }
@@ -974,44 +984,44 @@ mod test {
Ok(VarDecl { Ok(VarDecl {
name: "blah".into(), name: "blah".into(),
typename: Some("Foo".into()), typename: Some("Foo".into()),
size: Some(Node::Number(7)), size: Some(7.into()),
initial: Some(Node::Number(35)), initial: Some(35.into()),
}) })
); );
} }
#[test] // #[test]
fn parse_block() { // fn parse_block() {
assert_eq!( // assert_eq!(
Block::from_str("{ foo(); bar(); }"), // Block::from_str("{ foo(); bar(); }"),
Ok(Block(vec![ // Ok(Block(vec![
Statement::Call(Call { // Statement::Call(Call {
name: "foo".into(), // name: "foo".into(),
args: vec![] // args: vec![]
}), // }),
Statement::Call(Call { // Statement::Call(Call {
name: "bar".into(), // name: "bar".into(),
args: vec![] // args: vec![]
}), // }),
])) // ]))
); // );
} // }
#[test] #[test]
fn parse_conditional() { fn parse_conditional() {
assert_eq!( assert_eq!(
Statement::from_str("if(cond) { foo(); }"), Statement::from_str("if(cond) { foo(); }"),
Ok(Statement::Conditional(Conditional { Ok(Statement::Conditional(Conditional {
condition: Node::from_str("cond").unwrap(), condition: Expr::from_str("cond").unwrap(),
body: Block::from_str("{ foo(); }").unwrap(), body: Block::from_str("{ foo(); }").unwrap(),
alternative: None alternative: None,
})) }))
); );
assert_eq!( assert_eq!(
Statement::from_str("if(cond) { foo(); } else { bar(); }"), Statement::from_str("if(cond) { foo(); } else { bar(); }"),
Ok(Statement::Conditional(Conditional { Ok(Statement::Conditional(Conditional {
condition: Node::from_str("cond").unwrap(), condition: Expr::from_str("cond").unwrap(),
body: Block::from_str("{ foo(); }").unwrap(), body: Block::from_str("{ foo(); }").unwrap(),
alternative: Some(Block::from_str("{ bar(); }").unwrap()), alternative: Some(Block::from_str("{ bar(); }").unwrap()),
})) }))
@@ -1023,7 +1033,7 @@ mod test {
assert_eq!( assert_eq!(
Statement::from_str("while(cond) { foo(); }"), Statement::from_str("while(cond) { foo(); }"),
Ok(Statement::WhileLoop(WhileLoop { Ok(Statement::WhileLoop(WhileLoop {
condition: Node::from_str("cond").unwrap(), condition: Expr::from_str("cond").unwrap(),
body: Block::from_str("{ foo(); }").unwrap(), body: Block::from_str("{ foo(); }").unwrap(),
})) }))
); );
@@ -1031,33 +1041,33 @@ mod test {
#[test] #[test]
fn parse_repeat_loops() { fn parse_repeat_loops() {
assert_eq!( // assert_eq!(
Statement::from_str("repeat(10) x { foo(x); }"), // Statement::from_str("repeat(10) x { foo(x); }"),
Ok(Statement::RepeatLoop(RepeatLoop { // Ok(Statement::RepeatLoop(RepeatLoop {
count: Node::Number(10), // count: Node::Number(10),
name: Some("x".into()), // name: Some("x".into()),
body: Block::from_str("{ foo(x); }").unwrap(), // body: Block::from_str("{ foo(x); }").unwrap(),
})) // }))
); // );
//
assert_eq!( // assert_eq!(
Statement::from_str("repeat(10) { foo(); }"), // Statement::from_str("repeat(10) { foo(); }"),
Ok(Statement::RepeatLoop(RepeatLoop { // Ok(Statement::RepeatLoop(RepeatLoop {
count: Node::Number(10), // count: Node::Number(10),
name: None, // name: None,
body: Block::from_str("{ foo(); }").unwrap(), // body: Block::from_str("{ foo(); }").unwrap(),
})) // }))
); // );
} }
#[test] #[test]
fn parse_program() { fn parse_program() {
assert_eq!( // assert_eq!(
Program::from_str("global foo; struct Point { x, y }"), // Program::from_str("global foo; struct Point { x, y }"),
Ok(Program(vec![ // Ok(Program(vec![
Declaration::from_str("global foo;").unwrap(), // Declaration::from_str("global foo;").unwrap(),
Declaration::from_str("struct Point { x, y }").unwrap(), // Declaration::from_str("struct Point { x, y }").unwrap(),
])) // ]))
) // )
} }
} }
+2 -13
View File
@@ -64,19 +64,8 @@ operator = _{
| ne | ne
} }
expr = { prefix? ~ val ~ suffix* ~ (operator ~ prefix? ~ val ~ suffix*)* } expr = { val ~ (operator ~ val)* }
val = { val = { prefix* ~ (number | name | "(" ~ expr ~ ")") ~ suffix* }
// These are what get evaluated and left on the stack:
number
| // Literal numbers
("(" ~ expr ~ ")")
| // Nested parenthesized exprs
// Bare literal ids, fn calls, array references
// (call, or pointer arithmetic, since ids all reference addresses)
// (multiple calls / subscripts aren't allowed; use CALL or collapse to one
// subscript)
name
}
suffix = { subscript | arglist | member } suffix = { subscript | arglist | member }
subscript = { "[" ~ expr ~ "]" } subscript = { "[" ~ expr ~ "]" }