Browse Source

localize compiler messages

Ivan Denisov 4 years ago
parent
commit
8cb0a1c138

BIN
bin/compiled.zip


+ 5 - 3
src/ob/Code.ob

@@ -13,7 +13,9 @@ IMPORT
     Record,
     Record,
     String,
     String,
     TypeId, 
     TypeId, 
-    Types;
+    Types,
+    Format,
+    Message;
 
 
 TYPE
 TYPE
     StringsMap = MAP OF STRING;
     StringsMap = MAP OF STRING;
@@ -141,8 +143,8 @@ END;
 PROCEDURE checkIndex*(i: INTEGER);
 PROCEDURE checkIndex*(i: INTEGER);
 BEGIN
 BEGIN
     IF i < 0 THEN
     IF i < 0 THEN
-        Errors.raise("index is negative: " + String.fromInt(i));
+        Errors.raise(Format.format1(Message.negativeIndex, String.fromInt(i)));
     END;
     END;
 END checkIndex;
 END checkIndex;
 
 
-END Code.
+END Code.

+ 3 - 3
src/ob/ContextAssignment.ob

@@ -1,6 +1,6 @@
 MODULE ContextAssignment;
 MODULE ContextAssignment;
 IMPORT
 IMPORT
-    Chars, ContextHierarchy, Errors;
+    Chars, ContextHierarchy, Errors, Message;
 TYPE
 TYPE
     Check* = RECORD(ContextHierarchy.Node)
     Check* = RECORD(ContextHierarchy.Node)
     END;
     END;
@@ -8,7 +8,7 @@ TYPE
 PROCEDURE Check.handleLiteral(s: STRING);
 PROCEDURE Check.handleLiteral(s: STRING);
 BEGIN
 BEGIN
     IF s = "=" THEN
     IF s = "=" THEN
-        Errors.raise("did you mean ':=' (statement expected, got expression)?");
+        Errors.raise(Message.didYouMeanAssign);
     END;
     END;
 END;
 END;
 
 
@@ -17,4 +17,4 @@ BEGIN
     cx.codeGenerator().write(";" + Chars.ln);
     cx.codeGenerator().write(";" + Chars.ln);
 END;
 END;
 
 
-END ContextAssignment.
+END ContextAssignment.

+ 11 - 12
src/ob/ContextCase.ob

@@ -2,7 +2,8 @@ MODULE ContextCase;
 IMPORT
 IMPORT
     Cast, Chars, CodeGenerator, ConstValue, ContextExpression, ContextHierarchy,
     Cast, Chars, CodeGenerator, ConstValue, ContextExpression, ContextHierarchy,
     Designator, Errors, Expression, ExpressionTree,
     Designator, Errors, Expression, ExpressionTree,
-    Record, Scope, String, Symbols, TypeId, Types, Variable;
+    Record, Scope, String, Symbols, TypeId, Types, Variable,
+    Format, Message;
 TYPE
 TYPE
     Type* = RECORD(ContextExpression.ExpressionHandler)
     Type* = RECORD(ContextExpression.ExpressionHandler)
         PROCEDURE Type(parent: ContextHierarchy.PNode);
         PROCEDURE Type(parent: ContextHierarchy.PNode);
@@ -77,15 +78,14 @@ BEGIN
         IF (type IS Types.PRecord) OR (type IS Record.PPointer) THEN
         IF (type IS Types.PRecord) OR (type IS Record.PPointer) THEN
             isReference <- (info IS Types.PVariable) & info.isReference();
             isReference <- (info IS Types.PVariable) & info.isReference();
             IF (type IS Types.PRecord) & ~isReference THEN
             IF (type IS Types.PRecord) & ~isReference THEN
-                Errors.raise("only records passed as VAR argument can be used to test type in CASE");
+                Errors.raise(Message.onlyRecordsForCase);
             ELSIF ~(type IS Record.PPointer) OR ~isReference THEN
             ELSIF ~(type IS Record.PPointer) OR ~isReference THEN
                 SELF.guardVar := declVar;
                 SELF.guardVar := declVar;
             END;
             END;
 
 
             SELF.typeTest := e;
             SELF.typeTest := e;
         ELSIF ~Types.isInt(type) & (type # Types.basic.ch) THEN
         ELSIF ~Types.isInt(type) & (type # Types.basic.ch) THEN
-            Errors.raise("'RECORD' or 'POINTER' or "
-                         + Types.intsDescription() + " or 'CHAR' expected as CASE expression");
+            Errors.raise(Format.format1(Message.caseExpectations, Types.intsDescription()));
         END;
         END;
     END;
     END;
 
 
@@ -114,8 +114,7 @@ END;
 PROCEDURE Type.handleLabelType(type: Types.PType);
 PROCEDURE Type.handleLabelType(type: Types.PType);
 BEGIN
 BEGIN
     IF ~Cast.areTypesMatch(type, SELF.type) THEN
     IF ~Cast.areTypesMatch(type, SELF.type) THEN
-        Errors.raise("label must be '" + SELF.type.description() + "' (the same as case expression), got '"
-                     + type.description() + "'");
+        Errors.raise(Format.format2(Message.caseHandleLabelType, SELF.type.description(), type.description()));                    
     END;
     END;
 END;
 END;
 
 
@@ -215,13 +214,13 @@ VAR
     c: CHAR;
     c: CHAR;
 BEGIN
 BEGIN
     IF caseContext(SELF).typeTest # NIL THEN
     IF caseContext(SELF).typeTest # NIL THEN
-        Errors.raise("type's name expected in label, got expression: " + e.code());
+        Errors.raise(Format.format1(Message.typeNameExpectedInLabel, e.code()));
     END;
     END;
 
 
     type <- e.type();
     type <- e.type();
     IF type IS Types.PString THEN
     IF type IS Types.PString THEN
         IF ~Types.stringAsChar(type^, c) THEN
         IF ~Types.stringAsChar(type^, c) THEN
-            Errors.raise("single-character string expected");
+            Errors.raise(Message.singleCharStringExpected);
         END;
         END;
         handleLabel(SELF, Types.basic.ch, NEW ConstValue.Int(ORD(c)));
         handleLabel(SELF, Types.basic.ch, NEW ConstValue.Int(ORD(c)));
     ELSE
     ELSE
@@ -232,7 +231,7 @@ END;
 PROCEDURE Range.handleQIdent(q: ContextHierarchy.QIdent);
 PROCEDURE Range.handleQIdent(q: ContextHierarchy.QIdent);
 BEGIN
 BEGIN
     IF SELF.typeGuardHandled THEN
     IF SELF.typeGuardHandled THEN
-        Errors.raise("cannot use diapason (..) with type guard");
+        Errors.raise(Message.canNotUseDiapason);
     END;
     END;
 
 
     found <- ContextHierarchy.getQIdSymbolAndScope(SELF.root()^, q);
     found <- ContextHierarchy.getQIdSymbolAndScope(SELF.root()^, q);
@@ -243,10 +242,10 @@ BEGIN
             labelContext(SELF).handleTypeGuard(typeTest, info);
             labelContext(SELF).handleTypeGuard(typeTest, info);
             SELF.typeGuardHandled := TRUE;
             SELF.typeGuardHandled := TRUE;
         ELSE
         ELSE
-            Errors.raise("'" + q.code + "' is not a type");
+            Errors.raise(Format.format1(Message.isNotAType, q.code));
         END;
         END;
     ELSIF ~(info IS Types.PConst) THEN
     ELSIF ~(info IS Types.PConst) THEN
-        Errors.raise("'" + q.code + "' is not a constant");
+        Errors.raise(Format.format1(Message.isNotAConstant, q.code));
     ELSE
     ELSE
         type <- info.type;
         type <- info.type;
         IF type IS Types.PString THEN
         IF type IS Types.PString THEN
@@ -286,4 +285,4 @@ PROCEDURE GuardedVariable.id(): STRING;
     RETURN SELF.caseVariable.id();
     RETURN SELF.caseVariable.id();
 END;
 END;
 
 
-END ContextCase.
+END ContextCase.

+ 3 - 3
src/ob/ContextConst.ob

@@ -1,7 +1,7 @@
 MODULE ContextConst;
 MODULE ContextConst;
 IMPORT
 IMPORT
     Chars, ConstValue, Context, ContextExpression, 
     Chars, ConstValue, Context, ContextExpression, 
-    Errors, Expression, Symbols, Types;
+    Errors, Expression, Symbols, Types, Message;
 TYPE
 TYPE
     Type* = RECORD(ContextExpression.ExpressionHandler)
     Type* = RECORD(ContextExpression.ExpressionHandler)
         PROCEDURE handleIdentdef*(id: Context.PIdentdefInfo);
         PROCEDURE handleIdentdef*(id: Context.PIdentdefInfo);
@@ -21,7 +21,7 @@ PROCEDURE Type.handleExpression(e: Expression.PType);
 BEGIN
 BEGIN
     value <- e.constValue();
     value <- e.constValue();
     IF value = NIL THEN
     IF value = NIL THEN
-        Errors.raise("constant expression expected");
+        Errors.raise(Message.constExpressionExpected);
     END;
     END;
     SELF.type := e.type();
     SELF.type := e.type();
     SELF.value := value;
     SELF.value := value;
@@ -35,4 +35,4 @@ BEGIN
     RETURN TRUE;
     RETURN TRUE;
 END;
 END;
 
 
-END ContextConst.
+END ContextConst.

+ 9 - 13
src/ob/ContextDesignator.ob

@@ -2,7 +2,7 @@ MODULE ContextDesignator;
 IMPORT
 IMPORT
     Code, ConstValue, ContextExpression, ContextHierarchy, 
     Code, ConstValue, ContextExpression, ContextHierarchy, 
     Designator, Errors, Expression, ExpressionTree,
     Designator, Errors, Expression, ExpressionTree,
-    Record, String, TypeId, Types, Variable;
+    Record, String, TypeId, Types, Variable, Format, Message;
 TYPE
 TYPE
     Index* = RECORD
     Index* = RECORD
         PROCEDURE Index*(length: INTEGER; type: Types.PType; info: Types.PId; code, asProperty: STRING);
         PROCEDURE Index*(length: INTEGER; type: Types.PType; info: Types.PId; code, asProperty: STRING);
@@ -97,7 +97,7 @@ BEGIN
     IF info IS Types.PVariable THEN
     IF info IS Types.PVariable THEN
         ExpressionTree.checkTypeCast(info, SELF.currentType, type, "type cast");
         ExpressionTree.checkTypeCast(info, SELF.currentType, type, "type cast");
     ELSE
     ELSE
-        Errors.raise("cannot apply type cast to " + info.idType());
+        Errors.raise(Format.format1(Message.canNotApplyTypecast, info.idType()));
     END;
     END;
 
 
     code <- SELF.root().language().rtl.typeGuard(SELF.code, ExpressionTree.castCode(type, SELF));
     code <- SELF.root().language().rtl.typeGuard(SELF.code, ExpressionTree.castCode(type, SELF));
@@ -121,7 +121,7 @@ BEGIN
     IF t IS Record.PPointer THEN
     IF t IS Record.PPointer THEN
         base <- Record.pointerBase(t^);
         base <- Record.pointerBase(t^);
         IF base.finalizedAsNonExported THEN
         IF base.finalizedAsNonExported THEN
-            Errors.raise("POINTER TO non-exported RECORD type cannot be dereferenced");
+            Errors.raise(Message.pointerCantBeDereferenced);
         END;
         END;
         designator.currentType := base;
         designator.currentType := base;
 
 
@@ -130,8 +130,7 @@ BEGIN
             designator.code := Expression.derefCode(designator.code);
             designator.code := Expression.derefCode(designator.code);
         END;
         END;
     ELSE
     ELSE
-        Errors.raise("POINTER TO type expected, got '"
-                     + designator.currentType.description() + "'");
+        Errors.raise(Format.format1(Message.pointerTypeExpected, designator.currentType.description()));
     END;
     END;
 END;
 END;
 
 
@@ -194,8 +193,7 @@ END;
 PROCEDURE Type.doCheckIndexType(type: Types.PType);
 PROCEDURE Type.doCheckIndexType(type: Types.PType);
 BEGIN
 BEGIN
     IF ~Types.isInt(type) THEN
     IF ~Types.isInt(type) THEN
-        Errors.raise(Types.intsDescription() + " expression expected, got '" 
-                     + type.description() + "'");
+        Errors.raise(Format.format2(Message.expressionExpected, Types.intsDescription(), type.description()));
     END;
     END;
 END;
 END;
 
 
@@ -208,9 +206,7 @@ BEGIN
         length <- index.length;
         length <- index.length;
         IF (((SELF.currentType IS Types.PStaticArray) OR (SELF.currentType IS Types.PString))
         IF (((SELF.currentType IS Types.PStaticArray) OR (SELF.currentType IS Types.PString))
           & (value >= length)) THEN
           & (value >= length)) THEN
-            Errors.raise("index out of bounds: maximum possible index is "
-                         + String.fromInt(length - 1)
-                         + ", got " + String.fromInt(value));
+            Errors.raise(Format.format2(Message.indexOutOfBonds, String.fromInt(length - 1), String.fromInt(value)));
         END;
         END;
     END;
     END;
 END;
 END;
@@ -226,7 +222,7 @@ BEGIN
     ELSIF type IS Types.PString THEN
     ELSIF type IS Types.PString THEN
         indexType := Types.basic.ch;
         indexType := Types.basic.ch;
     ELSE
     ELSE
-        Errors.raise("ARRAY or string expected, got '" + type.description() + "'");
+        Errors.raise(Format.format1(Message.arrayOrStringExpected, type.description()));
     END;
     END;
 
 
     IF type IS Types.PStaticArray THEN
     IF type IS Types.PStaticArray THEN
@@ -234,7 +230,7 @@ BEGIN
     ELSIF type IS Types.PString THEN
     ELSIF type IS Types.PString THEN
         length := Types.stringLen(type^);
         length := Types.stringLen(type^);
         IF length = 0 THEN
         IF length = 0 THEN
-            Errors.raise("cannot index empty string" );
+            Errors.raise(Message.cantIndexEmptString);
         END;
         END;
     END;
     END;
 
 
@@ -299,4 +295,4 @@ BEGIN
     RETURN TRUE;
     RETURN TRUE;
 END;
 END;
 
 
-END ContextDesignator.
+END ContextDesignator.

+ 3 - 3
src/ob/ContextExpression.ob

@@ -2,7 +2,7 @@ MODULE ContextExpression;
 IMPORT 
 IMPORT 
     Chars, CodeGenerator, ConstValue, ContextHierarchy, 
     Chars, CodeGenerator, ConstValue, ContextHierarchy, 
     Designator, Errors, Expression, ExpressionTree, 
     Designator, Errors, Expression, ExpressionTree, 
-    Scope, String, Types;
+    Scope, String, Types, Format, Message;
 TYPE
 TYPE
     ExpressionHandler* = RECORD(ContextHierarchy.Node)
     ExpressionHandler* = RECORD(ContextHierarchy.Node)
         PROCEDURE handleExpression*(e: Expression.PType);
         PROCEDURE handleExpression*(e: Expression.PType);
@@ -335,7 +335,7 @@ BEGIN
 
 
     IF info IS Types.PProcedureId THEN
     IF info IS Types.PProcedureId THEN
         IF ~info.canBeReferenced() THEN
         IF ~info.canBeReferenced() THEN
-            Errors.raise(info.idType() + " cannot be referenced");
+            Errors.raise(Format.format1(Message.cantBeReferenced, info.idType()));
         END;
         END;
     ELSIF info IS Types.PConst THEN
     ELSIF info IS Types.PConst THEN
         value := info.value;
         value := info.value;
@@ -345,4 +345,4 @@ END;
 
 
 BEGIN
 BEGIN
     NEW(globalOps);
     NEW(globalOps);
-END ContextExpression.
+END ContextExpression.

+ 4 - 4
src/ob/ContextHierarchy.ob

@@ -1,7 +1,7 @@
 MODULE ContextHierarchy;
 MODULE ContextHierarchy;
 IMPORT 
 IMPORT 
     CodeGenerator, Context, Designator, Errors, LanguageContext, Module, 
     CodeGenerator, Context, Designator, Errors, LanguageContext, Module, 
-    OberonRtl, Object, Scope, ScopeBase, Symbols, String, Types;
+    OberonRtl, Object, Scope, ScopeBase, Symbols, String, Types, Format, LocMessage:=Message;
 TYPE
 TYPE
     PRoot* = POINTER TO Root;
     PRoot* = POINTER TO Root;
     PNode* = POINTER TO Node;
     PNode* = POINTER TO Node;
@@ -172,7 +172,7 @@ PROCEDURE getSymbolAndScope*(cx: Root; id: STRING): Symbols.PFoundSymbol;
 BEGIN
 BEGIN
     s <- cx.findSymbol(id);
     s <- cx.findSymbol(id);
     IF s = NIL THEN
     IF s = NIL THEN
-        Errors.raise("undeclared identifier: '" + id + "'");
+        Errors.raise(Format.format1(LocMessage.undeclaredId, id));
     END;
     END;
     RETURN s;
     RETURN s;
 END;
 END;
@@ -181,7 +181,7 @@ PROCEDURE getModuleSymbolAndScope*(m: Module.Type; id: STRING): Symbols.PFoundSy
 BEGIN
 BEGIN
     s <- m.findSymbol(id);
     s <- m.findSymbol(id);
     IF s = NIL THEN
     IF s = NIL THEN
-        Errors.raise("identifier '" + id + "' is not exported by module '" + m.name + "'");
+        Errors.raise(Format.format2(LocMessage.idIsNotExported, id, m.name));
     END;
     END;
     RETURN s;
     RETURN s;
 END;
 END;
@@ -206,4 +206,4 @@ PROCEDURE makeLanguageContext*(cx: PNode): LanguageContext.PType;
     RETURN NEW LanguageContext.Type(cx.root().language(), cx);
     RETURN NEW LanguageContext.Type(cx.root().language(), cx);
 END;
 END;
 
 
-END ContextHierarchy.
+END ContextHierarchy.

+ 3 - 3
src/ob/ContextIf.ob

@@ -1,6 +1,6 @@
 MODULE ContextIf;
 MODULE ContextIf;
 IMPORT
 IMPORT
-    ContextExpression, ContextHierarchy, Errors, Expression, Types;
+    ContextExpression, ContextHierarchy, Errors, Expression, Types, Message, Format;
 TYPE
 TYPE
     Type* = RECORD(ContextExpression.ExpressionHandler)
     Type* = RECORD(ContextExpression.ExpressionHandler)
         PROCEDURE Type*(parent: ContextHierarchy.PNode);
         PROCEDURE Type*(parent: ContextHierarchy.PNode);
@@ -10,7 +10,7 @@ PROCEDURE handleIfExpression*(e: Expression.PType);
 BEGIN
 BEGIN
     type <- e.type();
     type <- e.type();
     IF type # Types.basic.bool THEN
     IF type # Types.basic.bool THEN
-        Errors.raise("'BOOLEAN' expression expected, got '" + type.description() + "'");
+        Errors.raise(Format.format1(Message.boolExpressionExpected, type.description()));
     END;
     END;
 END;
 END;
 
 
@@ -47,4 +47,4 @@ BEGIN
     RETURN TRUE;
     RETURN TRUE;
 END;
 END;
 
 
-END ContextIf.
+END ContextIf.

+ 8 - 13
src/ob/ContextLoop.ob

@@ -1,7 +1,7 @@
 MODULE ContextLoop;
 MODULE ContextLoop;
 IMPORT
 IMPORT
     Chars, CodeGenerator, ConstValue, Context, ContextExpression, ContextIf, ContextHierarchy, 
     Chars, CodeGenerator, ConstValue, Context, ContextExpression, ContextIf, ContextHierarchy, 
-    Errors, Expression, Operator, String, Types;
+    Errors, Expression, Operator, String, Types, Format, Message;
 TYPE
 TYPE
     While* = RECORD(ContextExpression.ExpressionHandler)
     While* = RECORD(ContextExpression.ExpressionHandler)
         PROCEDURE While*(parent: ContextHierarchy.PNode);
         PROCEDURE While*(parent: ContextHierarchy.PNode);
@@ -110,12 +110,11 @@ BEGIN
     s <- ContextHierarchy.getSymbol(SELF.root()^, id);
     s <- ContextHierarchy.getSymbol(SELF.root()^, id);
     info <- s.info();
     info <- s.info();
     IF ~(info IS Types.PVariable) THEN
     IF ~(info IS Types.PVariable) THEN
-        Errors.raise("'" + s.id() + "' is not a variable");
+        Errors.raise(Format.format1(Message.isNotAVar, s.id()));
     ELSE
     ELSE
         type <- info.type();
         type <- info.type();
         IF type # Types.basic.integer THEN
         IF type # Types.basic.integer THEN
-            Errors.raise("'" + s.id() + "' is a '" + type.description() 
-                         + "' variable, 'FOR' control variable must be 'INTEGER'");
+            Errors.raise(Format.format2(Message.varMustBeInteger, s.id(), type.description()));
         END;
         END;
         SELF.doHandleInitCode(id, "for (" + id + " = ");
         SELF.doHandleInitCode(id, "for (" + id + " = ");
     END;
     END;
@@ -130,9 +129,7 @@ END;
 PROCEDURE For.doHandleInitExpression(type: Types.PType);
 PROCEDURE For.doHandleInitExpression(type: Types.PType);
 BEGIN
 BEGIN
     IF type # Types.basic.integer THEN
     IF type # Types.basic.integer THEN
-        Errors.raise(
-            "'INTEGER' expression expected to assign '" + SELF.var
-            + "', got '" + type.description() + "'");
+        Errors.raise(Format.format2(Message.intExpect, SELF.var, type.description()));
     END;
     END;
     SELF.initExprParsed := TRUE;
     SELF.initExprParsed := TRUE;
 END;
 END;
@@ -144,18 +141,16 @@ BEGIN
         SELF.doHandleInitExpression(type);
         SELF.doHandleInitExpression(type);
     ELSIF ~SELF.toParsed THEN
     ELSIF ~SELF.toParsed THEN
         IF type # Types.basic.integer THEN
         IF type # Types.basic.integer THEN
-            Errors.raise("'INTEGER' expression expected as 'TO' parameter, got '" 
-                         + type.description() + "'");
+            Errors.raise(Format.format1(Message.intExpectedAsTo, type.description()));
         END;
         END;
         SELF.toParsed := TRUE;
         SELF.toParsed := TRUE;
     ELSE
     ELSE
         IF type # Types.basic.integer THEN
         IF type # Types.basic.integer THEN
-            Errors.raise("'INTEGER' expression expected as 'BY' parameter, got '" 
-                         + type.description() + "'");
+            Errors.raise(Format.format1(Message.intExpectedAsBy, type.description()));
         END;
         END;
         value <- e.constValue();
         value <- e.constValue();
         IF value = NIL THEN
         IF value = NIL THEN
-            Errors.raise("constant expression expected as 'BY' parameter");
+            Errors.raise(Message.constExpectedAsBy);
         END;
         END;
         SELF.by := value(ConstValue.PInt).value;
         SELF.by := value(ConstValue.PInt).value;
     END;
     END;
@@ -209,4 +204,4 @@ BEGIN
     gen.openScope();
     gen.openScope();
 END;
 END;
 
 
-END ContextLoop.
+END ContextLoop.

+ 10 - 8
src/ob/ContextModule.ob

@@ -1,7 +1,7 @@
 MODULE ContextModule;
 MODULE ContextModule;
 IMPORT
 IMPORT
     CodeGenerator, ContextHierarchy, ContextType, Errors, LanguageContext, 
     CodeGenerator, ContextHierarchy, ContextType, Errors, LanguageContext, 
-    Object, Scope, ScopeBase, String, Symbols, Types;
+    Object, Scope, ScopeBase, String, Symbols, Types, Format, Message;
 TYPE
 TYPE
     Declaration* = RECORD(ContextHierarchy.Node)
     Declaration* = RECORD(ContextHierarchy.Node)
         PROCEDURE findModule(name: STRING): Types.PModule;
         PROCEDURE findModule(name: STRING): Types.PModule;
@@ -33,14 +33,14 @@ BEGIN
         Scope.defineExports(scope^);
         Scope.defineExports(scope^);
         SELF.codeGenerator().write(SELF.moduleGen.epilog(scope.exports));
         SELF.codeGenerator().write(SELF.moduleGen.epilog(scope.exports));
     ELSE
     ELSE
-        Errors.raise("original module name '" + SELF.name + "' expected, got '" + id + "'" );
+        Errors.raise(Format.format2(Message.moduleName, SELF.name, id));
     END;
     END;
 END;
 END;
 
 
 PROCEDURE Declaration.findModule(name: STRING): Types.PModule;
 PROCEDURE Declaration.findModule(name: STRING): Types.PModule;
 BEGIN
 BEGIN
     IF name = SELF.name THEN
     IF name = SELF.name THEN
-        Errors.raise("module '" + SELF.name + "' cannot import itself");
+        Errors.raise(Format.format1(Message.moduleCantImportItself, SELF.name));
     END;
     END;
     RETURN SELF.root().findModule(name);
     RETURN SELF.root().findModule(name);
 END;
 END;
@@ -109,9 +109,9 @@ BEGIN
     
     
     FOR a, m IN import.import DO
     FOR a, m IN import.import DO
         IF a = alias THEN
         IF a = alias THEN
-            Errors.raise("duplicated alias: '" + alias +"'");
+            Errors.raise(Format.format1(Message.duplicateAlias, alias));
         ELSIF m = import.currentModule THEN
         ELSIF m = import.currentModule THEN
-            Errors.raise("module already imported: '" + import.currentModule + "'");
+            Errors.raise(Format.format1(Message.moduleAlreadyImported, import.currentModule));
         END;
         END;
     END;
     END;
     import.import[alias] := import.currentModule;
     import.import[alias] := import.currentModule;
@@ -144,12 +144,14 @@ BEGIN
             modules.add(NEW Symbols.Symbol(alias, module));
             modules.add(NEW Symbols.Symbol(alias, module));
         END;
         END;
     END;
     END;
-    IF LEN(unresolved) # 0 THEN
-        Errors.raise("module(s) not found: " + String.join(unresolved, ", "));
+    IF LEN(unresolved) = 1 THEN
+        Errors.raise(Format.format1(Message.moduleNotFound1, String.join(unresolved, ", ")));
+    ELSIF LEN(unresolved) > 1 THEN
+        Errors.raise(Format.format1(Message.moduleNotFound2, String.join(unresolved, ", ")));
     END;
     END;
     
     
     parent.handleImport(modules);
     parent.handleImport(modules);
     RETURN TRUE;
     RETURN TRUE;
 END;
 END;
 
 
-END ContextModule.
+END ContextModule.

+ 9 - 13
src/ob/ContextProcedure.ob

@@ -3,7 +3,7 @@ IMPORT
     Cast, Chars, CodeGenerator, Context, ContextExpression, 
     Cast, Chars, CodeGenerator, Context, ContextExpression, 
     ContextHierarchy, ContextType, 
     ContextHierarchy, ContextType, 
     Errors, Expression, ExpressionTree, LanguageContext,
     Errors, Expression, ExpressionTree, LanguageContext,
-    Object, Procedure, Scope, Symbols, TypeId, Types, Variable;
+    Object, Procedure, Scope, Symbols, TypeId, Types, Variable, Format, Message;
 TYPE
 TYPE
     Declaration* = RECORD(ContextType.DeclarationAndIdentHandle)
     Declaration* = RECORD(ContextType.DeclarationAndIdentHandle)
         PROCEDURE Declaration*(parent: ContextHierarchy.PNode);
         PROCEDURE Declaration*(parent: ContextHierarchy.PNode);
@@ -82,8 +82,7 @@ PROCEDURE Declaration.handleIdent(id: STRING);
 BEGIN
 BEGIN
     expectId <- SELF.id.id();
     expectId <- SELF.id.id();
     IF expectId # id THEN
     IF expectId # id THEN
-        Errors.raise("mismatched procedure names: '" + expectId
-                     + "' at the begining and '" + id + "' at the end");
+        Errors.raise(Format.format2(Message.mismatchedProcName, expectId, id));
     END;
     END;
 END;
 END;
 
 
@@ -119,7 +118,7 @@ END;
 PROCEDURE addArgument(VAR declaration: Declaration; name: STRING; arg: Types.ProcedureArgument);
 PROCEDURE addArgument(VAR declaration: Declaration; name: STRING; arg: Types.ProcedureArgument);
 BEGIN
 BEGIN
     IF name = declaration.id.id() THEN
     IF name = declaration.id.id() THEN
-        Errors.raise("argument '" + name + "' has the same name as procedure");
+        Errors.raise(Format.format1(Message.argSameAsName, name));
     END;
     END;
     v <- declaration.doMakeArgumentVariable(arg, name);
     v <- declaration.doMakeArgumentVariable(arg, name);
     s <- NEW Symbols.Symbol(name, v);
     s <- NEW Symbols.Symbol(name, v);
@@ -166,14 +165,12 @@ BEGIN
     type <- e.type();
     type <- e.type();
     result <- SELF.type.result();
     result <- SELF.type.result();
     IF result = NIL THEN
     IF result = NIL THEN
-        Errors.raise("unexpected RETURN in PROCEDURE declared with no result type");
+        Errors.raise(Message.unexpectedReturn);
     END;
     END;
     
     
     language <- SELF.root().language();
     language <- SELF.root().language();
     IF language.types.implicitCast(type, result, FALSE, op) # Cast.errNo THEN
     IF language.types.implicitCast(type, result, FALSE, op) # Cast.errNo THEN
-        Errors.raise(
-            "RETURN '" + result.description() + "' expected, got '"
-            + type.description() + "'");
+        Errors.raise(Format.format2(Message.returnTypeMismatch, result.description(), type.description()));
     END;
     END;
 
 
     SELF.codeGenerator().write("return " + SELF.doMakeReturnCode(e, op^) + ";" + Chars.ln);
     SELF.codeGenerator().write("return " + SELF.doMakeReturnCode(e, op^) + ";" + Chars.ln);
@@ -188,8 +185,7 @@ BEGIN
 
 
     result <- SELF.type.result();
     result <- SELF.type.result();
     IF (result # NIL) & ~SELF.returnParsed THEN
     IF (result # NIL) & ~SELF.returnParsed THEN
-        Errors.raise("RETURN expected at the end of PROCEDURE declared with '"
-                     + result.description() + "' result type");
+        Errors.raise(Format.format1(Message.returnExpectedAtEnd, result.description()));
     END;
     END;
     RETURN TRUE;
     RETURN TRUE;
 END;
 END;
@@ -224,7 +220,7 @@ END;
 PROCEDURE FormalParameters.doCheckResultType(type: Types.PStorageType);
 PROCEDURE FormalParameters.doCheckResultType(type: Types.PStorageType);
 BEGIN
 BEGIN
     IF ~type.isScalar() THEN
     IF ~type.isScalar() THEN
-        Errors.raise("procedure cannot return " + type.description());
+        Errors.raise(Format.format1(Message.procedureCantReturn, type.description()));
     END;
     END;
 END;
 END;
 
 
@@ -311,7 +307,7 @@ BEGIN
     END;
     END;
     
     
     IF result = NIL THEN
     IF result = NIL THEN
-        Errors.raise("PROCEDURE expected, got '" + unexpected + "'");
+        Errors.raise(Format.format1(Message.procedureExpected, unexpected));
     END;
     END;
     
     
     RETURN result;
     RETURN result;
@@ -324,4 +320,4 @@ BEGIN
                             : assertProcType(type, info).callGenerator(l);
                             : assertProcType(type, info).callGenerator(l);
 END;
 END;
 
 
-END ContextProcedure.
+END ContextProcedure.

+ 11 - 17
src/ob/ContextType.ob

@@ -2,7 +2,7 @@ MODULE ContextType;
 IMPORT
 IMPORT
     Chars, CodeGenerator, ConstValue, Context, ContextExpression, ContextHierarchy, 
     Chars, CodeGenerator, ConstValue, Context, ContextExpression, ContextHierarchy, 
     Errors, Expression, ExpressionTree, Object, R := Record, 
     Errors, Expression, ExpressionTree, Object, R := Record, 
-    Scope, ScopeBase, String, Symbols, TypeId, Types;
+    Scope, ScopeBase, String, Symbols, TypeId, Types, Format, Message;
 TYPE
 TYPE
     HandleSymbolAsType* = RECORD(ContextHierarchy.Node)
     HandleSymbolAsType* = RECORD(ContextHierarchy.Node)
         PROCEDURE handleQIdent*(q: ContextHierarchy.QIdent);
         PROCEDURE handleQIdent*(q: ContextHierarchy.QIdent);
@@ -199,15 +199,15 @@ PROCEDURE ArrayDimensions.handleExpression(e: Expression.PType);
 BEGIN
 BEGIN
     type <- e.type();
     type <- e.type();
     IF type # Types.basic.integer THEN
     IF type # Types.basic.integer THEN
-        Errors.raise("'INTEGER' constant expression expected, got '" + type.description() + "'");
+        Errors.raise(Format.format1(Message.intContExprExpected, type.description()));
     END;
     END;
     value <- e.constValue();
     value <- e.constValue();
     IF value = NIL THEN
     IF value = NIL THEN
-        Errors.raise("constant expression expected as ARRAY size");
+        Errors.raise(Message.constExprExpected);
     END;
     END;
     dimension <- value(ConstValue.PInt).value;
     dimension <- value(ConstValue.PInt).value;
     IF dimension <= 0 THEN
     IF dimension <= 0 THEN
-        Errors.raise("array size must be greater than 0, got " + String.fromInt(dimension));
+        Errors.raise(Format.format1(Message.arraySizeMustBeGrater, String.fromInt(dimension)));
     END;
     END;
     SELF.doAddDimension(dimension);
     SELF.doAddDimension(dimension);
 END;
 END;
@@ -258,9 +258,7 @@ PROCEDURE checkIfFieldCanBeExported*(name: STRING; idents: ARRAY OF Context.PIde
 BEGIN
 BEGIN
     FOR id IN idents DO
     FOR id IN idents DO
         IF ~id.exported() THEN
         IF ~id.exported() THEN
-            Errors.raise(
-                "field '" + name + "' can be exported only if " + hint + " '" +
-                id.id() + "' itself is exported too");
+            Errors.raise(Format.format3(Message.fieldExpOnlyIfExported, name, hint, id.id()));
         END;
         END;
     END;
     END;
 END;
 END;
@@ -321,7 +319,7 @@ END;
 PROCEDURE Record.addField(field: Context.PIdentdefInfo; type: Types.PStorageType);
 PROCEDURE Record.addField(field: Context.PIdentdefInfo; type: Types.PStorageType);
 BEGIN
 BEGIN
     IF SELF.root().language().types.isRecursive(type, SELF.type) THEN
     IF SELF.root().language().types.isRecursive(type, SELF.type) THEN
-        Errors.raise("recursive field definition: '" + field.id() + "'");
+        Errors.raise(Format.format1(Message.recursiveFieldDef, field.id()));
     END;
     END;
     SELF.type.addField(SELF.doMakeField(field, type));
     SELF.type.addField(SELF.doMakeField(field, type));
     IF field.exported() THEN
     IF field.exported() THEN
@@ -332,14 +330,10 @@ END;
 PROCEDURE Record.setBaseType(type: Types.PType);
 PROCEDURE Record.setBaseType(type: Types.PType);
 BEGIN
 BEGIN
     IF ~(type IS R.PType) THEN
     IF ~(type IS R.PType) THEN
-        Errors.raise(
-            "RECORD type is expected as a base type, got '"
-            + type.description()
-            + "'");
+        Errors.raise(Format.format1(Message.recTypeExpected, type.description()));
     ELSE
     ELSE
         IF type = SELF.type THEN
         IF type = SELF.type THEN
-            Errors.raise("recursive inheritance: '"
-                         + SELF.type.description() + "'");
+            Errors.raise(Format.format1(Message.recursiveInheritance, SELF.type.description()));
         END;
         END;
 
 
         SELF.type.setBase(type);
         SELF.type.setBase(type);
@@ -475,7 +469,7 @@ BEGIN
             IF type # NIL THEN
             IF type # NIL THEN
                 typeDesc := ", got '" + type.description() + "'";
                 typeDesc := ", got '" + type.description() + "'";
             END;
             END;
-            Errors.raise("RECORD is expected as a POINTER base type" + typeDesc);
+            Errors.raise(Format.format1(Message.recExpectedAsPtrBaseType, typeDesc));
         END;
         END;
     END;
     END;
     
     
@@ -520,7 +514,7 @@ END;
 
 
 PROCEDURE Pointer.exportField(field: STRING);
 PROCEDURE Pointer.exportField(field: STRING);
 BEGIN
 BEGIN
-    Errors.raise("cannot export anonymous RECORD field: '" + field + "'");
+    Errors.raise(Format.format1(Message.cantExportAnonRecField, field));
 END;
 END;
 
 
 PROCEDURE ResolveClosure.ResolveClosure(root: ContextHierarchy.PRoot; id: STRING)
 PROCEDURE ResolveClosure.ResolveClosure(root: ContextHierarchy.PRoot; id: STRING)
@@ -609,4 +603,4 @@ BEGIN
     RETURN result;
     RETURN result;
 END;
 END;
 
 
-END ContextType.
+END ContextType.

+ 3 - 3
src/ob/ContextVar.ob

@@ -1,7 +1,7 @@
 MODULE ContextVar;
 MODULE ContextVar;
 IMPORT
 IMPORT
     Chars, CodeGenerator, Context, ContextHierarchy, ContextType, Errors, 
     Chars, CodeGenerator, Context, ContextHierarchy, ContextType, Errors, 
-    Object, Symbols, Types, Variable;
+    Object, Symbols, Types, Variable, Format, Message;
 TYPE
 TYPE
     Declaration* = RECORD(ContextType.DeclarationAndIdentHandle)
     Declaration* = RECORD(ContextType.DeclarationAndIdentHandle)
         PROCEDURE doInitCode*(): STRING;
         PROCEDURE doInitCode*(): STRING;
@@ -40,7 +40,7 @@ END;
 PROCEDURE Declaration.handleMessage(VAR msg: ContextHierarchy.Message): Object.PType;
 PROCEDURE Declaration.handleMessage(VAR msg: ContextHierarchy.Message): Object.PType;
 BEGIN
 BEGIN
     IF msg IS ContextType.ForwardTypeMsg THEN
     IF msg IS ContextType.ForwardTypeMsg THEN
-        Errors.raise("type '" + msg.id + "' was not declared");
+        Errors.raise(Format.format1(Message.typeWasntDeclared, msg.id));
     END;
     END;
     RETURN SUPER(msg);
     RETURN SUPER(msg);
 END;
 END;
@@ -65,4 +65,4 @@ BEGIN
     RETURN TRUE;
     RETURN TRUE;
 END;
 END;
 
 
-END ContextVar.
+END ContextVar.

+ 16 - 31
src/ob/ExpressionTree.ob

@@ -1,7 +1,7 @@
 MODULE ExpressionTree;
 MODULE ExpressionTree;
 IMPORT
 IMPORT
 	Cast, Context, ContextHierarchy,
 	Cast, Context, ContextHierarchy,
-	JS, 
+	JS, Format, Message,
 	Errors, Expression, LanguageContext, Operator, Record, String, Types, TypeId;
 	Errors, Expression, LanguageContext, Operator, Record, String, Types, TypeId;
 TYPE
 TYPE
     BinaryOperator* = PROCEDURE(l, r: Expression.PType): Expression.PType;
     BinaryOperator* = PROCEDURE(l, r: Expression.PType): Expression.PType;
@@ -120,7 +120,7 @@ VAR
 
 
 PROCEDURE throwTypeNameExpected*();
 PROCEDURE throwTypeNameExpected*();
 BEGIN
 BEGIN
-    Errors.raise("type name expected");
+    Errors.raise(Message.typeNameExpected);
 END;
 END;
 
 
 PROCEDURE castCode*(type: Types.PType; cx: Context.Type): STRING;
 PROCEDURE castCode*(type: Types.PType; cx: Context.Type): STRING;
@@ -161,8 +161,7 @@ VAR
             t := t.base;
             t := t.base;
         END;
         END;
         IF t = NIL THEN
         IF t = NIL THEN
-            Errors.raise(prefix + ": '" + to.description()
-                       + "' is not an extension of '" + from.description() + "'");
+            Errors.raise(Format.format3(Message.isNotAnExtencion, prefix, to.description(), from.description()));
         END;
         END;
     END;
     END;
 
 
@@ -171,24 +170,17 @@ BEGIN
 
 
     pointerExpected <- fromType IS Record.PPointer;
     pointerExpected <- fromType IS Record.PPointer;
     IF ~pointerExpected & ~(fromType IS Record.PType) THEN
     IF ~pointerExpected & ~(fromType IS Record.PType) THEN
-        Errors.raise(
-            prefix + ": POINTER to type or RECORD expected, got '"
-            + fromType.description() + "'");
+        Errors.raise(Format.format2(Message.ptrToTypeExpected, prefix, fromType.description()));
     END;
     END;
 
 
     IF ~pointerExpected THEN
     IF ~pointerExpected THEN
         IF (fromInfo # NIL) & ~fromInfo.isReference() THEN
         IF (fromInfo # NIL) & ~fromInfo.isReference() THEN
-            Errors.raise(
-                prefix + ": a value variable cannot be used");
+            Errors.raise(Format.format1(Message.valueVarCantBeUsed, prefix));
         ELSIF ~(toType IS Record.PType) THEN
         ELSIF ~(toType IS Record.PType) THEN
-            Errors.raise(
-                prefix + ": RECORD type expected as an argument of RECORD " + msg + ", got '"
-              + toType.description() + "'");
+            Errors.raise(Format.format3(Message.recTypeExpectedAsArg, prefix, msg, toType.description()));
         END;
         END;
     ELSIF ~(toType IS Record.PPointer) THEN
     ELSIF ~(toType IS Record.PPointer) THEN
-        Errors.raise(
-            prefix + ": POINTER type expected as an argument of POINTER " + msg + ", got '"
-          + toType.description() + "'");
+        Errors.raise(Format.format3(Message.ptrTypeExpectedAsArg, prefix, msg, toType.description()));
     END;
     END;
 
 
     IF pointerExpected THEN
     IF pointerExpected THEN
@@ -225,16 +217,12 @@ BEGIN
     ELSE
     ELSE
         fromDescription := "no type (proper procedure call)";
         fromDescription := "no type (proper procedure call)";
     END;
     END;
-    Errors.raise("type mismatch: expected '" + to.description() 
-               + "', got " + fromDescription);
+    Errors.raise(Format.format2(Message.typeMismatch, to.description(), fromDescription));
 END;
 END;
 
 
 PROCEDURE throwOperatorTypeMismatch(op, expect: STRING; type: Types.PType);
 PROCEDURE throwOperatorTypeMismatch(op, expect: STRING; type: Types.PType);
 BEGIN
 BEGIN
-    Errors.raise(
-        "operator '" + op +
-        "' type mismatch: " + expect + " expected, got '" +
-        type.description() + "'");
+    Errors.raise(Format.format3(Message.opTypeMismatch, op, expect, type.description()));
 END;
 END;
 
 
 PROCEDURE checkTypeMatch(from, to: Types.PType);
 PROCEDURE checkTypeMatch(from, to: Types.PType);
@@ -298,7 +286,7 @@ PROCEDURE notTypeId(e: Expression.PType);
 BEGIN
 BEGIN
     info <- e.info();
     info <- e.info();
     IF info IS TypeId.PType THEN
     IF info IS TypeId.PType THEN
-        Errors.raise("type name '" + info.type().description() + "' cannot be used as an expression");
+        Errors.raise(Format.format1(Message.typeNameCantBeExpr, info.type().description()));
     END;
     END;
 END;
 END;
 
 
@@ -381,7 +369,7 @@ BEGIN
         o := assertNumericOrSetOp(type, s, Operator.mulReal, Operator.mulInt, Operator.setIntersection);
         o := assertNumericOrSetOp(type, s, Operator.mulReal, Operator.mulInt, Operator.setIntersection);
     ELSIF s = "/" THEN
     ELSIF s = "/" THEN
         IF Types.isInt(type) THEN
         IF Types.isInt(type) THEN
-            Errors.raise("operator DIV expected for integer division");
+            Errors.raise(Message.opDivExpected);
         END;
         END;
         o := assertNumericOrSetOp(type, s, Operator.divReal, NIL, Operator.setSymmetricDiff);
         o := assertNumericOrSetOp(type, s, Operator.divReal, NIL, Operator.setSymmetricDiff);
     ELSIF s = "DIV" THEN
     ELSIF s = "DIV" THEN
@@ -390,8 +378,7 @@ BEGIN
         o := assertIntOp(type, s, Operator.mod);
         o := assertIntOp(type, s, Operator.mod);
     ELSIF s = "&" THEN
     ELSIF s = "&" THEN
         IF type # Types.basic.bool THEN
         IF type # Types.basic.bool THEN
-            Errors.raise("BOOLEAN expected as operand of '&', got '"
-                                 + type.description() + "'");
+            Errors.raise(Format.format1(Message.boolExpectedAsOperand, type.description()));
         END;
         END;
         o := Operator.and;
         o := Operator.and;
     ELSE
     ELSE
@@ -466,8 +453,7 @@ BEGIN
         result := assertNumericOrSetOp(type, s, Operator.subReal, Operator.subInt, Operator.setDiff);
         result := assertNumericOrSetOp(type, s, Operator.subReal, Operator.subInt, Operator.setDiff);
     ELSIF s = "OR" THEN
     ELSIF s = "OR" THEN
         IF type # Types.basic.bool THEN
         IF type # Types.basic.bool THEN
-            Errors.raise("BOOLEAN expected as operand of 'OR', got '"
-                         + type.description() + "'");
+        	Errors.raise(Format.format1(Message.boolExpectedAsOperandOfOr, type.description()));
         END;
         END;
         result := Operator.or;
         result := Operator.or;
     END;
     END;
@@ -509,7 +495,7 @@ BEGIN
 
 
     type <- result.type();
     type <- result.type();
     IF type = NIL THEN
     IF type = NIL THEN
-        Errors.raise("procedure returning no result cannot be used in an expression");
+        Errors.raise(Message.procReturningNoResult);
     END;
     END;
     RETURN result;
     RETURN result;
 END;
 END;
@@ -539,8 +525,7 @@ END;
 PROCEDURE Ops.in(left, right: Types.PType; cx: ContextHierarchy.Node): BinaryOperatorCx;
 PROCEDURE Ops.in(left, right: Types.PType; cx: ContextHierarchy.Node): BinaryOperatorCx;
 BEGIN
 BEGIN
     IF ~Types.isInt(left) THEN
     IF ~Types.isInt(left) THEN
-        Errors.raise(Types.intsDescription() 
-                     + " expected as an element of SET, got '" + left.description() + "'");
+        Errors.raise(Format.format2(Message.expectedAsElemOfSet, Types.intsDescription(), left.description()));
     END;
     END;
     checkImplicitCast(cx.root()^, right, Types.basic.set);
     checkImplicitCast(cx.root()^, right, Types.basic.set);
 
 
@@ -808,4 +793,4 @@ PROCEDURE NumericOrSetOpTypeCheck.check(t: Types.PType): BOOLEAN;
     RETURN SUPER(t) OR (t = Types.basic.set);
     RETURN SUPER(t) OR (t = Types.basic.set);
 END;
 END;
 
 
-END ExpressionTree.
+END ExpressionTree.

+ 4 - 3
src/ob/LanguageContext.ob

@@ -1,5 +1,6 @@
 MODULE LanguageContext;
 MODULE LanguageContext;
-IMPORT Chars, CodeGenerator, Context, Designator, Errors, Expression, OberonRtl, Record, Symbols, T := Types, Variable;
+IMPORT Chars, CodeGenerator, Context, Designator, Errors, Expression, OberonRtl, Record, Symbols, T := Types, Variable,
+	Format, Message;
 
 
 TYPE
 TYPE
     PType* = POINTER TO Type;
     PType* = POINTER TO Type;
@@ -133,7 +134,7 @@ BEGIN
             result := info.leadCode + "." + codeId;
             result := info.leadCode + "." + codeId;
         END;
         END;
     ELSE
     ELSE
-        Errors.raise("cannot reference " + info.idType());
+        Errors.raise(Format.format1(Message.cannotReference, info.idType()));
     END;
     END;
     RETURN result;
     RETURN result;
 END;
 END;
@@ -158,4 +159,4 @@ BEGIN
     RETURN result;
     RETURN result;
 END;
 END;
 
 
-END LanguageContext.
+END LanguageContext.

+ 4 - 4
src/ob/Lexer.ob

@@ -1,6 +1,6 @@
 MODULE Lexer;
 MODULE Lexer;
 IMPORT 
 IMPORT 
-    Chars, ContextExpression, ContextHierarchy, Errors, Stream, String;
+    Chars, ContextExpression, ContextHierarchy, Errors, Stream, String, Message;
 CONST
 CONST
     doubleQuote = Chars.doubleQuote;
     doubleQuote = Chars.doubleQuote;
     commentBegin = "(*";
     commentBegin = "(*";
@@ -68,7 +68,7 @@ BEGIN
             hexDetected := TRUE;
             hexDetected := TRUE;
             Stream.next(stream, 1);
             Stream.next(stream, 1);
         ELSIF hexDetected THEN
         ELSIF hexDetected THEN
-            Errors.raise("integer constant looks like having hexadecimal format but 'H' suffix is missing");
+            Errors.raise(Message.intLooksLikeHex);
         END;
         END;
 
 
         IF peekSeparator(stream) THEN
         IF peekSeparator(stream) THEN
@@ -208,7 +208,7 @@ PROCEDURE string*(VAR stream: Stream.Type; VAR cx: ContextExpression.Str): BOOLE
         END;
         END;
         
         
         IF c # doubleQuote THEN
         IF c # doubleQuote THEN
-            Errors.raise("unexpected end of string");
+            Errors.raise(Message.unexpectedEndOfString);
         END;
         END;
         
         
         cx.handleStr(s);
         cx.handleStr(s);
@@ -280,7 +280,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("comment was not closed");
+                    Errors.raise(Message.commentWasNotClosed);
                 END
                 END
             END
             END
         END;
         END;

+ 5 - 5
src/ob/Module.ob

@@ -1,6 +1,7 @@
 MODULE Module;
 MODULE Module;
 IMPORT 
 IMPORT 
-    Context, Errors, Expression, LanguageContext, Procedure, Symbols, TypeId, Types, Variable;
+    Context, Errors, Expression, LanguageContext, Procedure, Symbols, TypeId, Types, Variable,
+    Format, Message;
 CONST
 CONST
     doProcId = "do";
     doProcId = "do";
     varTypeId = "var";
     varTypeId = "var";
@@ -46,8 +47,7 @@ VAR
         arg := Procedure.checkSingleArgument(args, SELF, cx.language.types, NIL);
         arg := Procedure.checkSingleArgument(args, SELF, cx.language.types, NIL);
         type := arg.type();
         type := arg.type();
         IF ~(type IS Types.PString) THEN
         IF ~(type IS Types.PString) THEN
-            Errors.raise("string is expected as an argument of "
-                       + description + ", got " + type.description());
+            Errors.raise(Format.format2(Message.strExpected, description, type.description()));
         END;
         END;
         RETURN Expression.makeSimple(Types.stringValue(type(Types.PString)^), NIL)
         RETURN Expression.makeSimple(Types.stringValue(type(Types.PString)^), NIL)
     END Call.make;
     END Call.make;
@@ -70,11 +70,11 @@ END;
 PROCEDURE assertProcStatementResult*(type: Types.PType);
 PROCEDURE assertProcStatementResult*(type: Types.PType);
 BEGIN
 BEGIN
     IF (type # NIL) & ~(type^ IS Types.Any) THEN
     IF (type # NIL) & ~(type^ IS Types.Any) THEN
-        Errors.raise("procedure returning a result cannot be used as a statement");
+        Errors.raise(Message.procRetResCantBeStatement);
     END;
     END;
 END;
 END;
 
 
 BEGIN
 BEGIN
     doProcSymbol := makeDoProcSymbol();
     doProcSymbol := makeDoProcSymbol();
     varTypeSymbol := NEW Symbols.Symbol(varTypeId, NEW TypeId.Type(Types.any));
     varTypeSymbol := NEW Symbols.Symbol(varTypeId, NEW TypeId.Type(Types.any));
-END Module.
+END Module.

+ 9 - 11
src/ob/Operator.ob

@@ -10,7 +10,9 @@ IMPORT
     OberonRtl, 
     OberonRtl, 
     Precedence := CodePrecedence,
     Precedence := CodePrecedence,
     String,
     String,
-    Types;
+    Types,
+    Format,
+    Message;
 CONST
 CONST
     equalCode* = " == ";
     equalCode* = " == ";
     notEqualCode* = " != ";
     notEqualCode* = " != ";
@@ -460,12 +462,9 @@ VAR
     PROCEDURE assignArrayFromString(VAR a: Types.Array; s: Types.String): STRING;
     PROCEDURE assignArrayFromString(VAR a: Types.Array; s: Types.String): STRING;
     BEGIN
     BEGIN
         IF ~(a IS Types.StaticArray) THEN
         IF ~(a IS Types.StaticArray) THEN
-            Errors.raise("string cannot be assigned to open " + a.description());
+            Errors.raise(Format.format1(Message.strCantBeAssign, a.description()));
         ELSIF Types.stringLen(s) > a.length() THEN
         ELSIF Types.stringLen(s) > a.length() THEN
-            Errors.raise(String.fromInt(a.length()) 
-                         + "-character ARRAY is too small for "
-                         + String.fromInt(Types.stringLen(s))
-                         + "-character string");
+            Errors.raise(Format.format2(Message.arrIsTooSmall, String.fromInt(a.length()), String.fromInt(Types.stringLen(s))));
         END;
         END;
 
 
         l <- cx.language;
         l <- cx.language;
@@ -473,7 +472,7 @@ VAR
     END assignArrayFromString;
     END assignArrayFromString;
 BEGIN
 BEGIN
     IF ~(info IS Types.PVariable) OR info.isReadOnly() THEN
     IF ~(info IS Types.PVariable) OR info.isReadOnly() THEN
-        Errors.raise("cannot assign to " + info.idType());
+        Errors.raise(Format.format1(Message.cantAssignTo, info.idType()));
     ELSE 
     ELSE 
         rightCode := right.code();
         rightCode := right.code();
         leftType <- info.type();
         leftType <- info.type();
@@ -487,11 +486,10 @@ BEGIN
         ELSE
         ELSE
             IF cx.language.types.implicitCast(rightType, leftType, FALSE, castOperation)
             IF cx.language.types.implicitCast(rightType, leftType, FALSE, castOperation)
                 # Cast.errNo THEN
                 # Cast.errNo THEN
-                Errors.raise("type mismatch: '" + leftType.description()
-                             + "' cannot be assigned to '" + rightType.description() + "' expression");
+                Errors.raise(Format.format2(Message.typeMismatchExpr, leftType.description(), rightType.description()));
             END;
             END;
             IF (leftType IS Types.POpenArray) & (rightType IS Types.PArray) THEN
             IF (leftType IS Types.POpenArray) & (rightType IS Types.PArray) THEN
-                Errors.raise("open '" + leftType.description() + "' cannot be assigned");
+                Errors.raise(Format.format1(Message.openCantBeAssigned, leftType.description()));
             END;
             END;
                 
                 
             result := castOperation.assign(cx, info, right);
             result := castOperation.assign(cx, info, right);
@@ -769,4 +767,4 @@ BEGIN
     openArrayChar := NEW Types.OpenArray(Types.basic.ch);
     openArrayChar := NEW Types.OpenArray(Types.basic.ch);
     castOperations.castToUint8 := NEW CastToUint8();
     castOperations.castToUint8 := NEW CastToUint8();
     castOperations.castToRecord := NEW Cast.CastOpRecord();
     castOperations.castToRecord := NEW Cast.CastOpRecord();
-END Operator.
+END Operator.

+ 17 - 29
src/ob/Procedure.ob

@@ -16,7 +16,9 @@ IMPORT
     String,
     String,
     Symbols, 
     Symbols, 
     TypeId,
     TypeId,
-    Types;
+    Types,
+    Format,
+    Message;
 TYPE
 TYPE
     Call* = RECORD
     Call* = RECORD
         PROCEDURE make*(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType
         PROCEDURE make*(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType
@@ -112,22 +114,18 @@ BEGIN
         actualType <- actual.type();
         actualType <- actual.type();
         castErr := types.implicitCast(actualType, expectType, expected.isVar, result);
         castErr := types.implicitCast(actualType, expectType, expected.isVar, result);
         IF castErr = Cast.errVarParameter THEN
         IF castErr = Cast.errVarParameter THEN
-            Errors.raise("type mismatch for argument " + String.fromInt(pos + 1)
-                         + ": cannot pass '" + actualType.description()
-                         + "' as VAR parameter of type '" + expectType.description() + "'");
+            Errors.raise(Format.format3(Message.typeMismatchForArgPass, String.fromInt(pos + 1), actualType.description(), expectType.description()));
         ELSIF castErr # Cast.errNo THEN
         ELSIF castErr # Cast.errNo THEN
-            Errors.raise("type mismatch for argument " + String.fromInt(pos + 1)
-                         + ": '" + actualType.description() + "' cannot be converted to '"
-                         + expectType.description() + "'");
+            Errors.raise(Format.format3(Message.typeMismatchForArgConv, String.fromInt(pos + 1), actualType.description(), expectType.description()));
         END;
         END;
     END;
     END;
     IF expected.isVar THEN
     IF expected.isVar THEN
         info <- actual.info();
         info <- actual.info();
         IF info = NIL THEN
         IF info = NIL THEN
-            Errors.raise("expression cannot be used as VAR parameter");
+            Errors.raise(Message.expCannotUsedAsVar);
         END;
         END;
         IF ~(info IS Types.PVariable) OR info.isReadOnly() THEN
         IF ~(info IS Types.PVariable) OR info.isReadOnly() THEN
-            Errors.raise(info.idType() + " cannot be passed as VAR actual parameter");
+            Errors.raise(Format.format1(Message.cannotBePassedAsVar, info.idType()));
         END;
         END;
     END;
     END;
     IF code # NIL THEN
     IF code # NIL THEN
@@ -150,9 +148,7 @@ END;
 PROCEDURE checkArgumentsCount*(actual, expected: INTEGER);
 PROCEDURE checkArgumentsCount*(actual, expected: INTEGER);
 BEGIN
 BEGIN
     IF actual # expected THEN
     IF actual # expected THEN
-        Errors.raise(
-            String.fromInt(expected) + " argument(s) expected, got " 
-            + String.fromInt(actual));
+        Errors.raise(Format.format2(Message.argsExpected, String.fromInt(expected), String.fromInt(actual)));
     END;
     END;
 END;
 END;
 
 
@@ -366,12 +362,11 @@ PROCEDURE makeNew(): Symbols.PSymbol;
         arg <- checkSingleArgument(args, SELF, cx.language.types, NIL);
         arg <- checkSingleArgument(args, SELF, cx.language.types, NIL);
         argType <- arg.type();
         argType <- arg.type();
         IF ~(argType IS Record.PPointer) THEN
         IF ~(argType IS Record.PPointer) THEN
-            Errors.raise("POINTER variable expected, got '" 
-                         + argType.description() + "'");
+            Errors.raise(Format.format1(Message.procVarExpected, argType.description()));
         ELSE
         ELSE
             baseType <- Record.pointerBase(argType^);
             baseType <- Record.pointerBase(argType^);
             IF baseType.finalizedAsNonExported THEN
             IF baseType.finalizedAsNonExported THEN
-                Errors.raise("non-exported RECORD type cannot be used in NEW");
+                Errors.raise(Message.nonExpRecCantUsedInNew);
             END;
             END;
             right <- Expression.makeSimple(baseType.codeForNew(cx.cx^), argType);
             right <- Expression.makeSimple(baseType.codeForNew(cx.cx^), argType);
             result := Expression.makeSimple(Operator.assign(arg.info(), right, cx), NIL);
             result := Expression.makeSimple(Operator.assign(arg.info(), right, cx), NIL);
@@ -396,8 +391,7 @@ BEGIN
     arg := checkSingleArgument(args, SELF, cx.language.types, NIL);
     arg := checkSingleArgument(args, SELF, cx.language.types, NIL);
     argType := arg.type();
     argType := arg.type();
     IF ~SELF.check(argType) THEN
     IF ~SELF.check(argType) THEN
-        Errors.raise("ARRAY or string is expected as an argument of LEN, got '"
-                     + argType.description() + "'");
+        Errors.raise(Format.format1(Message.arrExpectedForLen, argType.description()));
     END;
     END;
     RETURN Expression.makeSimple(
     RETURN Expression.makeSimple(
         arg.code() + ".length",
         arg.code() + ".length",
@@ -498,8 +492,7 @@ PROCEDURE setBitImpl(name: STRING; bitOp: BinaryOpStr): Symbols.PSymbol;
         ELSE
         ELSE
             yValue := value^(ConstValue.Int).value;
             yValue := value^(ConstValue.Int).value;
             IF (yValue < 0) OR (yValue > 31) THEN
             IF (yValue < 0) OR (yValue > 31) THEN
-                Errors.raise("value (0..31) expected as a second argument of " 
-                             + SELF.name + ", got " + String.fromInt(yValue));
+                Errors.raise(Format.format2(Message.val31expected, SELF.name, String.fromInt(yValue)));
             END;
             END;
             comment := "bit: ";
             comment := "bit: ";
             IF y.isTerm() THEN
             IF y.isTerm() THEN
@@ -528,11 +521,9 @@ PROCEDURE checkVariableArgumentsCount(min, max: INTEGER; actual: ARRAY OF Expres
 BEGIN
 BEGIN
     len <- LEN(actual);
     len <- LEN(actual);
     IF len < min THEN
     IF len < min THEN
-        Errors.raise("at least " + String.fromInt(min) + " argument expected, got " 
-                     + String.fromInt(len));
+        Errors.raise(Format.format2(Message.atLeastArgExpected, String.fromInt(min), String.fromInt(len)));
     ELSIF len > max THEN
     ELSIF len > max THEN
-        Errors.raise("at most " + String.fromInt(max) + " arguments expected, got "
-                     + String.fromInt(len));
+        Errors.raise(Format.format2(Message.atMostArgExpected, String.fromInt(max), String.fromInt(len)));
     END;
     END;
 END checkVariableArgumentsCount;
 END checkVariableArgumentsCount;
 
 
@@ -620,8 +611,7 @@ PROCEDURE makeAbs(): Symbols.PSymbol;
         arg := checkSingleArgument(args, SELF, cx.language.types, NIL);
         arg := checkSingleArgument(args, SELF, cx.language.types, NIL);
         argType := arg.type();
         argType := arg.type();
         IF Types.numeric.indexOf(argType) = -1 THEN
         IF Types.numeric.indexOf(argType) = -1 THEN
-            Errors.raise("type mismatch: expected numeric type, got '"
-                         + argType.description() + "'");
+            Errors.raise(Format.format1(Message.typeMismatchNumExpected, argType.description()));
         END;
         END;
         RETURN Expression.makeSimple("Math.abs(" + arg.code() + ")", argType)
         RETURN Expression.makeSimple("Math.abs(" + arg.code() + ")", argType)
     END CallImpl.make;
     END CallImpl.make;
@@ -745,9 +735,7 @@ PROCEDURE makeOrd(): Symbols.PSymbol;
                 NIL,
                 NIL,
                 NEW ConstValue.Int(ORD(ch)));
                 NEW ConstValue.Int(ORD(ch)));
         ELSE
         ELSE
-            Errors.raise(
-                "ORD function expects CHAR or BOOLEAN or SET as an argument, got '"
-                + argType.description() + "'");
+            Errors.raise(Format.format1(Message.ordExpectCharBoolSet, argType.description()));
         END;
         END;
         RETURN result
         RETURN result
     END CallImpl.make;
     END CallImpl.make;
@@ -898,4 +886,4 @@ BEGIN
     predefined.add(makeChr());
     predefined.add(makeChr());
     predefined.add(makePack());
     predefined.add(makePack());
     predefined.add(makeUnpk());
     predefined.add(makeUnpk());
-END Procedure.
+END Procedure.

+ 5 - 5
src/ob/Record.ob

@@ -1,6 +1,6 @@
 MODULE Record;
 MODULE Record;
 IMPORT
 IMPORT
-    Chars, Context, Errors, Object, ScopeBase, TypeId, Types;
+    Chars, Context, Errors, Object, ScopeBase, TypeId, Types, Format, Message;
 TYPE
 TYPE
     FieldsMap = MAP OF Types.PField;
     FieldsMap = MAP OF Types.PField;
 
 
@@ -107,10 +107,10 @@ END;
 PROCEDURE Type.addField(f: Types.PField);
 PROCEDURE Type.addField(f: Types.PField);
 BEGIN
 BEGIN
     IF f.id() IN SELF.fields THEN
     IF f.id() IN SELF.fields THEN
-        Errors.raise("duplicated field: '" + f.id() + "'");
+        Errors.raise(Format.format1(Message.dupField, 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("base record already has field: '" + f.id() + "'");
+        Errors.raise(Format.format1(Message.baseRecHasField, f.id()));
     END;
     END;
     SELF.fields[f.id()] := f;
     SELF.fields[f.id()] := f;
     IF ~f.exported() THEN
     IF ~f.exported() THEN
@@ -134,7 +134,7 @@ PROCEDURE existingField(r: Type; id: STRING; d: Types.NamedType): Types.PField;
 BEGIN
 BEGIN
     result <- r.findSymbol(id);
     result <- r.findSymbol(id);
     IF result = NIL THEN
     IF result = NIL THEN
-        Errors.raise("type '" + d.description() + "' has no '" + id + "' field");
+        Errors.raise(Format.format2(Message.typeHasNoField, d.description(), id));
     END;
     END;
     RETURN result
     RETURN result
 END;
 END;
@@ -309,4 +309,4 @@ END;
 
 
 BEGIN
 BEGIN
     pGenerateTypeInfo := generateTypeInfo;
     pGenerateTypeInfo := generateTypeInfo;
-END Record.
+END Record.

+ 8 - 11
src/ob/Scope.ob

@@ -10,7 +10,9 @@ IMPORT
     Symbols, 
     Symbols, 
     TypeId,
     TypeId,
     Types,
     Types,
-    Variable;
+    Variable,
+    Format,
+    Message;
 TYPE
 TYPE
     Unresolved = ARRAY * OF STRING;
     Unresolved = ARRAY * OF STRING;
 
 
@@ -112,10 +114,7 @@ BEGIN
         info := symbol.info();
         info := symbol.info();
         type := info(TypeId.PType).type();
         type := info(TypeId.PType).type();
         IF (type # NIL) & ~(type IS Record.PType) THEN
         IF (type # NIL) & ~(type IS Record.PType) THEN
-            Errors.raise(
-                "'" 
-                + id
-                + "' must be of RECORD type because it was used before in the declation of POINTER");
+            Errors.raise(Format.format1(Message.mustBeRecordType, id));
         END;
         END;
         s.unresolved.remove(i);
         s.unresolved.remove(i);
     END;
     END;
@@ -124,8 +123,7 @@ END;
 PROCEDURE checkAllResolved*(s: Type);
 PROCEDURE checkAllResolved*(s: Type);
 BEGIN
 BEGIN
     IF LEN(s.unresolved) # 0 THEN
     IF LEN(s.unresolved) # 0 THEN
-        Errors.raise("no declaration found for '" 
-                     + String.join(s.unresolved, "', '") + "'");
+        Errors.raise(Format.format1(Message.noDeclarationFound, String.join(s.unresolved, "', '")));
     END;
     END;
 END;
 END;
 
 
@@ -157,7 +155,7 @@ PROCEDURE Type.addSymbol(s: Symbols.PSymbol; exported: BOOLEAN);
 BEGIN
 BEGIN
     id <- s.id();
     id <- s.id();
     IF SELF.findSymbol(id) # NIL THEN
     IF SELF.findSymbol(id) # NIL THEN
-        Errors.raise("'" + id + "' already declared");
+        Errors.raise(Format.format1(Message.alreadyDeclared, id));
     END;
     END;
     SELF.symbols[id] := s;
     SELF.symbols[id] := s;
 END;
 END;
@@ -188,8 +186,7 @@ VAR
 BEGIN
 BEGIN
     IF exported THEN
     IF exported THEN
         info := s.info();
         info := s.info();
-        Errors.raise("cannot export from within procedure: "
-                     + info.idType() + " '" + s.id() + "'");
+        Errors.raise(Format.format2(Message.cannotExport, info.idType(), s.id()));
     END;
     END;
     SUPER(s, exported);
     SUPER(s, exported);
 END;
 END;
@@ -247,4 +244,4 @@ PROCEDURE moduleSymbol*(m: Module): Symbols.PSymbol;
     RETURN m.symbol
     RETURN m.symbol
 END;
 END;
 
 
-END Scope.
+END Scope.

+ 2 - 2
src/ob/Types.ob

@@ -1,6 +1,6 @@
 MODULE Types;
 MODULE Types;
 IMPORT
 IMPORT
-    Chars, ConstValue, Context, Errors, OberonRtl, Object, Str := String;
+    Chars, ConstValue, Context, Errors, OberonRtl, Object, Str := String, Format, Message;
 TYPE
 TYPE
     Id* = RECORD(Object.Type)
     Id* = RECORD(Object.Type)
         PROCEDURE idType*(): STRING
         PROCEDURE idType*(): STRING
@@ -350,7 +350,7 @@ END;
 
 
 PROCEDURE raiseUnexpectedSelector*(id: STRING; obj: STRING);
 PROCEDURE raiseUnexpectedSelector*(id: STRING; obj: STRING);
 BEGIN
 BEGIN
-    Errors.raise("selector '." + id + "' cannot be applied to '" + obj + "'");
+    Errors.raise(Format.format2(Message.selectorCantBeApplied, id, obj));
 END;
 END;
 
 
 PROCEDURE StorageType.denote(id: STRING; isReadOnly: BOOLEAN): PField;
 PROCEDURE StorageType.denote(id: STRING; isReadOnly: BOOLEAN): PField;

+ 142 - 1
src/ob/en/Message.ob

@@ -2,5 +2,146 @@ MODULE Message;
 CONST
 CONST
     methodAnonRec* = "cannot declare methods for anonymous records (POINTER TO RECORD)";
     methodAnonRec* = "cannot declare methods for anonymous records (POINTER TO RECORD)";
     methodExport* = "{0} '{1}' cannot be exported because record itself is not exported";
     methodExport* = "{0} '{1}' cannot be exported because record itself is not exported";
+    
+    (* Code.ob *)
+    negativeIndex* = "index is negative: {0}";
+    
+    (* ContextAssignment.ob *)
+    didYouMeanAssign* = "did you mean ':=' (statement expected, got expression)?";
+    
+    (* ContextCase.ob *)
+    onlyRecordsForCase* = "only records passed as VAR argument can be used to test type in CASE";
+    caseExpectations* = "'RECORD' or 'POINTER' or {0} or 'CHAR' expected as CASE expression";
+    caseHandleLabelType* = "label must be '{0}' (the same as case expression), got '{1}'";
+    typeNameExpectedInLabel* = "type's name expected in label, got expression: {0}";
+    singleCharStringExpected* = "single-character string expected";
+    canNotUseDiapason* = "cannot use diapason (..) with type guard";
+    isNotAType* = "'{0}' is not a type";
+    isNotAConstant* = "'{0}' is not a constant";
+    
+    (* ContextConst.ob *)
+    constExpressionExpected* = "constant expression expected";
+    
+    (* ContextDesignator.ob *)
+    canNotApplyTypecast* = "cannot apply type cast to {0}";
+    pointerCantBeDereferenced* = "POINTER TO non-exported RECORD type cannot be dereferenced";
+    pointerTypeExpected* = "POINTER TO type expected, got '{0}'";
+    expressionExpected* = "{0} expression expected, got '{1}'";
+    indexOutOfBonds* = "index out of bounds: maximum possible index is {0}, got {1}";
+    arrayOrStringExpected* = "ARRAY or string expected, got '{0}'";
+    cantIndexEmptString* = "cannot index empty string";
+    
+    (* ContextExpression.ob *)
+    cantBeReferenced* = "{0} cannot be referenced";
+    
+    (* ContextHierarchy.ob *)
+    undeclaredId* = "undeclared identifier: '{0}'";
+    idIsNotExported* = "identifier '{0}' is not exported by module '{1}'";
+    
+    (* ContextIf.ob *)
+    boolExpressionExpected* = "'BOOLEAN' expression expected, got '{0}'";
+    
+    (* ContextLoop.ob *)
+    isNotAVar* = "'{0}' is not a variable";
+    varMustBeInteger* = "'{0}' is a '{1}' variable, 'FOR' control variable must be 'INTEGER'";
+    intExpect* = "'INTEGER' expression expected to assign '{0}', got '{1}'";
+    intExpectedAsTo* = "'INTEGER' expression expected as 'TO' parameter, got '{0}'";
+    intExpectedAsBy* = "'INTEGER' expression expected as 'BY' parameter, got '{0}'";
+    constExpectedAsBy* = "constant expression expected as 'BY' parameter";
+    
+    (* ContextModule.ob *)
+    moduleName* = "original module name '{0}' expected, got '{1}'";
+    moduleCantImportItself* = "module '{0}' cannot import itself";
+    duplicateAlias* = "duplicated alias: '{0}'";
+    moduleAlreadyImported* = "module already imported: '{0}'";
+    moduleNotFound1* = "module not found: {0}";
+    moduleNotFound2* = "modules not found: {0}";
+    
+    (* ContextProcedure.ob *)
+    mismatchedProcName* = "mismatched procedure names: '{0}' at the begining and '{1}' at the end";
+    argSameAsName* = "argument '{0}' has the same name as procedure";
+    unexpectedReturn* = "unexpected RETURN in PROCEDURE declared with no result type";
+    returnTypeMismatch* = "RETURN '{0}' expected, got '{1}'";
+    returnExpectedAtEnd* = "RETURN expected at the end of PROCEDURE declared with '{0}' result type";
+    procedureCantReturn* = "procedure cannot return {0}";
+    procedureExpected* = "PROCEDURE expected, got '{0}'";
+    
+    (* ContextType.ob *)
+    intContExprExpected* = "'INTEGER' constant expression expected, got '{0}'";
+    constExprExpected* = "constant expression expected as ARRAY size";
+    arraySizeMustBeGrater* = "array size must be greater than 0, got {0}";
+    fieldExpOnlyIfExported* = "field '{0}' can be exported only if {1} '{2}' itself is exported too";
+    recursiveFieldDef* = "recursive field definition: '{0}'";
+    recTypeExpected* = "RECORD type is expected as a base type, got '{0}'";
+    recursiveInheritance* = "recursive inheritance: '{0}'";
+    recExpectedAsPtrBaseType* = "RECORD is expected as a POINTER base type{0}";
+    cantExportAnonRecField* = "cannot export anonymous RECORD field: '{0}'";
+    
+    (* ContextVar.ob *)
+    typeWasntDeclared* = "type '{0}' was not declared";
+    
+    (* ExpressionTree.ob *)
+    typeNameExpected* = "type name expected";
+    isNotAnExtencion* = "{0}: '{1}' is not an extension of '{2}'";
+    ptrToTypeExpected* = "{0}: POINTER to type or RECORD expected, got '{1}'";
+    valueVarCantBeUsed* = "{0}: a value variable cannot be used";
+    recTypeExpectedAsArg* = "{0}: RECORD type expected as an argument of RECORD {1}, got '{2}'";
+    ptrTypeExpectedAsArg* = "{0}: POINTER type expected as an argument of POINTER {1}, got '{2}'";
+    typeMismatch* = "type mismatch: expected '{0}', got {1}";
+    opTypeMismatch* = "operator '{0}' type mismatch: {1} expected, got '{2}'";
+    typeNameCantBeExpr* = "type name '{0}' cannot be used as an expression";
+    opDivExpected* = "operator DIV expected for integer division";
+    boolExpectedAsOperand* = "BOOLEAN expected as operand of '&', got '{0}'";
+    boolExpectedAsOperandOfOr* = "BOOLEAN expected as operand of 'OR', got '{0}'";
+    procReturningNoResult* = "procedure returning no result cannot be used in an expression";
+    expectedAsElemOfSet* = "{0} expected as an element of SET, got '{1}'";
+    
+    (* LanguageContext.ob *)
+    cannotReference* = "cannot reference {0}";
+    
+    (* Lexer.ob *)
+    intLooksLikeHex* = "integer constant looks like having hexadecimal format but 'H' suffix is missing";
+    unexpectedEndOfString* = "unexpected end of string";
+    commentWasNotClosed* = "comment was not closed";
+    
+    (* Module.ob *)
+    strExpected* = "string is expected as an argument of {0}, got {1}";
+    procRetResCantBeStatement* = "procedure returning a result cannot be used as a statement";
+    
+    (* Operator.ob *)
+    strCantBeAssign* = "string cannot be assigned to open {0}";
+    arrIsTooSmall* = "{0}-character ARRAY is too small for {1}-character string";
+    cantAssignTo* = "cannot assign to {0}";
+    typeMismatchExpr* = "type mismatch: '{0}' cannot be assigned to '{1}' expression";
+    openCantBeAssigned* = "open '{0}' cannot be assigned";
+    
+    (* Procedure.ob *)
+    typeMismatchForArgPass* = "type mismatch for argument {0}: cannot pass '{1}' as VAR parameter of type '{2}'";
+    typeMismatchForArgConv* = "type mismatch for argument {0}: '{1}' cannot be converted to '{2}'";
+    expCannotUsedAsVar* = "expression cannot be used as VAR parameter";
+    cannotBePassedAsVar* = "{0} cannot be passed as VAR actual parameter";
+    argsExpected* = "{0} argument(s) expected, got {1}";
+    procVarExpected* = "POINTER variable expected, got '{0}'";
+    nonExpRecCantUsedInNew* = "non-exported RECORD type cannot be used in NEW";
+    arrExpectedForLen* = "ARRAY or string is expected as an argument of LEN, got '{0}'";
+    val31expected* = "value (0..31) expected as a second argument of {0}, got {1}";
+    atLeastArgExpected* = "at least {0} argument expected, got {1}";
+    atMostArgExpected* = "at most {0} arguments expected, got {1}";
+    typeMismatchNumExpected* = "type mismatch: expected numeric type, got '{0}'";
+    ordExpectCharBoolSet* = "ORD function expects CHAR or BOOLEAN or SET as an argument, got '{0}'";
+    
+    (* Record.ob *)
+    dupField* = "duplicated field: '{0}'";
+    baseRecHasField* = "base record already has field: '{0}'";
+    typeHasNoField* = "type '{0}' has no '{1}' field";
+    
+    (* Scope.ob *)
+    mustBeRecordType* = "'{0}' must be of RECORD type because it was used before in the declation of POINTER";
+    noDeclarationFound* = "no declaration found for '{0}'";
+    alreadyDeclared* = "'{0}' already declared";
+    cannotExport* = "cannot export from within procedure: {0} '{1}'";
+    
+    (* Types.ob *)
+    selectorCantBeApplied* = "selector '.{0}' cannot be applied to '{1}'";
 
 
-END Message.
+END Message.

+ 143 - 2
src/ob/ru/Message.ob

@@ -1,6 +1,147 @@
 MODULE Message;
 MODULE Message;
 CONST
 CONST
     methodAnonRec* = "объявление методов для анонимных записей невозможно (POINTER TO RECORD)";
     methodAnonRec* = "объявление методов для анонимных записей невозможно (POINTER TO RECORD)";
-    methodExport* = "{0} '{1}' не может быть экспротитрован, потому что сама запись не экспортирована";
+    methodExport* = "{0} '{1}' не может быть экспортирован, потому что сама запись не экспортирована";
+    
+    (* Code.ob *)
+    negativeIndex* = "отрицательный индекс: {0}";
+    
+    (* ContextAssignment.ob *)
+    didYouMeanAssign* = "имели в виду ':=' (ожидается оператор, но указано выражение)?";
+    
+    (* ContextCase.ob *)
+    onlyRecordsForCase* = "только записи переданные в виде VAR аргумента могут быть использованы в качестве тестирующего выражения CASE";
+    caseExpectations* = "в выражении CASE ожидается 'RECORD' или 'POINTER' или {0} или 'CHAR'";
+    caseHandleLabelType* = "вариант должен быть '{0}' (такого же типа, что и выражение в CASE), но имеем '{1}'";
+    typeNameExpectedInLabel* = "имя типа ожидается в варианте, но указано выражение: {0}";
+    singleCharStringExpected* = "ожидается строка из одного символа";
+    canNotUseDiapason* = "не могу использовать диапазон (..) с охраной типа";
+    isNotAType* = "'{0}' не является типом";
+    isNotAConstant* = "'{0}' не является константой";
+    
+    (* ContextConst.ob *)
+    constExpressionExpected* = "ожидается выражение из констант";
+    
+    (* ContextDesignator.ob *)
+    canNotApplyTypecast* = "не могу выполнить приведение типа для {0}";
+    pointerCantBeDereferenced* = "тип указателя на неэкспортированную запись (POINTER TO RECORD) не может быть разыменован";
+    pointerTypeExpected* = "POINTER TO тип ожидается, но имеем '{0}'";
+    expressionExpected* = "{0} выражение ожидается, но имеем '{1}'";
+    indexOutOfBonds* = "индекс за границей: максимальный возможный индекс {0}, но имеем {1}";
+    arrayOrStringExpected* = "ARRAY или строка ожидается, но имеем '{0}'";
+    cantIndexEmptString* = "не могу индексировать пустую строку";
+    
+	(* ContextExpression.ob *)
+    cantBeReferenced* = "нельзя получить ссылку на {0}";
+    
+    (* ContextHierarchy.ob *)
+    undeclaredId* = "неизвестный идентификатор: '{0}'";
+    idIsNotExported* = "идентификатор '{0}' не экспортирован модулем '{1}'";
+    
+    (* ContextIf.ob *)
+    boolExpressionExpected* = "'BOOLEAN' выражение ожидается, но имеем '{0}'";
+    
+    (* ContextLoop.ob *)
+    isNotAVar* = "'{0}' не переменная";
+    varMustBeInteger* = "переменной '{0}' имеет тип '{1}', но управляющая переменная в 'FOR' должна иметь тип 'INTEGER'";
+    intExpect* = "ожидается выражение с результатом 'INTEGER' для присваивания к '{0}', но имеем '{1}'";
+    intExpectedAsTo* = "'INTEGER' выражение ожидается в качестве 'TO' параметра, но имеем '{0}'";
+    intExpectedAsBy* = "'INTEGER' выражение ожидается в качестве 'BY' параметра, но имеем '{0}'";
+    constExpectedAsBy* = "константное выражение ожидается в качестве 'BY' параметра";
+    
+    (* ContextModule.ob *)
+    moduleName* = "ожидается заявленное в начале название модуля '{0}', но имеем '{1}'";
+    moduleCantImportItself* = "модуль '{0}' не может импортировать сам себя";
+    duplicateAlias* = "такая замена имени модуля уже занята: '{0}'";
+    moduleAlreadyImported* = "модуль уже импортирован: '{0}'";
+    moduleNotFound1* = "модуль не найден: {0}";
+    moduleNotFound2* = "модули не найдены: {0}";
+    
+    (* ContextProcedure.ob *)
+    mismatchedProcName* = "имя процедуры в начале '{0}' не совпадает с именем в конце '{1}'";
+    argSameAsName* = "аргумент '{0}' имеет такое же имя как и имя процедуры";
+    unexpectedReturn* = "неожиданный RETURN в процедуре без объявленного результирующего типа";
+    returnTypeMismatch* = "RETURN типа '{0}' ожидается, но имеем '{1}'";
+    returnExpectedAtEnd* = "RETURN ожидается в конце процедуры объявленной с результирующем типом '{0}'";
+    procedureCantReturn* = "процедура не может возвращать результат типа {0}";
+    procedureExpected* = "PROCEDURE ожидается, но имеем '{0}'";
+    
+    (* ContextType.ob *)
+    intContExprExpected* = "ожидается выражение с результатом 'INTEGER', но имеем '{0}'";
+    constExprExpected* = "константное выражение ожидается для указания размера массива";
+    arraySizeMustBeGrater* = "размер ARRAY должен быть больше нуля, но имеем {0}";
+    fieldExpOnlyIfExported* = "поле '{0}' может быть экспортировано только если {1} '{2}' также экспортируется";
+    recursiveFieldDef* = "рекурсивное определение поля: '{0}'";
+    recTypeExpected* = "ожидается тип RECORD в качестве базового типа, но имеем '{0}'";
+    recursiveInheritance* = "рекурсивное наследование: '{0}'";
+    recExpectedAsPtrBaseType* = "ожидается RECORD в качестве базового типа для POINTER {0}";
+    cantExportAnonRecField* = "невозможно экспортировать анонимное поле RECORD: '{0}'";
+    
+    (* ContextVar.ob *)
+    typeWasntDeclared* = "тип '{0}' не был объявлен";
+    
+    (* ExpressionTree.ob *)
+    typeNameExpected* = "ожидается имя типа";
+    isNotAnExtencion* = "{0}: '{1}' не является расширением '{2}'";
+    ptrToTypeExpected* = "{0}: ожидается указатель на тип или запись, но имеем '{1}'";
+    valueVarCantBeUsed* = "{0}: параметр-значение не может быть использован";
+    recTypeExpectedAsArg* = "{0}: тип RECORD ожидается в качестве аргумента RECORD {1}, но имеем '{2}'";
+    ptrTypeExpectedAsArg* = "{0}: тип POINTER ожидается в качестве аргумента POINTER {1}, но имеем '{2}'";
+    typeMismatch* = "несовпадение типов: ожидается '{0}', но имеем {1}";
+    opTypeMismatch* = "в операции '{0}' несовпадение типов: {1} ожидается, но имеем '{2}'";
+    typeNameCantBeExpr* = "имя типа '{0}' не может быть использовано как выражение";
+    opDivExpected* = "операция DIV ожидается для целочисленного деления";
+    boolExpectedAsOperand* = "BOOLEAN ожидается в качестве операнда для '&', но имеем '{0}'";
+    boolExpectedAsOperandOfOr* = "BOOLEAN ожидается в качестве операнда для 'OR', но имеем '{0}'";
+    procReturningNoResult* = "процедура, не возвращающая результат, не может быть использована в выражении";
+    expectedAsElemOfSet* = "{0} ожидается как элемент SET, но имеем '{1}'";
+    
+    (* LanguageContext.ob *)
+    cannotReference* = "нельзя получить ссылку на {0}";
+    
+    (* Lexer.ob *)
+    intLooksLikeHex* = "целая константа похоже в шестнадцатеричном формате, но суффикс 'H' отсутствует";
+    unexpectedEndOfString* = "неожиданный конец строки";
+    commentWasNotClosed* = "комментарий не закрыт";
+    
+    (* Module.ob *)
+    strExpected* = "строка ожидается в качестве аргумента {0}, но имеем {1}";
+    procRetResCantBeStatement* = "процедура, возвращающая результат, не может быть использована как оператор";
+    
+    (* Operator.ob *)
+    strCantBeAssign* = "строка не может быть присвоена к открытому {0}";
+    arrIsTooSmall* = "{0}-символьный ARRAY слишком мал для {1}-символьной строки";
+    cantAssignTo* = "не могу присвоить к {0}";
+    typeMismatchExpr* = "несовпадение типа: '{0}' не может быть присвоен к '{1}' выражению";
+    openCantBeAssigned* = "открытый '{0}' не может быть присвоен";
+    
+    (* Procedure.ob *)
+    typeMismatchForArgPass* = "несовпадение типа для аргумента {0}: не могу передать '{1}' как VAR параметр типа '{2}'";
+    typeMismatchForArgConv* = "несовпадение типа для аргумента {0}: '{1}' не может быть преобразован к '{2}'";
+    expCannotUsedAsVar* = "выражение не может быть использовано в качестве VAR параметра";
+    cannotBePassedAsVar* = "{0} не может быть передано в качестве VAR формального параметра";
+    argsExpected* = "ожидаем аргументов — {0}, но имеем {1}";
+    procVarExpected* = "ожидается переменная типа POINTER, но имеем '{0}'";
+    nonExpRecCantUsedInNew* = "неэкспортируемая запись не может быть использована в NEW";
+    arrExpectedForLen* = "ARRAY или строка ожидается в качестве аргумента LEN, но имеем '{0}'";
+    val31expected* = "ожидается значение (0..31) в качестве второго аргумента {0}, но имеем {1}";
+    atLeastArgExpected* = "минимальное число аргументов — {0}, но имеем {1}";
+    atMostArgExpected* = "максимальное число аргументов — {0}, но имеем {1}";
+    typeMismatchNumExpected* = "несовпадение типа, ожидается целое, но имеем '{0}'";
+    ordExpectCharBoolSet* = "функция ORD ожидает аргументы типа CHAR, BOOLEAN или SET, но имеем '{0}'";
+    
+    (* Record.ob *)
+    dupField* = "дублирование поля: '{0}'";
+    baseRecHasField* = "базовая запись уже имеет поле: '{0}'";
+    typeHasNoField* = "тип '{0}' не имеет поля '{1}'";
+    
+    (* Scope.ob *)
+    mustBeRecordType* = "'{0}' должен быть типа RECORD, поскольку был использован в объявлении POINTER";
+    noDeclarationFound* = "не найдено объявления для '{0}'";
+    alreadyDeclared* = "'{0}' уже объявлен";
+    cannotExport* = "не может быть экспортирован внутри процедуры: {0} '{1}'";
+    
+    (* Types.ob *)
+    selectorCantBeApplied* = "селектор '.{0}' не может быть применён к '{1}'";
 
 
-END Message.
+END Message.

+ 4 - 4
test/test_unit.js

@@ -1569,8 +1569,8 @@ return {
 "import unknown module": testWithGrammar(
 "import unknown module": testWithGrammar(
     grammar.module,
     grammar.module,
     pass(),
     pass(),
-    fail(["MODULE m; IMPORT unknown; END m.", "module(s) not found: unknown"],
-         ["MODULE m; IMPORT unknown1, unknown2; END m.", "module(s) not found: unknown1, unknown2"]
+    fail(["MODULE m; IMPORT unknown; END m.", "module not found: unknown"],
+         ["MODULE m; IMPORT unknown1, unknown2; END m.", "modules not found: unknown1, unknown2"]
          )
          )
     ),
     ),
 "self import is failed": testWithGrammar(
 "self import is failed": testWithGrammar(
@@ -1582,7 +1582,7 @@ return {
     grammar.module,
     grammar.module,
     pass("MODULE m; IMPORT J := JS; END m.",
     pass("MODULE m; IMPORT J := JS; END m.",
          "MODULE m; IMPORT J := JS; BEGIN J.alert(\"test\") END m."),
          "MODULE m; IMPORT J := JS; BEGIN J.alert(\"test\") END m."),
-    fail(["MODULE m; IMPORT u1 := unknown1, unknown2; END m.", "module(s) not found: unknown1, unknown2"],
+    fail(["MODULE m; IMPORT u1 := unknown1, unknown2; END m.", "modules not found: unknown1, unknown2"],
          ["MODULE m; IMPORT a1 := m1, a2 := m1; END m.", "module already imported: 'm1'"],
          ["MODULE m; IMPORT a1 := m1, a2 := m1; END m.", "module already imported: 'm1'"],
          ["MODULE m; IMPORT a1 := u1, a1 := u2; END m.", "duplicated alias: 'a1'"],
          ["MODULE m; IMPORT a1 := u1, a1 := u2; END m.", "duplicated alias: 'a1'"],
          ["MODULE m; IMPORT J := JS; BEGIN JS.alert(\"test\") END m.", "undeclared identifier: 'JS'"]
          ["MODULE m; IMPORT J := JS; BEGIN JS.alert(\"test\") END m.", "undeclared identifier: 'JS'"]
@@ -1623,4 +1623,4 @@ function run(){
     });
     });
 }
 }
 
 
-exports.run = run;
+exports.run = run;