Module: Y2R::AST::YCP::RubyVar
- Defined in:
- lib/y2r/ast/ycp.rb
Overview
Contains utility functions related to Ruby variables.
Constant Summary collapse
- RUBY_KEYWORDS =
Taken from Ruby’s parse.y (for 1.9.3).
[ "BEGIN", "END", "__ENCODING__", "__FILE__", "__LINE__", "alias", "and", "begin", "break", "case", "class", "def", "defined", "do", "else", "elsif", "end", "ensure", "false", "for", "if", "in", "module", "next", "nil", "not", "or", "redo", "rescue", "retry", "return", "self", "super", "then", "true", "undef", "unless", "until", "when", "while", "yield" ]
Class Method Summary collapse
-
.escape_local(name) ⇒ Object
Escapes a YCP variable name so that it is a valid Ruby local variable name.
-
.for(ns, name, context, mode) ⇒ Object
Builds a Ruby AST node for a variable with given name in given context, doing all necessary escaping, de-aliasing, etc.
Class Method Details
.escape_local(name) ⇒ Object
Escapes a YCP variable name so that it is a valid Ruby local variable name.
The escaping is constructed so that it can’t create any collision between names. More precisely, for any distinct strings passed to this function the results will be also distinct.
565 566 567 |
# File 'lib/y2r/ast/ycp.rb', line 565 def escape_local(name) name.sub(/^(#{RUBY_KEYWORDS.join("|")}|[A-Z_].*)$/) { |s| "_#{s}" } end |
.for(ns, name, context, mode) ⇒ Object
Builds a Ruby AST node for a variable with given name in given context, doing all necessary escaping, de-aliasing, etc.
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 |
# File 'lib/y2r/ast/ycp.rb', line 571 def for(ns, name, context, mode) # In the XML, all global module variable references are qualified # (e.g. "M::i"). This includes references to variables defined in # this module. All other variable references are unqualified (e.g # "i"). if ns if ns == context.module_name Ruby::Variable.new(:name => "@#{name}") else Ruby::MethodCall.new( :receiver => Ruby::Variable.new(:name => ns), :name => name, :args => [], :block => nil, :parens => true ) end else is_local = context.locals.include?(name) variables = if is_local context.locals else context.globals end # If there already is a variable with given name (coming from some # parent scope), suffix the variable name with "2". If there are two # such variables, suffix the name with "3". And so on. # # The loop is needed because we need to do the same check and maybe # additional round(s) of suffixing also for suffixed variable names to # prevent conflicts. suffixed_name = name begin count = variables.select { |v| v == suffixed_name }.size suffixed_name = suffixed_name + count.to_s if count > 1 end while count > 1 variable_name = if is_local RubyVar.escape_local(suffixed_name) else "@#{suffixed_name}" end variable = Ruby::Variable.new(:name => variable_name) case mode when :in_code symbol = context.symbol_for(name) # The "symbol &&" part is needed only because of tests. The symbol # should be always present in real-world situations. if symbol && symbol.category == :reference Ruby::MethodCall.new( :receiver => variable, :name => "value", :args => [], :block => nil, :parens => true ) else variable end when :in_arg variable else raise "Unknown mode: #{mode.inspect}." end end end |