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.
- data/lib/twostroke/ast/case.rb +1 -1
- data/lib/twostroke/ast/function.rb +2 -2
- data/lib/twostroke/ast/label.rb +20 -0
- data/lib/twostroke/ast/switch.rb +1 -0
- data/lib/twostroke/ast/try.rb +3 -3
- data/lib/twostroke/ast/unary_operators.rb +1 -1
- data/lib/twostroke/ast.rb +1 -0
- data/lib/twostroke/compiler/javascript.rb +20 -2
- data/lib/twostroke/compiler/tsasm.rb +89 -35
- data/lib/twostroke/compiler.rb +1 -1
- data/lib/twostroke/error.rb +3 -0
- data/lib/twostroke/lexer.rb +3 -2
- data/lib/twostroke/parser.rb +309 -227
- data/lib/twostroke/runtime/lib/array.js +9 -3
- data/lib/twostroke/runtime/lib/array.rb +15 -7
- data/lib/twostroke/runtime/lib/console.rb +3 -2
- data/lib/twostroke/runtime/lib/error.rb +1 -1
- data/lib/twostroke/runtime/lib/etc.js +38 -0
- data/lib/twostroke/runtime/lib/etc.rb +29 -0
- data/lib/twostroke/runtime/lib/math.rb +31 -0
- data/lib/twostroke/runtime/lib/number.rb +7 -1
- data/lib/twostroke/runtime/lib/object.rb +1 -1
- data/lib/twostroke/runtime/lib/regexp.rb +1 -0
- data/lib/twostroke/runtime/lib/string.rb +62 -22
- data/lib/twostroke/runtime/scope.rb +23 -2
- data/lib/twostroke/runtime/types/array.rb +5 -0
- data/lib/twostroke/runtime/types/function.rb +5 -2
- data/lib/twostroke/runtime/types/object.rb +3 -4
- data/lib/twostroke/runtime/types/regexp.rb +45 -2
- data/lib/twostroke/runtime/types.rb +1 -1
- data/lib/twostroke/runtime/vm.rb +2 -2
- data/lib/twostroke/runtime/vm_frame.rb +47 -8
- data/lib/twostroke/tokens.rb +32 -16
- metadata +5 -5
- data/lib/twostroke/ast/delete.rb +0 -15
- data/lib/twostroke/ast/unsorted_binop.rb +0 -97
- data/lib/twostroke/runtime/lib/function.js +0 -0
| @@ -18,12 +18,13 @@ module Twostroke::Runtime | |
| 18 18 | 
             
                end
         | 
| 19 19 |  | 
| 20 20 | 
             
                def execute(scope, this = nil, args = [])
         | 
| 21 | 
            -
                  @scope = scope ||  | 
| 21 | 
            +
                  @scope = scope || vm.global_scope
         | 
| 22 22 | 
             
                  @stack = []
         | 
| 23 23 | 
             
                  @sp_stack = []
         | 
| 24 24 | 
             
                  @catch_stack = []
         | 
| 25 25 | 
             
                  @finally_stack = []
         | 
| 26 26 | 
             
                  @enum_stack = []
         | 
| 27 | 
            +
                  @temp_slot = nil
         | 
| 27 28 | 
             
                  @ip = 0
         | 
| 28 29 | 
             
                  @return = false
         | 
| 29 30 | 
             
                  @this = this || @scope.global_scope.root_object
         | 
| @@ -35,13 +36,18 @@ module Twostroke::Runtime | |
| 35 36 | 
             
                  end
         | 
| 36 37 |  | 
| 37 38 | 
             
                  until @return
         | 
| 38 | 
            -
                    ins, arg =  | 
| 39 | 
            +
                    ins, arg = insns[ip]
         | 
| 39 40 | 
             
                    st = @stack.size
         | 
| 40 41 | 
             
                    @ip += 1
         | 
| 41 42 | 
             
                    if respond_to? ins
         | 
| 42 43 | 
             
                      if @exception = catch(:exception) { public_send ins, arg; nil }
         | 
| 43 | 
            -
                         | 
| 44 | 
            -
                        @ | 
| 44 | 
            +
            #            puts "--> #{Types.to_string(exception).string}  #{@name || "(anonymous function)"}:#{@line}  <#{@section}+#{@ip}>"
         | 
| 45 | 
            +
                        throw :exception, @exception if catch_stack.empty? && finally_stack.empty?
         | 
| 46 | 
            +
                        if catch_stack.any?
         | 
| 47 | 
            +
                          @ip = catch_stack.last
         | 
| 48 | 
            +
                        else
         | 
| 49 | 
            +
                          @ip = finally_stack.last
         | 
| 50 | 
            +
                        end
         | 
| 45 51 | 
             
                      end
         | 
| 46 52 | 
             
                    else
         | 
| 47 53 | 
             
                      error! "unknown instruction #{ins}"
         | 
| @@ -51,7 +57,12 @@ module Twostroke::Runtime | |
| 51 57 | 
             
                  stack.last
         | 
| 52 58 | 
             
                end
         | 
| 53 59 |  | 
| 60 | 
            +
                define_method ".line" do |arg|
         | 
| 61 | 
            +
                  @line = arg
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
                
         | 
| 54 64 | 
             
                define_method ".name" do |arg|
         | 
| 65 | 
            +
                  @name = arg
         | 
| 55 66 | 
             
                  scope.declare arg.intern
         | 
| 56 67 | 
             
                  scope.set_var arg.intern, @callee
         | 
| 57 68 | 
             
                end
         | 
| @@ -68,6 +79,7 @@ module Twostroke::Runtime | |
| 68 79 | 
             
                define_method ".catch" do |arg|
         | 
| 69 80 | 
             
                  scope.declare arg.intern
         | 
| 70 81 | 
             
                  scope.set_var arg.intern, @exception
         | 
| 82 | 
            +
                  @exception = nil
         | 
| 71 83 | 
             
                end
         | 
| 72 84 |  | 
| 73 85 | 
             
                ## instructions
         | 
| @@ -91,7 +103,7 @@ module Twostroke::Runtime | |
| 91 103 | 
             
                  arg.times { args.unshift @stack.pop }
         | 
| 92 104 | 
             
                  fun = stack.pop
         | 
| 93 105 | 
             
                  Lib.throw_type_error "called non callable" unless fun.respond_to?(:call)
         | 
| 94 | 
            -
                  stack.push fun.call(scope, scope.global_scope.root_object, args)
         | 
| 106 | 
            +
                  stack.push fun.call(scope, fun.inherits_caller_this ? @this : scope.global_scope.root_object, args)
         | 
| 95 107 | 
             
                end
         | 
| 96 108 |  | 
| 97 109 | 
             
                def thiscall(arg)
         | 
| @@ -99,7 +111,8 @@ module Twostroke::Runtime | |
| 99 111 | 
             
                  arg.times { args.unshift stack.pop }
         | 
| 100 112 | 
             
                  fun = stack.pop
         | 
| 101 113 | 
             
                  Lib.throw_type_error "called non callable" unless fun.respond_to?(:call)
         | 
| 102 | 
            -
                   | 
| 114 | 
            +
                  this_arg = Types.to_object stack.pop
         | 
| 115 | 
            +
                  stack.push fun.call(scope, fun.inherits_caller_this ? @this : this_arg, args)
         | 
| 103 116 | 
             
                end
         | 
| 104 117 |  | 
| 105 118 | 
             
                def newcall(arg)
         | 
| @@ -123,16 +136,33 @@ module Twostroke::Runtime | |
| 123 136 | 
             
                  stack.push *stack[-n..-1]
         | 
| 124 137 | 
             
                end
         | 
| 125 138 |  | 
| 139 | 
            +
                def tst(arg)
         | 
| 140 | 
            +
                  @temp_slot = stack.pop
         | 
| 141 | 
            +
                end
         | 
| 142 | 
            +
                
         | 
| 143 | 
            +
                def tld(arg)
         | 
| 144 | 
            +
                  stack.push @temp_slot
         | 
| 145 | 
            +
                end
         | 
| 146 | 
            +
                
         | 
| 126 147 | 
             
                def member(arg)
         | 
| 127 148 | 
             
                  stack.push Types.to_object(stack.pop).get(arg.to_s)
         | 
| 128 149 | 
             
                end
         | 
| 129 150 |  | 
| 130 151 | 
             
                def deleteg(arg)
         | 
| 131 | 
            -
                  scope. | 
| 152 | 
            +
                  scope.delete arg
         | 
| 153 | 
            +
                  stack.push Types::Boolean.true
         | 
| 132 154 | 
             
                end
         | 
| 133 155 |  | 
| 134 156 | 
             
                def delete(arg)
         | 
| 135 157 | 
             
                  Types.to_object(stack.pop).delete arg.to_s
         | 
| 158 | 
            +
                  stack.push Types::Boolean.true
         | 
| 159 | 
            +
                end
         | 
| 160 | 
            +
                
         | 
| 161 | 
            +
                def deleteindex(arg)
         | 
| 162 | 
            +
                  obj = Types.to_object stack.pop
         | 
| 163 | 
            +
                  idx = Types.to_string stack.pop
         | 
| 164 | 
            +
                  obj.delete idx.string
         | 
| 165 | 
            +
                  stack.push Types::Boolean.true
         | 
| 136 166 | 
             
                end
         | 
| 137 167 |  | 
| 138 168 | 
             
                def in(arg)
         | 
| @@ -169,7 +199,7 @@ module Twostroke::Runtime | |
| 169 199 |  | 
| 170 200 | 
             
                def setprop(arg)
         | 
| 171 201 | 
             
                  val = stack.pop
         | 
| 172 | 
            -
                  obj = stack.pop
         | 
| 202 | 
            +
                  obj = Types.to_object(stack.pop)
         | 
| 173 203 | 
             
                  obj.put arg.to_s, val
         | 
| 174 204 | 
             
                  stack.push val
         | 
| 175 205 | 
             
                end
         | 
| @@ -338,6 +368,11 @@ module Twostroke::Runtime | |
| 338 368 | 
             
                  stack.push Types::Number.new(left ^ right)
         | 
| 339 369 | 
             
                end
         | 
| 340 370 |  | 
| 371 | 
            +
                def bnot(arg)
         | 
| 372 | 
            +
                  val = Types.to_int32 stack.pop
         | 
| 373 | 
            +
                  stack.push Types::Number.new ~val
         | 
| 374 | 
            +
                end
         | 
| 375 | 
            +
                
         | 
| 341 376 | 
             
                def setindex(arg)
         | 
| 342 377 | 
             
                  val = stack.pop
         | 
| 343 378 | 
             
                  index = Types.to_string(stack.pop).string
         | 
| @@ -436,6 +471,10 @@ module Twostroke::Runtime | |
| 436 471 | 
             
                  finally_stack.pop
         | 
| 437 472 | 
             
                end
         | 
| 438 473 |  | 
| 474 | 
            +
                def endfinally(arg)
         | 
| 475 | 
            +
                  throw :exception, @exception if @exception
         | 
| 476 | 
            +
                end
         | 
| 477 | 
            +
                
         | 
| 439 478 | 
             
                def this(arg)
         | 
| 440 479 | 
             
                  stack.push @this
         | 
| 441 480 | 
             
                end
         | 
    
        data/lib/twostroke/tokens.rb
    CHANGED
    
    | @@ -7,9 +7,10 @@ module Twostroke | |
| 7 7 | 
             
                TOKENS = [
         | 
| 8 8 |  | 
| 9 9 | 
             
                  [ :MULTI_COMMENT, %r{/\*.*?\*/} ],
         | 
| 10 | 
            -
                  [ :SINGLE_COMMENT,  | 
| 10 | 
            +
                  [ :SINGLE_COMMENT, /\/\/.*?($|\r|\u2029|\u2028)/ ],
         | 
| 11 11 |  | 
| 12 | 
            -
                  [ : | 
| 12 | 
            +
                  [ :LINE_TERMINATOR, /[\n\r\u2028\u2029]/ ],
         | 
| 13 | 
            +
                  [ :WHITESPACE, /[[:space:]]+/ ],
         | 
| 13 14 | 
             
                  [ :NUMBER, /((?<oct>0[0-7]+)|(?<hex>0x[A-Fa-f0-9]+)|(?<to_f>(\d+(\.?\d*([eE][+-]?\d+)?)?|\.\d+([eE][+-]?\d+)?)))/, ->m do
         | 
| 14 15 | 
             
                    method, number = m.names.zip(m.captures).select { |k,v| v }.first
         | 
| 15 16 | 
             
                    n = number.send method
         | 
| @@ -25,21 +26,24 @@ module Twostroke | |
| 25 26 | 
             
                  end,
         | 
| 26 27 | 
             
                  [ :BAREWORD, /[a-zA-Z_\$][\$a-zA-Z_0-9]*/, ->m { m[0] } ],
         | 
| 27 28 |  | 
| 28 | 
            -
                  [ :STRING, /(["'])((\\\n|\\.|[^\1])*?[^\1\\]?)\1/, ->m do
         | 
| 29 | 
            -
                    m[2]
         | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
                      case m[1]
         | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 29 | 
            +
                  [ :STRING, /(["'])((\\\n|\\.|[^\n\r\u2028\u2029\1])*?[^\1\\]?)\1/, ->m do
         | 
| 30 | 
            +
                    m[2].gsub(/\\(([0-6]{1,3})|u([a-f0-9]{4})|x([a-f0-9]{2})|\n|.)/i) do |m|
         | 
| 31 | 
            +
                      case m
         | 
| 32 | 
            +
                      when /\\([0-6]{1,3})/; m[1..-1].to_i(7).chr "utf-8" 
         | 
| 33 | 
            +
                      when /\\u([a-f0-9]{4})/i; m[2..-1].to_i(16).chr "utf-8"
         | 
| 34 | 
            +
                      when /\\x([a-f0-9]{2})/i; m[2..-1].to_i(16).chr "utf-8"
         | 
| 35 | 
            +
                      else case m[1]
         | 
| 36 | 
            +
                             when "b"; "\b"
         | 
| 37 | 
            +
                             when "n"; "\n"
         | 
| 38 | 
            +
                             when "f"; "\f"
         | 
| 39 | 
            +
                             when "v"; "\v"
         | 
| 40 | 
            +
                             when "r"; "\r"
         | 
| 41 | 
            +
                             when "t"; "\t"
         | 
| 42 | 
            +
                             when "\n"; ""
         | 
| 43 | 
            +
                             else; m[1]
         | 
| 44 | 
            +
                           end
         | 
| 41 45 | 
             
                      end
         | 
| 42 | 
            -
                     | 
| 46 | 
            +
                    end
         | 
| 43 47 | 
             
                  end ],
         | 
| 44 48 |  | 
| 45 49 | 
             
                  [ :REGEXP, %r{/(?<src>(\\.|[^\1])*?[^\1\\]?)/(?<opts>[gim]+)?}, ->m { [m[:src], m[:opts]] } ],
         | 
| @@ -53,6 +57,18 @@ module Twostroke | |
| 53 57 |  | 
| 54 58 | 
             
                  [ :MEMBER_ACCESS, /\./ ],
         | 
| 55 59 |  | 
| 60 | 
            +
                  [ :ADD_EQUALS, /\+=/ ],
         | 
| 61 | 
            +
                  [ :MINUS_EQUALS, /-=/ ],
         | 
| 62 | 
            +
                  [ :TIMES_EQUALS, /\*=/ ], # textmate barfs it's syntax highlighting on this one lol
         | 
| 63 | 
            +
                  [ :DIVIDE_EQUALS, /\/=/ ],
         | 
| 64 | 
            +
                  [ :MOD_EQUALS, /%=/ ],
         | 
| 65 | 
            +
                  [ :LEFT_SHIFT_EQUALS, /<<=/ ],
         | 
| 66 | 
            +
                  [ :RIGHT_TRIPLE_SHIFT_EQUALS, />>>=/ ],
         | 
| 67 | 
            +
                  [ :RIGHT_SHIFT_EQUALS, />>=/ ],
         | 
| 68 | 
            +
                  [ :BITWISE_AND_EQUALS, /&=/ ],
         | 
| 69 | 
            +
                  [ :BITWISE_XOR_EQUALS, /\^=/ ],
         | 
| 70 | 
            +
                  [ :BITWISE_OR_EQUALS, /\|=/ ],
         | 
| 71 | 
            +
             | 
| 56 72 | 
             
                  [ :INCREMENT, /\+\+/ ],
         | 
| 57 73 | 
             
                  [ :DECREMENT, /--/ ],
         | 
| 58 74 | 
             
                  [ :PLUS, /\+/ ],
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: twostroke
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.2.0
         | 
| 5 5 | 
             
              prerelease: 
         | 
| 6 6 | 
             
            platform: ruby
         | 
| 7 7 | 
             
            authors:
         | 
| @@ -9,7 +9,7 @@ authors: | |
| 9 9 | 
             
            autorequire: 
         | 
| 10 10 | 
             
            bindir: bin
         | 
| 11 11 | 
             
            cert_chain: []
         | 
| 12 | 
            -
            date:  | 
| 12 | 
            +
            date: 2012-01-10 00:00:00.000000000 Z
         | 
| 13 13 | 
             
            dependencies: []
         | 
| 14 14 | 
             
            description: An implementation of Javascript written in pure Ruby. Twostroke contains
         | 
| 15 15 | 
             
              a parser, a bytecode compiler, a VM, and a minimal implementation of the Javascript
         | 
| @@ -29,7 +29,6 @@ files: | |
| 29 29 | 
             
            - lib/twostroke/ast/case.rb
         | 
| 30 30 | 
             
            - lib/twostroke/ast/continue.rb
         | 
| 31 31 | 
             
            - lib/twostroke/ast/declaration.rb
         | 
| 32 | 
            -
            - lib/twostroke/ast/delete.rb
         | 
| 33 32 | 
             
            - lib/twostroke/ast/do_while.rb
         | 
| 34 33 | 
             
            - lib/twostroke/ast/false.rb
         | 
| 35 34 | 
             
            - lib/twostroke/ast/for_in.rb
         | 
| @@ -37,6 +36,7 @@ files: | |
| 37 36 | 
             
            - lib/twostroke/ast/function.rb
         | 
| 38 37 | 
             
            - lib/twostroke/ast/if.rb
         | 
| 39 38 | 
             
            - lib/twostroke/ast/index.rb
         | 
| 39 | 
            +
            - lib/twostroke/ast/label.rb
         | 
| 40 40 | 
             
            - lib/twostroke/ast/member_access.rb
         | 
| 41 41 | 
             
            - lib/twostroke/ast/multi_expression.rb
         | 
| 42 42 | 
             
            - lib/twostroke/ast/new.rb
         | 
| @@ -53,7 +53,6 @@ files: | |
| 53 53 | 
             
            - lib/twostroke/ast/true.rb
         | 
| 54 54 | 
             
            - lib/twostroke/ast/try.rb
         | 
| 55 55 | 
             
            - lib/twostroke/ast/unary_operators.rb
         | 
| 56 | 
            -
            - lib/twostroke/ast/unsorted_binop.rb
         | 
| 57 56 | 
             
            - lib/twostroke/ast/variable.rb
         | 
| 58 57 | 
             
            - lib/twostroke/ast/while.rb
         | 
| 59 58 | 
             
            - lib/twostroke/ast/with.rb
         | 
| @@ -70,7 +69,8 @@ files: | |
| 70 69 | 
             
            - lib/twostroke/runtime/lib/console.rb
         | 
| 71 70 | 
             
            - lib/twostroke/runtime/lib/date.rb
         | 
| 72 71 | 
             
            - lib/twostroke/runtime/lib/error.rb
         | 
| 73 | 
            -
            - lib/twostroke/runtime/lib/ | 
| 72 | 
            +
            - lib/twostroke/runtime/lib/etc.js
         | 
| 73 | 
            +
            - lib/twostroke/runtime/lib/etc.rb
         | 
| 74 74 | 
             
            - lib/twostroke/runtime/lib/function.rb
         | 
| 75 75 | 
             
            - lib/twostroke/runtime/lib/math.rb
         | 
| 76 76 | 
             
            - lib/twostroke/runtime/lib/number.rb
         | 
    
        data/lib/twostroke/ast/delete.rb
    DELETED
    
    
| @@ -1,97 +0,0 @@ | |
| 1 | 
            -
            module Twostroke::AST
         | 
| 2 | 
            -
              class UnsortedBinop < Base
         | 
| 3 | 
            -
                attr_accessor :left, :op, :right
         | 
| 4 | 
            -
                
         | 
| 5 | 
            -
                def self.operator_class
         | 
| 6 | 
            -
                  @@classes ||= {
         | 
| 7 | 
            -
                    :ASTERISK           => Multiplication,
         | 
| 8 | 
            -
                    :SLASH              => Division,
         | 
| 9 | 
            -
                    :MOD                => Modulus,
         | 
| 10 | 
            -
                    :PLUS               => Addition,
         | 
| 11 | 
            -
                    :MINUS              => Subtraction,
         | 
| 12 | 
            -
                    :LEFT_SHIFT         => LeftShift,
         | 
| 13 | 
            -
                    :RIGHT_SHIFT        => RightArithmeticShift,
         | 
| 14 | 
            -
                    :RIGHT_TRIPLE_SHIFT => RightLogicalShift,
         | 
| 15 | 
            -
                    :LT                 => LessThan,
         | 
| 16 | 
            -
                    :LTE                => LessThanEqual,
         | 
| 17 | 
            -
                    :GT                 => GreaterThan,
         | 
| 18 | 
            -
                    :GTE                => GreaterThanEqual,
         | 
| 19 | 
            -
                    :IN                 => In,
         | 
| 20 | 
            -
                    :INSTANCEOF         => InstanceOf,
         | 
| 21 | 
            -
                    :DOUBLE_EQUALS      => Equality,
         | 
| 22 | 
            -
                    :NOT_EQUALS         => Inequality,
         | 
| 23 | 
            -
                    :TRIPLE_EQUALS      => StrictEquality,
         | 
| 24 | 
            -
                    :NOT_DOUBLE_EQUALS  => StrictInequality,
         | 
| 25 | 
            -
                    :AMPERSAND          => BitwiseAnd,
         | 
| 26 | 
            -
                    :CARET              => BitwiseXor,
         | 
| 27 | 
            -
                    :PIPE               => BitwiseOr,
         | 
| 28 | 
            -
                    :AND                => And,
         | 
| 29 | 
            -
                    :OR                 => Or
         | 
| 30 | 
            -
                  }
         | 
| 31 | 
            -
                end
         | 
| 32 | 
            -
                
         | 
| 33 | 
            -
                def self.operator_precedence
         | 
| 34 | 
            -
                  @precedences ||= {
         | 
| 35 | 
            -
                    :ASTERISK           => 5,
         | 
| 36 | 
            -
                    :SLASH              => 5,
         | 
| 37 | 
            -
                    :MOD                => 5,
         | 
| 38 | 
            -
                    :PLUS               => 6,
         | 
| 39 | 
            -
                    :MINUS              => 6,
         | 
| 40 | 
            -
                    :LEFT_SHIFT         => 7,
         | 
| 41 | 
            -
                    :RIGHT_SHIFT        => 7,
         | 
| 42 | 
            -
                    :RIGHT_TRIPLE_SHIFT => 7,
         | 
| 43 | 
            -
                    :LT                 => 8,
         | 
| 44 | 
            -
                    :LTE                => 8,
         | 
| 45 | 
            -
                    :GT                 => 8,
         | 
| 46 | 
            -
                    :GTE                => 8,
         | 
| 47 | 
            -
                    :IN                 => 8,
         | 
| 48 | 
            -
                    :INSTANCEOF         => 8,
         | 
| 49 | 
            -
                    :DOUBLE_EQUALS      => 9,
         | 
| 50 | 
            -
                    :NOT_EQUALS         => 9,
         | 
| 51 | 
            -
                    :TRIPLE_EQUALS      => 9,
         | 
| 52 | 
            -
                    :NOT_DOUBLE_EQUALS  => 9,
         | 
| 53 | 
            -
                    :AMPERSAND          => 10,
         | 
| 54 | 
            -
                    :CARET              => 11,
         | 
| 55 | 
            -
                    :PIPE               => 12,
         | 
| 56 | 
            -
                    :AND                => 13,
         | 
| 57 | 
            -
                    :OR                 => 14
         | 
| 58 | 
            -
                  }
         | 
| 59 | 
            -
                end
         | 
| 60 | 
            -
                
         | 
| 61 | 
            -
                def collapse(called_by_binop = false)
         | 
| 62 | 
            -
                  left_collapsed = left.is_a?(UnsortedBinop) ? left.collapse(true) : left.collapse
         | 
| 63 | 
            -
                  right_collapsed = right.is_a?(UnsortedBinop) ? right.collapse(true) : right.collapse
         | 
| 64 | 
            -
                  input = [*left_collapsed, op, *right_collapsed]
         | 
| 65 | 
            -
                  
         | 
| 66 | 
            -
                  unless called_by_binop
         | 
| 67 | 
            -
                    stack = []
         | 
| 68 | 
            -
                    output = []
         | 
| 69 | 
            -
                    input.each do |token|
         | 
| 70 | 
            -
                      if token.is_a? Symbol
         | 
| 71 | 
            -
                        while stack.size > 0 && UnsortedBinop.operator_precedence[stack.last] <= UnsortedBinop.operator_precedence[token]
         | 
| 72 | 
            -
                          output.push stack.pop
         | 
| 73 | 
            -
                        end
         | 
| 74 | 
            -
                        stack.push token
         | 
| 75 | 
            -
                      else
         | 
| 76 | 
            -
                        output.push token
         | 
| 77 | 
            -
                      end
         | 
| 78 | 
            -
                    end
         | 
| 79 | 
            -
                    output.push stack.pop until stack.empty?
         | 
| 80 | 
            -
                    
         | 
| 81 | 
            -
                    output.each do |token|
         | 
| 82 | 
            -
                      if token.is_a? Symbol
         | 
| 83 | 
            -
                        r = stack.pop
         | 
| 84 | 
            -
                        l = stack.pop
         | 
| 85 | 
            -
                        stack.push UnsortedBinop.operator_class[token].new(left: l, right: r)
         | 
| 86 | 
            -
                      else
         | 
| 87 | 
            -
                        stack.push token
         | 
| 88 | 
            -
                      end
         | 
| 89 | 
            -
                    end
         | 
| 90 | 
            -
                    
         | 
| 91 | 
            -
                    stack.last
         | 
| 92 | 
            -
                  else
         | 
| 93 | 
            -
                    input
         | 
| 94 | 
            -
                  end
         | 
| 95 | 
            -
                end
         | 
| 96 | 
            -
              end
         | 
| 97 | 
            -
            end
         | 
| 
            File without changes
         |