I am attempting to write a simple pluggable core for interactive fiction in Perl, using POE to keep track of the events passed between objects. I, however, am running into a problem where an event is not being triggered correctly.

Full code follows:

#!/usr/bin/perl -w use strict; # {{{ 0. Basic modules and declarations. use Carp; use Data::Dumper; use POE; use POE::Wheel::ReadLine; use vars qw($parser $player @objects @libmsgs $input); use constant false => 0; use constant true => 1; open LOG, ">log"; sub w { print LOG (@_, "\n") } # }}} # {{{ 2. Library messages. use constant UNK_VERB => 0; use constant UNK_WORD => 1; use constant NO_FORM => 2; sub libmsg { return meval($libmsgs[$_[0]], @_[1..$#_]) } @libmsgs[UNK_VERB, NO_FORM] = ("I don't know how to do that.\n", "Those words don't fit together; I can't understand you.\n"); { local $" = ''; $libmsgs[UNK_WORD] = sub { "I only understood you as wanting to @_" +}; } # {{{ 1. The parser. use constant PARSE_ERR => -1; use constant PARSE_OK => 0; # {{{ 1.1. init_parser sub init_parser { $parser && return 1; my $p = POE::Session->create ( # {{{ 1.1.1. Actual parsing routines. inline_states => { # {{{ 1.1.1.1. _start _start => sub { w("Parser starting"); $parser = $_[SESSION]; }, # }}} # {{{ 1.1.1.2. parse_line parse_line => sub { my ($heap, $text) = @_[HEAP, ARG0]; my (@text, $verb, $counter); w("Parsing line: $text"); # {{{ 1.1.1.2.1. Splitting the line into pieces for ($text) { pos = 0; while ( /(?: (?<=[a-zA-Z0-9_$%\#\-]) ([,!&().\/:; \t]+) (?=[a-zA-Z0-9_$%\#\-]))| (?: (?<=[,!&().\/:; \t]+) ([a-zA-Z0-9_$%\#\-]+) (?=[,!&9).\/:; \t])/gx) { w("Parsed piece: $+"); push @text, $+; } } # }}} # {{{ 1.1.1.2.2. Finding the verb ($verb = $heap->{verbs}->{$text[0]}) or (print libmsg(UNK_VERB), return PARSE_ERR); # }}} # {{{ 1.1.1.2.3. Parsing the verb $counter = 0; w("Got verb: \n",Dumper $verb); FORM: foreach (@$verb) { my @usedobjs; TOKEN: foreach (@$verb[0..($#$verb-1)]) { w("Token: $_"); next TOKEN unless $_; if (!ref) { if (/[a-zA-Z0-9_$%\#-]/) { ($text[$counter] =~ /^\s*$/) and $counter++; ($_ eq $text[$counter]) or next FORM; } else { my $x = $_; $x =~ tr/ \t//d; ($text[$counter] eq $x) or next FORM; } } elsif (ref eq 'CODE') { my $flag = false; OBJ: foreach my $obj (@objects) { if ($_->($obj)) { push @usedobjs, $obj; $flag = true; last OBJ; } } (!$flag) && next FORM; } } $verb->[$#$verb-1]->(@usedobjs); return PARSE_OK; } # }}} print libmsg(NO_FORM); return PARSE_ERR; }, # }}} # {{{ 1.1.1.3. mod_verb mod_verb => sub { my ($heap, $verb, $grammar) = @_[HEAP, ARG0, ARG1]; w("Modifying verb $verb to: ",Dumper $grammar); $heap->{verbs}->{$verb} = [ @$grammar ]; }, } # }}} ); } # }}} # }}} # }}} # }}} # {{{ 3. iscode, meval. sub iscode { return (ref shift eq 'CODE') } sub meval { return $_[0]->(@_[1..$#_]) if &iscode; return $_[0] } # }}} # {{{ 4. Input. # {{{ 4.1. init_input sub init_input { $input && return 1; my $i; $i = POE::Session->create ( # {{{ 4.1.1. Actual input subroutines. inline_states => { # {{{ 4.1.1.1. _start _start => sub { w("Input handler starting"); my $heap = $_[HEAP]; $input = $_[SESSION]; $heap->{wheel} = POE::Wheel::ReadLine->new ( InputEvent => 'got_line' ); w("Wheel created: ",$heap->{wheel}); $heap->{wheel}->get('> '); }, # }}} # {{{ 4.1.1.2. got_line got_line => sub { my ($heap, $line) = @_[HEAP, ARG0]; if (defined $line) { w("Line input: $line"); $heap->{wheel}->addhistory($line); $_[KERNEL]->call($parser, 'parse_line', $line); w("Event posted"); $heap->{wheel}->get('> '); } elsif ($_[ARG1] eq 'interrupt') { exit 0; } }, # }}} } # }}} ); } # }}} # }}} # {{{ 5. Tester. w("Calling init_input"); init_input(); w("Calling init_parser"); init_parser(); w("Posting mod_verb"); $poe_kernel->post($parser, 'mod_verb', "quit", [ '', sub { print "\n"; + exit 0 } ]); w("Running kernel"); $poe_kernel->run;

I know this could be cleaned up quite a bit; feel free to do so if you wish, but I was going to clean it up a bit later, and it shouldn't affect the problem I'm having. The problem is that when a line of text is typed, the wheel sends it to the input handler, which supposedly triggers an event in the parser object, which then calls the verb as necessary. Right now I have one verb implemented, just for a test of the read-parse-compute-output cycle: quit. However, typing "quit" doesn't work. In my log file, it gets as far having the POE kernel post an event to the parser; the event in the parser, however, is never actually called, as that line never appears in the log.

Can anyone help me figure out what is going on?


In reply to POE = woe by premchai21

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.