Permalink
Browse files

add def_own_property for array

  • Loading branch information...
1 parent 3ae8adf commit 97da1fd9968f00bc5b1f0f9add2ef24f7c8806e1 @tdsparrow committed Feb 26, 2012
View
@@ -1,5 +1,6 @@
# A sample Gemfile
source "http://rubygems.org"
+source "http://ruby.taobao.org"
gem "parslet"
@@ -9,5 +10,7 @@ gem "rspec-core"
gem "rspec-mocks"
gem "rspec-expectations"
+gem "mixlib-log"
+
gem "simplecov"
# gem "rails"
@@ -1,7 +1,7 @@
Then /^i get the array with size (\d+)$/ do |size|
p result
result.class.should == Moonr::JSArray
- result.length.should == size.to_i
+ result.get(:length).should == size.to_i
end
Then /^i get the object with (\d+) properites$/ do |size|
@@ -5,6 +5,7 @@
require 'rspec-expectations'
require 'moonr'
+Moonr::Log.level = :debug
module MoonrHelper
def parse(syntax)
parser = Moonr::Parser.new.send( syntax.empty? ? :root : syntax.lstrip )
View
@@ -31,7 +31,7 @@ module Expression
# [ ElementList ]
# [ ElementList , Elision(opt) ]
rule(:array_literal) {
- str('[') + elision? + str(']') |
+ str('[').as(:al) + elision? + str(']').as(:ar) |
str('[') + element_list + ( str(',') + elision? ).maybe + str(']')
}
View
@@ -1,4 +1,5 @@
require 'jsobject/jsbase'
+require 'jsobject/jsproperty'
require 'jsobject/jsarray'
require 'jsobject/jsobject'
-require 'jsobject/jsproperty'
+
@@ -21,8 +21,11 @@ def self.internal_property(prop, value)
internal_property :clazz, "Array"
internal_property :extensible, true
+ internal_property :prototype, JSNull.inst
+
property :length
+
def initialize(*args)
@properties = {}
@internal_properties = {}
@@ -35,10 +38,10 @@ def initialize(*args)
end
def update_length
- @properties[:length] = JSDataDescriptor.new(:value => @array.size,
- :writable => true,
- :enumerable => false,
- :configurable => false)
+ @properties[:length] = JSDataDescriptor.new(@array.size,
+ true,
+ false,
+ false)
end
def size
@@ -53,7 +56,11 @@ def create_arr_with_num(*args)
def create_arr_with_elem(*args)
@array = Array.new
- args.each { |a| @array << a }
+ args.each_with_index do |a,i|
+ desc = JSDataDescriptor.new(a, true, true, true)
+ @array << desc
+ @properties[i] = desc
+ end
end
def to_arr()
@@ -68,27 +75,106 @@ def <<(entry)
JSArray.new(@array << entry)
end
+ def base_def_own_property(name, desc, to_throw)
+ current = get_own_property(name)
+ reject if current.undefined? and not extensible
+
+ if current.undefined? and extensible
+ if desc.is_generic? or desc.is_data?
+ @properties[name] = desc.copy
+ else
+ @properties[name] = desc.copy
+ end
+ return true
+ end
+
+ return true if desc.select {|v| not v.nil?}.empty?
+ return true if desc == current
+
+ unless current.configurable
+ reject if desc.configurable
+ reject if current.configurable == ! desc.configurable
+ end
+ end
+
def def_own_property(name, desc, to_throw)
- @properties[name.to_sym] = desc
- p @properties
+
+ old_len_desc = get_own_property(name)
+ old_len = old_len_desc.value
+
+ if name == :length or name == "length"
+ return base_def_own_property(name, desc, to_throw) if (desc.value.nil?)
+
+ new_len_desc = desc.dup
+ new_len = desc.value
+ # todo TypeError check
+ new_len_desc.value = new_len
+
+ return base_def_own_property(name, new_len_desc, to_throw) if new_len >= old_len
+
+ reject unless old_len_desc.writable
+
+ if new_len_desc.writable.nil? or
+ new_len_desc.writable
+ new_writable = true
+ else
+ defer(:writable, false)
+ new_writable = false
+ new_len_desc.writable = true
+ end
+
+ succeed = base_def_own_property(prop, new_len_desc, to_throw)
+ return succeed unless succeed
+
+ while ( new_len < old_len )
+ old_len = old_len.pred
+ del_succeed = delete(old_len, false)
+
+ if not del_succeed
+ new_len_desc.value = old_len + 1
+ new_len_desc.writable = false unless new_writable
+ base_def_own_property(:length, new_len_desc, false)
+ reject
+ end
+ end
+
+ base_def_own_property(:length, JSDataDescriptor.new(nil, false), false) unless new_writable
+
+ return ture
+ elsif is_index?(name)
+ index = name.to_i
+ reject if index >= old_len and not old_len_desc.writable
+ succeed = base_def_own_property(name, desc, false)
+ reject unless succeed
+
+ if index >= old_len
+ old_len_desc.value = index + 1
+ base_def_own_property(:length, old_len_desc, false)
+ end
+ return true
+ end
+
+ return base_def_own_property(name, desc, to_throw)
+
end
def get_property(prop)
prop = get_own_property(prop)
return prop unless prop.undefined?
proto = prototype
- return Undefined.new if proto.null?
+ return JSUndefined.inst if proto.null?
return proto.get_property(prop)
end
-
+
def get(prop)
+
desc = get_property(prop)
- return Undefined.new if desc.undefined?
+ return JSUndefined.inst if desc.undefined?
return desc.value if desc.is_data?
getter = desc.get
- return undefined.new if getter.undefined?
+ return JSUndefined.inst if getter.undefined?
return getter.call(self)
end
@@ -98,9 +184,8 @@ def put(prop, value, to_throw)
return if not can_put(prop)
own_desc = get_own_property(prop)
- p own_desc
if own_desc.is_data?
- value_desc = JSDataDescriptor.new(:value=> value)
+ value_desc = JSDataDescriptor.new(value)
def_own_property(prop, value_desc, to_throw)
return
end
@@ -119,16 +204,14 @@ def put(prop, value, to_throw)
def can_put(prop)
desc = get_own_property(prop)
- p desc
-
if not desc.undefined?
if desc.is_accessor?
return false if desc.set.undefined?
return true
end
return desc.writable
- end
+ end
proto = prototype
return extensible if proto.null?
@@ -146,8 +229,8 @@ def can_put(prop)
end
def get_own_property(prop)
- return Undefined.new unless @properties[prop]
- return @properties[prop].dup
+ return JSUndefined.inst unless @properties[prop]
+ return @properties[prop]
end
end
end
@@ -1,6 +1,4 @@
module Moonr
- class Undefined
- end
class JSObject
def initialize(&block)
@@ -1,24 +1,85 @@
+require 'singleton'
+
module Moonr
module CheckType
def undefined?
- is_a? Undefined
+ is_a? JSUndefined
end
def is_data?
- is_a? JSDataDescriptor
+ return false if undefined?
+ return false if value.nil? and writable.nil?
+ true
+ end
+
+ def null?
+ is_a? JSNull
end
def is_accessor?
- is_a? JSAccessorDescriptor
+ return false if undefined?
+ return false if get.nil? and set.nil?
+ true
end
+
+ def is_generic?
+ return false if undefined?
+ return true if writable.nil? and value.nil?
+ false
+ end
+
end
- JSDataDescriptor = Struct.new(:value, :writable, :enumerable, :configurable)
+
+ class JSDataDescriptor < Struct.new(:value, :writable, :enumerable, :configurable)
+ include CheckType
+
+
+ def copy
+ desc = self.dup
+ value || self.value = Undefinded.inst
+ writable || self.writable = false
+ enumerable || self.enumerable = false
+ configurable || self.configurable = false
+ end
+ end
+
JSAccessorDescriptor = Struct.new(:get, :set, :writable, :enumerable, :configurable)
- class JSDataDescriptor
+ class JSUndefined
+ include CheckType
+ include Singleton
+
+ class << self
+ alias :inst :instance
+ end
+ end
+
+ class JSNull
include CheckType
+ include Singleton
+
+ class << self
+ alias :inst :instance
+ end
end
+
+ class JSDataDescriptor
+ end
+
+ class JSAccessorDescriptor
+ include CheckType
+
+ def copy
+ desc = self.dup
+ get || self.get = Undefinded.inst
+ set || self.set = Undefinded.inst
+ writable || self.writable = false
+ enumerable || self.enumerable = false
+ configurable || self.configurable = false
+ end
+ end
+
class JSPropIdentifier
attr_reader :name, :desc
View
@@ -4,8 +4,10 @@
require 'transform/transform'
require 'jsobject'
require 'util'
+require 'mixlib/log'
module Moonr
+ class Log; extend Mixlib::Log; end
class Result
def initialize ast
@ast = ast
View
@@ -4,15 +4,30 @@ class Expr < Parslet::Transform
# Array initialiser
rule(:elision => simple(:e) ) { e.to_s.count(',') }
rule(:elisions => simple(:e) ) { e.nil? ? 0:e }
+
+ # [ , , , ]
+ rule(:al => simple(:al), :elisions => simple(:e), :ar => simple(:ar) ) do
+ JSArray.new(e)
+ end
rule(:elisions => simple(:e), :assignment => simple(:a) ) do
ind = e.nil? ? 0 : e
obj = JSArray.new(ind)
obj.def_own_property(ind.to_s, JSDataDescriptor.new(a, true, true, true), false )
obj
end
-
- rule(:array_literal => sequence(:a) ) { a.inject(:+) }
+
+ rule(:array_literal => sequence(:a) ) do
+ a.inject do |total, value|
+ next total.put(:length, total.get(:length) + value, false) if value.is_a? Fixnum
+ pad = value.get(:length)
+ len = total.get(:length)
+
+ total.def_own_property(pad+len, JSDataDescriptor.new(value.get(pad), true, true, true), false)
+ Log.debug total
+ total
+ end
+ end
rule(:array_literal => simple(:a) ) { a }
# Object initialiser
@@ -8,7 +8,7 @@ def initialize
end
def apply(ast)
- @trans.inject(ast) { |res, t|p res; t.apply res }
+ @trans.inject(ast) { |res, t| Log.info res; t.apply res }
end
end
end
Oops, something went wrong.

0 comments on commit 97da1fd

Please sign in to comment.