[Oberon] FPGA - OberonV4 Dialogs

Jörg joerg.straube at iaeth.ch
Tue Nov 27 00:21:57 CET 2018


I just realized that the „do“ field has to be outside of the inheritance tree.
We should have two inheritance trees: one for the fields (without „do“) and one for the methods.

MODULE Term;

TYPE
  Term* = POINTER TO Desc;
  MethodPtr = POINTER TO Methods;
  Fields* = RECORD (* generic terminal data comes here *) END;
  Methods* = RECORD
    Write*: PROCEDURE(t: Term, ch: CHAR);
    Refresh*: PROCEDURE(t: Term);
    Ln*: PROCEDURE(t: Term);
  END
  Desc = RECORD (Fields)
     do*: MethodPtr
  END

MODULE CapTerm;

TYPE
  Term* = POINTER TO Desc;
  MethodPtr = POINTER TO Methods;
  Fields* = RECORD (Term.Fields)
    (* cap terminal data comes here *)
    col: INTEGER
  END;
  Methods* = RECORD (Term.Methods)
    Write0*: PROCEDURE(ct: Term);
    Write1*: PROCEDURE (ct: Term)
  END;
  Desc = RECORD (Fields)
    do*: MethodPtr
  END;
    
By applying this code pattern you don‘t have to use type guards for the „do“ calls.
You used              c.do(CapTerm.Methods).Write0(c)
You now write      c.do.Write0(c)    as c.do has the correct type

Jörg

> Am 26.11.2018 um 20:17 schrieb Tomas Kral <thomas.kral at email.cz>:
> 
> On Mon, 26 Nov 2018 15:22:28 +0100
> Jörg <joerg.straube at iaeth.ch> wrote:
> 
>> Dialog Texts will call the init procedure of Dialog Objects to
>> initialize its "method" RECORD with the base procedures. Afterwards
>> will overwrite some (or all) of the procedure with the own ones.
> 
> Hi,
> 
> Yes this helps. I have revisited `Term' OOP example, in effort to set a
> good coding template. I added methods to extended `CapTerm' type, that are
> initialised and called along the base methods. Type guard needed.
> 
> Is this any good?
> 
> MODULE Term; (* TK 16.8.2018 / 26.11.2018  revised OOP example *)
>  IMPORT Texts, Oberon;
> 
>  TYPE
>    Term* = POINTER TO TDesc;
>    Methods* = POINTER TO MDesc;
> 
>    (* Base method suite *)
> 
>    MDesc* = RECORD
>      Write*: PROCEDURE(t: Term; ch: CHAR);
>      Refresh*: PROCEDURE(t: Term);
>      Ln*: PROCEDURE(t: Term)
>      (* other methods come here *)
>    END ;
> 
>    (* Base data suite *)
> 
>    TDesc* = RECORD
>      do*: Methods;
>      (* generic terminal data comes here *)
>    END ;
> 
>  VAR W: Texts.Writer; methods: Methods;
> 
>  (* ------ Initialisation for clients ------ *)
> 
>  PROCEDURE Init*(t: Term);
>  BEGIN t.do := methods
>  END Init;
> 
>  PROCEDURE Clone*((*VAR*)m: Methods);
>  BEGIN m^ := methods^
>  END Clone;
> 
>  PROCEDURE Get*(VAR m: Methods);
>  BEGIN m := methods
>  END Get;
> 
>  (* ------ Term base methods ----- *)
> 
>  PROCEDURE Write(t: Term; ch: CHAR);
>  BEGIN Texts.Write(W, ch)
>  END Write;
> 
>  PROCEDURE Refresh(t: Term);
>  BEGIN Texts.Append(Oberon.Log, W.buf)
>  END Refresh;
> 
>  PROCEDURE Ln(t: Term);
>  BEGIN Texts.WriteLn(W)
>  END Ln;
> 
> BEGIN Texts.OpenWriter(W); NEW(methods); methods.Write := Write; methods.Refresh := Refresh; methods.Ln := Ln
> END Term.
> 
> 
> MODULE CapTerm;
>  IMPORT Term;
> 
>  TYPE
>    CapTerm* = POINTER TO CTDesc;
>    Methods* = POINTER TO MDesc;
> 
>    (* CapTerm specific methods *)
> 
>    MDesc* = RECORD(Term.MDesc)
>      Write0*: PROCEDURE(t: CapTerm);
>      Write1*: PROCEDURE(t: CapTerm);
>      (* other methods come here *)
>    END ;
> 
>    (* CapTerm specific data *)
> 
>    CTDesc* = RECORD (Term.TDesc)
>      (* cap terminal data comes here *)
>      col: INTEGER 
>    END ;
> 
>  VAR self: Methods; super: Term.Methods;
> 
>  PROCEDURE Init*(t: CapTerm; color: INTEGER (* other data for the CapTerm if any *) );
>  BEGIN t.do := self; t.col := color
>  END Init;
> 
>  PROCEDURE CAP(ch: CHAR): CHAR;
>    VAR up: CHAR;
>  BEGIN
>    IF (ch >= "a") & (ch <= "z") THEN
>      up := CHR(ORD(ch) + ORD("A") - ORD("a"))
>    ELSE up := ch END
>  RETURN up END CAP;
> 
>  (* --------- Methods added to CapTerm ------- *)
> 
>  PROCEDURE Write0(t: CapTerm);
>  BEGIN
>    super.Write(t, "0") (* upcalls base Term.Write() *)
>  END Write0;
> 
>  PROCEDURE Write1(t: CapTerm);
>  BEGIN
>    super.Write(t, "1") (* upcalls base Term.Write() *)
>  END Write1;
> 
>  (* --------- Methods overriden from Term base ------- *)
> 
>  PROCEDURE Write(t: Term.Term; ch: CHAR);
>  (* Write method specific for CapTerm *)
>  BEGIN
>    ch := CAP(ch); super.Write(t, ch) (* upcalls base Term.Write() *)
>  END Write;
> 
>  (* Refresh() method not to be overriden *)
>  (* Ln() method not to be overriden *)
> 
> BEGIN NEW(self); Term.Clone(self); Term.Get(super); self.Write := Write; self.Write0 := Write0; self.Write1 := Write1;
> END CapTerm.
> 
> 
> MODULE TestTerm;
>  IMPORT Texts, Term, CapTerm, Oberon;
> 
>  VAR t: Term.Term; c: CapTerm.CapTerm;
> 
>  PROCEDURE Run*;
>    VAR S: Texts.Scanner;
>  BEGIN
>    Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
>    WHILE S.class = Texts.Name DO
>      t.do.Write(t, S.s[0]); t.do.Refresh(t); 
>      c.do.Write(c, S.s[0]); c.do.Refresh(c); (* calls Term.Refresh() *)
>      Texts.Scan(S)
>    END ;
>    c.do(CapTerm.Methods).Write0(c); c.do(CapTerm.Methods).Write1(c); (* prints 01, note do(typeguard) *)
>    c.do.Ln(c); t.do.Ln(t); c.do.Refresh(c) (* calls Term.Ln() twice *)
>  END Run;
> 
> BEGIN NEW(t); Term.Init(t); NEW(c); CapTerm.Init(c, 20)
> END TestTerm.
> 
> TestTerm.Run  a b c ~
> 
> 
> 
> -- 
> Tomas Kral <thomas.kral at email.cz>
> --
> Oberon at lists.inf.ethz.ch mailing list for ETH Oberon and related systems
> https://lists.inf.ethz.ch/mailman/listinfo/oberon



More information about the Oberon mailing list