Permalink
Browse files

Extract Noscriptable mixin

  • Loading branch information...
1 parent 82ff767 commit 56ecf0359a823b0a7a8fa3a63c6b78a7443a34f0 @txus committed Jan 25, 2012
Showing with 130 additions and 127 deletions.
  1. +16 −16 kernel/test_case.nsc
  2. +6 −6 kernel/traits.nsc
  3. +5 −5 lib/noscript/compiler.rb
  4. +93 −95 lib/noscript/runtime.rb
  5. +1 −1 lib/noscript/signature.rb
  6. +9 −4 test/compiler_test.rb
View
@@ -478,8 +478,8 @@ US-ASCII
6
errors
x
-3
-get
+16
+__noscript_get__
x
5
Empty
@@ -530,8 +530,8 @@ x
10
noscript:+
x
-3
-put
+16
+__noscript_put__
p
15
I
@@ -750,8 +750,8 @@ US-ASCII
6
errors
x
-3
-get
+16
+__noscript_get__
x
5
Empty
@@ -802,8 +802,8 @@ x
10
noscript:+
x
-3
-put
+16
+__noscript_put__
p
15
I
@@ -1038,8 +1038,8 @@ US-ASCII
5
tests
x
-3
-get
+16
+__noscript_get__
x
5
Empty
@@ -1325,8 +1325,8 @@ US-ASCII
9
each slot
x
-3
-get
+16
+__noscript_get__
x
5
Empty
@@ -1524,8 +1524,8 @@ US-ASCII
5
setup
x
-3
-get
+16
+__noscript_get__
x
5
Empty
@@ -1581,8 +1581,8 @@ x
10
noscript:+
x
-3
-put
+16
+__noscript_put__
p
17
I
View
@@ -211,8 +211,8 @@ US-ASCII
6
traits
x
-3
-get
+16
+__noscript_get__
x
5
Empty
@@ -261,8 +261,8 @@ x
3
new
x
-3
-put
+16
+__noscript_put__
n
x
5
@@ -347,8 +347,8 @@ x
8
__name__
x
-3
-put
+16
+__noscript_put__
p
9
I
@@ -125,14 +125,14 @@ def visit_Identifier(o)
elsif o.deref? # @foo equals to self.foo
g.push_self
g.push_literal o.name
- g.send :get, 1
+ g.send :__noscript_get__, 1
g.raise_if_empty NameError, "Object has no slot named #{o.name}"
elsif o.self?
g.push_self
elsif s.slot_for(o.name)
visit_LocalVariableAccess(o)
else
- raise "CANT FIND #{o.name}"
+ raise "BUG: CANT FIND #{o.name}"
end
end
@@ -177,7 +177,7 @@ def visit_LocalVariableAssignment(o)
elsif identifier.deref?
g.push_literal name
g.swap
- g.send :put, 2
+ g.send :__noscript_put__, 2
else
s.set_local name
end
@@ -212,7 +212,7 @@ def visit_SlotGet(o)
g.find_const o.name.name.to_sym
else
g.push_literal o.name.name.to_sym
- g.send :get, 1
+ g.send :__noscript_get__, 1
end
g.raise_if_empty NameError, "Object has no slot named #{o.name}"
@@ -223,7 +223,7 @@ def visit_SlotAssign(o)
o.receiver.accept(self)
g.push_literal o.name
o.value.accept(self)
- g.send :put, 2
+ g.send :__noscript_put__, 2
end
def visit_IfNode(o)
@@ -1,3 +1,86 @@
+module Noscriptable
+ def __noscript_prototype__
+ @__noscript_prototype__
+ end
+
+ def __noscript_prototype__=(proto)
+ @__noscript_prototype__ = proto
+ end
+
+ def __noscript_slots__
+ @__noscript_slots__ ||= begin
+ slots = Rubinius::LookupTable.new
+ slots[:__name__] = "Object"
+ slots[:traits] = []
+ slots
+ end
+ end
+
+ def __noscript_get__(name)
+ if __noscript_slots__.key?(name)
+ __noscript_slots__[name]
+ elsif self.methods.include?(:"noscript:#{name}")
+ self.method(:"noscript:#{name}")
+ elsif method = __noscript_trait_has__(name)
+ method
+ elsif proto = __noscript_prototype__
+ proto.__noscript_get__(name)
+ else
+ Empty.new
+ end
+ end
+
+ def __noscript_trait_has__(name)
+ # Check for an explicit call, i.e. @Businessman run()
+ explicit_method = __noscript_slots__[:traits].map do |trait|
+ explicit_name = name.to_s.split(trait.__noscript_slots__[:__name__]).last.strip.to_sym
+ if name != explicit_name && trait.__noscript_has_property__(explicit_name, false)
+ trait.__noscript_get__(explicit_name)
+ else
+ nil
+ end
+ end.compact.first
+ return explicit_method if explicit_method
+
+ # Otherwise, check for the normal trait chain
+ matching = __noscript_slots__[:traits].map do |trait|
+ if trait.__noscript_has_property__(name, false)
+ trait.__noscript_get__(name)
+ else
+ nil
+ end
+ end.compact
+ return false if matching.length == 0
+ raise "Trait conflict: ##{name} is implemented by more than one trait." if matching.length > 1
+ return matching.first
+ end
+
+ def __noscript_has_property__(name, lookup=true)
+ if result = __noscript_slots__.key?(name)
+ result
+ elsif lookup && __noscript_trait_has__(name)
+ true
+ elsif lookup && proto = __noscript_prototype__
+ proto.__noscript_has_property__(name)
+ else
+ false
+ end
+ end
+
+ def __noscript_put__(name, object)
+ __noscript_slots__[name] = object
+ end
+
+ def method_missing(m, *args)
+ function = m.to_s.split(":").last.to_sym
+ if __noscript_has_property__(function)
+ fn = __noscript_get__(function)
+ return fn.call(*args) # First arg is this.
+ end
+ super
+ end
+end
+
class Module
def noscript_alias(noscript_name, ruby_name=nil)
Array(noscript_name).each do |noscript|
@@ -18,6 +101,7 @@ def noscript_def(name, &block)
end
class Object
+ # include Noscriptable
def noscript_send(name, *args)
__send__ "noscript:#{send}", *args
end
@@ -40,34 +124,22 @@ class Empty
end
class Runtime
- # Object protocol:
- #
- # get(name<Symbol>) => object
- # put(name<Symbol>, object<Object>)
- #
- class ObjectType < Rubinius::LookupTable
- attr_accessor :prototype
-
- def initialize
- @prototype = nil
- self[:__name__] = "Object"
- self[:traits] = []
- end
-
+ class ObjectKind
+ include Noscriptable
noscript_def("clone") do |*args|
- obj = ObjectType.new
- obj.prototype = self
+ obj = ObjectKind.new
+ obj.__noscript_prototype__ = self
if properties = args.first
properties.keys.each do |k|
- obj.put(k.to_sym, properties[k])
+ obj.__noscript_put__(k.to_sym, properties[k])
end
end
obj
end
noscript_def("each slot") do |*args|
fn = args.shift
- to_a.each do |k, v|
+ __noscript_slots__.to_a.each do |k, v|
fn.call(self, k.to_s, v)
end
end
@@ -77,88 +149,14 @@ def initialize
end
noscript_def("put") do |k, v|
- put(k, v)
+ __noscript_put__(k, v)
end
noscript_def("get") do |slot|
- get(slot)
- end
-
- # def function(name, block=name)
- # if block.is_a?(Symbol)
- # block = method(block).executable
- # else
- # block = block.code
- # end
-
- # self[name] = Function.new(name, block)
- # end
-
- def get(name)
- if self.key?(name)
- self[name]
- elsif self.methods.include?(:"noscript:#{name}")
- self.method(:"noscript:#{name}")
- elsif method = trait_implementation_of(name)
- method
- elsif proto = prototype
- proto.get(name)
- else
- Empty.new
- end
- end
-
- def trait_implementation_of(name)
- # Check for an explicit call, i.e. @Businessman run()
- explicit_method = self[:traits].map do |trait|
- explicit_name = name.to_s.split(trait[:__name__]).last.strip.to_sym
- if name != explicit_name && trait.key?(explicit_name)
- trait.get(explicit_name)
- else
- nil
- end
- end.compact.first
- return explicit_method if explicit_method
-
- # Otherwise, check for the normal trait chain
- matching = self[:traits].map do |trait|
- if trait.key?(name)
- trait.get(name)
- else
- nil
- end
- end.compact
- return false if matching.length == 0
- raise "Trait conflict: ##{name} is implemented by more than one trait." if matching.length > 1
- return matching.first
- end
-
- def put(name, object)
- self[name] = object
- end
-
- def has_property?(name)
- if result = key?(name)
- result
- elsif trait_implementation_of(name)
- true
- elsif proto = prototype
- proto.has_property?(name)
- else
- false
- end
- end
-
- def method_missing(m, *args)
- fun = m.to_s.split(":").last.to_sym
- if has_property?(fun)
- this = args.shift
- return get(fun).call(this, *args)
- end
- super
+ __noscript_get__(slot)
end
end
- Object = ObjectType.new
+ Object = ObjectKind.new
end
class Function
@@ -1,3 +1,3 @@
# This file is generated by `rake signature`. The signature
# is used to ensure that only current compiled files are loaded.
-Noscript::Signature = Rubinius::Signature ^ 1377728806764044089
+Noscript::Signature = Rubinius::Signature ^ 9737304784934064492
Oops, something went wrong.

0 comments on commit 56ecf03

Please sign in to comment.