mirror of
https://github.com/eliasstepanik/strudel-docker.git
synced 2026-01-25 04:28:30 +00:00
fix lint errors + cleanup
This commit is contained in:
parent
c232fb7dd5
commit
0123f4e5f3
@ -22,4 +22,4 @@ vite.config.js
|
|||||||
reverbGen.mjs
|
reverbGen.mjs
|
||||||
hydra.mjs
|
hydra.mjs
|
||||||
jsdoc-synonyms.js
|
jsdoc-synonyms.js
|
||||||
packages/tidal/hs2js.mjs
|
packages/hs2js/src/hs2js.mjs
|
||||||
@ -1,12 +1,10 @@
|
|||||||
import { parse } from "./parser.mjs";
|
import { parse } from './parser.mjs';
|
||||||
|
|
||||||
function runApply(node, scope, ops) {
|
function runApply(node, scope, ops) {
|
||||||
if (node.children.length !== 2)
|
if (node.children.length !== 2)
|
||||||
throw new Error(
|
throw new Error(`expected 2 children for node type apply, got ${node.children.length}`);
|
||||||
`expected 2 children for node type apply, got ${node.children.length}`
|
|
||||||
);
|
|
||||||
const [fn, arg] = node.children.map((child) => run(child, scope, ops));
|
const [fn, arg] = node.children.map((child) => run(child, scope, ops));
|
||||||
if (typeof fn !== "function") {
|
if (typeof fn !== 'function') {
|
||||||
throw new Error(`${node.children[0].text} is not a function`);
|
throw new Error(`${node.children[0].text} is not a function`);
|
||||||
}
|
}
|
||||||
// only works if fn is curried!
|
// only works if fn is curried!
|
||||||
@ -19,23 +17,23 @@ function runInfix(left, symbol, right, ops) {
|
|||||||
return customOp(left, right);
|
return customOp(left, right);
|
||||||
}
|
}
|
||||||
switch (symbol) {
|
switch (symbol) {
|
||||||
case "+":
|
case '+':
|
||||||
return left + right;
|
return left + right;
|
||||||
case "-":
|
case '-':
|
||||||
return left - right;
|
return left - right;
|
||||||
case "*":
|
case '*':
|
||||||
return left * right;
|
return left * right;
|
||||||
case "/":
|
case '/':
|
||||||
return left / right;
|
return left / right;
|
||||||
case "$":
|
case '$':
|
||||||
return left(right);
|
return left(right);
|
||||||
case "&":
|
case '&':
|
||||||
console.log("right", right);
|
console.log('right', right);
|
||||||
return right(left);
|
return right(left);
|
||||||
case ".":
|
case '.':
|
||||||
return (x) => left(right(x));
|
return (x) => left(right(x));
|
||||||
default:
|
default:
|
||||||
throw new Error("unexpected infix operator " + symbol);
|
throw new Error('unexpected infix operator ' + symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,79 +53,75 @@ export function run(node, scope, ops = {}) {
|
|||||||
let runInScope = (node, scp = scope) => run(node, scp, ops);
|
let runInScope = (node, scp = scope) => run(node, scp, ops);
|
||||||
//console.log("node", node.type, node.text);
|
//console.log("node", node.type, node.text);
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
case "ERROR":
|
case 'ERROR':
|
||||||
throw new Error(`invalid syntax: "${node.text}"`);
|
throw new Error(`invalid syntax: "${node.text}"`);
|
||||||
case "declarations":
|
case 'declarations':
|
||||||
let result;
|
let result;
|
||||||
node.children.forEach((declaration) => {
|
node.children.forEach((declaration) => {
|
||||||
result = runInScope(declaration);
|
result = runInScope(declaration);
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
case "integer":
|
case 'integer':
|
||||||
return Number(node.text);
|
return Number(node.text);
|
||||||
case "float":
|
case 'float':
|
||||||
return Number(node.text);
|
return Number(node.text);
|
||||||
case "string":
|
case 'string':
|
||||||
const str = node.text.slice(1, -1);
|
const str = node.text.slice(1, -1);
|
||||||
return String(str);
|
return String(str);
|
||||||
case "lambda":
|
case 'lambda':
|
||||||
const [_, lpatterns, __, lbody] = node.children;
|
const [_, lpatterns, __, lbody] = node.children;
|
||||||
return curry(lpatterns.children, lbody, scope, ops);
|
return curry(lpatterns.children, lbody, scope, ops);
|
||||||
case "function":
|
case 'function':
|
||||||
const [fvariable, fpatterns, fbody] = node.children;
|
const [fvariable, fpatterns, fbody] = node.children;
|
||||||
scope[fvariable.text] = curry(fpatterns.children, fbody, scope, ops);
|
scope[fvariable.text] = curry(fpatterns.children, fbody, scope, ops);
|
||||||
return scope[fvariable.text];
|
return scope[fvariable.text];
|
||||||
case "list": {
|
case 'list': {
|
||||||
return node.children
|
return node.children
|
||||||
.filter((_, i) => i % 2 === 1) // elements are at odd indices
|
.filter((_, i) => i % 2 === 1) // elements are at odd indices
|
||||||
.map((node) => runInScope(node));
|
.map((node) => runInScope(node));
|
||||||
}
|
}
|
||||||
case "match":
|
case 'match':
|
||||||
if (node.children[0].text !== "=" || node.children.length !== 2) {
|
if (node.children[0].text !== '=' || node.children.length !== 2) {
|
||||||
throw new Error("match node so far only support simple assignments");
|
throw new Error('match node so far only support simple assignments');
|
||||||
}
|
}
|
||||||
return runInScope(node.children[1]);
|
return runInScope(node.children[1]);
|
||||||
case "bind":
|
case 'bind':
|
||||||
if (node.children.length !== 2)
|
if (node.children.length !== 2) throw new Error('expected 2 children for node type bind');
|
||||||
throw new Error("expected 2 children for node type bind");
|
if (node.children[0].type !== 'variable') throw new Error('expected variable as first child of bind node');
|
||||||
if (node.children[0].type !== "variable")
|
if (node.children[1].type !== 'match') throw new Error('expected match as first child of bind node');
|
||||||
throw new Error("expected variable as first child of bind node");
|
|
||||||
if (node.children[1].type !== "match")
|
|
||||||
throw new Error("expected match as first child of bind node");
|
|
||||||
const [bvariable, bmatch] = node.children;
|
const [bvariable, bmatch] = node.children;
|
||||||
const value = runInScope(bmatch);
|
const value = runInScope(bmatch);
|
||||||
scope[bvariable.text] = value;
|
scope[bvariable.text] = value;
|
||||||
return value;
|
return value;
|
||||||
case "variable":
|
case 'variable':
|
||||||
return scope[node.text];
|
return scope[node.text];
|
||||||
case "infix": {
|
case 'infix': {
|
||||||
const [a, op, b] = node.children;
|
const [a, op, b] = node.children;
|
||||||
const symbol = op.text;
|
const symbol = op.text;
|
||||||
const [left, right] = [runInScope(a), runInScope(b)];
|
const [left, right] = [runInScope(a), runInScope(b)];
|
||||||
return runInfix(left, symbol, right, ops);
|
return runInfix(left, symbol, right, ops);
|
||||||
}
|
}
|
||||||
case "apply":
|
case 'apply':
|
||||||
return runApply(node, scope, ops);
|
return runApply(node, scope, ops);
|
||||||
case "left_section": {
|
case 'left_section': {
|
||||||
const [_, b, op] = node.children;
|
const [_, b, op] = node.children;
|
||||||
const right = runInScope(b);
|
const right = runInScope(b);
|
||||||
return (left) => runInfix(left, op.text, right, ops);
|
return (left) => runInfix(left, op.text, right, ops);
|
||||||
}
|
}
|
||||||
case "right_section": {
|
case 'right_section': {
|
||||||
const [_, op, b] = node.children;
|
const [_, op, b] = node.children;
|
||||||
const right = runInScope(b);
|
const right = runInScope(b);
|
||||||
return (left) => runInfix(left, op.text, right, ops);
|
return (left) => runInfix(left, op.text, right, ops);
|
||||||
}
|
}
|
||||||
case "parens":
|
case 'parens':
|
||||||
if (node.children.length !== 3)
|
if (node.children.length !== 3) throw new Error('expected 3 children for node type parens');
|
||||||
throw new Error("expected 3 children for node type parens");
|
|
||||||
return runInScope(node.children[1]);
|
return runInScope(node.children[1]);
|
||||||
default:
|
default:
|
||||||
if (node.children.length === 0) {
|
if (node.children.length === 0) {
|
||||||
throw new Error("unhandled leaf type " + node.type);
|
throw new Error('unhandled leaf type ' + node.type);
|
||||||
}
|
}
|
||||||
if (node.children.length > 1) {
|
if (node.children.length > 1) {
|
||||||
throw new Error("unhandled branch type " + node.type);
|
throw new Error('unhandled branch type ' + node.type);
|
||||||
}
|
}
|
||||||
return runInScope(node.children[0]);
|
return runInScope(node.children[0]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
export * from "./hs2js.mjs";
|
export * from './hs2js.mjs';
|
||||||
export * from "./parser.mjs";
|
export * from './parser.mjs';
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import Parser from "web-tree-sitter";
|
import Parser from 'web-tree-sitter';
|
||||||
|
|
||||||
let base = "/";
|
let base = '/';
|
||||||
export function setBase(path) {
|
export function setBase(path) {
|
||||||
base = path;
|
base = path;
|
||||||
}
|
}
|
||||||
@ -28,10 +28,5 @@ export function loadParser() {
|
|||||||
export async function parse(code) {
|
export async function parse(code) {
|
||||||
const parser = await loadParser();
|
const parser = await loadParser();
|
||||||
// for some reason, the parser doesn't like new lines..
|
// for some reason, the parser doesn't like new lines..
|
||||||
return parser.parse(
|
return parser.parse(code.replaceAll('\n\n', '~~~~').replaceAll('\n', '').replaceAll('~~~~', '\n'));
|
||||||
code
|
|
||||||
.replaceAll("\n\n", "~~~~")
|
|
||||||
.replaceAll("\n", "")
|
|
||||||
.replaceAll("~~~~", "\n")
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
20
packages/hs2js/vite.config.js
Normal file
20
packages/hs2js/vite.config.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import { resolve } from 'path';
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [],
|
||||||
|
build: {
|
||||||
|
lib: {
|
||||||
|
entry: resolve(__dirname, 'src', 'index.mjs'),
|
||||||
|
name: 'hs2js',
|
||||||
|
formats: ['es', 'iife'],
|
||||||
|
fileName: (ext) => ({ es: 'index.mjs', iife: 'index.js' })[ext],
|
||||||
|
},
|
||||||
|
rollupOptions: {
|
||||||
|
// external: [...Object.keys(dependencies)],
|
||||||
|
plugins: [],
|
||||||
|
},
|
||||||
|
target: 'esnext',
|
||||||
|
},
|
||||||
|
});
|
||||||
@ -1,20 +0,0 @@
|
|||||||
import { defineConfig } from "vite";
|
|
||||||
import { resolve } from "path";
|
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
|
||||||
export default defineConfig({
|
|
||||||
plugins: [],
|
|
||||||
build: {
|
|
||||||
lib: {
|
|
||||||
entry: resolve(__dirname, "src", "index.mjs"),
|
|
||||||
name: "hs2js",
|
|
||||||
formats: ["es", "iife"],
|
|
||||||
fileName: (ext) => ({ es: "index.mjs", iife: "index.js" }[ext]),
|
|
||||||
},
|
|
||||||
rollupOptions: {
|
|
||||||
// external: [...Object.keys(dependencies)],
|
|
||||||
plugins: [],
|
|
||||||
},
|
|
||||||
target: "esnext",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@ -1,130 +0,0 @@
|
|||||||
function runApply(node, scope, ops) {
|
|
||||||
if (node.children.length !== 2)
|
|
||||||
throw new Error(`expected 2 children for node type apply, got ${node.children.length}`);
|
|
||||||
const [fn, arg] = node.children.map((child) => run(child, scope, ops));
|
|
||||||
if (typeof fn !== 'function') {
|
|
||||||
throw new Error(`${node.children[0].text} is not a function`);
|
|
||||||
}
|
|
||||||
// only works if fn is curried!
|
|
||||||
return fn(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
function runInfix(left, symbol, right, ops) {
|
|
||||||
const customOp = ops[symbol];
|
|
||||||
if (customOp) {
|
|
||||||
return customOp(left, right);
|
|
||||||
}
|
|
||||||
switch (symbol) {
|
|
||||||
case '+':
|
|
||||||
return left + right;
|
|
||||||
case '-':
|
|
||||||
return left - right;
|
|
||||||
case '*':
|
|
||||||
return left * right;
|
|
||||||
case '/':
|
|
||||||
return left / right;
|
|
||||||
case '$':
|
|
||||||
return left(right);
|
|
||||||
case '&':
|
|
||||||
return right(left);
|
|
||||||
case '.':
|
|
||||||
return (x) => left(right(x));
|
|
||||||
default:
|
|
||||||
throw new Error('unexpected infix operator ' + symbol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function curry(patterns, body, scope, ops) {
|
|
||||||
const [variable, ...rest] = patterns;
|
|
||||||
return (arg) => {
|
|
||||||
let _scope = { ...scope, [variable.text]: arg };
|
|
||||||
if (patterns.length === 1) {
|
|
||||||
const result = run(body, _scope, ops);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return curry(rest, body, _scope, ops);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function run(node, scope, ops = {}) {
|
|
||||||
let runInScope = (node, scp = scope) => run(node, scp, ops);
|
|
||||||
//console.log("node", node.type, node.text);
|
|
||||||
switch (node.type) {
|
|
||||||
case 'ERROR':
|
|
||||||
throw new Error(`invalid syntax: "${node.text}"`);
|
|
||||||
case 'declarations':
|
|
||||||
let result;
|
|
||||||
node.children.forEach((declaration) => {
|
|
||||||
result = runInScope(declaration);
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
case 'integer':
|
|
||||||
return Number(node.text);
|
|
||||||
case 'float':
|
|
||||||
return Number(node.text);
|
|
||||||
case 'string':
|
|
||||||
const str = node.text.slice(1, -1);
|
|
||||||
return String(str);
|
|
||||||
case 'lambda':
|
|
||||||
const [_, lpatterns, __, lbody] = node.children;
|
|
||||||
return curry(lpatterns.children, lbody, scope, ops);
|
|
||||||
case 'function':
|
|
||||||
const [fvariable, fpatterns, fbody] = node.children;
|
|
||||||
scope[fvariable.text] = curry(fpatterns.children, fbody, scope, ops);
|
|
||||||
return scope[fvariable.text];
|
|
||||||
case 'list': {
|
|
||||||
return node.children
|
|
||||||
.filter((_, i) => i % 2 === 1) // elements are at odd indices
|
|
||||||
.map((node) => runInScope(node));
|
|
||||||
}
|
|
||||||
case 'match':
|
|
||||||
if (node.children[0].text !== '=' || node.children.length !== 2) {
|
|
||||||
throw new Error('match node so far only support simple assignments');
|
|
||||||
}
|
|
||||||
return runInScope(node.children[1]);
|
|
||||||
case 'bind':
|
|
||||||
if (node.children.length !== 2) throw new Error('expected 2 children for node type bind');
|
|
||||||
if (node.children[0].type !== 'variable') throw new Error('expected variable as first child of bind node');
|
|
||||||
if (node.children[1].type !== 'match') throw new Error('expected match as first child of bind node');
|
|
||||||
const [bvariable, bmatch] = node.children;
|
|
||||||
const value = runInScope(bmatch);
|
|
||||||
scope[bvariable.text] = value;
|
|
||||||
return value;
|
|
||||||
case 'variable':
|
|
||||||
return scope[node.text];
|
|
||||||
case 'infix': {
|
|
||||||
const [a, op, b] = node.children;
|
|
||||||
const symbol = op.text;
|
|
||||||
const [left, right] = [runInScope(a), runInScope(b)];
|
|
||||||
return runInfix(left, symbol, right, ops);
|
|
||||||
}
|
|
||||||
case 'apply':
|
|
||||||
return runApply(node, scope, ops);
|
|
||||||
case 'left_section': {
|
|
||||||
const [_, b, op] = node.children;
|
|
||||||
const right = runInScope(b);
|
|
||||||
return (left) => runInfix(left, op.text, right, ops);
|
|
||||||
}
|
|
||||||
case 'right_section': {
|
|
||||||
const [_, op, b] = node.children;
|
|
||||||
const right = runInScope(b);
|
|
||||||
return (left) => runInfix(left, op.text, right, ops);
|
|
||||||
}
|
|
||||||
case 'parens':
|
|
||||||
if (node.children.length !== 3) throw new Error('expected 3 children for node type parens');
|
|
||||||
return runInScope(node.children[1]);
|
|
||||||
default:
|
|
||||||
if (node.children.length === 0) {
|
|
||||||
throw new Error('unhandled leaf type ' + node.type);
|
|
||||||
}
|
|
||||||
if (node.children.length > 1) {
|
|
||||||
throw new Error('unhandled branch type ' + node.type);
|
|
||||||
}
|
|
||||||
return runInScope(node.children[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function evaluate(haskellCode, scope = globalThis, ops) {
|
|
||||||
const ast = await parse(haskellCode);
|
|
||||||
return run(ast.rootNode, scope, ops);
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
import Parser from 'web-tree-sitter';
|
|
||||||
|
|
||||||
const base = import.meta.env.BASE_URL;
|
|
||||||
|
|
||||||
async function loadParser() {
|
|
||||||
await Parser.init({
|
|
||||||
locateFile(scriptName, scriptDirectory) {
|
|
||||||
return `${base}${scriptName}`;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const parser = new Parser();
|
|
||||||
const Lang = await Parser.Language.load(`${base}tree-sitter-haskell.wasm`);
|
|
||||||
parser.setLanguage(Lang);
|
|
||||||
return parser;
|
|
||||||
}
|
|
||||||
|
|
||||||
let parserLoaded = loadParser();
|
|
||||||
export async function parse(code) {
|
|
||||||
const parser = await parserLoaded;
|
|
||||||
// for some reason, the parser doesn't like new lines..
|
|
||||||
return parser.parse(code.replaceAll('\n\n', '~~~~').replaceAll('\n', '').replaceAll('~~~~', '\n'));
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user