rlang 0.5.0 → 0.5.1

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