The NetRexx interpreter and static state

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

The NetRexx interpreter and static state

Marc Simpson
Hi all,

I've been experimenting with the NetRexx interpreter API and
came across some surprising behaviour when dealing with
static state.

For starters, consider the following code which increments
a static field:

--( counter.nrx )---------------------------------
class counter
  properties static
  n = 0

  method increment static
    n = n + 1
    return n
--------------------------------------------------

and a simple client to call the increment method,

--( client.nrx )----------------------------------
say "(in client.nrx)"
say "=>" counter.increment
--------------------------------------------------

Running 'client.nrx' yields the expected result,

--8<----------------------------------------------
$ nrc -run client counter
NetRexx portable processor, version NetRexx 3.01RC2, build 1-20110925-2337
Copyright (c) RexxLA, 2011.  All rights reserved.
Parts Copyright (c) IBM Corporation, 1995,2008.
Program client.nrx
Program counter.nrx
  === class counter ===
    function increment
Compilation of 'client.nrx' successful
Compilation of 'counter.nrx' successful
Running client...
(in client.nrx)
=> 1
--8<----------------------------------------------

So far, so good.

Now for the interpreter. This code parses/interprets
'client.nrx' and calls the its main (static) method:

--( interpreted.nrx )----------------------------------
import org.netrexx.process.
interp1 = NetRexxA()
interp2 = NetRexxA()

-- Increment twice to make things clear:
counter.increment
say "~ interpreted.nrx counter:" counter.increment

rule = '-'.copies(40)
say rule
loop for 3
  say ":: performParse     [interp1]"
  performParse(interp1)
  say ":: performInterpret [interp2]"
  performInterpret(interp2)
  say rule
end

method performParse(interpreter=NetRexxA) static
  files = [String 'client.nrx']
  flags = [String 'nologo']
  res   = 0
  do
    res = interpreter.parse(files, flags)
    if \res then return
    c = interpreter.getClassObject(null, "client")
    if c = null then do
      say "Class 'client' not found."
      return
    end
    m = c.getMethod("main", [flags.getClass])
    m.invoke(c, [Object files])
  catch ex=Exception
    ex.printStackTrace
  end
  return

method performInterpret(interpreter=NetRexxA) static
  do
    output = slurp("client.nrx")
    interpreter.interpret("client", output, "", "")
  catch ex=Exception
    ex.printStackTrace
  end
  return

method slurp(filename) static-
             signals FileNotFoundException, IOException
  reader = BufferedReader(FileReader(filename))
  line   = reader.readLine
  output = ''
  loop while line <> null
    output = output'\n'line
    line   = reader.readLine
  end
  return output
-------------------------------------------------------

First, 'interpreted.nrx' increments the counter twice and
prints the second result (this is just to make things
clearer). It then loops three times calling (a) 'parse' and
(b) 'interpret' on distinct NetRexxA instances. Reuse of
'files' and 'flags' for method invocation is just to keep
things concise.

Here's the output:

--8<----------------------------------------------
$ nrc -run interpreted
NetRexx portable processor, version NetRexx 3.01RC2, build 1-20110925-2337
Copyright (c) RexxLA, 2011.  All rights reserved.
Parts Copyright (c) IBM Corporation, 1995,2008.
Program interpreted.nrx
    function performParse(NetRexxA)
    function performInterpret(NetRexxA)
    function slurp(Rexx)
Compilation of 'interpreted.nrx' successful
Running interpreted...
~ interpreted.nrx counter: 2
----------------------------------------
:: performParse     [interp1]
Program client.nrx
(in client.nrx)
=> 1
:: performInterpret [interp2]
(in client.nrx)
=> 1
----------------------------------------
:: performParse     [interp1]
Program client.nrx
(in client.nrx)
=> 1
:: performInterpret [interp2]
(in client.nrx)
=> 2
----------------------------------------
:: performParse     [interp1]
Program client.nrx
(in client.nrx)
=> 1
:: performInterpret [interp2]
(in client.nrx)
=> 3
----------------------------------------
--8<----------------------------------------------

Two things surprised me here:

[1] Both 'performParse' and 'performInterpret' start with a
    counter state of 0, not 2 -- mutation performed by
    'interpreted.nrx' prior to calling these methods has no
    effect.

[2] The 'interpret' method maintains state between calls
    while 'parse' does not (perhaps because 'interpret'
    calls 'exec' on the translator while I explicitly call
    getClassObject after 'parse'.)

I'd appreciate it if someone could explain this -- both the
lack of shared state between host and interpreter and the
different behaviour of 'interpret' and 'parse'.

Finally: is there a (safe) way to share static state between
'interpreted.nrx' and a NetRexxA instance?

Best,
M

_______________________________________________
Ibm-netrexx mailing list
[hidden email]
Online Archive : http://ibm-netrexx.215625.n3.nabble.com/