Skip to content

Commit f34e00f

Browse files
authored
Merge pull request #1154 from stan-dev/expose-functions-reserved
Error when code has reserved keywords
2 parents 0c31c1b + 818c32e commit f34e00f

File tree

3 files changed

+108
-0
lines changed

3 files changed

+108
-0
lines changed

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
* text=auto eol=lf
2+
*.rda binary

R/utils.R

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -950,6 +950,32 @@ compile_functions <- function(env, verbose = FALSE, global = FALSE) {
950950
prep_fun_cpp(funs[ind], fun_end, env$hpp_code)
951951
})
952952

953+
reserved_names <- unique(
954+
unlist(
955+
lapply(stan_funs, function(stan_fun) {
956+
regmatches(
957+
stan_fun,
958+
gregexpr("(?<=_stan_)[[:alnum:]_]+", stan_fun, perl = TRUE)
959+
)[[1]]
960+
}),
961+
use.names = FALSE
962+
)
963+
)
964+
965+
if (length(reserved_names) > 0) {
966+
stop(
967+
paste0(
968+
"expose_functions() can't expose this Stan function because the function ",
969+
"name and/or one or more argument names use a reserved keyword ",
970+
"(typically in the C++ toolchain used to compile Stan). Please rename ",
971+
"the function/arguments in your Stan functions block and try again. ",
972+
"Conflicting names: ",
973+
paste(reserved_names, collapse = ", ")
974+
),
975+
call. = FALSE
976+
)
977+
}
978+
953979
env$fun_names <- sapply(seq_len(length(funs) - 1), function(ind) {
954980
get_function_name(funs[ind], funs[ind + 1], env$hpp_code)
955981
})

tests/testthat/test-model-expose-functions.R

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,86 @@ test_that("Overloaded functions give meaningful errors", {
380380
"Overloaded functions are currently not able to be exposed to R! The following overloaded functions were found: fun1, fun3")
381381
})
382382

383+
reserved_names_msg <- function(names) {
384+
paste(
385+
"expose_functions() can't expose this Stan function because the function",
386+
"name and/or one or more argument names use a reserved keyword",
387+
"(typically in the C++ toolchain used to compile Stan). Please rename",
388+
"the function/arguments in your Stan functions block and try again.",
389+
paste("Conflicting names:", paste(names, collapse = ", "))
390+
)
391+
}
392+
393+
test_that("Reserved names in Stan code give the same error", {
394+
stan_file <- write_stan_file(
395+
"
396+
functions {
397+
real min(real max, real class) {
398+
return max - class;
399+
}
400+
}
401+
"
402+
)
403+
404+
funmod <- cmdstan_model(stan_file, force_recompile = TRUE)
405+
expect_error(
406+
funmod$expose_functions(),
407+
reserved_names_msg(c("min", "max", "class")),
408+
fixed = TRUE
409+
)
410+
})
411+
412+
test_that("Multiple reserved C++ keywords in Stan code give the same error", {
413+
stan_file <- write_stan_file(
414+
"
415+
functions {
416+
real template(real class, real namespace, real private) {
417+
return class + namespace + private;
418+
}
419+
}
420+
"
421+
)
422+
423+
funmod <- cmdstan_model(stan_file, force_recompile = TRUE)
424+
expect_error(
425+
funmod$expose_functions(),
426+
reserved_names_msg(c("template", "class", "namespace", "private")),
427+
fixed = TRUE
428+
)
429+
})
430+
431+
test_that("Reserved keywords in Stan function bodies are allowed", {
432+
stan_file <- write_stan_file(
433+
"
434+
functions {
435+
real add_one(real x) {
436+
real class = 1;
437+
return x + class;
438+
}
439+
}
440+
"
441+
)
442+
443+
funmod <- cmdstan_model(stan_file, force_recompile = TRUE)
444+
expect_no_error(funmod$expose_functions())
445+
expect_equal(funmod$functions$add_one(2), 3)
446+
})
447+
448+
test_that("Stan code with no reserved names exposes functions", {
449+
stan_file <- write_stan_file(
450+
"
451+
functions {
452+
real add_pair(real left, real right) {
453+
return left + right;
454+
}
455+
}
456+
"
457+
)
458+
459+
funmod <- cmdstan_model(stan_file, force_recompile = TRUE)
460+
expect_no_error(funmod$expose_functions())
461+
})
462+
383463
test_that("Exposing external functions errors before v2.32", {
384464
fake_cmdstan_version("2.26.0")
385465

0 commit comments

Comments
 (0)