rlang 0.4.1 → 0.5.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 +4 -1
- data/Gemfile.lock +1 -1
- data/README.md +15 -9
- data/docs/RlangManual.md +26 -4
- data/lib/rlang/lib/array/array32.rb +43 -0
- data/lib/rlang/lib/array/array64.rb +43 -0
- data/lib/rlang/lib/array.rb +6 -0
- data/lib/rlang/lib/kernel.rb +18 -0
- data/lib/rlang/lib/malloc.rb +5 -3
- data/lib/rlang/lib/memory.rb +102 -2
- data/lib/rlang/lib/object.rb +11 -4
- data/lib/rlang/lib/string.rb +1 -0
- data/lib/rlang/lib/unistd.rb +1 -2
- data/lib/rlang/lib.rb +4 -2
- data/lib/rlang/parser/attr.rb +9 -13
- data/lib/rlang/parser/const.rb +105 -1
- data/lib/rlang/parser/cvar.rb +10 -6
- data/lib/rlang/parser/data.rb +5 -2
- data/lib/rlang/parser/ivar.rb +3 -7
- data/lib/rlang/parser/klass.rb +8 -35
- data/lib/rlang/parser/method.rb +22 -11
- data/lib/rlang/parser/module.rb +143 -0
- data/lib/rlang/parser/wgenerator.rb +190 -90
- data/lib/rlang/parser/wnode.rb +296 -121
- data/lib/rlang/parser/wtype.rb +18 -1
- data/lib/rlang/parser.rb +224 -113
- data/lib/rlang/version.rb +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a7fd26f4ab304200f0319e23e1e8529e538ea058a58fe4571e0e3525c2c5ce14
|
4
|
+
data.tar.gz: 88bb4ec22b5a2571944693da8ea21d0e1379fb41b3c9ae85d91851a2f8569d9b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f6c92dcfec61a4df573d2c911882f346fb242315596220e25aa547998f137b8578f18ca62467c77af2b75e92ea73d87a21cbc37eae1bd56e89038bc62fca2264
|
7
|
+
data.tar.gz: b9e09724905b3175904258174c834b8d52b9f7ae99c7046e81e13f97e699d94b53f110b70763283992e71c7d6a2f3d0eb9d9cba60a30a1ef319338f1ec580919
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
-
## 0.
|
1
|
+
## 0.5.0
|
2
2
|
* Class attributes syntac now identical to plain Ruby
|
3
3
|
* Very preliminary version of Rlang String class
|
4
|
+
* Class in class definition and module supported
|
5
|
+
* Class inheritance
|
6
|
+
* Basic array class
|
4
7
|
|
5
8
|
## 0.4.0
|
6
9
|
* Object instances, instance methods and instance variables now supported
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,12 +1,19 @@
|
|
1
|
-
# Rlang : a
|
1
|
+
# Rlang : a native Ruby to WebAssembly compiler
|
2
2
|
|
3
3
|
Rlang is meant to generate fast and uncluttered [WebAssembly](https://webassembly.org) code from the comfort of the Ruby language.
|
4
4
|
|
5
|
-
Rlang is actually two things: 1) a
|
5
|
+
Rlang is actually two things: 1) a subset of the Ruby language and 2) a **compiler** transforming this Ruby subset in a native, fully runnable WebAssembly module.
|
6
|
+
|
7
|
+
So in summary what Rlang does is:
|
8
|
+
<p align="center"><b>
|
9
|
+
Ruby source code → Rlang compiler → WebAssembly bytecode
|
10
|
+
</b></p>
|
11
|
+
|
12
|
+
Rlang must not be confused with other projects claiming to "compile" Ruby to WebAssembly. What they really do is to actually compile a mruby VM written in C in Webassembly (using tools like emscripten) and then run that VM in a Webassembly runtime.
|
6
13
|
|
7
14
|
Rlang can be seen as a foundational language that can help you quickly develop and debug high performance WebAssembly modules. For the rationale behind the creation of Rlang see [below](#why-rlang).
|
8
15
|
|
9
|
-
This is still a young project but Rlang has already been successfully tested with some real code such as the dynamic memory allocator provided with the Rlang library. It will keep mproving over time, always with the goal of generating crisp and uncluttered
|
16
|
+
This is still a young project but Rlang has already been successfully tested with some real code such as the dynamic memory allocator provided with the Rlang library. It will keep mproving over time, always with the goal of generating crisp and uncluttered WebAssembly code.
|
10
17
|
|
11
18
|
If you want to help with Rlang see [How you can help](#how-you-can-help).
|
12
19
|
|
@@ -22,7 +29,7 @@ Rlang is available as a gem from rubygems.org. So simply run the following comma
|
|
22
29
|
```
|
23
30
|
$ gem install rlang
|
24
31
|
```
|
25
|
-
Alternatively, if you clone this git repo and play with the Rlang source code you can generate your own local gem and install it
|
32
|
+
Alternatively, if you clone this git repo and play with the Rlang source code you can generate your own local gem and install it as follows:
|
26
33
|
|
27
34
|
```
|
28
35
|
$ bundle install
|
@@ -33,7 +40,7 @@ $ gem install --local rlang-x.y.z.gem
|
|
33
40
|
To check that the installation went well, run `rlang --help` and see if the help message displays correctly.
|
34
41
|
|
35
42
|
## A Quick example
|
36
|
-
An example is always worth a thousand words, so here is a quick one
|
43
|
+
An example is always worth a thousand words, so here is a quick one showing you how to compile some Rang code and run it from your browser. Since Chrome, Chromium, Firefox and Safari embed a WebAssembly runtime it is the easiest way to test your compiled Rlang code.
|
37
44
|
|
38
45
|
Navigate to the Fibonacci directory in [examples/fib](https://github.com/ljulliar/rlang/blob/master/examples/fib/) and download the three files from this directory: fib.rb, index.html, server.rb. Alternatively you can git clone the repo and go directly in that directory.
|
39
46
|
|
@@ -50,15 +57,14 @@ Point your browser to [http://localhost:8080](http://localhost:8080), a simple p
|
|
50
57
|
|
51
58
|
That was easy, right ?
|
52
59
|
|
53
|
-
|
54
60
|
## The Rlang language
|
55
61
|
Ruby features supported by Rlang are detailed in the [Rlang Manual](https://github.com/ljulliar/rlang/blob/master/docs/RlangManual.md)
|
56
62
|
|
57
63
|
You can look at the rlang test suite in [test/rlang_test_files](https://github.com/ljulliar/rlang/blob/master/test/rlang_test_files/) to get a flavor of the subset of Ruby currently supported.
|
58
64
|
|
59
|
-
For a more involved example of
|
65
|
+
For a more involved example of Rlang code, I invite you to look at the [dynamic memory allocator](https://github.com/ljulliar/rlang/blob/master/lib/rlang/lib/malloc.rb) provided with the Rlang library.
|
60
66
|
|
61
|
-
## rlang compiler
|
67
|
+
## The rlang compiler
|
62
68
|
The Rlang compiler can be invoked through the `rlang` command. See the [Rlang Compiler Documentation](https://github.com/ljulliar/rlang/blob/master/docs/RlangCompiler.md) for more details about the command line options.
|
63
69
|
|
64
70
|
Keep in mind that Rlang is **NOT** a Ruby interpreter or a Ruby VM executing some kind of bytecode. It does actually statically **compile** the Rlang language to WebAssembly code pretty much like gcc or llvm compiles C/C++ code to machine assembly language.
|
@@ -70,7 +76,7 @@ One of the big benefits of Rlang being a subset of the Ruby language is that you
|
|
70
76
|
## Why Rlang?
|
71
77
|
This project was created out of the need to develop a Virtual Machine written in WebAssembly capable of interpreting the [Rubinius](https://github.com/rubinius/rubinius) bytecode. And yes, ultimately run a native Ruby VM in a browser :-)
|
72
78
|
|
73
|
-
After a first proof of concept written directly by hand in WebAssembly (WAT code) it became clear that writing a full fledged VM directly in WebAssembly was going to be tedious, complex and unnecessarily painful.
|
79
|
+
After a first proof of concept written directly by hand in WebAssembly (WAT source code) it became clear that writing a full fledged VM directly in WebAssembly was going to be tedious, complex and unnecessarily painful.
|
74
80
|
|
75
81
|
Sure I could have written this VM in any of the language that can already be compiled directly to WebAssembly (C, C++, Rust, Go,...) but being fond of Ruby since 2000 I decided that I would go for a compiler capable of transforming a subset of the Ruby language directly into WebAssembly with a minimum overhead. So in a nutshell: the goal of Rlang is to let you develop efficient WebAssembly code with a reasonably high level of abstraction while keeping the generated WebAssembly code straightforward and human readable.
|
76
82
|
|
data/docs/RlangManual.md
CHANGED
@@ -14,6 +14,7 @@ In Rlang you can define classes and those classes can be instantiated either sta
|
|
14
14
|
|
15
15
|
Rlang provides:
|
16
16
|
* Classes, class attributes and class variables
|
17
|
+
* Modules
|
17
18
|
* Object instantiation, attribute accessors and instance variables
|
18
19
|
* Method definition and method calls
|
19
20
|
* Integers and booleans
|
@@ -46,8 +47,6 @@ calling that method later in your code is as simple as invoking `Math.fib(20)`
|
|
46
47
|
## Classes
|
47
48
|
Classes are core constructs of Rlang and are very similar to Ruby classes.
|
48
49
|
|
49
|
-
In Rlang, all methods must be defined within the scope of a class. In other words you can not define a method at the top level of your Rlang code (not a very good practice anyway, even in plain Ruby). Also there is no inheritance mechanism in Rlang in the current version.
|
50
|
-
|
51
50
|
Here is an example of a class definition and the initialization and use of a class variable written in Rlang (note: this example uses only class methods on purpose. Instance methods are covered later in this document):
|
52
51
|
|
53
52
|
```ruby
|
@@ -70,6 +69,22 @@ This short piece of code shows several interesting points:
|
|
70
69
|
1. Methods in this example are class methods, hence the use of `self.take_one` and `self.refill` in method definitions but instance methods are also supported (more on this later)
|
71
70
|
1. In `MyClass::take_one` you can see that Rlang also supports convenient syntactic sugar like `if` as a modifier or combined operation and assignment as in Ruby (here the `-=` operator)
|
72
71
|
|
72
|
+
### Class scope and inheritance
|
73
|
+
Rlang supports the definition of classes in class at any depth and class naming follows the exact same convention as in Ruby. In the example below the `B` class can be referred to as `A::B`.
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
class A
|
77
|
+
class B
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def main
|
82
|
+
new_object = A::B.new
|
83
|
+
end
|
84
|
+
```
|
85
|
+
A Class in RLang can also inherit from another class as in Ruby. Whan a superclass is not specified, a newly defined class automatically inherits from the Object class.
|
86
|
+
|
87
|
+
|
73
88
|
### Class attributes and instance variables
|
74
89
|
Rlang support both the use of class attributes and instance variables. Class attribute declaration is happening through the `attr_accessor`, `attr_reader` or `attr_writer` directives as in plain Ruby. It actually defines a couple of things for you:
|
75
90
|
|
@@ -113,6 +128,8 @@ class Square
|
|
113
128
|
end
|
114
129
|
end
|
115
130
|
```
|
131
|
+
## Modules
|
132
|
+
Modules in Rlang behaves exactly like modules in Ruby. Modules can be included, extended or prepended in other classes and modules. .
|
116
133
|
|
117
134
|
## Object instantiation
|
118
135
|
Starting with version 0.4.0, Rlang is equipped with a dynamic memory allocator (see [Rlang library](#the-rlang-library) section). It is therefore capable of allocating objects in a dynamic way at *runtime*. Prior versions were only capable of allocating objects statically at *compile* time.
|
@@ -131,7 +148,7 @@ class Test
|
|
131
148
|
end
|
132
149
|
```
|
133
150
|
|
134
|
-
**IMPORTANT NOTE**: in the current version of Rlang the new method call used to allocate
|
151
|
+
**IMPORTANT NOTE**: in the current version of Rlang the new method call used to allocate static objects doesn't do any initialization. That's why the new method in this context (class body or top level) doesn't accept any parameter.
|
135
152
|
|
136
153
|
### Dynamic objects
|
137
154
|
At any point in the body of method you can dynamically instantiate a new object. Here is an exemple:
|
@@ -171,6 +188,11 @@ end
|
|
171
188
|
## Methods
|
172
189
|
Methods in Rlang are defined as you would normally do in Ruby by using the `def` reserved keyword. They can be either class or instance methods.
|
173
190
|
|
191
|
+
### Method definition
|
192
|
+
A method in Rlang can either be defined in a class, a module or at the top level. In that case the method is implicitely defined within the context of the Object class as Ruby does.
|
193
|
+
|
194
|
+
Class methods must be defined using the `def self.mymethod` syntax. The `class << self ... end` form is not supported.
|
195
|
+
|
174
196
|
### Method arguments
|
175
197
|
Rlang method definition supports fixed name arguments in any number. The *args and **args notation are not supported.
|
176
198
|
|
@@ -251,7 +273,7 @@ The types currently supported by Rlang are integers either long (`:I32`) or doub
|
|
251
273
|
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 in `:I64` local variable too.
|
252
274
|
|
253
275
|
```ruby
|
254
|
-
def
|
276
|
+
def m_local_var(arg1)
|
255
277
|
arg :arg1, :I64
|
256
278
|
lvar = arg1 * 100
|
257
279
|
# ....
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Rubinius WebAssembly VM
|
2
|
+
# Copyright (c) 2019-2020, Laurent Julliard and contributors
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# 4 bytes object array class
|
6
|
+
require_relative '../memory'
|
7
|
+
require_relative '../kernel'
|
8
|
+
require_relative '../object'
|
9
|
+
require_relative '../string'
|
10
|
+
|
11
|
+
|
12
|
+
class Array32
|
13
|
+
attr_reader :count, :ptr
|
14
|
+
|
15
|
+
# count: number of elements in Array
|
16
|
+
# Array elements are native types or
|
17
|
+
# pointers to objects
|
18
|
+
# Arrays are fixed size for now
|
19
|
+
def initialize(count)
|
20
|
+
@ptr = Object.allocate(count * 4)
|
21
|
+
@count = count
|
22
|
+
end
|
23
|
+
|
24
|
+
def size; @count; end
|
25
|
+
def length; @count; end
|
26
|
+
|
27
|
+
def [](idx)
|
28
|
+
result :I32
|
29
|
+
raise "Index out of bound" if idx >= @count
|
30
|
+
# offset in memory for elt #idx is idx * 4
|
31
|
+
Memory.load32(@ptr + (idx << 2))
|
32
|
+
end
|
33
|
+
|
34
|
+
def []=(idx, value)
|
35
|
+
arg value: :I32
|
36
|
+
result :I32
|
37
|
+
raise "Index out of bound" if idx >= @count
|
38
|
+
# offset in memory for elt #idx is idx * 4
|
39
|
+
Memory.store32(@ptr + (idx << 2), value)
|
40
|
+
value
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Rubinius WebAssembly VM
|
2
|
+
# Copyright (c) 2019-2020, Laurent Julliard and contributors
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# 4 bytes object array class
|
6
|
+
require_relative '../memory'
|
7
|
+
require_relative '../kernel'
|
8
|
+
require_relative '../object'
|
9
|
+
require_relative '../string'
|
10
|
+
|
11
|
+
|
12
|
+
class Array64
|
13
|
+
attr_reader :count, :ptr
|
14
|
+
|
15
|
+
# count: number of elements in Array
|
16
|
+
# Array elements are native types or
|
17
|
+
# pointers to objects
|
18
|
+
# Arrays are fixed size for now
|
19
|
+
def initialize(count)
|
20
|
+
@ptr = Object.allocate(count * 8)
|
21
|
+
@count = count
|
22
|
+
end
|
23
|
+
|
24
|
+
def size; @count; end
|
25
|
+
def length; @count; end
|
26
|
+
|
27
|
+
def [](idx)
|
28
|
+
result :I64
|
29
|
+
raise "Index out of bound" if idx >= @count
|
30
|
+
# offset in memory for elt #idx is idx * 8
|
31
|
+
Memory.load64(@ptr + (idx << 3))
|
32
|
+
end
|
33
|
+
|
34
|
+
def []=(idx, value)
|
35
|
+
arg value: :I64
|
36
|
+
result :I64
|
37
|
+
raise "Index out of bound" if idx >= @count
|
38
|
+
# offset in memory for elt #idx is idx * 8
|
39
|
+
Memory.store64(@ptr + (idx << 3), value)
|
40
|
+
value
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Rubinius WebAssembly VM
|
2
|
+
# Copyright (c) 2019-2020, Laurent Julliard and contributors
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Kernel methods
|
6
|
+
|
7
|
+
$! = 0.cast_to(:String)
|
8
|
+
|
9
|
+
module Kernel
|
10
|
+
|
11
|
+
def raise(msg)
|
12
|
+
arg msg: :String
|
13
|
+
result :none
|
14
|
+
$! = msg
|
15
|
+
inline wat: '(unreachable)', wtype: :none
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
data/lib/rlang/lib/malloc.rb
CHANGED
@@ -30,9 +30,10 @@ $NALLOC = 1024
|
|
30
30
|
|
31
31
|
# Allocate some unused memory space to make
|
32
32
|
# sure so that freep doesn't point to memory
|
33
|
-
# address 0 because it has a
|
34
|
-
# Allocate 20 bytes (
|
35
|
-
DAta
|
33
|
+
# address 0 because it has a special meaning
|
34
|
+
# Allocate 20 bytes (4 x I32 integers)
|
35
|
+
DAta.align(4)
|
36
|
+
DAta[:dummy_malloc_data] = [0, 0, 0, 0]
|
36
37
|
|
37
38
|
class Header
|
38
39
|
attr_accessor :ptr, :size
|
@@ -47,6 +48,7 @@ class Malloc
|
|
47
48
|
# declare ahead of time because is used in
|
48
49
|
# the code before it is actually defined
|
49
50
|
result :Malloc, :free, :nil
|
51
|
+
result :Malloc, :morecore, :Header
|
50
52
|
|
51
53
|
# -------- Dynamic Memory Allocator Functions -----------
|
52
54
|
|
data/lib/rlang/lib/memory.rb
CHANGED
@@ -1,4 +1,9 @@
|
|
1
|
-
|
1
|
+
# Rubinius WebAssembly VM
|
2
|
+
# Copyright (c) 2019-2020, Laurent Julliard and contributors
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Web Assembly memory access methods
|
6
|
+
#
|
2
7
|
|
3
8
|
class Memory
|
4
9
|
|
@@ -25,5 +30,100 @@ class Memory
|
|
25
30
|
idx += 1
|
26
31
|
end
|
27
32
|
end
|
28
|
-
|
33
|
+
|
34
|
+
def self.load32_8(addr)
|
35
|
+
arg addr: :I32
|
36
|
+
result :I32
|
37
|
+
inline wat: '(i32.load8_u (local.get $addr))',
|
38
|
+
wtype: :I32
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.load32_16(addr)
|
42
|
+
arg addr: :I32
|
43
|
+
result :I32
|
44
|
+
inline wat: '(i32.load16_u (local.get $addr))',
|
45
|
+
wtype: :I32
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.load32(addr)
|
49
|
+
arg addr: :I32
|
50
|
+
result :I32
|
51
|
+
inline wat: '(i32.load (local.get $addr))',
|
52
|
+
wtype: :I32
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.load64_8(addr)
|
56
|
+
arg addr: :I32
|
57
|
+
result :I64
|
58
|
+
inline wat: '(i64.load8_u (local.get $addr))',
|
59
|
+
wtype: :I64
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.load64_16(addr)
|
63
|
+
arg addr: :I32
|
64
|
+
result :I64
|
65
|
+
inline wat: '(i64.load16_u (local.get $addr))',
|
66
|
+
wtype: :I64
|
67
|
+
end
|
68
|
+
def self.load64_32(addr)
|
69
|
+
arg addr: :I32
|
70
|
+
result :I64
|
71
|
+
inline wat: '(i64.load32_u (local.get $addr))',
|
72
|
+
wtype: :I64
|
73
|
+
end
|
74
|
+
def self.load64(addr)
|
75
|
+
arg addr: :I32
|
76
|
+
result :I64
|
77
|
+
inline wat: '(i64.load (local.get $addr))',
|
78
|
+
wtype: :I64
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.store32_8(addr, value)
|
82
|
+
arg addr: :I32, value: :I32
|
83
|
+
result :none
|
84
|
+
inline wat: '(i32.store8 (local.get $addr) (local.get $value))',
|
85
|
+
wtype: :none
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.store32_16(addr, value)
|
89
|
+
arg addr: :I32, value: :I32
|
90
|
+
result :none
|
91
|
+
inline wat: '(i32.store16 (local.get $addr) (local.get $value))',
|
92
|
+
wtype: :none
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.store32(addr, value)
|
96
|
+
arg addr: :I32, value: :I32
|
97
|
+
result :none
|
98
|
+
inline wat: '(i32.store (local.get $addr) (local.get $value))',
|
99
|
+
wtype: :none
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.store64_8(addr, value)
|
103
|
+
arg addr: :I32, value: :I64
|
104
|
+
result :none
|
105
|
+
inline wat: '(i64.store8 (local.get $addr) (local.get $value))',
|
106
|
+
wtype: :none
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.store64_16(addr, value)
|
110
|
+
arg addr: :I32, value: :I64
|
111
|
+
result :none
|
112
|
+
inline wat: '(i64.store16 (local.get $addr) (local.get $value))',
|
113
|
+
wtype: :none
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.store64_32(addr, value)
|
117
|
+
arg addr: :I32, value: :I64
|
118
|
+
result :none
|
119
|
+
inline wat: '(i64.store32 (local.get $addr) (local.get $value))',
|
120
|
+
wtype: :none
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.store64(addr, value)
|
124
|
+
arg addr: :I32, value: :I64
|
125
|
+
result :none
|
126
|
+
inline wat: '(i64.store (local.get $addr) (local.get $value))',
|
127
|
+
wtype: :none
|
128
|
+
end
|
29
129
|
end
|
data/lib/rlang/lib/object.rb
CHANGED
@@ -1,10 +1,17 @@
|
|
1
|
+
# Rubinius WebAssembly VM
|
2
|
+
# Copyright (c) 2019-2020, Laurent Julliard and contributors
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Base Object class
|
6
|
+
|
1
7
|
require_relative './malloc'
|
8
|
+
require_relative './kernel'
|
2
9
|
|
3
10
|
class Object
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
def self.
|
11
|
+
|
12
|
+
include Kernel
|
13
|
+
|
14
|
+
def self.allocate(nbytes)
|
8
15
|
result :I32
|
9
16
|
Malloc.malloc(nbytes)
|
10
17
|
end
|
data/lib/rlang/lib/string.rb
CHANGED
data/lib/rlang/lib/unistd.rb
CHANGED
@@ -8,6 +8,7 @@
|
|
8
8
|
# srbk(0) returns the current value of the break
|
9
9
|
# Note: in WASM we can only grow linear memory by pages (64 KB block)
|
10
10
|
|
11
|
+
require_relative './memory'
|
11
12
|
|
12
13
|
# These 3 global variables below are used by the
|
13
14
|
# dynamic memory allocator. You can redefine them
|
@@ -27,8 +28,6 @@ $HEAP_MAX_SIZE = 1073741824 # 1GB
|
|
27
28
|
$HEAP_SIZE = 0
|
28
29
|
|
29
30
|
class Unistd
|
30
|
-
result :Memory, :grow, :I32
|
31
|
-
result :Memory, :size, :I32
|
32
31
|
|
33
32
|
def self.sbrk(n)
|
34
33
|
# local variables used. All default type
|
data/lib/rlang/lib.rb
CHANGED
@@ -3,9 +3,11 @@
|
|
3
3
|
# All rights reserved.
|
4
4
|
|
5
5
|
# Rlang standard library
|
6
|
-
require_relative './lib/object'
|
7
6
|
require_relative './lib/type'
|
8
7
|
require_relative './lib/memory'
|
9
8
|
require_relative './lib/unistd'
|
10
9
|
require_relative './lib/malloc'
|
11
|
-
require_relative './lib/
|
10
|
+
require_relative './lib/object'
|
11
|
+
require_relative './lib/kernel'
|
12
|
+
require_relative './lib/string'
|
13
|
+
require_relative './lib/array'
|
data/lib/rlang/parser/attr.rb
CHANGED
@@ -11,14 +11,14 @@ require_relative './wtype'
|
|
11
11
|
module Rlang::Parser
|
12
12
|
class Attr
|
13
13
|
include Log
|
14
|
-
attr_reader :name, :getter, :setter, :ivar
|
14
|
+
attr_reader :name, :getter, :setter, :ivar, :klass
|
15
15
|
|
16
16
|
# The name argument can either be the attribute name
|
17
17
|
# (e.g. :size) or an ivar name (e.g. :@size)
|
18
|
-
def initialize(
|
19
|
-
@
|
18
|
+
def initialize(klass, name, wtype=WType::DEFAULT)
|
19
|
+
@klass = klass
|
20
20
|
@name = name
|
21
|
-
@ivar =
|
21
|
+
@ivar = klass.wnode.create_ivar(:"@#{name}", wtype)
|
22
22
|
@getter = nil
|
23
23
|
@setter = nil
|
24
24
|
@export = false
|
@@ -26,16 +26,16 @@ module Rlang::Parser
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def attr_reader
|
29
|
-
@getter = @
|
29
|
+
@getter = @klass.wnode.find_or_create_method(nil, self.getter_name, :instance, wtype)
|
30
30
|
@getter.export! if @export
|
31
|
-
logger.debug "Getter created: #{@getter
|
31
|
+
logger.debug "Getter created: #{@getter}"
|
32
32
|
@getter
|
33
33
|
end
|
34
34
|
|
35
35
|
def attr_writer
|
36
|
-
@setter = @
|
36
|
+
@setter = @klass.wnode.find_or_create_method(nil, self.setter_name, :instance, wtype)
|
37
37
|
@setter.export! if @export
|
38
|
-
logger.debug "Setter created: #{@setter
|
38
|
+
logger.debug "Setter created: #{@setter}"
|
39
39
|
@setter
|
40
40
|
end
|
41
41
|
|
@@ -47,10 +47,6 @@ module Rlang::Parser
|
|
47
47
|
@export = true
|
48
48
|
end
|
49
49
|
|
50
|
-
def class_name
|
51
|
-
@class_wnode.class_name
|
52
|
-
end
|
53
|
-
|
54
50
|
def wtype
|
55
51
|
@ivar.wtype
|
56
52
|
end
|
@@ -64,7 +60,7 @@ module Rlang::Parser
|
|
64
60
|
@getter.wtype = wtype if @getter
|
65
61
|
@setter.wtype = wtype if @setter
|
66
62
|
@ivar.wtype = wtype
|
67
|
-
logger.debug "Attr/Getter/Setter/ivar wtype updated : #{@getter
|
63
|
+
logger.debug "Attr/Getter/Setter/ivar wtype updated : #{@getter}"
|
68
64
|
end
|
69
65
|
|
70
66
|
def getter_name
|
data/lib/rlang/parser/const.rb
CHANGED
@@ -10,6 +10,110 @@ require_relative './cvar'
|
|
10
10
|
# Constants and Class variables are managed
|
11
11
|
# in exactly the same way
|
12
12
|
module Rlang::Parser
|
13
|
-
|
13
|
+
# Rubinius WebAssembly VM
|
14
|
+
# Copyright (c) 2019, Laurent Julliard and contributors
|
15
|
+
# All rights reserved.
|
16
|
+
#
|
17
|
+
# Class variables
|
18
|
+
# Note: Const class inherits from this class
|
19
|
+
|
20
|
+
require_relative '../../utils/log'
|
21
|
+
require_relative './wtype'
|
22
|
+
require_relative './data'
|
23
|
+
|
24
|
+
module Rlang::Parser
|
25
|
+
class Const
|
26
|
+
include Log
|
27
|
+
attr_reader :scope_class, :name, :value
|
28
|
+
attr_accessor :wtype
|
29
|
+
|
30
|
+
def initialize(name, value, wtype=WType::DEFAULT)
|
31
|
+
@scope_class = nil
|
32
|
+
@name = name
|
33
|
+
@wtype = wtype
|
34
|
+
@data = nil
|
35
|
+
self.value = value if value
|
36
|
+
end
|
37
|
+
|
38
|
+
# class or module in which constant is defined
|
39
|
+
# not to be confused with wtype that hold the Rlang
|
40
|
+
# class of the constant
|
41
|
+
def scope_class=(scope_class_or_mod)
|
42
|
+
logger.debug "Placing Constant #{name} in scope class #{scope_class_or_mod&.name}"
|
43
|
+
raise "Error: constant scope class already initialized with #{scope_class.name} / #{@scope_class}. Got #{scope_class_or_mod.name} / #{scope_class_or_mod}." \
|
44
|
+
if @scope_class
|
45
|
+
@scope_class = scope_class_or_mod
|
46
|
+
@scope_class.consts << self if @scope_class
|
47
|
+
end
|
48
|
+
|
49
|
+
# The value attribute can either be set at
|
50
|
+
# initialize time or later (e.g. for classes and modules)
|
51
|
+
def value=(value)
|
52
|
+
# TODO: as opposed to Ruby we don't handle constant
|
53
|
+
# reassignment for now.
|
54
|
+
raise "Constant #{self.name} already initialized with value #{@value}. Now getting #{value}" \
|
55
|
+
if @value
|
56
|
+
return nil unless value
|
57
|
+
logger.debug "Initializing constant #{@name} @ #{@address} with value #{@value} / wtype #{@wtype}"
|
58
|
+
if value.kind_of? Module
|
59
|
+
# for now just store 0 in constants
|
60
|
+
# pointing to class or module
|
61
|
+
# TODO: probably point to a minimal data
|
62
|
+
# with the class path string for instance (= class name)
|
63
|
+
self.data = 0
|
64
|
+
else
|
65
|
+
self.data = value
|
66
|
+
end
|
67
|
+
@value = value
|
68
|
+
end
|
69
|
+
|
70
|
+
def data=(value)
|
71
|
+
@data = DAta.new(self.wasm_name.to_sym, value, @wtype)
|
72
|
+
end
|
73
|
+
|
74
|
+
# the symbol form of this constant path
|
75
|
+
# e.g. a constant A::B will return :"A::B"
|
76
|
+
def path_name
|
77
|
+
#@scope_class ? "#{@scope_class.path_name}::#{@name}".to_sym : @name
|
78
|
+
self.path.map(&:name).join('::').to_sym
|
79
|
+
end
|
80
|
+
|
81
|
+
# Returns an array of successive Const objects that
|
82
|
+
# altogether makes the full path of this Const
|
83
|
+
# e.g. a constant A::B will return [Const(:A), Const(:B)]
|
84
|
+
def path
|
85
|
+
sk = nil; c = self; p = [c]
|
86
|
+
while (sk = c.scope_class) && sk.const != c
|
87
|
+
logger.debug "c: #{c.name}/#{c}, sk: #{sk.name}/#{sk}"
|
88
|
+
c = sk.const
|
89
|
+
p.unshift(c)
|
90
|
+
end
|
91
|
+
# Do not keep Object as the first element of the
|
92
|
+
# const path unless it is the only element
|
93
|
+
p.shift if p.first.name == :Object && p.size > 1
|
94
|
+
logger.debug "Const#path : #{p.map(&:name)}"
|
95
|
+
p
|
96
|
+
end
|
97
|
+
|
98
|
+
def class?
|
99
|
+
@wtype.name == :Class
|
100
|
+
end
|
101
|
+
|
102
|
+
def module?
|
103
|
+
@wtype.name == :Module
|
104
|
+
end
|
105
|
+
|
106
|
+
def address
|
107
|
+
@data.address
|
108
|
+
end
|
109
|
+
|
110
|
+
def wasm_name
|
111
|
+
"$#{self.path_name}"
|
112
|
+
end
|
113
|
+
|
114
|
+
def wasm_type
|
115
|
+
@wtype.wasm_type
|
116
|
+
end
|
14
117
|
end
|
15
118
|
end
|
119
|
+
end
|