xsharp.eu • Macro compiler problem
Page 1 of 1

Macro compiler problem

Posted: Thu Jun 16, 2022 10:34 am
by Plummet
Hi Folks,
Is anyone aware of an issue with the MCompile() function in latest X#?

I have this code below, working fine in VO, that fails in X#.

FUNCTION Compile(cStr AS STRING) AS _CODEBLOCK PASCAL
// Compile(cStr)
// Takes a string and returns a codeblock - runtime compiler
// Might as well make use of it since the compiler
// is always linked into your apps!
//RETURN &('{|x,y,z|'+cStr+'}') // allow for 3 params?
LOCAL bCB AS _CODEBLOCK
LOCAL cText AS STRING
cText := '{|x,y,z| '+cStr+'}' // allow for 3 params?
//bCB := &(cText)
bCB := MCompile(cText)
//IF ! DebugMsgA({cStr, cText, &(cText), bCB, MCompile(cText)});BREAK;ENDIF
IF bCB == NULL_OBJECT
// DC_ThrowError(ProcName(0), , "Empty _CODEBLOCK", cStr)
? ProcName(0), "Empty _CODEBLOCK", cStr
ENDIF
RETURN bCB


In VO I use the & operator. When this didn't work in X# I tried the MCompile function - both compile but no difference.

I use it to compile code into a variable and then execute (Eval) the result on some data at run time.
In VO when I inspect the variable it is a compiled CB (works).
In X# when I inspect the variable it is just the text unchanged (fails).

Thanks for any hints ...
Don

Macro compiler problem

Posted: Thu Jun 16, 2022 10:50 am
by robert
Don,
This should work just like VO.
Can you create a complete example.

Robert

Macro compiler problem

Posted: Thu Jun 16, 2022 12:55 pm
by Plummet
OK - X# code:
FUNCTION Compile(cStr AS STRING) AS _CODEBLOCK PASCAL
// Compile(cStr)
// Takes a string and returns a codeblock - runtime compiler
// Might as well make use of it since the compiler
// is always linked into your apps!
//RETURN &('{|x,y,z|'+cStr+'}') // allow for 3 params?
LOCAL bCB AS _CODEBLOCK
LOCAL cText AS STRING
cText := '{|x,y,z| '+cStr+'}' // allow for 3 params?
bCB := &(cText)
IF bCB == NULL_OBJECT
? ProcName(0), "Empty _CODEBLOCK", cText
ENDIF
RETURN bCB

FUNCTION DisplayArray(a)
AEval(a, {|x| ShowIt(x)})
RETURN NIL

FUNCTION ShowIt(x)
? x
RETURN NIL

FUNCTION Start() AS INT
LOCAL aCode, aCompiledCode AS ARRAY
LOCAL I AS DWORD
LOCAL cElem AS STRING
aCode := {}
aCompiledCode := {}
// sample rt logic
AAdd(aCode, "x:=IIF(z>1,STRTRAN(x,',','|'),x)")
DisplayArray(aCode)
WAIT
FOR I := 1 UPTO ALen(aCode)
cElem := aCode
AAdd(aCompiledCode, Compile(cElem))
NEXT
//WAIT
DisplayArray(aCompiledCode)
/* should get this
{(0x0010)0x101027D8} CLASS _CODEBLOCK
*/
WAIT
RETURN NIL


Strange thing is, this piece of code fails now in VO, although a completely similar logic works in 2 other apps. It's not my day ... :(
Don

Macro compiler problem

Posted: Thu Jun 16, 2022 1:51 pm
by robert
Don,
There is an error in your example:

Code: Select all

cElem := aCode
this should be

Code: Select all

cElem := aCode[i]
The codeblock is created properly.
What probably confuses you is that X# does not show

Code: Select all

{(0x0010)0x101027D8} CLASS _CODEBLOCK
but it shows the source code for the compiled codeblock:

Code: Select all

{|x,y,z| x:=IIF(z>1,STRTRAN(x,',','|'),x)}
But the codeblock is real. You can test that by evaluating the codeblock

Add this to the loop and you will see that it works:

Code: Select all

? Eval(ATail(aCompiledCode),  "a,b,c",0,1)
? Eval(ATail(aCompiledCode),  "a,b,c",0,2)
Roberty

Macro compiler problem

Posted: Thu Jun 16, 2022 5:38 pm
by Plummet
Thanks for explanation Robert.

Yes, I was expecting CLASS _CODEBLOCK. And yes it works ok now in this example.

BTW the error was only in the paste into the post. Sorry.

Unfortunately for some reason the evaluation still does not work in my actual program. This is the actual method -

METHOD EvaluateSubstitutionRules(cLine := NULL_STRING AS STRING, K AS DWORD) AS STRING PASCAL
// use run-time codeblocks read from cCfgFile file
LOCAL I AS DWORD
LOCAL cRet AS STRING
//LOCAL uError AS USUAL
//LOCAL oOldErrorHandler AS CODEBLOCK
// local error handler
//oOldErrorHandler := ErrorBlock({|o| _Break(o)})
IF ! SELF:lHaveSubstitute
RETURN cLine
ENDIF

BEGIN SEQUENCE
cRet := cLine
FOR I := 1 UPTO ALen(SELF:aSubstitute)
// poll event queue
DoEvents()
// break if error in eval
cRet := SELF:aSubstitute:Eval(cRet, , K)
IF SLen(cRet) == 0
// mod 15Mar2004
// allow substituting to remove an empty line - useful in script generation
EXIT
ENDIF
NEXT

END SEQUENCE
//ErrorBlock(oOldErrorHandler)
// NB. return modified line ...
RETURN cRet


cLine is the line of text.
SELF:aSubstitute is the array of compile CBs.
K is the line number.

Thanks for any hints -
Don

Macro compiler problem

Posted: Thu Jun 16, 2022 5:43 pm
by robert
Don
Try to isolate this in a stand alone program and upload that here or mail it.
Most likely the error is somewhere else.

Robert

Macro compiler problem

Posted: Thu Jun 16, 2022 5:49 pm
by Plummet
Another copy/paste error!

// break if error in eval
cRet := SELF:aSubstitute:Eval(cRet, , K)


The eval line does not display correctly!! SELF:aSubstitute should be followed by the index I,
but the square brackets just set italics for some reason!

Next time I'll attach code in a text file.
Gremlins in HTML or forum software?
Don

Macro compiler problem

Posted: Thu Jun 16, 2022 5:52 pm
by Plummet
Another copy/paste error!

// break if error in eval
cRet := SELF:aSubstitute:Eval(cRet, , K)


The eval line does not display correctly!! SELF:aSubstitute should be followed by the index I,
but the square brackets just set italics for some reason!

Next time I'll attach code in a text file.
Gremlins in HTML or forum software?
Don

Oops, I now see there is a button for code

Code: Select all

			// break if error in eval
			cRet := SELF:aSubstitute[I]:Eval(cRet, , K)
Sorry :/

Macro compiler problem

Posted: Thu Jun 16, 2022 6:32 pm
by Plummet
OK, I think the problem is resolved.

Instead of -

Code: Select all

cRet := SELF:aSubstitute[I]:Eval(cRet, , K)
use -

Code: Select all

cRet := Eval(SELF:aSubstitute[I], cRet, , K)
and it works, although the array:Eval method does not give an error.

Thanks all
Don

Macro compiler problem

Posted: Fri Jun 17, 2022 6:40 am
by robert
Don,
The original code is translated by the compiler into a late bound call of the Eval() method of the codeblock.
I am not sure why this does not work, but I am glad you found a workaround

Robert