rlang 0.5.1 → 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.
@@ -11,34 +11,118 @@ class String
11
11
  # ptr is a simple memory address of type
12
12
  # :I32 (see it as the equivalent of a
13
13
  # char * in C)
14
-
14
+ #
15
15
  # There are 3 ways to initialize a new String object
16
16
  # * with a string literal (e.g. mystring = "Hello World!")
17
17
  # * by pointing at an existing memory location (e.g. String.new(ptr, length))
18
18
  # * by asking Rlang to allocate the String space when ptr is NULL (e.g. String.new(0, length))
19
+ # No memory is allocated for the string bytes if the string is empty
19
20
  def initialize(ptr, length)
20
21
  result :none
21
22
  if ptr == 0
22
- @ptr = Malloc.malloc(length)
23
+ if length == 0
24
+ @ptr = 0
25
+ else
26
+ @ptr = Malloc.malloc(length)
27
+ end
23
28
  else
24
29
  @ptr = ptr
25
30
  end
26
31
  @length = length
27
32
  end
28
33
 
34
+ def size; @length; end
35
+ def to_s; self; end
36
+
37
+ def empty?
38
+ @length == 0
39
+ end
40
+
41
+ def ord
42
+ result :I32
43
+ Memory.load32_8(@ptr)
44
+ end
45
+
29
46
  def +(stg)
30
47
  arg stg: :String
31
48
  result :String
32
- new_length = self.length + stg.length
33
- # allocate space for concatenated string
34
- new_ptr = Malloc.malloc(new_length)
35
- Memory.copy(self.ptr, new_ptr, self.length)
36
- Memory.copy(stg.ptr, new_ptr + self.length, stg.length)
37
- # Create new object string
38
- String.new(new_ptr, new_length)
49
+
50
+ # Create new object string with proper size
51
+ s = String.new(0, @length + stg.length)
52
+ # Copy both strings in the new one
53
+ Memory.copy(@ptr, s.ptr, @length)
54
+ Memory.copy(stg.ptr, s.ptr + @length, stg.length)
55
+ s
39
56
  end
40
57
 
41
- def size; @length; end
42
- def to_s; self; end
58
+ def [](idx)
59
+ result :String
60
+ # The condition below should actually return nil
61
+ # to be compliant with the Ruby library but we don't
62
+ # have nil in Rlang so return an empty string
63
+ return "" if (idx >= @length) || (idx < -@length)
64
+ idx = (@length + idx) if idx < 0
65
+ stg = String.new(0,1)
66
+ Memory.copy(@ptr+idx, stg.ptr, 1)
67
+ stg
68
+ end
69
+
70
+ def []=(idx, stg)
71
+ arg stg: :String
72
+ result :String
73
+ if (idx >= @length) || (idx < -@length)
74
+ raise "IndexError: index out bound"
75
+ end
76
+ idx = (@length + idx) if idx < 0
77
+ i=0
78
+ tgt_ptr = @ptr+idx
79
+ while i < stg.length && (idx + i) < @length
80
+ Memory.copy(stg.ptr+i, tgt_ptr+i, 1)
81
+ i += 1
82
+ end
83
+ stg
84
+ end
85
+
86
+ def *(times)
87
+ result :String
88
+ full_length = @length * times
89
+ stg = String.new(0, full_length)
90
+ idx=0
91
+ while idx < full_length
92
+ stg[idx] = self
93
+ idx += @length
94
+ end
95
+ stg
96
+ end
97
+
98
+ def reverse!
99
+ result :String
100
+ half_size = @length/2
101
+ i=0
102
+ while i < half_size
103
+ swap = Memory.load32_8(@ptr+i)
104
+ Memory.store32_8(@ptr+i, Memory.load32_8(@ptr+@length-1-i))
105
+ Memory.store32_8(@ptr+@length-1-i, swap)
106
+ i += 1
107
+ end
108
+ self
109
+ end
110
+
111
+ def ==(stg)
112
+ arg stg: :String
113
+ return false if stg.length != @length
114
+ i = 0
115
+ stg_ptr = stg.ptr
116
+ while i < @length
117
+ return false if Memory.load32_8(@ptr+i) != Memory.load32_8(stg_ptr+i)
118
+ i += 1
119
+ end
120
+ true
121
+ end
122
+
123
+ def !=(stg)
124
+ arg stg: :String
125
+ !(self == stg)
126
+ end
43
127
 
44
128
  end
@@ -4,29 +4,47 @@
4
4
  #
5
5
  # Integer 32 methods
6
6
 
7
- class String; end
7
+ require_relative '../string'
8
8
 
9
9
  class I32
10
- ConvertString = "0123456789ABCDEF"
10
+
11
+ DIGITS = "0123456789ABCDEF"
11
12
 
12
13
  def self.size; 4; end
13
14
 
14
- def to_str(base)
15
+ # convert an integer to its string representation in a given base
16
+ def self.itoa(x,base)
15
17
  result :String
16
- "0"
17
- =begin
18
- # TODO
19
- if n < base
20
- return convertString[n]
21
- else
22
- return toStr(n//base,base) + convertString[n%base]
18
+
19
+ raise "itoa base out of range" if base < 2 || base > DIGITS.length
20
+ if x <= 0
21
+ if x == 0
22
+ return DIGITS[0]
23
+ else
24
+ return "-" + self.itoa(0-x, base)
25
+ end
26
+ end
27
+
28
+ result = ""
29
+ while x > 0
30
+ remainder = x % base
31
+ x /= base
32
+ result += DIGITS[remainder]
23
33
  end
24
- =end
34
+ result.reverse!
25
35
  end
26
36
 
27
37
  def to_s
28
38
  result :String
29
- self.to_str(10)
39
+ I32.itoa(self, 10)
40
+ end
41
+
42
+ def chr
43
+ result :String
44
+ raise "out of char range" if self > 255 || self < 0
45
+ stg = String.new(0,1)
46
+ Memory.store32_8(stg.ptr, self)
47
+ stg
30
48
  end
31
49
 
32
50
  end
@@ -4,8 +4,6 @@
4
4
  #
5
5
  # Integer 64 methods
6
6
 
7
- class String; end
8
-
9
7
  class I64
10
8
  def self.size; 8; end
11
9
  end
@@ -9,12 +9,15 @@ require_relative './string'
9
9
 
10
10
  ARGC = 0
11
11
  ARGV = 0.cast_to(:Array32)
12
+ ENV = 0.cast_to(:Array32)
12
13
 
13
14
  class WASI
14
15
  STDIN_FD = 0
15
16
  STDOUT_FD = 1
16
17
  STDERR_FD = 2
17
18
  @@argv_buf_size = 0
19
+ @@environc = 0
20
+ @@environ_buf_size = 0
18
21
 
19
22
  class CIOVec
20
23
  attr_reader :ciovs
@@ -81,9 +84,15 @@ class WASI
81
84
  # Import WASI functions
82
85
  import :wasi_unstable, :args_sizes_get
83
86
  def self.args_sizes_get(argc, args_size); end
84
-
87
+
85
88
  import :wasi_unstable, :args_get
86
89
  def self.args_get(argv, argv_buf); end
90
+
91
+ import :wasi_unstable, :environ_get
92
+ def self.environ_get(environ, environ_buf); end
93
+
94
+ import :wasi_unstable, :environ_sizes_get
95
+ def self.environ_sizes_get(environc, environ_buf_size); end
87
96
 
88
97
  import :wasi_unstable, :fd_write
89
98
  def self.fd_write(fd, iovs, iovs_count, nwritten_ptr); end
@@ -94,10 +103,8 @@ class WASI
94
103
  import :wasi_unstable, :proc_exit
95
104
  def self.proc_exit(exitcode); result :none; end
96
105
 
97
- # Initialize WASI environment and related Rlang
98
- # objects (ARGC, ARGV,...)
99
- def self.init
100
- local argv: :Array32
106
+ def self.argv_init
107
+ local argv: :Array32, environ: :Array32
101
108
 
102
109
  # Get number of arguments and their total size
103
110
  errno = WASI.args_sizes_get(ARGC.addr, @@argv_buf_size.addr)
@@ -108,7 +115,7 @@ class WASI
108
115
  #
109
116
  # Setup an extra slot in argv array to simplify the
110
117
  # loop below
111
- argv = Array32.new(ARGC+1) #Malloc.malloc((ARGC+1) * 4) # Assuming I32 for pointers
118
+ argv = Array32.new(ARGC+1) # Assuming I32 for pointers
112
119
  argv_buf = Malloc.malloc(@@argv_buf_size)
113
120
  errno = WASI.args_get(argv.ptr, argv_buf)
114
121
 
@@ -124,10 +131,54 @@ class WASI
124
131
  while i < ARGC
125
132
  length = argv[i+1] - argv[i] - 1 # -1 because of null terminated
126
133
  ARGV[i] = String.new(argv[i], length)
134
+ # Nullify argv[i] so that String is not freed
135
+ argv[i] = 0
127
136
  i += 1
128
137
  end
138
+ argv.free
129
139
  return errno
130
140
  end
131
141
 
142
+ # Initialize WASI environment and related Rlang
143
+ # objects (ARGC, ARGV,...)
144
+ def self.environ_init
145
+ local environ: :Array32
146
+
147
+ # Get environ variable count and buf size
148
+ errno = WASI.environ_sizes_get(@@environc.addr, @@environ_buf_size.addr)
149
+ raise "Errno environ_sizes_get" if errno != 0
150
+
151
+ # Allocate memory areas to receive the env var pointers
152
+ # (env) and the env var strings (env_buf)
153
+ environ = Array32.new(@@environc+1) # Assuming I32 for pointers
154
+ environ_buf = Malloc.malloc(@@environ_buf_size)
155
+ errno = WASI.environ_get(environ.ptr, environ_buf)
156
+
157
+ raise "Errno environ_get" if errno != 0
158
+ environ[@@environc] = environ[0] + @@environ_buf_size
159
+
160
+ # Workaround to avoid dynamic constant assignment error
161
+ Memory.store32(ENV.addr, Array32.new(@@environc))
162
+
163
+ # Now scan through arguments and turn them into a Rlang
164
+ # Array of Strings (like ARGV in Ruby)
165
+ i = 0
166
+ while i < @@environc
167
+ length = environ[i+1] - environ[i] - 1 # -1 because of null terminated
168
+ ENV[i] = String.new(environ[i], length)
169
+ # Nullify environ[i] so that String is not freed
170
+ #environ[i] = 0
171
+ i += 1
172
+ end
173
+ #environ.free
174
+
175
+ return errno
176
+ end
177
+
178
+ def self.init
179
+ self.argv_init
180
+ self.environ_init
181
+ end
182
+
132
183
  end
133
184
 
@@ -38,6 +38,8 @@ module Rlang::Parser
38
38
  @@current_address = 0
39
39
  end
40
40
 
41
+ # Append a value to the DAta object
42
+ # and return this DAta object
41
43
  def append_value(value, wtype)
42
44
  logger.warn "Data type #{@wtype} misaligned!!! (Data[:#{@label}] value #{value} at address #{@address}" \
43
45
  unless self.aligned?
@@ -49,6 +51,7 @@ module Rlang::Parser
49
51
  end
50
52
  # Always make sure current address is aligned
51
53
  self.class.align(WType::DEFAULT.size)
54
+ self
52
55
  end
53
56
 
54
57
  def aligned?
@@ -64,6 +67,8 @@ module Rlang::Parser
64
67
  @@label_table[label].address
65
68
  end
66
69
 
70
+ # Append a value to the DAta object identified by the
71
+ # label and return this DAta object object
67
72
  def self.append(label, value, wtype=WType::DEFAULT)
68
73
  logger.debug "appending #{value} to DAta[#{label}]"
69
74
  if self.exist? label
@@ -1,5 +1,7 @@
1
1
  class Integer
2
+ # Works for both signed and unsignd 32 or 64 bits integers
2
3
  def to_little_endian(byte_count)
3
- ("%0#{byte_count*2}X" % self).scan(/../).reverse.map {|byte| "\\#{byte}"}.join('')
4
+ i = (self < 0) ? 2**(byte_count*8) + self : self
5
+ ("%0#{byte_count*2}X" % i).scan(/../).reverse.map {|byte| "\\#{byte}"}.join('')
4
6
  end
5
7
  end
@@ -2,6 +2,18 @@ module Type
2
2
 
3
3
  class I64 < Numeric
4
4
  MAX = 2**64 - 1
5
+ MIN = 0
6
+ def self.signed?; true; end
7
+ def size; 8; end # size in bytes
8
+ def self.size; 8; end # size in bytes
9
+ def wasm_type; 'i64'; end
10
+ def self.wasm_type; 'i64'; end
11
+ end
12
+
13
+ class UI64 < Numeric
14
+ MAX = 2**63 - 1
15
+ MIN = -2**63
16
+ def self.signed?; false; end
5
17
  def size; 8; end # size in bytes
6
18
  def self.size; 8; end # size in bytes
7
19
  def wasm_type; 'i64'; end
@@ -9,9 +21,23 @@ module Type
9
21
  end
10
22
 
11
23
  class I32 < Numeric
12
- MAX = 2**64 - 1
24
+ MAX = 2**31 - 1
25
+ MIN = -2**31
26
+ def initialize(v); @v = Integer(v); end
27
+ def +(v); I32.new(v + @v); end
28
+ def self.signed?; true; end
29
+ def size; 4; end # size in bytes
30
+ def self.size; 4; end # size in bytes
31
+ def wasm_type; 'i32'; end
32
+ def self.wasm_type; 'i32'; end
33
+ end
34
+
35
+ class UI32 < Numeric
36
+ MAX = 2**32 - 1
37
+ MIN = 0
13
38
  def initialize(v); @v = Integer(v); end
14
39
  def +(v); I32.new(v + @v); end
40
+ def self.signed?; false; end
15
41
  def size; 4; end # size in bytes
16
42
  def self.size; 4; end # size in bytes
17
43
  def wasm_type; 'i32'; end
@@ -20,6 +46,7 @@ module Type
20
46
 
21
47
  class F64 < Numeric
22
48
  MAX = 1.7976931348623158E308
49
+ def self.signed?; true; end
23
50
  def size; 8; end # size in bytes
24
51
  def wasm_type; 'f64'; end
25
52
  def self.size; 8; end # size in bytes
@@ -29,6 +56,7 @@ module Type
29
56
  class F32 < Numeric
30
57
  MAX = 3.4028235E38
31
58
  # size in bytes
59
+ def self.signed?; true; end
32
60
  def size; 4; end
33
61
  def wasm_type; 'f32'; end
34
62
  def self.size; 4; end
@@ -60,5 +88,6 @@ module Type
60
88
  end
61
89
 
62
90
  DEFAULT = Type::I32
91
+ UNSIGNED_DEFAULT = Type::UI32
63
92
 
64
93
  end
@@ -53,6 +53,13 @@ module Rlang::Parser
53
53
  end
54
54
 
55
55
  def self.transpile(depth)
56
+ # TODO : we should probably do that in a less "hardcoded" way
57
+ # Adjust the Heap base address to start after the static DAta
58
+ # section
59
+ g_heap = Global.find(:$HEAP)
60
+ g_heap.value = [DAta.align(8), g_heap.value].max if g_heap
61
+
62
+ # Go generate code now
56
63
  indent = ' ' * depth * 2
57
64
  output = []
58
65
  @@globals.each do |g|