mondo: patternable function names
This commit is contained in:
parent
1738e4d538
commit
64a6dacc1e
3 changed files with 34 additions and 26 deletions
|
|
@ -280,7 +280,7 @@ export class MondoParser {
|
||||||
get_locations(code, offset = 0) {
|
get_locations(code, offset = 0) {
|
||||||
let walk = (ast, locations = []) => {
|
let walk = (ast, locations = []) => {
|
||||||
if (ast.type === 'list') {
|
if (ast.type === 'list') {
|
||||||
return ast.children.slice(1).forEach((child) => walk(child, locations));
|
return ast.children.forEach((child) => walk(child, locations));
|
||||||
}
|
}
|
||||||
if (ast.loc) {
|
if (ast.loc) {
|
||||||
locations.push(ast.loc);
|
locations.push(ast.loc);
|
||||||
|
|
@ -335,17 +335,11 @@ export class MondoRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
// is list
|
// is list
|
||||||
// the first element is expected to be the function name
|
if (!ast.children.length) {
|
||||||
const first = ast.children[0];
|
throw new Error(`empty list`);
|
||||||
let name;
|
|
||||||
if (first?.type !== 'list') {
|
|
||||||
name = first.value; // regular function call e.g. (fast 2 (s bd))
|
|
||||||
} else {
|
|
||||||
// dynamic function name e.g. "(<speed fast> 2 (s bd))"
|
|
||||||
name = this.evaluate(first);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name === 'lambda') {
|
if (ast.children[0].value === 'lambda') {
|
||||||
const [_, args, body] = ast.children;
|
const [_, args, body] = ast.children;
|
||||||
const argNames = args.children.map((child) => child.value);
|
const argNames = args.children.map((child) => child.value);
|
||||||
return (x) => {
|
return (x) => {
|
||||||
|
|
@ -356,8 +350,9 @@ export class MondoRunner {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const args = ast.children.map((arg) => this.evaluate(arg, scope));
|
||||||
|
// we could short circuit arg[0] if its plain...
|
||||||
// evaluate args
|
// evaluate args
|
||||||
const args = ast.children.slice(1).map((arg) => this.evaluate(arg, scope));
|
return this.lib.call(args[0], args.slice(1), scope);
|
||||||
return this.lib.call(name, args, scope);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import {
|
||||||
chooseIn,
|
chooseIn,
|
||||||
degradeBy,
|
degradeBy,
|
||||||
silence,
|
silence,
|
||||||
isPattern,
|
|
||||||
} from '@strudel/core';
|
} from '@strudel/core';
|
||||||
import { registerLanguage } from '@strudel/transpiler';
|
import { registerLanguage } from '@strudel/transpiler';
|
||||||
import { MondoRunner } from '../mondo/mondo.mjs';
|
import { MondoRunner } from '../mondo/mondo.mjs';
|
||||||
|
|
@ -24,7 +23,10 @@ const arrayRange = (start, stop, step = 1) =>
|
||||||
);
|
);
|
||||||
const range = (max, min) => min.squeezeBind((a) => max.bind((b) => seq(...arrayRange(a, b))));
|
const range = (max, min) => min.squeezeBind((a) => max.bind((b) => seq(...arrayRange(a, b))));
|
||||||
|
|
||||||
|
let nope = (...args) => args[args.length - 1];
|
||||||
|
|
||||||
let lib = {};
|
let lib = {};
|
||||||
|
lib['nope'] = nope;
|
||||||
lib['-'] = silence;
|
lib['-'] = silence;
|
||||||
lib['~'] = silence;
|
lib['~'] = silence;
|
||||||
lib.curly = stepcat;
|
lib.curly = stepcat;
|
||||||
|
|
@ -43,15 +45,19 @@ lib['or'] = (...children) => chooseIn(...children); // always has structure but
|
||||||
|
|
||||||
let runner = new MondoRunner({
|
let runner = new MondoRunner({
|
||||||
call(name, args, scope) {
|
call(name, args, scope) {
|
||||||
if (isPattern(name)) {
|
// name is expected to be a pattern of functions!
|
||||||
// patterned function name, e.g. "s bd . <speed fast> 2"
|
const first = name.firstCycle(true)[0];
|
||||||
return name.fmap((fn) => fn(...args)).innerJoin();
|
if (typeof first?.value !== 'function') {
|
||||||
|
throw new Error(`[mondough] "${first}" is not a function`);
|
||||||
}
|
}
|
||||||
const fn = lib[name] || strudelScope[name];
|
return name
|
||||||
if (!fn) {
|
.fmap((fn) => {
|
||||||
throw new Error(`[moundough]: unknown function "${name}"`);
|
if (typeof fn !== 'function') {
|
||||||
}
|
throw new Error(`[mondough] "${fn}" is not a function`);
|
||||||
return fn(...args);
|
}
|
||||||
|
return fn(...args);
|
||||||
|
})
|
||||||
|
.innerJoin();
|
||||||
},
|
},
|
||||||
leaf(token, scope) {
|
leaf(token, scope) {
|
||||||
let { value, type } = token;
|
let { value, type } = token;
|
||||||
|
|
@ -59,14 +65,21 @@ let runner = new MondoRunner({
|
||||||
if (type === 'plain' && scope[value]) {
|
if (type === 'plain' && scope[value]) {
|
||||||
return reify(scope[value]); // -> local scope has no location
|
return reify(scope[value]); // -> local scope has no location
|
||||||
}
|
}
|
||||||
const [from, to] = token.loc;
|
|
||||||
const variable = lib[value] ?? strudelScope[value];
|
const variable = lib[value] ?? strudelScope[value];
|
||||||
|
let pat;
|
||||||
if (type === 'plain' && typeof variable !== 'undefined') {
|
if (type === 'plain' && typeof variable !== 'undefined') {
|
||||||
// problem: collisions when we want a string that happens to also be a variable name
|
// problem: collisions when we want a string that happens to also be a variable name
|
||||||
// example: "s sine" -> sine is also a variable
|
// example: "s sine" -> sine is also a variable
|
||||||
return reify(strudelScope[value]).withLoc(from, to);
|
pat = reify(variable);
|
||||||
|
} else {
|
||||||
|
pat = reify(value);
|
||||||
}
|
}
|
||||||
return reify(value).withLoc(from, to);
|
|
||||||
|
if (token.loc) {
|
||||||
|
pat = pat.withLoc(token.loc[0], token.loc[1]);
|
||||||
|
}
|
||||||
|
pat.foo = true;
|
||||||
|
return pat;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ Here's an example:
|
||||||
<MiniRepl
|
<MiniRepl
|
||||||
mondo
|
mondo
|
||||||
client:idle
|
client:idle
|
||||||
tune={`$ note c2 .(euclid <3 6 3> <8 16>) . *2
|
tune={`$ note (c2 .euclid <3 6 3> <8 16>) . *2
|
||||||
.s "sine" .add (note [0 <12 24>]*2)
|
.s "sine" .add (note [0 <12 24>]*2)
|
||||||
.dec(sine .range .2 2) .room .5
|
.dec(sine .range .2 2) .room .5
|
||||||
.lpf(sine/3.range 120 400)
|
.lpf(sine/3.range 120 400)
|
||||||
|
|
@ -27,7 +27,7 @@ $ s [bd bd bd bd] .bank tr909.clip.5
|
||||||
.ply<1 [1 [2 4]]>
|
.ply<1 [1 [2 4]]>
|
||||||
|
|
||||||
$ s oh*4 .press .bank tr909 .speed.8
|
$ s oh*4 .press .bank tr909 .speed.8
|
||||||
.dec <.02 .05>*2 .(add (saw/8.range 0 1))`}
|
.dec (<.02 .05>*2 .add (saw/8.range 0 1))`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
## Mondo in the REPL
|
## Mondo in the REPL
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue