mondo: flip pipe order: now pining to the end of the function...

This commit is contained in:
Felix Roos 2025-03-21 23:50:14 +01:00
parent 5d4ef46ac7
commit f71db4aeed
No known key found for this signature in database
3 changed files with 34 additions and 66 deletions

View file

@ -106,25 +106,22 @@ export class MondoParser {
children = this.resolve_pipes(children); children = this.resolve_pipes(children);
return children; return children;
} }
// Token[] => Token[][] . returns empty list if type not found // Token[] => Token[][], e.g. (x , y z) => [['x'],['y','z']]
split_children(children, split_type) { split_children(children, split_type) {
const chunks = []; const chunks = [];
while (true) { while (true) {
let commaIndex = children.findIndex((child) => child.type === split_type); let splitIndex = children.findIndex((child) => child.type === split_type);
if (commaIndex === -1) break; if (splitIndex === -1) break;
const chunk = children.slice(0, commaIndex); const chunk = children.slice(0, splitIndex);
chunk.length && chunks.push(chunk); chunk.length && chunks.push(chunk);
children = children.slice(commaIndex + 1); children = children.slice(splitIndex + 1);
}
if (!chunks.length) {
return [];
} }
chunks.push(children); chunks.push(children);
return chunks; return chunks;
} }
desugar_split(children, split_type, next) { desugar_split(children, split_type, next) {
const chunks = this.split_children(children, split_type); const chunks = this.split_children(children, split_type);
if (!chunks.length) { if (chunks.length === 1) {
return next(children); return next(children);
} }
// collect args of stack function // collect args of stack function
@ -168,7 +165,8 @@ export class MondoParser {
children[opIndex] = op; children[opIndex] = op;
continue; continue;
} }
const call = { type: 'list', children: [op, left, right] }; //const call = { type: 'list', children: [op, left, right] };
const call = { type: 'list', children: [op, right, left] };
// insert call while keeping other siblings // insert call while keeping other siblings
children = [...children.slice(0, opIndex - 1), call, ...children.slice(opIndex + 2)]; children = [...children.slice(0, opIndex - 1), call, ...children.slice(opIndex + 2)];
children = this.unwrap_children(children); children = this.unwrap_children(children);
@ -176,46 +174,21 @@ export class MondoParser {
return children; return children;
} }
resolve_pipes(children) { resolve_pipes(children) {
while (true) { let chunks = this.split_children(children, 'pipe');
let pipeIndex = children.findIndex((child) => child.type === 'pipe'); while (chunks.length > 1) {
// no pipe => we're done let [left, right, ...rest] = chunks;
if (pipeIndex === -1) break; if (right.length && right[0].type === 'list') {
// pipe up front => lambda // s jazz hh.(fast 2) => s jazz (fast 2 hh)
if (pipeIndex === 0) { const target = left[left.length - 1]; // hh
// . as lambda: (.fast 2) = (lambda (_) (fast _ 2)) const call = { type: 'list', children: [...right[0].children, target] };
const args = [{ type: 'plain', value: '_' }]; chunks = [[...left.slice(0, -1), call, ...right.slice(1)], ...rest]; // jazz (fast 2 hh)
const body = this.desugar([args[0], ...children]);
return [
{ type: 'plain', value: 'lambda' },
{ type: 'list', children: args },
{ type: 'list', children: body },
];
}
const rightSide = children.slice(pipeIndex + 2);
const right = children[pipeIndex + 1];
if (right.type === 'list') {
// apply function only to left sibling (high precedence)
// s jazz.(fast 2) => s (fast jazz 2)
const [callee, ...rest] = right.children;
const leftSide = children.slice(0, pipeIndex - 1);
const left = children[pipeIndex - 1];
let args = [callee, left, ...rest];
const call = { type: 'list', children: args };
children = [...leftSide, call, ...rightSide];
} else { } else {
// apply function to all left siblings (low precedence) //s jazz hh.fast 2 => (fast 2 (s jazz hh))
// s jazz . fast 2 => fast (s jazz) 2 const call = left.length > 1 ? { type: 'list', children: left } : left[0];
let leftSide = children.slice(0, pipeIndex); chunks = [[...right, call], ...rest];
if (leftSide.length === 1) {
leftSide = leftSide[0];
} else {
// wrap in (..) if multiple items on the left side
leftSide = { type: 'list', children: leftSide };
}
children = [right, leftSide, ...rightSide];
} }
} }
return children; return chunks[0];
} }
parse_pair(open_type, close_type) { parse_pair(open_type, close_type) {
this.consume(open_type); this.consume(open_type);

View file

@ -80,15 +80,15 @@ describe('mondo sugar', () => {
it('should desugar mixed [] <>', () => expect(desguar('[a <b c>]')).toEqual('(square a (angle b c))')); it('should desugar mixed [] <>', () => expect(desguar('[a <b c>]')).toEqual('(square a (angle b c))'));
it('should desugar mixed <> []', () => expect(desguar('<a [b c]>')).toEqual('(angle a (square b c))')); it('should desugar mixed <> []', () => expect(desguar('<a [b c]>')).toEqual('(angle a (square b c))'));
it('should desugar .', () => expect(desguar('s jazz . fast 2')).toEqual('(fast (s jazz) 2)')); it('should desugar .', () => expect(desguar('s jazz . fast 2')).toEqual('(fast 2 (s jazz))'));
it('should desugar . square', () => expect(desguar('[bd cp . fast 2]')).toEqual('(fast (square bd cp) 2)')); it('should desugar . square', () => expect(desguar('[bd cp . fast 2]')).toEqual('(fast 2 (square bd cp))'));
it('should desugar . twice', () => expect(desguar('s jazz . fast 2 . slow 2')).toEqual('(slow (fast (s jazz) 2) 2)')); it('should desugar . twice', () => expect(desguar('s jazz . fast 2 . slow 2')).toEqual('(slow 2 (fast 2 (s jazz)))'));
it('should desugar . nested', () => expect(desguar('(s cp . fast 2)')).toEqual('(fast (s cp) 2)')); it('should desugar . nested', () => expect(desguar('(s cp . fast 2)')).toEqual('(fast 2 (s cp))'));
it('should desugar . within []', () => expect(desguar('[bd cp . fast 2]')).toEqual('(fast (square bd cp) 2)')); it('should desugar . within []', () => expect(desguar('[bd cp . fast 2]')).toEqual('(fast 2 (square bd cp))'));
it('should desugar . within , within []', () => it('should desugar . within , within []', () =>
expect(desguar('[bd cp . fast 2, x]')).toEqual('(stack (fast (square bd cp) 2) x)')); expect(desguar('[bd cp . fast 2, x]')).toEqual('(stack (fast 2 (square bd cp)) x)'));
it('should desugar . ()', () => expect(desguar('[jazz hh.(fast 2)]')).toEqual('(square jazz (fast hh 2))')); it('should desugar . ()', () => expect(desguar('[jazz hh.(fast 2)]')).toEqual('(square jazz (fast 2 hh))'));
it('should desugar , |', () => expect(desguar('[bd, hh | oh]')).toEqual('(stack bd (or hh oh))')); it('should desugar , |', () => expect(desguar('[bd, hh | oh]')).toEqual('(stack bd (or hh oh))'));
it('should desugar , | of []', () => it('should desugar , | of []', () =>
@ -102,15 +102,15 @@ describe('mondo sugar', () => {
it('should desugar , angle 3', () => it('should desugar , angle 3', () =>
expect(desguar('<bd cp, hh oh>')).toEqual('(stack (angle bd cp) (angle hh oh))')); expect(desguar('<bd cp, hh oh>')).toEqual('(stack (angle bd cp) (angle hh oh))'));
it('should desugar , ()', () => expect(desguar('(s bd, s cp)')).toEqual('(stack (s bd) (s cp))')); it('should desugar , ()', () => expect(desguar('(s bd, s cp)')).toEqual('(stack (s bd) (s cp))'));
it('should desugar * /', () => expect(desguar('[a b*2 c d/3 e]')).toEqual('(square a (* b 2) c (/ d 3) e)')); it('should desugar * /', () => expect(desguar('[a b*2 c d/3 e]')).toEqual('(square a (* 2 b) c (/ 3 d) e)'));
it('should desugar []*x', () => expect(desguar('[a [b c]*3]')).toEqual('(square a (* (square b c) 3))')); it('should desugar []*x', () => expect(desguar('[a [b c]*3]')).toEqual('(square a (* 3 (square b c)))'));
it('should desugar x:y', () => expect(desguar('x:y')).toEqual('(: x y)')); it('should desugar x:y', () => expect(desguar('x:y')).toEqual('(: y x)'));
it('should desugar x:y:z', () => expect(desguar('x:y:z')).toEqual('(: (: x y) z)')); it('should desugar x:y:z', () => expect(desguar('x:y:z')).toEqual('(: z (: y x))'));
it('should desugar x:y*x', () => expect(desguar('bd:0*2')).toEqual('(* (: bd 0) 2)')); it('should desugar x:y*x', () => expect(desguar('bd:0*2')).toEqual('(* 2 (: 0 bd))'));
it('should desugar a..b', () => expect(desguar('0..2')).toEqual('(.. 0 2)')); it('should desugar a..b', () => expect(desguar('0..2')).toEqual('(.. 2 0)'));
it('should desugar README example', () => it('should desugar README example', () =>
expect(desguar('s [bd hh*2 cp.(crush 4) <mt ht lt>] . speed .8')).toEqual( expect(desguar('s [bd hh*2 cp.(crush 4) <mt ht lt>] . speed .8')).toEqual(
'(speed (s (square bd (* hh 2) (crush cp 4) (angle mt ht lt))) .8)', '(speed .8 (s (square bd (* 2 hh) (crush 4 cp) (angle mt ht lt))))',
)); ));
}); });

View file

@ -43,11 +43,6 @@ let runner = new MondoRunner({
if (!fn) { if (!fn) {
throw new Error(`[moundough]: unknown function "${name}"`); throw new Error(`[moundough]: unknown function "${name}"`);
} }
if (!['square', 'angle', 'stack', 'curly'].includes(name)) {
// flip args (pat to end)
const [pat, ...rest] = args;
args = [...rest, pat];
}
return fn(...args); return fn(...args);
}, },
leaf(token, scope) { leaf(token, scope) {