rlang 0.3.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 (54) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rake_tasks~ +0 -0
  4. data/.travis.yml +7 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +373 -0
  8. data/README.md +61 -0
  9. data/Rakefile +10 -0
  10. data/bin/rlang +164 -0
  11. data/docs/RlangCompiler.md +37 -0
  12. data/docs/RlangManual.md +391 -0
  13. data/lib/builder/ext/tempfile.rb +7 -0
  14. data/lib/builder/ext.rb +5 -0
  15. data/lib/builder/rlang/builder.rb +31 -0
  16. data/lib/builder/rlang.rb +2 -0
  17. data/lib/builder/wat/builder.rb +52 -0
  18. data/lib/builder/wat/renderer.rb +28 -0
  19. data/lib/builder/wat.rb +3 -0
  20. data/lib/builder.rb +7 -0
  21. data/lib/rlang/lib/malloc.c +97 -0
  22. data/lib/rlang/lib/malloc.rb +169 -0
  23. data/lib/rlang/lib/memory.rb +11 -0
  24. data/lib/rlang/lib/type/i32.rb +7 -0
  25. data/lib/rlang/lib/type/i64.rb +7 -0
  26. data/lib/rlang/lib/type.rb +6 -0
  27. data/lib/rlang/lib/unistd.rb +47 -0
  28. data/lib/rlang/lib.rb +10 -0
  29. data/lib/rlang/parser/const.rb +15 -0
  30. data/lib/rlang/parser/cvar.rb +44 -0
  31. data/lib/rlang/parser/data.rb +105 -0
  32. data/lib/rlang/parser/export.rb +22 -0
  33. data/lib/rlang/parser/ext/integer.rb +5 -0
  34. data/lib/rlang/parser/ext/string.rb +5 -0
  35. data/lib/rlang/parser/ext/type.rb +64 -0
  36. data/lib/rlang/parser/global.rb +65 -0
  37. data/lib/rlang/parser/lvar.rb +29 -0
  38. data/lib/rlang/parser/marg.rb +30 -0
  39. data/lib/rlang/parser/method.rb +76 -0
  40. data/lib/rlang/parser/wattr.rb +65 -0
  41. data/lib/rlang/parser/wgenerator.rb +509 -0
  42. data/lib/rlang/parser/winstruction.rb +148 -0
  43. data/lib/rlang/parser/wnode.rb +455 -0
  44. data/lib/rlang/parser/wtree.rb +19 -0
  45. data/lib/rlang/parser/wtype.rb +116 -0
  46. data/lib/rlang/parser.rb +1842 -0
  47. data/lib/rlang/version.rb +3 -0
  48. data/lib/rlang.rb +4 -0
  49. data/lib/simul/classes/data.rb +80 -0
  50. data/lib/simul/classes/global.rb +38 -0
  51. data/lib/simul/classes/memory.rb +131 -0
  52. data/lib/utils/log.rb +32 -0
  53. data/rlang.gemspec +38 -0
  54. metadata +158 -0
@@ -0,0 +1,3 @@
1
+ module Rlang
2
+ VERSION = "0.3.0"
3
+ end
data/lib/rlang.rb ADDED
@@ -0,0 +1,4 @@
1
+ require_relative "./rlang/version"
2
+ require_relative "./utils/log"
3
+ require_relative "./rlang/parser"
4
+ require_relative "./builder"
@@ -0,0 +1,80 @@
1
+ require_relative '../../utils/log'
2
+ require_relative './memory'
3
+ require_relative '../../rlang/parser/ext/string'
4
+ require_relative '../../rlang/parser/ext/type'
5
+ require_relative '../../rlang/parser/ext/integer'
6
+
7
+
8
+ # Don't use class name Data because it's a deprecated
9
+ # Ruby class and it generates warning at runtime
10
+ class DAta
11
+
12
+ @@symbol_table = {}
13
+ @@current_address = 0
14
+
15
+ attr_reader :symbol, :value, :wtype, :address
16
+
17
+ def initialize(symbol, value, wtype=Type::I32)
18
+ @symbol = symbol
19
+ @value = (value.is_a?(Array) ? value : [value])
20
+ @wtype = wtype
21
+ @address = @@current_address
22
+ @@symbol_table[@symbol] = self
23
+ size = self.update(@symbol, @value, @wtype)
24
+ Log.debug "size after update #{size}"
25
+ @@current_address += size
26
+ end
27
+
28
+ def update(symbol, value, wtype)
29
+ Log.debug "updating data value #{value} at #{address} / #{wtype.size}"
30
+ original_address = self.address
31
+ new_address = address
32
+ value.each do |elt|
33
+ if elt.is_a? String
34
+ elt.each_byte do |b|
35
+ Memory.store(new_address, b, 8)
36
+ new_address += 1
37
+ end
38
+ elsif elt.is_a? Integer
39
+ Memory.store(new_address, elt, wtype.size*8)
40
+ new_address += wtype.size
41
+ Log.debug "new _address : #{new_address}"
42
+ else
43
+ raise "Unknown Data type: #{value.class}"
44
+ end
45
+ end
46
+ new_address - original_address
47
+ end
48
+
49
+ def self.has_symbol?(symbol)
50
+ @@symbol_table.has_key? symbol
51
+ end
52
+
53
+ def self.[](symbol)
54
+ raise "Unknown data symbol '#{symbol}'" unless self.has_symbol? symbol
55
+ @@symbol_table[symbol].address
56
+ end
57
+
58
+ # Store string or integer in memory
59
+ # (note: integer are treated as I32)
60
+ def self.[]=(symbol, value)
61
+ if self.has_symbol? symbol
62
+ self.update(symbol, value)
63
+ else
64
+ self.new(symbol, value)
65
+ end
66
+ end
67
+
68
+ def self.current_address=(address)
69
+ @@current_address = address
70
+ end
71
+
72
+ # Align current address to closest multiple of
73
+ # n by higher value
74
+ def self.align(n)
75
+ if (m = @@current_address % n) != 0
76
+ @@current_address = (@@current_address - m) + n
77
+ end
78
+ end
79
+
80
+ end
@@ -0,0 +1,38 @@
1
+ require_relative '../rlang/parser/ext/type'
2
+
3
+ class Global
4
+
5
+ @@globals = {}
6
+
7
+ attr_reader :key, :value, :wtype
8
+
9
+ def initialize(key, value, wtype = Type::DEFAULT_TYPE, mutable: true)
10
+ raise "Can't initialize same Global twice #{key}" \
11
+ if @@globals.has_key? key
12
+ @key = key
13
+ @value = value
14
+ @@globals[key] = self
15
+ @wtype = wtype
16
+ @mutable = mutable
17
+ end
18
+
19
+ def []= (key, value)
20
+ raise "Cannot modify unmutable global #{@key}" unless self.mutable?
21
+ end
22
+
23
+ def [] (key)
24
+ @@globals[key].value
25
+ end
26
+
27
+ def mutable?
28
+ @mutable
29
+ end
30
+
31
+ def self.has_key?(key)
32
+ @@globals.has_key? key
33
+ end
34
+
35
+ def self.find_gvar(key)
36
+ @@globals[key]
37
+ end
38
+ end
@@ -0,0 +1,131 @@
1
+ require_relative './../rlang/parser/ext/type.rb'
2
+
3
+ class Memory
4
+
5
+ # Initial memory size (8 pages of WASM memory - 64 KB each)
6
+ MAX_SIZE = 8
7
+ WASM_PAGE_SIZE = 64 * 1024
8
+ MAX_I32 = 2**32 - 1
9
+ @@mem = nil
10
+
11
+ # size unit in WASM pages (64 KB)
12
+ def self.init(max_size)
13
+ @@max_size = max_size || MAX_SIZE
14
+ @@mem_size = @@max_size * WASM_PAGE_SIZE
15
+ @@mem = String.new("\00"*@@mem_size, encoding:'ASCII-8BIT', capacity: @@mem_size)
16
+ end
17
+
18
+ def self.size
19
+ @@max_size
20
+ end
21
+
22
+ def self.size_in_bytes
23
+ @@mem_size
24
+ end
25
+
26
+ def self.dump
27
+ @@mem
28
+ end
29
+
30
+ def self.load(address, type=Type::I32 , nbits=nil, signed=false)
31
+ if type == Type::I32
32
+ if nbits.nil? || nbits == 32
33
+ # i32.load: load 4 bytes as i32
34
+ value = @@mem.byteslice(address,4).unpack('L').first
35
+ elsif nbits == 16
36
+ if signed
37
+ # i32.load16_s: load 2 bytes and sign-extend i16 to i32
38
+ value = @@mem.byteslice(address,2).unpack('s').first
39
+ else
40
+ # i32.load16_u: load 2 bytes and zero-extend i16 to i32
41
+ value = @@mem.byteslice(address,2).unpack('S').first
42
+ end
43
+ elsif nbits == 8
44
+ if signed
45
+ # i32.load8_s: load 1 byte and sign-extend i8 to i32
46
+ value = @@mem.byteslice(address).unpack('c').first
47
+ else
48
+ # i32.load16_u: load 1 byte and zero-extend i8 to i32
49
+ value = @@mem.byteslice(address).unpack('C').first
50
+ end
51
+ else
52
+ raise "Unknown number of bits #{nbits}"
53
+ end
54
+ return Type::I32.new(value)
55
+ elsif type == Type::I64
56
+ if nbits.nil? || nbits == 64
57
+ # i64.load: load 8 bytes as i64
58
+ value = @@mem.byteslice(address,8).unpack('Q').first
59
+ elsif nbits == 32
60
+ if signed
61
+ # i64.load32_s: load 4 bytes and sign-extend i32 to i64
62
+ value = @@mem.byteslice(address,4).unpack('l').first
63
+ else
64
+ # i64.load32_u: load 4 bytes and zero-extend i32 to i64
65
+ value = @@mem.byteslice(address,4).unpack('L').first
66
+ end
67
+ elsif nbits == 16
68
+ if signed
69
+ # i64.load16_s: load 2 bytes and sign-extend i16 to i64
70
+ value = @@mem.byteslice(address,2).unpack('s').first
71
+ else
72
+ # i64.load16_u: load 2 bytes and zero-extend i16 to i64
73
+ value = @@mem.byteslice(address,2).unpack('S').first
74
+ end
75
+ elsif nbits == 8
76
+ if signed
77
+ # i64.load8_s: load 1 byte and sign-extend i8 to i64
78
+ value = @@mem.byteslice(address).unpack('c').first
79
+ else
80
+ # i64.load8_u: load 1 byte and zero-extend i8 to i64
81
+ value = @@mem.byteslice(address).unpack('C').first
82
+ end
83
+ else
84
+ raise "Unknown number of bits #{nbits}"
85
+ end
86
+ return Type::I64.new(value)
87
+ else
88
+ raise "Unknown target type #{type}"
89
+ end
90
+
91
+ end
92
+
93
+ def self.store(address, value, nbits=32)
94
+ #puts '***', address, value, nbits
95
+ if value.is_a? Integer || (value.is_a? Type::I32)
96
+ raise "Value #{value} too large to fit in 32 bits at address #{}" if value > MAX_I32
97
+ case nbits
98
+ when 64
99
+ raise "Cannot store i64 in i32 memory location (wrap/truncate first)"
100
+ when nil, 32
101
+ # i32.store: (no conversion) store 4 bytes
102
+ @@mem[address,4] = [value].pack('L<')
103
+ when 16
104
+ # i32.store16: wrap i32 to i16 and store 2 bytes
105
+ @@mem[address,2] = [value].pack('S<')
106
+ when 8
107
+ # i32.store8: wrap i32 to i8 and store 1 byte
108
+ @@mem[address] = [value].pack('C')
109
+ end
110
+ elsif value.is_a? Type::I64
111
+ case nbits
112
+ when nil, 64
113
+ # i64.store: (no conversion) store 8 bytes
114
+ @@mem[address,8] = [value].pack('Q<')
115
+ when 32
116
+ # i64.store32: (no conversion) store 4 bytes
117
+ @@mem[address,4] = [value].pack('L<')
118
+ when 16
119
+ # i64.store16: wrap i32 to i16 and store 2 bytes
120
+ @@mem[address,2] = [value].pack('S<')
121
+ when 8
122
+ # i64.store8: wrap i32 to i8 and store 1 byte
123
+ @@mem[address] = [value].pack('C')
124
+ end
125
+ else
126
+ raise "Unknow data type #{value.class} for #{value}"
127
+ end
128
+
129
+ end
130
+
131
+ end
data/lib/utils/log.rb ADDED
@@ -0,0 +1,32 @@
1
+ # Rubinius WebAssembly VM
2
+ # Copyright (c) 2019, Laurent Julliard and contributors
3
+ # All rights reserved.
4
+ #
5
+ # Rlang logging module
6
+
7
+ require 'logger'
8
+
9
+ module Log
10
+ class << self
11
+ def logger
12
+ @logger ||= Logger.new($stdout)
13
+ end
14
+
15
+ def logger=(logger)
16
+ @logger = logger
17
+ end
18
+ end
19
+
20
+ # Addition
21
+ def self.included(base)
22
+ class << base
23
+ def logger
24
+ Log.logger
25
+ end
26
+ end
27
+ end
28
+
29
+ def logger
30
+ Log.logger
31
+ end
32
+ end
data/rlang.gemspec ADDED
@@ -0,0 +1,38 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "rlang/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "rlang"
7
+ spec.version = Rlang::VERSION
8
+ spec.authors = ["Laurent Julliard"]
9
+ spec.email = ["laurent@moldus.org"]
10
+
11
+ spec.summary = %q{A (subset of) Ruby to WebAssembly compiler}
12
+ spec.description = %q{Rlang is meant to create fast and uncluttered WebAssembly code
13
+ from the comfort of the Ruby language. It is actually made of two things: a supported
14
+ subset of the Ruby language and a compiler transforming this Ruby subset in a valid
15
+ and fully runnable WebAssembly module.}
16
+ spec.homepage = "https://github.com/ljulliar/rlang"
17
+ spec.license = "MPL-2.0"
18
+
19
+ #spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
20
+
21
+ spec.metadata["homepage_uri"] = spec.homepage
22
+ spec.metadata["source_code_uri"] = "https://github.com/ljulliar/rlang"
23
+ spec.metadata["changelog_uri"] = "https://github.com/ljulliar/rlang/blob/master/CHANGELOG.md"
24
+
25
+ # Specify which files should be added to the gem when it is released.
26
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
27
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
28
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|featuresi|\.)/}) }
29
+ end
30
+ spec.bindir = "bin"
31
+ spec.executables << "rlang"
32
+ spec.require_paths = ["lib"]
33
+
34
+ spec.add_development_dependency "bundler", "~> 2.0"
35
+ spec.add_development_dependency "rake", "~> 10.0"
36
+ spec.add_development_dependency "minitest", "~> 5.0"
37
+ spec.add_development_dependency "wasmer", "~> 0.3"
38
+ end
metadata ADDED
@@ -0,0 +1,158 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rlang
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Laurent Julliard
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-02-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: wasmer
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.3'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.3'
69
+ description: "Rlang is meant to create fast and uncluttered WebAssembly code \n from
70
+ the comfort of the Ruby language. It is actually made of two things: a supported
71
+ \n subset of the Ruby language and a compiler transforming this Ruby subset in
72
+ a valid \n and fully runnable WebAssembly module."
73
+ email:
74
+ - laurent@moldus.org
75
+ executables:
76
+ - rlang
77
+ extensions: []
78
+ extra_rdoc_files: []
79
+ files:
80
+ - ".gitignore"
81
+ - ".rake_tasks~"
82
+ - ".travis.yml"
83
+ - CODE_OF_CONDUCT.md
84
+ - Gemfile
85
+ - LICENSE
86
+ - README.md
87
+ - Rakefile
88
+ - bin/rlang
89
+ - docs/RlangCompiler.md
90
+ - docs/RlangManual.md
91
+ - lib/builder.rb
92
+ - lib/builder/ext.rb
93
+ - lib/builder/ext/tempfile.rb
94
+ - lib/builder/rlang.rb
95
+ - lib/builder/rlang/builder.rb
96
+ - lib/builder/wat.rb
97
+ - lib/builder/wat/builder.rb
98
+ - lib/builder/wat/renderer.rb
99
+ - lib/rlang.rb
100
+ - lib/rlang/lib.rb
101
+ - lib/rlang/lib/malloc.c
102
+ - lib/rlang/lib/malloc.rb
103
+ - lib/rlang/lib/memory.rb
104
+ - lib/rlang/lib/type.rb
105
+ - lib/rlang/lib/type/i32.rb
106
+ - lib/rlang/lib/type/i64.rb
107
+ - lib/rlang/lib/unistd.rb
108
+ - lib/rlang/parser.rb
109
+ - lib/rlang/parser/const.rb
110
+ - lib/rlang/parser/cvar.rb
111
+ - lib/rlang/parser/data.rb
112
+ - lib/rlang/parser/export.rb
113
+ - lib/rlang/parser/ext/integer.rb
114
+ - lib/rlang/parser/ext/string.rb
115
+ - lib/rlang/parser/ext/type.rb
116
+ - lib/rlang/parser/global.rb
117
+ - lib/rlang/parser/lvar.rb
118
+ - lib/rlang/parser/marg.rb
119
+ - lib/rlang/parser/method.rb
120
+ - lib/rlang/parser/wattr.rb
121
+ - lib/rlang/parser/wgenerator.rb
122
+ - lib/rlang/parser/winstruction.rb
123
+ - lib/rlang/parser/wnode.rb
124
+ - lib/rlang/parser/wtree.rb
125
+ - lib/rlang/parser/wtype.rb
126
+ - lib/rlang/version.rb
127
+ - lib/simul/classes/data.rb
128
+ - lib/simul/classes/global.rb
129
+ - lib/simul/classes/memory.rb
130
+ - lib/utils/log.rb
131
+ - rlang.gemspec
132
+ homepage: https://github.com/ljulliar/rlang
133
+ licenses:
134
+ - MPL-2.0
135
+ metadata:
136
+ homepage_uri: https://github.com/ljulliar/rlang
137
+ source_code_uri: https://github.com/ljulliar/rlang
138
+ changelog_uri: https://github.com/ljulliar/rlang/blob/master/CHANGELOG.md
139
+ post_install_message:
140
+ rdoc_options: []
141
+ require_paths:
142
+ - lib
143
+ required_ruby_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ required_rubygems_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ requirements: []
154
+ rubygems_version: 3.0.3
155
+ signing_key:
156
+ specification_version: 4
157
+ summary: A (subset of) Ruby to WebAssembly compiler
158
+ test_files: []