From b03c15f765fb0e6e735756b7f73b5f836d24de1d Mon Sep 17 00:00:00 2001 From: Chapman Siu Date: Mon, 27 Mar 2017 20:00:06 +1100 Subject: [PATCH] Update readme with contributor guide --- .Rbuildignore | 1 + example-pl0.R | 141 ------------------------- example/example-word2num.R | 52 +++++++++ example-xml.R => example/example-xml.R | 0 example.R => example/example.R | 0 readme.md | 17 ++- tests/testthat/test_word2num.R | 60 +++++++++++ 7 files changed, 129 insertions(+), 142 deletions(-) delete mode 100644 example-pl0.R create mode 100644 example/example-word2num.R rename example-xml.R => example/example-xml.R (100%) rename example.R => example/example.R (100%) create mode 100644 tests/testthat/test_word2num.R diff --git a/.Rbuildignore b/.Rbuildignore index e74966a..6573a40 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -6,3 +6,4 @@ readme.md cran-comments.md docs/* joss-paper/* +example/* diff --git a/example-pl0.R b/example-pl0.R deleted file mode 100644 index 8739c7c..0000000 --- a/example-pl0.R +++ /dev/null @@ -1,141 +0,0 @@ -#' PL/0 language using Ramble -#' -#' [PL/0](http://en.wikipedia.org/wiki/PL/0) is a simple language which is -#' used for educational purposes. Here we will provide a sample implementation -#' based on it. -#' -#' ## EBNF grammar -#' -#' program = block "." . -#' -#' block = [ "const" ident "=" number {"," ident "=" number} ";"] -#' [ "var" ident {"," ident} ";"] -#' { "procedure" ident ";" block ";" } statement . -#' -#' statement = [ ident ":=" expression | "call" ident -#' | "?" ident | "!" expression -#' | "begin" statement {";" statement } "end" -#' | "if" condition "then" statement -#' | "while" condition "do" statement ]. -#' -#' condition = "odd" expression | -#' expression ("="|"#"|"<"|"<="|">"|">=") expression . -#' -#' expression = [ "+"|"-"] term { ("+"|"-") term}. -#' -#' term = factor {("*"|"/") factor}. -#' -#' factor = ident | number | "(" expression ")". - -#' for the purposes of this example, all the assignments will be of the form -#' `assign(x, value, env=PL0)`, this will then assign the variable to -#' PL0 environment, which we will define. -#' -#' Currently this implementation is incomplete, as it is missing block and while grammar and logic - -PL0 <- new.env() - -# statement("if 1 > 2 then var1 := 3") -# statement("test := 1+2+3") -# statement("call test") -# invisible(statement("begin x := 1; x := x + 1; ! x end")) -statement <- (((identifier() %then% token(String(":=")) %then% expr) - %using% function(stateVar) { - if (stateVar[[2]] == ":=") { - assign(stateVar[[1]], stateVar[[3]], env=PL0) - } - return(stateVar) - }) - %alt% (symbol("!") %then% identifier() - %using% function(stateVar) { - # this calls a defined function (procedure) - print(get(stateVar[[2]], envir = PL0)) - return(stateVar) - }) - %alt% (token(String("if")) %then% condition %then% token(String("then")) - %then% statement %using% function(x) { - if(x[[2]]) { - return(x[[4]]) - } - else { - return(x) - } - }) - %alt% (token(String("begin")) %then% (statement %then% many(symbol(";") %then% statement)) - %then% token(String("end"))) - %alt% (token(String("call")) %then% identifier()) - # while loop not implemented - ) - -condition <- (expr %then% (token(String("<=")) - %alt% token(String(">=")) - %alt% symbol("=") - %alt% symbol("<") - %alt% symbol(">")) - %then% expr - %using% function(bool) { - if (bool[[2]] == "<") { - try(bool1 <- as.numeric(bool[[1]]) < as.numeric(bool[3]), silent=TRUE) - return(if (is.na(bool1)) bool else bool1) - } - else if (bool[[2]] == ">") { - try(bool1 <- as.numeric(bool[[1]]) > as.numeric(bool[3]), silent=TRUE) - return(if (is.na(bool1)) bool else bool1) - } - else if (bool[[2]] == "=") { - try(bool1 <- as.numeric(bool[[1]]) == as.numeric(bool[3]), silent=TRUE) - return(if (is.na(bool1)) bool else bool1) - } - else if (bool[[2]] == "<=") { - try(bool1 <- as.numeric(bool[[1]]) <= as.numeric(bool[3]), silent=TRUE) - return(if (is.na(bool1)) bool else bool1) - } - else if (bool[[2]] == ">=") { - try(bool1 <- as.numeric(bool[[1]]) >= as.numeric(bool[3]), silent=TRUE) - return(if (is.na(bool1)) bool else bool1) - } - else { - warning("boolean symbol should have matched, please check PL\\0 implementation") - return(bool) - } - }) - -expr <- ((term %then% - symbol("+") %then% - expr %using% function(x) { - #print(unlist(c(x))) - return(sum(as.numeric(unlist(c(x))[c(1,3)]))) - }) %alt% - (term %then% - symbol("-") %then% - expr %using% function(x) { - #print(unlist(c(x))) - return(Reduce("-", as.numeric(unlist(c(x))[c(1,3)]))) - }) %alt% term) - -term <- ((factor %then% - symbol("*") %then% - term %using% function(x) { - #print(unlist(c(x))) - return(prod(as.numeric(unlist(c(x))[c(1,3)]))) - }) %alt% - (factor %then% - symbol("/") %then% - term %using% function(x) { - #print(unlist(c(x))) - return(Reduce("/", as.numeric(unlist(c(x))[c(1,3)]))) - }) %alt% factor) - -factor <- ((symbol("(") %then% - expr %then% - symbol(")") %using% function(x){ - #print(unlist(c(x))) - return(as.numeric(unlist(c(x))[2])) - }) %alt% (natural() %using% function(x) { - as.numeric(x) - }) - %alt% (identifier() %using% function(x) { - # try to get the value from environment - get(x[[1]], envir = PL0) - })) - diff --git a/example/example-word2num.R b/example/example-word2num.R new file mode 100644 index 0000000..e167690 --- /dev/null +++ b/example/example-word2num.R @@ -0,0 +1,52 @@ +library(Ramble) + +# we might have hyphens or spaces, +# e.g. ninety-one or ninety one +remove_space_hyphen <- maybe(token(String("-"))) %using% function(...) return(0) + +token_string <- function(x) token(String(x)) + +unit_definition <- (remove_space_hyphen %alt% succeed(NULL)) %then% ( + (token_string("ten") %using% function(...) return(10)) %alt% + (token_string("eleven") %using% function(...) return(11)) %alt% + (token_string("twelve") %using% function(...) return(12)) %alt% + (token_string("thirteen") %using% function(...) return(13)) %alt% + (token_string("fourteen") %using% function(...) return(14)) %alt% + (token_string("fifteen") %using% function(...) return(15)) %alt% + (token_string("sixteen") %using% function(...) return(16)) %alt% + (token_string("seventeen") %using% function(...) return(17)) %alt% + (token_string("eighteen") %using% function(...) return(18)) %alt% + (token_string("nineteen") %using% function(...) return(19)) %alt% + (token_string("zero") %using% function(...) return(0)) %alt% + (token_string("oh") %using% function(...) return(0)) %alt% + (token_string("zip") %using% function(...) return(0)) %alt% + (token_string("zilch") %using% function(...) return(0)) %alt% + (token_string("nada") %using% function(...) return(0)) %alt% + (token_string("one") %using% function(...) return(1)) %alt% + (token_string("two") %using% function(...) return(2)) %alt% + (token_string("three") %using% function(...) return(3)) %alt% + (token_string("four") %using% function(...) return(4)) %alt% + (token_string("five") %using% function(...) return(5)) %alt% + (token_string("six") %using% function(...) return(6)) %alt% + (token_string("seven") %using% function(...) return(7)) %alt% + (token_string("eight") %using% function(...) return(8)) %alt% + (token_string("nine") %using% function(...) return(9)) +) + +tens_definition <- ( + (token_string("ten") %using% function(...) return(10)) %alt% + (token_string("twenty") %using% function(...) return(20)) %alt% + (token_string("thirty") %using% function(...) return(30)) %alt% + (token_string("forty") %using% function(...) return(40)) %alt% + (token_string("fourty") %using% function(...) return(40)) %alt% + (token_string("fifty") %using% function(...) return(50)) %alt% + (token_string("sixty") %using% function(...) return(60)) %alt% + (token_string("seventy") %using% function(...) return(70)) %alt% + (token_string("eighty") %using% function(...) return(80)) %alt% + (token_string("ninety") %using% function(...) return(90)) +) + +# optional tens_defintion + units +word2num <- ((tens_definition %alt% succeed(NULL)) %then% unit_definition) %using% function(x) return(sum(unlist(x))) +word2num("ninety one")$result +word2num("twenty-two")$result diff --git a/example-xml.R b/example/example-xml.R similarity index 100% rename from example-xml.R rename to example/example-xml.R diff --git a/example.R b/example/example.R similarity index 100% rename from example.R rename to example/example.R diff --git a/readme.md b/readme.md index d8ca0fd..ee54637 100644 --- a/readme.md +++ b/readme.md @@ -33,14 +33,29 @@ Python's [recursive descent parsing library](https://pypi.python.org/pypi/funcpa * [Higher-order functions for parsing](http://eprints.nottingham.ac.uk/221/1/parsing.pdf) +Contributing +============ + +You can contribute by opening issues on Github or implementing things yourself and making a pull request. + +Please ensure that package passes all checks with `--as-cran` flag (i.e. via `devtools::check(args = c('--as-cran'))`) before submitting a pull request. + How it Works ============ -To understand the differences between Ramble and other combinatory parsers please read [Ramble: A Parser Combinator in R](http://www.slideshare.net/chapm0nsiu/ramble-introduction). +To understand the differences between Ramble and other combinatory parsers please read [Ramble: A Parser Combinator in R](https://github.com/chappers/Ramble/blob/master/docs/ramble-introduction.pdf). Example ======= +You may view examples for: + +* Parsing xml file +* Creating a simple calculator +* Reading a number given in words, and converting it to the appropriate numeric value + +Within the `examples/*` folder. Below is the calculator example. + ```r #' expr :: = term + term | term - term | term #' term :: = factor * factor | factor / factor | factor diff --git a/tests/testthat/test_word2num.R b/tests/testthat/test_word2num.R new file mode 100644 index 0000000..0cedb51 --- /dev/null +++ b/tests/testthat/test_word2num.R @@ -0,0 +1,60 @@ +library(Ramble) + +# we might have hyphens or spaces, +# e.g. ninety-one or ninety one +remove_space_hyphen <- maybe(token(String("-"))) %using% function(...) return(0) + +token_string <- function(x) token(String(x)) + +unit_definition <- (remove_space_hyphen %alt% succeed(NULL)) %then% ( + (token_string("ten") %using% function(...) return(10)) %alt% + (token_string("eleven") %using% function(...) return(11)) %alt% + (token_string("twelve") %using% function(...) return(12)) %alt% + (token_string("thirteen") %using% function(...) return(13)) %alt% + (token_string("fourteen") %using% function(...) return(14)) %alt% + (token_string("fifteen") %using% function(...) return(15)) %alt% + (token_string("sixteen") %using% function(...) return(16)) %alt% + (token_string("seventeen") %using% function(...) return(17)) %alt% + (token_string("eighteen") %using% function(...) return(18)) %alt% + (token_string("nineteen") %using% function(...) return(19)) %alt% + (token_string("zero") %using% function(...) return(0)) %alt% + (token_string("oh") %using% function(...) return(0)) %alt% + (token_string("zip") %using% function(...) return(0)) %alt% + (token_string("zilch") %using% function(...) return(0)) %alt% + (token_string("nada") %using% function(...) return(0)) %alt% + (token_string("one") %using% function(...) return(1)) %alt% + (token_string("two") %using% function(...) return(2)) %alt% + (token_string("three") %using% function(...) return(3)) %alt% + (token_string("four") %using% function(...) return(4)) %alt% + (token_string("five") %using% function(...) return(5)) %alt% + (token_string("six") %using% function(...) return(6)) %alt% + (token_string("seven") %using% function(...) return(7)) %alt% + (token_string("eight") %using% function(...) return(8)) %alt% + (token_string("nine") %using% function(...) return(9)) +) + +tens_definition <- ( + (token_string("ten") %using% function(...) return(10)) %alt% + (token_string("twenty") %using% function(...) return(20)) %alt% + (token_string("thirty") %using% function(...) return(30)) %alt% + (token_string("forty") %using% function(...) return(40)) %alt% + (token_string("fourty") %using% function(...) return(40)) %alt% + (token_string("fifty") %using% function(...) return(50)) %alt% + (token_string("sixty") %using% function(...) return(60)) %alt% + (token_string("seventy") %using% function(...) return(70)) %alt% + (token_string("eighty") %using% function(...) return(80)) %alt% + (token_string("ninety") %using% function(...) return(90)) +) + +# optional tens_defintion + units +word2num <- ((tens_definition %alt% succeed(NULL)) %then% unit_definition) %using% function(x) return(sum(unlist(x))) + + +test_that("word2num", { + expect_equal(word2num("ninety one")$result, 91) + expect_equal(word2num("ninety-two")$result, 92) + expect_equal(word2num("ninety tone"), list()) + expect_equal(word2num("forty six")$result, 46) + expect_equal(word2num("nineteen")$result, 19) + expect_equal(word2num("thirty seven")$result, 37) +})