Parcourir la source

Make possible to assign any variable to `JS.var` but not the opposite

Vladislav Folts il y a 4 ans
Parent
commit
189c137aa5
7 fichiers modifiés avec 108 ajouts et 131 suppressions
  1. 9 2
      doc/wiki/JS-module.md
  2. 2 0
      src/ob/Cast.ob
  3. 1 1
      src/ob/ContextDesignator.ob
  4. 15 2
      src/ob/ContextProcedure.ob
  5. 6 125
      src/ob/Module.ob
  6. 73 0
      src/ob/Types.ob
  7. 2 1
      test/test_unit.js

+ 9 - 2
doc/wiki/JS-module.md

@@ -16,8 +16,15 @@ You can call any JavaScript function (from global scope) using notation "JS.anyN
 
 ### JS.var
 
-*JS.var* is a type to explicit declaration of variables specific for JavaScript code.
+*JS.var* is a type intended for explicit declaration of variables specific for JavaScript code.
 
     VAR v: JS.var;
     ...
-    v := JS.someFunction();
+    v := JS.someFunction();
+
+*JS.var* is considered compatibale with any other type (there no any type checking as for JavaScript variables). But the opposite is not true: you cannot you cannot assign *JS.var* to Oberon types:
+
+    VAR v: JS.var; i: INTEGER;
+    ...
+    v := i; (* OK *)
+    i := v; (* compile error *)

+ 2 - 0
src/ob/Cast.ob

@@ -228,6 +228,8 @@ BEGIN
         IF areProceduresMatch(from, to) THEN
             result := errNo;
         END
+    ELSIF to = Types.any THEN
+        result := errNo;
     END;
 
     IF (result = errNo) & (op = NIL) THEN

+ 1 - 1
src/ob/ContextDesignator.ob

@@ -73,7 +73,7 @@ BEGIN
         SELF.currentType := info.type;
     ELSIF info IS Types.PVariable THEN
         SELF.currentType := info.type();
-        IF q.module # NIL THEN
+        IF (q.module # NIL) & (SELF.currentType # Types.any) THEN
             code := code + "()";
         END;
     ELSIF info IS Types.PProcedureId THEN

+ 15 - 2
src/ob/ContextProcedure.ob

@@ -57,6 +57,9 @@ TYPE
     EndParametersMsg* = RECORD(ContextHierarchy.Message)
     END;
 
+    AnyProcCall = RECORD(Procedure.Call)
+    END;
+
 PROCEDURE Declaration.Declaration(parent: ContextHierarchy.PNode)
     | SUPER(parent),
       outerScope(SELF.root().currentScope());
@@ -285,6 +288,15 @@ PROCEDURE AddArgumentMsg.AddArgumentMsg(name: STRING; arg: Types.PProcedureArgum
       arg(arg);
 END;
 
+PROCEDURE AnyProcCall.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
+BEGIN
+    argCode <- Procedure.makeArgumentsCode(cx);
+    FOR a IN args DO
+        argCode.write(a, NIL, NIL);
+    END;
+    RETURN Expression.makeSimple("(" + argCode.result() + ")", Types.any)
+END;
+
 PROCEDURE assertProcType(type: Types.PType; info: Types.PId): Procedure.PType;
 VAR
     unexpected: STRING;
@@ -307,8 +319,9 @@ END;
 
 PROCEDURE makeCall*(cx: ContextHierarchy.PNode; type: Types.PType; info: Types.PId): Procedure.PCallGenerator;
 BEGIN
-    RETURN assertProcType(type, info)
-          .callGenerator(ContextHierarchy.makeLanguageContext(cx));
+    l <- ContextHierarchy.makeLanguageContext(cx)
+    RETURN type = Types.any ? Procedure.makeCallGenerator(NEW AnyProcCall(), l)
+                            : assertProcType(type, info).callGenerator(l);
 END;
 
 END ContextProcedure.

+ 6 - 125
src/ob/Module.ob

@@ -1,121 +1,20 @@
 MODULE Module;
 IMPORT 
     Context, Errors, Expression, LanguageContext, Procedure, Symbols, TypeId, Types, Variable;
+CONST
+    doProcId = "do";
+    varTypeId = "var";
 TYPE
     Type* = RECORD(Types.Module)
         PROCEDURE findSymbol*(id: STRING): Symbols.PFoundSymbol
     END;
     PType* = POINTER TO Type;
 
-    AnyType = RECORD(Procedure.Type)
-        PROCEDURE AnyType();
-    END;
-
-    AnyVariable = RECORD(Variable.TypedVariable)
-        PROCEDURE AnyVariable();
-    END;
-
-    AnyField = RECORD(Types.Field)
-        PROCEDURE AnyField(id: STRING);
-
-        mId: STRING;
-    END;
-
-    AnyProcCall = RECORD(Procedure.Call)
-    END;
-
     JS = RECORD(Type)
     END;
 VAR
-    doProcId, varTypeId: STRING;
-    any: POINTER TO AnyType;
-    anyVar: POINTER TO AnyVariable;
     doProcSymbol, varTypeSymbol: Symbols.PSymbol;
 
-PROCEDURE AnyType.description(): STRING;
-    RETURN "JS.var"
-END AnyType.description;
-
-PROCEDURE AnyType.initializer(cx: Context.Type): STRING;
-    RETURN "undefined"
-END;
-
-PROCEDURE makeCallGenerator(cx: LanguageContext.PType): Procedure.PCallGenerator;
-    RETURN Procedure.makeCallGenerator(NEW AnyProcCall(), cx)
-END makeCallGenerator;
-
-PROCEDURE AnyType.callGenerator(cx: LanguageContext.PType): Procedure.PCallGenerator;
-    RETURN makeCallGenerator(cx)
-END AnyType.callGenerator;
-
-PROCEDURE AnyType.denote(id: STRING; isReadObly: BOOLEAN): Types.PField;
-    RETURN NEW AnyField(id);
-END;
-
-PROCEDURE AnyType.designatorCode(id: STRING): STRING;
-    RETURN id;
-END;
-
-PROCEDURE AnyType.isScalar(): BOOLEAN;
-    RETURN FALSE;
-END;
-
-PROCEDURE AnyType.args(): Types.ProcedureArguments;
-VAR
-    result: Types.ProcedureArguments;
-BEGIN
-    RETURN result;
-END;
-
-PROCEDURE AnyType.result(): Types.PType;
-    RETURN NIL;
-END;
-
-PROCEDURE AnyVariable.AnyVariable()
-    | SUPER(any);
-END;
-
-PROCEDURE AnyVariable.isReadOnly(): BOOLEAN;
-    RETURN FALSE;
-END;
-
-PROCEDURE AnyVariable.isReference(): BOOLEAN;
-    RETURN TRUE;
-END;
-
-PROCEDURE AnyField.id(): STRING;
-    RETURN "any field"
-END AnyField.id;
-
-PROCEDURE AnyField.exported(): BOOLEAN;
-    RETURN FALSE
-END AnyField.exported;
-
-PROCEDURE AnyField.type(): Types.PStorageType;
-    RETURN any
-END AnyField.type;
-
-PROCEDURE AnyField.asVar(leadCode: STRING; isReadOnly: BOOLEAN; cx: Context.Type): Types.PId;
-    RETURN anyVar;
-END;
-
-PROCEDURE AnyField.designatorCode(leadCode: STRING; cx: Context.Type): Types.PFieldCode;
-    RETURN NEW Types.FieldCode(leadCode + "." + SELF.mId, "", "");
-END;
-(*)
-PROCEDURE AnyTypeProc.callGenerator(cx: LanguageContext.PType): Procedure.PCallGenerator;
-    RETURN makeCallGenerator(cx)
-END AnyTypeProc.callGenerator;
-*)
-PROCEDURE AnyProcCall.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
-BEGIN
-    argCode <- Procedure.makeArgumentsCode(cx);
-    FOR a IN args DO
-        argCode.write(a, NIL, NIL);
-    END;
-    RETURN Expression.makeSimple("(" + argCode.result() + ")", any)
-END AnyProcCall.make;
-
 PROCEDURE JS.findSymbol(id: STRING): Symbols.PFoundSymbol;
 VAR
     result: Symbols.PSymbol;
@@ -125,15 +24,11 @@ BEGIN
     ELSIF id = varTypeId THEN
         result := varTypeSymbol;
     ELSE
-        result := NEW Symbols.Symbol(id, NEW Procedure.Id(any, id, FALSE));
+        result := NEW Symbols.Symbol(id, Types.anyVar);
     END;
     RETURN NEW Symbols.FoundSymbol(result, NIL)
 END JS.findSymbol;
 
-PROCEDURE makeVarTypeSymbol(): Symbols.PSymbol;
-    RETURN NEW Symbols.Symbol(varTypeId, NEW TypeId.Type(any))
-END makeVarTypeSymbol;
-
 PROCEDURE makeDoProcSymbol(): Symbols.PSymbol;
 TYPE
     Call = RECORD(Procedure.StdCall)
@@ -172,28 +67,14 @@ PROCEDURE makeJS*(): PType;
     RETURN NEW JS("JS");
 END;
 
-PROCEDURE AnyType.AnyType()
-    | SUPER("any type");
-END;
-
-PROCEDURE AnyField.AnyField(id: STRING)
-    | mId(id);
-END;
-
 PROCEDURE assertProcStatementResult*(type: Types.PType);
 BEGIN
-    IF (type # NIL) & ~(type^ IS AnyType) THEN
+    IF (type # NIL) & ~(type^ IS Types.Any) THEN
         Errors.raise("procedure returning a result cannot be used as a statement");
     END;
 END;
 
 BEGIN
-    doProcId := "do";
-    varTypeId := "var";
-    
-    NEW(any);
-    NEW(anyVar);
-
     doProcSymbol := makeDoProcSymbol();
-    varTypeSymbol := makeVarTypeSymbol();
+    varTypeSymbol := NEW Symbols.Symbol(varTypeId, NEW TypeId.Type(Types.any));
 END Module.

+ 73 - 0
src/ob/Types.ob

@@ -36,6 +36,9 @@ TYPE
     END;
     PDeclaredVariable* = POINTER TO DeclaredVariable;
 
+    AnyVariable = RECORD(Variable)
+    END;
+
     PProcedure* = POINTER TO Procedure;
 
     ProcedureId* = RECORD(Id)
@@ -71,12 +74,22 @@ TYPE
     END;
     PField* = POINTER TO Field;
 
+    AnyField = RECORD(Field)
+        PROCEDURE AnyField(id: STRING);
+
+        mId: STRING;
+    END;
+
     StorageType* = RECORD(Type)    
         PROCEDURE initializer*(cx: Context.Type): STRING;
         PROCEDURE denote*(id: STRING; isReadObly: BOOLEAN): PField;
         PROCEDURE isScalar*(): BOOLEAN;
     END;
 
+    Any* = RECORD(StorageType)
+    END;
+    PAny = POINTER TO Any;
+
     NamedType* = RECORD(StorageType)
         PROCEDURE NamedType*(name: STRING);
 
@@ -148,6 +161,8 @@ TYPE
     ArrayDimensionDescriptionCallback = PROCEDURE(VAR a: Array): STRING;
 
 VAR
+    any*: PAny;
+    anyVar*: POINTER TO AnyVariable;
     basic*: RECORD
         bool*, ch*, integer*, uint8*, real*, set*: PBasicType
     END;
@@ -155,10 +170,24 @@ VAR
     numeric*: ARRAY * OF PType;
     nil*: POINTER TO Nil;
 
+    type: PType;
+
 PROCEDURE typeName*(type: NamedType): STRING;
     RETURN type.name
 END typeName;
 
+PROCEDURE Any.initializer(cx: Context.Type): STRING;
+    RETURN "undefined"
+END;
+
+PROCEDURE Any.description(): STRING;
+    RETURN "JS.var"
+END;
+
+PROCEDURE Any.isScalar(): BOOLEAN;
+    RETURN TRUE;
+END;
+
 PROCEDURE ProcedureId.idType(): STRING;
     RETURN "procedure"
 END ProcedureId.idType;
@@ -202,6 +231,18 @@ PROCEDURE Variable.idType(): STRING;
     RETURN "variable"
 END Variable.idType;
 
+PROCEDURE AnyVariable.type(): PStorageType;
+    RETURN any;
+END;
+
+PROCEDURE AnyVariable.isReadOnly(): BOOLEAN;
+    RETURN FALSE;
+END;
+
+PROCEDURE AnyVariable.isReference(): BOOLEAN;
+    RETURN TRUE;
+END;
+
 PROCEDURE BasicType.description(): STRING;
     RETURN SELF.name
 END BasicType.description;
@@ -283,6 +324,30 @@ PROCEDURE Array.isScalar(): BOOLEAN;
     RETURN FALSE;
 END;
 
+PROCEDURE AnyField.AnyField(id: STRING)
+    | mId(id);
+END;
+
+PROCEDURE AnyField.id(): STRING;
+    RETURN "any field"
+END;
+
+PROCEDURE AnyField.exported(): BOOLEAN;
+    RETURN FALSE
+END;
+
+PROCEDURE AnyField.type(): PStorageType;
+    RETURN any
+END;
+
+PROCEDURE AnyField.asVar(leadCode: STRING; isReadOnly: BOOLEAN; cx: Context.Type): PId;
+    RETURN anyVar;
+END;
+
+PROCEDURE AnyField.designatorCode(leadCode: STRING; cx: Context.Type): PFieldCode;
+    RETURN NEW FieldCode(leadCode + "." + SELF.mId, "", "");
+END;
+
 PROCEDURE raiseUnexpectedSelector*(id: STRING; obj: STRING);
 BEGIN
     Errors.raise("selector '." + id + "' cannot be applied to '" + obj + "'");
@@ -294,6 +359,11 @@ BEGIN
     RETURN NIL
 END;
 
+PROCEDURE Any.denote(id: STRING; isReadOnly: BOOLEAN): PField;
+BEGIN
+    RETURN NEW AnyField(id);
+END;
+
 PROCEDURE OpenArray.initializer(cx: Context.Type): STRING;
     RETURN ""
 END OpenArray.initializer;
@@ -378,6 +448,9 @@ PROCEDURE FieldCode.FieldCode(code, derefCode, propCode: STRING)
 END;
 
 BEGIN
+    any := NEW Any();
+    anyVar := NEW AnyVariable();
+
     basic.bool := NEW BasicType("BOOLEAN", "false");
     basic.ch := NEW BasicType("CHAR", "0");
     basic.integer := NEW BasicType("INTEGER", "0");

+ 2 - 1
test/test_unit.js

@@ -1560,7 +1560,8 @@ return {
     grammar.module,
     pass("MODULE m; IMPORT JS; VAR v: JS.var; END m.",
          "MODULE m; IMPORT JS; VAR v: JS.var; BEGIN v := JS.f(); END m.",
-         "MODULE m; IMPORT JS; VAR v: JS.var; BEGIN v := JS.f1(); JS.f2(v); END m."
+         "MODULE m; IMPORT JS; VAR v: JS.var; BEGIN v := JS.f1(); JS.f2(v); END m.",
+         "MODULE m; IMPORT JS; VAR v: JS.var; i: INTEGER; BEGIN v := i; END m."
          ),
     fail(["MODULE m; IMPORT JS; VAR v: JS.var; i: INTEGER; BEGIN i := v; END m.",
           "type mismatch: 'INTEGER' cannot be assigned to 'JS.var' expression"])