Class: Ryac::Pipeline::ConstantFold
- Defined in:
- lib/ryac/pipeline/constant_fold.rb,
sig/ryac/pipeline/constant_fold.rbs
Constant Summary collapse
- FOLDABLE_OPS =
%i[+ - * / % ** << >> & | ^].freeze
- INTEGER_ONLY_OPS =
%i[<< >> & | ^].freeze
Instance Method Summary collapse
-
#apply_op(lhs, op, rhs) ⇒ Numeric?
The operands are Integer | Float at runtime, but RBS's Numeric does not carry the arithmetic operators and the op is dispatched on a Symbol tag, so the operands stay untyped.
- #collect(ctx, patches) ⇒ void
- #try_constant_fold(node) ⇒ Numeric?
- #try_fold_binary_op(node) ⇒ Numeric?
- #walk(node, patches) ⇒ void
Methods inherited from Stage
#analysis, #analysis_options, #call, #finish, #fixpoint?, #needs_analysis?, new
Methods included from SourcePatcher
#apply_patches, #mk, #src, #verify_parses
Instance Method Details
#apply_op(lhs, op, rhs) ⇒ Numeric?
The operands are Integer | Float at runtime, but RBS's Numeric does not carry the arithmetic operators and the op is dispatched on a Symbol tag, so the operands stay untyped.
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'sig/ryac/pipeline/constant_fold.rbs', line 17 def apply_op(lhs, op, rhs) case op when :+ then lhs + rhs when :- then lhs - rhs when :* then lhs * rhs when :/ then lhs / rhs when :% then lhs % rhs when :** then lhs ** rhs when :<< then lhs << rhs when :>> then lhs >> rhs when :& then lhs & rhs when :| then lhs | rhs when :^ then lhs ^ rhs end end |
#collect(ctx, patches) ⇒ void
This method returns an undefined value.
9 10 11 |
# File 'lib/ryac/pipeline/constant_fold.rb', line 9 def collect(ctx, patches) walk(ctx.ast, patches) end |
#try_constant_fold(node) ⇒ Numeric?
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/ryac/pipeline/constant_fold.rb', line 29 def try_constant_fold(node) case node when Prism::IntegerNode then node.value when Prism::FloatNode then node.value when Prism::ParenthesesNode body = node.body if body.is_a?(Prism::StatementsNode) && body.body.size == 1 try_constant_fold(body.body.first) end when Prism::CallNode if node.receiver && node.arguments.nil? && node.name == :-@ inner = try_constant_fold(node.receiver) return nil unless inner.is_a?(Numeric) -inner else try_fold_binary_op(node) end end end |
#try_fold_binary_op(node) ⇒ Numeric?
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/ryac/pipeline/constant_fold.rb', line 49 def try_fold_binary_op(node) return nil unless node.receiver return nil unless node.arguments&.arguments&.size == 1 return nil if node.block op = node.name return nil unless FOLDABLE_OPS.include?(op) lhs = try_constant_fold(node.receiver) return nil unless lhs.is_a?(Numeric) # arguments proved non-nil above rhs = try_constant_fold(node.arguments.arguments.first) # steep:ignore NoMethod return nil unless rhs.is_a?(Numeric) return nil if INTEGER_ONLY_OPS.include?(op) && !(lhs.is_a?(Integer) && rhs.is_a?(Integer)) return nil if (op == :/ || op == :%) && rhs == 0 result = apply_op(lhs, op, rhs) return nil unless result.is_a?(Integer) || result.is_a?(Float) return nil if result.is_a?(Float) && (result.nan? || result.infinite?) result rescue StandardError nil end |
#walk(node, patches) ⇒ void
This method returns an undefined value.
15 16 17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/ryac/pipeline/constant_fold.rb', line 15 def walk(node, patches) if node.is_a?(Prism::CallNode) folded = try_constant_fold(node) if folded replacement = folded.to_s if replacement.bytesize < node.location.length patches << mk(node, replacement) return end end end node.compact_child_nodes.each { |child| walk(child, patches) } end |