Class: Ibex::TableSimulation::Session

Inherits:
Object
  • Object
show all
Defined in:
lib/ibex/table_simulation/simulator.rb,
sig/ibex/table_simulation/simulator.rbs

Overview

Stateful token-at-a-time table simulation session.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(simulator) ⇒ Session

Returns a new instance of Session.

RBS:

  • (Simulator simulator) -> void

Parameters:



91
92
93
94
95
96
97
98
# File 'lib/ibex/table_simulation/simulator.rb', line 91

def initialize(simulator)
  @simulator = simulator
  @state_stack = [0] #: Array[Integer]
  @status = nil
  @steps = []
  @tokens = []
  @finished = false
end

Instance Attribute Details

#statusSymbol? (readonly)

RBS:

  • @steps: Array[Step]

  • @tokens: Array[String]

Returns:

  • (Symbol, nil)


88
89
90
# File 'lib/ibex/table_simulation/simulator.rb', line 88

def status
  @status
end

Instance Method Details

#action_for(state, token_id) ⇒ [ IR::parser_action, String ]

RBS:

  • (IR::AutomatonState state, Integer token_id) -> [IR::parser_action, String]

Parameters:

Returns:

  • ([ IR::parser_action, String ])


159
160
161
162
163
164
# File 'lib/ibex/table_simulation/simulator.rb', line 159

def action_for(state, token_id)
  return [state.actions.fetch(token_id), "explicit"] if state.actions.key?(token_id)
  return [state.default_action, "default"] if state.default_action

  [Simulator::IMPLICIT_ERROR, "implicit"]
end

#append_step(state, terminal, action, source, before:, production_id: nil, lhs: nil, rhs_length: nil, target_state: nil) ⇒ void

This method returns an undefined value.

RBS:

  • (IR::AutomatonState state, IR::GrammarSymbol terminal, String action, String source, before: Integer, ?production_id: Integer?, ?lhs: String?, ?rhs_length: Integer?, ?target_state: Integer?) -> void

Parameters:

  • state (IR::AutomatonState)
  • terminal (IR::GrammarSymbol)
  • action (String)
  • source (String)
  • before: (Integer)
  • production_id: (Integer, nil) (defaults to: nil)
  • lhs: (String, nil) (defaults to: nil)
  • rhs_length: (Integer, nil) (defaults to: nil)
  • target_state: (Integer, nil) (defaults to: nil)


213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/ibex/table_simulation/simulator.rb', line 213

def append_step(state, terminal, action, source, before:, production_id: nil, lhs: nil, rhs_length: nil,
                target_state: nil)
  raise Ibex::Error, "(debug):1:1: simulation exceeded #{@simulator.max_steps} actions" \
    if @steps.length >= @simulator.max_steps

  @steps << Step.new(
    sequence: @steps.length + 1,
    state: state.id,
    token_id: terminal.id,
    token: terminal.display_name || terminal.name,
    action: action,
    action_source: source,
    production_id: production_id,
    lhs: lhs,
    rhs_length: rhs_length,
    target_state: target_state,
    stack_depth_before: before,
    stack_depth_after: @state_stack.length
  )
end

#current_stateIR::AutomatonState

RBS:

  • () -> IR::AutomatonState

Returns:



235
236
237
238
# File 'lib/ibex/table_simulation/simulator.rb', line 235

def current_state
  id = @state_stack.last || raise(Ibex::Error, "(debug):1:1: simulated state stack is empty")
  @simulator.automaton.states.fetch(id)
end

#enforce_stack_budget!void

This method returns an undefined value.

RBS:

  • () -> void



241
242
243
244
245
# File 'lib/ibex/table_simulation/simulator.rb', line 241

def enforce_stack_budget!
  return if @state_stack.length <= @simulator.max_stack

  raise Ibex::Error, "(debug):1:1: simulation exceeded stack depth #{@simulator.max_stack}"
end

#ensure_active!void

This method returns an undefined value.

RBS:

  • () -> void



248
249
250
# File 'lib/ibex/table_simulation/simulator.rb', line 248

def ensure_active!
  raise Ibex::Error, "(debug):1:1: simulation session is already finished" if @finished || @status
end

#finishResult

RBS:

  • () -> Result

Returns:



115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/ibex/table_simulation/simulator.rb', line 115

def finish
  raise Ibex::Error, "(debug):1:1: simulation session is already finished" if @finished

  @finished = true
  process(@simulator.eof, eof: true) until @status
  Result.new(
    grammar_digest: @simulator.automaton.grammar_digest,
    algorithm: @simulator.automaton.algorithm,
    tokens: @tokens,
    status: @status || raise(Ibex::Error, "(debug):1:1: simulation did not terminate"),
    steps: @steps
  )
end

#process(terminal, eof:) ⇒ Array[Step]

RBS:

  • (IR::GrammarSymbol terminal, eof: bool) -> Array[Step]

Parameters:

Returns:



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/ibex/table_simulation/simulator.rb', line 132

def process(terminal, eof:)
  first = @steps.length
  loop do
    state = current_state
    action, source = action_for(state, terminal.id)
    case action.fetch(:type)
    when :shift
      record_shift(state, terminal, action, source)
      next if eof

      break
    when :reduce then record_reduce(state, terminal, action, source)
    when :accept
      record_terminal(state, terminal, "accept", source)
      @status = :accepted
      break
    when :error
      record_terminal(state, terminal, "error", source)
      @status = :error
      break
    else raise Ibex::Error, "(debug):1:1: unknown table action #{action.inspect}"
    end
  end
  @steps.drop(first).freeze
end

#push(spelling) ⇒ Array[Step]

RBS:

  • (String spelling) -> Array[Step]

Parameters:

  • spelling (String)

Returns:



101
102
103
104
105
106
# File 'lib/ibex/table_simulation/simulator.rb', line 101

def push(spelling)
  ensure_active!
  terminal = @simulator.terminal(spelling)
  @tokens << terminal.name
  process(terminal, eof: false)
end

#record_reduce(state, terminal, action, source) ⇒ void

This method returns an undefined value.

RBS:

  • (IR::AutomatonState state, IR::GrammarSymbol terminal, IR::parser_action action, String source) -> void

Parameters:



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/ibex/table_simulation/simulator.rb', line 177

def record_reduce(state, terminal, action, source)
  reduction = action #: IR::reduce_action
  production_id = reduction.fetch(:production)
  production = @simulator.automaton.grammar.productions.fetch(production_id)
  length = production.rhs.length
  before = @state_stack.length
  if length >= before
    raise Ibex::Error, "(debug):1:1: production #{production_id} underflows the simulated state stack"
  end

  @state_stack.pop(length)
  goto = current_state.gotos[production.lhs]
  unless goto
    raise Ibex::Error, "(debug):1:1: missing goto for production #{production_id} from state #{current_state.id}"
  end

  @state_stack << goto
  enforce_stack_budget!
  lhs = @simulator.automaton.grammar.symbol_by_id(production.lhs)
  raise Ibex::Error, "(debug):1:1: missing lhs symbol #{production.lhs}" unless lhs

  append_step(
    state, terminal, "reduce", source,
    production_id: production_id, lhs: lhs.name, rhs_length: length,
    target_state: goto, before: before
  )
end

#record_shift(state, terminal, action, source) ⇒ void

This method returns an undefined value.

RBS:

  • (IR::AutomatonState state, IR::GrammarSymbol terminal, IR::parser_action action, String source) -> void

Parameters:



167
168
169
170
171
172
173
174
# File 'lib/ibex/table_simulation/simulator.rb', line 167

def record_shift(state, terminal, action, source)
  shift = action #: IR::shift_action
  before = @state_stack.length
  target = shift.fetch(:state)
  @state_stack << target
  enforce_stack_budget!
  append_step(state, terminal, "shift", source, target_state: target, before: before)
end

#record_terminal(state, terminal, action, source) ⇒ void

This method returns an undefined value.

RBS:

  • (IR::AutomatonState state, IR::GrammarSymbol terminal, String action, String source) -> void

Parameters:



206
207
208
# File 'lib/ibex/table_simulation/simulator.rb', line 206

def record_terminal(state, terminal, action, source)
  append_step(state, terminal, action, source, before: @state_stack.length)
end

#stepsArray[Step]

RBS:

  • () -> Array[Step]

Returns:



109
# File 'lib/ibex/table_simulation/simulator.rb', line 109

def steps = @steps.dup.freeze

#tokensArray[String]

RBS:

  • () -> Array[String]

Returns:

  • (Array[String])


112
# File 'lib/ibex/table_simulation/simulator.rb', line 112

def tokens = @tokens.dup.freeze