Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Remove JS.Class from involvement in constructing parser classes and s…

…yntax nodes. Generated parsers are now completely self-contained.
  • Loading branch information...
commit 522fc631cd0357b02b262aa7cdbb92b040a9752f 1 parent 6624357
@jcoglan authored
View
59 source/canopy/builder.js
@@ -34,6 +34,7 @@ Canopy.extend(Canopy.Builder.prototype, {
delimitField_: function() {
this.write(this._methodSeparator);
+ if (this._methodSeparator) this.newline_();
this._methodSeparator = ',';
},
@@ -72,10 +73,10 @@ Canopy.extend(Canopy.Builder.prototype, {
builder.line_(klass + ' = ' + nodeType);
});
this.else_(function(builder) {
- builder.line_(klass + ' = this.klass.SyntaxNode');
+ builder.line_(klass + ' = SyntaxNode');
});
} else {
- klass = this.tempVar_('klass', 'this.klass.SyntaxNode');
+ klass = this.tempVar_('klass', 'SyntaxNode');
}
this.line_(address + ' = new ' + klass + '(' + expression + of + elements + labelled + ')');
@@ -86,14 +87,14 @@ Canopy.extend(Canopy.Builder.prototype, {
extendNode_: function(address, nodeType) {
if (!nodeType) return;
this.unless_(nodeType + ' instanceof Function', function(builder) {
- builder.line_(address + '.extend(' + nodeType + ')');
+ builder.line_('extend(' + address + ', ' + nodeType + ')');
});
},
failure_: function(address, expected) {
this.line_(address + ' = null');
var input = this.input_(), of = this.offset_(), slice = this.slice_(1);
- var error = 'this.error = this.klass.lastError';
+ var error = 'this.error = this.constructor.lastError';
this.if_('!this.error || this.error.offset <= ' + of, function(builder) {
builder.line_(error + ' = {input: ' + input +
', offset: ' + of +
@@ -104,53 +105,35 @@ Canopy.extend(Canopy.Builder.prototype, {
nameSpace_: function(objectName) {
var parts = objectName.split('.');
- this.line_('(function() {');
- this.indent_(function() {
- this.var_('namespace', 'this');
- for (var i = 0, n = parts.length; i < n - 1; i++)
- this.line_('namespace = namespace.' + parts[i] + ' = namespace.' + parts[i] + ' || {}');
- this.if_('typeof exports === "object"', function(builder) {
- builder.line_('exports.' + parts[0] + ' = this.' + parts[0]);
- });
- }, this);
- this.line_('})()');
+ this.var_('namespace', 'this');
+ for (var i = 0, n = parts.length; i < n - 1; i++)
+ this.line_('namespace = namespace.' + parts[i] + ' = namespace.' + parts[i] + ' || {}');
},
- module_: function(name, block, context) {
- this.newline_();
- this.write(name + ' = new JS.Module("' + name + '", {');
+ closure_: function(block, context) {
+ this.write('(function() {');
new Canopy.Builder(this).indent_(block, context);
this.newline_();
- this.write('});');
+ this.write('})();');
+ this.newline_();
+ this.newline_();
},
- class_: function(name, block, context) {
+ function_: function(name, args, block, context) {
this.newline_();
- this.write(name + ' = new JS.Class("' + name + '", {');
+ this.write(name + ' = function(' + args.join(', ') + ') {');
new Canopy.Builder(this).indent_(block, context);
this.newline_();
- this.write('});');
- },
-
- include_: function(name) {
- this.delimitField_();
+ this.write('};');
this.newline_();
- this.write('include: ' + name);
},
- classMethods_: function(block, context) {
- this.delimitField_();
+ module_: function(name, block, context) {
this.newline_();
- this.write('extend: {');
+ this.write(name + ' = {');
new Canopy.Builder(this).indent_(block, context);
this.newline_();
- this.write('}');
- },
-
- field_: function(name, value) {
- this.delimitField_();
- this.newline_();
- this.write(name + ': ' + value);
+ this.write('};');
},
method_: function(name, args, block, context) {
@@ -188,6 +171,10 @@ Canopy.extend(Canopy.Builder.prototype, {
this.write('}');
},
+ for_: function(condition, block, context) {
+ this.conditional_('for', condition, block, context);
+ },
+
while_: function(condition, block, context) {
this.conditional_('while', condition, block, context);
},
View
69 source/canopy/compiler/grammar.js
@@ -12,41 +12,47 @@ Canopy.Compiler.Grammar = {
},
compile: function(builder) {
- builder.nameSpace_(this.grammarName());
- builder.newline_();
-
- builder.module_(this.grammarName(), function(builder) {
- builder.field_('root', '"' + this.rules.elements[0].grammar_rule.name() + '"');
- this.rules.forEach(function(rule) {
- rule.grammar_rule.compile(builder);
+ builder.closure_(function(builder) {
+ builder.function_('var extend', ['destination', 'source'], function(builder) {
+ builder.line_('if (!source) return destination');
+ builder.for_('var key in source', function(builder) {
+ builder.if_('destination[key] !== source[key]', function(builder) {
+ builder.line_('destination[key] = source[key]');
+ });
+ });
+ builder.return_('destination');
});
- }, this);
- builder.newline_();
-
- builder.class_(this.grammarName() + 'Parser', function(builder) {
- builder.include_(this.grammarName());
- builder.method_('initialize', ['input'], function(builder) {
+
+ builder.nameSpace_(this.grammarName());
+ builder.newline_();
+
+ builder.module_(this.grammarName(), function(builder) {
+ this.rules.forEach(function(rule) {
+ rule.grammar_rule.compile(builder);
+ });
+ }, this);
+ builder.newline_();
+
+ var parser = this.grammarName() + 'Parser',
+ root = this.rules.elements[0].grammar_rule.name();
+
+ builder.function_(parser, ['input'], function(builder) {
builder.ivar_('input', 'input');
builder.ivar_('offset', '0');
builder.ivar_('nodeCache', '{}');
});
- builder.method_('parse', [], function(builder) {
- builder.var_('result', 'this["__consume__" + this.root]()');
+ builder.function_(parser + '.prototype.parse', [], function(builder) {
+ builder.var_('result', 'this.__consume__' + root + '()');
builder.return_(builder.offset_() + ' === ' + builder.input_() + '.length ? result : null');
});
- builder.classMethods_(function(builder) {
- builder.method_('parse', ['input'], function(builder) {
- builder.var_('parser', 'new this(input)');
- builder.return_('parser.parse()');
- });
+ builder.function_(parser + '.parse', ['input'], function(builder) {
+ builder.var_('parser', 'new this(input)');
+ builder.return_('parser.parse()');
});
- }, this);
- builder.newline_();
-
- builder.class_(this.grammarName() + 'Parser.SyntaxNode', function(builder) {
- builder.include_('JS.Enumerable');
+ builder.line_('extend(' + parser + '.prototype, ' + this.grammarName() + ')');
+ builder.newline_();
- builder.method_('initialize', ['textValue', 'offset', 'elements', 'properties'], function(builder) {
+ builder.function_('var SyntaxNode', ['textValue', 'offset', 'elements', 'properties'], function(builder) {
builder.line_('this.textValue = textValue');
builder.line_('this.offset = offset');
builder.line_('this.elements = elements || []');
@@ -54,17 +60,18 @@ Canopy.Compiler.Grammar = {
builder.line_('if (!properties) return');
builder.line_('for (var key in properties) this[key] = properties[key]');
});
-
- builder.method_('forEach', ['block', 'context'], function(builder) {
+ builder.function_('SyntaxNode.prototype.forEach', ['block', 'context'], function(builder) {
builder.newline_();
builder.write('for (var i = 0, n = this.elements.length; i < n; i++)');
builder.indent_(function(builder) {
builder.line_('block.call(context, this.elements[i], i)');
});
});
- });
- builder.newline_();
- builder.line_(this.grammarName() + 'Parser.formatError = ' + Canopy.formatError.toString());
+ builder.line_(parser + '.SyntaxNode = SyntaxNode');
+
+ builder.newline_();
+ builder.line_(this.grammarName() + 'Parser.formatError = ' + Canopy.formatError.toString());
+ }, this);
}
};
View
4,312 source/canopy/meta_grammar.js
2,170 additions, 2,142 deletions not shown
View
2  spec/browser.html
@@ -3,12 +3,10 @@
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Canopy test runner</title>
- <link rel="stylesheet" type="text/css" href="../vendor/js.class/test/testui.css">
</head>
<body>
<script type="text/javascript">CWD = '..'</script>
<script type="text/javascript" src="../node_modules/jsclass/min/loader.js"></script>
- <script type="text/javascript" src="../node_modules/jsclass/min/core.js"></script>
<script type="text/javascript" src="../lib/canopy-min.js"></script>
<script type="text/javascript" src="../spec/runner.js"></script>
</body>
View
18 spec/canopy/compiler/choice_part_spec.js
@@ -7,7 +7,11 @@ function() { with(this) {
Canopy.compile('grammar ClassTypeTest\
rule <- "content" <NodeType>')
- NodeType = new JS.Class(ClassTypeTestParser.SyntaxNode)
+ NodeType = function(text, offset, children) {
+ this.textValue = text
+ this.offset = 0
+ this.elements = children
+ }
}})
it('creates nodes using the named type', function() { with(this) {
@@ -21,7 +25,7 @@ function() { with(this) {
describe('when the node type is a mixin', function() { with(this) {
before(function() { with(this) {
- NodeType = new JS.Module({ custom: function(){} })
+ NodeType = { custom: function() { return 'pass!' } }
Canopy.compile('grammar ModuleTypeTest\
rule <- "content" <NodeType>')
@@ -29,7 +33,7 @@ function() { with(this) {
it('creates nodes using the named type', function() { with(this) {
var result = ModuleTypeTestParser.parse('content')
- assertKindOf( NodeType, result )
+ assertEqual( 'pass!', result.custom() )
assertRespondTo( result, 'custom' )
}})
@@ -40,27 +44,27 @@ function() { with(this) {
describe('when the underlying parser is a choice', function() { with(this) {
before(function() { with(this) {
- NodeType = new JS.Module({ custom: function(){} })
+ NodeType = { custom: function() { return 'pass!' } }
Canopy.compile('grammar TypedChoiceTest\
rule <- ("content" / "booya") <NodeType>')
}})
it('extends the chosen node with the mixin', function() { with(this) {
- assertKindOf( NodeType, TypedChoiceTestParser.parse('booya') )
+ assertEqual( 'pass!', TypedChoiceTestParser.parse('content').custom() )
}})
}})
describe('when the underlying parser is a maybe', function() { with(this) {
before(function() { with(this) {
- NodeType = new JS.Module({ custom: function(){} })
+ NodeType = { custom: function() { return 'pass!' } }
Canopy.compile('grammar TypedMaybeTest\
rule <- "content"? <NodeType>')
}})
it('extends the chosen node with the mixin', function() { with(this) {
- assertKindOf( NodeType, TypedMaybeTestParser.parse('content') )
+ assertEqual( 'pass!', TypedMaybeTestParser.parse('content').custom() )
}})
}})
View
2  spec/canopy/meta_grammar_parser_spec.js
@@ -1,4 +1,4 @@
-Canopy.MetaGrammarParserSpec = JS.Test.describe(Canopy.MetaGrammarParser,
+Canopy.MetaGrammarParserSpec = JS.Test.describe("Canopy.MetaGrammarParser",
function() { with(this) {
describe('with an any-char rule', function() { with(this) {
before(function() { with(this) {
View
2  spec/console.js
@@ -14,12 +14,10 @@ JSCLASS_PATH = 'node_modules/jsclass/min'
if (typeof require === 'function') {
require('../' + JSCLASS_PATH + '/loader')
- JS.require('JS.Class')
Canopy = require('../lib/canopy-min')
require('./runner')
} else {
load(JSCLASS_PATH + '/loader.js')
- JS.require('JS.Class')
load('lib/canopy-min.js')
load('spec/runner.js')
}
Please sign in to comment.
Something went wrong with that request. Please try again.