Skip to content

Commit

Permalink
Add sequence element labelling to the compiler.
Browse files Browse the repository at this point in the history
  • Loading branch information
jcoglan committed May 1, 2010
1 parent 36df1ac commit 8d47630
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 30 deletions.
1 change: 1 addition & 0 deletions jake.yml
Expand Up @@ -39,6 +39,7 @@ packages:
- stake/compiler/string
- stake/compiler/repeat
- stake/compiler/sequence
- stake/compiler/sequence_part
meta:
provides:
- Stake
Expand Down
9 changes: 5 additions & 4 deletions source/stake/builder.js
Expand Up @@ -56,11 +56,12 @@ Stake.extend({
return input + '.substring(' + of + ', ' + of + ' + ' + length + ')';
},

syntaxNode_: function(address, expression, bump, elements) {
elements = elements || '[]';
var cons = 'new Stake.SyntaxNode', of = this.offset_();
syntaxNode_: function(address, expression, bump, elements, labelled) {
elements = ', ' + (elements || '[]');
labelled = ', ' + (labelled || '{}');
var cons = 'new Stake.SyntaxNode', of = ', ' + this.offset_();

this.line_(address + ' = ' + cons + '(' + expression + ', ' + of + ', ' + elements + ')');
this.line_(address + ' = ' + cons + '(' + expression + of + elements + labelled + ')');
this.line_(this.offset_() + ' += ' + bump);
},

Expand Down
21 changes: 0 additions & 21 deletions source/stake/compiler.js
Expand Up @@ -30,27 +30,6 @@ Stake.extend({
}
}),

SequencePart: new JS.Module({
atomic: function() {
var expression = this.expression;
return expression.parsing_expression || expression;
},

toSexp: function() {
var expression = this.atomic(),
sexp = expression.toSexp();

if (this.elements[0].identifier)
sexp = ['label', this.elements[0].identifier.textValue, sexp];

return sexp;
},

compile: function(builder, address) {
return this.atomic().compile(builder, address);
}
}),

PredicatedAtom: new JS.Module({
atomic: function() {
var expression = this.atom;
Expand Down
16 changes: 11 additions & 5 deletions source/stake/compiler/sequence.js
Expand Up @@ -20,29 +20,35 @@ Stake.Compiler.extend({
compile: function(builder, address) {
var startOffset = builder.tempVar_('index', builder.offset_()),
elements = builder.tempVar_('elements', '[]'),
labelled = builder.tempVar_('labelled', '{}'),
textValue = builder.tempVar_('text', '""');

this._compileExpressions(builder, 0, startOffset, elements, textValue);
this._compileExpressions(builder, 0, startOffset, elements, labelled, textValue);
builder.if_(elements, function(builder) {
builder.line_(builder.offset_() + ' = ' + startOffset);
builder.syntaxNode_(address, textValue, textValue + '.length', elements);
builder.syntaxNode_(address, textValue, textValue + '.length', elements, labelled);
});
builder.else_(function(builder) {
builder.line_(address + ' = null');
});
},

_compileExpressions: function(builder, index, startOffset, elements, textValue) {
_compileExpressions: function(builder, index, startOffset, elements, labelled, textValue) {
var expressions = this.expressions();
if (index === expressions.length) return;

var expAddr = builder.tempVar_('address');
var expAddr = builder.tempVar_('address'),
label = expressions[index].label();

expressions[index].compile(builder, expAddr);

builder.if_(expAddr, function(builder) {
builder.line_(elements + '.push(' + expAddr + ')');
builder.line_(textValue + ' += ' + expAddr + '.textValue');
this._compileExpressions(builder, index + 1, startOffset, elements, textValue);
if (label) builder.line_(labelled + '.' + label + ' = ' + expAddr);

this._compileExpressions(builder, index + 1, startOffset, elements, labelled, textValue);

}, this);
builder.else_(function(builder) {
builder.line_(elements + ' = null');
Expand Down
27 changes: 27 additions & 0 deletions source/stake/compiler/sequence_part.js
@@ -0,0 +1,27 @@
Stake.Compiler.extend({
SequencePart: new JS.Module({
atomic: function() {
var expression = this.expression;
return expression.parsing_expression || expression;
},

label: function() {
var element = this.elements[0].identifier;
return element ? element.textValue : null;
},

toSexp: function() {
var expression = this.atomic(),
label = this.label(),
sexp = expression.toSexp();

if (label) sexp = ['label', label, sexp];
return sexp;
},

compile: function(builder, address) {
return this.atomic().compile(builder, address);
}
})
});

76 changes: 76 additions & 0 deletions spec/stake/compiler/sequence_spec.js
Expand Up @@ -26,5 +26,81 @@ Stake.Compiler.SequenceSpec = JS.Test.describe(Stake.Compiler.Sequence, function
it('does not parse superstrings of itself', function() { with(this) {
assertNull( SequenceTestParser.parse('foobart') )
}})

describe('labelling', function() { with(this) {
describe('a terminal node', function() { with(this) {
before(function() { with(this) {
Stake.compile('grammar LabelTestA\
root <- "first" middle:"second" "third"')
}})

it('adds the label as an extra property to the parse tree', function() { with(this) {
assertParse(['firstsecondthird', 0, [
['first', 0, []],
['second', 5, []],
['third', 11, []]], {
middle: ['second', 5, []]
}],

LabelTestAParser.parse('firstsecondthird') )
}})
}})

describe('a repetition node', function() { with(this) {
before(function() { with(this) {
Stake.compile('grammar LabelTestB\
root <- "first" middle:"a"+ "third"')
}})

it('labels the node containing the repetition', function() { with(this) {
assertParse(['firstaathird', 0, [
['first', 0, []],
['aa', 5, [
['a', 5, []],
['a', 6, []]]],
['third', 7, []]], {
middle: ['aa', 5, [
['a', 5, []],
['a', 6, []]]]
}],

LabelTestBParser.parse('firstaathird') )
}})

it('does not parse if the expression it labels does not parse', function() { with(this) {
assertNull( LabelTestBParser.parse('firstthird') )
}})
}})

describe('nesting', function() { with(this) {
before(function() { with(this) {
Stake.compile('grammar LabelTestC\
root <- firstLetter:[a-z] restLetters:(", " letter:[a-z])*')

this.rest = [', b, c', 1, [
[', b', 1, [
[', ', 1, []],
['b', 3, []]], {
letter: ['b', 3, []]
}],
[', c', 4, [
[', ', 4, []],
['c', 6, []]], {
letter: ['c', 6, []]
}]]]
}})

it('applies labels to nested nodes', function() { with(this) {
assertParse(['a, b, c', 0, [
['a', 0, []],
rest], {
firstLetter: ['a', 0, []],
restLetters: rest
}],

LabelTestCParser.parse('a, b, c') )
}})
}})
}})
}})

0 comments on commit 8d47630

Please sign in to comment.