Explorar o código

Fix wrong code generation for vars with imported record type (Issue #15).

Vladislav Folts %!s(int64=12) %!d(string=hai) anos
pai
achega
0fff0d7f4b
Modificáronse 6 ficheiros con 128 adicións e 24 borrados
  1. 25 15
      src/context.js
  2. 4 1
      src/procedure.js
  3. 8 3
      src/type.js
  4. 56 0
      test/expected/modules.js
  5. 26 0
      test/input/modules.ob
  6. 9 5
      test/test_unit.js

+ 25 - 15
src/context.js

@@ -108,6 +108,7 @@ var ChainedContext = Class.extend({
     handleConst: function(type, value, code){this.__parent.handleConst(type, value, code);},
     handleConst: function(type, value, code){this.__parent.handleConst(type, value, code);},
     genTypeName: function(){return this.__parent.genTypeName();},
     genTypeName: function(){return this.__parent.genTypeName();},
     genVarName: function(id){return this.__parent.genVarName(id);},
     genVarName: function(id){return this.__parent.genVarName(id);},
+    qualifyScope: function(scope){return this.__parent.qualifyScope(scope);},
     rtl: function(){return this.__parent.rtl();}
     rtl: function(){return this.__parent.rtl();}
 });
 });
 
 
@@ -348,7 +349,8 @@ exports.Designator = ChainedContext.extend({
 
 
         checkTypeCast(this.__currentType, type, "invalid type cast");
         checkTypeCast(this.__currentType, type, "invalid type cast");
 
 
-        var castName = (type instanceof Type.Pointer ? type.baseType() : type).cons();
+        var baseType = type instanceof Type.Pointer ? type.baseType() : type;
+        var castName = this.qualifyScope(baseType.scope()) + baseType.cons();
         var code = this.rtl().typeGuard(this.__code.result(), castName);
         var code = this.rtl().typeGuard(this.__code.result(), castName);
         this.__code = new Code.SimpleGenerator(code);
         this.__code = new Code.SimpleGenerator(code);
 
 
@@ -603,8 +605,8 @@ exports.ArrayDecl = ChainedContext.extend({
     handleDimensions: function(dimensions){this.__dimensions = dimensions;},
     handleDimensions: function(dimensions){this.__dimensions = dimensions;},
     setType: function(type){
     setType: function(type){
         var initializer = type instanceof Type.Array || type instanceof Type.Record
         var initializer = type instanceof Type.Array || type instanceof Type.Record
-            ? "function(){return " + type.initializer() + ";}"
-            : type.initializer();
+            ? "function(){return " + type.initializer(this) + ";}"
+            : type.initializer(this);
         var dimensions = "";
         var dimensions = "";
         for(var i = 0; i < this.__dimensions.length; ++i){
         for(var i = 0; i < this.__dimensions.length; ++i){
             var length = this.__dimensions[i];
             var length = this.__dimensions[i];
@@ -1400,7 +1402,7 @@ exports.VariableDeclaration = ChainedContext.extend({
             var varName = id.id();
             var varName = id.id();
             this.currentScope().addSymbol(new Symbol.Symbol(varName, v), id.exported());
             this.currentScope().addSymbol(new Symbol.Symbol(varName, v), id.exported());
             var t = v.type();
             var t = v.type();
-            gen.write("var " + varName + " = " + t.initializer() + ";");
+            gen.write("var " + varName + " = " + t.initializer(this) + ";");
         }
         }
 
 
         gen.write("\n");
         gen.write("\n");
@@ -1532,7 +1534,7 @@ exports.RecordDecl = ChainedContext.extend({
         var parent = this.parent();
         var parent = this.parent();
         var cons = parent.genTypeName();
         var cons = parent.genTypeName();
         var name = parent.isAnonymousDeclaration() ? undefined : cons;
         var name = parent.isAnonymousDeclaration() ? undefined : cons;
-        this.__type = new Type.Record(name, cons);
+        this.__type = new Type.Record(name, cons, context.currentScope());
         parent.setType(this.__type);
         parent.setType(this.__type);
         parent.codeGenerator().write("var " + cons + " = ");
         parent.codeGenerator().write("var " + cons + " = ");
     },
     },
@@ -1562,7 +1564,7 @@ exports.RecordDecl = ChainedContext.extend({
             gen.write(baseType.name() + ".prototype.init.call(this);\n");
             gen.write(baseType.name() + ".prototype.init.call(this);\n");
         var ownFields = type.ownFields();
         var ownFields = type.ownFields();
         for(var f in ownFields)
         for(var f in ownFields)
-            gen.write("this." + f + " = " + ownFields[f].initializer() + ";\n");
+            gen.write("this." + f + " = " + ownFields[f].initializer(this) + ";\n");
 
 
         gen.closeScope();
         gen.closeScope();
         gen.closeScope(");\n");
         gen.closeScope(");\n");
@@ -1656,12 +1658,14 @@ exports.ModuleDeclaration = ChainedContext.extend({
     init: function ModuleDeclarationContext(context){
     init: function ModuleDeclarationContext(context){
         ChainedContext.prototype.init.call(this, context);
         ChainedContext.prototype.init.call(this, context);
         this.__name = undefined;
         this.__name = undefined;
-        this.__imports = [];
+        this.__imports = {};
+        this.__moduleScope = undefined;
     },
     },
     setIdent: function(id){
     setIdent: function(id){
         if (this.__name === undefined ) {
         if (this.__name === undefined ) {
             this.__name = id;
             this.__name = id;
-            this.parent().pushScope(new Scope.Module(id));
+            this.__moduleScope = new Scope.Module(id);
+            this.parent().pushScope(this.__moduleScope);
         }
         }
         else if (id === this.__name){
         else if (id === this.__name){
             var scope = this.parent().currentScope();
             var scope = this.parent().currentScope();
@@ -1672,12 +1676,13 @@ exports.ModuleDeclaration = ChainedContext.extend({
             gen.write("}(");
             gen.write("}(");
 
 
             var modules = this.__imports;
             var modules = this.__imports;
-            for(var i = 0; i < modules.length; ++i){
-                var s = modules[i];
-                if (i)
-                    gen.write(", ");
-                gen.write(s.info().name());
+            var importList = "";
+            for(var name in modules){
+                if (importList.length)
+                    importList += ", ";
+                importList += name;
             }
             }
+            gen.write(importList);
             gen.write(");\n");
             gen.write(");\n");
         }
         }
         else
         else
@@ -1694,13 +1699,18 @@ exports.ModuleDeclaration = ChainedContext.extend({
         var scope = this.currentScope();
         var scope = this.currentScope();
         for(var i = 0; i < modules.length; ++i){
         for(var i = 0; i < modules.length; ++i){
             var s = modules[i];
             var s = modules[i];
+            this.__imports[s.info().name()] = s;
             scope.addSymbol(s);
             scope.addSymbol(s);
             if (i)
             if (i)
                 gen.write(", ");
                 gen.write(", ");
             gen.write(s.id());
             gen.write(s.id());
         }
         }
         gen.write("){\n");
         gen.write("){\n");
-        this.__imports = modules;
+    },
+    qualifyScope: function(scope){
+        if (scope != this.__moduleScope && scope instanceof Scope.Module)
+            return this.__imports[scope.module().id()].id() + ".";
+        return "";
     }
     }
 });
 });
 
 
@@ -1725,7 +1735,7 @@ var ModuleImport = ChainedContext.extend({
             this.__handleImport();
             this.__handleImport();
 
 
         var modules = [];
         var modules = [];
-        var unresolved  = [];
+        var unresolved = [];
         for(var alias in this.__import){
         for(var alias in this.__import){
             var moduleName = this.__import[alias];
             var moduleName = this.__import[alias];
             var module = this.parent().findModule(moduleName);
             var module = this.parent().findModule(moduleName);

+ 4 - 1
src/procedure.js

@@ -310,7 +310,10 @@ exports.predefined = [
                 return new CheckArgumentResult(type, false);
                 return new CheckArgumentResult(type, false);
             },
             },
             epilog: function(){
             epilog: function(){
-                return " = new " + this.__baseType.cons() + "()";
+                return " = new " 
+                     + this.context().qualifyScope(this.__baseType.scope()) 
+                     + this.__baseType.cons()
+                     + "()";
             }
             }
         });
         });
 
 

+ 8 - 3
src/type.js

@@ -50,7 +50,7 @@ var BasicType = Type.extend({
     idType: function(){return "type";},
     idType: function(){return "type";},
     name: function() {return this.__name;},
     name: function() {return this.__name;},
     description: function(){return this.name();},
     description: function(){return this.name();},
-    initializer: function() {return this.__initValue;}
+    initializer: function(context){return this.__initValue;}
 });
 });
 
 
 exports.Basic = BasicType;
 exports.Basic = BasicType;
@@ -89,12 +89,17 @@ exports.ForwardRecord = Type.extend({
 });
 });
 
 
 exports.Record = BasicType.extend({
 exports.Record = BasicType.extend({
-    init: function RecordType(name, cons){
-        BasicType.prototype.init.call(this, name, "new " + cons + "()");
+    init: function RecordType(name, cons, scope){
+        BasicType.prototype.init.call(this, name);
         this.__cons = cons;        
         this.__cons = cons;        
+        this.__scope = scope;
         this.__fields = {};
         this.__fields = {};
         this.__base = undefined;
         this.__base = undefined;
     },
     },
+    initializer: function(context){
+        return "new " + context.qualifyScope(this.__scope) + this.__cons + "()";
+    },
+    scope: function(){return this.__scope;},
     cons: function(){return this.__cons;},
     cons: function(){return this.__cons;},
     addField: function(field, type){
     addField: function(field, type){
         var name = field.id();
         var name = field.id();

+ 56 - 0
test/expected/modules.js

@@ -13,13 +13,50 @@ var RTL$ = {
         result.extend = extend;
         result.extend = extend;
         return result;
         return result;
     },
     },
+    typeGuard: function (from, to){
+        if (!(from instanceof to))
+            throw new Error("typeguard assertion failed");
+        return from;
+    },
     makeRef: function (obj, prop){
     makeRef: function (obj, prop){
         return {set: function(v){ obj[prop] = v; },
         return {set: function(v){ obj[prop] = v; },
                 get: function(){ return obj[prop]; }};
                 get: function(){ return obj[prop]; }};
+    },
+    makeArray: function (/*dimensions, initializer*/){
+        var forward = Array.prototype.slice.call(arguments);
+        var result = new Array(forward.shift());
+        var i;
+        if (forward.length == 1){
+            var init = forward[0];
+            if (typeof init == "function")
+                for(i = 0; i < result.length; ++i)
+                    result[i] = init();
+            else
+                for(i = 0; i < result.length; ++i)
+                    result[i] = init;
+        }
+        else
+            for(i = 0; i < result.length; ++i)
+                result[i] = this.makeArray.apply(this, forward);
+        return result;
     }
     }
 };
 };
 var m1 = function (){
 var m1 = function (){
 var ci = 123;
 var ci = 123;
+var Base = RTL$.extend({
+	init: function Base(){
+		this.i = 0;
+	}
+});
+var T = Base.extend({
+	init: function T(){
+		Base.prototype.init.call(this);
+	}
+});
+var TPA = RTL$.extend({
+	init: function TPA(){
+	}
+});
 var i = 0;
 var i = 0;
 var anonymous$1 = RTL$.extend({
 var anonymous$1 = RTL$.extend({
 	init: function anonymous$1(){
 	init: function anonymous$1(){
@@ -33,23 +70,42 @@ function p(){
 pr = new anonymous$1();
 pr = new anonymous$1();
 return {
 return {
 	ci: ci,
 	ci: ci,
+	Base: Base,
+	T: T,
+	TP: TP,
+	TPA: TPA,
 	i: function(){return i;},
 	i: function(){return i;},
 	pr: function(){return pr;},
 	pr: function(){return pr;},
 	p: p
 	p: p
 }
 }
 }();
 }();
 var m2 = function (m1){
 var m2 = function (m1){
+var r = new m1.T();
+var pb = null;
+var ptr = null;
+var ptrA = null;
 
 
 function p(i/*INTEGER*/){
 function p(i/*INTEGER*/){
 }
 }
 
 
 function ref(i/*VAR INTEGER*/){
 function ref(i/*VAR INTEGER*/){
 }
 }
+ptr = new m1.T();
+pb = ptr;
+RTL$.typeGuard(pb, m1.T).i = 123;
+ptrA = new m1.TPA();
 m1.p();
 m1.p();
 p(m1.i());
 p(m1.i());
 p(m1.ci);
 p(m1.ci);
 ref(RTL$.makeRef(m1.pr(), "i"));
 ref(RTL$.makeRef(m1.pr(), "i"));
 }(m1);
 }(m1);
 var m3 = function (m1, m2){
 var m3 = function (m1, m2){
+var r = new m2.T();
+var a = RTL$.makeArray(3, function(){return new m2.Base();});
+var ptr = null;
+var pb = null;
+ptr = new m2.T();
+pb = ptr;
+RTL$.typeGuard(pb, m2.T).i = 123;
 m2.p();
 m2.p();
 }(m2, m1);
 }(m2, m1);

+ 26 - 0
test/input/modules.ob

@@ -1,6 +1,11 @@
 MODULE m1;
 MODULE m1;
 CONST
 CONST
     ci* = 123;
     ci* = 123;
+TYPE
+	Base* = RECORD i: INTEGER END;
+	T* = RECORD(Base) END;
+	TP* = POINTER TO T;
+	TPA* = POINTER TO RECORD END;
 VAR
 VAR
     i*: INTEGER;
     i*: INTEGER;
     pr*: POINTER TO RECORD i: INTEGER END;
     pr*: POINTER TO RECORD i: INTEGER END;
@@ -15,6 +20,12 @@ END m1.
 MODULE m2;
 MODULE m2;
 IMPORT m1;
 IMPORT m1;
 
 
+VAR 
+	r: m1.T;
+	pb: POINTER TO m1.Base;
+	ptr: m1.TP;
+	ptrA: m1.TPA;
+
 PROCEDURE p(i: INTEGER);
 PROCEDURE p(i: INTEGER);
 END p;
 END p;
 
 
@@ -22,6 +33,12 @@ PROCEDURE ref(VAR i: INTEGER);
 END ref;
 END ref;
 
 
 BEGIN
 BEGIN
+	NEW(ptr);
+	pb := ptr;
+	pb(m1.TP).i := 123;
+
+	NEW(ptrA);
+
 	m1.p();
 	m1.p();
     p(m1.i);
     p(m1.i);
     p(m1.ci);
     p(m1.ci);
@@ -30,6 +47,15 @@ END m2.
 
 
 MODULE m3;
 MODULE m3;
 IMPORT m1 := m2, m2 := m1;
 IMPORT m1 := m2, m2 := m1;
+VAR 
+    r: m2.T;
+    a: ARRAY 3 OF m2.Base;
+    ptr: m2.TP;
+    pb: POINTER TO m2.Base;
 BEGIN
 BEGIN
+    NEW(ptr);
+    pb := ptr;
+    pb(m2.TP).i := 123;
+
     m2.p();
     m2.p();
 END m3.
 END m3.

+ 9 - 5
test/test_unit.js

@@ -21,11 +21,15 @@ function parseInContext(grammar, s, context){
         throw new Errors.Error("not parsed");
         throw new Errors.Error("not parsed");
 }
 }
 
 
-function makeContext(){
-    var result = new Context.Context(Code.nullGenerator, new RTL());
-    result.pushScope(new Scope.Module("test"));
-    return result;
-}
+var TestContext = Context.Context.extend({
+    init: function TestContext(){
+        Context.Context.prototype.init.call(this, Code.nullGenerator, new RTL());
+        this.pushScope(new Scope.Module("test"));
+    },
+    qualifyScope: function(){return "";}
+});
+
+function makeContext(){return new TestContext();}
 
 
 function runAndHandleErrors(action, s, handlerError){
 function runAndHandleErrors(action, s, handlerError){
     try {
     try {