Module: Postsvg::Visitors::PsVisitor::ControlFlow
- Included in:
- Postsvg::Visitors::PsVisitor
- Defined in:
- lib/postsvg/visitors/ps_visitor/control_flow.rb
Overview
Control flow operator handlers. Each pops operands from the
RUNTIME stack (not the AST), so chained execution behaves
correctly. Bodies are Procedure values that descend_into_procedure
walks in the current visitor context.
Constant Summary collapse
- LOOP_LIMIT =
10_000
Instance Method Summary collapse
- #descend_into_procedure(procedure) ⇒ Object
- #visit_exec(_op, _ctx) ⇒ Object
- #visit_exit(_op, _ctx) ⇒ Object
- #visit_for(_op, _ctx) ⇒ Object
- #visit_if(_op, _ctx) ⇒ Object
- #visit_ifelse(_op, _ctx) ⇒ Object
- #visit_loop(_op, _ctx) ⇒ Object
- #visit_quit(_op, _ctx) ⇒ Object
- #visit_repeat(_op, _ctx) ⇒ Object
- #visit_stopped(_op, _ctx) ⇒ Object
Instance Method Details
#descend_into_procedure(procedure) ⇒ Object
100 101 102 103 104 |
# File 'lib/postsvg/visitors/ps_visitor/control_flow.rb', line 100 def descend_into_procedure(procedure) return unless procedure.is_a?(Model::Literals::Procedure) procedure.body.each { |node| node.accept(self, nil) } end |
#visit_exec(_op, _ctx) ⇒ Object
84 85 86 87 88 89 90 91 92 |
# File 'lib/postsvg/visitors/ps_visitor/control_flow.rb', line 84 def visit_exec(_op, _ctx) operand = @stack.pop case operand when Model::Literals::Procedure descend_into_procedure(operand) else @stack << operand end end |
#visit_exit(_op, _ctx) ⇒ Object
76 77 78 |
# File 'lib/postsvg/visitors/ps_visitor/control_flow.rb', line 76 def visit_exit(_op, _ctx) raise Postsvg::ExitSignal end |
#visit_for(_op, _ctx) ⇒ Object
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 |
# File 'lib/postsvg/visitors/ps_visitor/control_flow.rb', line 47 def visit_for(_op, _ctx) body = @stack.pop limit = pop_runtime_number.to_f increment = pop_runtime_number.to_f initial = pop_runtime_number.to_f iterations = 0 if increment.positive? value = initial while value <= limit @stack << value descend_into_procedure(body) value += increment iterations += 1 break if iterations > LOOP_LIMIT end elsif increment.negative? value = initial while value >= limit @stack << value descend_into_procedure(body) value += increment iterations += 1 break if iterations > LOOP_LIMIT end else raise RenderError, "for: zero increment" end end |
#visit_if(_op, _ctx) ⇒ Object
13 14 15 16 17 18 19 |
# File 'lib/postsvg/visitors/ps_visitor/control_flow.rb', line 13 def visit_if(_op, _ctx) body = @stack.pop condition = @stack.pop return unless truthy?(condition) descend_into_procedure(body) end |
#visit_ifelse(_op, _ctx) ⇒ Object
21 22 23 24 25 26 27 28 29 30 |
# File 'lib/postsvg/visitors/ps_visitor/control_flow.rb', line 21 def visit_ifelse(_op, _ctx) else_body = @stack.pop if_body = @stack.pop condition = @stack.pop if truthy?(condition) descend_into_procedure(if_body) else descend_into_procedure(else_body) end end |
#visit_loop(_op, _ctx) ⇒ Object
38 39 40 41 42 43 44 45 |
# File 'lib/postsvg/visitors/ps_visitor/control_flow.rb', line 38 def visit_loop(_op, _ctx) body = @stack.pop LOOP_LIMIT.times do descend_into_procedure(body) rescue Postsvg::ExitSignal break end end |
#visit_quit(_op, _ctx) ⇒ Object
80 81 82 |
# File 'lib/postsvg/visitors/ps_visitor/control_flow.rb', line 80 def visit_quit(_op, _ctx) raise Postsvg::QuitSignal end |
#visit_repeat(_op, _ctx) ⇒ Object
32 33 34 35 36 |
# File 'lib/postsvg/visitors/ps_visitor/control_flow.rb', line 32 def visit_repeat(_op, _ctx) body = @stack.pop count = pop_runtime_number.to_i.clamp(0, LOOP_LIMIT) count.times { descend_into_procedure(body) } end |
#visit_stopped(_op, _ctx) ⇒ Object
94 95 96 97 98 |
# File 'lib/postsvg/visitors/ps_visitor/control_flow.rb', line 94 def visit_stopped(_op, _ctx) body = @stack.pop descend_into_procedure(body) @stack << false end |