Explorar o código

Redo JS reserved words mangling: mangle identifiers in code generation
instead of lexer. It also resolves strange diagnostic for variables like
'var' etc.
Fix issue #50: Module reader called with 'Math$' name, expected 'Math'.

Vladislav Folts %!s(int64=8) %!d(string=hai) anos
pai
achega
b5c9786bf3

BIN=BIN
bin/compiled.zip


+ 2 - 2
src/eberon/EberonConstructor.ob

@@ -1,6 +1,6 @@
 MODULE EberonConstructor;
 MODULE EberonConstructor;
 IMPORT 
 IMPORT 
-    Cast, EberonCast, EberonRecord, Errors, Expression, 
+    Cast, CodeGenerator, EberonCast, EberonRecord, Errors, Expression, 
     LanguageContext, Procedure, Record, Stream, TypeId, Types;
     LanguageContext, Procedure, Record, Stream, TypeId, Types;
 TYPE
 TYPE
     ConstructorCall = RECORD(Procedure.StdCall)
     ConstructorCall = RECORD(Procedure.StdCall)
@@ -39,7 +39,7 @@ END;
 PROCEDURE BaseConstructorCall.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
 PROCEDURE BaseConstructorCall.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
 BEGIN
 BEGIN
     argCode <- checkArgs(SELF, args, cx);
     argCode <- checkArgs(SELF, args, cx);
-    code <- Record.constructor(cx.cx^, SELF.recordType^) + ".call(this, " + argCode + ");" + Stream.kCR;
+    code <- CodeGenerator.mangleId(Record.constructor(cx.cx^, SELF.recordType^)) + ".call(this, " + argCode + ");" + Stream.kCR;
     RETURN Expression.makeSimple(code, NIL);
     RETURN Expression.makeSimple(code, NIL);
 END;
 END;
 
 

+ 9 - 1
src/eberon/EberonContextDesignator.ob

@@ -32,6 +32,10 @@ TYPE
         var: PTypeNarrowVariable;
         var: PTypeNarrowVariable;
     END;
     END;
 
 
+    SelfVariable* = RECORD(Variable.Declared)
+        PROCEDURE SelfVariable(type: Types.PStorageType);
+    END;
+
     SelfAsPointer = RECORD(Types.Id)
     SelfAsPointer = RECORD(Types.Id)
     END;
     END;
 
 
@@ -205,7 +209,7 @@ PROCEDURE Type.handleLiteral(s: STRING);
 BEGIN
 BEGIN
     IF s = "SELF" THEN
     IF s = "SELF" THEN
         type <- SELF.handleMessage(getMethodSelfMsg)(Types.PStorageType);
         type <- SELF.handleMessage(getMethodSelfMsg)(Types.PStorageType);
-        info <- NEW Variable.Declared("this", type, NIL);
+        info <- NEW SelfVariable(type);
         ContextDesignator.advance(SELF, type, info, "this", FALSE);
         ContextDesignator.advance(SELF, type, info, "this", FALSE);
     ELSIF s = "POINTER" THEN
     ELSIF s = "POINTER" THEN
         type <- SELF.handleMessage(getSelfAsPointerMsg)(Types.PStorageType);
         type <- SELF.handleMessage(getSelfAsPointerMsg)(Types.PStorageType);
@@ -317,6 +321,10 @@ PROCEDURE SelfAsPointer.idType(): STRING;
     RETURN "SELF(POINTER)";
     RETURN "SELF(POINTER)";
 END;
 END;
 
 
+PROCEDURE SelfVariable.SelfVariable(type: Types.PStorageType)
+    | SUPER("SELF", type, NIL);
+END;
+
 PROCEDURE ExpressionProcedureCall.ExpressionProcedureCall(parent: ContextHierarchy.PNode)
 PROCEDURE ExpressionProcedureCall.ExpressionProcedureCall(parent: ContextHierarchy.PNode)
     | SUPER(parent);
     | SUPER(parent);
 BEGIN
 BEGIN

+ 1 - 1
src/eberon/EberonContextInPlace.ob

@@ -27,7 +27,7 @@ END;
 
 
 PROCEDURE VariableInit.handleLiteral(s: STRING);
 PROCEDURE VariableInit.handleLiteral(s: STRING);
 BEGIN
 BEGIN
-    SELF.code := "var " + SELF.id + " = ";
+    SELF.code := "var " + CodeGenerator.mangleId(SELF.id) + " = ";
 END;
 END;
 
 
 PROCEDURE VariableInit.handleExpression(e: Expression.PType);
 PROCEDURE VariableInit.handleExpression(e: Expression.PType);

+ 4 - 3
src/eberon/EberonContextProcedure.ob

@@ -92,7 +92,7 @@ BEGIN
     
     
     RETURN NEW EberonContextDesignator.SuperMethodInfo(
     RETURN NEW EberonContextDesignator.SuperMethodInfo(
         procId,
         procId,
-        d.qualifyScope(baseType.scope) + baseType.description() + ".prototype." + id + ".call");
+        CodeGenerator.mangleId(d.qualifyScope(baseType.scope) + baseType.description()) + ".prototype." + id + ".call");
 END;
 END;
 
 
 PROCEDURE handleFieldInit(d: PProcOrMethodDeclaration; id: STRING): Procedure.PCallGenerator;
 PROCEDURE handleFieldInit(d: PProcOrMethodDeclaration; id: STRING): Procedure.PCallGenerator;
@@ -162,10 +162,11 @@ VAR
     result: STRING;
     result: STRING;
 BEGIN
 BEGIN
     IF SELF.boundType # NIL THEN
     IF SELF.boundType # NIL THEN
+        boundTypeCode <- CodeGenerator.mangleId(SELF.boundType.name);
         IF SELF.isConstructor THEN
         IF SELF.isConstructor THEN
-            result := "function " + SELF.boundType.name + "(";
+            result := "function " + boundTypeCode + "(";
         ELSE
         ELSE
-            result := SELF.boundType.name + ".prototype." + SELF.methodId.id() + " = function(";
+            result :=  boundTypeCode + ".prototype." + SELF.methodId.id() + " = function(";
         END;
         END;
     ELSE
     ELSE
         result := SUPER();
         result := SUPER();

+ 9 - 12
src/eberon/EberonLanguageContext.ob

@@ -1,22 +1,19 @@
 MODULE EberonLanguageContext;
 MODULE EberonLanguageContext;
 IMPORT 
 IMPORT 
-	EberonMap, EberonTypePromotion, Expression, LanguageContext, Types;
+	EberonContextDesignator, EberonMap, EberonTypePromotion, Expression, LanguageContext, Types;
 TYPE
 TYPE
 	CodeTraits* = RECORD(LanguageContext.CodeTraits)
 	CodeTraits* = RECORD(LanguageContext.CodeTraits)
 	END;
 	END;
 
 
 PROCEDURE CodeTraits.referenceCode(VAR info: Types.Id): STRING;
 PROCEDURE CodeTraits.referenceCode(VAR info: Types.Id): STRING;
-VAR
-    result: STRING;
-BEGIN
-	IF info IS EberonTypePromotion.Variable THEN
-		result := info.id();
-	ELSIF (info IS EberonMap.ElementVariable) & ~info.elementType.isScalar() THEN
-		result := info.rval;
-	ELSE
-		result := SUPER(info);
-	END;
-    RETURN result;
+	RETURN 
+		info IS EberonContextDesignator.SelfVariable 
+				? "this"
+		: info IS EberonTypePromotion.Variable 			
+				? info.id()
+		: ((info IS EberonMap.ElementVariable) & ~info.elementType.isScalar()) 
+				? info.rval
+		: SUPER(info);
 END;
 END;
 
 
 PROCEDURE CodeTraits.assign(VAR info: Types.Id; right: Expression.PType): STRING;
 PROCEDURE CodeTraits.assign(VAR info: Types.Id; right: Expression.PType): STRING;

+ 2 - 1
src/nodejs.js

@@ -2,6 +2,7 @@
 
 
 var Class = require("rtl.js").Class;
 var Class = require("rtl.js").Class;
 var Code = require("js/Code.js");
 var Code = require("js/Code.js");
+var CodeGenerator = require("js/CodeGenerator.js");
 var Errors = require("js/Errors.js");
 var Errors = require("js/Errors.js");
 var ContextHierarchy = require("js/ContextHierarchy.js");
 var ContextHierarchy = require("js/ContextHierarchy.js");
 var LanguageContext = require("js/LanguageContext.js");
 var LanguageContext = require("js/LanguageContext.js");
@@ -24,7 +25,7 @@ var ModuleGenerator = Class.extend({
             var alias = modules[name];
             var alias = modules[name];
             var importName = this.__importDir ? this.__importDir + "/" + name
             var importName = this.__importDir ? this.__importDir + "/" + name
                                               : name;
                                               : name;
-            result += "var " + alias + " = " + (name == "this" 
+            result += "var " + CodeGenerator.mangleId(alias) + " = " + (name == "JS" 
                 ? "GLOBAL"
                 ? "GLOBAL"
                 : "require(\"" + importName + ".js\")") + ";\n";
                 : "require(\"" + importName + ".js\")") + ";\n";
         }
         }

+ 8 - 16
src/ob/Code.ob

@@ -66,17 +66,11 @@ BEGIN
 END;
 END;
 
 
 PROCEDURE genExport*(s: Symbols.Symbol): STRING;
 PROCEDURE genExport*(s: Symbols.Symbol): STRING;
-VAR
-    result: STRING;
 BEGIN
 BEGIN
-    IF s.isVariable() THEN
-        result := "function(){return " + s.id() + ";}";
-    ELSIF ~s.isType() THEN
-        result := s.id();
-    ELSE
-        result := typeShouldBeExported(s.info()(TypeId.PType), s.id())
-    END;
-    RETURN result
+    codeId <- CodeGenerator.mangleId(s.id());
+    RETURN s.isVariable() ? "function(){return " + codeId + ";}"
+        : ~s.isType()     ? codeId
+                          : typeShouldBeExported(s.info()(TypeId.PType), codeId);
 END;
 END;
 
 
 PROCEDURE genCommaList(m: StringsMap; import: BOOLEAN): STRING;
 PROCEDURE genCommaList(m: StringsMap; import: BOOLEAN): STRING;
@@ -87,17 +81,15 @@ BEGIN
         IF LEN(result) # 0 THEN
         IF LEN(result) # 0 THEN
             result := result + ", ";
             result := result + ", ";
         END;
         END;
-        IF import THEN
-            result := result + alias;
-        ELSE
-            result := result + name;
-        END;
+        result := result + ((~import & (name = "JS")) 
+                                ? "this"
+                                : CodeGenerator.mangleId(import ? alias : name));
     END;
     END;
     RETURN result;
     RETURN result;
 END;
 END;
 
 
 PROCEDURE ModuleGenerator.prolog(): STRING;
 PROCEDURE ModuleGenerator.prolog(): STRING;
-    RETURN "var " + SELF.name + " = function (" + genCommaList(SELF.imports, TRUE) + "){" + Stream.kCR
+    RETURN "var " + CodeGenerator.mangleId(SELF.name) + " = function (" + genCommaList(SELF.imports, TRUE) + "){" + Stream.kCR
 END;
 END;
 
 
 PROCEDURE exportId*(s: Symbols.Symbol): STRING;
 PROCEDURE exportId*(s: Symbols.Symbol): STRING;

+ 14 - 0
src/ob/CodeGenerator.ob

@@ -3,6 +3,16 @@ IMPORT
     Stream, String;
     Stream, String;
 CONST
 CONST
     kTab* = 09X;
     kTab* = 09X;
+
+    jsReservedWords = [
+        "break", "case", "catch", "const", "continue", "debugger", "default", "delete", "do", "else", "finally",
+        "for", "function", "if", "in", "instanceof", "new", "return", "switch", "this", "throw", "try", "typeof",
+        "var", "void", "while", "with", "false", "true", "null", "class", "enum", "export", "extends",
+        "import", "super", "implements", "interface", "let", "package", "private", "protected",
+        "public", "static", "yield",
+        "Object", "Math", "Number" (* Object, Math and Number are used in generated code for some functions so it is 
+                                      reserved word from code generator standpoint *)
+        ];
 TYPE
 TYPE
     Insertion* = RECORD
     Insertion* = RECORD
         PROCEDURE Insertion(index: INTEGER);
         PROCEDURE Insertion(index: INTEGER);
@@ -178,6 +188,10 @@ BEGIN
     SELF.indents.add(Indent(0));
     SELF.indents.add(Indent(0));
 END;
 END;
 
 
+PROCEDURE mangleId*(id: STRING): STRING;
+    RETURN jsReservedWords.indexOf(id) # -1 ? id + "$" : id;
+END;
+
 BEGIN
 BEGIN
     NEW(nullGenerator);
     NEW(nullGenerator);
 END CodeGenerator.
 END CodeGenerator.

+ 3 - 3
src/ob/ContextIdentdef.ob

@@ -1,6 +1,6 @@
 MODULE ContextIdentdef;
 MODULE ContextIdentdef;
 IMPORT
 IMPORT
-    Context, ContextDesignator, ContextHierarchy, ContextType, 
+    Context, CodeGenerator, ContextDesignator, ContextHierarchy, ContextType, 
     Module, Record, TypeId;
     Module, Record, TypeId;
 TYPE
 TYPE
     Type* = RECORD(ContextHierarchy.Node)
     Type* = RECORD(ContextHierarchy.Node)
@@ -64,7 +64,7 @@ END;
 PROCEDURE Qualified.handleModule(id: STRING; module: Module.PType);
 PROCEDURE Qualified.handleModule(id: STRING; module: Module.PType);
 BEGIN
 BEGIN
     SELF.module := module;
     SELF.module := module;
-    SELF.code := id + ".";
+    SELF.code := CodeGenerator.mangleId(id) + ".";
 END;
 END;
 
 
 PROCEDURE Qualified.endParse(): BOOLEAN;
 PROCEDURE Qualified.endParse(): BOOLEAN;
@@ -72,7 +72,7 @@ VAR
     code: STRING;
     code: STRING;
 BEGIN
 BEGIN
     IF LEN(SELF.code) = 0 THEN
     IF LEN(SELF.code) = 0 THEN
-        code := SELF.id;
+        code := CodeGenerator.mangleId(SELF.id);
     ELSE
     ELSE
         code := SELF.code + Record.mangleJSProperty(SELF.id);
         code := SELF.code + Record.mangleJSProperty(SELF.id);
     END;
     END;

+ 3 - 6
src/ob/ContextModule.ob

@@ -1,6 +1,6 @@
 MODULE ContextModule;
 MODULE ContextModule;
 IMPORT
 IMPORT
-    ContextHierarchy, ContextType, Errors, LanguageContext, 
+    CodeGenerator, ContextHierarchy, ContextType, Errors, LanguageContext, 
     Object, Scope, ScopeBase, String, Symbols, Types;
     Object, Scope, ScopeBase, String, Symbols, Types;
 TYPE
 TYPE
     Declaration* = RECORD(ContextHierarchy.Node)
     Declaration* = RECORD(ContextHierarchy.Node)
@@ -77,11 +77,8 @@ BEGIN
            should not be used in code generation, 
            should not be used in code generation, 
            just return non-empty value to indicate this is not current module
            just return non-empty value to indicate this is not current module
         *)
         *)
-        IF ~(id IN SELF.imports) THEN
-            result := "module '" + id + "' is not imported";
-        ELSE
-            result := SELF.imports[id].id() + ".";
-        END;
+        result := ~(id IN SELF.imports) ? "module '" + id + "' is not imported"
+                                        : CodeGenerator.mangleId(SELF.imports[id].id()) + ".";
     END;
     END;
     RETURN result;
     RETURN result;
 END;
 END;

+ 2 - 2
src/ob/ContextProcedure.ob

@@ -85,7 +85,7 @@ BEGIN
 END;
 END;
 
 
 PROCEDURE Declaration.doProlog(): STRING;
 PROCEDURE Declaration.doProlog(): STRING;
-    RETURN Chars.ln + "function " + SELF.id.id() + "(";
+    RETURN Chars.ln + "function " + CodeGenerator.mangleId(SELF.id.id()) + "(";
 END;
 END;
 
 
 PROCEDURE Declaration.doEpilog(): STRING;
 PROCEDURE Declaration.doEpilog(): STRING;
@@ -128,7 +128,7 @@ BEGIN
     ELSE
     ELSE
         declaration.multipleArguments := TRUE;
         declaration.multipleArguments := TRUE;
     END;
     END;
-    code.write(name + "/*" + arg.description() + "*/");
+    code.write(CodeGenerator.mangleId(name) + "/*" + arg.description() + "*/");
 END;
 END;
 
 
 PROCEDURE Declaration.doMakeArgumentVariable(arg: Types.ProcedureArgument; name: STRING): Types.PVariable;
 PROCEDURE Declaration.doMakeArgumentVariable(arg: Types.ProcedureArgument; name: STRING): Types.PVariable;

+ 6 - 2
src/ob/ContextType.ob

@@ -364,7 +364,7 @@ END;
 PROCEDURE Record.doGenerateConstructor(): STRING;
 PROCEDURE Record.doGenerateConstructor(): STRING;
 BEGIN
 BEGIN
     gen <- NEW CodeGenerator.Generator();
     gen <- NEW CodeGenerator.Generator();
-    gen.write("function " + SELF.cons + "()");
+    gen.write("function " + CodeGenerator.mangleId(SELF.cons) + "()");
     gen.openScope();
     gen.openScope();
     gen.write(SELF.doGenerateBaseConstructorCallCode() 
     gen.write(SELF.doGenerateBaseConstructorCallCode() 
             + generateFieldsInitializationCode(SELF));
             + generateFieldsInitializationCode(SELF));
@@ -385,7 +385,11 @@ BEGIN
         result := SELF.cons + ".prototype.$scope = " + scope + ";" + Chars.ln;
         result := SELF.cons + ".prototype.$scope = " + scope + ";" + Chars.ln;
     ELSE
     ELSE
         qualifiedBase <- SELF.qualifyScope(base.scope) + base.name; 
         qualifiedBase <- SELF.qualifyScope(base.scope) + base.name; 
-        result := SELF.root().language().rtl.extend(SELF.cons, qualifiedBase, scope) + ";" + Chars.ln;
+        result := SELF.root().language().rtl.extend(
+                    CodeGenerator.mangleId(SELF.cons), 
+                    CodeGenerator.mangleId(qualifiedBase), 
+                    scope) 
+                + ";" + Chars.ln;
     END;
     END;
     RETURN result;
     RETURN result;
 END;
 END;

+ 2 - 2
src/ob/ContextVar.ob

@@ -1,6 +1,6 @@
 MODULE ContextVar;
 MODULE ContextVar;
 IMPORT
 IMPORT
-    Chars, Context, ContextHierarchy, ContextType, Errors, 
+    Chars, CodeGenerator, Context, ContextHierarchy, ContextType, Errors, 
     Object, Symbols, Types, Variable;
     Object, Symbols, Types, Variable;
 TYPE
 TYPE
     Declaration* = RECORD(ContextType.DeclarationAndIdentHandle)
     Declaration* = RECORD(ContextType.DeclarationAndIdentHandle)
@@ -58,7 +58,7 @@ BEGIN
         scope <- SELF.root().currentScope();
         scope <- SELF.root().currentScope();
         v <- NEW Variable.Declared(varName, SELF.type, scope);
         v <- NEW Variable.Declared(varName, SELF.type, scope);
         scope.addSymbol(NEW Symbols.Symbol(varName, v), id.exported());
         scope.addSymbol(NEW Symbols.Symbol(varName, v), id.exported());
-        gen.write("var " + varName + " = " + SELF.doInitCode() + ";");
+        gen.write("var " + CodeGenerator.mangleId(varName) + " = " + SELF.doInitCode() + ";");
     END;
     END;
 
 
     gen.write(Chars.ln);
     gen.write(Chars.ln);

+ 4 - 3
src/ob/LanguageContext.ob

@@ -112,7 +112,7 @@ VAR
     result: STRING;
     result: STRING;
 BEGIN
 BEGIN
     IF info IS T.DeclaredVariable THEN
     IF info IS T.DeclaredVariable THEN
-        result := info.id();
+        result := CodeGenerator.mangleId(info.id());
         IF info.type().isScalar() & ~((info IS Variable.ArgumentVariable) & info.var) THEN
         IF info.type().isScalar() & ~((info IS Variable.ArgumentVariable) & info.var) THEN
             result := "{set: function($v){" + result + " = $v;}, get: function(){return " + result + ";}}";
             result := "{set: function($v){" + result + " = $v;}, get: function(){return " + result + ";}}";
         END
         END
@@ -144,10 +144,11 @@ VAR
 BEGIN
 BEGIN
     rightCode <- Expression.deref(right).code();
     rightCode <- Expression.deref(right).code();
     IF info IS T.DeclaredVariable THEN
     IF info IS T.DeclaredVariable THEN
+        idCode <- CodeGenerator.mangleId(info.id());
         IF (info IS Variable.ArgumentVariable) & info.var THEN
         IF (info IS Variable.ArgumentVariable) & info.var THEN
-            result := info.id() + ".set(" + rightCode + ")";
+            result := idCode + ".set(" + rightCode + ")";
         ELSE
         ELSE
-            result := info.id() + " = " + rightCode;
+            result := idCode + " = " + rightCode;
         END;
         END;
     ELSIF info IS Variable.PropertyVariable THEN
     ELSIF info IS Variable.PropertyVariable THEN
         result := SELF.putAt(info.leadCode, info.propCode, rightCode);
         result := SELF.putAt(info.leadCode, info.propCode, rightCode);

+ 2 - 12
src/ob/Lexer.ob

@@ -6,16 +6,6 @@ CONST
     commentBegin = "(*";
     commentBegin = "(*";
     commentEnd = "*)";
     commentEnd = "*)";
 
 
-    jsReservedWords = [
-        "break", "case", "catch", "const", "continue", "debugger", "default", "delete", "do", "else", "finally",
-        "for", "function", "if", "in", "instanceof", "new", "return", "switch", "this", "throw", "try", "typeof",
-        "var", "void", "while", "with", "false", "true", "null", "class", "enum", "export", "extends",
-        "import", "super", "implements", "interface", "let", "package", "private", "protected",
-        "public", "static", "yield",
-        "Object", "Math", "Number" (* Object, Math and Number are used in generated code for some functions so it is 
-                                      reserved word from code generator standpoint *)
-        ];
-
 TYPE
 TYPE
     Literal* = RECORD
     Literal* = RECORD
         PROCEDURE Literal*(s: STRING);
         PROCEDURE Literal*(s: STRING);
@@ -272,9 +262,9 @@ BEGIN
             END;
             END;
 
 
             IF reservedWords.indexOf(s) = -1 THEN
             IF reservedWords.indexOf(s) = -1 THEN
-                IF jsReservedWords.indexOf(s) # -1 THEN
+                (*IF jsReservedWords.indexOf(s) # -1 THEN
                     s := s + "$";
                     s := s + "$";
-                END;
+                END;*)
                 context.handleIdent(s);
                 context.handleIdent(s);
                 result := TRUE;
                 result := TRUE;
             END
             END

+ 3 - 3
src/ob/Module.ob

@@ -169,7 +169,7 @@ BEGIN
 END makeDoProcSymbol;
 END makeDoProcSymbol;
 
 
 PROCEDURE makeJS*(): PType;
 PROCEDURE makeJS*(): PType;
-    RETURN NEW JS("this");
+    RETURN NEW JS("JS");
 END;
 END;
 
 
 PROCEDURE AnyType.AnyType()
 PROCEDURE AnyType.AnyType()
@@ -188,8 +188,8 @@ BEGIN
 END;
 END;
 
 
 BEGIN
 BEGIN
-    doProcId := "do$";
-    varTypeId := "var$";
+    doProcId := "do";
+    varTypeId := "var";
     
     
     NEW(any);
     NEW(any);
     NEW(anyVar);
     NEW(anyVar);

+ 0 - 0
src/ob/Object$.ob → src/ob/Object.ob


+ 34 - 0
test/expected/eberon/js_keyword.js

@@ -0,0 +1,34 @@
+<rtl code>
+var import$ = function (){
+function Math$(){
+}
+Math$.prototype.do = function(){
+};
+Math$.prototype.catch = function(){
+};
+return {
+	Math: Math$
+}
+}();
+var m = function (import$){
+RTL$.extend(Object$, import$.Math);
+RTL$.extend(Number$, Object$);
+function Object$(var$/*INTEGER*/){
+	import$.Math.call(this);
+	this.var = var$;
+}
+Object$.prototype.catch = function(){
+	import$.Math.prototype.catch.call(this);
+};
+Object$.prototype.throw = function(){
+};
+function Number$(){
+	Object$.call(this, 123);
+}
+Number$.prototype.throw = function(){
+	Object$.prototype.throw.call(this);
+};
+Number$.prototype.do = function(){
+	Object$.prototype.do.call(this);
+};
+}(import$);

+ 28 - 5
test/expected/js_keyword.js

@@ -1,10 +1,33 @@
-var do$ = function (){
-var break$ = 0;var case$ = 0;var catch$ = 0;var continue$ = 0;var debugger$ = 0;var default$ = 0;var delete$ = 0;var else$ = 0;var class$ = 0;var const$ = 0;var enum$ = 0;var export$ = 0;var extends$ = 0;var import$ = 0;var super$ = 0;var true$ = 0;var false$ = 0;var null$ = 0;var implements$ = 0;var interface$ = 0;var let$ = 0;var package$ = 0;var private$ = 0;var protected$ = 0;var public$ = 0;var static$ = 0;var yield$ = 0;var finally$ = 0;var for$ = 0;var if$ = 0;var in$ = 0;var instanceof$ = 0;var new$ = 0;var return$ = 0;var switch$ = 0;var this$ = 0;var try$ = 0;var typeof$ = 0;var var$ = 0;var void$ = 0;var while$ = 0;var with$ = 0;var Object$ = 0;var Math$ = 0;var Number$ = 0;
+<rtl code>
+var Math$ = function (){
+function Object$(){
+}
+var var$ = 0;
 
 
-function function$(){
+function throw$(){
+}
+return {
+	Object: Object$,
+	var: function(){return var$;},
+	throw: throw$
+}
+}();
+var do$ = function (Math$){
+function D(){
+	Math$.Object.call(this);
+}
+RTL$.extend(D, Math$.Object);
+var break$ = 0;var case$ = 0;var catch$ = 0;var continue$ = 0;var debugger$ = 0;var default$ = 0;var delete$ = 0;var else$ = 0;var class$ = 0;var const$ = 0;var enum$ = 0;var export$ = 0;var extends$ = 0;var import$ = 0;var super$ = 0;var true$ = 0;var false$ = 0;var null$ = 0;var implements$ = 0;var interface$ = 0;var let$ = 0;var package$ = 0;var private$ = 0;var protected$ = 0;var public$ = 0;var static$ = 0;var yield$ = 0;var finally$ = 0;var for$ = 0;var if$ = 0;var in$ = 0;var instanceof$ = 0;var new$ = 0;var return$ = 0;var switch$ = 0;var this$ = 0;var try$ = 0;var typeof$ = 0;var var$ = 0;var void$ = 0;var while$ = 0;var with$ = 0;var Number$ = 0;var Object$ = 0;
+var r = new Math$.Object();
+
+function function$(else$/*VAR INTEGER*/){
 	var i = null;
 	var i = null;
+	var Math$ = 0;
 	i = function$;
 	i = function$;
 	case$ = 123;
 	case$ = 123;
+	else$.set(456);
 }
 }
-function$();
-}();
+function$({set: function($v){var$ = $v;}, get: function(){return var$;}});
+Math$.throw();
+var$ = Math$.var();
+}(Math$);

+ 57 - 0
test/input/eberon/js_keyword.ob

@@ -0,0 +1,57 @@
+MODULE import;
+TYPE
+	Math* = RECORD
+		PROCEDURE do*();
+		PROCEDURE catch*();
+	END;
+
+PROCEDURE Math.do();
+END;
+
+PROCEDURE Math.catch();
+END;
+
+END import.
+
+MODULE m;
+IMPORT import;
+
+TYPE 
+	Object = RECORD(import.Math)
+		PROCEDURE Object(var: INTEGER);
+		PROCEDURE throw();
+
+		var: INTEGER;
+	END;
+
+	Number = RECORD(Object)
+		PROCEDURE Number();
+	END;
+
+PROCEDURE Object.Object(var: INTEGER)
+	| var(var);
+END;
+
+PROCEDURE Object.catch();
+BEGIN
+	SUPER();
+END;
+
+PROCEDURE Object.throw();
+END;
+
+PROCEDURE Number.Number()
+	| SUPER(123);
+END;
+
+PROCEDURE Number.throw();
+BEGIN
+	SUPER();
+END;
+
+PROCEDURE Number.do();
+BEGIN
+	SUPER();
+END;
+
+END m.

+ 28 - 5
test/input/js_keyword.ob

@@ -1,20 +1,43 @@
+MODULE Math;
+
+TYPE
+    Object* = RECORD END;
+
+VAR var*: INTEGER;
+
+PROCEDURE throw*();
+END throw;
+
+END Math.
+
 MODULE do;
 MODULE do;
-TYPE throw = PROCEDURE;
+IMPORT Math;
+TYPE
+    throw = PROCEDURE(VAR catch: INTEGER);
+    D = RECORD(Math.Object) END;
 VAR
 VAR
     break, case, catch, continue, debugger, default, delete, else,
     break, case, catch, continue, debugger, default, delete, else,
     class, const, enum, export, extends, import, super,
     class, const, enum, export, extends, import, super,
     true, false, null,
     true, false, null,
     implements, interface, let, package, private, protected, public, static, yield,
     implements, interface, let, package, private, protected, public, static, yield,
     finally, for, if, in, instanceof, new, return, switch, this, 
     finally, for, if, in, instanceof, new, return, switch, this, 
-    try, typeof, var, void, while, with, Object, Math, Number
+    try, typeof, var, void, while, with, Number, Object
     : INTEGER;
     : INTEGER;
-PROCEDURE function();
-VAR i: throw;
+
+    r: Math.Object;
+
+PROCEDURE function(VAR else: INTEGER);
+VAR 
+    i: throw;
+    Math: INTEGER;
 BEGIN
 BEGIN
 	i := function;
 	i := function;
 	case := 123;
 	case := 123;
+    else := 456;
 END function;
 END function;
 
 
 BEGIN
 BEGIN
-	function();
+	function(var);
+    Math.throw();
+    var := Math.var;
 END do.
 END do.

+ 11 - 0
test/test_unit.js

@@ -1109,6 +1109,17 @@ return {
          ["ASSERT(TRUE, 123)", "1 argument(s) expected, got 2"],
          ["ASSERT(TRUE, 123)", "1 argument(s) expected, got 2"],
          ["ASSERT(123)", "type mismatch for argument 1: 'INTEGER' cannot be converted to 'BOOLEAN'"])
          ["ASSERT(123)", "type mismatch for argument 1: 'INTEGER' cannot be converted to 'BOOLEAN'"])
     ),
     ),
+"import module with reserved name": testWithContext(
+    { grammar: grammar.module,
+      source: "",
+      moduleReader: function(name){
+        TestUnitCommon.expectEq(name, "Math"); 
+        return "MODULE " + name + "; END " + name + "."; 
+        }
+    },
+    pass("MODULE m; IMPORT Math; END m."),
+    fail()
+    ),
 "imported module without exports": testWithModule(
 "imported module without exports": testWithModule(
     "MODULE test; END test.",
     "MODULE test; END test.",
     pass("MODULE m; IMPORT test; END m."),
     pass("MODULE m; IMPORT test; END m."),

+ 33 - 20
test/test_unit_common.js

@@ -30,7 +30,7 @@ var TestModuleGenerator = Class.extend({
 });
 });
 
 
 var TestContextRoot = Class.extend.call(ContextHierarchy.Root, {
 var TestContextRoot = Class.extend.call(ContextHierarchy.Root, {
-    init: function TestContextRoot(language){
+    init: function TestContextRoot(language, moduleResolver){
         var rtl = new makeRTL(language.rtl);
         var rtl = new makeRTL(language.rtl);
         ContextHierarchy.Root.call(
         ContextHierarchy.Root.call(
                 this,
                 this,
@@ -38,7 +38,8 @@ var TestContextRoot = Class.extend.call(ContextHierarchy.Root, {
                   moduleGenerator: function(){return new TestModuleGenerator();},
                   moduleGenerator: function(){return new TestModuleGenerator();},
                   rtl: rtl,
                   rtl: rtl,
                   types: language.types,
                   types: language.types,
-                  stdSymbols: language.stdSymbols
+                  stdSymbols: language.stdSymbols,
+                  moduleResolver: moduleResolver
                 });
                 });
         this.pushScope(new Scope.Module("test", language.stdSymbols));
         this.pushScope(new Scope.Module("test", language.stdSymbols));
     },
     },
@@ -51,13 +52,13 @@ var TestContextRoot = Class.extend.call(ContextHierarchy.Root, {
 });
 });
 
 
 var TestContext = Class.extend.call(ContextExpression.ExpressionHandler, {
 var TestContext = Class.extend.call(ContextExpression.ExpressionHandler, {
-    init: function TestContext(language){
-        ContextExpression.ExpressionHandler.call(this, new TestContextRoot(language));
+    init: function TestContext(language, moduleResolver){
+        ContextExpression.ExpressionHandler.call(this, new TestContextRoot(language, moduleResolver));
     },
     },
     handleExpression: function(){}
     handleExpression: function(){}
 });
 });
 
 
-function makeContext(language){return new TestContext(language);}
+function makeContext(language, moduleResolver){return new TestContext(language, moduleResolver);}
 
 
 function testWithSetup(setup, pass, fail){
 function testWithSetup(setup, pass, fail){
     return function(){
     return function(){
@@ -135,9 +136,20 @@ function setupParser(parser, language, contextFactory){
     return setup(parseImpl);
     return setup(parseImpl);
 }
 }
 
 
-function setupWithContext(grammar, contextGrammar, language, source){
+function compileModule(src, language){
+    var imported = oc.compileModule(language.grammar, new Stream.Type(src), makeContext(language));
+    return imported.symbol().info();
+}
+
+function makeModuleResolver(moduleReader, language){
+    return moduleReader ? function(name){ return compileModule(moduleReader(name), language); }
+                        : undefined;
+}
+
+function setupWithContext(fixture, contextGrammar, language){
     function innerMakeContext(){
     function innerMakeContext(){
-        var context = makeContext(language);
+        var context = makeContext(language, makeModuleResolver(fixture.moduleReader, language));
+        var source = fixture.source;
         try {
         try {
             parseInContext(contextGrammar, source, context);
             parseInContext(contextGrammar, source, context);
         }
         }
@@ -149,12 +161,12 @@ function setupWithContext(grammar, contextGrammar, language, source){
         return context;
         return context;
     }
     }
 
 
-    return setupParser(grammar, language, innerMakeContext);
+    return setupParser(fixture.grammar, language, innerMakeContext);
 }
 }
 
 
-function testWithContext(context, contextGrammar, language, pass, fail){
+function testWithContext(fixture, contextGrammar, language, pass, fail){
     return testWithSetup(
     return testWithSetup(
-        function(){return setupWithContext(context.grammar, contextGrammar, language, context.source);},
+        setupWithContext.bind(undefined, fixture, contextGrammar, language),
         pass,
         pass,
         fail);
         fail);
 }
 }
@@ -166,23 +178,15 @@ function testWithGrammar(parser, language, pass, fail){
         fail);
         fail);
 }
 }
 
 
-var TestContextWithModule = TestContext.extend({
-    init: function(module, language){
-        TestContext.prototype.init.call(this, language);
-        this.root().findModule = function(){return module;};
-    }
-});
-
 function testWithModule(src, language, pass, fail){
 function testWithModule(src, language, pass, fail){
     var grammar = language.grammar;
     var grammar = language.grammar;
     return testWithSetup(
     return testWithSetup(
         function(){
         function(){
-            var imported = oc.compileModule(grammar, new Stream.Type(src), makeContext(language));
-            var module = imported.symbol().info();
+            var module = compileModule(src, language);
             return setup(function(s){
             return setup(function(s){
                 oc.compileModule(grammar,
                 oc.compileModule(grammar,
                                  new Stream.Type(s),
                                  new Stream.Type(s),
-                                 new TestContextWithModule(module, language));
+                                 new TestContext(language, function(){return module;}));
             });},
             });},
         pass,
         pass,
         fail);
         fail);
@@ -204,7 +208,16 @@ function assert(cond){
     }
     }
 }
 }
 
 
+function expectEq(x1, x2){
+    if (x1 == x2)
+        return;
+
+    throw new TestError("'" + x1 + "' != '" + x2 + "'");
+    }
+
 exports.assert = assert;
 exports.assert = assert;
+exports.expectEq = expectEq;
+
 exports.context = context;
 exports.context = context;
 exports.pass = pass;
 exports.pass = pass;
 exports.fail = fail;
 exports.fail = fail;