Change grammar to properly allow if, while, and for loops (without confusing it with closures).
This commit is contained in:
parent
bf06407d16
commit
692411e232
24
Cargo.lock
generated
24
Cargo.lock
generated
@ -218,9 +218,9 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pest"
|
name = "pest"
|
||||||
version = "2.7.14"
|
version = "2.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442"
|
checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@ -229,9 +229,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pest_derive"
|
name = "pest_derive"
|
||||||
version = "2.7.14"
|
version = "2.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd"
|
checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pest",
|
"pest",
|
||||||
"pest_generator",
|
"pest_generator",
|
||||||
@ -239,9 +239,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pest_generator"
|
name = "pest_generator"
|
||||||
version = "2.7.14"
|
version = "2.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e"
|
checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pest",
|
"pest",
|
||||||
"pest_meta",
|
"pest_meta",
|
||||||
@ -252,9 +252,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pest_meta"
|
name = "pest_meta"
|
||||||
version = "2.7.14"
|
version = "2.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d"
|
checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"pest",
|
"pest",
|
||||||
@ -338,18 +338,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.69"
|
version = "2.0.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.69"
|
version = "2.0.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -12,9 +12,9 @@ name = "dmc"
|
|||||||
path = "src/bin/dmc/main.rs"
|
path = "src/bin/dmc/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
pest = "2.7.14"
|
pest = { version = "2.8.0" }
|
||||||
clap = { version = "4.5.23", features = ["derive"] }
|
clap = { version = "4.5.23", features = ["derive"] }
|
||||||
pest_derive = "2.7.14"
|
pest_derive = { version = "2.8.0", features = ["grammar-extras"] }
|
||||||
codespan-reporting = "0.12.0"
|
codespan-reporting = "0.12.0"
|
||||||
log = "0.4.27"
|
log = "0.4.27"
|
||||||
indoc = "2.0.6"
|
indoc = "2.0.6"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
fn main(args: Array<String>) {
|
fn main(args: Array<String>) {
|
||||||
if args[0] == 'test' {
|
if (args[0] == 'test') {
|
||||||
println('test');
|
println('test');
|
||||||
} else if args[0] == 'foo' {
|
} else if (args[0] == 'foo') {
|
||||||
println('foo');
|
println('foo');
|
||||||
} else {
|
} else {
|
||||||
println('not test');
|
println('not test');
|
||||||
|
117
src/ast/build.rs
117
src/ast/build.rs
@ -941,11 +941,51 @@ fn build_if_else_statement(file_id: usize, if_else_statement_pair: Pair<Rule>) -
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn build_while_statement(file_id: usize, while_statement_pair: Pair<Rule>) -> WhileStatement {
|
fn build_while_statement(file_id: usize, while_statement_pair: Pair<Rule>) -> WhileStatement {
|
||||||
todo!()
|
let mut inner = while_statement_pair.into_inner();
|
||||||
|
inner.next().unwrap(); // while
|
||||||
|
let condition = expect_and_use(
|
||||||
|
file_id,
|
||||||
|
inner.next().unwrap(),
|
||||||
|
Rule::Expression,
|
||||||
|
build_expression,
|
||||||
|
);
|
||||||
|
|
||||||
|
let body = expect_and_use(
|
||||||
|
file_id,
|
||||||
|
inner.next().unwrap(),
|
||||||
|
Rule::BlockStatement,
|
||||||
|
build_block_statement,
|
||||||
|
);
|
||||||
|
WhileStatement { condition, body }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_for_statement(file_id: usize, for_statement_pair: Pair<Rule>) -> ForStatement {
|
fn build_for_statement(file_id: usize, for_statement_pair: Pair<Rule>) -> ForStatement {
|
||||||
todo!()
|
let mut inner = for_statement_pair.into_inner();
|
||||||
|
inner.next().unwrap(); // for
|
||||||
|
let variable = expect_and_use(
|
||||||
|
file_id,
|
||||||
|
inner.next().unwrap(),
|
||||||
|
Rule::Identifier,
|
||||||
|
build_identifier,
|
||||||
|
);
|
||||||
|
inner.next().unwrap(); // in
|
||||||
|
let iterator = expect_and_use(
|
||||||
|
file_id,
|
||||||
|
inner.next().unwrap(),
|
||||||
|
Rule::Expression,
|
||||||
|
build_expression,
|
||||||
|
);
|
||||||
|
let body = expect_and_use(
|
||||||
|
file_id,
|
||||||
|
inner.next().unwrap(),
|
||||||
|
Rule::BlockStatement,
|
||||||
|
build_block_statement,
|
||||||
|
);
|
||||||
|
ForStatement {
|
||||||
|
variable,
|
||||||
|
iterator,
|
||||||
|
body,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_expression(file_id: usize, expression_pair: Pair<Rule>) -> Expression {
|
fn build_expression(file_id: usize, expression_pair: Pair<Rule>) -> Expression {
|
||||||
@ -1514,7 +1554,11 @@ mod tests {
|
|||||||
if let Err(e) = parse_result {
|
if let Err(e) = parse_result {
|
||||||
panic!("Parsing failed.\n{}", e)
|
panic!("Parsing failed.\n{}", e)
|
||||||
} else {
|
} else {
|
||||||
let ast = build_ast(0, parse_result.unwrap().next().unwrap());
|
let mut pairs = parse_result.unwrap();
|
||||||
|
if pairs.as_str().trim() != src.trim() {
|
||||||
|
panic!("Parsing did not consume entire input.");
|
||||||
|
}
|
||||||
|
let ast = build_ast(0, pairs.next().unwrap());
|
||||||
dbg!(ast);
|
dbg!(ast);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1576,7 +1620,7 @@ mod tests {
|
|||||||
fn if_statement() {
|
fn if_statement() {
|
||||||
assert_builds(indoc! {"
|
assert_builds(indoc! {"
|
||||||
fn main() {
|
fn main() {
|
||||||
if true {
|
if (true) {
|
||||||
foo
|
foo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1587,7 +1631,7 @@ mod tests {
|
|||||||
fn if_else_statement() {
|
fn if_else_statement() {
|
||||||
assert_builds(indoc! {"
|
assert_builds(indoc! {"
|
||||||
fn main() {
|
fn main() {
|
||||||
if true {
|
if (true) {
|
||||||
foo
|
foo
|
||||||
} else {
|
} else {
|
||||||
bar
|
bar
|
||||||
@ -1600,9 +1644,9 @@ mod tests {
|
|||||||
fn if_else_if_statement() {
|
fn if_else_if_statement() {
|
||||||
assert_builds(indoc! {"
|
assert_builds(indoc! {"
|
||||||
fn main() {
|
fn main() {
|
||||||
if true {
|
if (true) {
|
||||||
foo
|
foo
|
||||||
} else if false {
|
} else if (false) {
|
||||||
bar
|
bar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1613,9 +1657,9 @@ mod tests {
|
|||||||
fn if_else_if_else_statement() {
|
fn if_else_if_else_statement() {
|
||||||
assert_builds(indoc! {"
|
assert_builds(indoc! {"
|
||||||
fn main() {
|
fn main() {
|
||||||
if true {
|
if (true) {
|
||||||
foo
|
foo
|
||||||
} else if false {
|
} else if (false) {
|
||||||
bar
|
bar
|
||||||
} else {
|
} else {
|
||||||
buzz
|
buzz
|
||||||
@ -1623,4 +1667,59 @@ mod tests {
|
|||||||
}
|
}
|
||||||
"})
|
"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn while_statement() {
|
||||||
|
assert_builds(indoc! {"
|
||||||
|
fn main() {
|
||||||
|
while (true) {
|
||||||
|
foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_statement() {
|
||||||
|
assert_builds(indoc! {"
|
||||||
|
fn main(args: Array<String>) {
|
||||||
|
for (arg in args) {
|
||||||
|
foo(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn if_with_call_condition() {
|
||||||
|
assert_builds(indoc! {"
|
||||||
|
fn main() {
|
||||||
|
if (foo()) {
|
||||||
|
bar()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn while_with_call_condition() {
|
||||||
|
assert_builds(indoc! {"
|
||||||
|
fn main() {
|
||||||
|
while (foo()) {
|
||||||
|
bar()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_with_call_iterator() {
|
||||||
|
assert_builds(indoc! {"
|
||||||
|
fn main() {
|
||||||
|
for (foo in bar()) {
|
||||||
|
baz(foo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -824,9 +824,9 @@ impl Unparse for ReturnStatement {
|
|||||||
|
|
||||||
impl Unparse for IfStatement {
|
impl Unparse for IfStatement {
|
||||||
fn unparse(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
|
fn unparse(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
|
||||||
writer.write_indented("if ")?;
|
writer.write_indented("if (")?;
|
||||||
self.condition.unparse(writer)?;
|
self.condition.unparse(writer)?;
|
||||||
writer.writeln(" {")?;
|
writer.writeln(") {")?;
|
||||||
self.then_block.unparse_inner(writer)?;
|
self.then_block.unparse_inner(writer)?;
|
||||||
writer.writeln_indented("}")?;
|
writer.writeln_indented("}")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -847,9 +847,9 @@ impl Unparse for IfElseStatement {
|
|||||||
impl Unparse for ElseIfs {
|
impl Unparse for ElseIfs {
|
||||||
fn unparse(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
|
fn unparse(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
|
||||||
for if_statement in &self.0 {
|
for if_statement in &self.0 {
|
||||||
writer.write_indented("else if ")?;
|
writer.write_indented("else if (")?;
|
||||||
if_statement.condition.unparse(writer)?;
|
if_statement.condition.unparse(writer)?;
|
||||||
writer.writeln(" {")?;
|
writer.writeln(") {")?;
|
||||||
if_statement.then_block.unparse_inner(writer)?;
|
if_statement.then_block.unparse_inner(writer)?;
|
||||||
writer.writeln_indented("}")?;
|
writer.writeln_indented("}")?;
|
||||||
}
|
}
|
||||||
|
@ -536,7 +536,9 @@ ReturnStatement = {
|
|||||||
|
|
||||||
IfStatement = {
|
IfStatement = {
|
||||||
If
|
If
|
||||||
|
~ "("
|
||||||
~ Expression
|
~ Expression
|
||||||
|
~ ")"
|
||||||
~ BlockStatement
|
~ BlockStatement
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -558,15 +560,19 @@ ElseBlock = {
|
|||||||
|
|
||||||
WhileStatement = {
|
WhileStatement = {
|
||||||
While
|
While
|
||||||
|
~ "("
|
||||||
~ Expression
|
~ Expression
|
||||||
|
~ ")"
|
||||||
~ BlockStatement
|
~ BlockStatement
|
||||||
}
|
}
|
||||||
|
|
||||||
ForStatement = {
|
ForStatement = {
|
||||||
For
|
For
|
||||||
~ Expression
|
~ "("
|
||||||
|
~ Identifier
|
||||||
~ In
|
~ In
|
||||||
~ Expression
|
~ Expression
|
||||||
|
~ ")"
|
||||||
~ BlockStatement
|
~ BlockStatement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ pub struct DeimosParser;
|
|||||||
mod deimos_parser_tests {
|
mod deimos_parser_tests {
|
||||||
use crate::parser::{DeimosParser, Rule};
|
use crate::parser::{DeimosParser, Rule};
|
||||||
use indoc::indoc;
|
use indoc::indoc;
|
||||||
use pest::Parser;
|
use pest::{parses_to, Parser};
|
||||||
|
|
||||||
macro_rules! fail_rule {
|
macro_rules! fail_rule {
|
||||||
($pair: expr; $rule:path) => {{
|
($pair: expr; $rule:path) => {{
|
||||||
@ -34,7 +34,7 @@ mod deimos_parser_tests {
|
|||||||
panic!("Parsing failed.\n{}", e);
|
panic!("Parsing failed.\n{}", e);
|
||||||
} else {
|
} else {
|
||||||
let mut pairs = parse_result.unwrap();
|
let mut pairs = parse_result.unwrap();
|
||||||
if input != pairs.as_str() {
|
if input.trim() != pairs.as_str().trim() {
|
||||||
panic!(
|
panic!(
|
||||||
"Parsing did not consume entire input. Consumed only:\n{}",
|
"Parsing did not consume entire input. Consumed only:\n{}",
|
||||||
pairs.as_str()
|
pairs.as_str()
|
||||||
@ -101,7 +101,7 @@ mod deimos_parser_tests {
|
|||||||
parses_to(
|
parses_to(
|
||||||
Rule::IfStatement,
|
Rule::IfStatement,
|
||||||
indoc! {"
|
indoc! {"
|
||||||
if foo == 42 {
|
if (foo == 42) {
|
||||||
bar()
|
bar()
|
||||||
}"},
|
}"},
|
||||||
)
|
)
|
||||||
@ -112,7 +112,7 @@ mod deimos_parser_tests {
|
|||||||
parses_to(
|
parses_to(
|
||||||
Rule::IfElseStatement,
|
Rule::IfElseStatement,
|
||||||
indoc! {"
|
indoc! {"
|
||||||
if foo == 42 {
|
if (foo == 42) {
|
||||||
bar()
|
bar()
|
||||||
} else {
|
} else {
|
||||||
baz()
|
baz()
|
||||||
@ -125,9 +125,9 @@ mod deimos_parser_tests {
|
|||||||
parses_to(
|
parses_to(
|
||||||
Rule::IfElseStatement,
|
Rule::IfElseStatement,
|
||||||
indoc! {"
|
indoc! {"
|
||||||
if foo == 42 {
|
if (foo == 42) {
|
||||||
bar()
|
bar()
|
||||||
} else if foo == 16 {
|
} else if (foo == 16) {
|
||||||
baz()
|
baz()
|
||||||
}"},
|
}"},
|
||||||
)
|
)
|
||||||
@ -138,13 +138,46 @@ mod deimos_parser_tests {
|
|||||||
parses_to(
|
parses_to(
|
||||||
Rule::IfElseStatement,
|
Rule::IfElseStatement,
|
||||||
indoc! {"
|
indoc! {"
|
||||||
if foo == 42 {
|
if (foo == 42) {
|
||||||
foo()
|
foo()
|
||||||
} else if foo == 16 {
|
} else if (foo == 16) {
|
||||||
baz()
|
baz()
|
||||||
} else {
|
} else {
|
||||||
fizz()
|
fizz()
|
||||||
}"},
|
}"},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn while_statement() {
|
||||||
|
parses_to(Rule::WhileStatement, "while (foo) { bar() }");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_statement() {
|
||||||
|
parses_to(Rule::ForStatement, "for (foo in bar) { baz(foo); }");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn if_statement_with_call_condition() {
|
||||||
|
parses_to(Rule::IfStatement, indoc! {"
|
||||||
|
if (foo()) {
|
||||||
|
bar()
|
||||||
|
}
|
||||||
|
"})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn while_statement_with_call_condition() {
|
||||||
|
parses_to(Rule::WhileStatement, "while (foo()) { bar(); }")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_statement_with_call_iterator() {
|
||||||
|
parses_to(Rule::ForStatement, indoc! {"
|
||||||
|
for (foo in bar()) {
|
||||||
|
baz(foo);
|
||||||
|
}
|
||||||
|
"})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user