sweet-moon 0.0.1 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +7 -0
- data/README.md +156 -13
- data/components/interpreters/50/function.rb +8 -5
- data/components/interpreters/50/interpreter.rb +39 -23
- data/components/interpreters/50/reader.rb +11 -9
- data/components/interpreters/50/table.rb +20 -18
- data/components/interpreters/50/writer.rb +7 -7
- data/components/interpreters/51/function.rb +8 -5
- data/components/interpreters/51/interpreter.rb +30 -20
- data/components/interpreters/51/reader.rb +11 -9
- data/components/interpreters/51/table.rb +12 -11
- data/components/interpreters/51/writer.rb +7 -7
- data/components/interpreters/54/function.rb +8 -5
- data/components/interpreters/54/interpreter.rb +27 -17
- data/components/interpreters/54/reader.rb +11 -9
- data/components/interpreters/54/table.rb +11 -10
- data/components/interpreters/54/writer.rb +7 -7
- data/config/tests.sample.yml +50 -7
- data/controllers/state.rb +34 -9
- data/dsl/concerns/packages.rb +1 -1
- data/dsl/fennel.rb +3 -0
- data/dsl/state.rb +4 -2
- data/logic/interpreters/interpreter_50.rb +1 -0
- data/logic/interpreters/interpreter_54.rb +5 -5
- data/logic/spec.rb +6 -3
- metadata +9 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bdfabe100158948ea2c29fadca09e82cd9567d71230627f6bd0e8ba3a04f523d
|
4
|
+
data.tar.gz: 3bb2925b0ef437c3942a837a67bb94261d89c9aaf5a011973dcf4b98db07e6b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 582a792771b05e59a577349070709e78bb2a569ef14cdb955fb2666e826eb401ba4aa4e7b19297c30fd64f98eda244d656caf2e904f9c1af95e971807aed8820
|
7
|
+
data.tar.gz: 38307987e564f998b40b2792fd97a3e107095d6e46992689663d63d67bf248dfc16c3a8838f8461bf7a8765857e7b5c04da4e4ac3c636cd6a419abb85bab2e5b
|
data/LICENSE
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright 2022 Guilherme Baptista
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# Sweet Moon
|
2
|
+
[![Gem Version](https://badge.fury.io/rb/sweet-moon.svg)](https://badge.fury.io/rb/sweet-moon)
|
2
3
|
|
3
4
|
_Sweet Moon_ is a resilient solution that makes working with [Lua](https://www.lua.org) / [Fennel](https://fennel-lang.org) from [Ruby](https://www.ruby-lang.org) and vice versa a delightful experience.
|
4
5
|
|
@@ -20,12 +21,15 @@ _Sweet Moon_ is a resilient solution that makes working with [Lua](https://www.l
|
|
20
21
|
- [Tables, Arrays, and Hashes](#tables-arrays-and-hashes)
|
21
22
|
- [Functions](#functions)
|
22
23
|
- [Other Types](#other-types)
|
24
|
+
- [Lua Global vs Local Variables](#lua-global-vs-local-variables)
|
23
25
|
- [_destroy_ and _clear_](#destroy-and-clear)
|
24
26
|
- [Modules, Packages and LuaRocks](#modules-packages-and-luarocks)
|
25
27
|
- [Integration with LuaRocks](#integration-with-luarocks)
|
26
28
|
- [Fennel](#fennel)
|
27
29
|
- [Fennel Usage](#fennel-usage)
|
30
|
+
- [Fennel Global vs Local Variables](#fennel-global-vs-local-variables)
|
28
31
|
- [Fennel Setup](#fennel-setup)
|
32
|
+
- [Integration with fnx](#integration-with-fnx)
|
29
33
|
- [Global vs Isolated](#global-vs-isolated)
|
30
34
|
- [Error Handling](#error-handling)
|
31
35
|
- [Where can I find .so files?](#where-can-i-find-so-files)
|
@@ -38,6 +42,9 @@ _Sweet Moon_ is a resilient solution that makes working with [Lua](https://www.l
|
|
38
42
|
- [Lua 5.4](#lua-54)
|
39
43
|
- [Lua 4.0](#lua-40)
|
40
44
|
- [Development](#development)
|
45
|
+
- [Tests Setup](#tests-setup)
|
46
|
+
- [Running](#running)
|
47
|
+
- [Supporting New Versions](#supporting-new-versions)
|
41
48
|
|
42
49
|
## Supported Versions
|
43
50
|
|
@@ -64,7 +71,7 @@ gem install sweet-moon
|
|
64
71
|
> **Disclaimer:** It's an early-stage project, and you should expect breaking changes.
|
65
72
|
|
66
73
|
```ruby
|
67
|
-
gem 'sweet-moon', '~> 0.0.
|
74
|
+
gem 'sweet-moon', '~> 0.0.4'
|
68
75
|
```
|
69
76
|
|
70
77
|
```ruby
|
@@ -204,6 +211,7 @@ Compared to: [rufus-lua](https://github.com/jmettraux/rufus-lua), [YAML](https:/
|
|
204
211
|
- [Tables, Arrays, and Hashes](#tables-arrays-and-hashes)
|
205
212
|
- [Functions](#functions)
|
206
213
|
- [Other Types](#other-types)
|
214
|
+
- [Lua Global vs Local Variables](#lua-global-vs-local-variables)
|
207
215
|
- [_destroy_ and _clear_](#destroy-and-clear)
|
208
216
|
|
209
217
|
### Setup
|
@@ -384,6 +392,20 @@ state.eval('lua_value = {a = "text", b = 1.5, c = true}') # => nil
|
|
384
392
|
state.get(:lua_value, :b) # => 1.5
|
385
393
|
```
|
386
394
|
|
395
|
+
With `set`, you can use a second parameter to set a field:
|
396
|
+
|
397
|
+
```ruby
|
398
|
+
require 'sweet-moon'
|
399
|
+
|
400
|
+
state = SweetMoon::State.new
|
401
|
+
|
402
|
+
state.set(:myTable, {}) # => nil
|
403
|
+
|
404
|
+
state.set(:myTable, :a, 3) # => nil
|
405
|
+
|
406
|
+
state.eval('return myTable["a"]') # => 3
|
407
|
+
```
|
408
|
+
|
387
409
|
Caveats:
|
388
410
|
|
389
411
|
- Ruby `Symbol` (e.g. `:value`) is converted to Lua `string`.
|
@@ -507,6 +529,24 @@ fennel_eval = state.get(:fennel_eval)
|
|
507
529
|
fennel_eval.(['(+ 1 1)']) # => 2
|
508
530
|
```
|
509
531
|
|
532
|
+
#### Lua Global vs Local Variables
|
533
|
+
|
534
|
+
You can't exchange _local_ variables, only [_global_](https://www.lua.org/pil/1.2.html) ones:
|
535
|
+
|
536
|
+
```ruby
|
537
|
+
require 'sweet-moon'
|
538
|
+
|
539
|
+
state = SweetMoon::State.new
|
540
|
+
|
541
|
+
state.eval('lua_value = "Lua Text"') # => nil
|
542
|
+
|
543
|
+
state.get('lua_value') # => 'Lua Text'
|
544
|
+
|
545
|
+
state.eval('local lua_b = "b"') # => nil
|
546
|
+
|
547
|
+
state.get('lua_b') # => nil
|
548
|
+
```
|
549
|
+
|
510
550
|
## _destroy_ and _clear_
|
511
551
|
|
512
552
|
You can destroy a state:
|
@@ -552,8 +592,8 @@ require 'sweet-moon'
|
|
552
592
|
|
553
593
|
state = SweetMoon::State.new
|
554
594
|
|
555
|
-
state.eval('package.path =
|
556
|
-
state.eval('package.cpath =
|
595
|
+
state.eval('package.path = "/my-modules/?.lua;" .. package.path')
|
596
|
+
state.eval('package.cpath = "/my-modules/?.so;" .. package.cpath')
|
557
597
|
|
558
598
|
state.eval('some_package = require("my_module")')
|
559
599
|
```
|
@@ -682,7 +722,7 @@ For global:
|
|
682
722
|
```ruby
|
683
723
|
require 'sweet-moon'
|
684
724
|
|
685
|
-
SweetMoon.global.config
|
725
|
+
SweetMoon.global.config(
|
686
726
|
package_path: [
|
687
727
|
'/home/me/.luarocks/share/lua/5.4/?.lua',
|
688
728
|
'/home/me/.luarocks/share/lua/5.4/?/init.lua'
|
@@ -709,8 +749,8 @@ state = SweetMoon::State.new
|
|
709
749
|
|
710
750
|
state.fennel.eval('(+ 1 2)') # => 3
|
711
751
|
|
712
|
-
state.fennel.eval('(
|
713
|
-
state.fennel.eval('(mySum 2 3)') # => 5
|
752
|
+
state.fennel.eval('(set _G.mySum (fn [a b] (+ a b)))')
|
753
|
+
state.fennel.eval('(_G.mySum 2 3)') # => 5
|
714
754
|
|
715
755
|
mySum = state.fennel.get(:mySum)
|
716
756
|
|
@@ -720,7 +760,7 @@ sum_list = -> (list) { list.sum }
|
|
720
760
|
|
721
761
|
state.set('sumList', sum_list) # => nil
|
722
762
|
|
723
|
-
state.fennel.eval('(sumList [2 3 5])') # => 10
|
763
|
+
state.fennel.eval('(_G.sumList [2 3 5])') # => 10
|
724
764
|
|
725
765
|
state.fennel.load('file.fnl')
|
726
766
|
```
|
@@ -735,6 +775,49 @@ state = SweetMoon::State.new.fennel
|
|
735
775
|
state.eval('(+ 1 2)') # => 3
|
736
776
|
```
|
737
777
|
|
778
|
+
### Fennel Global vs Local Variables
|
779
|
+
|
780
|
+
Fennel encourages you to explicitly use the [_`_G`_](https://www.lua.org/manual/5.4/manual.html#pdf-_G) table to access global variables:
|
781
|
+
|
782
|
+
```ruby
|
783
|
+
require 'sweet-moon'
|
784
|
+
|
785
|
+
fennel = SweetMoon::State.new.fennel
|
786
|
+
|
787
|
+
fennel.eval('(set _G.a? 2)')
|
788
|
+
|
789
|
+
fennel.get('a?') # => 2
|
790
|
+
fennel.get('_G', 'a?') # => 2
|
791
|
+
|
792
|
+
fennel.set('b', 3)
|
793
|
+
|
794
|
+
fennel.eval('(print _G.b)') # => 3
|
795
|
+
```
|
796
|
+
|
797
|
+
Although older versions have the expression `(global name "value")`, it's deprecated, and you should avoid using that. _Sweet Moon_ has no commitments in supporting this deprecated expression, and you should prefer the `_G` way.
|
798
|
+
|
799
|
+
As is [true for Lua](#lua-global-vs-local-variables), you can't exchange _local_ variables, only [_global_](https://www.lua.org/pil/1.2.html) ones:
|
800
|
+
|
801
|
+
```ruby
|
802
|
+
require 'sweet-moon'
|
803
|
+
|
804
|
+
fennel = SweetMoon::State.new.fennel
|
805
|
+
|
806
|
+
fennel.eval('(local name "value")')
|
807
|
+
|
808
|
+
fennel.get('name') # => nil
|
809
|
+
|
810
|
+
fennel.eval('(set _G.name "value")')
|
811
|
+
|
812
|
+
fennel.get('name') # => "value"
|
813
|
+
|
814
|
+
fennel.set('var-b', 35) # => nil
|
815
|
+
|
816
|
+
fennel.eval('var-b') # => nil
|
817
|
+
|
818
|
+
fennel.eval('_G.var-b') # => 35
|
819
|
+
```
|
820
|
+
|
738
821
|
### Fennel Setup
|
739
822
|
|
740
823
|
To ensure that the Fennel module is available, you can set up the [_LuaRocks_](#integration-withluarocks) integration or manually add the `package_path` for the module.
|
@@ -783,6 +866,28 @@ SweetMoon.global.config(package_path: '/folder/fennel.lua')
|
|
783
866
|
SweetMoon.global.state.fennel.eval('(+ 1 1)') # => 2
|
784
867
|
```
|
785
868
|
|
869
|
+
### Integration with fnx
|
870
|
+
|
871
|
+
[fnx](https://github.com/gbaptista/fnx) is a package manager for the Fennel language.
|
872
|
+
|
873
|
+
After installing `fnx` and configuring it for [_Embedding_](https://github.com/gbaptista/fnx#embedding), you can:
|
874
|
+
|
875
|
+
```ruby
|
876
|
+
require 'sweet-moon'
|
877
|
+
|
878
|
+
fennel = SweetMoon::State.new.fennel
|
879
|
+
|
880
|
+
fennel.eval('(let [fnx (require :fnx)] (fnx.bootstrap!))')
|
881
|
+
```
|
882
|
+
|
883
|
+
Done. It will automatically inject all your dependencies according to your `.fnx.fnl` file, similar to using the `fnx` command.
|
884
|
+
|
885
|
+
To enforce the path for the `.fnx.fnl` file:
|
886
|
+
|
887
|
+
```ruby
|
888
|
+
fennel.eval('(let [fnx (require :fnx)] (fnx.bootstrap! "/project/.fnx.fnl"))')
|
889
|
+
```
|
890
|
+
|
786
891
|
## Global vs Isolated
|
787
892
|
|
788
893
|
You can use the **global** helper that provides an _API_ and a _State_ for quick-and-dirty coding. It uses internally a Ruby [_Singleton_](https://docs.ruby-lang.org/en/3.1/Singleton.html):
|
@@ -821,8 +926,8 @@ You may want to use an isolated API for scenarios like interacting with two Lua
|
|
821
926
|
```ruby
|
822
927
|
require 'sweet-moon'
|
823
928
|
|
824
|
-
api_5 = SweetMoon.
|
825
|
-
api_3 = SweetMoon.
|
929
|
+
api_5 = SweetMoon::API.new(shared_object: '/usr/lib/liblua5.s')
|
930
|
+
api_3 = SweetMoon::API.new(shared_object: '/usr/lib/liblua3.so')
|
826
931
|
|
827
932
|
api_5.luaL_newstate
|
828
933
|
|
@@ -882,7 +987,7 @@ require 'sweet-moon'
|
|
882
987
|
|
883
988
|
begin
|
884
989
|
SweetMoon.global.state.eval('return 1 + true')
|
885
|
-
rescue SweetMoon::Errors::
|
990
|
+
rescue SweetMoon::Errors::LuaRuntimeError => error
|
886
991
|
puts error.message
|
887
992
|
# => [string "return 1 + true"]:1: attempt to perform arithmetic on a boolean value
|
888
993
|
end
|
@@ -896,7 +1001,7 @@ require 'sweet-moon/errors'
|
|
896
1001
|
|
897
1002
|
begin
|
898
1003
|
SweetMoon.global.state.eval('return 1 + true')
|
899
|
-
rescue
|
1004
|
+
rescue LuaRuntimeError => error
|
900
1005
|
puts error.message
|
901
1006
|
# => [string "return 1 + true"]:1: attempt to perform arithmetic on a boolean value
|
902
1007
|
end
|
@@ -904,9 +1009,9 @@ end
|
|
904
1009
|
|
905
1010
|
## Where can I find .so files?
|
906
1011
|
|
907
|
-
Due to the Lua's popularity, you likely have it already on your system, and _Sweet Moon_ will be able to find the files
|
1012
|
+
Due to the Lua's popularity, you likely have it already on your system, and _Sweet Moon_ will be able to find the files by itself.
|
908
1013
|
|
909
|
-
Either way, you can download it from
|
1014
|
+
Either way, you can download it from:
|
910
1015
|
- [Lua Binaries](http://luabinaries.sourceforge.net)
|
911
1016
|
- [LuaJIT releases](http://luajit.org/download.html)
|
912
1017
|
|
@@ -1138,6 +1243,26 @@ rubocop -a
|
|
1138
1243
|
rspec
|
1139
1244
|
```
|
1140
1245
|
|
1246
|
+
### Tests Setup
|
1247
|
+
|
1248
|
+
To setup tests:
|
1249
|
+
|
1250
|
+
```
|
1251
|
+
cp config/tests.sample.yml config/tests.yml
|
1252
|
+
```
|
1253
|
+
|
1254
|
+
Clone the [sweet-moon-test](https://github.com/gbaptista/sweet-moon-test) repo somewhere:
|
1255
|
+
|
1256
|
+
```sh
|
1257
|
+
git clone git@github.com:gbaptista/sweet-moon-test.git
|
1258
|
+
```
|
1259
|
+
|
1260
|
+
Update the [`config/tests.yml`](https://github.com/gbaptista/sweet-moon/blob/main/config/tests.sample.yml) accordingly.
|
1261
|
+
|
1262
|
+
Alternatively: Find or build the _Shared Objects_ for your Operating System on your own.
|
1263
|
+
|
1264
|
+
### Running
|
1265
|
+
|
1141
1266
|
```sh
|
1142
1267
|
./ports/in/shell/sweet-moon version
|
1143
1268
|
|
@@ -1147,3 +1272,21 @@ bundle exec sweet-moon signatures /lua/lib/542 542.rb
|
|
1147
1272
|
|
1148
1273
|
bundle exec ruby some/file.rb
|
1149
1274
|
```
|
1275
|
+
|
1276
|
+
### Supporting New Versions
|
1277
|
+
|
1278
|
+
Download both the source code and the libraries.
|
1279
|
+
|
1280
|
+
Example: For [Lua 5.4.2](https://sourceforge.net/projects/luabinaries/files/5.4.2/), you would download _"Linux Libraries"_ and _"Docs and Sources."_
|
1281
|
+
|
1282
|
+
Extract everything to a folder, e.g., `lua-542-source-libs`.
|
1283
|
+
|
1284
|
+
Run the command to extract the signatures:
|
1285
|
+
|
1286
|
+
```shell
|
1287
|
+
bundle exec sweet-moon signatures /home/me/lua-542-source-libs 542.rb
|
1288
|
+
```
|
1289
|
+
|
1290
|
+
Check the `542.rb` file for the output and then start coding.
|
1291
|
+
|
1292
|
+
You can use the [`logic/signatures`](https://github.com/gbaptista/sweet-moon/tree/main/logic/signatures) folder as a reference starting point.
|
@@ -9,23 +9,26 @@ module Component
|
|
9
9
|
Function = {
|
10
10
|
push!: ->(api, state, closure) {
|
11
11
|
handler = ->(current_state) {
|
12
|
-
|
12
|
+
updated_state = state.merge(lua: current_state)
|
13
|
+
input = Reader[:read_all!].(api, updated_state)
|
13
14
|
result = closure.(*input)
|
14
|
-
Writer[:push!].(api,
|
15
|
+
Writer[:push!].(api, updated_state, result)
|
15
16
|
return 1
|
16
17
|
}
|
17
18
|
|
18
|
-
|
19
|
+
state[:avoid_gc] << handler
|
20
|
+
|
21
|
+
api.lua_pushcclosure(state[:lua], handler, 0)
|
19
22
|
},
|
20
23
|
|
21
24
|
read!: ->(api, state, _stack_index) {
|
22
25
|
reference = api.luaL_ref(
|
23
|
-
state, Logic::V50::Interpreter[:LUA_REGISTRYINDEX]
|
26
|
+
state[:lua], Logic::V50::Interpreter[:LUA_REGISTRYINDEX]
|
24
27
|
)
|
25
28
|
|
26
29
|
{ value: ->(input = [], output = 1) {
|
27
30
|
api.lua_rawgeti(
|
28
|
-
state, Logic::V50::Interpreter[:LUA_REGISTRYINDEX], reference
|
31
|
+
state[:lua], Logic::V50::Interpreter[:LUA_REGISTRYINDEX], reference
|
29
32
|
)
|
30
33
|
|
31
34
|
input.each do |value|
|
@@ -11,34 +11,40 @@ module Component
|
|
11
11
|
|
12
12
|
create_state!: ->(api) {
|
13
13
|
state = api.lua_open
|
14
|
-
{ state:
|
14
|
+
{ state: { lua: state, avoid_gc: [] },
|
15
|
+
error: state ? nil : :MemoryAllocation }
|
15
16
|
},
|
16
17
|
|
17
18
|
open_standard_libraries!: ->(api, state) {
|
18
|
-
api.luaopen_base(state)
|
19
|
-
api.luaopen_table(state)
|
20
|
-
api.luaopen_io(state)
|
21
|
-
api.luaopen_string(state)
|
22
|
-
api.luaopen_math(state)
|
19
|
+
api.luaopen_base(state[:lua])
|
20
|
+
api.luaopen_table(state[:lua])
|
21
|
+
api.luaopen_io(state[:lua])
|
22
|
+
api.luaopen_string(state[:lua])
|
23
|
+
api.luaopen_math(state[:lua])
|
23
24
|
|
24
|
-
api.lua_settop(state, -7 - 1)
|
25
|
+
api.lua_settop(state[:lua], -7 - 1)
|
25
26
|
|
26
27
|
{ state: state }
|
27
28
|
},
|
28
29
|
|
29
30
|
load_file_and_push_chunck!: ->(api, state, path) {
|
30
|
-
result = api.luaL_loadfile(state, path)
|
31
|
+
result = api.luaL_loadfile(state[:lua], path)
|
31
32
|
{ state: state, error: Interpreter[:_error].(api, state, result, pull: true) }
|
32
33
|
},
|
33
34
|
|
34
35
|
push_chunk!: ->(api, state, value) {
|
35
|
-
result = api.luaL_loadbuffer(state, value, value.size, value)
|
36
|
+
result = api.luaL_loadbuffer(state[:lua], value, value.size, value)
|
36
37
|
|
37
38
|
{ state: state, error: Interpreter[:_error].(api, state, result, pull: true) }
|
38
39
|
},
|
39
40
|
|
40
|
-
set_table!: ->(api, state
|
41
|
-
|
41
|
+
set_table!: ->(api, state) {
|
42
|
+
result = api.lua_settable(state[:lua], -3)
|
43
|
+
|
44
|
+
api.lua_settop(state[:lua], -2)
|
45
|
+
|
46
|
+
{ state: state,
|
47
|
+
error: Interpreter[:_error].(api, state, result, pull: false) }
|
42
48
|
},
|
43
49
|
|
44
50
|
push_value!: ->(api, state, value) {
|
@@ -47,31 +53,38 @@ module Component
|
|
47
53
|
},
|
48
54
|
|
49
55
|
pop_and_set_as!: ->(api, state, variable) {
|
50
|
-
api.lua_pushstring(state, variable)
|
51
|
-
api.lua_insert(state, -2)
|
52
|
-
api.lua_settable(state, Logic::V50::Interpreter[:LUA_GLOBALSINDEX])
|
56
|
+
api.lua_pushstring(state[:lua], variable)
|
57
|
+
api.lua_insert(state[:lua], -2)
|
58
|
+
api.lua_settable(state[:lua], Logic::V50::Interpreter[:LUA_GLOBALSINDEX])
|
53
59
|
{ state: state }
|
54
60
|
},
|
55
61
|
|
56
62
|
get_variable_and_push!: ->(api, state, variable, key = nil) {
|
57
|
-
|
58
|
-
|
63
|
+
extra_pop = true
|
64
|
+
if variable == '_G'
|
65
|
+
variable = key
|
66
|
+
key = nil
|
67
|
+
extra_pop = false
|
68
|
+
end
|
69
|
+
|
70
|
+
api.lua_pushstring(state[:lua], variable.to_s)
|
71
|
+
api.lua_gettable(state[:lua], Logic::V50::Interpreter[:LUA_GLOBALSINDEX])
|
59
72
|
|
60
73
|
Table[:read_field_and_push!].(api, state, key, -1) unless key.nil?
|
61
74
|
|
62
|
-
{ state: state }
|
75
|
+
{ state: state, extra_pop: extra_pop }
|
63
76
|
},
|
64
77
|
|
65
78
|
call!: ->(api, state, inputs = 0, outputs = 1) {
|
66
|
-
result = api.lua_pcall(state, inputs, outputs, 0)
|
79
|
+
result = api.lua_pcall(state[:lua], inputs, outputs, 0)
|
67
80
|
{ state: state, error: Interpreter[:_error].(api, state, result, pull: true) }
|
68
81
|
},
|
69
82
|
|
70
83
|
read_and_pop!: ->(api, state, stack_index = -1, extra_pop: false) {
|
71
84
|
result = Component::V50::Reader[:read!].(api, state, stack_index)
|
72
85
|
|
73
|
-
api.lua_settop(state, -2) if result[:pop]
|
74
|
-
api.lua_settop(state, -2) if extra_pop
|
86
|
+
api.lua_settop(state[:lua], -2) if result[:pop]
|
87
|
+
api.lua_settop(state[:lua], -2) if extra_pop
|
75
88
|
|
76
89
|
{ state: state, output: result[:value] }
|
77
90
|
},
|
@@ -83,9 +96,12 @@ module Component
|
|
83
96
|
},
|
84
97
|
|
85
98
|
destroy_state!: ->(api, state) {
|
86
|
-
result = api.lua_close(state)
|
99
|
+
result = api.lua_close(state[:lua])
|
100
|
+
|
101
|
+
state.delete(:lua)
|
102
|
+
state.delete(:avoid_gc)
|
87
103
|
|
88
|
-
{ state: nil, error: Interpreter[:_error].(api,
|
104
|
+
{ state: nil, error: Interpreter[:_error].(api, nil, result) }
|
89
105
|
},
|
90
106
|
|
91
107
|
_error: ->(api, state, code, options = {}) {
|
@@ -94,7 +110,7 @@ module Component
|
|
94
110
|
] || :error
|
95
111
|
|
96
112
|
if code.is_a?(Numeric) && code >= 1
|
97
|
-
return { status: status } unless options[:pull]
|
113
|
+
return { status: status } unless options[:pull] && state
|
98
114
|
|
99
115
|
{ status: status,
|
100
116
|
value: Interpreter[:read_and_pop!].(api, state, -1)[:output] }
|
@@ -8,15 +8,16 @@ module Component
|
|
8
8
|
module V50
|
9
9
|
Reader = {
|
10
10
|
read_all!: ->(api, state) {
|
11
|
-
(1..api.lua_gettop(state)).map do
|
11
|
+
(1..api.lua_gettop(state[:lua])).map do
|
12
12
|
Interpreter[:read_and_pop!].(api, state)[:output]
|
13
13
|
end.reverse
|
14
14
|
},
|
15
15
|
|
16
16
|
read!: ->(api, state, stack_index = -1) {
|
17
|
-
stack_index = api.lua_gettop(state) if stack_index == -1
|
17
|
+
stack_index = api.lua_gettop(state[:lua]) if stack_index == -1
|
18
18
|
|
19
|
-
type = api.lua_typename(state,
|
19
|
+
type = api.lua_typename(state[:lua],
|
20
|
+
api.lua_type(state[:lua], stack_index)).read_string
|
20
21
|
|
21
22
|
case type
|
22
23
|
when 'string'
|
@@ -36,29 +37,30 @@ module Component
|
|
36
37
|
else
|
37
38
|
# none nil boolean lightuserdata number
|
38
39
|
# string table function userdata thread
|
39
|
-
{ value:
|
40
|
+
{ value:
|
41
|
+
"#{type}: 0x#{api.lua_topointer(state[:lua], stack_index).address}",
|
40
42
|
type: type, pop: true }
|
41
43
|
end
|
42
44
|
},
|
43
45
|
|
44
46
|
read_string!: ->(api, state, stack_index) {
|
45
|
-
{ value: api.lua_tostring(state, stack_index).read_string,
|
47
|
+
{ value: api.lua_tostring(state[:lua], stack_index).read_string,
|
46
48
|
pop: true }
|
47
49
|
},
|
48
50
|
|
49
51
|
read_number!: ->(api, state, stack_index) {
|
50
52
|
if api.respond_to?(:lua_isinteger) &&
|
51
53
|
api.respond_to?(:lua_tointeger) &&
|
52
|
-
api.lua_isinteger(state, stack_index) == 1
|
54
|
+
api.lua_isinteger(state[:lua], stack_index) == 1
|
53
55
|
|
54
|
-
return { value: api.lua_tointeger(state, stack_index), pop: true }
|
56
|
+
return { value: api.lua_tointeger(state[:lua], stack_index), pop: true }
|
55
57
|
end
|
56
58
|
|
57
|
-
{ value: api.lua_tonumber(state, stack_index), pop: true }
|
59
|
+
{ value: api.lua_tonumber(state[:lua], stack_index), pop: true }
|
58
60
|
},
|
59
61
|
|
60
62
|
read_boolean!: ->(api, state, stack_index) {
|
61
|
-
{ value: api.lua_toboolean(state, stack_index) == 1, pop: true }
|
63
|
+
{ value: api.lua_toboolean(state[:lua], stack_index) == 1, pop: true }
|
62
64
|
}
|
63
65
|
}
|
64
66
|
end
|
@@ -7,68 +7,70 @@ module Component
|
|
7
7
|
module V50
|
8
8
|
Table = {
|
9
9
|
push!: ->(api, state, list, stack_index = -1) {
|
10
|
-
stack_index = api.lua_gettop(state) if stack_index == -1
|
10
|
+
stack_index = api.lua_gettop(state[:lua]) if stack_index == -1
|
11
11
|
|
12
|
-
api.lua_newtable(state)
|
12
|
+
api.lua_newtable(state[:lua])
|
13
13
|
|
14
14
|
if list.is_a? Hash
|
15
15
|
list.each_key do |key|
|
16
16
|
Writer[:push!].(api, state, key)
|
17
17
|
Writer[:push!].(api, state, list[key])
|
18
|
-
api.lua_settable(state, stack_index + 1)
|
18
|
+
api.lua_settable(state[:lua], stack_index + 1)
|
19
19
|
end
|
20
20
|
else
|
21
21
|
list.each_with_index do |value, index|
|
22
22
|
Writer[:push!].(api, state, index + 1)
|
23
23
|
Writer[:push!].(api, state, value)
|
24
|
-
api.lua_settable(state, stack_index + 1)
|
24
|
+
api.lua_settable(state[:lua], stack_index + 1)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
},
|
28
28
|
|
29
29
|
read!: ->(api, state, stack_index) {
|
30
|
-
stack_index = api.lua_gettop(state) if stack_index == -1
|
30
|
+
stack_index = api.lua_gettop(state[:lua]) if stack_index == -1
|
31
31
|
|
32
|
-
type = api.lua_typename(state,
|
32
|
+
type = api.lua_typename(state[:lua],
|
33
|
+
api.lua_type(state[:lua], stack_index)).read_string
|
33
34
|
|
34
|
-
api.lua_pushnil(state)
|
35
|
+
api.lua_pushnil(state[:lua])
|
35
36
|
|
36
37
|
return nil if type != 'table'
|
37
38
|
|
38
39
|
tuples = []
|
39
40
|
|
40
|
-
while api.lua_next(state, stack_index).positive?
|
41
|
+
while api.lua_next(state[:lua], stack_index).positive?
|
41
42
|
value = Reader[:read!].(api, state, stack_index + 2)
|
42
43
|
key = Reader[:read!].(api, state, stack_index + 1)
|
43
|
-
api.lua_settop(state, -2) if value[:pop]
|
44
|
+
api.lua_settop(state[:lua], -2) if value[:pop]
|
44
45
|
|
45
46
|
tuples << [key[:value], value[:value]]
|
46
47
|
|
47
|
-
break if value[:type] == 'no value'
|
48
|
+
break if value[:type] == 'no value' || key[:value].instance_of?(Proc)
|
48
49
|
end
|
49
50
|
|
50
51
|
{ value: Logic::Tables[:to_hash_or_array].(tuples), pop: true }
|
51
52
|
},
|
52
53
|
|
53
54
|
read_field_and_push!: ->(api, state, expected_key, stack_index) {
|
54
|
-
stack_index = api.lua_gettop(state) if stack_index == -1
|
55
|
+
stack_index = api.lua_gettop(state[:lua]) if stack_index == -1
|
55
56
|
|
56
|
-
type = api.lua_typename(state,
|
57
|
+
type = api.lua_typename(state[:lua],
|
58
|
+
api.lua_type(state[:lua], stack_index)).read_string
|
57
59
|
|
58
|
-
api.lua_pushnil(state)
|
60
|
+
api.lua_pushnil(state[:lua])
|
59
61
|
|
60
62
|
return nil if type != 'table'
|
61
63
|
|
62
64
|
result = nil
|
63
65
|
|
64
|
-
while api.lua_next(state, stack_index).positive?
|
66
|
+
while api.lua_next(state[:lua], stack_index).positive?
|
65
67
|
value = Reader[:read!].(api, state, stack_index + 2)
|
66
68
|
key = Reader[:read!].(api, state, stack_index + 1)
|
67
69
|
|
68
|
-
api.lua_settop(state, -2) if value[:pop]
|
70
|
+
api.lua_settop(state[:lua], -2) if value[:pop]
|
69
71
|
|
70
72
|
key_type = api.lua_typename(
|
71
|
-
state, api.lua_type(state, stack_index + 1)
|
73
|
+
state[:lua], api.lua_type(state[:lua], stack_index + 1)
|
72
74
|
).read_string
|
73
75
|
|
74
76
|
if Table[:is_same_key].(key_type, key[:value], expected_key)
|
@@ -76,10 +78,10 @@ module Component
|
|
76
78
|
break
|
77
79
|
end
|
78
80
|
|
79
|
-
break if value[:type] == 'no value'
|
81
|
+
break if value[:type] == 'no value' || key[:value].instance_of?(Proc)
|
80
82
|
end
|
81
83
|
|
82
|
-
api.lua_settop(state, -2)
|
84
|
+
api.lua_settop(state[:lua], -2)
|
83
85
|
|
84
86
|
Writer[:push!].(api, state, result)
|
85
87
|
},
|
@@ -7,26 +7,26 @@ module Component
|
|
7
7
|
push!: ->(api, state, value) {
|
8
8
|
case Writer[:_to_lua_type].(value)
|
9
9
|
when 'string'
|
10
|
-
api.lua_pushstring(state, value.to_s)
|
10
|
+
api.lua_pushstring(state[:lua], value.to_s)
|
11
11
|
when 'number'
|
12
|
-
api.lua_pushnumber(state, value)
|
12
|
+
api.lua_pushnumber(state[:lua], value)
|
13
13
|
when 'integer'
|
14
14
|
if api.respond_to? :lua_pushinteger
|
15
|
-
api.lua_pushinteger(state, value)
|
15
|
+
api.lua_pushinteger(state[:lua], value)
|
16
16
|
else
|
17
|
-
api.lua_pushnumber(state, value)
|
17
|
+
api.lua_pushnumber(state[:lua], value)
|
18
18
|
end
|
19
19
|
when 'nil'
|
20
|
-
api.lua_pushnil(state)
|
20
|
+
api.lua_pushnil(state[:lua])
|
21
21
|
when 'boolean'
|
22
|
-
api.lua_pushboolean(state, value ? 1 : 0)
|
22
|
+
api.lua_pushboolean(state[:lua], value ? 1 : 0)
|
23
23
|
when 'table'
|
24
24
|
Table[:push!].(api, state, value)
|
25
25
|
when 'function'
|
26
26
|
Function[:push!].(api, state, value)
|
27
27
|
else
|
28
28
|
api.lua_pushstring(
|
29
|
-
state, "#<#{value.class}:0x#{format('%016x', value.object_id)}>"
|
29
|
+
state[:lua], "#<#{value.class}:0x#{format('%016x', value.object_id)}>"
|
30
30
|
)
|
31
31
|
end
|
32
32
|
},
|