15 changed files with 502 additions and 0 deletions
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
function test() { |
||||
"test"; |
||||
"1"; |
||||
"2"; |
||||
"3"; |
||||
if ("test") { |
||||
"5"; |
||||
} |
||||
"4"; |
||||
} |
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
function test() { |
||||
{;} |
||||
; |
||||
"test"; |
||||
{ |
||||
"1"; |
||||
if (true) { |
||||
"2"; |
||||
} |
||||
; |
||||
{ |
||||
"3"; |
||||
if ("test") { |
||||
"5"; |
||||
} |
||||
} |
||||
"4"; |
||||
} |
||||
} |
@ -0,0 +1,28 @@
@@ -0,0 +1,28 @@
|
||||
function f1() { |
||||
/* head */ |
||||
"1"; |
||||
/* mid */ |
||||
"2"; |
||||
} |
||||
/* tail */ |
||||
function f2() { |
||||
// head
|
||||
"1"; |
||||
// mid
|
||||
"2"; |
||||
} |
||||
// tail
|
||||
function f2() { |
||||
if ("1") { |
||||
// begin block
|
||||
"1"; |
||||
} |
||||
"2"; |
||||
// trailing
|
||||
if (/* s */ |
||||
"3") |
||||
/*e*/ |
||||
{ |
||||
"4"; |
||||
} |
||||
} |
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
/* globals f0 */ |
||||
function f1() { |
||||
/* head */ |
||||
"1"; |
||||
/* mid */ |
||||
"2"; |
||||
/* tail */ |
||||
} |
||||
|
||||
function f2() { |
||||
// head
|
||||
"1"; |
||||
// mid
|
||||
"2"; |
||||
// tail
|
||||
} |
||||
|
||||
function f2() { |
||||
if ("1") { // begin block
|
||||
"1"; |
||||
} |
||||
"2"; // trailing
|
||||
if (/* s */"3"/*e*/) { |
||||
"4"; |
||||
} |
||||
} |
@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
|
||||
var a = true; |
||||
var b = false; |
||||
var c = '1'; |
||||
var d = false; |
||||
var e = true; |
||||
var f = '0'; |
||||
var g = '1'; |
||||
var h = '0'; |
||||
var i = true; |
||||
var j = false; |
||||
var k = false; |
||||
var l = true; |
||||
var m = '1' === true; |
||||
var n = false; |
||||
var o = true; |
@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
|
||||
var a = true; |
||||
var b = false; |
||||
var c = true && '1'; |
||||
var d = false && '0'; |
||||
var e = true || '1'; |
||||
var f = false || '0'; |
||||
var g = true ? '1' : '0'; |
||||
var h = false ? '1' : '0'; |
||||
var i = 'test' === 'test'; |
||||
var j = 'test' !== 'test'; |
||||
var k = 'test' === 'test2'; |
||||
var l = 'test' !== 'test2'; |
||||
var m = '1' === true; |
||||
var n = !true; |
||||
var o = !false; |
@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
|
||||
var a = false; |
||||
var b = true; |
||||
var c = true; |
||||
var d = false; |
||||
var e = true; |
||||
var f = 'text'; |
||||
var g = { |
||||
"obj": { "i": 1 }, |
||||
"j": 2 |
||||
}; |
||||
var h = { 'test': 'test' }; |
||||
var i = '0'; |
||||
var j = { "i": 1 }; |
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
var a = typeof PDFJSDev === 'undefined'; |
||||
var b = typeof PDFJSDev !== 'undefined'; |
||||
var c = PDFJSDev.test('TRUE'); |
||||
var d = PDFJSDev.test('FALSE'); |
||||
var e = PDFJSDev.eval('TRUE'); |
||||
var f = PDFJSDev.eval('TEXT'); |
||||
var g = PDFJSDev.eval('OBJ'); |
||||
var h = PDFJSDev.json('$ROOT/external/builder/fixtures_esprima/evals.json'); |
||||
var i = typeof PDFJSDev === 'undefined' ? PDFJSDev.eval('FALSE') : '0'; |
||||
var j = typeof PDFJSDev !== 'undefined' ? PDFJSDev.eval('OBJ.obj') : '0'; |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
{ 'test': 'test' } |
@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
|
||||
if ('test') { |
||||
"1"; |
||||
} |
||||
{ |
||||
"1"; |
||||
} |
||||
{ |
||||
"1"; |
||||
} |
||||
; |
||||
{ |
||||
"2"; |
||||
} |
||||
; |
||||
if ('1') { |
||||
"1"; |
||||
} |
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
if ('test') { |
||||
"1"; |
||||
} |
||||
if (true) { |
||||
"1"; |
||||
} |
||||
if (true) { |
||||
"1"; |
||||
} else { |
||||
"2"; |
||||
} |
||||
if (false) { |
||||
"1"; |
||||
} |
||||
if (false) { |
||||
"1"; |
||||
} else { |
||||
"2"; |
||||
} |
||||
if (true && false) { |
||||
"1"; |
||||
} |
||||
if (true && false || '1') { |
||||
"1"; |
||||
} |
@ -0,0 +1,266 @@
@@ -0,0 +1,266 @@
|
||||
/* jshint node:true */ |
||||
|
||||
'use strict'; |
||||
|
||||
var esprima = require('esprima'); |
||||
var escodegen = require('escodegen'); |
||||
var vm = require('vm'); |
||||
var fs = require('fs'); |
||||
var path = require('path'); |
||||
|
||||
var PDFJS_PREPROCESSOR_NAME = 'PDFJSDev'; |
||||
var ROOT_PREFIX = '$ROOT/'; |
||||
|
||||
function isLiteral(obj, value) { |
||||
return obj.type === 'Literal' && obj.value === value; |
||||
} |
||||
|
||||
function isPDFJSPreprocessor(obj) { |
||||
return obj.type === 'Identifier' && |
||||
obj.name === PDFJS_PREPROCESSOR_NAME; |
||||
} |
||||
|
||||
function evalWithDefines(code, defines, loc) { |
||||
if (!code || !code.trim()) { |
||||
throw new Error('No JavaScript expression given'); |
||||
} |
||||
return vm.runInNewContext(code, defines, {displayErrors: false}); |
||||
} |
||||
|
||||
function handlePreprocessorAction(ctx, actionName, args, loc) { |
||||
try { |
||||
var arg; |
||||
switch (actionName) { |
||||
case 'test': |
||||
arg = args[0]; |
||||
if (!arg || arg.type !== 'Literal' || |
||||
typeof arg.value !== 'string') { |
||||
throw new Error('No code for testing is given'); |
||||
} |
||||
var isTrue = !!evalWithDefines(arg.value, ctx.defines); |
||||
return {type: 'Literal', value: isTrue, loc: loc}; |
||||
case 'eval': |
||||
arg = args[0]; |
||||
if (!arg || arg.type !== 'Literal' || |
||||
typeof arg.value !== 'string') { |
||||
throw new Error('No code for eval is given'); |
||||
} |
||||
var result = evalWithDefines(arg.value, ctx.defines); |
||||
if (typeof result === 'boolean' || typeof result === 'string' || |
||||
typeof result === 'number') { |
||||
return {type: 'Literal', value: result, loc: loc}; |
||||
} |
||||
if (typeof result === 'object') { |
||||
var parsedObj = esprima.parse('(' + JSON.stringify(result) + ')'); |
||||
parsedObj.body[0].expression.loc = loc; |
||||
return parsedObj.body[0].expression; |
||||
} |
||||
break; |
||||
case 'json': |
||||
arg = args[0]; |
||||
if (!arg || arg.type !== 'Literal' || |
||||
typeof arg.value !== 'string') { |
||||
throw new Error('Path to JSON is not provided'); |
||||
} |
||||
var jsonPath = arg.value; |
||||
if (jsonPath.indexOf(ROOT_PREFIX) === 0) { |
||||
jsonPath = path.join(ctx.rootPath, |
||||
jsonPath.substring(ROOT_PREFIX.length)); |
||||
} |
||||
var jsonContent = fs.readFileSync(jsonPath).toString(); |
||||
var parsedJSON = esprima.parse('(' +jsonContent + ')'); |
||||
parsedJSON.body[0].expression.loc = loc; |
||||
return parsedJSON.body[0].expression; |
||||
} |
||||
throw new Error('Unsupported action'); |
||||
} catch (e) { |
||||
throw new Error('Could not process ' + PDFJS_PREPROCESSOR_NAME + '.' + |
||||
actionName + ' at ' + JSON.stringify(loc) + '\n' + |
||||
e.name + ': ' + e.message); |
||||
} |
||||
} |
||||
|
||||
function postprocessNode(ctx, node) { |
||||
switch (node.type) { |
||||
case 'IfStatement': |
||||
if (isLiteral(node.test, true)) { |
||||
// if (true) stmt1; => stmt1
|
||||
return node.consequent; |
||||
} else if (isLiteral(node.test, false)) { |
||||
// if (false) stmt1; else stmt2; => stmt2
|
||||
return node.alternate || {type: 'EmptyStatement', loc: node.loc}; |
||||
} |
||||
break; |
||||
case 'ConditionalExpression': |
||||
if (isLiteral(node.test, true)) { |
||||
// true ? stmt1 : stmt2 => stmt1
|
||||
return node.consequent; |
||||
} else if (isLiteral(node.test, false)) { |
||||
// false ? stmt1 : stmt2 => stmt2
|
||||
return node.alternate; |
||||
} |
||||
break; |
||||
case 'UnaryExpression': |
||||
if (node.operator === 'typeof' && |
||||
isPDFJSPreprocessor(node.argument)) { |
||||
// typeof PDFJSDev => 'object'
|
||||
return {type: 'Literal', value: 'object', loc: node.loc}; |
||||
} |
||||
if (node.operator === '!' && |
||||
node.argument.type === 'Literal' && |
||||
typeof node.argument.value === 'boolean') { |
||||
// !true => false, !false => true
|
||||
return {type: 'Literal', value: !node.argument.value, loc: node.loc}; |
||||
} |
||||
break; |
||||
case 'LogicalExpression': |
||||
switch (node.operator) { |
||||
case '&&': |
||||
if (isLiteral(node.left, true)) { |
||||
return node.right; |
||||
} |
||||
if (isLiteral(node.left, false)) { |
||||
return node.left; |
||||
} |
||||
break; |
||||
case '||': |
||||
if (isLiteral(node.left, true)) { |
||||
return node.left; |
||||
} |
||||
if (isLiteral(node.left, false)) { |
||||
return node.right; |
||||
} |
||||
break; |
||||
} |
||||
break; |
||||
case 'BinaryExpression': |
||||
switch (node.operator) { |
||||
case '==': |
||||
case '===': |
||||
case '!=': |
||||
case '!==': |
||||
if (node.left.type === 'Literal' && |
||||
node.right.type === 'Literal' && |
||||
typeof node.left.value === typeof node.right.value) { |
||||
// folding two literals == and != check
|
||||
switch (typeof node.left.value) { |
||||
case 'string': |
||||
case 'boolean': |
||||
case 'number': |
||||
var equal = node.left.value === node.right.value; |
||||
return { |
||||
type: 'Literal', |
||||
value: (node.operator[0] === '=') === equal, |
||||
loc: node.loc |
||||
}; |
||||
} |
||||
} |
||||
break; |
||||
} |
||||
break; |
||||
case 'CallExpression': |
||||
if (node.callee.type === 'MemberExpression' && |
||||
isPDFJSPreprocessor(node.callee.object) && |
||||
node.callee.property.type === 'Identifier') { |
||||
// PDFJSDev.xxxx(arg1, arg2, ...) => tranform
|
||||
var action = node.callee.property.name; |
||||
return handlePreprocessorAction(ctx, action, |
||||
node.arguments, node.loc); |
||||
} |
||||
break; |
||||
case 'BlockStatement': |
||||
var subExpressionIndex = 0; |
||||
while (subExpressionIndex < node.body.length) { |
||||
if (node.body[subExpressionIndex].type === 'EmptyStatement') { |
||||
// Removing empty statements from the blocks.
|
||||
node.body.splice(subExpressionIndex, 1); |
||||
continue; |
||||
} |
||||
if (node.body[subExpressionIndex].type === 'BlockStatement') { |
||||
// Block statements inside a block are moved to the parent one.
|
||||
var subChildren = node.body[subExpressionIndex].body; |
||||
Array.prototype.splice.apply(node.body, |
||||
[subExpressionIndex, 1].concat(subChildren)); |
||||
subExpressionIndex += subChildren.length; |
||||
continue; |
||||
} |
||||
subExpressionIndex++; |
||||
} |
||||
break; |
||||
} |
||||
return node; |
||||
} |
||||
|
||||
function fixComments(ctx, node) { |
||||
if (!ctx.saveComments) { |
||||
return; |
||||
} |
||||
// Fixes double comments in the escodegen output.
|
||||
delete node.trailingComments; |
||||
// Removes jshint and other service comments.
|
||||
if (node.leadingComments) { |
||||
var i = 0; |
||||
while (i < node.leadingComments.length) { |
||||
var type = node.leadingComments[i].type; |
||||
var value = node.leadingComments[i].value; |
||||
if (type === 'Block' && |
||||
/^\s*(globals|jshint|falls through|umdutils)\b/.test(value)) { |
||||
node.leadingComments.splice(i, 1); |
||||
continue; |
||||
} |
||||
i++; |
||||
} |
||||
} |
||||
} |
||||
|
||||
function traverseTree(ctx, node) { |
||||
// generic node processing
|
||||
for (var i in node) { |
||||
var child = node[i]; |
||||
if (typeof child === 'object' && child !== null && child.type) { |
||||
var result = traverseTree(ctx, child); |
||||
if (result !== child) { |
||||
node[i] = result; |
||||
} |
||||
} else if (Array.isArray(child)) { |
||||
child.forEach(function (childItem, index) { |
||||
if (typeof childItem === 'object' && childItem !== null && |
||||
childItem.type) { |
||||
var result = traverseTree(ctx, childItem); |
||||
if (result !== childItem) { |
||||
child[index] = result; |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
|
||||
node = postprocessNode(ctx, node) || node; |
||||
|
||||
fixComments(ctx, node); |
||||
return node; |
||||
} |
||||
|
||||
function preprocessPDFJSCode(ctx, code) { |
||||
var saveComments = !!ctx.saveComments; |
||||
var format = ctx.format || { |
||||
indent: { |
||||
style: ' ', |
||||
adjustMultilineComment: saveComments, |
||||
} |
||||
}; |
||||
var parseComment = { |
||||
loc: true, |
||||
attachComment: saveComments |
||||
}; |
||||
var codegenOptions = { |
||||
format: format, |
||||
comment: saveComments, |
||||
parse: esprima.parse |
||||
}; |
||||
var syntax = esprima.parse(code, parseComment); |
||||
traverseTree(ctx, syntax); |
||||
return escodegen.generate(syntax, codegenOptions); |
||||
} |
||||
|
||||
exports.preprocessPDFJSCode = preprocessPDFJSCode; |
@ -0,0 +1,54 @@
@@ -0,0 +1,54 @@
|
||||
/* jshint node:true */ |
||||
/* globals cat, cd, echo, ls */ |
||||
'use strict'; |
||||
|
||||
require('shelljs/make'); |
||||
|
||||
var p2 = require('./preprocessor2.js'); |
||||
var fs = require('fs'); |
||||
|
||||
var errors = 0; |
||||
|
||||
cd(__dirname); |
||||
cd('fixtures_esprima'); |
||||
ls('*-expected.*').forEach(function(expectationFilename) { |
||||
var inFilename = expectationFilename.replace('-expected', ''); |
||||
var expectation = cat(expectationFilename).trim() |
||||
.replace(/__filename/g, fs.realpathSync(inFilename)); |
||||
var input = fs.readFileSync(inFilename).toString(); |
||||
|
||||
var defines = { |
||||
TRUE: true, |
||||
FALSE: false, |
||||
OBJ: {obj: {i: 1}, j: 2}, |
||||
TEXT: 'text' |
||||
}; |
||||
var ctx = { |
||||
defines: defines, |
||||
rootPath: __dirname + '/../..', |
||||
saveComments: true |
||||
}; |
||||
var out; |
||||
try { |
||||
out = p2.preprocessPDFJSCode(ctx, input); |
||||
} catch (e) { |
||||
out = ('Error: ' + e.message).replace(/^/gm, '//'); |
||||
} |
||||
if (out !== expectation) { |
||||
echo('Assertion failed for ' + inFilename); |
||||
echo('--------------------------------------------------'); |
||||
echo('EXPECTED:'); |
||||
echo(expectation); |
||||
echo('--------------------------------------------------'); |
||||
echo('ACTUAL'); |
||||
echo(out); |
||||
echo('--------------------------------------------------'); |
||||
echo(); |
||||
} |
||||
}); |
||||
|
||||
if (errors) { |
||||
echo('Found ' + errors + ' expectation failures.'); |
||||
} else { |
||||
echo('All tests completed without errors.'); |
||||
} |
Loading…
Reference in new issue