Newbie questions about Pliant

Newbie questions about Pliant

unnamed variable to use in meta

i need to keep state between the calls generated by my meta,
and I don't want the state keeping variables to clash
Message posted by reitman on 2003/07/30 18:56:15
Hi, 

my meta will generate a sequence { var MyState s; A s; B s; C s }
where A, B, and C are some functions. However, sometimes this code 
is in global context (gvar), and sometimes it is in local context (var).
How do I make an expression for s, so that it has no name, and is declared
to either statically (gvar) or on the stack (var) ?

Thank you,
Boris
Message posted by hubert.tonneau on 2003/07/30 19:49:40
There are two kind of metas:

. the real ones, such as 'swap' in module /pliant/language/basic/swap.pli
  that will add some instructions in the expression instructions list.

. the rewriting ones that will build a new version of the expression to compile
  then call 'compile_as' such as in /pliant/language/basic/setfield.pli
  which is responsible for trying to compile

  a b c := d

  as

  a 'b :=' c d

  so that when you write something like this:

  var Array:Int a
  a size := 3

  in facts, Pliant will do

  var Array:Int a
  a 'size :=' b
Message posted by hubert.tonneau on 2003/07/30 19:51:23
You should first concentrate on the first kind of metas, even if they look
harder.

In the 'swap' example, the unamed local variable is created through:

var Link:Argument tmp :> argument local Int
Message posted by reitman on 2003/08/05 17:31:47
I need to store an addressof of one local variable into the other. 

var Link:Argument sp :> argument local Address
var Link:Argument asp :> argument local Address

e add (instruction (the_function get_sp -> Address) sp)
#now, I want asp to be addressof:sp

Below, is code skeleton on which I'm working.  Please, let me know if 
I am way off.

Thanks,
Boris
===================

module "/pliant/language/compiler.pli"
module "/borisreitman/perl/perl.pli"

function test_invoke funcname -> a
  arg Str funcname
  arg Address a
  a := null
  console "Got funcname = " funcname eol

meta perl e
  # create a string constant with value e:0:ident
  #var Link:Expression funcname :> expression immediat e:0:ident
  var Link:Argument funcname :> argument constant Str e:0:ident
  var Link:Argument sv :> argument local Address
  var Link:Argument sp :> argument local Address

  var Link:Expression result :> expression immediat {} near e

  #result suckup (expression immediat { asp := addressof lperl__GET_STACK_SP; console asp eol})
  result compile ?

  result add (instruction (the_function lperl__GET_STACK_SP -> Address) sp)
  #result add (instruction (the_function addressof Universal -> Address) sp asp)

  #result add (instruction (the_function perl__prepare_to_push_args Address) asp)
  #e:1 cast Int  #?
  #result add (instruction (the_function perl__push_integer Address Int) asp e:1:result) 

  result add (instruction (the_function test_invoke Str -> Address) funcname sv)
  #result add (instruction (the_function perl__post_cleanup Address) asp)

  e compile_as result

gvar Int x := 1;
perl hello 1
Message posted by hubert.tonneau on 2003/08/05 17:44:53
Please publish the Pliant prototype functions you use to access perl DLL.

About your meta, it's deaply buggy because you try the mixte two ways to handle
a meta:
. the plain one, using 'argument' 'instruction' and 'set_result'
. the rewritting one, using 'expression' and 'compile_as'
You need to write a plain meta.
Message posted by reitman on 2003/08/06 00:35:04
Below is the perl.pli file.  Some functions I am not accessing directly in 
libperl.so.5.6, but instead I access them in my wrapper library file
liblperl.so (the extra l stands for "light").

Should I be posting such large files in this forum, or should I post it in 
the patch forum ?

Function perl_call_onearg_int is an example of calling a perl function
that accepts an integer.  (I still have problems with getting at the 
perl return value.)  The perl meta must be similar to this function, except that
it will accept any number of arguments, and will handle different argument 
types.

Finally, and the end of the file, some auto-casting is done to convert 
automatically between Address and SV types.

When things are working, this package should export only 'perl_eval' meta 
(its a function now), 'perl' meta, and the type conversion stuff. 

I intend to have a pliant proxy of a perl hash type, and a perl array type,
so that the transitions between pliant and perl can be smooth. The perl hash
datatype will have api like the pliant Database datatype. 

I think this package will be instrumental in converting perl 
developers to pliant.  For example, the .page format may be used for websites 
which have the sql db backend already implemented with perl DBI package.

=========================

module "/pliant/language/unsafe.pli"
module "/pliant/language/compiler.pli"

public 

constant G_FALSE     (cast 0 Int32)
constant G_TRUE      (cast 1 Int32)

# some defines from cop.h 
constant G_SCALAR    (cast 0 Int32)
constant G_ARRAY     (cast 1 Int32)
constant G_VOID      (cast 128 Int32)    #/* skip this bit when adding flags below */

# /* extra flags for Perl_call_* routines */
constant G_DISCARD   (cast 2       Int32) #/* Call FREETMPS. */
constant G_EVAL      (cast 4       Int32) #/* Assume eval {} around subroutine call. */
constant G_NOARGS    (cast 8       Int32) #/* Don't construct a @_ array. */
constant G_KEEPERR   (cast 16       Int32) #/* Append errors to $@, don't overwrite it */
constant G_NODEBUG   (cast 32       Int32) #/* Disable debugging at toplevel.  */
constant G_METHOD    (cast 64       Int32) #/* Calling method. */

# /* flag bits for PL_in_eval */
constant EVAL_NULL      (cast 0       Int32) #/* not in an eval */
constant EVAL_INEVAL    (cast 1       Int32) #/* some enclosing scope is an eval */
constant EVAL_WARNONLY  (cast 2       Int32) #/* used by yywarn() when calling yyerror() */
constant EVAL_KEEPERR   (cast 4       Int32) #/* set by Perl_call_sv if G_KEEPERR */
constant EVAL_INREQUIRE (cast 8       Int32) #/* The code is being required. */



################################################################################
# mappings 
################################################################################
type SV
  field Address a        

function 'cast SV' a -> sv
  arg Address a
  arg SV sv
  implicit
  sv:a := a

function 'cast Address' sv -> a
  arg SV sv
  arg Address a
  implicit
  a := sv:a




function lperl_prepare 
  external "liblperl.so" "lperl_prepare"
function lperl_cleanup 
  external "liblperl.so" "lperl_cleanup"

function lperl_SvPV_nolen sv -> string
  arg Address sv
  arg CStr string
  external "liblperl.so" "lperl_SvPV_nolen"

function lperl_SvIV sv -> number
  arg Address sv
  arg Int number
  external "liblperl.so" "lperl_SvIV"

function lperl_eval_pv code_string bool_croak_on_error  -> sv
  arg CStr code_string
  arg Int32 bool_croak_on_error 
  arg Address sv
  #external "libperl.so.5.6" "perl_eval_pv"
  external "liblperl.so" "lperl_eval_pv"

function lperl_eval_sv code_string bool_croak_on_error  -> sv
  arg CStr code_string
  arg Int32 bool_croak_on_error 
  arg Address sv
  #external "libperl.so.5.6" "perl_eval_pv"
  external "liblperl.so" "lperl_eval_sv"

function perl_alloc -> interpreter
  arg Address interpreter
  external "libperl.so.5.6" "perl_alloc"

function perl_construct interpreter
  arg Address interpreter
  external "libperl.so.5.6" "perl_construct"

function perl_run interpreter -> retval
  arg Address interpreter
  arg Int retval
  external "libperl.so.5.6" "perl_run"

function perl_destruct interpreter -> retval
  arg Address interpreter
  arg Int retval
  external "libperl.so.5.6" "perl_destruct"

function perl_free interpreter 
  arg Address interpreter
  external "libperl.so.5.6" "perl_free"

function lperl_call_pv funcname flags -> retval 
  arg CStr funcname
  arg Int flags
  arg Int retval
  external "liblperl.so" "lperl_call_pv"

function perl_get_av varname flags -> retval 
  arg CStr varname
  arg Int flags
  arg Address retval
  #external "libperl.so.5.6" "perl_get_av"
  external "liblperl.so" "lperl_get_av"

function perl_av_clear av
  arg Address av
  external "libperl.so.5.6" "Perl_av_clear"

function perl_av_push av sv
  arg Address av
  arg Address sv
  external "libperl.so.5.6" "Perl_av_push"

function lperl_sv_2mortal sv -> mortal
  arg Address sv
  arg Address mortal
  external "liblperl.so" "lperl_sv_2mortal"

function lperl_newSViv intval -> sv
  arg Int intval
  arg Address sv
  external "liblperl.so" "lperl_newSViv"

### perl stack manipulation 

function lperl__GET_STACK_SP -> sp
  arg Address sp
  external "liblperl.so" "lperl__GET_STACK_SP"

function lperl_ENTER 
  external "liblperl.so" "lperl_ENTER"

function lperl_SAVETMPS 
  external "liblperl.so" "lperl_SAVETMPS"

function lperl_PUSHMARK sp
  arg Address sp
  external "liblperl.so" "lperl_PUSHMARK"

function lperl_XPUSHs sp sv
  arg Address sp
  arg Address sv
  external "liblperl.so" "lperl_XPUSHs"

function lperl_PUTBACK sp
  arg Address sp
  external "liblperl.so" "lperl_PUTBACK"

function lperl_SPAGAIN sp
  arg Address sp
  external "liblperl.so" "lperl_SPAGAIN"

function lperl_FREETMPS 
  external "liblperl.so" "lperl_FREETMPS"

function lperl_LEAVE 
  external "liblperl.so" "lperl_LEAVE"

function lperl_POPs sp -> sv 
  arg Address sp
  arg Address sv
  external "liblperl.so" "lperl_POPs"

function lperl_testme x
  arg Int x
  external "liblperl.so" "lperl_testme"

################################################################################
# macro like functions to call a perl function 
################################################################################

function perl__prepare_to_push_args asp
  arg Address asp
  lperl_ENTER
  lperl_SAVETMPS
  lperl_PUSHMARK asp

function perl__finish_pushing_args asp
  arg Address asp
  lperl_PUTBACK asp

function perl__push_integer asp x
  arg Address asp
  arg Int x
  lperl_XPUSHs asp (lperl_sv_2mortal lperl_newSViv:(cast x Int32))

function perl__call_sub_in_scalar_context asp subname -> sv
  arg Address asp
  arg Address sv
  arg Str subname
  var Int n
  n := lperl_call_pv subname G_SCALAR
  lperl_SPAGAIN asp
  if n = 1
    sv := lperl_POPs asp
  else
    sv := null 
    console "Failed" eol
    #TODO: communicate the error to caller

function perl__post_cleanup asp
  arg Address asp
  lperl_PUTBACK asp
  lperl_FREETMPS
  lperl_LEAVE
 
function perl_call_onearg_int subname x -> sv
  arg Str subname
  arg Int x
  arg SV sv
  var Address sp asp 

  #sp := lperl__GET_STACK_SP
  #asp := addressof sp
  asp := addressof lperl__GET_STACK_SP
  perl__prepare_to_push_args asp
  
  perl__push_integer asp x

  perl__finish_pushing_args asp
  sv := perl__call_sub_in_scalar_context asp subname

  perl__post_cleanup asp

function perl_eval_onearg_int x str -> sv
  arg_r Int x
  arg Str str
  arg SV sv
  var Address av 
 
  av := perl_get_av "_" 0
  perl_av_clear av 
  perl_av_push av (lperl_sv_2mortal lperl_newSViv:x)
  sv := lperl_eval_pv str G_FALSE

################################################################################
# perl <-> pliant glue
# and meta programming
################################################################################

function 'cast Str' sv -> str
  arg SV sv
  arg Str str
  implicit
  str := lperl_SvPV_nolen sv

function 'cast Int' sv -> integer
  arg SV sv
  arg Int integer
  implicit
  integer := lperl_SvIV sv

function perl_eval str -> sv
  arg Str str
  arg SV sv
  sv := lperl_eval_pv str G_FALSE
  

Message posted by maybe Hubert Tonneau on 2003/08/06 01:06:52
> Below is the perl.pli file.  Some functions I am not accessing directly in 
> libperl.so.5.6, but instead I access them in my wrapper library file
> liblperl.so (the extra l stands for "light").

I find it a very bad idea from the design point of view except if libperl has
only C++ interface.

I also find your code very complex, probably because I don't understand well
the perl C interface, and you don't understand how to do it simply on Pliant
side.

Would you have an URL to some sample code demonstrating calling Perl from C ?
Message posted by reitman on 2003/08/06 06:35:18
yes, these links are from the book I am reading

high level interface: 
  http://www.rzg.mpg.de/~ata/perl-bookshelf-2.0/advprog/ch19_03.htm  (example)
  http://www.rzg.mpg.de/~ata/perl-bookshelf-2.0/advprog/ch19_02.htm  (api)

low level interface:
  http://www.rzg.mpg.de/~ata/perl-bookshelf-2.0/advprog/ch20_06.htm 

I went into the low-level interface, because I was afraid that using high level
will not allow me to make very transparent glue syntax between pliant and perl.
I also wanted to practice meta programming...  Maybe it was a bad idea, since 
it creates many sensitive incompatibility points.

Many of those low level functions are actually macros, so I have created 
a C function in my light-perl library for those.  In other cases, where functions are not macros, still using them directly didn't work, and 
generated an exception. Thats why I wrapped them too.  
Here is my light perl code:

==lperl.h====================

#include <EXTERN.h>
#include <perl.h>
void lperl_prepare();
void lperl_cleanup();
char * lperl_SvPV_nolen(SV *);
long int lperl_SvIV(SV *);
SV* lperl_eval_pv(char *code, long int bool_croak_on_error);
int lperl_call_pv(char *code, int flags);
long int lperl_eval_sv(SV *sv, long int bool_croak_on_error);
AV* lperl_get_av(char *varname, int);
SV* lperl_sv_2mortal(SV* sv);
SV* lperl_newSViv(int x);

/*  stack manipulation -- since macros are used to define the variables, 
 *  we need a wrapper per function-macro */

#define STACKNANIP 1
SV** lperl__GET_STACK_SP();
void lperl_ENTER();
void lperl_SAVETMPS();
void lperl_FREETMPS();
void lperl_LEAVE();
void lperl_PUSHMARK(SV ***mysp);
void lperl_XPUSHs(SV*** mysp, SV *);
void lperl_PUTBACK(SV ***mysp);
void lperl_SPAGAIN(SV ***mysp);
SV*  lperl_POPs(SV ***mysp);

=====lperl.c==================================
#include "lperl.h"

static PerlInterpreter *my_perl;  

void print_int32(I32 x)
{
  printf("print_int32: number = %d\n", x);
}

void lperl_prepare()
{
   char *embedding[] = { "", "-e", "0" };
   my_perl = perl_alloc();
   perl_construct(my_perl);
   perl_parse(my_perl, NULL, 3, embedding, (char **)NULL);
}

SV* lperl_eval_pv(char *str, long int croak_on_error)
{
  return eval_pv(str, croak_on_error);
}

int lperl_call_pv(char *str, int flags)
{
#if 0 
  printf("Got str = %s\n", str);
#endif
  return perl_call_pv(str, 0);
}

SV* lperl_sv_2mortal(SV* sv)
{
  return sv_2mortal(sv);
}

SV* lperl_newSViv(int x)
{
  return newSViv(x);
}

char * lperl_SvPV_nolen(SV *sv)
{
  return SvPV_nolen(sv);
}

I32 lperl_SvIV(SV *sv)
{
  I32 x = SvIV(sv);
#if 0 
  printf("lperl_SvIV: %d\n", x);
#endif
  //return SvIV(sv);
  return x;
}

long int lperl_eval_sv(SV *sv, long int croak_on_error)
{
  return eval_sv(sv, croak_on_error);
}

AV* lperl_get_av(char *varname, int flag)
{
  AV* tmp = get_av(varname, flag);
#if 0
  printf("C: av  = %d\n", tmp);
#endif
  return tmp;
}

void lperl_cleanup()
{
   perl_destruct(my_perl);
   perl_free(my_perl);
}

/* stack manipulation macro wrapper  */
SV** lperl__GET_STACK_SP()  { return PL_stack_sp; }
void lperl_ENTER()          { ENTER; }
void lperl_SAVETMPS()       { SAVETMPS; }
void lperl_FREETMPS()       { FREETMPS; }
void lperl_LEAVE()          { LEAVE; }
void lperl_PUSHMARK(SV ***mysp)         { register SV** sp = *mysp; PUSHMARK(sp);                   *mysp = sp; }
void lperl_XPUSHs(SV  ***mysp, SV *sv)  { register SV** sp = *mysp; EXTEND(sp,1); (*++sp = (sv));   *mysp = sp; }
void lperl_PUTBACK(SV ***mysp)          { register SV** sp = *mysp; PUTBACK;                        *mysp = sp; }
void lperl_SPAGAIN(SV ***mysp)          { register SV** sp = *mysp; SPAGAIN;                        *mysp = sp; }
SV*  lperl_POPs(SV ***mysp)             { register SV** sp = *mysp; SV *sv; sv = POPs;              *mysp = sp; return sv; }

#if  1
lperl_testme(int x)
{
  SV **sp, ***asp;
  int n;

  lperl_eval_pv("sub hello {  print 'hello world:' . shift() . \"\\n\"; }", 1);
  sp = lperl__GET_STACK_SP();
  asp = &sp;

  lperl_ENTER();
  lperl_SAVETMPS();
  lperl_PUSHMARK(asp);
  lperl_XPUSHs(asp, lperl_sv_2mortal(lperl_newSViv(x)));
  lperl_PUTBACK(asp);
  printf("Before\n");
  n = perl_call_pv("main::hello", G_SCALAR);
  printf("Got n = %d\n", n);

  lperl_SPAGAIN(asp);
  lperl_PUTBACK(asp);
  lperl_FREETMPS();
  lperl_LEAVE();
}
#endif

Message posted by maybe Hubert Tonneau on 2003/08/06 09:38:23
Looking at Perl C prototypes, I found that most of them look like:
PERL_CALLCONV int perl_run(PerlInterpreter* interp);
So, you have to check on your system what 'PERL_CALLCONV' is.
If it's empty just like on mine, it should be ok.
If not, we have to tell Pliant how to do the same calling convention, what
might be very tricky.

The second point is that C strings are Strz in Pliant, not Str.
This might explain some of your early crash.

The last point is that the perl C interface library is an ugly set of code,
so the main problem is to sort out what truely has to be done.

Now a Pliant meta that implements something like va_arg in C would look like
this (the key advantage of Pliant is that you can test the type of the arguments):

meta perl e
  if e:size<1 or not (e:0 cast Strz)
    return
  var Link:Argument sp :> argument local Address
  e add (instruction (the_function init_then_return_stack_pointer -> Address) sp)
  for (var Int i) 1 e:size-1
    if (e:i cast Int)
      e suckup e:i # add instruction that compute e:i
      e add (instruction (the_function push_an_int Address Int) sp e:i:result)
    eif (e:i cast Strz)
      e suckup e:i
      e add (instruction (the_function push_a_string Address Strz) sp e:i:result)
    else
      return
  e suckup e:0
  e add (instruction (the_function evaluate Strz) e:0:result)
  e add (instruction (the_function do_garbadge))
  e set_void_result
Message posted by reitman on 2003/08/06 16:14:56
In the example code that you gave, I need to pass addressof:sp to subsequent functions, since they must change its value (increment it or decrement it).
So I still don't understand how to do that in pliant, during instruction generation.

#what I want is something like this,
  e add (instruction (the_function init_then_return_stack_pointer -> Address) sp)                                                   
  e add (instruction (the_function push_an_int Address Int) sp:address e:i:result)                                                      


Also, whats the difference between Strz and CStr ?
 
Message posted by hubert.tonneau on 2003/08/06 16:49:47
If you have:

function push_an_int sp i
  arg_rw Address sp ; arg Int i
  sp map Int := i
  sp := sp translate Int 1

then calling it with
  e add (instruction (the_function push_an_int Address Int) sp e:i:result)
is just fine.

Pliant knows that 'push_an_int' function wants to receive the first argument
by address since it's marked 'arg_rw', so it will do it automatically.

> Also, whats the difference between Strz and CStr ?

Oops, looks like I'm drunk.
'CStr' is a C like string, and 'Strz' does not exist any more.