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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -3
- data/Gemfile.lock +1 -1
- data/README.md +8 -6
- data/bin/rlang +13 -5
- data/docs/RlangCompiler.md +3 -1
- data/docs/RlangManual.md +36 -9
- data/examples/fib/fib.rb +5 -1
- data/lib/builder/rlang/compiler.rb +2 -21
- data/lib/rlang.rb +3 -0
- data/lib/rlang/lib/array/array32.rb +9 -2
- data/lib/rlang/lib/array/array64.rb +6 -1
- data/lib/rlang/lib/io.rb +70 -0
- data/lib/rlang/lib/kernel.rb +7 -2
- data/lib/rlang/lib/malloc.rb +2 -2
- data/lib/rlang/lib/object.rb +6 -0
- data/lib/rlang/lib/rlang.rb +29 -0
- data/lib/rlang/lib/rlang_core.rb +14 -0
- data/lib/rlang/lib/string.rb +14 -1
- data/lib/rlang/lib/type/i32.rb +25 -0
- data/lib/rlang/lib/type/i64.rb +4 -0
- data/lib/rlang/lib/wasi.rb +133 -0
- data/lib/rlang/parser.rb +134 -22
- data/lib/rlang/parser/const.rb +1 -1
- data/lib/rlang/parser/cvar.rb +2 -2
- data/lib/rlang/parser/data.rb +7 -4
- data/lib/rlang/parser/export.rb +4 -3
- data/lib/rlang/parser/global.rb +3 -2
- data/lib/rlang/parser/method.rb +15 -2
- data/lib/rlang/parser/wgenerator.rb +72 -16
- data/lib/rlang/parser/wnode.rb +55 -12
- data/lib/rlang/version.rb +1 -1
- metadata +6 -3
- data/lib/rlang/lib.rb +0 -13
data/lib/rlang/lib/object.rb
CHANGED
@@ -6,6 +6,7 @@
|
|
6
6
|
|
7
7
|
require_relative './malloc'
|
8
8
|
require_relative './kernel'
|
9
|
+
require_relative './string'
|
9
10
|
|
10
11
|
class Object
|
11
12
|
|
@@ -20,4 +21,9 @@ class Object
|
|
20
21
|
result :none
|
21
22
|
Malloc.free(object_ptr)
|
22
23
|
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
result :String
|
27
|
+
"Object <addr>"
|
28
|
+
end
|
23
29
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Rubinius WebAssembly VM
|
2
|
+
# Copyright (c) 2019-2020, Laurent Julliard and contributors
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Rlang standard library classes and modules
|
6
|
+
# and runtime initialization
|
7
|
+
#
|
8
|
+
require_relative './rlang_core'
|
9
|
+
require_relative './wasi'
|
10
|
+
require_relative './io'
|
11
|
+
|
12
|
+
class Rlang
|
13
|
+
def self.init
|
14
|
+
# WASI init: setup ARGC, ARGV, etc...
|
15
|
+
errno = WASI.init
|
16
|
+
|
17
|
+
# IO init: setup fd of stdin, out and err
|
18
|
+
# This code cannot be executed within io.rb
|
19
|
+
# as STDxxx can only be used after io.rb is
|
20
|
+
# compiled
|
21
|
+
STDIN.fd = WASI::STDIN_FD
|
22
|
+
STDOUT.fd = WASI::STDOUT_FD
|
23
|
+
STDERR.fd = WASI::STDERR_FD
|
24
|
+
$stdin = STDIN
|
25
|
+
$stdout = STDOUT
|
26
|
+
$stderr = STDERR
|
27
|
+
errno
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Rubinius WebAssembly VM
|
2
|
+
# Copyright (c) 2019-2020, Laurent Julliard and contributors
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Rlang core library classes and modules
|
6
|
+
#
|
7
|
+
require_relative './type'
|
8
|
+
require_relative './memory'
|
9
|
+
require_relative './unistd'
|
10
|
+
require_relative './malloc'
|
11
|
+
require_relative './object'
|
12
|
+
require_relative './kernel'
|
13
|
+
require_relative './string'
|
14
|
+
require_relative './array'
|
data/lib/rlang/lib/string.rb
CHANGED
@@ -11,8 +11,18 @@ class String
|
|
11
11
|
# ptr is a simple memory address of type
|
12
12
|
# :I32 (see it as the equivalent of a
|
13
13
|
# char * in C)
|
14
|
+
|
15
|
+
# There are 3 ways to initialize a new String object
|
16
|
+
# * with a string literal (e.g. mystring = "Hello World!")
|
17
|
+
# * by pointing at an existing memory location (e.g. String.new(ptr, length))
|
18
|
+
# * by asking Rlang to allocate the String space when ptr is NULL (e.g. String.new(0, length))
|
14
19
|
def initialize(ptr, length)
|
15
|
-
|
20
|
+
result :none
|
21
|
+
if ptr == 0
|
22
|
+
@ptr = Malloc.malloc(length)
|
23
|
+
else
|
24
|
+
@ptr = ptr
|
25
|
+
end
|
16
26
|
@length = length
|
17
27
|
end
|
18
28
|
|
@@ -28,4 +38,7 @@ class String
|
|
28
38
|
String.new(new_ptr, new_length)
|
29
39
|
end
|
30
40
|
|
41
|
+
def size; @length; end
|
42
|
+
def to_s; self; end
|
43
|
+
|
31
44
|
end
|
data/lib/rlang/lib/type/i32.rb
CHANGED
@@ -2,6 +2,31 @@
|
|
2
2
|
# Copyright (c) 2019, Laurent Julliard and contributors
|
3
3
|
# All rights reserved.
|
4
4
|
#
|
5
|
+
# Integer 32 methods
|
6
|
+
|
7
|
+
class String; end
|
8
|
+
|
5
9
|
class I32
|
10
|
+
ConvertString = "0123456789ABCDEF"
|
11
|
+
|
6
12
|
def self.size; 4; end
|
13
|
+
|
14
|
+
def to_str(base)
|
15
|
+
result :String
|
16
|
+
"0"
|
17
|
+
=begin
|
18
|
+
# TODO
|
19
|
+
if n < base
|
20
|
+
return convertString[n]
|
21
|
+
else
|
22
|
+
return toStr(n//base,base) + convertString[n%base]
|
23
|
+
end
|
24
|
+
=end
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
result :String
|
29
|
+
self.to_str(10)
|
30
|
+
end
|
31
|
+
|
7
32
|
end
|
data/lib/rlang/lib/type/i64.rb
CHANGED
@@ -0,0 +1,133 @@
|
|
1
|
+
# Rubinius WebAssembly VM
|
2
|
+
# Copyright (c) 2019-2020, Laurent Julliard and contributors
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# WASI Interface to WASM runtime
|
6
|
+
|
7
|
+
require_relative './array'
|
8
|
+
require_relative './string'
|
9
|
+
|
10
|
+
ARGC = 0
|
11
|
+
ARGV = 0.cast_to(:Array32)
|
12
|
+
|
13
|
+
class WASI
|
14
|
+
STDIN_FD = 0
|
15
|
+
STDOUT_FD = 1
|
16
|
+
STDERR_FD = 2
|
17
|
+
@@argv_buf_size = 0
|
18
|
+
|
19
|
+
class CIOVec
|
20
|
+
attr_reader :ciovs
|
21
|
+
attr_type ciovs: :Array32
|
22
|
+
|
23
|
+
def initialize(n)
|
24
|
+
result :none
|
25
|
+
# a ciov is list of n (address to buffer, length of buffer)
|
26
|
+
@n = n
|
27
|
+
@index = 0
|
28
|
+
@max_index = 2 * @n
|
29
|
+
@ciovs = Array32.new(2*n)
|
30
|
+
end
|
31
|
+
|
32
|
+
def << (string)
|
33
|
+
arg string: :String
|
34
|
+
result :CIOVec
|
35
|
+
raise "CIOVec full !" if @index >= @max_index
|
36
|
+
@ciovs[@index] = string.ptr
|
37
|
+
@ciovs[@index+1] = string.length
|
38
|
+
@index += 2
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
def free
|
43
|
+
result :none
|
44
|
+
@ciovs.free
|
45
|
+
Object.free(self)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# An IOVec is an array of (address to buffer, length of buffer)
|
50
|
+
# where WASM runtime can read data coming from the WASM module
|
51
|
+
class IOVec
|
52
|
+
attr_reader :iovs
|
53
|
+
attr_type iovs: :Array32
|
54
|
+
|
55
|
+
IOV_SIZE = 1024
|
56
|
+
|
57
|
+
def initialize(n)
|
58
|
+
result :none
|
59
|
+
@iovs = Array32.new(2*n)
|
60
|
+
@n = n
|
61
|
+
i = 0
|
62
|
+
while i < n;
|
63
|
+
@iovs[i] = Malloc.malloc(IOV_SIZE)
|
64
|
+
@iovs[i+1] = IOV_SIZE
|
65
|
+
i += 2
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def free
|
70
|
+
result :none
|
71
|
+
i = 0
|
72
|
+
while i < @n
|
73
|
+
Malloc.free(@iovs[i])
|
74
|
+
i += 2
|
75
|
+
end
|
76
|
+
@iovs.free
|
77
|
+
Object.free(self)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Import WASI functions
|
82
|
+
import :wasi_unstable, :args_sizes_get
|
83
|
+
def self.args_sizes_get(argc, args_size); end
|
84
|
+
|
85
|
+
import :wasi_unstable, :args_get
|
86
|
+
def self.args_get(argv, argv_buf); end
|
87
|
+
|
88
|
+
import :wasi_unstable, :fd_write
|
89
|
+
def self.fd_write(fd, iovs, iovs_count, nwritten_ptr); end
|
90
|
+
|
91
|
+
import :wasi_unstable, :fd_read
|
92
|
+
def self.fd_read(fd, iovs, iovs_count, nread_ptr); end
|
93
|
+
|
94
|
+
import :wasi_unstable, :proc_exit
|
95
|
+
def self.proc_exit(exitcode); result :none; end
|
96
|
+
|
97
|
+
# Initialize WASI environment and related Rlang
|
98
|
+
# objects (ARGC, ARGV,...)
|
99
|
+
def self.init
|
100
|
+
local argv: :Array32
|
101
|
+
|
102
|
+
# Get number of arguments and their total size
|
103
|
+
errno = WASI.args_sizes_get(ARGC.addr, @@argv_buf_size.addr)
|
104
|
+
raise "Errno args_sizes_get" if errno != 0
|
105
|
+
|
106
|
+
# Allocate memory areas to receive the argument pointers
|
107
|
+
# (argv) and the argument strings (argv_buf)
|
108
|
+
#
|
109
|
+
# Setup an extra slot in argv array to simplify the
|
110
|
+
# loop below
|
111
|
+
argv = Array32.new(ARGC+1) #Malloc.malloc((ARGC+1) * 4) # Assuming I32 for pointers
|
112
|
+
argv_buf = Malloc.malloc(@@argv_buf_size)
|
113
|
+
errno = WASI.args_get(argv.ptr, argv_buf)
|
114
|
+
|
115
|
+
raise "Errno args_get" if errno != 0
|
116
|
+
argv[ARGC] = argv[0] + @@argv_buf_size
|
117
|
+
|
118
|
+
# Workaround to avoid dynamic constant assignment error
|
119
|
+
Memory.store32(ARGV.addr, Array32.new(ARGC))
|
120
|
+
|
121
|
+
# Now scan through arguments and turn them into a Rlang
|
122
|
+
# Array of Strings (like ARGV in Ruby)
|
123
|
+
i = 0
|
124
|
+
while i < ARGC
|
125
|
+
length = argv[i+1] - argv[i] - 1 # -1 because of null terminated
|
126
|
+
ARGV[i] = String.new(argv[i], length)
|
127
|
+
i += 1
|
128
|
+
end
|
129
|
+
return errno
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
data/lib/rlang/parser.rb
CHANGED
@@ -29,23 +29,19 @@ module Rlang::Parser
|
|
29
29
|
|
30
30
|
include Log
|
31
31
|
|
32
|
-
ARITHMETIC_OPS = [:+, :-, :*, :/, :%, :&, :|, :^, :>>, :<<]
|
33
|
-
RELATIONAL_OPS = [:==, :!=, :>, :<, :>=, :<=, :'>s', :'<s', :'>=s', :'>=s']
|
34
|
-
UNARY_OPS = [:'!']
|
35
|
-
|
36
|
-
# Type cast order in decreading order of precedence
|
37
|
-
TYPE_CAST_PRECEDENCE = [Type::F64, Type::F32, Type::I64, Type::I32]
|
38
|
-
|
39
32
|
# WARNING!! THIS IS A **VERY** NASTY HACK PRETENDING
|
40
33
|
# THAT THIS int VALUE means NIL. It's totally unsafe
|
41
34
|
# of course as an expression could end up evaluating
|
42
35
|
# to this value and not be nil at all. But I'm using
|
43
36
|
# it for now in the xxxx_with_result_type variants of
|
44
37
|
# some parsing methods (if, while,...)
|
38
|
+
# NOTE: those variants with result type are **NOT** the
|
39
|
+
# ones used by Rlang right now
|
45
40
|
NIL = 999999999
|
46
41
|
|
47
|
-
# export toggle for method declaration
|
48
|
-
@@export = false
|
42
|
+
# export and import toggle for method declaration
|
43
|
+
@@export, @@export_name = false, nil
|
44
|
+
@@import, @@import_module_name, @@import_function_name = false, nil, nil
|
49
45
|
|
50
46
|
|
51
47
|
attr_accessor :wgenerator, :source, :config
|
@@ -121,6 +117,8 @@ module Rlang::Parser
|
|
121
117
|
raise "wnode type is incorrect (got #{wnode})" unless wnode.is_a?(WNode) || wnode.nil?
|
122
118
|
logger.debug "\n---------------------->>\n" +
|
123
119
|
"Parsing node: #{node}, wnode: #{wnode.head}, keep_eval: #{keep_eval}"
|
120
|
+
# Nothing to parse
|
121
|
+
return if node.nil?
|
124
122
|
|
125
123
|
case node.type
|
126
124
|
when :self
|
@@ -274,8 +272,12 @@ module Rlang::Parser
|
|
274
272
|
super_class_path = _build_const_path(super_class_const_node)
|
275
273
|
wn_class = @wgenerator.klass(wnode, class_path, super_class_path)
|
276
274
|
|
275
|
+
# If body node is nil then this must be interpreted as
|
276
|
+
# a class declaration (no implementation yet)
|
277
|
+
return wn_class unless body_node
|
278
|
+
|
277
279
|
# Parse the body of the class
|
278
|
-
parse_node(body_node, wn_class)
|
280
|
+
parse_node(body_node, wn_class)
|
279
281
|
|
280
282
|
# We finished parsing the class body so
|
281
283
|
# 1) postprocess instance variables
|
@@ -962,7 +964,9 @@ module Rlang::Parser
|
|
962
964
|
|
963
965
|
# create corresponding func node
|
964
966
|
wn_method = @wgenerator.def_method(wnode, method_name, :class)
|
965
|
-
|
967
|
+
if @@import
|
968
|
+
wn_import = @wgenerator.import_method(wn_method, @@import_module_name, @@import_function_name)
|
969
|
+
end
|
966
970
|
|
967
971
|
# collect method arguments
|
968
972
|
parse_args(arg_nodes, wn_method)
|
@@ -970,7 +974,7 @@ module Rlang::Parser
|
|
970
974
|
# that we know what the return type is in advance
|
971
975
|
# If :nil for instance then it may change the way
|
972
976
|
# we generate code in the body of the method
|
973
|
-
if (result_node = body_node.children.find {|n| n.respond_to?(:type) && n.type == :send && n.children[1] == :result})
|
977
|
+
if body_node && (result_node = body_node.children.find {|n| n.respond_to?(:type) && n.type == :send && n.children[1] == :result})
|
974
978
|
logger.debug "result directive found: #{result_node}"
|
975
979
|
parse_node(result_node, wn_method, keep_eval)
|
976
980
|
end
|
@@ -987,9 +991,12 @@ module Rlang::Parser
|
|
987
991
|
@wgenerator.locals(wn_method)
|
988
992
|
@wgenerator.result(wn_method)
|
989
993
|
@wgenerator.params(wn_method)
|
994
|
+
@wgenerator.export_method(wn_method, @@export_name) if (@@export || self.config[:export_all])
|
990
995
|
logger.debug "Full method wnode: #{wn_method}"
|
991
|
-
|
992
|
-
|
996
|
+
|
997
|
+
# reset method toggles
|
998
|
+
self.class._reset_toggles
|
999
|
+
|
993
1000
|
return wn_method
|
994
1001
|
end
|
995
1002
|
|
@@ -1008,18 +1015,19 @@ module Rlang::Parser
|
|
1008
1015
|
logger.debug "Defining instance method: #{method_name}"
|
1009
1016
|
|
1010
1017
|
# create corresponding func node
|
1011
|
-
# Note: because module inclusion generate both instance
|
1012
|
-
# and class methods we may get two methods wnode
|
1013
1018
|
wn_method = @wgenerator.def_method(wnode, method_name, :instance)
|
1014
|
-
|
1019
|
+
if @@import
|
1020
|
+
wn_import = @wgenerator.import_method(wn_method, @@import_module_name, @@import_function_name)
|
1021
|
+
end
|
1015
1022
|
|
1016
1023
|
# collect method arguments
|
1017
1024
|
wn_args = parse_args(arg_nodes, wn_method)
|
1025
|
+
|
1018
1026
|
# Look for any result directive and parse it so
|
1019
1027
|
# that we know what the return type is in advance
|
1020
1028
|
# If :nil for instance then it may change the way
|
1021
1029
|
# we generate code in the body of the method
|
1022
|
-
if (result_node = body_node.children.find {|n| n.respond_to?(:type) && n.type == :send && n.children[1] == :result})
|
1030
|
+
if body_node && (result_node = body_node.children.find {|n| n.respond_to?(:type) && n.type == :send && n.children[1] == :result})
|
1023
1031
|
logger.debug "result directive found: #{result_node}"
|
1024
1032
|
parse_node(result_node, wn_method, keep_eval)
|
1025
1033
|
end
|
@@ -1036,9 +1044,11 @@ module Rlang::Parser
|
|
1036
1044
|
@wgenerator.locals(wn_method)
|
1037
1045
|
@wgenerator.result(wn_method)
|
1038
1046
|
@wgenerator.params(wn_method)
|
1047
|
+
@wgenerator.export_method(wn_method, @@export_name) if (@@export || self.config[:export_all])
|
1039
1048
|
logger.debug "Full method wnode: #{wn_method}"
|
1040
|
-
|
1041
|
-
|
1049
|
+
|
1050
|
+
# reset method toggles
|
1051
|
+
self.class._reset_toggles
|
1042
1052
|
|
1043
1053
|
# if we are in a module then also define
|
1044
1054
|
# the class method because we don't know
|
@@ -1067,10 +1077,12 @@ module Rlang::Parser
|
|
1067
1077
|
when /^\./
|
1068
1078
|
# If file starts with . then look for file in pwd
|
1069
1079
|
load_path = [Dir.pwd]
|
1080
|
+
=begin
|
1070
1081
|
when /^rlang/
|
1071
1082
|
# If it starts with rlang then look for it in the
|
1072
1083
|
# installed rlang gem in addition to load path
|
1073
1084
|
load_path = self.config[:LOAD_PATH] + $LOAD_PATH
|
1085
|
+
=end
|
1074
1086
|
else
|
1075
1087
|
load_path = self.config[:LOAD_PATH]
|
1076
1088
|
load_path = [Dir.pwd] if self.config[:LOAD_PATH].empty?
|
@@ -1090,7 +1102,7 @@ module Rlang::Parser
|
|
1090
1102
|
end
|
1091
1103
|
end
|
1092
1104
|
end
|
1093
|
-
raise LoadError, "no such file to load: #{
|
1105
|
+
raise LoadError, "no such file to load: #{file}" unless full_path_file
|
1094
1106
|
|
1095
1107
|
# Now load the file
|
1096
1108
|
if File.extname(full_path_file) == '.wat'
|
@@ -1274,6 +1286,49 @@ module Rlang::Parser
|
|
1274
1286
|
return wn_cast
|
1275
1287
|
end
|
1276
1288
|
|
1289
|
+
# addr method applied to statically allocated variables
|
1290
|
+
# only constant and class variables returns their address
|
1291
|
+
# in memory
|
1292
|
+
#
|
1293
|
+
# Example
|
1294
|
+
# @@argv_bu_size.addr
|
1295
|
+
# ---
|
1296
|
+
# (send (cvar :@@argv_buf_size) :addr)
|
1297
|
+
#
|
1298
|
+
if method_name == :addr
|
1299
|
+
if recv_node.type == :const
|
1300
|
+
# Build constant path from embedded const sexp
|
1301
|
+
const_path = _build_const_path(recv_node)
|
1302
|
+
full_const_name = const_path.join('::')
|
1303
|
+
|
1304
|
+
# See if constant exists. It should at this point
|
1305
|
+
unless (const = wnode.find_const(const_path))
|
1306
|
+
raise "unknown constant #{full_const_name}"
|
1307
|
+
end
|
1308
|
+
wn_const_addr = @wgenerator.const_addr(wnode, const)
|
1309
|
+
|
1310
|
+
# Drop last evaluated result if asked to
|
1311
|
+
@wgenerator.drop(wnode) unless keep_eval
|
1312
|
+
return wn_const_addr
|
1313
|
+
|
1314
|
+
elsif recv_node.type == :cvar
|
1315
|
+
raise "Class variable can only be accessed in method scope" \
|
1316
|
+
unless wnode.in_method_scope?
|
1317
|
+
cv_name = recv_node.children.first
|
1318
|
+
if (cvar = wnode.find_cvar(cv_name))
|
1319
|
+
wn_cvar_addr = @wgenerator.cvar_addr(wnode, cvar)
|
1320
|
+
else
|
1321
|
+
raise "unknown class variable #{cv_name}"
|
1322
|
+
end
|
1323
|
+
# Drop last evaluated result if asked to
|
1324
|
+
@wgenerator.drop(wnode) unless keep_eval
|
1325
|
+
return wn_cvar_addr
|
1326
|
+
|
1327
|
+
else
|
1328
|
+
# Do nothing. This will be treated as a regular method call
|
1329
|
+
end
|
1330
|
+
end
|
1331
|
+
|
1277
1332
|
# A that stage it's a method call of some sort
|
1278
1333
|
# (call on class or instance)
|
1279
1334
|
return parse_send_method_lookup(node, wnode, keep_eval)
|
@@ -1310,6 +1365,10 @@ module Rlang::Parser
|
|
1310
1365
|
return parse_send_export(node, wnode, keep_eval)
|
1311
1366
|
end
|
1312
1367
|
|
1368
|
+
if recv_node.nil? && method_name == :import
|
1369
|
+
return parse_send_import(node, wnode, keep_eval)
|
1370
|
+
end
|
1371
|
+
|
1313
1372
|
if recv_node.nil? && method_name == :local
|
1314
1373
|
return parse_send_local(node, wnode, keep_eval)
|
1315
1374
|
end
|
@@ -1420,9 +1479,57 @@ module Rlang::Parser
|
|
1420
1479
|
|
1421
1480
|
# Directive to declare the current method
|
1422
1481
|
# in the WASM exports
|
1482
|
+
# Example
|
1483
|
+
#
|
1484
|
+
# export
|
1485
|
+
# ---
|
1486
|
+
# (send nil :export)
|
1487
|
+
# OR
|
1488
|
+
# export :function_name
|
1489
|
+
# ---
|
1490
|
+
# (send nil :export
|
1491
|
+
# (sym :function_name))
|
1492
|
+
#
|
1493
|
+
# With out an explicit function name, the export name
|
1494
|
+
# will be automatically built from the class/method names
|
1423
1495
|
def parse_send_export(node, wnode, keep_eval)
|
1424
|
-
|
1496
|
+
logger.debug "Export directive found for..."
|
1497
|
+
raise "export must be used in class scope" unless wnode.in_class_or_module_scope?
|
1425
1498
|
@@export = true
|
1499
|
+
if (function_node = node.children[2])
|
1500
|
+
raise "export function name must be a symbol (got #{function_node})" \
|
1501
|
+
unless function_node.type == :sym
|
1502
|
+
@@export_name = function_node.children.last
|
1503
|
+
end
|
1504
|
+
logger.debug "... #{@@export_name}"
|
1505
|
+
return
|
1506
|
+
end
|
1507
|
+
|
1508
|
+
# Directive to declare the current method
|
1509
|
+
# in the WASM imports
|
1510
|
+
# Example
|
1511
|
+
#
|
1512
|
+
# import :module_name, :function_name
|
1513
|
+
# ---
|
1514
|
+
# (send nil :import
|
1515
|
+
# (sym :mod)
|
1516
|
+
# (sym :func))
|
1517
|
+
#
|
1518
|
+
def parse_send_import(node, wnode, keep_eval)
|
1519
|
+
logger.debug "Import directive found for..."
|
1520
|
+
raise "export must be used in class scope" unless wnode.in_class_or_module_scope?
|
1521
|
+
raise "import expects 2 arguments (got #{node.children.count - 2})" \
|
1522
|
+
unless node.children.count == 4
|
1523
|
+
|
1524
|
+
module_node, function_node = node.children[2..-1]
|
1525
|
+
raise "import module name must be a symbol (got #{module_node})" \
|
1526
|
+
unless module_node.type == :sym
|
1527
|
+
raise "import function name must be a symbol (got #{function_node})" \
|
1528
|
+
unless function_node.type == :sym
|
1529
|
+
@@import = true
|
1530
|
+
@@import_module_name = module_node.children.last
|
1531
|
+
@@import_function_name = function_node.children.last
|
1532
|
+
logger.debug "... #{@@import_module_name}, #{@@import_function_name}"
|
1426
1533
|
return
|
1427
1534
|
end
|
1428
1535
|
|
@@ -2145,6 +2252,11 @@ module Rlang::Parser
|
|
2145
2252
|
const_path
|
2146
2253
|
end
|
2147
2254
|
|
2255
|
+
def self._reset_toggles
|
2256
|
+
@@export, @@export_name = false, nil
|
2257
|
+
@@import, @@import_module_name, @@import_function_name = false, nil, nil
|
2258
|
+
end
|
2259
|
+
|
2148
2260
|
def dump
|
2149
2261
|
@ast
|
2150
2262
|
end
|