[Oberon] FPGA - Simple OOP example

Jörg joerg.straube at iaeth.ch
Tue Aug 14 19:05:21 CEST 2018


Tomas

Your example is a very good base.
Please understand the following hints only as a minor refinement of your
example....
Hint1: Try to separate the procedures (methods of your object) from the
object's data. Okay in the example, your Terms had no local data but as a
general design pattern.

MODULE Term;
TYPE
   T* = POINTER TO TDesc;
   Methods* = POINTER TO MDesc;
   MDesc = RECORD
      Write*: PROCEDURE (t: Term);
      Refresh*: PROCEDURE (t: Term);
      (* other methods come here *)
   END;
   TDesc = RECORD
      do*: Methods;
      (* generic terminal data comes here *)
   END;
VAR methods: Methods;
PROCEDURE InitMethods*(VAR m: Methods); BEGIN m := methods END Methods;

Hint2: Then in every specific module provide an Init() procedure for the
specific terminal, to initialize the DATA for that specific type of Term.
Initialize the METHODS once per module in the module body.

MODULE CapTerm;
IMPORT Term;
TYPE
   T* = POINTER TO TermDesc;
   TDesc = RECORD (Term.TDesc) col: INTEGER (*or any data you may need for
CapTerm *) END;

VAR m: Term.Methods;

PROCEDURE Init* (t: T; color: INTEGER (* other data for the CapTerm if any
*));
   BEGIN t.do := m; t.col := color END Init;

PROCEDURE Write(t: Term.T, ch: CHAR); BEGIN (* Write method specific to
CapTerm *) END Write;
(* let's assume Refresh() has not to be overwritten *)

BEGIN
   (* here you allocate the container for all your CapTerm methods once per
module and initialize it with the specific CapTerm methods *)
   NEW(m); Term.InitMethods(m); m.Write := Write; (* you have the
possibility to overwrite Write, but leave e.g Refresh as in the base methods
*)
END CapTerm.

Hint3: The parameter t:Term to the procedures is basically only needed to
find the local data of your term not the methods.
As in your specific example term have no local data, you could basically
leave away the parameter, but as a general design add it to the methods.

Then in your Test module you can write something like this

MODULE Test;
IMPORT Term, CapTerm;
VAR t: Term.T; c: CapTerm.T;
BEGIN
   NEW(t); Term.Init(t);                t.do.Write(t, "Q");
t.do.Refresh(t);   (* calls Term.Refresh *)
   NEW(c); CapTerm.Init(c, 20);  c.do.Write(c, "A");   c.do.Refresh(c)   (*
also calls Term.Refresh, as we chose to not overwrite it with
CapTerm.Refresh *)
END Test.

-----Original Message-----
From: Oberon [mailto:oberon-bounces at lists.inf.ethz.ch] On Behalf Of Tomas
Kral
Sent: Tuesday, August 14, 2018 1:52 PM
To: Oberon at lists.inf.ethz.ch
Subject: [Oberon] FPGA - Simple OOP example

Hi,

Just reading Oberon book on OOP by Hanspeter Mosenbok. I would like to set a
reusable code pattern for that, not sure how close I am, my try below. There
is also other way of doing it, using so called `message' handler.

Cheers Tomas

MODULE Term; (* TK 14.8.2018 lower/capital case terminal, simple OOP example
*)
  IMPORT Texts, Oberon;

  TYPE
    Term* = POINTER TO TermDesc;
    TermDesc* = RECORD
      write*: PROCEDURE(t: Term; ch: CHAR)
    END ;

    VAR
      W: Texts.Writer; t*: Term;

    (* Generic output routine accepting any Term based type *)

    PROCEDURE Out*(t: Term; ch: CHAR);
    BEGIN t.write(t, ch)
    END Out;

    PROCEDURE Write(t: Term; ch: CHAR);
    BEGIN
      Texts.Write(W, ch); Texts.Append(Oberon.Log, W.buf)
    END Write;
    
BEGIN  Texts.OpenWriter(W); NEW(t); t.write := Write; END Term.


MODULE CapTerm; (* capital terminal *)
  IMPORT Term, Texts, Oberon;

  TYPE
    CapTerm* = POINTER TO CapTermDesc;
    CapTermDesc* = RECORD (Term.TermDesc) END ;
     
  VAR
     W: Texts.Writer; ct*: CapTerm;

  PROCEDURE CAP(ch: CHAR): CHAR;
    VAR up: CHAR;
  BEGIN
    up := CHR(ORD(ch) + ORD("A") - ORD("a"));
  RETURN up END CAP;

  PROCEDURE Write(t: Term.Term; ch: CHAR);
  BEGIN
    IF (ch >= "a") OR (ch <= "z") THEN ch := CAP(ch) END ;
    Texts.Write(W, ch); Texts.Append(Oberon.Log, W.buf)
  END Write;

BEGIN Texts.OpenWriter(W); NEW(ct); ct.write := Write; END CapTerm.


MODULE TestTerm;
  IMPORT Term, CapTerm, Texts, Oberon;

  VAR
    W: Texts.Writer; t: Term.Term; ct: 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
      Term.Out(t, S.s[0]); Term.Out(ct, S.s[0]);
      Texts.Scan(S)
    END ;
    Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
  END Run;

BEGIN Texts.OpenWriter(W); t := Term.t; ct := CapTerm.ct; 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