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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 79d7b00c236a8ce4b85d6cb4230d7e4e9714b0e537199fa3445254c0577b5bfa
4
- data.tar.gz: befd1ae3a4bcec8a274a256b5aab3c690cf876df1167531a896650b956e7dc58
3
+ metadata.gz: 46891cd3e8103176f3f909415432df155df1bd33cbed89a80f0042f5d303a2b7
4
+ data.tar.gz: af7617e43eacc588135285dbd652f644d9bda8b87735c86ff89a7719ce6bfe1a
5
5
  SHA512:
6
- metadata.gz: 05ff924f37bab331deb03a55e21b968384fd7755cc38d8b4780b45ec5a14d21487df64df1dea2122c41ad4dedfb4e8013964e926a826537e713aa253b923be90
7
- data.tar.gz: 8d1266390a693ef67f8bf5209eb5b2cf2b997bddb1e9f90ba5e2030fadd9ddf5819f2411099173b7a4528eafdcd09b7157675bcff77e3ca864fe600018085355
6
+ metadata.gz: 1949e5f83c00dd65cdf78e2e8ebd4f66654dc24df1769add99ad8f01e75cc97bcb090e9d0dc0cf5d10dcdd4d1d338252b4ad78894bd3d4cef40b91ae31aab3d0
7
+ data.tar.gz: 9a09f1231c7e02250f232e368abd95b7bb1b4d5e366ef2614ce9871248c49201fb480b8b698833df66d769e7688602e8c3415a454366ef5ad3ede02163e1c5a4
data/.rubocop.yml CHANGED
@@ -5,6 +5,9 @@ AllCops:
5
5
  Style/Documentation:
6
6
  Enabled: false
7
7
 
8
+ Lint/RescueException:
9
+ Exclude: ['components/interpreters/**/function.rb']
10
+
8
11
  Layout/LineLength:
9
12
  Max: 86
10
13
  Exclude: ['spec/**/*', 'logic/signatures/*']
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.3'
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.lua')
618
+ state.add_package_path('/home/me/fennel/?.lua')
581
619
 
582
- state.add_package_cpath('/home/me/lib.so')
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.lua']
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/lib.so']
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.lua',
615
- package_cpath: '/lib/lib.so',
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.lua',
626
- package_cpath: '/lib/lib.so',
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('(global mySum (fn [a b] (+ a b)))')
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.lua')
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.lua').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.lua')
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.lua')
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
- if shared_objects.size > 1
14
- # TODO: Dangerous
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)
@@ -0,0 +1,17 @@
1
+ require 'singleton'
2
+
3
+ module Component
4
+ class Default
5
+ include Singleton
6
+
7
+ attr_reader :options
8
+
9
+ def initialize
10
+ @options = { global_ffi: true }
11
+ end
12
+
13
+ def set(key, value)
14
+ @options[key.to_sym] = value
15
+ end
16
+ end
17
+ end
@@ -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 '../../../logic/interpreters/interpreter_50'
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
- push!: ->(api, state, closure) {
11
- handler = ->(current_state) {
12
- updated_state = state.merge(lua: current_state)
13
- input = Reader[:read_all!].(api, updated_state)
14
- result = closure.(*input)
15
- Writer[:push!].(api, updated_state, result)
16
- return 1
17
- }
18
-
19
- state[:avoid_gc] << handler
20
-
21
- api.lua_pushcclosure(state[:lua], handler, 0)
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