Skip to content

Instantly share code, notes, and snippets.

@long-long-float
Created October 31, 2016 09:27
Show Gist options
  • Save long-long-float/b77e9ff08b23c1e731b43b5cbced8743 to your computer and use it in GitHub Desktop.
Save long-long-float/b77e9ff08b23c1e731b43b5cbced8743 to your computer and use it in GitHub Desktop.
miniscript
["for", ["range", 0, 100], ["do", ["n"],
["print", ["switch",
["=", ["%", ["n"], 15], 0], "FizzBuzz",
["=", ["%", ["n"], 3], 0], "Fizz",
["=", ["%", ["n"], 5], 0], "Buzz",
["n"]
]]
]]
[["do", []
["set", "printHello", ["do", [], ["print", "hello"]]],
[["printHello"]],
[["printHello"]],
[["printHello"]],
["set", "sum", ["do", ["x", "y"], ["+", ["x"], ["y"]]]],
["print", [["sum"], 1, 2]]
]]
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<title></title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="">
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<textarea id="src">
["for", {
"name": "long_long_float",
"interests": ["Ubuntu", "Ruby"],
"homepage": "http://llfloat.net"
}, ["do", ["k", "v"], ["print", ["+", "* ", ["k"], ": ", ["v"]]]]]
</textarea>
<textarea id="output"></textarea>
<button id="run-btn">Run</button>
<script src="./main.js"></script>
</body>
</html>
const output = document.getElementById('output')
document.getElementById('run-btn').onclick = () => {
const src = JSON.parse(document.getElementById('src').value)
const env = [{}]
function applyLambda(lambda, args) {
env.unshift({})
lambda[1].forEach((n, i) => env[0][n] = args[i])
const r = lambda.slice(2).map(evalExpr)[lambda.length - 3]
env.shift()
return r
}
function evalExpr(expr) {
if (Array.isArray(expr) && expr[0] !== 'do') { // function call
const fst = evalExpr(expr[0])
if (fst[0] == 'do') {
return applyLambda(lambda, args.slice(1))
} else {
const f = {
set: (a) => env[0][a[0]] = a[1],
print: (a) => output.value += a[0] + "\n" || a[0],
"+": (a) => a.reduce((x, y) => x + y),
"%": (a) => a[0] % a[1],
"=": (a) => a[0] === a[1],
range: (a) => {
const r = []
for (let i = a[0]; i <= a[1]; i++) r.push(i)
return r
}
}[fst]
const s = {
if: (a) => evalExpr(a[0]) ? evalExpr(a[1]) : evalExpr(a[2]),
for: (a) => {
const coll = evalExpr(a[0])
const cb = evalExpr(a[1])
const r = []
if (Array.isArray(coll)) {
for (let i = 0; i < coll.length; i++) {
r.push(applyLambda(cb, [coll[i]]))
}
} else {
const keys = Object.keys(coll)
for (let i = 0; i < keys.length; i++) {
r.push(applyLambda(cb, [keys[i], coll[keys[i]]]))
}
}
return r
},
switch: (a) => {
let r = null
for (let i = 0; i < a.length; ) {
if (a.length % 2 !== 0 && i === a.length - 1) {
r = evalExpr(a[i])
break
}
if (evalExpr(a[i])) {
r = evalExpr(a[i + 1])
break
}
i += 2
}
return r
},
}[fst]
if (f) {
return f(expr.slice(1).map(evalExpr))
} else if(s) {
return s(expr.slice(1))
} else if(env[0].hasOwnProperty(fst)) {
return env[0][fst]
} else {
throw `unknown identifier '${fst}'`
}
}
} else { return expr } // literal
}
evalExpr(src)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment