js-slang under the hood
1
what happens when you press ▶️
2
/source-academy/<?>
/frontend
/backend
/js-slang
/sling
/modules
/sinter
3
/source-academy/<?>
/frontend
/backend
/js-slang
/sling
/modules
/sinter
db
interface
program str
context
import stmts
SVML
SVML
bundle(s)
result
result
4
/source-academy/<?>
/frontend
/js-slang
/modules
program str
context
import stmts
bundle(s)
result
5
pressing the ▶️ button
/frontend
6
pressing the ▶️ button
/js-slang
runInContext(programString, context, options)
runInContext :: (string, Context, IOptions) -> Result
7
pressing the ▶️ button
/js-slang
runInContext(programString, context, options)
runInContext :: (string, Context, IOptions) -> Result
8
pressing the ▶️ button
/js-slang
export interface Context<T = any> {
chapter: Chapter
executionMethod: ExecutionMethod
variant: Variant
prelude: string | null
nativeStorage: NativeStorage
moduleContexts: {...}
errors: SourceError[]
runtime: {
environmentTree: EnvTree
environments: Environment[]
nodes: es.Node[]
}
}
Context
9
pressing the ▶️ button
/js-slang
Context
runInContext(_, context, _)
already contains builtins (e.g. pair, list)
stored in
context.nativeStorage.builtins :: Map<String, any>
10
pressing the ▶️ button
/js-slang
Context
function createContext(chapter, variant) {
const context = createEmptyContext(chapter, variant)
// context
// .nativeStorage
// .builtins
// .insert(<name>, <value>)
importBuiltins(context)
}
11
pressing the ▶️ button
/js-slang
runInContext(programString, context, options)
runInContext :: (string, Context, IOptions) -> Result
12
pressing the ▶️ button
/js-slang
Options
13
pressing the ▶️ button
/js-slang
Options
14
pressing the ▶️ button
/js-slang
chapter
executionMethod
variant
useSubst
determines the builtins
native / debug mode
how should it be executed
should i run stepper
15
pressing the ▶️ button
/js-slang
chapter
executionMethod
variant
useSubst
determines the builtins
native / debug mode
how should it be executed
should i run stepper
prelude
what magic 🪄should be added
16
✅ program string
✅ the “recipe” to run it
✅ builtins (sort of)
✅ prelude (sort of)
17
✅ program string
✅ the “recipe” to run it
✅ builtins (sort of)
✅ prelude (sort of)
🤔 REPL support
18
after pressing the ▶️ button
program evaluation
{
// e.g. const pair = (x, y) => [x,y];
...builtins
// e.g. import {show, heart} from ‘rune’;
...prelude
// e.g. show(heart);
...program string
}
🤔
19
after pressing the ▶️ button
program evaluation
{
const pair = (x, y) => [x,y];
import {show, heart} from ‘rune’;
show(heart);
}
🤔
curr_program_str
20
after pressing the ▶️ button
program evaluation
function boo(...args1) {
const a = 1;
function hoo(...args2) {
return a;
}
return hoo
}
21
after pressing the ▶️ button
program evaluation
evaller = (program) => eval(program)
evaller :: (String) -> any
context.nativeStorage.evaller = typeof evaller | null
22
after pressing the ▶️ button
program evaluation
{
// e.g. const pair = (x, y) => [x,y];
...builtins
// e.g. import {show, heart} from ‘rune’;
...prelude
nativeStorage.evaller = (program) => eval(program)
// e.g. show(heart);
...program string
}
23
after pressing the ▶️ button
program evaluation
24
after pressing the ▶️ button
program evaluation
{
const pair = (x, y) => [x,y];
import {show, heart} from ‘rune’;
nativeStorage.evaller = (program) => eval(program)
show(heart);
}
curr_program_str
25
after pressing the ▶️ button
program evaluation
26
after pressing the ▶️ button
program evaluation
function sandBoxedEval(code: string, {nativeStorage, ...ctx}){
if (nativeStorage.evaller) {
return nativeStorage.evaller(code)
}
return eval(code)
}
27
after pressing the ▶️ button
program evaluation
function sandBoxedEval(code: string, {nativeStorage, ...ctx}){
return eval(
{
const pair = (x, y) => [x,y];
import {show, heart} from ‘rune’;
nativeStorage.evaller = (program) => eval(program)
show(heart);
}
)
}
28
after pressing the ▶️ button
program evaluation
function sandBoxedEval(code: string, {nativeStorage, ...ctx}){
if (nativeStorage.evaller) {
return nativeStorage.evaller(code)
}
return eval(code)
}
29
after pressing the ▶️ button
program evaluation
function sandBoxedEval(code: string, {nativeStorage, ...ctx}){
// nativeStorage.evaller = (program) => eval(program)
return nativeStorage.evaller(code)
}
30
after pressing the ▶️ button
program evaluation
function sandBoxedEval(code: string, {nativeStorage, ...ctx}){
// Note which scope the evaller belongs to!!
return ((program) => eval(program))(code)
}
31
after pressing the ▶️ button
program evaluation
function sandBoxedEval(code: string, {nativeStorage, ...ctx}){
return eval(
{
const pair = (x, y) => [x,y];
import {show, heart} from ‘rune’;
nativeStorage.evaller = (program) => eval(program)
show(heart);
}
)
}
32
after pressing the ▶️ button
program evaluation
function sandBoxedEval(code: string, {nativeStorage, ...ctx}){
return ((program) => eval(program))(
const a = pair(heart, heart);
const b = pair(show(heart), show(heart));
)
}
33
after pressing the ▶️ button
program evaluation
function sandBoxedEval(code: string, {nativeStorage, ...ctx}){
return ((program) => eval(program))(
const a = pair(heart, heart);
const b = pair(show(heart), show(heart));
nativeStorage.evaller = (program) => eval(program)
)
}
34
✅ program string
✅ the “recipe” to run it
✅ builtins (sort of)
✅ prelude (sort of)
✅ REPL support
35
{
...builtins
{
nativeStorage.evaller = (program) => eval(program)
...prelude
}
}
after pressing the ▶️ button
evaluation stage 1
36
{
...builtins
{
nativeStorage.evaller = (program) => eval(program)
...program_str
}
}
after pressing the ▶️ button
evaluation stage 2
37
const __MODULE_N__ = (...)(context) // IIFE
{
...builtins
{
nativeStorage.evaller = (program) => eval(program)
const heart = __MODULE_N__.heart;
...program_str
}
}
after pressing the ▶️ button
evaluation with imports
38
const __MODULE_N__ = (...)(context) // IIFE
{
...builtins
{
nativeStorage.evaller = (program) => eval(program)
const heart = __MODULE_N__.heart;
pair(heart, heart);
}
}
after pressing the ▶️ button
evaluation with imports
39
improvements
40
improvements