Bläddra i källkod

cast.js -> Cast.ob

Vladislav Folts 11 år sedan
förälder
incheckning
f217506754
18 ändrade filer med 529 tillägg och 203 borttagningar
  1. 0 117
      src/cast.js
  2. 6 5
      src/context.js
  3. 1 1
      src/eberon/eberon_context.js
  4. 170 0
      src/js/Cast.js
  5. 6 0
      src/js/Code.js
  6. 1 1
      src/js/JsArray.js
  7. 37 8
      src/js/Types.js
  8. 1 1
      src/module.js
  9. 177 0
      src/ob/Cast.ob
  10. 9 2
      src/ob/Code.ob
  11. 1 1
      src/ob/JsArray.ob
  12. 52 14
      src/ob/Types.ob
  13. 12 4
      src/operator.js
  14. 26 31
      src/procedure.js
  15. 8 6
      src/rtl.js
  16. 8 6
      test/expected/cast.js
  17. 8 6
      test/expected/modules.js
  18. 6 0
      test/test_unit.js

+ 0 - 117
src/cast.js

@@ -1,117 +0,0 @@
-"use strict";
-var Code = require("js/Code.js");
-var Type = require("js/Types.js");
-var ArrayType = Type.Array;
-var PointerType = Type.Pointer;
-var ProcedureType = Type.Procedure;
-
-var basicTypes = Type.basic();
-
-function doNoting(context, e){return e;}
-
-function findBaseType(base, type){
-    while (type && type != base)
-        type = Type.recordBase(type);
-    return type;
-}
-
-function findPointerBaseType(pBase, pType){
-    if (!findBaseType(Type.pointerBase(pBase), Type.pointerBase(pType)))
-        return undefined;
-    return pBase;
-}
-
-function matchesToNIL(t){
-    return t instanceof PointerType || t instanceof ProcedureType;
-}
-
-function areTypesExactlyMatch(t1, t2){
-    if (t1 == t2)
-        return true;
-    if (t1 instanceof ArrayType && t2 instanceof ArrayType)
-        return Type.arrayLength(t1) == Type.arrayLength(t2) 
-            && areTypesMatch(Type.arrayElementsType(t1), Type.arrayElementsType(t2));
-    if (t1 instanceof PointerType && t2 instanceof PointerType)
-        return areTypesMatch(Type.pointerBase(t1), Type.pointerBase(t2));
-    if (t1 instanceof ProcedureType && t2 instanceof ProcedureType)
-        return areProceduresMatch(t1, t2);
-    return false;
-}
-
-function areTypesMatch(t1, t2){
-    return areTypesExactlyMatch(t1, t2)
-        || (Type.isInt(t1) && Type.isInt(t2))
-        || (t1 == Type.nil && matchesToNIL(t2)
-            || t2 == Type.nil && matchesToNIL(t1))
-        ;
-}
-
-function areProceduresMatch(p1, p2){
-    var args1 = p1.args();
-    var args2 = p2.args();
-    if (args1.length != args2.length)
-        return false;
-
-    for(var i = 0; i < args1.length; ++i){
-        var a1 = args1[i];
-        var a2 = args2[i];
-        if (a1.isVar != a2.isVar)
-            return false;
-        if (a1.type != p1 && a2.type != p2
-            &&!areTypesExactlyMatch(a1.type, a2.type))
-            return false;
-    }
-
-    var r1 = p1.result();
-    var r2 = p2.result();
-    if (r1 == p1 && r2 == p2)
-        return true;
-    return areTypesExactlyMatch(r1, r2);
-}
-
-function implicitCast(from, to, ops){
-    if (from == to)
-        return doNoting;
-
-    if (from == basicTypes.uint8 && to == basicTypes.integer)
-        return doNoting;
-
-    if (from == basicTypes.integer && to == basicTypes.uint8)
-        return function(context, e){
-            return ops.setIntersection(e, Code.makeExpression("0xFF", basicTypes.integer, null, 0xFF));
-        };
-
-    if (from instanceof Type.String){
-        if (to === basicTypes.ch){
-            var v;
-            if (Type.stringAsChar(from, {set: function(value){v = value;}}))
-                return function(){return Code.makeExpression(v, to);};
-        }
-        else if (to instanceof Type.Array && Type.arrayElementsType(to) == basicTypes.ch)
-            return doNoting;
-    }
-    else if (from instanceof ArrayType && to instanceof ArrayType)
-        return (Type.arrayLength(to) == Type.openArrayLength || Type.arrayLength(to) == Type.arrayLength(from))
-            ? implicitCast(Type.arrayElementsType(from), Type.arrayElementsType(to))
-            : undefined;
-    else if (from instanceof PointerType && to instanceof PointerType){
-        if (findPointerBaseType(to, from))
-            return doNoting;
-    }
-    else if (from instanceof Type.Record && to instanceof Type.Record){
-        if (findBaseType(to, from))
-            return doNoting;
-    }
-    else if (from == Type.nil && matchesToNIL(to))
-        return doNoting;
-    else if (from instanceof ProcedureType && to instanceof ProcedureType){
-        if (areProceduresMatch(from, to))
-            return doNoting;
-    }
-    return undefined;
-}
-
-exports.areProceduresMatch = areProceduresMatch;
-exports.areTypesMatch = areTypesMatch;
-exports.implicit = implicitCast;
-exports.findPointerBaseType = findPointerBaseType;

+ 6 - 5
src/context.js

@@ -1,6 +1,6 @@
 "use strict";
 
-var Cast = require("cast.js");
+var Cast = require("js/Cast.js");
 var Code = require("js/Code.js");
 var Errors = require("js/Errors.js");
 var Module = require("module.js");
@@ -14,6 +14,7 @@ var Type = require("js/Types.js");
 
 var basicTypes = Type.basic();
 var nullCodeGenerator = Code.nullGenerator();
+var nilType = Type.nil();
 
 function getSymbolAndScope(context, id){
     var s = context.findSymbol(id);
@@ -57,7 +58,7 @@ function checkImplicitCast(from, to){
     var result = Cast.implicit(from, to, op);
     if (!result)
         throwTypeMismatch(from, to);
-    return result;
+    return result.make.bind(result);
 }
 
 function promoteTypeInExpression(e, type){
@@ -627,7 +628,7 @@ exports.ProcParams = HandleSymbolAsType.extend({
         for(var i = 0; i < names.length; ++i){
             var name = names[i];
             this.handleMessage(
-                new AddArgumentMsg(name, new Procedure.Arg(type, this.__isVar)));
+                new AddArgumentMsg(name, Type.makeProcedureArgument(type, this.__isVar)));
         }
         this.__isVar = false;
         this.__argNamesForType = [];
@@ -771,7 +772,7 @@ var equalOpTypeCheck = {
             || Type.isString(t)
             || t instanceof Type.Pointer
             || t instanceof Type.Procedure
-            || t == Type.nil;
+            || t == nilType;
     }
 };
 
@@ -967,7 +968,7 @@ exports.Factor = ChainedContext.extend({
     handleLiteral: function(s){
         var parent = this.parent();
         if (s == "NIL")
-            parent.handleConst(Type.nil, undefined, "null");
+            parent.handleConst(nilType, undefined, "null");
         else if (s == "TRUE")
             parent.handleConst(basicTypes.bool, true, "true");
         else if (s == "FALSE")

+ 1 - 1
src/eberon/eberon_context.js

@@ -1,6 +1,6 @@
 "use strict";
 
-var Cast = require("cast.js");
+var Cast = require("js/Cast.js");
 var Context = require("context.js");
 var Errors = require("js/Errors.js");
 var Symbol = require("js/Symbols.js");

+ 170 - 0
src/js/Cast.js

@@ -0,0 +1,170 @@
+var RTL$ = require("rtl.js");
+var Code = require("js/Code.js");
+var Context = require("js/Context.js");
+var JsArray = require("js/JsArray.js");
+var JsString = require("js/JsString.js");
+var Object = require("js/Object.js");
+var Types = require("js/Types.js");
+var CastOp = RTL$.extend({
+	init: function CastOp(){
+	}
+});
+var CastOpDoNothing = CastOp.extend({
+	init: function CastOpDoNothing(){
+		CastOp.prototype.init.call(this);
+	}
+});
+var CastOpStrToChar = CastOp.extend({
+	init: function CastOpStrToChar(){
+		CastOp.prototype.init.call(this);
+		this.c = 0;
+	}
+});
+var Operations = RTL$.extend({
+	init: function Operations(){
+		this.castToUint8 = null;
+	}
+});
+var areTypesExactlyMatch = null;
+var doNothing = null;
+CastOpDoNothing.prototype.make = function(c/*Type*/, e/*PExpression*/){
+	return e;
+}
+
+function findBaseType(base/*PRecord*/, type/*PRecord*/){
+	while (true){
+		if (type != null && type != base){
+			type = Types.recordBase(type);
+		} else break;
+	}
+	return type;
+}
+
+function findPointerBaseType(base/*PPointer*/, type/*Pointer*/){
+	var result = null;
+	if (findBaseType(Types.pointerBase(base), Types.pointerBase(type)) != null){
+		result = base;
+	}
+	return result;
+}
+
+function matchesToNIL(t/*Type*/){
+	return t instanceof Types.Pointer || t instanceof Types.Procedure;
+}
+
+function areTypesMatch(t1/*PType*/, t2/*PType*/){
+	return areTypesExactlyMatch(t1, t2) || Types.isInt(t1) && Types.isInt(t2) || (t1 == Types.nil() && matchesToNIL(t2) || t2 == Types.nil() && matchesToNIL(t1));
+}
+
+function areArgsMatch(oa1/*PType*/, oa2/*PType*/, p1/*PProcedure*/, p2/*PProcedure*/){
+	var a1 = null;
+	var a2 = null;
+	a1 = RTL$.typeGuard(oa1, Types.ProcedureArgument);
+	a2 = RTL$.typeGuard(oa2, Types.ProcedureArgument);
+	return a1.isVar == a2.isVar && (a1.type == p1 && a2.type == p2 || areTypesExactlyMatch(a1.type, a2.type));
+}
+
+function areProceduresMatch(p1/*PProcedure*/, p2/*PProcedure*/){
+	var result = false;
+	var args1 = null;var args2 = null;
+	var argsLen = 0;
+	var i = 0;
+	var r1 = null;var r2 = null;
+	args1 = p1.args();
+	args2 = p2.args();
+	argsLen = JsArray.len(args1);
+	if (JsArray.len(args2) == argsLen){
+		while (true){
+			if (i < argsLen && areArgsMatch(JsArray.at(args1, i), JsArray.at(args2, i), p1, p2)){
+				++i;
+			} else break;
+		}
+		if (i == argsLen){
+			r1 = p1.result();
+			r2 = p2.result();
+			result = r1 == p1 && r2 == p2 || areTypesExactlyMatch(r1, r2);
+		}
+	}
+	return result;
+}
+
+function areTypesExactlyMatchImpl(t1/*PType*/, t2/*PType*/){
+	var result = false;
+	if (t1 == t2){
+		result = true;
+	}
+	else if (t1 instanceof Types.Array && t2 instanceof Types.Array){
+		result = Types.arrayLength(RTL$.typeGuard(t1, Types.Array)) == Types.arrayLength(RTL$.typeGuard(t2, Types.Array)) && areTypesMatch(Types.arrayElementsType(RTL$.typeGuard(t1, Types.Array)), Types.arrayElementsType(RTL$.typeGuard(t2, Types.Array)));
+	}
+	else if (t1 instanceof Types.Pointer && t2 instanceof Types.Pointer){
+		result = areTypesMatch(Types.pointerBase(RTL$.typeGuard(t1, Types.Pointer)), Types.pointerBase(RTL$.typeGuard(t2, Types.Pointer)));
+	}
+	else if (t1 instanceof Types.Procedure && t2 instanceof Types.Procedure){
+		result = areProceduresMatch(RTL$.typeGuard(t1, Types.Procedure), RTL$.typeGuard(t2, Types.Procedure));
+	}
+	return result;
+}
+CastOpStrToChar.prototype.make = function(c/*Type*/, e/*PExpression*/){
+	return Code.makeSimpleExpression(JsString.fromInt(this.c), Types.basic().ch);
+}
+
+function makeCastOpStrToChar(c/*CHAR*/){
+	var result = null;
+	result = new CastOpStrToChar();
+	result.c = c;
+	return result;
+}
+
+function implicit(from/*PType*/, to/*PType*/, ops/*Operations*/){
+	var result = null;
+	var c = 0;
+	if (from == to){
+		result = doNothing;
+	}
+	else if (from == Types.basic().uint8 && to == Types.basic().integer){
+		result = doNothing;
+	}
+	else if (from == Types.basic().integer && to == Types.basic().uint8){
+		result = ops.castToUint8;
+	}
+	else if (from instanceof Types.String){
+		if (to == Types.basic().ch){
+			if (Types.stringAsChar(RTL$.typeGuard(from, Types.String), {set: function($v){c = $v;}, get: function(){return c;}})){
+				result = makeCastOpStrToChar(c);
+			}
+		}
+		else if (to instanceof Types.Array && Types.arrayElementsType(RTL$.typeGuard(to, Types.Array)) == Types.basic().ch){
+			result = doNothing;
+		}
+	}
+	else if (from instanceof Types.Array && to instanceof Types.Array){
+		if (Types.arrayLength(RTL$.typeGuard(to, Types.Array)) == Types.openArrayLength || Types.arrayLength(RTL$.typeGuard(to, Types.Array)) == Types.arrayLength(RTL$.typeGuard(from, Types.Array))){
+			result = implicit(Types.arrayElementsType(RTL$.typeGuard(from, Types.Array)), Types.arrayElementsType(RTL$.typeGuard(to, Types.Array)), ops);
+		}
+	}
+	else if (from instanceof Types.Pointer && to instanceof Types.Pointer){
+		if (findPointerBaseType(RTL$.typeGuard(to, Types.Pointer), RTL$.typeGuard(from, Types.Pointer)) != null){
+			result = doNothing;
+		}
+	}
+	else if (from instanceof Types.Record && to instanceof Types.Record){
+		if (findBaseType(RTL$.typeGuard(to, Types.Record), RTL$.typeGuard(from, Types.Record)) != null){
+			result = doNothing;
+		}
+	}
+	else if (from == Types.nil() && matchesToNIL(to)){
+		result = doNothing;
+	}
+	else if (from instanceof Types.Procedure && to instanceof Types.Procedure){
+		if (areProceduresMatch(RTL$.typeGuard(from, Types.Procedure), RTL$.typeGuard(to, Types.Procedure))){
+			result = doNothing;
+		}
+	}
+	return result;
+}
+areTypesExactlyMatch = areTypesExactlyMatchImpl;
+doNothing = new CastOpDoNothing();
+exports.findPointerBaseType = findPointerBaseType;
+exports.areTypesMatch = areTypesMatch;
+exports.areProceduresMatch = areProceduresMatch;
+exports.implicit = implicit;

+ 6 - 0
src/js/Code.js

@@ -162,6 +162,10 @@ function makeExpressionWithPrecedence(code/*Type*/, type/*PType*/, designator/*P
 function makeExpression(code/*Type*/, type/*PType*/, designator/*PDesigantor*/, constValue/*JS.var*/){
 	return makeExpressionWithPrecedence(code, type, designator, constValue, kNoPrecedence);
 }
+
+function makeSimpleExpression(code/*Type*/, type/*PType*/){
+	return makeExpression(code, type, null, undefined);
+}
 Designator.prototype.code = function(){
 	return this.mCode;
 }
@@ -323,9 +327,11 @@ function makeModuleGenerator(name/*Type*/, imports/*Strings*/){
 	result.imports = imports;
 	return result;
 }
+exports.Expression = Expression;
 exports.nullGenerator = function(){return nullGenerator;};
 exports.makeExpressionWithPrecedence = makeExpressionWithPrecedence;
 exports.makeExpression = makeExpression;
+exports.makeSimpleExpression = makeSimpleExpression;
 exports.makeDesignator = makeDesignator;
 exports.derefExpression = derefExpression;
 exports.refExpression = refExpression;

+ 1 - 1
src/js/JsArray.js

@@ -31,7 +31,7 @@ function stringsAdd(a/*Strings*/, o/*Type*/){
 	a.push(o);
 }
 
-function at(a/*Strings*/, i/*INTEGER*/){
+function at(a/*Type*/, i/*INTEGER*/){
 	var result = null;
 	result = a[i];
 	return result;

+ 37 - 8
src/js/Types.js

@@ -17,6 +17,11 @@ var Type = Object.Type.extend({
 		Object.Type.prototype.init.call(this);
 	}
 });
+var StorageType = Type.extend({
+	init: function StorageType(){
+		Type.prototype.init.call(this);
+	}
+});
 var TypeId = Id.extend({
 	init: function TypeId(){
 		Id.prototype.init.call(this);
@@ -70,9 +75,9 @@ var String = Type.extend({
 		this.s = null;
 	}
 });
-var NamedType = Type.extend({
+var NamedType = StorageType.extend({
 	init: function NamedType(){
-		Type.prototype.init.call(this);
+		StorageType.prototype.init.call(this);
 		this.name = null;
 	}
 });
@@ -95,6 +100,13 @@ var Procedure = NamedType.extend({
 		NamedType.prototype.init.call(this);
 	}
 });
+var ProcedureArgument = Object.Type.extend({
+	init: function ProcedureArgument(){
+		Object.Type.prototype.init.call(this);
+		this.type = null;
+		this.isVar = false;
+	}
+});
 var BasicType = NamedType.extend({
 	init: function BasicType(){
 		NamedType.prototype.init.call(this);
@@ -122,9 +134,9 @@ var NonExportedRecord = Record.extend({
 		Record.prototype.init.call(this);
 	}
 });
-var Nil = Id.extend({
+var Nil = Type.extend({
 	init: function Nil(){
-		Id.prototype.init.call(this);
+		Type.prototype.init.call(this);
 	}
 });
 var Module = Id.extend({
@@ -288,7 +300,7 @@ BasicType.prototype.description = function(){
 BasicType.prototype.initializer = function(cx/*Type*/){
 	return this.mInitializer;
 }
-Nil.prototype.idType = function(){
+Nil.prototype.description = function(){
 	return JsString.make("NIL");
 }
 
@@ -430,15 +442,30 @@ function arrayElementsType(a/*Array*/){
 function arrayLength(a/*Array*/){
 	return a.len;
 }
-String.prototype.initializer = function(cx/*Type*/){
-	return JsString.make("null");
-}
 Procedure.prototype.initializer = function(cx/*Type*/){
 	return JsString.make("null");
 }
 Procedure.prototype.description = function(){
 	return this.name;
 }
+ProcedureArgument.prototype.description = function(){
+	var result = null;
+	if (this.isVar){
+		result = JsString.make("VAR ");
+	}
+	else {
+		result = JsString.makeEmpty();
+	}
+	return JsString.concat(result, this.type.description());
+}
+
+function makeProcedureArgument(type/*PType*/, isVar/*BOOLEAN*/){
+	var result = null;
+	result = new ProcedureArgument();
+	result.type = type;
+	result.isVar = isVar;
+	return result;
+}
 Module.prototype.idType = function(){
 	return JsString.make("module");
 }
@@ -558,6 +585,7 @@ exports.String = String;
 exports.Array = Array;
 exports.Pointer = Pointer;
 exports.Procedure = Procedure;
+exports.ProcedureArgument = ProcedureArgument;
 exports.Record = Record;
 exports.NonExportedRecord = NonExportedRecord;
 exports.Module = Module;
@@ -588,6 +616,7 @@ exports.recordOwnFields = recordOwnFields;
 exports.pointerBase = pointerBase;
 exports.arrayElementsType = arrayElementsType;
 exports.arrayLength = arrayLength;
+exports.makeProcedureArgument = makeProcedureArgument;
 exports.makeTypeId = makeTypeId;
 exports.makeLazyTypeId = makeLazyTypeId;
 exports.makeString = makeString;

+ 1 - 1
src/module.js

@@ -58,7 +58,7 @@ var doProcSymbol = (function(){
         }
     });
 
-    var args = [new Procedure.Arg(undefined, false)];
+    var args = [Type.makeProcedureArgument(undefined, false)];
     var ProcType = Type.Procedure.extend({
         init: function(){
             Type.Procedure.prototype.init.call(this);

+ 177 - 0
src/ob/Cast.ob

@@ -0,0 +1,177 @@
+MODULE Cast;
+IMPORT Code, Context, JsArray, JsString, Object, Types;
+
+TYPE
+    CastOp = RECORD
+        PROCEDURE make(c: Context.Type; e: Code.PExpression): Code.PExpression
+    END;
+
+    PCastOp = POINTER TO CastOp;
+
+    CastOpDoNothing = RECORD (CastOp)
+    END;
+
+    CastOpStrToChar = RECORD (CastOp)
+        c: CHAR
+    END;
+
+    Operations = RECORD
+        castToUint8: PCastOp
+    END;
+
+VAR
+    (*workaround recursive usage*)
+    areTypesExactlyMatch: PROCEDURE (t1: Types.PType; t2: Types.PType): BOOLEAN;
+    doNothing: POINTER TO CastOpDoNothing;
+
+PROCEDURE CastOpDoNothing.make(c: Context.Type; e: Code.PExpression): Code.PExpression;
+    RETURN e
+END CastOpDoNothing.make;
+
+PROCEDURE findBaseType(base: Types.PRecord; type: Types.PRecord): Types.PRecord;
+BEGIN
+    WHILE (type # NIL) & (type # base) DO
+        type := Types.recordBase(type^);
+    END;
+    RETURN type
+END findBaseType;
+
+PROCEDURE findPointerBaseType*(base: Types.PPointer; type: Types.Pointer): Types.PPointer;
+VAR
+    result: Types.PPointer;
+BEGIN
+    IF findBaseType(Types.pointerBase(base^), Types.pointerBase(type)) # NIL THEN
+        result := base;
+    END;
+    RETURN result
+END findPointerBaseType;
+
+PROCEDURE matchesToNIL(t: Types.Type): BOOLEAN;
+    RETURN (t IS Types.Pointer) OR (t IS Types.Procedure)
+END matchesToNIL;
+
+PROCEDURE areTypesMatch*(t1: Types.PType; t2: Types.PType): BOOLEAN;
+    RETURN areTypesExactlyMatch(t1, t2)
+        OR (Types.isInt(t1) & Types.isInt(t2))
+        OR (((t1 = Types.nil) & (matchesToNIL(t2^)))
+            OR ((t2 = Types.nil) & (matchesToNIL(t1^))))
+END areTypesMatch;
+
+PROCEDURE areArgsMatch(oa1, oa2: Object.PType; p1, p2: Types.PProcedure): BOOLEAN;
+VAR
+    a1: Types.PProcedureArgument;
+    a2: Types.PProcedureArgument;
+BEGIN
+    a1 := oa1(Types.PProcedureArgument);
+    a2 := oa2(Types.PProcedureArgument);
+    RETURN (a1.isVar = a2.isVar)
+        & (    ((a1.type = p1) & (a2.type = p2))
+            OR areTypesExactlyMatch(a1.type, a2.type))
+END areArgsMatch;
+
+PROCEDURE areProceduresMatch*(p1: Types.PProcedure; p2: Types.PProcedure): BOOLEAN;
+VAR
+    result: BOOLEAN;
+    args1, args2: JsArray.Type;
+    argsLen: INTEGER;
+    i: INTEGER;
+    r1, r2: Types.PType;
+BEGIN
+    args1 := p1.args();
+    args2 := p2.args();
+    argsLen := JsArray.len(args1);
+    IF JsArray.len(args2) = argsLen THEN
+        WHILE (i < argsLen) 
+            & areArgsMatch(JsArray.at(args1, i), JsArray.at(args2, i), p1, p2) DO
+            INC(i);
+        END;
+        IF i = argsLen THEN
+            r1 := p1.result();
+            r2 := p2.result();
+            result := ((r1 = p1) & (r2 = p2)) OR areTypesExactlyMatch(r1, r2);
+        END;
+    END;
+    RETURN result
+END areProceduresMatch;
+
+PROCEDURE areTypesExactlyMatchImpl(t1: Types.PType; t2: Types.PType): BOOLEAN;
+VAR
+    result: BOOLEAN;
+BEGIN
+    IF t1 = t2 THEN
+        result := TRUE;
+    ELSIF (t1 IS Types.PArray) & (t2 IS Types.PArray) THEN
+        result := (Types.arrayLength(t1(Types.PArray)^) = Types.arrayLength(t2(Types.PArray)^)) 
+                & (areTypesMatch(Types.arrayElementsType(t1(Types.PArray)^), 
+                                 Types.arrayElementsType(t2(Types.PArray)^)));
+    ELSIF (t1 IS Types.PPointer) & (t2 IS Types.PPointer) THEN
+        result := areTypesMatch(Types.pointerBase(t1(Types.PPointer)^), 
+                                Types.pointerBase(t2(Types.PPointer)^));
+    ELSIF (t1 IS Types.PProcedure) & (t2 IS Types.PProcedure) THEN
+        result := areProceduresMatch(t1(Types.PProcedure), 
+                                     t2(Types.PProcedure));
+    END;
+    RETURN result
+END areTypesExactlyMatchImpl;
+
+PROCEDURE CastOpStrToChar.make(c: Context.Type; e: Code.PExpression): Code.PExpression;
+    RETURN Code.makeSimpleExpression(JsString.fromInt(ORD(SELF.c)), Types.basic.ch)
+END CastOpStrToChar.make;
+
+PROCEDURE makeCastOpStrToChar(c: CHAR): PCastOp;
+VAR
+    result: POINTER TO CastOpStrToChar;
+BEGIN
+    NEW(result);
+    result.c := c;
+    RETURN result
+END makeCastOpStrToChar;
+
+PROCEDURE implicit*(from, to: Types.PType; ops: Operations): PCastOp;
+VAR
+    result: PCastOp;
+    c: CHAR;
+BEGIN
+    IF from = to THEN
+        result := doNothing;
+    ELSIF (from = Types.basic.uint8) & (to = Types.basic.integer) THEN
+        result := doNothing;
+    ELSIF (from = Types.basic.integer) & (to = Types.basic.uint8) THEN
+        result := ops.castToUint8;
+    ELSIF from IS Types.PString THEN
+        IF to = Types.basic.ch THEN
+            IF Types.stringAsChar(from(Types.PString)^, c) THEN
+                result := makeCastOpStrToChar(c);
+            END;
+        ELSIF (to IS Types.PArray) & (Types.arrayElementsType(to(Types.PArray)^) = Types.basic.ch) THEN
+            result := doNothing;
+        END;
+    ELSIF (from IS Types.PArray) & (to IS Types.PArray) THEN
+        IF     (Types.arrayLength(to(Types.PArray)^) = Types.openArrayLength)
+            OR (Types.arrayLength(to(Types.PArray)^) = Types.arrayLength(from(Types.PArray)^)) THEN
+            result := implicit(Types.arrayElementsType(from(Types.PArray)^), 
+                               Types.arrayElementsType(to(Types.PArray)^),
+                               ops);
+        END;
+    ELSIF (from IS Types.PPointer) & (to IS Types.PPointer) THEN
+        IF findPointerBaseType(to(Types.PPointer), from(Types.PPointer)^) # NIL THEN
+            result := doNothing;
+        END;
+    ELSIF (from IS Types.PRecord) & (to IS Types.PRecord) THEN
+        IF findBaseType(to(Types.PRecord), from(Types.PRecord)) # NIL THEN
+            result := doNothing;
+        END;
+    ELSIF (from = Types.nil) & matchesToNIL(to^) THEN
+        result := doNothing;
+    ELSIF (from IS Types.PProcedure) & (to IS Types.PProcedure) THEN
+        IF areProceduresMatch(from(Types.PProcedure), to(Types.PProcedure)) THEN
+            result := doNothing;
+        END
+    END;
+    RETURN result
+END implicit;
+
+BEGIN
+    areTypesExactlyMatch := areTypesExactlyMatchImpl;
+    NEW(doNothing);
+END Cast.

+ 9 - 2
src/ob/Code.ob

@@ -46,9 +46,9 @@ TYPE
 
     PDesigantor = POINTER TO Designator;
 
-    PExpression = POINTER TO Expression;
+    PExpression* = POINTER TO Expression;
 
-    Expression = RECORD
+    Expression* = RECORD
         PROCEDURE code(): JsString.Type;
         PROCEDURE lval(): JsString.Type;
         PROCEDURE type(): Types.PType;
@@ -215,6 +215,13 @@ PROCEDURE makeExpression*(
     RETURN makeExpressionWithPrecedence(code, type, designator, constValue, kNoPrecedence)
 END makeExpression;
 
+PROCEDURE makeSimpleExpression*(
+    code: JsString.Type; 
+    type: Types.PType)
+    : PExpression;
+    RETURN makeExpression(code, type, NIL, undefined)
+END makeSimpleExpression;
+
 PROCEDURE Designator.code(): JsString.Type;
     RETURN SELF.mCode
 END Designator.code;

+ 1 - 1
src/ob/JsArray.ob

@@ -30,7 +30,7 @@ BEGIN
     JS.do("a.push(o)");
 END stringsAdd;
 
-PROCEDURE at*(a: Strings; i: INTEGER): Object.PType;
+PROCEDURE at*(a: Type; i: INTEGER): Object.PType;
 VAR
     result: Object.PType;
 BEGIN

+ 52 - 14
src/ob/Types.ob

@@ -12,11 +12,14 @@ TYPE
     PId* = POINTER TO Id;
     
     Type* = RECORD(Object.Type)
-        PROCEDURE description(): JsString.Type;
-        PROCEDURE initializer(cx: Context.Type): JsString.Type
+        PROCEDURE description(): JsString.Type
     END;
     PType* = POINTER TO Type;
-    
+
+    StorageType = RECORD(Type)    
+        PROCEDURE initializer(cx: Context.Type): JsString.Type
+    END;
+
     TypeId* = RECORD(Id)
         PROCEDURE type*(): PType;
         PROCEDURE description(): JsString.Type;
@@ -73,9 +76,9 @@ TYPE
         s: JsString.Type
     END;
 
-    PString = POINTER TO String;
+    PString* = POINTER TO String;
 
-    NamedType = RECORD(Type)
+    NamedType = RECORD(StorageType)
         name: JsString.Type
     END;
 
@@ -96,10 +99,23 @@ TYPE
     PPointer* = POINTER TO Pointer;
 
     Procedure* = RECORD(NamedType)
+        PROCEDURE args*(): JsArray.Type;
+        PROCEDURE result*(): PType
     END;
 
     PProcedure* = POINTER TO Procedure;
 
+    ProcedureArgument* = RECORD (Object.Type)
+        PROCEDURE description(): JsString.Type;
+
+        type*: PType;
+        isVar*: BOOLEAN
+    END;
+
+    PProcedureArgument* = POINTER TO ProcedureArgument;
+
+
+
     BasicType = RECORD(NamedType)
         mInitializer: JsString.Type
     END;
@@ -127,7 +143,7 @@ TYPE
     END;
     PNonExportedRecord = POINTER TO NonExportedRecord;
 
-    Nil = RECORD(Id)
+    Nil = RECORD(Type)
     END;
 
     Module* = RECORD(Id)
@@ -138,7 +154,7 @@ TYPE
 
 VAR
     basic*: RECORD
-        bool, ch, integer, uint8, real, set: PBasicType
+        bool*, ch*, integer*, uint8*, real*, set*: PBasicType
     END;
 
     numeric*: JsArray.Type;
@@ -323,15 +339,15 @@ END BasicType.description;
 PROCEDURE BasicType.initializer(cx: Context.Type): JsString.Type;
     RETURN SELF.mInitializer
 END BasicType.initializer;
-
+(*
 PROCEDURE Nil.idType(): JsString.Type;
     RETURN JsString.make("NIL")
 END Nil.idType;
-(*
+*)
 PROCEDURE Nil.description(): JsString.Type;
-    RETURN SELF.idType()
+    RETURN JsString.make("NIL")
 END Nil.description;
-*)
+
 PROCEDURE isInt*(t: PType): BOOLEAN;
     RETURN (t = basic.integer) OR (t = basic.uint8)
 END isInt;
@@ -413,7 +429,7 @@ BEGIN
     RETURN result
 END Record.findSymbol;
 
-PROCEDURE recordBase*(r: Record): PType;
+PROCEDURE recordBase*(r: Record): PRecord;
     RETURN r.base
 END recordBase;
 
@@ -518,11 +534,11 @@ END arrayElementsType;
 PROCEDURE arrayLength*(a: Array): INTEGER;
     RETURN a.len
 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")
 END Procedure.initializer;
@@ -531,6 +547,28 @@ PROCEDURE Procedure.description(): JsString.Type;
     RETURN SELF.name
 END Procedure.description;
 
+PROCEDURE ProcedureArgument.description(): JsString.Type;
+VAR
+    result: JsString.Type;
+BEGIN
+    IF SELF.isVar THEN
+        result := JsString.make("VAR ");
+    ELSE
+        result := JsString.makeEmpty();
+    END;
+    RETURN JsString.concat(result, SELF.type.description())
+END ProcedureArgument.description;
+
+PROCEDURE makeProcedureArgument*(type: PType; isVar: BOOLEAN): PProcedureArgument;
+VAR
+    result: PProcedureArgument;
+BEGIN
+    NEW(result);
+    result.type := type;
+    result.isVar := isVar;
+    RETURN result
+END makeProcedureArgument;
+
 PROCEDURE Module.idType(): JsString.Type;
     RETURN JsString.make("module")
 END Module.idType;

+ 12 - 4
src/operator.js

@@ -1,6 +1,6 @@
 "use strict";
 
-var Cast = require("cast.js");
+var Cast = require("js/Cast.js");
 var Code = require("js/Code.js");
 var Errors = require("js/Errors.js");
 var Type = require("js/Types.js");
@@ -60,9 +60,15 @@ var openArrayChar = Type.makeArray(undefined, undefined, basicTypes.ch, 0);
 function castToStr(e, context){
     var type = e.type();
     var opCast = Cast.implicit(type, openArrayChar);
-    return opCast(context, e).code();
+    return opCast.make(context, e).code();
 }
 
+var castToUint8 = {
+    make: function (context, e){
+        return exports.setIntersection(e, Code.makeExpression("0xFF", basicTypes.integer, null, 0xFF));
+    }
+};
+
 function makeStrCmp(op){
     return function(left, right, context){
         return Code.makeExpression(
@@ -124,7 +130,7 @@ function assign(left, right, context){
     if (isArray || rightType instanceof Type.Record)
         return context.rtl().copy(rightCode, leftCode);
 
-    var castCode = castOperation(context, Code.derefExpression(right)).code();
+    var castCode = castOperation.make(context, Code.derefExpression(right)).code();
     rightCode = castCode ? castCode : rightCode;
     return leftCode + (info instanceof Type.VariableRef 
                       ? ".set(" + rightCode + ")"
@@ -214,7 +220,9 @@ var operators = {
     divInplace: makeInplace(" /= ", div),
     
     pow2:       pow2,
-    log2:       log2
+    log2:       log2,
+
+    castToUint8: castToUint8
 };
 
 for(var p in operators)

+ 26 - 31
src/procedure.js

@@ -1,6 +1,6 @@
 "use strict";
 
-var Cast = require("cast.js");
+var Cast = require("js/Cast.js");
 var Class = require("rtl.js").Class;
 var Code = require("js/Code.js");
 var Errors = require("js/Errors.js");
@@ -11,20 +11,14 @@ var Type = require("js/Types.js");
 
 var basicTypes = Type.basic();
 
-var Arg = Class.extend({
-    init: function(type, isVar){
-        this.type = type;
-        this.isVar = isVar;
-    },
-    description: function(){
-        return (this.isVar ? "VAR " : "") + this.type.description();
-    }
-});
-exports.Arg = Arg;
+var Arg = Type.ProcedureArgument;
+var makeArg = Type.makeProcedureArgument;
 
 var CheckArgumentResult = Arg.extend({
     init: function(type, isVar, convert){
-        Arg.prototype.init.call(this, type, isVar);
+        Arg.prototype.init.call(this);
+        this.type = type;
+        this.isVar = isVar;
         this.convert = convert;
     }
 });
@@ -91,6 +85,7 @@ var ProcCallGenerator = Class.extend({
                 throw new Errors.Error(
                       "type mismatch for argument " + (pos + 1) + ": '" + type.description()
                     + "' cannot be converted to '" + expectType.description() + "'");
+            castOperation = castOperation.make.bind(castOperation);
             if (arg.isVar && expectType != type && Type.isInt(type))
                 throw new Errors.Error(
                       "type mismatch for argument " + (pos + 1) + ": cannot pass '" 
@@ -197,8 +192,8 @@ function makeProcSymbol(name, proc){
 }
 
 function setBitImpl(name, bitOp){
-    var args = [new Arg(basicTypes.set, true),
-                new Arg(basicTypes.integer, false)];
+    var args = [makeArg(basicTypes.set, true),
+                makeArg(basicTypes.integer, false)];
     function operator(x, y){
         var value = y.constValue();
         var valueCode;
@@ -226,8 +221,8 @@ function setBitImpl(name, bitOp){
 }
 
 function incImpl(name, unary, op){
-    var args = [new Arg(basicTypes.integer, true),
-                new Arg(basicTypes.integer, false)];
+    var args = [makeArg(basicTypes.integer, true),
+                makeArg(basicTypes.integer, false)];
     function operator(x, y){
         if (!y)
             return unary + x.code();
@@ -272,8 +267,8 @@ function bitShiftImpl(name, op){
             return op(args[0], args[1]);
         }
     });
-    var args = [new Arg(basicTypes.integer, false),
-                new Arg(basicTypes.integer, false)
+    var args = [makeArg(basicTypes.integer, false),
+                makeArg(basicTypes.integer, false)
                ];
     var proc = new Std(
         name,
@@ -319,7 +314,7 @@ exports.predefined = [
         });
 
         var name = "NEW";
-        var args = [new Arg(undefined, true)];
+        var args = [makeArg(undefined, true)];
         var type = new Std(
             name,
             args,
@@ -348,7 +343,7 @@ exports.predefined = [
         });
 
         var name = "LEN";
-        var args = [new Arg(Type.makeArray("ARRAY OF any type", undefined, undefined, 0), false)];
+        var args = [makeArg(Type.makeArray("ARRAY OF any type", undefined, undefined, 0), false)];
         var type = new Std(
             name,
             args,
@@ -372,7 +367,7 @@ exports.predefined = [
             }
         });
         var name = "ODD";
-        var args = [new Arg(basicTypes.integer, false)];
+        var args = [makeArg(basicTypes.integer, false)];
         var type = new Std(
             "ODD",
             args,
@@ -391,7 +386,7 @@ exports.predefined = [
             prolog: function(){return this.context().rtl().assertId() + "(";}
         });
 
-        var args = [new Arg(basicTypes.bool)];
+        var args = [makeArg(basicTypes.bool)];
         var proc = new Std(
             "ASSERT",
             args,
@@ -423,7 +418,7 @@ exports.predefined = [
             },
             resultType: function(){return this.__argType;}
         });
-        var args = [new Arg(undefined, false)];
+        var args = [makeArg(undefined, false)];
         var proc = new Std(
             "ABS",
             args,
@@ -441,7 +436,7 @@ exports.predefined = [
             },
             prolog: function(){return "Math.floor(";}
         });
-        var args = [new Arg(basicTypes.real, false)];
+        var args = [makeArg(basicTypes.real, false)];
         var proc = new Std(
             "FLOOR",
             args,
@@ -463,7 +458,7 @@ exports.predefined = [
                     e.code(), basicTypes.real, undefined, e.constValue(), e.maxPrecedence());
             }
         });
-        var args = [new Arg(basicTypes.integer, false)];
+        var args = [makeArg(basicTypes.integer, false)];
         var proc = new Std(
             "FLT",
             args,
@@ -515,7 +510,7 @@ exports.predefined = [
         });
         var name = "ORD";
         //var argType = new basicTypes("CHAR or BOOLEAN or SET");
-        var args = [new Arg(undefined, false)];
+        var args = [makeArg(undefined, false)];
         var type = new Std(
             name,
             args,
@@ -538,7 +533,7 @@ exports.predefined = [
         var name = "CHR";
         var type = new Std(
             name,
-            [new Arg(basicTypes.integer, false)],
+            [makeArg(basicTypes.integer, false)],
             basicTypes.ch,
             function(context, id, type){
                 return new CallGenerator(context, id, type);
@@ -547,8 +542,8 @@ exports.predefined = [
         return symbol;
     }(),
     function(){
-        var args = [new Arg(basicTypes.real, true),
-                    new Arg(basicTypes.integer, false)];
+        var args = [makeArg(basicTypes.real, true),
+                    makeArg(basicTypes.integer, false)];
         function operator(x, y){
             return op.mulInplace(x, op.pow2(y));
         }
@@ -565,8 +560,8 @@ exports.predefined = [
         return symbol;
     }(),
     function(){
-        var args = [new Arg(basicTypes.real, true),
-                    new Arg(basicTypes.integer, true)];
+        var args = [makeArg(basicTypes.real, true),
+                    makeArg(basicTypes.integer, true)];
         function operator(x, y){
             return op.assign(y, op.log2(x)) +
                    "; " +

+ 8 - 6
src/rtl.js

@@ -30,14 +30,16 @@ var impl = {
         if (!(from instanceof to)){
             var fromStr;
             var toStr;
-            if (!from)
-                fromStr = "" + fromStr;
-            else if (from.constructor && from.constructor.name)
+            
+            if (from && from.constructor && from.constructor.name)
                 fromStr = "" + from.constructor.name;
-            if (!to)
-                toStr = "" + to;
-            else if (to.constructor && to.constructor.name)
+            else
+                fromStr = "" + from;
+            
+            if (to && to.constructor && to.constructor.name)
                 toStr = "" + to.constructor.name;
+            else
+                toStr = "" + to;
             
             var msg = "typeguard assertion failed";
             if (fromStr || toStr)               

+ 8 - 6
test/expected/cast.js

@@ -17,14 +17,16 @@ var RTL$ = {
         if (!(from instanceof to)){
             var fromStr;
             var toStr;
-            if (!from)
-                fromStr = "" + fromStr;
-            else if (from.constructor && from.constructor.name)
+            
+            if (from && from.constructor && from.constructor.name)
                 fromStr = "" + from.constructor.name;
-            if (!to)
-                toStr = "" + to;
-            else if (to.constructor && to.constructor.name)
+            else
+                fromStr = "" + from;
+            
+            if (to && to.constructor && to.constructor.name)
                 toStr = "" + to.constructor.name;
+            else
+                toStr = "" + to;
             
             var msg = "typeguard assertion failed";
             if (fromStr || toStr)               

+ 8 - 6
test/expected/modules.js

@@ -17,14 +17,16 @@ var RTL$ = {
         if (!(from instanceof to)){
             var fromStr;
             var toStr;
-            if (!from)
-                fromStr = "" + fromStr;
-            else if (from.constructor && from.constructor.name)
+            
+            if (from && from.constructor && from.constructor.name)
                 fromStr = "" + from.constructor.name;
-            if (!to)
-                toStr = "" + to;
-            else if (to.constructor && to.constructor.name)
+            else
+                fromStr = "" + from;
+            
+            if (to && to.constructor && to.constructor.name)
                 toStr = "" + to.constructor.name;
+            else
+                toStr = "" + to;
             
             var msg = "typeguard assertion failed";
             if (fromStr || toStr)               

+ 6 - 0
test/test_unit.js

@@ -245,6 +245,12 @@ return {
          ["vb(PDerived)",
           "invalid type cast: a value variable cannot be used in typeguard"])
     ),
+"NIL": testWithContext(
+    context(grammar.expression,
+            "VAR i: INTEGER;"),
+    pass(),
+    fail(["i = NIL", "type mismatch: expected 'INTEGER', got 'NIL'"])
+        ),
 "POINTER relations": testWithContext(
     context(grammar.expression,
             "TYPE B = RECORD END; D = RECORD(B) END;"