[obsidian] vault backup: 2023-11-25 00:30:28[

This commit is contained in:
松浦 知也 Matsuura Tomoya 2023-11-25 00:30:28 +09:00
parent e197479fa4
commit 6de340c8d0
2 changed files with 119 additions and 0 deletions

View File

@ -0,0 +1,117 @@
#programming-language #compiler-design #lisp
[Make A Lisp](https://github.com/kanaka/mal)よりさらに最小限の実装ってどのくらいかなー、というのを考えた。
クロージャも作れるのでこのくらいのことはできる。
```lisp
(let double (lambda (x) (* x x)) (double 6))
```
まあプリミティブ演算は四則演算だけで再帰関数は自力で定義
```lisp
(let fix (lambda (f) ((lambda (x) (f (lambda (y) (x x y) ))) ()) ) )
```
```js
const reader = require("readline").createInterface({
input: process.stdin,
});
const tokenize = (str) =>
str.match(/[\(]|[\)]|[\+\-\*\/]|[a-zA-Z_]+|(-?\d+(\.\d+)?)/g);
const parse_token = (token, stack, res) => {
switch (token) {
case '(': {
let child = [];
stack.push(child);
return child;
}
case ')': {
let c = stack.pop();
if (stack.length == 0) {
return c
} else {
stack[stack.length - 1].push(c)
return stack[stack.length - 1]
}
}
default: {
res.push(token);
return res
}
}
}
const parse = (tokens) => {
let stack = [];
let next_res = [];
for (token of tokens) {
next_res = parse_token(token, stack, next_res)
}
return next_res
}
const read = (str) => {
const res = parse(tokenize(str));
return res
}
const binop = (args, fn) => fn(args[0], args[1]);
const env = {
"parent": null,
"+": args => binop(args, (a, b) => a + b),
"-": args => binop(args, (a, b) => a - b),
"*": args => binop(args, (a, b) => a * b),
"/": args => binop(args, (a, b) => a / b)
}
const try_find = (name, env) => {
if (env)
if (env[name]) {
return env[name]
} else {
return try_find(name, env["parent"])
} else {
return null
}
}
const eval = (expr, env) => {
if (!Array.isArray(expr)) {
return !isNaN(parseFloat(expr)) ? parseFloat(expr) : try_find(expr, env)
} else {
const op = expr.shift();
switch (op) {
case 'let': {
let newenv = { "parent": env };
env[expr[0]] = eval(expr[1], newenv);
return eval(expr[2], env)
}
case 'lambda': return ['closure', expr[0], expr[1], env]//ids,body,env
default: {
let fn = try_find(op, env);
if (fn) {
if (Array.isArray(fn) && fn[0] === "closure") {
for (let i = 0; i < fn[1].length; i++) {
fn[3][fn[1][i]] = expr[i]
}
return eval(fn[2], fn[3])
} else {
return fn(expr.map(e => eval(e, env)))
}
} else {
console.error(`symbol ${op} not found`)
}
}
}
}
}
const rep = (line) => {
console.log(eval(read(line), env))
}
reader.on("line", (line) => {
if (line) { rep(line); }
});
```

View File

@ -1,5 +1,7 @@
#programming-language #compiler-design
[[Node.jsで100行で書くLISP風ラムダ計算]]
[Write a JavaScript Parser in Rust](https://oxc-project.github.io/javascript-parser-in-rust/ja/docs/intro/)