Преглед изворни кода

fix string literal indexing

Vladislav Folts пре 11 година
родитељ
комит
482a4be79d
4 измењених фајлова са 36 додато и 13 уклоњено
  1. 10 6
      src/context.js
  2. 5 0
      test/expected/string.js
  3. 6 0
      test/input/string.ob
  4. 15 7
      test/test_unit.js

+ 10 - 6
src/context.js

@@ -316,16 +316,20 @@ exports.Designator = ChainedContext.extend({
                 Type.intsDescription() + " expression expected, got '" + expType.description() + "'");
 
         var type = this.__currentType;
-        if (!(type instanceof Type.Array))
-            throw new Errors.Error("ARRAY expected, got '" + type.description() + "'");
+        var isArray = type instanceof Type.Array;
+        if (!isArray && !(type instanceof Type.String))
+            throw new Errors.Error("ARRAY or string expected, got '" + type.description() + "'");
+        var arrayLen = isArray ? Type.arrayLength(type) : Type.stringLen(type);
+        if (!isArray && !arrayLen)
+            throw new Errors.Error("cannot index empty string" );
+
         var value = e.constValue();
-        var arrayLen = Type.arrayLength(type);
-        if (value && arrayLen != Type.openArrayLength && value.value >= arrayLen)
+        if (value && (!isArray || arrayLen != Type.openArrayLength) && value.value >= arrayLen)
             throw new Errors.Error("index out of bounds: maximum possible index is "
-                                 + (Type.arrayLength(type) - 1)
+                                 + (arrayLen - 1)
                                  + ", got " + value.value );
 
-        this.__currentType = Type.arrayElementsType(type);
+        this.__currentType = isArray ? Type.arrayElementsType(type) : basicTypes.ch;
         this.__info = Type.makeVariable(this.__currentType, Type.isVariableReadOnly(this.__info));
     },
     handleLiteral: function(s){

+ 5 - 0
test/expected/string.js

@@ -64,6 +64,7 @@ var s9 = "\\";
 var ch1 = 0;
 var a1 = RTL$.makeCharArray(15);
 var a2 = RTL$.makeCharArray(3);
+var i = 0;
 
 function p1(s/*ARRAY OF CHAR*/){
 }
@@ -92,4 +93,8 @@ RTL$.assert(RTL$.strCmp(s1, a1) <= 0);
 RTL$.assert(RTL$.strCmp(s1, a1) != 0);
 a1[0] = 97;
 a1[1] = a1.charCodeAt(0);
+RTL$.assert(s1.charCodeAt(0) == 34);
+RTL$.assert(s2.charCodeAt(0) == 65);
+p2(s2.charCodeAt(0));
+p2(s2.charCodeAt(i));
 }();

+ 6 - 0
test/input/string.ob

@@ -14,6 +14,7 @@ VAR
     ch1: CHAR;
 	a1: ARRAY 15 OF CHAR;
 	a2: ARRAY 3 OF CHAR;
+	i: INTEGER;
 
 PROCEDURE p1(s: ARRAY OF CHAR);
 END p1;
@@ -50,4 +51,9 @@ BEGIN
 
 	a1[0] := "a";
 	a1[1] := a1[0];
+
+	ASSERT(s1[0] = 22X);
+	ASSERT(s2[0] = "A");
+	p2(s2[0]);
+	p2(s2[i]);
 END m.

+ 15 - 7
test/test_unit.js

@@ -28,7 +28,7 @@ function makeSuiteForGrammar(language){
         return TestUnitCommon.testWithModule(src, language, pass, fail);
     }
 
-    function testWithGrammar(parser, pass, faile){
+    function testWithGrammar(parser, pass, fail){
         return TestUnitCommon.testWithGrammar(parser, language, pass, fail);
     }
 
@@ -1088,7 +1088,8 @@ return {
          "VAR a: ARRAY 10 OF INTEGER; BEGIN a[0] := 1; a[1] := a[0] END",
          "VAR a1, a2: ARRAY 3 OF CHAR; BEGIN ASSERT(a1 = a2); END",
          "VAR a1: ARRAY 2 OF CHAR; a2: ARRAY 3 OF CHAR; BEGIN ASSERT(a1 = a2); END",
-         "CONST cs = \"a\"; VAR a: ARRAY 3 OF CHAR; BEGIN ASSERT(a = cs); ASSERT(cs # a); ASSERT(a < cs); ASSERT(cs > a); END"
+         "CONST cs = \"a\"; VAR a: ARRAY 3 OF CHAR; BEGIN ASSERT(a = cs); ASSERT(cs # a); ASSERT(a < cs); ASSERT(cs > a); END",
+         "CONST cs = \"a\"; BEGIN ASSERT(cs[0] = \"a\"); END"
          ),
     fail(["VAR a: ARRAY 10 OF INTEGER; BEGIN a[0] := TRUE END",
           "type mismatch: 'a[0]' is 'INTEGER' and cannot be assigned to 'BOOLEAN' expression"],
@@ -1097,13 +1098,13 @@ return {
          ["VAR a: ARRAY 10 OF INTEGER; p: POINTER TO RECORD END; BEGIN a[p] := 1 END",
           "'INTEGER' or 'BYTE' expression expected, got 'POINTER TO anonymous RECORD'"],
          ["VAR i: INTEGER; BEGIN i[0] := 1 END",
-          "ARRAY expected, got 'INTEGER'"],
+          "ARRAY or string expected, got 'INTEGER'"],
          ["VAR p: POINTER TO RECORD END; BEGIN p[0] := 1 END",
-          "ARRAY expected, got 'POINTER TO anonymous RECORD'"],
+          "ARRAY or string expected, got 'POINTER TO anonymous RECORD'"],
          ["VAR a: ARRAY 10 OF INTEGER; BEGIN a[0][0] := 1 END",
-          "ARRAY expected, got 'INTEGER'"],
+          "ARRAY or string expected, got 'INTEGER'"],
          ["VAR a: ARRAY 10 OF BOOLEAN; BEGIN a[0,0] := TRUE END",
-          "ARRAY expected, got 'BOOLEAN'"],
+          "ARRAY or string expected, got 'BOOLEAN'"],
          ["VAR a: ARRAY 10, 20 OF BOOLEAN; BEGIN a[0] := TRUE END",
           "type mismatch: 'a[0]' is 'ARRAY 20 OF BOOLEAN' and cannot be assigned to 'BOOLEAN' expression"],
          ["VAR a: ARRAY 10 OF INTEGER; BEGIN a[10] := 0 END",
@@ -1111,7 +1112,14 @@ return {
          ["CONST c1 = 5; VAR a: ARRAY 10 OF INTEGER; BEGIN a[10 + c1] := 0 END",
           "index out of bounds: maximum possible index is 9, got 15"],
          ["VAR a1, a2: ARRAY 3 OF INTEGER; BEGIN ASSERT(a1 = a2); END",
-          "operator '=' type mismatch: numeric type or SET or BOOLEAN or CHAR or character array or POINTER or PROCEDURE expected, got 'ARRAY 3 OF INTEGER'"])
+          "operator '=' type mismatch: numeric type or SET or BOOLEAN or CHAR or character array or POINTER or PROCEDURE expected, got 'ARRAY 3 OF INTEGER'"],
+         ["CONST cs = \"\"; BEGIN ASSERT(cs[0] = \"a\"); END",
+          "cannot index empty string"],
+         ["CONST cs = \"\"; VAR i: INTEGER; BEGIN ASSERT(cs[i] = \"a\"); END",
+          "cannot index empty string"],
+         ["CONST cs = \"a\"; BEGIN ASSERT(cs[1] = \"a\"); END",
+          "index out of bounds: maximum possible index is 0, got 1"]
+        )
     ),
 "multi-dimensional array expression": testWithGrammar(
     grammar.procedureBody,