--- /dev/null
+package DX::RuleDefinitionContext;
+
+use DX::PropositionSequence;
+use DX::Predicate::Rule;
+use DX::Class;
+
+has arg_names => (is => 'ro', required => 1);
+
+has proposition_sequence => (is => 'rwp', lazy => 1, builder => sub {
+ my ($self) = @_;
+ my %arg_names = map +($_ => 1), @{$self->arg_names};
+ DX::PropositionSequence->new_empty
+ ->but(external_names => \%arg_names);
+});
+
+has expander => (is => 'ro', required => 1, handles => [ qw(expand_args) ]);
+
+sub apply_predicate {
+ my ($self, $pred, @arg_strings) = @_;
+ my @args = $self->expand_args(@arg_strings);
+ my ($intro, $need) = ({}, {});
+ foreach my $arg (@args) {
+ next if ref($arg);
+ next if $arg =~ /^\??[a-z]/; # skip globals
+ # ?Foo is intro, Foo is need
+ ($arg =~ s/^\?// ? $intro : $need)->{$arg} = 1;
+ }
+ my $prop = DX::Proposition->new(
+ predicate => $pred,
+ args => \@args,
+ introduced_names => $intro,
+ required_names => $need,
+ );
+ $self->_set_proposition_sequence(
+ $self->proposition_sequence->with_additional_proposition($prop)
+ );
+ return;
+}
+
+sub bake_rule {
+ my ($self) = @_;
+ DX::Predicate::Rule->new(
+ arg_names => $self->arg_names,
+ proposition_sequence => $self->proposition_sequence
+ );
+}
+
+1;
use DX::Expander;
use DX::Proposition;
use DX::ActionBuilder::Normal;
+use DX::RuleDefinitionContext;
use DX::Utils qw(deparse);
use DX::Class;
) {
$tcl->CreateCommand($pred => sub {
my (undef, undef, undef, @args) = @_; # ($data, $interp, $pred)
- $self->apply_predicate($pred => @args);
+ (our $Shell_Context)->apply_predicate($pred => @args);
});
}
$tcl->CreateCommand(const => sub {
$self->shell_state->with_trace_changes(@trace)
);
});
+ $tcl->CreateCommand(rule => sub {
+ my (undef, undef, undef, $pred, $args, $body) = @_;
+ local our $Shell_Context = DX::RuleDefinitionContext->new(
+ arg_names => [ $self->tcl->SplitList($args) ],
+ expander => $self->expander,
+ );
+ $self->tcl->Eval($body);
+ my $rule = $Shell_Context->bake_rule;
+ my $tqs = $self->shell_state->template_query_state;
+ my $new_tqs = $tqs->but(
+ predicates => {
+ %{$tqs->predicates},
+ $pred => $rule,
+ },
+ );
+ $self->_set_shell_state(
+ $self->shell_state->but(
+ template_query_state => $new_tqs
+ ),
+ );
+ $self->tcl->CreateCommand($pred => sub {
+ my (undef, undef, undef, @args) = @_; # ($data, $interp, $pred)
+ (our $Shell_Context)->apply_predicate($pred => @args);
+ });
+ });
return $tcl;
});
try {
no warnings 'redefine';
local *DX::Utils::trace = $self->shell_state->trace_sub;
+ local our $Shell_Context = $self;
$self->tcl->Eval($string);
} catch {
push @Result, [ output => $_ ];