ldmud-3.2.9/doc/
ldmud-3.2.9/doc/efun/
ldmud-3.2.9/mud/
ldmud-3.2.9/mud/heaven7/
ldmud-3.2.9/mud/heaven7/lib/
ldmud-3.2.9/mud/lp-245/
ldmud-3.2.9/mud/lp-245/banish/
ldmud-3.2.9/mud/lp-245/doc/
ldmud-3.2.9/mud/lp-245/doc/examples/
ldmud-3.2.9/mud/lp-245/doc/sefun/
ldmud-3.2.9/mud/lp-245/log/
ldmud-3.2.9/mud/lp-245/obj/Go/
ldmud-3.2.9/mud/lp-245/players/lars/
ldmud-3.2.9/mud/lp-245/room/death/
ldmud-3.2.9/mud/lp-245/room/maze1/
ldmud-3.2.9/mud/lp-245/room/sub/
ldmud-3.2.9/mud/lp-245/secure/
ldmud-3.2.9/mud/morgengrauen/
ldmud-3.2.9/mud/morgengrauen/lib/
ldmud-3.2.9/mud/sticklib/
ldmud-3.2.9/mud/sticklib/src/
ldmud-3.2.9/mudlib/uni-crasher/
ldmud-3.2.9/pkg/
ldmud-3.2.9/pkg/debugger/
ldmud-3.2.9/pkg/diff/
ldmud-3.2.9/pkg/misc/
ldmud-3.2.9/src/autoconf/
ldmud-3.2.9/src/bugs/
ldmud-3.2.9/src/bugs/MudCompress/
ldmud-3.2.9/src/bugs/b-020916-files/
ldmud-3.2.9/src/bugs/doomdark/
ldmud-3.2.9/src/bugs/ferrycode/ferry/
ldmud-3.2.9/src/bugs/ferrycode/obj/
ldmud-3.2.9/src/bugs/psql/
ldmud-3.2.9/src/done/
ldmud-3.2.9/src/done/order_alist/
ldmud-3.2.9/src/done/order_alist/obj/
ldmud-3.2.9/src/done/order_alist/room/
ldmud-3.2.9/src/gcc/
ldmud-3.2.9/src/gcc/2.7.0/
ldmud-3.2.9/src/gcc/2.7.1/
ldmud-3.2.9/src/hosts/
ldmud-3.2.9/src/hosts/GnuWin32/
ldmud-3.2.9/src/hosts/amiga/NetIncl/
ldmud-3.2.9/src/hosts/amiga/NetIncl/netinet/
ldmud-3.2.9/src/hosts/amiga/NetIncl/sys/
ldmud-3.2.9/src/hosts/i386/
ldmud-3.2.9/src/hosts/msdos/byacc/
ldmud-3.2.9/src/hosts/msdos/doc/
ldmud-3.2.9/src/hosts/os2/
ldmud-3.2.9/src/hosts/win32/
ldmud-3.2.9/src/util/
ldmud-3.2.9/src/util/erq/
ldmud-3.2.9/src/util/indent/hosts/next/
ldmud-3.2.9/src/util/xerq/
ldmud-3.2.9/src/util/xerq/lpc/
ldmud-3.2.9/src/util/xerq/lpc/www/
Short: Inline-Closures with runtime arguments
From: d-chat
Date: 2002-05-28 (actually one year earlier)
Type: Feature
State: Done - implemented in 3.3.271
See also: f-991104-1

Generische Syntax:
  func mixed (int a, int b, ...) {}
  func (int a, int b, ...) {}
  func {} -> implicite parameters $1..

To pass parameters from the generating function to the lfun, a special kind of
lfun closure is used internally which adds an array of initial values:


  void caller() {
    int i;
    return func int (int a) { return a + i; }
  }

is compiled as

  int _func_1(mixed * _vals, int a) { return a + _vals[i]; }
  void caller() {
    int i;
    return context_lfun(#'_func_1, ({ i }));
  }

A funcall()/apply() on this special lfun then executes internally:

   _func_1( ({ i }), a);

On VM level, the VM gets a new svalue_t* 'context' which points to the
inherited context variables (i in this example). The storage area is in the
closure_t, similar to how arrays are stored. The context variables are
accessed using special bytecodes similar to the F_LOCAL bytecodes. In effect,
a context lfun has three variable spaces: global, local, and context.

As a result, assignments to the inherited vars are possible, but effect just
this closure, not the creating function.

The '==' and '!=' operators need to be extended to compare two inlines with
identical context values as equal.

    Note: with this context (and linking of contexts through a
    'parent_context' pointer in the VM control record) it would be possible to
    use implement local functions as in Oberon. Creating an lfun from a local
    function would be legal, however the context pointer would be NULL and any
    attempt to access a context variable would cause a runtime error.

How to implement with a one-pass compiler and without lexer hacks:

Lexer recognizes keyword 'func' as L_FUNC, value is the synthetic name of the
function. Parser upon receipt of L_FUNC remembers the current program address
and starts a new function. Once the inline function is complete, the block is
stored in a list, and the program size is set back to the stored address.
Now the assignment of the local variables to the context is done.
When the creating function is complete, all stored inline functions are
inserted back into the program block. Be careful though with the backpatching
lists.

The problem is recognizing the locals: every rule recognizing a local would
have to check if an inline closure is parsed and if yes generate the code to
reference the _vals[] array instead instead.

Value-returning Smiley-closures could be implemented like this:

 (: ... :)   -> L_BEGIN_INLINE ... L_END_INLINE

Statement smiley-closures might be supportable if the terminating
';' is taken out of the statement rule and written explicitely whereever
a statement is used (block, statements). statement would have to return
a flag if the statement left a value on the stack, and the ';' recognition
would have to insert the F_POP instruction (see current handling of comma_expr
in statement).

No idea about the linenumber information yet. Maybe record names, lines and
program sizes and replay when the inline closures is inserted?

-------------------------------------------------------------------------

[d-chat:Alfe@Tubmud] nee, im ernst mal mateese: die smiley-notation fuer
  closures hat noch einen grossen nachteil: man kann keine werte in eine
  solche closure reinnehmen, die zur laufzeit erst bekannt werden.  dafuer
  muss man dann doch immer wieder lambdas bauen.  kannst du daran nicht mal
  was aendern?
[d-chat:Alfe@Tubmud] beispiel: closure adder(int x) { return (: $1 + x :); }
[d-chat:Dan@GueldenLand] Das was Alfe will geht prinzipiell nicht weil
  Inlines zur Compilezeit uebersetzt werden, wie alle anderen lfuns auch.
[d-chat:Alfe@Tubmud] und ugh@tubmud meinte sofort, als er die smiley-notation
  gesehen hat, die sei ja nicht rekursiv einsetzbar (also eine closure, die
  eine closure liefert), weil dann innen drin nicht klar sei, auf welchen
  scope sich ein $1 usw. bezoege.
[d-chat:Mateese@OSB-aquarius] closure adder (int i) { return lambda(({'x}),
  ({ (: $1 + $2 :), 'x, i }) ); }
[d-chat:Alfe@Tubmud] das liefert ja ne closure, die dann erst noch ne closure
  liefern wuerde, die nen int liefert.  das will ich auch nicht.  ich will
  nur ein smiley-equivalent fuer
[d-chat:Alfe@Tubmud] closure adder (int i) { return lambda(({'x}),({ #'+,'x,i
  })); }
[d-chat:Perle@Tubmud] wenn man argumentnamen festlegt, ist man doch genau
  wieder bei lambda.
[d-chat:Alfe@Tubmud] ugh schlug was in der art vor: (: a,b,c; a+b+c :)
[d-chat:Alfe@Tubmud] also namen vergeben statt $1 usw.
[d-chat:Alfe@Tubmud] (waere ja ohnehin schoener)(
[d-chat:Dan@GueldenLand] Alfe, denk doch mal drueber nach was Du willst: Du
  willst eine Closure auf einen *Clon einer LFUN*. Wie soll das ins Konzept
  passen?
[d-chat:Alfe@Tubmud] wenn man das dann noch mit der version von
  python-lambdas kombiniert, dann koennte man auch closure adder(int i) {
  return (: a,b=i; a+b :); }  schreiben und haette dadurch auch noch mein
  erstes problem erschlagen.
[d-chat:Alfe@Tubmud] oh, dan, glaub mir, ich weiss, wovon ich rede, ich weiss
  das es geht und dass es ins konzept passt.  es ist nur nicht so trivial
  umzusetzen, da geb ich dir recht.
[d-chat:Dan@GueldenLand] Man muesste die Inlines teileweise neu
  implementieren (das allerdings wuerde ich unterstuetzen ;)
[d-chat:Perle@Tubmud] mixing declarations with initializations considered
  harmful.
[d-chat:Alfe@Tubmud] perle, du schwarzmaler ;-)
[d-chat:Mateese@OSB-aquarius] Perle, huh?
[d-chat:Alfe@Tubmud] ich haette auch nichts dagegen, wenn smiley-notierte
  closures keine lfun-closure, sondern eine lambda-closure wuerden (wohl
  zwangslaeufig, wenn laufzeit-werte reingebracht werden sollen).
[d-chat:Dan@GueldenLand] das meine ich mit nicht ins Konzept passen (und ich
  bin auch dafuer dass sie wie lambdas gehandhabt werden, aber dann muesste
  man die zur Laufzeit uebersetzen...)
[d-chat:Alfe@Tubmud] nein, dan, das nicht, man muesste ihnen nur argument
  versteckt uebergeben koennen.  der code kann zur compile-zeit gebaut
  werden.
[d-chat:Dan@GueldenLand] du kannst ne lambda closure bauen die die argumente
  weitergibt + ein paar versteckte ;) das geht alles mit nem macro wenn Du
  Glueck hast ;)