浏览代码

js -> eberon transition

Vladislav Folts 10 年之前
父节点
当前提交
d1bfc92f86
共有 6 个文件被更改,包括 133 次插入98 次删除
  1. 二进制
      bin/compiled.zip
  2. 45 57
      src/context.js
  3. 34 29
      src/eberon/eberon_context.js
  4. 52 10
      src/ob/ContextHierarchy.ob
  5. 1 1
      src/oberon/oberon_context.js
  6. 1 1
      src/oc.js

二进制
bin/compiled.zip


+ 45 - 57
src/context.js

@@ -3,6 +3,7 @@
 var Cast = require("js/Cast.js");
 var Cast = require("js/Cast.js");
 var Code = require("js/Code.js");
 var Code = require("js/Code.js");
 var CodeGenerator = require("js/CodeGenerator.js");
 var CodeGenerator = require("js/CodeGenerator.js");
+var ContextHierarchy = require("js/ContextHierarchy.js");
 var Errors = require("js/Errors.js");
 var Errors = require("js/Errors.js");
 var Module = require("js/Module.js");
 var Module = require("js/Module.js");
 var op = require("js/Operator.js");
 var op = require("js/Operator.js");
@@ -33,11 +34,11 @@ function getSymbolAndScope(context, id){
 }
 }
 
 
 function getQIdSymbolAndScope(context, q){
 function getQIdSymbolAndScope(context, q){
-    return getSymbolAndScope(q.module ? q.module : context, q.id);
+    return getSymbolAndScope(q.module ? q.module : context.root(), q.id);
 }
 }
 
 
 function getSymbol(context, id){
 function getSymbol(context, id){
-    return getSymbolAndScope(context, id).symbol();
+    return getSymbolAndScope(context.root(), id).symbol();
 }
 }
 
 
 function unwrapTypeId(type){
 function unwrapTypeId(type){
@@ -89,7 +90,7 @@ function promoteExpressionType(context, left, right){
     if (!rightType)
     if (!rightType)
         return;
         return;
 
 
-    checkImplicitCast(context.language().types, rightType, leftType);
+    checkImplicitCast(context.root().language().types, rightType, leftType);
 }
 }
 
 
 function checkTypeCast(fromInfo, fromType, toType, msg){
 function checkTypeCast(fromInfo, fromType, toType, msg){
@@ -129,23 +130,9 @@ function checkTypeCast(fromInfo, fromType, toType, msg){
                              + "' is not an extension of '" + fromType.description() + "'");
                              + "' is not an extension of '" + fromType.description() + "'");
 }
 }
 
 
-var ChainedContext = Class.extend({
-    init: function ChainedContext(parent){
-        this.__parent = parent;
-        this.attributes = parent.attributes;
-    },
-    parent: function(){return this.__parent;},
-    handleMessage: function(msg){return this.__parent.handleMessage(msg);},
-    language: function(){return this.__parent.language();},
-    codeGenerator: function(){return this.__parent.codeGenerator();},
-    findSymbol: function(id){return this.__parent.findSymbol(id);},
-    currentScope: function(s){return this.__parent.currentScope();},
-    pushScope: function(scope){this.__parent.pushScope(scope);},
-    popScope: function(){this.__parent.popScope();},
-    qualifyScope: function(scope){return this.__parent.qualifyScope(scope);},
-    handleLiteral: function(s){},
-    genTypeName: function(){return this.__parent.genTypeName();}
-});
+var ChainedContext = ContextHierarchy.Node;
+ChainedContext.extend = Class.extend;
+ChainedContext.prototype.init = ContextHierarchy.Node;
 
 
 exports.Integer = ChainedContext.extend({
 exports.Integer = ChainedContext.extend({
     init: function IntegerContext(context){
     init: function IntegerContext(context){
@@ -247,7 +234,7 @@ exports.QualifiedIdentificatorModule = ChainedContext.extend({
         this.__id = id;
         this.__id = id;
     },
     },
     endParse: function(){
     endParse: function(){
-        var found = this.findSymbol(this.__id);
+        var found = this.root().findSymbol(this.__id);
         if (!found)
         if (!found)
             return false;
             return false;
         var s = found.symbol();
         var s = found.symbol();
@@ -303,7 +290,7 @@ function castCode(type, context){
 }
 }
 
 
 function makeContext(context){
 function makeContext(context){
-    var l = context.language();
+    var l = context.root().language();
     return {
     return {
         types: l.types, 
         types: l.types, 
         rtl: l.rtl, 
         rtl: l.rtl, 
@@ -356,7 +343,7 @@ exports.Designator = ChainedContext.extend({
         }
         }
         var field = t.denote(id, isReadOnly);
         var field = t.denote(id, isReadOnly);
         var currentType = field.type();
         var currentType = field.type();
-        var language = this.language();
+        var language = this.root().language();
         var cx = makeContext(this);
         var cx = makeContext(this);
         var fieldCode = field.designatorCode(this.__code, cx);
         var fieldCode = field.designatorCode(this.__code, cx);
         this.__derefCode = fieldCode.derefCode;
         this.__derefCode = fieldCode.derefCode;
@@ -426,7 +413,7 @@ exports.Designator = ChainedContext.extend({
 
 
         return { length: length,
         return { length: length,
                  type: indexType,
                  type: indexType,
-                 info: new Type.PropertyVariable(indexType, leadCode, indexCode, info instanceof Type.Const || info.isReadOnly(), this.language().rtl),
+                 info: new Type.PropertyVariable(indexType, leadCode, indexCode, info instanceof Type.Const || info.isReadOnly(), this.root().language().rtl),
                  code: code,
                  code: code,
                  lval: lval,
                  lval: lval,
                  asProperty: indexCode
                  asProperty: indexCode
@@ -462,7 +449,7 @@ exports.Designator = ChainedContext.extend({
     handleTypeCast: function(type){
     handleTypeCast: function(type){
         checkTypeCast(this.__info, this.__currentType, type, "type cast");
         checkTypeCast(this.__info, this.__currentType, type, "type cast");
 
 
-        var code = this.language().rtl.typeGuard(this.__code, castCode(type, this));
+        var code = this.root().language().rtl.typeGuard(this.__code, castCode(type, this));
         this.__code = code;
         this.__code = code;
 
 
         this.__currentType = type;
         this.__currentType = type;
@@ -500,7 +487,7 @@ exports.FormalType = HandleSymbolAsType.extend({
     },
     },
     setType: function(type){           
     setType: function(type){           
         for(var i = 0; i < this.__arrayDimension; ++i)
         for(var i = 0; i < this.__arrayDimension; ++i)
-            type = new (this.language().types.OpenArray)(type);
+            type = new (this.root().language().types.OpenArray)(type);
         this.parent().setType(type);
         this.parent().setType(type);
 
 
     },
     },
@@ -587,13 +574,14 @@ exports.ProcDecl = ChainedContext.extend({
         this.__firstArgument = true;
         this.__firstArgument = true;
         this.__type = undefined;
         this.__type = undefined;
         this.__returnParsed = false;
         this.__returnParsed = false;
-        this.__outerScope = this.parent().currentScope();
-        this.__stdSymbols = this.language().stdSymbols;
+        var root = this.root();
+        this.__outerScope = root.currentScope();
+        this.__stdSymbols = root.language().stdSymbols;
     },
     },
     handleIdentdef: function(id){
     handleIdentdef: function(id){
         this.__id = id;
         this.__id = id;
         this.codeGenerator().write(this._prolog());
         this.codeGenerator().write(this._prolog());
-        this.parent().pushScope(Scope.makeProcedure(this.__stdSymbols));
+        this.root().pushScope(Scope.makeProcedure(this.__stdSymbols));
     },
     },
     handleIdent: function(id){
     handleIdent: function(id){
         if (this.__id.id() != id)
         if (this.__id.id() != id)
@@ -619,7 +607,7 @@ exports.ProcDecl = ChainedContext.extend({
             throw new Errors.Error("argument '" + name + "' has the same name as procedure");
             throw new Errors.Error("argument '" + name + "' has the same name as procedure");
         var v = this._makeArgumentVariable(arg, name);
         var v = this._makeArgumentVariable(arg, name);
         var s = new Symbol.Symbol(name, v);
         var s = new Symbol.Symbol(name, v);
-        this.currentScope().addSymbol(s);
+        this.root().currentScope().addSymbol(s);
 
 
         var code = this.codeGenerator();
         var code = this.codeGenerator();
         if (!this.__firstArgument)
         if (!this.__firstArgument)
@@ -647,7 +635,7 @@ exports.ProcDecl = ChainedContext.extend({
         if (!result)
         if (!result)
             throw new Errors.Error("unexpected RETURN in PROCEDURE declared with no result type");
             throw new Errors.Error("unexpected RETURN in PROCEDURE declared with no result type");
         
         
-        var language = this.language();
+        var language = this.root().language();
         var op;
         var op;
         if (language.types.implicitCast(type, result, false, {set: function(v){op = v;}, get:function(){return op;}}))
         if (language.types.implicitCast(type, result, false, {set: function(v){op = v;}, get:function(){return op;}}))
             throw new Errors.Error(
             throw new Errors.Error(
@@ -660,7 +648,7 @@ exports.ProcDecl = ChainedContext.extend({
     },
     },
     endParse: function(){
     endParse: function(){
         this.codeGenerator().closeScope("");
         this.codeGenerator().closeScope("");
-        this.parent().popScope();
+        this.root().popScope();
 
 
         var result = this.__type.result();
         var result = this.__type.result();
         if (result && !this.__returnParsed)
         if (result && !this.__returnParsed)
@@ -714,7 +702,7 @@ exports.PointerDecl = ChainedContext.extend({
         var id = q.id;
         var id = q.id;
         var s = q.module
         var s = q.module
               ? getQIdSymbolAndScope(this, q)
               ? getQIdSymbolAndScope(this, q)
-              : this.findSymbol(id);
+              : this.root().findSymbol(id);
         
         
         var info = s ? s.symbol().info()
         var info = s ? s.symbol().info()
                      : this.parent().handleMessage(new ForwardTypeMsg(id));
                      : this.parent().handleMessage(new ForwardTypeMsg(id));
@@ -738,7 +726,7 @@ exports.PointerDecl = ChainedContext.extend({
     },
     },
     setType: function(type){
     setType: function(type){
         var typeId = new Type.TypeId(type);
         var typeId = new Type.TypeId(type);
-        this.currentScope().addFinalizer(function(){typeId.strip();});
+        this.root().currentScope().addFinalizer(function(){typeId.strip();});
         this.__setTypeId(typeId);
         this.__setTypeId(typeId);
     },
     },
     isAnonymousDeclaration: function(){return true;},
     isAnonymousDeclaration: function(){return true;},
@@ -769,7 +757,7 @@ exports.ArrayDecl = HandleSymbolAsType.extend({
     isAnonymousDeclaration: function(){return true;},
     isAnonymousDeclaration: function(){return true;},
     endParse: function(){this.parent().setType(this.__type);},
     endParse: function(){this.parent().setType(this.__type);},
     _makeInit: function(type, dimensions, length){
     _makeInit: function(type, dimensions, length){
-        var rtl = this.language().rtl;
+        var rtl = this.root().language().rtl;
         if (type == basicTypes.ch)
         if (type == basicTypes.ch)
             return rtl.makeCharArray(dimensions);
             return rtl.makeCharArray(dimensions);
 
 
@@ -779,7 +767,7 @@ exports.ArrayDecl = HandleSymbolAsType.extend({
         return rtl.makeArray(dimensions + ", " + initializer);
         return rtl.makeArray(dimensions + ", " + initializer);
     },
     },
     _makeType: function(elementsType, init, length){
     _makeType: function(elementsType, init, length){
-        return new (this.language().types.StaticArray)(init, elementsType, length);
+        return new (this.root().language().types.StaticArray)(init, elementsType, length);
     }
     }
 });
 });
 
 
@@ -941,7 +929,7 @@ function checkSetHasBit(leftType, rightType, context){
     if (!Type.isInt(leftType))
     if (!Type.isInt(leftType))
         throw new Errors.Error(
         throw new Errors.Error(
             Type.intsDescription() + " expected as an element of SET, got '" + Type.typeName(leftType) + "'");
             Type.intsDescription() + " expected as an element of SET, got '" + Type.typeName(leftType) + "'");
-    checkImplicitCast(context.language().types, rightType, basicTypes.set);
+    checkImplicitCast(context.root().language().types, rightType, basicTypes.set);
 }
 }
 
 
 function relationOp(leftType, rightType, literal, ops, context){
 function relationOp(leftType, rightType, literal, ops, context){
@@ -1187,7 +1175,7 @@ exports.Set = ChainedContext.extend({
         if (!this.__expr.length)
         if (!this.__expr.length)
             parent.handleConst(basicTypes.set, Code.makeSetConst(this.__value), this.__value.toString());
             parent.handleConst(basicTypes.set, Code.makeSetConst(this.__value), this.__value.toString());
         else{
         else{
-            var code = this.language().rtl.makeSet(this.__expr);
+            var code = this.root().language().rtl.makeSet(this.__expr);
             if (this.__value)
             if (this.__value)
                 code += " | " + this.__value;
                 code += " | " + this.__value;
             var e = Code.makeExpression(code, basicTypes.set);
             var e = Code.makeExpression(code, basicTypes.set);
@@ -1264,7 +1252,7 @@ exports.SimpleExpression = ChainedContext.extend({
         if (type === undefined || this.__type === undefined)
         if (type === undefined || this.__type === undefined)
             this.__type = type;
             this.__type = type;
         else
         else
-            checkImplicitCast(this.language().types, type, this.__type);
+            checkImplicitCast(this.root().language().types, type, this.__type);
     },
     },
     handleBinaryOperator: function(o){this.__binaryOperator = o;},
     handleBinaryOperator: function(o){this.__binaryOperator = o;},
     endParse: function(){
     endParse: function(){
@@ -1291,7 +1279,7 @@ exports.Expression = ChainedContext.extend({
         rightExpression = promoteTypeInExpression(rightExpression, leftExpression.type());
         rightExpression = promoteTypeInExpression(rightExpression, leftExpression.type());
 
 
         var o = this._relationOperation(leftExpression.type(), rightExpression.type(), this.__relation);
         var o = this._relationOperation(leftExpression.type(), rightExpression.type(), this.__relation);
-        this.__expression = o(leftExpression, rightExpression, this.language());
+        this.__expression = o(leftExpression, rightExpression, this.root().language());
     },
     },
     _relationOperation: function(left, right, relation){
     _relationOperation: function(left, right, relation){
         return relationOp(left, right, relation, this.__relOps, this);
         return relationOp(left, right, relation, this.__relOps, this);
@@ -1366,7 +1354,7 @@ exports.Case = ChainedContext.extend({
         ChainedContext.prototype.init.call(this, context);
         ChainedContext.prototype.init.call(this, context);
         this.__type = undefined;
         this.__type = undefined;
         this.__firstCase = true;
         this.__firstCase = true;
-        this.__var = this.currentScope().generateTempVar("case");
+        this.__var = this.root().currentScope().generateTempVar("case");
         this.codeGenerator().write("var " + this.__var + " = ");
         this.codeGenerator().write("var " + this.__var + " = ");
     },
     },
     caseVar: function(){return this.__var;},
     caseVar: function(){return this.__var;},
@@ -1636,7 +1624,7 @@ exports.ConstDecl = ChainedContext.extend({
     },
     },
     endParse: function(){
     endParse: function(){
         var c = new Type.Const(this.__type, this.__value);
         var c = new Type.Const(this.__type, this.__value);
-        this.currentScope().addSymbol(new Symbol.Symbol(this.__id.id(), c), this.__id.exported());
+        this.root().currentScope().addSymbol(new Symbol.Symbol(this.__id.id(), c), this.__id.exported());
         this.codeGenerator().write(";\n");
         this.codeGenerator().write(";\n");
     }
     }
 });
 });
@@ -1684,7 +1672,7 @@ exports.VariableDeclaration = HandleSymbolAsType.extend({
                 this.checkExport(varName);
                 this.checkExport(varName);
 
 
             var v = new Type.DeclaredVariable(varName, this.__type);
             var v = new Type.DeclaredVariable(varName, this.__type);
-            this.currentScope().addSymbol(new Symbol.Symbol(varName, v), id.exported());
+            this.root().currentScope().addSymbol(new Symbol.Symbol(varName, v), id.exported());
             gen.write("var " + varName + " = " + this._initCode() + ";");
             gen.write("var " + varName + " = " + this._initCode() + ";");
         }
         }
 
 
@@ -1768,7 +1756,7 @@ exports.RecordDecl = ChainedContext.extend({
         var parent = this.parent();
         var parent = this.parent();
         this.__cons = parent.genTypeName();
         this.__cons = parent.genTypeName();
         var name = parent.isAnonymousDeclaration() ? "" : this.__cons;
         var name = parent.isAnonymousDeclaration() ? "" : this.__cons;
-        this.__type = new RecordCons(name, this.__cons, context.currentScope());
+        this.__type = new RecordCons(name, this.__cons, context.root().currentScope());
         parent.setType(this.__type);
         parent.setType(this.__type);
     },
     },
     type: function(){return this.__type;},
     type: function(){return this.__type;},
@@ -1834,7 +1822,7 @@ exports.RecordDecl = ChainedContext.extend({
         if (!base)
         if (!base)
             return "";
             return "";
         var qualifiedBase = this.qualifyScope(Type.recordScope(base)) + Type.typeName(base); 
         var qualifiedBase = this.qualifyScope(Type.recordScope(base)) + Type.typeName(base); 
-        return this.language().rtl.extend(this.__cons, qualifiedBase) + ";\n";
+        return this.root().language().rtl.extend(this.__cons, qualifiedBase) + ";\n";
     },
     },
     _makeField: function(field, type){
     _makeField: function(field, type){
         return new Type.RecordField(field, type);
         return new Type.RecordField(field, type);
@@ -1850,15 +1838,16 @@ exports.TypeDeclaration = ChainedContext.extend({
     handleIdentdef: function(id){
     handleIdentdef: function(id){
         var typeId = new Type.LazyTypeId();
         var typeId = new Type.LazyTypeId();
         var symbol = new Symbol.Symbol(id.id(), typeId);
         var symbol = new Symbol.Symbol(id.id(), typeId);
-        this.currentScope().addSymbol(symbol, id.exported());
+        var scope = this.root().currentScope();
+        scope.addSymbol(symbol, id.exported());
         if (!id.exported())
         if (!id.exported())
-            this.currentScope().addFinalizer(function(){typeId.strip();});
+            scope.addFinalizer(function(){typeId.strip();});
         this.__id = id;
         this.__id = id;
         this.__symbol = symbol;
         this.__symbol = symbol;
     },
     },
     setType: function(type){
     setType: function(type){
         Type.defineTypeId(this.__symbol.info(), type);
         Type.defineTypeId(this.__symbol.info(), type);
-        Scope.resolve(this.currentScope(), this.__symbol);
+        Scope.resolve(this.root().currentScope(), this.__symbol);
     },
     },
     typeName: function(){return this.__id.id();},
     typeName: function(){return this.__id.id();},
     id: function(){return this.__id;},
     id: function(){return this.__id;},
@@ -1876,7 +1865,7 @@ exports.TypeSection = ChainedContext.extend({
     },
     },
     handleMessage: function(msg){
     handleMessage: function(msg){
         if (msg instanceof ForwardTypeMsg){
         if (msg instanceof ForwardTypeMsg){
-            var scope = this.currentScope();
+            var scope = this.root().currentScope();
             Scope.addUnresolved(scope, msg.id);
             Scope.addUnresolved(scope, msg.id);
             var resolve = function(){return getSymbol(this, msg.id).info().type();}.bind(this);
             var resolve = function(){return getSymbol(this, msg.id).info().type();}.bind(this);
 
 
@@ -1885,7 +1874,7 @@ exports.TypeSection = ChainedContext.extend({
         return ChainedContext.prototype.handleMessage.call(this, msg);
         return ChainedContext.prototype.handleMessage.call(this, msg);
     },
     },
     endParse: function(){
     endParse: function(){
-        var unresolved = Scope.unresolved(this.currentScope());
+        var unresolved = Scope.unresolved(this.root().currentScope());
         if (unresolved.length)
         if (unresolved.length)
             throw new Errors.Error("no declaration found for '" + unresolved.join("', '") + "'");
             throw new Errors.Error("no declaration found for '" + unresolved.join("', '") + "'");
     }
     }
@@ -1918,17 +1907,16 @@ exports.ModuleDeclaration = ChainedContext.extend({
         this.__imports = {};
         this.__imports = {};
         this.__moduleScope = undefined;
         this.__moduleScope = undefined;
         this.__moduleGen = undefined;
         this.__moduleGen = undefined;
-        this.__stdSymbols = this.language().stdSymbols;
+        this.__stdSymbols = this.root().language().stdSymbols;
     },
     },
     handleIdent: function(id){
     handleIdent: function(id){
-        var parent = this.parent();
         if (this.__name === undefined ) {
         if (this.__name === undefined ) {
             this.__name = id;
             this.__name = id;
             this.__moduleScope = new Scope.Module(id, this.__stdSymbols);
             this.__moduleScope = new Scope.Module(id, this.__stdSymbols);
-            parent.pushScope(this.__moduleScope);
+            this.root().pushScope(this.__moduleScope);
         }
         }
         else if (id === this.__name){
         else if (id === this.__name){
-            var scope = parent.currentScope();
+            var scope = this.root().currentScope();
             scope.close();
             scope.close();
             var exports = scope.exports;
             var exports = scope.exports;
             Scope.defineExports(Scope.moduleSymbol(scope).info(), exports);
             Scope.defineExports(Scope.moduleSymbol(scope).info(), exports);
@@ -1943,7 +1931,7 @@ exports.ModuleDeclaration = ChainedContext.extend({
         return this.parent().findModule(name);
         return this.parent().findModule(name);
     },
     },
     handleImport: function(modules){
     handleImport: function(modules){
-        var scope = this.currentScope();
+        var scope = this.root().currentScope();
         var moduleAliases = {};
         var moduleAliases = {};
         for(var i = 0; i < modules.length; ++i){
         for(var i = 0; i < modules.length; ++i){
             var s = modules[i];
             var s = modules[i];
@@ -1952,7 +1940,7 @@ exports.ModuleDeclaration = ChainedContext.extend({
             scope.addSymbol(s);
             scope.addSymbol(s);
             moduleAliases[name] = s.id();
             moduleAliases[name] = s.id();
         }
         }
-        this.__moduleGen = this.parent().language().moduleGenerator(
+        this.__moduleGen = this.root().language().moduleGenerator(
                 this.__name,
                 this.__name,
                 moduleAliases);
                 moduleAliases);
         this.codeGenerator().write(this.__moduleGen.prolog());
         this.codeGenerator().write(this.__moduleGen.prolog());
@@ -2028,7 +2016,7 @@ exports.ModuleImport = ModuleImport;
 
 
 function makeProcCall(context, type, info){
 function makeProcCall(context, type, info){
     assertProcType(type, info);
     assertProcType(type, info);
-    var l = context.language();
+    var l = context.root().language();
     return type.callGenerator(
     return type.callGenerator(
         { types: l.types, 
         { types: l.types, 
           rtl: l.rtl, 
           rtl: l.rtl, 

+ 34 - 29
src/eberon/eberon_context.js

@@ -46,13 +46,13 @@ var ProcOrMethodId = Context.Chained.extend({
     },
     },
     handleIdent: function(id){this.__maybeTypeId = id;},
     handleIdent: function(id){this.__maybeTypeId = id;},
     handleLiteral: function(s){
     handleLiteral: function(s){
-        var ss = Context.getSymbolAndScope(this, this.__maybeTypeId);
+        var ss = Context.getSymbolAndScope(this.root(), this.__maybeTypeId);
         var type = Context.unwrapType(ss.symbol().info());
         var type = Context.unwrapType(ss.symbol().info());
         if (!(type instanceof Type.Record))
         if (!(type instanceof Type.Record))
             throw new Errors.Error(
             throw new Errors.Error(
                   "RECORD type expected in method declaration, got '"
                   "RECORD type expected in method declaration, got '"
                 + type.description() + "'");
                 + type.description() + "'");
-        if (ss.scope() != this.currentScope())
+        if (ss.scope() != this.root().currentScope())
             throw new Errors.Error(
             throw new Errors.Error(
                   "method should be defined in the same scope as its bound type '"
                   "method should be defined in the same scope as its bound type '"
                 + this.__maybeTypeId
                 + this.__maybeTypeId
@@ -248,7 +248,7 @@ var Designator = Context.Designator.extend({
 
 
         if (currentType instanceof EberonMap.Type){
         if (currentType instanceof EberonMap.Type){
             var indexType = currentType.valueType;
             var indexType = currentType.valueType;
-            var rval = this.language().rtl.getMappedValue(code, indexCode);
+            var rval = this.root().language().rtl.getMappedValue(code, indexCode);
             return { length: undefined, 
             return { length: undefined, 
                      type: indexType,
                      type: indexType,
                      info: new MapElementVariable(indexType, info.isReadOnly(), rval),
                      info: new MapElementVariable(indexType, info.isReadOnly(), rval),
@@ -390,7 +390,7 @@ var InPlaceVariableInit = Context.Chained.extend({
         if (type instanceof Type.Record){
         if (type instanceof Type.Record){
             EberonRecord.ensureCanBeInstantiated(this, type, EberonRecord.instantiateForCopy);
             EberonRecord.ensureCanBeInstantiated(this, type, EberonRecord.instantiateForCopy);
             if (e.designator()){
             if (e.designator()){
-                var l = this.language();
+                var l = this.root().language();
                 this._code += l.rtl.clone(e.code(), l.types.typeInfo(type));
                 this._code += l.rtl.clone(e.code(), l.types.typeInfo(type));
             }
             }
             else // do not clone if it is temporary, e.g. constructor call
             else // do not clone if it is temporary, e.g. constructor call
@@ -400,7 +400,7 @@ var InPlaceVariableInit = Context.Chained.extend({
             if (type instanceof Type.OpenArray)
             if (type instanceof Type.OpenArray)
                 throw new Errors.Error("cannot initialize variable '" + this.__id + "' with open array");
                 throw new Errors.Error("cannot initialize variable '" + this.__id + "' with open array");
           
           
-            var language = this.language();
+            var language = this.root().language();
             var cloneOp;
             var cloneOp;
             language.types.implicitCast(type, type, false, {set: function(v){cloneOp = v;}, get:function(){return cloneOp;}});
             language.types.implicitCast(type, type, false, {set: function(v){cloneOp = v;}, get:function(){return cloneOp;}});
             this._code += cloneOp.clone(language, e);
             this._code += cloneOp.clone(language, e);
@@ -413,7 +413,7 @@ var InPlaceVariableInit = Context.Chained.extend({
         if (!this._symbol)
         if (!this._symbol)
             return false;
             return false;
 
 
-        this.currentScope().addSymbol(this._symbol);
+        this.root().currentScope().addSymbol(this._symbol);
         this._onParsed();
         this._onParsed();
         return true;
         return true;
     }
     }
@@ -1068,12 +1068,13 @@ var OperatorScopes = Class.extend({
         this.__ignorePromotions = true;
         this.__ignorePromotions = true;
     },
     },
     alternate: function(){
     alternate: function(){
+        var root = this.__context.root();
         if (this.__scope)
         if (this.__scope)
-            this.__context.popScope();
+            root.popScope();
         this.__scope = EberonScope.makeOperator(
         this.__scope = EberonScope.makeOperator(
-            this.__context.currentScope(),
-            this.__context.language().stdSymbols);
-        this.__context.pushScope(this.__scope);
+            root.currentScope(),
+            root.language().stdSymbols);
+        root.pushScope(this.__scope);
 
 
         if (this.__typePromotion){
         if (this.__typePromotion){
             this.__typePromotion.reset();
             this.__typePromotion.reset();
@@ -1083,7 +1084,7 @@ var OperatorScopes = Class.extend({
         this.__ignorePromotions = false;
         this.__ignorePromotions = false;
     },
     },
     reset: function(){
     reset: function(){
-        this.__context.popScope();
+        this.__context.root().popScope();
         for(var i = 0; i < this.__typePromotions.length; ++i){
         for(var i = 0; i < this.__typePromotions.length; ++i){
             this.__typePromotions[i].reset();
             this.__typePromotions[i].reset();
         }
         }
@@ -1144,14 +1145,15 @@ var CaseLabel = Context.CaseLabel.extend({
     },
     },
     handleLiteral: function(s){
     handleLiteral: function(s){
         if (s == ':'){ // statement sequence is expected now
         if (s == ':'){ // statement sequence is expected now
+            var root = this.root();
             var scope = EberonScope.makeOperator(
             var scope = EberonScope.makeOperator(
-                this.parent().currentScope(),
-                this.language().stdSymbols);
-            this.pushScope(scope);
+                root.currentScope(),
+                root.language().stdSymbols);
+            root.pushScope(scope);
         }
         }
     },
     },
     endParse: function(){
     endParse: function(){
-        this.popScope();
+        this.root().popScope();
         Context.CaseLabel.prototype.endParse.call(this);
         Context.CaseLabel.prototype.endParse.call(this);
     }
     }
 });
 });
@@ -1159,13 +1161,14 @@ var CaseLabel = Context.CaseLabel.extend({
 var Repeat = Context.Repeat.extend({
 var Repeat = Context.Repeat.extend({
     init: function EberonContext$Repeat(context){
     init: function EberonContext$Repeat(context){
         Context.Repeat.prototype.init.call(this, context);
         Context.Repeat.prototype.init.call(this, context);
+        var root = this.root();
         var scope = EberonScope.makeOperator(
         var scope = EberonScope.makeOperator(
-            this.parent().currentScope(),
-            this.language().stdSymbols);
-        this.pushScope(scope);
+            root.currentScope(),
+            root.language().stdSymbols);
+        root.pushScope(scope);
     },
     },
     endParse: function(){
     endParse: function(){
-        this.popScope();
+        this.root().popScope();
         //Context.Repeat.prototype.endParse.call(this);
         //Context.Repeat.prototype.endParse.call(this);
     }
     }
 });
 });
@@ -1175,17 +1178,18 @@ var Return = Context.Return;
 var For = Context.For.extend({
 var For = Context.For.extend({
     init: function EberonContext$Repeat(context){
     init: function EberonContext$Repeat(context){
         Context.For.prototype.init.call(this, context);
         Context.For.prototype.init.call(this, context);
+        var root = this.root();
         var scope = EberonScope.makeOperator(
         var scope = EberonScope.makeOperator(
-            this.parent().currentScope(),
-            this.language().stdSymbols);
-        this.pushScope(scope);
+            root.currentScope(),
+            root.language().stdSymbols);
+        root.pushScope(scope);
     },
     },
     handleInPlaceInit: function(symbol, code){
     handleInPlaceInit: function(symbol, code){
         this._handleInitCode(symbol.id(), "for (" + code);
         this._handleInitCode(symbol.id(), "for (" + code);
         this._handleInitExpression(symbol.info().type());
         this._handleInitExpression(symbol.info().type());
     },
     },
     endParse: function(){
     endParse: function(){
-        this.popScope();
+        this.root().popScope();
         Context.For.prototype.endParse.call(this);
         Context.For.prototype.endParse.call(this);
     }
     }
 });
 });
@@ -1246,14 +1250,15 @@ var ForEach = Context.Chained.extend({
             throw new Errors.Error("expression of type MAP is expected in FOR, got '" 
             throw new Errors.Error("expression of type MAP is expected in FOR, got '" 
                                  + type.description() + "'");
                                  + type.description() + "'");
 
 
+        var root = this.root();
         var scope = EberonScope.makeOperator(
         var scope = EberonScope.makeOperator(
-            this.parent().currentScope(),
-            this.language().stdSymbols);
-        this.pushScope(scope);
+            root.currentScope(),
+            root.language().stdSymbols);
+        root.pushScope(scope);
         this.__scopeWasCreated = true;
         this.__scopeWasCreated = true;
 
 
         var code = this.parent().codeGenerator();
         var code = this.parent().codeGenerator();
-        var mapVar = this.currentScope().generateTempVar("map");
+        var mapVar = root.currentScope().generateTempVar("map");
         code.write("var " + mapVar + " = " + e.code() + ";\n");
         code.write("var " + mapVar + " = " + e.code() + ";\n");
         code.write("for(var " + this.__keyId + " in " + mapVar + ")");
         code.write("for(var " + this.__keyId + " in " + mapVar + ")");
         code.openScope();
         code.openScope();
@@ -1266,7 +1271,7 @@ var ForEach = Context.Chained.extend({
     endParse: function(){
     endParse: function(){
         this.__codeGenerator.closeScope("");
         this.__codeGenerator.closeScope("");
         if (this.__scopeWasCreated)
         if (this.__scopeWasCreated)
-            this.popScope();
+            this.root().popScope();
     },
     },
     __makeVariable: function(id, type, scope){
     __makeVariable: function(id, type, scope){
         var v = new ForEachVariable(type);
         var v = new ForEachVariable(type);
@@ -1335,7 +1340,7 @@ var FormalType = Context.HandleSymbolAsType.extend({
         for(var i = this.__arrayDimensions.length; i--;){
         for(var i = this.__arrayDimensions.length; i--;){
             var Cons = this.__arrayDimensions[i]
             var Cons = this.__arrayDimensions[i]
                 ? EberonDynamicArray.DynamicArray
                 ? EberonDynamicArray.DynamicArray
-                : this.language().types.OpenArray;
+                : this.root().language().types.OpenArray;
             type = new Cons(type);
             type = new Cons(type);
         }
         }
         this.parent().setType(type);
         this.parent().setType(type);

+ 52 - 10
src/ob/ContextHierarchy.ob

@@ -4,25 +4,41 @@ TYPE
     PRoot = POINTER TO Root;
     PRoot = POINTER TO Root;
     PNode = POINTER TO Node;
     PNode = POINTER TO Node;
 
 
+    Language = RECORD
+        moduleResolver: PROCEDURE(name: STRING): Module.PType;
+        codeGenerator: CodeGenerator.PIGenerator;
+    END;
+    PLanguage = POINTER TO Language;
+
+    Message = RECORD
+    END;
+
+    PMessageResult = POINTER TO RECORD
+    END;
+
+    Attributes = POINTER TO RECORD
+    END;
+
     Node* = RECORD
     Node* = RECORD
+        PROCEDURE Node(parent: PNode);
+
         PROCEDURE root(): PRoot;
         PROCEDURE root(): PRoot;
         PROCEDURE parent(): PNode;
         PROCEDURE parent(): PNode;
+        PROCEDURE handleMessage(VAR msg: Message): PMessageResult;
+        PROCEDURE codeGenerator(): CodeGenerator.PIGenerator;
+        PROCEDURE qualifyScope(scope: Scope.PType): STRING;
+        PROCEDURE handleLiteral(s: STRING);
+        PROCEDURE genTypeName(): STRING;
 
 
         mParent: PNode;
         mParent: PNode;
+        attributes: Attributes;
     END;
     END;
 
 
-    Language = RECORD
-        moduleResolver: PROCEDURE(name: STRING): Module.PType;
-        codeGenerator: CodeGenerator.PIGenerator;
-    END;
-    PLanguage = POINTER TO Language;
-
     Root* = RECORD(Node)
     Root* = RECORD(Node)
         PROCEDURE Root(language: PLanguage);
         PROCEDURE Root(language: PLanguage);
 
 
         PROCEDURE language(): PLanguage;
         PROCEDURE language(): PLanguage;
 
 
-        PROCEDURE genTypeName(): STRING;
         PROCEDURE findSymbol(ident: STRING): Symbols.PFoundSymbol;
         PROCEDURE findSymbol(ident: STRING): Symbols.PFoundSymbol;
         PROCEDURE findModule(name: STRING): Module.PType;
         PROCEDURE findModule(name: STRING): Module.PType;
 
 
@@ -30,13 +46,19 @@ TYPE
         PROCEDURE pushScope(scope: Scope.PType);
         PROCEDURE pushScope(scope: Scope.PType);
         PROCEDURE popScope();
         PROCEDURE popScope();
 
 
-        PROCEDURE codeGenerator(): CodeGenerator.PIGenerator;
-
         mLanguage: PLanguage;
         mLanguage: PLanguage;
         scopes: ARRAY * OF Scope.PType;
         scopes: ARRAY * OF Scope.PType;
         gen: INTEGER;
         gen: INTEGER;
     END;
     END;
 
 
+PROCEDURE Node.Node(parent: PNode)
+    | mParent(parent);
+BEGIN
+    IF parent # NIL THEN
+        SELF.attributes := parent.attributes;
+    END;
+END;
+
 PROCEDURE Node.root(): PRoot;
 PROCEDURE Node.root(): PRoot;
     RETURN SELF.mParent.root();
     RETURN SELF.mParent.root();
 END;
 END;
@@ -45,8 +67,28 @@ PROCEDURE Node.parent(): PNode;
     RETURN SELF.mParent;
     RETURN SELF.mParent;
 END;
 END;
 
 
+PROCEDURE Node.handleMessage(VAR msg: Message): PMessageResult;
+    RETURN SELF.mParent.handleMessage(msg);
+END;
+
+PROCEDURE Node.codeGenerator(): CodeGenerator.PIGenerator;
+    RETURN SELF.mParent.codeGenerator();
+END;
+
+PROCEDURE Node.qualifyScope(scope: Scope.PType): STRING;
+    RETURN SELF.mParent.qualifyScope(scope);
+END;
+
+PROCEDURE Node.handleLiteral(s: STRING);
+END;
+
+PROCEDURE Node.genTypeName(): STRING;
+    RETURN SELF.mParent.genTypeName();
+END;
+
 PROCEDURE Root.Root(language: PLanguage)
 PROCEDURE Root.Root(language: PLanguage)
-    | mLanguage(language);
+    | SUPER(NIL),
+      mLanguage(language);
 END;
 END;
 
 
 PROCEDURE Root.language(): PLanguage;
 PROCEDURE Root.language(): PLanguage;

+ 1 - 1
src/oberon/oberon_context.js

@@ -102,7 +102,7 @@ var Assignment = Context.Chained.extend({
     handleExpression: function(e){
     handleExpression: function(e){
         var d = this.attributes.designator;
         var d = this.attributes.designator;
         var left = Code.makeExpression(d.code(), d.type(), d);
         var left = Code.makeExpression(d.code(), d.type(), d);
-        this.parent().codeGenerator().write(op.assign(left, e, this.language()));
+        this.parent().codeGenerator().write(op.assign(left, e, this.root().language()));
     }
     }
 });
 });
 
 

+ 1 - 1
src/oc.js

@@ -37,7 +37,7 @@ function compileModule(grammar, stream, context, handleErrors){
             x.message = "internal compiler error while parsing line " + Stream.lineNumber(stream) + ": " + Stream.currentLine(stream) + "\n" + x.message;
             x.message = "internal compiler error while parsing line " + Stream.lineNumber(stream) + ": " + Stream.currentLine(stream) + "\n" + x.message;
         throw x;
         throw x;
     }
     }
-    var scope = context.currentScope();
+    var scope = context.root().currentScope();
     return new CompiledModule(
     return new CompiledModule(
             Scope.moduleSymbol(scope),
             Scope.moduleSymbol(scope),
             context.codeGenerator().result(),
             context.codeGenerator().result(),