Skip to content

Commit

Permalink
Generate class sexps using ClassNode
Browse files Browse the repository at this point in the history
  • Loading branch information
adambeynon committed Oct 22, 2013
1 parent 7a16fb2 commit 49e6195
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 86 deletions.
92 changes: 56 additions & 36 deletions lib/opal/nodes/class.rb
Expand Up @@ -4,80 +4,100 @@ module Opal
class Parser
class BaseScopeNode < Node
def in_scope(type, &block)
@parser.in_scope(type, &block)
indent { @parser.in_scope(type, &block) }
end
end

class SingletonClassNode < BaseScopeNode
children :object, :body

def compile
push "(function(self) {"

in_scope(:sclass) do
add_temp '$scope = self._scope'
add_temp 'def = self._proto'

push scope.to_vars
push stmt(body)
line scope.to_vars
line stmt(body)
end

push "})("
push recv(object)
wrap "(function(self) {", ".$singleton_class())"
line "})(", recv(object), ".$singleton_class())"
end
end

class ModuleNode < BaseScopeNode
children :cid, :body

def compile
name, base = name_and_base
helper :module

push pre_code
push "(function($base) {"
line " var self = $module($base, '#{name}');"

@parser.indent do
in_scope(:module) do
scope.name = module_name
add_temp "#{scope.proto} = self._proto"
add_temp '$scope = self._scope'
in_scope(:module) do
scope.name = name
add_temp "#{scope.proto} = self._proto"
add_temp '$scope = self._scope'

body_code = stmt(body)
body_code = stmt(body)
empty_line

push "#{@indent}", scope.to_vars, "\n\n#{@indent}"
push body_code
push "\n#{@indent}", scope.to_donate_methods
end
line scope.to_vars
line body_code
line scope.to_donate_methods
end

push "\n#{@indent}})(", module_base, ")"
end

def pre_code
name = module_name
"(function($base) {\n#{@indent} var self = $module($base, '#{name}');\n"
line "})(", base, ")"
end

def module_base
def name_and_base
if Symbol === cid or String === cid
'self'
[cid.to_s, 'self']
elsif cid.type == :colon2
expr(cid[1])
[cid[2].to_s, expr(cid[1])]
elsif cid.type == :colon3
'$opal.Object'
[cid[1].to_s, '$opal.Object']
else
raise "Bad receiver in module"
end
end
end

def module_name
if Symbol === cid or String === cid
cid.to_s
elsif cid.type == :colon2
cid[2].to_s
elsif cid.type == :colon3
cid[1].to_s
else
raise "Bad receiver in module"
class ClassNode < ModuleNode
children :cid, :sup, :body

def compile
name, base = name_and_base
helper :klass

push "(function($base, $super) {"
line " function #{name}(){};"
line " var self = #{name} = $klass($base, $super, '#{name}', #{name});"

in_scope(:class) do
scope.name = name
add_temp "#{scope.proto} = #{name}._proto"
add_temp "$scope = #{name}._scope"

body_code = self.body_code
empty_line

line scope.to_vars
line body_code
end

line "})(", base, ", ", self.super_code, ")"
end

def super_code
sup ? expr(sup) : 'null'
end

def body_code
body[1] = s(:nil) unless body[1]
stmt(@parser.returns(body))
end
end
end
Expand Down
3 changes: 1 addition & 2 deletions lib/opal/nodes/definitions.rb
Expand Up @@ -112,8 +112,7 @@ def compile
end

def stmt_join
indent = @parser.instance_variable_get(:@indent)
scope.class_scope? ? "\n\n#{indent}" : "\n#{indent}"
scope.class_scope? ? "\n\n#{current_indent}" : "\n#{current_indent}"
end

def child_is_expr?(child)
Expand Down
17 changes: 17 additions & 0 deletions lib/opal/nodes/helpers.rb
Expand Up @@ -13,6 +13,23 @@ def reserved?(name)
def variable(name)
reserved?(name) ? "#{name}$" : name
end

def indent(&block)
@parser.indent(&block)
end

def current_indent
@parser.parser_indent
end

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

def empty_line
push "\n"
end
end
end
end
49 changes: 1 addition & 48 deletions lib/opal/parser.rb
Expand Up @@ -101,6 +101,7 @@ def add_handler(klass, *types)
# class
add_handler SingletonClassNode, :sclass
add_handler ModuleNode, :module
add_handler ClassNode, :class

# definitions
add_handler UndefNode, :undef
Expand Down Expand Up @@ -768,54 +769,6 @@ def process_arglist(sexp, level)
code
end

# s(:class, cid, super, body)
def process_class(sexp, level)
cid, sup, body = sexp

body[1] = s(:nil) unless body[1]

code = []
helper :klass

if Symbol === cid or String === cid
base = process s(:self)
name = cid.to_s
elsif cid[0] == :colon2
base = process(cid[1])
name = cid[2].to_s
elsif cid[0] == :colon3
base = process(s(:js_tmp, '$opal.Object'))
name = cid[1].to_s
else
raise "Bad receiver in class"
end

sup = sup ? process(sup) : process(s(:js_tmp, 'null'))

indent do
in_scope(:class) do
@scope.name = name
@scope.add_temp "#{@scope.proto} = #{name}._proto",
"$scope = #{name}._scope"

body = process(returns(body), :stmt)
code << f("\n")

code << f(@indent)
code << @scope.to_vars
code << f("\n\n#@indent")
code << body
end
end

spacer = "\n#{@indent}#{INDENT}"
cls = "function #{name}() {};"
boot = "var self = #{name} = $klass($base, $super, #{name.inspect}, #{name});"

[f("(function($base, $super){#{spacer}#{cls}#{spacer}#{boot}\n", sexp),
code, f("\n#@indent})", sexp), f("(", sexp), base, f(", ", sexp), sup, f(")", sexp)]
end

# s(:def, recv, mid, s(:args), s(:scope))
def process_def(sexp, level)
recvr, mid, args, stmts = sexp
Expand Down

0 comments on commit 49e6195

Please sign in to comment.