sweet-moon 0.0.3 → 0.0.6

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