From 87765d0a9cf5ed1742deeead5a8099162d8559f4 Mon Sep 17 00:00:00 2001 From: Pragmatic Software Date: Sat, 11 Jul 2020 21:15:54 -0700 Subject: [PATCH] Progress on embedding Plang --- Plang | 2 +- Plugins/Plang.pm | 131 ++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 114 insertions(+), 19 deletions(-) diff --git a/Plang b/Plang index 16e65fdc..80f9afa6 160000 --- a/Plang +++ b/Plang @@ -1 +1 @@ -Subproject commit 16e65fdcab9571ce0a2edbc492e83fc6e05ceb7f +Subproject commit 80f9afa670d2e96cd4b70df69c052a490d499273 diff --git a/Plugins/Plang.pm b/Plugins/Plang.pm index 13ca0613..3bba1e15 100644 --- a/Plugins/Plang.pm +++ b/Plugins/Plang.pm @@ -23,9 +23,18 @@ sub initialize { unshift @INC, $path if not grep { $_ eq $path } @INC; require "$path/Interpreter.pm"; + # regset plang.debug 0-10 -- Plugin must be reloaded for this value to take effect. my $debug = $self->{pbot}->{registry}->get_value('plang', 'debug') // 0; + + # create our Plang interpreter object $self->{plang} = Plang::Interpreter->new(embedded => 1, debug => $debug); + # register some built-in functions + $self->{plang}->{interpreter}->add_function_builtin('set', [qw/channel keyword text/], \&set_factoid); + $self->{plang}->{interpreter}->add_function_builtin('get', [qw/channel keyword/], \&get_factoid); + $self->{plang}->{interpreter}->add_function_builtin('append', [qw/channel keyword text/], \&append_factoid); + + # register the `plang` command $self->{pbot}->{commands}->register(sub { $self->cmd_plang(@_) }, "plang", 0); } @@ -39,28 +48,114 @@ sub cmd_plang { my $usage = "plang ; see https://github.com/pragma-/Plang"; - my $getopt_error; - local $SIG{__WARN__} = sub { - $getopt_error = shift; - chomp $getopt_error; - }; + return $usage if not length $context->{arguments}; - my ($show_usage); - my @opt_args = $self->{pbot}->{interpreter}->split_line($context->{arguments}, strip_quotes => 1); + # run() returns result of the final statement + my $result = $self->run($context->{arguments}); - Getopt::Long::Configure("bundling"); - GetOptionsFromArray( - \@opt_args, - 'h' => \$show_usage - ); + # check to see if we need to append final result to output + if (defined $result) { + if (ref $result->[0] eq 'ARRAY') { + foreach my $r (@$result) { + $self->{output} .= $r->[1] if defined $r->[1]; + } + } else { + $self->{output} .= $result->[1] if defined $result->[1]; + } + } - return $usage if $show_usage; - return "/say $getopt_error -- $usage" if defined $getopt_error; - $context->{arguments} = "@opt_args"; + return length $self->{output} ? $self->{output} : "No output."; +} - my $result = $self->{plang}->interpret_string($context->{arguments}); - return "No output." if not defined $result; - return "/say $result"; +# run an embedded plang program +sub run { + my ($self, $code) = @_; + + # parse the code into an ast + my $ast = $self->{plang}->parse_string($code); + return if not defined $ast; + + # create a new environment for a Plang program + my $context = $self->{plang}->{interpreter}->init_program; + + # grab our program's statements + my $program = $ast->[0]; + my $statements = $program->[1]; + + $self->{output} = ""; # collect output of the embedded Plang program + my $result; # result of the final statement + + # interpret the statements + foreach my $node (@$statements) { + my $ins = $node->[0]; + + if ($ins eq 'STMT') { + $result = $self->{plang}->{interpreter}->statement($context, $node->[1]); + $result = $self->handle_statement_results($result); + } + + last if $self->{error}; + } + + return $result; # return result of the final statement +} +use Data::Dumper; + +# handle a Plang statement result +sub handle_statement_results { + my ($self, $results) = @_; + + if (ref $results->[0] eq 'ARRAY') { + my $ret; + foreach my $result (@$results) { + $ret = $self->handle_statement_result($result); + } + return $ret; + } else { + return $self->handle_statement_result($results); + } +} + +sub handle_statement_result { + my ($self, $result) = @_; + + if ($result->[0] eq 'ERROR') { + $self->{output} .= $result->[1]; + $self->{error} = 1; + return; + } + + if ($result->[0] eq 'WARNING') { + $self->{output} .= $result->[1]; + return; + } + + if ($result->[0] eq 'STDOUT') { + $self->{output} .= $result->[1]; + return; + } + + return $result; +} + +# our custom PBot built-in functions for Plang + +sub get_factoid { + my ($plang, $name, $arguments) = @_; + my ($channel, $keyword) = ($arguments->[0]->[1], $arguments->[1]->[1]); + return ['STRING', "get_factoid: channel: [$channel], keyword: [$keyword]"]; +} + +sub set_factoid { + my ($plang, $name, $arguments) = @_; + my ($channel, $keyword, $text) = ($arguments->[0]->[1], $arguments->[1]->[1], $arguments->[2]->[1]); + return ['STRING', "set_factoid: channel: [$channel], keyword: [$keyword], text: [$text]"]; +} + +sub append_factoid { + my ($plang, $name, $arguments) = @_; + my ($channel, $keyword, $text) = ($arguments->[0]->[1], $arguments->[1]->[1], $arguments->[2]->[1]); + return ['STRING', "append_factoid: channel: [$channel], keyword: [$keyword], text: [$text]"]; } 1;