twostroke 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. data/lib/twostroke/ast/case.rb +1 -1
  2. data/lib/twostroke/ast/function.rb +2 -2
  3. data/lib/twostroke/ast/label.rb +20 -0
  4. data/lib/twostroke/ast/switch.rb +1 -0
  5. data/lib/twostroke/ast/try.rb +3 -3
  6. data/lib/twostroke/ast/unary_operators.rb +1 -1
  7. data/lib/twostroke/ast.rb +1 -0
  8. data/lib/twostroke/compiler/javascript.rb +20 -2
  9. data/lib/twostroke/compiler/tsasm.rb +89 -35
  10. data/lib/twostroke/compiler.rb +1 -1
  11. data/lib/twostroke/error.rb +3 -0
  12. data/lib/twostroke/lexer.rb +3 -2
  13. data/lib/twostroke/parser.rb +309 -227
  14. data/lib/twostroke/runtime/lib/array.js +9 -3
  15. data/lib/twostroke/runtime/lib/array.rb +15 -7
  16. data/lib/twostroke/runtime/lib/console.rb +3 -2
  17. data/lib/twostroke/runtime/lib/error.rb +1 -1
  18. data/lib/twostroke/runtime/lib/etc.js +38 -0
  19. data/lib/twostroke/runtime/lib/etc.rb +29 -0
  20. data/lib/twostroke/runtime/lib/math.rb +31 -0
  21. data/lib/twostroke/runtime/lib/number.rb +7 -1
  22. data/lib/twostroke/runtime/lib/object.rb +1 -1
  23. data/lib/twostroke/runtime/lib/regexp.rb +1 -0
  24. data/lib/twostroke/runtime/lib/string.rb +62 -22
  25. data/lib/twostroke/runtime/scope.rb +23 -2
  26. data/lib/twostroke/runtime/types/array.rb +5 -0
  27. data/lib/twostroke/runtime/types/function.rb +5 -2
  28. data/lib/twostroke/runtime/types/object.rb +3 -4
  29. data/lib/twostroke/runtime/types/regexp.rb +45 -2
  30. data/lib/twostroke/runtime/types.rb +1 -1
  31. data/lib/twostroke/runtime/vm.rb +2 -2
  32. data/lib/twostroke/runtime/vm_frame.rb +47 -8
  33. data/lib/twostroke/tokens.rb +32 -16
  34. metadata +5 -5
  35. data/lib/twostroke/ast/delete.rb +0 -15
  36. data/lib/twostroke/ast/unsorted_binop.rb +0 -97
  37. data/lib/twostroke/runtime/lib/function.js +0 -0
@@ -21,13 +21,19 @@ Array.prototype.reverse = function() {
21
21
  return this;
22
22
  };
23
23
 
24
- Array.prototype.concat = function(other) {
24
+ Array.prototype.concat = function() {
25
25
  var x = [];
26
26
  Array.prototype.slice.call(this).forEach(function(el) {
27
27
  x.push(el);
28
28
  });
29
- Array.prototype.slice.call(other).forEach(function(el) {
30
- x.push(el);
29
+ Array.prototype.slice.call(arguments).forEach(function(obj) {
30
+ if(obj instanceof Array) {
31
+ obj.forEach(function(el) {
32
+ x.push(el);
33
+ });
34
+ } else {
35
+ x.push(obj);
36
+ }
31
37
  });
32
38
  return x;
33
39
  };
@@ -50,6 +50,20 @@ module Twostroke::Runtime
50
50
  Types::Array.new this.generic_items[begin_index.number.to_i...end_index.number.to_i]
51
51
  end
52
52
  }, nil, "slice", [])
53
+ # Array.prototype.splice
54
+ proto.proto_put "splice", Types::Function.new(->(scope, this, args) {
55
+ Lib.throw_type_error "Array.prototype.splice is not generic" unless this.is_a? Types::Array
56
+ idx = Types.to_uint32(args[0] || Types::Undefined.new)
57
+ count = args[1] && Types.to_uint32(args[1])
58
+ if count and count >= 0
59
+ retn = this.items[idx...(idx + count)]
60
+ this.items[idx...(idx + count)] = args.drop(2)
61
+ else
62
+ retn = this.items[idx..-1]
63
+ this.items[idx..-1] = args.drop(2)
64
+ end
65
+ Types::Array.new retn
66
+ }, nil, "splice", [])
53
67
  # Array.prototype.sort
54
68
  proto.proto_put "sort", Types::Function.new(->(scope, this, args) {
55
69
  Lib.throw_type_error "Array.prototype.sort is not generic" unless this.is_a? Types::Array
@@ -59,13 +73,7 @@ module Twostroke::Runtime
59
73
  this
60
74
  }, nil, "sort", [])
61
75
  # Array.prototype.length
62
- proto.define_own_property "length", get: ->(this) { Types::Number.new this.items.size }, set: ->(this,val) do
63
- Lib.throw_type_error "Array.prototype.length is not generic" unless this.is_a? Types::Array
64
- len = Types.to_number(val)
65
- Lib.throw_range_error "invalid array length" if len.nan? || len.number < 0 || (len.number % 1) != 0
66
- this.items = this.items[0...len.number.to_i]
67
- len
68
- end, writable: true
76
+ proto.define_own_property "length", get: ->(this) { Types::Number.new this.items.size }
69
77
  ary.proto_put "prototype", proto
70
78
  end
71
79
  end
@@ -1,12 +1,13 @@
1
1
  module Twostroke::Runtime
2
2
  Lib.register do |scope|
3
- log = Types::Function.new(->(scope, this, args) { puts args.map { |o| Types.to_string(o).string }.join(" ") }, nil, "log", ["string"])
3
+ log = Types::Function.new(->(scope, this, args) { print args.map { |o| Types.to_string(o).string }.join(" ") + "\n" }, nil, "log", ["string"])
4
4
 
5
5
  console = Types::Object.new
6
6
  ["log", "info", "warn", "error"].each do |m|
7
7
  console.proto_put m, log
8
8
  end
9
- console.proto_put "_gets", Types::Function.new(->(scope, this, args) { Types::String.new gets }, nil, "_gets", [])
9
+ console.proto_put "_gets", Types::Function.new(->(scope, this, args) { Types::String.new STDIN.gets }, nil, "_gets", [])
10
+ console.proto_put "_readAll", Types::Function.new(->(scope, this, args) { Types::String.new STDIN.read }, nil, "_readAll", [])
10
11
  console.proto_put "_print", Types::Function.new(->(scope, this, args) { print args.map { |o| Types.to_string(o).string }.join(" ") }, nil, "_print", ["string"])
11
12
  scope.set_var "console", console
12
13
  end
@@ -12,7 +12,7 @@ module Twostroke::Runtime
12
12
  }, nil, "toString", [])
13
13
  error.proto_put "prototype", error.prototype
14
14
 
15
- ["Eval", "Range", "Reference", "Syntax", "Type", "URI"].each do |e|
15
+ ["Eval", "Range", "Reference", "Syntax", "Type", "URI", "_Interrupt"].each do |e|
16
16
  obj = Types::Function.new(->(scope, this, args) {
17
17
  this.proto_put "name", Types::String.new("#{e}Error")
18
18
  this.proto_put "message", (args[0] || Types::Undefined.new)
@@ -0,0 +1,38 @@
1
+ JSON = {
2
+ stringify: function(obj) {
3
+ switch(typeof obj) {
4
+ case "string":
5
+ return '"' + obj.replace(/["\\]/g, function(x) { return "\\" + x; }).replace(/[\x00-\x1F]/g, function(x) {
6
+ var s = x.charCodeAt(0).toString(16);
7
+ while(s.length < 4) s = "0" + s;
8
+ return "\\u" + s;
9
+ }) + '"';
10
+ case "number":
11
+ case "boolean":
12
+ return obj.toString();
13
+ case "undefined":
14
+ return "null";
15
+ case "object":
16
+ if(obj === null) {
17
+ return "null";
18
+ } else if(obj instanceof Array) {
19
+ return "[" + obj.map(function(x) { return JSON.stringify(x); }).filter(function(o) { return o !== undefined; }).join(",") + "]";
20
+ } else {
21
+ var keys = [];
22
+ for(var k in obj) {
23
+ if(obj.hasOwnProperty(k)) {
24
+ keys.push(k);
25
+ }
26
+ }
27
+ return "{" + keys.map(function(k) {
28
+ var v = JSON.stringify(obj[k]);
29
+ if(v) {
30
+ return '"' + k + '":' + JSON.stringify(obj[k]);
31
+ }
32
+ }).filter(function(o) { return o !== undefined; }).join(",") + "}";
33
+ }
34
+ default:
35
+ return undefined;
36
+ }
37
+ }
38
+ };
@@ -0,0 +1,29 @@
1
+ module Twostroke::Runtime
2
+ Lib.register do |scope|
3
+ evaled = 0
4
+ eval = Types::Function.new(->(_scope, this, args) {
5
+ src = Types.to_string(args[0] || Types::Undefined.new).string + ";"
6
+
7
+ begin
8
+ parser = Twostroke::Parser.new Twostroke::Lexer.new src
9
+ parser.parse
10
+
11
+ evaled += 1
12
+ compiler = Twostroke::Compiler::TSASM.new parser.statements, "evaled_#{evaled}_"
13
+ compiler.compile
14
+ rescue Twostroke::SyntaxError => e
15
+ Lib.throw_syntax_error e.to_s
16
+ end
17
+
18
+ vm = scope.global_scope.vm
19
+ compiler.bytecode.each do |k,v|
20
+ vm.bytecode[k] = v
21
+ end
22
+
23
+ vm.bytecode[:"evaled_#{evaled}_main"][-2] = [:ret]
24
+ vm.execute :"evaled_#{evaled}_main", _scope, this
25
+ }, nil, "eval", [])
26
+ eval.inherits_caller_this = true
27
+ scope.set_var "eval", eval
28
+ end
29
+ end
@@ -6,6 +6,31 @@ module Twostroke::Runtime
6
6
  scope.set_var "Infinity", Types::Number.new(Float::INFINITY)
7
7
  scope.set_var "NaN", Types::Number.new(Float::NAN)
8
8
 
9
+ scope.set_var "isNaN", Types::Function.new(->(scope, this, args) {
10
+ Types::Boolean.new(args[0].is_a?(Types::Number) && args[0].nan?)
11
+ }, nil, "isNaN", [])
12
+
13
+ scope.set_var "parseInt", Types::Function.new(->(scope, this, args) {
14
+ str = Types.to_string(args[0] || Undefined.new).string.gsub(/\A\s+/,"")
15
+ unless args[1] and (radix = Types.to_uint32(args[1])) != 0
16
+ case str
17
+ when /\A0x/i; radix = 16
18
+ when /\A0/i; radix = 8
19
+ else; radix = 10
20
+ end
21
+ end
22
+ if radix < 2 or radix > 36
23
+ Types::Number.new(Float::NAN)
24
+ else
25
+ begin
26
+ Integer(str[0], radix) # ensure the first character can be converted
27
+ Types::Number.new str.to_i radix
28
+ rescue
29
+ Types::Number.new(Float::NAN)
30
+ end
31
+ end
32
+ }, nil, "parseInt", [])
33
+
9
34
  # one argument functions
10
35
  %w(sqrt sin cos tan).each do |method|
11
36
  obj.proto_put method, Types::Function.new(->(scope, this, args) {
@@ -13,6 +38,8 @@ module Twostroke::Runtime
13
38
  }, nil, method, [])
14
39
  end
15
40
 
41
+ obj.proto_put "PI", Types::Number.new(Math::PI)
42
+
16
43
  obj.proto_put "random", Types::Function.new(->(scope, this, args) {
17
44
  Types::Number.new rand
18
45
  }, nil, "random", [])
@@ -24,6 +51,10 @@ module Twostroke::Runtime
24
51
  obj.proto_put "ceil", Types::Function.new(->(scope, this, args) {
25
52
  Types::Number.new Types.to_number(args[0] || Undefined.new).number.ceil
26
53
  }, nil, "ceil", [])
54
+
55
+ obj.proto_put "abs", Types::Function.new(->(scope, this, args) {
56
+ Types::Number.new Types.to_number(args[0] || Undefined.new).number.abs
57
+ }, nil, "floor", [])
27
58
 
28
59
  obj.proto_put "max", Types::Function.new(->(scope, this, args) {
29
60
  Types::Number.new [-Float::INFINITY, *args.map { |a| Types.to_number(a).number }].max
@@ -6,7 +6,13 @@ module Twostroke::Runtime
6
6
  proto = Types::Object.new
7
7
  proto.proto_put "toString", Types::Function.new(->(scope, this, args) {
8
8
  if this.is_a?(Types::NumberObject)
9
- Types::String.new(this.number.to_s)
9
+ base = args[0] ? Types.to_uint32(args[0]) : 10
10
+ Lib.throw_range_error "toString() radix argument must be between 2 and 36" if base < 2 or base > 36
11
+ if this.number.is_a? Fixnum or this.number.is_a? Bignum
12
+ Types::String.new this.number.to_s base
13
+ else
14
+ Types::String.new this.number.to_s
15
+ end
10
16
  else
11
17
  Lib.throw_type_error "Number.prototype.toString is not generic"
12
18
  end
@@ -41,7 +41,7 @@ module Twostroke::Runtime
41
41
  prop = Types.to_string(args[0] || Types::Undefined.new).string
42
42
  if this.has_accessor(prop)
43
43
  Types::Boolean.new this.accessors[prop][:enumerable]
44
- elsif this.has_property
44
+ elsif this.has_property(prop)
45
45
  Types::Boolean.new true
46
46
  else
47
47
  Types::Boolean.new false
@@ -23,6 +23,7 @@ module Twostroke::Runtime
23
23
  Lib.throw_type_error "RegExp.prototype.test is not generic" unless this.is_a?(Types::RegExp)
24
24
  Types::Boolean.new((Types.to_string(args[0] || Undefined.new).string =~ this.regexp) != nil)
25
25
  }, nil, "test", [])
26
+ proto.proto_put "exec", Types::Function.new(Types::RegExp.method(:exec), nil, "exec", [])
26
27
  regexp.proto_put "prototype", proto
27
28
  end
28
29
  end
@@ -52,31 +52,71 @@ module Twostroke::Runtime
52
52
 
53
53
  Types::String.new retn
54
54
  }, nil, "replace", [])
55
- =begin
56
- find = args[0] || Types::Undefined.new
57
- find = Types.to_string(find).string unless find.is_a?(Types::RegExp)
58
- replace = args[1] || Types::Undefined.new
59
- replace = Types.to_string(replace).string unless replace.respond_to? :call
60
- Types::String.new(if find.is_a?(String)
61
- if replace.is_a?(String)
62
- s.sub find, replace
63
- else
64
- s.sub(find) { |m| Types.to_string(replace.call(scope, nil, [Types::String.new(m), Types::Number.new(s.index m), sobj])).string }
65
- end
55
+ # String.prototype.slice
56
+ proto.proto_put "slice", Types::Function.new(->(scope, this, args) {
57
+ sobj = Types.to_string(this)
58
+ s = sobj.string
59
+ if args[0].nil?
60
+ sobj
66
61
  else
67
- m = s.method(find.global ? :gsub : :sub)
68
- if replace.is_a?(String)
69
- m.(find.regexp, replace)
62
+ start = Types.to_int32 args[0]
63
+ if args[1]
64
+ fin = Types.to_int32 args[1]
65
+ Types::String.new s[start...fin]
70
66
  else
71
- offset = 0
72
- m.(find.regexp) do |m|
73
- idx = s.index m, offset
74
- offset = idx + m.size
75
- Types.to_string(replace.call(scope, nil, [Types::String.new(m), Types::Number.new(idx), sobj])).string
76
- end
67
+ Types::String.new s[start..-1]
77
68
  end
78
- end)
79
- =end
69
+ end
70
+ }, nil, "slice", [])
71
+ # String.prototype.indexOf
72
+ proto.proto_put "indexOf", Types::Function.new(->(scope, this, args) {
73
+ idx = args[1] ? Types.to_int32(args[1]) : 0
74
+ Types::Number.new(Types.to_string(this).string.index(Types.to_string(args[0] || Types::Undefined.new).string, idx) || -1)
75
+ }, nil, "indexOf", [])
76
+ # String.prototype.lastIndexOf
77
+ proto.proto_put "lastIndexOf", Types::Function.new(->(scope, this, args) {
78
+ idx = args[1] ? Types.to_int32(args[1]) : -1
79
+ Types::Number.new(Types.to_string(this).string.rindex(Types.to_string(args[0] || Types::Undefined.new).string, idx) || -1)
80
+ }, nil, "lastIndexOf", [])
81
+ # String.prototype.charAt
82
+ proto.proto_put "charAt", Types::Function.new(->(scope, this, args) {
83
+ idx = args[0] ? Types.to_int32(args[0]) : 0
84
+ str = Types.to_string(this).string
85
+ if idx < 0 or idx >= str.length
86
+ Types::String.new ""
87
+ else
88
+ Types::String.new str[idx]
89
+ end
90
+ }, nil, "charAt", [])
91
+ # String.prototype.charAt
92
+ proto.proto_put "charCodeAt", Types::Function.new(->(scope, this, args) {
93
+ idx = args[0] ? Types.to_int32(args[0]) : 0
94
+ str = Types.to_string(this).string
95
+ if idx < 0 or idx >= str.length
96
+ Types::Number.new Float::NAN
97
+ else
98
+ Types::Number.new str[idx].ord
99
+ end
100
+ }, nil, "charCodeAt", [])
101
+ # String.prototype.match
102
+ proto.proto_put "match", Types::Function.new(->(scope, this, args) {
103
+ re = args[0] || Types::Undefined.new
104
+ re = Types::RegExp.constructor_function.(nil, nil, re) unless re.is_a?(Types::RegExp)
105
+ unless re.global
106
+ # same as re.exec(str) in this case
107
+ Types::RegExp.exec(nil, re, [this])
108
+ else
109
+ Types::RegExp.all_matches(nil, re, [this])
110
+ end
111
+ }, nil, "match", [])
112
+ # String.prototype.toUpperCase
113
+ proto.proto_put "toUpperCase", Types::Function.new(->(scope, this, args) {
114
+ Types::String.new Types.to_string(this).string.upcase
115
+ }, nil, "toUpperCase", [])
116
+ # String.prototype.toUpperCase
117
+ proto.proto_put "toLowerCase", Types::Function.new(->(scope, this, args) {
118
+ Types::String.new Types.to_string(this).string.downcase
119
+ }, nil, "toLowerCase", [])
80
120
  obj.proto_put "prototype", proto
81
121
 
82
122
  obj.proto_put "fromCharCode", Types::Function.new(->(scope, this, args) {
@@ -31,6 +31,14 @@ module Twostroke::Runtime
31
31
  @locals[var] = Types::Undefined.new
32
32
  end
33
33
 
34
+ def delete(var)
35
+ if has_var var
36
+ @locals.delete var
37
+ else
38
+ parent.delete var
39
+ end
40
+ end
41
+
34
42
  def close
35
43
  Scope.new self
36
44
  end
@@ -59,11 +67,11 @@ module Twostroke::Runtime
59
67
  if object.has_property var.to_s
60
68
  object.put var.to_s, value
61
69
  else
62
- parent.set_var var.to_s, value
70
+ parent.set_var var, value
63
71
  end
64
72
  end
65
73
 
66
- def has_var
74
+ def has_var(var)
67
75
  object.has_property(var.to_s) || parent.has_var(var)
68
76
  end
69
77
 
@@ -71,6 +79,14 @@ module Twostroke::Runtime
71
79
  parent.declare var
72
80
  end
73
81
 
82
+ def delete(var)
83
+ if has_var var
84
+ object.delete var.to_s
85
+ else
86
+ parent.delete var
87
+ end
88
+ end
89
+
74
90
  def close
75
91
  Scope.new self
76
92
  end
@@ -103,6 +119,11 @@ module Twostroke::Runtime
103
119
  end
104
120
 
105
121
  def declare(var)
122
+ @root_object.put var.to_s, Types::Undefined.new
123
+ end
124
+
125
+ def delete(var)
126
+ @root_object.delete var.to_s
106
127
  end
107
128
 
108
129
  def close
@@ -19,6 +19,11 @@ module Twostroke::Runtime
19
19
  @prototype = Array.constructor_function.get("prototype")
20
20
  super()
21
21
  @items = items
22
+ define_own_property "length", get: ->(this) { Types::Number.new this.items.size }, set: ->(this,val) do
23
+ Lib.throw_type_error "Array.prototype.length is not generic" unless this.is_a? Types::Array
24
+ len = Types.to_uint32(val)
25
+ this.items = this.items[0...len]
26
+ end, writable: true, enumerable: false
22
27
  end
23
28
 
24
29
  def length
@@ -33,6 +33,7 @@ module Twostroke::Runtime::Types
33
33
  end
34
34
 
35
35
  attr_reader :arguments, :name, :source, :function
36
+ attr_accessor :inherits_caller_this
36
37
  def initialize(function, source, name, arguments)
37
38
  @function = function
38
39
  @source = source
@@ -44,11 +45,13 @@ module Twostroke::Runtime::Types
44
45
  @_class = nil unless defined?(@@constructor_function)
45
46
  super()
46
47
  @prototype = nil
47
- proto_put "prototype", Object.new
48
+ proto = Object.new
49
+ proto.construct _class: self
50
+ put "prototype", proto
48
51
  end
49
52
 
50
53
  def prototype
51
- @prototype ||= Function.constructor_function.get("prototype")
54
+ @prototype ||= Function.constructor_function.get("prototype") if Function.constructor_function
52
55
  end
53
56
 
54
57
  def has_instance(obj)
@@ -2,7 +2,6 @@ module Twostroke::Runtime::Types
2
2
  class Object < Value
3
3
  attr_accessor :_class, :prototype
4
4
  attr_reader :accessors, :properties, :extensible, :data
5
- private :accessors, :properties
6
5
 
7
6
  def initialize
8
7
  @extensible = true
@@ -49,7 +48,7 @@ module Twostroke::Runtime::Types
49
48
  instance_variable_set "@#{k}", v
50
49
  end
51
50
  end
52
- yield
51
+ yield if block_given?
53
52
  @constructing = false
54
53
  end
55
54
 
@@ -90,8 +89,8 @@ module Twostroke::Runtime::Types
90
89
  accessors[prop][:set].(this, value) if accessors[prop][:set] && accessors[prop][:writable]
91
90
  elsif properties.has_key? prop
92
91
  properties[prop] = value
93
- #elsif prototype && prototype.is_a?(Object) && prototype.has_accessor(prop)
94
- # prototype.put prop, value, this
92
+ # elsif prototype && prototype.is_a?(Object) && prototype.has_accessor(prop)
93
+ # prototype.put prop, value, this
95
94
  else
96
95
  properties[prop] = value
97
96
  end
@@ -3,7 +3,7 @@ module Twostroke::Runtime::Types
3
3
  def self.constructor_function
4
4
  @@constructor_function ||=
5
5
  Function.new(->(scope, this, args) {
6
- RegExp.new Twostroke::Runtime::Types.to_string(args[0] || Undefined.new).string, args[1] && Twostroke::Runtime::Types.to_string(args[1]).string
6
+ RegExp.new((args[0] && !args[0].is_a?(Undefined)) ? Twostroke::Runtime::Types.to_string(args[0]).string : "", args[1] && Twostroke::Runtime::Types.to_string(args[1]).string)
7
7
  }, nil, "RegExp", [])
8
8
  end
9
9
 
@@ -18,7 +18,7 @@ module Twostroke::Runtime::Types
18
18
  else; 0
19
19
  end
20
20
  end
21
- @regexp = Regexp.new regexp_source, opts
21
+ @regexp = Regexp.new RegExp.to_ruby_regexp(regexp_source), opts
22
22
  @global = options.include? "g"
23
23
  @prototype = RegExp.constructor_function.get("prototype")
24
24
  super()
@@ -27,5 +27,48 @@ module Twostroke::Runtime::Types
27
27
  def primitive_value
28
28
  String.new(regexp.inspect + (@global ? "g" : ""))
29
29
  end
30
+
31
+ def self.to_ruby_regexp(src)
32
+ src.
33
+
34
+ # javascript's ^$ match the start and end of the entire string
35
+ # ruby's ^$ are line-based, so convert to \A and \z
36
+ gsub(/([^\[]|\A)\^/,"\\1\\A").gsub("$","\\z").
37
+
38
+ # javascript supports \cA through \cZ for control characters
39
+ gsub(/\\c[a-z]/i) { |m| (m.last.downcase.ord - 'a'.ord).chr }
40
+ end
41
+
42
+ def self.exec(scope, this, args)
43
+ re = this.is_a?(RegExp) ? this : constructor_function.(nil, nil, this)
44
+ str = Twostroke::Runtime::Types.to_string(args[0] || Twostroke::Runtime::Types::Undefined.new).string
45
+ if md = re.regexp.match(str)
46
+ result = Twostroke::Runtime::Types::Array.new md.to_a.map { |s| s ? Twostroke::Runtime::Types::String.new(s) : Twostroke::Runtime::Types::Undefined.new }
47
+ result.put "index", Twostroke::Runtime::Types::Number.new(md.offset(0).first)
48
+ result.put "input", Twostroke::Runtime::Types::String.new(str)
49
+ result
50
+ else
51
+ Twostroke::Runtime::Types::Null.new
52
+ end
53
+ end
54
+
55
+ def self.all_matches(scope, this, args)
56
+ re = this.is_a?(RegExp) ? this : constructor_function.(nil, nil, this)
57
+ str = Twostroke::Runtime::Types.to_string(args[0] || Twostroke::Runtime::Types::Undefined.new).string
58
+ arr = []
59
+ idx = 0
60
+ while md = re.regexp.match(str, idx)
61
+ arr << Twostroke::Runtime::Types::String.new(md[0])
62
+ idx = md.offset(0).last
63
+ end
64
+ if arr.any?
65
+ result = Twostroke::Runtime::Types::Array.new arr
66
+ result.put "index", Twostroke::Runtime::Types::Number.new(re.regexp.match(str).offset(0).first)
67
+ result.put "input", Twostroke::Runtime::Types::String.new(str)
68
+ result
69
+ else
70
+ Twostroke::Runtime::Types::Null.new
71
+ end
72
+ end
30
73
  end
31
74
  end
@@ -44,7 +44,7 @@ module Twostroke::Runtime::Types
44
44
  0
45
45
  else
46
46
  int32 = num.number.to_i & 0xffff_ffff
47
- int32 -= 2 ** 31 if int32 >= 2 ** 31
47
+ int32 -= 2 ** 32 if int32 >= 2 ** 31
48
48
  int32
49
49
  end
50
50
  end
@@ -9,8 +9,8 @@ module Twostroke::Runtime
9
9
  @lib = {}
10
10
  end
11
11
 
12
- def execute(section = :main, scope = nil)
13
- Frame.new(self, section).execute scope
12
+ def execute(section = :main, scope = nil, this = nil)
13
+ Frame.new(self, section).execute scope, this
14
14
  end
15
15
 
16
16
  def throw_error(type, message)