R interface to Altair SLC (Statistical Language Compiler).
You can install the development version of slcR from GitHub with:
# install.packages("devtools")
devtools::install_github("sol-eng/slcr")library(slcR)
# Create SLC connection
slc <- Slc$new()
# Get the WORK library
work_lib <- slc$get_library("WORK")
# Submit SAS code
slc$submit("data test; x = 1; run;")
# Retrieve log and listing output
cat(slc$get_log())
cat(slc$get_listing_output())
# Clean up
slc$shutdown()Install the Quarto extension into your project once:
slcR::install_slc_extension()Every Quarto document that uses {slc} chunks needs three things:
1. engine: knitr in the YAML front matter — without this Quarto defaults to Jupyter and the slc engine is never registered:
---
title: "My SAS Analysis"
format:
html:
code-fold: false
filters:
- slcr
engine: knitr
---2. A hidden R setup chunk that loads slcR — this fires .onLoad, which registers the knitr engine:
```{r setup, include=FALSE}
library(slcR)
```3. The extension installed (once per project, see above).
Without engine: knitr, Quarto renders the document with Jupyter and {slc} chunks appear as literal text. Without library(slcR), knitr reports Warning: Unknown language engine 'slc' and skips all SLC chunks.
Basic chunk — shows the log in a collapsible "📊 SLC Output" block:
```{slc}
proc print data=sashelp.class(obs=5);
run;
```All {slc} chunks in a document share a single SLC process by default. Datasets and macro variables created in one chunk are available in all subsequent chunks — no need to pass data back and forth through R:
```{slc}
data work.scores;
input name $ score;
datalines;
Alice 92
Bob 85
;
run;
```
```{slc}
/* work.scores from the previous chunk is still in scope */
proc means data=work.scores mean;
var score;
run;
```The shared process is shut down automatically when the document finishes rendering. To run a specific chunk in an isolated process (one that cannot see state from other chunks), set new_session = TRUE on that chunk.
Tabular procedures (proc print, proc tabulate, proc means, etc.) automatically produce formatted HTML tables — no special chunk options needed. The output appears in a green collapsible "📋 SLC Table Output" block, open by default:
```{slc}
proc print data=work.summary noobs;
run;
```The engine uses ods tagsets.htmlcss internally to capture static HTML table markup. This is skipped for figure chunks (those containing ods html) to avoid destination conflicts.
Plain-text listing output is shown as a fallback when a chunk produces no HTML table output. Suppress it with show_listing=FALSE:
```{slc show_listing=FALSE}
proc means data=sashelp.class;
run;
```Figures are auto-discovered — ODS graphics are embedded automatically. The engine scans NOTE: Successfully written image ... lines from the SAS log (scoped to the current chunk's new log lines only) and resolves paths against the SLC WORK directory:
```{slc label="my-figure"}
#| fig.cap: "Height vs Weight"
ods html body='' gpath="&slcr_gpath" style=htmlblue;
ods graphics / width=700px height=500px;
proc sgplot data=sashelp.class;
scatter x=height y=weight;
run;
ods html close;
```Always use #| for captions — never the inline header. Writing ```{slc fig-cap="..."} causes a parse error because knitr's alist() parser treats the hyphen in fig-cap as a minus operator. Use #| fig.cap: inside the chunk body instead (with a dot or as shown above).
&slcr_gpath is a per-chunk SAS macro variable set by the engine. Note that SLC always writes images to its WORK temp directory regardless of gpath=; the engine resolves those paths automatically.
Use output_files only when auto-discovery misses a file at a fully custom path:
```{slc output_files="/custom/path/myplot.png"}
ods html body='/custom/path/myplot.png';
proc sgplot data=sashelp.class;
scatter x=height y=weight;
run;
ods html close;
```Transfer R data frames into SLC and retrieve SLC datasets back into R:
```{slc input_data="my_df" output_data="results"}
proc means data=work.my_df noprint;
output out=work.results mean= / autoname;
run;
```