1. Object-oriented preprocessor
- Posted by jmduro Aug 24, 2022
- 2505 views
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
2. Re: Object-oriented preprocessor
- Posted by achury Aug 24, 2022
- 2466 views
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.
3. Re: Object-oriented preprocessor
- Posted by achury Aug 24, 2022
- 2479 views
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?
4. Re: Object-oriented preprocessor
- Posted by jmduro Aug 25, 2022
- 2447 views
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
5. Re: Object-oriented preprocessor
- Posted by jmduro Aug 25, 2022
- 2437 views
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
6. Re: Object-oriented preprocessor
- Posted by jmduro Aug 25, 2022
- 2456 views
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
7. Re: Object-oriented preprocessor
- Posted by jmduro Aug 25, 2022
- 2422 views
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
8. Re: Object-oriented preprocessor
- Posted by Icy_Viking Aug 25, 2022
- 2408 views
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?
9. Re: Object-oriented preprocessor
- Posted by jmduro Aug 26, 2022
- 2388 views
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
10. Re: Object-oriented preprocessor
- Posted by jmduro Aug 26, 2022
- 2402 views
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
11. Re: Object-oriented preprocessor
- Posted by jmduro Aug 26, 2022
- 2383 views
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
12. Re: Object-oriented preprocessor
- Posted by jmduro Aug 26, 2022
- 2357 views
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
13. Re: Object-oriented preprocessor
- Posted by ghaberek (admin) Aug 27, 2022
- 2332 views
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
14. Re: Object-oriented preprocessor
- Posted by jmduro Aug 29, 2022
- 2246 views
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
15. Re: Object-oriented preprocessor
- Posted by jmduro Aug 30, 2022
- 2140 views
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
16. Re: Object-oriented preprocessor
- Posted by ghaberek (admin) Aug 30, 2022
- 2129 views
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
17. Re: Object-oriented preprocessor
- Posted by jmduro Sep 09, 2022
- 1763 views
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
18. Re: Object-oriented preprocessor
- Posted by jmduro Sep 11, 2022
- 1678 views
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
19. Re: Object-oriented preprocessor
- Posted by jmduro Sep 12, 2022
- 1624 views
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
20. Re: Object-oriented preprocessor
- Posted by jmduro Sep 16, 2022
- 1459 views
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