Code Planting Tutorial Part 6 - GetPoplog/Seed GitHub Wiki

Work in progress ...

Implementing Pythonic Generators

Introduce this is a serious exercise, where we cover the bit about making it an autoloadable syntax in your personal library. A bit of chat about generators in Python. And then a bit of chat about coroutines in Poplog.

For this tutorial it helps to know:

  • How to program with Poplog processes see REF PROCESS
  • _Assigning to the discard (underscore) variable _ will discard the value.

Problem

In this section we describe the extension to define and the yield keywords.

Strategy

Explain how we are going to do it. Especially about $poplib and autoloading.

Extending the define syntax

define lconstant read_revargs() -> revargs;
    pop11_need_nextitem( "(" ) -> _;
    lvars revargs = [];
    until pop11_try_nextitem( ")" ) do
        nextif( pop11_try_nextitem( "," ) );
        lvars arg = readitem();
        if arg.isword then
            arg :: revargs -> revargs
        else
            mishap( 'Invalid parameter', [ ^arg ] )
        endif
    enduntil;
enddefine;

define :define_form generator;
    lvars name = readitem();
    lvars revargs = read_revargs();
    sysSYNTAX( name, "procedure", pop_debugging == false );
    sysPROCEDURE( name, revargs.length );
    lvars a;
    for a in revargs do
        sysLVARS( a, 0 );
        sysPOP( a );
    endfor;
    sysPUSH( "runproc" );
    sysPUSH( "popstackmark" );
    sysPUSHQ( 0 );
    sysPUSHQ( 0 );
    sysPROCEDURE( "generator_" <> name, 0 );
    pop11_comp_stmnt_seq_to( "enddefine" ) -> _;
    sysPUSHQ( termin );
    sysPUSHQ( sysENDPROCEDURE() );
    sysCALL( "consproc" );
    sysCALL( "sysconslist" );
    sysCALL( "partapply" );
    sysPASSIGN( sysENDPROCEDURE(), name );
enddefine;

Implementing yield

define syntax yield;
    dlocal pop_new_lvar_list;
    pop11_need_nextitem( "(" ) -> _;
    lvars tmpvar = sysNEW_LVAR();
    sysCALL( "stacklength" );
    sysPOP( tmpvar );
    pop11_comp_expr_to( ")" ) -> _;
    sysCALL( "stacklength" );
    sysPUSH( tmpvar );
    sysCALL( "fi_-" );
    sysCALL( "suspend" );
enddefine;

define lconstant plant_yield_conditionally( if_unless );
    pop11_need_nextitem( "(" ) -> _;
    pop11_comp_expr_to( ")" ) -> _;
    lvars sys_IF = if_unless and sysIFNOT else sysIFSO;
    lvars skip_label = sysNEW_LABEL();
    sysIFNOT( skip_label );
    nonsyntax yield();
    sysLABEL( skip_label );
enddefine;

define syntax yieldif;
    plant_yield_conditionally( true )
enddefine;

define syntax yieldunless;
    plant_yield_conditionally( false )
enddefine;