Oxygen Basic

Programming => Bugs & Feature Requests => Topic started by: pber on June 21, 2014, 06:50:57 AM

Title: compile/call
Post by: pber on June 21, 2014, 06:50:57 AM
hi charles,
i'm writing some test functions that make use of compile/call

assert quote -- mid("123",1,1) = "1"  --
assert quote -- "1" = mid("123",1,1)  --

the 2nd row crashes.
The code evaluated is something like

Code: [Select]
    basic
    if not ( "1" = mid("123",1,1) ) then
        assertErr=-1
    end if
Title: Re: compile/call
Post by: Charles Pegge on June 21, 2014, 07:25:03 AM
Hi Paolo, Can you give more details?
Title: Re: compile/call
Post by: pber on June 21, 2014, 07:46:47 AM
hi Charles,

it seems it crashes only when printing a string.
The initial code I used was similar to this one

Code: [Select]
int assertError=0
string src= quote ||

if not ( "2" = mid("123",2,1) ) then
  assertError= -1
endif
||

sys p= compile(src)
call p

print assertError
print "ok"

the print with assertError pass,
the one with "ok" generates gpf

Now I worked around this problem by assigning
the 2 values to be compared to 2 different sys vars,
then testing. This way the problem does not occur.


.
Title: Re: compile/call
Post by: pber on June 21, 2014, 07:57:30 AM
...my mini-asserts have some problem with UDF

this does not work:

Code: [Select]
function mySqrt(int n)
  return sqrt(n)
end function

assertEQ "3" , "mySqrt(9)"
Title: Re: compile/call
Post by: pber on June 21, 2014, 08:26:52 AM
oh... code evaluated by compile
does not see outer functions, only variables  :(
Title: Re: compile/call
Post by: Charles Pegge on June 21, 2014, 09:09:32 AM
There is a simple workaround for most things :)

The solution is to use a vectored function, wherebye the function address is stored in a variable, which is visible to your dynamic code.

declare *foo()
@foo=@foofun


Code: [Select]
function foofun() as sys, label
===============================
print "foo!"
end function

declare *foo()
@foo=@foofun

function DynExec(string src)
============================
sys    c=compile src
string er=error
if er then
  print "DynExec:" er
else
  call c
end if
freememory c
end function

DynExec "foo()"
Title: Re: compile/call
Post by: pber on June 22, 2014, 02:30:07 AM
Great!

What does label mean?
Code: [Select]
...
function foofun() as sys, label
...
Your example works even without it.

Your example implies the compiled code must use a different syntax
(i.e. function names in compiled code are different
from the "production" code).

Oxygen does not implement namespace, and scope is anonymous.

Maybe I could implement a module-system like this:
Code: [Select]
' here i want to be sure that functions
' are still callable (even if not exported outside the module)
sub worker_function()
  print "I'm just an anonymous worker"
end sub

function entry_function() as sys ', label
  worker_function
end function

type fun_module
    sys (* f1)()
   
    ''''''''''''''''''''''''''
    ' next 2 do not work (...don't they declare a name?)
    'declare *f1() as sys
    '! * f1() as sys
end type

' declare and initialize module <fun>
dim fun as fun_module
@fun.f1= @entry_function


function DynExec(string src)
============================
sys    c=compile src
string er=error
if er then
  print "DynExec:" er
else
  call c
end if
freememory c
end function


DynExec "fun.f1()"

Do exist a better way?
Title: Re: compile/call
Post by: Charles Pegge on June 22, 2014, 03:48:49 AM
Dynamically compiled code has the same syntax as statically compiled code, though there are constraints on the visibility of host functions variables. It's somewhat like a DLL.

OxygenBasic does not have namespaces but scopes are available to confine visibility, without requiring procedures.

sys a=42
scope
  sys a=24
  print a '24
end scope
print a '42

Procedures can also be defined inside procedures, if you need to confine them.

Code: [Select]
function f(sys a,b) as sys
  sys c=45
  '
  function g() as sys
  return a+b+c
  end function
  '
  return g()
end function

print f 100,200 'result 345
Title: Re: compile/call
Post by: Charles Pegge on June 22, 2014, 10:23:23 AM
Not to forget classes as the optimal construct for encapsulation:

Code: [Select]
class fruit
===========

sys skin,flesh,seed

method juice()
print "Juice!"
end method

end class

fruit apple
fruit.juice()
Title: Re: compile/call
Post by: Peter on June 22, 2014, 12:22:19 PM
Quote
class fruit

Hi Charles
Is a joke, isn't it  ;D



.
Title: Re: compile/call
Post by: Charles Pegge on June 22, 2014, 12:44:54 PM
Oh, deadly serious :)

Classes  and their methods are directly visible to dynamically compiled code. No need to setup a vectored function as above:

Code: [Select]
class fruit
===========

sys skin,flesh,seed

method juice()
print "Juice!"
end method

end class


function DynExec(string src)
============================
sys    c
c=compile src
string er=error
if er then
  print "DynExec:" er
else
  call c
end if
freememory c
end function

DynExec "fruit pear : pear.juice" 'Juice!

Title: Re: compile/call
Post by: pber on June 22, 2014, 02:33:01 PM
Right: using class make things simpler.
thanks Charles.
Title: Re: compile/call
Post by: JRS on June 22, 2014, 05:23:11 PM
Quote from: Peter
Is a joke, isn't it

Oops, no joke.

Title: Re: compile/call
Post by: pber on June 23, 2014, 12:38:14 AM
Oxygen is not a joke.
Without tests i'm not able to move one step ahead,
using classes and objects do not make things easier.

...i feel like they do just what they want, not what i say to do