Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Clean up various helper methods
Browse files Browse the repository at this point in the history
adambeynon committed Oct 23, 2013
1 parent f3b11ec commit 0ee6da4
Showing 18 changed files with 219 additions and 176 deletions.
14 changes: 12 additions & 2 deletions lib/opal/nodes/base.rb
Original file line number Diff line number Diff line change
@@ -3,7 +3,17 @@
module Opal
class Parser
class Node
include NodeHelpers
include Helpers

def self.handlers
@handlers ||= {}
end

def self.handle(*types)
types.each do |type|
Node.handlers[type] = self
end
end

def self.children(*names)
names.each_with_index do |name, idx|
@@ -18,7 +28,7 @@ def self.children(*names)
def initialize(sexp, level, compiler)
@sexp = sexp
@level = level
@compiler = @parser = compiler
@compiler = compiler
end

def type
7 changes: 4 additions & 3 deletions lib/opal/nodes/call.rb
Original file line number Diff line number Diff line change
@@ -3,6 +3,8 @@
module Opal
class Parser
class CallNode < Node
handle :call

children :recvr, :meth, :arglist, :iter

def compile
@@ -11,15 +13,14 @@ def compile
return
end

mid = compiler.mid_to_jsid meth.to_s
mid = mid_to_jsid meth.to_s

compiler.method_calls << meth.to_sym

# trying to access an lvar in irb mode
if using_irb?
with_temp do |tmp|
lvar = meth.intern
lvar = "#{lvar}$" if Parser::RESERVED.include?(lvar)
lvar = variable(meth)
call = s(:call, s(:self), meth.intern, s(:arglist))
push "((#{tmp} = $opal.irb_vars.#{lvar}) == null ? ", expr(call), " : #{tmp})"
end
12 changes: 12 additions & 0 deletions lib/opal/nodes/call_special.rb
Original file line number Diff line number Diff line change
@@ -5,6 +5,8 @@ class Parser
# recv.mid = rhs
# s(:recv, :mid=, s(:arglist, rhs))
class AttrAssignNode < Node
handle :attrasgn

children :recvr, :mid, :arglist

def compile
@@ -16,6 +18,8 @@ def compile
# lhs =~ rhs
# s(:match3, lhs, rhs)
class Match3Node < Node
handle :match3

children :lhs, :rhs

def compile
@@ -27,6 +31,8 @@ def compile
# a ||= rhs
# s(:op_asgn_or, s(:lvar, :a), s(:lasgn, :a, rhs))
class OpAsgnOrNode < Node
handle :op_asgn_or

children :recvr, :rhs

def compile
@@ -38,6 +44,8 @@ def compile
# a &&= rhs
# s(:op_asgn_and, s(:lvar, :a), s(:lasgn, a:, rhs))
class OpAsgnAndNode < Node
handle :op_asgn_and

children :recvr, :rhs

def compile
@@ -49,6 +57,8 @@ def compile
# lhs[args] ||= rhs
# s(:op_asgn1, lhs, args, :||, rhs)
class OpAsgn1Node < Node
handle :op_asgn1

children :lhs, :args, :op, :rhs

def first_arg
@@ -72,6 +82,8 @@ def compile
# lhs.b += rhs
# s(:op_asgn2, lhs, :b=, :+, rhs)
class OpAsgn2Node < Node
handle :op_asgn2

children :lhs, :mid, :op, :rhs

def meth
4 changes: 4 additions & 0 deletions lib/opal/nodes/case.rb
Original file line number Diff line number Diff line change
@@ -3,6 +3,8 @@
module Opal
class Parser
class CaseNode < Node
handle :case

children :condition

def compile
@@ -51,6 +53,8 @@ def case_stmt
end

class WhenNode < Node
handle :when

children :whens, :body

def compile
6 changes: 6 additions & 0 deletions lib/opal/nodes/class.rb
Original file line number Diff line number Diff line change
@@ -9,6 +9,8 @@ def in_scope(type, &block)
end

class SingletonClassNode < BaseScopeNode
handle :sclass

children :object, :body

def compile
@@ -27,6 +29,8 @@ def compile
end

class ModuleNode < BaseScopeNode
handle :module

children :cid, :body

def compile
@@ -66,6 +70,8 @@ def name_and_base
end

class ClassNode < ModuleNode
handle :class

children :cid, :sup, :body

def compile
12 changes: 12 additions & 0 deletions lib/opal/nodes/constants.rb
Original file line number Diff line number Diff line change
@@ -3,6 +3,8 @@
module Opal
class Parser
class ConstNode < Node
handle :const

children :name

def compile
@@ -17,6 +19,8 @@ def compile
end

class ConstDeclarationNode < Node
handle :cdecl

children :name, :base

def compile
@@ -26,6 +30,8 @@ def compile
end

class ConstAssignNode < Node
handle :casgn

children :base, :name, :value

def compile
@@ -38,6 +44,8 @@ def compile
end

class ConstGetNode < Node
handle :colon2

children :base, :name

def compile
@@ -56,6 +64,8 @@ def compile
end

class TopConstNode < Node
handle :colon3

children :name

def compile
@@ -67,6 +77,8 @@ def compile
end

class TopConstAssignNode < Node
handle :casgn3

children :name, :value

def compile
8 changes: 6 additions & 2 deletions lib/opal/nodes/def.rb
Original file line number Diff line number Diff line change
@@ -4,10 +4,12 @@ module Opal
class Parser
# FIXME: needs rewrite
class DefNode < BaseScopeNode
handle :def

children :recvr, :mid, :args, :stmts

def compile
jsid = compiler.mid_to_jsid mid.to_s
jsid = mid_to_jsid mid.to_s
params = nil
scope_name = nil

@@ -66,7 +68,7 @@ def compile

opt[1..-1].each do |o|
next if o[2][2] == :undefined
line "if (#{compiler.lvar_to_js o[1]} == null) {"
line "if (#{variable(o[1])} == null) {"
line ' ', expr(o)
line "}"
end if opt
@@ -138,6 +140,8 @@ def arity_check(args, opt, splat, block_name, mid)

# FIXME: needs rewrite
class ArglistNode < Node
handle :arglist

def compile
code, work = [], []

26 changes: 23 additions & 3 deletions lib/opal/nodes/definitions.rb
Original file line number Diff line number Diff line change
@@ -4,6 +4,8 @@ module Opal
class Parser

class SvalueNode < Node
handle :svalue

children :value

def compile
@@ -14,6 +16,8 @@ def compile
# :scope nodes are actually inside scopes (e.g. :module, :class).
# These are not actually the scopes themselves.
class ScopeNode < Node
handle :scope

children :body

def compile
@@ -24,23 +28,27 @@ def compile
end

class UndefNode < Node
handle :undef

children :mid

# FIXME: we should be setting method to a stub method here
def compile
push "delete #{scope.proto}#{compiler.mid_to_jsid mid[1].to_s}"
push "delete #{scope.proto}#{mid_to_jsid mid[1].to_s}"
end
end

class AliasNode < Node
handle :alias

children :new_name, :old_name

def new_mid
compiler.mid_to_jsid new_name[1].to_s
mid_to_jsid new_name[1].to_s
end

def old_mid
compiler.mid_to_jsid old_name[1].to_s
mid_to_jsid old_name[1].to_s
end

def compile
@@ -54,6 +62,8 @@ def compile
end

class BeginNode < Node
handle :begin

children :body

def compile
@@ -67,6 +77,8 @@ def compile
end

class ParenNode < Node
handle :paren

children :body

def compile
@@ -85,6 +97,8 @@ def compile
end

class RescueModNode < Node
handle :rescue_mod

children :lhs, :rhs

def body
@@ -103,6 +117,8 @@ def compile
end

class BlockNode < Node
handle :block

def compile
return push "nil" if children.empty?

@@ -184,6 +200,8 @@ def find_inline_yield(stmt)
end

class WhileNode < Node
handle :while

children :test, :body

def compile
@@ -230,6 +248,8 @@ def wrap_in_closure?
end

class UntilNode < WhileNode
handle :until

def while_open
"while (!("
end
36 changes: 33 additions & 3 deletions lib/opal/nodes/helpers.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,47 @@
module Opal
class Parser
module NodeHelpers
module Helpers

# Reserved javascript keywords - we cannot create variables with the
# same name
RESERVED = %w[
break case catch continue debugger default delete do else finally for
function if in instanceof new return switch this throw try typeof var let
void while with class enum export extends import super true false native
const static
]

def property(name)
reserved?(name) ? "['#{name}']" : ".#{name}"
end

def reserved?(name)
Opal::Parser::RESERVED.include? name
RESERVED.include? name
end

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

# 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
def lvar_to_js(var)
var = "#{var}$" if Parser::Helpers::RESERVED.include? var.to_s
var.to_sym
end

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

def indent(&block)
2 changes: 2 additions & 0 deletions lib/opal/nodes/if.rb
Original file line number Diff line number Diff line change
@@ -3,6 +3,8 @@
module Opal
class Parser
class IfNode < Node
handle :if

children :test, :true_body, :false_body

def compile
10 changes: 5 additions & 5 deletions lib/opal/nodes/iter.rb
Original file line number Diff line number Diff line change
@@ -4,6 +4,8 @@ module Opal
class Parser
# FIXME: this needs a rewrite very urgently
class IterNode < BaseScopeNode
handle :iter

children :args_sexp, :body_sexp

def compile
@@ -38,8 +40,7 @@ def compile

args[1..-1].each_with_index do |arg, idx|
if arg.type == :lasgn
arg = arg[1]
arg = "#{arg}$" if Parser::RESERVED.include?(arg.to_s)
arg = variable(arg[1])

if opt_args and current_opt = opt_args.find { |s| s[1] == arg.to_sym }
push "if (#{arg} == null) #{arg} = ", expr(current_opt[2]), ";"
@@ -48,8 +49,7 @@ def compile
end
elsif arg.type == :array
arg[1..-1].each_with_index do |_arg, _idx|
_arg = _arg[1]
_arg = "#{_arg}$" if Parser::RESERVED.include?(_arg.to_s)
_arg = variable(_arg[1])
push "#{_arg} = #{params[idx]}#{_idx};"
end
else
@@ -101,7 +101,7 @@ def args_to_params(sexp)
result = []
sexp.each do |arg|
if arg[0] == :lasgn
ref = compiler.lvar_to_js(arg[1])
ref = variable(arg[1])
scope.add_arg ref
result << ref
elsif arg[0] == :array
34 changes: 32 additions & 2 deletions lib/opal/nodes/literal.rb
Original file line number Diff line number Diff line change
@@ -3,6 +3,8 @@
module Opal
class Parser
class ValueNode < Node
handle :true, :false, :self, :nil

def compile
# :self, :true, :false, :nil
push type.to_s
@@ -14,31 +16,41 @@ class LiteralNode < Node
end

class NumericNode < LiteralNode
handle :int, :float

def compile
push value.to_s
wrap '(', ')' if recv?
end
end

class StringNode < LiteralNode
handle :str

def compile
push value.inspect
end
end

class SymbolNode < LiteralNode
handle :sym

def compile
push value.to_s.inspect
end
end

class RegexpNode < LiteralNode
handle :regexp

def compile
push((value == // ? /^/ : value).inspect)
end
end

class XStringNode < LiteralNode
handle :xstr

def needs_semicolon?
stmt? and !value.to_s.include?(';')
end
@@ -52,6 +64,8 @@ def compile
end

class DynamicStringNode < Node
handle :dstr

def compile
children.each_with_index do |part, idx|
push " + " unless idx == 0
@@ -74,6 +88,8 @@ def compile
end

class DynamicSymbolNode < Node
handle :dsym

def compile
children.each_with_index do |part, idx|
push " + " unless idx == 0
@@ -94,6 +110,8 @@ def compile
end

class DynamicXStringNode < Node
handle :dxstr

def requires_semicolon(code)
stmt? and !code.include?(';')
end
@@ -121,6 +139,8 @@ def compile
end

class DynamicRegexpNode < Node
handle :dregx

def compile
children.each_with_index do |part, idx|
push " + " unless idx == 0
@@ -139,6 +159,8 @@ def compile
end

class ExclusiveRangeNode < Node
handle :dot2

children :start, :finish

def compile
@@ -153,6 +175,8 @@ def compile
end

class InclusiveRangeNode < Node
handle :dot3

children :start, :finish

def compile
@@ -167,6 +191,8 @@ def compile
end

class HashNode < Node
handle :hash

def keys_and_values
keys, values = [], []

@@ -227,6 +253,8 @@ def compile_hash2(keys, values)
end

class ArrayNode < Node
handle :array

def compile
return push('[]') if children.empty?

@@ -275,14 +303,16 @@ def compile

# def args list
class ArgsNode < Node
handle :args

def compile
children.each_with_index do |child, idx|
next if child.to_s == '*'

child = child.to_sym
push ', ' unless idx == 0
child = compiler.lvar_to_js child
scope.add_arg child
child = variable(child)
scope.add_arg child.to_sym
push child.to_s
end
end
26 changes: 25 additions & 1 deletion lib/opal/nodes/logic.rb
Original file line number Diff line number Diff line change
@@ -3,6 +3,8 @@
module Opal
class Parser
class NextNode < Node
handle :next

children :value

def compile
@@ -14,6 +16,8 @@ def compile
end

class BreakNode < Node
handle :break

children :value

def compile
@@ -42,6 +46,8 @@ def compile_iter
end

class RedoNode < Node
handle :redo

def compile
if in_while?
compile_while
@@ -63,6 +69,8 @@ def compile_iter
end

class NotNode < Node
handle :not

children :value

def compile
@@ -74,6 +82,8 @@ def compile
end

class SplatNode < Node
handle :splat

children :value

def empty_splat?
@@ -92,6 +102,8 @@ def compile
end

class OrNode < Node
handle :or

children :lhs, :rhs

def compile
@@ -106,6 +118,8 @@ def compile
end

class AndNode < Node
handle :and

children :lhs, :rhs

def compile
@@ -129,6 +143,8 @@ def compile
end

class ReturnNode < Node
handle :return

children :value

def return_val
@@ -162,6 +178,8 @@ def compile
end

class JSReturnNode < Node
handle :js_return

children :value

def compile
@@ -171,6 +189,8 @@ def compile
end

class JSTempNode < Node
handle :js_tmp

children :value

def compile
@@ -179,6 +199,8 @@ def compile
end

class BlockPassNode < Node
handle :block_pass

children :value

def compile
@@ -187,6 +209,8 @@ def compile
end

class DefinedNode < Node
handle :defined

children :value

def compile
@@ -211,7 +235,7 @@ def compile
end

def compile_call
mid = compiler.mid_to_jsid value[2].to_s
mid = mid_to_jsid value[2].to_s
recv = value[1] ? expr(value[1]) : 'self'

push '(', recv, "#{mid} || ", recv
6 changes: 6 additions & 0 deletions lib/opal/nodes/rescue.rb
Original file line number Diff line number Diff line change
@@ -3,6 +3,8 @@
module Opal
class Parser
class EnsureNode < Node
handle :ensure

children :begn, :ensr

def compile
@@ -29,6 +31,8 @@ def wrap_in_closure?
end

class RescueNode < Node
handle :rescue

children :body

def compile
@@ -61,6 +65,8 @@ def body_code
end

class ResBodyNode < Node
handle :resbody

children :args, :body

def compile
4 changes: 4 additions & 0 deletions lib/opal/nodes/super.rb
Original file line number Diff line number Diff line change
@@ -50,6 +50,8 @@ def iter_sexp
end

class DefinedSuperNode < BaseSuperNode
handle :defined_super

def compile
# insert method body to find super method
self.compile_dispatcher
@@ -59,6 +61,8 @@ def compile
end

class SuperNode < BaseSuperNode
handle :super

children :arglist, :iter

def compile
22 changes: 22 additions & 0 deletions lib/opal/nodes/variables.rb
Original file line number Diff line number Diff line change
@@ -3,6 +3,8 @@
module Opal
class Parser
class LocalVariableNode < Node
handle :lvar

children :var_name

def using_irb?
@@ -20,6 +22,8 @@ def compile
end

class LocalAssignNode < Node
handle :lasgn

children :var_name, :value

def using_irb?
@@ -42,6 +46,8 @@ def compile
end

class InstanceVariableNode < Node
handle :ivar

children :name

def var_name
@@ -56,6 +62,8 @@ def compile
end

class InstanceAssignNode < Node
handle :iasgn

children :name, :value

def var_name
@@ -70,6 +78,8 @@ def compile
end

class GlobalVariableNode < Node
handle :gvar

children :name

def var_name
@@ -83,6 +93,8 @@ def compile
end

class GlobalAssignNode < Node
handle :gasgn

children :name, :value

def var_name
@@ -97,12 +109,16 @@ def compile
end

class BackrefNode < Node
handle :nth_ref

def compile
push "nil"
end
end

class ClassVariableNode < Node
handle :cvar

children :name

def compile
@@ -113,6 +129,8 @@ def compile
end

class ClassVarAssignNode < Node
handle :casgn

children :name, :value

def compile
@@ -123,6 +141,8 @@ def compile
end

class ClassVarDeclNode < Node
handle :cvdecl

children :name, :value

def compile
@@ -133,6 +153,8 @@ def compile
end

class MassAssignNode < Node
handle :masgn

children :lhs, :rhs

def compile
6 changes: 6 additions & 0 deletions lib/opal/nodes/yield.rb
Original file line number Diff line number Diff line change
@@ -34,6 +34,8 @@ def uses_splat?(children)
end

class YieldNode < BaseYieldNode
handle :yield

def compile
compile_call(children, @level)

@@ -55,6 +57,8 @@ def compile
#
# s(:yasgn, :a, s(:yield, arg1, arg2))
class YasgnNode < BaseYieldNode
handle :yasgn

children :var_name, :yield_args

def compile
@@ -66,6 +70,8 @@ def compile
# Created by `#returns()` for when a yield statement should return
# it's value (its last in a block etc).
class ReturnableYieldNode < BaseYieldNode
handle :returnable_yield

def compile
compile_call children, @level

160 changes: 5 additions & 155 deletions lib/opal/parser.rb
Original file line number Diff line number Diff line change
@@ -15,132 +15,6 @@ class Parser
# math comparisons
COMPARE = %w[< > <= >=]

# Reserved javascript keywords - we cannot create variables with the
# same name
RESERVED = %w(
break case catch continue debugger default delete do else finally for
function if in instanceof new return switch this throw try typeof var let
void while with class enum export extends import super true false native
const static
)

class << self
def handlers
@handlers ||= {}
end

def add_handler(klass, *types)
types.each do |type|
handlers[type] = klass
end
end
end

# literals and primitives
add_handler ValueNode, :true, :false, :nil, :self
add_handler NumericNode, :int, :float
add_handler StringNode, :str
add_handler SymbolNode, :sym
add_handler RegexpNode, :regexp
add_handler XStringNode, :xstr
add_handler DynamicStringNode, :dstr
add_handler DynamicSymbolNode, :dsym
add_handler DynamicXStringNode, :dxstr
add_handler DynamicRegexpNode, :dregx
add_handler ExclusiveRangeNode, :dot2
add_handler InclusiveRangeNode, :dot3
add_handler HashNode, :hash
add_handler ArrayNode, :array
add_handler ArgsNode, :args

# variables
add_handler LocalVariableNode, :lvar
add_handler LocalAssignNode, :lasgn
add_handler InstanceVariableNode, :ivar
add_handler InstanceAssignNode, :iasgn
add_handler GlobalVariableNode, :gvar
add_handler GlobalAssignNode, :gasgn
add_handler BackrefNode, :nth_ref
add_handler ClassVariableNode, :cvar
add_handler ClassVarAssignNode, :cvasgn
add_handler ClassVarDeclNode, :cvdecl
add_handler MassAssignNode, :masgn

# constants
add_handler ConstDeclarationNode, :cdecl
add_handler ConstAssignNode, :casgn
add_handler ConstNode, :const
add_handler ConstGetNode, :colon2
add_handler TopConstNode, :colon3
add_handler TopConstAssignNode, :casgn3

# control flow
add_handler NextNode, :next
add_handler BreakNode, :break
add_handler RedoNode, :redo
add_handler NotNode, :not
add_handler SplatNode, :splat
add_handler OrNode, :or
add_handler AndNode, :and
add_handler ReturnNode, :return
add_handler JSReturnNode, :js_return
add_handler JSTempNode, :js_tmp
add_handler BlockPassNode, :block_pass
add_handler DefinedNode, :defined

# call special
add_handler AttrAssignNode, :attrasgn
add_handler Match3Node, :match3
add_handler OpAsgnOrNode, :op_asgn_or
add_handler OpAsgnAndNode, :op_asgn_and
add_handler OpAsgn1Node, :op_asgn1
add_handler OpAsgn2Node, :op_asgn2

# yield
add_handler YieldNode, :yield
add_handler YasgnNode, :yasgn
add_handler ReturnableYieldNode, :returnable_yield

# class
add_handler SingletonClassNode, :sclass
add_handler ModuleNode, :module
add_handler ClassNode, :class

# definitions
add_handler SvalueNode, :svalue
add_handler UndefNode, :undef
add_handler AliasNode, :alias
add_handler BeginNode, :begin
add_handler ParenNode, :paren
add_handler RescueModNode, :rescue_mod
add_handler BlockNode, :block
add_handler ScopeNode, :scope
add_handler WhileNode, :while
add_handler UntilNode, :until

# if
add_handler IfNode, :if

add_handler IterNode, :iter
add_handler DefNode, :def
add_handler ArglistNode, :arglist

# rescue/ensure
add_handler EnsureNode, :ensure
add_handler RescueNode, :rescue
add_handler ResBodyNode, :resbody

# case
add_handler CaseNode, :case
add_handler WhenNode, :when

# call
add_handler CallNode, :call

# super
add_handler SuperNode, :super
add_handler DefinedSuperNode, :defined_super

# Final generated javascript for this parser
attr_reader :result

@@ -259,34 +133,6 @@ def fragment(code, sexp = nil)
Fragment.new(code, sexp)
end

# 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.
#
# mid_to_jsid('foo') # => ".$foo"
# mid_to_jsid('class') # => ".$class"
# mid_to_jsid('==') # => "['$==']"
# mid_to_jsid('name=') # => "['$name=']"
#
# @param [String] mid ruby method id
# @return [String]
def mid_to_jsid(mid)
if /\=|\+|\-|\*|\/|\!|\?|\<|\>|\&|\||\^|\%|\~|\[/ =~ mid.to_s
"['$#{mid}']"
else
'.$' + mid
end
end

# 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.
def lvar_to_js(var)
var = "#{var}$" if RESERVED.include? var.to_s
var.to_sym
end

# Used to generate a unique id name per file. These are used
# mainly to name method bodies for methods that use blocks.
#
@@ -403,14 +249,18 @@ def in_while?
# Process the given sexp by creating a node instance, based on its type,
# and compiling it to fragments.
def process(sexp, level = :expr)
if handler = Parser.handlers[sexp.type]
if handler = handlers[sexp.type]
@line = sexp.line
return handler.new(sexp, level, self).compile_to_fragments
else
raise "Unsupported sexp: #{sexp.type}"
end
end

def handlers
@handlers ||= Parser::Node.handlers
end

# Handle "special" method calls, e.g. require(). Subclasses can override
# this method. If this method returns nil, then the method will continue
# to be generated by CallNode.

0 comments on commit 0ee6da4

Please sign in to comment.