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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rake_tasks~ +0 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/LICENSE +373 -0
- data/README.md +61 -0
- data/Rakefile +10 -0
- data/bin/rlang +164 -0
- data/docs/RlangCompiler.md +37 -0
- data/docs/RlangManual.md +391 -0
- data/lib/builder/ext/tempfile.rb +7 -0
- data/lib/builder/ext.rb +5 -0
- data/lib/builder/rlang/builder.rb +31 -0
- data/lib/builder/rlang.rb +2 -0
- data/lib/builder/wat/builder.rb +52 -0
- data/lib/builder/wat/renderer.rb +28 -0
- data/lib/builder/wat.rb +3 -0
- data/lib/builder.rb +7 -0
- data/lib/rlang/lib/malloc.c +97 -0
- data/lib/rlang/lib/malloc.rb +169 -0
- data/lib/rlang/lib/memory.rb +11 -0
- data/lib/rlang/lib/type/i32.rb +7 -0
- data/lib/rlang/lib/type/i64.rb +7 -0
- data/lib/rlang/lib/type.rb +6 -0
- data/lib/rlang/lib/unistd.rb +47 -0
- data/lib/rlang/lib.rb +10 -0
- data/lib/rlang/parser/const.rb +15 -0
- data/lib/rlang/parser/cvar.rb +44 -0
- data/lib/rlang/parser/data.rb +105 -0
- data/lib/rlang/parser/export.rb +22 -0
- data/lib/rlang/parser/ext/integer.rb +5 -0
- data/lib/rlang/parser/ext/string.rb +5 -0
- data/lib/rlang/parser/ext/type.rb +64 -0
- data/lib/rlang/parser/global.rb +65 -0
- data/lib/rlang/parser/lvar.rb +29 -0
- data/lib/rlang/parser/marg.rb +30 -0
- data/lib/rlang/parser/method.rb +76 -0
- data/lib/rlang/parser/wattr.rb +65 -0
- data/lib/rlang/parser/wgenerator.rb +509 -0
- data/lib/rlang/parser/winstruction.rb +148 -0
- data/lib/rlang/parser/wnode.rb +455 -0
- data/lib/rlang/parser/wtree.rb +19 -0
- data/lib/rlang/parser/wtype.rb +116 -0
- data/lib/rlang/parser.rb +1842 -0
- data/lib/rlang/version.rb +3 -0
- data/lib/rlang.rb +4 -0
- data/lib/simul/classes/data.rb +80 -0
- data/lib/simul/classes/global.rb +38 -0
- data/lib/simul/classes/memory.rb +131 -0
- data/lib/utils/log.rb +32 -0
- data/rlang.gemspec +38 -0
- metadata +158 -0
data/lib/rlang.rb
ADDED
@@ -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: []
|