Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/workflows/lexer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ on:
- code/src/include/Rinlinedfuns.h
- code/tests/reg-encodings.R
- code/tests/ir-unicode-lexer.R
- code/tests/ir-package-compat.R
- .github/workflows/lexer.yml

jobs:
Expand Down Expand Up @@ -46,3 +47,14 @@ jobs:

- name: Test Unicode lexer priority
run: build/bin/R --vanilla < code/tests/ir-unicode-lexer.R

- name: Install package compatibility oracle
run: |
mkdir -p build/compat-lib
IR_COMPAT_LIB="$PWD/build/compat-lib" \
build/bin/Rscript -e 'install.packages(c("rlang", "testthat", "tibble", "dplyr"), lib = Sys.getenv("IR_COMPAT_LIB"), repos = "https://cloud.r-project.org", type = "source", Ncpus = 2L)'

- name: Test unmodified-package compatibility
env:
IR_COMPAT_LIB: ${{ github.workspace }}/build/compat-lib
run: build/bin/R --vanilla < code/tests/ir-package-compat.R
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
### fn λ → ÷ ≟ ←
### λ ƒ → ÷ ≟ ←

→ and ← can now be used for assignment, not just `<-` and `->`.

`function(x) x**3` can now be written `fn(x) x**3`, `λ(x) x**3`, or `ƒ(x) x**3`.
`function(x) x**3` can now be written `λ(x) x**3` or `ƒ(x) x**3`.

÷ means division.

Expand Down Expand Up @@ -35,7 +35,7 @@ because ≟ tests equality.
| `3 → x` | assign |
| `3 ↠ x` | assign in an enclosing frame |
| `left ≟ right` | test equality |
| `fn(x) expression`, `λ(x) expression`, or `ƒ(x) expression` | construct a function |
| `λ(x) expression` or `ƒ(x) expression` | construct a function |
| `left ÷ right` | divide |


Expand All @@ -61,7 +61,7 @@ stopifnot((answer = 4))

Code that used a single `=` as assignment must use an arrow in this R. The comma and argument-label rules have otherwise been left alone.

`fn` also used to be an ordinary name. It is reserved here, so old code using bare `fn` as a variable or argument must choose another name. This source uses `fun`; in particular, write `optim(par, fun = ...)` rather than `optim(par, fn = ...)`.
`fn` is an ordinary identifier, as in standard R. Code using `fn` as a variable, formal argument, or named argument does not need to change; for example, `optim(par, fn = ...)` remains valid. `fn(...)` is an ordinary call to a function named `fn`, not function-constructor syntax.


------
Expand Down
1 change: 0 additions & 1 deletion code/src/main/gram.c
Original file line number Diff line number Diff line change
Expand Up @@ -4493,7 +4493,6 @@ static keywords[] = {
{ "NA_character_", NUM_CONST },
{ "NA_complex_", NUM_CONST },
{ "function", FUNCTION },
{ "fn", FUNCTION },
{ "λ", FUNCTION },
{ "ƒ", FUNCTION },
{ "while", WHILE },
Expand Down
1 change: 0 additions & 1 deletion code/src/main/gram.y
Original file line number Diff line number Diff line change
Expand Up @@ -2179,7 +2179,6 @@ static keywords[] = {
{ "NA_character_", NUM_CONST },
{ "NA_complex_", NUM_CONST },
{ "function", FUNCTION },
{ "fn", FUNCTION },
{ "λ", FUNCTION },
{ "ƒ", FUNCTION },
{ "while", WHILE },
Expand Down
40 changes: 40 additions & 0 deletions code/tests/ir-package-compat.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
## IR compatibility smoke: bare fn must remain ordinary R syntax.

parse1 <- function(text) parse(text = text, keep.source = FALSE)[[1L]]

## Regression for the shape used by rlang: fn is a formal and is assigned to.
stopifnot(identical(parse1("fn"), as.name("fn")))
call_trace_context <- eval(parse1(
"function(call, fn) {
fn <- fn
fn
}"
))
stopifnot(
identical(names(formals(call_trace_context)), c("call", "fn")),
identical(call_trace_context(NULL, 7L), 7L)
)

## The IR constructor spellings remain distinctive syntax.
lambda_identity <- eval(parse1("λ(fn) fn"))
florin_identity <- eval(parse1("ƒ(fn) fn"))
stopifnot(
identical(lambda_identity(11L), 11L),
identical(florin_identity(12L), 12L)
)

## Upstream packages are the oracle: do not patch or translate them.
compat_lib <- Sys.getenv("IR_COMPAT_LIB", "build/compat-lib")
.libPaths(c(compat_lib, .libPaths()))

packages <- c("rlang", "testthat", "tibble", "dplyr")
for (package in packages) {
suppressPackageStartupMessages(
library(package, character.only = TRUE)
)
}

testthat::test_that("IR spellings work inside upstream testthat", {
answer ← 8 ÷ 2
testthat::expect_true(answer ≟ 4)
})
Loading