lib/minjs/ecma262/lit.rb in minjs-0.2.0 vs lib/minjs/ecma262/lit.rb in minjs-0.2.1
- old
+ new
@@ -1,6 +1,7 @@
# coding: utf-8
+require 'set'
module Minjs
module ECMA262
class Literal < Base
def ws?
false
@@ -117,10 +118,18 @@
def to_ecma262_boolean
false
end
+ def to_ecma262_string
+ "null"
+ end
+
+ def to_ecma262_number
+ 0
+ end
+
def ecma262_typeof
:boolean
end
end
@@ -154,18 +163,34 @@
def true?
@val == :true
end
+ def to_ecma262_string
+ if @val == :false
+ "false"
+ else
+ "true"
+ end
+ end
+
def to_ecma262_boolean
if @val == :false
false
else
true
end
end
+ def to_ecma262_number
+ if @val == :false
+ 0
+ else
+ 1
+ end
+ end
+
def ecma262_typeof
:boolean
end
@@true = self.new(:true)
@@ -178,10 +203,11 @@
end
end
end
class ECMA262String < Literal
+ include Ctype
attr_reader :val
def initialize(val)
@val = val
end
@@ -249,42 +275,213 @@
else
true
end
end
+ def to_ecma262_string
+ @val.dup
+ end
+ # 9.3.1 ToNumber Applied to the String Type
+ def to_ecma262_number
+ begin
+ pos1 = pos0 = pos = 0
+ v = @val.codepoints
+ while true
+ return 0 if v[pos].nil? # ToInteger(empty string) => 0
+ if white_space?(v[pos]) or line_terminator?(v[pos])
+ pos += 1
+ else
+ break
+ end
+ end
+ #hex
+ if v[pos] == 0x30 and (v[pos+1] == 0x78 || v[pos+1] == 0x58) and hex_number?(v[pos+2])
+ base = 16
+ pos += 2
+ pos0 = pos
+ while true
+ break if v[pos].nil?
+ if hex_number?(v[pos])
+ pos += 1
+ else
+ break
+ end
+ end
+ #decimal
+ else
+ base = 10
+ sign = 1
+ pos0 = pos
+ if v[pos].nil?
+ raise :error
+ elsif v[pos] == 0x2b #+
+ pos += 1
+ elsif v[pos] == 0x2d #-
+ sign = -1
+ pos += 1
+ end
+ has_decimal = false
+ has_exp = false
+
+ while true
+ break if v[pos].nil?
+ if v[pos] >= 0x30 and v[pos] <= 0x39
+ pos += 1
+ elsif v[pos] == 0x2e #.
+ pos += 1
+ has_decimal = true
+ break;
+ else
+ break
+ end
+ end
+ if has_decimal
+ while true
+ break if v[pos].nil?
+ if v[pos] >= 0x30 and v[pos] <= 0x39
+ pos += 1
+ elsif v[pos] == 0x45 or v[pos] == 0x65 #E/e
+ pos += 1
+ has_exp = true
+ break;
+ else
+ break
+ end
+ end
+ end
+ if has_exp
+ if v[pos] == 0x2b #+
+ pos += 1
+ else v[pos] == 0x2d #-
+ pos += 1
+ end
+ while true
+ break if v[pos].nil?
+ if v[pos] >= 0x30 and v[pos] <= 0x39
+ pos += 1
+ else
+ break
+ end
+ end
+ end
+ end
+ pos1 = pos
+ while white_space?(v[pos]) or line_terminator?(v[pos])
+ raise :error if v[pos].nil?
+ pos += 1
+ end
+ raise :error unless v[pos].nil?
+ if base == 16
+ ret = v[pos0...pos1].pack("U*").to_i(base)
+ else
+ ret = v[pos0...pos1].pack("U*").to_f
+ end
+ rescue => e
+ ret = nil #Float::NAN
+ end
+ ret
+ end
+
def ecma262_typeof
:string
end
end
+ #
+ # 8.5 The Number Type
+ #
+ # ECMA262 say:
+ #
+ # The Number type has exactly 18437736874454810627
+ # (that is, 264−253+3) values, representing the
+ # double-precision 64-bit format IEEE 754 values
+ # as specified in the IEEE Standard for Binary
+ # Floating-Point Arithmetic
+ #
+ # To simplify the implementation,
+ # Minjs assumes that ruby has IEEE754 dobule precision.
+ #
class ECMA262Numeric < Literal
- attr_reader :integer, :decimal, :exp
+ attr_reader :integer, :decimal, :exp, :number
+ if Float::DIG != 15
+ if defined?(@logger)
+ @logger.warn{
+ "minjs assumes that ruby has IEEE754 dobule precision."
+ }
+ end
+ end
+
def initialize(integer, decimal = nil, exp = nil)
- if integer == :nan
- integer = nil
- @nan = true
- elsif integer == :infinity
- integer = nil
- @infinity = true
- elsif integer.kind_of? Float
- @integer, @decimal = integer.to_i.to_s
- @decimal = (integer - @integer).to_s.sub(/^.*0\./, '')
- else
- @integer = integer.to_s
- if decimal
- @decimal = decimal.to_s
+ if integer == :nan or integer == "NaN"
+ @number = Float::NAN
+ @integer = "NaN"
+ @decimal = nil
+ @exp = nil
+ elsif integer == :infinity or integer == Float::INFINITY or integer == "Infinity"
+ @number = Float::INFINITY
+ @integer = "Infinity"
+ @decimal = nil
+ @exp = nil
+ elsif integer == -Float::INFINITY or integer == "-Infinity"
+ @number = -Float::INFINITY
+ @integer = "-Infinity"
+ @decimal = nil
+ @exp = nil
+ elsif integer.kind_of? String
+ @integer = integer.to_s #String
+ @decimal = decimal.to_s #String
+ @exp = exp ? exp.to_i : nil
+ if @decimal == ""
+ d = ""
+ else
+ d = ".#{@decimal}"
end
- if exp
- @exp = exp.to_i
+ if @exp
+ @number = "#{integer}#{d}e#{exp}".to_f
+ else
+ @number = "#{integer}#{d}".to_f
end
+ if @number.kind_of? Float and @number.nan?
+ @integer = "NaN"
+ @decimal = nil
+ @exp = nil
+ elsif @number == Float::INFINITY
+ @integer = "Infinity"
+ @decimal = nil
+ @exp = nil
+ elsif @number == -Float::INFINITY
+ @integer = "-Infinity"
+ @decimal = nil
+ @exp = nil
+ end
+ elsif integer.kind_of? Numeric
+ if integer.kind_of? Float and integer.nan?
+ @number = Float::NAN
+ @decimal = nil
+ @exp = nil
+ elsif integer == Float::INFINITY
+ @number = Float::INFINITY
+ @decimal = nil
+ @exp = nil
+ elsif integer == -Float::INFINITY
+ @number = -Float::INFINITY
+ @decimal = nil
+ @exp = nil
+ else
+ @number = integer
+ @integer = @number.to_i.to_s
+ @decimal = (@number - @integer.to_i).to_s.sub(/0\.?/, '')
+ @exp = nil
+ end
+ else
+ raise 'internal error'
end
- @decimal = nil if @decimal == 0
end
def deep_dup
- self.class.new(@integer, @decimal, @exp)
+ self.class.new(@number)
end
def traverse(parent, &block)
yield self, parent
end
@@ -292,73 +489,79 @@
def ==(obj)
self.class == obj.class and self.to_ecma262_string == obj.to_ecma262_string
end
def to_js(options = {})
- if @nan
+ if nan?
return "NaN"
+ elsif @number == Float::INFINITY
+ return "Infinity"
+ elsif @number == -Float::INFINITY
+ return "-Infinity"
end
- t = @integer.dup.to_s
+ t0 = to_ecma262_string
+ t = @integer.nil? ? "" : @integer.dup.to_s
- if @decimal
+ d = @decimal.to_s
+ if d == '0'
+ d = ''
+ end
+ if d.length > 0
if @integer == '0'
- t = ".#{@decimal}"
+ t = ".#{d}"
else
- t << ".#{@decimal}"
+ t << ".#{d}"
end
end
if @exp
t << "e#{@exp}"
end
- if @decimal.nil? and @exp.nil? and t.match(/0{3,}$/)
+ if !t.match(/e/) and !t.match(/\./) and t.match(/0{3,}$/)
len = $&.length
t.sub!(/0+$/, "e#{len}")
end
- t
+ t.sub!(/e\+/, 'e')
+ t0.sub!(/e\+/, 'e')
+
+ t.length <= t0.length ? t : t0
end
- def integer?
- @decimal.nil?
+ def to_i
+ to_ecma262_string.to_i
end
- def to_num
- if @decimal
- to_f
- else
- to_i
- end
+ def to_f
+ to_ecma262_string.to_f
end
- def to_i
- if @exp
- @integer.to_i * (10 ** @exp.to_i)
- else
- @integer.to_i
- end
+ def nan?
+ @number.kind_of? Float and @number.nan?
end
- def to_f
- d = @decimal
- if d.to_s == ''
- d = '0'
- end
- "#{@integer}.#{d}e#{@exp}".to_f
+ def infinity?
+ @number == Float::INFINITY || @number == -Float::INFINITY
end
+ def number?
+ !nan? and !infinity?
+ end
+
#
# 9.8.1
#
def to_ecma262_string
- if @nan
+ if nan?
"NaN"
+ elsif @number == Float::INFINITY
+ "Infinity"
+ elsif @number == -Float::INFINITY
+ "-Infinity"
elsif @integer == '0' and @decimal.nil? and @exp.nil?
"0"
- elsif @intinify
- "Infinity"
else
- f = to_f.to_s
+ f = @number.to_f.to_s
_n, _e = f.split('e')
_i, _d = _n.split('.')
e = _e.to_i
if(e == 0)
@@ -390,10 +593,22 @@
else
true
end
end
+ def to_ecma262_number
+ if nan?
+ nil
+ elsif @number == Float::INFINITY
+ nil
+ elsif @number == -Float::INFINITY
+ nil
+ else
+ @number
+ end
+ end
+
def ecma262_typeof
:number
end
def ecma262_eval(type)
@@ -421,10 +636,14 @@
def traverse(parent)
yield self, parent
end
+ def to_ecma262_boolean
+ true
+ end
+
def ==(obj)
self.class == obj.class and @body == obj.body and @flags == obj.flags
end
def to_js(options = {})
@@ -510,16 +729,11 @@
t = "set #{x.val.to_s}(#{y.args[0].to_js(options)}){#{y.statements.to_js(options)}}"
end
else
if x.kind_of? ECMA262Numeric
a = "#{x.to_ecma262_string}"
- b = "#{x.to_js}"
- if a.length <= b.length || a == "Infinity"
- t = a
- else
- t = b
- end
+ t = a
elsif idname?(x.val.to_s)
t = "#{x.val.to_s}"
else
t = "#{x.to_js(options)}"
end
@@ -610,25 +824,25 @@
def self.get(context, val)
@@sym[val] ||= self.new(context, val)
end
- RESERVED_WORD = [
+ RESERVED_WORD = Set.new [
:break, :do, :instanceof, :typeof, :case, :else,
:new, :var, :catch, :finally, :return, :void, :continue,
:for, :switch, :while,:debugger, :function, :this, :with,
:default, :if, :throw, :delete, :in, :try,
:class, :enum, :extends, :super, :const, :export, :import,
:implements, :let, :private, :public, :yield,
:interface, :package, :protected, :static,
:null, :false, :true
]
def reserved?
- RESERVED_WORD.index(val)
+ RESERVED_WORD.include?(val)
end
def self.reserved?(val)
- RESERVED_WORD.index(val)
+ RESERVED_WORD.include?(val)
end
def traverse(parent)
yield self, parent
end