rlang 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/Gemfile.lock +3 -5
- data/README +11 -0
- data/bin/rlang +4 -0
- data/docs/RlangCompiler.md +2 -0
- data/docs/RlangManual.md +37 -8
- data/lib/rlang/lib/array/array32.rb +13 -4
- data/lib/rlang/lib/array/array64.rb +11 -3
- data/lib/rlang/lib/base64.rb +223 -0
- data/lib/rlang/lib/io.rb +7 -2
- data/lib/rlang/lib/malloc.rb +5 -3
- data/lib/rlang/lib/object.rb +23 -0
- data/lib/rlang/lib/rlang_core.rb +2 -1
- data/lib/rlang/lib/string.rb +95 -11
- data/lib/rlang/lib/type/i32.rb +30 -12
- data/lib/rlang/lib/type/i64.rb +0 -2
- data/lib/rlang/lib/wasi.rb +57 -6
- data/lib/rlang/parser/data.rb +5 -0
- data/lib/rlang/parser/ext/integer.rb +3 -1
- data/lib/rlang/parser/ext/type.rb +30 -1
- data/lib/rlang/parser/global.rb +7 -0
- data/lib/rlang/parser/wgenerator.rb +221 -83
- data/lib/rlang/parser/wnode.rb +41 -14
- data/lib/rlang/parser/wtype.rb +12 -6
- data/lib/rlang/parser.rb +182 -130
- data/lib/rlang/version.rb +1 -1
- data/lib/ruby/mirror/rstring.rb +16 -0
- data/lib/utils/exceptions.rb +12 -0
- data/rlang.gemspec +4 -4
- metadata +16 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 853a10a09ac23cc4cedb2c2b5bc966258cfc858673bbecc7a7bb625c8ddf4b92
|
4
|
+
data.tar.gz: f27458788eb2cccaa49bb319436979a91e93de4e54fb3fd83c28fd67b481a631
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 78a5e6da19f10887854dd40fb85e4a48d2073c10ece4acc01c07651041110eceb4c13cb67fd7251b1e0abbc310bc25134ef32c27bd2bb4e6af3488eec3a2bdf5
|
7
|
+
data.tar.gz: 3bfc1ffe8b133f4b8b2621c810af522f51fa88d44ab5dcc00a679dd0bf3eab857321d311c9b156dcd63428e62222669d87a6c1f1a501203ba0e448b44300a60f
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## 0.6.0
|
2
|
+
* Support for signed/unsigned integers (arithmetics, relational operatos, explicit and implicit type cast)
|
3
|
+
* More methods in String ([], []=, +, *, ==, !=, chr,...)
|
4
|
+
* More methods in Array ([], []=, ==, !=,...)
|
5
|
+
* More methods in I32 and I64 classes (to_s,...)
|
6
|
+
* Base 64 encoding and decidong module (same methods as in Ruby)
|
7
|
+
* Array literal ([]) supported as initializer
|
8
|
+
* Automatically adjust HEAP base address at compile time
|
9
|
+
* Various bug fixes and code cleanup
|
10
|
+
|
1
11
|
## 0.5.1
|
2
12
|
* Imported WASM methods can now be defined
|
3
13
|
* Preliminary version of WASI interface and IO class added to Rlang library
|
data/Gemfile.lock
CHANGED
@@ -13,13 +13,11 @@ GEM
|
|
13
13
|
parser (2.7.0.2)
|
14
14
|
ast (~> 2.4.0)
|
15
15
|
rake (12.3.3)
|
16
|
-
rutie (0.0.4)
|
17
16
|
simplecov (0.18.1)
|
18
17
|
docile (~> 1.1)
|
19
18
|
simplecov-html (~> 0.11.0)
|
20
19
|
simplecov-html (0.11.0)
|
21
|
-
wasmer (0.
|
22
|
-
rutie (~> 0.0.3)
|
20
|
+
wasmer (1.0.0)
|
23
21
|
|
24
22
|
PLATFORMS
|
25
23
|
ruby
|
@@ -30,7 +28,7 @@ DEPENDENCIES
|
|
30
28
|
rake (~> 12.0)
|
31
29
|
rlang!
|
32
30
|
simplecov (~> 0.18)
|
33
|
-
wasmer (~> 0
|
31
|
+
wasmer (~> 1.0)
|
34
32
|
|
35
33
|
BUNDLED WITH
|
36
|
-
2.
|
34
|
+
2.3.13
|
data/README
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
All contents here come from http://www.wolczko.com/st80/
|
2
|
+
|
3
|
+
image.tar.gz:original Xerox virtual image (as provided on tape by Xerox PARC)
|
4
|
+
manual.pdf: the manual that came with the tape (incl. errata for the Blue Book implementation section)
|
5
|
+
st.tar.gz: C implementation of the Smalltalk VM from Mario Wolczko
|
6
|
+
VMsrc.shar: Smalltalk VM sourcesas re-keyed from the Blue Book by Mario Wolczko
|
7
|
+
|
8
|
+
Xerox Star
|
9
|
+
----------
|
10
|
+
8010_hd_images.zip: Xerox Star images. hard disk images for Viewpoint 2.0, XDE 5.0, and The Harmony release of Interlisp-D (Not Smalltalk)
|
11
|
+
See article at https://engblg.livingcomputers.org/index.php/2019/01/19/introducing-darkstar-a-xerox-star-emulator/
|
data/bin/rlang
CHANGED
@@ -70,6 +70,10 @@ options:
|
|
70
70
|
options[:wasm] = v
|
71
71
|
end
|
72
72
|
|
73
|
+
opts.on("-c", "--comments", "Include comments in WAT source file") do |v|
|
74
|
+
options[:comments] = v
|
75
|
+
end
|
76
|
+
|
73
77
|
opts.on("-S", "--start FUNCTION", "Function name where execution starts (default '_start')") do |function|
|
74
78
|
options[:start] = function
|
75
79
|
end
|
data/docs/RlangCompiler.md
CHANGED
@@ -19,6 +19,7 @@ Usage: rlang [options] rlang_file.rb
|
|
19
19
|
-w, --wat Generate WAT source file
|
20
20
|
-a, --ast Generate Ruby AST file
|
21
21
|
-s, --wasm Generate WASM bytecode file
|
22
|
+
-c, --comments Include comments in WAT source file
|
22
23
|
-S, --start FUNCTION Function name where execution starts (default '_start')
|
23
24
|
-o, --output FILE Write output to file
|
24
25
|
-v, --verbose [LEVEL] Verbosity level (fatal, error, warn, info, debug)
|
@@ -32,6 +33,7 @@ Usage: rlang [options] rlang_file.rb
|
|
32
33
|
* **-w, --wat**: parse Rlang file and generate WAT source code
|
33
34
|
* **-a, --ast**: parse Rlang file and generate the Ruby abstract syntax tree
|
34
35
|
* **-s, --wasm**: parse Rlang file, generate WAT source code and compile it to WASM bytecode
|
36
|
+
* **-c, --comments**: include the Rlang comments at the corresponding location in the generated WAT source file.
|
35
37
|
* **-S, --start**: function to use as the execution starting point of the WASM module (default is `_start`)
|
36
38
|
* **-o, --output FILE**: send rlang output to FILE
|
37
39
|
* **-v, --verbose [LEVEL]**: verbosity level (fatal, error, warn, info, debug). Default is warn
|
data/docs/RlangManual.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# The Rlang language
|
2
2
|
|
3
|
-
Rlang is a subset of the Ruby language that is meant to provide a
|
3
|
+
Rlang is a subset of the Ruby language that is meant to provide a good level of abstraction and expressiveness while keeping its compilation to WebAssembly straightforward.
|
4
4
|
|
5
5
|
Ruby programmers will feel at home with Rlang and non Ruby programmers will find it useful to generate efficient WebAssembly code from a language that is much easier to use.
|
6
6
|
|
@@ -21,6 +21,7 @@ Rlang provides:
|
|
21
21
|
* Arithmetic, relational and logical operators
|
22
22
|
* WebAssembly source code (WAT) inlining
|
23
23
|
* Requiring other Rlang or WAT files
|
24
|
+
* Importing and exporting WASM functions
|
24
25
|
* A Rlang library (written in Rlang of course) that you can reuse in your own WebAssembly module
|
25
26
|
|
26
27
|
Here is a sample of Rlang code to whet your appetite:
|
@@ -117,7 +118,7 @@ end
|
|
117
118
|
The code is pretty straightforward: a new square instance is created, its side attribute is set to 10. As you would expect, the call to the Square#area method returns 100 and the perimeter is 40.
|
118
119
|
|
119
120
|
### Class attribute type
|
120
|
-
In the example above the `side` attribute is implicitely using the `:I32` (
|
121
|
+
In the example above the `side` attribute is implicitely using the `:I32` (signed 32-bit integer) WebAssembly type. It's the default Rlang type. Assuming you want to manage big squares, you'd have to use `:I64` (double integer) like this for the `side` attribute and also instruct Rlang that the return value of area is also `:I64` (more on this later).
|
121
122
|
|
122
123
|
```ruby
|
123
124
|
class Square
|
@@ -229,9 +230,9 @@ Rlang also gives you the ability to declare the return type of a method like thi
|
|
229
230
|
result :class_name, :method_name, :your_type_here
|
230
231
|
```
|
231
232
|
|
232
|
-
This result directive must be used to instruct the compiler about the return type of a method if
|
233
|
+
This result directive must be used to instruct the compiler about the return type of a method if the compiler has not yet compiled this method (e.g. the method definition is coming later in your source code) or when calling a method from another class defined in a different file not yet compiled. Keep in mind that this is only needed if the method returns something different than the default type (`:I32`).
|
233
234
|
|
234
|
-
Note: in this directive `:method_name` symbol starts with a `#` characters if it refers to an instance method. Without
|
235
|
+
Note: in this directive `:method_name` symbol starts with a `#` characters if it refers to an instance method. Without the `#` it refers to a class method.
|
235
236
|
|
236
237
|
For an example see the [test_def_result_type_declaration.rb](https://github.com/ljulliar/rlang/blob/master/test/rlang_test_files/test_def_result_type_declaration.rb), a Rlang file that is part of the Rlang test suite.
|
237
238
|
|
@@ -294,10 +295,10 @@ The example above is taken from the Rlang WASI class that defines the interface
|
|
294
295
|
|
295
296
|
|
296
297
|
## Rlang types
|
297
|
-
The types currently supported by Rlang are integers either long (`:I32`)
|
298
|
+
The types currently supported by Rlang are integers either signed long (`:I32`), unsigned long (`:UI32`), signed double (`:I64`), unsigned double (`:UI64`) or a class type. Float types (`:F32`, `:F64`) may follow in a future version. By default Rlang assumes that any integer literal, variable, argument,... is of type `:I32`. If you need it to be of a different type you must declare it explicitely in the method body (see above) or cast it explicitely (see below).
|
298
299
|
|
299
300
|
### Implicit type cast
|
300
|
-
Only in rare cases will you use the `local` directive in methods as Rlang does its best to infer the type of a variable from its first assigned value. As an example, in the code below, the fact that `arg1` is known to be an `:I64` type of argument is enough to auto-magically create lvar as
|
301
|
+
Only in rare cases will you use the `local` directive in methods as Rlang does its best to infer the type of a variable from its first assigned value. As an example, in the code below, the fact that `arg1` is known to be an `:I64` type of argument is enough to auto-magically create lvar as an `:I64` local variable too.
|
301
302
|
|
302
303
|
```ruby
|
303
304
|
def m_local_var(arg1)
|
@@ -307,7 +308,7 @@ def m_local_var(arg1)
|
|
307
308
|
end
|
308
309
|
```
|
309
310
|
|
310
|
-
Conversely in the method below the first statement `lvar = 10` auto-vivifies `lvar` as a variable of type `:I32` (the default Rlang type). On the next line, Rlang evaluates `arg1 * 100` as an `:I64` result because `arg1` is declared as being of type `:I64`. Similarly as the type of `lvar` local variable was auto-vivified as `:I32`, the result of the expression `arg1 * 100` will be type cast from `:I64` to `:I32`. Note that
|
311
|
+
Conversely in the method below the first statement `lvar = 10` auto-vivifies `lvar` as a variable of type `:I32` (the default Rlang type). On the next line, Rlang evaluates `arg1 * 100` as an `:I64` result because `arg1` is declared as being of type `:I64`. Similarly as the type of `lvar` local variable was auto-vivified as `:I32`, the result of the expression `arg1 * 100` will be type cast from `:I64` to `:I32`. Note that such a type cast may of course result in the value being truncated and the Rlang compiler will emit a warning accordingly.
|
311
312
|
|
312
313
|
```ruby
|
313
314
|
def self.m_local_var(arg1)
|
@@ -318,6 +319,33 @@ def self.m_local_var(arg1)
|
|
318
319
|
end
|
319
320
|
```
|
320
321
|
|
322
|
+
### Implicit type cast precedence
|
323
|
+
|
324
|
+
Rlang follows the C IEC/ISO Standard to implicitely convert types. When operands of different types are mixed in arithmetic or relational operators, Rlang will conver them according to the following priority order from the highest priority to the lowest:
|
325
|
+
|
326
|
+
`:F64`, `:F32`, `:UI64`, `:I64`, `:Class`, `:UI32`, `:I32`
|
327
|
+
|
328
|
+
Let's take a few examples:
|
329
|
+
* If you use 32 bit floating point numbers and 64 bit floating point numbers in the same expression all `:F32` values will be converted to `:F64`
|
330
|
+
* Similarly if you mix `:F32` values and `:I64` values, all 64-bit integers will be converted to 32-bit floating point values before evaluating the expression
|
331
|
+
* **IMPORTANT** note that unsigned integers `:UI64` and `:UI32`have a higher priority than their signed counter part `:I64` and `:I32`. This means that when mixing signed and unsigned integer values in the same expression, the signed integers will be reinterpreted as its unsigned equivalent bitwise. As an example in this context an `:I32` with a value of -6 will be reinterpreted as an`:UI32` with a value of 4294967290. So be very cautious when mixing signed and unsigned integers as this may be give somewhat suprising results especially when using relational operators such >, <, >=,...
|
332
|
+
|
333
|
+
### Pointer arithmetics
|
334
|
+
|
335
|
+
In the types priority order mentioned above, the `:Class` type designate any value pointing to a class instance, in other word an object. This means that object pointers are values that you can process through arithmetic and relational operators like in C. A pointer to an object is a 32 bit memory address that has type casting precedence over `:UI32` and `:I32` types.
|
336
|
+
|
337
|
+
Consequently when doing some arithmetics on object pointers like an addition or a substraction the integer vale will be interpreted as a multiple of the object size as if you were moving an index over objects of the same type in memory. Again this behavior is similar to the C language.
|
338
|
+
|
339
|
+
|
340
|
+
```ruby
|
341
|
+
class MyClass
|
342
|
+
up = Header.new
|
343
|
+
next_hdr = up + 1
|
344
|
+
#...
|
345
|
+
end
|
346
|
+
```
|
347
|
+
In the example above, a new header object is created and it meory location is stored in the up variable. When adding 1 to the up variable, Rlang knows that up is of type Header and will therefore increase up not by 1 but by the size in byted of the Header Object in memory. You can see examples of pointer arithmetics in the memory allocator of Rlang in lib/malloc.rb.
|
348
|
+
|
321
349
|
### Explicit type cast
|
322
350
|
If Rlang is not capable of guessing the proper type of an expression or variable, you can explicitely cast it to any known type. Look at this example:
|
323
351
|
|
@@ -334,7 +362,7 @@ The first line will auto-vivify the `@@cvar` class variable as type `:I64`.
|
|
334
362
|
|
335
363
|
The second example turns the value `123876` into a pointer to a `Square` object. It's pretty much like turning an integer into a pointer to a memory address in C.
|
336
364
|
|
337
|
-
For
|
365
|
+
For type cast a number or an expression to native type you can also use shortcuts like `100.to_I64` or `100.to_UI32`, etc...
|
338
366
|
|
339
367
|
Note that type cast can be used anywhere in the code whether in class body or method definition.
|
340
368
|
|
@@ -510,6 +538,7 @@ For now, the Rlang library is very modest and containoffers the following classe
|
|
510
538
|
* Malloc.malloc(nbytes) : dynamically allocates nbytes of memory and return address of the allocated memory space or -1 if it fails
|
511
539
|
* Malloc.free(address) : frees the block of memory at the given address
|
512
540
|
* **Object** class: provides a couple of object management method. Use `Object.free` to free an object.
|
541
|
+
* **Array32**, **Array64** : Arrays can be initialized with the usual bracket operator '[]'. When the array is initialized at compile time (statically) such as for constants or class variables you can only use integers in the array initializers (e.g.`[0, 100, 200]`). When the array is initialized at runtime (dynamically) such as in the body of a method definition you can either use integers or any Rlang object (e.g. `[ 1, 2, "A string", my_object]`)
|
513
542
|
* **String** class: string are initialized in Rlang by using a string literal like `"This is my string"`. String methods supported are very minimal for the moment. See [rlang/lib/String.rb](https://github.com/ljulliar/rlang/blob/master/lib/rlang/lib/string.rb). Feel free to improve.
|
514
543
|
|
515
544
|
As a side note, the dynamic memory allocator currently used in Rlang is shamelessly adapted from the example provided in the famous Kernigan & Richie C book 2nd edition. Take a look at the [C version](https://github.com/ljulliar/rlang/blob/master/lib/rlang/lib/malloc.c) and see how easy it is to rewrite it in [Rlang](https://github.com/ljulliar/rlang/blob/master/lib/rlang/lib/malloc.rb).
|
@@ -5,6 +5,7 @@
|
|
5
5
|
# 4 bytes object array class
|
6
6
|
require_relative '../memory'
|
7
7
|
require_relative '../kernel'
|
8
|
+
require_relative '../type'
|
8
9
|
#require_relative '../string'
|
9
10
|
|
10
11
|
|
@@ -18,16 +19,23 @@ class Array32
|
|
18
19
|
# pointers to objects
|
19
20
|
# Arrays are fixed size for now
|
20
21
|
def initialize(count)
|
21
|
-
|
22
|
+
if count == 0
|
23
|
+
@ptr = 0
|
24
|
+
else
|
25
|
+
# Memory size is count * 4 bytes
|
26
|
+
@ptr = Object.allocate(count << 2)
|
27
|
+
end
|
22
28
|
@count = count
|
23
29
|
end
|
24
30
|
|
25
|
-
def size;
|
31
|
+
def size; @count; end
|
26
32
|
def length; @count; end
|
33
|
+
def empty?; @count == 0; end
|
27
34
|
|
28
35
|
def [](idx)
|
29
36
|
result :I32
|
30
|
-
raise "Index out of bound" if idx >= @count
|
37
|
+
raise "Index out of bound" if idx >= @count || idx < -@count
|
38
|
+
idx = @count + idx if idx <0
|
31
39
|
# offset in memory for elt #idx is idx * 4
|
32
40
|
Memory.load32(@ptr + (idx << 2))
|
33
41
|
end
|
@@ -35,7 +43,8 @@ class Array32
|
|
35
43
|
def []=(idx, value)
|
36
44
|
arg value: :I32
|
37
45
|
result :I32
|
38
|
-
raise "Index out of bound" if idx >= @count
|
46
|
+
raise "Index out of bound" if idx >= @count || idx < -@count
|
47
|
+
idx = @count + idx if idx <0
|
39
48
|
# offset in memory for elt #idx is idx * 4
|
40
49
|
Memory.store32(@ptr + (idx << 2), value)
|
41
50
|
value
|
@@ -5,6 +5,7 @@
|
|
5
5
|
# 4 bytes object array class
|
6
6
|
require_relative '../memory'
|
7
7
|
require_relative '../object'
|
8
|
+
require_relative '../type'
|
8
9
|
require_relative '../string'
|
9
10
|
|
10
11
|
|
@@ -16,16 +17,23 @@ class Array64
|
|
16
17
|
# pointers to objects
|
17
18
|
# Arrays are fixed size for now
|
18
19
|
def initialize(count)
|
19
|
-
|
20
|
+
# Avoid allocating 0 bytes in memory
|
21
|
+
if count == 0
|
22
|
+
@ptr = 0
|
23
|
+
else
|
24
|
+
# Memory size is count * 8 bytes
|
25
|
+
@ptr = Object.allocate(count << 3)
|
26
|
+
end
|
20
27
|
@count = count
|
21
28
|
end
|
22
29
|
|
23
30
|
def size; @count; end
|
24
31
|
def length; @count; end
|
32
|
+
def empty?; self.size == 0; end
|
25
33
|
|
26
34
|
def [](idx)
|
27
35
|
result :I64
|
28
|
-
raise "Index out of bound" if idx >= @count
|
36
|
+
raise "Index out of bound" if idx >= @count || idx < -@count
|
29
37
|
# offset in memory for elt #idx is idx * 8
|
30
38
|
Memory.load64(@ptr + (idx << 3))
|
31
39
|
end
|
@@ -33,7 +41,7 @@ class Array64
|
|
33
41
|
def []=(idx, value)
|
34
42
|
arg value: :I64
|
35
43
|
result :I64
|
36
|
-
raise "Index out of bound" if idx >= @count
|
44
|
+
raise "Index out of bound" if idx >= @count || idx < -@count
|
37
45
|
# offset in memory for elt #idx is idx * 8
|
38
46
|
Memory.store64(@ptr + (idx << 3), value)
|
39
47
|
value
|
@@ -0,0 +1,223 @@
|
|
1
|
+
# Rlang WebAssembly compiler
|
2
|
+
# Copyright (c) 2019-2022, Laurent Julliard and contributors
|
3
|
+
# All rights reserved.
|
4
|
+
|
5
|
+
require 'kernel'
|
6
|
+
require 'string'
|
7
|
+
require 'array'
|
8
|
+
|
9
|
+
module Base64
|
10
|
+
|
11
|
+
include Kernel
|
12
|
+
|
13
|
+
BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
14
|
+
BASE64_CHARS_URLSAFE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
|
15
|
+
PAD = "="
|
16
|
+
LINE_SEP = "\n" # Would be "\r\n" on Windows
|
17
|
+
|
18
|
+
# Tables of valid ASCII char maps for Base64 decoding.
|
19
|
+
# -1 : the char is invalid
|
20
|
+
# >= 0 : the binary value to use for decoding (note: the '=' sign is also 0)
|
21
|
+
#
|
22
|
+
BASE64_CHAR_MAP =
|
23
|
+
[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
24
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
|
25
|
+
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,
|
26
|
+
9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26,
|
27
|
+
27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
|
28
|
+
51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
29
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
30
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
31
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
32
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
33
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
34
|
+
|
35
|
+
BASE64_CHAR_MAP_URLSAFE =
|
36
|
+
[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
37
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
|
38
|
+
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,
|
39
|
+
9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, -1, 26,
|
40
|
+
27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
|
41
|
+
51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
42
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
43
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
44
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
45
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
46
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
|
47
|
+
|
48
|
+
|
49
|
+
# Generic base 64 encoding
|
50
|
+
# Derived from
|
51
|
+
# http://www.java2s.com/Code/Java/Development-Class/AfastandmemoryefficientclasstoencodeanddecodetoandfromBASE64infullaccordancewithRFC2045.htm)
|
52
|
+
def self._encode64(bin, line_sep, base64_chars)
|
53
|
+
arg bin: :String, base64_chars: :String
|
54
|
+
local str: :String
|
55
|
+
result :String
|
56
|
+
|
57
|
+
# Check special case
|
58
|
+
return "" if bin.empty?
|
59
|
+
slen = bin.length
|
60
|
+
|
61
|
+
# Number of even 24 bits (groups of 3 bytes)
|
62
|
+
elen = (slen / 3) * 3
|
63
|
+
# Encoded character count
|
64
|
+
ccnt = ((slen - 1) / 3 + 1) << 2
|
65
|
+
# Size of encoded string (incl. line separators)
|
66
|
+
# Note : Ruby implementation always add a \n at the end
|
67
|
+
# hence the +1
|
68
|
+
dlen = ccnt
|
69
|
+
dlen += ((ccnt - 1) / 60 + 1) * LINE_SEP.length if line_sep
|
70
|
+
|
71
|
+
# Allocate the proper size for encoded string
|
72
|
+
# to avoid allocating many string objects during
|
73
|
+
# concatenation
|
74
|
+
str = String.new(0, dlen)
|
75
|
+
|
76
|
+
# Encode even 24 bits
|
77
|
+
s=0; d=0; cc=0
|
78
|
+
while s < elen
|
79
|
+
# Copy next three bytes into lower 24 bits of int,
|
80
|
+
# paying attention to sign.
|
81
|
+
i = bin[s].ord << 16 | bin[s+1].ord << 8 | bin[s+2].ord
|
82
|
+
s += 3
|
83
|
+
|
84
|
+
# Encode the int into four chars
|
85
|
+
str[d] = base64_chars[(i >> 18) & 0x3f]; d += 1
|
86
|
+
str[d] = base64_chars[(i >> 12) & 0x3f]; d += 1
|
87
|
+
str[d] = base64_chars[(i >> 6) & 0x3f]; d += 1
|
88
|
+
str[d] = base64_chars[i & 0x3f]; d += 1
|
89
|
+
cc += 1
|
90
|
+
|
91
|
+
# Add optional line separator each 60 chars in Ruby
|
92
|
+
if (line_sep && cc == 15 && d < dlen - 1)
|
93
|
+
str[d] = LINE_SEP; d += LINE_SEP.length
|
94
|
+
cc = 0
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Pad and encode last bits if source isn't even 24 bits.
|
99
|
+
left = slen - elen # 0 - 2
|
100
|
+
if left > 0
|
101
|
+
# Prepare the last int
|
102
|
+
i = bin[elen].ord << 10
|
103
|
+
i |= (bin[slen - 1].ord << 2) if left == 2
|
104
|
+
|
105
|
+
# Set last four chars
|
106
|
+
str[d] = base64_chars[i >> 12]; d += 1
|
107
|
+
str[d] = base64_chars[(i >> 6) & 0x3f]; d += 1
|
108
|
+
if left == 2
|
109
|
+
str[d] = base64_chars[i & 0x3f]
|
110
|
+
else
|
111
|
+
str[d] = PAD
|
112
|
+
end
|
113
|
+
d += 1
|
114
|
+
str[d] = PAD; d += 1
|
115
|
+
end
|
116
|
+
|
117
|
+
str[d] = LINE_SEP if line_sep
|
118
|
+
return str
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
# Decodes a BASE64 encoded String. All illegal characters will be
|
123
|
+
# ignored and can handle both arrays with and without line separators.
|
124
|
+
#
|
125
|
+
# Derived from
|
126
|
+
# http://www.java2s.com/Code/Java/Development-Class/AfastandmemoryefficientclasstoencodeanddecodetoandfromBASE64infullaccordancewithRFC2045.htm)
|
127
|
+
|
128
|
+
def self._decode64(str, base64_chars, base64_char_map)
|
129
|
+
arg str: :String, base64_chars: :String, base64_char_map: :Array32
|
130
|
+
local bin: :String
|
131
|
+
result :String
|
132
|
+
|
133
|
+
# Check special case
|
134
|
+
return "" if (slen = str.length) == 0
|
135
|
+
|
136
|
+
# Count illegal characters (including '\r', '\n') to know what
|
137
|
+
# size the returned array will be, so we don't have to reallocate
|
138
|
+
# & copy it later.
|
139
|
+
# Number of separator characters. (Actually illegal characters,
|
140
|
+
# but that's a bonus...)
|
141
|
+
sepcnt = 0; i = 0
|
142
|
+
while i < slen
|
143
|
+
sepcnt += 1 if base64_char_map[str[i].ord] < 0
|
144
|
+
i += 1
|
145
|
+
end
|
146
|
+
|
147
|
+
# Check that legal chars (including '=') are evenly divideable
|
148
|
+
# by 4 as specified in RFC 2045.
|
149
|
+
return "" if (slen - sepcnt) % 4 != 0
|
150
|
+
|
151
|
+
# Count padding chars from the end
|
152
|
+
pad = 0; i = slen-1
|
153
|
+
while i > 0 && base64_char_map[str[i].ord] <= 0
|
154
|
+
pad += 1 if str[i] == PAD
|
155
|
+
i -= 1
|
156
|
+
end
|
157
|
+
|
158
|
+
# Preallocate String of exact length
|
159
|
+
len = ((slen - sepcnt) * 6 >> 3) - pad
|
160
|
+
bin = String.new(0, len)
|
161
|
+
|
162
|
+
# Go on decoding
|
163
|
+
s = 0; d = 0
|
164
|
+
while d < len
|
165
|
+
# Assemble 3 bytes into an int from 4 valid characters.
|
166
|
+
i = 0; j = 0
|
167
|
+
while j < 4
|
168
|
+
c = base64_char_map[str[s].ord]; s += 1
|
169
|
+
# j increases only if a valid char is found
|
170
|
+
if c != -1
|
171
|
+
i |= c << (18 - j * 6)
|
172
|
+
j += 1
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# Now decode the int and add 3 chars to the bin string
|
177
|
+
bin[d] = (i >> 16 & 0xff).chr; d += 1
|
178
|
+
if d < len
|
179
|
+
bin[d] = (i >> 8 & 0xff).chr; d += 1
|
180
|
+
if d < len
|
181
|
+
bin[d] = (i & 0xff).chr; d += 1
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
return bin
|
187
|
+
end
|
188
|
+
|
189
|
+
def self.decode64(str)
|
190
|
+
arg str: :String
|
191
|
+
result :String
|
192
|
+
self._decode64(str, BASE64_CHARS, BASE64_CHAR_MAP)
|
193
|
+
end
|
194
|
+
|
195
|
+
def self.encode64(bin)
|
196
|
+
arg bin: :String
|
197
|
+
result :String
|
198
|
+
self._encode64(bin, 1, BASE64_CHARS)
|
199
|
+
end
|
200
|
+
|
201
|
+
def self.strict_decode64(str)
|
202
|
+
arg str: :String
|
203
|
+
self._decode64(str, BASE64_CHARS, BASE64_CHAR_MAP)
|
204
|
+
end
|
205
|
+
|
206
|
+
def self.strict_encode64(bin)
|
207
|
+
arg bin: :String
|
208
|
+
result :String
|
209
|
+
self._encode64(bin, 0, BASE64_CHARS)
|
210
|
+
end
|
211
|
+
|
212
|
+
def self.urlsafe_decode64(str)
|
213
|
+
arg str: :String
|
214
|
+
self._decode64(str, BASE64_CHARS_URLSAFE, BASE64_CHAR_MAP_URLSAFE)
|
215
|
+
end
|
216
|
+
|
217
|
+
def self.urlsafe_encode64(bin)
|
218
|
+
arg bin: :String
|
219
|
+
result :String
|
220
|
+
self._encode64(bin, 0, BASE64_CHARS_URLSAFE)
|
221
|
+
end
|
222
|
+
|
223
|
+
end
|
data/lib/rlang/lib/io.rb
CHANGED
@@ -40,11 +40,16 @@ class IO
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def read
|
43
|
-
result :
|
43
|
+
result :String
|
44
|
+
local stg: :String
|
44
45
|
iovec = WASI::IOVec.new(1)
|
45
46
|
errno = WASI.fd_read(@fd, iovec.iovs.ptr, 1, @@num_bytes_read.addr)
|
46
47
|
# -1 below because of \0 terminated string
|
47
|
-
String.new(iovec.iovs[0], @@num_bytes_read-1)
|
48
|
+
stg = String.new(iovec.iovs[0], @@num_bytes_read-1)
|
49
|
+
# Nullify the iovs entry used by the String object so it is not freed
|
50
|
+
iovec.iovs[0] = 0
|
51
|
+
iovec.free
|
52
|
+
stg
|
48
53
|
end
|
49
54
|
|
50
55
|
end
|
data/lib/rlang/lib/malloc.rb
CHANGED
@@ -37,7 +37,7 @@ DAta[:dummy_malloc_data] = [0, 0, 0, 0]
|
|
37
37
|
|
38
38
|
class Header
|
39
39
|
attr_accessor :ptr, :size
|
40
|
-
attr_type ptr: :Header, size: :
|
40
|
+
attr_type ptr: :Header, size: :UI32
|
41
41
|
end
|
42
42
|
|
43
43
|
class Malloc
|
@@ -55,7 +55,8 @@ class Malloc
|
|
55
55
|
# malloc: allocate n bytes of memory and return pointer
|
56
56
|
# to data block
|
57
57
|
def self.malloc(nbytes)
|
58
|
-
|
58
|
+
arg nbytes: :UI32
|
59
|
+
local p: :Header, prevp: :Header, nunits: :UI32
|
59
60
|
|
60
61
|
# allocate memory by chunk of units (the unit is
|
61
62
|
# the size of a Header object here)
|
@@ -107,6 +108,7 @@ class Malloc
|
|
107
108
|
|
108
109
|
# morecore: ask system for more memory
|
109
110
|
def self.morecore(nu)
|
111
|
+
arg nu: :UI32
|
110
112
|
result :Header
|
111
113
|
local up: :Header
|
112
114
|
|
@@ -122,7 +124,7 @@ class Malloc
|
|
122
124
|
|
123
125
|
# Free memory block
|
124
126
|
def self.free(ap)
|
125
|
-
arg ap: :
|
127
|
+
arg ap: :UI32
|
126
128
|
result :none
|
127
129
|
local bp: :Header, p: :Header
|
128
130
|
|
data/lib/rlang/lib/object.rb
CHANGED
@@ -26,4 +26,27 @@ class Object
|
|
26
26
|
result :String
|
27
27
|
"Object <addr>"
|
28
28
|
end
|
29
|
+
|
30
|
+
def object_id
|
31
|
+
result :I32
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def eql?(object)
|
36
|
+
result :I32
|
37
|
+
inline wat: '(i32.eq
|
38
|
+
(local.get $_self_)
|
39
|
+
(local.get $object))',
|
40
|
+
wtype: :I32,
|
41
|
+
ruby: 'self.object_id == object.object_id'
|
42
|
+
end
|
43
|
+
|
44
|
+
def ==(object)
|
45
|
+
self.eql?(object)
|
46
|
+
end
|
47
|
+
|
48
|
+
def !=(object)
|
49
|
+
!(self == object)
|
50
|
+
end
|
51
|
+
|
29
52
|
end
|
data/lib/rlang/lib/rlang_core.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
#
|
5
5
|
# Rlang core library classes and modules
|
6
6
|
#
|
7
|
-
|
7
|
+
|
8
8
|
require_relative './memory'
|
9
9
|
require_relative './unistd'
|
10
10
|
require_relative './malloc'
|
@@ -12,3 +12,4 @@ require_relative './object'
|
|
12
12
|
require_relative './kernel'
|
13
13
|
require_relative './string'
|
14
14
|
require_relative './array'
|
15
|
+
require_relative './type'
|