Vladislav Folts пре 11 година
родитељ
комит
c68d387ee9
13 измењених фајлова са 555 додато и 153 уклоњено
  1. 10 10
      src/context.js
  2. 19 2
      src/js/JsArray.js
  3. 2 2
      src/js/JsMap.js
  4. 223 0
      src/js/Scope.js
  5. 2 1
      src/js/Types.js
  6. 1 1
      src/ob/Context.ob
  7. 19 2
      src/ob/JsArray.ob
  8. 4 4
      src/ob/JsMap.ob
  9. 267 0
      src/ob/Scope.ob
  10. 3 3
      src/ob/Types.ob
  11. 3 2
      src/oc.js
  12. 0 124
      src/scope.js
  13. 2 2
      test/test_unit_common.js

+ 10 - 10
src/context.js

@@ -8,7 +8,7 @@ var op = require("js/Operator.js");
 var Parser = require("parser.js");
 var Procedure = require("js/Procedure.js");
 var Class = require("rtl.js").Class;
-var Scope = require("scope.js");
+var Scope = require("js/Scope.js");
 var Symbol = require("js/Symbols.js");
 var Type = require("js/Types.js");
 
@@ -527,7 +527,7 @@ exports.ProcDecl = ChainedContext.extend({
     handleIdentdef: function(id){
         this.__id = id;
         this.codeGenerator().write(this._prolog());
-        this.parent().pushScope(new Scope.Procedure());
+        this.parent().pushScope(Scope.makeProcedure());
     },
     handleIdent: function(id){
         if (this.__id.id() != id)
@@ -672,7 +672,7 @@ exports.PointerDecl = ChainedContext.extend({
             return existing;
 
         var scope = this.currentScope();
-        scope.addUnresolved(id);
+        Scope.addUnresolved(scope, id);
         var resolve = function(){return getSymbol(parent, id).info().type();};
 
         return Symbol.makeFound(
@@ -1653,7 +1653,7 @@ exports.ExpressionProcedureCall = ProcedureCall.extend({
                 if (proc instanceof Procedure.Std)
                     throw new Errors.Error(proc.description() + " cannot be referenced");
                 var scope = d.scope();
-                if (scope && scope.id() == "procedure")
+                if (scope instanceof Scope.Procedure)
                     throw new Errors.Error("local procedure '" + d.code() + "' cannot be referenced");
             }
             parent.setDesignator(d);
@@ -1747,7 +1747,7 @@ exports.TypeDeclaration = ChainedContext.extend({
     },
     setType: function(type){
         Type.defineTypeId(this.__symbol.info(), type);
-        this.currentScope().resolve(this.__symbol);
+        Scope.resolve(this.currentScope(), this.__symbol);
     },
     typeName: function(){return this.__id.id();},
     genTypeName: function(){return this.__id.id();},
@@ -1763,7 +1763,7 @@ exports.TypeSection = ChainedContext.extend({
         ChainedContext.prototype.init.call(this, context);
     },
     endParse: function(){
-        var unresolved = this.currentScope().unresolved();
+        var unresolved = Scope.unresolved(this.currentScope());
         if (unresolved.length)
             throw new Errors.Error("no declaration found for '" + unresolved.join("', '") + "'");
     }
@@ -1800,14 +1800,14 @@ exports.ModuleDeclaration = ChainedContext.extend({
         var parent = this.parent();
         if (this.__name === undefined ) {
             this.__name = id;
-            this.__moduleScope = new Scope.Module(id);
+            this.__moduleScope = Scope.makeModule(id);
             parent.pushScope(this.__moduleScope);
         }
         else if (id === this.__name){
             var scope = parent.currentScope();
             scope.close();
-            var exports = scope.exports();
-            scope.module().info().defineExports(exports);
+            var exports = Scope.moduleExports(scope);
+            Scope.defineExports(Scope.moduleSymbol(scope).info(), exports);
             this.codeGenerator().write(this.__moduleGen.epilog(exports));
         }
         else
@@ -1835,7 +1835,7 @@ exports.ModuleDeclaration = ChainedContext.extend({
     },
     qualifyScope: function(scope){
         if (scope != this.__moduleScope && scope instanceof Scope.Module){
-            var id = scope.module().id();
+            var id = Scope.moduleSymbol(scope).id();
             return this.__imports[id].id() + ".";
         }
         return "";

+ 19 - 2
src/js/JsArray.js

@@ -27,10 +27,14 @@ function add(a/*Type*/, o/*PType*/){
 	a.push(o);
 }
 
-function stringsAdd(a/*Strings*/, o/*Type*/){
+function addString(a/*Strings*/, o/*Type*/){
 	a.push(o);
 }
 
+function removeString(a/*Strings*/, i/*INTEGER*/){
+	a.splice(i, 1);
+}
+
 function at(a/*Type*/, i/*INTEGER*/){
 	var result = null;
 	result = a[i];
@@ -43,12 +47,22 @@ function stringsAt(a/*Strings*/, i/*INTEGER*/){
 	return result;
 }
 
+function stringsIndexOf(a/*Strings*/, x/*Type*/){
+	var result = 0;
+	result = a.indexOf(x);
+	return result;
+}
+
 function contains(a/*Type*/, x/*PType*/){
 	var result = false;
 	result = (a.indexOf(x) != -1);
 	return result;
 }
 
+function containsString(a/*Strings*/, x/*Type*/){
+	return stringsIndexOf(a, x) != -1;
+}
+
 function make(){
 	var result = null;
 	result = [];
@@ -65,9 +79,12 @@ exports.Strings = Strings;
 exports.len = len;
 exports.stringsLen = stringsLen;
 exports.add = add;
-exports.stringsAdd = stringsAdd;
+exports.addString = addString;
+exports.removeString = removeString;
 exports.at = at;
 exports.stringsAt = stringsAt;
+exports.stringsIndexOf = stringsIndexOf;
 exports.contains = contains;
+exports.containsString = containsString;
 exports.make = make;
 exports.makeStrings = makeStrings;

+ 2 - 2
src/js/JsMap.js

@@ -37,11 +37,11 @@ function erase(m/*Type*/, s/*Type*/){
 	delete m[s];
 }
 
-function forEach(m/*Type*/, p/*forEachProc*/, closure/*VAR Type*/){
+function forEach(m/*Type*/, p/*ForEachProc*/, closure/*VAR Type*/){
 	for(var key in m){p(key, m[key], closure)};
 }
 
-function forEachString(m/*Strings*/, p/*forEachStringProc*/, closure/*VAR Type*/){
+function forEachString(m/*Strings*/, p/*ForEachStringProc*/, closure/*VAR Type*/){
 	for(var key in m){p(key, m[key], closure)};
 }
 exports.Type = Type;

+ 223 - 0
src/js/Scope.js

@@ -0,0 +1,223 @@
+var RTL$ = require("rtl.js");
+var Context = require("js/Context.js");
+var Errors = require("js/Errors.js");
+var JsArray = require("js/JsArray.js");
+var JsMap = require("js/JsMap.js");
+var JsString = require("js/JsString.js");
+var Object = require("js/Object.js");
+var Procedures = require("js/Procedure.js");
+var Symbols = require("js/Symbols.js");
+var Types = require("js/Types.js");
+var Type = Context.Scope.extend({
+	init: function Type(){
+		Context.Scope.prototype.init.call(this);
+		this.symbols = null;
+		this.unresolved = null;
+		this.finalizers = null;
+	}
+});
+var Procedure = Type.extend({
+	init: function Procedure(){
+		Type.prototype.init.call(this);
+	}
+});
+var CompiledModule = Types.Module.extend({
+	init: function CompiledModule(){
+		Types.Module.prototype.init.call(this);
+		this.exports = null;
+	}
+});
+var Module = Type.extend({
+	init: function Module(){
+		Type.prototype.init.call(this);
+		this.symbol = null;
+		this.exports = null;
+	}
+});
+var Finalizer = Object.Type.extend({
+	init: function Finalizer(){
+		Object.Type.prototype.init.call(this);
+		this.proc = null;
+		this.closure = null;
+	}
+});
+var stdSymbols = null;
+
+function makeStdSymbols(){
+	var result = null;
+	var i = 0;
+	var proc = null;
+	
+	function addSymbol(t/*PBasicType*/){
+		var name = null;
+		name = Types.typeName(t);
+		JsMap.put(result, name, Symbols.makeSymbol(name, Types.makeTypeId(t)));
+	}
+	result = JsMap.make();
+	addSymbol(Types.basic().bool);
+	addSymbol(Types.basic().ch);
+	addSymbol(Types.basic().integer);
+	addSymbol(Types.basic().uint8);
+	addSymbol(Types.basic().real);
+	addSymbol(Types.basic().set);
+	for (i = 0; i <= JsArray.len(Procedures.predefined()) - 1 | 0; ++i){
+		proc = JsArray.at(Procedures.predefined(), i);
+		JsMap.put(result, RTL$.typeGuard(proc, Symbols.Symbol).id(), proc);
+	}
+	return result;
+}
+
+function init(scope/*Type*/){
+	scope.symbols = JsMap.make();
+	scope.unresolved = JsArray.makeStrings();
+	scope.finalizers = JsArray.make();
+}
+
+function makeCompiledModule(name/*Type*/){
+	var result = null;
+	result = new CompiledModule();
+	Types.initModule(result, name);
+	result.exports = JsMap.make();
+	return result;
+}
+
+function makeModule(name/*Type*/){
+	var result = null;
+	result = new Module();
+	init(result);
+	result.exports = JsMap.make();
+	result.symbol = Symbols.makeSymbol(name, makeCompiledModule(name));
+	result.addSymbol(result.symbol, false);
+	return result;
+}
+
+function addUnresolved(s/*Type*/, id/*Type*/){
+	if (!JsArray.containsString(s.unresolved, id)){
+		JsArray.addString(s.unresolved, id);
+	}
+}
+
+function resolve(s/*Type*/, symbol/*PSymbol*/){
+	var id = null;
+	var i = 0;
+	var info = null;
+	var type = null;
+	id = symbol.id();
+	i = JsArray.stringsIndexOf(s.unresolved, id);
+	if (i != -1){
+		info = symbol.info();
+		type = RTL$.typeGuard(info, Types.TypeId).type();
+		if (type != null && !(type instanceof Types.Record)){
+			Errors.raise(JsString.concat(JsString.concat(JsString.make("'"), id), JsString.make("' must be of RECORD type because it was used before in the declation of POINTER")));
+		}
+		JsArray.removeString(s.unresolved, i);
+	}
+}
+
+function unresolved(s/*Type*/){
+	return s.unresolved;
+}
+Type.prototype.close = function(){
+	var i = 0;
+	var p = null;
+	var finalizer = null;
+	if (this.finalizers != null){
+		for (i = 0; i <= JsArray.len(this.finalizers) - 1 | 0; ++i){
+			p = JsArray.at(this.finalizers, i);
+			finalizer = RTL$.typeGuard(p, Finalizer);
+			finalizer.proc(finalizer.closure);
+		}
+		this.finalizers = null;
+	}
+}
+Type.prototype.addFinalizer = function(proc/*FinalizerProc*/, closure/*PType*/){
+	var f = null;
+	f = new Finalizer();
+	f.proc = proc;
+	f.closure = closure;
+	JsArray.add(this.finalizers, f);
+}
+
+function close(s/*Type*/){
+	return s.unresolved;
+}
+Type.prototype.addSymbol = function(s/*PSymbol*/, exported/*BOOLEAN*/){
+	var id = null;
+	id = s.id();
+	if (this.findSymbol(id) != null){
+		Errors.raise(JsString.concat(JsString.concat(JsString.make("'"), id), JsString.make("' already declared")));
+	}
+	JsMap.put(this.symbols, id, s);
+}
+Type.prototype.findSymbol = function(id/*Type*/){
+	var result = null;
+	var void$ = false;
+	if (!JsMap.find(this.symbols, id, {set: function($v){result = $v;}, get: function(){return result;}})){
+		void$ = JsMap.find(stdSymbols, id, {set: function($v){result = $v;}, get: function(){return result;}});
+	}
+	return RTL$.typeGuard(result, Symbols.Symbol);
+}
+Procedure.prototype.addSymbol = function(s/*PSymbol*/, exported/*BOOLEAN*/){
+	var info = null;
+	if (exported){
+		info = s.info();
+		Errors.raise(JsString.concat(JsString.concat(JsString.concat(JsString.concat(JsString.make("cannot export from within procedure: "), info.idType()), JsString.make(" '")), s.id()), JsString.make("'")));
+	}
+	Type.prototype.addSymbol.call(this, s, exported);
+}
+
+function makeProcedure(){
+	var result = null;
+	result = new Procedure();
+	init(result);
+	return result;
+}
+
+function addExport(id/*Type*/, value/*PType*/, closure/*VAR Type*/){
+	var symbol = null;
+	var info = null;
+	symbol = RTL$.typeGuard(value, Symbols.Symbol);
+	info = symbol.info();
+	if (info instanceof Types.Variable){
+		symbol = Symbols.makeSymbol(id, Types.makeExportedVariable(RTL$.typeGuard(info, Types.Variable)));
+	}
+	JsMap.put(RTL$.typeGuard(closure, CompiledModule).exports, id, symbol);
+}
+
+function defineExports(m/*CompiledModule*/, exports/*Type*/){
+	JsMap.forEach(exports, addExport, m);
+}
+CompiledModule.prototype.findSymbol = function(id/*Type*/){
+	var s = null;
+	var result = null;
+	if (JsMap.find(this.exports, id, {set: function($v){s = $v;}, get: function(){return s;}})){
+		result = Symbols.makeFound(RTL$.typeGuard(s, Symbols.Symbol), null);
+	}
+	return result;
+}
+Module.prototype.addSymbol = function(s/*PSymbol*/, exported/*BOOLEAN*/){
+	Type.prototype.addSymbol.call(this, s, exported);
+	if (exported){
+		JsMap.put(this.exports, s.id(), s);
+	}
+}
+
+function moduleSymbol(m/*Module*/){
+	return m.symbol;
+}
+
+function moduleExports(m/*Module*/){
+	return m.exports;
+}
+stdSymbols = makeStdSymbols();
+exports.Procedure = Procedure;
+exports.Module = Module;
+exports.makeModule = makeModule;
+exports.addUnresolved = addUnresolved;
+exports.resolve = resolve;
+exports.unresolved = unresolved;
+exports.close = close;
+exports.makeProcedure = makeProcedure;
+exports.defineExports = defineExports;
+exports.moduleSymbol = moduleSymbol;
+exports.moduleExports = moduleExports;

+ 2 - 1
src/js/Types.js

@@ -354,7 +354,7 @@ Record.prototype.addField = function(f/*Field*/, type/*PType*/){
 	}
 	JsMap.put(this.fields, f.id(), type);
 	if (!f.exported()){
-		JsArray.stringsAdd(this.notExported, f.id());
+		JsArray.addString(this.notExported, f.id());
 	}
 }
 Record.prototype.findSymbol = function(id/*Type*/){
@@ -594,6 +594,7 @@ exports.Pointer = Pointer;
 exports.Procedure = Procedure;
 exports.DefinedProcedure = DefinedProcedure;
 exports.ProcedureArgument = ProcedureArgument;
+exports.BasicType = BasicType;
 exports.Record = Record;
 exports.NonExportedRecord = NonExportedRecord;
 exports.Module = Module;

+ 1 - 1
src/ob/Context.ob

@@ -1,7 +1,7 @@
 MODULE Context;
 IMPORT JsString, Object;
 TYPE
-    FinalizerProc = PROCEDURE(closure: Object.PType);
+    FinalizerProc* = PROCEDURE(closure: Object.PType);
 
     Scope* = RECORD
         PROCEDURE addFinalizer*(finalizer: FinalizerProc; closure: Object.PType)

+ 19 - 2
src/ob/JsArray.ob

@@ -25,10 +25,15 @@ BEGIN
     JS.do("a.push(o)");
 END add;
 
-PROCEDURE stringsAdd*(a: Strings; o: JsString.Type);
+PROCEDURE addString*(a: Strings; o: JsString.Type);
 BEGIN
     JS.do("a.push(o)");
-END stringsAdd;
+END addString;
+
+PROCEDURE removeString*(a: Strings; i: INTEGER);
+BEGIN
+    JS.do("a.splice(i, 1)");
+END removeString;
 
 PROCEDURE at*(a: Type; i: INTEGER): Object.PType;
 VAR
@@ -46,6 +51,14 @@ BEGIN
     RETURN result
 END stringsAt;
 
+PROCEDURE stringsIndexOf*(a: Strings; x: JsString.Type): INTEGER;
+VAR
+    result: INTEGER;
+BEGIN
+    JS.do("result = a.indexOf(x)");
+    RETURN result
+END stringsIndexOf;
+
 PROCEDURE contains*(a: Type; x: Object.PType): BOOLEAN;
 VAR
     result: BOOLEAN;
@@ -54,6 +67,10 @@ BEGIN
     RETURN result
 END contains;
 
+PROCEDURE containsString*(a: Strings; x: JsString.Type): BOOLEAN;
+    RETURN stringsIndexOf(a, x) # -1
+END containsString;
+
 PROCEDURE make*(): Type;
 VAR
     result: Type;

+ 4 - 4
src/ob/JsMap.ob

@@ -2,10 +2,10 @@ MODULE JsMap;
 IMPORT JS, JsString, Object;
 TYPE
     Type* = POINTER TO RECORD END;
-    forEachProc = PROCEDURE(key: JsString.Type; value: Object.PType; VAR closure: Object.Type);
+    ForEachProc = PROCEDURE(key: JsString.Type; value: Object.PType; VAR closure: Object.Type);
     
     Strings* = POINTER TO RECORD END;
-    forEachStringProc = PROCEDURE(key: JsString.Type; value: JsString.Type; VAR closure: Object.Type);
+    ForEachStringProc = PROCEDURE(key: JsString.Type; value: JsString.Type; VAR closure: Object.Type);
 
 PROCEDURE make*(): Type;
 VAR
@@ -41,12 +41,12 @@ BEGIN
     JS.do("delete m[s]");
 END erase;
 
-PROCEDURE forEach*(m: Type; p: forEachProc; VAR closure: Object.Type);
+PROCEDURE forEach*(m: Type; p: ForEachProc; VAR closure: Object.Type);
 BEGIN
     JS.do("for(var key in m){p(key, m[key], closure)}");
 END forEach;
 
-PROCEDURE forEachString*(m: Strings; p: forEachStringProc; VAR closure: Object.Type);
+PROCEDURE forEachString*(m: Strings; p: ForEachStringProc; VAR closure: Object.Type);
 BEGIN
     JS.do("for(var key in m){p(key, m[key], closure)}");
 END forEachString;

+ 267 - 0
src/ob/Scope.ob

@@ -0,0 +1,267 @@
+MODULE Scope;
+IMPORT 
+    Context,
+    Errors, 
+    JsArray, 
+    JsMap, 
+    JsString, 
+    Object, 
+    Procedures := Procedure, 
+    Symbols, 
+    Types;
+TYPE
+    Type = RECORD(Context.Scope)
+        PROCEDURE addSymbol(s: Symbols.PSymbol; exported: BOOLEAN);
+        PROCEDURE findSymbol(id: JsString.Type): Symbols.PSymbol;
+        PROCEDURE close();
+
+        symbols: JsMap.Type;
+        unresolved: JsArray.Strings;
+        finalizers: JsArray.Type
+    END;
+    PType = POINTER TO Type;
+
+    Procedure* = RECORD(Type)
+    END;
+
+    CompiledModule = RECORD(Types.Module)
+        PROCEDURE findSymbol(id: JsString.Type): Symbols.PFoundSymbol;
+
+        exports: JsMap.Type
+    END;
+    PCompiledModule = POINTER TO CompiledModule;
+
+    Module* = RECORD(Type)
+        symbol: Symbols.PSymbol;
+        exports: JsMap.Type
+    END;
+    PModule = POINTER TO Module;
+
+    Finalizer = POINTER TO RECORD (Object.Type)
+        proc: Context.FinalizerProc;
+        closure: Object.PType
+    END;
+VAR
+    stdSymbols: JsMap.Type;
+
+PROCEDURE makeStdSymbols(): JsMap.Type;
+VAR 
+    result: JsMap.Type;
+    i: INTEGER;
+    proc: Object.PType;
+
+    PROCEDURE addSymbol(t: Types.PBasicType);
+    VAR
+        name: JsString.Type;
+    BEGIN
+        name := Types.typeName(t^);
+        JsMap.put(result, name, Symbols.makeSymbol(name, Types.makeTypeId(t)));
+    END addSymbol;
+BEGIN
+    result := JsMap.make();
+    addSymbol(Types.basic.bool);
+    addSymbol(Types.basic.ch);
+    addSymbol(Types.basic.integer);
+    addSymbol(Types.basic.uint8);
+    addSymbol(Types.basic.real);
+    addSymbol(Types.basic.set); 
+
+    FOR i := 0 TO JsArray.len(Procedures.predefined) - 1 DO
+        proc := JsArray.at(Procedures.predefined, i);
+        JsMap.put(result, proc(Symbols.PSymbol).id(), proc);
+    END;
+    RETURN result
+END makeStdSymbols;
+
+PROCEDURE init(scope: Type);
+BEGIN
+    scope.symbols := JsMap.make();
+    scope.unresolved := JsArray.makeStrings();
+    scope.finalizers := JsArray.make();
+END init;
+
+PROCEDURE makeCompiledModule(name: JsString.Type): PCompiledModule;
+VAR
+    result: PCompiledModule;
+BEGIN
+    NEW(result);
+    Types.initModule(result^, name);
+    result.exports := JsMap.make();
+    RETURN result
+END makeCompiledModule;
+
+PROCEDURE makeModule*(name: JsString.Type): PModule;
+VAR
+    result: PModule;
+BEGIN
+    NEW(result);
+    init(result^);
+    result.exports := JsMap.make();
+    result.symbol := Symbols.makeSymbol(name, makeCompiledModule(name));
+    result.addSymbol(result.symbol, FALSE);
+    RETURN result
+END makeModule;
+
+PROCEDURE addUnresolved*(s: Type; id: JsString.Type);
+BEGIN
+    IF ~JsArray.containsString(s.unresolved, id) THEN
+        JsArray.addString(s.unresolved, id);
+    END;
+END addUnresolved;
+
+PROCEDURE resolve*(s: Type; symbol: Symbols.PSymbol);
+VAR
+    id: JsString.Type;
+    i: INTEGER;
+    info: Types.PId;
+    type: Types.PType;
+BEGIN
+    id := symbol.id();
+    i := JsArray.stringsIndexOf(s.unresolved, id);
+    IF i # -1 THEN
+        info := symbol.info();
+        type := info(Types.PTypeId).type();
+        IF (type # NIL) & ~(type IS Types.PRecord) THEN
+            Errors.raise(JsString.concat(JsString.concat(
+                JsString.make("'"),
+                id),
+                JsString.make("' must be of RECORD type because it was used before in the declation of POINTER")));
+        END;
+        JsArray.removeString(s.unresolved, i);
+    END;
+END resolve;
+
+PROCEDURE unresolved*(s: Type): JsArray.Strings;
+    RETURN s.unresolved
+END unresolved;
+
+PROCEDURE Type.close();
+VAR
+    i: INTEGER;
+    p: Object.PType;
+    finalizer: Finalizer;
+BEGIN
+    IF SELF.finalizers # NIL THEN
+        FOR i := 0 TO JsArray.len(SELF.finalizers) - 1 DO
+            p := JsArray.at(SELF.finalizers, i);
+            finalizer := p(Finalizer);
+            finalizer.proc(finalizer.closure);
+        END;
+
+        (* make second close() call safe and free memory *)
+        SELF.finalizers := NIL; 
+    END;
+END Type.close;
+
+PROCEDURE Type.addFinalizer(proc: Context.FinalizerProc; closure: Object.PType);
+VAR
+    f: Finalizer;
+BEGIN
+    NEW(f);
+    f.proc := proc;
+    f.closure := closure;
+    JsArray.add(SELF.finalizers, f);
+END Type.addFinalizer;
+
+PROCEDURE close*(s: Type): JsArray.Strings;
+    RETURN s.unresolved
+END close;
+
+PROCEDURE Type.addSymbol(s: Symbols.PSymbol; exported: BOOLEAN);
+VAR
+    id: JsString.Type;
+BEGIN
+    id := s.id();
+    IF SELF.findSymbol(id) # NIL THEN
+        Errors.raise(JsString.concat(JsString.concat(
+            JsString.make("'"),
+            id),
+            JsString.make("' already declared")));
+    END;
+    JsMap.put(SELF.symbols, id, s);
+END Type.addSymbol;
+
+PROCEDURE Type.findSymbol(id: JsString.Type): Symbols.PSymbol;
+VAR
+    result: Object.PType;
+    void: BOOLEAN;
+BEGIN
+    IF ~JsMap.find(SELF.symbols, id, result) THEN
+        void := JsMap.find(stdSymbols, id, result);
+    END;
+    RETURN result(Symbols.PSymbol)
+END Type.findSymbol;
+
+PROCEDURE Procedure.addSymbol(s: Symbols.PSymbol; exported: BOOLEAN);
+VAR
+    info: Types.PId;
+BEGIN
+    IF exported THEN
+        info := s.info();
+        Errors.raise(JsString.concat(JsString.concat(JsString.concat(JsString.concat(
+            JsString.make("cannot export from within procedure: "),
+            info.idType()),
+            JsString.make(" '")),
+            s.id()),
+            JsString.make("'")));
+    END;
+    SUPER(s, exported);
+END Procedure.addSymbol;
+
+PROCEDURE makeProcedure*(): PType;
+VAR
+    result: POINTER TO Procedure;
+BEGIN
+    NEW(result);
+    init(result^);
+    RETURN result
+END makeProcedure;
+
+PROCEDURE addExport(id: JsString.Type; value: Object.PType; VAR closure: Object.Type);
+VAR
+    symbol: Symbols.PSymbol;
+    info: Types.PId;
+BEGIN
+    symbol := value(Symbols.PSymbol);
+    info := symbol.info();
+    IF info IS Types.PVariable THEN
+        symbol := Symbols.makeSymbol(id, Types.makeExportedVariable(info(Types.PVariable)^));
+    END;
+    JsMap.put(closure(CompiledModule).exports, id, symbol);
+END addExport;
+
+PROCEDURE defineExports*(m: CompiledModule; exports: JsMap.Type);
+BEGIN
+    JsMap.forEach(exports, addExport, m);
+END defineExports;
+
+PROCEDURE CompiledModule.findSymbol(id: JsString.Type): Symbols.PFoundSymbol;
+VAR
+    s: Object.PType;
+    result: Symbols.PFoundSymbol;
+BEGIN
+    IF JsMap.find(SELF.exports, id, s) THEN
+        result := Symbols.makeFound(s(Symbols.PSymbol), NIL);
+    END;
+    RETURN result
+END CompiledModule.findSymbol;
+
+PROCEDURE Module.addSymbol(s: Symbols.PSymbol; exported: BOOLEAN);
+BEGIN
+    SUPER(s, exported);
+    IF exported THEN
+        JsMap.put(SELF.exports, s.id(), s);
+    END;
+END Module.addSymbol;
+
+PROCEDURE moduleSymbol*(m: Module): Symbols.PSymbol;
+    RETURN m.symbol
+END moduleSymbol;
+
+PROCEDURE moduleExports*(m: Module): JsMap.Type;
+    RETURN m.exports
+END moduleExports;
+
+BEGIN
+    stdSymbols := makeStdSymbols();
+END Scope.

+ 3 - 3
src/ob/Types.ob

@@ -117,11 +117,11 @@ TYPE
 
     PProcedureArgument* = POINTER TO ProcedureArgument;
 
-    BasicType = RECORD(NamedType)
+    BasicType* = RECORD(NamedType)
         mInitializer: JsString.Type
     END;
 
-    PBasicType = POINTER TO BasicType;
+    PBasicType* = POINTER TO BasicType;
 
     Field = RECORD
         id: PROCEDURE(): JsString.Type;
@@ -416,7 +416,7 @@ BEGIN
     END;
     JsMap.put(SELF.fields, f.id(), type);
     IF ~f.exported() THEN
-        JsArray.stringsAdd(SELF.notExported, f.id());
+        JsArray.addString(SELF.notExported, f.id());
     END;
 END Record.addField;
 

+ 3 - 2
src/oc.js

@@ -6,6 +6,7 @@ var Context = require("context.js");
 var Errors = require("js/Errors.js");
 var Lexer = require("js/Lexer.js");
 var RTL = require("rtl_code.js").RTL;
+var Scope = require("js/Scope.js");
 var Stream = require("js/Stream.js");
 
 var CompiledModule = Class.extend({
@@ -37,9 +38,9 @@ function compileModule(grammar, stream, context, handleErrors){
     }
     var scope = context.currentScope();
     return new CompiledModule(
-            scope.module(),
+            Scope.moduleSymbol(scope),
             context.codeGenerator().result(),
-            scope.exports());
+            Scope.moduleExports(scope));
 }
 
 function compileModulesFromText(

+ 0 - 124
src/scope.js

@@ -1,124 +0,0 @@
-"use strict";
-
-var Class = require("rtl.js").Class;
-var Errors = require("js/Errors.js");
-var Procedure = require("js/Procedure.js");
-var Symbol = require("js/Symbols.js");
-var Type = require("js/Types.js");
-
-var stdSymbols = function(){
-    var symbols = {};
-    var basicTypes = Type.basic();
-    for(var t in basicTypes){
-        var type = basicTypes[t];
-        var name = Type.typeName(type);
-        symbols[name] = Symbol.makeSymbol(name, Type.makeTypeId(type));
-    }
-    
-    var predefined = Procedure.predefined();
-    for(var i = 0; i < predefined.length; ++i){
-        var s = predefined[i];
-        symbols[s.id()] = s;
-    }
-    return symbols;
-}();
-
-var Scope = Class.extend({
-    init: function Scope(id){
-        this.__id = id;
-        this.__symbols = {};
-        for(var p in stdSymbols)
-            this.__symbols[p] = stdSymbols[p];
-        this.__unresolved = [];
-        this.__finalizers = [];
-    },
-    id: function(){return this.__id;},
-    addSymbol: function(symbol){
-        var id = symbol.id();
-        if (this.findSymbol(id))
-            throw new Errors.Error( "'" + id + "' already declared");
-        this.__symbols[id] = symbol;
-    },
-    addFinalizer: function(f, closure){this.__finalizers.push(f.bind(undefined, closure));},
-    resolve: function(symbol){
-        var id = symbol.id();
-        var i = this.__unresolved.indexOf(id);
-        if (i != -1){
-            var info = symbol.info();
-            var type = info.type();
-            if (type !== undefined && !(type instanceof Type.Record))
-                throw new Errors.Error(
-                    "'" + id + "' must be of RECORD type because it was used before in the declation of POINTER");
-            this.__unresolved.splice(i, 1);
-        }
-    },
-    findSymbol: function(ident){return this.__symbols[ident];},
-    addUnresolved: function(id){
-        if (this.__unresolved.indexOf(id) == -1)
-            this.__unresolved.push(id);
-    },
-    unresolved: function(){return this.__unresolved;},
-    close: function(){
-        for(var i = 0; i < this.__finalizers.length; ++i)
-            this.__finalizers[i]();
-
-        // make second close() call safe and free memory
-        this.__finalizers = []; 
-    }
-});
-
-var ProcedureScope = Scope.extend({
-    init: function ProcedureScope(){
-        Scope.prototype.init.call(this, "procedure");
-    },
-    addSymbol: function(symbol, exported){
-        if (exported)
-            throw new Errors.Error("cannot export from within procedure: " 
-                + symbol.info().idType() + " '" + symbol.id() + "'");
-        Scope.prototype.addSymbol.call(this, symbol, exported);
-    }
-});
-
-var CompiledModule = Type.Module.extend({
-    init: function Scope$CompiledModule(id){
-        Type.Module.prototype.init.call(this);
-        Type.initModule(this, id);
-        this.__exports = {};
-    },
-    defineExports: function(exports){
-        for(var id in exports){
-            var symbol = exports[id];
-            if (symbol.isVariable())
-                symbol = Symbol.makeSymbol(
-                    id,
-                    Type.makeExportedVariable(symbol.info()));
-            this.__exports[id] = symbol;
-        }
-    },  
-    findSymbol: function(id){
-        var s = this.__exports[id];
-        if (!s)
-            return undefined;
-        return Symbol.makeFound(s);
-    }
-});
-
-var Module = Scope.extend({
-    init: function Scope$Module(name){
-        Scope.prototype.init.call(this, "module");
-        this.__name = name;
-        this.__exports = {};
-        this.__symbol = Symbol.makeSymbol(name, new CompiledModule(name));
-        this.addSymbol(this.__symbol);
-    },
-    module: function(){return this.__symbol;},
-    addSymbol: function(symbol, exported){
-        Scope.prototype.addSymbol.call(this, symbol, exported);
-        if (exported)
-            this.__exports[symbol.id()] = symbol;
-    },
-    exports: function(){return this.__exports;}
-});
-
-exports.Procedure = ProcedureScope;
-exports.Module = Module;

+ 2 - 2
test/test_unit_common.js

@@ -6,7 +6,7 @@ var Context = require("context.js");
 var Errors = require("js/Errors.js");
 var oc = require("oc.js");
 var RTL = require("rtl_code.js").RTL;
-var Scope = require("scope.js");
+var Scope = require("js/Scope.js");
 var Stream = require("Stream.js");
 var Test = require("test.js");
 
@@ -33,7 +33,7 @@ var TestContext = Context.Context.extend({
                 Code.nullGenerator(),
                 function(){return new TestModuleGenerator();},
                 new RTL());
-        this.pushScope(new Scope.Module("test"));
+        this.pushScope(Scope.makeModule("test"));
     },
     qualifyScope: function(){return "";}
 });