|
65 | 65 | * @expose |
66 | 66 | */ |
67 | 67 | this.errorSourceAhead = 50; |
| 68 | + |
| 69 | + /** |
| 70 | + * Runtime defines. |
| 71 | + * @type {Array.<string>} |
| 72 | + */ |
| 73 | + this.defines = []; |
68 | 74 | }; |
69 | 75 |
|
70 | 76 | /** |
71 | 77 | * Definition expression |
72 | 78 | * @type {RegExp} |
73 | 79 | */ |
74 | | - Preprocessor.EXPR = /([ ]*)\/\/[ ]+#(include|ifn?def|if|endif|else|elif|put)/g; |
| 80 | + Preprocessor.EXPR = /([ ]*)\/\/[ ]+#(include|ifn?def|if|endif|else|elif|put|define)/g; |
75 | 81 |
|
76 | 82 | /** |
77 | 83 | * #include "path/to/file". Requires node.js' "fs" module. |
|
97 | 103 | */ |
98 | 104 | Preprocessor.PUT = /put[ ]+([^\n]+)[ ]*/g; |
99 | 105 |
|
| 106 | + /** |
| 107 | + * #define EXPRESSION |
| 108 | + * @type {RegExp} |
| 109 | + */ |
| 110 | + Preprocessor.DEFINE = /define[ ]+([^\n]+)\r?(?:\n|$)/g; |
| 111 | + |
100 | 112 | /** |
101 | 113 | * Strips slashes from an escaped string. |
102 | 114 | * @param {string} str Escaped string |
|
152 | 164 |
|
153 | 165 | /** |
154 | 166 | * Evaluates an expression. |
155 | | - * @param {object.<strin,string>} defines Defines |
156 | | - * @param {string} expr Expression to evaluate |
| 167 | + * @param {object.<string,string>} runtimeDefines Runtime defines |
| 168 | + * @param {Array.<string>|string} inlineDefines Inline defines (optional for backward compatibility) |
| 169 | + * @param {string=} expr Expression to evaluate |
157 | 170 | * @return {*} Expression result |
158 | 171 | * @throws {Error} If the expression cannot be evaluated |
159 | 172 | * @expose |
160 | 173 | */ |
161 | | - Preprocessor.evaluate = function(defines, expr) { |
| 174 | + Preprocessor.evaluate = function(runtimeDefines, inlineDefines, expr) { |
| 175 | + if (typeof inlineDefines === 'string') { |
| 176 | + expr = inlineDefines; |
| 177 | + inlineDefines = []; |
| 178 | + } |
162 | 179 | var addSlashes = Preprocessor.addSlashes; |
163 | | - return (function(defines, expr) { |
164 | | - var Preprocessor = null; |
165 | | - for (var key in defines) { |
166 | | - if (defines.hasOwnProperty(key)) { |
167 | | - eval("var "+key+" = \""+addSlashes(""+defines[key])+"\";"); |
| 180 | + return (function(runtimeDefines, inlineDefines, expr) { |
| 181 | + for (var key in runtimeDefines) { |
| 182 | + if (runtimeDefines.hasOwnProperty(key)) { |
| 183 | + eval("var "+key+" = \""+addSlashes(""+runtimeDefines[key])+"\";"); |
| 184 | + } |
| 185 | + } |
| 186 | + for (var i=0; i<inlineDefines.length; i++) { |
| 187 | + var def = inlineDefines[i]; |
| 188 | + if (def.substring(0,9) != 'function ' && def.substring(0,4) != 'var ') { |
| 189 | + def = "var "+def; // Enforce local |
168 | 190 | } |
| 191 | + eval(def); |
169 | 192 | } |
170 | 193 | return eval(expr); |
171 | | - }).bind(null)(defines, expr); |
| 194 | + }).bind(null)(runtimeDefines, inlineDefines, expr); |
172 | 195 | }; |
173 | 196 |
|
174 | 197 | /** |
175 | | - * Runs the Preprocesses. |
| 198 | + * Preprocesses. |
176 | 199 | * @param {object.<string,string>} defines Defines |
177 | 200 | * @param {function(string)=} verbose Print verbose processing information to the specified function as the first parameter. Defaults to not print debug information. |
178 | 201 | * @return {string} Processed source |
|
221 | 244 | } |
222 | 245 | include = match2[1]; |
223 | 246 | verbose(" expr: "+match2[1]); |
224 | | - include = Preprocessor.evaluate(defines, match2[1]); |
| 247 | + include = Preprocessor.evaluate(defines, this.defines, match2[1]); |
225 | 248 | verbose(" value: "+Preprocessor.nlToStr(include)); |
226 | 249 | this.source = this.source.substring(0, match.index)+indent+include+this.source.substring(Preprocessor.PUT.lastIndex); |
227 | 250 | Preprocessor.EXPR.lastIndex = match.index + include.length; |
|
240 | 263 | } else if (match2[1] == "ifndef") { |
241 | 264 | include = !defines[match2[2]]; |
242 | 265 | } else { |
243 | | - include = Preprocessor.evaluate(defines, match2[2]); |
| 266 | + include = Preprocessor.evaluate(defines, this.defines, match2[2]); |
244 | 267 | } |
245 | 268 | verbose(" value: "+include); |
246 | 269 | stack.push(p={ |
|
280 | 303 | if (match2[1] == 'else') { |
281 | 304 | include = !before["include"]; |
282 | 305 | } else { |
283 | | - include = Preprocessor.evaluate(defines, match2[2]); |
| 306 | + include = Preprocessor.evaluate(defines, this.defines, match2[2]); |
284 | 307 | } |
285 | 308 | stack.push(p={ |
286 | 309 | "include": !before["include"], |
|
290 | 313 | verbose(" push: "+JSON.stringify(p)); |
291 | 314 | } |
292 | 315 | break; |
| 316 | + case 'define': |
| 317 | + // https://github.com/dcodeIO/Preprocessor.js/issues/5 |
| 318 | + Preprocessor.DEFINE.lastIndex = match.index; |
| 319 | + if ((match2 = Preprocessor.DEFINE.exec(this.source)) === null) { |
| 320 | + throw(new Error("Illegal #"+match[2]+": "+this.source.substring(match.index, match.index+this.errorSourceAhead)+"...")); |
| 321 | + } |
| 322 | + var define = match2[1]; |
| 323 | + verbose(" def: "+match2[1]); |
| 324 | + this.defines.push(define); |
| 325 | + this.source = this.source.substring(0, match.index)+indent+this.source.substring(Preprocessor.DEFINE.lastIndex); |
| 326 | + Preprocessor.EXPR.lastIndex = match.index; |
| 327 | + verbose(" continue at "+Preprocessor.EXPR.lastIndex); |
293 | 328 | } |
294 | 329 | } |
295 | 330 | if (stack.length > 0) { |
|
0 commit comments