1
0
Jelajahi Sumber

Throw unknown variable errors only if the node value is undeclared in `window'

Nicolas Petton 12 tahun lalu
induk
melakukan
09ef3fa281

+ 4 - 15
js/Compiler-Semantic.deploy.js

@@ -834,17 +834,6 @@ smalltalk.UnknownVar);
 
 
 smalltalk.addClass('SemanticAnalyzer', smalltalk.NodeVisitor, ['currentScope', 'theClass', 'classReferences', 'messageSends'], 'Compiler-Semantic');
-smalltalk.addMethod(
-"_allowUnknownVariables",
-smalltalk.method({
-selector: "allowUnknownVariables",
-fn: function (){
-var self=this;
-return true;
-}
-}),
-smalltalk.SemanticAnalyzer);
-
 smalltalk.addMethod(
 "_classReferences",
 smalltalk.method({
@@ -884,14 +873,14 @@ selector: "errorUnknownVariable:",
 fn: function (aNode){
 var self=this;
 var $1,$2,$3;
-$1=smalltalk.send(self,"_allowUnknownVariables",[]);
-if(smalltalk.assert($1)){
-smalltalk.send(smalltalk.send(smalltalk.send(self["@currentScope"],"_methodScope",[]),"_unknownVariables",[]),"_add_",[smalltalk.send(aNode,"_value",[])]);
-} else {
+$1=smalltalk.send(window,"_at_",[smalltalk.send(aNode,"_value",[])]);
+if(($receiver = $1) == nil || $receiver == undefined){
 $2=smalltalk.send((smalltalk.UnknownVariableError || UnknownVariableError),"_new",[]);
 smalltalk.send($2,"_variableName_",[smalltalk.send(aNode,"_value",[])]);
 $3=smalltalk.send($2,"_signal",[]);
 $3;
+} else {
+smalltalk.send(smalltalk.send(smalltalk.send(self["@currentScope"],"_methodScope",[]),"_unknownVariables",[]),"_add_",[smalltalk.send(aNode,"_value",[])]);
 };
 return self}
 }),

+ 6 - 22
js/Compiler-Semantic.js

@@ -1145,22 +1145,6 @@ smalltalk.UnknownVar);
 
 smalltalk.addClass('SemanticAnalyzer', smalltalk.NodeVisitor, ['currentScope', 'theClass', 'classReferences', 'messageSends'], 'Compiler-Semantic');
 smalltalk.SemanticAnalyzer.comment="I semantically analyze the abstract syntax tree and annotate it with informations such as non local returns and variable scopes."
-smalltalk.addMethod(
-"_allowUnknownVariables",
-smalltalk.method({
-selector: "allowUnknownVariables",
-category: 'testing',
-fn: function (){
-var self=this;
-return true;
-},
-args: [],
-source: "allowUnknownVariables\x0a\x09^ true",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.SemanticAnalyzer);
-
 smalltalk.addMethod(
 "_classReferences",
 smalltalk.method({
@@ -1211,19 +1195,19 @@ category: 'error handling',
 fn: function (aNode){
 var self=this;
 var $1,$2,$3;
-$1=smalltalk.send(self,"_allowUnknownVariables",[]);
-if(smalltalk.assert($1)){
-smalltalk.send(smalltalk.send(smalltalk.send(self["@currentScope"],"_methodScope",[]),"_unknownVariables",[]),"_add_",[smalltalk.send(aNode,"_value",[])]);
-} else {
+$1=smalltalk.send(window,"_at_",[smalltalk.send(aNode,"_value",[])]);
+if(($receiver = $1) == nil || $receiver == undefined){
 $2=smalltalk.send((smalltalk.UnknownVariableError || UnknownVariableError),"_new",[]);
 smalltalk.send($2,"_variableName_",[smalltalk.send(aNode,"_value",[])]);
 $3=smalltalk.send($2,"_signal",[]);
 $3;
+} else {
+smalltalk.send(smalltalk.send(smalltalk.send(self["@currentScope"],"_methodScope",[]),"_unknownVariables",[]),"_add_",[smalltalk.send(aNode,"_value",[])]);
 };
 return self},
 args: ["aNode"],
-source: "errorUnknownVariable: aNode\x0a\x09self allowUnknownVariables \x0a\x09\x09ifTrue: [ currentScope methodScope unknownVariables add: aNode value ]\x0a\x09\x09ifFalse: [ \x0a\x09\x09\x09UnknownVariableError new\x0a\x09\x09\x09\x09variableName: aNode value;\x0a\x09\x09\x09\x09signal ]",
-messageSends: ["ifTrue:ifFalse:", "add:", "value", "unknownVariables", "methodScope", "variableName:", "new", "signal", "allowUnknownVariables"],
+source: "errorUnknownVariable: aNode\x0a\x09\x22Throw an error if the variable is undeclared in the global JS scope (i.e. window)\x22\x0a\x0a\x09(window at: aNode value) \x0a\x09\x09ifNil: [ \x0a\x09\x09\x09UnknownVariableError new\x0a\x09\x09\x09\x09variableName: aNode value;\x0a\x09\x09\x09\x09signal ]\x0a\x09\x09ifNotNil: [\x0a\x09\x09\x09currentScope methodScope unknownVariables add: aNode value. ]",
+messageSends: ["ifNil:ifNotNil:", "variableName:", "value", "new", "signal", "add:", "unknownVariables", "methodScope", "at:"],
 referencedClasses: ["UnknownVariableError"]
 }),
 smalltalk.SemanticAnalyzer);

+ 19 - 4
js/Compiler-Tests.deploy.js

@@ -523,8 +523,22 @@ var src;
 var ast;
 src="foo | a | b + a";
 ast=smalltalk.send(smalltalk,"_parse_",[src]);
-smalltalk.send(self["@analyzer"],"_visit_",[ast]);
-smalltalk.send(self,"_assert_",[smalltalk.send(smalltalk.send(smalltalk.send(ast,"_scope",[]),"_unknownVariables",[]),"__eq",[["b"]])]);
+smalltalk.send(self,"_should_raise_",[(function(){
+return smalltalk.send(self["@analyzer"],"_visit_",[ast]);
+}),(smalltalk.UnknownVariableError || UnknownVariableError)]);
+return self}
+}),
+smalltalk.SemanticAnalyzerTest);
+
+smalltalk.addMethod(
+"_testUnknownVariablesInWindow",
+smalltalk.method({
+selector: "testUnknownVariablesInWindow",
+fn: function (){
+var self=this;
+smalltalk.send(self,"_shouldnt_raise_",[(function(){
+return smalltalk.send(smalltalk,"_parse_",["foo jQuery"]);
+}),(smalltalk.UnknownVariableError || UnknownVariableError)]);
 return self}
 }),
 smalltalk.SemanticAnalyzerTest);
@@ -539,8 +553,9 @@ var src;
 var ast;
 src="foo | a b | [ c + 1. [ a + 1. d + 1 ]]";
 ast=smalltalk.send(smalltalk,"_parse_",[src]);
-smalltalk.send(self["@analyzer"],"_visit_",[ast]);
-smalltalk.send(self,"_assert_",[smalltalk.send(smalltalk.send(smalltalk.send(ast,"_scope",[]),"_unknownVariables",[]),"__eq",[["c", "d"]])]);
+smalltalk.send(self,"_should_raise_",[(function(){
+return smalltalk.send(self["@analyzer"],"_visit_",[ast]);
+}),(smalltalk.UnknownVariableError || UnknownVariableError)]);
 return self}
 }),
 smalltalk.SemanticAnalyzerTest);

+ 30 - 10
js/Compiler-Tests.js

@@ -694,13 +694,32 @@ var src;
 var ast;
 src="foo | a | b + a";
 ast=smalltalk.send(smalltalk,"_parse_",[src]);
-smalltalk.send(self["@analyzer"],"_visit_",[ast]);
-smalltalk.send(self,"_assert_",[smalltalk.send(smalltalk.send(smalltalk.send(ast,"_scope",[]),"_unknownVariables",[]),"__eq",[["b"]])]);
+smalltalk.send(self,"_should_raise_",[(function(){
+return smalltalk.send(self["@analyzer"],"_visit_",[ast]);
+}),(smalltalk.UnknownVariableError || UnknownVariableError)]);
 return self},
 args: [],
-source: "testUnknownVariables\x0a\x09| src ast |\x0a\x0a\x09src := 'foo | a | b + a'.\x0a\x09ast := smalltalk parse: src.\x0a\x09analyzer visit: ast.\x0a\x0a\x09self assert: ast scope unknownVariables = #('b')",
-messageSends: ["parse:", "visit:", "assert:", "=", "unknownVariables", "scope"],
-referencedClasses: []
+source: "testUnknownVariables\x0a\x09| src ast |\x0a\x0a\x09src := 'foo | a | b + a'.\x0a\x09ast := smalltalk parse: src.\x0a\x0a\x09self should: [ analyzer visit: ast ] raise: UnknownVariableError",
+messageSends: ["parse:", "should:raise:", "visit:"],
+referencedClasses: ["UnknownVariableError"]
+}),
+smalltalk.SemanticAnalyzerTest);
+
+smalltalk.addMethod(
+"_testUnknownVariablesInWindow",
+smalltalk.method({
+selector: "testUnknownVariablesInWindow",
+category: 'tests',
+fn: function (){
+var self=this;
+smalltalk.send(self,"_shouldnt_raise_",[(function(){
+return smalltalk.send(smalltalk,"_parse_",["foo jQuery"]);
+}),(smalltalk.UnknownVariableError || UnknownVariableError)]);
+return self},
+args: [],
+source: "testUnknownVariablesInWindow\x0a\x0a\x09self shouldnt: [ smalltalk parse: 'foo jQuery' ] raise: UnknownVariableError",
+messageSends: ["shouldnt:raise:", "parse:"],
+referencedClasses: ["UnknownVariableError"]
 }),
 smalltalk.SemanticAnalyzerTest);
 
@@ -715,13 +734,14 @@ var src;
 var ast;
 src="foo | a b | [ c + 1. [ a + 1. d + 1 ]]";
 ast=smalltalk.send(smalltalk,"_parse_",[src]);
-smalltalk.send(self["@analyzer"],"_visit_",[ast]);
-smalltalk.send(self,"_assert_",[smalltalk.send(smalltalk.send(smalltalk.send(ast,"_scope",[]),"_unknownVariables",[]),"__eq",[["c", "d"]])]);
+smalltalk.send(self,"_should_raise_",[(function(){
+return smalltalk.send(self["@analyzer"],"_visit_",[ast]);
+}),(smalltalk.UnknownVariableError || UnknownVariableError)]);
 return self},
 args: [],
-source: "testUnknownVariablesWithScope\x0a\x09| src ast |\x0a\x0a\x09src := 'foo | a b | [ c + 1. [ a + 1. d + 1 ]]'.\x0a\x09ast := smalltalk parse: src.\x0a\x09analyzer visit: ast.\x0a\x0a\x09self assert: ast scope unknownVariables = #('c' 'd' )",
-messageSends: ["parse:", "visit:", "assert:", "=", "unknownVariables", "scope"],
-referencedClasses: []
+source: "testUnknownVariablesWithScope\x0a\x09| src ast |\x0a\x0a\x09src := 'foo | a b | [ c + 1. [ a + 1. d + 1 ]]'.\x0a\x09ast := smalltalk parse: src.\x0a\x09\x0a\x09self should: [ analyzer visit: ast ] raise: UnknownVariableError",
+messageSends: ["parse:", "should:raise:", "visit:"],
+referencedClasses: ["UnknownVariableError"]
 }),
 smalltalk.SemanticAnalyzerTest);
 

+ 6 - 9
st/Compiler-Semantic.st

@@ -406,12 +406,15 @@ errorShadowingVariable: aString
 !
 
 errorUnknownVariable: aNode
-	self allowUnknownVariables 
-		ifTrue: [ currentScope methodScope unknownVariables add: aNode value ]
-		ifFalse: [ 
+	"Throw an error if the variable is undeclared in the global JS scope (i.e. window)"
+
+	(window at: aNode value) 
+		ifNil: [ 
 			UnknownVariableError new
 				variableName: aNode value;
 				signal ]
+		ifNotNil: [
+			currentScope methodScope unknownVariables add: aNode value. ]
 ! !
 
 !SemanticAnalyzer methodsFor: 'factory'!
@@ -449,12 +452,6 @@ validateVariableScope: aString
 		self errorShadowingVariable: aString ]
 ! !
 
-!SemanticAnalyzer methodsFor: 'testing'!
-
-allowUnknownVariables
-	^ true
-! !
-
 !SemanticAnalyzer methodsFor: 'visiting'!
 
 visitAssignmentNode: aNode

+ 8 - 5
st/Compiler-Tests.st

@@ -302,9 +302,13 @@ testUnknownVariables
 
 	src := 'foo | a | b + a'.
 	ast := smalltalk parse: src.
-	analyzer visit: ast.
 
-	self assert: ast scope unknownVariables = #('b')
+	self should: [ analyzer visit: ast ] raise: UnknownVariableError
+!
+
+testUnknownVariablesInWindow
+
+	self shouldnt: [ smalltalk parse: 'foo jQuery' ] raise: UnknownVariableError
 !
 
 testUnknownVariablesWithScope
@@ -312,9 +316,8 @@ testUnknownVariablesWithScope
 
 	src := 'foo | a b | [ c + 1. [ a + 1. d + 1 ]]'.
 	ast := smalltalk parse: src.
-	analyzer visit: ast.
-
-	self assert: ast scope unknownVariables = #('c' 'd' )
+	
+	self should: [ analyzer visit: ast ] raise: UnknownVariableError
 !
 
 testVariableShadowing