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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 45f6d0c347cfcf901dcd935e2b979098759f2c9b435ff5d900f77a830d5b2101
4
- data.tar.gz: 88c0e8f7b79f3cb784f0dd0c85fc10b68427958893f3401998f9866fa9a9b50a
3
+ metadata.gz: a7fd26f4ab304200f0319e23e1e8529e538ea058a58fe4571e0e3525c2c5ce14
4
+ data.tar.gz: 88bb4ec22b5a2571944693da8ea21d0e1379fb41b3c9ae85d91851a2f8569d9b
5
5
  SHA512:
6
- metadata.gz: d6f959bc61a5f4f9548455244662a8b3d9482d9e4670fdb66fd9d5ea1101e062bb93d5fbaffabac5e24852c85058130f92680e76f7d01bbe1745914bee25640b
7
- data.tar.gz: 30e4ecce3b01f850fd9515ab614e75d3cd915545b172bab7174872d0d5fab4875a96ade32dac2f1b7a95a3ca0f58ef0ef891544b926ba0e6c23fa38c4cb6fca2
6
+ metadata.gz: f6c92dcfec61a4df573d2c911882f346fb242315596220e25aa547998f137b8578f18ca62467c77af2b75e92ea73d87a21cbc37eae1bd56e89038bc62fca2264
7
+ data.tar.gz: b9e09724905b3175904258174c834b8d52b9f7ae99c7046e81e13f97e699d94b53f110b70763283992e71c7d6a2f3d0eb9d9cba60a30a1ef319338f1ec580919
data/CHANGELOG.md CHANGED
@@ -1,6 +1,9 @@
1
- ## 0.4.1
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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rlang (0.4.0)
4
+ rlang (0.5.0)
5
5
  parser
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -1,12 +1,19 @@
1
- # Rlang : a (subset of) Ruby to WebAssembly compiler
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 supported subset of the Ruby language and 2) a **compiler** transforming this Ruby subset in a valid, fully runnable and native WebAssembly module.
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 &rarr; Rlang compiler &rarr; 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 WAT code.
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 like this:
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 that'll show you how to compile some Rang code and run it from your browser. Since Chrome, Chromium, Firefox and Safari all natively embed a WebAssembly runtime it is the easiest way to test compiled Rlang code.
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 Ruby 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.
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 the object sape doesn't do any initialization. That's why the new method in this context (class body or top level) doesn't accept any parameter
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 self.m_local_var(arg1)
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,6 @@
1
+ # Rubinius WebAssembly VM
2
+ # Copyright (c) 2019, Laurent Julliard and contributors
3
+ # All rights reserved.
4
+ #
5
+ require_relative './array/array32'
6
+ require_relative './array/array64'
@@ -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
@@ -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 sepcial meaning
34
- # Allocate 20 bytes (5 x I32 integers)
35
- DAta[:dummy_malloc_data] = [0, 0, 0, 0, 0]
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
 
@@ -1,4 +1,9 @@
1
- require 'rlang/lib/type'
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
@@ -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
- # don't use allocate as a name to avoid
5
- # colliding with Ruby native method in
6
- # Rlang simulator
7
- def self.alloc(nbytes)
11
+
12
+ include Kernel
13
+
14
+ def self.allocate(nbytes)
8
15
  result :I32
9
16
  Malloc.malloc(nbytes)
10
17
  end
@@ -1,4 +1,5 @@
1
1
  require_relative './malloc'
2
+ require_relative './memory'
2
3
 
3
4
  class String
4
5
  attr_reader :length, :ptr
@@ -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/string'
10
+ require_relative './lib/object'
11
+ require_relative './lib/kernel'
12
+ require_relative './lib/string'
13
+ require_relative './lib/array'
@@ -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(class_wnode, name, wtype=WType::DEFAULT)
19
- @class_wnode = class_wnode
18
+ def initialize(klass, name, wtype=WType::DEFAULT)
19
+ @klass = klass
20
20
  @name = name
21
- @ivar = class_wnode.create_ivar(:"@#{name}", wtype)
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 = @class_wnode.find_or_create_method(self.getter_name, nil, wtype, :instance)
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.inspect}"
31
+ logger.debug "Getter created: #{@getter}"
32
32
  @getter
33
33
  end
34
34
 
35
35
  def attr_writer
36
- @setter = @class_wnode.find_or_create_method(self.setter_name, nil, wtype, :instance)
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.inspect}"
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.inspect}"
63
+ logger.debug "Attr/Getter/Setter/ivar wtype updated : #{@getter}"
68
64
  end
69
65
 
70
66
  def getter_name
@@ -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
- class Const < CVar
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