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.
This commit is contained in:
Tony Garnock-Jones 2016-07-11 12:02:36 -04:00
parent b323d7c650
commit 9644aa3ad1
2 changed files with 53 additions and 48 deletions

View File

@ -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);
});
}
});

View File

@ -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
};