1. Object-oriented preprocessor

I have have updated my previous Class preprocessor to be used with OEU -p option: http://jean-marc.duro.pagesperso-orange.fr/oop_demo.zip

Let's take following example, test_class.oex:

include std/datetime.e 
include std/console.e 
 
function get_years(atom secs) 
  atom days = floor(secs/86400) 
  return floor(days/365.25) 
end function 
 
class person 
  datetime birth_date 
  sequence birth_place 
  sequence mother_tongue 
  procedure describe(sequence params) 
    atom secs = diff(self.birth_date, now()) 
    printf(1, "\nHello! I speak %s.\n", {self.mother_tongue}) 
    if length(params) then 
      printf(1, "I am %d years old. I was born in %s (%s).\n", {get_years(secs), self.birth_place, params[1]}) 
    else 
      printf(1, "I am %d years old. I was born in %s.\n", {get_years(secs), self.birth_place}) 
    end if 
  end procedure 
end class 
 
sequence englishman = new(person) 
englishman.birth_date = datetime:new(2010, 5, 14) 
englishman.birth_place = "Liverpool" 
englishman.mother_tongue = "english" 
 
sequence frenchman = new(person) 
frenchman.birth_date = datetime:new(1960, 8, 10) 
frenchman.birth_place = "Thionville" 
frenchman.mother_tongue = "french" 
 
sequence german = new(person) 
german.birth_date = datetime:new(1993, 2, 23) 
german.birth_place = "Munich" 
german.mother_tongue = "german" 
 
englishman.describe({"Merseyside"}) 
frenchman.describe({"Lorraine"}) 
german.describe({"Bavaria"}) 
 
maybe_any_key() 

Run it with the preprocessor:

C:\Data\Euphoria\oop_demo>eui -p oex:classes.ex test_classes.oex 
 
Hello! I speak english. 
I am 12 years old. I was born in Liverpool (Merseyside). 
 
Hello! I speak french. 
I am 62 years old. I was born in Thionville (Lorraine). 
 
Hello! I speak german. 
I am 29 years old. I was born in Munich (Bavaria). 
 
C:\Data\Euphoria\oop_demo> 

Jean-Marc

new topic     » topic index » view message » categorize

2. Re: Object-oriented preprocessor

Very nice.

That is an run-time preprocessor? Or the processed file is saved to avoid process on each run?

Also I am curios to check how would looks the preprocessed file.

new topic     » goto parent     » topic index » view message » categorize

3. Re: Object-oriented preprocessor

I already check. Very nice and simple! An object is just a sequence of attribs that includes a pointer to the method.

Some languages today use things like pass a function as parameter, and functions that return functions.

Such things may me emulated on a similar way, just receiving or passing proc_id?

new topic     » goto parent     » topic index » view message » categorize

4. Re: Object-oriented preprocessor

Run as indicated with -p option, OE preprocesses the file and generates test_classes.pp.oex which is run. This is transparent to the user. The processed file remains so you can have a look at it.

Jean-Marc

new topic     » goto parent     » topic index » view message » categorize

5. Re: Object-oriented preprocessor

achury said...

Some languages today use things like pass a function as parameter, and functions that return functions.

Such things may me emulated on a similar way, just receiving or passing proc_id?

I don't know. Maybe there is something to try. I'm not sure this can work without also having var_id as with OOEU or VEEU.

Jean-Marc

new topic     » goto parent     » topic index » view message » categorize

6. Re: Object-oriented preprocessor

There is always a class-like method here: http://jean-marc.duro.pagesperso-orange.fr/non-oop_demo.zip

include std/datetime.e 
include std/console.e 
include classes.e 
 
------------------------------------------------------------------------------ 
 
function get_years(atom secs) 
  atom days = floor(secs/86400) 
  return floor(days/365.25) 
end function 
 
------------------------------------------------------------------------------ 
 
function describe(integer entityID, sequence params) 
  atom secs = diff(getProperty(entityID, "birth_date"), now()) 
  printf(1, "\nHello! I speak %s.\n", {getProperty(entityID, "mother_tongue")}) 
  if length(params) then 
    printf(1, "I am %d years old. I was born in %s (%s).\n", {get_years(secs), getProperty(entityID, "birth_place"), params[1]}) 
  else 
    printf(1, "I am %d years old. I was born in %s.\n", {get_years(secs), getProperty(entityID, "birth_place")}) 
  end if 
  return 0 
end function 
 
------------------------------------------------------------------------------ 
 
procedure main(sequence cmd) 
  object void 
  integer TPerson = class("TPerson") 
 
  addProperty(TPerson, "birth_date", now()) 
  addProperty(TPerson, "birth_place", "") 
  addProperty(TPerson, "mother_tongue", "") 
  addMethod(TPerson, "describe", routine_id("describe")) 
 
  integer englishman = classes:new(TPerson) 
  setProperty(englishman, "birth_date", datetime:new(2010, 5, 14)) 
  setProperty(englishman, "birth_place", "Liverpool") 
  setProperty(englishman, "mother_tongue", "english") 
 
  integer frenchman = classes:new(TPerson) 
  setProperty(frenchman, "birth_date", datetime:new(1960, 8, 10)) 
  setProperty(frenchman, "birth_place", "Thionville") 
  setProperty(frenchman, "mother_tongue", "french") 
 
  integer german = classes:new(TPerson) 
  setProperty(german, "birth_date", datetime:new(1993, 2, 23)) 
  setProperty(german, "birth_place", "Munich") 
  setProperty(german, "mother_tongue", "german") 
 
  void = callMethod(englishman, "describe", {"Merseyside"}) 
  void = callMethod(frenchman, "describe", {"Lorraine"}) 
  void = callMethod(german, "describe", {"Bavaria"}) 
end procedure  -- main 
 
------------------------------------------------------------------------------ 
 
-- Main 
main(command_line()) 
maybe_any_key() 

Do you mean something else ?

Jean-Marc

new topic     » goto parent     » topic index » view message » categorize

7. Re: Object-oriented preprocessor

There is even a version without lists of classes or entities: http://jean-marc.duro.pagesperso-orange.fr/class_demo.zip

include std/datetime.e 
include std/console.e 
include classes.e 
 
------------------------------------------------------------------------------ 
 
function get_years(atom secs) 
  atom days = floor(secs/86400) 
  return floor(days/365.25) 
end function 
 
------------------------------------------------------------------------------ 
 
function describe(sequence entity, sequence params) 
  atom secs = diff(getProperty(entity, "birth_date"), now()) 
  printf(1, "\nHello! I speak %s.\n", {getProperty(entity, "mother_tongue")}) 
  if length(params) then 
    printf(1, "I am %d years old. I was born in %s (%s).\n", {get_years(secs), getProperty(entity, "birth_place"), params[1]}) 
  else 
    printf(1, "I am %d years old. I was born in %s.\n", {get_years(secs), getProperty(entity, "birth_place")}) 
  end if 
  return 0 
end function 
 
------------------------------------------------------------------------------ 
 
procedure main(sequence cmd) 
  object void 
 
  sequence TPerson = class("TPerson") 
  TPerson = addProperty(TPerson, "birth_date", now()) 
  TPerson = addProperty(TPerson, "birth_place", "") 
  TPerson = addProperty(TPerson, "mother_tongue", "") 
  TPerson = addMethod(TPerson, "describe", routine_id("describe")) 
 
  sequence englishman = classes:new(TPerson) 
  englishman = setProperty(englishman, "birth_date", datetime:new(2010, 5, 14)) 
  englishman = setProperty(englishman, "birth_place", "Liverpool") 
  englishman = setProperty(englishman, "mother_tongue", "english") 
 
  sequence frenchman = classes:new(TPerson) 
  frenchman = setProperty(frenchman, "birth_date", datetime:new(1960, 8, 10)) 
  frenchman = setProperty(frenchman, "birth_place", "Thionville") 
  frenchman = setProperty(frenchman, "mother_tongue", "french") 
 
  sequence german = classes:new(TPerson) 
  german = setProperty(german, "birth_date", datetime:new(1993, 2, 23)) 
  german = setProperty(german, "birth_place", "Munich") 
  german = setProperty(german, "mother_tongue", "german") 
 
  void = callMethod(englishman, "describe", {"Merseyside"}) 
  void = callMethod(frenchman, "describe", {"Lorraine"}) 
  void = callMethod(german, "describe", {"Bavaria"}) 
end procedure  -- main 
 
------------------------------------------------------------------------------ 
 
-- Main 
main(command_line()) 
maybe_any_key() 

Jean-Marc

new topic     » goto parent     » topic index » view message » categorize

8. Re: Object-oriented preprocessor

jmduro said...

There is even a version without lists of classes or entities: http://jean-marc.duro.pagesperso-orange.fr/class_demo.zip

include std/datetime.e 
include std/console.e 
include classes.e 
 
------------------------------------------------------------------------------ 
 
function get_years(atom secs) 
  atom days = floor(secs/86400) 
  return floor(days/365.25) 
end function 
 
------------------------------------------------------------------------------ 
 
function describe(sequence entity, sequence params) 
  atom secs = diff(getProperty(entity, "birth_date"), now()) 
  printf(1, "\nHello! I speak %s.\n", {getProperty(entity, "mother_tongue")}) 
  if length(params) then 
    printf(1, "I am %d years old. I was born in %s (%s).\n", {get_years(secs), getProperty(entity, "birth_place"), params[1]}) 
  else 
    printf(1, "I am %d years old. I was born in %s.\n", {get_years(secs), getProperty(entity, "birth_place")}) 
  end if 
  return 0 
end function 
 
------------------------------------------------------------------------------ 
 
procedure main(sequence cmd) 
  object void 
 
  sequence TPerson = class("TPerson") 
  TPerson = addProperty(TPerson, "birth_date", now()) 
  TPerson = addProperty(TPerson, "birth_place", "") 
  TPerson = addProperty(TPerson, "mother_tongue", "") 
  TPerson = addMethod(TPerson, "describe", routine_id("describe")) 
 
  sequence englishman = classes:new(TPerson) 
  englishman = setProperty(englishman, "birth_date", datetime:new(2010, 5, 14)) 
  englishman = setProperty(englishman, "birth_place", "Liverpool") 
  englishman = setProperty(englishman, "mother_tongue", "english") 
 
  sequence frenchman = classes:new(TPerson) 
  frenchman = setProperty(frenchman, "birth_date", datetime:new(1960, 8, 10)) 
  frenchman = setProperty(frenchman, "birth_place", "Thionville") 
  frenchman = setProperty(frenchman, "mother_tongue", "french") 
 
  sequence german = classes:new(TPerson) 
  german = setProperty(german, "birth_date", datetime:new(1993, 2, 23)) 
  german = setProperty(german, "birth_place", "Munich") 
  german = setProperty(german, "mother_tongue", "german") 
 
  void = callMethod(englishman, "describe", {"Merseyside"}) 
  void = callMethod(frenchman, "describe", {"Lorraine"}) 
  void = callMethod(german, "describe", {"Bavaria"}) 
end procedure  -- main 
 
------------------------------------------------------------------------------ 
 
-- Main 
main(command_line()) 
maybe_any_key() 

Jean-Marc

I wonder if this would work making wrappers?

Something like

include classes.e 
 
sequence TRect = class("TRect") 
TRect = addProperty(TRect,atom x,"") 
TRect = addProperty(TRect,atom y,"") 

Would that work or would I be on the right track?

new topic     » goto parent     » topic index » view message » categorize

9. Re: Object-oriented preprocessor

Icy_Viking said...

I wonder if this would work making wrappers?

Something like

include classes.e 
 
sequence TRect = class("TRect") 
TRect = addProperty(TRect,atom x,"") 
TRect = addProperty(TRect,atom y,"") 

Would that work or would I be on the right track?

Actual syntax would be:

TRect = addProperty(TRect,"x",0)  
TRect = addProperty(TRect,"y",0)  

x and y are objects in the actual code.

sequence TRect is stored as

{"TRect", {{"x",0}, {"y",0}}, {}} 

You probably want it to be in another format.

Jean-Marc

new topic     » goto parent     » topic index » view message » categorize

10. Re: Object-oriented preprocessor

Let's take an example with win32lib.

Original code:

global procedure drawRectangle( integer id, integer filled, 
	    	    integer x1, integer y1, 
	    	    integer x2, integer y2 ) 
 
    -- draw a rectangle 
    atom hdc 
 
    -- get the device context 
    hdc = getDC( id ) 
 
    -- create a pen 
    createPen( id, hdc ) 
 
    -- create the brush 
    createBrush( id, filled, hdc ) 
 
    -- call Rectangle 
    VOID = w32Func( xRectangle, {hdc, x1, y1, x2, y2 } ) 
 
    -- release the device context 
    releaseDC( id ) 
end procedure 

You would probably define a generic class TRect then specify properties of its instance rect as follows:

--generic class 
sequence TRect = class("TRect")  
TRect = addProperty(TRect,"x1",0)  
TRect = addProperty(TRect,"y1",0)  
TRect = addProperty(TRect,"x2",0)  
TRect = addProperty(TRect,"y2",0)  
 
-- specific instance: x2 and y2 differ from default values 
sequence rect = classes:new(TRect) 
rect = setProperty(rect, "x2", 10) 
rect = setProperty(rect, "y2", 10) 

Class-like code first version (needs to rewrite win32lib):

global procedure drawRectangle( integer id, integer filled, 
	    	    sequence rect ) 
    integer x1 = getProperty(rect, "x1") 
    integer y1 = getProperty(rect, "y1") 
	  integer x2 = getProperty(rect, "x2") 
    integer y2 = getProperty(rect, "y2") 
     
    -- draw a rectangle 
    atom hdc 
 
    -- get the device context 
    hdc = getDC( id ) 
 
    -- create a pen 
    createPen( id, hdc ) 
 
    -- create the brush 
    createBrush( id, filled, hdc ) 
 
    -- call Rectangle 
    VOID = w32Func( xRectangle, {hdc, x1, y1, x2, y2 } ) 
 
    -- release the device context 
    releaseDC( id ) 
end procedure 
 
drawRectangle(win, 1, rect ) 

Class-like code second version (uses original win32lib):

TRect = addMethod(TRect, "drawRectangle", routine_id("drawRectangle"))  
void = callMethod(rect, "drawRectangle", {id, filled, 
  getProperty(rect, "x1"), 
  getProperty(rect, "y1"), 
  getProperty(rect, "x2"), 
  getProperty(rect, "y2") 
}) 

It remains verbose compared to classical Openeuphoria style.

To get something more easy to program, I think the preprocessor version is more adequate (untested).

include win32lib as win 
 
class TRect 
  integer x1, y1, x2, y2 
  procedure drawRectangle(sequence params) 
    win:drawRectangle(params[1], params[2], 
	    	    self.x1, self.y1, 
	    	    self.x2, self.y2 ) 
  end procedure 
end class 
 
sequence rect = new(TRect) 
rect.x2 = 10 
rect.y2 = 10 
rect.drawRectangle({win, filled}) 

Jean-Marc

new topic     » goto parent     » topic index » view message » categorize

11. Re: Object-oriented preprocessor

If the preprocessor was not in alpha stage following win32lib demo (mletext.exw) could have been written in OOP style:

include win32lib_r2.ew 
without warning 
 
constant w = create(Window, "MLE Test", 0, 0, 0, 400, 300, 0), 
         m = create(MleText, "", w, 10, 10, 200, 200, 0) 
          
setText(m, "Line 1\nLine 2\nLine 3") 
 
WinMain(w, Normal)          

OOP style:

include win32lib_r2.ew as win 
 
class TWindow 
  integer id 
  sequence caption 
  atom pOwner 
  object x 
  object y 
  object cx 
  object cy 
  object styleFlags 
   
  procedure create(sequence params) 
    self.caption = params[1] 
    self.pOwner = params[2] 
    self.x = params[3] 
    self.y = params[4] 
    self.cx = params[5] 
    self.cy = params[6] 
    self.styleFlags = params[7] 
    self.id = win:create(Window, 
      self.caption, self.pOwner, 
      self.x, self.y, self.cx, self.cy, 
      self.styleFlags) 
  end procedure 
end class 
 
class TMleText 
  integer id 
  sequence caption 
  atom pOwner 
  object x 
  object y 
  object cx 
  object cy 
  object styleFlags 
   
  procedure create(sequence params) 
    self.caption = params[1] 
    self.pOwner = params[2] 
    self.x = params[3] 
    self.y = params[4] 
    self.cx = params[5] 
    self.cy = params[6] 
    self.styleFlags = params[7] 
    self.id = win:create(MleText, 
      self.caption, self.pOwner, 
      self.x, self.y, self.cx, self.cy, 
      self.styleFlags) 
  end procedure 
   
  procedure set(sequence params) 
    win:setText(self.id, params[1]) 
  end procedure 
   
  function get(sequence params) 
    win:getText(MleText) 
  end function 
end class 
 
sequence win = new(TWindow) 
win.create({"MLE Test", 0, 0, 0, 400, 300, 0}) 
 
sequence mle = new(TMleText) 
mle.create({"", w, 10, 10, 200, 200, 0}) 
mle.set({"Line 1\nLine 2\nLine 3"}) 
 
WinMain(win.id, Normal)          

This sould have been translated to:

include win32lib_r2.ew as win 
without warning 
 
procedure class_proc(sequence entity, integer method, sequence params = {}) 
  call_proc(entity[method], {entity, params}) 
end procedure 
 
function class_func(sequence entity, integer method, sequence params = {}) 
  return call_func(entity[method], {entity, params}) 
end function 
 
 
enum type TWINDOW 
  TWINDOW_ID, TWINDOW_CAPTION, TWINDOW_POWNER, 
  TWINDOW_X, TWINDOW_Y, TWINDOW_CX, TWINDOW_CY, 
  TWINDOW_STYLEFLAGS, 
 
  TWINDOW_CREATE 
end type 
 
sequence TWindow = {0,"",0,0,0,0,0,0, 
                    routine_id("TWindow_create")} 
 
function TWindow_create(sequence entity, sequence params) 
  entity[TWINDOW_CAPTION] = params[1] 
  entity[TWINDOW_POWNER] = params[2] 
  entity[TWINDOW_X] = params[3] 
  entity[TWINDOW_Y] = params[4] 
  entity[TWINDOW_CX] = params[5] 
  entity[TWINDOW_CY] = params[6] 
  entity[TWINDOW_STYLEFLAGS] = params[7] 
  entity[TWINDOW_ID] = win:create(Window, 
    entity[TWINDOW_CAPTION], entity[TWINDOW_POWNER], 
    entity[TWINDOW_X], entity[TWINDOW_Y], entity[TWINDOW_CX], entity[TWINDOW_CY], 
    entity[TWINDOW_STYLEFLAGS]) 
  return entity 
end function 
 
enum type TMLETEXT 
  TMLETEXT_ID, TMLETEXT_CAPTION, TMLETEXT_POWNER, 
  TMLETEXT_X, TMLETEXT_Y, TMLETEXT_CX, TMLETEXT_CY, 
  TMLETEXT_STYLEFLAGS, 
 
  TMLETEXT_CREATE, 
  TMLETEXT_SET, 
  TMLETEXT_GET 
end type 
 
sequence TMleText = {0,"",0.0,0,0,0,0,0, 
                     routine_id("TMleText_create"), 
                     routine_id("TMleText_set"), 
                     routine_id("TMleText_get")} 
 
function TMleText_create(sequence entity, sequence params) 
  entity[TMLETEXT_CAPTION] = params[1] 
  entity[TMLETEXT_POWNER] = params[2] 
  entity[TMLETEXT_X] = params[3] 
  entity[TMLETEXT_Y] = params[4] 
  entity[TMLETEXT_CX] = params[5] 
  entity[TMLETEXT_CY] = params[6] 
  entity[TMLETEXT_STYLEFLAGS] = params[7] 
  entity[TMLETEXT_ID] = win:create(MleText, 
    entity[TMLETEXT_CAPTION], entity[TMLETEXT_POWNER], 
    entity[TMLETEXT_X], entity[TMLETEXT_Y], entity[TMLETEXT_CX], entity[TMLETEXT_CY], 
    entity[TMLETEXT_STYLEFLAGS]) 
  return entity 
end function 
 
procedure TMleText_set(sequence entity, sequence params) 
  win:setText(entity[TMLETEXT_ID], params[1]) 
end procedure 
 
function TMleText_get(sequence entity, sequence params) 
  return win:getText(entity[TMLETEXT_ID]) 
end function 
 
sequence win = TWindow 
win = class_func(win, TWINDOW_CREATE, {"MLE Test", 0, 0, 0, 400, 300, 0}) 
 
sequence mle = TMleText 
mle = class_func(mle, TMLETEXT_CREATE, {"", win[TWINDOW_ID], 10, 10, 200, 200, 0}) 
class_proc(mle, TMLETEXT_SET, {"Line 1\nLine 2\nLine 3"}) 
 
WinMain(win[TWINDOW_ID], Normal)          

Targeted translated code has been tested: it works like the original demo.

Unfortunately, the preprocessor is far from being able to translate the code correctly. It doesn't work with multiple classes in same file. It doesn't work with trailing spaces, and so on.

Jean-Marc

new topic     » goto parent     » topic index » view message » categorize

12. Re: Object-oriented preprocessor

With a drop of inheritance, OOP style would be:

include win32lib_r2.ew as win 
 
class TWin32() 
  integer id = 0 
  sequence caption = "" 
  atom pOwner = 0 
  object x = 0, y = 0, cx = 0, cy = 0 
  object styleFlags = 0 
 
  procedure create(sequence params) 
    self.caption = params[1] 
    self.pOwner = params[2] 
    self.x = params[3] 
    self.y = params[4] 
    self.cx = params[5] 
    self.cy = params[6] 
    self.styleFlags = params[7] 
  end procedure 
end class 
 
class TWindow(TWin32) 
  procedure create(sequence params) 
    super.create(params) 
    self.id = win:create(Window, 
      self.caption, self.pOwner, 
      self.x, self.y, self.cx, self.cy, 
      self.styleFlags) 
  end procedure 
end class 
 
class TMleText(TWin32) 
  procedure create(sequence params) 
    super.create(params) 
    self.id = win:create(MleText, 
      self.caption, self.pOwner, 
      self.x, self.y, self.cx, self.cy, 
      self.styleFlags) 
  end procedure 
 
  procedure set(sequence params) 
    win:setText(self.id, params[1]) 
  end procedure 
 
  function get(sequence params) 
    win:getText(MleText) 
  end function 
end class 
 
sequence win = new(TWindow) 
win.create({"MLE Test", 0, 0, 0, 400, 300, 0}) 
 
sequence mle = new(TMleText) 
mle.create({"", w, 10, 10, 200, 200, 0}) 
mle.set({"Line 1\nLine 2\nLine 3"}) 
 
WinMain(win.id, Normal) 

targeted translated code should be:

include win32lib_r2.ew as win 
without warning 
 
procedure class_proc(sequence entity, integer method, sequence params = {}) 
  call_proc(entity[method], {entity, params}) 
end procedure 
 
function class_func(sequence entity, integer method, sequence params = {}) 
  return call_func(entity[method], {entity, params}) 
end function 
 
enum type TWIN32 
  TWIN32_ID, TWIN32_CAPTION, TWIN32_POWNER, 
  TWIN32_X, TWIN32_Y, TWIN32_CX, TWIN32_CY, 
  TWIN32_STYLEFLAGS, 
 
  TWIN32_CREATE 
end type 
 
sequence TWin32 = {0,"",0,0,0,0,0,0} 
 
enum type TWINDOW 
  TWINDOW_CREATE = TWIN32_CREATE 
end type 
 
sequence TWindow = TWin32 & { 
                     routine_id("TWindow_create") 
                   } 
 
function TWindow_create(sequence entity, sequence params) 
  entity[TWIN32_CAPTION] = params[1] 
  entity[TWIN32_POWNER] = params[2] 
  entity[TWIN32_X] = params[3] 
  entity[TWIN32_Y] = params[4] 
  entity[TWIN32_CX] = params[5] 
  entity[TWIN32_CY] = params[6] 
  entity[TWIN32_STYLEFLAGS] = params[7] 
  entity[TWIN32_ID] = win:create(Window, 
    entity[TWIN32_CAPTION], entity[TWIN32_POWNER], 
    entity[TWIN32_X], entity[TWIN32_Y], entity[TWIN32_CX], entity[TWIN32_CY], 
    entity[TWIN32_STYLEFLAGS]) 
  return entity 
end function 
 
enum type TMLETEXT 
  TMLETEXT_CREATE = TWIN32_CREATE, 
  TMLETEXT_SET, 
  TMLETEXT_GET 
end type 
 
sequence TMleText = TWin32 & { 
                      routine_id("TMleText_create"), 
                      routine_id("TMleText_set"), 
                      routine_id("TMleText_get") 
                    } 
 
function TMleText_create(sequence entity, sequence params) 
  entity[TWIN32_CAPTION] = params[1] 
  entity[TWIN32_POWNER] = params[2] 
  entity[TWIN32_X] = params[3] 
  entity[TWIN32_Y] = params[4] 
  entity[TWIN32_CX] = params[5] 
  entity[TWIN32_CY] = params[6] 
  entity[TWIN32_STYLEFLAGS] = params[7] 
  entity[TWIN32_ID] = win:create(MleText, 
    entity[TWIN32_CAPTION], entity[TWIN32_POWNER], 
    entity[TWIN32_X], entity[TWIN32_Y], entity[TWIN32_CX], entity[TWIN32_CY], 
    entity[TWIN32_STYLEFLAGS]) 
  return entity 
end function 
 
procedure TMleText_set(sequence entity, sequence params) 
  win:setText(entity[TWIN32_ID], params[1]) 
end procedure 
 
function TMleText_get(sequence entity, sequence params) 
  return win:getText(entity[TWIN32_ID]) 
end function 
 
sequence win = TWindow 
win = class_func(win, TWINDOW_CREATE, {"MLE Test", 0, 0, 0, 400, 300, 0}) 
 
sequence mle = TMleText 
mle = class_func(mle, TMLETEXT_CREATE, {"", win[TWIN32_ID], 10, 10, 200, 200, 0}) 
class_proc(mle, TMLETEXT_SET, {"Line 1\nLine 2\nLine 3"}) 
 
WinMain(win[TWIN32_ID], Normal)          

Target code has been tested OK.

Jean-Marc

new topic     » goto parent     » topic index » view message » categorize

13. Re: Object-oriented preprocessor

I really think we need to add object oriented features to the core of the interpreter instead of trying to pad around it with the preprocessor (which I'm still not convinced is a great feature). I'd really like to merge Matt's OOEU but that merge is going to have to be done by hand. It's probably a better approach than how memstruct works and I'm pretty sure it could be use to provide structure support as well.

-Greg

new topic     » goto parent     » topic index » view message » categorize

14. Re: Object-oriented preprocessor

ghaberek said...

I'd really like to merge Matt's OOEU but that merge is going to have to be done by hand.

-Greg

When I ported OOEU to Raspberry Pi, I used partially OpenEuphoria code to get it working. Maybe it can help: http://jean-marc.duro.pagesperso-orange.fr/ooeu-pi-1-9-0.tar.gz

Jean-Marc

new topic     » goto parent     » topic index » view message » categorize

15. Re: Object-oriented preprocessor

I used the last OpenEuphoria 4.1 development code from Github and I tried to apply almost all changes (except goto and continue) added by Matt to this version. It is available here: http://jean-marc.duro.pagesperso-orange.fr/ooeu-master.zip

It is buggy as expected but the problem is how to debug it ? When I run the class.ex demo of OOEU, I get this:

C:\Data\Euphoria\ooeu-pi-1-9-0\ooeu\demo\class.ex:2 
<0019>:: 'p' has not been declared 
global euclass person( sequence p ) 
                                 ^ 

It doesn't help. I needed many days to implement all the changes. 12 files were modified.

Jean-Marc

new topic     » goto parent     » topic index » view message » categorize

16. Re: Object-oriented preprocessor

jmduro said...

It is buggy as expected but the problem is how to debug it ? When I run the class.ex demo of OOEU, I get this:

Yeah that's part of the problem I've been having with memstruct as well. I've tried running eu.ex with trace() in some cases but most of the time it's just awful trying to make sense of anything. I want to see how the scanner reads source code and what its output looks like, and then see how the parser reads tokens and what its output looks like, etc. So the "best" approach is probably to deconstruct each major component into independently testable parts and examine them at each step, which basically means refactoring the entire codebase without even having it stable to begin with. We also need better debugging tools because trace() just doesn't cut it any more. I want to be able to see the entire symbol table in memory and step through the execution of a program. Ugh. That's just so much to do.

-Greg

new topic     » goto parent     » topic index » view message » categorize

17. Re: Object-oriented preprocessor

I have updated my object-oriented translator. It seems robust enough to be usable on a daily basis now and it is still available on the link provided at the beginning of this thread.

It allows now multiple classes in the same file. An example is provided using win32lib_r2.ew, my restructured version of Win32Lib available on rapideuphoria.com and on archive.usingeuphoria.com. It has some debugging facilities too.

Arguments of the translator are the same as for the preprocessor: -i <input_file> -o <output_file>. It has to be adapted as a real preprocessor.

Run with parameters "-i test_classes.oex -o test_classes.ex", it translates the provided input file, test_classes.oex, in a file that can be executed by OpenEuphoria: test_classes.ex which displays a window with an MleText input.

It uses an updated version of my library that extracts variables of a string according to a template.

Jean-Marc

new topic     » goto parent     » topic index » view message » categorize

18. Re: Object-oriented preprocessor

I have tested the program as a preprocessor with following command and it works with no change.

eui -p oex:preprocessor.ex test_classes.oex 

It translates following class-like program:

include win32lib_r2.ew as win 
 
class TWin32() 
  integer self.hwnd = 0 
  sequence self.caption = "" 
  atom self.pOwner = 0 
  object self.x = 0, self.y = 0, self.cx = 0, self.cy = 0 
  object self.styleFlags = 0 
 
  procedure create(sequence params) 
    self.caption = params[1] 
    self.pOwner = params[2] 
    self.x = params[3] 
    self.y = params[4] 
    self.cx = params[5] 
    self.cy = params[6] 
    self.styleFlags = params[7] 
  end procedure 
end class 
 
class TWindow(TWin32) 
  sequence self.additional = "unused" 
  procedure create(sequence params) 
    super.create(params) 
    self.additional = params[8] 
    self.hwnd = win:create(Window, 
      self.caption, self.pOwner, 
      self.x, self.y, self.cx, self.cy, 
      self.styleFlags) 
  end procedure 
end class 
 
class TMleText(TWin32) 
  procedure create(sequence params) 
    super.create(params) 
    self.hwnd = win:create(MleText, 
      self.caption, self.pOwner, 
      self.x, self.y, self.cx, self.cy, 
      self.styleFlags) 
  end procedure 
 
  procedure set(sequence params) 
    win:setText(self.hwnd, params[1]) 
  end procedure 
 
  function get(sequence params) 
    return win:getText(self.hwnd) 
  end function 
end class 
 
sequence mainWin = new(TWindow) 
mainWin.create({"MLE Test", 0, 0, 0, 300, 300, 0, "unused"}) 
mainWin.cx = 400 
 
sequence mle = new(TMleText) 
mle.create({"", mainWin.hwnd, 10, 10, 200, 200, 0}) 
mle.set({"Line 1\nLine 2\nLine 3"}) 
 
WinMain(mainWin.hwnd, Normal) 

Resulting code, test_classes.pp.oex, is as follows:

include win32lib_r2.ew as win 
 
include classes.e 
f_debug = open("debug.log", "w") 
 
 
--- class TWin32 --------------------------------------------------------------- 
 
integer TWin32 = class("TWin32") 
 
addProperty(TWin32, "hwnd", 0) 
addProperty(TWin32, "caption", "") 
addProperty(TWin32, "pOwner", 0) 
addProperty(TWin32, "x", 0) 
addProperty(TWin32, "y", 0) 
addProperty(TWin32, "cx", 0) 
addProperty(TWin32, "cy", 0) 
addProperty(TWin32, "styleFlags", 0) 
 
function TWin32_create(integer instanceID, sequence params) 
  setProperty(instanceID, "caption", params[1]) 
  setProperty(instanceID, "pOwner", params[2]) 
  setProperty(instanceID, "x", params[3]) 
  setProperty(instanceID, "y", params[4]) 
  setProperty(instanceID, "cx", params[5]) 
  setProperty(instanceID, "cy", params[6]) 
  setProperty(instanceID, "styleFlags", params[7]) 
  return 0 
end function 
addMethod(TWin32, "create", routine_id("TWin32_create")) 
 
 
--- class TWindow -------------------------------------------------------------- 
 
integer TWindow = class("TWindow", TWin32) 
 
addProperty(TWindow, "additional", "unused") 
 
function TWindow_create(integer instanceID, sequence params) 
  callParentMethod(instanceID, "create", params) 
  setProperty(instanceID, "additional", params[8]) 
  setProperty(instanceID, "hwnd", win:create(Window, getProperty(instanceID, "caption"), getProperty(instanceID, "pOwner"), getProperty(instanceID, "x"), getProperty(instanceID, "y"), getProperty(instanceID, "cx"), getProperty(instanceID, "cy"), getProperty(instanceID, "styleFlags"))) 
  return 0 
end function 
addMethod(TWindow, "create", routine_id("TWindow_create")) 
 
 
--- class TMleText ------------------------------------------------------------- 
 
integer TMleText = class("TMleText", TWin32) 
 
 
function TMleText_create(integer instanceID, sequence params) 
  callParentMethod(instanceID, "create", params) 
  setProperty(instanceID, "hwnd", win:create(MleText, getProperty(instanceID, "caption"), getProperty(instanceID, "pOwner"), getProperty(instanceID, "x"), getProperty(instanceID, "y"), getProperty(instanceID, "cx"), getProperty(instanceID, "cy"), getProperty(instanceID, "styleFlags"))) 
  return 0 
end function 
addMethod(TMleText, "create", routine_id("TMleText_create")) 
 
function TMleText_set(integer instanceID, sequence params) 
  win:setText(getProperty(instanceID, "hwnd"), params[1])  
  return 0 
end function 
addMethod(TMleText, "set", routine_id("TMleText_set")) 
 
function TMleText_get(integer instanceID, sequence params) 
  return win:getText(getProperty(instanceID, "hwnd"))  
end function 
addMethod(TMleText, "get", routine_id("TMleText_get")) 
 
-------------------------------------------------------------------------------- 
 
 
 
integer mainWin = classes:new("mainWin", TWindow) 
callMethod(mainWin, "create", {"MLE Test", 0, 0, 0, 300, 300, 0, "unused"}) 
setProperty(mainWin, "cx", 400) 
 
integer mle = classes:new("mle", TMleText) 
callMethod(mle, "create", {"", getProperty(mainWin, "hwnd"), 10, 10, 200, 200, 0}) 
callMethod(mle, "set", {"Line 1\nLine 2\nLine 3"}) 
 
WinMain(getProperty(mainWin, "hwnd"), Normal) 
close(f_debug) 

Of course, you have to update eu.cfg to your own configuration.

I wonder if it would make sense to rewrite whole Win32Lib_r2 one of both ways (with the preprocessor or in the resulting style).

Jean-Marc

new topic     » goto parent     » topic index » view message » categorize

19. Re: Object-oriented preprocessor

I have have added scoping to the Class preprocessor: http://jean-marc.duro.pagesperso-orange.fr/oop_demo.zip

Now, classes can be used in modules. Using OEU -p oex:preprocessor.ex main.oex automatically translates not only the main file but also included files.

I had to understand how -p option works. Lines referring to includes files to be preprocessed have to be renamed with extension .pp.oex only at the end of the preprocessing. See the preprocessor code (deferred_includes).

Now I will adapt the demo\win32 examples of OEU. This will be in another thread when available and could be a basis for a new win32lib_r2.oex.

As the preprocessor leaves translated files in place, users will have to versions available: OOP style and translated version.

Jean-Marc

new topic     » goto parent     » topic index » view message » categorize

20. Re: Object-oriented preprocessor

jmduro said...

Now I will adapt the demo\win32 examples of OEU. This will be in another thread when available and could be a basis for a new win32lib_r2.oex.

As the preprocessor leaves translated files in place, users will have to versions available: OOP style and translated version.

The preprocessor has still a lot of bugs but the translated version of the windows demo works. It is available here: http://jean-marc.duro.pagesperso-orange.fr/window_demo.zip

I don't see the benefits of programming in such a way. It has roughly the same number of lines of code than the original.

Maybe if the whole win32lib replacement was written it could be different. Than, the demo would be:

include new_win32lib.ew 
include classes.e 
 
-- callback routine to handle Window class 
function WndProc(atom hwnd, atom iMsg, atom wParam, atom lParam) 
  atom  
    wav_file = allocate_string(getenv("windir")&`\Media\tada.wav`), 
    Euphoria = allocate_string("A Plain Vanilla Window using Euphoria!"), 
    ps = allocate(64), 
    rect = allocate(16)  
 
  if iMsg = WM_CREATE then 
    c_proc(PlaySound, {wav_file, 
           NULL, 
           or_bits(SND_FILENAME, SND_ASYNC)}) 
    return 0 
 
  elsif iMsg = WM_PAINT then 
    atom hdc = c_func(BeginPaint, {hwnd, ps}) 
    c_proc(GetClientRect, {hwnd, rect}) 
    c_proc(DrawText, {hdc, Euphoria, -1, rect,  
          or_all({DT_SINGLELINE, DT_CENTER, DT_VCENTER})}) 
    c_proc(EndPaint, {hwnd, ps}) 
    return 0 
 
  elsif iMsg = WM_DESTROY then 
    c_proc(PostQuitMessage, {0}) 
    return 0 
   
  end if 
   
  return c_func(DefWindowProc, {hwnd, iMsg, wParam, lParam}) 
end function 
 
integer mainWin = classes:new("mainWin", TWindow) 
callMethod(mainWin, "create", {"MLE Test", 0, 0, 0, 300, 300, 0, routine_id("WndProc")}) 
 
WinMain() 

It is such a tremendous work that it will probably not be achieved.

Jean-Marc

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu