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.
@@ -0,0 +1,116 @@
1
+ module Lignite
2
+ # Compile a conditional jump forward or backward
3
+ class Condition
4
+ # Call that instruction of the compiler
5
+ # that jumps by *offset* according to the condition that we implement
6
+ def cond_jump(_compiler, _offset)
7
+ raise ScriptError, "subclasses must override this"
8
+ end
9
+
10
+ # Negation of this condition.
11
+ # An `if(cond){ body }` becomes roughly `cond.not.jump_forward(body.size); body`
12
+ def not
13
+ raise ScriptError, "subclasses must override this"
14
+ end
15
+
16
+ def jump_forward(compiler, body_size)
17
+ cond_jump(compiler, body_size)
18
+ end
19
+
20
+ def jump_back(compiler, body_size, self_size = nil)
21
+ if self_size.nil?
22
+ fake = compiler.clone_context
23
+ jump_back(fake, body_size, 0)
24
+ self_size = fake.bytes.bytesize
25
+ end
26
+
27
+ cond_jump(compiler, - (body_size + self_size))
28
+ end
29
+ end
30
+
31
+ # A condition that is always true
32
+ class Always < Condition
33
+ def not
34
+ Never.new
35
+ end
36
+
37
+ def cond_jump(compiler, offset)
38
+ compiler.jr(JumpOffset.new(offset))
39
+ end
40
+ end
41
+
42
+ # A condition that is never true
43
+ class Never < Condition
44
+ def not
45
+ Always.new
46
+ end
47
+
48
+ def cond_jump(compiler, _offset)
49
+ # Never jump: do a jump of size 0
50
+ # but it must be a jump because code size calculations need that
51
+ compiler.jr(JumpOffset.new(0))
52
+ end
53
+ end
54
+
55
+ # Less-than (32 bit)
56
+ class Lt32 < Condition
57
+ def initialize(a, b)
58
+ @a = a
59
+ @b = b
60
+ end
61
+
62
+ def not
63
+ Gteq32.new(@a, @b)
64
+ end
65
+
66
+ def cond_jump(compiler, offset)
67
+ compiler.jr_lt32(@a, @b, JumpOffset.new(offset))
68
+ end
69
+ end
70
+
71
+ # Greater-than-or-equal (32 bit)
72
+ class Gteq32 < Condition
73
+ def initialize(a, b)
74
+ @a = a
75
+ @b = b
76
+ end
77
+
78
+ def not
79
+ Lt32.new(@a, @b)
80
+ end
81
+
82
+ def cond_jump(compiler, offset)
83
+ compiler.jr_gteq32(@a, @b, JumpOffset.new(offset))
84
+ end
85
+ end
86
+
87
+ # Test a boolean flag
88
+ class Flag < Condition
89
+ def initialize(f)
90
+ @f = f
91
+ end
92
+
93
+ def not
94
+ NotFlag.new(@f)
95
+ end
96
+
97
+ def cond_jump(compiler, offset)
98
+ compiler.jr_true(@f, JumpOffset.new(offset))
99
+ end
100
+ end
101
+
102
+ # Test a negated boolean flag
103
+ class NotFlag < Condition
104
+ def initialize(f)
105
+ @f = f
106
+ end
107
+
108
+ def not
109
+ Flag.new(@f)
110
+ end
111
+
112
+ def cond_jump(compiler, offset)
113
+ compiler.jr_false(@f, JumpOffset.new(offset))
114
+ end
115
+ end
116
+ end
@@ -5,18 +5,22 @@ module Lignite
5
5
  class Connection
6
6
  include Bytes
7
7
  include Logger
8
+ extend Logger
8
9
 
9
10
  # @return [Connection] Try a {Usb} connection first, then a {Bluetooth} one.
10
11
  def self.create
11
12
  @c ||= Replay.new(ENV["LIGNITE_REPLAY"]) if ENV["LIGNITE_REPLAY"]
12
13
 
13
14
  @c ||= begin
15
+ logger.debug "Connection: trying USB"
14
16
  Usb.new
15
17
  rescue NoUsbDevice
18
+ logger.debug "Connection: trying BT"
16
19
  Bluetooth.new
17
20
  end
18
21
 
19
22
  @c = Tap.new(@c, ENV["LIGNITE_TAP"]) if ENV["LIGNITE_TAP"]
23
+ logger.debug "Connection: #{@c.inspect}"
20
24
  @c
21
25
  end
22
26
 
@@ -140,7 +140,7 @@ module Lignite
140
140
 
141
141
  bytes = u8(0x09)
142
142
  bytes += param_simple(objid)
143
- bytes += param_multiple(*parameters)
143
+ bytes += param_n_multiple(*parameters)
144
144
  logger.debug "returning bytecode: #{bytes.inspect}"
145
145
  bytes
146
146
  end
@@ -862,7 +862,23 @@ module Lignite
862
862
  bytes
863
863
  end
864
864
 
865
- # Could not define init_bytes: Unhandled param type PARVALUES
865
+ # Move LENGTH number of DATA8 from BYTE STREAM to memory DESTINATION START
866
+ # @param destination [PAR8] (out) First element in DATA8 array to be initiated
867
+ # @param length [PAR32] (in) Number of elements to initiate
868
+ # @param source [PARVALUES] (in) First element to initiate DATA8 array with
869
+ def init_bytes(destination, length, *source)
870
+ logger.debug do
871
+ args = [destination, length, *source]
872
+ "called init_bytes with #{args.inspect}"
873
+ end
874
+
875
+ bytes = u8(0x2F)
876
+ bytes += param_simple(destination)
877
+ bytes += param_simple(length)
878
+ bytes += param_multiple(*source)
879
+ logger.debug "returning bytecode: #{bytes.inspect}"
880
+ bytes
881
+ end
866
882
 
867
883
  # Move 8 bit value from SOURCE to DESTINATION
868
884
  # @param source [PAR8] (in)
@@ -6045,7 +6061,7 @@ module Lignite
6045
6061
  bytes += param_simple(no)
6046
6062
  bytes += param_simple(type)
6047
6063
  bytes += param_simple(mode)
6048
- bytes += param_multiple(*values)
6064
+ bytes += param_n_multiple(*values)
6049
6065
  logger.debug "returning bytecode: #{bytes.inspect}"
6050
6066
  bytes
6051
6067
  end
@@ -6070,7 +6086,7 @@ module Lignite
6070
6086
  bytes += param_simple(no)
6071
6087
  bytes += param_simple(type)
6072
6088
  bytes += param_simple(mode)
6073
- bytes += param_multiple(*values)
6089
+ bytes += param_n_multiple(*values)
6074
6090
  logger.debug "returning bytecode: #{bytes.inspect}"
6075
6091
  bytes
6076
6092
  end
@@ -6095,7 +6111,7 @@ module Lignite
6095
6111
  bytes += param_simple(no)
6096
6112
  bytes += param_simple(type)
6097
6113
  bytes += param_simple(mode)
6098
- bytes += param_multiple(*values)
6114
+ bytes += param_n_multiple(*values)
6099
6115
  logger.debug "returning bytecode: #{bytes.inspect}"
6100
6116
  bytes
6101
6117
  end
@@ -6277,7 +6293,7 @@ module Lignite
6277
6293
  bytes += param_simple(type)
6278
6294
  bytes += param_simple(mode)
6279
6295
  bytes += param_simple(format)
6280
- bytes += param_multiple(*values)
6296
+ bytes += param_n_multiple(*values)
6281
6297
  logger.debug "returning bytecode: #{bytes.inspect}"
6282
6298
  bytes
6283
6299
  end
@@ -7559,19 +7575,95 @@ module Lignite
7559
7575
  #
7560
7576
  Lignite::INIT8 = 8
7561
7577
 
7562
- # Could not define array_init8: Unhandled param type PARVALUES
7578
+ #
7579
+ # @param handle [PAR16] (in) Array handle
7580
+ # @param index [PAR32] (in) Index to element to write
7581
+ # @param elements [PAR32] (in) Number of elements to write
7582
+ # @param values [PARVALUES] (in)
7583
+ def array_init8(handle, index, elements, *values)
7584
+ logger.debug do
7585
+ args = [handle, index, elements, *values]
7586
+ "called array_init8 with #{args.inspect}"
7587
+ end
7588
+
7589
+ bytes = u8(0xC1)
7590
+ bytes += param_simple(8)
7591
+ bytes += param_simple(handle)
7592
+ bytes += param_simple(index)
7593
+ bytes += param_simple(elements)
7594
+ bytes += param_multiple(*values)
7595
+ logger.debug "returning bytecode: #{bytes.inspect}"
7596
+ bytes
7597
+ end
7563
7598
  #
7564
7599
  Lignite::INIT16 = 9
7565
7600
 
7566
- # Could not define array_init16: Unhandled param type PARVALUES
7601
+ #
7602
+ # @param handle [PAR16] (in) Array handle
7603
+ # @param index [PAR32] (in) Index to element to write
7604
+ # @param elements [PAR32] (in) Number of elements to write
7605
+ # @param values [PARVALUES] (in)
7606
+ def array_init16(handle, index, elements, *values)
7607
+ logger.debug do
7608
+ args = [handle, index, elements, *values]
7609
+ "called array_init16 with #{args.inspect}"
7610
+ end
7611
+
7612
+ bytes = u8(0xC1)
7613
+ bytes += param_simple(9)
7614
+ bytes += param_simple(handle)
7615
+ bytes += param_simple(index)
7616
+ bytes += param_simple(elements)
7617
+ bytes += param_multiple(*values)
7618
+ logger.debug "returning bytecode: #{bytes.inspect}"
7619
+ bytes
7620
+ end
7567
7621
  #
7568
7622
  Lignite::INIT32 = 10
7569
7623
 
7570
- # Could not define array_init32: Unhandled param type PARVALUES
7624
+ #
7625
+ # @param handle [PAR16] (in) Array handle
7626
+ # @param index [PAR32] (in) Index to element to write
7627
+ # @param elements [PAR32] (in) Number of elements to write
7628
+ # @param values [PARVALUES] (in)
7629
+ def array_init32(handle, index, elements, *values)
7630
+ logger.debug do
7631
+ args = [handle, index, elements, *values]
7632
+ "called array_init32 with #{args.inspect}"
7633
+ end
7634
+
7635
+ bytes = u8(0xC1)
7636
+ bytes += param_simple(10)
7637
+ bytes += param_simple(handle)
7638
+ bytes += param_simple(index)
7639
+ bytes += param_simple(elements)
7640
+ bytes += param_multiple(*values)
7641
+ logger.debug "returning bytecode: #{bytes.inspect}"
7642
+ bytes
7643
+ end
7571
7644
  #
7572
7645
  Lignite::INITF = 11
7573
7646
 
7574
- # Could not define array_initf: Unhandled param type PARVALUES
7647
+ #
7648
+ # @param handle [PAR16] (in) Array handle
7649
+ # @param index [PAR32] (in) Index to element to write
7650
+ # @param elements [PAR32] (in) Number of elements to write
7651
+ # @param values [PARVALUES] (in)
7652
+ def array_initf(handle, index, elements, *values)
7653
+ logger.debug do
7654
+ args = [handle, index, elements, *values]
7655
+ "called array_initf with #{args.inspect}"
7656
+ end
7657
+
7658
+ bytes = u8(0xC1)
7659
+ bytes += param_simple(11)
7660
+ bytes += param_simple(handle)
7661
+ bytes += param_simple(index)
7662
+ bytes += param_simple(elements)
7663
+ bytes += param_multiple(*values)
7664
+ logger.debug "returning bytecode: #{bytes.inspect}"
7665
+ bytes
7666
+ end
7575
7667
  #
7576
7668
  Lignite::SIZE = 12
7577
7669
 
@@ -8924,7 +9016,7 @@ module Lignite
8924
9016
  bytes += param_simple(hardware)
8925
9017
  bytes += param_simple(boxname)
8926
9018
  bytes += param_simple(type)
8927
- bytes += param_multiple(*values)
9019
+ bytes += param_n_multiple(*values)
8928
9020
  logger.debug "returning bytecode: #{bytes.inspect}"
8929
9021
  bytes
8930
9022
  end
@@ -8942,7 +9034,7 @@ module Lignite
8942
9034
  bytes = u8(0xDA)
8943
9035
  bytes += param_simple(no)
8944
9036
  bytes += param_simple(length)
8945
- bytes += param_multiple(*values)
9037
+ bytes += param_n_multiple(*values)
8946
9038
  logger.debug "returning bytecode: #{bytes.inspect}"
8947
9039
  bytes
8948
9040
  end
@@ -32,14 +32,15 @@ module Lignite
32
32
  desc "download BRICK_FILENAME [LOCAL_FILENAME]", "download a file"
33
33
  map "dl" => "download"
34
34
  def download(brick_filename, local_filename = nil)
35
+ chunk_size = 1000 # 2000 stalls, 4096 goes out of sync in our code
35
36
  local_filename ||= File.basename(brick_filename)
36
- fsize, handle, data = sc.begin_upload(4096, brick_filename)
37
+ fsize, handle, data = sc.begin_upload(chunk_size, brick_filename)
37
38
  File.open(local_filename, "w") do |f|
38
39
  loop do
39
40
  f.write(data)
40
41
  fsize -= data.bytesize
41
42
  break if fsize.zero?
42
- handle, data = sc.continue_upload(handle, 4096)
43
+ handle, data = sc.continue_upload(handle, chunk_size)
43
44
  end
44
45
  end
45
46
  end
@@ -55,6 +56,12 @@ module Lignite
55
56
  puts raw_ls(name)
56
57
  end
57
58
 
59
+ desc "asm RUBYFILE RBFFILE", "assemble RUBYFILE to RBFFILE"
60
+ def asm(ruby_fn, rbf_fn)
61
+ a = Assembler.new
62
+ a.assemble(ruby_fn, rbf_fn)
63
+ end
64
+
58
65
  no_commands do
59
66
  def raw_list_files(name)
60
67
  name ||= EV3TOOL_HOME
@@ -0,0 +1,18 @@
1
+ module Lignite
2
+ # A specialized Integer.
3
+ # When compiling jumps, the jump instruction itself must have a constant size
4
+ # so this class is special-cased in {OpCompiler#param_simple}.
5
+ class JumpOffset
6
+ # @return [Integer]
7
+ attr_reader :value
8
+
9
+ def size
10
+ 2
11
+ end
12
+
13
+ def initialize(v)
14
+ raise "Jumping too far: #{value}" if v.abs > 32767
15
+ @value = v
16
+ end
17
+ end
18
+ end
@@ -13,9 +13,18 @@ module Lignite
13
13
 
14
14
  # 0x02 | 0x04 | 0x08 -> [1, 2, 3]
15
15
  def nos_as_indices
16
- [0, 1, 2, 3].find_all do |n|
16
+ r = [0, 1, 2, 3].find_all do |n|
17
17
  (nos & (1 << n)) != 0
18
18
  end
19
+ r
20
+ end
21
+
22
+ # 0x02 | 0x04 | 0x08 -> [0x02, 0x04, 0x08]
23
+ def nos_as_bits
24
+ r = [1, 2, 4, 8].find_all do |n|
25
+ (nos & n) != 0
26
+ end
27
+ r
19
28
  end
20
29
 
21
30
  def initialize(layer, nos, dc = Lignite::DirectCommands.new)
@@ -85,17 +94,17 @@ module Lignite
85
94
  end
86
95
 
87
96
  # ATTR running?
97
+ # @return [Boolean] true if busy/running
88
98
  def test
89
99
  layer = @layer
90
- nos_as_indices.map do |no|
91
- busy = dc.with_reply do
92
- data8 :busy
93
- block do
94
- output_test(layer, no, :busy)
95
- end
100
+ nos = @nos
101
+ busy = dc.with_reply do
102
+ data8 :busy
103
+ block do
104
+ output_test(layer, nos, :busy)
96
105
  end
97
- busy
98
106
  end
107
+ busy != 0
99
108
  end
100
109
 
101
110
  # which commands are affected? not output_start they say
@@ -43,22 +43,29 @@ module Lignite
43
43
 
44
44
  PRIMPAR_LABEL = 0x20
45
45
 
46
- def make_lcn(n, bytes)
47
- case bytes
48
- when 0
49
- [n & PRIMPAR_VALUE]
50
- when 1
51
- [PRIMPAR_LONG | PRIMPAR_1_BYTE, n & 0xff]
52
- when 2
53
- [PRIMPAR_LONG | PRIMPAR_2_BYTES, n & 0xff, (n >> 8) & 0xff]
54
- else
55
- [PRIMPAR_LONG | PRIMPAR_4_BYTES,
56
- n & 0xff, (n >> 8) & 0xff, (n >> 16) & 0xff, (n >> 24) & 0xff]
46
+ # @param n [Integer] value to encode
47
+ # @param next_size [Integer] how many bytes follow the initial opcode
48
+ # @return [ByteString]
49
+ def numeric_literal_with_size(n, next_size)
50
+ bytes = case next_size
51
+ when 0
52
+ [n & PRIMPAR_VALUE]
53
+ when 1
54
+ [PRIMPAR_LONG | PRIMPAR_1_BYTE, n & 0xff]
55
+ when 2
56
+ [PRIMPAR_LONG | PRIMPAR_2_BYTES, n & 0xff, (n >> 8) & 0xff]
57
+ else
58
+ [PRIMPAR_LONG | PRIMPAR_4_BYTES,
59
+ n & 0xff, (n >> 8) & 0xff, (n >> 16) & 0xff, (n >> 24) & 0xff]
57
60
  end
61
+ bytes.map(&:chr).join("")
58
62
  end
59
63
 
60
- def make_lc(n, bytes = nil)
61
- bytes ||= if (-31..31).cover? n
64
+ # @param n [Integer] value to encode
65
+ # @param next_size [Integer] how many bytes follow the initial opcode
66
+ # @return [ByteString]
67
+ def numeric_literal(n, next_size = nil)
68
+ next_size ||= if (-31..31).cover? n
62
69
  0
63
70
  elsif (-127..127).cover? n
64
71
  1
@@ -67,12 +74,13 @@ module Lignite
67
74
  else
68
75
  4
69
76
  end
70
- make_lcn(n, bytes)
77
+ numeric_literal_with_size(n, next_size)
71
78
  end
72
79
 
80
+ # @return [ByteString]
73
81
  def make_v(n, local_or_global)
74
82
  vartag = PRIMPAR_VARIABEL | local_or_global
75
- if (0..31).cover? n
83
+ bytes = if (0..31).cover? n
76
84
  [vartag | (n & PRIMPAR_VALUE)]
77
85
  elsif (0..255).cover? n
78
86
  [vartag | PRIMPAR_LONG | PRIMPAR_1_BYTE, n & 0xff]
@@ -82,10 +90,12 @@ module Lignite
82
90
  [vartag | PRIMPAR_LONG | PRIMPAR_4_BYTES,
83
91
  n & 0xff, (n >> 8) & 0xff, (n >> 16) & 0xff, (n >> 24) & 0xff]
84
92
  end
93
+ bytes.map(&:chr).join("")
85
94
  end
86
95
 
87
96
  # Reference a variable.
88
97
  # (For declaring, see {VariableDeclarer}.)
98
+ # @return [ByteString]
89
99
  def make_var(sym)
90
100
  raise "No variables declared, cannot process symbols" if @locals.nil? && @globals.nil?
91
101
  if @locals.key?(sym)
@@ -99,27 +109,43 @@ module Lignite
99
109
  end
100
110
  end
101
111
 
112
+ # @return [ByteString]
113
+ def param_n_multiple(*args)
114
+ u8(args.size) + param_multiple(*args)
115
+ end
116
+
102
117
  # @return [ByteString]
103
118
  def param_multiple(*args)
104
- u8(args.size) + args.map { |a| param_simple(a) }.join("")
119
+ args.map { |a| param_simple(a) }.join("")
105
120
  end
106
121
 
107
122
  # @return [ByteString]
108
- def param_simple(x)
123
+ def param_simple_numeric(x)
109
124
  case x
110
125
  when Integer
111
- make_lc(x).map(&:chr).join("")
112
- when Complex
113
- # a Complex number:
114
- # #real: just like an Integer above, but
115
- # #imag tells how many bytes to use for it
116
- make_lc(x.real, x.imag).map(&:chr).join("")
117
- when String
118
- u8(0x80) + x + u8(0x00)
126
+ numeric_literal(x)
119
127
  when Float
120
128
  u8(0x83) + f32(x)
129
+ else
130
+ raise ArgumentError, "Unexpected type: #{x.class}"
131
+ end
132
+ end
133
+
134
+ # @return [ByteString]
135
+ def param_simple(x)
136
+ case x
137
+ when Numeric
138
+ param_simple_numeric(x)
139
+ when JumpOffset
140
+ numeric_literal(x.value, x.size)
141
+ when String
142
+ u8(0x80) + x + u8(0x00)
143
+ when true
144
+ param_simple(1)
145
+ when false
146
+ param_simple(0)
121
147
  when Symbol
122
- make_var(x).map(&:chr).join("")
148
+ make_var(x)
123
149
  else
124
150
  raise ArgumentError, "Unexpected type: #{x.class}"
125
151
  end