Skip to content
This repository was archived by the owner on Jun 5, 2020. It is now read-only.

Commit c8eab36

Browse files
committed
Post-merge
2 parents 24d81ff + 0fb4d67 commit c8eab36

File tree

7 files changed

+193
-87
lines changed

7 files changed

+193
-87
lines changed

Preprocessor.js

Lines changed: 80 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@
2828
* @param {string} source Source to process
2929
* @param {string|Object.<string,string>=} baseDirOrIncludes Source base directory used for includes (node.js only)
3030
* or an object containing all the included sources by filename. Defaults to the current working directory.
31+
* @param {boolean} preserveLineNumbers When removing blocks of code, replace the block with blank lines so that
32+
* line numbers are preserved, as long as #include is not used
3133
* @constructor
3234
*/
33-
var Preprocessor = function Preprocessor(source, baseDirOrIncludes) {
35+
var Preprocessor = function Preprocessor(source, baseDirOrIncludes, preserveLineNumbers) {
3436

3537
/**
3638
* Source code to pre-process.
@@ -47,18 +49,23 @@
4749
this.baseDir = typeof baseDirOrIncludes == 'string' ? baseDirOrIncludes : ".";
4850

4951
/**
50-
* Current base directory.
51-
* @type {string}
52-
* @expose
52+
* Included sources by filename.
53+
* @type {Object.<string, string>}
5354
*/
54-
this.dir = this.baseDir;
55+
this.includes = typeof baseDirOrIncludes == 'object' ? baseDirOrIncludes : {};
5556

5657
/**
57-
* Included sources by filename.
58-
* @type {!Object.<string, string>}
58+
* Preserve line numbers when removing blocks of code
59+
* @type {boolean}
60+
*/
61+
this.preserveLineNumbers = typeof preserveLineNumbers == 'boolean' ? preserveLineNumbers : false;
62+
63+
/**
64+
* Whether running inside of node.js or not.
65+
* @type {boolean}
5966
* @expose
6067
*/
61-
this.includes = typeof baseDirOrIncludes == 'object' ? baseDirOrIncludes : {};
68+
this.isNode = (typeof window == 'undefined' || !window.window) && typeof require == 'function';
6269

6370
/**
6471
* Error reporting source ahead length.
@@ -68,21 +75,12 @@
6875
this.errorSourceAhead = 50;
6976

7077
/**
71-
* Defines.
72-
* @type {!Object.<string>}
73-
* @expose
78+
* Runtime defines.
79+
* @type {Array.<string>}
7480
*/
75-
this.defines = {};
81+
this.defines = [];
7682
};
7783

78-
/**
79-
* Whether running under node.js or not.
80-
* @type {boolean}
81-
* @const
82-
* @expose
83-
*/
84-
Preprocessor.IS_NODE = (typeof window === 'undefined' || !window.window) && typeof require === 'function' && typeof process === 'object' && typeof process.nextTick === 'function';
85-
8684
/**
8785
* Definition expression
8886
* @type {!RegExp}
@@ -117,14 +115,20 @@
117115
* #define EXPRESSION
118116
* @type {!RegExp}
119117
*/
120-
Preprocessor.DEFINE = /define[ ]+([^ ]+)[ ]+([^\n]+)\r?(?:\n|$)/g;
118+
Preprocessor.DEFINE = /define[ ]+([^\n]+)\r?(?:\n|$)/g;
121119

122120
/**
123121
* @type {!RegExp}
124122
* @inner
125123
*/
126124
var GLOB_EXP = /(?:^|[^\\])\*/;
127125

126+
/**
127+
* @type {!RegExp}
128+
* @inner
129+
*/
130+
var NOT_LINE_ENDING = /[^\r\n]/g;
131+
128132
/**
129133
* Strips slashes from an escaped string.
130134
* @param {string} str Escaped string
@@ -177,36 +181,41 @@
177181
Preprocessor.nlToStr = function(str) {
178182
return '['+str.replace(/\r/g, "").replace(/\n/g, "\\n")+']';
179183
};
180-
184+
181185
/**
182186
* Evaluates an expression.
187+
* @param {object.<string,string>} runtimeDefines Runtime defines
188+
* @param {Array.<string>|string} inlineDefines Inline defines (optional for backward compatibility)
183189
* @param {string=} expr Expression to evaluate
184190
* @return {*} Expression result
185191
* @throws {Error} If the expression cannot be evaluated
186192
* @expose
187193
*/
188-
Preprocessor.evaluate = function(expr) {
189-
// Potentially this is dangerous but as we don't want to write a special interpreter, it must be good enough.
190-
if (expr.indexOf(";") >= 0)
191-
throw(new Error("Illegal expression: "+expr));
192-
return eval("(function() { return "+expr+" }()"); // May also throw
193-
};
194-
195-
/**
196-
* Processes the specified sources using the given parameters.
197-
* @param {string} source Source to process
198-
* @param {string|Object.<string,string>=} baseDirOrIncludes Source base directory used for includes (node.js only)
199-
* or an object containing all the included sources by filename. Defaults to the current working directory.
200-
* @param {object.<string,string>} defines Defines
201-
* @param {function(string)=} verbose Print verbose processing information to the specified function as the first parameter. Defaults to not print debug information.
202-
* @returns {string}
203-
*/
204-
Preprocessor.process = function(source, baseDirOrIncludes, defines, verbose) {
205-
return new Preprocessor(source, baseDirOrIncludes).process(defines, verbose);
194+
Preprocessor.evaluate = function(runtimeDefines, inlineDefines, expr) {
195+
if (typeof inlineDefines === 'string') {
196+
expr = inlineDefines;
197+
inlineDefines = [];
198+
}
199+
var addSlashes = Preprocessor.addSlashes;
200+
return (function(runtimeDefines, inlineDefines, expr) {
201+
for (var key in runtimeDefines) {
202+
if (runtimeDefines.hasOwnProperty(key)) {
203+
eval("var "+key+" = \""+addSlashes(""+runtimeDefines[key])+"\";");
204+
}
205+
}
206+
for (var i=0; i<inlineDefines.length; i++) {
207+
var def = inlineDefines[i];
208+
if (def.substring(0,9) != 'function ' && def.substring(0,4) != 'var ') {
209+
def = "var "+def; // Enforce local
210+
}
211+
eval(def);
212+
}
213+
return eval(expr);
214+
}).bind(null)(runtimeDefines, inlineDefines, expr);
206215
};
207216

208217
/**
209-
* Processes this instances sources.
218+
* Preprocesses.
210219
* @param {object.<string,string>} defines Defines
211220
* @param {function(string)=} verbose Print verbose processing information to the specified function as the first parameter. Defaults to not print debug information.
212221
* @return {string} Processed source
@@ -218,14 +227,6 @@
218227
verbose = typeof verbose == 'function' ? verbose : function() {};
219228
verbose("Defines: "+JSON.stringify(defines));
220229

221-
var defs = {};
222-
for (var i in this.defines) // Inline defines
223-
if (this.defines.hasOwnProperty(i))
224-
defs[i] = this.defines[i];
225-
for (i in defines) // Runtime defines
226-
if (defines.hasOwnProperty(i))
227-
defs[i] = this.defines[i];
228-
229230
var match, match2, include, p, stack = [];
230231
while ((match = Preprocessor.EXPR.exec(this.source)) !== null) {
231232
verbose(match[2]+" @ "+match.index+"-"+Preprocessor.EXPR.lastIndex);
@@ -247,7 +248,7 @@
247248
include = this.includes[include];
248249
}
249250
} else { // Load it if in node.js...
250-
if (!Preprocessor.IS_NODE) {
251+
if (!this.isNode) {
251252
throw(new Error("Failed to resolve include: "+this.baseDir+"/"+include));
252253
}
253254
try {
@@ -262,7 +263,7 @@
262263
include = '';
263264
for (var i=0; i<files.length; i++) {
264265
verbose(' incl: '+files[i]);
265-
var contents = fs.readFileSync(files[i])+"\n"; // One new line between files
266+
var contents = fs.readFileSync(files[i])+"";
266267
_this.includes[key] = contents;
267268
include += contents;
268269
}
@@ -287,7 +288,7 @@
287288
}
288289
include = match2[1];
289290
verbose(" expr: "+match2[1]);
290-
include = Preprocessor.evaluate(defs, match2[1]);
291+
include = Preprocessor.evaluate(defines, this.defines, match2[1]);
291292
verbose(" value: "+Preprocessor.nlToStr(include));
292293
this.source = this.source.substring(0, match.index)+indent+include+this.source.substring(Preprocessor.PUT.lastIndex);
293294
Preprocessor.EXPR.lastIndex = match.index + include.length;
@@ -302,11 +303,11 @@
302303
}
303304
verbose(" test: "+match2[2]);
304305
if (match2[1] == "ifdef") {
305-
include = typeof defs[match2[2]] !== 'undefined';
306+
include = !!defines[match2[2]];
306307
} else if (match2[1] == "ifndef") {
307-
include = typeof defs[match2[2]] === 'undefined';
308+
include = !defines[match2[2]];
308309
} else {
309-
include = Preprocessor.evaluate(defines, match2[2]);
310+
include = Preprocessor.evaluate(defines, this.defines, match2[2]);
310311
}
311312
verbose(" value: "+include);
312313
stack.push(p={
@@ -328,10 +329,22 @@
328329
}
329330
var before = stack.pop();
330331
verbose(" pop: "+JSON.stringify(before));
331-
include = this.source.substring(before["lastIndex"], match.index);
332+
333+
if (this.preserveLineNumbers) {
334+
include = this.source.substring(before["index"], before["lastIndex"]).replace(NOT_LINE_ENDING, "")+
335+
this.source.substring(before["lastIndex"], match.index)+
336+
this.source.substring(match.index, Preprocessor.ENDIF.lastIndex).replace(NOT_LINE_ENDING, "");
337+
} else {
338+
include = this.source.substring(before["lastIndex"], match.index);
339+
}
340+
332341
if (before["include"]) {
333342
verbose(" incl: "+Preprocessor.nlToStr(include)+", 0-"+before['index']+" + "+include.length+" bytes + "+Preprocessor.ENDIF.lastIndex+"-"+this.source.length);
334343
this.source = this.source.substring(0, before["index"])+include+this.source.substring(Preprocessor.ENDIF.lastIndex);
344+
} else if (this.preserveLineNumbers) {
345+
verbose(" excl(\\n): "+Preprocessor.nlToStr(include)+", 0-"+before['index']+" + "+Preprocessor.ENDIF.lastIndex+"-"+this.source.length);
346+
include = include.replace(NOT_LINE_ENDING, "");
347+
this.source = this.source.substring(0, before["index"])+include+this.source.substring(Preprocessor.ENDIF.lastIndex);
335348
} else {
336349
verbose(" excl: "+Preprocessor.nlToStr(include)+", 0-"+before['index']+" + "+Preprocessor.ENDIF.lastIndex+"-"+this.source.length);
337350
include = "";
@@ -346,7 +359,7 @@
346359
if (match2[1] == 'else') {
347360
include = !before["include"];
348361
} else {
349-
include = Preprocessor.evaluate(defs, match2[2]);
362+
include = Preprocessor.evaluate(defines, this.defines, match2[2]);
350363
}
351364
stack.push(p={
352365
"include": !before["include"],
@@ -362,11 +375,14 @@
362375
if ((match2 = Preprocessor.DEFINE.exec(this.source)) === null) {
363376
throw(new Error("Illegal #"+match[2]+": "+this.source.substring(match.index, match.index+this.errorSourceAhead)+"..."));
364377
}
365-
var defineName = match2[1],
366-
defineValue = match2[2];
367-
verbose(" def: "+defineName+" "+defineValue);
368-
defs[defineName] = defineValue;
369-
this.source = this.source.substring(0, match.index)+indent+this.source.substring(Preprocessor.DEFINE.lastIndex);
378+
var define = match2[1];
379+
verbose(" def: "+match2[1]);
380+
this.defines.push(define);
381+
var lineEnding = ""
382+
if (this.preserveLineNumbers) {
383+
lineEnding = this.source.substring(match.index, Preprocessor.DEFINE.lastIndex).replace(NOT_LINE_ENDING, "");
384+
}
385+
this.source = this.source.substring(0, match.index)+indent+lineEnding+this.source.substring(Preprocessor.DEFINE.lastIndex);
370386
Preprocessor.EXPR.lastIndex = match.index;
371387
verbose(" continue at "+Preprocessor.EXPR.lastIndex);
372388
}
@@ -398,5 +414,5 @@
398414
}
399415
global["dcodeIO"]["Preprocessor"] = Preprocessor;
400416
}
401-
402-
})(this);
417+
418+
})(this);

0 commit comments

Comments
 (0)