From 85d13bc26e5e7c8b844064980add656e1fdf1220 Mon Sep 17 00:00:00 2001 From: Dane Johnson Date: Mon, 31 Jan 2022 14:03:47 -0600 Subject: [PATCH] Assignments, numbers, funcalls --- rust/.gitignore | 1 + rust/Cargo.lock | 61 +++++++++++++++++++++++++++++ rust/Cargo.toml | 9 +++++ rust/src/main.rs | 5 +++ rust/src/parser.rs | 95 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 171 insertions(+) create mode 100644 rust/.gitignore create mode 100644 rust/Cargo.lock create mode 100644 rust/Cargo.toml create mode 100644 rust/src/main.rs create mode 100644 rust/src/parser.rs diff --git a/rust/.gitignore b/rust/.gitignore new file mode 100644 index 0000000..c8b241f --- /dev/null +++ b/rust/.gitignore @@ -0,0 +1 @@ +target/* \ No newline at end of file diff --git a/rust/Cargo.lock b/rust/Cargo.lock new file mode 100644 index 0000000..8adbc7e --- /dev/null +++ b/rust/Cargo.lock @@ -0,0 +1,61 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "deelang" +version = "0.1.0" +dependencies = [ + "peg", +] + +[[package]] +name = "peg" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af728fe826811af3b38c37e93de6d104485953ea373d656eebae53d6987fcd2c" +dependencies = [ + "peg-macros", + "peg-runtime", +] + +[[package]] +name = "peg-macros" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4536be147b770b824895cbad934fccce8e49f14b4c4946eaa46a6e4a12fcdc16" +dependencies = [ + "peg-runtime", + "proc-macro2", + "quote", +] + +[[package]] +name = "peg-runtime" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9b0efd3ba03c3a409d44d60425f279ec442bcf0b9e63ff4e410da31c8b0f69f" + +[[package]] +name = "proc-macro2" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" diff --git a/rust/Cargo.toml b/rust/Cargo.toml new file mode 100644 index 0000000..66a043a --- /dev/null +++ b/rust/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "deelang" +version = "0.1.0" +edition = "2021" + + +[dependencies] + +peg = "0.8.0" diff --git a/rust/src/main.rs b/rust/src/main.rs new file mode 100644 index 0000000..f2bb78f --- /dev/null +++ b/rust/src/main.rs @@ -0,0 +1,5 @@ +mod parser; + +fn main() { + println!("Hello, world!"); +} diff --git a/rust/src/parser.rs b/rust/src/parser.rs new file mode 100644 index 0000000..f2c9ce3 --- /dev/null +++ b/rust/src/parser.rs @@ -0,0 +1,95 @@ +#[derive(Debug,PartialEq)] +pub enum Statement { + Assignment(String, Expression), + Funcall(Funcall), +} + +#[derive(Debug,PartialEq)] +pub enum Expression { + Id(String), + Num(f64), + Funcall(Funcall) +} +#[derive(Debug,PartialEq)] +pub struct Funcall { + id: String, + args: Vec, +} + +peg::parser! { + grammar deelang_parser() for str { + pub rule program() -> Vec + = __* s:statement()* eof() { s } + pub rule statement() -> Statement + = i:id() "<-" _ e:expr() __* { Statement::Assignment(i, e) } / + f:funcall() __* { Statement::Funcall(f)} + rule expr() -> Expression + = f:funcall() _ { Expression::Funcall(f) } / + i:id() _ { Expression::Id(i) } / + n:num() _ { Expression::Num(n) } + rule id() -> String + = i:$(letter() (letter() / digit() / ['?'|'.'|'-'])*) _ { i.to_string() } + rule num() -> f64 + = n:$(digit()+ "."? digit()* / "." digit()+) _ { n.to_string().parse().unwrap() } + rule funcall() -> Funcall + = i:id() "(" _ e:(expr() ** ("," _)) ")" _ { Funcall{id: i, args: e} } + rule letter() + = ['A'..='Z'] / ['a'..='z'] + rule digit() + = ['0'..='9'] + rule _ // Non-meaningful whitespace + = ['\t'|' ']* + rule __ // Blank lines and lines containing only comments + = comment() &eof() / comment() newline() / newline() + rule comment() + = "#" (!newline() [_])* &(newline() / eof()) + rule newline() + = "\r\n" / "\r" / "\n" + rule eof() + = ![_] + } +} + + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_comments() { + let expected = vec![]; + let prgm = "## This is a comment"; + assert_eq!(deelang_parser::program(prgm).unwrap(), expected); + } + + #[test] + fn test_funcall() { + let expected = vec![ + Statement::Funcall(Funcall{id: "pear".to_string(), args: vec![]}), + Statement::Funcall(Funcall { + id: "pear".to_string(), + args: vec![Expression::Id("x".to_string()), Expression::Id("y".to_string())], + }) + ]; + let prgm = r"pear() +pear(x, y)"; + assert_eq!(deelang_parser::program(prgm).unwrap(), expected); + } + + #[test] + fn test_assignment() { + let prgm = r"apple <- 1 +apple <- pear(x, y)"; + let expected = vec![ + Statement::Assignment("apple".to_string(), + Expression::Num(1.0)), + Statement::Assignment("apple".to_string(), + Expression::Funcall(Funcall { + id: "pear".to_string(), + args: vec![ + Expression::Id("x".to_string()), + Expression::Id("y".to_string()) + ]}))]; + assert_eq!(deelang_parser::program(prgm).unwrap(), expected); + } +}