-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathindex.js
117 lines (105 loc) · 2.67 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//
// pegjs-coffee-plugin
//
var CoffeeScript = require('coffee-script')
var detectIndent = require('detect-indent')
// The acutal compilation of CoffeeScript.
function compileCoffeeScript (code) {
// Compile options
var options = {
bare: true
}
try {
return CoffeeScript.compile(code, options)
} catch (error) {
var message = 'In: \n' + code + '\n was the following error:' + error.message
throw new SyntaxError(message, error.fileName, error.lineNumber)
}
}
// The initializer gets its own scope which we save
// in __initializer for later use
function wrapInitializer (initializer) {
var indent = detectIndent(initializer).indent || ' '
return [
'__initializer = ( ->',
indent + initializer,
indent + 'return this',
').call({})'
].join('\n')
}
function wrapCode (code) {
return [
'return ( -> ',
code,
' ).apply(__initializer)'
].join('')
}
function compileNode (node) {
if (node.code === undefined) {
return
}
// We inject the scope of the initializer if it exists
// into the function that calls the action code
node.code = compileCoffeeScript(wrapCode(node.code))
return node
}
function buildNodeVisitor (visitorMap) {
visitorMap = visitorMap || {}
return function (node) {
var visitor = visitorMap[node.type] || function () {}
return visitor(node)
}
}
function compileExpression (node) {
compile(node.expression)
compileNode(node)
return node
}
function compileSubnodes (property) {
return function (node) {
for (var i = 0; i < node[property].length; i++) {
compile(node[property][i])
}
return node
}
}
// Recursively walk through all nodes
function compile (nodes) {
buildNodeVisitor({
grammar: compileSubnodes('rules'),
choice: compileSubnodes('alternatives'),
sequence: compileSubnodes('elements'),
semantic_not: compileNode,
semantic_and: compileNode,
literal: compileNode,
rule_ref: compileNode,
'class': compileNode,
any: compileNode,
action: compileExpression,
rule: compileExpression,
named: compileExpression,
labeled: compileExpression,
text: compileExpression,
simple_and: compileExpression,
simple_not: compileExpression,
optional: compileExpression,
zero_or_more: compileExpression,
one_or_more: compileExpression
})(nodes)
}
function pass (ast) {
// Add an initializer block if there is none.
if (!ast.initializer) {
ast.initializer = {
type: 'initializer',
code: ''
}
}
ast.initializer.code = compileCoffeeScript(wrapInitializer(ast.initializer.code))
compile(ast)
}
module.exports = {
use: function (config, options) {
config.passes.transform.unshift(pass)
}
}