sweet-moon 0.0.3 → 0.0.6
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/.rubocop.yml +3 -0
- data/README.md +283 -16
- data/components/api.rb +6 -3
- data/components/default.rb +17 -0
- data/components/injections/injections_503.rb +2 -1
- data/components/injections/injections_514.rb +2 -1
- data/components/injections/injections_542.rb +2 -1
- data/components/interpreters/50/function.rb +14 -50
- data/components/interpreters/50/interpreter.rb +27 -9
- data/components/interpreters/50/reader.rb +2 -62
- data/components/interpreters/50/table.rb +12 -49
- data/components/interpreters/50/writer.rb +2 -40
- data/components/interpreters/51/function.rb +3 -49
- data/components/interpreters/51/interpreter.rb +16 -10
- data/components/interpreters/51/reader.rb +2 -62
- data/components/interpreters/51/table.rb +2 -56
- data/components/interpreters/51/writer.rb +2 -40
- data/components/interpreters/54/function.rb +80 -24
- data/components/interpreters/54/interpreter.rb +17 -9
- data/components/interpreters/54/reader.rb +11 -10
- data/components/interpreters/54/table.rb +17 -12
- data/components/interpreters/54/writer.rb +4 -4
- data/config/tests.sample.yml +10 -7
- data/controllers/api.rb +4 -1
- data/controllers/state.rb +47 -12
- data/dsl/api.rb +23 -3
- data/dsl/cache.rb +90 -76
- data/dsl/errors.rb +9 -1
- data/dsl/fennel.rb +2 -0
- data/dsl/global.rb +26 -27
- data/dsl/state.rb +26 -7
- data/dsl/sweet_moon.rb +4 -4
- data/logic/interpreters/interpreter_50.rb +1 -0
- data/logic/interpreters/interpreter_54.rb +5 -5
- data/logic/spec.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 46891cd3e8103176f3f909415432df155df1bd33cbed89a80f0042f5d303a2b7
|
4
|
+
data.tar.gz: af7617e43eacc588135285dbd652f644d9bda8b87735c86ff89a7719ce6bfe1a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1949e5f83c00dd65cdf78e2e8ebd4f66654dc24df1769add99ad8f01e75cc97bcb090e9d0dc0cf5d10dcdd4d1d338252b4ad78894bd3d4cef40b91ae31aab3d0
|
7
|
+
data.tar.gz: 9a09f1231c7e02250f232e368abd95b7bb1b4d5e366ef2614ce9871248c49201fb480b8b698833df66d769e7688602e8c3415a454366ef5ad3ede02163e1c5a4
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -21,15 +21,20 @@ _Sweet Moon_ is a resilient solution that makes working with [Lua](https://www.l
|
|
21
21
|
- [Tables, Arrays, and Hashes](#tables-arrays-and-hashes)
|
22
22
|
- [Functions](#functions)
|
23
23
|
- [Other Types](#other-types)
|
24
|
+
- [Lua Global vs Local Variables](#lua-global-vs-local-variables)
|
24
25
|
- [_destroy_ and _clear_](#destroy-and-clear)
|
25
26
|
- [Modules, Packages and LuaRocks](#modules-packages-and-luarocks)
|
26
27
|
- [Integration with LuaRocks](#integration-with-luarocks)
|
27
28
|
- [Fennel](#fennel)
|
28
29
|
- [Fennel Usage](#fennel-usage)
|
30
|
+
- [Fennel Global vs Local Variables](#fennel-global-vs-local-variables)
|
29
31
|
- [Fennel Setup](#fennel-setup)
|
30
32
|
- [Integration with fnx](#integration-with-fnx)
|
33
|
+
- [Fennel REPL](#fennel-repl)
|
31
34
|
- [Global vs Isolated](#global-vs-isolated)
|
35
|
+
- [Global FFI](#global-ffi)
|
32
36
|
- [Error Handling](#error-handling)
|
37
|
+
- [Ruby feat. Lua Errors](#ruby-feat-lua-errors)
|
33
38
|
- [Where can I find .so files?](#where-can-i-find-so-files)
|
34
39
|
- [Low-Level C API](#low-level-c-api)
|
35
40
|
- [The API](#the-api)
|
@@ -69,7 +74,7 @@ gem install sweet-moon
|
|
69
74
|
> **Disclaimer:** It's an early-stage project, and you should expect breaking changes.
|
70
75
|
|
71
76
|
```ruby
|
72
|
-
gem 'sweet-moon', '~> 0.0.
|
77
|
+
gem 'sweet-moon', '~> 0.0.6'
|
73
78
|
```
|
74
79
|
|
75
80
|
```ruby
|
@@ -209,6 +214,7 @@ Compared to: [rufus-lua](https://github.com/jmettraux/rufus-lua), [YAML](https:/
|
|
209
214
|
- [Tables, Arrays, and Hashes](#tables-arrays-and-hashes)
|
210
215
|
- [Functions](#functions)
|
211
216
|
- [Other Types](#other-types)
|
217
|
+
- [Lua Global vs Local Variables](#lua-global-vs-local-variables)
|
212
218
|
- [_destroy_ and _clear_](#destroy-and-clear)
|
213
219
|
|
214
220
|
### Setup
|
@@ -389,6 +395,20 @@ state.eval('lua_value = {a = "text", b = 1.5, c = true}') # => nil
|
|
389
395
|
state.get(:lua_value, :b) # => 1.5
|
390
396
|
```
|
391
397
|
|
398
|
+
With `set`, you can use a second parameter to set a field:
|
399
|
+
|
400
|
+
```ruby
|
401
|
+
require 'sweet-moon'
|
402
|
+
|
403
|
+
state = SweetMoon::State.new
|
404
|
+
|
405
|
+
state.set(:myTable, {}) # => nil
|
406
|
+
|
407
|
+
state.set(:myTable, :a, 3) # => nil
|
408
|
+
|
409
|
+
state.eval('return myTable["a"]') # => 3
|
410
|
+
```
|
411
|
+
|
392
412
|
Caveats:
|
393
413
|
|
394
414
|
- Ruby `Symbol` (e.g. `:value`) is converted to Lua `string`.
|
@@ -512,6 +532,24 @@ fennel_eval = state.get(:fennel_eval)
|
|
512
532
|
fennel_eval.(['(+ 1 1)']) # => 2
|
513
533
|
```
|
514
534
|
|
535
|
+
#### Lua Global vs Local Variables
|
536
|
+
|
537
|
+
You can't exchange _local_ variables, only [_global_](https://www.lua.org/pil/1.2.html) ones:
|
538
|
+
|
539
|
+
```ruby
|
540
|
+
require 'sweet-moon'
|
541
|
+
|
542
|
+
state = SweetMoon::State.new
|
543
|
+
|
544
|
+
state.eval('lua_value = "Lua Text"') # => nil
|
545
|
+
|
546
|
+
state.get('lua_value') # => 'Lua Text'
|
547
|
+
|
548
|
+
state.eval('local lua_b = "b"') # => nil
|
549
|
+
|
550
|
+
state.get('lua_b') # => nil
|
551
|
+
```
|
552
|
+
|
515
553
|
## _destroy_ and _clear_
|
516
554
|
|
517
555
|
You can destroy a state:
|
@@ -577,21 +615,21 @@ state.add_package_path('/home/me/my-lua-modules/?/init.lua')
|
|
577
615
|
|
578
616
|
state.add_package_cpath('/home/me/my-lua-modules/?.so')
|
579
617
|
|
580
|
-
state.add_package_path('/home/me/fennel
|
618
|
+
state.add_package_path('/home/me/fennel/?.lua')
|
581
619
|
|
582
|
-
state.add_package_cpath('/home/me
|
620
|
+
state.add_package_cpath('/home/me/?.so')
|
583
621
|
|
584
622
|
state.package_path
|
585
623
|
# => ['./?.lua',
|
586
624
|
# './?/init.lua',
|
587
625
|
# '/home/me/my-lua-modules/?.lua',
|
588
626
|
# '/home/me/my-lua-modules/?/init.lua',
|
589
|
-
# '/home/me/fennel
|
627
|
+
# '/home/me/fennel/?.lua']
|
590
628
|
|
591
629
|
state.package_cpath
|
592
630
|
# => ['./?.so',
|
593
631
|
# '/home/me/my-lua-modules/?.so',
|
594
|
-
# '/home/me
|
632
|
+
# '/home/me/?.so']
|
595
633
|
```
|
596
634
|
|
597
635
|
Requiring a module:
|
@@ -611,8 +649,8 @@ You can set packages in State constructors:
|
|
611
649
|
require 'sweet-moon'
|
612
650
|
|
613
651
|
SweetMoon::State.new(
|
614
|
-
package_path: '/folder/lib
|
615
|
-
package_cpath: '/lib/lib
|
652
|
+
package_path: '/folder/lib/?.lua',
|
653
|
+
package_cpath: '/lib/lib/?.so',
|
616
654
|
)
|
617
655
|
```
|
618
656
|
|
@@ -622,8 +660,8 @@ Also, you can add packages through the global config:
|
|
622
660
|
require 'sweet-moon'
|
623
661
|
|
624
662
|
SweetMoon.global.config(
|
625
|
-
package_path: '/folder/lib
|
626
|
-
package_cpath: '/lib/lib
|
663
|
+
package_path: '/folder/lib/?.lua',
|
664
|
+
package_cpath: '/lib/lib/?.so',
|
627
665
|
)
|
628
666
|
```
|
629
667
|
|
@@ -714,8 +752,8 @@ state = SweetMoon::State.new
|
|
714
752
|
|
715
753
|
state.fennel.eval('(+ 1 2)') # => 3
|
716
754
|
|
717
|
-
state.fennel.eval('(
|
718
|
-
state.fennel.eval('(mySum 2 3)') # => 5
|
755
|
+
state.fennel.eval('(set _G.mySum (fn [a b] (+ a b)))')
|
756
|
+
state.fennel.eval('(_G.mySum 2 3)') # => 5
|
719
757
|
|
720
758
|
mySum = state.fennel.get(:mySum)
|
721
759
|
|
@@ -725,7 +763,7 @@ sum_list = -> (list) { list.sum }
|
|
725
763
|
|
726
764
|
state.set('sumList', sum_list) # => nil
|
727
765
|
|
728
|
-
state.fennel.eval('(sumList [2 3 5])') # => 10
|
766
|
+
state.fennel.eval('(_G.sumList [2 3 5])') # => 10
|
729
767
|
|
730
768
|
state.fennel.load('file.fnl')
|
731
769
|
```
|
@@ -740,6 +778,49 @@ state = SweetMoon::State.new.fennel
|
|
740
778
|
state.eval('(+ 1 2)') # => 3
|
741
779
|
```
|
742
780
|
|
781
|
+
### Fennel Global vs Local Variables
|
782
|
+
|
783
|
+
Fennel encourages you to explicitly use the [_`_G`_](https://www.lua.org/manual/5.4/manual.html#pdf-_G) table to access global variables:
|
784
|
+
|
785
|
+
```ruby
|
786
|
+
require 'sweet-moon'
|
787
|
+
|
788
|
+
fennel = SweetMoon::State.new.fennel
|
789
|
+
|
790
|
+
fennel.eval('(set _G.a? 2)')
|
791
|
+
|
792
|
+
fennel.get('a?') # => 2
|
793
|
+
fennel.get('_G', 'a?') # => 2
|
794
|
+
|
795
|
+
fennel.set('b', 3)
|
796
|
+
|
797
|
+
fennel.eval('(print _G.b)') # => 3
|
798
|
+
```
|
799
|
+
|
800
|
+
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.
|
801
|
+
|
802
|
+
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:
|
803
|
+
|
804
|
+
```ruby
|
805
|
+
require 'sweet-moon'
|
806
|
+
|
807
|
+
fennel = SweetMoon::State.new.fennel
|
808
|
+
|
809
|
+
fennel.eval('(local name "value")')
|
810
|
+
|
811
|
+
fennel.get('name') # => nil
|
812
|
+
|
813
|
+
fennel.eval('(set _G.name "value")')
|
814
|
+
|
815
|
+
fennel.get('name') # => "value"
|
816
|
+
|
817
|
+
fennel.set('var-b', 35) # => nil
|
818
|
+
|
819
|
+
fennel.eval('var-b') # => nil
|
820
|
+
|
821
|
+
fennel.eval('_G.var-b') # => 35
|
822
|
+
```
|
823
|
+
|
743
824
|
### Fennel Setup
|
744
825
|
|
745
826
|
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.
|
@@ -753,7 +834,7 @@ require 'sweet-moon'
|
|
753
834
|
|
754
835
|
state = SweetMoon::State.new
|
755
836
|
|
756
|
-
state.add_package_path('/folder/fennel
|
837
|
+
state.add_package_path('/folder/fennel/?.lua')
|
757
838
|
|
758
839
|
state.fennel.eval('(+ 1 1)') # => 2
|
759
840
|
```
|
@@ -763,7 +844,7 @@ With the constructor:
|
|
763
844
|
```ruby
|
764
845
|
require 'sweet-moon'
|
765
846
|
|
766
|
-
fennel = SweetMoon::State.new(package_path: '/folder/fennel
|
847
|
+
fennel = SweetMoon::State.new(package_path: '/folder/fennel/?.lua').fennel
|
767
848
|
|
768
849
|
fennel.eval('(+ 1 1)') # => 2
|
769
850
|
```
|
@@ -773,7 +854,7 @@ With global:
|
|
773
854
|
```ruby
|
774
855
|
require 'sweet-moon'
|
775
856
|
|
776
|
-
SweetMoon.global.state.add_package_path('/folder/fennel
|
857
|
+
SweetMoon.global.state.add_package_path('/folder/fennel/?.lua')
|
777
858
|
|
778
859
|
SweetMoon.global.state.fennel.eval('(+ 1 1)') # => 2
|
779
860
|
```
|
@@ -783,7 +864,7 @@ Alternatively:
|
|
783
864
|
```ruby
|
784
865
|
require 'sweet-moon'
|
785
866
|
|
786
|
-
SweetMoon.global.config(package_path: '/folder/fennel
|
867
|
+
SweetMoon.global.config(package_path: '/folder/fennel/?.lua')
|
787
868
|
|
788
869
|
SweetMoon.global.state.fennel.eval('(+ 1 1)') # => 2
|
789
870
|
```
|
@@ -810,6 +891,44 @@ To enforce the path for the `.fnx.fnl` file:
|
|
810
891
|
fennel.eval('(let [fnx (require :fnx)] (fnx.bootstrap! "/project/.fnx.fnl"))')
|
811
892
|
```
|
812
893
|
|
894
|
+
### Fennel REPL
|
895
|
+
|
896
|
+
In Ruby, you can start a [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) at any time somewhere in your code with [_pry_](https://github.com/pry/pry):
|
897
|
+
|
898
|
+
```ruby
|
899
|
+
require 'pry'
|
900
|
+
|
901
|
+
binding.pry
|
902
|
+
```
|
903
|
+
|
904
|
+
The same is true for Fennel, you just need to:
|
905
|
+
```fnl
|
906
|
+
(let [fennel (require :fennel)]
|
907
|
+
(fennel.repl {}))
|
908
|
+
```
|
909
|
+
|
910
|
+
Fennel's REPL won't have your _local_ values. But, you can tweak it to receive values to be checked inside the REPL:
|
911
|
+
|
912
|
+
```fnl
|
913
|
+
(fn my-repl [to-expose]
|
914
|
+
(let [fennel (require :fennel) env _G]
|
915
|
+
(each [key value (pairs to-expose)] (tset env key value))
|
916
|
+
(fennel.repl {:env env})))
|
917
|
+
|
918
|
+
(local value "some value")
|
919
|
+
|
920
|
+
(my-repl {:value value})
|
921
|
+
|
922
|
+
; Inside the REPL:
|
923
|
+
|
924
|
+
; >> value
|
925
|
+
; "some value"
|
926
|
+
```
|
927
|
+
|
928
|
+
You can install [_readline_](https://luarocks.org/modules/peterbillam/readline) for a better experience, e.g., autocompleting.
|
929
|
+
|
930
|
+
> _Check [Fennel's documentation](https://fennel-lang.org/api#start-a-configurable-repl) to learn more about the REPL._
|
931
|
+
|
813
932
|
## Global vs Isolated
|
814
933
|
|
815
934
|
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):
|
@@ -856,6 +975,8 @@ api_5.luaL_newstate
|
|
856
975
|
api_3.luaH_new
|
857
976
|
```
|
858
977
|
|
978
|
+
> _Check the caveats related to [_Global FFI_](#global-ffi) when working with multiple versions._
|
979
|
+
|
859
980
|
On the other hand, using the **global** _State_ may lead to a lot of issues. You need to consider from simple things – _"If I load two different files, the first file may impact the state of the second one?"_ – to more complex ones like multithreading, concurrency, etc.
|
860
981
|
|
861
982
|
So, you can at any time create a new isolated _State_ and destroy it when you don't need it anymore:
|
@@ -885,6 +1006,48 @@ state_5.eval('return _VERSION') # => Lua 5.4
|
|
885
1006
|
state_3.eval('return _VERSION') # => Lua 3.2
|
886
1007
|
```
|
887
1008
|
|
1009
|
+
> _Check the caveats related to [_Global FFI_](#global-ffi) when working with multiple versions._
|
1010
|
+
|
1011
|
+
## Global FFI
|
1012
|
+
|
1013
|
+
Some Lua libraries (e.g., [_readline_](https://pjb.com.au/comp/lua/readline.html) and [_luafilesystem_](https://keplerproject.github.io/luafilesystem/)) require the Lua C API functions available in the global C environment.
|
1014
|
+
|
1015
|
+
By default, _Sweet Moon_ enables [_Global FFI_](https://github.com/ffi/ffi/wiki/Loading-Libraries#function-visibility) to reduce friction when using popular libraries.
|
1016
|
+
|
1017
|
+
Using distinct Lua versions simultaneously with multiple _Shared Objects_ may be dangerous in this setup: Two APIs with the same name functions could be an issue because something will be overwritten.
|
1018
|
+
|
1019
|
+
Also, libraries that need Lua C API functions are compiled for a specific Lua version. If you are, e.g., using _LuaJIT_ and your library expects the _Standard Lua_, you may face issues.
|
1020
|
+
|
1021
|
+
You can disable _Global FFI_ at any time with:
|
1022
|
+
|
1023
|
+
```ruby
|
1024
|
+
require 'sweet-moon'
|
1025
|
+
|
1026
|
+
SweetMoon.global.config(global_ffi: false)
|
1027
|
+
|
1028
|
+
SweetMoon::State.new(global_ffi: false)
|
1029
|
+
|
1030
|
+
SweetMoon::API.new(global_ffi: false)
|
1031
|
+
```
|
1032
|
+
|
1033
|
+
To check if it's enabled or not:
|
1034
|
+
|
1035
|
+
```ruby
|
1036
|
+
require 'sweet-moon'
|
1037
|
+
|
1038
|
+
SweetMoon.global.api.meta.global_ffi # => true
|
1039
|
+
SweetMoon.global.state.meta.global_ffi # => true
|
1040
|
+
|
1041
|
+
SweetMoon::API.new.meta.global_ffi # => true
|
1042
|
+
|
1043
|
+
SweetMoon::State.new.meta.global_ffi # => true
|
1044
|
+
```
|
1045
|
+
|
1046
|
+
**Caveats:**
|
1047
|
+
|
1048
|
+
Binding globally a C API is irreversible, so if you start something with `global_ffi: true` and then change to `global_ffi: false`, it won't make the global one disappear. If you need _local_, ensure that you do it from the first line and never put anything as global throughout the entire program life cycle.
|
1049
|
+
|
1050
|
+
Also, the simple action of accessing `meta.global_ff` will bind the API, so you need to set your desired configuration before checking.
|
888
1051
|
|
889
1052
|
## Error Handling
|
890
1053
|
|
@@ -929,6 +1092,108 @@ rescue LuaRuntimeError => error
|
|
929
1092
|
end
|
930
1093
|
```
|
931
1094
|
|
1095
|
+
### Ruby feat. Lua Errors
|
1096
|
+
|
1097
|
+
Lua errors can be rescued inside Ruby:
|
1098
|
+
|
1099
|
+
```lua
|
1100
|
+
-- source.lua
|
1101
|
+
error('error from lua')
|
1102
|
+
```
|
1103
|
+
|
1104
|
+
```ruby
|
1105
|
+
require 'sweet-moon'
|
1106
|
+
require 'sweet-moon/errors'
|
1107
|
+
|
1108
|
+
state = SweetMoon::State.new
|
1109
|
+
|
1110
|
+
begin
|
1111
|
+
state.load('source.lua')
|
1112
|
+
rescue LuaRuntimeError => e
|
1113
|
+
puts e.message
|
1114
|
+
# => source.lua:2: error from lua
|
1115
|
+
end
|
1116
|
+
```
|
1117
|
+
|
1118
|
+
Ruby errors can be handled inside Lua:
|
1119
|
+
|
1120
|
+
```ruby
|
1121
|
+
require 'sweet-moon'
|
1122
|
+
|
1123
|
+
state = SweetMoon::State.new
|
1124
|
+
|
1125
|
+
state.set(:rubyFn, -> { raise 'error from ruby' })
|
1126
|
+
|
1127
|
+
state.load('source.lua')
|
1128
|
+
```
|
1129
|
+
|
1130
|
+
```lua
|
1131
|
+
-- source.lua
|
1132
|
+
local status, err = pcall(rubyFn)
|
1133
|
+
|
1134
|
+
print(status) -- => false
|
1135
|
+
|
1136
|
+
print(err)
|
1137
|
+
-- [string " return function (...)..."]:5: RuntimeError: error from ruby stack traceback:
|
1138
|
+
-- [string " return function (...)..."]:5: in function 'rubyFn'
|
1139
|
+
-- [C]: in function 'pcall'
|
1140
|
+
-- source.lua:2: in main chunk
|
1141
|
+
```
|
1142
|
+
|
1143
|
+
Ruby errors not handled inside Lua can be rescued inside Ruby again, with an additional Lua backtrace:
|
1144
|
+
|
1145
|
+
```lua
|
1146
|
+
-- source.lua
|
1147
|
+
a = 1
|
1148
|
+
|
1149
|
+
rubyFn()
|
1150
|
+
```
|
1151
|
+
|
1152
|
+
```ruby
|
1153
|
+
require 'sweet-moon'
|
1154
|
+
|
1155
|
+
state = SweetMoon::State.new
|
1156
|
+
|
1157
|
+
state.set(:rubyFn, -> { raise 'error from ruby' })
|
1158
|
+
|
1159
|
+
begin
|
1160
|
+
state.load('source.lua')
|
1161
|
+
rescue RuntimeError => e
|
1162
|
+
puts e.message # => error from ruby
|
1163
|
+
|
1164
|
+
puts e.backtrace.last
|
1165
|
+
# => source.lua:4: in main chunk
|
1166
|
+
end
|
1167
|
+
```
|
1168
|
+
|
1169
|
+
Lua errors inside Lua functions can be rescued inside Ruby:
|
1170
|
+
|
1171
|
+
```lua
|
1172
|
+
-- source.lua
|
1173
|
+
function luaFn()
|
1174
|
+
error('lua function error')
|
1175
|
+
end
|
1176
|
+
```
|
1177
|
+
|
1178
|
+
```ruby
|
1179
|
+
require 'sweet-moon'
|
1180
|
+
require 'sweet-moon/errors'
|
1181
|
+
|
1182
|
+
state = SweetMoon::State.new
|
1183
|
+
|
1184
|
+
state.load('source.lua')
|
1185
|
+
|
1186
|
+
lua_fn = state.get(:luaFn)
|
1187
|
+
|
1188
|
+
begin
|
1189
|
+
lua_fn.()
|
1190
|
+
rescue LuaRuntimeError => e
|
1191
|
+
puts e.message # => "source.lua:3: lua function error"
|
1192
|
+
end
|
1193
|
+
```
|
1194
|
+
|
1195
|
+
For Fennel, all the examples above are equally true, with additional stack traceback as well.
|
1196
|
+
|
932
1197
|
## Where can I find .so files?
|
933
1198
|
|
934
1199
|
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.
|
@@ -1183,6 +1448,8 @@ Update the [`config/tests.yml`](https://github.com/gbaptista/sweet-moon/blob/mai
|
|
1183
1448
|
|
1184
1449
|
Alternatively: Find or build the _Shared Objects_ for your Operating System on your own.
|
1185
1450
|
|
1451
|
+
Install the expected Lua _rocks_ described in `config/tests.yml`.
|
1452
|
+
|
1186
1453
|
### Running
|
1187
1454
|
|
1188
1455
|
```sh
|
data/components/api.rb
CHANGED
@@ -2,7 +2,7 @@ require 'ffi'
|
|
2
2
|
|
3
3
|
module Component
|
4
4
|
API = {
|
5
|
-
open!: ->(shared_objects) {
|
5
|
+
open!: ->(shared_objects, options = {}, default = {}) {
|
6
6
|
api = Module.new
|
7
7
|
|
8
8
|
api.extend FFI::Library
|
@@ -10,8 +10,11 @@ module Component
|
|
10
10
|
# TODO: Lua Constants
|
11
11
|
# attach_variable
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
global_ffi = default[:global_ffi]
|
14
|
+
|
15
|
+
global_ffi = options[:global_ffi] unless options[:global_ffi].nil?
|
16
|
+
|
17
|
+
if global_ffi
|
15
18
|
api.ffi_lib_flags(:global, :now)
|
16
19
|
else
|
17
20
|
api.ffi_lib_flags(:local, :now)
|
@@ -6,7 +6,8 @@ module Component
|
|
6
6
|
ffi: [:cfunction, [:pointer], :int],
|
7
7
|
overwrite: {
|
8
8
|
lua_pushcclosure: [%i[pointer cfunction int], :void],
|
9
|
-
lua_tocfunction: [%i[pointer int], :cfunction]
|
9
|
+
lua_tocfunction: [%i[pointer int], :cfunction],
|
10
|
+
lua_atpanic: [%i[pointer cfunction], :cfunction]
|
10
11
|
}
|
11
12
|
}
|
12
13
|
],
|
@@ -6,7 +6,8 @@ module Component
|
|
6
6
|
ffi: [:cfunction, [:pointer], :int],
|
7
7
|
overwrite: {
|
8
8
|
lua_pushcclosure: [%i[pointer cfunction int], :void],
|
9
|
-
lua_tocfunction: [%i[pointer int], :cfunction]
|
9
|
+
lua_tocfunction: [%i[pointer int], :cfunction],
|
10
|
+
lua_atpanic: [%i[pointer cfunction], :cfunction]
|
10
11
|
}
|
11
12
|
}
|
12
13
|
],
|
@@ -6,7 +6,8 @@ module Component
|
|
6
6
|
ffi: [:cfunction, [:pointer], :int],
|
7
7
|
overwrite: {
|
8
8
|
lua_pushcclosure: [%i[pointer cfunction int], :void],
|
9
|
-
lua_tocfunction: [%i[pointer int], :cfunction]
|
9
|
+
lua_tocfunction: [%i[pointer int], :cfunction],
|
10
|
+
lua_atpanic: [%i[pointer cfunction], :cfunction]
|
10
11
|
}
|
11
12
|
}
|
12
13
|
],
|
@@ -1,55 +1,19 @@
|
|
1
|
-
require_relative '
|
2
|
-
require_relative '../../../dsl/errors'
|
3
|
-
|
4
|
-
require_relative 'writer'
|
5
|
-
require_relative 'reader'
|
1
|
+
require_relative '../54/function'
|
6
2
|
|
7
3
|
module Component
|
8
4
|
module V50
|
9
|
-
Function =
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
},
|
23
|
-
|
24
|
-
read!: ->(api, state, _stack_index) {
|
25
|
-
reference = api.luaL_ref(
|
26
|
-
state[:lua], Logic::V50::Interpreter[:LUA_REGISTRYINDEX]
|
27
|
-
)
|
28
|
-
|
29
|
-
{ value: ->(input = [], output = 1) {
|
30
|
-
api.lua_rawgeti(
|
31
|
-
state[:lua], Logic::V50::Interpreter[:LUA_REGISTRYINDEX], reference
|
32
|
-
)
|
33
|
-
|
34
|
-
input.each do |value|
|
35
|
-
Writer[:push!].(api, state, value)
|
36
|
-
end
|
37
|
-
|
38
|
-
result = Interpreter[:call!].(api, state, input.size, output)
|
39
|
-
|
40
|
-
if result[:error]
|
41
|
-
raise SweetMoon::Errors::SweetMoonErrorHelper.for(
|
42
|
-
result[:error][:status]
|
43
|
-
), result[:error][:value]
|
44
|
-
end
|
45
|
-
|
46
|
-
result = Reader[:read_all!].(api, state)
|
47
|
-
|
48
|
-
return result.first if output == 1
|
49
|
-
|
50
|
-
result
|
51
|
-
}, pop: false }
|
52
|
-
}
|
53
|
-
}
|
5
|
+
Function = Component::V54::Function
|
6
|
+
|
7
|
+
LUA_HANDLER = <<~LUA
|
8
|
+
return function (...)
|
9
|
+
result = _ruby(unpack(arg))
|
10
|
+
|
11
|
+
if result['error'] then
|
12
|
+
error(result['output'])
|
13
|
+
else
|
14
|
+
return result['output']
|
15
|
+
end
|
16
|
+
end
|
17
|
+
LUA
|
54
18
|
end
|
55
19
|
end
|