diff --git a/src/parser/__tests__/source.spec.ts b/src/parser/__tests__/source.spec.ts index 1c42a61b..8e55a4e9 100644 --- a/src/parser/__tests__/source.spec.ts +++ b/src/parser/__tests__/source.spec.ts @@ -1823,4 +1823,24 @@ describe('SonicWeave parser', () => { '27\\27', ]); }); + + it('supports guard rails against absurd MOS declarations', () => { + const ast = parseAST('MOS 420L 69s'); + + const visitor = getSourceVisitor(false); + visitor.rootContext!.gas = 100; + expect(() => visitor.executeProgram(ast)).toThrow(); + }); + + it('supports guard rails against unreasonable automos', () => { + const ast = parseAST(` + MOS 20L 20s + automos() + `); + + const visitor = getSourceVisitor(false); + visitor.rootContext!.gas = 100; + visitor.visit(ast.body[0]); + expect(() => visitor.visit(ast.body[1])).toThrow(); + }); }); diff --git a/src/parser/mos.ts b/src/parser/mos.ts index 38744b7e..add6f340 100644 --- a/src/parser/mos.ts +++ b/src/parser/mos.ts @@ -43,10 +43,15 @@ export class Tardigrade { this.subVisitor = subVisitor; } + spendGas(amount?: number) { + this.subVisitor.spendGas(amount); + } + createMosConfig(): MosConfig { if (!this.pattern) { throw new Error('Mode must be given in MOS declaration.'); } + this.spendGas(this.pattern.length); const notation = generateNotation(this.pattern); const N = new Fraction(this.pattern.length); const countL = new Fraction((this.pattern.match(/L/g) ?? []).length); @@ -179,6 +184,7 @@ export class Tardigrade { } visit(node: MosExpression) { + this.spendGas(); switch (node.type) { case 'AbstractStepPattern': return this.visitAbstractStepPattern(node); @@ -202,6 +208,7 @@ export class Tardigrade { } visitAbstractStepPattern(node: AbstractStepPattern) { + this.spendGas(node.pattern.length); this.pattern = node.pattern.join(''); if (node.equave) { this.equave = this.visitRationalEquave(node.equave); @@ -209,6 +216,7 @@ export class Tardigrade { } visitIntegerPattern(node: IntegerPattern) { + this.spendGas(node.pattern.length); const small = Math.min(...node.pattern); const large = Math.max(...node.pattern); this.pattern = node.pattern.map(i => (i === small ? 's' : 'L')).join(''); @@ -223,6 +231,7 @@ export class Tardigrade { } visitPatternUpDownPeriod(node: PatternUpDownPeriod) { + this.spendGas(Math.abs(node.countLarge) + Math.abs(node.countSmall)); const options: MosOptions = {}; if (node.udp) { options.up = node.udp.up; diff --git a/src/stdlib/builtin.ts b/src/stdlib/builtin.ts index c8117eab..7d72f9f4 100644 --- a/src/stdlib/builtin.ts +++ b/src/stdlib/builtin.ts @@ -1933,6 +1933,7 @@ function automos(this: ExpressionVisitor) { if (!this.rootContext?.mosConfig || scale.length) { return; } + this.spendGas(this.rootContext.mosConfig.scale.size); const J4 = this.rootContext.C4; const monzos = scaleMonzos(this.rootContext.mosConfig).map(m => J4.mul(m)); return monzos.map(