rlang 0.4.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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