浏览代码

MAP's clear method + fixes

Vladislav Folts 10 年之前
父节点
当前提交
99084b3602

二进制
bin/compiled.zip


+ 2 - 2
src/context.js

@@ -333,9 +333,9 @@ exports.Designator = ChainedContext.extend({
             this.__handleDeref();
             this.__handleDeref();
             isReadOnly = false;
             isReadOnly = false;
         }
         }
-        var field = t.denote(id);
+        var field = t.denote(id, isReadOnly);
         var currentType = field.type();
         var currentType = field.type();
-        var fieldCode = field.designatorCode(this.__code);
+        var fieldCode = field.designatorCode(this.__code, this.language());
         this.__derefCode = fieldCode.derefCode;
         this.__derefCode = fieldCode.derefCode;
         this.__propCode = fieldCode.propCode;
         this.__propCode = fieldCode.propCode;
         this._advance(currentType, field.asVar(isReadOnly, this), fieldCode.code, undefined, true);
         this._advance(currentType, field.asVar(isReadOnly, this), fieldCode.code, undefined, true);

+ 6 - 6
src/eberon/EberonArray.ob

@@ -69,22 +69,22 @@ BEGIN
     RETURN result
     RETURN result
 END denote;
 END denote;
 
 
-PROCEDURE StaticArray.denote(id: STRING): Types.PField;
+PROCEDURE StaticArray.denote(id: STRING; isReadObly: BOOLEAN): Types.PField;
 BEGIN
 BEGIN
     result <- denote(id, SELF);
     result <- denote(id, SELF);
     IF result = NIL THEN
     IF result = NIL THEN
-        result := SUPER(id);
+        result := SUPER(id, isReadObly);
     END;
     END;
     RETURN result
     RETURN result
-END StaticArray.denote;
+END;
 
 
-PROCEDURE OpenArray.denote(id: STRING): Types.PField;
+PROCEDURE OpenArray.denote(id: STRING; isReadObly: BOOLEAN): Types.PField;
 BEGIN
 BEGIN
     result <- denote(id, SELF);
     result <- denote(id, SELF);
     IF result = NIL THEN
     IF result = NIL THEN
-        result := SUPER(id);
+        result := SUPER(id, isReadObly);
     END;
     END;
     RETURN result
     RETURN result
-END OpenArray.denote;
+END;
 
 
 END EberonArray.
 END EberonArray.

+ 14 - 6
src/eberon/EberonDynamicArray.ob

@@ -1,5 +1,5 @@
 MODULE EberonDynamicArray;
 MODULE EberonDynamicArray;
-IMPORT Cast, Code, Context, EberonArray, EberonTypes, Errors, LanguageContext, Procedure, Types;
+IMPORT Cast, Code, Context, EberonArray, EberonRecord, EberonTypes, Errors, LanguageContext, Procedure, Types;
 CONST
 CONST
     methodNameAdd = "add";
     methodNameAdd = "add";
     methodNameClear = "clear";
     methodNameClear = "clear";
@@ -77,20 +77,28 @@ PROCEDURE MethodAdd.MethodAdd(elementsType: Types.PType)
       elementsType(elementsType);
       elementsType(elementsType);
 END;
 END;
 
 
-PROCEDURE DynamicArray.denote(id: STRING): Types.PField;
+PROCEDURE DynamicArray.denote(id: STRING; isReadObly: BOOLEAN): Types.PField;
 VAR
 VAR
     result: Types.PField;
     result: Types.PField;
+
+    PROCEDURE assertReadOnly();
+    BEGIN
+        EberonRecord.assertNotReadOnly(isReadObly, id, "dynamic array");
+    END;
 BEGIN
 BEGIN
     IF      id = methodNameAdd THEN
     IF      id = methodNameAdd THEN
+        assertReadOnly();
         result := NEW MethodAddField(SELF.elementsType);
         result := NEW MethodAddField(SELF.elementsType);
     ELSIF   id = methodNameClear THEN
     ELSIF   id = methodNameClear THEN
+        assertReadOnly();
         result := methodClear;
         result := methodClear;
     ELSIF   id = methodNameRemove THEN
     ELSIF   id = methodNameRemove THEN
+        assertReadOnly();
         result := methodRemove;
         result := methodRemove;
     ELSE
     ELSE
         result := EberonArray.denoteMethod(id, SELF.elementsType);
         result := EberonArray.denoteMethod(id, SELF.elementsType);
         IF result = NIL THEN
         IF result = NIL THEN
-            result := SUPER(id);
+            result := SUPER(id, isReadObly);
         END;
         END;
     END;
     END;
     RETURN result
     RETURN result
@@ -133,15 +141,15 @@ PROCEDURE Method.description(): STRING;
     RETURN "dynamic array method '" + SELF.name + "'"
     RETURN "dynamic array method '" + SELF.name + "'"
 END Method.description;
 END Method.description;
 
 
-PROCEDURE MethodAddField.designatorCode(leadCode: STRING): Types.PFieldCode;
+PROCEDURE MethodAddField.designatorCode(leadCode: STRING; cx: Context.Type): Types.PFieldCode;
     RETURN NEW Types.FieldCode(leadCode + "." + "push", "", "");
     RETURN NEW Types.FieldCode(leadCode + "." + "push", "", "");
 END;
 END;
 
 
-PROCEDURE MethodClearField.designatorCode(leadCode: STRING): Types.PFieldCode;
+PROCEDURE MethodClearField.designatorCode(leadCode: STRING; cx: Context.Type): Types.PFieldCode;
     RETURN NEW Types.FieldCode(leadCode + "." + "splice", "", "");
     RETURN NEW Types.FieldCode(leadCode + "." + "splice", "", "");
 END;
 END;
 
 
-PROCEDURE MethodRemoveField.designatorCode(leadCode: STRING): Types.PFieldCode;
+PROCEDURE MethodRemoveField.designatorCode(leadCode: STRING; cx: Context.Type): Types.PFieldCode;
     RETURN NEW Types.FieldCode(leadCode + "." + "splice", "", "");
     RETURN NEW Types.FieldCode(leadCode + "." + "splice", "", "");
 END;
 END;
 
 

+ 61 - 8
src/eberon/EberonMap.ob

@@ -1,7 +1,8 @@
 MODULE EberonMap;
 MODULE EberonMap;
-IMPORT Code, Context, EberonString, EberonTypes, LanguageContext, Procedure, Types;
+IMPORT Code, Context, EberonRtl, EberonString, EberonRecord, EberonTypes, Errors, LanguageContext, Procedure, Types;
 CONST
 CONST
     removeMethodName = "remove";
     removeMethodName = "remove";
+    clearMethodName = "clear";
 TYPE
 TYPE
     Type* = RECORD(Types.StorageType)
     Type* = RECORD(Types.StorageType)
         PROCEDURE Type*(type: Types.PType);
         PROCEDURE Type*(type: Types.PType);
@@ -16,12 +17,27 @@ TYPE
         PROCEDURE MethodRemoveField();
         PROCEDURE MethodRemoveField();
     END;
     END;
 
 
-    MethodRemove = RECORD(Method)
+    MethodClearField = RECORD(EberonTypes.MethodField)
+        PROCEDURE MethodClearField();
+    END;
+
+    MapMethod = RECORD(Method)
+    END;
+
+    MethodRemove = RECORD(MapMethod)
+        PROCEDURE MethodRemove();
+    END;
+
+    MethodClear = RECORD(MapMethod)
+        PROCEDURE MethodClear();
     END;
     END;
 
 
     MethodCallRemove = RECORD(Procedure.StdCall)
     MethodCallRemove = RECORD(Procedure.StdCall)
     END;
     END;
 
 
+    MethodCallClear = RECORD(Procedure.StdCall)
+    END;
+
 PROCEDURE Type.initializer(cx: Context.Type): STRING;
 PROCEDURE Type.initializer(cx: Context.Type): STRING;
     RETURN "{}";
     RETURN "{}";
 END;
 END;
@@ -34,14 +50,23 @@ PROCEDURE Type.Type(valueType: Types.PType)
     | valueType(valueType);
     | valueType(valueType);
 END;
 END;
 
 
-PROCEDURE Type.denote(id: STRING): Types.PField;
+PROCEDURE Type.denote(id: STRING; isReadObly: BOOLEAN): Types.PField;
 VAR
 VAR
     result: Types.PField;
     result: Types.PField;
+
+    PROCEDURE assertReadOnly();
+    BEGIN
+        EberonRecord.assertNotReadOnly(isReadObly, id, "MAP");
+    END;
 BEGIN
 BEGIN
     IF id = removeMethodName THEN
     IF id = removeMethodName THEN
+        assertReadOnly();
         result := NEW MethodRemoveField();
         result := NEW MethodRemoveField();
+    ELSIF id = clearMethodName THEN
+        assertReadOnly();
+        result := NEW MethodClearField();
     ELSE
     ELSE
-        result := SUPER(id);
+        result := SUPER(id, isReadObly);
     END;
     END;
     RETURN result;
     RETURN result;
 END;
 END;
@@ -51,10 +76,24 @@ BEGIN
     argCode <- Procedure.makeArgumentsCode(cx);
     argCode <- Procedure.makeArgumentsCode(cx);
     arg <- Procedure.checkSingleArgument(args, SELF, cx.types, argCode);
     arg <- Procedure.checkSingleArgument(args, SELF, cx.types, argCode);
     RETURN Code.makeSimpleExpression("[" + argCode.result() + "]", NIL)
     RETURN Code.makeSimpleExpression("[" + argCode.result() + "]", NIL)
+END;        
+
+PROCEDURE MethodCallClear.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+BEGIN
+    Procedure.checkArgumentsCount(LEN(args), 0);
+    RETURN Code.makeSimpleExpression("", NIL);
 END;
 END;
 
 
-PROCEDURE MethodRemove.description(): STRING;
-    RETURN "MAP's method 'remove'";
+PROCEDURE MapMethod.description(): STRING;
+    RETURN "MAP's method '" + SELF.name + "'";
+END;
+
+PROCEDURE MethodRemove.MethodRemove()
+    | SUPER(removeMethodName, NIL);
+END;
+
+PROCEDURE MethodClear.MethodClear()
+    | SUPER(clearMethodName, NIL);
 END;
 END;
 
 
 PROCEDURE MethodRemove.callGenerator(cx: LanguageContext.PType): Procedure.PCallGenerator;
 PROCEDURE MethodRemove.callGenerator(cx: LanguageContext.PType): Procedure.PCallGenerator;
@@ -65,13 +104,27 @@ BEGIN
     RETURN Procedure.makeCallGenerator(call, cx)
     RETURN Procedure.makeCallGenerator(call, cx)
 END;
 END;
 
 
+PROCEDURE MethodClear.callGenerator(cx: LanguageContext.PType): Procedure.PCallGenerator;
+BEGIN
+    call <- NEW MethodCallClear();
+    RETURN Procedure.makeCallGenerator(call, cx)
+END;
+
 PROCEDURE MethodRemoveField.MethodRemoveField()
 PROCEDURE MethodRemoveField.MethodRemoveField()
-    | SUPER(NEW MethodRemove(removeMethodName, NIL));
+    | SUPER(NEW MethodRemove());
+END;
+
+PROCEDURE MethodClearField.MethodClearField()
+    | SUPER(NEW MethodClear());
 END;
 END;
 
 
-PROCEDURE MethodRemoveField.designatorCode(leadCode: STRING): Types.PFieldCode;
+PROCEDURE MethodRemoveField.designatorCode(leadCode: STRING; cx: Context.Type): Types.PFieldCode;
     RETURN NEW Types.FieldCode("delete " + leadCode, "", "");
     RETURN NEW Types.FieldCode("delete " + leadCode, "", "");
 END;
 END;
 
 
+PROCEDURE MethodClearField.designatorCode(leadCode: STRING; cx: Context.Type): Types.PFieldCode;
+    RETURN NEW Types.FieldCode(cx.rtl(EberonRtl.PType).clearMap(leadCode), "", "");
+END;
+
 END EberonMap.
 END EberonMap.
 
 

+ 9 - 2
src/eberon/EberonRecord.ob

@@ -69,6 +69,13 @@ TYPE
         code: STRING;
         code: STRING;
     END;
     END;
 
 
+PROCEDURE assertNotReadOnly*(isReadObly: BOOLEAN; method: STRING; class: STRING);
+BEGIN
+    IF isReadObly THEN
+        Errors.raise("method '" + method + "' cannot be applied to non-VAR " + class);
+    END;
+END;
+
 PROCEDURE cannotInstantiateErrMsg(r: Types.Record): STRING;
 PROCEDURE cannotInstantiateErrMsg(r: Types.Record): STRING;
     RETURN "cannot instantiate '" 
     RETURN "cannot instantiate '" 
          + r.name 
          + r.name 
@@ -96,7 +103,7 @@ BEGIN
 END;
 END;
 
 
 PROCEDURE ensureMethodDefinitionsForEach(key: STRING; value: Object.PType; VAR closure: Object.Type);
 PROCEDURE ensureMethodDefinitionsForEach(key: STRING; value: Object.PType; VAR closure: Object.Type);
-    PROCEDURE do(ids: ARRAY OF STRING; closure: EnsureMethodDefinitionsClosure);
+    PROCEDURE do(ids: ARRAY OF STRING; VAR closure: EnsureMethodDefinitionsClosure);
     VAR
     VAR
         report: ARRAY * OF STRING;
         report: ARRAY * OF STRING;
     BEGIN
     BEGIN
@@ -413,7 +420,7 @@ BEGIN
     SELF.customConstructorDefined := TRUE;
     SELF.customConstructorDefined := TRUE;
 END;
 END;
 
 
-PROCEDURE collectAbstractMethods(r: Record);
+PROCEDURE collectAbstractMethods(VAR r: Record);
 VAR
 VAR
     methods: ARRAY * OF STRING;
     methods: ARRAY * OF STRING;
 BEGIN
 BEGIN

+ 9 - 0
src/eberon/EberonRtl.ob

@@ -0,0 +1,9 @@
+MODULE EberonRtl;
+IMPORT OberonRtl;
+TYPE
+    Type* = RECORD(OberonRtl.Type)
+        clearMap*: PROCEDURE(s: STRING): STRING;
+    END;
+    PType* = POINTER TO Type;
+
+END EberonRtl.

+ 1 - 1
src/eberon/EberonTypes.ob

@@ -72,7 +72,7 @@ PROCEDURE MethodField.asVar(isReadOnly: BOOLEAN; cx: Context.Type): Types.PId;
     RETURN NEW MethodVariable(SELF.method)
     RETURN NEW MethodVariable(SELF.method)
 END;
 END;
 
 
-PROCEDURE MethodField.designatorCode(leadCode: STRING): Types.PFieldCode;
+PROCEDURE MethodField.designatorCode(leadCode: STRING; cx: Context.Type): Types.PFieldCode;
     RETURN NEW Types.FieldCode(leadCode + "." + Types.mangleField(SELF.method.name, SELF.method), "", "");
     RETURN NEW Types.FieldCode(leadCode + "." + Types.mangleField(SELF.method.name, SELF.method), "", "");
 END;
 END;
 
 

+ 3 - 1
src/eberon/eberon_grammar.js

@@ -6,6 +6,7 @@ var EbArray = require("js/EberonArray.js");
 var CodeGenerator = require("js/CodeGenerator.js");
 var CodeGenerator = require("js/CodeGenerator.js");
 var EbContext = require("eberon/eberon_context.js");
 var EbContext = require("eberon/eberon_context.js");
 var Grammar = require("grammar.js");
 var Grammar = require("grammar.js");
+var EbRtl = require("js/EberonRtl.js");
 var Parser = require("parser.js");
 var Parser = require("parser.js");
 var Symbols = require("js/EberonSymbols.js");
 var Symbols = require("js/EberonSymbols.js");
 
 
@@ -166,5 +167,6 @@ exports.language = {
     codeGenerator: {
     codeGenerator: {
         make: CodeGenerator.makeGenerator,
         make: CodeGenerator.makeGenerator,
         nil: CodeGenerator.nullGenerator()
         nil: CodeGenerator.nullGenerator()
-    }
+    },
+    rtlBase: EbRtl.Type
 };
 };

+ 2 - 2
src/nodejs.js

@@ -4,7 +4,7 @@ var Class = require("rtl.js").Class;
 var Code = require("js/Code.js");
 var Code = require("js/Code.js");
 var Context = require("context.js");
 var Context = require("context.js");
 var oc = require("oc.js");
 var oc = require("oc.js");
-var RTL = require("rtl_code.js").RTL;
+var makeRTL = require("rtl_code.js").makeRTL;
 var Type = require("js/Types.js");
 var Type = require("js/Types.js");
 
 
 var fs = require("fs");
 var fs = require("fs");
@@ -57,7 +57,7 @@ function writeCompiledModule(name, code, outDir){
 
 
 function compile(sources, language, handleErrors, includeDirs, outDir, importDir){
 function compile(sources, language, handleErrors, includeDirs, outDir, importDir){
     var rtlCodeWatcher = new RtlCodeUsingWatcher();
     var rtlCodeWatcher = new RtlCodeUsingWatcher();
-    var rtl = new RTL(rtlCodeWatcher.using.bind(rtlCodeWatcher));
+    var rtl = new makeRTL(language.rtlBase, rtlCodeWatcher.using.bind(rtlCodeWatcher));
     var moduleCode = function(name, imports){
     var moduleCode = function(name, imports){
         return new ModuleGenerator(name, imports, importDir);};
         return new ModuleGenerator(name, imports, importDir);};
 
 

+ 2 - 2
src/ob/Module.ob

@@ -50,7 +50,7 @@ PROCEDURE AnyType.callGenerator(cx: LanguageContext.PType): Procedure.PCallGener
     RETURN makeCallGenerator(cx)
     RETURN makeCallGenerator(cx)
 END AnyType.callGenerator;
 END AnyType.callGenerator;
 
 
-PROCEDURE AnyType.denote(id: STRING): Types.PField;
+PROCEDURE AnyType.denote(id: STRING; isReadObly: BOOLEAN): Types.PField;
     RETURN NEW AnyField(id);
     RETURN NEW AnyField(id);
 END;
 END;
 
 
@@ -74,7 +74,7 @@ PROCEDURE AnyField.asVar(isReadOnly: BOOLEAN; cx: Context.Type): Types.PId;
     RETURN any.asVar
     RETURN any.asVar
 END AnyField.asVar;
 END AnyField.asVar;
 
 
-PROCEDURE AnyField.designatorCode(leadCode: STRING): Types.PFieldCode;
+PROCEDURE AnyField.designatorCode(leadCode: STRING; cx: Context.Type): Types.PFieldCode;
     RETURN NEW Types.FieldCode(leadCode + "." + SELF.mId, "", "");
     RETURN NEW Types.FieldCode(leadCode + "." + SELF.mId, "", "");
 END;
 END;
 
 

+ 3 - 3
src/ob/Scope.ob

@@ -104,14 +104,14 @@ BEGIN
     SELF.addSymbol(SELF.symbol, FALSE);
     SELF.addSymbol(SELF.symbol, FALSE);
 END;
 END;
 
 
-PROCEDURE addUnresolved*(s: Type; id: STRING);
+PROCEDURE addUnresolved*(VAR s: Type; id: STRING);
 BEGIN
 BEGIN
     IF s.unresolved.indexOf(id) = -1 THEN
     IF s.unresolved.indexOf(id) = -1 THEN
         s.unresolved.add(id);
         s.unresolved.add(id);
     END;
     END;
 END addUnresolved;
 END addUnresolved;
 
 
-PROCEDURE resolve*(s: Type; symbol: Symbols.PSymbol);
+PROCEDURE resolve*(VAR s: Type; symbol: Symbols.PSymbol);
 VAR
 VAR
     id: STRING;
     id: STRING;
     i: INTEGER;
     i: INTEGER;
@@ -205,7 +205,7 @@ END Procedure.addSymbol;
 
 
 PROCEDURE generateTempVar(pattern: STRING; VAR counter: INTEGER): STRING;
 PROCEDURE generateTempVar(pattern: STRING; VAR counter: INTEGER): STRING;
 BEGIN
 BEGIN
-    counter := counter + 1;
+    INC(counter);
     RETURN "$" + pattern + String.fromInt(counter);
     RETURN "$" + pattern + String.fromInt(counter);
 END;
 END;
 
 

+ 8 - 8
src/ob/Types.ob

@@ -102,7 +102,7 @@ TYPE
         PROCEDURE exported*(): BOOLEAN;
         PROCEDURE exported*(): BOOLEAN;
         PROCEDURE type*(): PType;
         PROCEDURE type*(): PType;
         PROCEDURE asVar*(isReadOnly: BOOLEAN; cx: Context.Type): PId;
         PROCEDURE asVar*(isReadOnly: BOOLEAN; cx: Context.Type): PId;
-        PROCEDURE designatorCode*(leadCode: STRING): PFieldCode;
+        PROCEDURE designatorCode*(leadCode: STRING; cx: Context.Type): PFieldCode;
     END;
     END;
     PField* = POINTER TO Field;
     PField* = POINTER TO Field;
 
 
@@ -118,7 +118,7 @@ TYPE
 
 
     StorageType* = RECORD(Type)    
     StorageType* = RECORD(Type)    
         PROCEDURE initializer*(cx: Context.Type): STRING;
         PROCEDURE initializer*(cx: Context.Type): STRING;
-        PROCEDURE denote*(id: STRING): PField;
+        PROCEDURE denote*(id: STRING; isReadObly: BOOLEAN): PField;
     END;
     END;
     PStorageType* = POINTER TO StorageType;
     PStorageType* = POINTER TO StorageType;
 
 
@@ -484,10 +484,10 @@ BEGIN
     RETURN result
     RETURN result
 END existingField;
 END existingField;
 
 
-PROCEDURE Record.denote(id: STRING): PField;
+PROCEDURE Record.denote(id: STRING; isReadObly: BOOLEAN): PField;
 BEGIN
 BEGIN
     RETURN existingField(SELF, id, SELF)
     RETURN existingField(SELF, id, SELF)
-END Record.denote;
+END;
 
 
 PROCEDURE recordBase*(r: Record): PRecord;
 PROCEDURE recordBase*(r: Record): PRecord;
     RETURN r.base
     RETURN r.base
@@ -536,7 +536,7 @@ PROCEDURE Pointer.initializer(cx: Context.Type): STRING;
     RETURN "null"
     RETURN "null"
 END Pointer.initializer;
 END Pointer.initializer;
 
 
-PROCEDURE Pointer.denote(id: STRING): PField;
+PROCEDURE Pointer.denote(id: STRING; isReadObly: BOOLEAN): PField;
 VAR
 VAR
     d: POINTER TO NamedType;
     d: POINTER TO NamedType;
 BEGIN
 BEGIN
@@ -547,7 +547,7 @@ BEGIN
         d := SELF(POINTER);
         d := SELF(POINTER);
     END;
     END;
     RETURN existingField(base^, id, d^)
     RETURN existingField(base^, id, d^)
-END Pointer.denote;
+END;
 
 
 PROCEDURE foldArrayDimensions(VAR a: Array; dimToStr: ArrayDimensionDescriptionCallback; VAR sizes, of: STRING);
 PROCEDURE foldArrayDimensions(VAR a: Array; dimToStr: ArrayDimensionDescriptionCallback; VAR sizes, of: STRING);
 BEGIN  
 BEGIN  
@@ -592,7 +592,7 @@ PROCEDURE Array.description(): STRING;
     RETURN arrayDescription(SELF, arrayDimensionDescription)
     RETURN arrayDescription(SELF, arrayDimensionDescription)
 END Array.description;
 END Array.description;
 
 
-PROCEDURE StorageType.denote(id: STRING): PField;
+PROCEDURE StorageType.denote(id: STRING; isReadObly: BOOLEAN): PField;
 BEGIN
 BEGIN
     Errors.raise("selector '." + id + "' cannot be applied to '" 
     Errors.raise("selector '." + id + "' cannot be applied to '" 
                + SELF.description() + "'");
                + SELF.description() + "'");
@@ -773,7 +773,7 @@ PROCEDURE RecordField.identdef(): Context.PIdentdefInfo;
     RETURN SELF.mIdentdef;
     RETURN SELF.mIdentdef;
 END;
 END;
 
 
-PROCEDURE RecordField.designatorCode(leadCode: STRING): PFieldCode;
+PROCEDURE RecordField.designatorCode(leadCode: STRING; cx: Context.Type): PFieldCode;
 CONST
 CONST
     kQuote = 22X;
     kQuote = 22X;
 BEGIN
 BEGIN

+ 3 - 1
src/oberon/oberon_grammar.js

@@ -5,6 +5,7 @@ var CodeGenerator = require("js/CodeGenerator.js");
 var Context = require("context.js");
 var Context = require("context.js");
 var Grammar = require("grammar.js");
 var Grammar = require("grammar.js");
 var ObContext = require("oberon/oberon_context.js");
 var ObContext = require("oberon/oberon_context.js");
+var ObRtl = require("js/OberonRtl.js");
 var Parser = require("parser.js");
 var Parser = require("parser.js");
 var Symbols = require("js/OberonSymbols.js");
 var Symbols = require("js/OberonSymbols.js");
 var Types = require("js/Types.js");
 var Types = require("js/Types.js");
@@ -133,7 +134,8 @@ exports.language = {
     codeGenerator: {
     codeGenerator: {
         make: CodeGenerator.makeGenerator,
         make: CodeGenerator.makeGenerator,
         nil: CodeGenerator.nullGenerator()
         nil: CodeGenerator.nullGenerator()
-    }
+    },
+    rtlBase: ObRtl.Type
 };
 };
 
 
 
 

+ 2 - 2
src/oc.js

@@ -5,7 +5,7 @@ var Code = require("js/Code.js");
 var Context = require("context.js");
 var Context = require("context.js");
 var Errors = require("js/Errors.js");
 var Errors = require("js/Errors.js");
 var Lexer = require("js/Lexer.js");
 var Lexer = require("js/Lexer.js");
-var RTL = require("rtl_code.js").RTL;
+var makeRTL = require("rtl_code.js").makeRTL;
 var Scope = require("js/Scope.js");
 var Scope = require("js/Scope.js");
 var Stream = require("js/Stream.js");
 var Stream = require("js/Stream.js");
 
 
@@ -122,7 +122,7 @@ function compileModules(names, moduleReader, grammar, contextFactory, handleErro
 
 
 function compile(text, language, handleErrors){
 function compile(text, language, handleErrors){
     var result = "";
     var result = "";
-    var rtl = new RTL();
+    var rtl = new makeRTL(language.rtlBase);
     var moduleCode = function(name, imports){return new Code.ModuleGenerator(name, imports);};
     var moduleCode = function(name, imports){return new Code.ModuleGenerator(name, imports);};
     var resolver = makeResolver(
     var resolver = makeResolver(
             language.grammar,
             language.grammar,

+ 5 - 0
src/rtl.js

@@ -60,6 +60,10 @@ var impl = {
             throw new Error("invalid key: " + key);
             throw new Error("invalid key: " + key);
         return map[key];
         return map[key];
     },
     },
+    clearMap: function(map){
+        for(var p in map)
+            delete map[p];
+    },
     makeArray: function(/*dimensions, initializer*/){
     makeArray: function(/*dimensions, initializer*/){
         var forward = Array.prototype.slice.call(arguments);
         var forward = Array.prototype.slice.call(arguments);
         var result = new Array(forward.shift());
         var result = new Array(forward.shift());
@@ -247,5 +251,6 @@ exports.dependencies = {
     "__makeCharArray": ["__setupCharArrayMethods"]
     "__makeCharArray": ["__setupCharArrayMethods"]
 };
 };
 
 
+exports.methods = impl;
 for(var e in impl)
 for(var e in impl)
     exports[e] = impl[e];
     exports[e] = impl[e];

+ 24 - 11
src/rtl_code.js

@@ -1,6 +1,7 @@
 "use strict";
 "use strict";
 
 
 var Rtl = require("rtl.js");
 var Rtl = require("rtl.js");
+//var OberonRtl = require("js/OberonRtl.js");
 
 
 // support IE8
 // support IE8
 if (!Array.prototype.indexOf)
 if (!Array.prototype.indexOf)
@@ -21,16 +22,16 @@ if (!Function.prototype.bind)
         };
         };
     };
     };
 
 
-exports.RTL = Rtl.Class.extend({
-    init: function RTL(demandedCallback){
-        this.__entries = {};
-        this.__demandedCallback = demandedCallback;
+function RtlCons(demandedCallback){
+    this.__entries = {};
+    this.__demandedCallback = demandedCallback;
 
 
-        for(var name in Rtl){
-            this[name] = this.__makeOnDemand(name);
-            this[name + "Id"] = this.__makeIdOnDemand(name);
-        }
-    },
+    for(var name in Rtl.methods){
+        this[name] = this.__makeOnDemand(name);
+        this[name + "Id"] = this.__makeIdOnDemand(name);
+    }
+}
+var rtlPrototype = {
     name: function(){return "RTL$";},
     name: function(){return "RTL$";},
     generate: function(){
     generate: function(){
         var result = "var " + this.name() + " = {\n";
         var result = "var " + this.name() + " = {\n";
@@ -51,7 +52,7 @@ exports.RTL = Rtl.Class.extend({
     },
     },
     __putEntry: function(name){
     __putEntry: function(name){
         if (!this.__entries[name])
         if (!this.__entries[name])
-            this.__entries[name] = Rtl[name];
+            this.__entries[name] = Rtl.methods[name];
         
         
         var dependencies = Rtl.dependencies[name];
         var dependencies = Rtl.dependencies[name];
         if (dependencies)
         if (dependencies)
@@ -78,5 +79,17 @@ exports.RTL = Rtl.Class.extend({
             return result;
             return result;
         };
         };
     }
     }
+};
+
+function makeRTL(base, demandedCallback){
+    function RTL(){
+        RtlCons.apply(this, arguments);
+    }
+
+    Rtl.extend(RTL, base);
+    for(var m in rtlPrototype)
+        RTL.prototype[m] = rtlPrototype[m];
+    return new RTL(demandedCallback);
+}
 
 
-});
+exports.makeRTL = makeRTL;

+ 10 - 0
test/expected/eberon/map.js

@@ -62,6 +62,10 @@ var RTL$ = {
                                                   : this.cloneRecord(v);
                                                   : this.cloneRecord(v);
             }
             }
         }
         }
+    },
+    clearMap: function (map){
+        for(var p in map)
+            delete map[p];
     }
     }
 };
 };
 var test = function (){
 var test = function (){
@@ -158,6 +162,12 @@ function remove(){
 	var m = {};
 	var m = {};
 	delete m["abc"];
 	delete m["abc"];
 }
 }
+
+function clear(){
+	var m = {};
+	RTL$.clearMap(m);
+	RTL$.clearMap(m);
+}
 var $map1 = m;
 var $map1 = m;
 for(var k in $map1){
 for(var k in $map1){
 	var v = $map1[k];
 	var v = $map1[k];

+ 8 - 0
test/input/eberon/map.ob

@@ -97,6 +97,14 @@ BEGIN
     m.remove("abc");
     m.remove("abc");
 END;
 END;
 
 
+PROCEDURE clear();
+VAR
+    m: MapOfInteger;
+BEGIN
+    m.clear();
+    m.clear;
+END;
+
 BEGIN
 BEGIN
     FOREACH v, k IN m DO
     FOREACH v, k IN m DO
         FOREACH v2, k2 IN m DO
         FOREACH v2, k2 IN m DO

+ 2 - 2
test/test_unit_common.js

@@ -5,7 +5,7 @@ var Code = require("js/Code.js");
 var Context = require("context.js");
 var Context = require("context.js");
 var Errors = require("js/Errors.js");
 var Errors = require("js/Errors.js");
 var oc = require("oc.js");
 var oc = require("oc.js");
-var RTL = require("rtl_code.js").RTL;
+var makeRTL = require("rtl_code.js").makeRTL;
 var Scope = require("js/Scope.js");
 var Scope = require("js/Scope.js");
 var Stream = require("js/Stream.js");
 var Stream = require("js/Stream.js");
 var Test = require("test.js");
 var Test = require("test.js");
@@ -32,7 +32,7 @@ var TestContext = Context.Context.extend({
                 this,
                 this,
                 { codeGenerator: language.codeGenerator.nil,
                 { codeGenerator: language.codeGenerator.nil,
                   moduleGenerator: function(){return new TestModuleGenerator();},
                   moduleGenerator: function(){return new TestModuleGenerator();},
-                  rtl: new RTL(),
+                  rtl: new makeRTL(language.rtlBase),
                   types: language.types,
                   types: language.types,
                   stdSymbols: language.stdSymbols
                   stdSymbols: language.stdSymbols
                 });
                 });

+ 28 - 0
test/test_unit_eberon.js

@@ -1073,6 +1073,18 @@ exports.suite = {
                         "VAR a: ARRAY * OF INTEGER;"),
                         "VAR a: ARRAY * OF INTEGER;"),
                 pass("a.clear()"),
                 pass("a.clear()"),
                 fail(["a.clear(0)", "0 argument(s) expected, got 1"])
                 fail(["a.clear(0)", "0 argument(s) expected, got 1"])
+            ),
+            "add, remove and clear cannot be called for read-only array": testWithContext(
+                context(grammar.declarationSequence, 
+                        "TYPE T = RECORD a: ARRAY * OF INTEGER; END;"),
+                pass("PROCEDURE p(VAR r: T); BEGIN r.a.add(1); END;",
+                     "PROCEDURE p(VAR r: T); BEGIN r.a.remove(1); END;",
+                     "PROCEDURE p(VAR r: T); BEGIN r.a.clear(); END;"
+                     ),
+                fail(["PROCEDURE p(r: T); BEGIN r.a.add(1); END;", "method 'add' cannot be applied to non-VAR dynamic array"],
+                     ["PROCEDURE p(r: T); BEGIN r.a.remove(1); END;", "method 'remove' cannot be applied to non-VAR dynamic array"],
+                     ["PROCEDURE p(r: T); BEGIN r.a.clear(); END;", "method 'clear' cannot be applied to non-VAR dynamic array"]
+                    )
             )
             )
         }
         }
     },
     },
@@ -1415,6 +1427,22 @@ exports.suite = {
              ["m.remove(\"abc\", \"abc\")", "1 argument(s) expected, got 2"],
              ["m.remove(\"abc\", \"abc\")", "1 argument(s) expected, got 2"],
              ["v <- m.remove", "MAP's method 'remove' cannot be referenced"]
              ["v <- m.remove", "MAP's method 'remove' cannot be referenced"]
             )
             )
+        ),
+    "clear": testWithContext(
+        context(grammar.statement,
+                "VAR m: MAP OF INTEGER;"),
+        pass("m.clear()", "m.clear"),
+        fail(["m.clear(123)", "0 argument(s) expected, got 1"]
+            )
+        ),
+    "clear and remove cannot be applied to read only map": testWithContext(
+        context(grammar.declarationSequence,
+                "TYPE M = MAP OF INTEGER;"),
+        pass("PROCEDURE p(VAR m: M); BEGIN; m.remove(\"abc\"); END;",
+             "PROCEDURE p(VAR m: M); BEGIN; m.clear(); END;"),
+        fail(["PROCEDURE p(m: M); BEGIN; m.remove(\"abc\"); END;", "method 'remove' cannot be applied to non-VAR MAP"],
+             ["PROCEDURE p(m: M); BEGIN; m.clear(); END;", "method 'clear' cannot be applied to non-VAR MAP"]
+            )
         )
         )
     }
     }
 };
 };