Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Implemented several of the (placeholding) tests, just a few left now

  • Loading branch information...
commit 0ba4509e85441023616416aa201b95c511ae9280 1 parent 0d8c86e
@qfox authored
Showing with 141 additions and 63 deletions.
  1. +9 −4 Gui.js
  2. +18 −15 Zeon.js
  3. +114 −44 test.js
View
13 Gui.js
@@ -1338,8 +1338,13 @@ Gui.prototype = {
return value;
},
showWarnings: function(match){
- if (!this.config[match.warning]) return;
- switch (match.warning) {
+ // find the first warning that's not disabled
+ var warnings = match.warnings;
+ var i = 0;
+ while (warnings[i] && !this.config[warnings[i]]) ++i;
+ if (!warnings[i] || !this.config[warnings[i]]) return; // note, "undefined" is also a key so we cant just check if warnings[i] in this.config... :)
+
+ switch (warnings[i]) {
case 'missing block good':
this.bubble('{', match, {color:'black','background-color':'yellow'});
break;
@@ -1595,8 +1600,8 @@ Gui.prototype = {
case 'is dev relic':
this.bubble('d', match, {color:'white', 'background-color':'black'}, 12);
break;
- case 'weaker operator than neighbor':
- this.bubble('w', match, {color:'black','background-color':'yellow'});
+ case 'multiple operators on same level':
+ this.bubble('S', match, {color:'black','background-color':'yellow'});
break;
case 'useless multiple throw args':
this.bubble('a', match, {color:'black','background-color':'yellow'});
View
33 Zeon.js
@@ -180,7 +180,7 @@ Zeon.getNewConfig = function(){
'pragma start missing end': true,
'macro name should be identifier': true,
'is dev relic': true,
- 'weaker operator than neighbor': true,
+ 'multiple operators on same level': true,
'useless multiple throw args': true,
'unnecessary parentheses': true,
'uninitialized value in loop': true,
@@ -266,7 +266,7 @@ Zeon.prototype = {
regexEcma: /^Object$|^Array$|^String$|^Number$|^Boolean$|^Date$|^Function$|^RegExp$|^Error$|^arguments$|^Math$|^JSON$|^parseInt$|^parseFloat$|^isFinite$|^isNaN$|^undefined$|^eval$|^true$|^false$|^null$/,
regexBrowser: /^document$|^window$|^setTimeout$|^setInterval$|^clearInterval$|^clearTimeout$|^console$|^navigator$|^Image$|^alert$|^confirm$|^XMLHttpRequest$/,
- regexDevSigns: /^console$|^log$|^debug$|^debugger$|^alert$|^foo$|^bar$|^boo$/,
+ regexDevSigns: /^console$|^log$|^debug$|^debugger$|^alert$|^foo$|^bar$|^baz$|^boo$|^tmp$|^temp$|^test$/,
regexBuiltinObjects: /^Object$|^Array$|^String$|^Number$|^Boolean$|^Date$|^Function$|^RegExp$|^Error$|^Math$|^JSON$/,
regexBuiltinBadConstructors: /^Object$|^Array$|^String$|^Number$|^Boolean$|^Function$|^RegExp$|^Error$|^Math$|^JSON$/,
regexBinaryOps: /^\&$|^\|$|^\^$|^\~$|^<<$|^>>$|^>>>$/,
@@ -1370,21 +1370,23 @@ Zeon.prototype = {
if (stack.desc == 'expression') {
// scan all operators. remember the most important one.
// if same level, keep left-most (even for assignments)
-
while (stack.length % 2 == 1 && stack.length > 3 && stack[1].isBinaryOperator) {
var minTarget = 1;
+ stack[1][0].isAmbiguous = true;
var minValue = this.precedence[stack[1].sub];
var n = 3;
+ var wasLess = false;
while (n < stack.length-1) {
+ stack[n][0].isAmbiguous = true;
var curValue = this.precedence[stack[n].sub];
if (curValue < minValue || (curValue == minValue && (stack[n].isAssignment || stack[n].sub == '?' || stack[n].sub == ':'))) {
minValue = curValue;
minTarget = n;
+ wasLess = true;
}
n += 2;
}
- stack[minTarget][0].isAmbiguous = true;
// minTarget is now our next "cut"
// take the token directly left and right of the operator
var newExpr = [stack[minTarget-1], stack[minTarget], stack[minTarget+1]];
@@ -1542,7 +1544,6 @@ Zeon.prototype = {
this.setTypeToRef(prev, 'Function');
}
} else if (next.value == 'prototype') {
-
// mark prev as constructor
if (!prev.isConstructor) {
// the only reason to mess with prototype is to change a constructor or
@@ -1551,7 +1552,7 @@ Zeon.prototype = {
prev.isConstructor = true;
prev.constructorName = prev.value; // TOFIX: this is not quite correct yet
}
- if (prev.trackingObject && prev.trackingObject.isConstructor) {
+ if (prev.trackingObject && !prev.trackingObject.isConstructor) {
// the only reason to mess with prototype is to change a constructor or
// to copy the prototype of another constructor. either way, you're
// very very likely to only take that property of a constructor.
@@ -1995,9 +1996,9 @@ Zeon.prototype = {
var seenIn = false;
var deleteToken = null;
stack.forEach(function(token, i){
- if (stack.sub == 'block' && token.sub == 'block' && stack.statements == 1) this.addWarning(this.btree[stack.nextBlack], 'double block');
- else if ((stack.root || stack.desc == 'func body') && token.sub == 'block') this.addWarning(this.btree[token.nextBlack], 'useless block');
-
+ if (stack.sub == 'block' && token.sub == 'block') this.addWarning(this.btree[stack.nextBlack], 'double block');
+ else if ((stack.root || stack.desc == 'func body' || stack.sub == 'block') && token.sub == 'block') this.addWarning(this.btree[token.nextBlack], 'useless block');
+
// statement headers are not wrapped in own group (maybe they ought to be..)
if (token.statementHeaderStart && stack.forType != 'each') _insideConditional = true;
else if (token.statementHeaderStop) _insideConditional = false;
@@ -2872,7 +2873,7 @@ Zeon.prototype = {
if (stack[i+2]) {
var testForOp = this.btree[stack[i+1].nextBlack];
- if (testForOp && testForOp.name == 11/*PUNCTUATOR*/) {
+ if (testForOp) {
testForOp.typeofOperator = true;
switch (testForOp.value) {
case '===':
@@ -3559,7 +3560,9 @@ Zeon.prototype = {
// crock hates short
if (token.value == '--' || token.value == '++') {
if (prev.isCallExpressionStop) this.addWarning(token, 'cannot inc/dec on call expression');
- else if (next && next.value == 'new') this.addWarning(token, 'inc/dec only valid on vars');
+ else if (next && next.valueType == 'call') this.addWarning(token, 'cannot inc/dec on call expression');
+ // check if prev/next is primitive. dont worry about line terminators, semi's or ASI are part of the btree.
+ else if ((next && (next.value == 'new' || next.isPrimitive)) || prev.isPrimitive) this.addWarning(token, 'inc/dec only valid on vars');
else if (prev && prev.isGroupStop && prev.twin.numberOfExpressions > 1) {
this.addWarning(token, 'comma in group makes inc/dec fail');
}
@@ -3617,7 +3620,7 @@ Zeon.prototype = {
if (token.value == ',' && next && (next.value == ']' || next.value == '}')) this.addWarning(token, 'trailing comma');
}
// there's a stronger operator on the same level as this one...
- if (token.isAmbiguous) this.addWarning(token, 'weaker operator than neighbor');
+ if (token.isAmbiguous) this.addWarning(token, 'multiple operators on same level');
// we want to warn for empty statements
if (token.emptyStatement) this.addWarning(token, 'empty statement');
}
@@ -3697,8 +3700,8 @@ Zeon.prototype = {
// were there any other types found than those declared by jsdoc?
if (token.jsdocIncomplete) this.addWarning(token, 'jsdoc type mismatch');
// using parentheses in silly places
- if ((token.value == 'throw' || token.value == 'delete' || token.value == 'new') && next && next.value == '(') {
- this.addWarning(token, 'unnecessary parentheses');
+ if ((token.value == 'typeof' || token.value == 'throw' || token.value == 'return' || token.value == 'delete' || token.value == 'new' || token.value == 'void') && next && next.value == '(') {
+ this.addWarning(next, 'unnecessary parentheses');
}
// using uninitialized variable in loop
@@ -3774,7 +3777,7 @@ Zeon.prototype = {
if (this.regexInvalidHexEscape.test(token.value)) this.addWarning(token, 'invalid hex escape in string');
} else if (token.isComment) {
// probably only bad for multi-line comment. but warn regardless.
- if (token.value.indexOf('/*',1) > 0 || token.value.indexOf('*/',1) > 0) this.addWarning(token, 'nested comment');
+ if (token.value.indexOf('/*',1) > 0 || (token.name == 7/*COMMENT_SINGLE*/ && token.value.indexOf('*/',1) > 0)) this.addWarning(token, 'nested comment');
}
// ### end warning stuff
View
158 test.js
@@ -658,11 +658,15 @@ new function(){ testgroup = 'Warnings';
}
);
test('nested comment',
- '/* /* */ // /*\n// */\n/* */// /* */',
+ '/* /* */\n// /*\n// */\n// /* */\n/* */',
function(zeon){
+ // we must do it the hard way because we need to target wtree, not btree
var comments = zeon.wtree.filter(function(t){ return t.isComment; });
assert('has items', comments.length);
- reject('has', comments.some(function(t){ return !t.warnings || t.warnings.indexOf('nested comment') < 0; }));
+ comments.some(function(t,i){
+ if (i < 4) return reject('has not '+i, !t.warnings || t.warnings.indexOf('nested comment') < 0);
+ return assert('has '+i, !t.warnings || t.warnings.indexOf('nested comment') < 0);
+ });
}
);
test('new statement',
@@ -692,7 +696,6 @@ new function(){ testgroup = 'Warnings';
test('empty clause',
'switch(x){ case x: }',
function(zeon){
- console.log(zeon.btree.filter(function(v){ return v.value == 'case'; }))
hasWarning(zeon, 'case', 'empty clause');
}
);
@@ -747,79 +750,85 @@ new function(){ testgroup = 'Warnings';
test('use {}',
'new Object();',
function(zeon){
- hasWarning(zeon, 'new', 'use {}');
+ hasWarning(zeon, 'Object', 'use {}');
}
);
test('use []',
'new Array();',
function(zeon){
- hasWarning(zeon, 'new', 'use []');
+ hasWarning(zeon, 'Array', 'use []');
}
);
test('double block',
'{{ i; think; }}',
function(zeon){
- assert('has', (zeon.btree.filter(function(t){ return t.value == '==='; })[0].warnings||[]).indexOf('typeof always string') >= 0);
+ hasWarning(zeon, '{', 'double block', 1);
}
);
test('useless block',
- 'FIXME todo',
+ 'function f(){{}} {}',
function(zeon){
- assert('has', (zeon.btree.filter(function(t){ return t.value == '==='; })[0].warnings||[]).indexOf('typeof always string') >= 0);
+ noWarning(zeon, '{', 'useless block', 1);
}
);
test('use capital namespacing',
- 'new Foo; new bar;',
+ 'new foo; new Bar;',
function(zeon){
- hasWarning(zeon, ['Foo', 'bar'], 'typeof always string');
+ hasWarning(zeon, ['foo', 'Bar'], 'use capital namespacing', 1);
}
);
- test('constructor called as a function',
- 'function F(){} F.prototype = 5; F(); function G(){}; new G; g();',
+ test('constructor called as a function (1)',
+ 'function f(){} f.prototype = 5; f();',
function(zeon){
- assert('has', (zeon.btree.filter(function(t){ return t.value == '==='; })[0].warnings||[]).indexOf('typeof always string') >= 0);
+ noWarning(zeon, 'f', 'constructor called as function', 2);
+ }
+ );
+ test('constructor called as a function (2)',
+ 'function g(){}; new g; g();',
+ function(zeon){
+ noWarning(zeon, 'g', 'constructor called as function', 2);
}
);
- test('cannot incdec on call expression',
+ test('cannot inc/dec on call expression',
'++a(); --b(); c()++; d()--;',
function(zeon){
- hasWarning(zeon, ['++','--'], 'cannot incdec on call expression');
+ hasWarning(zeon, ['++','--'], 'cannot inc/dec on call expression');
}
);
- test('incdec only valid on vars',
+ test('inc/dec only valid on vars',
'++"foo"; --"foo"; "foo"++; "foo"--; ++5; --5; 5--; 5++; ++true; --true; true++; true--; ++false; --false; false++; false--; ++null; --null; null++; null--; ++/foo/; --/foo/; /foo/++; /foo/--;',
function(zeon){
- hasWarning(zeon, ['++','--'], 'incdec only valid on vars');
+ hasWarning(zeon, ['++','--'], 'inc/dec only valid on vars');
}
);
- test('bad asi patterns',
+ test('bad asi pattern',
'x\n/* foo */(function(){}); a\n(b);',
function(zeon){
- assert('has', (zeon.btree.filter(function(t){ return t.value == '==='; })[0].warnings||[]).indexOf('typeof always string') >= 0);
+ hasWarning(zeon, function(t){ return t.isCallExpressionStart; }, 'bad asi pattern');
}
);
test('unlikely typeof result',
'typeof x == "crap"; typeof x == "string"',
function(zeon){
- assert('has', (zeon.btree.filter(function(t){ return t.value == '==='; })[0].warnings||[]).indexOf('typeof always string') >= 0);
+ hasWarning(zeon, function(t){ return t.isString; }, 'unlikely typeof result', 1);
}
);
test('weird typeof op',
- 'FIXME todo',
+ 'typeof x % "foo"; typeof x in y; typeof x == y;',
function(zeon){
- assert('has', (zeon.btree.filter(function(t){ return t.value == '==='; })[0].warnings||[]).indexOf('typeof always string') >= 0);
+ hasWarning(zeon, ['%','in','=='], 'weird typeof op', 2);
}
);
test('typeof always string',
- 'FIXME todo',
+ 'typeof x === "string"; typeof x !== "string"; typeof x == "string";',
function(zeon){
- assert('has', (zeon.btree.filter(function(t){ return t.value == '==='; })[0].warnings||[]).indexOf('typeof always string') >= 0);
+ hasWarning(zeon, ['===','!==','=='], 'typeof always string', 2);
}
);
test('static expression',
- '5+5; 5-"5"; "x"=="y"; t%/t/; / / / / /; x*(5&8);(2^1)-(3>>4);',
+ '5+5; 5-"5"; "x"=="y"; true%/t/; / / / / /; (2^1)-(3>>4);(5&8)*x;',
function(zeon){
- hasWarning(zeon, ['+','-','==','%','/','*','&','^','>>'], 'static expression');
+ hasWarning(zeon, ['+','-','==','%','/','*','&','^','>>'], 'static expression', 9);
}
);
test('static condition',
@@ -829,51 +838,82 @@ new function(){ testgroup = 'Warnings';
}
);
test('pragma requires name parameter',
- '//#define \n//#ifdef \n', // tofix: others
+ '//#define\n//#ifdef\n', // tofix: others
function(zeon){
- assert('has', (zeon.btree.filter(function(t){ return t.value == '==='; })[0].warnings||[]).indexOf('typeof always string') >= 0);
+ // we must do it the hard way because we need to target wtree, not btree
+ var comments = zeon.wtree.filter(function(t){ return t.isComment; });
+ assert('has items', comments.length);
+ comments.some(function(t,i){
+ return assert('has '+i, t.warnings && t.warnings.indexOf('pragma requires name parameter') >= 0);
+ });
}
);
test('pragma requires value parameter',
'//#macro foo ',
function(zeon){
- assert('has', (zeon.btree.filter(function(t){ return t.value == '==='; })[0].warnings||[]).indexOf('typeof always string') >= 0);
+ // we must do it the hard way because we need to target wtree, not btree
+ var comments = zeon.wtree.filter(function(t){ return t.isComment; });
+ assert('has items', comments.length);
+ comments.forEach(function(t,i){
+ assert('has '+i, t.warnings && t.warnings.indexOf('pragma requires value parameter') >= 0);
+ });
}
);
test('missing ifdef',
'//#endif\n', // tofix: need to add way more
function(zeon){
- assert('has', (zeon.btree.filter(function(t){ return t.value == '==='; })[0].warnings||[]).indexOf('typeof always string') >= 0);
+ // we must do it the hard way because we need to target wtree, not btree
+ var comments = zeon.wtree.filter(function(t){ return t.isComment; });
+ assert('has items', comments.length);
+ comments.forEach(function(t,i){
+ assert('has '+i, t.warnings && t.warnings.indexOf('missing ifdef') >= 0);
+ });
}
);
test('missing inline',
'//#endline',
function(zeon){
- assert('has', (zeon.btree.filter(function(t){ return t.value == '==='; })[0].warnings||[]).indexOf('typeof always string') >= 0);
+ // we must do it the hard way because we need to target wtree, not btree
+ var comments = zeon.wtree.filter(function(t){ return t.isComment; });
+ assert('has items', comments.length);
+ comments.forEach(function(t,i){
+ assert('has '+i, t.warnings && t.warnings.indexOf('missing inline') >= 0);
+ });
}
);
- test('pragma missing end',
+ test('pragma start missing end',
'//#ifdef foo\n//#inline foo',
function(zeon){
- assert('has', (zeon.btree.filter(function(t){ return t.value == '==='; })[0].warnings||[]).indexOf('typeof always string') >= 0);
+ // we must do it the hard way because we need to target wtree, not btree
+ var comments = zeon.wtree.filter(function(t){ return t.isComment; });
+ assert('has items', comments.length == 2);
+ comments.forEach(function(t,i){
+ assert('has '+i, t.warnings && t.warnings.indexOf('pragma start missing end') >= 0);
+ });
}
);
test('macro name should be identifier',
'//#macro fail-ing 4\n//#macro ok 6\n//#macro also.ok 7',
function(zeon){
- assert('has', (zeon.btree.filter(function(t){ return t.value == '==='; })[0].warnings||[]).indexOf('typeof always string') >= 0);
+ // we must do it the hard way because we need to target wtree, not btree
+ var comments = zeon.wtree.filter(function(t){ return t.isComment; });
+ assert('has items', comments.length);
+ comments.forEach(function(t,i){
+ if (i == 0) assert('has '+i, t.warnings && t.warnings.indexOf('macro name should be identifier') >= 0);
+ else reject('has not '+i, t.warnings && t.warnings.indexOf('macro name should be identifier') >= 0);
+ });
}
);
test('is dev relic',
'foo; bar; baz; tmp; log; console; test; alert; temp;',
function(zeon){
- hasWarning(zeon, ['foo','bar','baz','tmp','log','console','test','alert','temp'], 'is dev relic');
+ hasWarning(zeon, function(t){ return t.name == 2/*identifier*/; }, 'is dev relic');
}
);
- test('weaker operator than neighbor',
- '5+5*5; 5+5+5; (5+5)*5;',
+ test('multiple operators on same level',
+ '5+5*5; 5*5+5; 5+5+5; (5+5)*5; 5+(5*5);',
function(zeon){
- assert('has', (zeon.btree.filter(function(t){ return t.value == '==='; })[0].warnings||[]).indexOf('typeof always string') >= 0);
+ hasWarning(zeon, ['+','*'], 'multiple operators on same level', 6);
}
);
test('useless multiple throw args',
@@ -883,15 +923,45 @@ new function(){ testgroup = 'Warnings';
}
);
test('unnecessary parentheses',
- 'delete(foo); void(foo);',
+ 'typeof(x); throw(x); return(x); delete(x); new(x); void(x);',
function(zeon){
hasWarning(zeon, '(', 'unnecessary parentheses');
}
);
- test('uninitialized value in loop',
- 'var x; while (x) x = 5; var y; while (5) alert(y); var z; while (5) z(); var a = 5; while (a) a = 5; var b = 5; while (5) alert(b); var c = 5; while (5) c();',
+ test('uninitialized value in loop (1)',
+ 'var x; while (x) x = 5;',
function(zeon){
- assert('has', (zeon.btree.filter(function(t){ return t.value == '==='; })[0].warnings||[]).indexOf('typeof always string') >= 0);
+ noWarning(zeon, 'x', 'uninitialized value in loop', 1);
+ }
+ );
+ test('uninitialized value in loop (2)',
+ 'var y; for (;5;) alert(y);',
+ function(zeon){
+ noWarning(zeon, 'y', 'uninitialized value in loop', 1);
+ }
+ );
+ test('uninitialized value in loop (3)',
+ 'var z; while (5) z();',
+ function(zeon){
+ noWarning(zeon, 'z', 'uninitialized value in loop');
+ }
+ );
+ test('uninitialized value in loop (4)',
+ 'var a = 5; while (a) a = 5;',
+ function(zeon){
+ noWarning(zeon, 'a', 'uninitialized value in loop', 2);
+ }
+ );
+ test('uninitialized value in loop (5)',
+ 'var b = 5; while (5) alert(b);',
+ function(zeon){
+ noWarning(zeon, '(', 'uninitialized value in loop', 1);
+ }
+ );
+ test('uninitialized value in loop (6)',
+ 'var c = 5; while (5) c();',
+ function(zeon){
+ noWarning(zeon, 'c', 'uninitialized value in loop',1);
}
);
test('jsdoc mismatch',
@@ -944,9 +1014,9 @@ new function(){ testgroup = 'Warnings';
}
);
test('useless parens',
- '(a);',
+ '(a); x = (t+z); (5 + 5) * 5;',
function(zeon){
- hasWarning(zeon, '(', 'useless parens');
+ hasWarning(zeon, '(', 'useless parens', 2);
}
);
test('known implicit global',

0 comments on commit 0ba4509

Please sign in to comment.
Something went wrong with that request. Please try again.