rlang 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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|