Ver código fonte

Get rid of JsString in favor of STRING

Vladislav Folts 11 anos atrás
pai
commit
2a959f63db

BIN
bin/compiled.zip


+ 14 - 11
src/context.js

@@ -491,7 +491,10 @@ exports.FormalParameters = ChainedContext.extend({
         this.__result = undefined;
         this.__result = undefined;
 
 
         var parent = this.parent();
         var parent = this.parent();
-        this.__type = new Procedure.make(parent.typeName());
+        var name = parent.typeName();
+        if (name === undefined)
+            name = "";
+        this.__type = new Procedure.make(name);
         parent.setType(this.__type);
         parent.setType(this.__type);
     },
     },
     handleMessage: function(msg){
     handleMessage: function(msg){
@@ -551,7 +554,7 @@ exports.ProcDecl = ChainedContext.extend({
         if (this.__id.id() != id)
         if (this.__id.id() != id)
             throw new Errors.Error("mismatched procedure names: '" + this.__id.id()
             throw new Errors.Error("mismatched procedure names: '" + this.__id.id()
                                  + "' at the begining and '" + id + "' at the end");
                                  + "' at the begining and '" + id + "' at the end");
-        this.codeGenerator().closeScope();
+        this.codeGenerator().closeScope("");
         this.parent().popScope();
         this.parent().popScope();
     },
     },
     _prolog: function(){return "\nfunction " + this.__id.id() + "(";},
     _prolog: function(){return "\nfunction " + this.__id.id() + "(";},
@@ -663,7 +666,7 @@ exports.PointerDecl = ChainedContext.extend({
 
 
         var parent = this.parent();
         var parent = this.parent();
         var name = parent.isAnonymousDeclaration() 
         var name = parent.isAnonymousDeclaration() 
-            ? undefined
+            ? ""
             : parent.genTypeName();
             : parent.genTypeName();
         var pointerType = Type.makePointer(name, typeId);
         var pointerType = Type.makePointer(name, typeId);
         parent.setType(pointerType);
         parent.setType(pointerType);
@@ -1269,7 +1272,7 @@ exports.ElseIf = IfContextBase.extend({
     init: function ElseIfContext(context){
     init: function ElseIfContext(context){
         ChainedContext.prototype.init.call(this, context);
         ChainedContext.prototype.init.call(this, context);
         var gen = this.codeGenerator();
         var gen = this.codeGenerator();
-        gen.closeScope();
+        gen.closeScope("");
         gen.write("else if (");
         gen.write("else if (");
     }
     }
 });
 });
@@ -1278,7 +1281,7 @@ exports.Else = ChainedContext.extend({
     init: function ElseContext(context){
     init: function ElseContext(context){
         ChainedContext.prototype.init.call(this, context);
         ChainedContext.prototype.init.call(this, context);
         var gen = this.codeGenerator();
         var gen = this.codeGenerator();
-        gen.closeScope();
+        gen.closeScope("");
         gen.write("else ");
         gen.write("else ");
         gen.openScope();
         gen.openScope();
     }
     }
@@ -1289,7 +1292,7 @@ exports.emitEndStatement = function(context){
 };
 };
 
 
 exports.emitIfEnd = function(context){
 exports.emitIfEnd = function(context){
-    context.codeGenerator().closeScope();
+    context.codeGenerator().closeScope("");
 };
 };
 
 
 exports.Case = ChainedContext.extend({
 exports.Case = ChainedContext.extend({
@@ -1364,7 +1367,7 @@ exports.CaseLabel = ChainedContext.extend({
     },
     },
     handleLabelType: function(type){this.parent().handleLabelType(type);},
     handleLabelType: function(type){this.parent().handleLabelType(type);},
     handleRange: function(from, to){this.parent().handleRange(from, to);},
     handleRange: function(from, to){this.parent().handleRange(from, to);},
-    endParse: function(){this.codeGenerator().closeScope();}
+    endParse: function(){this.codeGenerator().closeScope("");}
 });
 });
 
 
 exports.CaseRange = ChainedContext.extend({
 exports.CaseRange = ChainedContext.extend({
@@ -1423,7 +1426,7 @@ exports.While = ChainedContext.extend({
 exports.emitWhileEnd = function(context){
 exports.emitWhileEnd = function(context){
     var gen = context.codeGenerator();
     var gen = context.codeGenerator();
     gen.closeScope(" else break;\n");
     gen.closeScope(" else break;\n");
-    gen.closeScope();
+    gen.closeScope("");
 };
 };
 
 
 exports.Repeat = ChainedContext.extend({
 exports.Repeat = ChainedContext.extend({
@@ -1510,7 +1513,7 @@ exports.For = ChainedContext.extend({
         gen.write(s);
         gen.write(s);
         gen.openScope();
         gen.openScope();
     },
     },
-    endParse: function(){this.codeGenerator().closeScope();}
+    endParse: function(){this.codeGenerator().closeScope("");}
 });
 });
 
 
 exports.emitForBegin = function(context){context.handleBegin();};
 exports.emitForBegin = function(context){context.handleBegin();};
@@ -1745,7 +1748,7 @@ exports.RecordDecl = ChainedContext.extend({
         ChainedContext.prototype.init.call(this, context);
         ChainedContext.prototype.init.call(this, context);
         var parent = this.parent();
         var parent = this.parent();
         var cons = parent.genTypeName();
         var cons = parent.genTypeName();
-        var name = parent.isAnonymousDeclaration() ? undefined : cons;
+        var name = parent.isAnonymousDeclaration() ? "" : cons;
         this.__type = makeRecord(name, cons, context.currentScope());
         this.__type = makeRecord(name, cons, context.currentScope());
         parent.setType(this.__type);
         parent.setType(this.__type);
         parent.codeGenerator().write("var " + cons + " = ");
         parent.codeGenerator().write("var " + cons + " = ");
@@ -1787,7 +1790,7 @@ exports.RecordDecl = ChainedContext.extend({
         for(var f in ownFields)
         for(var f in ownFields)
             gen.write("this." + f + " = " + ownFields[f].initializer(this) + ";\n");
             gen.write("this." + f + " = " + ownFields[f].initializer(this) + ";\n");
 
 
-        gen.closeScope();
+        gen.closeScope("");
         gen.closeScope(");\n");
         gen.closeScope(");\n");
     }
     }
 });
 });

+ 2 - 1
src/eberon/EberonCast.ob

@@ -5,7 +5,8 @@ PROCEDURE implicit*(from, to: Types.PType; toVar: BOOLEAN; ops: Cast.Operations;
 VAR
 VAR
     result: INTEGER;
     result: INTEGER;
 BEGIN
 BEGIN
-    IF ((from = EberonString.string) & (to IS Types.PArray) & (Types.arrayLength(to(Types.PArray)^) = Types.openArrayLength))
+    IF ((from = EberonString.string) 
+            & ((to IS Types.PString) OR (to IS Types.PArray) & (Types.arrayLength(to(Types.PArray)^) = Types.openArrayLength)))
         OR (Types.isString(from) & (to = EberonString.string)) THEN
         OR (Types.isString(from) & (to = EberonString.string)) THEN
         IF toVar THEN 
         IF toVar THEN 
             result := Cast.errVarParameter;
             result := Cast.errVarParameter;

+ 11 - 7
src/eberon/EberonOperator.ob

@@ -1,9 +1,9 @@
 MODULE EberonOperator;
 MODULE EberonOperator;
-IMPORT Code, CodePrecedence, JsString, OberonRtl, Operator;
+IMPORT Code, CodePrecedence, OberonRtl, Operator;
 
 
 PROCEDURE opAddStr(left, right: Code.PConst): Code.PConst;
 PROCEDURE opAddStr(left, right: Code.PConst): Code.PConst;
-    RETURN Code.makeStringConst(JsString.concat(left^(Code.StringConst).value, 
-                                                right^(Code.StringConst).value))
+    RETURN Code.makeStringConst(left^(Code.StringConst).value
+                              + right^(Code.StringConst).value)
 END opAddStr;
 END opAddStr;
 
 
 PROCEDURE opEqualStr(left, right: Code.PConst): Code.PConst;
 PROCEDURE opEqualStr(left, right: Code.PConst): Code.PConst;
@@ -17,19 +17,23 @@ PROCEDURE opNotEqualStr(left, right: Code.PConst): Code.PConst;
 END opNotEqualStr;
 END opNotEqualStr;
 
 
 PROCEDURE opLessStr(left, right: Code.PConst): Code.PConst;
 PROCEDURE opLessStr(left, right: Code.PConst): Code.PConst;
-    RETURN Code.makeIntConst(0) (*to fix*)
+    RETURN Code.makeIntConst(ORD(left^(Code.StringConst).value
+                               < right^(Code.StringConst).value))
 END opLessStr;
 END opLessStr;
 
 
 PROCEDURE opGreaterStr(left, right: Code.PConst): Code.PConst;
 PROCEDURE opGreaterStr(left, right: Code.PConst): Code.PConst;
-    RETURN Code.makeIntConst(0) (*to fix*)
+    RETURN Code.makeIntConst(ORD(left^(Code.StringConst).value
+                               > right^(Code.StringConst).value))
 END opGreaterStr;
 END opGreaterStr;
 
 
 PROCEDURE opLessEqualStr(left, right: Code.PConst): Code.PConst;
 PROCEDURE opLessEqualStr(left, right: Code.PConst): Code.PConst;
-    RETURN Code.makeIntConst(0) (*to fix*)
+    RETURN Code.makeIntConst(ORD(left^(Code.StringConst).value
+                              <= right^(Code.StringConst).value))
 END opLessEqualStr;
 END opLessEqualStr;
 
 
 PROCEDURE opGraterEqualStr(left, right: Code.PConst): Code.PConst;
 PROCEDURE opGraterEqualStr(left, right: Code.PConst): Code.PConst;
-    RETURN Code.makeIntConst(0) (*to fix*)
+    RETURN Code.makeIntConst(ORD(left^(Code.StringConst).value
+                              >= right^(Code.StringConst).value))
 END opGraterEqualStr;
 END opGraterEqualStr;
 
 
 PROCEDURE addStr*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
 PROCEDURE addStr*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;

+ 3 - 3
src/eberon/EberonString.ob

@@ -1,13 +1,13 @@
 MODULE EberonString;
 MODULE EberonString;
-IMPORT JsString, Types;
+IMPORT Types;
 TYPE
 TYPE
     ElementVariable = RECORD(Types.Variable)
     ElementVariable = RECORD(Types.Variable)
     END;
     END;
 VAR
 VAR
     string*: POINTER TO Types.BasicType;
     string*: POINTER TO Types.BasicType;
 
 
-PROCEDURE ElementVariable.idType(): JsString.Type;
-    RETURN JsString.make("string element")
+PROCEDURE ElementVariable.idType(): STRING;
+    RETURN "string element"
 END ElementVariable.idType;
 END ElementVariable.idType;
 
 
 PROCEDURE ElementVariable.isReadOnly(): BOOLEAN;
 PROCEDURE ElementVariable.isReadOnly(): BOOLEAN;

+ 2 - 2
src/ob/Cast.ob

@@ -1,5 +1,5 @@
 MODULE Cast;
 MODULE Cast;
-IMPORT Code, OberonRtl, JsArray, JsString, Object, Types;
+IMPORT Code, OberonRtl, JsArray, Object, String, Types;
 CONST
 CONST
     errNo* = 0;
     errNo* = 0;
     err* = 1;
     err* = 1;
@@ -118,7 +118,7 @@ BEGIN
 END areTypesExactlyMatchImpl;
 END areTypesExactlyMatchImpl;
 
 
 PROCEDURE CastOpStrToChar.make(rtl: OberonRtl.PType; e: Code.PExpression): Code.PExpression;
 PROCEDURE CastOpStrToChar.make(rtl: OberonRtl.PType; e: Code.PExpression): Code.PExpression;
-    RETURN Code.makeSimpleExpression(JsString.fromInt(ORD(SELF.c)), Types.basic.ch)
+    RETURN Code.makeSimpleExpression(String.fromInt(ORD(SELF.c)), Types.basic.ch)
 END CastOpStrToChar.make;
 END CastOpStrToChar.make;
 
 
 PROCEDURE makeCastOpStrToChar(c: CHAR): PCastOp;
 PROCEDURE makeCastOpStrToChar(c: CHAR): PCastOp;

+ 89 - 126
src/ob/Code.ob

@@ -1,15 +1,22 @@
 MODULE Code;
 MODULE Code;
-IMPORT JsMap, JsString, Object, Stream, ScopeBase, Symbols, Precedence := CodePrecedence, Types;
-
+IMPORT 
+    JsMap, 
+    Object, 
+    Stream, 
+    ScopeBase, 
+    Symbols, 
+    Precedence := CodePrecedence, 
+    String, 
+    Types;
 CONST
 CONST
     kTab = 09X;
     kTab = 09X;
 
 
 TYPE
 TYPE
     IGenerator = RECORD
     IGenerator = RECORD
-        PROCEDURE write(s: JsString.Type);
+        PROCEDURE write(s: STRING);
         PROCEDURE openScope();
         PROCEDURE openScope();
-        PROCEDURE closeScope(ending: JsString.Type);
-        PROCEDURE result(): JsString.Type
+        PROCEDURE closeScope(ending: STRING);
+        PROCEDURE result(): STRING
     END;
     END;
 
 
     PIGenerator = POINTER TO IGenerator;
     PIGenerator = POINTER TO IGenerator;
@@ -18,25 +25,25 @@ TYPE
     END;
     END;
 
 
     SimpleGenerator = RECORD(NullGenerator)
     SimpleGenerator = RECORD(NullGenerator)
-        mResult: JsString.Type
+        mResult: STRING
     END;
     END;
 
 
     Generator = RECORD(SimpleGenerator)
     Generator = RECORD(SimpleGenerator)
         indent: INTEGER
         indent: INTEGER
     END;
     END;
 
 
-    RefCodeProc = PROCEDURE(s: JsString.Type): JsString.Type;
+    RefCodeProc = PROCEDURE(s: STRING): STRING;
 
 
     Designator* = RECORD
     Designator* = RECORD
-        PROCEDURE code(): JsString.Type;
-        PROCEDURE lval(): JsString.Type;
+        PROCEDURE code(): STRING;
+        PROCEDURE lval(): STRING;
         PROCEDURE refCode(): RefCodeProc;
         PROCEDURE refCode(): RefCodeProc;
         PROCEDURE type(): Types.PType;
         PROCEDURE type(): Types.PType;
         PROCEDURE info*(): Types.PId;
         PROCEDURE info*(): Types.PId;
         PROCEDURE scope(): ScopeBase.PType;
         PROCEDURE scope(): ScopeBase.PType;
 
 
-        mCode: JsString.Type;
-        mLval: JsString.Type;
+        mCode: STRING;
+        mLval: STRING;
         mRefCode: RefCodeProc;
         mRefCode: RefCodeProc;
         mType: Types.PType;
         mType: Types.PType;
         mInfo: Types.PId;
         mInfo: Types.PId;
@@ -62,19 +69,19 @@ TYPE
     END;
     END;
 
 
     StringConst* = RECORD (Const)
     StringConst* = RECORD (Const)
-        value*: JsString.Type
+        value*: STRING
     END;
     END;
 
 
     Expression* = RECORD(Object.Type)
     Expression* = RECORD(Object.Type)
-        PROCEDURE code*(): JsString.Type;
-        PROCEDURE lval*(): JsString.Type;
+        PROCEDURE code*(): STRING;
+        PROCEDURE lval*(): STRING;
         PROCEDURE type*(): Types.PType;
         PROCEDURE type*(): Types.PType;
         PROCEDURE designator*(): PDesignator;
         PROCEDURE designator*(): PDesignator;
         PROCEDURE constValue*(): PConst;
         PROCEDURE constValue*(): PConst;
         PROCEDURE maxPrecedence*(): INTEGER;
         PROCEDURE maxPrecedence*(): INTEGER;
         PROCEDURE isTerm*(): BOOLEAN;
         PROCEDURE isTerm*(): BOOLEAN;
 
 
-        mCode: JsString.Type;
+        mCode: STRING;
         mType: Types.PType;
         mType: Types.PType;
         mDesignator: PDesignator;
         mDesignator: PDesignator;
         mConstValue: PConst;
         mConstValue: PConst;
@@ -84,99 +91,96 @@ TYPE
     PExpression* = POINTER TO Expression;
     PExpression* = POINTER TO Expression;
 
 
     ModuleGenerator = RECORD
     ModuleGenerator = RECORD
-        PROCEDURE prolog(): JsString.Type;
-        PROCEDURE epilog(exports: JsMap.Type): JsString.Type;
+        PROCEDURE prolog(): STRING;
+        PROCEDURE epilog(exports: JsMap.Type): STRING;
 
 
-        name: JsString.Type;
+        name: STRING;
         imports: JsMap.Strings
         imports: JsMap.Strings
     END;
     END;
 
 
     PModuleGenerator = POINTER TO ModuleGenerator;
     PModuleGenerator = POINTER TO ModuleGenerator;
 
 
     Closure = RECORD(Object.Type)
     Closure = RECORD(Object.Type)
-        result: JsString.Type
+        result: STRING
     END;
     END;
 
 
 VAR
 VAR
     nullGenerator*: NullGenerator;
     nullGenerator*: NullGenerator;
 
 
-PROCEDURE NullGenerator.write(s: JsString.Type);
+PROCEDURE NullGenerator.write(s: STRING);
 END NullGenerator.write;
 END NullGenerator.write;
 
 
 PROCEDURE NullGenerator.openScope();
 PROCEDURE NullGenerator.openScope();
 END NullGenerator.openScope;
 END NullGenerator.openScope;
 
 
-PROCEDURE NullGenerator.closeScope(ending: JsString.Type);
+PROCEDURE NullGenerator.closeScope(ending: STRING);
 END NullGenerator.closeScope;
 END NullGenerator.closeScope;
 
 
-PROCEDURE NullGenerator.result(): JsString.Type;
-    RETURN NIL
+PROCEDURE NullGenerator.result(): STRING;
+    RETURN ""
 END NullGenerator.result;
 END NullGenerator.result;
 
 
-PROCEDURE SimpleGenerator.write(s: JsString.Type);
+PROCEDURE SimpleGenerator.write(s: STRING);
 BEGIN
 BEGIN
-    SELF.mResult := JsString.concat(SELF.mResult, s);
+    SELF.mResult := SELF.mResult + s;
 END SimpleGenerator.write;
 END SimpleGenerator.write;
 
 
-PROCEDURE SimpleGenerator.result(): JsString.Type;
+PROCEDURE SimpleGenerator.result(): STRING;
     RETURN SELF.mResult
     RETURN SELF.mResult
 END SimpleGenerator.result;
 END SimpleGenerator.result;
 
 
-PROCEDURE putIndent(s: JsString.Type; indent: INTEGER): JsString.Type;
+PROCEDURE putIndent(s: STRING; indent: INTEGER): STRING;
 VAR
 VAR
     i: INTEGER;
     i: INTEGER;
 BEGIN
 BEGIN
     FOR i := 0 TO indent - 1 DO
     FOR i := 0 TO indent - 1 DO
-        s := JsString.appendChar(s, kTab);
+        s := s + kTab;
     END;
     END;
     RETURN s
     RETURN s
 END putIndent;
 END putIndent;
 
 
-PROCEDURE Generator.write(s: JsString.Type);
+PROCEDURE Generator.write(s: STRING);
 VAR
 VAR
     pos: INTEGER;
     pos: INTEGER;
     index: INTEGER;
     index: INTEGER;
 BEGIN
 BEGIN
-    index := JsString.indexOf(s, Stream.kCR);
+    index := String.indexOf(s, Stream.kCR);
     WHILE index # -1 DO
     WHILE index # -1 DO
         INC(index);
         INC(index);
-        SELF.mResult := JsString.concat(SELF.mResult, JsString.substr(s, pos, index - pos));
+        SELF.mResult := SELF.mResult + String.substr(s, pos, index - pos);
         SELF.mResult := putIndent(SELF.mResult, SELF.indent);
         SELF.mResult := putIndent(SELF.mResult, SELF.indent);
         pos := index;
         pos := index;
-        index := JsString.indexOfFrom(s, Stream.kCR, pos);
+        index := String.indexOfFrom(s, Stream.kCR, pos);
     END;
     END;
-    SELF.mResult := JsString.concat(SELF.mResult, 
-                                    JsString.substr(s, pos, JsString.len(s) - pos));
+    SELF.mResult := SELF.mResult + String.substr(s, pos, LEN(s) - pos);
 END Generator.write;
 END Generator.write;
 
 
 PROCEDURE Generator.openScope();
 PROCEDURE Generator.openScope();
 BEGIN
 BEGIN
     INC(SELF.indent);
     INC(SELF.indent);
-    SELF.mResult := JsString.appendChar(SELF.mResult, "{");
-    SELF.mResult := JsString.appendChar(SELF.mResult, Stream.kCR);
+    SELF.mResult := SELF.mResult + "{" + Stream.kCR;
     SELF.mResult := putIndent(SELF.mResult, SELF.indent);
     SELF.mResult := putIndent(SELF.mResult, SELF.indent);
 END Generator.openScope;
 END Generator.openScope;
 
 
-PROCEDURE Generator.closeScope(ending: JsString.Type);
+PROCEDURE Generator.closeScope(ending: STRING);
 BEGIN
 BEGIN
     DEC(SELF.indent);
     DEC(SELF.indent);
-    SELF.mResult := JsString.substr(SELF.mResult, 0, JsString.len(SELF.mResult) - 1);
-    SELF.mResult := JsString.appendChar(SELF.mResult, "}");
-    IF ending # NIL THEN
+    SELF.mResult := String.substr(SELF.mResult, 0, LEN(SELF.mResult) - 1) + "}";
+    IF LEN(ending) # 0 THEN
         SELF.write(ending);
         SELF.write(ending);
     ELSE
     ELSE
-        SELF.mResult := JsString.appendChar(SELF.mResult, Stream.kCR);
+        SELF.mResult := SELF.mResult + Stream.kCR;
         SELF.mResult := putIndent(SELF.mResult, SELF.indent);
         SELF.mResult := putIndent(SELF.mResult, SELF.indent);
     END;
     END;
 END Generator.closeScope;
 END Generator.closeScope;
 
 
-PROCEDURE Expression.code(): JsString.Type;
+PROCEDURE Expression.code(): STRING;
     RETURN SELF.mCode
     RETURN SELF.mCode
 END Expression.code;
 END Expression.code;
 
 
-PROCEDURE Expression.lval(): JsString.Type;
+PROCEDURE Expression.lval(): STRING;
 VAR
 VAR
-    result: JsString.Type;
+    result: STRING;
 BEGIN
 BEGIN
     IF SELF.mDesignator # NIL THEN
     IF SELF.mDesignator # NIL THEN
         result := SELF.mDesignator.mLval;
         result := SELF.mDesignator.mLval;
@@ -233,7 +237,7 @@ BEGIN
     RETURN result
     RETURN result
 END makeSetConst;
 END makeSetConst;
 
 
-PROCEDURE makeStringConst*(s: JsString.Type): PConst;
+PROCEDURE makeStringConst*(s: STRING): PConst;
 VAR
 VAR
     result: POINTER TO StringConst;
     result: POINTER TO StringConst;
 BEGIN
 BEGIN
@@ -243,7 +247,7 @@ BEGIN
 END makeStringConst;
 END makeStringConst;
 
 
 PROCEDURE makeExpressionWithPrecedence*(
 PROCEDURE makeExpressionWithPrecedence*(
-    code: JsString.Type; 
+    code: STRING; 
     type: Types.PType; 
     type: Types.PType; 
     designator: PDesignator; 
     designator: PDesignator; 
     constValue: PConst; 
     constValue: PConst; 
@@ -251,7 +255,6 @@ PROCEDURE makeExpressionWithPrecedence*(
 VAR
 VAR
     result: PExpression;
     result: PExpression;
 BEGIN
 BEGIN
-    ASSERT(code # NIL);
     NEW(result);
     NEW(result);
     result.mCode := code;
     result.mCode := code;
     result.mType := type;
     result.mType := type;
@@ -262,7 +265,7 @@ BEGIN
 END makeExpressionWithPrecedence;
 END makeExpressionWithPrecedence;
 
 
 PROCEDURE makeExpression*(
 PROCEDURE makeExpression*(
-    code: JsString.Type; 
+    code: STRING; 
     type: Types.PType; 
     type: Types.PType; 
     designator: PDesignator; 
     designator: PDesignator; 
     constValue: PConst)
     constValue: PConst)
@@ -271,17 +274,17 @@ PROCEDURE makeExpression*(
 END makeExpression;
 END makeExpression;
 
 
 PROCEDURE makeSimpleExpression*(
 PROCEDURE makeSimpleExpression*(
-    code: JsString.Type; 
+    code: STRING; 
     type: Types.PType)
     type: Types.PType)
     : PExpression;
     : PExpression;
     RETURN makeExpression(code, type, NIL, NIL)
     RETURN makeExpression(code, type, NIL, NIL)
 END makeSimpleExpression;
 END makeSimpleExpression;
 
 
-PROCEDURE Designator.code(): JsString.Type;
+PROCEDURE Designator.code(): STRING;
     RETURN SELF.mCode
     RETURN SELF.mCode
 END Designator.code;
 END Designator.code;
 
 
-PROCEDURE Designator.lval(): JsString.Type;
+PROCEDURE Designator.lval(): STRING;
     RETURN SELF.mLval
     RETURN SELF.mLval
 END Designator.lval;
 END Designator.lval;
 
 
@@ -301,7 +304,7 @@ PROCEDURE Designator.scope(): ScopeBase.PType;
     RETURN SELF.mScope
     RETURN SELF.mScope
 END Designator.scope;
 END Designator.scope;
 
 
-PROCEDURE makeDesignator*(code: JsString.Type; lval: JsString.Type; refCode: RefCodeProc; type: Types.PType; info: Types.PId; scope: ScopeBase.PType): PDesignator;
+PROCEDURE makeDesignator*(code: STRING; lval: STRING; refCode: RefCodeProc; type: Types.PType; info: Types.PId; scope: ScopeBase.PType): PDesignator;
 VAR
 VAR
     result: PDesignator;
     result: PDesignator;
 BEGIN
 BEGIN
@@ -324,8 +327,7 @@ BEGIN
         OR ~(e.mDesignator.mInfo IS Types.PVariableRef) THEN
         OR ~(e.mDesignator.mInfo IS Types.PVariableRef) THEN
         result := e;
         result := e;
     ELSE
     ELSE
-        result := makeSimpleExpression(JsString.concat(e.mCode, JsString.make(".get()")),
-                                       e.mType);
+        result := makeSimpleExpression(e.mCode + ".get()", e.mType);
     END;
     END;
     RETURN result
     RETURN result
 END derefExpression;
 END derefExpression;
@@ -344,35 +346,32 @@ BEGIN
     RETURN result
     RETURN result
 END refExpression;
 END refExpression;
 
 
-PROCEDURE adjustPrecedence*(e: PExpression; precedence: INTEGER): JsString.Type;
+PROCEDURE adjustPrecedence*(e: PExpression; precedence: INTEGER): STRING;
 VAR
 VAR
-    result: JsString.Type;
+    result: STRING;
 BEGIN
 BEGIN
     result := e.mCode;
     result := e.mCode;
     IF (precedence # Precedence.none) & (e.mMaxPrecedence > precedence) THEN
     IF (precedence # Precedence.none) & (e.mMaxPrecedence > precedence) THEN
-        result := JsString.concat(JsString.concat(
-            JsString.make("("), 
-            result), 
-            JsString.make(")"));
+        result := "(" + result + ")";
     END;
     END;
     RETURN result
     RETURN result
 END adjustPrecedence;
 END adjustPrecedence;
 
 
-PROCEDURE isPointerShouldBeExported(type: Types.Pointer): JsString.Type;
+PROCEDURE isPointerShouldBeExported(type: Types.Pointer): STRING;
 VAR
 VAR
     r: Types.PRecord;
     r: Types.PRecord;
-    result: JsString.Type;
+    result: STRING;
 BEGIN
 BEGIN
     r := Types.pointerBase(type);
     r := Types.pointerBase(type);
-    IF Types.typeName(r^) = NIL THEN
+    IF LEN(Types.typeName(r^)) = 0 THEN
         result := Types.recordConstructor(r^);
         result := Types.recordConstructor(r^);
     END;
     END;
     RETURN result
     RETURN result
 END isPointerShouldBeExported;
 END isPointerShouldBeExported;
 
 
-PROCEDURE typeShouldBeExported(typeId: Types.PId; defaultId: JsString.Type): JsString.Type;
+PROCEDURE typeShouldBeExported(typeId: Types.PId; defaultId: STRING): STRING;
 VAR
 VAR
-    result: JsString.Type;
+    result: STRING;
     type: Types.PType;
     type: Types.PType;
 BEGIN
 BEGIN
     type := typeId(Types.PTypeId).type();
     type := typeId(Types.PTypeId).type();
@@ -384,15 +383,12 @@ BEGIN
     RETURN result
     RETURN result
 END typeShouldBeExported;
 END typeShouldBeExported;
 
 
-PROCEDURE genExport*(s: Symbols.Symbol): JsString.Type;
+PROCEDURE genExport*(s: Symbols.Symbol): STRING;
 VAR
 VAR
-    result: JsString.Type;
+    result: STRING;
 BEGIN
 BEGIN
     IF s.isVariable() THEN
     IF s.isVariable() THEN
-        result := JsString.concat(JsString.concat(
-            JsString.make("function(){return "),
-            s.id()),
-            JsString.make(";}"));
+        result := "function(){return " + s.id() + ";}";
     ELSIF ~s.isType() THEN
     ELSIF ~s.isType() THEN
         result := s.id();
         result := s.id();
     ELSE
     ELSE
@@ -401,105 +397,73 @@ BEGIN
     RETURN result
     RETURN result
 END genExport;
 END genExport;
 
 
-PROCEDURE genCommaList(name: JsString.Type; closure: Closure);
+PROCEDURE genCommaList(name: STRING; closure: Closure);
 BEGIN
 BEGIN
-    IF JsString.len(closure.result) # 0 THEN
-        closure.result := JsString.concat(closure.result, JsString.make(", "));
+    IF LEN(closure.result) # 0 THEN
+        closure.result := closure.result + ", ";
     END;
     END;
-    closure.result := JsString.concat(closure.result, name);
+    closure.result := closure.result + name;
 END genCommaList;
 END genCommaList;
 
 
-PROCEDURE genAliasesAdaptor(key: JsString.Type; value: JsString.Type; VAR closure: Object.Type);
+PROCEDURE genAliasesAdaptor(key: STRING; value: STRING; VAR closure: Object.Type);
 BEGIN
 BEGIN
     genCommaList(value, closure(Closure));
     genCommaList(value, closure(Closure));
 END genAliasesAdaptor;
 END genAliasesAdaptor;
 
 
-PROCEDURE ModuleGenerator.prolog(): JsString.Type;
+PROCEDURE ModuleGenerator.prolog(): STRING;
 VAR
 VAR
     closure: Closure;
     closure: Closure;
 BEGIN
 BEGIN
-    closure.result := JsString.makeEmpty();
     JsMap.forEachString(SELF.imports, genAliasesAdaptor, closure);
     JsMap.forEachString(SELF.imports, genAliasesAdaptor, closure);
-    RETURN JsString.appendChar(JsString.concat(JsString.concat(JsString.concat(JsString.concat(
-        JsString.make("var "),
-        SELF.name),
-        JsString.make(" = function (")),
-        closure.result),
-        JsString.make("){")),
-        Stream.kCR)
+    RETURN "var " + SELF.name + " = function (" + closure.result + "){" + Stream.kCR
 END ModuleGenerator.prolog;
 END ModuleGenerator.prolog;
 
 
 PROCEDURE genExports(s: Symbols.Symbol; closure: Closure);
 PROCEDURE genExports(s: Symbols.Symbol; closure: Closure);
 VAR
 VAR
-    code: JsString.Type;
+    code: STRING;
 BEGIN
 BEGIN
     code := genExport(s);
     code := genExport(s);
-    IF code # NIL THEN
-        IF JsString.len(closure.result) # 0 THEN
-            closure.result := JsString.appendChar(JsString.appendChar(
-                closure.result,
-                ","),
-                Stream.kCR);
+    IF LEN(code) # 0 THEN
+        IF LEN(closure.result) # 0 THEN
+            closure.result := closure.result + "," + Stream.kCR;
         END;
         END;
-        closure.result := JsString.concat(JsString.concat(JsString.concat(JsString.appendChar(
-            closure.result, 
-            kTab),
-            s.id()),
-            JsString.make(": ")),
-            code);
+        closure.result := closure.result + kTab + s.id() + ": " + code;
     END;
     END;
 END genExports;
 END genExports;
 
 
-PROCEDURE genExportsAdaptor(key: JsString.Type; value: Object.PType; VAR closure: Object.Type);
+PROCEDURE genExportsAdaptor(key: STRING; value: Object.PType; VAR closure: Object.Type);
 BEGIN
 BEGIN
     genExports(value^(Symbols.Symbol), closure(Closure));
     genExports(value^(Symbols.Symbol), closure(Closure));
 END genExportsAdaptor;
 END genExportsAdaptor;
 
 
-PROCEDURE genImportListAdaptor(key: JsString.Type; value: JsString.Type; VAR closure: Object.Type);
+PROCEDURE genImportListAdaptor(key: STRING; value: STRING; VAR closure: Object.Type);
 BEGIN
 BEGIN
     genCommaList(key, closure(Closure));
     genCommaList(key, closure(Closure));
 END genImportListAdaptor;
 END genImportListAdaptor;
 
 
-PROCEDURE ModuleGenerator.epilog(exports: JsMap.Type): JsString.Type;
+PROCEDURE ModuleGenerator.epilog(exports: JsMap.Type): STRING;
 VAR
 VAR
-    result: JsString.Type;
+    result: STRING;
     closure: Closure;
     closure: Closure;
 BEGIN
 BEGIN
-    closure.result := JsString.makeEmpty();
     JsMap.forEach(exports, genExportsAdaptor, closure);
     JsMap.forEach(exports, genExportsAdaptor, closure);
     result := closure.result;
     result := closure.result;
-    IF JsString.len(result) # 0 THEN
-        result := JsString.appendChar(JsString.appendChar(JsString.appendChar(JsString.concat(JsString.appendChar(
-            JsString.make("return {"),
-            Stream.kCR),
-            result),
-            Stream.kCR),
-            "}"),
-            Stream.kCR);
+    IF LEN(result) # 0 THEN
+        result := "return {" + Stream.kCR + result + Stream.kCR + "}" + Stream.kCR;
     END;
     END;
-    result := JsString.concat(result, JsString.make("}("));
+    result := result + "}(";
 
 
-    closure.result := JsString.makeEmpty();
+    closure.result := "";
     JsMap.forEachString(SELF.imports, genImportListAdaptor, closure);
     JsMap.forEachString(SELF.imports, genImportListAdaptor, closure);
-    result := JsString.appendChar(JsString.concat(JsString.concat(
-        result, 
-        closure.result), 
-        JsString.make(");")), 
-        Stream.kCR);
+    result := result + closure.result + ");" + Stream.kCR;
     RETURN result
     RETURN result
 END ModuleGenerator.epilog;
 END ModuleGenerator.epilog;
 
 
-PROCEDURE initSimpleGenerator(g: SimpleGenerator);
-BEGIN
-    g.mResult := JsString.makeEmpty();
-END initSimpleGenerator;
-
 PROCEDURE makeSimpleGenerator*(): PIGenerator;
 PROCEDURE makeSimpleGenerator*(): PIGenerator;
 VAR
 VAR
     result: POINTER TO SimpleGenerator;
     result: POINTER TO SimpleGenerator;
 BEGIN
 BEGIN
     NEW(result);
     NEW(result);
-    initSimpleGenerator(result^);
     RETURN result
     RETURN result
 END makeSimpleGenerator;
 END makeSimpleGenerator;
 
 
@@ -508,11 +472,10 @@ VAR
     result: POINTER TO Generator;
     result: POINTER TO Generator;
 BEGIN
 BEGIN
     NEW(result);
     NEW(result);
-    initSimpleGenerator(result^);
     RETURN result
     RETURN result
 END makeGenerator;
 END makeGenerator;
 
 
-PROCEDURE makeModuleGenerator*(name: JsString.Type; imports: JsMap.Strings): PModuleGenerator;
+PROCEDURE makeModuleGenerator*(name: STRING; imports: JsMap.Strings): PModuleGenerator;
 VAR
 VAR
     result: PModuleGenerator;
     result: PModuleGenerator;
 BEGIN
 BEGIN

+ 5 - 5
src/ob/Context.ob

@@ -1,13 +1,13 @@
 MODULE Context;
 MODULE Context;
-IMPORT JsString, OberonRtl, Object, ScopeBase;
+IMPORT OberonRtl, Object, ScopeBase;
 TYPE
 TYPE
     Type* = RECORD
     Type* = RECORD
         handleChar*:    PROCEDURE(c: CHAR);
         handleChar*:    PROCEDURE(c: CHAR);
-        handleLiteral*: PROCEDURE(s: JsString.Type): BOOLEAN;
-        handleString*:  PROCEDURE(s: JsString.Type);
-        handleIdent*:   PROCEDURE(s: JsString.Type);
+        handleLiteral*: PROCEDURE(s: STRING): BOOLEAN;
+        handleString*:  PROCEDURE(s: STRING);
+        handleIdent*:   PROCEDURE(s: STRING);
         isLexem*:       PROCEDURE(): BOOLEAN;
         isLexem*:       PROCEDURE(): BOOLEAN;
-        qualifyScope*:  PROCEDURE(scope: ScopeBase.PType): JsString.Type;
+        qualifyScope*:  PROCEDURE(scope: ScopeBase.PType): STRING;
         
         
         rtl*: OberonRtl.PType
         rtl*: OberonRtl.PType
     END;
     END;

+ 2 - 2
src/ob/Errors.ob

@@ -1,9 +1,9 @@
 MODULE Errors;
 MODULE Errors;
-IMPORT JS, JsString;
+IMPORT JS;
 
 
 TYPE Error* = RECORD END;
 TYPE Error* = RECORD END;
 
 
-PROCEDURE raise*(msg: JsString.Type);
+PROCEDURE raise*(msg: STRING);
 BEGIN
 BEGIN
     JS.do("throw new Error(msg)")
     JS.do("throw new Error(msg)")
 END raise;
 END raise;

+ 6 - 6
src/ob/JsArray.ob

@@ -1,5 +1,5 @@
 MODULE JsArray;
 MODULE JsArray;
-IMPORT JS, Object, JsString;
+IMPORT JS, Object;
 TYPE
 TYPE
     Type* = POINTER TO RECORD END;
     Type* = POINTER TO RECORD END;
     Strings* = POINTER TO RECORD END;
     Strings* = POINTER TO RECORD END;
@@ -25,7 +25,7 @@ BEGIN
     JS.do("a.push(o)");
     JS.do("a.push(o)");
 END add;
 END add;
 
 
-PROCEDURE addString*(a: Strings; o: JsString.Type);
+PROCEDURE addString*(a: Strings; o: STRING);
 BEGIN
 BEGIN
     JS.do("a.push(o)");
     JS.do("a.push(o)");
 END addString;
 END addString;
@@ -43,15 +43,15 @@ BEGIN
     RETURN result
     RETURN result
 END at;
 END at;
 
 
-PROCEDURE stringsAt*(a: Strings; i: INTEGER): JsString.Type;
+PROCEDURE stringsAt*(a: Strings; i: INTEGER): STRING;
 VAR
 VAR
-    result: JsString.Type;
+    result: STRING;
 BEGIN
 BEGIN
     JS.do("result = a[i]");
     JS.do("result = a[i]");
     RETURN result
     RETURN result
 END stringsAt;
 END stringsAt;
 
 
-PROCEDURE stringsIndexOf*(a: Strings; x: JsString.Type): INTEGER;
+PROCEDURE stringsIndexOf*(a: Strings; x: STRING): INTEGER;
 VAR
 VAR
     result: INTEGER;
     result: INTEGER;
 BEGIN
 BEGIN
@@ -67,7 +67,7 @@ BEGIN
     RETURN result
     RETURN result
 END contains;
 END contains;
 
 
-PROCEDURE containsString*(a: Strings; x: JsString.Type): BOOLEAN;
+PROCEDURE containsString*(a: Strings; x: STRING): BOOLEAN;
     RETURN stringsIndexOf(a, x) # -1
     RETURN stringsIndexOf(a, x) # -1
 END containsString;
 END containsString;
 
 

+ 7 - 7
src/ob/JsMap.ob

@@ -1,11 +1,11 @@
 MODULE JsMap;
 MODULE JsMap;
-IMPORT JS, JsString, Object;
+IMPORT JS, Object;
 TYPE
 TYPE
     Type* = POINTER TO RECORD END;
     Type* = POINTER TO RECORD END;
-    ForEachProc = PROCEDURE(key: JsString.Type; value: Object.PType; VAR closure: Object.Type);
+    ForEachProc = PROCEDURE(key: STRING; value: Object.PType; VAR closure: Object.Type);
     
     
     Strings* = POINTER TO RECORD END;
     Strings* = POINTER TO RECORD END;
-    ForEachStringProc = PROCEDURE(key: JsString.Type; value: JsString.Type; VAR closure: Object.Type);
+    ForEachStringProc = PROCEDURE(key: STRING; value: STRING; VAR closure: Object.Type);
 
 
 PROCEDURE make*(): Type;
 PROCEDURE make*(): Type;
 VAR
 VAR
@@ -15,7 +15,7 @@ BEGIN
     RETURN result    
     RETURN result    
 END make;
 END make;
 
 
-PROCEDURE has*(m: Type; s: JsString.Type): BOOLEAN;
+PROCEDURE has*(m: Type; s: STRING): BOOLEAN;
 VAR
 VAR
     result: BOOLEAN;
     result: BOOLEAN;
 BEGIN
 BEGIN
@@ -23,7 +23,7 @@ BEGIN
     RETURN result
     RETURN result
 END has;
 END has;
 
 
-PROCEDURE find*(m: Type; s: JsString.Type; VAR r: Object.PType): BOOLEAN;
+PROCEDURE find*(m: Type; s: STRING; VAR r: Object.PType): BOOLEAN;
 VAR
 VAR
     result: BOOLEAN;
     result: BOOLEAN;
 BEGIN
 BEGIN
@@ -31,12 +31,12 @@ BEGIN
     RETURN result
     RETURN result
 END find;
 END find;
 
 
-PROCEDURE put*(m: Type; s: JsString.Type; o: Object.PType);
+PROCEDURE put*(m: Type; s: STRING; o: Object.PType);
 BEGIN
 BEGIN
     JS.do("m[s] = o");
     JS.do("m[s] = o");
 END put;
 END put;
 
 
-PROCEDURE erase*(m: Type; s: JsString.Type);
+PROCEDURE erase*(m: Type; s: STRING);
 BEGIN
 BEGIN
     JS.do("delete m[s]");
     JS.do("delete m[s]");
 END erase;
 END erase;

+ 0 - 92
src/ob/JsString.ob

@@ -1,92 +0,0 @@
-MODULE JsString;
-IMPORT JS;
-
-TYPE
-    Type* = POINTER TO RECORD END;
-
-PROCEDURE make*(s: ARRAY OF CHAR): Type;
-VAR 
-    result: Type;
-    i: INTEGER;
-BEGIN
-    JS.do("result = ''");
-    FOR i := 0 TO LEN(s) - 1 DO
-        JS.do("result += JS.String.fromCharCode(s.charCodeAt(i))")
-    END
-    RETURN result
-END make;
-
-PROCEDURE makeEmpty*(): Type;
-VAR 
-    result: Type;
-BEGIN
-    JS.do("result = ''");
-    RETURN result
-END makeEmpty;
-
-PROCEDURE fromInt*(i: INTEGER): Type;
-VAR 
-    result: Type;
-BEGIN
-    JS.do("result = '' + i");
-    RETURN result
-END fromInt;
-
-PROCEDURE len*(self: Type): INTEGER;
-VAR result: INTEGER;
-BEGIN
-    JS.do("result = self.length");
-    RETURN result
-END len;
-
-PROCEDURE at*(self: Type; pos: INTEGER): CHAR;
-VAR result: CHAR;
-BEGIN
-    JS.do("result = self.charCodeAt(pos)")
-    RETURN result
-END at;
-
-PROCEDURE indexOf*(self: Type; c: CHAR): INTEGER;
-VAR result: INTEGER;
-BEGIN
-    JS.do("result = self.indexOf(JS.String.fromCharCode(c))")
-    RETURN result
-END indexOf;
-
-PROCEDURE indexOfFrom*(self: Type; c: CHAR; pos: INTEGER): INTEGER;
-VAR result: INTEGER;
-BEGIN
-    JS.do("result = self.indexOf(JS.String.fromCharCode(c), pos)")
-    RETURN result
-END indexOfFrom;
-
-PROCEDURE substr*(self: Type; pos: INTEGER; len: INTEGER): Type;
-VAR result: Type;
-BEGIN
-    JS.do("result = self.substr(pos, len)")
-    RETURN result
-END substr;
-
-PROCEDURE appendChar*(self: Type; c: CHAR): Type;
-VAR result: Type;
-BEGIN
-    result := self;
-    JS.do("result += JS.String.fromCharCode(c)")
-    RETURN result
-END appendChar;
-
-PROCEDURE concat*(self: Type; add: Type): Type;
-VAR result: Type;
-BEGIN
-    JS.do("result = self + add");
-    RETURN result
-END concat;
-
-PROCEDURE eq*(s1, s2: Type): BOOLEAN;
-VAR result: BOOLEAN;
-BEGIN
-    JS.do("result = s1 == s2");
-    RETURN result
-END eq;
-
-END JsString.

+ 1 - 1
src/ob/Language.ob

@@ -1,5 +1,5 @@
 MODULE Language;
 MODULE Language;
-IMPORT Cast, JsString, T := Types;
+IMPORT Cast, T := Types;
 TYPE
 TYPE
     Types* = RECORD         
     Types* = RECORD         
         PROCEDURE implicitCast*(from, to: T.PType; toVar: BOOLEAN; ops: Cast.Operations; VAR op: Cast.PCastOp): INTEGER
         PROCEDURE implicitCast*(from, to: T.PType; toVar: BOOLEAN; ops: Cast.Operations; VAR op: Cast.PCastOp): INTEGER

+ 32 - 25
src/ob/Lexer.ob

@@ -1,13 +1,20 @@
 MODULE Lexer;
 MODULE Lexer;
-IMPORT Context, JS, JsString, Errors, Stream;
+IMPORT Context, JS, Errors, Stream, String;
 
 
 CONST
 CONST
     quote = 22X; (* " *)
     quote = 22X; (* " *)
     commentBegin = "(*";
     commentBegin = "(*";
     commentEnd = "*)";
     commentEnd = "*)";
 
 
-    (* Math is used in generated code for some functions so it is reserved word from code generator standpoint *)
-    jsReservedWords = "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 false true null class enum export extends import super implements interface let package private protected public static yield Math";
+    jsReservedWords 
+        = "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 false true null class enum export extends "
+        + "import super implements interface let package private protected "
+        + "public static yield "
+        + "Math" (* Math is used in generated code for some functions so it is 
+                    reserved word from code generator standpoint *)
+        ;
 
 
 TYPE
 TYPE
     Literal = POINTER TO RECORD
     Literal = POINTER TO RECORD
@@ -50,10 +57,10 @@ BEGIN
     RETURN result
     RETURN result
 END hexDigit;
 END hexDigit;
 
 
-PROCEDURE handleLiteral(context: Context.Type; s: ARRAY OF CHAR): BOOLEAN;
+PROCEDURE handleLiteral(context: Context.Type; s: STRING): BOOLEAN;
 VAR result: BOOLEAN;
 VAR result: BOOLEAN;
 BEGIN
 BEGIN
-    JS.do("var r = context.handleLiteral(JsString.make(s)); result = (r === undefined || r)");
+    JS.do("var r = context.handleLiteral(s); result = (r === undefined || r)");
     RETURN result
     RETURN result
 END handleLiteral;
 END handleLiteral;
 
 
@@ -73,23 +80,24 @@ PROCEDURE string*(stream: Stream.Type; context: Context.Type): BOOLEAN;
 VAR
 VAR
     result: BOOLEAN;
     result: BOOLEAN;
     c: CHAR;
     c: CHAR;
-    s: JsString.Type;
+    s: STRING;
 BEGIN
 BEGIN
     IF ~Stream.eof(stream) THEN
     IF ~Stream.eof(stream) THEN
         c := Stream.getChar(stream);
         c := Stream.getChar(stream);
         IF c = quote THEN
         IF c = quote THEN
             IF ~Stream.eof(stream) THEN
             IF ~Stream.eof(stream) THEN
-                s := JsString.make("");
                 c := Stream.getChar(stream);
                 c := Stream.getChar(stream);
                 WHILE (c # quote) & ~Stream.eof(stream) DO
                 WHILE (c # quote) & ~Stream.eof(stream) DO
                     IF c # quote THEN
                     IF c # quote THEN
-                        s := JsString.appendChar(s, c);
+                        s := s + String.fromChar(c);
                     END;
                     END;
                     c := Stream.getChar(stream);
                     c := Stream.getChar(stream);
                 END;
                 END;
+            ELSE
+                c := 0X;
             END;
             END;
-            IF (s = NIL) OR (c # quote) THEN
-                Errors.raise(JsString.make("unexpected end of string"));
+            IF c # quote THEN
+                Errors.raise("unexpected end of string");
             END;
             END;
             context.handleString(s);
             context.handleString(s);
             result := TRUE;
             result := TRUE;
@@ -98,47 +106,46 @@ BEGIN
     RETURN result
     RETURN result
 END string;
 END string;
 
 
-PROCEDURE isReservedWorld(s: JsString.Type; words: ARRAY OF CHAR): BOOLEAN;
+PROCEDURE isReservedWord(s: STRING; words: STRING): BOOLEAN;
 VAR
 VAR
     i, w: INTEGER;
     i, w: INTEGER;
 BEGIN
 BEGIN
     WHILE (w < LEN(words))
     WHILE (w < LEN(words))
-        & (i < JsString.len(s))
-        & (words[w] = JsString.at(s, i))
+        & (i < LEN(s))
+        & (words[w] = s[i])
         & ((i # 0) OR (w = 0) OR (words[w - 1] = " ")) DO
         & ((i # 0) OR (w = 0) OR (words[w - 1] = " ")) DO
         INC(w);
         INC(w);
         INC(i);
         INC(i);
     ELSIF (w < LEN(words)) 
     ELSIF (w < LEN(words)) 
-        & ((i < JsString.len(s)) OR (words[w] # " ")) DO
+        & ((i < LEN(s)) OR (words[w] # " ")) DO
         INC(w);
         INC(w);
         i := 0;
         i := 0;
     END;
     END;
-    RETURN i = JsString.len(s)
-END isReservedWorld;
+    RETURN i = LEN(s)
+END isReservedWord;
 
 
-PROCEDURE ident*(stream: Stream.Type; context: Context.Type; reservedWords: ARRAY OF CHAR): BOOLEAN;
+PROCEDURE ident*(stream: Stream.Type; context: Context.Type; reservedWords: STRING): BOOLEAN;
 VAR
 VAR
     result: BOOLEAN;
     result: BOOLEAN;
     c: CHAR;
     c: CHAR;
-    s: JsString.Type;
+    s: STRING;
 BEGIN
 BEGIN
     IF ~Stream.eof(stream) THEN
     IF ~Stream.eof(stream) THEN
         c := Stream.getChar(stream);
         c := Stream.getChar(stream);
         IF isLetter(c) THEN
         IF isLetter(c) THEN
-            s := JsString.make("");
             WHILE ~Stream.eof(stream) & (isLetter(c) OR isDigit(c)) DO (* OR c = "_" *)
             WHILE ~Stream.eof(stream) & (isLetter(c) OR isDigit(c)) DO (* OR c = "_" *)
-                s := JsString.appendChar(s, c);
+                s := s + String.fromChar(c);
                 c := Stream.getChar(stream);
                 c := Stream.getChar(stream);
             END;
             END;
             IF isLetter(c) OR isDigit(c) THEN
             IF isLetter(c) OR isDigit(c) THEN
-                s := JsString.appendChar(s, c);
+                s := s + String.fromChar(c);
             ELSE
             ELSE
                 Stream.next(stream, -1);
                 Stream.next(stream, -1);
             END;
             END;
 
 
-            IF ~isReservedWorld(s, reservedWords) THEN
-                IF isReservedWorld(s, jsReservedWords) THEN
-                    s := JsString.appendChar(s, "$");
+            IF ~isReservedWord(s, reservedWords) THEN
+                IF isReservedWord(s, jsReservedWords) THEN
+                    s := s + "$";
                 END;
                 END;
                 context.handleIdent(s);
                 context.handleIdent(s);
                 result := TRUE;
                 result := TRUE;
@@ -158,7 +165,7 @@ BEGIN
             IF ~skipComment(stream, context) THEN
             IF ~skipComment(stream, context) THEN
                 Stream.next(stream, 1);
                 Stream.next(stream, 1);
                 IF Stream.eof(stream) THEN
                 IF Stream.eof(stream) THEN
-                    Errors.raise(JsString.make("comment was not closed"));
+                    Errors.raise("comment was not closed");
                 END
                 END
             END
             END
         END;
         END;

+ 25 - 28
src/ob/Module.ob

@@ -1,14 +1,14 @@
 MODULE Module;
 MODULE Module;
-IMPORT Code, Context, Errors, JsArray, JsString, Procedure, Symbols, Types;
+IMPORT Code, Context, Errors, JsArray, LanguageContext, Procedure, Symbols, Types;
 TYPE
 TYPE
     Type* = RECORD(Types.Module)
     Type* = RECORD(Types.Module)
-        PROCEDURE findSymbol(id: JsString.Type): Symbols.PFoundSymbol
+        PROCEDURE findSymbol(id: STRING): Symbols.PFoundSymbol
     END;
     END;
     PType* = POINTER TO Type;
     PType* = POINTER TO Type;
 
 
     AnyType* = RECORD(Types.StorageType)
     AnyType* = RECORD(Types.StorageType)
-        PROCEDURE callGenerator(cx: Context.PType; id: JsString.Type): Procedure.PCallGenerator;
-        PROCEDURE findSymbol(id: JsString.Type): Types.PType
+        PROCEDURE callGenerator(cx: LanguageContext.PType; id: STRING): Procedure.PCallGenerator;
+        PROCEDURE findSymbol(id: STRING): Types.PType
     END;
     END;
 
 
     AnyTypeProc* = RECORD(Types.DefinedProcedure)
     AnyTypeProc* = RECORD(Types.DefinedProcedure)
@@ -17,24 +17,24 @@ TYPE
     JS = RECORD(Type)
     JS = RECORD(Type)
     END;
     END;
 VAR
 VAR
-    doProcId, varTypeId: JsString.Type;
+    doProcId, varTypeId: STRING;
     any: POINTER TO AnyType;
     any: POINTER TO AnyType;
     anyProc: AnyTypeProc;
     anyProc: AnyTypeProc;
     doProcSymbol, varTypeSymbol: Symbols.PSymbol;
     doProcSymbol, varTypeSymbol: Symbols.PSymbol;
 
 
-PROCEDURE AnyType.description(): JsString.Type;
-    RETURN JsString.make("JS.var")
+PROCEDURE AnyType.description(): STRING;
+    RETURN "JS.var"
 END AnyType.description;
 END AnyType.description;
 
 
-PROCEDURE AnyType.initializer(cx: Context.Type): JsString.Type;
-    RETURN JsString.make("undefined")
+PROCEDURE AnyType.initializer(cx: Context.Type): STRING;
+    RETURN "undefined"
 END AnyType.initializer;
 END AnyType.initializer;
 
 
-PROCEDURE AnyType.callGenerator(cx: Context.PType; id: JsString.Type): Procedure.PCallGenerator;
+PROCEDURE AnyType.callGenerator(cx: LanguageContext.PType; id: STRING): Procedure.PCallGenerator;
     RETURN Procedure.makeProcCallGenerator(cx, id, anyProc)
     RETURN Procedure.makeProcCallGenerator(cx, id, anyProc)
 END AnyType.callGenerator;
 END AnyType.callGenerator;
 
 
-PROCEDURE AnyType.findSymbol(id: JsString.Type): Types.PType;
+PROCEDURE AnyType.findSymbol(id: STRING): Types.PType;
     RETURN any
     RETURN any
 END AnyType.findSymbol;
 END AnyType.findSymbol;
 
 
@@ -46,13 +46,13 @@ PROCEDURE AnyTypeProc.result(): Types.PType;
     RETURN any
     RETURN any
 END AnyTypeProc.result;
 END AnyTypeProc.result;
 
 
-PROCEDURE JS.findSymbol(id: JsString.Type): Symbols.PFoundSymbol;
+PROCEDURE JS.findSymbol(id: STRING): Symbols.PFoundSymbol;
 VAR
 VAR
     result: Symbols.PSymbol;
     result: Symbols.PSymbol;
 BEGIN
 BEGIN
-    IF JsString.eq(id, doProcId) THEN
+    IF id = doProcId THEN
         result := doProcSymbol;
         result := doProcSymbol;
-    ELSIF JsString.eq(id, varTypeId) THEN
+    ELSIF id = varTypeId THEN
         result := varTypeSymbol;
         result := varTypeSymbol;
     ELSE
     ELSE
         result := Symbols.makeSymbol(id, Types.makeProcedure(any));
         result := Symbols.makeSymbol(id, Types.makeProcedure(any));
@@ -71,38 +71,35 @@ TYPE
     Proc = RECORD(Procedure.Std)
     Proc = RECORD(Procedure.Std)
     END;
     END;
 VAR
 VAR
-    description: JsString.Type;
+    description: STRING;
     call: POINTER TO Call;
     call: POINTER TO Call;
     proc: POINTER TO Proc;
     proc: POINTER TO Proc;
 
 
-    PROCEDURE Call.make(args: JsArray.Type; cx: Context.Type): Code.PExpression;
+    PROCEDURE Call.make(args: JsArray.Type; cx: LanguageContext.Type): Code.PExpression;
     VAR
     VAR
         arg: Code.PExpression;
         arg: Code.PExpression;
         type: Types.PType;
         type: Types.PType;
     BEGIN
     BEGIN
-        arg := Procedure.checkSingleArgument(args, SELF);
+        arg := Procedure.checkSingleArgument(args, SELF, cx.types);
         type := arg.type();
         type := arg.type();
         IF ~(type IS Types.PString) THEN
         IF ~(type IS Types.PString) THEN
-            Errors.raise(JsString.concat(JsString.concat(JsString.concat(
-                JsString.make("string is expected as an argument of "),
-                description),
-                JsString.make(", got ")),
-                type.description()));
+            Errors.raise("string is expected as an argument of "
+                       + description + ", got " + type.description());
         END;
         END;
         RETURN Code.makeSimpleExpression(Types.stringValue(type(Types.PString)^), NIL)
         RETURN Code.makeSimpleExpression(Types.stringValue(type(Types.PString)^), NIL)
     END Call.make;
     END Call.make;
 
 
-    PROCEDURE Proc.description(): JsString.Type;
+    PROCEDURE Proc.description(): STRING;
         RETURN description
         RETURN description
     END Proc.description;
     END Proc.description;
 BEGIN
 BEGIN
-    description := JsString.make("JS predefined procedure 'do'");
+    description := "JS predefined procedure 'do'";
     NEW(call);
     NEW(call);
     Procedure.initStdCall(call);
     Procedure.initStdCall(call);
     Procedure.hasArgumentWithCustomType(call);
     Procedure.hasArgumentWithCustomType(call);
 
 
     NEW(proc);
     NEW(proc);
-    Procedure.initStd(JsString.makeEmpty(), call, proc^);
+    Procedure.initStd("", call, proc^);
     RETURN Procedure.makeSymbol(proc)
     RETURN Procedure.makeSymbol(proc)
 END makeDoProcSymbol;
 END makeDoProcSymbol;
 
 
@@ -111,13 +108,13 @@ VAR
     result: POINTER TO JS;
     result: POINTER TO JS;
 BEGIN
 BEGIN
     NEW(result);
     NEW(result);
-    Types.initModule(result^, JsString.make("this"));
+    Types.initModule(result^, "this");
     RETURN result
     RETURN result
 END makeJS;
 END makeJS;
 
 
 BEGIN
 BEGIN
-    doProcId := JsString.make("do$");
-    varTypeId := JsString.make("var$");
+    doProcId := "do$";
+    varTypeId := "var$";
     NEW(any);
     NEW(any);
     doProcSymbol := makeDoProcSymbol();
     doProcSymbol := makeDoProcSymbol();
     varTypeSymbol := makeVarTypeSymbol();
     varTypeSymbol := makeVarTypeSymbol();

+ 6 - 7
src/ob/OberonRtl.ob

@@ -1,13 +1,12 @@
 MODULE OberonRtl;
 MODULE OberonRtl;
-IMPORT JsString;
 TYPE
 TYPE
     Type* = RECORD
     Type* = RECORD
-        copy*: PROCEDURE(s1, s2: JsString.Type): JsString.Type;
-        strCmp*: PROCEDURE(s1, s2: JsString.Type): JsString.Type;
-        assignArrayFromString*: PROCEDURE(s1, s2: JsString.Type): JsString.Type;
-        setInclL*: PROCEDURE(l, r: JsString.Type): JsString.Type;
-        setInclR*: PROCEDURE(l, r: JsString.Type): JsString.Type;
-        assertId*: PROCEDURE(): JsString.Type
+        copy*: PROCEDURE(s1, s2: STRING): STRING;
+        strCmp*: PROCEDURE(s1, s2: STRING): STRING;
+        assignArrayFromString*: PROCEDURE(s1, s2: STRING): STRING;
+        setInclL*: PROCEDURE(l, r: STRING): STRING;
+        setInclR*: PROCEDURE(l, r: STRING): STRING;
+        assertId*: PROCEDURE(): STRING
     END;
     END;
     PType* = POINTER TO Type;
     PType* = POINTER TO Type;
 END OberonRtl.
 END OberonRtl.

+ 49 - 82
src/ob/Operator.ob

@@ -3,27 +3,27 @@ IMPORT
     Cast, 
     Cast, 
     Code, 
     Code, 
     Errors, 
     Errors, 
-    JsString, 
     Language, 
     Language, 
     LanguageContext, 
     LanguageContext, 
     OberonRtl, 
     OberonRtl, 
-    Precedence := CodePrecedence, 
+    Precedence := CodePrecedence,
+    String,
     Types;
     Types;
 TYPE
 TYPE
     BinaryProc = PROCEDURE(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
     BinaryProc = PROCEDURE(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
 
 
     BinaryOp = PROCEDURE(left, right: Code.PConst): Code.PConst;
     BinaryOp = PROCEDURE(left, right: Code.PConst): Code.PConst;
-    CodePredicate = PROCEDURE(left, right: JsString.Type; rtl: OberonRtl.PType): JsString.Type;
+    CodePredicate = PROCEDURE(left, right: STRING; rtl: OberonRtl.PType): STRING;
 
 
     UnaryOp = PROCEDURE(value: Code.PConst): Code.PConst;
     UnaryOp = PROCEDURE(value: Code.PConst): Code.PConst;
 
 
     CodeMaker = RECORD
     CodeMaker = RECORD
-        PROCEDURE make(left, right: JsString.Type; rtl: OberonRtl.PType): JsString.Type
+        PROCEDURE make(left, right: STRING; rtl: OberonRtl.PType): STRING
     END;
     END;
     PCodeMaker = POINTER TO CodeMaker;
     PCodeMaker = POINTER TO CodeMaker;
 
 
     SimpleCodeMaker = RECORD (CodeMaker)
     SimpleCodeMaker = RECORD (CodeMaker)
-        code: JsString.Type
+        code: STRING
     END;
     END;
 
 
     IntCodeMaker = RECORD (SimpleCodeMaker)
     IntCodeMaker = RECORD (SimpleCodeMaker)
@@ -53,7 +53,7 @@ PROCEDURE binary(
 VAR
 VAR
     result: Code.PExpression;
     result: Code.PExpression;
     leftValue, rightValue, resultValue: Code.PConst;
     leftValue, rightValue, resultValue: Code.PConst;
-    leftCode, rightCode, resultCode: JsString.Type;
+    leftCode, rightCode, resultCode: STRING;
     resultType: Types.PType;
     resultType: Types.PType;
     resultPrecedence: INTEGER;
     resultPrecedence: INTEGER;
     rightExpDeref: Code.PExpression;
     rightExpDeref: Code.PExpression;
@@ -90,38 +90,35 @@ BEGIN
     RETURN Code.makeExpressionWithPrecedence(resultCode, resultType, NIL, resultValue, resultPrecedence)
     RETURN Code.makeExpressionWithPrecedence(resultCode, resultType, NIL, resultValue, resultPrecedence)
 END binary;
 END binary;
 
 
-PROCEDURE SimpleCodeMaker.make(left, right: JsString.Type; rtl: OberonRtl.PType): JsString.Type;
-    RETURN JsString.concat(JsString.concat(
-        left, 
-        SELF.code), 
-        right)
+PROCEDURE SimpleCodeMaker.make(left, right: STRING; rtl: OberonRtl.PType): STRING;
+    RETURN left + SELF.code + right
 END SimpleCodeMaker.make;
 END SimpleCodeMaker.make;
 
 
-PROCEDURE IntCodeMaker.make(left, right: JsString.Type; rtl: OberonRtl.PType): JsString.Type;
+PROCEDURE IntCodeMaker.make(left, right: STRING; rtl: OberonRtl.PType): STRING;
 BEGIN
 BEGIN
-    RETURN JsString.concat(SUPER(left, right, rtl), JsString.make(" | 0"))
+    RETURN SUPER(left, right, rtl) + " | 0"
 END IntCodeMaker.make;
 END IntCodeMaker.make;
 
 
-PROCEDURE PredCodeMaker.make(left, right: JsString.Type; rtl: OberonRtl.PType): JsString.Type;
+PROCEDURE PredCodeMaker.make(left, right: STRING; rtl: OberonRtl.PType): STRING;
 BEGIN
 BEGIN
     RETURN SELF.pred(left, right, rtl)
     RETURN SELF.pred(left, right, rtl)
 END PredCodeMaker.make;
 END PredCodeMaker.make;
 
 
-PROCEDURE makeSimpleCodeMaker(code: ARRAY OF CHAR): PCodeMaker;
+PROCEDURE makeSimpleCodeMaker(code: STRING): PCodeMaker;
 VAR
 VAR
     result: POINTER TO SimpleCodeMaker;
     result: POINTER TO SimpleCodeMaker;
 BEGIN
 BEGIN
     NEW(result);
     NEW(result);
-    result.code := JsString.make(code);
+    result.code := code;
     RETURN result
     RETURN result
 END makeSimpleCodeMaker;
 END makeSimpleCodeMaker;
 
 
-PROCEDURE makeIntCodeMaker(code: ARRAY OF CHAR): PCodeMaker;
+PROCEDURE makeIntCodeMaker(code: STRING): PCodeMaker;
 VAR
 VAR
     result: POINTER TO IntCodeMaker;
     result: POINTER TO IntCodeMaker;
 BEGIN
 BEGIN
     NEW(result);
     NEW(result);
-    result.code := JsString.make(code);
+    result.code := code;
     RETURN result
     RETURN result
 END makeIntCodeMaker;
 END makeIntCodeMaker;
 
 
@@ -218,22 +215,21 @@ PROCEDURE binaryPred(
         )
         )
 END binaryPred;
 END binaryPred;
 
 
-PROCEDURE unary(e: Code.PExpression; op: UnaryOp; code: ARRAY OF CHAR): Code.PExpression;
+PROCEDURE unary(e: Code.PExpression; op: UnaryOp; code: STRING): Code.PExpression;
 VAR
 VAR
     value: Code.PConst;
     value: Code.PConst;
-    resultCode: JsString.Type;
+    resultCode: STRING;
 BEGIN
 BEGIN
     value := e.constValue();
     value := e.constValue();
     IF value # NIL THEN
     IF value # NIL THEN
         value := op(value);
         value := op(value);
     END;
     END;
-    resultCode := JsString.concat(
-        JsString.make(code), 
-        Code.adjustPrecedence(Code.derefExpression(e), Precedence.unary));
+    resultCode := code 
+                + Code.adjustPrecedence(Code.derefExpression(e), Precedence.unary);
     RETURN Code.makeExpression(resultCode, e.type(), NIL, value)
     RETURN Code.makeExpression(resultCode, e.type(), NIL, value)
 END unary;
 END unary;
 
 
-PROCEDURE castToStr(e: Code.PExpression; rtl: OberonRtl.PType): JsString.Type;
+PROCEDURE castToStr(e: Code.PExpression; rtl: OberonRtl.PType): STRING;
 VAR
 VAR
     resultExpression: Code.PExpression;
     resultExpression: Code.PExpression;
     op: Cast.PCastOp;
     op: Cast.PCastOp;
@@ -438,48 +434,43 @@ PROCEDURE opRor(left, right: Code.PConst): Code.PConst;
                                  right^(Code.IntConst).value))
                                  right^(Code.IntConst).value))
 END opRor;
 END opRor;
 
 
-PROCEDURE codeSetInclL(left, right: JsString.Type; rtl: OberonRtl.PType): JsString.Type;
+PROCEDURE codeSetInclL(left, right: STRING; rtl: OberonRtl.PType): STRING;
 BEGIN
 BEGIN
     RETURN rtl.setInclL(left, right)
     RETURN rtl.setInclL(left, right)
 END codeSetInclL;
 END codeSetInclL;
 
 
-PROCEDURE codeSetInclR(left, right: JsString.Type; rtl: OberonRtl.PType): JsString.Type;
+PROCEDURE codeSetInclR(left, right: STRING; rtl: OberonRtl.PType): STRING;
     RETURN rtl.setInclR(left, right)
     RETURN rtl.setInclR(left, right)
 END codeSetInclR;
 END codeSetInclR;
 
 
 PROCEDURE strCmp(op: ARRAY OF CHAR; left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
 PROCEDURE strCmp(op: ARRAY OF CHAR; left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
 BEGIN   
 BEGIN   
     RETURN Code.makeSimpleExpression(
     RETURN Code.makeSimpleExpression(
-            JsString.concat(JsString.concat(
-                rtl.strCmp(castToStr(left, rtl), castToStr(right, rtl)),
-                JsString.make(op)), 
-                JsString.make("0")),
+            rtl.strCmp(castToStr(left, rtl), castToStr(right, rtl)) + op + "0",
             Types.basic.bool)
             Types.basic.bool)
 END strCmp;
 END strCmp;
 
 
-PROCEDURE assign*(left, right: Code.PExpression; cx: LanguageContext.Type): JsString.Type;
+PROCEDURE assign*(left, right: Code.PExpression; cx: LanguageContext.Type): STRING;
 VAR
 VAR
     designator: Code.PDesignator;
     designator: Code.PDesignator;
     info: Types.PId;
     info: Types.PId;
-    leftCode, rightCode: JsString.Type;
+    leftCode, rightCode: STRING;
     leftType, rightType: Types.PType;
     leftType, rightType: Types.PType;
     isArray: BOOLEAN;
     isArray: BOOLEAN;
     castOperation: Cast.PCastOp;
     castOperation: Cast.PCastOp;
     castExp: Code.PExpression;
     castExp: Code.PExpression;
     ignored: BOOLEAN;
     ignored: BOOLEAN;
-    result: JsString.Type;
+    result: STRING;
 
 
-    PROCEDURE assignArrayFromString(a: Types.Array; s: Types.String): JsString.Type;
+    PROCEDURE assignArrayFromString(a: Types.Array; s: Types.String): STRING;
     BEGIN
     BEGIN
         IF Types.arrayLength(a) = Types.openArrayLength THEN
         IF Types.arrayLength(a) = Types.openArrayLength THEN
-            Errors.raise(JsString.concat(JsString.make("string cannot be assigned to open "),
-                                         a.description()));
+            Errors.raise("string cannot be assigned to open " + a.description());
         ELSIF Types.stringLen(s) > Types.arrayLength(a) THEN
         ELSIF Types.stringLen(s) > Types.arrayLength(a) THEN
-            Errors.raise(JsString.concat(JsString.concat(JsString.concat(
-                JsString.fromInt(Types.arrayLength(a)), 
-                JsString.make("-character ARRAY is too small for ")),
-                JsString.fromInt(Types.stringLen(s))), 
-                JsString.make("-character string")));
+            Errors.raise(String.fromInt(Types.arrayLength(a)) 
+                         + "-character ARRAY is too small for "
+                         + String.fromInt(Types.stringLen(s))
+                         + "-character string");
         END;
         END;
         RETURN cx.rtl.assignArrayFromString(leftCode, rightCode)
         RETURN cx.rtl.assignArrayFromString(leftCode, rightCode)
     END assignArrayFromString;
     END assignArrayFromString;
@@ -488,7 +479,7 @@ BEGIN
     info := designator.info();
     info := designator.info();
     IF ~(info IS Types.PVariable) 
     IF ~(info IS Types.PVariable) 
         OR info(Types.PVariable).isReadOnly() THEN
         OR info(Types.PVariable).isReadOnly() THEN
-        Errors.raise(JsString.concat(JsString.make("cannot assign to "), info.idType()));
+        Errors.raise("cannot assign to " + info.idType());
     END; 
     END; 
 
 
     leftCode := left.lval();
     leftCode := left.lval();
@@ -504,23 +495,12 @@ BEGIN
     ELSE
     ELSE
         IF cx.types.implicitCast(rightType, leftType, FALSE, castOperations, castOperation)
         IF cx.types.implicitCast(rightType, leftType, FALSE, castOperations, castOperation)
             # Cast.errNo THEN;
             # Cast.errNo THEN;
-            Errors.raise(JsString.concat(JsString.concat(JsString.concat(JsString.concat(JsString.concat(JsString.concat(
-                JsString.make("type mismatch: '"), 
-                leftCode),
-                JsString.make("' is '")),
-                leftType.description()),
-                JsString.make("' and cannot be assigned to '")),
-                rightType.description()),
-                JsString.make("' expression")));
+            Errors.raise("type mismatch: '" + leftCode + "' is '" + leftType.description()
+                         + "' and cannot be assigned to '" + rightType.description() + "' expression");
         END;
         END;
         IF isArray & (rightType IS Types.PArray) 
         IF isArray & (rightType IS Types.PArray) 
             & (Types.arrayLength(leftType(Types.PArray)^) = Types.openArrayLength) THEN
             & (Types.arrayLength(leftType(Types.PArray)^) = Types.openArrayLength) THEN
-            Errors.raise(JsString.concat(JsString.concat(JsString.concat(JsString.concat(
-                JsString.make("'"),
-                leftCode),
-                JsString.make("' is open '")),
-                leftType.description()),
-                JsString.make("' and cannot be assigned")));
+            Errors.raise("'" + leftCode + "' is open '" + leftType.description() + "' and cannot be assigned");
         END;
         END;
         IF isArray OR (rightType IS Types.PRecord) THEN
         IF isArray OR (rightType IS Types.PRecord) THEN
             result := cx.rtl.copy(rightCode, leftCode);
             result := cx.rtl.copy(rightCode, leftCode);
@@ -532,34 +512,28 @@ BEGIN
             END;
             END;
             rightCode := castExp.code();
             rightCode := castExp.code();
             IF info IS Types.PVariableRef THEN
             IF info IS Types.PVariableRef THEN
-                rightCode := JsString.concat(JsString.concat(
-                    JsString.make(".set("), 
-                    rightCode), 
-                    JsString.make(")"));
+                rightCode := ".set(" + rightCode + ")";
             ELSE
             ELSE
-                rightCode := JsString.concat(JsString.make(" = "), rightCode);
+                rightCode := " = " + rightCode;
             END;
             END;
-            result := JsString.concat(leftCode, rightCode);
+            result := leftCode + rightCode;
         END;
         END;
     END;
     END;
     RETURN result
     RETURN result
 END assign;
 END assign;
     
     
-PROCEDURE inplace(left, right: Code.PExpression; cx: LanguageContext.Type; code: ARRAY OF CHAR; altOp: BinaryProc): JsString.Type;
+PROCEDURE inplace(left, right: Code.PExpression; cx: LanguageContext.Type; code: STRING; altOp: BinaryProc): STRING;
 VAR
 VAR
     designator: Code.PDesignator;
     designator: Code.PDesignator;
     rightExp: Code.PExpression;
     rightExp: Code.PExpression;
-    result: JsString.Type;
+    result: STRING;
 BEGIN
 BEGIN
     designator := left.designator();
     designator := left.designator();
     IF designator.info() IS Types.PVariableRef THEN
     IF designator.info() IS Types.PVariableRef THEN
         result := assign(left, altOp(left, right, cx.rtl), cx);
         result := assign(left, altOp(left, right, cx.rtl), cx);
     ELSE
     ELSE
         rightExp := Code.derefExpression(right);
         rightExp := Code.derefExpression(right);
-        result := JsString.concat(JsString.concat(
-            left.code(), 
-            JsString.make(code)), 
-            rightExp.code());
+        result := left.code() + code + rightExp.code();
     END;
     END;
     RETURN result
     RETURN result
 END inplace;
 END inplace;
@@ -757,11 +731,11 @@ PROCEDURE ror*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpre
     RETURN binaryWithCode(left, right, rtl, opRor, " >>> ", Precedence.shift)
     RETURN binaryWithCode(left, right, rtl, opRor, " >>> ", Precedence.shift)
 END ror;
 END ror;
 
 
-PROCEDURE mulInplace*(left, right: Code.PExpression; cx: LanguageContext.Type): JsString.Type;
+PROCEDURE mulInplace*(left, right: Code.PExpression; cx: LanguageContext.Type): STRING;
     RETURN inplace(left, right, cx, " *= ", mulReal)
     RETURN inplace(left, right, cx, " *= ", mulReal)
 END mulInplace;
 END mulInplace;
 
 
-PROCEDURE divInplace*(left, right: Code.PExpression; cx: LanguageContext.Type): JsString.Type;
+PROCEDURE divInplace*(left, right: Code.PExpression; cx: LanguageContext.Type): STRING;
     RETURN inplace(left, right, cx, " /= ", divReal)
     RETURN inplace(left, right, cx, " /= ", divReal)
 END divInplace;
 END divInplace;
 
 
@@ -770,12 +744,8 @@ VAR
     derefExp: Code.PExpression;
     derefExp: Code.PExpression;
 BEGIN
 BEGIN
     derefExp := Code.derefExpression(e);
     derefExp := Code.derefExpression(e);
-    RETURN Code.makeSimpleExpression(
-            JsString.concat(JsString.concat(
-                JsString.make("Math.pow(2, "),
-                derefExp.code()),
-                JsString.make(")")),
-            Types.basic.real)
+    RETURN Code.makeSimpleExpression("Math.pow(2, " + derefExp.code() + ")",
+                                     Types.basic.real)
 END pow2;
 END pow2;
 
 
 PROCEDURE log2*(e: Code.PExpression): Code.PExpression;
 PROCEDURE log2*(e: Code.PExpression): Code.PExpression;
@@ -784,10 +754,7 @@ VAR
 BEGIN
 BEGIN
     derefExp := Code.derefExpression(e);
     derefExp := Code.derefExpression(e);
     RETURN Code.makeExpressionWithPrecedence(
     RETURN Code.makeExpressionWithPrecedence(
-            JsString.concat(JsString.concat(
-                JsString.make("(Math.log("),
-                derefExp.code()),
-                JsString.make(") / Math.LN2) | 0")),
+            "(Math.log(" + derefExp.code() + ") / Math.LN2) | 0",
             Types.basic.integer,
             Types.basic.integer,
             NIL,
             NIL,
             NIL,
             NIL,
@@ -802,7 +769,7 @@ END opCastToUint8;
 PROCEDURE CastToUint8.make(rtl: OberonRtl.PType; e: Code.PExpression): Code.PExpression;
 PROCEDURE CastToUint8.make(rtl: OberonRtl.PType; e: Code.PExpression): Code.PExpression;
     RETURN binaryWithCode(
     RETURN binaryWithCode(
         e, 
         e, 
-        Code.makeExpression(JsString.make("0xFF"), 
+        Code.makeExpression("0xFF", 
                             Types.basic.integer, 
                             Types.basic.integer, 
                             NIL, 
                             NIL, 
                             Code.makeIntConst(0FFH)), 
                             Code.makeIntConst(0FFH)), 
@@ -813,7 +780,7 @@ PROCEDURE CastToUint8.make(rtl: OberonRtl.PType; e: Code.PExpression): Code.PExp
 END CastToUint8.make;
 END CastToUint8.make;
 
 
 BEGIN
 BEGIN
-    openArrayChar := Types.makeArray(NIL, NIL, Types.basic.ch, Types.openArrayLength);
+    openArrayChar := Types.makeArray("", "", Types.basic.ch, Types.openArrayLength);
 
 
     NEW(castToUint8);
     NEW(castToUint8);
     castOperations.castToUint8 := castToUint8;
     castOperations.castToUint8 := castToUint8;

+ 119 - 189
src/ob/Procedure.ob

@@ -5,13 +5,13 @@ IMPORT
     Context, 
     Context, 
     Errors, 
     Errors, 
     JsArray, 
     JsArray, 
-    JsString, 
     Language,
     Language,
     LanguageContext,
     LanguageContext,
     OberonRtl,
     OberonRtl,
     Object, 
     Object, 
     Operator, 
     Operator, 
     Precedence := CodePrecedence, 
     Precedence := CodePrecedence, 
+    String,
     Symbols, 
     Symbols, 
     Types;
     Types;
 TYPE
 TYPE
@@ -45,7 +45,7 @@ TYPE
     END;
     END;
 
 
     Type* = RECORD(Types.DefinedProcedure)
     Type* = RECORD(Types.DefinedProcedure)
-        PROCEDURE callGenerator(cx: LanguageContext.PType; id: JsString.Type): PCallGenerator;
+        PROCEDURE callGenerator(cx: LanguageContext.PType; id: STRING): PCallGenerator;
         PROCEDURE define(args: JsArray.Type; result: Types.PType);
         PROCEDURE define(args: JsArray.Type; result: Types.PType);
 
 
         mArgs: JsArray.Type;
         mArgs: JsArray.Type;
@@ -62,17 +62,17 @@ TYPE
                         expected: Types.PProcedureArgument; 
                         expected: Types.PProcedureArgument; 
                         cast: Cast.PCastOp
                         cast: Cast.PCastOp
                         );
                         );
-        PROCEDURE result(): JsString.Type
+        PROCEDURE result(): STRING
     END;
     END;
     PArgumentsCode = POINTER TO ArgumentsCode;
     PArgumentsCode = POINTER TO ArgumentsCode;
 
 
     GenArgCode = RECORD(ArgumentsCode)
     GenArgCode = RECORD(ArgumentsCode)
-        code: JsString.Type;
+        code: STRING;
         cx: Context.PType
         cx: Context.PType
     END;
     END;
 
 
     BinaryOp = PROCEDURE(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
     BinaryOp = PROCEDURE(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    BinaryOpStr = PROCEDURE (x, y: JsString.Type): JsString.Type;
+    BinaryOpStr = PROCEDURE (x, y: STRING): STRING;
 VAR
 VAR
     predefined*: JsArray.Type;
     predefined*: JsArray.Type;
 
 
@@ -95,37 +95,27 @@ BEGIN
         actualType := actual.type();
         actualType := actual.type();
         castErr := types.implicitCast(actualType, expectType, expected.isVar, Operator.castOperations, result);
         castErr := types.implicitCast(actualType, expectType, expected.isVar, Operator.castOperations, result);
         IF castErr = Cast.errVarParameter THEN
         IF castErr = Cast.errVarParameter THEN
-                Errors.raise(JsString.concat(JsString.concat(JsString.concat(JsString.concat(JsString.concat(JsString.concat(
-                    JsString.make("type mismatch for argument "),
-                    JsString.fromInt(pos + 1)),
-                    JsString.make(": cannot pass '")),
-                    actualType.description()),
-                    JsString.make("' as VAR parameter of type '")),
-                    expectType.description()),
-                    JsString.make("'")));
+            Errors.raise("type mismatch for argument " + String.fromInt(pos + 1)
+                         + ": cannot pass '" + actualType.description()
+                         + "' as VAR parameter of type '" + expectType.description() + "'");
         ELSIF castErr # Cast.errNo THEN
         ELSIF castErr # Cast.errNo THEN
-                Errors.raise(JsString.concat(JsString.concat(JsString.concat(JsString.concat(JsString.concat(JsString.concat(
-                    JsString.make("type mismatch for argument "),
-                    JsString.fromInt(pos + 1)),
-                    JsString.make(": '")),
-                    actualType.description()),
-                    JsString.make("' cannot be converted to '")),
-                    expectType.description()),
-                    JsString.make("'")));
+            Errors.raise("type mismatch for argument " + String.fromInt(pos + 1)
+                         + ": '" + actualType.description() + "' cannot be converted to '"
+                         + expectType.description() + "'");
         END;
         END;
     END;
     END;
     IF expected.isVar THEN
     IF expected.isVar THEN
         designator := actual.designator();
         designator := actual.designator();
         IF designator = NIL THEN
         IF designator = NIL THEN
-            Errors.raise(JsString.make("expression cannot be used as VAR parameter"));
+            Errors.raise("expression cannot be used as VAR parameter");
         END;
         END;
         info := designator.info();
         info := designator.info();
         IF info IS Types.PConst THEN
         IF info IS Types.PConst THEN
-            Errors.raise(JsString.make("constant cannot be used as VAR parameter"));
+            Errors.raise("constant cannot be used as VAR parameter");
         END;
         END;
         IF (info IS Types.PVariable) 
         IF (info IS Types.PVariable) 
          & info(Types.PVariable).isReadOnly() THEN
          & info(Types.PVariable).isReadOnly() THEN
-            Errors.raise(JsString.concat(info.idType(), JsString.make(" cannot be used as VAR parameter")));
+            Errors.raise(info.idType() + " cannot be used as VAR parameter");
         END;
         END;
     END;
     END;
     IF code # NIL THEN
     IF code # NIL THEN
@@ -157,10 +147,9 @@ END checkArgumentsType;
 PROCEDURE checkArgumentsCount*(actual, expected: INTEGER);
 PROCEDURE checkArgumentsCount*(actual, expected: INTEGER);
 BEGIN
 BEGIN
     IF actual # expected THEN
     IF actual # expected THEN
-        Errors.raise(JsString.concat(JsString.concat(
-            JsString.fromInt(expected),
-            JsString.make(" argument(s) expected, got ")),
-            JsString.fromInt(actual)));
+        Errors.raise(
+            String.fromInt(expected) + " argument(s) expected, got " 
+            + String.fromInt(actual));
     END;
     END;
 END checkArgumentsCount;
 END checkArgumentsCount;
 
 
@@ -180,13 +169,13 @@ BEGIN
     processArguments(actual, expected, NIL, types);
     processArguments(actual, expected, NIL, types);
 END checkArguments;
 END checkArguments;
 
 
-PROCEDURE initStd*(name: JsString.Type; call: PCall; result: Std);
+PROCEDURE initStd*(name: STRING; call: PCall; result: Std);
 BEGIN
 BEGIN
     Types.initProcedure(result, name);
     Types.initProcedure(result, name);
     result.call := call;
     result.call := call;
 END initStd;
 END initStd;
 
 
-PROCEDURE makeStd(name: JsString.Type; call: PCall): Types.PProcedure;
+PROCEDURE makeStd(name: STRING; call: PCall): Types.PProcedure;
 VAR
 VAR
     result: POINTER TO Std;
     result: POINTER TO Std;
 BEGIN
 BEGIN
@@ -225,30 +214,30 @@ BEGIN
     ELSE
     ELSE
         actual := Code.derefExpression(actual);
         actual := Code.derefExpression(actual);
     END;
     END;
-    IF JsString.len(SELF.code) # 0 THEN
-        SELF.code := JsString.concat(SELF.code, JsString.make(", "));
+    IF LEN(SELF.code) # 0 THEN
+        SELF.code := SELF.code + ", ";
     END;
     END;
     IF cast # NIL THEN
     IF cast # NIL THEN
         e := cast.make(SELF.cx.rtl, actual);
         e := cast.make(SELF.cx.rtl, actual);
     ELSE
     ELSE
         e := actual;
         e := actual;
     END;
     END;
-    SELF.code := JsString.concat(SELF.code, e.code());
+    SELF.code := SELF.code + e.code();
 END GenArgCode.write;
 END GenArgCode.write;
 
 
-PROCEDURE GenArgCode.result(): JsString.Type;
+PROCEDURE GenArgCode.result(): STRING;
     RETURN SELF.code
     RETURN SELF.code
 END GenArgCode.result;
 END GenArgCode.result;
 
 
 PROCEDURE makeProcCallGeneratorWithCustomArgs*(
 PROCEDURE makeProcCallGeneratorWithCustomArgs*(
     cx: LanguageContext.PType; 
     cx: LanguageContext.PType; 
-    id: JsString.Type; 
+    id: STRING; 
     type: Types.DefinedProcedure;
     type: Types.DefinedProcedure;
     argumentsCode: PArgumentsCode
     argumentsCode: PArgumentsCode
     ) : PCallGenerator;
     ) : PCallGenerator;
 TYPE
 TYPE
     CallImpl = RECORD(Call)
     CallImpl = RECORD(Call)
-        id: JsString.Type;
+        id: STRING;
         args: JsArray.Type;
         args: JsArray.Type;
         result: Types.PType;
         result: Types.PType;
         argumentsCode: PArgumentsCode
         argumentsCode: PArgumentsCode
@@ -273,13 +262,9 @@ VAR
             END;
             END;
         END;
         END;
         RETURN Code.makeSimpleExpression(
         RETURN Code.makeSimpleExpression(
-            JsString.concat(JsString.concat(JsString.concat(
-                SELF.id,
-                JsString.make("(")),
-                SELF.argumentsCode.result()),
-                JsString.make(")")),
-            SELF.result
-            )
+                SELF.id + "(" + SELF.argumentsCode.result() + ")",
+                SELF.result
+                )
     END CallImpl.make;
     END CallImpl.make;
 BEGIN
 BEGIN
     NEW(call);
     NEW(call);
@@ -295,21 +280,20 @@ VAR
     result: POINTER TO GenArgCode;
     result: POINTER TO GenArgCode;
 BEGIN
 BEGIN
     NEW(result);
     NEW(result);
-    result.code := JsString.makeEmpty();
     result.cx := cx;
     result.cx := cx;
     RETURN result
     RETURN result
 END makeArgumentsCode;
 END makeArgumentsCode;
 
 
 PROCEDURE makeProcCallGenerator*(
 PROCEDURE makeProcCallGenerator*(
     cx: LanguageContext.PType; 
     cx: LanguageContext.PType; 
-    id: JsString.Type; 
+    id: STRING; 
     type: Types.DefinedProcedure
     type: Types.DefinedProcedure
     ) : PCallGenerator;
     ) : PCallGenerator;
     RETURN makeProcCallGeneratorWithCustomArgs(cx, id, type, makeArgumentsCode(cx))
     RETURN makeProcCallGeneratorWithCustomArgs(cx, id, type, makeArgumentsCode(cx))
 END makeProcCallGenerator;
 END makeProcCallGenerator;
 
 
-PROCEDURE Std.description(): JsString.Type;
-    RETURN JsString.concat(JsString.make("standard procedure "), Types.typeName(SELF))
+PROCEDURE Std.description(): STRING;
+    RETURN "standard procedure " + Types.typeName(SELF)
 END Std.description;
 END Std.description;
 
 
 PROCEDURE Std.callGenerator(cx: LanguageContext.PType): PCallGenerator;
 PROCEDURE Std.callGenerator(cx: LanguageContext.PType): PCallGenerator;
@@ -393,27 +377,22 @@ PROCEDURE makeNew(): Symbols.PSymbol;
         arg := checkSingleArgument(args, SELF, cx.types);
         arg := checkSingleArgument(args, SELF, cx.types);
         argType := arg.type();
         argType := arg.type();
         IF ~(argType IS Types.PPointer) THEN
         IF ~(argType IS Types.PPointer) THEN
-            Errors.raise(JsString.concat(JsString.concat(
-                JsString.make("POINTER variable expected, got '"),
-                argType.description()),
-                JsString.make("'")));
+            Errors.raise("POINTER variable expected, got '" 
+                         + argType.description() + "'");
         END;
         END;
         baseType := Types.pointerBase(argType(Types.PPointer)^);
         baseType := Types.pointerBase(argType(Types.PPointer)^);
         IF baseType IS Types.PNonExportedRecord THEN
         IF baseType IS Types.PNonExportedRecord THEN
-            Errors.raise(JsString.make("non-exported RECORD type cannot be used in NEW"));
+            Errors.raise("non-exported RECORD type cannot be used in NEW");
         END;
         END;
         RETURN Code.makeSimpleExpression(
         RETURN Code.makeSimpleExpression(
-            JsString.concat(JsString.concat(
-                arg.code(), 
-                JsString.make(" = ")),
-                baseType.initializer(cx)),
-            NIL)
+                arg.code() + " = " + baseType.initializer(cx),
+                NIL)
     END CallImpl.make;
     END CallImpl.make;
 BEGIN
 BEGIN
     NEW(call);
     NEW(call);
     initStdCall(call);
     initStdCall(call);
     hasVarArgumnetWithCustomType(call);
     hasVarArgumnetWithCustomType(call);
-    RETURN makeSymbol(makeStd(JsString.make("NEW"), call))
+    RETURN makeSymbol(makeStd("NEW", call))
 END makeNew;
 END makeNew;
 
 
 PROCEDURE lenArgumentCheck*(argType: Types.PType): BOOLEAN;
 PROCEDURE lenArgumentCheck*(argType: Types.PType): BOOLEAN;
@@ -428,13 +407,11 @@ BEGIN
     arg := checkSingleArgument(args, SELF, cx.types);
     arg := checkSingleArgument(args, SELF, cx.types);
     argType := arg.type();
     argType := arg.type();
     IF ~SELF.check(argType) THEN
     IF ~SELF.check(argType) THEN
-        Errors.raise(JsString.concat(JsString.concat(
-            JsString.make("ARRAY or string is expected as an argument of LEN, got '"),
-            argType.description()),
-            JsString.make("'")));
+        Errors.raise("ARRAY or string is expected as an argument of LEN, got '"
+                     + argType.description() + "'");
     END;
     END;
     RETURN Code.makeSimpleExpression(
     RETURN Code.makeSimpleExpression(
-        JsString.concat(arg.code(), JsString.make(".length")),
+        arg.code() + ".length",
         Types.basic.integer)
         Types.basic.integer)
 END CallLen.make;
 END CallLen.make;
 
 
@@ -446,7 +423,7 @@ BEGIN
     initStdCall(call);
     initStdCall(call);
     call.check := check;
     call.check := check;
     hasArgumentWithCustomType(call);
     hasArgumentWithCustomType(call);
-    RETURN makeSymbol(makeStd(JsString.make("LEN"), call))
+    RETURN makeSymbol(makeStd("LEN", call))
 END makeLen;
 END makeLen;
 
 
 PROCEDURE makeOdd(): Symbols.PSymbol;
 PROCEDURE makeOdd(): Symbols.PSymbol;
@@ -459,7 +436,7 @@ PROCEDURE makeOdd(): Symbols.PSymbol;
     PROCEDURE CallImpl.make(args: JsArray.Type; cx: LanguageContext.Type): Code.PExpression;
     PROCEDURE CallImpl.make(args: JsArray.Type; cx: LanguageContext.Type): Code.PExpression;
     VAR
     VAR
         arg: Code.PExpression;
         arg: Code.PExpression;
-        code: JsString.Type;
+        code: STRING;
         constValue: Code.PConst;
         constValue: Code.PConst;
     BEGIN
     BEGIN
         arg := checkSingleArgument(args, SELF, cx.types);
         arg := checkSingleArgument(args, SELF, cx.types);
@@ -472,7 +449,7 @@ PROCEDURE makeOdd(): Symbols.PSymbol;
         END;
         END;
 
 
         RETURN Code.makeExpressionWithPrecedence(
         RETURN Code.makeExpressionWithPrecedence(
-            JsString.concat(code, JsString.make(" & 1")),
+            code + " & 1",
             Types.basic.bool,
             Types.basic.bool,
             NIL,
             NIL,
             constValue,
             constValue,
@@ -482,7 +459,7 @@ BEGIN
     NEW(call);
     NEW(call);
     initStdCall(call);
     initStdCall(call);
     hasArgument(call, Types.basic.integer);
     hasArgument(call, Types.basic.integer);
-    RETURN makeSymbol(makeStd(JsString.make("ODD"), call))
+    RETURN makeSymbol(makeStd("ODD", call))
 END makeOdd;
 END makeOdd;
 
 
 PROCEDURE makeAssert(): Symbols.PSymbol;
 PROCEDURE makeAssert(): Symbols.PSymbol;
@@ -498,24 +475,20 @@ PROCEDURE makeAssert(): Symbols.PSymbol;
     BEGIN
     BEGIN
         arg := checkSingleArgument(args, SELF, cx.types);
         arg := checkSingleArgument(args, SELF, cx.types);
         RETURN Code.makeSimpleExpression(
         RETURN Code.makeSimpleExpression(
-            JsString.concat(JsString.concat(JsString.concat(
-                cx.rtl.assertId(), 
-                JsString.make("(")), 
-                arg.code()), 
-                JsString.make(")")),
-            NIL)
+                cx.rtl.assertId() + "(" + arg.code() + ")",
+                NIL)
     END CallImpl.make;
     END CallImpl.make;
 BEGIN
 BEGIN
     NEW(call);
     NEW(call);
     initStdCall(call);
     initStdCall(call);
     hasArgument(call, Types.basic.bool);
     hasArgument(call, Types.basic.bool);
-    RETURN makeSymbol(makeStd(JsString.make("ASSERT"), call))
+    RETURN makeSymbol(makeStd("ASSERT", call))
 END makeAssert;
 END makeAssert;
 
 
-PROCEDURE setBitImpl(name: ARRAY OF CHAR; bitOp: BinaryOpStr): Symbols.PSymbol;
+PROCEDURE setBitImpl(name: STRING; bitOp: BinaryOpStr): Symbols.PSymbol;
     TYPE
     TYPE
         CallImpl = RECORD(StdCall)
         CallImpl = RECORD(StdCall)
-            name: JsString.Type;
+            name: STRING;
             bitOp: BinaryOpStr
             bitOp: BinaryOpStr
         END;
         END;
     VAR
     VAR
@@ -527,8 +500,8 @@ PROCEDURE setBitImpl(name: ARRAY OF CHAR; bitOp: BinaryOpStr): Symbols.PSymbol;
         yValue: INTEGER;
         yValue: INTEGER;
         value: Code.PConst;
         value: Code.PConst;
         valueCodeExp: Code.PExpression;
         valueCodeExp: Code.PExpression;
-        valueCode: JsString.Type;
-        comment: JsString.Type;
+        valueCode: STRING;
+        comment: STRING;
     BEGIN
     BEGIN
         checkArguments(args, SELF.args, cx.types);
         checkArguments(args, SELF.args, cx.types);
         ASSERT(JsArray.len(args) = 2);
         ASSERT(JsArray.len(args) = 2);
@@ -538,7 +511,7 @@ PROCEDURE setBitImpl(name: ARRAY OF CHAR; bitOp: BinaryOpStr): Symbols.PSymbol;
         IF value = NIL THEN
         IF value = NIL THEN
             valueCodeExp := Operator.lsl(
             valueCodeExp := Operator.lsl(
                 Code.makeExpression(
                 Code.makeExpression(
-                    JsString.make("1"), 
+                    "1", 
                     Types.basic.integer,
                     Types.basic.integer,
                     NIL,
                     NIL,
                     Code.makeIntConst(1)), 
                     Code.makeIntConst(1)), 
@@ -548,24 +521,17 @@ PROCEDURE setBitImpl(name: ARRAY OF CHAR; bitOp: BinaryOpStr): Symbols.PSymbol;
         ELSE
         ELSE
             yValue := value^(Code.IntConst).value;
             yValue := value^(Code.IntConst).value;
             IF (yValue < 0) OR (yValue > 31) THEN
             IF (yValue < 0) OR (yValue > 31) THEN
-                Errors.raise(JsString.concat(JsString.concat(JsString.concat(
-                    JsString.make("value (0..31) expected as a second argument of "),
-                    SELF.name),
-                    JsString.make(", got ")),
-                    JsString.fromInt(yValue)));
+                Errors.raise("value (0..31) expected as a second argument of " 
+                             + SELF.name + ", got " + String.fromInt(yValue));
             END;
             END;
-            comment := JsString.make("bit: ");
+            comment := "bit: ";
             IF y.isTerm() THEN
             IF y.isTerm() THEN
-                comment := JsString.concat(comment, JsString.fromInt(yValue));
+                comment := comment + String.fromInt(yValue);
             ELSE
             ELSE
-                comment := JsString.concat(comment, Code.adjustPrecedence(y, Precedence.shift));
+                comment := comment + Code.adjustPrecedence(y, Precedence.shift);
             END;
             END;
             yValue := LSL(1, yValue);
             yValue := LSL(1, yValue);
-            valueCode := JsString.concat(JsString.concat(JsString.concat(
-                JsString.fromInt(yValue), 
-                JsString.make("/*")),
-                comment),
-                JsString.make("*/"));
+            valueCode := String.fromInt(yValue) + "/*" + comment + "*/";
         END;
         END;
 
 
         RETURN Code.makeSimpleExpression(
         RETURN Code.makeSimpleExpression(
@@ -575,7 +541,7 @@ PROCEDURE setBitImpl(name: ARRAY OF CHAR; bitOp: BinaryOpStr): Symbols.PSymbol;
 BEGIN
 BEGIN
     NEW(call);
     NEW(call);
     initStdCall(call);
     initStdCall(call);
-    call.name := JsString.make(name);
+    call.name := name;
     call.bitOp := bitOp;
     call.bitOp := bitOp;
     hasVarArgument(call, Types.basic.set);
     hasVarArgument(call, Types.basic.set);
     hasArgument(call, Types.basic.integer);
     hasArgument(call, Types.basic.integer);
@@ -588,25 +554,19 @@ VAR
 BEGIN
 BEGIN
     len := JsArray.len(actual);
     len := JsArray.len(actual);
     IF len < min THEN
     IF len < min THEN
-        Errors.raise(JsString.concat(JsString.concat(JsString.concat(
-            JsString.make("at least "), 
-            JsString.fromInt(min)), 
-            JsString.make(" argument expected, got ")), 
-            JsString.fromInt(len)));
+        Errors.raise("at least " + String.fromInt(min) + " argument expected, got " 
+                     + String.fromInt(len));
     ELSIF len > max THEN
     ELSIF len > max THEN
-        Errors.raise(JsString.concat(JsString.concat(JsString.concat(
-            JsString.make("at most "),
-            JsString.fromInt(max)),
-            JsString.make(" arguments expected, got ")),
-            JsString.fromInt(len)));
+        Errors.raise("at most " + String.fromInt(max) + " arguments expected, got "
+                     + String.fromInt(len));
     END;
     END;
 END checkVariableArgumentsCount;
 END checkVariableArgumentsCount;
 
 
-PROCEDURE incImpl(name: ARRAY OF CHAR; unary: ARRAY OF CHAR; incOp: BinaryOpStr): Symbols.PSymbol;
+PROCEDURE incImpl(name: STRING; unary: STRING; incOp: BinaryOpStr): Symbols.PSymbol;
     TYPE
     TYPE
         CallImpl = RECORD(StdCall)
         CallImpl = RECORD(StdCall)
-            name: JsString.Type;
-            unary: JsString.Type;
+            name: STRING;
+            unary: STRING;
             incOp: BinaryOpStr
             incOp: BinaryOpStr
         END;
         END;
     VAR
     VAR
@@ -615,28 +575,24 @@ PROCEDURE incImpl(name: ARRAY OF CHAR; unary: ARRAY OF CHAR; incOp: BinaryOpStr)
     PROCEDURE CallImpl.make(args: JsArray.Type; cx: LanguageContext.Type): Code.PExpression;
     PROCEDURE CallImpl.make(args: JsArray.Type; cx: LanguageContext.Type): Code.PExpression;
     VAR
     VAR
         x, y: Code.PExpression;
         x, y: Code.PExpression;
-        code: JsString.Type;
+        code: STRING;
         value: Code.PConst;
         value: Code.PConst;
-        valueCode: JsString.Type;
+        valueCode: STRING;
     BEGIN
     BEGIN
         checkVariableArgumentsCount(1, 2, args);
         checkVariableArgumentsCount(1, 2, args);
         checkArgumentsType(args, SELF.args, NIL, cx.types);
         checkArgumentsType(args, SELF.args, NIL, cx.types);
         x := nthArgument(args, 0);
         x := nthArgument(args, 0);
         IF JsArray.len(args) = 1 THEN
         IF JsArray.len(args) = 1 THEN
-            code := JsString.concat(SELF.unary, x.code());
+            code := SELF.unary + x.code();
         ELSE
         ELSE
             y := nthArgument(args, 1);
             y := nthArgument(args, 1);
             value := y.constValue();
             value := y.constValue();
             IF value = NIL THEN
             IF value = NIL THEN
                 valueCode := y.code();
                 valueCode := y.code();
             ELSE
             ELSE
-                valueCode := JsString.fromInt(value^(Code.IntConst).value);
+                valueCode := String.fromInt(value^(Code.IntConst).value);
                 IF ~y.isTerm() THEN
                 IF ~y.isTerm() THEN
-                    valueCode := JsString.concat(JsString.concat(JsString.concat(
-                        valueCode, 
-                        JsString.make("/*")), 
-                        y.code()), 
-                        JsString.make("*/"));
+                    valueCode := valueCode + "/*" + y.code() + "*/";
                 END;
                 END;
             END;
             END;
             code := SELF.incOp(x.code(), valueCode);
             code := SELF.incOp(x.code(), valueCode);
@@ -646,32 +602,28 @@ PROCEDURE incImpl(name: ARRAY OF CHAR; unary: ARRAY OF CHAR; incOp: BinaryOpStr)
 BEGIN
 BEGIN
     NEW(call);
     NEW(call);
     initStdCall(call);
     initStdCall(call);
-    call.name := JsString.make(name);
-    call.unary := JsString.make(unary);
+    call.name := name;
+    call.unary := unary;
     call.incOp := incOp;
     call.incOp := incOp;
     hasVarArgument(call, Types.basic.integer);
     hasVarArgument(call, Types.basic.integer);
     hasArgument(call, Types.basic.integer);
     hasArgument(call, Types.basic.integer);
     RETURN makeSymbol(makeStd(call.name, call))
     RETURN makeSymbol(makeStd(call.name, call))
 END incImpl;
 END incImpl;
 
 
-PROCEDURE inclOp(x, y: JsString.Type): JsString.Type;
-    RETURN JsString.concat(JsString.concat(x, JsString.make(" |= ")), y)
+PROCEDURE inclOp(x, y: STRING): STRING;
+    RETURN x + " |= " + y
 END inclOp;
 END inclOp;
 
 
-PROCEDURE exclOp(x, y: JsString.Type): JsString.Type;
-    RETURN JsString.concat(JsString.concat(JsString.concat(
-        x, 
-        JsString.make(" &= ~(" )), 
-        y), 
-        JsString.make(")"))
+PROCEDURE exclOp(x, y: STRING): STRING;
+    RETURN x + " &= ~(" + y + ")"
 END exclOp;
 END exclOp;
 
 
-PROCEDURE incOp(x, y: JsString.Type): JsString.Type;
-    RETURN JsString.concat(JsString.concat(x, JsString.make(" += ")), y)
+PROCEDURE incOp(x, y: STRING): STRING;
+    RETURN x + " += " + y
 END incOp;
 END incOp;
 
 
-PROCEDURE decOp(x, y: JsString.Type): JsString.Type;
-    RETURN JsString.concat(JsString.concat(x, JsString.make(" -= ")), y)
+PROCEDURE decOp(x, y: STRING): STRING;
+    RETURN x + " -= " + y
 END decOp;
 END decOp;
 
 
 PROCEDURE makeAbs(): Symbols.PSymbol;
 PROCEDURE makeAbs(): Symbols.PSymbol;
@@ -689,23 +641,16 @@ PROCEDURE makeAbs(): Symbols.PSymbol;
         arg := checkSingleArgument(args, SELF, cx.types);
         arg := checkSingleArgument(args, SELF, cx.types);
         argType := arg.type();
         argType := arg.type();
         IF ~JsArray.contains(Types.numeric, argType) THEN
         IF ~JsArray.contains(Types.numeric, argType) THEN
-            Errors.raise(JsString.concat(JsString.concat(
-                JsString.make("type mismatch: expected numeric type, got '"),
-                argType.description()),
-                JsString.make("'")));
+            Errors.raise("type mismatch: expected numeric type, got '"
+                         + argType.description() + "'");
         END;
         END;
-        RETURN Code.makeSimpleExpression(
-            JsString.concat(JsString.concat(
-                JsString.make("Math.abs("), 
-                arg.code()), 
-                JsString.make(")")),
-            argType)
+        RETURN Code.makeSimpleExpression("Math.abs(" + arg.code() + ")", argType)
     END CallImpl.make;
     END CallImpl.make;
 BEGIN
 BEGIN
     NEW(call);
     NEW(call);
     initStdCall(call);
     initStdCall(call);
     hasArgumentWithCustomType(call);
     hasArgumentWithCustomType(call);
-    RETURN makeSymbol(makeStd(JsString.make("ABS"), call))
+    RETURN makeSymbol(makeStd("ABS", call))
 END makeAbs;
 END makeAbs;
 
 
 PROCEDURE makeFloor(): Symbols.PSymbol;
 PROCEDURE makeFloor(): Symbols.PSymbol;
@@ -721,17 +666,14 @@ PROCEDURE makeFloor(): Symbols.PSymbol;
     BEGIN
     BEGIN
         arg := checkSingleArgument(args, SELF, cx.types);
         arg := checkSingleArgument(args, SELF, cx.types);
         RETURN Code.makeSimpleExpression(
         RETURN Code.makeSimpleExpression(
-            JsString.concat(JsString.concat(
-                JsString.make("Math.floor("), 
-                arg.code()), 
-                JsString.make(")")),
+            "Math.floor(" + arg.code() + ")",
             Types.basic.integer)
             Types.basic.integer)
     END CallImpl.make;
     END CallImpl.make;
 BEGIN
 BEGIN
     NEW(call);
     NEW(call);
     initStdCall(call);
     initStdCall(call);
     hasArgument(call, Types.basic.real);
     hasArgument(call, Types.basic.real);
-    RETURN makeSymbol(makeStd(JsString.make("FLOOR"), call))
+    RETURN makeSymbol(makeStd("FLOOR", call))
 END makeFloor;
 END makeFloor;
 
 
 PROCEDURE makeFlt(): Symbols.PSymbol;
 PROCEDURE makeFlt(): Symbols.PSymbol;
@@ -762,13 +704,13 @@ BEGIN
     NEW(call);
     NEW(call);
     initStdCall(call);
     initStdCall(call);
     hasArgument(call, Types.basic.integer);
     hasArgument(call, Types.basic.integer);
-    RETURN makeSymbol(makeStd(JsString.make("FLT"), call))
+    RETURN makeSymbol(makeStd("FLT", call))
 END makeFlt;
 END makeFlt;
 
 
-PROCEDURE bitShiftImpl(name: ARRAY OF CHAR; op: BinaryOp): Symbols.PSymbol;
+PROCEDURE bitShiftImpl(name: STRING; op: BinaryOp): Symbols.PSymbol;
     TYPE
     TYPE
         CallImpl = RECORD(StdCall)
         CallImpl = RECORD(StdCall)
-            name: JsString.Type;
+            name: STRING;
             op: BinaryOp
             op: BinaryOp
         END;
         END;
     VAR
     VAR
@@ -787,7 +729,7 @@ PROCEDURE bitShiftImpl(name: ARRAY OF CHAR; op: BinaryOp): Symbols.PSymbol;
 BEGIN
 BEGIN
     NEW(call);
     NEW(call);
     initStdCall(call);
     initStdCall(call);
-    call.name := JsString.make(name);
+    call.name := name;
     call.op := op;
     call.op := op;
     hasArgument(call, Types.basic.integer);
     hasArgument(call, Types.basic.integer);
     hasArgument(call, Types.basic.integer);
     hasArgument(call, Types.basic.integer);
@@ -806,7 +748,7 @@ PROCEDURE makeOrd(): Symbols.PSymbol;
         arg: Code.PExpression;
         arg: Code.PExpression;
         argType: Types.PType;
         argType: Types.PType;
         value: Code.PConst;
         value: Code.PConst;
-        code: JsString.Type;
+        code: STRING;
         ch: CHAR;
         ch: CHAR;
         result: Code.PExpression;
         result: Code.PExpression;
     BEGIN
     BEGIN
@@ -819,9 +761,8 @@ PROCEDURE makeOrd(): Symbols.PSymbol;
             END;
             END;
             result := Code.makeExpression(arg.code(), Types.basic.integer, NIL, value);
             result := Code.makeExpression(arg.code(), Types.basic.integer, NIL, value);
         ELSIF argType = Types.basic.bool THEN
         ELSIF argType = Types.basic.bool THEN
-            code := JsString.concat(
-                Code.adjustPrecedence(arg, Precedence.conditional), 
-                JsString.make(" ? 1 : 0"));
+            code := Code.adjustPrecedence(arg, Precedence.conditional) 
+                  + " ? 1 : 0";
             result := Code.makeExpressionWithPrecedence(
             result := Code.makeExpressionWithPrecedence(
                 code, 
                 code, 
                 Types.basic.integer, 
                 Types.basic.integer, 
@@ -831,15 +772,14 @@ PROCEDURE makeOrd(): Symbols.PSymbol;
         ELSIF (argType IS Types.PString) 
         ELSIF (argType IS Types.PString) 
             & (Types.stringAsChar(argType(Types.PString)^, ch)) THEN
             & (Types.stringAsChar(argType(Types.PString)^, ch)) THEN
             result := Code.makeExpression(
             result := Code.makeExpression(
-                JsString.fromInt(ORD(ch)), 
+                String.fromInt(ORD(ch)), 
                 Types.basic.integer,
                 Types.basic.integer,
                 NIL,
                 NIL,
                 Code.makeIntConst(ORD(ch)));
                 Code.makeIntConst(ORD(ch)));
         ELSE
         ELSE
-            Errors.raise(JsString.concat(JsString.concat(
-                JsString.make("ORD function expects CHAR or BOOLEAN or SET as an argument, got '"),
-                argType.description()),
-                JsString.make("'")));
+            Errors.raise(
+                "ORD function expects CHAR or BOOLEAN or SET as an argument, got '"
+                + argType.description() + "'");
         END;
         END;
         RETURN result
         RETURN result
     END CallImpl.make;
     END CallImpl.make;
@@ -847,7 +787,7 @@ BEGIN
     NEW(call);
     NEW(call);
     initStdCall(call);
     initStdCall(call);
     hasArgumentWithCustomType(call);
     hasArgumentWithCustomType(call);
-    RETURN makeSymbol(makeStd(JsString.make("ORD"), call))
+    RETURN makeSymbol(makeStd("ORD", call))
 END makeOrd;
 END makeOrd;
 
 
 PROCEDURE makeChr(): Symbols.PSymbol;
 PROCEDURE makeChr(): Symbols.PSymbol;
@@ -868,7 +808,7 @@ BEGIN
     NEW(call);
     NEW(call);
     initStdCall(call);
     initStdCall(call);
     hasArgument(call, Types.basic.integer);
     hasArgument(call, Types.basic.integer);
-    RETURN makeSymbol(makeStd(JsString.make("CHR"), call))
+    RETURN makeSymbol(makeStd("CHR", call))
 END makeChr;
 END makeChr;
 
 
 PROCEDURE makePack(): Symbols.PSymbol;
 PROCEDURE makePack(): Symbols.PSymbol;
@@ -894,7 +834,7 @@ BEGIN
     initStdCall(call);
     initStdCall(call);
     hasVarArgument(call, Types.basic.real);
     hasVarArgument(call, Types.basic.real);
     hasArgument(call, Types.basic.integer);
     hasArgument(call, Types.basic.integer);
-    RETURN makeSymbol(makeStd(JsString.make("PACK"), call))
+    RETURN makeSymbol(makeStd("PACK", call))
 END makePack;
 END makePack;
 
 
 PROCEDURE makeUnpk(): Symbols.PSymbol;
 PROCEDURE makeUnpk(): Symbols.PSymbol;
@@ -912,10 +852,9 @@ PROCEDURE makeUnpk(): Symbols.PSymbol;
         x := nthArgument(args, 0);
         x := nthArgument(args, 0);
         y := nthArgument(args, 1);
         y := nthArgument(args, 1);
         RETURN Code.makeSimpleExpression(
         RETURN Code.makeSimpleExpression(
-            JsString.concat(JsString.concat(
-                Operator.assign(y, Operator.log2(x), cx),
-                JsString.make("; ")),
-                Operator.divInplace(x, Operator.pow2(y), cx)),
+                Operator.assign(y, Operator.log2(x), cx) 
+                + "; "
+                + Operator.divInplace(x, Operator.pow2(y), cx),
             NIL)
             NIL)
     END CallImpl.make;
     END CallImpl.make;
 BEGIN
 BEGIN
@@ -923,12 +862,12 @@ BEGIN
     initStdCall(call);
     initStdCall(call);
     hasVarArgument(call, Types.basic.real);
     hasVarArgument(call, Types.basic.real);
     hasVarArgument(call, Types.basic.integer);
     hasVarArgument(call, Types.basic.integer);
-    RETURN makeSymbol(makeStd(JsString.make("UNPK"), call))
+    RETURN makeSymbol(makeStd("UNPK", call))
 END makeUnpk;
 END makeUnpk;
 
 
-PROCEDURE dumpProcArgs(proc: Type): JsString.Type;
+PROCEDURE dumpProcArgs(proc: Type): STRING;
 VAR
 VAR
-    result: JsString.Type;
+    result: STRING;
     len: INTEGER;
     len: INTEGER;
     i: INTEGER;
     i: INTEGER;
     arg: Object.PType;
     arg: Object.PType;
@@ -936,46 +875,37 @@ BEGIN
     len := JsArray.len(proc.mArgs);
     len := JsArray.len(proc.mArgs);
     IF len = 0 THEN
     IF len = 0 THEN
         IF proc.mResult # NIL THEN
         IF proc.mResult # NIL THEN
-            result := JsString.make("()");
-        ELSE
-            result := JsString.makeEmpty();
+            result := "()";
         END;
         END;
     ELSE
     ELSE
-        result := JsString.make("(");
+        result := "(";
         FOR i := 0 TO len - 1 DO
         FOR i := 0 TO len - 1 DO
             IF i # 0 THEN
             IF i # 0 THEN
-                result := JsString.concat(result, JsString.make(", "));
+                result := result + ", ";
             END;
             END;
             arg := JsArray.at(proc.mArgs, i);
             arg := JsArray.at(proc.mArgs, i);
-            result := JsString.concat(
-                result, 
-                arg(Types.PProcedureArgument).type.description());
+            result := result + arg(Types.PProcedureArgument).type.description();
         END;
         END;
-        result := JsString.concat(result, JsString.make(")"));
+        result := result + ")";
     END;
     END;
     RETURN result
     RETURN result
 END dumpProcArgs;
 END dumpProcArgs;
 
 
-PROCEDURE Type.description(): JsString.Type;
+PROCEDURE Type.description(): STRING;
 VAR
 VAR
-    result: JsString.Type;
+    result: STRING;
 BEGIN
 BEGIN
     result := Types.typeName(SELF);
     result := Types.typeName(SELF);
-    IF result = NIL THEN
-        result := JsString.concat(
-            JsString.make("PROCEDURE"), 
-            dumpProcArgs(SELF));
+    IF LEN(result) = 0 THEN
+        result := "PROCEDURE" + dumpProcArgs(SELF);
         IF SELF.mResult # NIL THEN
         IF SELF.mResult # NIL THEN
-            result := JsString.concat(JsString.concat(
-                result, 
-                JsString.make(": ")), 
-                SELF.mResult.description());
+            result := result + ": " + SELF.mResult.description();
         END;
         END;
     END;
     END;
     RETURN result
     RETURN result
 END Type.description;
 END Type.description;
 
 
-PROCEDURE Type.callGenerator(cx: LanguageContext.PType; id: JsString.Type): PCallGenerator;
+PROCEDURE Type.callGenerator(cx: LanguageContext.PType; id: STRING): PCallGenerator;
     RETURN makeProcCallGenerator(cx, id, SELF)
     RETURN makeProcCallGenerator(cx, id, SELF)
 END Type.callGenerator;
 END Type.callGenerator;
 
 
@@ -993,7 +923,7 @@ PROCEDURE Type.result(): Types.PType;
     RETURN SELF.mResult
     RETURN SELF.mResult
 END Type.result;
 END Type.result;
 
 
-PROCEDURE make*(name: JsString.Type): PType;
+PROCEDURE make*(name: STRING): PType;
 VAR
 VAR
     result: PType;
     result: PType;
 BEGIN
 BEGIN

+ 18 - 26
src/ob/Scope.ob

@@ -3,7 +3,6 @@ IMPORT
     Errors, 
     Errors, 
     JsArray, 
     JsArray, 
     JsMap, 
     JsMap, 
-    JsString, 
     Object, 
     Object, 
     Procedures := Procedure, 
     Procedures := Procedure, 
     ScopeBase,
     ScopeBase,
@@ -12,7 +11,7 @@ IMPORT
 TYPE
 TYPE
     Type = RECORD(ScopeBase.Type)
     Type = RECORD(ScopeBase.Type)
         PROCEDURE addSymbol(s: Symbols.PSymbol; exported: BOOLEAN);
         PROCEDURE addSymbol(s: Symbols.PSymbol; exported: BOOLEAN);
-        PROCEDURE findSymbol(id: JsString.Type): Symbols.PSymbol;
+        PROCEDURE findSymbol(id: STRING): Symbols.PSymbol;
         PROCEDURE close();
         PROCEDURE close();
 
 
         stdSymbols: JsMap.Type;
         stdSymbols: JsMap.Type;
@@ -26,7 +25,7 @@ TYPE
     END;
     END;
 
 
     CompiledModule = RECORD(Types.Module)
     CompiledModule = RECORD(Types.Module)
-        PROCEDURE findSymbol(id: JsString.Type): Symbols.PFoundSymbol;
+        PROCEDURE findSymbol(id: STRING): Symbols.PFoundSymbol;
 
 
         exports: JsMap.Type
         exports: JsMap.Type
     END;
     END;
@@ -45,7 +44,7 @@ TYPE
 
 
 PROCEDURE addSymbolForType*(t: Types.PBasicType; result: JsMap.Type);
 PROCEDURE addSymbolForType*(t: Types.PBasicType; result: JsMap.Type);
 VAR
 VAR
-    name: JsString.Type;
+    name: STRING;
 BEGIN
 BEGIN
     name := Types.typeName(t^);
     name := Types.typeName(t^);
     JsMap.put(result, name, Symbols.makeSymbol(name, Types.makeTypeId(t)));
     JsMap.put(result, name, Symbols.makeSymbol(name, Types.makeTypeId(t)));
@@ -85,7 +84,7 @@ BEGIN
     scope.finalizers := JsArray.make();
     scope.finalizers := JsArray.make();
 END init;
 END init;
 
 
-PROCEDURE makeCompiledModule(name: JsString.Type): PCompiledModule;
+PROCEDURE makeCompiledModule(name: STRING): PCompiledModule;
 VAR
 VAR
     result: PCompiledModule;
     result: PCompiledModule;
 BEGIN
 BEGIN
@@ -95,7 +94,7 @@ BEGIN
     RETURN result
     RETURN result
 END makeCompiledModule;
 END makeCompiledModule;
 
 
-PROCEDURE makeModule*(name: JsString.Type; stdSymbols: JsMap.Type): PModule;
+PROCEDURE makeModule*(name: STRING; stdSymbols: JsMap.Type): PModule;
 VAR
 VAR
     result: PModule;
     result: PModule;
 BEGIN
 BEGIN
@@ -107,7 +106,7 @@ BEGIN
     RETURN result
     RETURN result
 END makeModule;
 END makeModule;
 
 
-PROCEDURE addUnresolved*(s: Type; id: JsString.Type);
+PROCEDURE addUnresolved*(s: Type; id: STRING);
 BEGIN
 BEGIN
     IF ~JsArray.containsString(s.unresolved, id) THEN
     IF ~JsArray.containsString(s.unresolved, id) THEN
         JsArray.addString(s.unresolved, id);
         JsArray.addString(s.unresolved, id);
@@ -116,7 +115,7 @@ END addUnresolved;
 
 
 PROCEDURE resolve*(s: Type; symbol: Symbols.PSymbol);
 PROCEDURE resolve*(s: Type; symbol: Symbols.PSymbol);
 VAR
 VAR
-    id: JsString.Type;
+    id: STRING;
     i: INTEGER;
     i: INTEGER;
     info: Types.PId;
     info: Types.PId;
     type: Types.PType;
     type: Types.PType;
@@ -127,10 +126,10 @@ BEGIN
         info := symbol.info();
         info := symbol.info();
         type := info(Types.PTypeId).type();
         type := info(Types.PTypeId).type();
         IF (type # NIL) & ~(type IS Types.PRecord) THEN
         IF (type # NIL) & ~(type IS Types.PRecord) THEN
-            Errors.raise(JsString.concat(JsString.concat(
-                JsString.make("'"),
-                id),
-                JsString.make("' must be of RECORD type because it was used before in the declation of POINTER")));
+            Errors.raise(
+                "'" 
+                + id
+                + "' must be of RECORD type because it was used before in the declation of POINTER");
         END;
         END;
         JsArray.removeString(s.unresolved, i);
         JsArray.removeString(s.unresolved, i);
     END;
     END;
@@ -174,19 +173,16 @@ END close;
 
 
 PROCEDURE Type.addSymbol(s: Symbols.PSymbol; exported: BOOLEAN);
 PROCEDURE Type.addSymbol(s: Symbols.PSymbol; exported: BOOLEAN);
 VAR
 VAR
-    id: JsString.Type;
+    id: STRING;
 BEGIN
 BEGIN
     id := s.id();
     id := s.id();
     IF SELF.findSymbol(id) # NIL THEN
     IF SELF.findSymbol(id) # NIL THEN
-        Errors.raise(JsString.concat(JsString.concat(
-            JsString.make("'"),
-            id),
-            JsString.make("' already declared")));
+        Errors.raise("'" + id + "' already declared");
     END;
     END;
     JsMap.put(SELF.symbols, id, s);
     JsMap.put(SELF.symbols, id, s);
 END Type.addSymbol;
 END Type.addSymbol;
 
 
-PROCEDURE Type.findSymbol(id: JsString.Type): Symbols.PSymbol;
+PROCEDURE Type.findSymbol(id: STRING): Symbols.PSymbol;
 VAR
 VAR
     result: Object.PType;
     result: Object.PType;
     void: BOOLEAN;
     void: BOOLEAN;
@@ -203,12 +199,8 @@ VAR
 BEGIN
 BEGIN
     IF exported THEN
     IF exported THEN
         info := s.info();
         info := s.info();
-        Errors.raise(JsString.concat(JsString.concat(JsString.concat(JsString.concat(
-            JsString.make("cannot export from within procedure: "),
-            info.idType()),
-            JsString.make(" '")),
-            s.id()),
-            JsString.make("'")));
+        Errors.raise("cannot export from within procedure: "
+                     + info.idType() + " '" + s.id() + "'");
     END;
     END;
     SUPER(s, exported);
     SUPER(s, exported);
 END Procedure.addSymbol;
 END Procedure.addSymbol;
@@ -222,7 +214,7 @@ BEGIN
     RETURN result
     RETURN result
 END makeProcedure;
 END makeProcedure;
 
 
-PROCEDURE addExport(id: JsString.Type; value: Object.PType; VAR closure: Object.Type);
+PROCEDURE addExport(id: STRING; value: Object.PType; VAR closure: Object.Type);
 VAR
 VAR
     symbol: Symbols.PSymbol;
     symbol: Symbols.PSymbol;
     info: Types.PId;
     info: Types.PId;
@@ -240,7 +232,7 @@ BEGIN
     JsMap.forEach(exports, addExport, m);
     JsMap.forEach(exports, addExport, m);
 END defineExports;
 END defineExports;
 
 
-PROCEDURE CompiledModule.findSymbol(id: JsString.Type): Symbols.PFoundSymbol;
+PROCEDURE CompiledModule.findSymbol(id: STRING): Symbols.PFoundSymbol;
 VAR
 VAR
     s: Object.PType;
     s: Object.PType;
     result: Symbols.PFoundSymbol;
     result: Symbols.PFoundSymbol;

+ 13 - 13
src/ob/Stream.ob

@@ -1,18 +1,18 @@
 MODULE Stream;
 MODULE Stream;
-IMPORT JsString;
-
+IMPORT
+    String;
 CONST
 CONST
     kCR* = 0AX;
     kCR* = 0AX;
 
 
 TYPE
 TYPE
     Type* = POINTER TO RECORD
     Type* = POINTER TO RECORD
-        s: JsString.Type;
+        s: STRING;
         pos: INTEGER
         pos: INTEGER
     END;
     END;
 
 
     ReaderProc = PROCEDURE(c: CHAR): BOOLEAN;
     ReaderProc = PROCEDURE(c: CHAR): BOOLEAN;
 
 
-PROCEDURE make*(text: JsString.Type): Type;
+PROCEDURE make*(text: STRING): Type;
 VAR result: Type;
 VAR result: Type;
 BEGIN
 BEGIN
     NEW(result);
     NEW(result);
@@ -21,7 +21,7 @@ BEGIN
 END make;
 END make;
 
 
 PROCEDURE eof*(self: Type): BOOLEAN;
 PROCEDURE eof*(self: Type): BOOLEAN;
-    RETURN self.pos = JsString.len(self.s)
+    RETURN self.pos = LEN(self.s)
 END eof;
 END eof;
 
 
 PROCEDURE pos*(self: Type): INTEGER;
 PROCEDURE pos*(self: Type): INTEGER;
@@ -30,27 +30,27 @@ END pos;
 
 
 PROCEDURE setPos*(self: Type; pos: INTEGER);
 PROCEDURE setPos*(self: Type; pos: INTEGER);
 BEGIN
 BEGIN
-    ASSERT(pos <= JsString.len(self.s));
+    ASSERT(pos <= LEN(self.s));
     self.pos := pos
     self.pos := pos
 END setPos;
 END setPos;
 
 
 PROCEDURE next*(self: Type; n: INTEGER);
 PROCEDURE next*(self: Type; n: INTEGER);
 BEGIN
 BEGIN
-    ASSERT(self.pos + n <= JsString.len(self.s));
+    ASSERT(self.pos + n <= LEN(self.s));
     self.pos := self.pos + n;
     self.pos := self.pos + n;
 END next;
 END next;
 
 
 PROCEDURE peekChar*(self: Type): CHAR;
 PROCEDURE peekChar*(self: Type): CHAR;
 BEGIN
 BEGIN
     ASSERT(~eof(self));
     ASSERT(~eof(self));
-    RETURN JsString.at(self.s, self.pos)
+    RETURN self.s[self.pos]
 END peekChar;
 END peekChar;
 
 
 PROCEDURE getChar*(self: Type): CHAR;
 PROCEDURE getChar*(self: Type): CHAR;
 VAR result: CHAR;
 VAR result: CHAR;
 BEGIN
 BEGIN
     ASSERT(~eof(self));
     ASSERT(~eof(self));
-    result := JsString.at(self.s, self.pos);
+    result := self.s[self.pos];
     INC(self.pos);
     INC(self.pos);
     RETURN result
     RETURN result
 END getChar;
 END getChar;
@@ -60,8 +60,8 @@ VAR
     result: BOOLEAN;
     result: BOOLEAN;
     i: INTEGER;
     i: INTEGER;
 BEGIN
 BEGIN
-    IF LEN(s) <= JsString.len(self.s) - self.pos THEN
-        WHILE (i < LEN(s)) & (s[i] = JsString.at(self.s, self.pos + i)) DO
+    IF LEN(s) <= LEN(self.s) - self.pos THEN
+        WHILE (i < LEN(s)) & (s[i] = self.s[self.pos + i]) DO
             INC(i)
             INC(i)
         END;
         END;
         result := i = LEN(s);
         result := i = LEN(s);
@@ -82,10 +82,10 @@ VAR
     line: INTEGER;
     line: INTEGER;
     lastPos: INTEGER;
     lastPos: INTEGER;
 BEGIN
 BEGIN
-    lastPos := JsString.indexOf(self.s, kCR);
+    lastPos := String.indexOf(self.s, kCR);
     WHILE (lastPos # -1) & (lastPos < self.pos) DO
     WHILE (lastPos # -1) & (lastPos < self.pos) DO
         INC(line);
         INC(line);
-        lastPos := JsString.indexOfFrom(self.s, kCR, lastPos + 1);
+        lastPos := String.indexOfFrom(self.s, kCR, lastPos + 1);
     END;
     END;
     RETURN line + 1
     RETURN line + 1
 END lineNumber;
 END lineNumber;

+ 44 - 0
src/ob/String.ob

@@ -0,0 +1,44 @@
+MODULE String;
+IMPORT JS;
+
+PROCEDURE fromChar*(c: CHAR): STRING;
+VAR
+    result: STRING;
+BEGIN
+    JS.do("result = JS.String.fromCharCode(c)")
+    RETURN result
+END fromChar;
+
+PROCEDURE fromInt*(i: INTEGER): STRING;
+VAR 
+    result: STRING;
+BEGIN
+    JS.do("result = '' + i");
+    RETURN result
+END fromInt;
+
+PROCEDURE indexOf*(self: STRING; c: CHAR): INTEGER;
+VAR 
+    result: INTEGER;
+BEGIN
+    JS.do("result = self.indexOf(JS.String.fromCharCode(c))")
+    RETURN result
+END indexOf;
+
+PROCEDURE indexOfFrom*(self: STRING; c: CHAR; pos: INTEGER): INTEGER;
+VAR 
+    result: INTEGER;
+BEGIN
+    JS.do("result = self.indexOf(JS.String.fromCharCode(c), pos)")
+    RETURN result
+END indexOfFrom;
+
+PROCEDURE substr*(self: STRING; pos: INTEGER; len: INTEGER): STRING;
+VAR 
+    result: STRING;
+BEGIN
+    JS.do("result = self.substr(pos, len)")
+    RETURN result
+END substr;
+
+END String.

+ 5 - 5
src/ob/Symbols.ob

@@ -1,8 +1,8 @@
 MODULE Symbols;
 MODULE Symbols;
-IMPORT JsString, Object, ScopeBase, Types;
+IMPORT Object, ScopeBase, Types;
 TYPE
 TYPE
     Symbol* = RECORD(Object.Type)
     Symbol* = RECORD(Object.Type)
-        PROCEDURE id*(): JsString.Type;
+        PROCEDURE id*(): STRING;
         PROCEDURE info*(): Types.PId;
         PROCEDURE info*(): Types.PId;
         PROCEDURE isModule*(): BOOLEAN;
         PROCEDURE isModule*(): BOOLEAN;
         PROCEDURE isVariable*(): BOOLEAN;
         PROCEDURE isVariable*(): BOOLEAN;
@@ -10,7 +10,7 @@ TYPE
         PROCEDURE isType*(): BOOLEAN;
         PROCEDURE isType*(): BOOLEAN;
         PROCEDURE isProcedure*(): BOOLEAN;
         PROCEDURE isProcedure*(): BOOLEAN;
 
 
-        mId: JsString.Type;
+        mId: STRING;
         mInfo: Types.PId
         mInfo: Types.PId
     END;
     END;
 
 
@@ -26,7 +26,7 @@ TYPE
 
 
     PFoundSymbol* = POINTER TO FoundSymbol;
     PFoundSymbol* = POINTER TO FoundSymbol;
 
 
-PROCEDURE Symbol.id(): JsString.Type;
+PROCEDURE Symbol.id(): STRING;
     RETURN SELF.mId
     RETURN SELF.mId
 END Symbol.id;
 END Symbol.id;
 
 
@@ -62,7 +62,7 @@ PROCEDURE FoundSymbol.symbol(): PSymbol;
     RETURN SELF.mSymbol
     RETURN SELF.mSymbol
 END FoundSymbol.symbol;
 END FoundSymbol.symbol;
 
 
-PROCEDURE makeSymbol*(id: JsString.Type; info: Types.PId): PSymbol;
+PROCEDURE makeSymbol*(id: STRING; info: Types.PId): PSymbol;
 VAR
 VAR
     result: PSymbol;
     result: PSymbol;
 BEGIN
 BEGIN

+ 98 - 139
src/ob/Types.ob

@@ -1,28 +1,28 @@
 MODULE Types;
 MODULE Types;
 IMPORT
 IMPORT
-    Context, Errors, JS, JsArray, JsMap, JsString, Object, ScopeBase;
+    Context, Errors, JS, JsArray, JsMap, Object, ScopeBase, Str := String;
 CONST
 CONST
     openArrayLength* = 0;
     openArrayLength* = 0;
 
 
 TYPE
 TYPE
     Id* = RECORD(Object.Type)
     Id* = RECORD(Object.Type)
-        PROCEDURE idType*(): JsString.Type
+        PROCEDURE idType*(): STRING
     END;
     END;
 
 
     PId* = POINTER TO Id;
     PId* = POINTER TO Id;
     
     
     Type* = RECORD(Object.Type)
     Type* = RECORD(Object.Type)
-        PROCEDURE description*(): JsString.Type
+        PROCEDURE description*(): STRING
     END;
     END;
     PType* = POINTER TO Type;
     PType* = POINTER TO Type;
 
 
     StorageType* = RECORD(Type)    
     StorageType* = RECORD(Type)    
-        PROCEDURE initializer*(cx: Context.Type): JsString.Type
+        PROCEDURE initializer*(cx: Context.Type): STRING
     END;
     END;
 
 
     TypeId* = RECORD(Id)
     TypeId* = RECORD(Id)
         PROCEDURE type*(): PType;
         PROCEDURE type*(): PType;
-        PROCEDURE description(): JsString.Type;
+        PROCEDURE description(): STRING;
         PROCEDURE strip();
         PROCEDURE strip();
 
 
         mType: PType
         mType: PType
@@ -81,17 +81,17 @@ TYPE
     PProcedureId* = POINTER TO ProcedureId;
     PProcedureId* = POINTER TO ProcedureId;
 
 
     String* = RECORD(Type)
     String* = RECORD(Type)
-        s: JsString.Type
+        s: STRING
     END;
     END;
 
 
     PString* = POINTER TO String;
     PString* = POINTER TO String;
 
 
     NamedType* = RECORD(StorageType)
     NamedType* = RECORD(StorageType)
-        name*: JsString.Type
+        name*: STRING
     END;
     END;
 
 
     Array* = RECORD(NamedType)
     Array* = RECORD(NamedType)
-        mInitializer: JsString.Type;
+        mInitializer: STRING;
         elementsType: PType;
         elementsType: PType;
         len: INTEGER
         len: INTEGER
     END;
     END;
@@ -117,7 +117,7 @@ TYPE
     PDefinedProcedure* = POINTER TO DefinedProcedure;
     PDefinedProcedure* = POINTER TO DefinedProcedure;
 
 
     ProcedureArgument* = RECORD (Object.Type)
     ProcedureArgument* = RECORD (Object.Type)
-        PROCEDURE description(): JsString.Type;
+        PROCEDURE description(): STRING;
 
 
         type*: PType;
         type*: PType;
         isVar*: BOOLEAN
         isVar*: BOOLEAN
@@ -126,24 +126,24 @@ TYPE
     PProcedureArgument* = POINTER TO ProcedureArgument;
     PProcedureArgument* = POINTER TO ProcedureArgument;
 
 
     BasicType* = RECORD(NamedType)
     BasicType* = RECORD(NamedType)
-        mInitializer: JsString.Type
+        mInitializer: STRING
     END;
     END;
 
 
     PBasicType* = POINTER TO BasicType;
     PBasicType* = POINTER TO BasicType;
 
 
     Field = RECORD
     Field = RECORD
-        id: PROCEDURE(): JsString.Type;
+        id: PROCEDURE(): STRING;
         exported: PROCEDURE(): BOOLEAN
         exported: PROCEDURE(): BOOLEAN
     END;
     END;
 
 
     Record* = RECORD(NamedType)
     Record* = RECORD(NamedType)
         PROCEDURE addField(f: Field; type: PType);
         PROCEDURE addField(f: Field; type: PType);
-        PROCEDURE findSymbol(id: JsString.Type): PType;
+        PROCEDURE findSymbol(id: STRING): PType;
         PROCEDURE finalize();
         PROCEDURE finalize();
 
 
         fields: JsMap.Type;
         fields: JsMap.Type;
         base:   PRecord;
         base:   PRecord;
-        cons:   JsString.Type;
+        cons:   STRING;
         scope:  ScopeBase.PType;
         scope:  ScopeBase.PType;
         notExported: JsArray.Strings
         notExported: JsArray.Strings
     END;
     END;
@@ -156,7 +156,7 @@ TYPE
     END;
     END;
 
 
     Module* = RECORD(Id)
     Module* = RECORD(Id)
-        name: JsString.Type
+        name: STRING
     END;
     END;
 
 
     PModule* = POINTER TO Module;
     PModule* = POINTER TO Module;
@@ -169,12 +169,12 @@ VAR
     numeric*: JsArray.Type;
     numeric*: JsArray.Type;
     nil*: POINTER TO Nil;
     nil*: POINTER TO Nil;
 
 
-PROCEDURE TypeId.description(): JsString.Type;
+PROCEDURE TypeId.description(): STRING;
 VAR
 VAR
     t: PType;
     t: PType;
 BEGIN
 BEGIN
     t := SELF.type();
     t := SELF.type();
-    RETURN JsString.concat(JsString.make("type "), t.description())
+    RETURN "type " + t.description()
 END TypeId.description;
 END TypeId.description;
 
 
 PROCEDURE TypeId.type(): PType;
 PROCEDURE TypeId.type(): PType;
@@ -196,7 +196,7 @@ BEGIN
     SELF.notExported := NIL;
     SELF.notExported := NIL;
 END Record.finalize;
 END Record.finalize;
 
 
-PROCEDURE initRecord*(r: PRecord; name: JsString.Type; cons: JsString.Type; scope: ScopeBase.PType);
+PROCEDURE initRecord*(r: PRecord; name: STRING; cons: STRING; scope: ScopeBase.PType);
 BEGIN
 BEGIN
     r.name := name;
     r.name := name;
     r.cons := cons;
     r.cons := cons;
@@ -206,12 +206,12 @@ BEGIN
     scope.addFinalizer(finalizeRecord, r);
     scope.addFinalizer(finalizeRecord, r);
 END initRecord;
 END initRecord;
 
 
-PROCEDURE makeNonExportedRecord(cons: JsString.Type; scope: ScopeBase.PType; base: PRecord): PNonExportedRecord;
+PROCEDURE makeNonExportedRecord(cons: STRING; scope: ScopeBase.PType; base: PRecord): PNonExportedRecord;
 VAR
 VAR
     result: PNonExportedRecord;
     result: PNonExportedRecord;
 BEGIN
 BEGIN
     NEW(result);
     NEW(result);
-    initRecord(result, NIL, cons, scope);
+    initRecord(result, "", cons, scope);
     result.base := base;
     result.base := base;
     RETURN result
     RETURN result
 END makeNonExportedRecord;    
 END makeNonExportedRecord;    
@@ -250,32 +250,32 @@ BEGIN
     tId.mType := t;
     tId.mType := t;
 END defineTypeId;
 END defineTypeId;
 
 
-PROCEDURE typeName*(type: NamedType): JsString.Type;
+PROCEDURE typeName*(type: NamedType): STRING;
     RETURN type.name
     RETURN type.name
 END typeName;
 END typeName;
 
 
-PROCEDURE ProcedureId.idType(): JsString.Type;
-    RETURN JsString.make("procedure")
+PROCEDURE ProcedureId.idType(): STRING;
+    RETURN "procedure"
 END ProcedureId.idType;
 END ProcedureId.idType;
 
 
-PROCEDURE String.description(): JsString.Type;
+PROCEDURE String.description(): STRING;
 VAR
 VAR
-    prefix: JsString.Type;
+    prefix: STRING;
 BEGIN
 BEGIN
-    IF JsString.len(SELF.s) = 1 THEN
-        prefix := JsString.make("single-");
+    IF LEN(SELF.s) = 1 THEN
+        prefix := "single-";
     ELSE
     ELSE
-        prefix := JsString.make("multi-");
+        prefix := "multi-";
     END;
     END;
-    RETURN JsString.concat(prefix, JsString.make("character string"))
+    RETURN prefix + "character string"
 END String.description;
 END String.description;
 
 
-PROCEDURE stringValue*(s: String): JsString.Type;
+PROCEDURE stringValue*(s: String): STRING;
     RETURN s.s
     RETURN s.s
 END stringValue;
 END stringValue;
 
 
 PROCEDURE stringLen*(s: String): INTEGER;
 PROCEDURE stringLen*(s: String): INTEGER;
-    RETURN JsString.len(s.s)
+    RETURN LEN(s.s)
 END stringLen;
 END stringLen;
 
 
 PROCEDURE stringAsChar*(s: String; VAR c: CHAR): BOOLEAN;
 PROCEDURE stringAsChar*(s: String; VAR c: CHAR): BOOLEAN;
@@ -284,13 +284,13 @@ VAR
 BEGIN
 BEGIN
     result := stringLen(s) = 1;
     result := stringLen(s) = 1;
     IF result THEN
     IF result THEN
-        c := JsString.at(s.s, 0);
+        c := s.s[0];
     END;
     END;
     RETURN result
     RETURN result
 END stringAsChar;
 END stringAsChar;
 
 
-PROCEDURE Const.idType(): JsString.Type;
-    RETURN JsString.make("constant")
+PROCEDURE Const.idType(): STRING;
+    RETURN "constant"
 END Const.idType;
 END Const.idType;
 
 
 PROCEDURE constType*(c: Const): PType;
 PROCEDURE constType*(c: Const): PType;
@@ -301,12 +301,12 @@ PROCEDURE constValue*(c: Const): JS.var;
     RETURN c.value
     RETURN c.value
 END constValue;
 END constValue;
 
 
-PROCEDURE Variable.idType(): JsString.Type;
-    RETURN JsString.make("variable")
+PROCEDURE Variable.idType(): STRING;
+    RETURN "variable"
 END Variable.idType;
 END Variable.idType;
 
 
-PROCEDURE ReadOnlyVariable.idType(): JsString.Type;
-    RETURN JsString.make("read-only variable")
+PROCEDURE ReadOnlyVariable.idType(): STRING;
+    RETURN "read-only variable"
 END ReadOnlyVariable.idType;
 END ReadOnlyVariable.idType;
 
 
 PROCEDURE VariableImpl.type(): PType;
 PROCEDURE VariableImpl.type(): PType;
@@ -325,36 +325,32 @@ PROCEDURE ReadOnlyVariable.isReadOnly(): BOOLEAN;
     RETURN TRUE
     RETURN TRUE
 END ReadOnlyVariable.isReadOnly;
 END ReadOnlyVariable.isReadOnly;
 
 
-PROCEDURE ExportedVariable.idType(): JsString.Type;
-    RETURN JsString.make("imported variable")
+PROCEDURE ExportedVariable.idType(): STRING;
+    RETURN "imported variable"
 END ExportedVariable.idType;
 END ExportedVariable.idType;
 
 
-PROCEDURE TypeId.idType(): JsString.Type;
-    RETURN JsString.make("type")
+PROCEDURE TypeId.idType(): STRING;
+    RETURN "type"
 END TypeId.idType;
 END TypeId.idType;
 
 
-PROCEDURE BasicType.description(): JsString.Type;
+PROCEDURE BasicType.description(): STRING;
     RETURN SELF.name
     RETURN SELF.name
 END BasicType.description;
 END BasicType.description;
 
 
-PROCEDURE BasicType.initializer(cx: Context.Type): JsString.Type;
+PROCEDURE BasicType.initializer(cx: Context.Type): STRING;
     RETURN SELF.mInitializer
     RETURN SELF.mInitializer
 END BasicType.initializer;
 END BasicType.initializer;
-(*
-PROCEDURE Nil.idType(): JsString.Type;
-    RETURN JsString.make("NIL")
-END Nil.idType;
-*)
-PROCEDURE Nil.description(): JsString.Type;
-    RETURN JsString.make("NIL")
+
+PROCEDURE Nil.description(): STRING;
+    RETURN "NIL"
 END Nil.description;
 END Nil.description;
 
 
 PROCEDURE isInt*(t: PType): BOOLEAN;
 PROCEDURE isInt*(t: PType): BOOLEAN;
     RETURN (t = basic.integer) OR (t = basic.uint8)
     RETURN (t = basic.integer) OR (t = basic.uint8)
 END isInt;
 END isInt;
 
 
-PROCEDURE intsDescription*(): JsString.Type;
-    RETURN JsString.make("'INTEGER' or 'BYTE'")
+PROCEDURE intsDescription*(): STRING;
+    RETURN "'INTEGER' or 'BYTE'"
 END intsDescription;
 END intsDescription;
 
 
 PROCEDURE isString*(t: PType): BOOLEAN;
 PROCEDURE isString*(t: PType): BOOLEAN;
@@ -362,57 +358,43 @@ PROCEDURE isString*(t: PType): BOOLEAN;
            OR (t^ IS String)
            OR (t^ IS String)
 END isString;
 END isString;
 
 
-PROCEDURE moduleName*(m: Module): JsString.Type;
+PROCEDURE moduleName*(m: Module): STRING;
     RETURN m.name
     RETURN m.name
 END moduleName;
 END moduleName;
 
 
-PROCEDURE makeBasic*(name: ARRAY OF CHAR; initializer: ARRAY OF CHAR): PBasicType;
+PROCEDURE makeBasic*(name: STRING; initializer: STRING): PBasicType;
 VAR
 VAR
     result: PBasicType;
     result: PBasicType;
 BEGIN
 BEGIN
     NEW(result);
     NEW(result);
-    result.name := JsString.make(name);
-    result.mInitializer := JsString.make(initializer);
+    result.name := name;
+    result.mInitializer := initializer;
     RETURN result
     RETURN result
 END makeBasic;
 END makeBasic;
-(*
-PROCEDURE Record.idType(): JsString.Type;
-    RETURN JsString.make("record")
-END Record.idType;
-*)
-PROCEDURE Record.description(): JsString.Type;
+
+PROCEDURE Record.description(): STRING;
 VAR
 VAR
-    result: JsString.Type;
+    result: STRING;
 BEGIN
 BEGIN
-    IF SELF.name # NIL THEN
+    IF LEN(SELF.name) # 0 THEN
         result := SELF.name;
         result := SELF.name;
     ELSE
     ELSE
-        result := JsString.make("anonymous RECORD");
+        result := "anonymous RECORD";
     END;
     END;
     RETURN result
     RETURN result
 END Record.description;
 END Record.description;
 
 
-PROCEDURE Record.initializer(cx: Context.Type): JsString.Type;
-    RETURN JsString.concat(JsString.concat(JsString.concat(
-        JsString.make("new "), 
-        cx.qualifyScope(SELF.scope)), 
-        SELF.cons), 
-        JsString.make("()"))
+PROCEDURE Record.initializer(cx: Context.Type): STRING;
+    RETURN "new " + cx.qualifyScope(SELF.scope) + SELF.cons + "()"
 END Record.initializer;
 END Record.initializer;
 
 
 PROCEDURE Record.addField(f: Field; type: PType);
 PROCEDURE Record.addField(f: Field; type: PType);
 BEGIN
 BEGIN
     IF JsMap.has(SELF.fields, f.id()) THEN
     IF JsMap.has(SELF.fields, f.id()) THEN
-        Errors.raise(JsString.concat(JsString.concat(
-            JsString.make("duplicated field: '"), 
-            f.id()), 
-            JsString.make("'")));
+        Errors.raise("duplicated field: '" + f.id() + "'");
     END;
     END;
     IF (SELF.base # NIL) & (SELF.base.findSymbol(f.id()) # NIL) THEN
     IF (SELF.base # NIL) & (SELF.base.findSymbol(f.id()) # NIL) THEN
-        Errors.raise(JsString.concat(JsString.concat(
-            JsString.make("base record already has field: '"),
-            f.id()),
-            JsString.make("'")));
+        Errors.raise("base record already has field: '" + f.id() + "'");
     END;
     END;
     JsMap.put(SELF.fields, f.id(), type);
     JsMap.put(SELF.fields, f.id(), type);
     IF ~f.exported() THEN
     IF ~f.exported() THEN
@@ -420,7 +402,7 @@ BEGIN
     END;
     END;
 END Record.addField;
 END Record.addField;
 
 
-PROCEDURE Record.findSymbol(id: JsString.Type): PType;
+PROCEDURE Record.findSymbol(id: STRING): PType;
 VAR
 VAR
     result: PType;
     result: PType;
 BEGIN
 BEGIN
@@ -443,18 +425,14 @@ PROCEDURE recordScope*(r: Record): ScopeBase.PType;
     RETURN r.scope
     RETURN r.scope
 END recordScope;
 END recordScope;
 
 
-PROCEDURE recordConstructor*(r: Record): JsString.Type;
+PROCEDURE recordConstructor*(r: Record): STRING;
     RETURN r.cons
     RETURN r.cons
 END recordConstructor;
 END recordConstructor;
 
 
 PROCEDURE recordOwnFields*(r: Record): JsMap.Type;
 PROCEDURE recordOwnFields*(r: Record): JsMap.Type;
     RETURN r.fields
     RETURN r.fields
 END recordOwnFields;
 END recordOwnFields;
-(*
-PROCEDURE Pointer.idType(): JsString.Type;
-    RETURN JsString.make("pointer")
-END Pointer.idType;
-*)
+
 PROCEDURE pointerBase*(p: Pointer): PRecord;
 PROCEDURE pointerBase*(p: Pointer): PRecord;
 VAR
 VAR
     result: PType;
     result: PType;
@@ -463,68 +441,55 @@ BEGIN
     RETURN result(PRecord)
     RETURN result(PRecord)
 END pointerBase;
 END pointerBase;
 
 
-PROCEDURE Pointer.description(): JsString.Type;
+PROCEDURE Pointer.description(): STRING;
 VAR
 VAR
     base: PRecord;
     base: PRecord;
-    result: JsString.Type;
+    result: STRING;
 BEGIN
 BEGIN
-    IF SELF.name # NIL THEN
+    IF LEN(SELF.name) # 0 THEN
         result := SELF.name;
         result := SELF.name;
     ELSE
     ELSE
         base := pointerBase(SELF);
         base := pointerBase(SELF);
-        result := JsString.concat(JsString.make("POINTER TO "), base.description());
+        result := "POINTER TO " + base.description();
     END;
     END;
     RETURN result
     RETURN result
 END Pointer.description;
 END Pointer.description;
 
 
-PROCEDURE Pointer.initializer(cx: Context.Type): JsString.Type;
-    RETURN JsString.make("null")
+PROCEDURE Pointer.initializer(cx: Context.Type): STRING;
+    RETURN "null"
 END Pointer.initializer;
 END Pointer.initializer;
-(*
-PROCEDURE Array.idType(): JsString.Type;
-    RETURN JsString.make("array")
-END Array.idType;
-*)
-PROCEDURE foldArrayDimensions(a: Array; VAR sizes, of: JsString.Type);
+
+PROCEDURE foldArrayDimensions(a: Array; VAR sizes, of: STRING);
 BEGIN  
 BEGIN  
     IF (a.len # openArrayLength) & (a.elementsType IS PArray) THEN
     IF (a.len # openArrayLength) & (a.elementsType IS PArray) THEN
         foldArrayDimensions(a.elementsType^(Array), sizes, of);
         foldArrayDimensions(a.elementsType^(Array), sizes, of);
-        sizes := JsString.concat(JsString.concat(
-            JsString.fromInt(a.len),
-            JsString.make(", ")),
-            sizes);
+        sizes := Str.fromInt(a.len) + ", " + sizes;
     ELSE
     ELSE
         IF a.len # openArrayLength THEN
         IF a.len # openArrayLength THEN
-            sizes := JsString.fromInt(a.len);
+            sizes := Str.fromInt(a.len);
         END;
         END;
         of := a.elementsType.description();
         of := a.elementsType.description();
     END
     END
 END foldArrayDimensions;
 END foldArrayDimensions;
 
 
-PROCEDURE Array.description(): JsString.Type;
+PROCEDURE Array.description(): STRING;
 VAR
 VAR
-    result: JsString.Type;
-    sizes, of: JsString.Type;
+    result: STRING;
+    sizes, of: STRING;
 BEGIN
 BEGIN
     IF SELF.elementsType = NIL THEN (* special arrays, see procedure "LEN" *)
     IF SELF.elementsType = NIL THEN (* special arrays, see procedure "LEN" *)
         result := SELF.name;
         result := SELF.name;
     ELSE
     ELSE
         foldArrayDimensions(SELF, sizes, of);
         foldArrayDimensions(SELF, sizes, of);
-        IF sizes = NIL THEN
-            sizes := JsString.make("");
-        ELSE
-            sizes := JsString.concat(JsString.make(" "), sizes);
+        IF LEN(sizes) # 0 THEN
+            sizes := " " + sizes;
         END;
         END;
-        result := JsString.concat(JsString.concat(JsString.concat(
-            JsString.make("ARRAY"),
-            sizes),
-            JsString.make(" OF ")),
-            of);
+        result := "ARRAY" + sizes + " OF " + of;
     END;
     END;
     RETURN result
     RETURN result
 END Array.description;
 END Array.description;
 
 
-PROCEDURE Array.initializer(cx: Context.Type): JsString.Type;
+PROCEDURE Array.initializer(cx: Context.Type): STRING;
     RETURN SELF.mInitializer
     RETURN SELF.mInitializer
 END Array.initializer;
 END Array.initializer;
 
 
@@ -535,29 +500,23 @@ END arrayElementsType;
 PROCEDURE arrayLength*(a: Array): INTEGER;
 PROCEDURE arrayLength*(a: Array): INTEGER;
     RETURN a.len
     RETURN a.len
 END arrayLength;
 END arrayLength;
-(*
-PROCEDURE String.initializer(cx: Context.Type): JsString.Type;
-    RETURN JsString.make("null")
-END String.initializer;
-*)
-PROCEDURE Procedure.initializer(cx: Context.Type): JsString.Type;
-    RETURN JsString.make("null")
+
+PROCEDURE Procedure.initializer(cx: Context.Type): STRING;
+    RETURN "null"
 END Procedure.initializer;
 END Procedure.initializer;
 
 
-PROCEDURE Procedure.description(): JsString.Type;
+PROCEDURE Procedure.description(): STRING;
     RETURN SELF.name
     RETURN SELF.name
 END Procedure.description;
 END Procedure.description;
 
 
-PROCEDURE ProcedureArgument.description(): JsString.Type;
+PROCEDURE ProcedureArgument.description(): STRING;
 VAR
 VAR
-    result: JsString.Type;
+    result: STRING;
 BEGIN
 BEGIN
     IF SELF.isVar THEN
     IF SELF.isVar THEN
-        result := JsString.make("VAR ");
-    ELSE
-        result := JsString.makeEmpty();
+        result := "VAR ";
     END;
     END;
-    RETURN JsString.concat(result, SELF.type.description())
+    RETURN result + SELF.type.description()
 END ProcedureArgument.description;
 END ProcedureArgument.description;
 
 
 PROCEDURE makeProcedureArgument*(type: PType; isVar: BOOLEAN): PProcedureArgument;
 PROCEDURE makeProcedureArgument*(type: PType; isVar: BOOLEAN): PProcedureArgument;
@@ -570,8 +529,8 @@ BEGIN
     RETURN result
     RETURN result
 END makeProcedureArgument;
 END makeProcedureArgument;
 
 
-PROCEDURE Module.idType(): JsString.Type;
-    RETURN JsString.make("MODULE")
+PROCEDURE Module.idType(): STRING;
+    RETURN "MODULE"
 END Module.idType;
 END Module.idType;
 
 
 PROCEDURE makeTypeId*(type: PType): PTypeId;
 PROCEDURE makeTypeId*(type: PType): PTypeId;
@@ -591,7 +550,7 @@ BEGIN
     RETURN result
     RETURN result
 END makeLazyTypeId;
 END makeLazyTypeId;
 
 
-PROCEDURE makeString*(s: JsString.Type): PString;
+PROCEDURE makeString*(s: STRING): PString;
 VAR
 VAR
     result: PString;
     result: PString;
 BEGIN
 BEGIN
@@ -601,8 +560,8 @@ BEGIN
 END makeString;
 END makeString;
 
 
 PROCEDURE makeArray*(
 PROCEDURE makeArray*(
-    name: JsString.Type;
-    initializer: JsString.Type;
+    name: STRING;
+    initializer: STRING;
     elementsType: PType;
     elementsType: PType;
     len: INTEGER (* see openArrayLength *)
     len: INTEGER (* see openArrayLength *)
     ): PArray;
     ): PArray;
@@ -617,7 +576,7 @@ BEGIN
     RETURN result
     RETURN result
 END makeArray;
 END makeArray;
 
 
-PROCEDURE makePointer*(name: JsString.Type; base: PTypeId): PPointer;
+PROCEDURE makePointer*(name: STRING; base: PTypeId): PPointer;
 VAR
 VAR
     result: PPointer;
     result: PPointer;
 BEGIN
 BEGIN
@@ -627,7 +586,7 @@ BEGIN
     RETURN result
     RETURN result
 END makePointer;
 END makePointer;
 
 
-PROCEDURE makeRecord*(name: JsString.Type; cons: JsString.Type; scope: ScopeBase.PType): PRecord;
+PROCEDURE makeRecord*(name: STRING; cons: STRING; scope: ScopeBase.PType): PRecord;
 VAR
 VAR
     result: PRecord;
     result: PRecord;
 BEGIN
 BEGIN
@@ -702,12 +661,12 @@ BEGIN
     RETURN result
     RETURN result
 END makeProcedure;
 END makeProcedure;
 
 
-PROCEDURE initProcedure*(p: Procedure; name: JsString.Type);
+PROCEDURE initProcedure*(p: Procedure; name: STRING);
 BEGIN
 BEGIN
     p.name := name;
     p.name := name;
 END initProcedure;
 END initProcedure;
 
 
-PROCEDURE initModule*(m: Module; name: JsString.Type);
+PROCEDURE initModule*(m: Module; name: STRING);
 BEGIN
 BEGIN
     m.name := name;
     m.name := name;
 END initModule;
 END initModule;

+ 2 - 0
test/test_unit_eberon.js

@@ -199,6 +199,8 @@ exports.suite = {
     context(grammar.expression,
     context(grammar.expression,
             "VAR s1, s2: STRING; a: ARRAY 10 OF CHAR;"),
             "VAR s1, s2: STRING; a: ARRAY 10 OF CHAR;"),
     pass("s1 + s2",
     pass("s1 + s2",
+         "s1 + \"abc\"",
+         "\"abc\" + s1",
          "s1 = s2",
          "s1 = s2",
          "s1 # s2",
          "s1 # s2",
          "s1 < s2",
          "s1 < s2",