rlang 0.5.0 → 0.5.1

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.
@@ -68,7 +68,7 @@ module Rlang::Parser
68
68
  end
69
69
 
70
70
  def data=(value)
71
- @data = DAta.new(self.wasm_name.to_sym, value, @wtype)
71
+ @data = DAta.new(self.path_name.to_sym, value, @wtype)
72
72
  end
73
73
 
74
74
  # the symbol form of this constant path
@@ -26,7 +26,7 @@ module Rlang::Parser
26
26
  end
27
27
 
28
28
  def class_name
29
- @klass.name
29
+ @klass.path_name
30
30
  end
31
31
 
32
32
  def address
@@ -38,7 +38,7 @@ module Rlang::Parser
38
38
  end
39
39
 
40
40
  def wasm_name
41
- "$#{@class_name}::#{@name}"
41
+ "$#{self.class_name}::#{@name}"
42
42
  end
43
43
 
44
44
  def wasm_type
@@ -39,14 +39,16 @@ module Rlang::Parser
39
39
  end
40
40
 
41
41
  def append_value(value, wtype)
42
+ logger.warn "Data type #{@wtype} misaligned!!! (Data[:#{@label}] value #{value} at address #{@address}" \
43
+ unless self.aligned?
42
44
  @value << value
43
45
  if value.is_a? String
44
46
  @@current_address += value.length
45
47
  else
46
- logger.warn "Data type #{@wtype} misaligned!!! (Data[:#{@label}] value #{value} at address #{@address}" \
47
- unless self.aligned?
48
48
  @@current_address += @wtype.size
49
49
  end
50
+ # Always make sure current address is aligned
51
+ self.class.align(WType::DEFAULT.size)
50
52
  end
51
53
 
52
54
  def aligned?
@@ -89,7 +91,8 @@ module Rlang::Parser
89
91
 
90
92
  # Transpile data to WAT code
91
93
  # in order of increasing address
92
- def self.transpile
94
+ def self.transpile(depth)
95
+ indent = ' ' * depth * 2
93
96
  output = []
94
97
  @@label_table.sort_by {|s,d| d.address}.each do |s,d|
95
98
  logger.debug "Generating data #{d.inspect}"
@@ -109,7 +112,7 @@ module Rlang::Parser
109
112
  end
110
113
  end
111
114
  end
112
- output.join("\n")
115
+ indent + output.join("\n #{indent}")
113
116
  end
114
117
  end
115
118
 
@@ -17,10 +17,11 @@ module Rlang::Parser
17
17
 
18
18
  # Export Rlang funcs, etc... grouping them
19
19
  # by object type for Wasm code readability
20
- def self.transpile
21
- @@exports.sort_by {|e| e.object.class.to_s}.collect do |export|
20
+ def self.transpile(depth)
21
+ indent = ' ' * depth * 2
22
+ indent + @@exports.sort_by {|e| e.object.class.to_s}.collect do |export|
22
23
  export.object.export_wasm_code
23
- end.join("\n")
24
+ end.join("\n#{indent}")
24
25
  end
25
26
  end
26
27
  end
@@ -52,7 +52,8 @@ 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
+ indent = ' ' * depth * 2
56
57
  output = []
57
58
  @@globals.each do |g|
58
59
  if g.mutable?
@@ -63,7 +64,7 @@ module Rlang::Parser
63
64
  % {name: g.wasm_name, type: g.wtype.wasm_type, value: g.value}
64
65
  end
65
66
  end
66
- output.join("\n")
67
+ indent + output.join("\n#{indent}")
67
68
  end
68
69
  end
69
70
  end
@@ -14,7 +14,8 @@ module Rlang::Parser
14
14
  include Log
15
15
 
16
16
  attr_reader :name, :wtype, :method_type, :wnode
17
- attr_accessor :klass, :margs, :lvars
17
+ attr_writer :export_name
18
+ attr_accessor :klass, :margs, :lvars, :export_as
18
19
 
19
20
  METHOD_TYPES = [:instance, :class]
20
21
 
@@ -29,6 +30,8 @@ module Rlang::Parser
29
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
32
35
  end
33
36
 
34
37
  # Setup bidirectional links between
@@ -79,6 +82,7 @@ module Rlang::Parser
79
82
  end
80
83
 
81
84
  def export_name
85
+ return @export_name if @export_name
82
86
  # [] method name is illegal in Wasm function name
83
87
  name = @name.to_s.sub(/\[\]/, 'brackets').to_sym
84
88
  if self.instance?
@@ -88,7 +92,16 @@ module Rlang::Parser
88
92
  end
89
93
  end
90
94
 
91
- 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
92
105
  Export.new(self)
93
106
  end
94
107
 
@@ -112,7 +112,7 @@ module Rlang::Parser
112
112
  class WGenerator
113
113
  include Log
114
114
  attr_accessor :parser
115
- attr_reader :root
115
+ attr_reader :root, :wn_imports, :wn_exports, :wn_globals, :wn_data, :wn_code
116
116
 
117
117
  def initialize(parser)
118
118
  @parser = parser
@@ -120,6 +120,20 @@ module Rlang::Parser
120
120
  @new_count = 0
121
121
  @static_count = 0
122
122
 
123
+ # Create section wnodes
124
+ @wn_imports = WNode.new(:imports, @root)
125
+ @wn_memory = WNode.new(:memory, @root)
126
+ @wn_exports = WNode.new(:exports, @root)
127
+ @wn_globals = WNode.new(:globals, @root)
128
+ @wn_data = WNode.new(:data, @root)
129
+
130
+ # Module code generation
131
+ @root.c(:module, module: parser.config[:module])
132
+
133
+ # Memory code generation
134
+ WNode.new(:insn, @wn_memory). \
135
+ c(:memory, min: parser.config[:memory_min], max: parser.config[:memory_max])
136
+
123
137
  # define Object class and Kernel modules
124
138
  # and include Kernel in Object
125
139
  wn_object_class = self.klass(@root, [:Object], [])
@@ -222,17 +236,24 @@ module Rlang::Parser
222
236
  def declare_method(wnode, wtype, method_name, result_type)
223
237
  class_path = wtype.class_path
224
238
  logger.debug "Declaring method #{method_name} in class #{class_path}"
225
- klass = WNode.root.find_or_create_class(class_path, [])
239
+ klass = WNode.root.find_class_or_module(class_path)
240
+ raise "Can't find class or module #{class_path} in method declaration" unless klass
241
+ method_types = []
226
242
  if method_name[0] == '#'
227
- method_type = :instance
243
+ method_types << :instance
244
+ method_types << :class if klass.const.module?
228
245
  mth_name = method_name[1..-1].to_sym
229
246
  else
230
- method_type = :class
247
+ method_types << :class
248
+ method_types << :instance if klass.const.module?
231
249
  mth_name = method_name.to_sym
232
250
  end
233
- (m = wnode.find_or_create_method(klass, mth_name, method_type, nil)).wtype = WType.new(result_type)
234
- logger.debug "Declared #{method_type} method #{m.name} in class #{m.klass.name} with wtype #{m.wtype.name}"
235
- m
251
+ mth = method_types.each do |mt|
252
+ (m = wnode.find_or_create_method(klass, mth_name, mt, nil)).wtype = WType.new(result_type)
253
+ logger.debug "Declared #{mt} method #{m.name} in class #{m.klass.name} with wtype #{m.wtype.name}"
254
+ m
255
+ end
256
+ mth
236
257
  end
237
258
 
238
259
  # Postprocess ivars
@@ -283,7 +304,7 @@ module Rlang::Parser
283
304
  size_method = wnc.find_or_create_method(klass, SIZE_METHOD, :class, WType::DEFAULT)
284
305
  unless size_method.wnode
285
306
  logger.debug("Generating #{size_method.klass.name}\##{size_method.name}")
286
- wns = WNode.new(:insn, wnc, true)
307
+ wns = WNode.new(:insn, wnc)
287
308
  wns.wtype = WType::DEFAULT
288
309
  wns.c(:class_size, func_name: size_method.wasm_name,
289
310
  wtype: wns.wasm_type, size: wnc.class_size)
@@ -318,20 +339,41 @@ module Rlang::Parser
318
339
  else
319
340
  method = wnode.create_method(nil, method_name, method_type, nil, true)
320
341
  end
342
+
343
+ # If it's the main method, give it the proper name in export if
344
+ # specified on command line
345
+ if method.klass.path_name == :Object && method.name == :main
346
+ method.export_name = @parser.config[:start]
347
+ end
348
+
321
349
  # Generate method definition wnode
322
350
  logger.debug("Generating wnode for #{method_type} method #{method_name}")
323
351
  wn = WNode.new(:method, wnode)
324
352
  method.wnode = wn
325
353
  wn.wtype = method.wtype
326
354
  wn.c(:func, func_name: wn.method.wasm_name)
327
- # On instance method also declare a first parameter
328
- # called _self_ representing the pointer to the
329
- # object instance
355
+
356
+ # Instance methods 1st argument is always self
330
357
  wn.create_marg(:_self_) if method.instance?
331
- logger.debug("Building #{method_type} method: wn.wtype #{wn.wtype}, wn.method #{wn.method}")
358
+ logger.debug("Built #{method_type} method definition: wn.wtype #{wn.wtype}, wn.method #{wn.method}")
332
359
  wn
333
360
  end
334
361
 
362
+ def import_method(wnode, module_name, function_name)
363
+ # Create the import node
364
+ (wn_import = WNode.new(:insn, self.wn_imports)).c(:import, module_name: module_name, function_name: function_name)
365
+ wn_import.link = wnode
366
+ wnode.method.imported!
367
+ # now silence the method wnode so that
368
+ # it doesn't generate WASM code in the code section
369
+ wnode.silence!
370
+ wn_import
371
+ end
372
+
373
+ def export_method(wnode, export_name)
374
+ wnode.method.export!(export_name)
375
+ end
376
+
335
377
  def params(wnode)
336
378
  wnm = wnode.method_wnode
337
379
  # use reverse to preserve proper param order
@@ -384,6 +426,13 @@ module Rlang::Parser
384
426
  wn
385
427
  end
386
428
 
429
+ # Get constant addres
430
+ def const_addr(wnode, const)
431
+ (wn = WNode.new(:insn, wnode)).wtype = const.wtype
432
+ wn.c(:addr, value: const.address)
433
+ wn
434
+ end
435
+
387
436
  # Set Global variable
388
437
  def gvasgn(wnode, gvar)
389
438
  (wn = WNode.new(:insn, wnode)).wtype = gvar.wtype
@@ -450,6 +499,14 @@ module Rlang::Parser
450
499
  wn
451
500
  end
452
501
 
502
+
503
+ # Get class variable address
504
+ def cvar_addr(wnode, cvar)
505
+ (wn = WNode.new(:insn, wnode)).wtype = cvar.wtype
506
+ wn.c(:addr, value: cvar.address)
507
+ wn
508
+ end
509
+
453
510
  # Create the local variable storage node
454
511
  def lvasgn(wnode, lvar)
455
512
  (wn = WNode.new(:insn, wnode)).wtype = lvar.wtype
@@ -490,9 +547,8 @@ module Rlang::Parser
490
547
  # Generate a phony node (generally used to create
491
548
  # a wnode subtree under the phony node and later
492
549
  # reparent it to the proper place in the wtree)
493
- def phony(wnode)
494
- phony = WNode.new(:none, wnode)
495
- phony
550
+ def phony(wnode, type=:none)
551
+ WNode.new(type, wnode)
496
552
  end
497
553
 
498
554
  # Static string allocation
@@ -702,7 +758,7 @@ module Rlang::Parser
702
758
  # no need to define new method for native types
703
759
  return if wnode_class.klass.wtype.native?
704
760
  if (new_mth = wnode_class.find_method(k, :new, :class, true))
705
- return if new_mth.wnode # already implemented
761
+ return if new_mth.implemented? # already implemented
706
762
  end
707
763
 
708
764
  logger.debug "Creating code for #{k.name}.new"
@@ -21,6 +21,7 @@ module Rlang::Parser
21
21
  # WASM code templates
22
22
  T = {
23
23
  func: 'func %{func_name}',
24
+ import: 'import "%{module_name}" "%{function_name}"',
24
25
  param: 'param %{name} %{wasm_type}',
25
26
  result: 'result %{wasm_type}',
26
27
  return: 'return',
@@ -57,12 +58,15 @@ module Rlang::Parser
57
58
  (local.get %{attr_name})
58
59
  (%{wtype}.store offset=%{offset} (local.get $_self_) (local.get %{attr_name}))},
59
60
  class_size: %q{func %{func_name} (result %{wtype})
60
- (%{wtype}.const %{size})}
61
+ (%{wtype}.const %{size})},
62
+ comment: ';; %{comment}',
63
+ memory: 'memory $0 %{min} %{max}',
64
+ module: 'module %{module}'
61
65
  }
62
66
 
63
67
  attr_accessor :type, :wargs, :children, :parent, :comment,
64
68
  :method, :template, :keep_on_stack, :classes,
65
- :modules
69
+ :modules, :link
66
70
  attr_reader :wtype, :label, :klass, :module
67
71
 
68
72
  @@label_index = 0
@@ -98,6 +102,10 @@ module Rlang::Parser
98
102
  # For insn wnode with
99
103
  # label (.e.g block, loop)
100
104
  @label = nil
105
+
106
+ # link to a related node
107
+ # Semantic of the link depend on the wnode type
108
+ @link = nil
101
109
  end
102
110
 
103
111
  def self.root
@@ -168,7 +176,7 @@ module Rlang::Parser
168
176
  end
169
177
  alias :<< :add_child
170
178
 
171
- # Remove child to current node
179
+ # Remove child from current node
172
180
  def remove_child(wnode)
173
181
  logger.debug "Removing #{wnode.object_id} from wnodes list #{self.children.map(&:object_id)} under parent #{self.parent.object_id}"
174
182
  unless (wn = self.children.delete(wnode)) && wn == wnode
@@ -204,8 +212,8 @@ module Rlang::Parser
204
212
 
205
213
  # insert a blank wnode above self, so between self wnode
206
214
  # and its parent (self -> parent becomes self -> wn -> parent)
207
- def insert(wtype=:none)
208
- wn = WNode.new(wtype, self.parent)
215
+ def insert(type=:none)
216
+ wn = WNode.new(type, self.parent)
209
217
  self.reparent_to(wn)
210
218
  wn
211
219
  end
@@ -217,6 +225,13 @@ module Rlang::Parser
217
225
  self.parent.remove_child(self)
218
226
  end
219
227
 
228
+ # Silence the current wnode (which means
229
+ # inserting a silent type wnode between this
230
+ # and its parent)
231
+ def silence!
232
+ self.insert(:silent)
233
+ end
234
+
220
235
  def klass=(klass)
221
236
  @klass = klass
222
237
  @klass.wnode = self
@@ -519,7 +534,7 @@ module Rlang::Parser
519
534
  if (mn = self.method_wnode)
520
535
  mn.method.margs << (marg = MArg.new(name))
521
536
  else
522
- raise "No class found for class variable #{marg}"
537
+ raise "No class found for method argument #{marg}"
523
538
  end
524
539
  marg
525
540
  end
@@ -659,6 +674,10 @@ module Rlang::Parser
659
674
  !self.module_wnode.nil? && !self.in_method_scope?
660
675
  end
661
676
 
677
+ def in_class_or_module_scope?
678
+ self.in_class_scope? || self.in_module_scope?
679
+ end
680
+
662
681
  def in_root_scope?
663
682
  self.root? || (self.parent.root? && !self.in_class_scope?)
664
683
  end
@@ -688,17 +707,41 @@ module Rlang::Parser
688
707
  end
689
708
 
690
709
  # Generate WAT code starting for this node and tree branches below
691
- def transpile(indent=0)
710
+ def transpile(depth=0)
711
+ # follow children first and then go on with
712
+ # the wnode link if it exits
713
+ children = self.children + (self.link ? [self.link] : [])
714
+ indent = ' ' * depth * 2
715
+ logger.debug "children: #{self} / #{children.map(&:head)}" if self.link
716
+
692
717
  case @type
693
- when :insn, :method
718
+ # Section nodes
719
+ when :imports
720
+ "\n%s;;============= %s SECTION ===============\n" % [indent, @type.to_s.upcase] +
721
+ children.map { |wn| wn.transpile(depth) }.join('')
722
+ when :data
723
+ "\n\n%s;;============= %s SECTION ===============\n" % [indent, @type.to_s.upcase] +
724
+ DAta.transpile(depth)
725
+ when :globals
726
+ "\n\n%s;;============= %s SECTION ===============\n" % [indent, @type.to_s.upcase] +
727
+ Global.transpile(depth)
728
+ when :exports
729
+ "\n\n%s;;============= %s SECTION ===============\n" % [indent, @type.to_s.upcase] +
730
+ "%s(export \"memory\" (memory $0))\n" % [indent] +
731
+ Export.transpile(depth)
732
+ when :insn, :method, :root
694
733
  if @template == :inline
695
- "\n%s%s" % [' '*2*indent, self.wasm_code]
734
+ "\n%s%s" % [indent, self.wasm_code]
696
735
  else
697
- "\n%s(%s" % [' '*2*indent, self.wasm_code] + self.children.map { |wn| wn.transpile(indent+1) }.join('') + ')'
736
+ "\n%s(%s" % [indent, self.wasm_code] + children.map { |wn| wn.transpile(depth+1) }.join('') + ')'
698
737
  end
699
- when :root, :class, :module, :none
738
+ when :class, :module, :none, :memory
700
739
  # no WAT code to generate for these nodes. Process children directly.
701
- self.children.map { |wn| wn.transpile(indent) }.join('')
740
+ children.map { |wn| wn.transpile(depth) }.join('')
741
+ when :silent
742
+ # Do not generate any WAT code for a silent node and
743
+ # and its children
744
+ ''
702
745
  else
703
746
  raise "Error: Unknown wnode type #{@type}. No WAT code generated"
704
747
  end
@@ -1,3 +1,3 @@
1
1
  module Rlang
2
- VERSION = "0.5.0"
2
+ VERSION = "0.5.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rlang
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Laurent Julliard
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-25 00:00:00.000000000 Z
11
+ date: 2020-05-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser
@@ -130,20 +130,23 @@ files:
130
130
  - lib/builder/wat/builder.rb
131
131
  - lib/builder/wat/renderer.rb
132
132
  - lib/rlang.rb
133
- - lib/rlang/lib.rb
134
133
  - lib/rlang/lib/array.rb
135
134
  - lib/rlang/lib/array/array32.rb
136
135
  - lib/rlang/lib/array/array64.rb
136
+ - lib/rlang/lib/io.rb
137
137
  - lib/rlang/lib/kernel.rb
138
138
  - lib/rlang/lib/malloc.c
139
139
  - lib/rlang/lib/malloc.rb
140
140
  - lib/rlang/lib/memory.rb
141
141
  - lib/rlang/lib/object.rb
142
+ - lib/rlang/lib/rlang.rb
143
+ - lib/rlang/lib/rlang_core.rb
142
144
  - lib/rlang/lib/string.rb
143
145
  - lib/rlang/lib/type.rb
144
146
  - lib/rlang/lib/type/i32.rb
145
147
  - lib/rlang/lib/type/i64.rb
146
148
  - lib/rlang/lib/unistd.rb
149
+ - lib/rlang/lib/wasi.rb
147
150
  - lib/rlang/parser.rb
148
151
  - lib/rlang/parser/attr.rb
149
152
  - lib/rlang/parser/const.rb