فهرست منبع

make possible to use JavaScript strings as ARRAY OF CHAR without convetion

Vladislav Folts 11 سال پیش
والد
کامیت
3516b3a649

+ 1 - 3
src/cast.js

@@ -80,9 +80,7 @@ function implicitCast(from, to, ops){
                 return function(){return new Code.Expression(v, to);};
         }
         else if (to instanceof Type.Array && to.elementsType() == Type.basic.ch)
-            return function(context, e){
-                return new Code.Expression(context.rtl().strToArray(e.code()), to);
-            };
+            return doNoting;
     }
     else if (from instanceof ArrayType && to instanceof ArrayType)
         return (to.length() === undefined || to.length() === from.length())

+ 1 - 0
src/code.js

@@ -49,6 +49,7 @@ var Expression = Class.extend({
         this.__maxPrecedence = maxPrecedence;
     },
     code: function(){return this.__code;},
+    lval: function(){return this.__designator ? this.__designator.lval() : this.__code;},
     type: function(){return this.__type;},
     designator: function(){return this.__designator;},
     constValue: function(){return this.__constValue;},

+ 24 - 20
src/context.js

@@ -114,12 +114,7 @@ var ChainedContext = Class.extend({
     rtl: function(){return this.__parent.rtl();},
     
     // called from oberon code
-    raiseException: function(s){
-        var result = "";
-        for(var i = 0; i < s.length; ++i)
-            result += String.fromCharCode(s[i]);
-        throw new Errors.Error(result);
-    }
+    raiseException: function(s){throw new Errors.Error(s);}
 });
 
 exports.Integer = ChainedContext.extend({
@@ -213,14 +208,16 @@ exports.BaseType = ChainedContext.extend({
 });
 
 var DesignatorInfo = Class.extend({
-    init: function(code, refCode, type, info, scope){
+    init: function(code, lval, refCode, type, info, scope){
         this.__code = code;
+        this.__lval = lval;
         this.__refCode = refCode;
         this.__type = type;
         this.__info = info;
         this.__scope = scope;
     },
     code: function(){return this.__code;},
+    lval: function(){return this.__lval;},
     refCode: function(){return this.__refCode(this.__code);},
     type: function(){return this.__type;},
     info: function(){return this.__info;},
@@ -282,7 +279,8 @@ exports.Designator = ChainedContext.extend({
         this.__currentType = undefined;
         this.__info = undefined;
         this.__scope = undefined;
-        this.__code = new Code.SimpleGenerator();
+        this.__code = "";
+        this.__lval = undefined;
         this.__indexExpression = undefined;
         this.__derefCode = undefined;
         this.__propCode = undefined;
@@ -296,7 +294,7 @@ exports.Designator = ChainedContext.extend({
         else if (s.isVariable() || s.isConst())
             this.__currentType = info.type();
         this.__info = info;
-        this.__code.write(code);
+        this.__code += code;
     },
     handleIdent: function(id){
         var t = this.__currentType;
@@ -317,7 +315,6 @@ exports.Designator = ChainedContext.extend({
         this.__info = new Type.Variable(this.__currentType, isReadOnly);
         this.__scope = undefined;
     },
-    codeGenerator: function(){return this.__code;},
     handleExpression: function(e){this.__indexExpression = e;},
     __handleIndexExpression: function(){
         var e = this.__indexExpression;
@@ -343,11 +340,16 @@ exports.Designator = ChainedContext.extend({
             this.__handleIndexExpression();
             var indexCode = this.__indexExpression.deref().code();
             this.__propCode = indexCode;
-            this.__code = new Code.SimpleGenerator(this.__derefCode + "[" + indexCode + "]");
+            var code = this.__derefCode + "[" + indexCode + "]";
+            if (this.__currentType == basicTypes.ch){
+                this.__lval = code;
+                code = this.__derefCode + ".charCodeAt(" + indexCode + ")";
+            }
+            this.__code += code;
             }
         if (s == "[" || s == ","){
-            this.__derefCode = this.__code.result();
-            this.__code = new Code.SimpleGenerator();
+            this.__derefCode = this.__code;
+            this.__code = "";
         }
         else if (s == "^"){
             this.__handleDeref();
@@ -382,8 +384,8 @@ exports.Designator = ChainedContext.extend({
 
         var baseType = type instanceof Type.Pointer ? type.baseType() : type;
         var castName = this.qualifyScope(baseType.scope()) + baseType.cons();
-        var code = this.rtl().typeGuard(this.__code.result(), castName);
-        this.__code = new Code.SimpleGenerator(code);
+        var code = this.rtl().typeGuard(this.__code, castName);
+        this.__code = code;
 
         this.__currentType = type;
     },
@@ -396,17 +398,17 @@ exports.Designator = ChainedContext.extend({
                 : t.description();
             throw new Errors.Error("type '" + typeDesc + "' has no '" + id + "' field");
         }
-        this.__derefCode = this.__code.result();
+        this.__derefCode = this.__code;
         this.__propCode = "\"" + id + "\"";
-        this.__code.write("." + id);
+        this.__code += "." + id;
         this.__currentType = fieldType;
     },
     endParse: function(){
-        var code = this.__code.result();
+        var code = this.__code;
         var self = this;
         var refCode = function(code){return self.__makeRefCode(code);};
         this.parent().setDesignator(
-            new DesignatorInfo(code, refCode, this.__currentType, this.__info, this.__scope));
+            new DesignatorInfo(code, this.__lval ? this.__lval : code, refCode, this.__currentType, this.__info, this.__scope));
     },
     __makeRefCode: function(code){
         if (   this.__currentType instanceof Type.Array
@@ -683,12 +685,14 @@ exports.ArrayDecl = HandleSymbolAsType.extend({
         var initializer = type instanceof Type.Array || type instanceof Type.Record
             ? "function(){return " + type.initializer(this) + ";}"
             : type.initializer(this);
+        var isCharArray = (type == basicTypes.ch);
         var dimensions = "";
         for(var i = this.__dimensions.length; i-- ;){
             var length = this.__dimensions[i];
             dimensions = length + (dimensions.length ? ", " + dimensions : "");
             var arrayInit = !i
-                ? this.rtl().makeArray(dimensions + ", " + initializer)
+                ? isCharArray ? this.rtl().makeCharArray(dimensions)
+                              : this.rtl().makeArray(dimensions + ", " + initializer)
                 : undefined;
             type = new Type.Array("ARRAY OF " + type.name()
                                , arrayInit

+ 0 - 0
src/lexer.js


+ 1 - 1
src/oberon.js/JsString.js

@@ -10,7 +10,7 @@ function make(s/*ARRAY OF CHAR*/){
 	var i = 0;
 	result = '';
 	for (i = 0; i <= s.length - 1 | 0; ++i){
-		result += JS.String.fromCharCode(s[i]);
+		result += JS.String.fromCharCode(s.charCodeAt(i));
 	}
 	return result;
 }

+ 11 - 11
src/oberon.js/Lexer.js

@@ -17,7 +17,7 @@ var Context = RTL$.extend({
 });
 var Literal = RTL$.extend({
 	init: function Literal(){
-		this.s = RTL$.makeArray(1, 0);
+		this.s = RTL$.makeCharArray(1);
 	}
 });
 var reservedWords = null;
@@ -64,7 +64,7 @@ function handleLiteral(context/*Context*/, s/*ARRAY OF CHAR*/){
 function point(stream/*Type*/, context/*Context*/){
 	var result = false;
 	if (!Stream.eof(stream) && Stream.getChar(stream) == 46 && (Stream.eof(stream) || Stream.peekChar(stream) != 46)){
-		result = handleLiteral(context, RTL$.strToArray("."));
+		result = handleLiteral(context, ".");
 	}
 	return result;
 }
@@ -77,7 +77,7 @@ function string(stream/*Type*/, context/*Context*/){
 		c = Stream.getChar(stream);
 		if (c == 34){
 			if (!Stream.eof(stream)){
-				s = JsString.make(RTL$.strToArray(""));
+				s = JsString.make("");
 				c = Stream.getChar(stream);
 				while (true){
 					if (c != 34 && !Stream.eof(stream)){
@@ -89,7 +89,7 @@ function string(stream/*Type*/, context/*Context*/){
 				}
 			}
 			if (s == null || c != 34){
-				context.raiseException(RTL$.strToArray("unexpected end of string"));
+				context.raiseException("unexpected end of string");
 			}
 			context.handleString(s);
 			result = true;
@@ -120,7 +120,7 @@ function ident(stream/*Type*/, context/*Context*/){
 	if (!Stream.eof(stream)){
 		c = Stream.getChar(stream);
 		if (isLetter(c)){
-			s = JsString.make(RTL$.strToArray(""));
+			s = JsString.make("");
 			while (true){
 				if (!Stream.eof(stream) && (isLetter(c) || isDigit(c))){
 					s = JsString.appendChar(s, c);
@@ -147,14 +147,14 @@ function ident(stream/*Type*/, context/*Context*/){
 
 function skipComment(stream/*Type*/, context/*Context*/){
 	var result = false;
-	if (Stream.peekStr(stream, RTL$.strToArray(commentBegin))){
+	if (Stream.peekStr(stream, commentBegin)){
 		Stream.next(stream, commentBegin.length);
 		while (true){
-			if (!Stream.peekStr(stream, RTL$.strToArray(commentEnd))){
+			if (!Stream.peekStr(stream, commentEnd)){
 				if (!skipComment(stream, context)){
 					Stream.next(stream, 1);
 					if (Stream.eof(stream)){
-						context.raiseException(RTL$.strToArray("comment was not closed"));
+						context.raiseException("comment was not closed");
 					}
 				}
 			} else break;
@@ -193,14 +193,14 @@ function literal(l/*Literal*/, stream/*Type*/, context/*Context*/){
 	var result = false;
 	if (Stream.peekStr(stream, l.s)){
 		Stream.next(stream, l.s.length);
-		if (context.isLexem != null && context.isLexem() || !isLetter(l.s[l.s.length - 1 | 0]) || Stream.eof(stream) || !isLetter(Stream.peekChar(stream)) && !isDigit(Stream.peekChar(stream))){
+		if (context.isLexem != null && context.isLexem() || !isLetter(l.s.charCodeAt(l.s.length - 1 | 0)) || Stream.eof(stream) || !isLetter(Stream.peekChar(stream)) && !isDigit(Stream.peekChar(stream))){
 			result = handleLiteral(context, l.s);
 		}
 	}
 	return result;
 }
-reservedWords = JsString.make(RTL$.strToArray("ARRAY IMPORT THEN BEGIN IN TO BY IS TRUE CASE MOD TYPE CONST MODULE UNTIL DIV NIL VAR DO OF WHILE ELSE OR ELSIF POINTER END PROCEDURE FALSE RECORD FOR REPEAT IF RETURN"));
-jsReservedWords = JsString.make(RTL$.strToArray("break case catch continue debugger default delete do else finally for function if in instanceof new return switch this throw try typeof var void while with Math"));
+reservedWords = JsString.make("ARRAY IMPORT THEN BEGIN IN TO BY IS TRUE CASE MOD TYPE CONST MODULE UNTIL DIV NIL VAR DO OF WHILE ELSE OR ELSIF POINTER END PROCEDURE FALSE RECORD FOR REPEAT IF RETURN");
+jsReservedWords = JsString.make("break case catch continue debugger default delete do else finally for function if in instanceof new return switch this throw try typeof var void while with Math");
 exports.digit = digit;
 exports.hexDigit = hexDigit;
 exports.point = point;

+ 1 - 1
src/oberon.js/Stream.js

@@ -50,7 +50,7 @@ function peekStr(self/*Type*/, s/*ARRAY OF CHAR*/){
 	var i = 0;
 	if (s.length <= (JsString.len(self.s) - self.pos | 0)){
 		while (true){
-			if (i < s.length && s[i] == JsString.at(self.s, self.pos + i | 0)){
+			if (i < s.length && s.charCodeAt(i) == JsString.at(self.s, self.pos + i | 0)){
 				++i;
 			} else break;
 		}

+ 1 - 1
src/oberon/JsString.ob

@@ -11,7 +11,7 @@ VAR
 BEGIN
     JS.do("result = ''");
     FOR i := 0 TO LEN(s) - 1 DO
-        JS.do("result += JS.String.fromCharCode(s[i])")
+        JS.do("result += JS.String.fromCharCode(s.charCodeAt(i))")
     END
     RETURN result
 END make;

+ 0 - 0
src/oberon/String.ob


+ 0 - 0
src/oberon/TestString.ob


+ 1 - 1
src/operator.js

@@ -87,7 +87,7 @@ function assign(left, right, context){
     if (!(info instanceof Type.Variable) || info.isReadOnly())
         throw new Errors.Error("cannot assign to " + info.idType());
 
-    var leftCode = left.code();
+    var leftCode = left.lval();
     var leftType = left.type();
     var rightCode = right.code();
     var rightType = right.type();

+ 1 - 2
src/parser.js

@@ -4,10 +4,9 @@ var assert = require("assert.js").ok;
 var Errors = require("errors.js");
 var Lexer = require("oberon.js/lexer.js");
 var Stream = require("oberon.js/Stream.js");
-var Rtl = require("rtl.js");
 
 function literal(s){
-	var l = Lexer.makeLiteral(Rtl.strToArray(s));
+	var l = Lexer.makeLiteral(s);
 	return function(stream, context){
 		return Lexer.literal(l, stream, context);
 	};

+ 32 - 7
src/rtl.js

@@ -41,6 +41,37 @@ var impl = {
                 result[i] = this.makeArray.apply(this, forward);
         return result;
     },
+    makeCharArray: function(/*dimensions*/){
+        var forward = Array.prototype.slice.call(arguments);
+        var length = forward.pop();
+
+        if (!forward.length)
+            return makeCharArray(length);
+
+        function makeCharArray(length){
+            var result = new Uint16Array(length);
+            result.charCodeAt = function(i){return this[i];};
+            return result;
+        }
+
+        function makeArray(){
+            var forward = Array.prototype.slice.call(arguments);
+            var result = new Array(forward.shift());
+            var i;
+            if (forward.length == 1){
+                var init = forward[0];
+                for(i = 0; i < result.length; ++i)
+                    result[i] = init();
+            }
+            else
+                for(i = 0; i < result.length; ++i)
+                    result[i] = makeArray.apply(undefined, forward);
+            return result;
+        }
+
+        forward.push(makeCharArray.bind(undefined, length));
+        return makeArray.apply(undefined, forward);
+    },
     makeSet: function(/*...*/){
         var result = 0;
         
@@ -82,17 +113,11 @@ var impl = {
         for(i = s.length; i < a.length; ++i)
             a[i] = 0;
     },
-    strToArray: function(s){
-        var result = new Array(s.length);
-        for(var i = 0; i < s.length; ++i)
-            result[i] = s.charCodeAt(i);
-        return result;
-    },
     strCmp: function(s1, s2){
         var cmp = 0;
         var i = 0;
         while (!cmp && i < s1.length && i < s2.length){
-            cmp = s1[i] - s2[i];
+            cmp = s1.charCodeAt(i) - s2.charCodeAt(i);
             ++i;
         }
         return cmp ? cmp : s1.length - s2.length;

+ 0 - 5
test/compile_oberon_source.cmd

@@ -1,5 +0,0 @@
-@SET NODE_PATH=%~dp0../snapshot/oberon.js
-
-cd %~dp0../src/oberon
-call %~dp0/run_nodejs.cmd %~dp0../snapshot/oc_nodejs.js %~dp0../src/oberon.js %~dp0../src/oberon/Stream.ob
-cd %~dp0

+ 27 - 14
test/expected/blur.js

@@ -1,21 +1,34 @@
 var RTL$ = {
-    makeArray: function (/*dimensions, initializer*/){
+    makeCharArray: function (/*dimensions*/){
         var forward = Array.prototype.slice.call(arguments);
-        var result = new Array(forward.shift());
-        var i;
-        if (forward.length == 1){
-            var init = forward[0];
-            if (typeof init == "function")
+        var length = forward.pop();
+
+        if (!forward.length)
+            return makeCharArray(length);
+
+        function makeCharArray(length){
+            var result = new Uint16Array(length);
+            result.charCodeAt = function(i){return this[i];};
+            return result;
+        }
+
+        function makeArray(){
+            var forward = Array.prototype.slice.call(arguments);
+            var result = new Array(forward.shift());
+            var i;
+            if (forward.length == 1){
+                var init = forward[0];
                 for(i = 0; i < result.length; ++i)
                     result[i] = init();
+            }
             else
                 for(i = 0; i < result.length; ++i)
-                    result[i] = init;
+                    result[i] = makeArray.apply(undefined, forward);
+            return result;
         }
-        else
-            for(i = 0; i < result.length; ++i)
-                result[i] = this.makeArray.apply(this, forward);
-        return result;
+
+        forward.push(makeCharArray.bind(undefined, length));
+        return makeArray.apply(undefined, forward);
     }
 };
 var Blur = function (){
@@ -25,7 +38,7 @@ var H = 480;
 var H1 = 480 - 3 | 0;
 var N = 13;
 var Frames = 1;
-var a = RTL$.makeArray(1920, 480, 0);var b = RTL$.makeArray(1920, 480, 0);
+var a = RTL$.makeCharArray(1920, 480);var b = RTL$.makeCharArray(1920, 480);
 var time = 0;
 
 function Blur2DArray(){
@@ -37,14 +50,14 @@ function Blur2DArray(){
 			for (y = 1; y <= H - 2 | 0; ++y){
 				for (x = 1; x <= W - 2 | 0; ++x){
 					for (color = 0; color <= 2; ++color){
-						b[(x * 3 | 0) + color | 0][y] = (((a[(x * 3 | 0) + color | 0][y + 1 | 0] + a[(x * 3 | 0) + color | 0][y - 1 | 0] | 0) + a[(x - 1 | 0) * 3 | 0][y] | 0) + a[(x + 1 | 0) * 3 | 0][y] | 0) / 4 | 0;
+						b[(x * 3 | 0) + color | 0][y] = (((a[(x * 3 | 0) + color | 0].charCodeAt(y + 1 | 0) + a[(x * 3 | 0) + color | 0].charCodeAt(y - 1 | 0) | 0) + a[(x - 1 | 0) * 3 | 0].charCodeAt(y) | 0) + a[(x + 1 | 0) * 3 | 0].charCodeAt(y) | 0) / 4 | 0;
 					}
 				}
 			}
 			for (y = 1; y <= H - 2 | 0; ++y){
 				for (x = 1; x <= W - 2 | 0; ++x){
 					for (color = 0; color <= 2; ++color){
-						a[(x * 3 | 0) + color | 0][y] = (((b[(x * 3 | 0) + color | 0][y + 1 | 0] + b[(x * 3 | 0) + color | 0][y - 1 | 0] | 0) + b[(x - 1 | 0) * 3 | 0][y] | 0) + b[(x + 1 | 0) * 3 | 0][y] | 0) / 4 | 0;
+						a[(x * 3 | 0) + color | 0][y] = (((b[(x * 3 | 0) + color | 0].charCodeAt(y + 1 | 0) + b[(x * 3 | 0) + color | 0].charCodeAt(y - 1 | 0) | 0) + b[(x - 1 | 0) * 3 | 0].charCodeAt(y) | 0) + b[(x + 1 | 0) * 3 | 0].charCodeAt(y) | 0) / 4 | 0;
 					}
 				}
 			}

+ 32 - 1
test/expected/len.js

@@ -17,6 +17,37 @@ var RTL$ = {
                 result[i] = this.makeArray.apply(this, forward);
         return result;
     },
+    makeCharArray: function (/*dimensions*/){
+        var forward = Array.prototype.slice.call(arguments);
+        var length = forward.pop();
+
+        if (!forward.length)
+            return makeCharArray(length);
+
+        function makeCharArray(length){
+            var result = new Uint16Array(length);
+            result.charCodeAt = function(i){return this[i];};
+            return result;
+        }
+
+        function makeArray(){
+            var forward = Array.prototype.slice.call(arguments);
+            var result = new Array(forward.shift());
+            var i;
+            if (forward.length == 1){
+                var init = forward[0];
+                for(i = 0; i < result.length; ++i)
+                    result[i] = init();
+            }
+            else
+                for(i = 0; i < result.length; ++i)
+                    result[i] = makeArray.apply(undefined, forward);
+            return result;
+        }
+
+        forward.push(makeCharArray.bind(undefined, length));
+        return makeArray.apply(undefined, forward);
+    },
     assert: function (condition, code){
         if (!condition)
             throw new Error("assertion failed"
@@ -27,7 +58,7 @@ var m = function (){
 var s1 = "\"";
 var a1 = RTL$.makeArray(10, 0);
 var a2 = RTL$.makeArray(15, false);
-var a3 = RTL$.makeArray(20, 0);
+var a3 = RTL$.makeCharArray(20);
 var i = 0;
 
 function p1(a/*ARRAY OF INTEGER*/){

+ 39 - 29
test/expected/string.js

@@ -1,21 +1,34 @@
 var RTL$ = {
-    makeArray: function (/*dimensions, initializer*/){
+    makeCharArray: function (/*dimensions*/){
         var forward = Array.prototype.slice.call(arguments);
-        var result = new Array(forward.shift());
-        var i;
-        if (forward.length == 1){
-            var init = forward[0];
-            if (typeof init == "function")
+        var length = forward.pop();
+
+        if (!forward.length)
+            return makeCharArray(length);
+
+        function makeCharArray(length){
+            var result = new Uint16Array(length);
+            result.charCodeAt = function(i){return this[i];};
+            return result;
+        }
+
+        function makeArray(){
+            var forward = Array.prototype.slice.call(arguments);
+            var result = new Array(forward.shift());
+            var i;
+            if (forward.length == 1){
+                var init = forward[0];
                 for(i = 0; i < result.length; ++i)
                     result[i] = init();
+            }
             else
                 for(i = 0; i < result.length; ++i)
-                    result[i] = init;
+                    result[i] = makeArray.apply(undefined, forward);
+            return result;
         }
-        else
-            for(i = 0; i < result.length; ++i)
-                result[i] = this.makeArray.apply(this, forward);
-        return result;
+
+        forward.push(makeCharArray.bind(undefined, length));
+        return makeArray.apply(undefined, forward);
     },
     assignArrayFromString: function (a, s){
         var i;
@@ -24,12 +37,6 @@ var RTL$ = {
         for(i = s.length; i < a.length; ++i)
             a[i] = 0;
     },
-    strToArray: function (s){
-        var result = new Array(s.length);
-        for(var i = 0; i < s.length; ++i)
-            result[i] = s.charCodeAt(i);
-        return result;
-    },
     assert: function (condition, code){
         if (!condition)
             throw new Error("assertion failed"
@@ -39,7 +46,7 @@ var RTL$ = {
         var cmp = 0;
         var i = 0;
         while (!cmp && i < s1.length && i < s2.length){
-            cmp = s1[i] - s2[i];
+            cmp = s1.charCodeAt(i) - s2.charCodeAt(i);
             ++i;
         }
         return cmp ? cmp : s1.length - s2.length;
@@ -56,8 +63,8 @@ var s7 = "\t";
 var s8 = "\f";
 var s9 = "\\";
 var ch1 = 0;
-var a1 = RTL$.makeArray(15, 0);
-var a2 = RTL$.makeArray(3, 0);
+var a1 = RTL$.makeCharArray(15);
+var a2 = RTL$.makeCharArray(3);
 
 function p1(s/*ARRAY OF CHAR*/){
 }
@@ -68,19 +75,22 @@ ch1 = 34;
 RTL$.assignArrayFromString(a1, s1);
 RTL$.assignArrayFromString(a2, s2);
 RTL$.assignArrayFromString(a1, s2);
-p1(RTL$.strToArray(s1));
-p1(RTL$.strToArray(s2));
+p1(s1);
+p1(s2);
 p2(34);
+p2(a1.charCodeAt(0));
 RTL$.assert(ch1 == 34);
 RTL$.assert(34 == ch1);
-RTL$.assert(RTL$.strCmp(RTL$.strToArray("abc"), RTL$.strToArray("abc")) == 0);
+RTL$.assert(RTL$.strCmp("abc", "abc") == 0);
 RTL$.assert(RTL$.strCmp(a1, a2) == 0);
 RTL$.assert(RTL$.strCmp(a1, a2) != 0);
 RTL$.assert(RTL$.strCmp(a1, a2) > 0);
-RTL$.assert(RTL$.strCmp(a1, RTL$.strToArray(s1)) > 0);
-RTL$.assert(RTL$.strCmp(a1, RTL$.strToArray(s1)) >= 0);
-RTL$.assert(RTL$.strCmp(a1, RTL$.strToArray(s1)) != 0);
-RTL$.assert(RTL$.strCmp(RTL$.strToArray(s1), a1) < 0);
-RTL$.assert(RTL$.strCmp(RTL$.strToArray(s1), a1) <= 0);
-RTL$.assert(RTL$.strCmp(RTL$.strToArray(s1), a1) != 0);
+RTL$.assert(RTL$.strCmp(a1, s1) > 0);
+RTL$.assert(RTL$.strCmp(a1, s1) >= 0);
+RTL$.assert(RTL$.strCmp(a1, s1) != 0);
+RTL$.assert(RTL$.strCmp(s1, a1) < 0);
+RTL$.assert(RTL$.strCmp(s1, a1) <= 0);
+RTL$.assert(RTL$.strCmp(s1, a1) != 0);
+a1[0] = 97;
+a1[1] = a1.charCodeAt(0);
 }();

+ 9 - 0
test/input/run/string.ob

@@ -3,6 +3,7 @@ MODULE m;
 VAR
 	a3: ARRAY 3 OF CHAR;
 	a4: ARRAY 4 OF CHAR;
+    a34: ARRAY 3, 4 OF CHAR;
 
 BEGIN
 	ASSERT("abc" = "abc");
@@ -13,4 +14,12 @@ BEGIN
 	a4 := "abc";
 	ASSERT(a3 < a4); (*a4 has extra 0*)
 
+    a34[0] := "abcd";
+    a34[1][0] := "c";
+    ASSERT(a34[0][0] = "a");
+    ASSERT(a34[0][1] = "b");
+    ASSERT(a34[0][2] = "c");
+    ASSERT(a34[0][3] = "d");
+    ASSERT(a34[1][0] = "c");
+
 END m.

+ 3 - 0
test/input/string.ob

@@ -30,6 +30,7 @@ BEGIN
 	p1(s1);
 	p1(s2);
     p2(s1);
+	p2(a1[0]);
 
     ASSERT(ch1 = s1);
 	ASSERT(s1 = ch1);
@@ -47,4 +48,6 @@ BEGIN
 	ASSERT(s1 <= a1);
 	ASSERT(s1 # a1);
 
+	a1[0] := "a";
+	a1[1] := a1[0];
 END m.

+ 3 - 0
test/recompile_oberon.js.cmd

@@ -0,0 +1,3 @@
+cd %~dp0../src/oberon
+call %~dp0/run_nodejs.cmd %~dp0../src/oc_nodejs.js %~dp0/_out %~dp0../src/oberon/Lexer.ob
+cd %~dp0

+ 5 - 1
test/test_compile.js

@@ -64,7 +64,11 @@ function expectError(src, dirs){
 }
 
 function run(src, dirs){
-    eval(compile(src));
+    var result = compile(src);
+    var resultName = path.basename(src).replace(".ob", ".js");
+    var resultPath = path.join(dirs.output, resultName);
+    fs.writeFileSync(resultPath, result);
+    require(resultPath);
 }
 
 function makeTest(test, src, dirs){