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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -3
  3. data/Gemfile.lock +4 -6
  4. data/README +11 -0
  5. data/README.md +18 -10
  6. data/bin/rlang +17 -5
  7. data/docs/RlangCompiler.md +5 -1
  8. data/docs/RlangManual.md +98 -20
  9. data/examples/fib/fib.rb +5 -1
  10. data/lib/builder/rlang/compiler.rb +2 -21
  11. data/lib/rlang/lib/array/array32.rb +59 -0
  12. data/lib/rlang/lib/array/array64.rb +56 -0
  13. data/lib/rlang/lib/array.rb +6 -0
  14. data/lib/rlang/lib/base64.rb +223 -0
  15. data/lib/rlang/lib/io.rb +75 -0
  16. data/lib/rlang/lib/kernel.rb +23 -0
  17. data/lib/rlang/lib/malloc.rb +12 -8
  18. data/lib/rlang/lib/memory.rb +102 -2
  19. data/lib/rlang/lib/object.rb +40 -4
  20. data/lib/rlang/lib/rlang.rb +29 -0
  21. data/lib/rlang/lib/rlang_core.rb +15 -0
  22. data/lib/rlang/lib/string.rb +106 -8
  23. data/lib/rlang/lib/type/i32.rb +43 -0
  24. data/lib/rlang/lib/type/i64.rb +2 -0
  25. data/lib/rlang/lib/unistd.rb +1 -2
  26. data/lib/rlang/lib/wasi.rb +184 -0
  27. data/lib/rlang/parser/attr.rb +9 -13
  28. data/lib/rlang/parser/const.rb +105 -1
  29. data/lib/rlang/parser/cvar.rb +11 -7
  30. data/lib/rlang/parser/data.rb +17 -6
  31. data/lib/rlang/parser/export.rb +4 -3
  32. data/lib/rlang/parser/ext/integer.rb +3 -1
  33. data/lib/rlang/parser/ext/type.rb +30 -1
  34. data/lib/rlang/parser/global.rb +10 -2
  35. data/lib/rlang/parser/ivar.rb +3 -7
  36. data/lib/rlang/parser/klass.rb +8 -35
  37. data/lib/rlang/parser/method.rb +36 -12
  38. data/lib/rlang/parser/module.rb +143 -0
  39. data/lib/rlang/parser/wgenerator.rb +462 -168
  40. data/lib/rlang/parser/wnode.rb +387 -142
  41. data/lib/rlang/parser/wtype.rb +30 -7
  42. data/lib/rlang/parser.rb +506 -231
  43. data/lib/rlang/version.rb +1 -1
  44. data/lib/rlang.rb +3 -0
  45. data/lib/ruby/mirror/rstring.rb +16 -0
  46. data/lib/utils/exceptions.rb +12 -0
  47. data/rlang.gemspec +4 -4
  48. metadata +25 -13
  49. 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**64 - 1
24
+ MAX = 2**31 - 1
25
+ MIN = -2**31
26
+ def initialize(v); @v = Integer(v); end
27
+ def +(v); I32.new(v + @v); end
28
+ def self.signed?; true; end
29
+ def size; 4; end # size in bytes
30
+ def self.size; 4; end # size in bytes
31
+ def wasm_type; 'i32'; end
32
+ def self.wasm_type; 'i32'; end
33
+ end
34
+
35
+ class UI32 < Numeric
36
+ MAX = 2**32 - 1
37
+ MIN = 0
13
38
  def initialize(v); @v = Integer(v); end
14
39
  def +(v); I32.new(v + @v); end
40
+ def self.signed?; false; end
15
41
  def size; 4; end # size in bytes
16
42
  def self.size; 4; end # size in bytes
17
43
  def wasm_type; 'i32'; end
@@ -20,6 +46,7 @@ module Type
20
46
 
21
47
  class F64 < Numeric
22
48
  MAX = 1.7976931348623158E308
49
+ def self.signed?; true; end
23
50
  def size; 8; end # size in bytes
24
51
  def wasm_type; 'f64'; end
25
52
  def self.size; 8; end # size in bytes
@@ -29,6 +56,7 @@ module Type
29
56
  class F32 < Numeric
30
57
  MAX = 3.4028235E38
31
58
  # size in bytes
59
+ def self.signed?; true; end
32
60
  def size; 4; end
33
61
  def wasm_type; 'f32'; end
34
62
  def self.size; 4; end
@@ -60,5 +88,6 @@ module Type
60
88
  end
61
89
 
62
90
  DEFAULT = Type::I32
91
+ UNSIGNED_DEFAULT = Type::UI32
63
92
 
64
93
  end
@@ -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
@@ -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(class_wnode, name, wtype=WType::DEFAULT)
18
- @class_wnode = class_wnode
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
@@ -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
- attr_reader :wtype
16
- attr_accessor :name, :wnode, :attrs, :ivars, :cvars,
17
- :consts, :methods, :offset
17
+ attr_accessor :super_class
18
18
 
19
- def initialize(name)
20
- @name = name
21
- # the type of a class is its name by definition
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
@@ -13,22 +13,32 @@ module Rlang::Parser
13
13
  class MEthod
14
14
  include Log
15
15
 
16
- attr_reader :name, :wtype
17
- attr_accessor :class_name, :margs, :lvars, :wnode
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 = [:class, :instance]
20
+ METHOD_TYPES = [:instance, :class]
20
21
 
21
- def initialize(name, class_name, wtype, method_type)
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
- @class_name = class_name
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 # wnode where method is implemented
29
- logger.debug "Method created #{self.inspect}"
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
- "$#{@class_name}##{@name}"
74
+ "$#{@klass.path_name}##{name}"
63
75
  else
64
- "$#{@class_name}::#{@name}"
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
- "#{@class_name.downcase}_i_#{@name}"
89
+ "#{@klass.path_name.downcase}_i_#{name}"
75
90
  else
76
- "#{@class_name.downcase}_c_#{@name}"
91
+ "#{@klass.path_name.downcase}_c_#{name}"
77
92
  end
78
93
  end
79
94
 
80
- def export!
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