Browse Source

Check indexes for arrays (on write) as an option.
Bug fixes.

Vladislav Folts 9 years ago
parent
commit
a7ce93348e

BIN
bin/compiled.zip


+ 1 - 1
build.py

@@ -130,7 +130,7 @@ def recompile(bin, cwd):
                'EberonSymbols.ob', 
                'EberonSymbols.ob', 
                'EberonContextCase.ob', 'EberonContextExpression.ob', 'EberonContextIdentdef.ob', 
                'EberonContextCase.ob', 'EberonContextExpression.ob', 'EberonContextIdentdef.ob', 
                'EberonContextIf.ob', 'EberonContextInPlace.ob', 'EberonContextType.ob', 
                'EberonContextIf.ob', 'EberonContextInPlace.ob', 'EberonContextType.ob', 
-               'EberonContextVar.ob',
+               'EberonContextVar.ob', 'EberonLanguageContext.ob',
                'OberonContext.ob', 'OberonContextType.ob', 'OberonContextVar.ob',
                'OberonContext.ob', 'OberonContextType.ob', 'OberonContextVar.ob',
                'OberonSymbols.ob', 'Lexer.ob', 'Module.ob']
                'OberonSymbols.ob', 'Lexer.ob', 'Module.ob']
     
     

+ 3 - 3
src/eberon/EberonCast.ob

@@ -1,6 +1,6 @@
 MODULE EberonCast;
 MODULE EberonCast;
 IMPORT 
 IMPORT 
-    Cast, Code, Context, 
+    Cast, Code, Context, Designator, 
     EberonMap, EberonString, EberonOperator, EberonDynamicArray, Expression, 
     EberonMap, EberonString, EberonOperator, EberonDynamicArray, Expression, 
     LanguageContext, OberonRtl, Types;
     LanguageContext, OberonRtl, Types;
 TYPE
 TYPE
@@ -30,7 +30,7 @@ BEGIN
     RETURN result
     RETURN result
 END;
 END;
 
 
-PROCEDURE CastOpToDynamicArray.assign(cx: LanguageContext.PType; left, right: Expression.PType): STRING;
+PROCEDURE CastOpToDynamicArray.assign(cx: LanguageContext.PType; left: Designator.Type; right: Expression.PType): STRING;
     RETURN copyArray(left.type()(Types.PArray), left.code(), right.code(), cx.language.rtl^)
     RETURN copyArray(left.type()(Types.PArray), left.code(), right.code(), cx.language.rtl^)
 END;
 END;
 
 
@@ -38,7 +38,7 @@ PROCEDURE CastOpToMap.make(cx: LanguageContext.PType; e: Expression.PType): Expr
     RETURN e;
     RETURN e;
 END;
 END;
 
 
-PROCEDURE CastOpToMap.assign(cx: LanguageContext.PType; left, right: Expression.PType): STRING;
+PROCEDURE CastOpToMap.assign(cx: LanguageContext.PType; left: Designator.Type; right: Expression.PType): STRING;
     RETURN cx.language.rtl.copy(right.code(), left.code(), EberonOperator.generateTypeInfo(left.type()));
     RETURN cx.language.rtl.copy(right.code(), left.code(), EberonOperator.generateTypeInfo(left.type()));
 END;
 END;
 
 

+ 10 - 34
src/eberon/EberonContextDesignator.ob

@@ -10,12 +10,12 @@ TYPE
     END;
     END;
     PType = POINTER TO Type;
     PType = POINTER TO Type;
 
 
-    MapElementVariable = RECORD(Types.Variable)
-        PROCEDURE MapElementVariable(type: Types.PStorageType; readOnly: BOOLEAN; code: STRING);
+    MapElementVariable* = RECORD(Types.Variable)
+        PROCEDURE MapElementVariable(type: Types.PStorageType; readOnly: BOOLEAN; lval, rval: STRING);
 
 
-        elementType: Types.PStorageType; 
+        elementType-: Types.PStorageType; 
         readOnly: BOOLEAN; 
         readOnly: BOOLEAN; 
-        code: STRING;
+        lval-, rval-: STRING;
     END;
     END;
 
 
     ResultVariable = RECORD(Types.Variable)
     ResultVariable = RECORD(Types.Variable)
@@ -134,7 +134,7 @@ BEGIN
         rtl <- SELF.root().language().rtl(EberonRtl.PType);
         rtl <- SELF.root().language().rtl(EberonRtl.PType);
         rval <- rtl.getMappedValue(code, indexCode);
         rval <- rtl.getMappedValue(code, indexCode);
         lval <- code + "[" + indexCode + "]";
         lval <- code + "[" + indexCode + "]";
-        var <- NEW MapElementVariable(indexType, info(Types.PVariable).isReadOnly(), rval);
+        var <- NEW MapElementVariable(indexType, info(Types.PVariable).isReadOnly(), lval, rval);
         result := NEW ContextDesignator.Index(0, indexType, var, rval, lval, "");
         result := NEW ContextDesignator.Index(0, indexType, var, rval, lval, "");
     ELSE
     ELSE
         result := SUPER(info, code, indexCode);
         result := SUPER(info, code, indexCode);
@@ -236,10 +236,11 @@ BEGIN
     END;
     END;
 END;
 END;
 
 
-PROCEDURE MapElementVariable.MapElementVariable(type: Types.PStorageType; readOnly: BOOLEAN; code: STRING)
+PROCEDURE MapElementVariable.MapElementVariable(type: Types.PStorageType; readOnly: BOOLEAN; lval, rval: STRING)
     | elementType(type),
     | elementType(type),
       readOnly(readOnly),
       readOnly(readOnly),
-      code(code);
+      lval(lval),
+      rval(rval);
 END;
 END;
 
 
 PROCEDURE MapElementVariable.type(): Types.PStorageType;
 PROCEDURE MapElementVariable.type(): Types.PStorageType;
@@ -254,20 +255,11 @@ PROCEDURE MapElementVariable.isReadOnly(): BOOLEAN;
     RETURN SELF.readOnly;
     RETURN SELF.readOnly;
 END;
 END;
 
 
-PROCEDURE MapElementVariable.referenceCode(): STRING;
-BEGIN
-    IF SELF.elementType.isScalar() THEN
-        Errors.raise("cannot reference map element of type '" 
-                     + SELF.elementType.description() + "'");
-    END;
-    RETURN SELF.code;        
-END;
-
 PROCEDURE MapElementVariable.idType(): STRING;
 PROCEDURE MapElementVariable.idType(): STRING;
 VAR
 VAR
     result: STRING;
     result: STRING;
 BEGIN
 BEGIN
-    result := "MAP's element";
+    result := "MAP's element of type '" + SELF.elementType.description() + "'";
     IF SELF.readOnly THEN
     IF SELF.readOnly THEN
         result := "read-only " + result;
         result := "read-only " + result;
     END;
     END;
@@ -286,11 +278,6 @@ PROCEDURE ResultVariable.isReference(): BOOLEAN;
     RETURN FALSE;
     RETURN FALSE;
 END;
 END;
 
 
-PROCEDURE ResultVariable.referenceCode(): STRING;
-BEGIN
-    RETURN "";        
-END;
-
 PROCEDURE ResultVariable.isReadOnly(): BOOLEAN;
 PROCEDURE ResultVariable.isReadOnly(): BOOLEAN;
     RETURN TRUE;
     RETURN TRUE;
 END;
 END;
@@ -331,11 +318,6 @@ PROCEDURE TypeNarrowVariable.isReadOnly(): BOOLEAN;
     RETURN SELF.readOnly;
     RETURN SELF.readOnly;
 END;
 END;
 
 
-PROCEDURE TypeNarrowVariable.referenceCode(): STRING;
-BEGIN
-    RETURN SELF.code;        
-END;
-
 PROCEDURE TypeNarrowVariable.id(): STRING;
 PROCEDURE TypeNarrowVariable.id(): STRING;
 BEGIN
 BEGIN
     RETURN SELF.code;        
     RETURN SELF.code;        
@@ -374,11 +356,6 @@ PROCEDURE DereferencedTypeNarrowVariable.isReadOnly(): BOOLEAN;
     RETURN FALSE;
     RETURN FALSE;
 END;
 END;
 
 
-PROCEDURE DereferencedTypeNarrowVariable.referenceCode(): STRING;
-BEGIN
-    RETURN SELF.var.code;        
-END;
-
 PROCEDURE DereferencedTypeNarrowVariable.id(): STRING;
 PROCEDURE DereferencedTypeNarrowVariable.id(): STRING;
 BEGIN
 BEGIN
     RETURN SELF.var.id();        
     RETURN SELF.var.id();        
@@ -426,8 +403,7 @@ BEGIN
     d <- SELF.attributes.designator;
     d <- SELF.attributes.designator;
     type <- d.type();
     type <- d.type();
     IF SELF.right # NIL THEN
     IF SELF.right # NIL THEN
-        left <- Expression.make(d.code(), type, d, NIL);
-        code := Operator.assign(left, SELF.right, ContextHierarchy.makeLanguageContext(SELF(POINTER)));
+        code := Operator.assign(d^, SELF.right, ContextHierarchy.makeLanguageContext(SELF(POINTER)));
     ELSIF ~(d.info()^ IS ResultVariable) THEN
     ELSIF ~(d.info()^ IS ResultVariable) THEN
         procCall <- ContextProcedure.makeCall(SELF(POINTER), type, d.info());
         procCall <- ContextProcedure.makeCall(SELF(POINTER), type, d.info());
         result <- procCall.end();
         result <- procCall.end();

+ 0 - 4
src/eberon/EberonContextLoop.ob

@@ -99,10 +99,6 @@ PROCEDURE ForEachVariable.idType(): STRING;
     RETURN "FOR variable";
     RETURN "FOR variable";
 END;
 END;
 
 
-PROCEDURE ForEachVariable.referenceCode(): STRING;
-    RETURN "";
-END;
-
 PROCEDURE ForEachVariable.isReference(): BOOLEAN;
 PROCEDURE ForEachVariable.isReference(): BOOLEAN;
     RETURN FALSE;
     RETURN FALSE;
 END;
 END;

+ 34 - 0
src/eberon/EberonLanguageContext.ob

@@ -0,0 +1,34 @@
+MODULE EberonLanguageContext;
+IMPORT 
+	EberonContextDesignator, EberonTypePromotion, Expression, LanguageContext, Types;
+TYPE
+	CodeTraits* = RECORD(LanguageContext.CodeTraits)
+	END;
+
+PROCEDURE CodeTraits.referenceCode(VAR info: Types.Id): STRING;
+VAR
+    result: STRING;
+BEGIN
+	IF info IS EberonTypePromotion.Variable THEN
+		result := info.id();
+	ELSIF (info IS EberonContextDesignator.MapElementVariable) & ~info.elementType.isScalar() THEN
+		result := info.rval;
+	ELSE
+		result := SUPER(info);
+	END;
+    RETURN result;
+END;
+
+PROCEDURE CodeTraits.assign(VAR info: Types.Id; right: Expression.PType): STRING;
+VAR
+    result: STRING;
+BEGIN
+	IF info IS EberonContextDesignator.MapElementVariable THEN
+    	result := info.lval + " = " + Expression.deref(right).code();
+    ELSE
+    	result := SUPER(info, right);
+    END;
+    RETURN result;
+END;
+
+END EberonLanguageContext.

+ 2 - 2
src/eberon/EberonOperator.ob

@@ -1,6 +1,6 @@
 MODULE EberonOperator;
 MODULE EberonOperator;
 IMPORT 
 IMPORT 
-    Cast, CodePrecedence, ConstValue, 
+    Cast, CodePrecedence, ConstValue, Designator, 
     EberonMap, EberonString, Expression, LanguageContext, 
     EberonMap, EberonString, Expression, LanguageContext, 
     OberonRtl, Operator, Record, Types;
     OberonRtl, Operator, Record, Types;
 TYPE
 TYPE
@@ -97,7 +97,7 @@ BEGIN
     RETURN result;
     RETURN result;
 END;
 END;
 
 
-PROCEDURE CastOpRecord.assign(cx: LanguageContext.PType; left, right: Expression.PType): STRING;
+PROCEDURE CastOpRecord.assign(cx: LanguageContext.PType; left: Designator.Type; right: Expression.PType): STRING;
 VAR
 VAR
     result: STRING;
     result: STRING;
 BEGIN
 BEGIN

+ 0 - 5
src/eberon/EberonString.ob

@@ -22,11 +22,6 @@ PROCEDURE ElementVariable.isReference(): BOOLEAN;
     RETURN FALSE
     RETURN FALSE
 END;
 END;
 
 
-PROCEDURE ElementVariable.referenceCode(): STRING;
-BEGIN
-    RETURN "";
-END;
-
 PROCEDURE makeElementVariable*(): Types.PVariable;
 PROCEDURE makeElementVariable*(): Types.PVariable;
     RETURN NEW ElementVariable();
     RETURN NEW ElementVariable();
 END;
 END;

+ 4 - 0
src/eberon/eberon_grammar.js

@@ -15,6 +15,7 @@ var EberonContextLoop = require("js/EberonContextLoop.js");
 var EberonContextProcedure = require("js/EberonContextProcedure.js");
 var EberonContextProcedure = require("js/EberonContextProcedure.js");
 var EberonContextType = require("js/EberonContextType.js");
 var EberonContextType = require("js/EberonContextType.js");
 var EberonContextVar = require("js/EberonContextVar.js");
 var EberonContextVar = require("js/EberonContextVar.js");
+var EberonLanguageContext = require("js/EberonLanguageContext.js");
 var Grammar = require("grammar.js");
 var Grammar = require("grammar.js");
 var EbRtl = require("js/EberonRtl.js");
 var EbRtl = require("js/EberonRtl.js");
 var EbRtlCode = require("eberon/eberon_rtl.js");
 var EbRtlCode = require("eberon/eberon_rtl.js");
@@ -195,6 +196,9 @@ exports.language = {
         make: function(){ return new CodeGenerator.Generator(); },                                                                                                                                                                                          
         make: function(){ return new CodeGenerator.Generator(); },                                                                                                                                                                                          
         nil: CodeGenerator.nullGenerator()
         nil: CodeGenerator.nullGenerator()
     },                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
     },                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
+    makeCodeTraits: function(codeGenerator, rtl, options){
+        return new EberonLanguageContext.CodeTraits(codeGenerator, rtl, options && options.checkIndexes); 
+    },
     rtl: {
     rtl: {
         base: EbRtl.Type,
         base: EbRtl.Type,
         methods: EbRtlCode.rtl.methods,
         methods: EbRtlCode.rtl.methods,

+ 13 - 2
src/nodejs.js

@@ -2,6 +2,7 @@
 
 
 var Class = require("rtl.js").Class;
 var Class = require("rtl.js").Class;
 var Code = require("js/Code.js");
 var Code = require("js/Code.js");
+var Errors = require("js/Errors.js");
 var ContextHierarchy = require("js/ContextHierarchy.js");
 var ContextHierarchy = require("js/ContextHierarchy.js");
 var LanguageContext = require("js/LanguageContext.js");
 var LanguageContext = require("js/LanguageContext.js");
 var oc = require("oc.js");
 var oc = require("oc.js");
@@ -62,12 +63,18 @@ function compile(sources, language, handleErrors, includeDirs, outDir, importDir
         return new ModuleGenerator(name, imports, importDir);};
         return new ModuleGenerator(name, imports, importDir);};
 
 
     var compiledFilesStack = [];
     var compiledFilesStack = [];
+    var failToCompile = {};
     oc.compileModules(
     oc.compileModules(
             sources,
             sources,
             function(name){
             function(name){
                 var fileName = name;
                 var fileName = name;
                 if (!path.extname(fileName).length)
                 if (!path.extname(fileName).length)
                     fileName += ".ob";
                     fileName += ".ob";
+                
+                var alreadyFail = failToCompile[fileName];
+                if (alreadyFail)
+                    throw new Errors.Error("'" + fileName + "': error " + alreadyFail);
+
                 compiledFilesStack.push(fileName);
                 compiledFilesStack.push(fileName);
 
 
                 var readPath = fileName;
                 var readPath = fileName;
@@ -83,14 +90,18 @@ function compile(sources, language, handleErrors, includeDirs, outDir, importDir
             language.grammar,
             language.grammar,
             function(moduleResolver){
             function(moduleResolver){
                 return new ContextHierarchy.Root(
                 return new ContextHierarchy.Root(
-                { codeTraits: new LanguageContext.CodeTraits(language.codeGenerator.make()),
+                { codeTraits: language.makeCodeTraits(language.codeGenerator.make(), rtl),
                   moduleGenerator: moduleCode,
                   moduleGenerator: moduleCode,
                   rtl: rtl,
                   rtl: rtl,
                   types: language.types,
                   types: language.types,
                   stdSymbols: language.stdSymbols,
                   stdSymbols: language.stdSymbols,
                   moduleResolver: moduleResolver
                   moduleResolver: moduleResolver
                 });},
                 });},
-            function(e){handleErrors("File \"" + compiledFilesStack[compiledFilesStack.length - 1] + "\", " + e);},
+            function(e){
+                var fileName = compiledFilesStack[compiledFilesStack.length - 1];
+                failToCompile[fileName] = e;
+                handleErrors("File \"" + fileName + "\", " + e);
+            },
             function(name, code){
             function(name, code){
                 if (rtlCodeWatcher.used()){
                 if (rtlCodeWatcher.used()){
                     code = "var " + rtl.name() + " = require(\"" + rtl.module() + "\");\n" + code;
                     code = "var " + rtl.name() + " = require(\"" + rtl.module() + "\");\n" + code;

+ 9 - 18
src/ob/Cast.ob

@@ -1,6 +1,6 @@
 MODULE Cast;
 MODULE Cast;
 IMPORT 
 IMPORT 
-    Expression, LanguageContext, OberonRtl, Record, String, TypeId, Types;
+    Designator, Expression, LanguageContext, OberonRtl, Record, String, TypeId, Types;
 CONST
 CONST
     errNo* = 0;
     errNo* = 0;
     err* = 1;
     err* = 1;
@@ -113,27 +113,18 @@ PROCEDURE CastOpDoNothing.make(cx: LanguageContext.PType; e: Expression.PType):
     RETURN e
     RETURN e
 END;
 END;
 
 
-PROCEDURE passedByReference*(e: Expression.PType): BOOLEAN;
+PROCEDURE passedByReference*(d: Designator.Type): BOOLEAN;
 BEGIN
 BEGIN
-    info <- e.designator().info();
+    info <- d.info();
     RETURN (info IS Types.PVariable) & info.isReference();
     RETURN (info IS Types.PVariable) & info.isReference();
 END;
 END;
 
 
-PROCEDURE assignByReference*(left, right: Expression.PType): STRING;
-    RETURN left.code() + ".set(" + Expression.deref(right).code() + ")";
+PROCEDURE assign*(cx: LanguageContext.PType; left: Designator.Type; right: Expression.PType): STRING;
+    RETURN cx.language.codeTraits.assign(left.info()^, right);
 END;
 END;
 
 
-PROCEDURE CastOpDoNothing.assign(cx: LanguageContext.PType; left, right: Expression.PType): STRING;
-VAR
-    result: STRING;
-BEGIN
-    rightConverted <- SELF.make(cx, right);
-    IF passedByReference(left) THEN
-        result := assignByReference(left, rightConverted);
-    ELSE
-        result := left.lval() + " = " + Expression.deref(rightConverted).code();
-    END;
-    RETURN result;
+PROCEDURE CastOpDoNothing.assign(cx: LanguageContext.PType; left: Designator.Type; right: Expression.PType): STRING;
+    RETURN assign(cx, left, SELF.make(cx, right));
 END;
 END;
 
 
 PROCEDURE CastOpDoNothing.clone(cx: LanguageContext.PType; e: Expression.PType): STRING;
 PROCEDURE CastOpDoNothing.clone(cx: LanguageContext.PType; e: Expression.PType): STRING;
@@ -153,7 +144,7 @@ BEGIN
     RETURN result
     RETURN result
 END;
 END;
 
 
-PROCEDURE CastOpArray.assign(cx: LanguageContext.PType; left, right: Expression.PType): STRING;
+PROCEDURE CastOpArray.assign(cx: LanguageContext.PType; left: Designator.Type; right: Expression.PType): STRING;
     RETURN left.code() + " = " + cloneArray(right.type()(Types.PArray), right.code(), cx)
     RETURN left.code() + " = " + cloneArray(right.type()(Types.PArray), right.code(), cx)
 END;
 END;
 
 
@@ -161,7 +152,7 @@ PROCEDURE CastOpArray.clone(cx: LanguageContext.PType; e: Expression.PType): STR
     RETURN cloneArray(e.type()(Types.PArray), e.code(), cx);
     RETURN cloneArray(e.type()(Types.PArray), e.code(), cx);
 END;
 END;
 
 
-PROCEDURE CastOpRecord.assign(cx: LanguageContext.PType; left, right: Expression.PType): STRING;
+PROCEDURE CastOpRecord.assign(cx: LanguageContext.PType; left: Designator.Type; right: Expression.PType): STRING;
     RETURN cx.language.rtl.copy(right.code(), left.lval(), Record.generateTypeInfo(left.type()));
     RETURN cx.language.rtl.copy(right.code(), left.lval(), Record.generateTypeInfo(left.type()));
 END;
 END;
 
 

+ 6 - 6
src/ob/ContextCase.ob

@@ -39,10 +39,10 @@ TYPE
         typeGuardHandled: BOOLEAN;
         typeGuardHandled: BOOLEAN;
     END;
     END;
 
 
-    GuardedVariable = RECORD(Types.Variable)
-        PROCEDURE GuardedVariable(caseVariable: Types.PVariable; guardedType: Types.PStorageType);
+    GuardedVariable = RECORD(Types.DeclaredVariable)
+        PROCEDURE GuardedVariable(caseVariable: Types.PDeclaredVariable; guardedType: Types.PStorageType);
 
 
-        caseVariable: Types.PVariable;
+        caseVariable: Types.PDeclaredVariable;
         guardedType: Types.PStorageType;
         guardedType: Types.PStorageType;
     END;
     END;
 
 
@@ -276,7 +276,7 @@ BEGIN
     RETURN TRUE;
     RETURN TRUE;
 END;
 END;
 
 
-PROCEDURE GuardedVariable.GuardedVariable(caseVariable: Types.PVariable; guardedType: Types.PStorageType)
+PROCEDURE GuardedVariable.GuardedVariable(caseVariable: Types.PDeclaredVariable; guardedType: Types.PStorageType)
     | caseVariable(caseVariable),
     | caseVariable(caseVariable),
       guardedType(guardedType);
       guardedType(guardedType);
 END;
 END;
@@ -293,8 +293,8 @@ PROCEDURE GuardedVariable.isReference(): BOOLEAN;
     RETURN SELF.caseVariable.isReference();
     RETURN SELF.caseVariable.isReference();
 END;
 END;
 
 
-PROCEDURE GuardedVariable.referenceCode(): STRING;
-    RETURN SELF.caseVariable.referenceCode();
+PROCEDURE GuardedVariable.id(): STRING;
+    RETURN SELF.caseVariable.id();
 END;
 END;
 
 
 END ContextCase.
 END ContextCase.

+ 1 - 1
src/ob/ContextDesignator.ob

@@ -250,7 +250,7 @@ BEGIN
 
 
     readOnly <- (info IS Types.PConst) 
     readOnly <- (info IS Types.PConst) 
              OR ((info IS Types.PVariable) & info.isReadOnly());
              OR ((info IS Types.PVariable) & info.isReadOnly());
-    v <- NEW Variable.PropertyVariable(indexType, leadCode, indexCode, readOnly, SELF.root().language().rtl);
+    v <- NEW Variable.PropertyVariable(indexType, leadCode, indexCode, readOnly);
     RETURN NEW Index(length, indexType, v, wholeCode, lval, indexCode);
     RETURN NEW Index(length, indexType, v, wholeCode, lval, indexCode);
 END;
 END;
 
 

+ 0 - 13
src/ob/Expression.ob

@@ -11,7 +11,6 @@ TYPE
             maxPrecedence: INTEGER);
             maxPrecedence: INTEGER);
 
 
         PROCEDURE code*(): STRING;
         PROCEDURE code*(): STRING;
-        PROCEDURE lval*(): STRING;
         PROCEDURE type*(): Types.PType;
         PROCEDURE type*(): Types.PType;
         PROCEDURE designator*(): Designator.PType;
         PROCEDURE designator*(): Designator.PType;
         PROCEDURE constValue*(): ConstValue.PType;
         PROCEDURE constValue*(): ConstValue.PType;
@@ -31,18 +30,6 @@ PROCEDURE Type.code(): STRING;
     RETURN SELF.mCode
     RETURN SELF.mCode
 END;
 END;
 
 
-PROCEDURE Type.lval(): STRING;
-VAR
-    result: STRING;
-BEGIN
-    IF SELF.mDesignator # NIL THEN
-        result := SELF.mDesignator.lval();
-    ELSE
-        result := SELF.mCode;
-    END;
-    RETURN result
-END;
-
 PROCEDURE Type.type(): Types.PType;
 PROCEDURE Type.type(): Types.PType;
     RETURN SELF.mType
     RETURN SELF.mType
 END;
 END;

+ 73 - 6
src/ob/LanguageContext.ob

@@ -1,12 +1,12 @@
 MODULE LanguageContext;
 MODULE LanguageContext;
-IMPORT CodeGenerator, Context, Expression, OberonRtl, Symbols, T := Types;
+IMPORT Chars, CodeGenerator, Context, Designator, Errors, Expression, OberonRtl, Record, Symbols, T := Types, Variable;
 
 
 TYPE
 TYPE
     PType* = POINTER TO Type;
     PType* = POINTER TO Type;
 
 
     CastOp* = RECORD
     CastOp* = RECORD
         PROCEDURE make*(cx: PType; e: Expression.PType): Expression.PType;
         PROCEDURE make*(cx: PType; e: Expression.PType): Expression.PType;
-        PROCEDURE assign*(cx: PType; left, right: Expression.PType): STRING;
+        PROCEDURE assign*(cx: PType; left: Designator.Type; right: Expression.PType): STRING;
         PROCEDURE clone*(cx: PType; e: Expression.PType): STRING;
         PROCEDURE clone*(cx: PType; e: Expression.PType): STRING;
     END;
     END;
 
 
@@ -28,13 +28,17 @@ TYPE
     PModuleGenerator* = POINTER TO ModuleGenerator;
     PModuleGenerator* = POINTER TO ModuleGenerator;
 
 
     CodeTraits* = RECORD
     CodeTraits* = RECORD
-        PROCEDURE CodeTraits*(code: CodeGenerator.PIGenerator; rtl: OberonRtl.PType);
+        PROCEDURE CodeTraits*(code: CodeGenerator.PIGenerator; rtl: OberonRtl.PType; checkIndexes: BOOLEAN);
 
 
         PROCEDURE generator*(): CodeGenerator.PIGenerator;
         PROCEDURE generator*(): CodeGenerator.PIGenerator;
         PROCEDURE stringIndex*(e, index: STRING): STRING;
         PROCEDURE stringIndex*(e, index: STRING): STRING;
+        PROCEDURE putAt*(where, index, what: STRING): STRING;
+        PROCEDURE referenceCode*(VAR info: T.Id): STRING;
+        PROCEDURE assign*(VAR info: T.Id; right: Expression.PType): STRING;
 
 
         code: CodeGenerator.PIGenerator;
         code: CodeGenerator.PIGenerator;
         rtl: OberonRtl.PType;
         rtl: OberonRtl.PType;
+        checkIndexes: BOOLEAN;
     END;
     END;
 
 
     Imports = MAP OF STRING;
     Imports = MAP OF STRING;
@@ -61,9 +65,10 @@ PROCEDURE Type.Type(language: PLanguage; cx: Context.PType)
       cx(cx);
       cx(cx);
 END;
 END;
 
 
-PROCEDURE CodeTraits.CodeTraits(code: CodeGenerator.PIGenerator; rtl: OberonRtl.PType)
+PROCEDURE CodeTraits.CodeTraits(code: CodeGenerator.PIGenerator; rtl: OberonRtl.PType; checkIndexes: BOOLEAN)
     | code(code),
     | code(code),
-      rtl(rtl);
+      rtl(rtl),
+      checkIndexes(checkIndexes);
 END;
 END;
 
 
 PROCEDURE CodeTraits.generator(): CodeGenerator.PIGenerator;
 PROCEDURE CodeTraits.generator(): CodeGenerator.PIGenerator;
@@ -74,7 +79,7 @@ PROCEDURE CodeTraits.stringIndex(e, index: STRING): STRING;
 VAR
 VAR
     r: STRING;
     r: STRING;
 BEGIN
 BEGIN
-    IF SELF.rtl = NIL THEN
+    IF ~SELF.checkIndexes THEN
         r := e + ".charCodeAt(" + index + ")";
         r := e + ".charCodeAt(" + index + ")";
     ELSE
     ELSE
         r := SELF.rtl.charAt(e, index);
         r := SELF.rtl.charAt(e, index);
@@ -82,4 +87,66 @@ BEGIN
     RETURN r;
     RETURN r;
 END;
 END;
 
 
+PROCEDURE CodeTraits.putAt(where, index, what: STRING): STRING;
+VAR
+    r: STRING;
+BEGIN
+    IF ~SELF.checkIndexes THEN
+        r := where + "[" + index + "] = " + what;
+    ELSE
+        r := SELF.rtl.putAt(where, index, what);
+    END; 
+    RETURN r;
+END;
+
+PROCEDURE CodeTraits.referenceCode(VAR info: T.Id): STRING;
+VAR
+    result: STRING;
+BEGIN
+    IF info IS T.DeclaredVariable THEN
+        result := info.id();
+        IF info.type().isScalar() & ~((info IS Variable.ArgumentVariable) & info.var) THEN
+            result := "{set: function($v){" + result + " = $v;}, get: function(){return " + result + ";}}";
+        END
+    ELSIF info IS Variable.PropertyVariable THEN
+        IF info.type().isScalar() THEN
+            result := SELF.rtl.makeRef(info.leadCode, info.propCode);
+        ELSE
+            result := info.leadCode + "[" + info.propCode + "]";
+        END;
+    ELSIF info IS Variable.DerefVariable THEN
+        result := info.code;
+    ELSIF info IS Record.FieldVariable THEN
+        codeId <- Record.mangleField(info.field.id());
+        IF info.type().isScalar() THEN
+            result := SELF.rtl.makeRef(info.leadCode, 
+                                       Chars.doubleQuote + codeId + Chars.doubleQuote);
+        ELSE
+            result := info.leadCode + "." + codeId;
+        END;
+    ELSE
+        Errors.raise("cannot reference " + info.idType());
+    END;
+    RETURN result;
+END;
+
+PROCEDURE CodeTraits.assign(VAR info: T.Id; right: Expression.PType): STRING;
+VAR
+    result: STRING;
+BEGIN
+    rightCode <- Expression.deref(right).code();
+    IF info IS T.DeclaredVariable THEN
+        IF (info IS Variable.ArgumentVariable) & info.var THEN
+            result := info.id() + ".set(" + rightCode + ")";
+        ELSE
+            result := info.id() + " = " + rightCode;
+        END;
+    ELSIF info IS Variable.PropertyVariable THEN
+        result := SELF.putAt(info.leadCode, info.propCode, rightCode);
+    ELSIF info IS Record.FieldVariable THEN
+        result := info.leadCode + "." + Record.mangleField(info.field.id()) + " = " + rightCode;
+    END;
+    RETURN result;
+END;
+
 END LanguageContext.
 END LanguageContext.

+ 0 - 4
src/ob/Module.ob

@@ -87,10 +87,6 @@ PROCEDURE AnyVariable.isReference(): BOOLEAN;
     RETURN TRUE;
     RETURN TRUE;
 END;
 END;
 
 
-PROCEDURE AnyVariable.referenceCode(): STRING;
-    RETURN "";
-END;
-
 PROCEDURE AnyField.id(): STRING;
 PROCEDURE AnyField.id(): STRING;
     RETURN "any field"
     RETURN "any field"
 END AnyField.id;
 END AnyField.id;

+ 1 - 0
src/ob/OberonRtl.ob

@@ -15,6 +15,7 @@ TYPE
         PROCEDURE makeCharArray*(dimensions: STRING): STRING;
         PROCEDURE makeCharArray*(dimensions: STRING): STRING;
         PROCEDURE typeGuard*(from, to: STRING): STRING;
         PROCEDURE typeGuard*(from, to: STRING): STRING;
         PROCEDURE charAt*(s, index: STRING): STRING;
         PROCEDURE charAt*(s, index: STRING): STRING;
+        PROCEDURE putAt*(where, index, what: STRING): STRING;
     END;
     END;
     PType* = POINTER TO Type;
     PType* = POINTER TO Type;
 END OberonRtl.
 END OberonRtl.

+ 3 - 5
src/ob/Operator.ob

@@ -449,9 +449,8 @@ PROCEDURE strCmp(op: STRING; left, right: Expression.PType; cx: LanguageContext.
             Types.basic.bool)
             Types.basic.bool)
 END;
 END;
 
 
-PROCEDURE assign*(left, right: Expression.PType; cx: LanguageContext.PType): STRING;
+PROCEDURE assign*(left: Designator.Type; right: Expression.PType; cx: LanguageContext.PType): STRING;
 VAR
 VAR
-    designator: Designator.PType;
     leftCode, rightCode: STRING;
     leftCode, rightCode: STRING;
     isArray: BOOLEAN;
     isArray: BOOLEAN;
     castOperation: LanguageContext.PCastOp;
     castOperation: LanguageContext.PCastOp;
@@ -471,8 +470,7 @@ VAR
         RETURN cx.language.rtl.assignArrayFromString(leftCode, rightCode)
         RETURN cx.language.rtl.assignArrayFromString(leftCode, rightCode)
     END assignArrayFromString;
     END assignArrayFromString;
 BEGIN
 BEGIN
-    designator := left.designator();
-    info <- designator.info();
+    info <- left.info();
     IF ~(info IS Types.PVariable) OR info.isReadOnly() THEN
     IF ~(info IS Types.PVariable) OR info.isReadOnly() THEN
         Errors.raise("cannot assign to " + info.idType());
         Errors.raise("cannot assign to " + info.idType());
     END; 
     END; 
@@ -511,7 +509,7 @@ BEGIN
     designator := left.designator();
     designator := left.designator();
     info <- designator.info();
     info <- designator.info();
     IF (info IS Types.PVariable) & info.isReference() THEN
     IF (info IS Types.PVariable) & info.isReference() THEN
-        result := assign(left, altOp(left, right), cx);
+        result := assign(designator^, altOp(left, right), cx);
     ELSE
     ELSE
         rightExp := Expression.deref(right);
         rightExp := Expression.deref(right);
         result := left.code() + code + rightExp.code();
         result := left.code() + code + rightExp.code();

+ 5 - 6
src/ob/Procedure.ob

@@ -206,8 +206,7 @@ VAR
     coercedArg: Expression.PType;
     coercedArg: Expression.PType;
 BEGIN
 BEGIN
     IF (expected # NIL) & expected.isVar THEN
     IF (expected # NIL) & expected.isVar THEN
-        referenceCode <- actual.designator().info()(Types.PVariable).referenceCode();
-        coercedArg := Expression.makeSimple(referenceCode, actual.type());
+        coercedArg := Expression.makeSimple(SELF.cx.language.codeTraits.referenceCode(actual.designator().info()^), actual.type());
     ELSE
     ELSE
         coercedArg := Expression.deref(actual);
         coercedArg := Expression.deref(actual);
     END;
     END;
@@ -337,7 +336,7 @@ PROCEDURE makeNew(): Symbols.PSymbol;
                 Errors.raise("non-exported RECORD type cannot be used in NEW");
                 Errors.raise("non-exported RECORD type cannot be used in NEW");
             END;
             END;
             right <- Expression.makeSimple(baseType.codeForNew(cx.cx^), argType);
             right <- Expression.makeSimple(baseType.codeForNew(cx.cx^), argType);
-            result := Expression.makeSimple(Operator.assign(arg, right, cx), NIL);
+            result := Expression.makeSimple(Operator.assign(arg.designator()^, right, cx), NIL);
         END;
         END;
         RETURN result;
         RETURN result;
     END;
     END;
@@ -518,14 +517,14 @@ PROCEDURE incImpl(name: STRING; unary: STRING; incOp: BinaryOpStr; incRefOp: Ope
         checkVariableArgumentsCount(1, 2, args);
         checkVariableArgumentsCount(1, 2, args);
         checkArgumentsType(args, SELF.args, NIL, cx.language.types);
         checkArgumentsType(args, SELF.args, NIL, cx.language.types);
         x := args[0];
         x := args[0];
-        IF Cast.passedByReference(x) THEN
+        IF Cast.passedByReference(x.designator()^) THEN
             IF LEN(args) = 1 THEN
             IF LEN(args) = 1 THEN
                 y := Expression.makeSimple("1", NIL);
                 y := Expression.makeSimple("1", NIL);
             ELSE
             ELSE
                 y := args[1];
                 y := args[1];
             END;
             END;
             addExp <- SELF.incRefOp(x, y);
             addExp <- SELF.incRefOp(x, y);
-            code := Cast.assignByReference(x, addExp);
+            code := Cast.assign(cx, x.designator()^, addExp);
         ELSIF LEN(args) = 1 THEN
         ELSIF LEN(args) = 1 THEN
             code := SELF.unary + x.code();
             code := SELF.unary + x.code();
         ELSE
         ELSE
@@ -774,7 +773,7 @@ PROCEDURE makeUnpk(): Symbols.PSymbol;
         x := args[0];
         x := args[0];
         y := args[1];
         y := args[1];
         RETURN Expression.makeSimple(
         RETURN Expression.makeSimple(
-                Operator.assign(y, Operator.log2(x), cx) 
+                Operator.assign(y.designator()^, Operator.log2(x), cx) 
                 + "; "
                 + "; "
                 + Operator.divInplace(x, Operator.pow2(y), cx),
                 + Operator.divInplace(x, Operator.pow2(y), cx),
             NIL)
             NIL)

+ 7 - 23
src/ob/Record.ob

@@ -1,6 +1,6 @@
 MODULE Record;
 MODULE Record;
 IMPORT
 IMPORT
-    Chars, Context, Errors, OberonRtl, Object, ScopeBase, TypeId, Types;
+    Chars, Context, Errors, Object, ScopeBase, TypeId, Types;
 TYPE
 TYPE
     FieldsMap = MAP OF Types.PField;
     FieldsMap = MAP OF Types.PField;
 
 
@@ -41,12 +41,11 @@ TYPE
     PPointer* = POINTER TO Pointer;
     PPointer* = POINTER TO Pointer;
 
 
     FieldVariable* = RECORD(Types.Variable)
     FieldVariable* = RECORD(Types.Variable)
-        PROCEDURE FieldVariable(f: PField; leadCode: STRING; isReadOnly: BOOLEAN; rtl: OberonRtl.PType);
+        PROCEDURE FieldVariable(f: PField; leadCode: STRING; isReadOnly: BOOLEAN);
 
 
-        field: PField;
-        leadCode: STRING;
+        field-: PField;
+        leadCode-: STRING;
         readOnly: BOOLEAN;
         readOnly: BOOLEAN;
-        rtl: OberonRtl.PType;
     END;
     END;
 
 
 VAR
 VAR
@@ -229,7 +228,7 @@ PROCEDURE Field.type(): Types.PStorageType;
 END;
 END;
 
 
 PROCEDURE Field.asVar(leadCode: STRING; isReadOnly: BOOLEAN; cx: Context.Type): Types.PId;
 PROCEDURE Field.asVar(leadCode: STRING; isReadOnly: BOOLEAN; cx: Context.Type): Types.PId;
-    RETURN NEW FieldVariable(SELF(POINTER), leadCode, isReadOnly, cx.rtl());
+    RETURN NEW FieldVariable(SELF(POINTER), leadCode, isReadOnly);
 END;
 END;
 
 
 PROCEDURE Field.Field(identdef: Context.PIdentdefInfo; type: Types.PStorageType)
 PROCEDURE Field.Field(identdef: Context.PIdentdefInfo; type: Types.PStorageType)
@@ -279,11 +278,10 @@ PROCEDURE Pointer.isScalar(): BOOLEAN;
     RETURN TRUE;
     RETURN TRUE;
 END;
 END;
 
 
-PROCEDURE FieldVariable.FieldVariable(f: PField; leadCode: STRING; isReadOnly: BOOLEAN; rtl: OberonRtl.PType)
+PROCEDURE FieldVariable.FieldVariable(f: PField; leadCode: STRING; isReadOnly: BOOLEAN)
     | field(f),
     | field(f),
       leadCode(leadCode),
       leadCode(leadCode),
-      readOnly(isReadOnly),
-      rtl(rtl);
+      readOnly(isReadOnly);
 END;
 END;
 
 
 PROCEDURE FieldVariable.idType(): STRING;
 PROCEDURE FieldVariable.idType(): STRING;
@@ -301,20 +299,6 @@ PROCEDURE FieldVariable.type(): Types.PStorageType;
     RETURN SELF.field.mType;
     RETURN SELF.field.mType;
 END;
 END;
 
 
-PROCEDURE FieldVariable.referenceCode(): STRING;
-VAR
-    result: STRING;
-BEGIN
-    codeId <- mangleField(SELF.field.mIdentdef.id());
-    IF SELF.type().isScalar() THEN
-        result := SELF.rtl.makeRef(SELF.leadCode, 
-                                   Chars.doubleQuote + codeId + Chars.doubleQuote);
-    ELSE
-        result := SELF.leadCode + "." + codeId;
-    END;
-    RETURN result;
-END;
-
 PROCEDURE FieldVariable.isReference(): BOOLEAN;
 PROCEDURE FieldVariable.isReference(): BOOLEAN;
     RETURN FALSE;
     RETURN FALSE;
 END;
 END;

+ 1 - 1
src/ob/Scope.ob

@@ -215,7 +215,7 @@ BEGIN
         symbol <- k;
         symbol <- k;
         info <- symbol.info();
         info <- symbol.info();
         IF info IS Types.PVariable THEN
         IF info IS Types.PVariable THEN
-            symbol := NEW Symbols.Symbol(id, Variable.makeExportedVariable(info^));
+            symbol := NEW Symbols.Symbol(id, NEW Variable.ExportedVariable(id, info.type()));
         END;
         END;
         cm.exports[id] := symbol;
         cm.exports[id] := symbol;
     END;
     END;

+ 0 - 1
src/ob/Types.ob

@@ -28,7 +28,6 @@ TYPE
         PROCEDURE type*(): PStorageType;
         PROCEDURE type*(): PStorageType;
         PROCEDURE isReadOnly*(): BOOLEAN;
         PROCEDURE isReadOnly*(): BOOLEAN;
         PROCEDURE isReference*(): BOOLEAN;
         PROCEDURE isReference*(): BOOLEAN;
-        PROCEDURE referenceCode*(): STRING;
     END;
     END;
     PVariable* = POINTER TO Variable;
     PVariable* = POINTER TO Variable;
 
 

+ 15 - 55
src/ob/Variable.ob

@@ -1,6 +1,6 @@
 MODULE Variable;
 MODULE Variable;
 IMPORT
 IMPORT
-    OberonRtl, Types;
+    Types;
 TYPE
 TYPE
 
 
     TypedVariable* = RECORD(Types.Variable)
     TypedVariable* = RECORD(Types.Variable)
@@ -24,20 +24,22 @@ TYPE
     END;
     END;
 
 
     PropertyVariable* = RECORD(TypedVariable)
     PropertyVariable* = RECORD(TypedVariable)
-        PROCEDURE PropertyVariable*(type: Types.PStorageType; leadCode, propCode: STRING; isReadOnly: BOOLEAN; rtl: OberonRtl.PType);
+        PROCEDURE PropertyVariable*(type: Types.PStorageType; leadCode, propCode: STRING; isReadOnly: BOOLEAN);
 
 
-        leadCode, propCode: STRING;
+        leadCode-, propCode-: STRING;
         readOnly: BOOLEAN;
         readOnly: BOOLEAN;
-        rtl: OberonRtl.PType;
     END;
     END;
 
 
     DerefVariable* = RECORD(TypedVariable)
     DerefVariable* = RECORD(TypedVariable)
         PROCEDURE DerefVariable*(type: Types.PStorageType; code: STRING);
         PROCEDURE DerefVariable*(type: Types.PStorageType; code: STRING);
 
 
-        code: STRING;
+        code-: STRING;
     END;
     END;
 
 
-    ExportedVariable = RECORD(TypedVariable)
+    ExportedVariable* = RECORD(TypedVariable)
+        PROCEDURE ExportedVariable*(id: STRING; type: Types.PStorageType);
+
+        id: STRING;
     END;
     END;
 
 
     PExportedVariable = POINTER TO ExportedVariable;
     PExportedVariable = POINTER TO ExportedVariable;
@@ -46,15 +48,6 @@ PROCEDURE TypedVariable.type(): Types.PStorageType;
     RETURN SELF.mType
     RETURN SELF.mType
 END;
 END;
 
 
-PROCEDURE Declared.referenceCode(): STRING;
-BEGIN
-    result <- SELF.mId;
-    IF SELF.mType.isScalar() THEN
-        result := "{set: function($v){" + result + " = $v;}, get: function(){return " + result + ";}}";
-    END;
-    RETURN result;
-END;
-
 PROCEDURE Declared.isReference(): BOOLEAN;
 PROCEDURE Declared.isReference(): BOOLEAN;
     RETURN FALSE;
     RETURN FALSE;
 END;
 END;
@@ -82,18 +75,6 @@ BEGIN
     RETURN result;
     RETURN result;
 END;
 END;
 
 
-PROCEDURE PropertyVariable.referenceCode(): STRING;
-VAR
-    result: STRING;
-BEGIN
-    IF SELF.type().isScalar() THEN
-        result := SELF.rtl.makeRef(SELF.leadCode, SELF.propCode);
-    ELSE
-        result := SELF.leadCode + "[" + SELF.propCode + "]";
-    END;
-    RETURN result;
-END;
-
 PROCEDURE PropertyVariable.isReference(): BOOLEAN;
 PROCEDURE PropertyVariable.isReference(): BOOLEAN;
     RETURN FALSE;
     RETURN FALSE;
 END;
 END;
@@ -102,10 +83,6 @@ PROCEDURE PropertyVariable.isReadOnly(): BOOLEAN;
     RETURN SELF.readOnly;
     RETURN SELF.readOnly;
 END;
 END;
 
 
-PROCEDURE DerefVariable.referenceCode(): STRING;
-    RETURN SELF.code;
-END;
-
 PROCEDURE DerefVariable.isReference(): BOOLEAN;
 PROCEDURE DerefVariable.isReference(): BOOLEAN;
     RETURN TRUE;
     RETURN TRUE;
 END;
 END;
@@ -114,6 +91,11 @@ PROCEDURE DerefVariable.isReadOnly(): BOOLEAN;
     RETURN FALSE;
     RETURN FALSE;
 END;
 END;
 
 
+PROCEDURE ExportedVariable.ExportedVariable(id: STRING; type: Types.PStorageType)
+    | SUPER(type),
+      id(id);
+END;
+
 PROCEDURE ExportedVariable.idType(): STRING;
 PROCEDURE ExportedVariable.idType(): STRING;
     RETURN "imported variable"
     RETURN "imported variable"
 END ExportedVariable.idType;
 END ExportedVariable.idType;
@@ -126,11 +108,6 @@ PROCEDURE ExportedVariable.isReadOnly(): BOOLEAN;
     RETURN TRUE;
     RETURN TRUE;
 END;
 END;
 
 
-PROCEDURE ExportedVariable.referenceCode(): STRING;
-BEGIN
-    RETURN "";
-END;
-
 PROCEDURE TypedVariable.TypedVariable(type: Types.PStorageType)
 PROCEDURE TypedVariable.TypedVariable(type: Types.PStorageType)
     | mType(type);
     | mType(type);
 END;
 END;
@@ -140,12 +117,11 @@ PROCEDURE Declared.Declared(id: STRING; type: Types.PStorageType)
       mId(id);
       mId(id);
 END;
 END;
 
 
-PROCEDURE PropertyVariable.PropertyVariable(type: Types.PStorageType; leadCode, propCode: STRING; isReadOnly: BOOLEAN; rtl: OberonRtl.PType)
+PROCEDURE PropertyVariable.PropertyVariable(type: Types.PStorageType; leadCode, propCode: STRING; isReadOnly: BOOLEAN)
     | SUPER(type),
     | SUPER(type),
       leadCode(leadCode),
       leadCode(leadCode),
       propCode(propCode),
       propCode(propCode),
-      readOnly(isReadOnly),
-      rtl(rtl);
+      readOnly(isReadOnly);
 END;
 END;
 
 
 PROCEDURE DerefVariable.DerefVariable(type: Types.PStorageType; code: STRING)
 PROCEDURE DerefVariable.DerefVariable(type: Types.PStorageType; code: STRING)
@@ -183,20 +159,4 @@ BEGIN
     RETURN r;
     RETURN r;
 END;
 END;
 
 
-PROCEDURE ArgumentVariable.referenceCode(): STRING;
-VAR
-    result: STRING;
-BEGIN
-    IF SELF.var THEN
-        result := SELF.mId;
-    ELSE
-        result := SUPER();
-    END;
-    RETURN result;
-END;
-
-PROCEDURE makeExportedVariable*(v: Types.Variable): Types.PVariable;
-    RETURN NEW ExportedVariable(v.type());
-END;
-
 END Variable.
 END Variable.

+ 1 - 2
src/oberon/OberonContext.ob

@@ -115,9 +115,8 @@ END;
 PROCEDURE Assignment.handleExpression(e: Expression.PType);
 PROCEDURE Assignment.handleExpression(e: Expression.PType);
 BEGIN
 BEGIN
     d <- SELF.attributes.designator;
     d <- SELF.attributes.designator;
-    left <- Expression.make(d.code(), d.type(), d, NIL);
     SELF.parent().codeGenerator().write(
     SELF.parent().codeGenerator().write(
-            Operator.assign(left, e, ContextHierarchy.makeLanguageContext(SELF(POINTER))));
+            Operator.assign(d^, e, ContextHierarchy.makeLanguageContext(SELF(POINTER))));
 END;
 END;
 
 
 END OberonContext.
 END OberonContext.

+ 4 - 0
src/oberon/oberon_grammar.js

@@ -13,6 +13,7 @@ var ContextModule = require("js/ContextModule.js");
 var ContextProcedure = require("js/ContextProcedure.js");
 var ContextProcedure = require("js/ContextProcedure.js");
 var ContextType = require("js/ContextType.js");
 var ContextType = require("js/ContextType.js");
 var Grammar = require("grammar.js");
 var Grammar = require("grammar.js");
+var LanguageContext = require("js/LanguageContext.js");
 var OberonContext = require("js/OberonContext.js");
 var OberonContext = require("js/OberonContext.js");
 var OberonContextType = require("js/OberonContextType.js");
 var OberonContextType = require("js/OberonContextType.js");
 var OberonContextVar = require("js/OberonContextVar.js");
 var OberonContextVar = require("js/OberonContextVar.js");
@@ -156,6 +157,9 @@ exports.language = {
         make: function(){ return new CodeGenerator.Generator(); },
         make: function(){ return new CodeGenerator.Generator(); },
         nil: CodeGenerator.nullGenerator()
         nil: CodeGenerator.nullGenerator()
     },
     },
+    makeCodeTraits: function(codeGenerator, rtl, options){
+        return new LanguageContext.CodeTraits(codeGenerator, rtl, options && options.checkIndexes); 
+    },
     rtl: {
     rtl: {
         base: ObRtl.Type,
         base: ObRtl.Type,
         methods: ObRtlCode.rtl.methods,
         methods: ObRtlCode.rtl.methods,

+ 1 - 2
src/oc.js

@@ -130,8 +130,7 @@ function compile(text, language, handleErrors, options){
             language.grammar,
             language.grammar,
             function(moduleResolver){
             function(moduleResolver){
                 return new ContextHierarchy.Root(
                 return new ContextHierarchy.Root(
-                    { codeTraits: new LanguageContext.CodeTraits(language.codeGenerator.make(), 
-                                                                 options && options.checkIndexes ? rtl : null),
+                    { codeTraits: language.makeCodeTraits(language.codeGenerator.make(), rtl, options),
                       moduleGenerator: moduleCode,
                       moduleGenerator: moduleCode,
                       rtl: rtl,
                       rtl: rtl,
                       types: language.types,
                       types: language.types,

+ 7 - 1
src/rtl.js

@@ -69,9 +69,15 @@ var methods = {
     },
     },
     charAt: function(s, index){
     charAt: function(s, index){
         if (index >= 0 && index < s.length)
         if (index >= 0 && index < s.length)
-            return s[index];
+            return s.charCodeAt(index);
         throw new Error("index out of bounds: " + index);
         throw new Error("index out of bounds: " + index);
     },
     },
+    putAt: function(where, index, what){
+        if (index >= 0 && index < where.length)
+            where[index] = what;
+        else
+            throw new Error("index out of bounds: " + index);
+    },
     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());

+ 26 - 0
test/expected/case.js

@@ -30,8 +30,34 @@ function caseIntByVar(i/*VAR INTEGER*/){
 	}
 	}
 }
 }
 
 
+function caseRef(p/*VAR Base*/){
+	
+	function passRef(p/*Derived*/){
+	}
+	
+	function passRefVar(p/*VAR Derived2*/){
+	}
+	var $case1 = p;
+	if ($case1 instanceof Derived){
+		passRef(p);
+	}
+	else if ($case1 instanceof Derived2){
+		passRefVar(p);
+	}
+}
+
 function casePointer(p/*PBase*/){
 function casePointer(p/*PBase*/){
+	
+	function passRef(p/*Derived*/){
+	}
+	
+	function passRefVar(p/*VAR Derived2*/){
+	}
 	if (p instanceof Derived){
 	if (p instanceof Derived){
+		passRef(p);
+	}
+	else if (p instanceof Derived2){
+		passRefVar(p);
 	}
 	}
 	if (p instanceof Derived){
 	if (p instanceof Derived){
 		p.i = 0;
 		p.i = 0;

+ 12 - 1
test/expected/check_indexes.js

@@ -1,9 +1,20 @@
 <rtl code>
 <rtl code>
 var m = function (){
 var m = function (){
 
 
-function charArray(a/*ARRAY OF CHAR*/){
+function readCharArray(a/*ARRAY OF CHAR*/){
 	var c = 0;
 	var c = 0;
 	c = RTL$.charAt(a, 1);
 	c = RTL$.charAt(a, 1);
 	c = RTL$.charAt(a, RTL$.charAt(a, 1));
 	c = RTL$.charAt(a, RTL$.charAt(a, 1));
 }
 }
+
+function writeCharArray(a/*VAR ARRAY OF CHAR*/){
+	var c = 0;
+	RTL$.putAt(a, 1, c);
+	RTL$.putAt(a, RTL$.charAt(a, 1), c);
+}
+
+function writeIntArray(a/*VAR ARRAY OF INTEGER*/){
+	var i = 0;
+	RTL$.putAt(a, 1, i);
+}
 }();
 }();

+ 1 - 0
test/expected/errorsRT/check_indexes_int.txt

@@ -0,0 +1 @@
+Error: index out of bounds: 1

+ 1 - 0
test/expected/errorsRT/check_indexes_write.txt

@@ -0,0 +1 @@
+Error: index out of bounds: 1

+ 5 - 0
test/expected/pointer.js

@@ -22,6 +22,11 @@ function passByRef(p/*VAR PT*/){
 	passByRef(p);
 	passByRef(p);
 	passByRef(RTL$.makeRef(p.get(), "p"));
 	passByRef(RTL$.makeRef(p.get(), "p"));
 }
 }
+
+function derefAndAssign(){
+	p = new T();
+	RTL$.copy(r, p, {record: {p: null, i: null}});
+}
 r.p = new T();
 r.p = new T();
 r.p.p = new T();
 r.p.p = new T();
 r.p.i = 123;
 r.p.i = 123;

+ 17 - 0
test/input/case.ob

@@ -37,7 +37,21 @@ BEGIN
 	END;
 	END;
 END caseIntByVar;
 END caseIntByVar;
 
 
+PROCEDURE caseRef(VAR p: Base);
+	PROCEDURE passRef(p: Derived); END passRef;
+	PROCEDURE passRefVar(VAR p: Derived2); END passRefVar;
+BEGIN
+	CASE p OF
+		| Derived:
+			passRef(p);
+		| Derived2:
+			passRefVar(p);
+	END;
+END caseRef;
+
 PROCEDURE casePointer(p: PBase);
 PROCEDURE casePointer(p: PBase);
+	PROCEDURE passRef(p: Derived); END passRef;
+	PROCEDURE passRefVar(VAR p: Derived2); END passRefVar;
 BEGIN
 BEGIN
 	CASE p OF END;
 	CASE p OF END;
 
 
@@ -47,6 +61,9 @@ BEGIN
 
 
 	CASE p OF
 	CASE p OF
 		| PDerived:
 		| PDerived:
+			passRef(p^);
+		| PDerived2:
+			passRefVar(p^);
 	END;
 	END;
 
 
 	CASE p OF
 	CASE p OF

+ 17 - 2
test/input/check_indexes.ob

@@ -1,12 +1,27 @@
 (*options:{"checkIndexes": true}*)
 (*options:{"checkIndexes": true}*)
 MODULE m;
 MODULE m;
 
 
-PROCEDURE charArray(a: ARRAY OF CHAR);
+PROCEDURE readCharArray(a: ARRAY OF CHAR);
 VAR
 VAR
 	c: CHAR;
 	c: CHAR;
 BEGIN
 BEGIN
 	c := a[1];
 	c := a[1];
 	c := a[ORD(a[1])]
 	c := a[ORD(a[1])]
-END charArray;
+END readCharArray;
+
+PROCEDURE writeCharArray(VAR a: ARRAY OF CHAR);
+VAR
+	c: CHAR;
+BEGIN
+	a[1] := c;
+	a[ORD(a[1])] := c;
+END writeCharArray;
+
+PROCEDURE writeIntArray(VAR a: ARRAY OF INTEGER);
+VAR
+	i: INTEGER;
+BEGIN
+	a[1] := i;
+END writeIntArray;
 
 
 END m.
 END m.

+ 15 - 0
test/input/errorsRT/check_indexes_int.ob

@@ -0,0 +1,15 @@
+(*options:{"checkIndexes": true}*)
+MODULE m;
+VAR
+	a: ARRAY 1 OF INTEGER;
+
+PROCEDURE intArray(VAR a: ARRAY OF INTEGER);
+VAR
+	i: INTEGER;
+BEGIN
+	a[1] := 1;
+END intArray;
+
+BEGIN
+	intArray(a);
+END m.

+ 13 - 0
test/input/errorsRT/check_indexes_write.ob

@@ -0,0 +1,13 @@
+(*options:{"checkIndexes": true}*)
+MODULE m;
+VAR
+	s: ARRAY 1 OF CHAR;
+
+PROCEDURE putCharAt(VAR a: ARRAY OF CHAR; i: INTEGER);
+BEGIN
+	a[i] := "a";
+END putCharAt;
+
+BEGIN
+	putCharAt(s, 1);
+END m.

+ 6 - 0
test/input/pointer.ob

@@ -21,6 +21,12 @@ BEGIN
 	passByRef(p.p);
 	passByRef(p.p);
 END passByRef;
 END passByRef;
 
 
+PROCEDURE derefAndAssign();
+BEGIN
+	NEW(p);
+	p^ := r;
+END derefAndAssign;
+
 BEGIN
 BEGIN
 	NEW(r.p);
 	NEW(r.p);
     NEW(r.p.p);
     NEW(r.p.p);

+ 10 - 0
test/input/run/check_indexes.ob

@@ -0,0 +1,10 @@
+(*options:{"checkIndexes": true}*)
+MODULE m;
+
+PROCEDURE charAt(a: ARRAY OF CHAR; i: INTEGER): CHAR;
+	RETURN a[i]
+END charAt;
+
+BEGIN
+	ASSERT(charAt("abc", 1) = "b");
+END m.

+ 13 - 0
test/input/run/check_indexes_int.ob

@@ -0,0 +1,13 @@
+(*options:{"checkIndexes": true}*)
+MODULE m;
+VAR
+	a: ARRAY 2 OF INTEGER;
+
+PROCEDURE intAt(a: ARRAY OF INTEGER; i: INTEGER): INTEGER;
+	RETURN a[i]
+END intAt;
+
+BEGIN
+	a[1] := 1;
+	ASSERT(intAt(a, 1) = 1);
+END m.

+ 33 - 8
test/test_unit.js

@@ -222,16 +222,26 @@ return {
     ),
     ),
 "POINTER dereference": testWithContext(
 "POINTER dereference": testWithContext(
     context(grammar.statement,
     context(grammar.statement,
-            "TYPE PT = POINTER TO RECORD END;"
-            + "VAR pt: PT; p: POINTER TO RECORD field: INTEGER END; i: INTEGER; r: RECORD END;"),
+            "TYPE T = RECORD END; PT = POINTER TO T;"
+            + "VAR pt: PT; p: POINTER TO RECORD field: INTEGER END; i: INTEGER; r: RECORD END;"
+            + "PROCEDURE pVar(VAR r: T);END pVar;"),
     pass("p^.field := 1",
     pass("p^.field := 1",
-         "p.field := 0"),
+         "p.field := 0",
+         "pVar(pt^)"),
     fail(["i^", "POINTER TO type expected, got 'INTEGER'"],
     fail(["i^", "POINTER TO type expected, got 'INTEGER'"],
          ["r^", "POINTER TO type expected, got 'anonymous RECORD'"],
          ["r^", "POINTER TO type expected, got 'anonymous RECORD'"],
          ["p.unknown := 0", "type 'anonymous RECORD' has no 'unknown' field"],
          ["p.unknown := 0", "type 'anonymous RECORD' has no 'unknown' field"],
-         ["pt.constructor := 0", "type 'PT' has no 'constructor' field"], // "constructor" is JS predefined property
-         ["pt.prototype := 0", "type 'PT' has no 'prototype' field"], // "prototype" is JS predefined property
-         ["pt.unknown := 0", "type 'PT' has no 'unknown' field"])
+         ["pt.constructor := 0", "type 'T' has no 'constructor' field"], // "constructor" is JS predefined property
+         ["pt.prototype := 0", "type 'T' has no 'prototype' field"], // "prototype" is JS predefined property
+         ["pt.unknown := 0", "type 'T' has no 'unknown' field"])
+    ),
+"POINTER argument dereference and passing as VAR": testWithContext(
+    context(grammar.declarationSequence,
+            "TYPE T = RECORD END; PT = POINTER TO T;"
+            + "VAR pt: PT; p: POINTER TO RECORD field: INTEGER END; i: INTEGER; r: RECORD END;"
+            + "PROCEDURE pVar(VAR r: T);END pVar;"),
+    pass("PROCEDURE proc(p: PT); BEGIN pVar(p^); END proc;"),
+    fail()
     ),
     ),
 "POINTER assignment": testWithContext(
 "POINTER assignment": testWithContext(
     context(grammar.statement,
     context(grammar.statement,
@@ -695,6 +705,17 @@ return {
          ["CASE c OF 0..PDerived: END", "'PDerived' is not a constant"]
          ["CASE c OF 0..PDerived: END", "'PDerived' is not a constant"]
          )
          )
     ),
     ),
+"CASE statement with type guard - pass as VAR argument": testWithContext(
+    context(grammar.declarationSequence,
+              "TYPE Base = RECORD END;" 
+            + "Derived = RECORD (Base) END; PDerived = POINTER TO Derived;"
+            + "PROCEDURE passDerived(d: Derived); END passDerived;"
+            + "PROCEDURE passDerivedVar(VAR d: Derived); END passDerivedVar;"
+            ),
+    pass("PROCEDURE p(VAR b: Base); BEGIN CASE b OF Derived: passDerived(b) END; END p;",
+         "PROCEDURE p(VAR b: Base); BEGIN CASE b OF Derived: passDerivedVar(b) END; END p;"
+         )
+    ),
 "CASE statement with type guard for VAR argument": testWithContext(
 "CASE statement with type guard for VAR argument": testWithContext(
     context(grammar.declarationSequence,
     context(grammar.declarationSequence,
               "TYPE Base = RECORD END; Derived = RECORD (Base) i: INTEGER END; PBase = POINTER TO Base; PDerived = POINTER TO Derived;"),
               "TYPE Base = RECORD END; Derived = RECORD (Base) i: INTEGER END; PBase = POINTER TO Base; PDerived = POINTER TO Derived;"),
@@ -1049,10 +1070,14 @@ return {
             "TYPE Base1 = RECORD END;"
             "TYPE Base1 = RECORD END;"
                 + "T1 = RECORD (Base1) END;"
                 + "T1 = RECORD (Base1) END;"
                 + "T2 = RECORD END;"
                 + "T2 = RECORD END;"
-            + "VAR b1: Base1; r1: T1; r2: T2;"
+            + "VAR b1: Base1; r1: T1; r2: T2; pb1: POINTER TO Base1;"
             ),
             ),
     pass("r1 := r1",
     pass("r1 := r1",
-         "b1 := r1"),
+         "b1 := r1",
+         "pb1^ := b1",
+         "pb1^ := r1",
+         "pb1^ := pb1^"
+         ),
     fail(["r1 := r2", "type mismatch: 'r1' is 'T1' and cannot be assigned to 'T2' expression"],
     fail(["r1 := r2", "type mismatch: 'r1' is 'T1' and cannot be assigned to 'T2' expression"],
          ["r1 := b1", "type mismatch: 'r1' is 'T1' and cannot be assigned to 'Base1' expression"])
          ["r1 := b1", "type mismatch: 'r1' is 'T1' and cannot be assigned to 'Base1' expression"])
     ),
     ),

+ 1 - 1
test/test_unit_common.js

@@ -34,7 +34,7 @@ var TestContextRoot = Class.extend.call(ContextHierarchy.Root, {
         var rtl = new makeRTL(language.rtl);
         var rtl = new makeRTL(language.rtl);
         ContextHierarchy.Root.call(
         ContextHierarchy.Root.call(
                 this,
                 this,
-                { codeTraits: new LanguageContext.CodeTraits(language.codeGenerator.nil),
+                { codeTraits: language.makeCodeTraits(language.codeGenerator.nil, rtl),
                   moduleGenerator: function(){return new TestModuleGenerator();},
                   moduleGenerator: function(){return new TestModuleGenerator();},
                   rtl: rtl,
                   rtl: rtl,
                   types: language.types,
                   types: language.types,

+ 3 - 3
test/test_unit_eberon.js

@@ -1452,8 +1452,8 @@ exports.suite = {
                 + "PROCEDURE recordByRef(VAR r: T); END;"
                 + "PROCEDURE recordByRef(VAR r: T); END;"
                 ),
                 ),
         pass("recordByRef(mR[\"a\"])"),
         pass("recordByRef(mR[\"a\"])"),
-        fail(["intByRef(mInt[\"a\"])", "cannot reference map element of type 'INTEGER'"],
-             ["stringByRef(mS[\"a\"])", "cannot reference map element of type 'STRING'"]
+        fail(["intByRef(mInt[\"a\"])", "cannot reference MAP's element of type 'INTEGER'"],
+             ["stringByRef(mS[\"a\"])", "cannot reference MAP's element of type 'STRING'"]
             )
             )
         ),
         ),
     "IN": testWithContext(
     "IN": testWithContext(
@@ -1471,7 +1471,7 @@ exports.suite = {
         context(grammar.declarationSequence,
         context(grammar.declarationSequence,
                 "TYPE M = MAP OF INTEGER;"),
                 "TYPE M = MAP OF INTEGER;"),
         pass(),
         pass(),
-        fail(["PROCEDURE p(m: M); BEGIN m[\"abc\"] := 123; END;", "cannot assign to read-only MAP's element"])
+        fail(["PROCEDURE p(m: M); BEGIN m[\"abc\"] := 123; END;", "cannot assign to read-only MAP's element of type 'INTEGER'"])
         ),
         ),
     "remove": testWithContext(
     "remove": testWithContext(
         context(grammar.statement,
         context(grammar.statement,