rlang 0.4.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -3
- data/Gemfile.lock +4 -6
- data/README +11 -0
- data/README.md +18 -10
- data/bin/rlang +17 -5
- data/docs/RlangCompiler.md +5 -1
- data/docs/RlangManual.md +98 -20
- data/examples/fib/fib.rb +5 -1
- data/lib/builder/rlang/compiler.rb +2 -21
- data/lib/rlang/lib/array/array32.rb +59 -0
- data/lib/rlang/lib/array/array64.rb +56 -0
- data/lib/rlang/lib/array.rb +6 -0
- data/lib/rlang/lib/base64.rb +223 -0
- data/lib/rlang/lib/io.rb +75 -0
- data/lib/rlang/lib/kernel.rb +23 -0
- data/lib/rlang/lib/malloc.rb +12 -8
- data/lib/rlang/lib/memory.rb +102 -2
- data/lib/rlang/lib/object.rb +40 -4
- data/lib/rlang/lib/rlang.rb +29 -0
- data/lib/rlang/lib/rlang_core.rb +15 -0
- data/lib/rlang/lib/string.rb +106 -8
- data/lib/rlang/lib/type/i32.rb +43 -0
- data/lib/rlang/lib/type/i64.rb +2 -0
- data/lib/rlang/lib/unistd.rb +1 -2
- data/lib/rlang/lib/wasi.rb +184 -0
- data/lib/rlang/parser/attr.rb +9 -13
- data/lib/rlang/parser/const.rb +105 -1
- data/lib/rlang/parser/cvar.rb +11 -7
- data/lib/rlang/parser/data.rb +17 -6
- data/lib/rlang/parser/export.rb +4 -3
- data/lib/rlang/parser/ext/integer.rb +3 -1
- data/lib/rlang/parser/ext/type.rb +30 -1
- data/lib/rlang/parser/global.rb +10 -2
- data/lib/rlang/parser/ivar.rb +3 -7
- data/lib/rlang/parser/klass.rb +8 -35
- data/lib/rlang/parser/method.rb +36 -12
- data/lib/rlang/parser/module.rb +143 -0
- data/lib/rlang/parser/wgenerator.rb +462 -168
- data/lib/rlang/parser/wnode.rb +387 -142
- data/lib/rlang/parser/wtype.rb +30 -7
- data/lib/rlang/parser.rb +506 -231
- data/lib/rlang/version.rb +1 -1
- data/lib/rlang.rb +3 -0
- data/lib/ruby/mirror/rstring.rb +16 -0
- data/lib/utils/exceptions.rb +12 -0
- data/rlang.gemspec +4 -4
- metadata +25 -13
- data/lib/rlang/lib.rb +0 -11
@@ -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**
|
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
|
data/lib/rlang/parser/global.rb
CHANGED
@@ -52,7 +52,15 @@ module Rlang::Parser
|
|
52
52
|
'(export "%s" (global %s (mut %s)))' % [self.export_name, self.wasm_name, self.wtype.wasm_type]
|
53
53
|
end
|
54
54
|
|
55
|
-
def self.transpile
|
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
|
63
|
+
indent = ' ' * depth * 2
|
56
64
|
output = []
|
57
65
|
@@globals.each do |g|
|
58
66
|
if g.mutable?
|
@@ -63,7 +71,7 @@ module Rlang::Parser
|
|
63
71
|
% {name: g.wasm_name, type: g.wtype.wasm_type, value: g.value}
|
64
72
|
end
|
65
73
|
end
|
66
|
-
output.join("\n")
|
74
|
+
indent + output.join("\n#{indent}")
|
67
75
|
end
|
68
76
|
end
|
69
77
|
end
|
data/lib/rlang/parser/ivar.rb
CHANGED
@@ -11,11 +11,11 @@ require_relative './data'
|
|
11
11
|
module Rlang::Parser
|
12
12
|
class IVar
|
13
13
|
include Log
|
14
|
-
attr_reader :name
|
14
|
+
attr_reader :name, :klass
|
15
15
|
attr_accessor :wtype, :offset
|
16
16
|
|
17
|
-
def initialize(
|
18
|
-
@
|
17
|
+
def initialize(klass, name, wtype=WType::DEFAULT)
|
18
|
+
@klass = klass
|
19
19
|
@name = name
|
20
20
|
@wtype = wtype
|
21
21
|
# this is the offset of the instance variable
|
@@ -26,10 +26,6 @@ module Rlang::Parser
|
|
26
26
|
logger.debug "Instance variable #{name} created"
|
27
27
|
end
|
28
28
|
|
29
|
-
def class_name
|
30
|
-
@class_wnode.class_name
|
31
|
-
end
|
32
|
-
|
33
29
|
def size
|
34
30
|
@wtype.size
|
35
31
|
end
|
data/lib/rlang/parser/klass.rb
CHANGED
@@ -1,52 +1,25 @@
|
|
1
1
|
# Rubinius WebAssembly VM
|
2
|
-
# Copyright (c) 2019, Laurent Julliard and contributors
|
2
|
+
# Copyright (c) 2019-2020, Laurent Julliard and contributors
|
3
3
|
# All rights reserved.
|
4
4
|
|
5
5
|
# Rlang classes
|
6
6
|
require_relative '../../utils/log'
|
7
7
|
require_relative './wtype'
|
8
|
+
require_relative './const'
|
9
|
+
require_relative './module'
|
8
10
|
|
9
11
|
module Rlang::Parser
|
10
12
|
# Note: Cannot use Class as class name
|
11
13
|
# because it's already used by Ruby
|
12
|
-
class Klass
|
14
|
+
class Klass < Module
|
13
15
|
include Log
|
14
16
|
|
15
|
-
|
16
|
-
attr_accessor :name, :wnode, :attrs, :ivars, :cvars,
|
17
|
-
:consts, :methods, :offset
|
17
|
+
attr_accessor :super_class
|
18
18
|
|
19
|
-
def initialize(
|
20
|
-
|
21
|
-
|
22
|
-
@wtype = WType.new(name)
|
23
|
-
@size = 0
|
24
|
-
# the wnode implementing the code of the class
|
25
|
-
@wnode = nil
|
26
|
-
logger.debug "Klass created #{self.inspect}"
|
27
|
-
@attrs = [] # class attributes
|
28
|
-
@ivars = [] # instance variables
|
29
|
-
@cvars = [] # class variables
|
30
|
-
@consts = [] # class constants
|
31
|
-
@methods = [] # methods
|
32
|
-
@offset = 0 # offset of the next class attribute in memory
|
19
|
+
def initialize(const, scope_class, super_class)
|
20
|
+
super(const, scope_class)
|
21
|
+
self.super_class = super_class
|
33
22
|
end
|
34
23
|
|
35
|
-
def size
|
36
|
-
@offset
|
37
|
-
end
|
38
|
-
|
39
|
-
def wtype=(wtype)
|
40
|
-
@wtype = wtype
|
41
|
-
logger.debug "Klass #{@name} wtype updated: #{self.inspect}"
|
42
|
-
end
|
43
|
-
|
44
|
-
def wasm_name
|
45
|
-
@name
|
46
|
-
end
|
47
|
-
|
48
|
-
def wasm_type
|
49
|
-
@wtype.wasm_type
|
50
|
-
end
|
51
24
|
end
|
52
25
|
end
|
data/lib/rlang/parser/method.rb
CHANGED
@@ -13,22 +13,32 @@ module Rlang::Parser
|
|
13
13
|
class MEthod
|
14
14
|
include Log
|
15
15
|
|
16
|
-
attr_reader :name, :wtype
|
17
|
-
|
16
|
+
attr_reader :name, :wtype, :method_type, :wnode
|
17
|
+
attr_writer :export_name
|
18
|
+
attr_accessor :klass, :margs, :lvars, :export_as
|
18
19
|
|
19
|
-
METHOD_TYPES = [:
|
20
|
+
METHOD_TYPES = [:instance, :class]
|
20
21
|
|
21
|
-
def initialize(name,
|
22
|
+
def initialize(name, klass, wtype, method_type)
|
22
23
|
raise "Wrong method wtype argument: #{wtype.inspect}" unless wtype.is_a? WType
|
23
24
|
@name = name
|
24
|
-
@
|
25
|
+
@klass = klass
|
25
26
|
@wtype = wtype || WType::DEFAULT
|
26
27
|
@method_type = method_type
|
27
28
|
raise "Unknown method type: #{method_type}" unless METHOD_TYPES.include? @method_type
|
28
|
-
@wnode = nil
|
29
|
-
logger.debug "Method created #{
|
29
|
+
@wnode = nil # wnode where this method is implemented
|
30
|
+
logger.debug "Method created #{name} in class #{klass.name} / ID:#{self}"
|
30
31
|
@margs = [] # method args
|
31
32
|
@lvars = [] # local variables
|
33
|
+
|
34
|
+
@export_name = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
# Setup bidirectional links between
|
38
|
+
# wnode and method
|
39
|
+
def wnode=(wnode)
|
40
|
+
@wnode = wnode
|
41
|
+
wnode.method = self
|
32
42
|
end
|
33
43
|
|
34
44
|
def implemented?
|
@@ -58,10 +68,12 @@ module Rlang::Parser
|
|
58
68
|
end
|
59
69
|
|
60
70
|
def wasm_name
|
71
|
+
# [] method name is illegal in Wasm function name
|
72
|
+
name = @name.to_s.sub(/\[\]/, 'brackets').to_sym
|
61
73
|
if self.instance?
|
62
|
-
"$#{@
|
74
|
+
"$#{@klass.path_name}##{name}"
|
63
75
|
else
|
64
|
-
"$#{@
|
76
|
+
"$#{@klass.path_name}::#{name}"
|
65
77
|
end
|
66
78
|
end
|
67
79
|
|
@@ -70,14 +82,26 @@ module Rlang::Parser
|
|
70
82
|
end
|
71
83
|
|
72
84
|
def export_name
|
85
|
+
return @export_name if @export_name
|
86
|
+
# [] method name is illegal in Wasm function name
|
87
|
+
name = @name.to_s.sub(/\[\]/, 'brackets').to_sym
|
73
88
|
if self.instance?
|
74
|
-
"#{@
|
89
|
+
"#{@klass.path_name.downcase}_i_#{name}"
|
75
90
|
else
|
76
|
-
"#{@
|
91
|
+
"#{@klass.path_name.downcase}_c_#{name}"
|
77
92
|
end
|
78
93
|
end
|
79
94
|
|
80
|
-
def
|
95
|
+
def imported!
|
96
|
+
@imported = true
|
97
|
+
end
|
98
|
+
|
99
|
+
def imported?
|
100
|
+
@imported
|
101
|
+
end
|
102
|
+
|
103
|
+
def export!(export_name=nil)
|
104
|
+
@export_name = export_name
|
81
105
|
Export.new(self)
|
82
106
|
end
|
83
107
|
|
@@ -0,0 +1,143 @@
|
|
1
|
+
# Rubinius WebAssembly VM
|
2
|
+
# Copyright (c) 2019, Laurent Julliard and contributors
|
3
|
+
# All rights reserved.
|
4
|
+
|
5
|
+
# Rlang classes
|
6
|
+
require_relative '../../utils/log'
|
7
|
+
require_relative './const'
|
8
|
+
|
9
|
+
module Rlang::Parser
|
10
|
+
class Module
|
11
|
+
include Log
|
12
|
+
|
13
|
+
attr_reader :wtype, :const
|
14
|
+
attr_accessor :wnode, :attrs, :ivars, :cvars,
|
15
|
+
:consts, :methods, :offset,
|
16
|
+
:includes, :extends
|
17
|
+
|
18
|
+
def initialize(const, scope_class)
|
19
|
+
@const = const
|
20
|
+
# upper lexical class or module
|
21
|
+
logger.debug "scope_class: #{scope_class}"
|
22
|
+
@const.scope_class = scope_class
|
23
|
+
# the wtype of a Class/Module is either :Class or :Module
|
24
|
+
@wtype = WType.new(@const.path_name)
|
25
|
+
# memory space used by ivars in bytes
|
26
|
+
@size = 0
|
27
|
+
# the wnode implementing the code of the class
|
28
|
+
@wnode = nil
|
29
|
+
@super_class = nil
|
30
|
+
@attrs = [] # class attributes
|
31
|
+
@ivars = [] # instance variables
|
32
|
+
@cvars = [] # class variables
|
33
|
+
# Note: the consts list is fed from the Const class
|
34
|
+
# on purpose so that it applies to any constant not jus
|
35
|
+
# Classes and modules
|
36
|
+
@consts = [] # class constants
|
37
|
+
@methods = [] # methods
|
38
|
+
@offset = 0 # memory offset of next ivar
|
39
|
+
|
40
|
+
# Modules included/extended/prepended in
|
41
|
+
# this module/class
|
42
|
+
@modules = [] # all modules included, prepended, extended
|
43
|
+
@includes = [] # modules included
|
44
|
+
@prepends = [] # modules prepended
|
45
|
+
@extends = [] # modules extended
|
46
|
+
|
47
|
+
# Is this module extended, included, prepended ?
|
48
|
+
@extended = false
|
49
|
+
@included = false
|
50
|
+
@prepended = false
|
51
|
+
|
52
|
+
# Associated constant/value points to the class/module
|
53
|
+
@const.value = self
|
54
|
+
logger.debug "Created Class/Module #{@const} / #{self}"
|
55
|
+
end
|
56
|
+
|
57
|
+
def object_class?
|
58
|
+
self.const.name == :Object && self.const.scope_class == self
|
59
|
+
end
|
60
|
+
|
61
|
+
def name
|
62
|
+
@const.name
|
63
|
+
end
|
64
|
+
|
65
|
+
def path
|
66
|
+
@const.path
|
67
|
+
end
|
68
|
+
|
69
|
+
def path_name
|
70
|
+
@const.path_name
|
71
|
+
end
|
72
|
+
|
73
|
+
# Do not include the top class Object in nesting
|
74
|
+
def nesting
|
75
|
+
sk = nil; k = self; n = [k]
|
76
|
+
while (sk = k.const.scope_class) && (sk != k) && !sk.object_class?
|
77
|
+
logger.debug "k: #{k.name}/#{k}, sk: #{sk.name}/#{sk}, sk.object_class? #{sk.object_class?}"
|
78
|
+
n.unshift(sk)
|
79
|
+
k = sk
|
80
|
+
end
|
81
|
+
logger.debug "Class#nesting : #{n.map(&:name)}"
|
82
|
+
n
|
83
|
+
end
|
84
|
+
|
85
|
+
def include(klass)
|
86
|
+
@modules |= [klass]
|
87
|
+
@includes |= [klass]
|
88
|
+
end
|
89
|
+
|
90
|
+
def prepend(klass)
|
91
|
+
@modules |= [klass]
|
92
|
+
@prepends |= [klass]
|
93
|
+
end
|
94
|
+
|
95
|
+
def extend(klass)
|
96
|
+
@modules |= [klass]
|
97
|
+
@extends |= [klass]
|
98
|
+
end
|
99
|
+
|
100
|
+
def ancestors
|
101
|
+
@prepends.reverse + [self] + @includes.reverse + @extends.reverse + \
|
102
|
+
(@super_class ? @super_class.ancestors : [])
|
103
|
+
end
|
104
|
+
|
105
|
+
def const_get(name)
|
106
|
+
consts.find { |c| c.name == name}
|
107
|
+
end
|
108
|
+
|
109
|
+
def delete_instance_methods
|
110
|
+
@methods.select { |m| m.instance? }.each { |m| m.wnode.delete!; @methods.delete(m) }
|
111
|
+
end
|
112
|
+
|
113
|
+
def delete_class_methods
|
114
|
+
self.methods.select { |m| m.class? }.each { |m| m.wnode.delete!; @methods.delete(m) }
|
115
|
+
end
|
116
|
+
|
117
|
+
def size
|
118
|
+
@offset
|
119
|
+
end
|
120
|
+
|
121
|
+
def wtype=(wtype)
|
122
|
+
@wtype = wtype
|
123
|
+
logger.debug "#{self.class} #{@name} wtype updated: #{self.inspect}"
|
124
|
+
end
|
125
|
+
|
126
|
+
def wasm_name
|
127
|
+
@name
|
128
|
+
end
|
129
|
+
|
130
|
+
def wasm_type
|
131
|
+
@wtype.wasm_type
|
132
|
+
end
|
133
|
+
|
134
|
+
def extended?; @extended; end
|
135
|
+
def extended!; @extended = true; end
|
136
|
+
|
137
|
+
def included?; @included; end
|
138
|
+
def included!; @included = true; end
|
139
|
+
|
140
|
+
def prepended?; @prepended; end
|
141
|
+
def prepended!; @prepended = true; end
|
142
|
+
end
|
143
|
+
end
|