Class: Stupidedi::Parser::BuilderDsl

Inherits:
Object
  • Object
show all
Includes:
Inspect, Tokenization
Defined in:
lib/stupidedi/parser/builder_dsl.rb

Instance Attribute Summary collapse

Constructors collapse

Instance Method Summary collapse

Methods included from Tokenization

#blank, #composite, #default, #not_used, #repeated

Methods included from Inspect

#inspect

Constructor Details

#initialize(machine, strict = true) ⇒ BuilderDsl

Returns a new instance of BuilderDsl.



24
25
26
27
28
29
# File 'lib/stupidedi/parser/builder_dsl.rb', line 24

def initialize(machine, strict = true)
  @machine = machine
  @strict  = strict
  @reader  = DslReader.new(Reader::Separators.empty,
                           Reader::SegmentDict.empty)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) (private)



101
102
103
104
105
106
107
# File 'lib/stupidedi/parser/builder_dsl.rb', line 101

def method_missing(name, *args)
  if SEGMENT_ID =~ name.to_s
    segment!(name, Reader::Position.caller(2), *args)
  else
    super
  end
end

Instance Attribute Details

#machineStateMachine (readonly)

Returns:



14
15
16
# File 'lib/stupidedi/parser/builder_dsl.rb', line 14

def machine
  @machine
end

#readerDslReader (readonly)

Returns:

  • (DslReader)


20
21
22
# File 'lib/stupidedi/parser/builder_dsl.rb', line 20

def reader
  @reader
end

#strict=(value) ⇒ Boolean (writeonly)

Returns:

  • (Boolean)


17
18
19
# File 'lib/stupidedi/parser/builder_dsl.rb', line 17

def strict=(value)
  @strict = value
end

Class Method Details

.build(config, strict = true) ⇒ BuilderDsl

Returns:



260
261
262
# File 'lib/stupidedi/parser/builder_dsl.rb', line 260

def build(config, strict = true)
  new(StateMachine.build(config), strict)
end

Instance Method Details

#respond_to_missing?(name, include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


31
32
33
# File 'lib/stupidedi/parser/builder_dsl.rb', line 31

def respond_to_missing?(name, include_private = false)
  SEGMENT_ID =~ name.to_s || super
end

#segment!(name, position, *elements) ⇒ BuilderDsl

Returns:



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
91
92
93
94
95
96
97
# File 'lib/stupidedi/parser/builder_dsl.rb', line 40

def segment!(name, position, *elements)
  segment_tok     = mksegment_tok(@reader.segment_dict, name, elements, position)
  machine, reader = @machine.insert(segment_tok, @strict, @reader)

  if @strict
    unless machine.deterministic?
      matches = machine.active.map do |m|
        segment_def = m.node.zipper.node.definition
        "#{segment_def.id} #{segment_def.name}"
      end.join(", ")

      raise Exceptions::ParseError,
        "non-deterministic machine state: #{matches}"
    end

    # Validate the new segment (recursively, including its children)
    machine.active.each{|m| critique(m.node.zipper) }

    # We want to detect when we've ended a syntax node (or more), like
    # starting a new interchange will end all previously "open" syntax
    # nodes. So we compare the state before adding `segment_tok` to the
    # corresponding state after we've added `segment_tok`.

    machine.prev.tap do |prev|
      prev.active.zip(machine.active) do |p, q|
        # If the new state `q` is a descendent of `p`, we know that `p`
        # and all of its ancestors are unterminated. However, if `q` is
        # not a descendent of `p`, but is a descendent of one of `p`s
        # descendents, then `p` and perhaps some of its ancestors were
        # terminated when the state transitioned to `q`.
        qancestors = Set.new

        # Operate on the syntax tree (instead of the state tree)
        q = q.node.zipper
        p = p.node.zipper

        while q.respond_to?(:parent)
          qancestors << q.parent
          q = q.parent
        end

        while p.respond_to?(:parent)
          break if qancestors.include?(p)

          # Now that we're sure that this syntax node (loop, table, etc)
          # is done being constructed, we can perform more validations.
          critique(p)
          p = p.parent
        end
      end
    end
  end

  @machine = machine
  @reader  = reader

  self
end

#strict?Boolean

Returns:

  • (Boolean)


35
36
37
# File 'lib/stupidedi/parser/builder_dsl.rb', line 35

def strict?
  @strict
end