From 9644aa3ad129070119e50feb1259d2075f47e660 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Mon, 11 Jul 2016 12:02:36 -0400 Subject: [PATCH] Fixes to code-generation in Syndicate/js compiler. 1. Repair .buildSubscription(mode) so it doesn't delete spaces in unchanged ES5 code. 2. Avoid ',' between successive translated clauses in a FacetStateTransitionBlock. --- js/compiler/compiler.js | 55 ++++++++++++++++++++--------------------- js/compiler/es5.js | 46 +++++++++++++++++++--------------- 2 files changed, 53 insertions(+), 48 deletions(-) diff --git a/js/compiler/compiler.js b/js/compiler/compiler.js index f674ace..d153266 100644 --- a/js/compiler/compiler.js +++ b/js/compiler/compiler.js @@ -141,7 +141,7 @@ var modifiedSourceActions = { return (init ? init.asES5 : '') + situations.asES5.join('') + (done ? done.asES5 : ''); }, FacetStateTransitionBlock: function(_leftParen, transitions, _rightParen) { - return transitions.asES5; + return transitions.asES5.join(''); }, FacetInitBlock: function(_init, block) { @@ -238,7 +238,7 @@ function buildSubscription(children, patchMethod, mode, whenClause, cachedAssert if (cachedAssertionVar) { fragments.push(cachedAssertionVar); } else { - children.forEach(function (c) { c.buildSubscription(fragments, mode); }); + children.forEach(function (c) { fragments.push(c.buildSubscription(mode)); }); } if (patchMethod) { fragments.push(', '); @@ -268,7 +268,7 @@ semantics.addAttribute('instantiatedAssertion', { _default: function(children) { var fragments = []; fragments.push('(function() { var _ = Syndicate.__; return '); - children.forEach(function (c) { c.buildSubscription(fragments, 'instantiated'); }); + children.forEach(function (c) { fragments.push(c.buildSubscription('instantiated')); }); fragments.push('; })()'); return fragments.join(''); } @@ -307,43 +307,41 @@ semantics.addAttribute('metalevel', { } }); -semantics.addOperation('buildSubscription(acc,mode)', { +semantics.addOperation('buildSubscription(mode)', { FacetEventPattern_messageEvent: function(_kw, pattern) { - pattern.buildSubscription(this.args.acc, this.args.mode); + return pattern.buildSubscription(this.args.mode); }, FacetEventPattern_assertedEvent: function(_kw, pattern) { - pattern.buildSubscription(this.args.acc, this.args.mode); + return pattern.buildSubscription(this.args.mode); }, FacetEventPattern_retractedEvent: function(_kw, pattern) { - pattern.buildSubscription(this.args.acc, this.args.mode); + return pattern.buildSubscription(this.args.mode); }, FacetTransitionEventPattern_facetEvent: function (pattern) { - pattern.buildSubscription(this.args.acc, this.args.mode); + return pattern.buildSubscription(this.args.mode); }, FacetPattern: function (v) { - v.children[0].buildSubscription(this.args.acc, this.args.mode); // both branches! + return v.children[0].buildSubscription(this.args.mode); // both branches! }, AssignmentExpression_assignment: function (lhsExpr, _assignmentOperator, rhsExpr) { var i = lhsExpr.interval.contents; if (i[0] === '$' && i.length > 1) { switch (this.args.mode) { - case 'pattern': rhsExpr.buildSubscription(this.args.acc, this.args.mode); break; - case 'instantiated': lhsExpr.buildSubscription(this.args.acc, this.args.mode); break; - case 'projection': { - this.args.acc.push('(Syndicate._$(' + JSON.stringify(i.slice(1)) + ','); - rhsExpr.buildSubscription(this.args.acc, this.args.mode); - this.args.acc.push('))'); - break; - } + case 'pattern': return rhsExpr.buildSubscription(this.args.mode); + case 'instantiated': return lhsExpr.buildSubscription(this.args.mode); + case 'projection': + return '(Syndicate._$(' + JSON.stringify(i.slice(1)) + ',' + + rhsExpr.buildSubscription(this.args.mode) + + '))'; default: throw new Error('Unexpected buildSubscription mode ' + this.args.mode); } } else { - lhsExpr.buildSubscription(this.args.acc, this.args.mode); - _assignmentOperator.buildSubscription(this.args.acc, this.args.mode); - rhsExpr.buildSubscription(this.args.acc, this.args.mode); + return lhsExpr.buildSubscription(this.args.mode) + + _assignmentOperator.buildSubscription(this.args.mode) + + rhsExpr.buildSubscription(this.args.mode); } }, @@ -351,23 +349,24 @@ semantics.addOperation('buildSubscription(acc,mode)', { var i = this.interval.contents; if (i[0] === '$' && i.length > 1) { switch (this.args.mode) { - case 'pattern': this.args.acc.push('_'); break; - case 'instantiated': this.args.acc.push(i.slice(1)); break; - case 'projection': this.args.acc.push('(Syndicate._$(' + JSON.stringify(i.slice(1)) + '))'); break; + case 'pattern': return '_'; + case 'instantiated': return i.slice(1); + case 'projection': return '(Syndicate._$(' + JSON.stringify(i.slice(1)) + '))'; default: throw new Error('Unexpected buildSubscription mode ' + this.args.mode); } } else { - this.args.acc.push(i); + return i; } }, _terminal: function() { - this.args.acc.push(this.interval.contents); + return undefined; }, _nonterminal: function(children) { var self = this; - forEachChild(children, function (c) { - c.buildSubscription(self.args.acc, self.args.mode); - }); + return ES5.translateNonterminalCode(children, + function(n) { + return n.buildSubscription(self.args.mode); + }); } }); diff --git a/js/compiler/es5.js b/js/compiler/es5.js index c453618..5bd44e8 100644 --- a/js/compiler/es5.js +++ b/js/compiler/es5.js @@ -40,28 +40,33 @@ function compareByInterval(node, otherNode) { return node.interval.startIdx - otherNode.interval.startIdx; } +function translateNonterminalCode(children, nodeTranslator) { + var flatChildren = flattenIterNodes(children).sort(compareByInterval); + var childResults = flatChildren.map(nodeTranslator); + if (flatChildren.length === 0 || childResults.every(isUndefined)) { + return undefined; + } + var code = ''; + var interval = flatChildren[0].interval.collapsedLeft(); + for (var i = 0; i < flatChildren.length; ++i) { + if (childResults[i] == null) { + // Grow the interval to include this node. + interval = interval.coverageWith(flatChildren[i].interval.collapsedRight()); + } else { + interval = interval.coverageWith(flatChildren[i].interval.collapsedLeft()); + code += interval.contents + childResults[i]; + interval = flatChildren[i].interval.collapsedRight(); + } + } + code += interval.contents; + return code; +} + // Semantic actions for the `modifiedSource` attribute (see below). var modifiedSourceActions = { _nonterminal: function(children) { - var flatChildren = flattenIterNodes(children).sort(compareByInterval); - var childResults = flatChildren.map(function(n) { return n.modifiedSource; }); - if (flatChildren.length === 0 || childResults.every(isUndefined)) { - return undefined; - } - var code = ''; - var interval = flatChildren[0].interval.collapsedLeft(); - for (var i = 0; i < flatChildren.length; ++i) { - if (childResults[i] == null) { - // Grow the interval to include this node. - interval = interval.coverageWith(flatChildren[i].interval.collapsedRight()); - } else { - interval = interval.coverageWith(flatChildren[i].interval.collapsedLeft()); - code += interval.contents + childResults[i]; - interval = flatChildren[i].interval.collapsedRight(); - } - } - code += interval.contents; - return code; + return translateNonterminalCode(children, + function(n) { return n.modifiedSource; }); }, _iter: function(_) { throw new Error('_iter semantic action should never be hit'); @@ -90,5 +95,6 @@ semantics.addAttribute('asES5', { module.exports = { grammar: g, - semantics: semantics + semantics: semantics, + translateNonterminalCode: translateNonterminalCode };