lignite 0.5.0 → 0.6.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -0
- data/NEWS.md +10 -0
- data/VERSION +1 -1
- data/examples/bobbee.rb +75 -29
- data/examples/gyro-sensor.rb +19 -0
- data/lib/lignite.rb +12 -0
- data/lib/lignite/assembler.rb +48 -5
- data/lib/lignite/body_compiler.rb +35 -37
- data/lib/lignite/condition.rb +116 -0
- data/lib/lignite/connection.rb +4 -0
- data/lib/lignite/ev3_ops.rb +104 -12
- data/lib/lignite/ev3_tool.rb +9 -2
- data/lib/lignite/jump_offset.rb +18 -0
- data/lib/lignite/motors.rb +17 -8
- data/lib/lignite/op_compiler.rb +52 -26
- data/lib/lignite/parameter_declarer.rb +15 -15
- data/lib/lignite/variables.rb +27 -15
- data/lignite.gemspec +3 -0
- data/spec/data/HelloWorld.rb +2 -2
- data/spec/data/Performance.rb +1 -1
- data/spec/data/Performance.rbf +0 -0
- data/spec/data/ev3tool_download.yml +4 -2
- data/spec/data/everstorm.rbf +0 -0
- data/spec/ev3_tool_spec.rb +4 -1
- data/tools/ops_from_yml +9 -1
- metadata +5 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 3fef446a97c670acf0bfc1944d3287d80e40799a
         | 
| 4 | 
            +
              data.tar.gz: 034b4f841c015e98af6b1776b1705a3f20905936
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: fd4a8eaaf713aef7ca9081a4755ff953b24aaba900c4c22b6547d90392390c7563125fc874f926cc6179aecc2428e8209f17df5799285fefda7b500c35d33c6a
         | 
| 7 | 
            +
              data.tar.gz: f257ff8520fd6b5b124eb824a0869aac56c94db788c7b245cd116284e09a7a4cee20d467f634215329ffc37a664d738d419e934d768202172c3c7a6022d161d0
         | 
    
        data/.rubocop.yml
    CHANGED
    
    
    
        data/NEWS.md
    CHANGED
    
    | @@ -2,6 +2,16 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            ## unreleased
         | 
| 4 4 |  | 
| 5 | 
            +
            ## 0.6.0, 2018-03-25
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            - Fixed silent corruption of files obtained by `ev3tool download`
         | 
| 8 | 
            +
            - Added `ev3tool asm foo.rb foo.rbf`
         | 
| 9 | 
            +
            - Added SimpleAssembler
         | 
| 10 | 
            +
            - Added BodyCompiler#if_else, #loop_until_pre
         | 
| 11 | 
            +
            - Implemented array_init* (PARVALUES)
         | 
| 12 | 
            +
            - Added JumpOffset, replacing the Complex hack
         | 
| 13 | 
            +
            - Variables are now aligned automatically; subroutine argument alignment is checked
         | 
| 14 | 
            +
             | 
| 5 15 | 
             
            ## 0.5.0, 2018-03-05
         | 
| 6 16 |  | 
| 7 17 | 
             
            - Ev3Ops: added missing array_* ops (with PARV in the signature).
         | 
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            0. | 
| 1 | 
            +
            0.6.0
         | 
    
        data/examples/bobbee.rb
    CHANGED
    
    | @@ -13,14 +13,20 @@ class Bobbee | |
| 13 13 | 
             
              # Interface to all other commands
         | 
| 14 14 | 
             
              # @return [Lignite::DirectCommands]
         | 
| 15 15 | 
             
              attr_reader :dc
         | 
| 16 | 
            +
              # The robot is built with a https://en.wikipedia.org/wiki/Worm_drive
         | 
| 17 | 
            +
              # lift mechanism
         | 
| 18 | 
            +
              # @return [Boolean]
         | 
| 19 | 
            +
              attr_reader :worm_lift
         | 
| 16 20 |  | 
| 17 21 | 
             
              def initialize(drive: Lignite::PORT_B | Lignite::PORT_C,
         | 
| 18 22 | 
             
                             lift: Lignite::PORT_A,
         | 
| 19 | 
            -
                             dc: Lignite::DirectCommands.new | 
| 23 | 
            +
                             dc: Lignite::DirectCommands.new,
         | 
| 24 | 
            +
                             worm_lift: false)
         | 
| 20 25 | 
             
                layer = 0
         | 
| 21 26 | 
             
                @drive = Lignite::Motors.new(layer, drive, dc)
         | 
| 22 27 | 
             
                @lift = Lignite::Motors.new(layer, lift, dc)
         | 
| 23 28 | 
             
                @dc = dc
         | 
| 29 | 
            +
                @worm_lift = worm_lift
         | 
| 24 30 | 
             
              end
         | 
| 25 31 |  | 
| 26 32 | 
             
              # @param speed [Integer] -100..100
         | 
| @@ -43,34 +49,51 @@ class Bobbee | |
| 43 49 | 
             
              end
         | 
| 44 50 |  | 
| 45 51 | 
             
              LIFT_FULL = 220
         | 
| 52 | 
            +
              WORM_LIFT_FULL = 2400
         | 
| 46 53 |  | 
| 47 54 | 
             
              # Raise the fork from the ground up
         | 
| 48 55 | 
             
              def raise(wait: true)
         | 
| 49 | 
            -
                 | 
| 56 | 
            +
                if worm_lift
         | 
| 57 | 
            +
                  lift.step_power(-30, 10, WORM_LIFT_FULL - 20, 10)
         | 
| 58 | 
            +
                else
         | 
| 59 | 
            +
                  lift.step_power(30, 10, LIFT_FULL - 20, 10)
         | 
| 60 | 
            +
                end
         | 
| 50 61 | 
             
                lift.ready if wait
         | 
| 51 62 | 
             
              end
         | 
| 52 63 |  | 
| 53 64 | 
             
              # Raise the fork one third of the way from the ground up
         | 
| 54 65 | 
             
              def third_raise(wait: true)
         | 
| 55 | 
            -
                 | 
| 66 | 
            +
                if worm_lift
         | 
| 67 | 
            +
                  lift.step_power(-30, 10, WORM_LIFT_FULL / 3 - 20, 10)
         | 
| 68 | 
            +
                else
         | 
| 69 | 
            +
                  lift.step_power(30, 10, LIFT_FULL / 3 - 20, 10)
         | 
| 70 | 
            +
                end
         | 
| 56 71 | 
             
                lift.ready if wait
         | 
| 57 72 |  | 
| 58 73 | 
             
                beep
         | 
| 59 | 
            -
                 | 
| 74 | 
            +
                ready
         | 
| 60 75 | 
             
              end
         | 
| 61 76 |  | 
| 62 77 | 
             
              # Lower the fork from above to the ground
         | 
| 63 78 | 
             
              def lower(wait: true)
         | 
| 64 | 
            -
                 | 
| 79 | 
            +
                if worm_lift
         | 
| 80 | 
            +
                  lift.step_power(30, 10, WORM_LIFT_FULL - 20, 10)
         | 
| 81 | 
            +
                else
         | 
| 82 | 
            +
                  lift.step_power(-1, 10, LIFT_FULL - 20, 10)
         | 
| 83 | 
            +
                end
         | 
| 65 84 | 
             
                lift.ready if wait
         | 
| 66 85 |  | 
| 67 86 | 
             
                beep
         | 
| 68 | 
            -
                 | 
| 87 | 
            +
                ready
         | 
| 69 88 | 
             
              end
         | 
| 70 89 |  | 
| 71 90 | 
             
              # Lower the fork one third of the way from above to the ground
         | 
| 72 91 | 
             
              def third_lower(wait: true)
         | 
| 73 | 
            -
                 | 
| 92 | 
            +
                if worm_lift
         | 
| 93 | 
            +
                  lift.step_power(30, 10, WORM_LIFT_FULL / 3 - 20, 10)
         | 
| 94 | 
            +
                else
         | 
| 95 | 
            +
                  lift.step_power(-1, 10, LIFT_FULL / 3 - 20, 10)
         | 
| 96 | 
            +
                end
         | 
| 74 97 | 
             
                lift.ready if wait
         | 
| 75 98 | 
             
              end
         | 
| 76 99 |  | 
| @@ -87,14 +110,14 @@ class Bobbee | |
| 87 110 | 
             
              def forward(steps = SQUARE_STEPS)
         | 
| 88 111 | 
             
                step_sync(50, 0, steps)
         | 
| 89 112 | 
             
                beep
         | 
| 90 | 
            -
                 | 
| 113 | 
            +
                ready
         | 
| 91 114 | 
             
              end
         | 
| 92 115 |  | 
| 93 116 | 
             
              # Drive backward 1 square on the Boost mat
         | 
| 94 117 | 
             
              def back(steps = SQUARE_STEPS)
         | 
| 95 118 | 
             
                step_sync(-50, 0, back_factor(steps))
         | 
| 96 119 | 
             
                beep
         | 
| 97 | 
            -
                 | 
| 120 | 
            +
                ready
         | 
| 98 121 | 
             
              end
         | 
| 99 122 |  | 
| 100 123 | 
             
              # Compensation factor when moving backward
         | 
| @@ -121,37 +144,49 @@ class Bobbee | |
| 121 144 |  | 
| 122 145 | 
             
              # Motor degrees needed to turn the robot 90 degrees when using turn=200
         | 
| 123 146 | 
             
              TURN_90_AT_200_STEPS = 600
         | 
| 147 | 
            +
              # Similar, but when we're carrying 100 grams, turning becomes harder!
         | 
| 148 | 
            +
              LOADED_TURN_90_AT_200_STEPS = 750
         | 
| 124 149 |  | 
| 125 150 | 
             
              # Turn 90 degrees left, simply by moving tracks in opposite directions
         | 
| 126 | 
            -
              def left_immediate
         | 
| 127 | 
            -
                 | 
| 151 | 
            +
              def left_immediate(loaded: false)
         | 
| 152 | 
            +
                steps = loaded ? LOADED_TURN_90_AT_200_STEPS : TURN_90_AT_200_STEPS
         | 
| 153 | 
            +
                step_sync(50, -200, steps)
         | 
| 128 154 | 
             
                beep(100)
         | 
| 129 | 
            -
                 | 
| 155 | 
            +
                ready
         | 
| 130 156 | 
             
              end
         | 
| 131 157 |  | 
| 132 158 | 
             
              # Turn 90 degrees right, simply by moving tracks in opposite directions
         | 
| 133 | 
            -
              def right_immediate
         | 
| 134 | 
            -
                 | 
| 159 | 
            +
              def right_immediate(loaded: false)
         | 
| 160 | 
            +
                steps = loaded ? LOADED_TURN_90_AT_200_STEPS : TURN_90_AT_200_STEPS
         | 
| 161 | 
            +
                step_sync(50, 200, steps)
         | 
| 135 162 | 
             
                beep(100)
         | 
| 136 | 
            -
                 | 
| 163 | 
            +
                ready
         | 
| 137 164 | 
             
              end
         | 
| 138 165 |  | 
| 139 166 | 
             
              # Turn 90 degrees left, starting and ending inside a Boost mat square
         | 
| 140 | 
            -
              def left
         | 
| 167 | 
            +
              def left(loaded: false)
         | 
| 141 168 | 
             
                align_centers_for_turning do
         | 
| 142 | 
            -
                  left_immediate
         | 
| 169 | 
            +
                  left_immediate(loaded: loaded)
         | 
| 143 170 | 
             
                end
         | 
| 144 171 | 
             
              end
         | 
| 145 172 |  | 
| 146 173 | 
             
              # Turn 90 degrees right, starting and ending inside a Boost mat square
         | 
| 147 | 
            -
              def right
         | 
| 174 | 
            +
              def right(loaded: false)
         | 
| 148 175 | 
             
                align_centers_for_turning do
         | 
| 149 | 
            -
                  right_immediate
         | 
| 176 | 
            +
                  right_immediate(loaded: loaded)
         | 
| 150 177 | 
             
                end
         | 
| 151 178 | 
             
              end
         | 
| 152 | 
            -
            end
         | 
| 153 179 |  | 
| 154 | 
            -
             | 
| 180 | 
            +
              # Wait until the previous motor movements are complete
         | 
| 181 | 
            +
              def ready
         | 
| 182 | 
            +
                return unless @dc.is_a? Lignite::DirectCommands
         | 
| 183 | 
            +
             | 
| 184 | 
            +
                print "Ready... "
         | 
| 185 | 
            +
                drive.test
         | 
| 186 | 
            +
                lift.test
         | 
| 187 | 
            +
                puts "OK"
         | 
| 188 | 
            +
              end
         | 
| 189 | 
            +
            end
         | 
| 155 190 |  | 
| 156 191 | 
             
            # Put Bobb3e (B) on the blue arrow (^). Move it one square left, and forward.
         | 
| 157 192 | 
             
            # Put the container on a raised platform on the "twins" square (T).
         | 
| @@ -169,18 +204,18 @@ def from_twins_to_fire(bb) | |
| 169 204 |  | 
| 170 205 | 
             
                right
         | 
| 171 206 | 
             
                forward
         | 
| 172 | 
            -
                third_raise
         | 
| 207 | 
            +
                2.times { third_raise }
         | 
| 173 208 | 
             
                back
         | 
| 174 | 
            -
                left
         | 
| 209 | 
            +
                left(loaded: true)
         | 
| 175 210 | 
             
                # we're at the starting position, but carrying the load
         | 
| 176 211 |  | 
| 177 212 | 
             
                # move towards the recipient
         | 
| 178 213 | 
             
                2.times { forward }
         | 
| 179 | 
            -
                right
         | 
| 214 | 
            +
                right(loaded: true)
         | 
| 180 215 |  | 
| 181 216 | 
             
                # deliver and unload
         | 
| 182 217 | 
             
                forward
         | 
| 183 | 
            -
                third_lower
         | 
| 218 | 
            +
                2.times { third_lower }
         | 
| 184 219 | 
             
                back
         | 
| 185 220 |  | 
| 186 221 | 
             
                # resting position
         | 
| @@ -202,17 +237,17 @@ def from_fire_to_twins(bb) | |
| 202 237 |  | 
| 203 238 | 
             
                # load
         | 
| 204 239 | 
             
                forward
         | 
| 205 | 
            -
                third_raise
         | 
| 240 | 
            +
                2.times { third_raise }
         | 
| 206 241 | 
             
                back
         | 
| 207 242 |  | 
| 208 243 | 
             
                # starting position
         | 
| 209 | 
            -
                left
         | 
| 244 | 
            +
                left(loaded: true)
         | 
| 210 245 | 
             
                2.times { back }
         | 
| 211 246 |  | 
| 212 247 | 
             
                # deliver
         | 
| 213 | 
            -
                right
         | 
| 248 | 
            +
                right(loaded: true)
         | 
| 214 249 | 
             
                forward
         | 
| 215 | 
            -
                third_lower
         | 
| 250 | 
            +
                2.times { third_lower }
         | 
| 216 251 | 
             
                back
         | 
| 217 252 | 
             
                left
         | 
| 218 253 |  | 
| @@ -228,6 +263,17 @@ def calibrate_forward_and_back(bb) | |
| 228 263 | 
             
              end
         | 
| 229 264 | 
             
            end
         | 
| 230 265 |  | 
| 266 | 
            +
            mode = ARGV.first || "direct"
         | 
| 267 | 
            +
            dc = if mode == "rbf"
         | 
| 268 | 
            +
              Lignite::SimpleAssembler.new
         | 
| 269 | 
            +
            else
         | 
| 270 | 
            +
              Lignite::DirectCommands.new
         | 
| 271 | 
            +
            end
         | 
| 272 | 
            +
             | 
| 273 | 
            +
            bb = Bobbee.new(dc: dc, worm_lift: true)
         | 
| 274 | 
            +
             | 
| 231 275 | 
             
            # calibrate_forward_and_back(bb)
         | 
| 232 276 | 
             
            from_twins_to_fire(bb)
         | 
| 233 277 | 
             
            # from_fire_to_twins(bb)
         | 
| 278 | 
            +
             | 
| 279 | 
            +
            dc.write("bobbee.rbf") if mode == "rbf"
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            #!/usr/bin/ruby
         | 
| 2 | 
            +
            require "lignite"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            dc = Lignite::DirectCommands.new
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            # Read gyro sensor angle on port 2
         | 
| 7 | 
            +
            LAYER0 = 0
         | 
| 8 | 
            +
            MODE = 0
         | 
| 9 | 
            +
            pct = dc.with_reply do
         | 
| 10 | 
            +
              # global vars
         | 
| 11 | 
            +
              dataf :angle
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              block do
         | 
| 14 | 
            +
                input_device_ready_si(LAYER0, Lignite::PORT_2, Lignite::TYPE_GYRO, MODE, :angle)
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
            end
         | 
| 17 | 
            +
            puts "Gyro sensor angle: #{pct}"
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            dc.close
         | 
    
        data/lib/lignite.rb
    CHANGED
    
    | @@ -4,11 +4,13 @@ require "lignite/logger" | |
| 4 4 | 
             
            require "lignite/assembler"
         | 
| 5 5 | 
             
            require "lignite/body_compiler"
         | 
| 6 6 | 
             
            require "lignite/connection"
         | 
| 7 | 
            +
            require "lignite/condition"
         | 
| 7 8 | 
             
            require "lignite/connection/bluetooth"
         | 
| 8 9 | 
             
            require "lignite/connection/replay"
         | 
| 9 10 | 
             
            require "lignite/connection/tap"
         | 
| 10 11 | 
             
            require "lignite/connection/usb"
         | 
| 11 12 | 
             
            require "lignite/direct_commands"
         | 
| 13 | 
            +
            require "lignite/jump_offset"
         | 
| 12 14 | 
             
            require "lignite/message"
         | 
| 13 15 | 
             
            require "lignite/motors"
         | 
| 14 16 | 
             
            require "lignite/op_compiler"
         | 
| @@ -17,7 +19,10 @@ require "lignite/system_commands" | |
| 17 19 | 
             
            require "lignite/variables"
         | 
| 18 20 | 
             
            require "lignite/version"
         | 
| 19 21 |  | 
| 22 | 
            +
            # The main namespace
         | 
| 20 23 | 
             
            module Lignite
         | 
| 24 | 
            +
              LAYER_0 = 0
         | 
| 25 | 
            +
             | 
| 21 26 | 
             
              PORT_A = 1
         | 
| 22 27 | 
             
              PORT_B = 2
         | 
| 23 28 | 
             
              PORT_C = 4
         | 
| @@ -39,4 +44,11 @@ module Lignite | |
| 39 44 | 
             
              # Represents an error returned by the robot
         | 
| 40 45 | 
             
              class VMError < RuntimeError
         | 
| 41 46 | 
             
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              def program(&block)
         | 
| 49 | 
            +
                p = Assembler.new
         | 
| 50 | 
            +
                p.compile(&block)
         | 
| 51 | 
            +
                p
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
              module_function :program
         | 
| 42 54 | 
             
            end
         | 
    
        data/lib/lignite/assembler.rb
    CHANGED
    
    | @@ -17,6 +17,7 @@ module Lignite | |
| 17 17 | 
             
              class Assembler
         | 
| 18 18 | 
             
                include Bytes
         | 
| 19 19 | 
             
                include Logger
         | 
| 20 | 
            +
                include Lignite # for constants
         | 
| 20 21 |  | 
| 21 22 | 
             
                HEADER_SIZE = 16
         | 
| 22 23 | 
             
                SIGNATURE = "LEGO".freeze
         | 
| @@ -26,9 +27,14 @@ module Lignite | |
| 26 27 | 
             
                end
         | 
| 27 28 |  | 
| 28 29 | 
             
                # @return [Array<RbfObject>]
         | 
| 29 | 
            -
                 | 
| 30 | 
            +
                attr_accessor :objects
         | 
| 30 31 | 
             
                # @return [Variables]
         | 
| 31 | 
            -
                 | 
| 32 | 
            +
                attr_accessor :globals
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def initialize
         | 
| 35 | 
            +
                  @objects = []
         | 
| 36 | 
            +
                  @globals = Variables.new
         | 
| 37 | 
            +
                end
         | 
| 32 38 |  | 
| 33 39 | 
             
                # Assemble a complete RBF program file.
         | 
| 34 40 | 
             
                # (it is OK to reuse an Assembler and call this several times in a sequence)
         | 
| @@ -36,9 +42,8 @@ module Lignite | |
| 36 42 | 
             
                # @param rb_filename [String] input
         | 
| 37 43 | 
             
                # @param rbf_filename [String] output
         | 
| 38 44 | 
             
                def assemble(rb_filename, rbf_filename, version: 109)
         | 
| 45 | 
            +
                  initialize
         | 
| 39 46 | 
             
                  rb_text = File.read(rb_filename)
         | 
| 40 | 
            -
                  @objects = []
         | 
| 41 | 
            -
                  @globals = Variables.new
         | 
| 42 47 |  | 
| 43 48 | 
             
                  @declarer = RbfDeclarer.new
         | 
| 44 49 | 
             
                  @declarer.instance_eval(rb_text, rb_filename, 1) # 1 is the line number
         | 
| @@ -47,7 +52,13 @@ module Lignite | |
| 47 52 | 
             
                  write(rbf_filename, version)
         | 
| 48 53 | 
             
                end
         | 
| 49 54 |  | 
| 50 | 
            -
                def  | 
| 55 | 
            +
                def compile(&block)
         | 
| 56 | 
            +
                  @declarer = RbfDeclarer.new
         | 
| 57 | 
            +
                  @declarer.instance_exec(&block)
         | 
| 58 | 
            +
                  instance_exec(&block)
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                def write(rbf_filename, version = 109)
         | 
| 51 62 | 
             
                  image_size = HEADER_SIZE + @objects.map(&:size).reduce(0, :+)
         | 
| 52 63 |  | 
| 53 64 | 
             
                  File.open(rbf_filename, "w") do |f|
         | 
| @@ -99,4 +110,36 @@ module Lignite | |
| 99 110 | 
             
                                                local_bytes: @locals.bytesize)
         | 
| 100 111 | 
             
                end
         | 
| 101 112 | 
             
              end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
              # Acts like DirectCommands but instead of executing, assembles them to a RBF file
         | 
| 115 | 
            +
              class SimpleAssembler
         | 
| 116 | 
            +
                def initialize
         | 
| 117 | 
            +
                  @globals = Variables.new
         | 
| 118 | 
            +
                  @locals = Variables.new
         | 
| 119 | 
            +
                  @declarer = RbfDeclarer::Dummy.new
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                  @interp = BodyCompiler.new(@globals, @locals, @declarer)
         | 
| 122 | 
            +
                end
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                def write(rbf_filename)
         | 
| 125 | 
            +
                  @interp.object_end
         | 
| 126 | 
            +
                  vmthread = RbfObject.vmthread(body: @interp.bytes, local_bytes: @locals.bytesize)
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                  asm = Assembler.new
         | 
| 129 | 
            +
                  asm.objects = [vmthread]
         | 
| 130 | 
            +
                  asm.globals = @globals
         | 
| 131 | 
            +
                  asm.write(rbf_filename)
         | 
| 132 | 
            +
                end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                # Delegate the ops to the {BodyCompiler},
         | 
| 135 | 
            +
                def method_missing(name, *args, &block)
         | 
| 136 | 
            +
                  super unless @interp.respond_to?(name)
         | 
| 137 | 
            +
             | 
| 138 | 
            +
                  @interp.public_send(name, *args, &block)
         | 
| 139 | 
            +
                end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                def respond_to_missing?(name, _include_private)
         | 
| 142 | 
            +
                  @interp.respond_to?(name) || super
         | 
| 143 | 
            +
                end
         | 
| 144 | 
            +
              end
         | 
| 102 145 | 
             
            end
         | 
| @@ -1,30 +1,4 @@ | |
| 1 1 | 
             
            module Lignite
         | 
| 2 | 
            -
              # Less-than (32 bit)
         | 
| 3 | 
            -
              class Lt32 # < Condition
         | 
| 4 | 
            -
                def initialize(a, b)
         | 
| 5 | 
            -
                  @a = a
         | 
| 6 | 
            -
                  @b = b
         | 
| 7 | 
            -
                end
         | 
| 8 | 
            -
             | 
| 9 | 
            -
                def not
         | 
| 10 | 
            -
                  Ge32.new(@a, @b)
         | 
| 11 | 
            -
                end
         | 
| 12 | 
            -
             | 
| 13 | 
            -
                def jump_forward(compiler, body_size)
         | 
| 14 | 
            -
                  compiler.jr_lt32(@a, @b, Complex(body_size, 2))
         | 
| 15 | 
            -
                end
         | 
| 16 | 
            -
             | 
| 17 | 
            -
                def jump_back(compiler, body_size, self_size = nil)
         | 
| 18 | 
            -
                  if self_size.nil?
         | 
| 19 | 
            -
                    fake = compiler.clone_context
         | 
| 20 | 
            -
                    jump_back(fake, body_size, 0)
         | 
| 21 | 
            -
                    self_size = fake.bytes.bytesize
         | 
| 22 | 
            -
                  end
         | 
| 23 | 
            -
             | 
| 24 | 
            -
                  compiler.jr_lt32(@a, @b, Complex(- (body_size + self_size), 2))
         | 
| 25 | 
            -
                end
         | 
| 26 | 
            -
              end
         | 
| 27 | 
            -
             | 
| 28 2 | 
             
              # Extends {OpCompiler} by
         | 
| 29 3 | 
             
              # - variable declarations: {VariableDeclarer}
         | 
| 30 4 | 
             
              # - high level flow control: {#loop}
         | 
| @@ -62,28 +36,39 @@ module Lignite | |
| 62 36 | 
             
                  BodyCompiler.new(@globals, @locals, @declared_objects)
         | 
| 63 37 | 
             
                end
         | 
| 64 38 |  | 
| 65 | 
            -
                def if( | 
| 66 | 
            -
                   | 
| 39 | 
            +
                def if(cond, &body)
         | 
| 40 | 
            +
                  cond = Flag.new(cond) unless cond.is_a? Condition
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  subc = clone_context
         | 
| 67 43 | 
             
                  subc.instance_exec(&body)
         | 
| 68 44 |  | 
| 69 | 
            -
                   | 
| 45 | 
            +
                  cond.not.jump_forward(self, subc.bytes.bytesize)
         | 
| 70 46 | 
             
                  @bytes << subc.bytes
         | 
| 71 47 | 
             
                end
         | 
| 72 48 |  | 
| 49 | 
            +
                def if_else(flag8, body_true, body_false)
         | 
| 50 | 
            +
                  truec = clone_context
         | 
| 51 | 
            +
                  falsec = clone_context
         | 
| 52 | 
            +
                  truec.instance_exec(&body_true)
         | 
| 53 | 
            +
                  falsec.instance_exec(&body_false)
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  # 4 is the unconditional jump size
         | 
| 56 | 
            +
                  jr_false(flag8, JumpOffset.new(truec.bytes.bytesize + 4))
         | 
| 57 | 
            +
                  @bytes << truec.bytes
         | 
| 58 | 
            +
                  jr(JumpOffset.new(falsec.bytes.bytesize))
         | 
| 59 | 
            +
                  @bytes << falsec.bytes
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 73 62 | 
             
                def loop(&body)
         | 
| 74 | 
            -
                  subc =  | 
| 63 | 
            +
                  subc = clone_context
         | 
| 75 64 | 
             
                  subc.instance_exec(&body)
         | 
| 76 65 | 
             
                  @bytes << subc.bytes
         | 
| 77 66 | 
             
                  # the jump takes up 4 bytes: JR, LC2, LO, HI
         | 
| 78 | 
            -
                  jr( | 
| 67 | 
            +
                  jr(JumpOffset.new(- (subc.bytes.bytesize + 4)))
         | 
| 79 68 | 
             
                end
         | 
| 80 69 |  | 
| 81 70 | 
             
                def loop_while_postcond(flag8, &body)
         | 
| 82 | 
            -
                   | 
| 83 | 
            -
                  subc.instance_exec(&body)
         | 
| 84 | 
            -
                  @bytes << subc.bytes
         | 
| 85 | 
            -
                  # the jump takes up 5 bytes: JR_TRUE, LV0(flag8), LC2, LO, HI
         | 
| 86 | 
            -
                  jr_true(flag8, Complex(- (subc.bytes.bytesize + 5), 2))
         | 
| 71 | 
            +
                  loop_while(body, Flag.new(flag8))
         | 
| 87 72 | 
             
                end
         | 
| 88 73 |  | 
| 89 74 | 
             
                def loop_while(a, b)
         | 
| @@ -95,18 +80,31 @@ module Lignite | |
| 95 80 | 
             
                end
         | 
| 96 81 |  | 
| 97 82 | 
             
                def loop_while_post(condition, &body)
         | 
| 98 | 
            -
                  subc =  | 
| 83 | 
            +
                  subc = clone_context
         | 
| 99 84 | 
             
                  subc.instance_exec(&body)
         | 
| 100 85 | 
             
                  @bytes << subc.bytes
         | 
| 101 86 | 
             
                  body_size = subc.bytes.bytesize
         | 
| 102 87 | 
             
                  condition.jump_back(self, body_size)
         | 
| 103 88 | 
             
                end
         | 
| 104 89 |  | 
| 90 | 
            +
                def loop_until_pre(condition, &body)
         | 
| 91 | 
            +
                  subc = clone_context
         | 
| 92 | 
            +
                  subc.instance_exec(&body)
         | 
| 93 | 
            +
                  ofs1 = @bytes.bytesize
         | 
| 94 | 
            +
                  condition.jump_forward(self, subc.bytes.bytesize + 4)
         | 
| 95 | 
            +
                  ofs2 = @bytes.bytesize
         | 
| 96 | 
            +
                  fw_jump_size = ofs2 - ofs1
         | 
| 97 | 
            +
                  @bytes << subc.bytes
         | 
| 98 | 
            +
                  jr(JumpOffset.new(-(fw_jump_size + subc.bytes.bytesize + 4)))
         | 
| 99 | 
            +
                end
         | 
| 100 | 
            +
             | 
| 105 101 | 
             
                def call(name, *args)
         | 
| 106 102 | 
             
                  obj_id = declared_objects.index_of(name)
         | 
| 107 103 | 
             
                  raise "Name #{name} not found" if obj_id.nil?
         | 
| 108 104 |  | 
| 109 105 | 
             
                  # TODO: check that args match their declaration
         | 
| 106 | 
            +
                  # In particular, mixing up data32 with dataf passes the VM validity check
         | 
| 107 | 
            +
                  # but then misinterprets the bits.
         | 
| 110 108 | 
             
                  super(obj_id, *args) # Ev3Ops::call
         | 
| 111 109 | 
             
                end
         | 
| 112 110 |  |