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