Eval-Compile

 view release on metacpan or  search on metacpan

Compile.xs  view on Meta::CPAN

	else if ( optype == 1 ){
	    SV *sv;
	    sv =  out_values [ position_from ];
	    closure_values[ position_to ] = sv;
	}
	else if ( optype == 2 ){
	    SV *sv;
	    sv = out_values [ position_from ];
	    closure_values[ position_to ] = cl->temporary [ j ];
	}
    }
}
void
cl_run_closure( pTHX_ p_closure closure){
    dSP;
    I32 ret_count;
    int i;
    PUSHMARK(SP);
    PUTBACK;
    cl_prepare_closure( aTHX_ closure, 1); 
    ret_count = call_sv( (SV*)closure->closure_cv, G_NOARGS | G_SCALAR |G_EVAL );
    cl_prepare_closure( aTHX_ closure, 2); 
    SPAGAIN;
    if ( ret_count != 1 )
	croak( "Incorrect number of stack items " );
    for( i=0; i<ret_count; ++i){
	closure->return_value = POPs;
    }
    PUTBACK;
}


long
dive_in_stack(){
    long i;
    for( i= cxstack_ix; i>= 0 ;--i ){
	if (CxTYPE(&cxstack[i]) == CXt_SUB) {
	    CV * cur_cv = cxstack[i].blk_sub.cv;
	    if ( PL_DBsub && GvCV(PL_DBsub) == cur_cv ){
		continue;
	    }
	    return i;
	}
	else if ( CxTYPE( &cxstack[i] )  ==CXt_EVAL ) {
	    if (CxOLD_OP_TYPE( &cxstack[i] ) == OP_ENTERTRY ){
		continue;
	    }
	    return -2;
	}
    }
    return -1;
}
static AV *eval_cache=0;

MODULE = Eval::Compile		PACKAGE = Eval::Compile		

void 
cache_eval_undef()
    PREINIT:
    SV *last;
    PPCODE:
    last = eval_cache;
    if ( !eval_cache ){
	XSRETURN(0);
    };
    eval_cache=0;
    SvREFCNT_dec( last );
    last =0 ;
    XSRETURN(0);
	

void 
cache_eval (SV * eval_string,  ... )
    ALIAS:
	ceval=1
	cached_eval=2
    PROTOTYPE: $@
    PREINIT:
    I32 ret_count;
    //I32 i;
    SV **value;
    char *pstr;
    STRLEN plen;
    AV* temppad;
    HV* closure_cache;
    p_closure closure;
    dXSTARG;
    PPCODE:
    PERL_UNUSED_VAR(ix);
    if ( !eval_cache ){
	eval_cache = newAV();
	temppad = eval_cache;
	closure_cache = newHV();
	AvPUSHs( eval_cache, (SV*)closure_cache );
    }
    else {
	temppad = eval_cache;
	closure_cache =( HV*)  AvELT( eval_cache,  0);
	if ( SvTYPE( closure_cache ) != SVt_PVHV )
	    croak( "panic: not a hash" );
    }
    temppad = (AV *) eval_cache;
    sv_setpvn( TARG, &PL_curcop, sizeof( &PL_curcop ));
    sv_catsv(  TARG, eval_string );

    pstr = SvPV( TARG, plen );
    value = hv_fetch( closure_cache , pstr, plen, 0);

    if ( value){
	closure = (p_closure) SvIV( * value );
	// XPUSHs(*value);
	// XSRETURN(1);
    };

    if ( !value ){
	SV *text;
	SV *anonsub;
	// Allocation of closure body
	closure = ( p_closure ) M_alloc( temppad,  sizeof( *closure) );

	hv_store( closure_cache, pstr, plen, newSViv( PTR2IV( closure )),0);
	
	
	text= sv_newmortal( );
	// TODO
	
	sv_setpv( text , "sub {\n" );
	sv_catpvf( text, "#line 0 \"<%s:%d>\"\n", CopFILE( PL_curcop ), CopLINE( PL_curcop ));
	sv_catsv( text,  eval_string );
	sv_catpv( text, ";\n};\n" );
	// fprintf( stderr, "%s\n", SvPV_nolen( text ));


	{
	dSP;
	sv_setpvn( ERRSV, "", 0);
	eval_sv( text , G_SCALAR | G_KEEPERR  );
	SPAGAIN;
	anonsub = POPs;
	PUTBACK;
	};
	
	// TODO
	//sv_dump( anonsub );
	closure->ok = 0;

	if ( SvOK(anonsub) && !SvTRUE(ERRSV)){
	    AvPUSHs( temppad, anonsub );
	    closure->ok = 1;
	    closure->closure_cv = (CV *)SvRV(anonsub);
	    cl_init( aTHX_ closure, temppad);
	}
	else {
	    warn( "%s", SvPVx_nolen_const( ERRSV ));
	    closure->ok = 0;
	    closure->return_value = newSVsv( ERRSV );
	    AvPUSHs( temppad, closure->return_value );
	    cl_init( aTHX_ closure, temppad);
	};
    }

    if ( closure->ok ){
	SV *result;
	ENTER;
	PUSHMARK(SP);
	cl_prepare_closure( aTHX_ closure, 1); 
	ret_count = call_sv( (SV *) closure->closure_cv, G_SCALAR | G_EVAL |  G_NOARGS );
	cl_prepare_closure( aTHX_ closure, 2); 

	SPAGAIN;
	result = POPs;
	if (ret_count != 1)
	    croak( "Invalid sub call" );
	if ( SvTRUE(ERRSV) )
	    warn("%s", SvPV_nolen( ERRSV ));
	PUTBACK;
	PUSHs(result);
	LEAVE;
	//sv_dump( result );
	XSRETURN(1);
    }
    else {
	sv_setsv( ERRSV, closure->return_value );
	XSRETURN_UNDEF;
    }
    
void 
cache_this ( SV * key, CV * calc_sv )
    PREINIT:
    I32 ret_count;
    //I32 i;
    SV **value;
    char *pstr;
    STRLEN plen;
    dXSTARG;
    PPCODE:
    if ( ! (PL_op->op_private & OPpENTERSUB_HASTARG )){
	croak( "panic: XS sub no target " );
    };
    if (SvTYPE(TARG) != SVt_PVHV ){
	(void)SvUPGRADE( TARG , SVt_PVHV );
    }
    pstr = SvPV( key, plen );
    value = hv_fetch( (HV*) TARG, pstr, plen, 0);
    if (value){
	XPUSHs(*value);
	XSRETURN(1);
    };
    PUSHMARK(SP);
    XPUSHs(ST(0));
    PUTBACK;
    ret_count = call_sv( (SV *)calc_sv, G_SCALAR | G_EVAL);
    SPAGAIN;
    if (ret_count != 1)
	croak( "Invalid sub call" );
    if ( SvTRUE(ERRSV) )
	warn("%s", SvPV_nolen( ERRSV ));
    else {
	SV *ret = POPs;
	SvREFCNT_inc_simple_void_NN(ret);
	(void) hv_store( (HV *)TARG, pstr, plen, ret , 0);
    }
    PUTBACK;
    XSRETURN(1);
    


    

void run_sub( SV * code )
    PREINIT:
    I32 ret_count;
    int i;
    PPCODE:
    dSP;
    PUSHMARK(SP);
    PUTBACK;
    ret_count = call_sv( code, G_NOARGS | G_SCALAR );
    SPAGAIN;
    for( i=0; i<ret_count; ++i){
	sv_dump( POPs );
    }
    PUTBACK;



void
compile_sub( SV *codetext)
    PREINIT:
    SV *text;
    SV *anonsub;
    PPCODE:
    //dSP;
    text= sv_newmortal( );
    sv_setpv( text , "sub {\n" );
    sv_catsv( text,  codetext );
    sv_catpv( text, "\n};\n" );

    anonsub = eval_pv( SvPV_nolen(text) , 0 );
    if ( !SvTRUE(ERRSV)){
	XPUSHs(&PL_sv_no);
	XPUSHs( anonsub );
	XPUSHs( codetext );
    }
    else {
	XPUSHs( ERRSV );
    };


void
callers( CV * cv, SV *eval_string )
    PREINIT:
    int i;
    PADNAMELIST *names;
    PAD *values;
    CV *subcv;
    long subcv_depth;
    long stack_depth;
    bool context_match;
    U32  context_seq;
    AV *results;
    PPCODE:
    if (cv && CvPADLIST( cv ) ){
	PADLIST *padlist = CvPADLIST( cv );
	if (CvDEPTH(cv)){
	    croak( "Fail compile: cv is running" );
	}
	stack_depth = dive_in_stack();
	if ( stack_depth < 0 ){
	    warn( "found no variables " );
	}
	context_match = FALSE;
	context_seq   = 0;
	if ( cxstack[ stack_depth ].blk_sub.cv != CvOUTSIDE(cv) ){
	    CV *out;
	    U32 seq;
	    out = CvOUTSIDE(cv);
	    seq = CvOUTSIDE_SEQ(cv);
	    while( out ){
		if ( cxstack[ stack_depth ].blk_sub.cv == out ){
		    context_match = TRUE;
		    context_seq = seq;
		    break;
		};
		seq = CvOUTSIDE_SEQ(out);
		out = CvOUTSIDE(out);
	    }
	    if ( ! context_match )
		warn("Cv from other context %p", CvOUTSIDE(cv) );
	};
	subcv = cxstack[ stack_depth ].blk_sub.cv;
	subcv_depth =  cxstack[ stack_depth ].blk_sub.olddepth+1;
	results = newAV();
	sv_2mortal( (SV *) results );
	AvPUSHi( results, 1 ) ; //0:  set that everything ok
	AvPUSHi( results, cxstack_ix - stack_depth ); //1: stack depth
	AvPUSHs( results, newRV((SV*)subcv));//2: context_cv
	AvPUSHs( results, eval_string );     //3:eval string
	AvPUSHs( results, newRV( (SV*)cv ) );//4: cv
	mXPUSHi(cxstack_ix - stack_depth); //  5: context_depth
	AvPUSHi( results, context_seq); //     6: seq

	_show_cvpad( cxstack[ stack_depth ].blk_sub.cv );

	names = PadlistNAMES(padlist);
	values =PadlistARRAY(padlist)[1];

	for (i=0; i<= PadnamelistMAX( names ) ; ++i ){
	    PADNAME *padn;
	    SV *val_sv;
	    padn = (PadnamelistARRAY(names)[i]);
	    val_sv  = PadARRAY( values )[i];
	    if ( PadnamePV(padn) && PadnameOUTER(padn) 
		    && !PadnameIsOUR(padn)
		    && PadnameLEN(padn) > 1 ){
		I32 position;
		SV * const name_sv = PadnameSV(padn);
		XPUSHs(name_sv);
		mXPUSHi( i );
		position = find_sv( subcv, subcv_depth, context_seq, val_sv);
		mXPUSHi( position );
		AvPUSHi( results, position );



( run in 0.476 second using v1.01-cache-2.11-cpan-71847e10f99 )