laser 0.7.0.pre1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +14 -0
- data/LICENSE +661 -0
- data/README.md +158 -0
- data/Rakefile +104 -0
- data/VERSION +1 -0
- data/bin/laser +7 -0
- data/design_docs/goals.md +57 -0
- data/design_docs/object_regex.md +426 -0
- data/design_docs/type_annotations.md +80 -0
- data/ext/laser/BasicBlock.cpp +572 -0
- data/ext/laser/BasicBlock.h +118 -0
- data/ext/laser/extconf.rb +3 -0
- data/features/laser.feature +25 -0
- data/features/step_definitions/laser_steps.rb +39 -0
- data/features/support/env.rb +14 -0
- data/features/support/testdata/1_input +1 -0
- data/features/support/testdata/1_output +1 -0
- data/features/support/testdata/2_input +4 -0
- data/features/support/testdata/2_output +4 -0
- data/features/support/testdata/3_input +8 -0
- data/features/support/testdata/3_output +11 -0
- data/features/support/testdata/4_input +5 -0
- data/features/support/testdata/4_output +5 -0
- data/features/support/testdata/5_input +13 -0
- data/laser.gemspec +382 -0
- data/lib/laser.rb +98 -0
- data/lib/laser/analysis/annotations.rb +95 -0
- data/lib/laser/analysis/annotations/annotation_config.yaml +3 -0
- data/lib/laser/analysis/annotations/comment_attachment_annotation.rb +66 -0
- data/lib/laser/analysis/annotations/node_pointers_annotation.rb +36 -0
- data/lib/laser/analysis/annotations/runtime_annotation.rb +55 -0
- data/lib/laser/analysis/argument_expansion.rb +132 -0
- data/lib/laser/analysis/arity.rb +34 -0
- data/lib/laser/analysis/bindings.rb +144 -0
- data/lib/laser/analysis/bootstrap/bootstrap.rb +298 -0
- data/lib/laser/analysis/bootstrap/laser_class.rb +106 -0
- data/lib/laser/analysis/bootstrap/laser_method.rb +255 -0
- data/lib/laser/analysis/bootstrap/laser_module.rb +403 -0
- data/lib/laser/analysis/bootstrap/laser_module_copy.rb +74 -0
- data/lib/laser/analysis/bootstrap/laser_object.rb +69 -0
- data/lib/laser/analysis/bootstrap/laser_proc.rb +150 -0
- data/lib/laser/analysis/bootstrap/laser_singleton_class.rb +44 -0
- data/lib/laser/analysis/comments.rb +35 -0
- data/lib/laser/analysis/control_flow.rb +28 -0
- data/lib/laser/analysis/control_flow/alias_analysis.rb +31 -0
- data/lib/laser/analysis/control_flow/basic_block.rb +105 -0
- data/lib/laser/analysis/control_flow/cfg_builder.rb +2505 -0
- data/lib/laser/analysis/control_flow/cfg_instruction.rb +190 -0
- data/lib/laser/analysis/control_flow/constant_propagation.rb +742 -0
- data/lib/laser/analysis/control_flow/control_flow_graph.rb +370 -0
- data/lib/laser/analysis/control_flow/lifetime_analysis.rb +91 -0
- data/lib/laser/analysis/control_flow/method_call_search.rb +26 -0
- data/lib/laser/analysis/control_flow/raise_properties.rb +25 -0
- data/lib/laser/analysis/control_flow/simulation.rb +385 -0
- data/lib/laser/analysis/control_flow/static_single_assignment.rb +185 -0
- data/lib/laser/analysis/control_flow/unreachability_analysis.rb +57 -0
- data/lib/laser/analysis/control_flow/unused_variables.rb +91 -0
- data/lib/laser/analysis/control_flow/yield_properties.rb +103 -0
- data/lib/laser/analysis/errors.rb +131 -0
- data/lib/laser/analysis/laser_utils.rb +18 -0
- data/lib/laser/analysis/lexical_analysis.rb +172 -0
- data/lib/laser/analysis/method_call.rb +68 -0
- data/lib/laser/analysis/protocol_registry.rb +30 -0
- data/lib/laser/analysis/scope.rb +118 -0
- data/lib/laser/analysis/sexp.rb +159 -0
- data/lib/laser/analysis/sexp_analysis.rb +40 -0
- data/lib/laser/analysis/sexp_extensions/constant_extraction.rb +115 -0
- data/lib/laser/analysis/sexp_extensions/source_location.rb +164 -0
- data/lib/laser/analysis/sexp_extensions/type_inference.rb +47 -0
- data/lib/laser/analysis/signature.rb +76 -0
- data/lib/laser/analysis/special_methods/send.rb +67 -0
- data/lib/laser/analysis/unused_methods.rb +21 -0
- data/lib/laser/analysis/visitor.rb +141 -0
- data/lib/laser/annotation_parser/annotations.treetop +126 -0
- data/lib/laser/annotation_parser/annotations_parser.rb +748 -0
- data/lib/laser/annotation_parser/class_annotations.treetop +82 -0
- data/lib/laser/annotation_parser/class_annotations_parser.rb +654 -0
- data/lib/laser/annotation_parser/overload.treetop +24 -0
- data/lib/laser/annotation_parser/overload_parser.rb +167 -0
- data/lib/laser/annotation_parser/parsers.rb +6 -0
- data/lib/laser/annotation_parser/structural.treetop +37 -0
- data/lib/laser/annotation_parser/structural_parser.rb +406 -0
- data/lib/laser/annotation_parser/useful_parsers.treetop +47 -0
- data/lib/laser/annotation_parser/useful_parsers_parser.rb +674 -0
- data/lib/laser/rake/task.rb +46 -0
- data/lib/laser/runner.rb +189 -0
- data/lib/laser/scanner.rb +169 -0
- data/lib/laser/standard_library/_thread.rb +110 -0
- data/lib/laser/standard_library/abbrev.rb +103 -0
- data/lib/laser/standard_library/array.rb +418 -0
- data/lib/laser/standard_library/base64.rb +91 -0
- data/lib/laser/standard_library/basic_object.rb +55 -0
- data/lib/laser/standard_library/benchmark.rb +556 -0
- data/lib/laser/standard_library/bignum.rb +185 -0
- data/lib/laser/standard_library/cgi.rb +275 -0
- data/lib/laser/standard_library/cgi/cookie.rb +147 -0
- data/lib/laser/standard_library/cgi/core.rb +791 -0
- data/lib/laser/standard_library/cgi/html.rb +1021 -0
- data/lib/laser/standard_library/cgi/session.rb +537 -0
- data/lib/laser/standard_library/cgi/session/pstore.rb +111 -0
- data/lib/laser/standard_library/cgi/util.rb +188 -0
- data/lib/laser/standard_library/class_definitions.rb +333 -0
- data/lib/laser/standard_library/comparable.rb +125 -0
- data/lib/laser/standard_library/complex.rb +162 -0
- data/lib/laser/standard_library/enumerable.rb +178 -0
- data/lib/laser/standard_library/exceptions.rb +135 -0
- data/lib/laser/standard_library/fixnum.rb +188 -0
- data/lib/laser/standard_library/float.rb +180 -0
- data/lib/laser/standard_library/hash.rb +237 -0
- data/lib/laser/standard_library/integer.rb +123 -0
- data/lib/laser/standard_library/laser_magic.rb +7 -0
- data/lib/laser/standard_library/nil_false_true.rb +113 -0
- data/lib/laser/standard_library/numbers.rb +192 -0
- data/lib/laser/standard_library/proc.rb +31 -0
- data/lib/laser/standard_library/set.rb +1348 -0
- data/lib/laser/standard_library/string.rb +666 -0
- data/lib/laser/standard_library/stringio.rb +2 -0
- data/lib/laser/standard_library/symbol.rb +125 -0
- data/lib/laser/standard_library/tsort.rb +242 -0
- data/lib/laser/support/acts_as_struct.rb +66 -0
- data/lib/laser/support/frequency.rb +55 -0
- data/lib/laser/support/inheritable_attributes.rb +145 -0
- data/lib/laser/support/module_extensions.rb +94 -0
- data/lib/laser/support/placeholder_object.rb +13 -0
- data/lib/laser/third_party/rgl/adjacency.rb +221 -0
- data/lib/laser/third_party/rgl/base.rb +228 -0
- data/lib/laser/third_party/rgl/bidirectional.rb +39 -0
- data/lib/laser/third_party/rgl/condensation.rb +47 -0
- data/lib/laser/third_party/rgl/connected_components.rb +138 -0
- data/lib/laser/third_party/rgl/control_flow.rb +170 -0
- data/lib/laser/third_party/rgl/depth_first_spanning_tree.rb +37 -0
- data/lib/laser/third_party/rgl/dominators.rb +124 -0
- data/lib/laser/third_party/rgl/dot.rb +93 -0
- data/lib/laser/third_party/rgl/graphxml.rb +51 -0
- data/lib/laser/third_party/rgl/implicit.rb +174 -0
- data/lib/laser/third_party/rgl/mutable.rb +117 -0
- data/lib/laser/third_party/rgl/rdot.rb +445 -0
- data/lib/laser/third_party/rgl/topsort.rb +72 -0
- data/lib/laser/third_party/rgl/transitivity.rb +180 -0
- data/lib/laser/third_party/rgl/traversal.rb +348 -0
- data/lib/laser/types/types.rb +433 -0
- data/lib/laser/version.rb +14 -0
- data/lib/laser/warning.rb +149 -0
- data/lib/laser/warning_sets/default.yml +13 -0
- data/lib/laser/warnings/assignment_in_condition.rb +20 -0
- data/lib/laser/warnings/comment_spacing.rb +31 -0
- data/lib/laser/warnings/extra_blank_lines.rb +30 -0
- data/lib/laser/warnings/extra_whitespace.rb +16 -0
- data/lib/laser/warnings/hash_symbol_18_warning.rb +63 -0
- data/lib/laser/warnings/hash_symbol_19_warning.rb +29 -0
- data/lib/laser/warnings/line_length.rb +115 -0
- data/lib/laser/warnings/misaligned_unindentation.rb +17 -0
- data/lib/laser/warnings/operator_spacing.rb +68 -0
- data/lib/laser/warnings/parens_on_declaration.rb +30 -0
- data/lib/laser/warnings/rescue_exception.rb +42 -0
- data/lib/laser/warnings/semicolon.rb +25 -0
- data/lib/laser/warnings/sexp_errors.rb +24 -0
- data/lib/laser/warnings/uncalled_method_warning.rb +7 -0
- data/lib/laser/warnings/useless_double_quotes.rb +38 -0
- data/spec/analysis_specs/annotations_spec.rb +47 -0
- data/spec/analysis_specs/annotations_specs/comment_attachment_spec.rb +68 -0
- data/spec/analysis_specs/annotations_specs/node_pointers_annotation_spec.rb +90 -0
- data/spec/analysis_specs/annotations_specs/runtime_annotation_spec.rb +135 -0
- data/spec/analysis_specs/annotations_specs/spec_helper.rb +33 -0
- data/spec/analysis_specs/argument_expansion_spec.rb +113 -0
- data/spec/analysis_specs/bindings_spec.rb +36 -0
- data/spec/analysis_specs/comment_spec.rb +93 -0
- data/spec/analysis_specs/control_flow_specs/cfg_instruction_spec.rb +111 -0
- data/spec/analysis_specs/control_flow_specs/constant_propagation_spec.rb +560 -0
- data/spec/analysis_specs/control_flow_specs/control_flow_graph_spec.rb +5 -0
- data/spec/analysis_specs/control_flow_specs/raise_properties_spec.rb +310 -0
- data/spec/analysis_specs/control_flow_specs/raise_type_inference_spec.rb +301 -0
- data/spec/analysis_specs/control_flow_specs/return_type_inference_spec.rb +431 -0
- data/spec/analysis_specs/control_flow_specs/simulation_spec.rb +158 -0
- data/spec/analysis_specs/control_flow_specs/spec_helper.rb +110 -0
- data/spec/analysis_specs/control_flow_specs/tuple_misuse_inference_spec.rb +125 -0
- data/spec/analysis_specs/control_flow_specs/unreachability_analysis_spec.rb +76 -0
- data/spec/analysis_specs/control_flow_specs/unused_variable_spec.rb +99 -0
- data/spec/analysis_specs/control_flow_specs/yield_properties_spec.rb +372 -0
- data/spec/analysis_specs/error_spec.rb +30 -0
- data/spec/analysis_specs/laser_class_spec.rb +322 -0
- data/spec/analysis_specs/lexical_analysis_spec.rb +184 -0
- data/spec/analysis_specs/protocol_registry_spec.rb +63 -0
- data/spec/analysis_specs/scope_annotation_spec.rb +1013 -0
- data/spec/analysis_specs/scope_spec.rb +126 -0
- data/spec/analysis_specs/sexp_analysis_spec.rb +30 -0
- data/spec/analysis_specs/sexp_extension_specs/constant_extraction_spec.rb +309 -0
- data/spec/analysis_specs/sexp_extension_specs/source_location_spec.rb +231 -0
- data/spec/analysis_specs/sexp_extension_specs/spec_helper.rb +1 -0
- data/spec/analysis_specs/sexp_extension_specs/type_inference_spec.rb +252 -0
- data/spec/analysis_specs/sexp_spec.rb +167 -0
- data/spec/analysis_specs/spec_helper.rb +27 -0
- data/spec/analysis_specs/unused_methods_spec.rb +65 -0
- data/spec/analysis_specs/visitor_spec.rb +64 -0
- data/spec/annotation_parser_specs/annotations_parser_spec.rb +89 -0
- data/spec/annotation_parser_specs/class_annotation_parser_spec.rb +120 -0
- data/spec/annotation_parser_specs/overload_parser_spec.rb +39 -0
- data/spec/annotation_parser_specs/parsers_spec.rb +14 -0
- data/spec/annotation_parser_specs/spec_helper.rb +1 -0
- data/spec/annotation_parser_specs/structural_parser_spec.rb +67 -0
- data/spec/laser_spec.rb +14 -0
- data/spec/rake_specs/spec_helper.rb +1 -0
- data/spec/rake_specs/task_spec.rb +67 -0
- data/spec/runner_spec.rb +207 -0
- data/spec/scanner_spec.rb +75 -0
- data/spec/spec_helper.rb +121 -0
- data/spec/standard_library/exceptions_spec.rb +19 -0
- data/spec/standard_library/globals_spec.rb +14 -0
- data/spec/standard_library/set_spec.rb +31 -0
- data/spec/standard_library/spec_helper.rb +1 -0
- data/spec/standard_library/standard_library_spec.rb +302 -0
- data/spec/support_specs/acts_as_struct_spec.rb +94 -0
- data/spec/support_specs/frequency_spec.rb +23 -0
- data/spec/support_specs/module_extensions_spec.rb +117 -0
- data/spec/support_specs/spec_helper.rb +1 -0
- data/spec/type_specs/spec_helper.rb +1 -0
- data/spec/type_specs/types_spec.rb +133 -0
- data/spec/warning_spec.rb +95 -0
- data/spec/warning_specs/assignment_in_condition_spec.rb +68 -0
- data/spec/warning_specs/comment_spacing_spec.rb +65 -0
- data/spec/warning_specs/extra_blank_lines_spec.rb +70 -0
- data/spec/warning_specs/extra_whitespace_spec.rb +33 -0
- data/spec/warning_specs/hash_symbol_18_warning_spec.rb +89 -0
- data/spec/warning_specs/hash_symbol_19_warning_spec.rb +63 -0
- data/spec/warning_specs/line_length_spec.rb +173 -0
- data/spec/warning_specs/misaligned_unindentation_spec.rb +35 -0
- data/spec/warning_specs/operator_spacing_spec.rb +104 -0
- data/spec/warning_specs/parens_on_declaration_spec.rb +57 -0
- data/spec/warning_specs/rescue_exception_spec.rb +105 -0
- data/spec/warning_specs/semicolon_spec.rb +58 -0
- data/spec/warning_specs/spec_helper.rb +1 -0
- data/spec/warning_specs/useless_double_quotes_spec.rb +74 -0
- data/status_reports/2010/12/2010-12-14.md +163 -0
- data/status_reports/2010/12/2010-12-23.md +298 -0
- data/status_reports/2010/12/2010-12-24.md +6 -0
- data/test/third_party_tests/rgl_tests/TestComponents.rb +65 -0
- data/test/third_party_tests/rgl_tests/TestCycles.rb +61 -0
- data/test/third_party_tests/rgl_tests/TestDirectedGraph.rb +125 -0
- data/test/third_party_tests/rgl_tests/TestDot.rb +18 -0
- data/test/third_party_tests/rgl_tests/TestEdge.rb +34 -0
- data/test/third_party_tests/rgl_tests/TestGraph.rb +71 -0
- data/test/third_party_tests/rgl_tests/TestGraphXML.rb +57 -0
- data/test/third_party_tests/rgl_tests/TestImplicit.rb +52 -0
- data/test/third_party_tests/rgl_tests/TestRdot.rb +863 -0
- data/test/third_party_tests/rgl_tests/TestTransitivity.rb +129 -0
- data/test/third_party_tests/rgl_tests/TestTraversal.rb +220 -0
- data/test/third_party_tests/rgl_tests/TestUnDirectedGraph.rb +102 -0
- data/test/third_party_tests/rgl_tests/examples/north/Graph.log +128 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.0.graphml +28 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.1.graphml +28 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.11.graphml +31 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.12.graphml +27 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.13.graphml +27 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.14.graphml +27 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.15.graphml +26 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.16.graphml +26 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.17.graphml +26 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.19.graphml +37 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.2.graphml +28 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.20.graphml +38 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.22.graphml +43 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.24.graphml +30 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.25.graphml +45 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.27.graphml +38 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.28.graphml +30 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.29.graphml +38 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.3.graphml +26 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.30.graphml +34 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.31.graphml +42 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.34.graphml +42 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.37.graphml +28 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.38.graphml +38 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.39.graphml +36 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.4.graphml +26 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.40.graphml +37 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.41.graphml +37 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.42.graphml +26 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.45.graphml +28 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.46.graphml +32 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.5.graphml +31 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.50.graphml +30 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.56.graphml +29 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.57.graphml +32 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.58.graphml +32 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.6.graphml +26 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.60.graphml +32 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.61.graphml +34 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.62.graphml +34 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.68.graphml +30 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.69.graphml +32 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.7.graphml +29 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.70.graphml +26 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.71.graphml +27 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.72.graphml +28 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.74.graphml +29 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.75.graphml +29 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.78.graphml +27 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.79.graphml +34 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.8.graphml +29 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.80.graphml +34 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.82.graphml +35 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.83.graphml +32 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.85.graphml +34 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.86.graphml +34 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.88.graphml +37 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.89.graphml +29 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.9.graphml +26 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.90.graphml +32 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.91.graphml +31 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.92.graphml +26 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.93.graphml +32 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.94.graphml +34 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.12.8.graphml +40 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.14.9.graphml +36 -0
- data/test/third_party_tests/rgl_tests/test_helper.rb +7 -0
- data/test/third_party_tests/test_inheritable_attributes.rb +187 -0
- metadata +470 -0
data/lib/laser.rb
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
module Laser
|
|
2
|
+
VERSION = "0.5.0"
|
|
3
|
+
TESTS_ACTIVATED = false
|
|
4
|
+
ROOT = File.expand_path(File.dirname(__FILE__))
|
|
5
|
+
SETTINGS = {}
|
|
6
|
+
def self.debug_puts(*args)
|
|
7
|
+
puts *args if debug?
|
|
8
|
+
end
|
|
9
|
+
def self.debug_p(*args)
|
|
10
|
+
p *args if debug?
|
|
11
|
+
end
|
|
12
|
+
def self.debug_pp(*args)
|
|
13
|
+
pp *args if debug?
|
|
14
|
+
end
|
|
15
|
+
def self.debug_dotty(graph)
|
|
16
|
+
graph.dotty
|
|
17
|
+
end
|
|
18
|
+
def self.debug?
|
|
19
|
+
SETTINGS[:debug]
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
Laser::SETTINGS[:debug] = (ENV['LASER_DEBUG'] == 'true')
|
|
23
|
+
|
|
24
|
+
# Dependencies
|
|
25
|
+
require 'ripper'
|
|
26
|
+
require 'treetop'
|
|
27
|
+
require 'ripper-plus'
|
|
28
|
+
require 'axiom_of_choice'
|
|
29
|
+
require 'stream'
|
|
30
|
+
require 'object_regex'
|
|
31
|
+
require 'trollop'
|
|
32
|
+
$:.unshift(File.expand_path(File.dirname(__FILE__)))
|
|
33
|
+
$:.unshift(File.join(File.expand_path(File.dirname(__FILE__)), '..', 'ext'))
|
|
34
|
+
require 'laser/third_party/rgl/dot' # KILLME
|
|
35
|
+
require 'laser/third_party/rgl/bidirectional'
|
|
36
|
+
require 'laser/third_party/rgl/depth_first_spanning_tree'
|
|
37
|
+
require 'laser/third_party/rgl/control_flow'
|
|
38
|
+
require 'laser/support/placeholder_object'
|
|
39
|
+
require 'laser/support/inheritable_attributes'
|
|
40
|
+
require 'laser/support/acts_as_struct'
|
|
41
|
+
require 'laser/support/module_extensions'
|
|
42
|
+
require 'laser/support/frequency'
|
|
43
|
+
require 'laser/analysis/errors'
|
|
44
|
+
require 'laser/analysis/lexical_analysis'
|
|
45
|
+
|
|
46
|
+
require 'laser/analysis/sexp_extensions/type_inference'
|
|
47
|
+
require 'laser/analysis/sexp_extensions/constant_extraction'
|
|
48
|
+
require 'laser/analysis/sexp_extensions/source_location'
|
|
49
|
+
|
|
50
|
+
require 'laser/analysis/sexp'
|
|
51
|
+
require 'laser/analysis/sexp_analysis'
|
|
52
|
+
|
|
53
|
+
require 'laser/analysis/arity'
|
|
54
|
+
require 'laser/analysis/argument_expansion'
|
|
55
|
+
require 'laser/analysis/method_call'
|
|
56
|
+
require 'laser/analysis/bindings'
|
|
57
|
+
require 'laser/analysis/signature'
|
|
58
|
+
require 'laser/analysis/bootstrap/laser_object'
|
|
59
|
+
require 'laser/analysis/bootstrap/laser_module'
|
|
60
|
+
require 'laser/analysis/bootstrap/laser_class'
|
|
61
|
+
require 'laser/analysis/bootstrap/laser_module_copy'
|
|
62
|
+
require 'laser/analysis/bootstrap/laser_singleton_class'
|
|
63
|
+
require 'laser/analysis/bootstrap/laser_proc'
|
|
64
|
+
require 'laser/analysis/bootstrap/laser_method'
|
|
65
|
+
require 'laser/analysis/laser_utils.rb'
|
|
66
|
+
require 'laser/analysis/protocol_registry'
|
|
67
|
+
require 'laser/analysis/scope'
|
|
68
|
+
require 'laser/analysis/comments'
|
|
69
|
+
require 'laser/analysis/control_flow'
|
|
70
|
+
Dir[File.join(File.dirname(__FILE__), 'laser/analysis/special_methods/*.rb')].each do |file|
|
|
71
|
+
require file
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
require 'laser/analysis/bootstrap/bootstrap'
|
|
75
|
+
# Liftoff Instructions:
|
|
76
|
+
# 1. Tuck in your shirt
|
|
77
|
+
# 2. Remove spurs
|
|
78
|
+
# 3. Bend at the waist
|
|
79
|
+
# 4. PULL UP ON THEM BOOTSTRAPS!
|
|
80
|
+
Laser::Analysis::Bootstrap.bootstrap
|
|
81
|
+
# Load the type engine
|
|
82
|
+
require 'laser/types/types'
|
|
83
|
+
Laser::Analysis::Bootstrap.bootstrap_magic
|
|
84
|
+
require 'laser/annotation_parser/parsers'
|
|
85
|
+
|
|
86
|
+
require 'laser/analysis/visitor'
|
|
87
|
+
require 'laser/analysis/annotations'
|
|
88
|
+
require 'laser/analysis/unused_methods'
|
|
89
|
+
# Runners
|
|
90
|
+
require 'laser/runner'
|
|
91
|
+
require 'laser/rake/task'
|
|
92
|
+
# Program logic
|
|
93
|
+
require 'laser/warning'
|
|
94
|
+
require 'laser/scanner'
|
|
95
|
+
|
|
96
|
+
require 'laser/version'
|
|
97
|
+
# All methods created from the stdlib should never be marked as unused.
|
|
98
|
+
Laser::Analysis::Bootstrap.load_standard_library
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
module Laser
|
|
3
|
+
module Analysis
|
|
4
|
+
module Annotations
|
|
5
|
+
extend ModuleExtensions
|
|
6
|
+
# Global annotations are only run once, at the root.
|
|
7
|
+
cattr_accessor_with_default :global_annotations, []
|
|
8
|
+
|
|
9
|
+
# Performs full analysis on the given inputs.
|
|
10
|
+
def self.annotate_inputs(inputs, opts={})
|
|
11
|
+
inputs.map! do |filename, text|
|
|
12
|
+
[filename, text, Sexp.new(RipperPlus.sexp(text), filename, text)]
|
|
13
|
+
end
|
|
14
|
+
apply_inherited_attributes(inputs)
|
|
15
|
+
perform_load_time_analysis(inputs, opts)
|
|
16
|
+
inputs.map! { |filename, _, tree| [filename, tree] }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Applies all the inherited attributes to the given inputs, in the
|
|
20
|
+
# order specified by annotation_config.yaml
|
|
21
|
+
def self.apply_inherited_attributes(inputs)
|
|
22
|
+
ordered_annotations.each do |annotator|
|
|
23
|
+
inputs.each do |filename, text, tree|
|
|
24
|
+
Scope::GlobalScope.lookup('$"').value.unshift(filename)
|
|
25
|
+
if SETTINGS[:profile]
|
|
26
|
+
time = Benchmark.realtime { annotator.annotate_with_text(tree, text) }
|
|
27
|
+
puts "Time spent running #{annotator.class} on #{filename}: #{time}"
|
|
28
|
+
else
|
|
29
|
+
annotator.annotate_with_text(tree, text)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Performs load-time analysis on the given inputs. Inherited attributes
|
|
36
|
+
# must be applied at this point.
|
|
37
|
+
def self.perform_load_time_analysis(inputs, opts={})
|
|
38
|
+
inputs.each do |filename, text, tree|
|
|
39
|
+
if SETTINGS[:profile]
|
|
40
|
+
time = Benchmark.realtime { annotator.annotate_with_text(tree, text) }
|
|
41
|
+
puts "Time spent running #{annotator.class} on #{filename}: #{time}"
|
|
42
|
+
else
|
|
43
|
+
ControlFlow.perform_cfg_analysis(tree, text, opts)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Returns the order that annotations should be run.
|
|
49
|
+
def self.annotation_ordered
|
|
50
|
+
@order ||= YAML.load_file(File.join(File.dirname(__FILE__), 'annotations', 'annotation_config.yaml'))
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Returns the inherited attributes in the order they are intended
|
|
54
|
+
# to be run by the YAML file.
|
|
55
|
+
def self.ordered_annotations
|
|
56
|
+
annotation_ordered.map do |mod_name|
|
|
57
|
+
global_annotations.select { |annotation| annotation.class.name.include?(mod_name) }.first
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
# This is the base module for all annotations that can run on ASTs.
|
|
62
|
+
# It includes all other annotation modules to provide all the
|
|
63
|
+
# annotations to the Sexp class. These annotations are run at initialize
|
|
64
|
+
# time for the Sexps and have access to a node and all of its child nodes,
|
|
65
|
+
# all of which have been annotated. Synthesized attributes are fair game,
|
|
66
|
+
# and adding inherited attributes to subnodes is also fair game.
|
|
67
|
+
#
|
|
68
|
+
# All annotations add O(V) to the parser running time.
|
|
69
|
+
#
|
|
70
|
+
# This module also provides some helper methods to inject functionality into
|
|
71
|
+
# the Sexp class. Since that's what an annotation is, I don't consider
|
|
72
|
+
# this bad form!
|
|
73
|
+
class BasicAnnotation
|
|
74
|
+
extend ModuleExtensions
|
|
75
|
+
include Visitor
|
|
76
|
+
cattr_accessor_with_default :dependencies, []
|
|
77
|
+
def self.inherited(klass)
|
|
78
|
+
add_global_annotator klass
|
|
79
|
+
end
|
|
80
|
+
def self.add_global_annotator(*args)
|
|
81
|
+
Annotations.global_annotations.concat args.map(&:new)
|
|
82
|
+
end
|
|
83
|
+
def self.add_property(*args)
|
|
84
|
+
Analysis::Sexp.__send__(:attr_accessor, *args)
|
|
85
|
+
end
|
|
86
|
+
def self.add_computed_property(name, &blk)
|
|
87
|
+
Analysis::Sexp.__send__(:define_method, name, &blk)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
Dir[File.expand_path(File.join(File.dirname(__FILE__), 'annotations', '**', '*.rb'))].each do |file|
|
|
94
|
+
load file
|
|
95
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module Laser
|
|
2
|
+
module Analysis
|
|
3
|
+
# This annotation attempts to attach each comment in the program to the
|
|
4
|
+
# first node in the AST that follows the comment, as well as all subnodes with
|
|
5
|
+
# the same source location.
|
|
6
|
+
#
|
|
7
|
+
# This annotation will NOT always succeed, as it relies on the SourceLocationAnnotator,
|
|
8
|
+
# which due to limitations in Ripper's output, cannot always succeed.
|
|
9
|
+
class CommentAttachmentAnnotation < BasicAnnotation
|
|
10
|
+
add_property :comment
|
|
11
|
+
def annotate_with_text(root, text)
|
|
12
|
+
comments = extract_comments(text)
|
|
13
|
+
# root[1] here to ignore the spurious :program node
|
|
14
|
+
dfs_enumerator = root.dfs_enumerator
|
|
15
|
+
# For each comment:
|
|
16
|
+
# find the first node, by DFS, that has a location *greater* than the
|
|
17
|
+
# comment's. However, not all nodes will have locations due to Ripper
|
|
18
|
+
# being kinda crappy.
|
|
19
|
+
# When the enumerator finishes (raises StopIteration): we can no longer
|
|
20
|
+
# annotate. So return.
|
|
21
|
+
comments.each do |comment|
|
|
22
|
+
begin
|
|
23
|
+
cur = dfs_for_useful_node(dfs_enumerator)
|
|
24
|
+
end while (cur.source_begin <=> comment.location) == -1
|
|
25
|
+
# if we're here, we found the first node after the comment.
|
|
26
|
+
cur.comment = comment
|
|
27
|
+
extend_annotation_to_equal_nodes(cur, dfs_enumerator)
|
|
28
|
+
end
|
|
29
|
+
rescue StopIteration
|
|
30
|
+
# do nothing – this signals the end of the algorithm. If has_next made sense
|
|
31
|
+
# for enumerators, we'd use it, but it doesn't, so we just catch and return.
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Runs the generator until we find a node we can use in the context of
|
|
35
|
+
# comment annotation: it must have a source_begin attribute (not all nodes
|
|
36
|
+
# can successfully resolve their source_begin) and it shouldn't be a mere
|
|
37
|
+
# Array, it should have an actual node type.
|
|
38
|
+
def dfs_for_useful_node(generator)
|
|
39
|
+
begin
|
|
40
|
+
cur = generator.next
|
|
41
|
+
end until cur.source_begin && (::Symbol === cur[0])
|
|
42
|
+
cur
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Many nodes in the tree will have the same source_begin value, and they
|
|
46
|
+
# must all share the comment. Otherwise, we'll have a lot of trouble making
|
|
47
|
+
# sure that the interesting nodes, often nested deeply, will be annotated.
|
|
48
|
+
def extend_annotation_to_equal_nodes(first, generator)
|
|
49
|
+
while generator.peek.source_begin.nil? || generator.peek.source_begin[0] <= first.source_begin[0]
|
|
50
|
+
generator.next.comment = first.comment
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Extracts the comments from the text with some straightforward lexical analysis.
|
|
55
|
+
def extract_comments(text)
|
|
56
|
+
tokens = Ripper.lex(text).map { |tok| LexicalAnalysis::Token.new(tok) }
|
|
57
|
+
comments = ObjectRegex.new('comment (sp? comment)*').all_matches(tokens).map do |token_list|
|
|
58
|
+
token_list.select { |token| token.type == :on_comment }
|
|
59
|
+
end.map do |token_list|
|
|
60
|
+
body = token_list.map { |comment_token| comment_token.body[1..-1] }.join.rstrip
|
|
61
|
+
Comment.new(body, token_list.first.line, token_list.first.col)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Laser
|
|
2
|
+
module Analysis
|
|
3
|
+
# This is a simple inherited attribute applied to each node,
|
|
4
|
+
# giving a pointer to that node's parent. That way AST traversal
|
|
5
|
+
# is easier.
|
|
6
|
+
# This is the annotator for the parent annotation.
|
|
7
|
+
class NodePointersAnnotation < BasicAnnotation
|
|
8
|
+
add_property :parent, :next, :prev
|
|
9
|
+
add_computed_property :ancestors do
|
|
10
|
+
case parent
|
|
11
|
+
when nil then []
|
|
12
|
+
else parent.ancestors + [parent]
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
add_computed_property :root do
|
|
16
|
+
case parent
|
|
17
|
+
when nil then self
|
|
18
|
+
else parent.root
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Replaces the general node visit method with one that assigns
|
|
23
|
+
# the current scope to the visited node.
|
|
24
|
+
def default_visit(node)
|
|
25
|
+
children = node.children
|
|
26
|
+
children.each_with_index do |elt, idx|
|
|
27
|
+
next unless Analysis::Sexp === elt
|
|
28
|
+
elt.parent = node
|
|
29
|
+
elt.next = children[idx+1]
|
|
30
|
+
elt.prev = children[idx-1] if idx >= 1
|
|
31
|
+
end
|
|
32
|
+
visit_children(node)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module Laser
|
|
2
|
+
module Analysis
|
|
3
|
+
# This is a simple inherited attribute that specifies whether a given node
|
|
4
|
+
# will be executed when at load-time or at run-time. In short, method bodies
|
|
5
|
+
# and not-run blocks at the top-level are not run, and everything else is.
|
|
6
|
+
#
|
|
7
|
+
# The possible values of #runtime are :load, :run, or :unknown.
|
|
8
|
+
class RuntimeAnnotation < BasicAnnotation
|
|
9
|
+
add_property :runtime
|
|
10
|
+
|
|
11
|
+
def annotate!(root)
|
|
12
|
+
@current_runtime = :load
|
|
13
|
+
super
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def default_visit(node)
|
|
17
|
+
node.runtime = @current_runtime
|
|
18
|
+
visit_children(node)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def visit_with_runtime(*nodes, new_runtime)
|
|
22
|
+
old_runtime, @current_runtime = @current_runtime, new_runtime
|
|
23
|
+
nodes.each { |node| visit node }
|
|
24
|
+
ensure
|
|
25
|
+
@current_runtime = old_runtime
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
add :def do |node, name, params, body|
|
|
29
|
+
default_visit(node)
|
|
30
|
+
default_visit(name)
|
|
31
|
+
visit_with_runtime(params, body, :run)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
add :defs do |node, singleton, separator, name, params, body|
|
|
35
|
+
default_visit(node)
|
|
36
|
+
default_visit(singleton)
|
|
37
|
+
default_visit(name)
|
|
38
|
+
visit_with_runtime(params, body, :run)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
add :method_add_block do |node, call, block|
|
|
42
|
+
# TODO(adgar): Check if call is resolved, and if so, check if the block is in fact
|
|
43
|
+
# executed immediately or stored. If we know the answer to that, we can specify :run
|
|
44
|
+
# or :load for the block instead of just :unknown.
|
|
45
|
+
default_visit(node)
|
|
46
|
+
default_visit(call)
|
|
47
|
+
|
|
48
|
+
if @current_runtime == :load
|
|
49
|
+
then visit_with_runtime(block, :unknown)
|
|
50
|
+
else default_visit block
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
module Laser
|
|
2
|
+
module Analysis
|
|
3
|
+
# This class handles the interpretation and expansion of arguments being
|
|
4
|
+
# passed to a method call.
|
|
5
|
+
class ArgumentExpansion
|
|
6
|
+
attr_reader :node
|
|
7
|
+
# @node can end up either being nil, for no args at all, or an
|
|
8
|
+
# args_add_block node.
|
|
9
|
+
def initialize(node)
|
|
10
|
+
node = node[1] if !node.nil? && node.type == :arg_paren
|
|
11
|
+
@node = node
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Returns whether the node has a block argument. If it does, it
|
|
15
|
+
# returns the block argument's node.
|
|
16
|
+
def has_block?
|
|
17
|
+
if node.nil?
|
|
18
|
+
false
|
|
19
|
+
elsif node.type == :args_add_block
|
|
20
|
+
node[2]
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Returns the arity of the argument block being passed, as a range of
|
|
25
|
+
# possible values.
|
|
26
|
+
def arity
|
|
27
|
+
return Arity::EMPTY if node.nil?
|
|
28
|
+
Arity.new(arity_for_node(node))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Are there no arguments being passed?
|
|
32
|
+
def empty?
|
|
33
|
+
arity == (0..0)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Returns whether all arguments are constant.
|
|
37
|
+
def is_constant?
|
|
38
|
+
return true if node.nil?
|
|
39
|
+
node_is_constant?(node)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Returns an array of constant values that are the arguments being passed.
|
|
43
|
+
#
|
|
44
|
+
# pre-contract: is_constant?.should be_true
|
|
45
|
+
def constant_values
|
|
46
|
+
return [] if node.nil?
|
|
47
|
+
node_constant_values(node)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Returns the block argument (&blk) for the argument expansion.
|
|
51
|
+
def block_arg
|
|
52
|
+
return false if node.nil?
|
|
53
|
+
block_arg_for_node node
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
# Finds the arity of a given argument node.
|
|
59
|
+
def arity_for_node(node)
|
|
60
|
+
case node[0]
|
|
61
|
+
when Array
|
|
62
|
+
node.inject(0..0) { |acc, cur| range_add(acc, arity_for_node(cur)) }
|
|
63
|
+
when :args_add_block
|
|
64
|
+
arity_for_node(node[1])
|
|
65
|
+
when :args_add_star
|
|
66
|
+
initial = arity_for_node(node[1])
|
|
67
|
+
star_arity = arity_for_star(node[2])
|
|
68
|
+
extra = node.size > 3 ? arity_for_node(node[3..-1]) : (0..0)
|
|
69
|
+
range_add(range_add(initial, star_arity), extra)
|
|
70
|
+
else
|
|
71
|
+
1..1
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Adds two ranges together.
|
|
76
|
+
def range_add(r1, r2)
|
|
77
|
+
(r1.begin + r2.begin)..(r1.end + r2.end)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Finds the arity for a splatted argument. If it's a constant value, we can
|
|
81
|
+
# compute its value
|
|
82
|
+
def arity_for_star(node)
|
|
83
|
+
if node.is_constant
|
|
84
|
+
ary = node.constant_value.to_a rescue [node.constant_value]
|
|
85
|
+
size = ary.size
|
|
86
|
+
size..size
|
|
87
|
+
else
|
|
88
|
+
0..Float::INFINITY
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Returns the node representing the argument's block argument.
|
|
93
|
+
def block_arg_for_node(node)
|
|
94
|
+
case node.type
|
|
95
|
+
when :method_add_arg then block_arg_for_node node[2]
|
|
96
|
+
when :args_add_block then node[2]
|
|
97
|
+
when :arg_paren then block_arg_for_node node[1]
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Determines whether a given arg AST node is constant.
|
|
102
|
+
def node_is_constant?(node)
|
|
103
|
+
case node[0]
|
|
104
|
+
when nil then true
|
|
105
|
+
when Array then node.all? { |child| node_is_constant?(child) }
|
|
106
|
+
when :args_add_block
|
|
107
|
+
node[2] ? node_is_constant?(node[1..2]) : node_is_constant?(node[1])
|
|
108
|
+
when :args_add_star then node.children.all? { |child| node_is_constant?(child) }
|
|
109
|
+
else node.is_constant
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Determines the constant values of all arguments being passed, expanding
|
|
114
|
+
# splats.
|
|
115
|
+
def node_constant_values(node)
|
|
116
|
+
case node[0]
|
|
117
|
+
when nil then []
|
|
118
|
+
when Array then node.map { |child| node_constant_values(child) }
|
|
119
|
+
when :args_add_block
|
|
120
|
+
node_constant_values(node[1])
|
|
121
|
+
when :args_add_star
|
|
122
|
+
pre_args = node_constant_values(node[1])
|
|
123
|
+
splat_arg = node_constant_values(node[2])
|
|
124
|
+
real_splat_ary = splat_arg.to_a rescue [splat_arg]
|
|
125
|
+
post_args = node_constant_values(node[3..-1])
|
|
126
|
+
pre_args + real_splat_ary + post_args
|
|
127
|
+
else node.constant_value
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|