Class: RegularExpression::Interpreter

Inherits:
Object
  • Object
show all
Defined in:
lib/regular_expression/interpreter.rb

Overview

An interpreter for our compiled bytecode. Maybe we could make this possible to enter at a given state and deoptimise to it from the compiled code?

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(bytecode) ⇒ Interpreter

Returns a new instance of Interpreter.



9
10
11
# File 'lib/regular_expression/interpreter.rb', line 9

def initialize(bytecode)
  @bytecode = bytecode
end

Instance Attribute Details

#bytecodeObject (readonly)

Returns the value of attribute bytecode.



7
8
9
# File 'lib/regular_expression/interpreter.rb', line 7

def bytecode
  @bytecode
end

Instance Method Details

#match?(string) ⇒ Boolean

Returns:

  • (Boolean)


19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/regular_expression/interpreter.rb', line 19

def match?(string)
  stack = []

  (0..string.size).any? do |start_n|
    string_n = start_n
    insn_n = 0

    loop do
      insn = bytecode.insns[insn_n]

      case insn
      when Bytecode::Insns::PushIndex
        stack << string_n
        insn_n += 1
      when Bytecode::Insns::PopIndex
        string_n = stack.pop
        insn_n += 1
      when Bytecode::Insns::GuardBegin
        return false if start_n != 0

        insn_n = bytecode.labels[insn.guarded]
      when Bytecode::Insns::GuardEnd
        break if string_n != string.size

        insn_n = bytecode.labels[insn.guarded]
      when Bytecode::Insns::JumpAny
        if string_n < string.size
          string_n += 1
          insn_n = bytecode.labels[insn.target]
        else
          insn_n += 1
        end
      when Bytecode::Insns::JumpValue
        if string_n < string.size && string[string_n] == insn.char
          string_n += 1
          insn_n = bytecode.labels[insn.target]
        else
          insn_n += 1
        end
      when Bytecode::Insns::JumpValuesInvert
        if string_n < string.size && !insn.chars.include?(string[string_n])
          string_n += 1
          insn_n = bytecode.labels[insn.target]
        else
          insn_n += 1
        end
      when Bytecode::Insns::JumpRange
        if string_n < string.size && string[string_n] >= insn.left && string[string_n] <= insn.right
          string_n += 1
          insn_n = bytecode.labels[insn.target]
        else
          insn_n += 1
        end
      when Bytecode::Insns::JumpRangeInvert
        if string_n < string.size && (string[string_n] < insn.left || string[string_n] > insn.right)
          string_n += 1
          insn_n = bytecode.labels[insn.target]
        else
          insn_n += 1
        end
      when Bytecode::Insns::Jump
        insn_n = bytecode.labels[insn.target]
      when Bytecode::Insns::Match
        return true
      when Bytecode::Insns::Fail
        break
      else
        raise
      end
    end
  end
end

#to_procObject

This is just here for API parity with the compiled outputs.



14
15
16
17
# File 'lib/regular_expression/interpreter.rb', line 14

def to_proc
  interpreter = self
  ->(string) { interpreter.match?(string) }
end