├── codecov.yml ├── NEWS.md ├── LICENSE ├── .gitignore ├── NAMESPACE ├── .Rbuildignore ├── man ├── help.Rd └── removeTypes.Rd ├── .travis.yml ├── DESCRIPTION ├── appveyor.yml ├── tests └── test.R ├── README.md ├── R └── package.R └── README.Rmd /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # types 1.0.0 2 | 3 | * Initial release 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2016 2 | COPYRIGHT HOLDER: James Hester 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | cran-comments.md 5 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | export("?") 2 | export(removeTypes) 3 | export(remove_types) 4 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^README\.Rmd$ 4 | ^README-.*\.png$ 5 | ^\.travis\.yml$ 6 | ^codecov\.yml$ 7 | ^cran-comments\.md$ 8 | ^appveyor\.yml$ 9 | -------------------------------------------------------------------------------- /man/help.Rd: -------------------------------------------------------------------------------- 1 | \name{?} 2 | \alias{?} 3 | \title{Documentation Shortcuts} 4 | \usage{ 5 | "?"(e1, e2) 6 | } 7 | \arguments{ 8 | \item{e1}{The type of documentation} 9 | 10 | \item{e2}{The topic of documentation} 11 | } 12 | \description{ 13 | Documentation Shortcuts 14 | } 15 | \seealso{ 16 | \code{\link[utils]{?}} 17 | } 18 | 19 | -------------------------------------------------------------------------------- /man/removeTypes.Rd: -------------------------------------------------------------------------------- 1 | \name{removeTypes} 2 | \alias{removeTypes} 3 | \alias{remove_types} 4 | \title{Remove types from a language object} 5 | \usage{ 6 | removeTypes(x) 7 | 8 | remove_types(x) 9 | } 10 | \arguments{ 11 | \item{x}{R language object} 12 | } 13 | \description{ 14 | Remove types from a language object 15 | } 16 | 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # R for travis: see documentation at https://docs.travis-ci.com/user/languages/r 2 | 3 | language: R 4 | r: 5 | - oldrel 6 | - release 7 | - devel 8 | 9 | sudo: false 10 | cache: packages 11 | 12 | r_github_packages: 13 | - hadley/devtools 14 | 15 | after_success: 16 | - Rscript -e 'install.packages("covr");covr::codecov()' 17 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: types 2 | Title: Type annotations 3 | Version: 1.0.0 4 | Authors@R: person("Jim", "Hester", email = "james.f.hester@gmail.com", role = c("aut", "cre")) 5 | Description: Provides a syntax for static type annotations of R code. 6 | Depends: 7 | R (>= 3.0.3) 8 | License: MIT + file LICENSE 9 | Encoding: UTF-8 10 | LazyData: true 11 | URL: https://github.com/jimhester/types#readme 12 | BugReports: https://github.com/jimhester/types/issues 13 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # DO NOT CHANGE the "init" and "install" sections below 2 | 3 | # Download script file from GitHub 4 | init: 5 | ps: | 6 | $ErrorActionPreference = "Stop" 7 | Invoke-WebRequest http://raw.github.com/krlmlr/r-appveyor/master/scripts/appveyor-tool.ps1 -OutFile "..\appveyor-tool.ps1" 8 | Import-Module '..\appveyor-tool.ps1' 9 | 10 | install: 11 | ps: Bootstrap 12 | 13 | cache: 14 | - C:\RLibrary 15 | 16 | # Adapt as necessary starting from here 17 | 18 | build_script: 19 | - travis-tool.sh install_deps 20 | 21 | test_script: 22 | - travis-tool.sh run_tests 23 | 24 | on_failure: 25 | - 7z a failure.zip *.Rcheck\* 26 | - appveyor PushArtifact failure.zip 27 | 28 | artifacts: 29 | - path: '*.Rcheck\**\*.log' 30 | name: Logs 31 | 32 | - path: '*.Rcheck\**\*.out' 33 | name: Logs 34 | 35 | - path: '*.Rcheck\**\*.fail' 36 | name: Logs 37 | 38 | - path: '*.Rcheck\**\*.Rout' 39 | name: Logs 40 | 41 | - path: '\*_*.tar.gz' 42 | name: Bits 43 | 44 | - path: '\*_*.zip' 45 | name: Bits 46 | -------------------------------------------------------------------------------- /tests/test.R: -------------------------------------------------------------------------------- 1 | library(types) 2 | add <- function(x = ? numeric, y = 1) { 3 | x + y 4 | } ? numeric 5 | 6 | add2 <- function(x = 1, y = ? numeric) { 7 | sum(x, y) ? numeric 8 | } 9 | 10 | label <- function(x) paste(as.call(list(x[[1]], quote(...))), collapse = "\n") 11 | 12 | expect_error <- function(x, regexp) { 13 | error <- tryCatch({ 14 | x 15 | NULL 16 | }, error = function(e) e) 17 | 18 | if (is.null(error)) { 19 | stop(label(x), " did not throw an error.") 20 | } 21 | if (!grepl(regexp, error$message)) { 22 | stop(error$message, " did not match ", regexp) 23 | } 24 | invisible(TRUE) 25 | } 26 | 27 | expect_error(add(), "argument is missing, with no default") 28 | expect_error(add2(), "argument is missing, with no default") 29 | 30 | stopifnot(add(1, 2) == 3) 31 | stopifnot(add2(1, 2) == 3) 32 | 33 | add_untyped <- remove_types(add) 34 | stopifnot(identical(formals(add_untyped), as.pairlist(alist(x=, y = 1)))) 35 | stopifnot(all.equal(body(add_untyped), quote({ x + y }))) 36 | 37 | add2_untyped <- remove_types(add2) 38 | stopifnot(identical(formals(add2_untyped), as.pairlist(alist(x = 1, y = )))) 39 | stopifnot(all.equal(body(add2_untyped), quote({ sum(x, y) }))) 40 | 41 | stopifnot(identical(remove_types(quote(a ? b)), quote(a))) 42 | stopifnot(identical(remove_types(quote(a + 1 ? b)), quote(a + 1))) 43 | 44 | stopifnot(identical(remove_types(expression(a ? b, a + 1 ? b)), expression(a, a + 1))) 45 | 46 | stopifnot(identical(remove_types(list(quote(a ? b), quote(a + 1 ? b))), list(quote(a), quote(a + 1)))) 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [![CRAN\_Status\_Badge](http://www.r-pkg.org/badges/version/types)](https://cran.r-project.org/package=types) [![Travis-CI Build Status](https://travis-ci.org/jimhester/types.svg?branch=master)](https://travis-ci.org/jimhester/types) [![Coverage Status](https://img.shields.io/codecov/c/github/jimhester/types/master.svg)](https://codecov.io/github/jimhester/types?branch=master) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/jimhester/types?branch=master&svg=true)](https://ci.appveyor.com/project/jimhester/types) 4 | 5 | Types for R 6 | ----------- 7 | 8 | This package provides a simple type annotation for R that is usable in scripts, in the R console and in packages. It is intended as a convention to allow other packages or IDE's to use the type information to provide error checking, automatic documentation or optimizations. 9 | 10 | The annotations are syntactically valid R code rather than comments, which provides additional assurance they are specified properly. However this package does not do anything with the type annotations, they have no effect on the calculated result. 11 | 12 | `?` when used on the command line continues to work as before, accessing the R help pages for the topic requested. 13 | 14 | Examples 15 | -------- 16 | 17 | Function arguments can be annotated with types 18 | 19 | ``` r 20 | f <- function(x = 1 ? numeric) { 21 | x + 1 22 | } 23 | ``` 24 | 25 | Default arguments can also be annotated (the `=` is required however) 26 | 27 | ``` r 28 | f <- function(x = ? numeric) { 29 | x + 1 30 | } 31 | ``` 32 | 33 | Function statements can be annotated with types 34 | 35 | ``` r 36 | f <- function(x = "Yay") { 37 | paste(x, "types!") ? character 38 | } 39 | ``` 40 | 41 | Function return values can be annotated with types 42 | 43 | ``` r 44 | f <- function(x = 1) { 45 | x %% 2 == 0 46 | } ? boolean 47 | ``` 48 | 49 | Prior work 50 | ---------- 51 | 52 | The [argufy package](https://github.com/gaborcsardi/argufy#readme) by Gábor Csárdi was an exploration of typed arguments and was the original impetus of the `?` syntax. 53 | -------------------------------------------------------------------------------- /R/package.R: -------------------------------------------------------------------------------- 1 | `?` <- function(e1, e2) { 2 | if (missing(e2)) { 3 | stop( 4 | structure(class = c("error", "condition"), 5 | list(call = sys.call(-1), 6 | message = "argument is missing, with no default"))) 7 | } else { 8 | e1 9 | } 10 | } 11 | 12 | removeTypes <- function (x) { 13 | recurse <- function(y) { 14 | lapply(y, remove_types) 15 | } 16 | if (is.atomic(x) || is.name(x)) { 17 | x 18 | } 19 | else if (is.call(x)) { 20 | if (identical(x[[1]], as.symbol("?"))) { 21 | if (length(x) == 3) { 22 | if (length(x[[2]]) == 1) { 23 | x[[2]] 24 | } else { 25 | as.call(recurse(x[[2]])) 26 | } 27 | } else { 28 | # ?(x) call, This should only occur for arguments with no default 29 | quote(expr = ) 30 | } 31 | } else { 32 | as.call(recurse(x)) 33 | } 34 | } 35 | else if (is.function(x)) { 36 | formals(x) <- Recall(formals(x)) 37 | body(x) <- Recall(body(x)) 38 | x 39 | } 40 | else if (is.pairlist(x)) { 41 | as.pairlist(recurse(x)) 42 | } 43 | else if (is.expression(x)) { 44 | as.expression(recurse(x)) 45 | } 46 | else if (is.list(x)) { 47 | recurse(x) 48 | } 49 | else { 50 | stop("Unknown language class: ", paste(class(x), collapse = "/"), # nocov 51 | call. = FALSE) # nocov 52 | } 53 | } 54 | 55 | remove_types <- removeTypes 56 | 57 | .onAttach <- function(libname, pkgname) { 58 | 59 | # If the package is attached add a check for a top level call from the REPL 60 | # to the package environment definition 61 | # As interactive help is only used on the command line this is only necessary 62 | # when the package is attached. 63 | ns <- as.environment(paste("package", pkgname, sep = ":")) 64 | body(ns$`?`) <- as.call( 65 | append( 66 | as.list(body(ns$`?`)), 67 | quote( 68 | if (interactive() && sys.nframe() <= 1L) { 69 | call <- get("?", pos = 3L) # nocov start 70 | return(eval(as.call(list(call, substitute(e1), substitute(e2))))) # nocov end 71 | }), 72 | after = 1)) 73 | } 74 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r, echo = FALSE} 8 | knitr::opts_chunk$set( 9 | collapse = TRUE, 10 | comment = "#>", 11 | fig.path = "README-" 12 | ) 13 | ``` 14 | 15 | [![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/types)](https://cran.r-project.org/package=types) 16 | [![Travis-CI Build Status](https://travis-ci.org/jimhester/types.svg?branch=master)](https://travis-ci.org/jimhester/types) 17 | [![Coverage Status](https://img.shields.io/codecov/c/github/jimhester/types/master.svg)](https://codecov.io/github/jimhester/types?branch=master) 18 | [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/jimhester/types?branch=master&svg=true)](https://ci.appveyor.com/project/jimhester/types) 19 | 20 | ## Types for R ## 21 | This package provides a simple type annotation for R that is usable in scripts, 22 | in the R console and in packages. It is intended as a convention to allow other 23 | packages or IDE's to use the type information to provide error checking, 24 | automatic documentation or optimizations. 25 | 26 | The annotations are syntactically valid R code rather than comments, which 27 | provides additional assurance they are specified properly. However this package 28 | does not do anything with the type annotations, they have no effect on the 29 | calculated result. 30 | 31 | `?` when used on the command line continues to work as before, accessing the R 32 | help pages for the topic requested. 33 | 34 | ## Examples ## 35 | 36 | Function arguments can be annotated with types 37 | ```{r} 38 | f <- function(x = 1 ? numeric) { 39 | x + 1 40 | } 41 | ``` 42 | Default arguments can also be annotated (the `=` is required however) 43 | 44 | ```{r} 45 | f <- function(x = ? numeric) { 46 | x + 1 47 | } 48 | ``` 49 | 50 | Function statements can be annotated with types 51 | ```{r} 52 | f <- function(x = "Yay") { 53 | paste(x, "types!") ? character 54 | } 55 | ``` 56 | 57 | Function return values can be annotated with types 58 | ```{r} 59 | f <- function(x = 1) { 60 | x %% 2 == 0 61 | } ? boolean 62 | ``` 63 | 64 | ## Prior work ## 65 | The [argufy package](https://github.com/gaborcsardi/argufy#readme) by Gábor 66 | Csárdi was an exploration of typed arguments and was the original impetus of 67 | the `?` syntax. 68 | --------------------------------------------------------------------------------