<commit_before>=head1 TITLE

PGE::Exp - base class for expressions

=cut

.namespace [ 'PGE';'Exp' ]

.include "interpinfo.pasm"
.include "cclass.pasm"
.const int PGE_INF = 2147483647
.const int PGE_CUT_GROUP = -1
.const int PGE_CUT_RULE = -2
.const int PGE_CUT_MATCH = -3
.const int PGE_CUT_CUT = -4
.const int PGE_BACKTRACK_GREEDY = 1
.const int PGE_BACKTRACK_EAGER = 2
.const int PGE_BACKTRACK_NONE = 3

.sub "__onload" :load
    .local pmc optable
    .local pmc term

    .local pmc p6meta, expproto
    p6meta = get_hll_global 'P6metaclass'
    expproto = p6meta.'new_class'('PGE::Exp', 'parent'=>'PGE::Match')
    p6meta.'new_class'('PGE::Exp::Literal',      'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Scalar',       'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::CCShortcut',   'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Newline',      'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::EnumCharList', 'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Anchor',       'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Concat',       'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Alt',          'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Conj',         'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Group',        'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::CGroup',       'parent'=>'PGE::Exp::Group')
    p6meta.'new_class'('PGE::Exp::Subrule',      'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Cut',          'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Quant',        'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Modifier',     'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Closure',      'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Action',       'parent'=>expproto)
.end


=over 4

=item C<compile(PMC adverbs :slurpy :named)>

Compile C<self> into PIR or a subroutine, according to the
C<target> adverbs.

=cut

.sub 'compile' :method
    .param pmc adverbs         :slurpy :named

    .local string target
    target = adverbs['target']
    target = downcase target
    if target == 'parse' goto return_exp
    if target == 'pge::exp' goto return_exp

    .local pmc code
    code = new 'CodeString'

    .local pmc ns
    ns = adverbs['namespace']
    if null ns goto ns_grammar
    unless ns goto ns_grammar
    $P0 = code.'key'(ns)
    code.'emit'('.namespace %0', $P0)
    goto ns_done
  ns_grammar:
    .local string grammar
    grammar = adverbs['grammar']
    if grammar == '' goto ns_root
    $P0 = split '::', grammar
    $P0 = code.'key'($P0 :flat)
    code.'emit'(".namespace %0", $P0)
    goto ns_done
  ns_root:
    code.'emit'('.namespace []')
  ns_done:

    $P0 = self.'root_pir'(adverbs :flat :named)
    code .= $P0
    if target != 'pir' goto bytecode
    .return (code)

  bytecode:
    $P0 = compreg 'PIR'
    $P1 = $P0(code)
  make_grammar:
    if grammar == '' goto end
    push_eh end
    $P0 = get_hll_global 'P6metaclass'
    $P0.'new_class'(grammar, 'parent'=>'PGE::Grammar')
  end:
    .return ($P1)

  return_exp:
    .return (self)
.end


=item C<root_pir(PMC adverbs)>

Return a CodeString object containing the entire expression
tree as a PIR code object that can be compiled.

=cut

.sub 'root_pir' :method
    .param pmc adverbs         :slurpy :named

    .local pmc code
    code = new 'CodeString'

    .local string name, namecorou
    name = adverbs['name']
    namecorou = concat name, '_corou'
    if name > '' goto have_name
    name = code.'unique'('_regex')
    namecorou = concat name, '_corou'
  have_name:
    name = code.'escape'(name)
    namecorou = code.'escape'(namecorou)

    ##   Perform reduction/optimization on the
    ##   expression tree before generating PIR.
    .local pmc exp
    .local string explabel
    exp = self
    set_hll_global ['PGE';'Exp'], '$!group', exp
    exp = exp.'reduce'(self)

    ##   we don't need a coroutine if :ratchet is set
    .local int cutrule
    $I0 = adverbs['ratchet']
    cutrule = isne $I0, 0

    ##   generate the PIR for the expression tree.
    .local pmc expcode
    expcode = new 'CodeString'
    explabel = 'R'
    exp.'pir'(expcode, explabel, 'succeed')

    if cutrule goto code_cutrule
    ##   Generate the initial PIR code for a backtracking (uncut) rule.
    .local string returnop
    returnop = '.yield'
    code.'emit'(<<"        CODE", name, namecorou, .INTERPINFO_CURRENT_SUB)
      .sub %0 :method
          .param pmc adverbs   :slurpy :named
          .local pmc mob
          .const 'Sub' corou = %1
          $P0 = corou
          $P0 = clone $P0
          mob = $P0(self, adverbs)
          .return (mob)
      .end
      .sub %1
          .param pmc mob       :unique_reg
          .param pmc adverbs   :unique_reg
          .local string target :unique_reg
          .local pmc mfrom, mpos :unique_reg
          .local int cpos, iscont :unique_reg
          $P0 = get_hll_global ['PGE'], 'Match'
          (mob, cpos, target, mfrom, mpos, iscont) = $P0.'new'(mob, adverbs :flat :named)
          $P0 = interpinfo %2
          setattribute mob, '&!corou', $P0
          .local int lastpos
          lastpos = length target
          if cpos > lastpos goto fail_rule
        CODE
    goto code_body

  code_cutrule:
    ##   Initial code for a rule that cannot be backtracked into.
    returnop = '.return'
    code.'emit'(<<"        CODE", name)
      .sub %0 :method
          .param pmc adverbs      :unique_reg :slurpy :named
          .local pmc mob
          .local string target    :unique_reg
          .local pmc mfrom, mpos  :unique_reg
          .local int cpos, iscont :unique_reg
          $P0 = get_hll_global ['PGE'], 'Match'<commit_msg>[pge]:  Switch PGE to use :subid, add 'subid' option.<commit_after>=head1 TITLE

PGE::Exp - base class for expressions

=cut

.namespace [ 'PGE';'Exp' ]

.include "interpinfo.pasm"
.include "cclass.pasm"
.const int PGE_INF = 2147483647
.const int PGE_CUT_GROUP = -1
.const int PGE_CUT_RULE = -2
.const int PGE_CUT_MATCH = -3
.const int PGE_CUT_CUT = -4
.const int PGE_BACKTRACK_GREEDY = 1
.const int PGE_BACKTRACK_EAGER = 2
.const int PGE_BACKTRACK_NONE = 3

.sub "__onload" :load
    .local pmc optable
    .local pmc term

    .local pmc p6meta, expproto
    p6meta = get_hll_global 'P6metaclass'
    expproto = p6meta.'new_class'('PGE::Exp', 'parent'=>'PGE::Match')
    p6meta.'new_class'('PGE::Exp::Literal',      'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Scalar',       'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::CCShortcut',   'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Newline',      'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::EnumCharList', 'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Anchor',       'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Concat',       'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Alt',          'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Conj',         'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Group',        'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::CGroup',       'parent'=>'PGE::Exp::Group')
    p6meta.'new_class'('PGE::Exp::Subrule',      'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Cut',          'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Quant',        'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Modifier',     'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Closure',      'parent'=>expproto)
    p6meta.'new_class'('PGE::Exp::Action',       'parent'=>expproto)
.end


=over 4

=item C<compile(PMC adverbs :slurpy :named)>

Compile C<self> into PIR or a subroutine, according to the
C<target> adverbs.

=cut

.sub 'compile' :method
    .param pmc adverbs         :slurpy :named

    .local string target
    target = adverbs['target']
    target = downcase target
    if target == 'parse' goto return_exp
    if target == 'pge::exp' goto return_exp

    .local pmc code
    code = new 'CodeString'

    .local pmc ns
    ns = adverbs['namespace']
    if null ns goto ns_grammar
    unless ns goto ns_grammar
    $P0 = code.'key'(ns)
    code.'emit'('.namespace %0', $P0)
    goto ns_done
  ns_grammar:
    .local string grammar
    grammar = adverbs['grammar']
    if grammar == '' goto ns_root
    $P0 = split '::', grammar
    $P0 = code.'key'($P0 :flat)
    code.'emit'(".namespace %0", $P0)
    goto ns_done
  ns_root:
    code.'emit'('.namespace []')
  ns_done:

    $P0 = self.'root_pir'(adverbs :flat :named)
    code .= $P0
    if target != 'pir' goto bytecode
    .return (code)

  bytecode:
    $P0 = compreg 'PIR'
    $P1 = $P0(code)
  make_grammar:
    if grammar == '' goto end
    push_eh end
    $P0 = get_hll_global 'P6metaclass'
    $P0.'new_class'(grammar, 'parent'=>'PGE::Grammar')
  end:
    .return ($P1)

  return_exp:
    .return (self)
.end


=item C<root_pir(PMC adverbs)>

Return a CodeString object containing the entire expression
tree as a PIR code object that can be compiled.

=cut

.sub 'root_pir' :method
    .param pmc adverbs         :slurpy :named

    .local pmc code
    code = new 'CodeString'

    .local string name, namecorou
    name = adverbs['name']
    namecorou = concat name, '_corou'
    if name > '' goto have_name
    name = code.'unique'('_regex')
    namecorou = concat name, '_corou'
  have_name:
    name = code.'escape'(name)
    namecorou = code.'escape'(namecorou)

    .local string subid
    subid = ''
    $P0 = adverbs['subid']
    if null $P0 goto have_subid
    $S0 = code.'escape'($P0)
    subid = concat ':subid(', $S0
    concat subid, ')'
  have_subid:

    ##   Perform reduction/optimization on the
    ##   expression tree before generating PIR.
    .local pmc exp
    .local string explabel
    exp = self
    set_hll_global ['PGE';'Exp'], '$!group', exp
    exp = exp.'reduce'(self)

    ##   we don't need a coroutine if :ratchet is set
    .local int cutrule
    $I0 = adverbs['ratchet']
    cutrule = isne $I0, 0

    ##   generate the PIR for the expression tree.
    .local pmc expcode
    expcode = new 'CodeString'
    explabel = 'R'
    exp.'pir'(expcode, explabel, 'succeed')

    if cutrule goto code_cutrule
    ##   Generate the initial PIR code for a backtracking (uncut) rule.
    .local string returnop
    returnop = '.yield'
    code.'emit'(<<"        CODE", name, subid, namecorou, .INTERPINFO_CURRENT_SUB)
      .sub %0 :method %1
          .param pmc adverbs   :slurpy :named
          .local pmc mob
          .const 'Sub' corou = %2
          $P0 = corou
          $P0 = clone $P0
          mob = $P0(self, adverbs)
          .return (mob)
      .end
      .sub '' :subid(%2)
          .param pmc mob       :unique_reg
          .param pmc adverbs   :unique_reg
          .local string target :unique_reg
          .local pmc mfrom, mpos :unique_reg
          .local int cpos, iscont :unique_reg
          $P0 = get_hll_global ['PGE'], 'Match'
          (mob, cpos, target, mfrom, mpos, iscont) = $P0.'new'(mob, adverbs :flat :named)
          $P0 = interpinfo %3
          setattribute mob, '&!corou', $P0
          .local int lastpos
          lastpos = length target
          if cpos > lastpos goto fail_rule
        CODE
    goto code_body

  code_cutrule:
    ##   Initial code for a rule that cannot be backtracked into.
    returnop = '.return'
    code.'emit'(<<"        CODE", name, subid)
      .sub %0 :method %1
          .param pmc adverbs      :unique_reg :slurpy :named
          .local pmc mob
          .local string target    :unique_reg
          .local pmc mfrom, mpos  :unique_reg
          .local int cpos, iscont :unique_reg
          $P0 = get_hll_global ['PGE'], 'Match'
{'fraction_non_alphanumeric': 0.14027884697630655, 'fraction_numerical': 0.013258061756907023, 'mean_word_length': 2.6964906734113185, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2100186', 'n_tokens_mistral': 4366, 'n_tokens_neox': 4258, 'n_words': 1053}