Module: Opal::Nodes::Helpers

Included in:
Base
Defined in:
opal/lib/opal/nodes/helpers.rb

Constant Summary

ES51_RESERVED_WORD =

Reserved javascript keywords - we cannot create variables with the same name (ref: http://stackoverflow.com/a/9337272/601782)

/#{REGEXP_START}(?:do|if|in|for|let|new|try|var|case|else|enum|eval|false|null|this|true|void|with|break|catch|class|const|super|throw|while|yield|delete|export|import|public|return|static|switch|typeof|default|extends|finally|package|private|continue|debugger|function|arguments|interface|protected|implements|instanceof)#{REGEXP_END}/
ES3_RESERVED_WORD_EXCLUSIVE =

ES3 reserved words that aren’t ES5.1 reserved words

/#{REGEXP_START}(?:int|byte|char|goto|long|final|float|short|double|native|throws|boolean|abstract|volatile|transient|synchronized)#{REGEXP_END}/
PROTO_SPECIAL_PROPS =

Prototype special properties.

/#{REGEXP_START}(?:constructor|displayName|__proto__|__parent__|__noSuchMethod__|__count__)#{REGEXP_END}/
PROTO_SPECIAL_METHODS =

Prototype special methods.

/#{REGEXP_START}(?:hasOwnProperty|valueOf)#{REGEXP_END}/
IMMUTABLE_PROPS =

Immutable properties of the global object

/#{REGEXP_START}(?:NaN|Infinity|undefined)#{REGEXP_END}/
BASIC_IDENTIFIER_RULES =

Doesn't take in account utf8

/#{REGEXP_START}[$_a-z][$_a-z\d]*#{REGEXP_END}/i
RESERVED_FUNCTION_NAMES =

Defining a local function like Array may break everything

/#{REGEXP_START}(?:Array)#{REGEXP_END}/

Instance Method Summary collapse

Instance Method Details

#current_indentObject


79
80
81
# File 'opal/lib/opal/nodes/helpers.rb', line 79

def current_indent
  compiler.parser_indent
end

#empty_lineObject


88
89
90
# File 'opal/lib/opal/nodes/helpers.rb', line 88

def empty_line
  push "\n"
end

#indent(&block) ⇒ Object


75
76
77
# File 'opal/lib/opal/nodes/helpers.rb', line 75

def indent(&block)
  compiler.indent(&block)
end

#ivar(name) ⇒ Object


50
51
52
# File 'opal/lib/opal/nodes/helpers.rb', line 50

def ivar(name)
  valid_ivar_name?(name.to_s) ? name : "#{name}$"
end

#js_falsy(sexp) ⇒ Object


102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'opal/lib/opal/nodes/helpers.rb', line 102

def js_falsy(sexp)
  if sexp.type == :call
    mid = sexp[2]
    if mid == :block_given?
      scope.uses_block!
      return "#{scope.block_name} === nil"
    end
  end

  with_temp do |tmp|
    [fragment("((#{tmp} = "), expr(sexp), fragment(") === nil || #{tmp} == null || (#{tmp}.$$is_boolean && #{tmp} == false))")]
  end
end

#js_truthy(sexp) ⇒ Object


92
93
94
95
96
97
98
99
100
# File 'opal/lib/opal/nodes/helpers.rb', line 92

def js_truthy(sexp)
  if optimize = js_truthy_optimize(sexp)
    return optimize
  end

  with_temp do |tmp|
    [fragment("((#{tmp} = "), expr(sexp), fragment(") !== nil && #{tmp} != null && (!#{tmp}.$$is_boolean || #{tmp} == true))")]
  end
end

#js_truthy_optimize(sexp) ⇒ Object


116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'opal/lib/opal/nodes/helpers.rb', line 116

def js_truthy_optimize(sexp)
  if sexp.type == :call
    mid = sexp[2]
    receiver_handler_class = (receiver = sexp[1]) && compiler.handlers[receiver.type]

    # Only operator calls on the truthy_optimize? node classes should be optimized.
    # Monkey patch method calls might return 'self'/aka a bridged instance and need
    # the nil check - see discussion at https://github.com/opal/opal/pull/1097
    allow_optimization_on_type = Compiler::COMPARE.include?(mid.to_s) &&
      receiver_handler_class &&
      receiver_handler_class.truthy_optimize?

    if allow_optimization_on_type ||
      mid == :block_given? ||
      mid == :=="
      expr(sexp)
    end
  elsif [:lvar, :self].include? sexp.type
    [expr(sexp.dup), fragment(" !== false && "), expr(sexp.dup), fragment(" !== nil && "), expr(sexp.dup), fragment(" != null")]
  end
end

#line(*strs) ⇒ Object


83
84
85
86
# File 'opal/lib/opal/nodes/helpers.rb', line 83

def line(*strs)
  push "\n#{current_indent}"
  push(*strs)
end

#lvar_to_js(var) ⇒ Object

Converts a ruby lvar/arg name to a js identifier. Not all ruby names are valid in javascript. A $ suffix is added to non-valid names. varibales


57
58
59
60
# File 'opal/lib/opal/nodes/helpers.rb', line 57

def lvar_to_js(var)
  var = "#{var}$" unless valid_name? var.to_s
  var.to_sym
end

#mid_to_jsid(mid) ⇒ Object

Converts a ruby method name into its javascript equivalent for a method/function call. All ruby method names get prefixed with a '$', and if the name is a valid javascript identifier, it will have a '.' prefix (for dot-calling), otherwise it will be wrapped in brackets to use reference notation calling.


67
68
69
70
71
72
73
# File 'opal/lib/opal/nodes/helpers.rb', line 67

def mid_to_jsid(mid)
  if /\=|\+|\-|\*|\/|\!|\?|<|\>|\&|\||\^|\%|\~|\[/ =~ mid.to_s
    "['$#{mid}']"
  else
    '.$' + mid
  end
end

#property(name) ⇒ Object


30
31
32
# File 'opal/lib/opal/nodes/helpers.rb', line 30

def property(name)
  valid_name?(name) ? ".#{name}" : "[#{name.inspect}]"
end

#valid_ivar_name?(name) ⇒ Boolean

Returns:

  • (Boolean)

46
47
48
# File 'opal/lib/opal/nodes/helpers.rb', line 46

def valid_ivar_name?(name)
  not (PROTO_SPECIAL_PROPS =~ name or PROTO_SPECIAL_METHODS =~ name)
end

#valid_name?(name) ⇒ Boolean

Returns:

  • (Boolean)

34
35
36
37
38
39
40
# File 'opal/lib/opal/nodes/helpers.rb', line 34

def valid_name?(name)
  BASIC_IDENTIFIER_RULES =~ name and not(
    ES51_RESERVED_WORD          =~ name or
    ES3_RESERVED_WORD_EXCLUSIVE =~ name or
    IMMUTABLE_PROPS             =~ name
  )
end

#variable(name) ⇒ Object


42
43
44
# File 'opal/lib/opal/nodes/helpers.rb', line 42

def variable(name)
  valid_name?(name.to_s) ? name : "#{name}$"
end