Nothing
# Rtinycc - TinyCC for R
# Copyright (C) 2025-2026 Sounkou Mahamane Toure
# SPDX-License-Identifier: GPL-3.0-or-later
# Internal lambda.r rules for codegen dispatch
#
# This file defines many small "rules" used by the code generator. Each
# rule is registered with a tiny DSL (the lambda.r style rules such as
# `ffi_input_rule`, `ffi_return_rule`, `r_to_c_return_lines_rule`, etc.)
# and returns either a string or a character vector containing C source
# lines to be injected into generated bindings. The sections below are
# grouped by purpose (input conversion, return conversion, array helpers,
# struct/union accessors, callback helpers, type mapping keys, etc.).
#
# NOTE: many groups include nearly-identical rules for multiple integer
# and floating types; these were written out explicitly for clarity. See
# TODOs later in this file for suggestions where a small generator could
# reduce repetition by producing similar rules programmatically.
## ------------------------------------------------------------------
## FFI input conversion rules
##
## Produce C lines that convert an incoming R `SEXP` (named by `r_name`)
## into a C variable (named by `arg_name`) of the requested FFI type.
## These rules are used when generating the C thunk that bridges R -> C.
## ------------------------------------------------------------------
rtinycc_register_scalar_codegen_rules()
ffi_input_enum_rule(type_name, arg_name, r_name) %as%
{
sprintf(" int %s = asInteger(%s);", arg_name, r_name)
}
ffi_input_callback_rule(type_name, arg_name, r_name) %as%
{
sprintf(" void* %s = R_ExternalPtrAddr(%s);", arg_name, r_name)
}
ffi_input_rule("raw", arg_name, r_name) %as%
{
sprintf(" uint8_t* %s = RAW(%s);", arg_name, r_name)
}
ffi_input_rule("integer_array", arg_name, r_name) %as%
{
sprintf(" int32_t* %s = INTEGER(%s);", arg_name, r_name)
}
ffi_input_rule("numeric_array", arg_name, r_name) %as%
{
sprintf(" double* %s = REAL(%s);", arg_name, r_name)
}
ffi_input_rule("logical_array", arg_name, r_name) %as%
{
sprintf(" int* %s = LOGICAL(%s);", arg_name, r_name)
}
ffi_input_rule("character_array", arg_name, r_name) %as%
{
sprintf(" const SEXP* %s = STRING_PTR_RO(%s);", arg_name, r_name)
}
ffi_input_rule("cstring_array", arg_name, r_name) %as%
{
rtinycc_render_template(
c(
" if (!Rf_isString({{r_name}})) Rf_error(\"expected character vector\");",
" R_xlen_t _{{arg_name}}_n = XLENGTH({{r_name}});",
" const char** {{arg_name}} = (const char**) R_alloc((size_t)_{{arg_name}}_n, sizeof(const char*));",
" for (R_xlen_t _{{arg_name}}_i = 0; _{{arg_name}}_i < _{{arg_name}}_n; _{{arg_name}}_i++) {",
" SEXP _{{arg_name}}_elt = STRING_ELT({{r_name}}, _{{arg_name}}_i);",
" {{arg_name}}[_{{arg_name}}_i] = (_{{arg_name}}_elt == NA_STRING) ? NULL : Rf_translateCharUTF8(_{{arg_name}}_elt);",
" }"
),
list(
r_name = r_name,
arg_name = arg_name
)
)
}
ffi_input_rule(type, arg_name, r_name) %as%
{
stop("Unsupported FFI type: ", type, call. = FALSE)
}
## ------------------------------------------------------------------
## Runtime `.RtinyccCall` dispatch rules
##
## Dispatch small arities directly and fall back to do.call for larger
## signatures.
## ------------------------------------------------------------------
rtinycc_call(0L, call_ptr, args) %as%
{
.RtinyccCall(call_ptr)
}
rtinycc_call(1L, call_ptr, args) %as%
{
.RtinyccCall(call_ptr, args[[1]])
}
rtinycc_call(2L, call_ptr, args) %as%
{
.RtinyccCall(call_ptr, args[[1]], args[[2]])
}
rtinycc_call(3L, call_ptr, args) %as%
{
.RtinyccCall(call_ptr, args[[1]], args[[2]], args[[3]])
}
rtinycc_call(4L, call_ptr, args) %as%
{
.RtinyccCall(call_ptr, args[[1]], args[[2]], args[[3]], args[[4]])
}
rtinycc_call(5L, call_ptr, args) %as%
{
.RtinyccCall(
call_ptr,
args[[1]],
args[[2]],
args[[3]],
args[[4]],
args[[5]]
)
}
rtinycc_call(n_args, call_ptr, args) %as%
{
do.call(.RtinyccCall, c(list(call_ptr), args))
}
## ------------------------------------------------------------------
## Runtime platform dispatch rules
##
## Keep platform-specific path/name/env branching declarative using
## lambda.r dispatch instead of large switch/if chains.
## ------------------------------------------------------------------
tcc_platform_lib_paths("Linux") %as%
{
c(
"/usr/lib",
"/usr/lib64",
"/usr/local/lib",
"/lib",
"/lib64",
"/lib32",
"/usr/local/lib64",
"/usr/lib/x86_64-linux-gnu",
"/usr/lib/i386-linux-gnu",
"/lib/x86_64-linux-gnu",
"/lib32/x86_64-linux-gnu",
"/lib/x86_64-linux-gnu/",
# linux-unknown-gnu is for Alpine Linux with musl
# which uses different library paths
"/usr/lib/x86_64-linux-gnu",
"/usr/lib/i386-linux-gnu",
"/lib/x86_64-linux-gnu",
"/lib32/x86_64-linux-gnu",
"/usr/lib/x86_64-linux-musl",
"/usr/lib/i386-linux-musl",
"/lib/x86_64-linux-musl",
"/lib32/x86_64-linux-musl",
# amd/aarch64 multiarch paths
"/usr/lib/amd64-linux-gnu",
"/usr/lib/aarch64-linux-gnu"
# manylinux paths
)
}
tcc_platform_lib_paths("Darwin") %as%
{
c(
"/usr/lib",
"/usr/local/lib",
"/opt/homebrew/lib", # Apple Silicon Homebrew
"/opt/local/lib", # MacPorts
"/System/Library/Frameworks", # Apple system libs
"/Library/Frameworks"
)
}
tcc_platform_lib_paths("Windows") %as%
{
sysroot <- Sys.getenv("SystemRoot", unset = "C:/Windows")
r_bin <- file.path(R.home(), "bin")
r_arch_bin <- file.path(R.home(), "bin", .Platform$r_arch)
path_dirs <- strsplit(
Sys.getenv("PATH", ""),
.Platform$path.sep,
fixed = TRUE
)[[1]]
unique(c(
"C:/msys64/mingw64/lib", # MSYS2
"C:/msys64/mingw32/lib",
"C:/Rtools45/mingw_64/lib", # Rtools
"C:/Rtools45/mingw_32/lib",
"C:/Rtools44/mingw_64/lib", # Rtools
"C:/Rtools44/mingw_32/lib",
# Native Windows loader locations / common runtime dirs
file.path(sysroot, "System32"),
file.path(sysroot, "SysWOW64"),
r_bin,
r_arch_bin,
# User/runtime PATH entries (non-Rtools setups)
path_dirs
))
}
tcc_platform_lib_paths(sysname) %as%
{
c("/usr/lib", "/usr/local/lib")
}
tcc_short_lib_filename("Linux", name) %as%
{
paste0("lib", name, ".so")
}
tcc_short_lib_filename("Darwin", name) %as%
{
paste0("lib", name, ".dylib")
}
tcc_short_lib_filename("Windows", name) %as%
{
paste0(name, ".dll")
}
tcc_short_lib_filename(sysname, name) %as%
{
paste0("lib", name, ".so")
}
tcc_output_type_rule("memory") %as% 1L
tcc_output_type_rule("obj") %as% 3L
tcc_output_type_rule("dll") %as% 4L
tcc_output_type_rule("exe") %as% 2L
tcc_output_type_rule("preprocess") %as% 5L
tcc_loader_env_key("Windows") %as% "PATH"
tcc_loader_env_key("Darwin") %as% "DYLD_LIBRARY_PATH"
tcc_loader_env_key(sysname) %as% "LD_LIBRARY_PATH"
tcc_loader_env_sep("Windows") %as% .Platform$path.sep
tcc_loader_env_sep(sysname) %as% ":"
## ------------------------------------------------------------------
## FFI return conversion rules
##
## Produce C code that converts a C expression (`value_expr`) into an
## R `SEXP` return value. Used when generating the C -> R return thunk.
## ------------------------------------------------------------------
ffi_return_enum_rule(type_name, value_expr) %as%
{
sprintf("return ScalarInteger((int)%s);", value_expr)
}
ffi_return_rule(type, value_expr) %as%
{
stop("Unsupported FFI return type: ", type, call. = FALSE)
}
## ------------------------------------------------------------------
## Array return helpers
##
## Helper rules for allocating an R vector to hold array returns and for
## copying C buffers into the newly allocated R vector (`out`).
## ------------------------------------------------------------------
array_return_alloc_line_rule("raw", len_name) %as%
{
sprintf("SEXP out = PROTECT(allocVector(RAWSXP, %s));", len_name)
}
array_return_alloc_line_rule("integer_array", len_name) %as%
{
sprintf("SEXP out = PROTECT(allocVector(INTSXP, %s));", len_name)
}
array_return_alloc_line_rule("numeric_array", len_name) %as%
{
sprintf("SEXP out = PROTECT(allocVector(REALSXP, %s));", len_name)
}
array_return_alloc_line_rule("logical_array", len_name) %as%
{
sprintf("SEXP out = PROTECT(allocVector(LGLSXP, %s));", len_name)
}
array_return_alloc_line_rule(type, len_name) %as%
{
stop("Unsupported array return type: ", type, call. = FALSE)
}
array_return_copy_line_rule("raw", len_name, value_expr) %as%
{
sprintf(
" if (%s > 0) memcpy(RAW(out), %s, sizeof(uint8_t) * %s);",
len_name,
value_expr,
len_name
)
}
array_return_copy_line_rule("integer_array", len_name, value_expr) %as%
{
sprintf(
" if (%s > 0) memcpy(INTEGER(out), %s, sizeof(int32_t) * %s);",
len_name,
value_expr,
len_name
)
}
array_return_copy_line_rule("numeric_array", len_name, value_expr) %as%
{
sprintf(
" if (%s > 0) memcpy(REAL(out), %s, sizeof(double) * %s);",
len_name,
value_expr,
len_name
)
}
array_return_copy_line_rule("logical_array", len_name, value_expr) %as%
{
sprintf(
" if (%s > 0) memcpy(LOGICAL(out), %s, sizeof(int) * %s);",
len_name,
value_expr,
len_name
)
}
array_return_copy_line_rule(type, len_name, value_expr) %as%
{
stop("Unsupported array return type: ", type, call. = FALSE)
}
## ------------------------------------------------------------------
## Struct field getter rules
##
## Produce code that reads a field from a C struct (pointer `p`) and
## converts it into an R `SEXP` for consumer code. Rules are repeated
## for multiple primitive types for clarity and explicit handling.
## ------------------------------------------------------------------
struct_field_getter_rule("i8", field_name) %as%
{
sprintf("return ScalarInteger((int)p->%s);", field_name)
}
struct_field_getter_rule("i16", field_name) %as%
{
sprintf("return ScalarInteger((int)p->%s);", field_name)
}
struct_field_getter_rule("i32", field_name) %as%
{
sprintf("return ScalarInteger(p->%s);", field_name)
}
struct_field_getter_rule("i64", field_name) %as%
{
c(
sprintf(" int64_t __rtinycc_ret = p->%s;", field_name),
" if (__rtinycc_ret > INT64_C(9007199254740992) || __rtinycc_ret < -INT64_C(9007199254740992)) Rf_warning(\"i64 precision loss in R numeric\");",
" return ScalarReal((double)__rtinycc_ret);"
)
}
struct_field_getter_rule("u8", field_name) %as%
{
sprintf("return ScalarInteger((int)p->%s);", field_name)
}
struct_field_getter_rule("u16", field_name) %as%
{
sprintf("return ScalarInteger((int)p->%s);", field_name)
}
struct_field_getter_rule("u32", field_name) %as%
{
sprintf("return ScalarReal((double)p->%s);", field_name)
}
struct_field_getter_rule("u64", field_name) %as%
{
c(
sprintf(" uint64_t __rtinycc_ret = p->%s;", field_name),
" if (__rtinycc_ret > UINT64_C(9007199254740992)) Rf_warning(\"u64 precision loss in R numeric\");",
" return ScalarReal((double)__rtinycc_ret);"
)
}
struct_field_getter_rule("f32", field_name) %as%
{
sprintf("return ScalarReal((double)p->%s);", field_name)
}
struct_field_getter_rule("f64", field_name) %as%
{
sprintf("return ScalarReal(p->%s);", field_name)
}
struct_field_getter_rule("bool", field_name) %as%
{
sprintf("return ScalarLogical((int)p->%s);", field_name)
}
struct_field_getter_rule("cstring", field_name) %as%
{
c(
sprintf(" if (p->%s) {", field_name),
sprintf(" SEXP out = PROTECT(mkString(p->%s));", field_name),
" UNPROTECT(1);",
" return out;",
" } else {",
" return R_NilValue;",
" }"
)
}
struct_field_getter_rule("ptr", field_name) %as%
{
sprintf(
"return RC_make_borrowed_view(p->%s, Rf_install(\"rtinycc_borrowed\"), ext);",
field_name
)
}
struct_field_getter_rule(type_name, field_name) %as%
{
sprintf(
"return RC_make_borrowed_view(&p->%s, Rf_install(\"rtinycc_borrowed\"), ext);",
field_name
)
}
## ------------------------------------------------------------------
## Struct array field getter rules
##
## Like the struct field getters, but for array fields inside structs
## (access element `idx`). Returns an R scalar for the selected element.
## ------------------------------------------------------------------
struct_array_field_getter_rule("i8", field_name) %as%
{
sprintf("return ScalarInteger((int)p->%s[idx]);", field_name)
}
struct_array_field_getter_rule("i16", field_name) %as%
{
sprintf("return ScalarInteger((int)p->%s[idx]);", field_name)
}
struct_array_field_getter_rule("i32", field_name) %as%
{
sprintf("return ScalarInteger(p->%s[idx]);", field_name)
}
struct_array_field_getter_rule("i64", field_name) %as%
{
c(
sprintf(" int64_t __rtinycc_ret = p->%s[idx];", field_name),
" if (__rtinycc_ret > INT64_C(9007199254740992) || __rtinycc_ret < -INT64_C(9007199254740992)) Rf_warning(\"i64 precision loss in R numeric\");",
" return ScalarReal((double)__rtinycc_ret);"
)
}
struct_array_field_getter_rule("u8", field_name) %as%
{
sprintf("return ScalarInteger((int)p->%s[idx]);", field_name)
}
struct_array_field_getter_rule("u16", field_name) %as%
{
sprintf("return ScalarInteger((int)p->%s[idx]);", field_name)
}
struct_array_field_getter_rule("u32", field_name) %as%
{
sprintf("return ScalarReal((double)p->%s[idx]);", field_name)
}
struct_array_field_getter_rule("u64", field_name) %as%
{
c(
sprintf(" uint64_t __rtinycc_ret = p->%s[idx];", field_name),
" if (__rtinycc_ret > UINT64_C(9007199254740992)) Rf_warning(\"u64 precision loss in R numeric\");",
" return ScalarReal((double)__rtinycc_ret);"
)
}
struct_array_field_getter_rule("f32", field_name) %as%
{
sprintf("return ScalarReal((double)p->%s[idx]);", field_name)
}
struct_array_field_getter_rule("f64", field_name) %as%
{
sprintf("return ScalarReal(p->%s[idx]);", field_name)
}
struct_array_field_getter_rule("bool", field_name) %as%
{
sprintf("return ScalarLogical((int)p->%s[idx]);", field_name)
}
struct_array_field_getter_rule(type_name, field_name) %as%
{
sprintf("return ScalarInteger((int)p->%s[idx]);", field_name)
}
## ------------------------------------------------------------------
## Struct array field setter rules
##
## Generate code to set an element of an array field inside a struct
## from an R `SEXP` value (named `val`).
## ------------------------------------------------------------------
struct_array_field_setter_rule("i8", field_name) %as%
{
sprintf("p->%s[idx] = (int8_t)asInteger(val);", field_name)
}
struct_array_field_setter_rule("i16", field_name) %as%
{
sprintf("p->%s[idx] = (int16_t)asInteger(val);", field_name)
}
struct_array_field_setter_rule("i32", field_name) %as%
{
sprintf("p->%s[idx] = asInteger(val);", field_name)
}
struct_array_field_setter_rule("i64", field_name) %as%
{
sprintf("p->%s[idx] = (int64_t)REAL(val)[0];", field_name)
}
struct_array_field_setter_rule("u8", field_name) %as%
{
sprintf("p->%s[idx] = (uint8_t)asInteger(val);", field_name)
}
struct_array_field_setter_rule("u16", field_name) %as%
{
sprintf("p->%s[idx] = (uint16_t)asInteger(val);", field_name)
}
struct_array_field_setter_rule("u32", field_name) %as%
{
sprintf("p->%s[idx] = (uint32_t)REAL(val)[0];", field_name)
}
struct_array_field_setter_rule("u64", field_name) %as%
{
sprintf("p->%s[idx] = (uint64_t)REAL(val)[0];", field_name)
}
struct_array_field_setter_rule("f32", field_name) %as%
{
sprintf("p->%s[idx] = (float)REAL(val)[0];", field_name)
}
struct_array_field_setter_rule("f64", field_name) %as%
{
sprintf("p->%s[idx] = REAL(val)[0];", field_name)
}
struct_array_field_setter_rule("bool", field_name) %as%
{
sprintf("p->%s[idx] = (bool)asLogical(val);", field_name)
}
struct_array_field_setter_rule(type_name, field_name) %as%
{
sprintf("p->%s[idx] = (uint8_t)asInteger(val);", field_name)
}
## ------------------------------------------------------------------
## Struct field setter rules
##
## Produce code that assigns an R value (`val`) into a struct field
## (handles scalar fields and fixed-size char arrays). These are the
## counterparts to the getter rules above.
## ------------------------------------------------------------------
struct_field_setter_rule("i8", field_name, size) %as%
{
sprintf("p->%s = (int8_t)asInteger(val);", field_name)
}
struct_field_setter_rule("i16", field_name, size) %as%
{
sprintf("p->%s = (int16_t)asInteger(val);", field_name)
}
struct_field_setter_rule("i32", field_name, size) %as%
{
sprintf("p->%s = asInteger(val);", field_name)
}
struct_field_setter_rule("i64", field_name, size) %as%
{
sprintf("p->%s = (int64_t)REAL(val)[0];", field_name)
}
struct_field_setter_rule("u8", field_name, size) %as%
{
sprintf("p->%s = (uint8_t)asInteger(val);", field_name)
}
struct_field_setter_rule("u16", field_name, size) %as%
{
sprintf("p->%s = (uint16_t)asInteger(val);", field_name)
}
struct_field_setter_rule("u32", field_name, size) %as%
{
sprintf("p->%s = (uint32_t)REAL(val)[0];", field_name)
}
struct_field_setter_rule("u64", field_name, size) %as%
{
sprintf("p->%s = (uint64_t)REAL(val)[0];", field_name)
}
struct_field_setter_rule("f32", field_name, size) %as%
{
sprintf("p->%s = (float)asReal(val);", field_name)
}
struct_field_setter_rule("f64", field_name, size) %as%
{
sprintf("p->%s = asReal(val);", field_name)
}
struct_field_setter_rule("bool", field_name, size) %as%
{
sprintf("p->%s = (bool)asLogical(val);", field_name)
}
struct_field_setter_rule("ptr", field_name, size) %as%
{
sprintf("p->%s = R_ExternalPtrAddr(val);", field_name)
}
struct_field_setter_rule("cstring", field_name, size) %as%
{
if (!is.null(size)) {
return(c(
" const char *src = CHAR(STRING_ELT(val, 0));",
sprintf(" strncpy(p->%s, src, %d);", field_name, size - 1),
sprintf(" p->%s[%d] = '\\0';", field_name, size - 1)
))
}
sprintf("p->%s = CHAR(STRING_ELT(val, 0));", field_name)
}
struct_field_setter_rule(type_name, field_name, size) %as%
{
sprintf("// Cannot set field of type %s", type_name)
}
## ------------------------------------------------------------------
## Union field helper rules
##
## Unions are represented by mapping to the corresponding struct rules
## wherever possible; setting array members in unions is unsupported and
## emits placeholder comments. These rules delegate to struct helpers.
## ------------------------------------------------------------------
union_field_getter_rule(type_name, mem_name) %as%
{
struct_field_getter_rule(type_name, mem_name)
}
union_field_setter_rule("raw", mem_name, size) %as%
{
sprintf("// Cannot set union member array type raw")
}
union_field_setter_rule("integer_array", mem_name, size) %as%
{
sprintf("// Cannot set union member array type integer_array")
}
union_field_setter_rule("numeric_array", mem_name, size) %as%
{
sprintf("// Cannot set union member array type numeric_array")
}
union_field_setter_rule("logical_array", mem_name, size) %as%
{
sprintf("// Cannot set union member array type logical_array")
}
union_field_setter_rule("character_array", mem_name, size) %as%
{
sprintf("// Cannot set union member array type character_array")
}
union_field_setter_rule("cstring_array", mem_name, size) %as%
{
sprintf("// Cannot set union member array type cstring_array")
}
union_field_setter_rule(type_name, mem_name, size) %as%
{
struct_field_setter_rule(type_name, mem_name, size)
}
## ------------------------------------------------------------------
## Callback argument kind/value helpers
##
## Map a callback argument type to an internal CB_ARG_* kind and to the
## field name that holds the value inside the generic callback value
## union struct used by the runtime. These are small lookup rules used
## when generating callback trampoline code.
## ------------------------------------------------------------------
cb_arg_kind_rule("ptr") %as%
{
"CB_ARG_PTR"
}
cb_arg_kind_rule("cstring") %as%
{
"CB_ARG_CSTRING"
}
cb_arg_kind_rule("real") %as%
{
"CB_ARG_REAL"
}
cb_arg_kind_rule("logical") %as%
{
"CB_ARG_LOGICAL"
}
cb_arg_kind_rule("int") %as%
{
"CB_ARG_INT"
}
cb_arg_value_rule("ptr", arg_expr) %as%
{
list(field = "p", expr = arg_expr)
}
cb_arg_value_rule("cstring", arg_expr) %as%
{
list(field = "s", expr = arg_expr)
}
cb_arg_value_rule("real", arg_expr) %as%
{
list(field = "d", expr = arg_expr)
}
cb_arg_value_rule("logical", arg_expr) %as%
{
list(field = "i", expr = arg_expr)
}
cb_arg_value_rule("int", arg_expr) %as%
{
list(field = "i", expr = arg_expr)
}
## ------------------------------------------------------------------
## C default return helpers
##
## When a callback or conversion fails we need a sensible C-level default
## return statement for a given C type. These helpers emit appropriately
## indented return lines (used by many `r_to_c_return_lines_rule` cases).
## ------------------------------------------------------------------
c_default_return_rule("void", indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
paste0(pad, "return;")
}
c_default_return_rule("sexp", indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
paste0(pad, "return R_NilValue;")
}
c_default_return_rule("ptr", indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
paste0(pad, "return NULL;")
}
c_default_return_rule("cstring", indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
paste0(pad, "return NULL;")
}
c_default_return_rule("real", indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
paste0(pad, "return NA_REAL;")
}
c_default_return_rule("logical", indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
paste0(pad, "return -1;")
}
c_default_return_rule("int", indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
paste0(pad, "return NA_INTEGER;")
}
## ------------------------------------------------------------------
## C <-> SEXP type name helpers
##
## Map between C types used in generated stubs and the canonical names
## used for selecting conversion rules and SEXP constructors.
## ------------------------------------------------------------------
c_sexp_type_rule("ptr") %as%
{
"void*"
}
c_sexp_type_rule("int") %as%
{
"int"
}
c_sexp_type_rule("longlong") %as%
{
"long long"
}
c_sexp_type_rule("real") %as%
{
"double"
}
c_sexp_type_rule("cstring") %as%
{
"const char*"
}
c_sexp_type_rule("bool") %as%
{
"bool"
}
## ------------------------------------------------------------------
## Canonical R-facing type keys
##
## Map C types into the compact R-facing type keys (e.g. "i32", "f64",
## "ptr") used across many rule lookups.
## ------------------------------------------------------------------
c_r_type_rule("ptr") %as%
{
"ptr"
}
c_r_type_rule("i32") %as%
{
"i32"
}
c_r_type_rule("f64") %as%
{
"f64"
}
c_r_type_rule("cstring") %as%
{
"cstring"
}
c_r_type_rule("bool") %as%
{
"bool"
}
c_r_type_rule("void") %as%
{
"void"
}
c_r_type_rule("sexp") %as%
{
"sexp"
}
## ------------------------------------------------------------------
## SEXP constructor helpers
##
## Provide the name of the constructor (or the full call form) used to
## create a SEXP from a native C value during return conversion.
## ------------------------------------------------------------------
sexp_constructor_rule("ptr") %as%
{
"R_MakeExternalPtr"
}
sexp_constructor_rule("int") %as%
{
"ScalarInteger"
}
sexp_constructor_rule("real") %as%
{
"ScalarReal"
}
sexp_constructor_rule("cstring") %as%
{
"mkString"
}
sexp_constructor_rule("bool") %as%
{
"ScalarLogical"
}
sexp_constructor_rule("sexp") %as%
{
"identity"
}
## ------------------------------------------------------------------
## SEXP constructor call forms
##
## Produce the string of C code to call the SEXP constructor for a given
## expression (used when building return expressions inline).
## ------------------------------------------------------------------
sexp_constructor_call_rule("ptr", arg_expr) %as%
{
sprintf("RC_make_unowned_ptr(%s, R_NilValue)", arg_expr)
}
sexp_constructor_call_rule("cstring", arg_expr) %as%
{
sprintf(
"({ const char* __rtinycc_tmp = %s; __rtinycc_tmp ? mkString(__rtinycc_tmp) : R_NilValue; })",
arg_expr
)
}
sexp_constructor_call_rule("int", arg_expr) %as%
{
sprintf("ScalarInteger(%s)", arg_expr)
}
sexp_constructor_call_rule("real", arg_expr) %as%
{
sprintf("ScalarReal(%s)", arg_expr)
}
sexp_constructor_call_rule("bool", arg_expr) %as%
{
sprintf("ScalarLogical(%s)", arg_expr)
}
sexp_constructor_call_rule("sexp", arg_expr) %as%
{
sprintf("%s", arg_expr)
}
## ------------------------------------------------------------------
## R -> C converter helpers
##
## Provide the simple converter function name used to extract C values
## from R `SEXP` objects (e.g. `asInteger`, `asReal`, `R_ExternalPtrAddr`).
## ------------------------------------------------------------------
r_to_c_converter_rule("ptr") %as%
{
"R_ExternalPtrAddr"
}
r_to_c_converter_rule("int") %as%
{
"asInteger"
}
r_to_c_converter_rule("real") %as%
{
"asReal"
}
r_to_c_converter_rule("cstring") %as%
{
"CHAR"
}
r_to_c_converter_rule("bool") %as%
{
"asLogical"
}
r_to_c_converter_rule("sexp") %as%
{
"identity"
}
## ------------------------------------------------------------------
## R -> C return conversion lines
##
## These rules emit one or more lines of C that validate and convert
## a returned R `SEXP` (from a callback) into the expected C return
## value. They handle NA/NA_REAL checks, range checks, and emit warnings
## and default returns on error.
## ------------------------------------------------------------------
r_to_c_return_lines_rule("void", c_type, result_var, indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
paste0(pad, "return;")
}
r_to_c_return_lines_rule("sexp", c_type, result_var, indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
paste0(pad, "return ", result_var, ";")
}
r_to_c_return_lines_rule("ptr", c_type, result_var, indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
paste0(pad, "return R_ExternalPtrAddr(", result_var, ");")
}
r_to_c_return_lines_rule("cstring", c_type, result_var, indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
c(
paste0(pad, "if (", result_var, " == R_NilValue) return NULL;"),
paste0(
pad,
"if (!Rf_isString(",
result_var,
") || XLENGTH(",
result_var,
") < 1) {"
),
paste0(pad, " Rf_warning(\"callback returned non-string\");"),
paste0(pad, " return NULL;"),
paste0(pad, "}"),
paste0(pad, "SEXP _str = STRING_ELT(", result_var, ", 0);"),
paste0(pad, "if (_str == NA_STRING) return NULL;"),
paste0(pad, "return Rf_translateCharUTF8(_str);")
)
}
r_to_c_return_lines_rule("bool", c_type, result_var, indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
default_line <- get_c_default_return(c_type, indent = indent)
c(
paste0(pad, "int _v = asLogical(", result_var, ");"),
paste0(pad, "if (_v == NA_LOGICAL) {"),
paste0(pad, " Rf_warning(\"callback returned NA logical\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "return (_v != 0);")
)
}
r_to_c_return_lines_rule("i8", c_type, result_var, indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
default_line <- get_c_default_return(c_type, indent = indent)
c(
paste0(pad, "int _v = asInteger(", result_var, ");"),
paste0(pad, "if (_v == NA_INTEGER) {"),
paste0(pad, " Rf_warning(\"callback returned NA integer\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "if (_v < INT8_MIN || _v > INT8_MAX) {"),
paste0(pad, " Rf_warning(\"callback returned out-of-range i8\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "return (int8_t)_v;")
)
}
r_to_c_return_lines_rule("i16", c_type, result_var, indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
default_line <- get_c_default_return(c_type, indent = indent)
c(
paste0(pad, "int _v = asInteger(", result_var, ");"),
paste0(pad, "if (_v == NA_INTEGER) {"),
paste0(pad, " Rf_warning(\"callback returned NA integer\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "if (_v < INT16_MIN || _v > INT16_MAX) {"),
paste0(pad, " Rf_warning(\"callback returned out-of-range i16\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "return (int16_t)_v;")
)
}
r_to_c_return_lines_rule("i32", c_type, result_var, indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
default_line <- get_c_default_return(c_type, indent = indent)
c(
paste0(pad, "int _v = asInteger(", result_var, ");"),
paste0(pad, "if (_v == NA_INTEGER) {"),
paste0(pad, " Rf_warning(\"callback returned NA integer\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "return (int32_t)_v;")
)
}
r_to_c_return_lines_rule("int", c_type, result_var, indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
default_line <- get_c_default_return(c_type, indent = indent)
c(
paste0(pad, "int _v = asInteger(", result_var, ");"),
paste0(pad, "if (_v == NA_INTEGER) {"),
paste0(pad, " Rf_warning(\"callback returned NA integer\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "return _v;")
)
}
r_to_c_return_lines_rule("u8", c_type, result_var, indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
default_line <- get_c_default_return(c_type, indent = indent)
c(
paste0(pad, "int _v = asInteger(", result_var, ");"),
paste0(pad, "if (_v == NA_INTEGER) {"),
paste0(pad, " Rf_warning(\"callback returned NA integer\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "if (_v < 0 || _v > UINT8_MAX) {"),
paste0(pad, " Rf_warning(\"callback returned out-of-range u8\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "return (uint8_t)_v;")
)
}
r_to_c_return_lines_rule("u16", c_type, result_var, indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
default_line <- get_c_default_return(c_type, indent = indent)
c(
paste0(pad, "int _v = asInteger(", result_var, ");"),
paste0(pad, "if (_v == NA_INTEGER) {"),
paste0(pad, " Rf_warning(\"callback returned NA integer\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "if (_v < 0 || _v > UINT16_MAX) {"),
paste0(pad, " Rf_warning(\"callback returned out-of-range u16\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "return (uint16_t)_v;")
)
}
r_to_c_return_lines_rule("u32", c_type, result_var, indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
default_line <- get_c_default_return(c_type, indent = indent)
c(
paste0(pad, "double _v = asReal(", result_var, ");"),
paste0(pad, "if (ISNA(_v) || ISNAN(_v)) {"),
paste0(pad, " Rf_warning(\"callback returned NA numeric\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "if (_v < 0 || _v > (double)UINT32_MAX) {"),
paste0(pad, " Rf_warning(\"callback returned out-of-range u32\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "if (trunc(_v) != _v) {"),
paste0(pad, " Rf_warning(\"callback returned non-integer numeric\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "return (uint32_t)_v;")
)
}
r_to_c_return_lines_rule("i64", c_type, result_var, indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
default_line <- get_c_default_return(c_type, indent = indent)
c(
paste0(pad, "double _v = asReal(", result_var, ");"),
paste0(pad, "if (ISNA(_v) || ISNAN(_v)) {"),
paste0(pad, " Rf_warning(\"callback returned NA numeric\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "if (fabs(_v) > 9007199254740992.0) {"),
paste0(
pad,
" Rf_warning(\"callback i64 precision loss in R numeric\");"
),
default_line,
paste0(pad, "}"),
paste0(pad, "if (trunc(_v) != _v) {"),
paste0(pad, " Rf_warning(\"callback returned non-integer numeric\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "if (_v < (double)INT64_MIN || _v > (double)INT64_MAX) {"),
paste0(pad, " Rf_warning(\"callback returned out-of-range i64\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "return (int64_t)_v;")
)
}
r_to_c_return_lines_rule("u64", c_type, result_var, indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
default_line <- get_c_default_return(c_type, indent = indent)
c(
paste0(pad, "double _v = asReal(", result_var, ");"),
paste0(pad, "if (ISNA(_v) || ISNAN(_v)) {"),
paste0(pad, " Rf_warning(\"callback returned NA numeric\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "if (_v < 0) {"),
paste0(pad, " Rf_warning(\"callback returned out-of-range u64\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "if (fabs(_v) > 9007199254740992.0) {"),
paste0(
pad,
" Rf_warning(\"callback u64 precision loss in R numeric\");"
),
default_line,
paste0(pad, "}"),
paste0(pad, "if (trunc(_v) != _v) {"),
paste0(pad, " Rf_warning(\"callback returned non-integer numeric\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "if (_v > (double)UINT64_MAX) {"),
paste0(pad, " Rf_warning(\"callback returned out-of-range u64\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "return (uint64_t)_v;")
)
}
r_to_c_return_lines_rule("double", c_type, result_var, indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
default_line <- get_c_default_return(c_type, indent = indent)
c(
paste0(pad, "double _v = asReal(", result_var, ");"),
paste0(pad, "if (ISNA(_v) || ISNAN(_v)) {"),
paste0(pad, " Rf_warning(\"callback returned NA numeric\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "return _v;")
)
}
r_to_c_return_lines_rule("float", c_type, result_var, indent) %as%
{
pad <- paste(rep(" ", indent), collapse = "")
default_line <- get_c_default_return(c_type, indent = indent)
c(
paste0(pad, "double _v = asReal(", result_var, ");"),
paste0(pad, "if (ISNA(_v) || ISNAN(_v)) {"),
paste0(pad, " Rf_warning(\"callback returned NA numeric\");"),
default_line,
paste0(pad, "}"),
paste0(pad, "return (float)_v;")
)
}
## ------------------------------------------------------------------
## Callback kind key mapping
##
## Map C types (and pointer-ness) to the compact kinds used by the
## callback trampoline generator (ptr, cstring, real, logical, int).
## ------------------------------------------------------------------
cb_kind_key_rule(type_name, TRUE) %as%
{
"ptr"
}
cb_kind_key_rule("void*", FALSE) %as%
{
"ptr"
}
cb_kind_key_rule("void *", FALSE) %as%
{
"ptr"
}
cb_kind_key_rule("ptr", FALSE) %as%
{
"ptr"
}
cb_kind_key_rule("char*", FALSE) %as%
{
"cstring"
}
cb_kind_key_rule("const char*", FALSE) %as%
{
"cstring"
}
cb_kind_key_rule("string", FALSE) %as%
{
"cstring"
}
cb_kind_key_rule("cstring", FALSE) %as%
{
"cstring"
}
cb_kind_key_rule("double", FALSE) %as%
{
"real"
}
cb_kind_key_rule("float", FALSE) %as%
{
"real"
}
cb_kind_key_rule("f64", FALSE) %as%
{
"real"
}
cb_kind_key_rule("f32", FALSE) %as%
{
"real"
}
cb_kind_key_rule("int64_t", FALSE) %as%
{
"real"
}
cb_kind_key_rule("i64", FALSE) %as%
{
"real"
}
cb_kind_key_rule("uint32_t", FALSE) %as%
{
"real"
}
cb_kind_key_rule("u32", FALSE) %as%
{
"real"
}
cb_kind_key_rule("uint64_t", FALSE) %as%
{
"real"
}
cb_kind_key_rule("u64", FALSE) %as%
{
"real"
}
cb_kind_key_rule("bool", FALSE) %as%
{
"logical"
}
cb_kind_key_rule("_Bool", FALSE) %as%
{
"logical"
}
cb_kind_key_rule(type_name, is_ptr) %as%
{
"int"
}
## ------------------------------------------------------------------
## C-to-R type key map for arguments
##
## These rules map C type spellings (and pointer-ness) to the canonical
## R-facing type key used across code generation (e.g. "i32", "f64",
## "ptr"). This centralizes many small spelling variants in one place.
## ------------------------------------------------------------------
c_r_key_rule(type_name, TRUE) %as%
{
"ptr"
}
c_r_key_rule("void*", FALSE) %as%
{
"ptr"
}
c_r_key_rule("void *", FALSE) %as%
{
"ptr"
}
c_r_key_rule("ptr", FALSE) %as%
{
"ptr"
}
c_r_key_rule("int", FALSE) %as%
{
"i32"
}
c_r_key_rule("int32_t", FALSE) %as%
{
"i32"
}
c_r_key_rule("i32", FALSE) %as%
{
"i32"
}
c_r_key_rule("int16_t", FALSE) %as%
{
"i32"
}
c_r_key_rule("i16", FALSE) %as%
{
"i32"
}
c_r_key_rule("int8_t", FALSE) %as%
{
"i32"
}
c_r_key_rule("i8", FALSE) %as%
{
"i32"
}
c_r_key_rule("long", FALSE) %as%
{
"i32"
}
c_r_key_rule("long long", FALSE) %as%
{
"i32"
}
c_r_key_rule("int64_t", FALSE) %as%
{
"i32"
}
c_r_key_rule("i64", FALSE) %as%
{
"i32"
}
c_r_key_rule("uint8_t", FALSE) %as%
{
"i32"
}
c_r_key_rule("u8", FALSE) %as%
{
"i32"
}
c_r_key_rule("uint16_t", FALSE) %as%
{
"i32"
}
c_r_key_rule("u16", FALSE) %as%
{
"i32"
}
c_r_key_rule("uint32_t", FALSE) %as%
{
"i32"
}
c_r_key_rule("u32", FALSE) %as%
{
"i32"
}
c_r_key_rule("uint64_t", FALSE) %as%
{
"i32"
}
c_r_key_rule("u64", FALSE) %as%
{
"i32"
}
c_r_key_rule("double", FALSE) %as%
{
"f64"
}
c_r_key_rule("float", FALSE) %as%
{
"f64"
}
c_r_key_rule("f64", FALSE) %as%
{
"f64"
}
c_r_key_rule("f32", FALSE) %as%
{
"f64"
}
c_r_key_rule("char*", FALSE) %as%
{
"cstring"
}
c_r_key_rule("const char*", FALSE) %as%
{
"cstring"
}
c_r_key_rule("string", FALSE) %as%
{
"cstring"
}
c_r_key_rule("cstring", FALSE) %as%
{
"cstring"
}
c_r_key_rule("bool", FALSE) %as%
{
"bool"
}
c_r_key_rule("_Bool", FALSE) %as%
{
"bool"
}
c_r_key_rule("void", FALSE) %as%
{
"void"
}
c_r_key_rule("SEXP", FALSE) %as%
{
"sexp"
}
c_r_key_rule("sexp", FALSE) %as%
{
"sexp"
}
c_r_key_rule(type_name, is_ptr) %as%
{
"ptr"
}
## ------------------------------------------------------------------
## SEXP constructor key mapping
##
## Map C type names to the key used to select a SEXP constructor (e.g.
## mkString, ScalarReal). Handles pointer cases specially.
## ------------------------------------------------------------------
sexp_ctor_key_rule(type_name, TRUE) %as%
{
"ptr"
}
sexp_ctor_key_rule("void*", FALSE) %as%
{
"ptr"
}
sexp_ctor_key_rule("void *", FALSE) %as%
{
"ptr"
}
sexp_ctor_key_rule("ptr", FALSE) %as%
{
"ptr"
}
sexp_ctor_key_rule("int", FALSE) %as%
{
"int"
}
sexp_ctor_key_rule("int32_t", FALSE) %as%
{
"int"
}
sexp_ctor_key_rule("i32", FALSE) %as%
{
"int"
}
sexp_ctor_key_rule("int16_t", FALSE) %as%
{
"int"
}
sexp_ctor_key_rule("i16", FALSE) %as%
{
"int"
}
sexp_ctor_key_rule("int8_t", FALSE) %as%
{
"int"
}
sexp_ctor_key_rule("i8", FALSE) %as%
{
"int"
}
sexp_ctor_key_rule("uint8_t", FALSE) %as%
{
"int"
}
sexp_ctor_key_rule("u8", FALSE) %as%
{
"int"
}
sexp_ctor_key_rule("uint16_t", FALSE) %as%
{
"int"
}
sexp_ctor_key_rule("u16", FALSE) %as%
{
"int"
}
sexp_ctor_key_rule("long", FALSE) %as%
{
"real"
}
sexp_ctor_key_rule("long long", FALSE) %as%
{
"real"
}
sexp_ctor_key_rule("int64_t", FALSE) %as%
{
"real"
}
sexp_ctor_key_rule("i64", FALSE) %as%
{
"real"
}
sexp_ctor_key_rule("uint32_t", FALSE) %as%
{
"real"
}
sexp_ctor_key_rule("u32", FALSE) %as%
{
"real"
}
sexp_ctor_key_rule("uint64_t", FALSE) %as%
{
"real"
}
sexp_ctor_key_rule("u64", FALSE) %as%
{
"real"
}
sexp_ctor_key_rule("double", FALSE) %as%
{
"real"
}
sexp_ctor_key_rule("float", FALSE) %as%
{
"real"
}
sexp_ctor_key_rule("f64", FALSE) %as%
{
"real"
}
sexp_ctor_key_rule("f32", FALSE) %as%
{
"real"
}
sexp_ctor_key_rule("char*", FALSE) %as%
{
"cstring"
}
sexp_ctor_key_rule("const char*", FALSE) %as%
{
"cstring"
}
sexp_ctor_key_rule("string", FALSE) %as%
{
"cstring"
}
sexp_ctor_key_rule("cstring", FALSE) %as%
{
"cstring"
}
sexp_ctor_key_rule("bool", FALSE) %as%
{
"bool"
}
sexp_ctor_key_rule("_Bool", FALSE) %as%
{
"bool"
}
sexp_ctor_key_rule("SEXP", FALSE) %as%
{
"sexp"
}
sexp_ctor_key_rule("sexp", FALSE) %as%
{
"sexp"
}
sexp_ctor_key_rule(type_name, is_ptr) %as%
{
"ptr"
}
## ------------------------------------------------------------------
## R -> C key map
##
## Map C type spellings to the key that selects the appropriate R -> C
## converter (e.g. asInteger, asReal, R_ExternalPtrAddr). Pointer types
## map to "ptr".
## ------------------------------------------------------------------
r_to_c_key_rule(type_name, TRUE) %as%
{
"ptr"
}
r_to_c_key_rule("void*", FALSE) %as%
{
"ptr"
}
r_to_c_key_rule("void *", FALSE) %as%
{
"ptr"
}
r_to_c_key_rule("ptr", FALSE) %as%
{
"ptr"
}
r_to_c_key_rule("int", FALSE) %as%
{
"int"
}
r_to_c_key_rule("int32_t", FALSE) %as%
{
"int"
}
r_to_c_key_rule("i32", FALSE) %as%
{
"int"
}
r_to_c_key_rule("int16_t", FALSE) %as%
{
"int"
}
r_to_c_key_rule("i16", FALSE) %as%
{
"int"
}
r_to_c_key_rule("int8_t", FALSE) %as%
{
"int"
}
r_to_c_key_rule("i8", FALSE) %as%
{
"int"
}
r_to_c_key_rule("uint8_t", FALSE) %as%
{
"int"
}
r_to_c_key_rule("u8", FALSE) %as%
{
"int"
}
r_to_c_key_rule("uint16_t", FALSE) %as%
{
"int"
}
r_to_c_key_rule("u16", FALSE) %as%
{
"int"
}
r_to_c_key_rule("long", FALSE) %as%
{
"real"
}
r_to_c_key_rule("long long", FALSE) %as%
{
"real"
}
r_to_c_key_rule("int64_t", FALSE) %as%
{
"real"
}
r_to_c_key_rule("i64", FALSE) %as%
{
"real"
}
r_to_c_key_rule("uint32_t", FALSE) %as%
{
"real"
}
r_to_c_key_rule("u32", FALSE) %as%
{
"real"
}
r_to_c_key_rule("uint64_t", FALSE) %as%
{
"real"
}
r_to_c_key_rule("u64", FALSE) %as%
{
"real"
}
r_to_c_key_rule("double", FALSE) %as%
{
"real"
}
r_to_c_key_rule("float", FALSE) %as%
{
"real"
}
r_to_c_key_rule("f64", FALSE) %as%
{
"real"
}
r_to_c_key_rule("f32", FALSE) %as%
{
"real"
}
r_to_c_key_rule("char*", FALSE) %as%
{
"cstring"
}
r_to_c_key_rule("const char*", FALSE) %as%
{
"cstring"
}
r_to_c_key_rule("string", FALSE) %as%
{
"cstring"
}
r_to_c_key_rule("cstring", FALSE) %as%
{
"cstring"
}
r_to_c_key_rule("bool", FALSE) %as%
{
"bool"
}
r_to_c_key_rule("_Bool", FALSE) %as%
{
"bool"
}
r_to_c_key_rule("SEXP", FALSE) %as%
{
"sexp"
}
r_to_c_key_rule("sexp", FALSE) %as%
{
"sexp"
}
r_to_c_key_rule(type_name, is_ptr) %as%
{
"ptr"
}
## ------------------------------------------------------------------
## Default type key mapping
##
## A general-purpose fallback mapping used when no more specific key
## mapping is appropriate. This helps many rule lookups remain simple.
## ------------------------------------------------------------------
default_key_rule("void", FALSE) %as%
{
"void"
}
default_key_rule("SEXP", FALSE) %as%
{
"sexp"
}
default_key_rule("sexp", FALSE) %as%
{
"sexp"
}
default_key_rule(type_name, TRUE) %as%
{
"ptr"
}
default_key_rule("void*", FALSE) %as%
{
"ptr"
}
default_key_rule("void *", FALSE) %as%
{
"ptr"
}
default_key_rule("ptr", FALSE) %as%
{
"ptr"
}
default_key_rule("char*", FALSE) %as%
{
"cstring"
}
default_key_rule("const char*", FALSE) %as%
{
"cstring"
}
default_key_rule("string", FALSE) %as%
{
"cstring"
}
default_key_rule("cstring", FALSE) %as%
{
"cstring"
}
default_key_rule("double", FALSE) %as%
{
"real"
}
default_key_rule("float", FALSE) %as%
{
"real"
}
default_key_rule("f64", FALSE) %as%
{
"real"
}
default_key_rule("f32", FALSE) %as%
{
"real"
}
default_key_rule("bool", FALSE) %as%
{
"logical"
}
default_key_rule("_Bool", FALSE) %as%
{
"logical"
}
default_key_rule(type_name, is_ptr) %as%
{
"int"
}
## ------------------------------------------------------------------
## SEXP type key mapping
##
## Determine which SEXP type (int/real/longlong/ptr/cstring/etc.) should
## be used for a C type when generating wrappers that will box/unbox
## values to/from R.
## ------------------------------------------------------------------
sexp_type_key_rule(type_name, TRUE) %as%
{
"ptr"
}
sexp_type_key_rule("int", FALSE) %as%
{
"int"
}
sexp_type_key_rule("int32_t", FALSE) %as%
{
"int"
}
sexp_type_key_rule("i32", FALSE) %as%
{
"int"
}
sexp_type_key_rule("int16_t", FALSE) %as%
{
"int"
}
sexp_type_key_rule("i16", FALSE) %as%
{
"int"
}
sexp_type_key_rule("int8_t", FALSE) %as%
{
"int"
}
sexp_type_key_rule("i8", FALSE) %as%
{
"int"
}
sexp_type_key_rule("long", FALSE) %as%
{
"longlong"
}
sexp_type_key_rule("long long", FALSE) %as%
{
"longlong"
}
sexp_type_key_rule("int64_t", FALSE) %as%
{
"longlong"
}
sexp_type_key_rule("i64", FALSE) %as%
{
"longlong"
}
sexp_type_key_rule("uint8_t", FALSE) %as%
{
"longlong"
}
sexp_type_key_rule("u8", FALSE) %as%
{
"longlong"
}
sexp_type_key_rule("uint16_t", FALSE) %as%
{
"longlong"
}
sexp_type_key_rule("u16", FALSE) %as%
{
"longlong"
}
sexp_type_key_rule("uint32_t", FALSE) %as%
{
"longlong"
}
sexp_type_key_rule("u32", FALSE) %as%
{
"longlong"
}
sexp_type_key_rule("uint64_t", FALSE) %as%
{
"longlong"
}
sexp_type_key_rule("u64", FALSE) %as%
{
"longlong"
}
sexp_type_key_rule("double", FALSE) %as%
{
"real"
}
sexp_type_key_rule("float", FALSE) %as%
{
"real"
}
sexp_type_key_rule("f64", FALSE) %as%
{
"real"
}
sexp_type_key_rule("f32", FALSE) %as%
{
"real"
}
sexp_type_key_rule("char*", FALSE) %as%
{
"cstring"
}
sexp_type_key_rule("const char*", FALSE) %as%
{
"cstring"
}
sexp_type_key_rule("string", FALSE) %as%
{
"cstring"
}
sexp_type_key_rule("cstring", FALSE) %as%
{
"cstring"
}
sexp_type_key_rule("void*", FALSE) %as%
{
"ptr"
}
sexp_type_key_rule("void *", FALSE) %as%
{
"ptr"
}
sexp_type_key_rule("ptr", FALSE) %as%
{
"ptr"
}
sexp_type_key_rule("bool", FALSE) %as%
{
"bool"
}
sexp_type_key_rule("_Bool", FALSE) %as%
{
"bool"
}
sexp_type_key_rule("SEXP", FALSE) %as%
{
"sexp"
}
sexp_type_key_rule("sexp", FALSE) %as%
{
"sexp"
}
sexp_type_key_rule(type_name, is_ptr) %as%
{
"ptr"
}
## ------------------------------------------------------------------
## Return type key mapping
##
## Map C return types to the compact keys used by the ffi_return_rule
## lookup (e.g. "i8", "i32", "double", "cstring", "ptr").
## ------------------------------------------------------------------
return_key_rule("void", FALSE) %as%
{
"void"
}
return_key_rule("SEXP", FALSE) %as%
{
"sexp"
}
return_key_rule("sexp", FALSE) %as%
{
"sexp"
}
return_key_rule(type_name, TRUE) %as%
{
"ptr"
}
return_key_rule("void*", FALSE) %as%
{
"ptr"
}
return_key_rule("void *", FALSE) %as%
{
"ptr"
}
return_key_rule("ptr", FALSE) %as%
{
"ptr"
}
return_key_rule("char*", FALSE) %as%
{
"cstring"
}
return_key_rule("const char*", FALSE) %as%
{
"cstring"
}
return_key_rule("string", FALSE) %as%
{
"cstring"
}
return_key_rule("cstring", FALSE) %as%
{
"cstring"
}
return_key_rule("bool", FALSE) %as%
{
"bool"
}
return_key_rule("_Bool", FALSE) %as%
{
"bool"
}
return_key_rule("int8_t", FALSE) %as%
{
"i8"
}
return_key_rule("i8", FALSE) %as%
{
"i8"
}
return_key_rule("int16_t", FALSE) %as%
{
"i16"
}
return_key_rule("i16", FALSE) %as%
{
"i16"
}
return_key_rule("int32_t", FALSE) %as%
{
"i32"
}
return_key_rule("i32", FALSE) %as%
{
"i32"
}
return_key_rule("int", FALSE) %as%
{
"int"
}
return_key_rule("long", FALSE) %as%
{
"int"
}
return_key_rule("short", FALSE) %as%
{
"int"
}
return_key_rule("uint8_t", FALSE) %as%
{
"u8"
}
return_key_rule("u8", FALSE) %as%
{
"u8"
}
return_key_rule("uint16_t", FALSE) %as%
{
"u16"
}
return_key_rule("u16", FALSE) %as%
{
"u16"
}
return_key_rule("uint32_t", FALSE) %as%
{
"u32"
}
return_key_rule("u32", FALSE) %as%
{
"u32"
}
return_key_rule("int64_t", FALSE) %as%
{
"i64"
}
return_key_rule("i64", FALSE) %as%
{
"i64"
}
return_key_rule("long long", FALSE) %as%
{
"i64"
}
return_key_rule("uint64_t", FALSE) %as%
{
"u64"
}
return_key_rule("u64", FALSE) %as%
{
"u64"
}
return_key_rule("double", FALSE) %as%
{
"double"
}
return_key_rule("f64", FALSE) %as%
{
"double"
}
return_key_rule("float", FALSE) %as%
{
"float"
}
return_key_rule("f32", FALSE) %as%
{
"float"
}
return_key_rule(type_name, is_ptr) %as%
{
"ptr"
}
## ------------------------------------------------------------------
## FFI C type canonicalization
##
## Map many C type spellings into the canonical internal FFI type keys
## used throughout this file (i8/i16/i32/i64/u8/u16/u32/u64/f32/f64/ptr
## etc.). This central lookup keeps downstream rule selection uniform.
## ------------------------------------------------------------------
ffi_c_type_map_rule(type_name, TRUE, is_ptr) %as%
{
"ptr"
}
ffi_c_type_map_rule(type_name, FALSE, TRUE) %as%
{
"ptr"
}
ffi_c_type_map_rule("void", FALSE, FALSE) %as%
{
"void"
}
ffi_c_type_map_rule("bool", FALSE, FALSE) %as%
{
"bool"
}
ffi_c_type_map_rule("_Bool", FALSE, FALSE) %as%
{
"bool"
}
ffi_c_type_map_rule("SEXP", FALSE, FALSE) %as%
{
"sexp"
}
ffi_c_type_map_rule("sexp", FALSE, FALSE) %as%
{
"sexp"
}
ffi_c_type_map_rule("int", FALSE, FALSE) %as%
{
"i32"
}
ffi_c_type_map_rule("signed", FALSE, FALSE) %as%
{
"i32"
}
ffi_c_type_map_rule("int32_t", FALSE, FALSE) %as%
{
"i32"
}
ffi_c_type_map_rule("__int32", FALSE, FALSE) %as%
{
"i32"
}
ffi_c_type_map_rule("signed int", FALSE, FALSE) %as%
{
"i32"
}
ffi_c_type_map_rule("short", FALSE, FALSE) %as%
{
"i16"
}
ffi_c_type_map_rule("short int", FALSE, FALSE) %as%
{
"i16"
}
ffi_c_type_map_rule("signed short", FALSE, FALSE) %as%
{
"i16"
}
ffi_c_type_map_rule("signed short int", FALSE, FALSE) %as%
{
"i16"
}
ffi_c_type_map_rule("int16_t", FALSE, FALSE) %as%
{
"i16"
}
ffi_c_type_map_rule("char", FALSE, FALSE) %as%
{
"i8"
}
ffi_c_type_map_rule("signed char", FALSE, FALSE) %as%
{
"i8"
}
ffi_c_type_map_rule("int8_t", FALSE, FALSE) %as%
{
"i8"
}
ffi_c_type_map_rule("long", FALSE, FALSE) %as%
{
"i64"
}
ffi_c_type_map_rule("long int", FALSE, FALSE) %as%
{
"i64"
}
ffi_c_type_map_rule("long long", FALSE, FALSE) %as%
{
"i64"
}
ffi_c_type_map_rule("long long int", FALSE, FALSE) %as%
{
"i64"
}
ffi_c_type_map_rule("signed long", FALSE, FALSE) %as%
{
"i64"
}
ffi_c_type_map_rule("signed long int", FALSE, FALSE) %as%
{
"i64"
}
ffi_c_type_map_rule("signed long long", FALSE, FALSE) %as%
{
"i64"
}
ffi_c_type_map_rule("signed long long int", FALSE, FALSE) %as%
{
"i64"
}
ffi_c_type_map_rule("int64_t", FALSE, FALSE) %as%
{
"i64"
}
ffi_c_type_map_rule("__int64", FALSE, FALSE) %as%
{
"i64"
}
ffi_c_type_map_rule("intptr_t", FALSE, FALSE) %as%
{
"i64"
}
ffi_c_type_map_rule("ptrdiff_t", FALSE, FALSE) %as%
{
"i64"
}
ffi_c_type_map_rule("ssize_t", FALSE, FALSE) %as%
{
"i64"
}
ffi_c_type_map_rule("off_t", FALSE, FALSE) %as%
{
"i64"
}
ffi_c_type_map_rule("unsigned int", FALSE, FALSE) %as%
{
"u32"
}
ffi_c_type_map_rule("unsigned", FALSE, FALSE) %as%
{
"u32"
}
ffi_c_type_map_rule("uint32_t", FALSE, FALSE) %as%
{
"u32"
}
ffi_c_type_map_rule("unsigned __int32", FALSE, FALSE) %as%
{
"u32"
}
ffi_c_type_map_rule("unsigned short", FALSE, FALSE) %as%
{
"u16"
}
ffi_c_type_map_rule("unsigned short int", FALSE, FALSE) %as%
{
"u16"
}
ffi_c_type_map_rule("uint16_t", FALSE, FALSE) %as%
{
"u16"
}
ffi_c_type_map_rule("unsigned char", FALSE, FALSE) %as%
{
"u8"
}
ffi_c_type_map_rule("uint8_t", FALSE, FALSE) %as%
{
"u8"
}
ffi_c_type_map_rule("unsigned long", FALSE, FALSE) %as%
{
"u64"
}
ffi_c_type_map_rule("unsigned long int", FALSE, FALSE) %as%
{
"u64"
}
ffi_c_type_map_rule("unsigned long long", FALSE, FALSE) %as%
{
"u64"
}
ffi_c_type_map_rule("unsigned long long int", FALSE, FALSE) %as%
{
"u64"
}
ffi_c_type_map_rule("uint64_t", FALSE, FALSE) %as%
{
"u64"
}
ffi_c_type_map_rule("unsigned __int64", FALSE, FALSE) %as%
{
"u64"
}
ffi_c_type_map_rule("size_t", FALSE, FALSE) %as%
{
"u64"
}
ffi_c_type_map_rule("uintptr_t", FALSE, FALSE) %as%
{
"u64"
}
ffi_c_type_map_rule("double", FALSE, FALSE) %as%
{
"f64"
}
ffi_c_type_map_rule("long double", FALSE, FALSE) %as%
{
"f64"
}
ffi_c_type_map_rule("float", FALSE, FALSE) %as%
{
"f32"
}
ffi_c_type_map_rule(type_name, is_char_ptr, is_ptr) %as%
{
"ptr"
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.