Class: RedParse::DottedRule

Inherits:
Object
  • Object
show all
Defined in:
lib/redparse/compile.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(rule, pos, parser) ⇒ DottedRule

Returns a new instance of DottedRule.



395
396
397
398
399
# File 'lib/redparse/compile.rb', line 395

def initialize(rule,pos,parser)
  @rule,@pos=rule,pos
  fail unless (0...rule.patterns.size)===@pos
#      @also_allow= compute_also_allow(parser) if parser unless defined? $OLD_PAA
end

Instance Attribute Details

#also_allowObject

Returns the value of attribute also_allow.



415
416
417
# File 'lib/redparse/compile.rb', line 415

def also_allow
  @also_allow
end

#posObject (readonly)

Returns the value of attribute pos.



414
415
416
# File 'lib/redparse/compile.rb', line 414

def pos
  @pos
end

#ruleObject (readonly)

Returns the value of attribute rule.



414
415
416
# File 'lib/redparse/compile.rb', line 414

def rule
  @rule
end

Class Method Details

.create(rule, pos, parser) ⇒ Object



417
418
419
420
421
422
423
424
# File 'lib/redparse/compile.rb', line 417

def self.create(rule,pos,parser)
  result=rule.drs[pos] and return result
  result=rule.drs[pos]=DottedRule.new(rule,pos,parser)
unless defined? $OLD_PAA
  result.also_allow=result.compute_also_allow(parser) if parser
end
  return result
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?



427
# File 'lib/redparse/compile.rb', line 427

def == other; DottedRule===other and @pos==other.pos and @rule==other.rule end

#compute_also_allow(parser, provisional = [false]) ⇒ Object

@also_allow= compute_also_allow(parser) if parser unless defined? $OLD_PAA



400
401
402
403
404
405
406
407
408
409
410
411
412
413
# File 'lib/redparse/compile.rb', line 400

def compute_also_allow(parser,provisional=[false])
    parser.all_initial_dotted_rules.map{|dr|
      next if dr==self
      fake_rule=dr.rule.final_promised_rule
      final_more_dr=DottedRule.create(fake_rule,0,nil)
      also=dr.also_allow
      unless also
        provisional[0]||=0
        provisional[0]+=1
        also=[]
      end
      also+[dr] if optionally_combine final_more_dr,parser
    }.flatten.compact.uniq
end

#evolve(input, parser, seenlist, result2) ⇒ Object

returns Conditional|Rule|DottedRule|[DottedRule.]|nil



437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
# File 'lib/redparse/compile.rb', line 437

def evolve input, parser, seenlist,result2
  #print "["
  #$stdout.flush
  idname=input.identity_name
  idname=parser.identity_name_alias? idname 
  cache=seenlist[[self,idname]]
  unless cache==:dunno_yet
    result2.concat Array(cache).flatten.compact.uniq.sort_by{|x| x.name}
    return cache
  end
  i=pos
  lasti=i-1
  result=[]
  result=loop do #might need multiple tries if optional matcher(s) here
    fail unless i>lasti
    lasti=i
    p=@rule.at(i)  #what is current pattern in this dottedrule?
    fail if Proc===p #shouldnt happen anymore
    if parser.pattern_matches_nodes? p

      #if any dotted rules have nodes at this point, 
      #also include the set of rules@0 which
      #can (possibly indirectly) generate that node.
      #(match tokens found on left sides of productions for p)
      seenlist[[self,idname]]=result
if false
      result.concat recurse_match_drs(parser).uniq.map{|dr|
        dr and 
        #begin  print "{#{dr.name}"
               dr.evolve input,parser,seenlist,result2
        #ensure print "}" end
      }.flatten.compact.uniq
end
    end
    @saw_item_that={}
    if p===input
      i+=1 unless @rule.looping?(i)
      fail if i>@rule.patterns.size

      if !@saw_item_that.empty?
        p(:saw_item_that!)
        fail unless @saw_item_that.size==1
        pair=@saw_item_that.to_a.first
        fail unless p.equal? pair.last
        it=pair.first
        action=
        if i==@rule.patterns.size
          @rule
        else
          DottedRule.create(@rule,i,parser)
        end
        break Conditional.new(it,action)
      end
      @saw_item_that=nil

      if i == @rule.patterns.size
        break @rule
      else
        break result<<DottedRule.create(@rule,i,parser)
      end
    elsif !@rule.optional?(i) 
      break result.empty? ? nil : result
    elsif (i+=1) >= @rule.patterns.size
      break @rule
    #else next p
    end
  end #loop
  seenlist[[self,idname]]=result
  result2.concat Array(result).flatten.compact.uniq.sort_by{|x| x.name}
  return result
#ensure print "]"
end

#hashObject



426
# File 'lib/redparse/compile.rb', line 426

def hash; (@rule.priority<<3)^@pos end

#looping?Boolean

Returns:

  • (Boolean)


432
433
434
# File 'lib/redparse/compile.rb', line 432

def looping?
  @rule.looping?(@pos)
end

#nameObject



430
# File 'lib/redparse/compile.rb', line 430

def name; @rule.name+"@#@pos"  end

#optionally_combine(weaker, parser) ⇒ Object



566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
# File 'lib/redparse/compile.rb', line 566

def optionally_combine weaker,parser
  #lotsa caching needed if this is ever to be performant
  if parser.oc_cache
    result=parser.oc_cache[[self,weaker]]  
    return result unless result.nil?
  else
    parser.oc_cache={}
  end

  other=weaker
  mymatches,myposes=  self.outcomes
  matches,  poses  = other.outcomes
  matches.each_with_index{|match,i|
    mymatches.each_with_index{|mymatch,myi|
      intersect=parser.inputs.grep(match&mymatch)
      unless intersect.empty?

        #but don't allow matches that would be matched 
        #by an earlier (but optional) pattern.
        disallowed=Reg::Or.new(
          *possible_matchers_til(myi)+
            other.possible_matchers_til(i)
        )
        intersect.reject{|x| disallowed===x }

        if intersect.empty?
          return result=false 
        elsif poses[i]>=other.rule.patterns.size
          return result=true  #success if weaker rule is at an end
        elsif myposes[myi]>=rule.patterns.size
          return result=false             #fail if stronger rule at an end
        else
          p [:**,rule.name,myposes[myi]]
          mynew=DottedRule.create(rule,myposes[myi],parser)
          new=DottedRule.create(other.rule,poses[i],parser)
          return result=mynew.optionally_combine( new,parser )
        end
      end
    }
  }
  return result=false
ensure
  parser.oc_cache[[self,weaker]]=result
end

#outcomesObject



618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
# File 'lib/redparse/compile.rb', line 618

def outcomes
  til=@rule.patterns.size
  at=@pos
  result=[[],[]]
  loop do
    m=@rule.patterns[at]
    case m
    when Proc; 
      result.first.push Object
      result.last.push at+1
      break
    when Reg::Repeat
      assert @rule.optional?(at)
      to=at
      to+=1 unless @rule.looping? at
      result.first.push m.subregs[0]
      result.last.push to
    else
      result.first.push m
      result.last.push at+1
      break
    end
    at+=1
    break if at>=til
  end
  return result
end

#possible_matchers_til(i) ⇒ Object



611
612
613
614
615
616
# File 'lib/redparse/compile.rb', line 611

def possible_matchers_til i
  (pos...i-1).map{|j|
    m=rule.at(j)
    Reg::Repeat===m ? m.subregs[0] : m
  }
end

#recurse_match_drs(parser, result = nil) ⇒ Object

returns +[(DottedRule|nil).*]



511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
# File 'lib/redparse/compile.rb', line 511

def recurse_match_drs parser, result=nil
  unless result
    table=parser.rmd_cache
    if table
      cache=table[self]
      return cache if cache
    else
      parser.rmd_cache={}
    end

    result=[]
  end
  #print "("
  #print @rule.name+"@#@pos"
  p=@rule.at(@pos)
  
  #find set of nodes that could match here
  nodes_here=parser.exemplars_that_match(p&Node)

  #find the set of rules that could generate a node in our list
  rrules=parser.all_rules.select{|rule| 
           !rule.unruly? and !nodes_here.grep(rule.action).empty?
         }.map{|rule|
           DottedRule.create(rule,0,parser) 
         }

  #if any generating rules match a node in the leftmost pattern,
  #add the rules which can generate _that_ node too.
  result.push self  #force self to be excluded from future recursion
  oldsize=result.size
  unless rrules.empty?
    result.concat rrules
    
    unless result.respond_to? :index_of
      class<<result
        attr_accessor :index_of
      end
      result.index_of={}
    end
    rio=result.index_of
    oldsize.upto(result.size){|i| rio[result[i]]||=i }
    rrules.each{|rrule|
      i=rio[rrule] or fail #index() inside each() == O(N**2) complexity. this is the slow line.
      #but skip recursion on rules already done at a higher level
      rrule.recurse_match_drs parser,result if i>=oldsize
    }
  end
  result[oldsize-1]=nil #don't actually include self in result
  #result.update_indices oldsize-1, oldsize-1
 
  parser.rmd_cache[self]=result
  return result
#ensure print ")"
end