sweet-moon 0.0.2 → 0.0.5

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: 7bc6ba34912c2d5c9e26b95b385e4a992b186b6adbe81e40e0e6068cc363a948
4
- data.tar.gz: 751f266193c94b533cf8f0b38f99745870688a2efd01e5277bb25d0aafe4b314
3
+ metadata.gz: 8e216a8bf96c191f08675bad6b2d4d9a1dceb9649a5e856ce4d6b4894e09b35e
4
+ data.tar.gz: b807eb9b92df1e53a0e0011f6132724c95b11a76dafab1073a46d2c5bf35c6ab
5
5
  SHA512:
6
- metadata.gz: 1fac3cd35cc1afd5cf1918f98326237203f9e12c631ccde66946a6496d24d90e69cf06a43413b1f58527c486f81f50098d7d866547389936becac5b6ba8eda84
7
- data.tar.gz: e14b5c3eecbdeefa68747f4b2cf8377c0b99289783bfd5dd3eec5c295368bea65eca70be594f4272777cbd811ecdb6a3fef36ce73103349831072d44851a51bb
6
+ metadata.gz: 538a7a773c11fe66a13c0be49efeb1f8d37da83f52a85d32fe8a7c52b3b590d155b0cdfb50efec3755181947db6a7b67a238b31c10bc382362b70301594949fb
7
+ data.tar.gz: 95d84ea3cf24919e4646c766f66302308f22392434ba5f76b0ae7743d4ef9ad3868d90b13b3d4bf26d58d7500d276b88be7ee26393818cf00950f08f4e6c4fc6
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,18 @@ _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)
31
33
  - [Global vs Isolated](#global-vs-isolated)
32
34
  - [Error Handling](#error-handling)
35
+ - [Ruby feat. Lua Errors](#ruby-feat-lua-errors)
33
36
  - [Where can I find .so files?](#where-can-i-find-so-files)
34
37
  - [Low-Level C API](#low-level-c-api)
35
38
  - [The API](#the-api)
@@ -69,7 +72,7 @@ gem install sweet-moon
69
72
  > **Disclaimer:** It's an early-stage project, and you should expect breaking changes.
70
73
 
71
74
  ```ruby
72
- gem 'sweet-moon', '~> 0.0.2'
75
+ gem 'sweet-moon', '~> 0.0.5'
73
76
  ```
74
77
 
75
78
  ```ruby
@@ -209,6 +212,7 @@ Compared to: [rufus-lua](https://github.com/jmettraux/rufus-lua), [YAML](https:/
209
212
  - [Tables, Arrays, and Hashes](#tables-arrays-and-hashes)
210
213
  - [Functions](#functions)
211
214
  - [Other Types](#other-types)
215
+ - [Lua Global vs Local Variables](#lua-global-vs-local-variables)
212
216
  - [_destroy_ and _clear_](#destroy-and-clear)
213
217
 
214
218
  ### Setup
@@ -389,6 +393,20 @@ state.eval('lua_value = {a = "text", b = 1.5, c = true}') # => nil
389
393
  state.get(:lua_value, :b) # => 1.5
390
394
  ```
391
395
 
396
+ With `set`, you can use a second parameter to set a field:
397
+
398
+ ```ruby
399
+ require 'sweet-moon'
400
+
401
+ state = SweetMoon::State.new
402
+
403
+ state.set(:myTable, {}) # => nil
404
+
405
+ state.set(:myTable, :a, 3) # => nil
406
+
407
+ state.eval('return myTable["a"]') # => 3
408
+ ```
409
+
392
410
  Caveats:
393
411
 
394
412
  - Ruby `Symbol` (e.g. `:value`) is converted to Lua `string`.
@@ -512,6 +530,24 @@ fennel_eval = state.get(:fennel_eval)
512
530
  fennel_eval.(['(+ 1 1)']) # => 2
513
531
  ```
514
532
 
533
+ #### Lua Global vs Local Variables
534
+
535
+ You can't exchange _local_ variables, only [_global_](https://www.lua.org/pil/1.2.html) ones:
536
+
537
+ ```ruby
538
+ require 'sweet-moon'
539
+
540
+ state = SweetMoon::State.new
541
+
542
+ state.eval('lua_value = "Lua Text"') # => nil
543
+
544
+ state.get('lua_value') # => 'Lua Text'
545
+
546
+ state.eval('local lua_b = "b"') # => nil
547
+
548
+ state.get('lua_b') # => nil
549
+ ```
550
+
515
551
  ## _destroy_ and _clear_
516
552
 
517
553
  You can destroy a state:
@@ -577,21 +613,21 @@ state.add_package_path('/home/me/my-lua-modules/?/init.lua')
577
613
 
578
614
  state.add_package_cpath('/home/me/my-lua-modules/?.so')
579
615
 
580
- state.add_package_path('/home/me/fennel.lua')
616
+ state.add_package_path('/home/me/fennel/?.lua')
581
617
 
582
- state.add_package_cpath('/home/me/lib.so')
618
+ state.add_package_cpath('/home/me/?.so')
583
619
 
584
620
  state.package_path
585
621
  # => ['./?.lua',
586
622
  # './?/init.lua',
587
623
  # '/home/me/my-lua-modules/?.lua',
588
624
  # '/home/me/my-lua-modules/?/init.lua',
589
- # '/home/me/fennel.lua']
625
+ # '/home/me/fennel/?.lua']
590
626
 
591
627
  state.package_cpath
592
628
  # => ['./?.so',
593
629
  # '/home/me/my-lua-modules/?.so',
594
- # '/home/me/lib.so']
630
+ # '/home/me/?.so']
595
631
  ```
596
632
 
597
633
  Requiring a module:
@@ -611,8 +647,8 @@ You can set packages in State constructors:
611
647
  require 'sweet-moon'
612
648
 
613
649
  SweetMoon::State.new(
614
- package_path: '/folder/lib.lua',
615
- package_cpath: '/lib/lib.so',
650
+ package_path: '/folder/lib/?.lua',
651
+ package_cpath: '/lib/lib/?.so',
616
652
  )
617
653
  ```
618
654
 
@@ -622,8 +658,8 @@ Also, you can add packages through the global config:
622
658
  require 'sweet-moon'
623
659
 
624
660
  SweetMoon.global.config(
625
- package_path: '/folder/lib.lua',
626
- package_cpath: '/lib/lib.so',
661
+ package_path: '/folder/lib/?.lua',
662
+ package_cpath: '/lib/lib/?.so',
627
663
  )
628
664
  ```
629
665
 
@@ -714,8 +750,8 @@ state = SweetMoon::State.new
714
750
 
715
751
  state.fennel.eval('(+ 1 2)') # => 3
716
752
 
717
- state.fennel.eval('(global mySum (fn [a b] (+ a b)))')
718
- state.fennel.eval('(mySum 2 3)') # => 5
753
+ state.fennel.eval('(set _G.mySum (fn [a b] (+ a b)))')
754
+ state.fennel.eval('(_G.mySum 2 3)') # => 5
719
755
 
720
756
  mySum = state.fennel.get(:mySum)
721
757
 
@@ -725,7 +761,7 @@ sum_list = -> (list) { list.sum }
725
761
 
726
762
  state.set('sumList', sum_list) # => nil
727
763
 
728
- state.fennel.eval('(sumList [2 3 5])') # => 10
764
+ state.fennel.eval('(_G.sumList [2 3 5])') # => 10
729
765
 
730
766
  state.fennel.load('file.fnl')
731
767
  ```
@@ -740,6 +776,49 @@ state = SweetMoon::State.new.fennel
740
776
  state.eval('(+ 1 2)') # => 3
741
777
  ```
742
778
 
779
+ ### Fennel Global vs Local Variables
780
+
781
+ Fennel encourages you to explicitly use the [_`_G`_](https://www.lua.org/manual/5.4/manual.html#pdf-_G) table to access global variables:
782
+
783
+ ```ruby
784
+ require 'sweet-moon'
785
+
786
+ fennel = SweetMoon::State.new.fennel
787
+
788
+ fennel.eval('(set _G.a? 2)')
789
+
790
+ fennel.get('a?') # => 2
791
+ fennel.get('_G', 'a?') # => 2
792
+
793
+ fennel.set('b', 3)
794
+
795
+ fennel.eval('(print _G.b)') # => 3
796
+ ```
797
+
798
+ 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.
799
+
800
+ 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:
801
+
802
+ ```ruby
803
+ require 'sweet-moon'
804
+
805
+ fennel = SweetMoon::State.new.fennel
806
+
807
+ fennel.eval('(local name "value")')
808
+
809
+ fennel.get('name') # => nil
810
+
811
+ fennel.eval('(set _G.name "value")')
812
+
813
+ fennel.get('name') # => "value"
814
+
815
+ fennel.set('var-b', 35) # => nil
816
+
817
+ fennel.eval('var-b') # => nil
818
+
819
+ fennel.eval('_G.var-b') # => 35
820
+ ```
821
+
743
822
  ### Fennel Setup
744
823
 
745
824
  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 +832,7 @@ require 'sweet-moon'
753
832
 
754
833
  state = SweetMoon::State.new
755
834
 
756
- state.add_package_path('/folder/fennel.lua')
835
+ state.add_package_path('/folder/fennel/?.lua')
757
836
 
758
837
  state.fennel.eval('(+ 1 1)') # => 2
759
838
  ```
@@ -763,7 +842,7 @@ With the constructor:
763
842
  ```ruby
764
843
  require 'sweet-moon'
765
844
 
766
- fennel = SweetMoon::State.new(package_path: '/folder/fennel.lua').fennel
845
+ fennel = SweetMoon::State.new(package_path: '/folder/fennel/?.lua').fennel
767
846
 
768
847
  fennel.eval('(+ 1 1)') # => 2
769
848
  ```
@@ -773,7 +852,7 @@ With global:
773
852
  ```ruby
774
853
  require 'sweet-moon'
775
854
 
776
- SweetMoon.global.state.add_package_path('/folder/fennel.lua')
855
+ SweetMoon.global.state.add_package_path('/folder/fennel/?.lua')
777
856
 
778
857
  SweetMoon.global.state.fennel.eval('(+ 1 1)') # => 2
779
858
  ```
@@ -783,7 +862,7 @@ Alternatively:
783
862
  ```ruby
784
863
  require 'sweet-moon'
785
864
 
786
- SweetMoon.global.config(package_path: '/folder/fennel.lua')
865
+ SweetMoon.global.config(package_path: '/folder/fennel/?.lua')
787
866
 
788
867
  SweetMoon.global.state.fennel.eval('(+ 1 1)') # => 2
789
868
  ```
@@ -929,6 +1008,108 @@ rescue LuaRuntimeError => error
929
1008
  end
930
1009
  ```
931
1010
 
1011
+ ### Ruby feat. Lua Errors
1012
+
1013
+ Lua errors can be rescued inside Ruby:
1014
+
1015
+ ```lua
1016
+ -- source.lua
1017
+ error('error from lua')
1018
+ ```
1019
+
1020
+ ```ruby
1021
+ require 'sweet-moon'
1022
+ require 'sweet-moon/errors'
1023
+
1024
+ state = SweetMoon::State.new
1025
+
1026
+ begin
1027
+ state.load('source.lua')
1028
+ rescue LuaRuntimeError => e
1029
+ puts e.message
1030
+ # => source.lua:2: error from lua
1031
+ end
1032
+ ```
1033
+
1034
+ Ruby errors can be handled inside Lua:
1035
+
1036
+ ```ruby
1037
+ require 'sweet-moon'
1038
+
1039
+ state = SweetMoon::State.new
1040
+
1041
+ state.set(:rubyFn, -> { raise 'error from ruby' })
1042
+
1043
+ state.load('source.lua')
1044
+ ```
1045
+
1046
+ ```lua
1047
+ -- source.lua
1048
+ local status, err = pcall(rubyFn)
1049
+
1050
+ print(status) -- => false
1051
+
1052
+ print(err)
1053
+ -- [string " return function (...)..."]:5: RuntimeError: error from ruby stack traceback:
1054
+ -- [string " return function (...)..."]:5: in function 'rubyFn'
1055
+ -- [C]: in function 'pcall'
1056
+ -- source.lua:2: in main chunk
1057
+ ```
1058
+
1059
+ Ruby errors not handled inside Lua can be rescued inside Ruby again, with an additional Lua backtrace:
1060
+
1061
+ ```lua
1062
+ -- source.lua
1063
+ a = 1
1064
+
1065
+ rubyFn()
1066
+ ```
1067
+
1068
+ ```ruby
1069
+ require 'sweet-moon'
1070
+
1071
+ state = SweetMoon::State.new
1072
+
1073
+ state.set(:rubyFn, -> { raise 'error from ruby' })
1074
+
1075
+ begin
1076
+ state.load('source.lua')
1077
+ rescue RuntimeError => e
1078
+ puts e.message # => error from ruby
1079
+
1080
+ puts e.backtrace.last
1081
+ # => source.lua:4: in main chunk
1082
+ end
1083
+ ```
1084
+
1085
+ Lua errors inside Lua functions can be rescued inside Ruby:
1086
+
1087
+ ```lua
1088
+ -- source.lua
1089
+ function luaFn()
1090
+ error('lua function error')
1091
+ end
1092
+ ```
1093
+
1094
+ ```ruby
1095
+ require 'sweet-moon'
1096
+ require 'sweet-moon/errors'
1097
+
1098
+ state = SweetMoon::State.new
1099
+
1100
+ state.load('source.lua')
1101
+
1102
+ lua_fn = state.get(:luaFn)
1103
+
1104
+ begin
1105
+ lua_fn.()
1106
+ rescue LuaRuntimeError => e
1107
+ puts e.message # => "source.lua:3: lua function error"
1108
+ end
1109
+ ```
1110
+
1111
+ For Fennel, all the examples above are equally true, with additional stack traceback as well.
1112
+
932
1113
  ## Where can I find .so files?
933
1114
 
934
1115
  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.
@@ -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,52 +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
- input = Reader[:read_all!].(api, current_state)
13
- result = closure.(*input)
14
- Writer[:push!].(api, current_state, result)
15
- return 1
16
- }
17
-
18
- api.lua_pushcclosure(state, handler, 0)
19
- },
20
-
21
- read!: ->(api, state, _stack_index) {
22
- reference = api.luaL_ref(
23
- state, Logic::V50::Interpreter[:LUA_REGISTRYINDEX]
24
- )
25
-
26
- { value: ->(input = [], output = 1) {
27
- api.lua_rawgeti(
28
- state, Logic::V50::Interpreter[:LUA_REGISTRYINDEX], reference
29
- )
30
-
31
- input.each do |value|
32
- Writer[:push!].(api, state, value)
33
- end
34
-
35
- result = Interpreter[:call!].(api, state, input.size, output)
36
-
37
- if result[:error]
38
- raise SweetMoon::Errors::SweetMoonErrorHelper.for(
39
- result[:error][:status]
40
- ), result[:error][:value]
41
- end
42
-
43
- result = Reader[:read_all!].(api, state)
44
-
45
- return result.first if output == 1
46
-
47
- result
48
- }, pop: false }
49
- }
50
- }
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
51
18
  end
52
19
  end
@@ -1,91 +1,113 @@
1
1
  require_relative '../../../logic/interpreters/interpreter_50'
2
2
 
3
+ require_relative 'function'
3
4
  require_relative 'reader'
4
- require_relative 'writer'
5
5
  require_relative 'table'
6
+ require_relative 'writer'
6
7
 
7
8
  module Component
8
9
  module V50
9
10
  Interpreter = {
10
11
  version: Logic::V50::Interpreter[:version],
12
+ logic: Logic::V50,
11
13
 
12
14
  create_state!: ->(api) {
13
15
  state = api.lua_open
14
- { state: state, error: state ? nil : :MemoryAllocation }
16
+ { state: { lua: state, avoid_gc: [], ruby_error_info: nil },
17
+ error: state ? nil : :MemoryAllocation }
15
18
  },
16
19
 
17
20
  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)
21
+ api.luaopen_base(state[:lua])
22
+ api.luaopen_table(state[:lua])
23
+ api.luaopen_io(state[:lua])
24
+ api.luaopen_string(state[:lua])
25
+ api.luaopen_math(state[:lua])
23
26
 
24
- api.lua_settop(state, -7 - 1)
27
+ api.lua_settop(state[:lua], -7 - 1)
25
28
 
26
29
  { state: state }
27
30
  },
28
31
 
29
32
  load_file_and_push_chunck!: ->(api, state, path) {
30
- result = api.luaL_loadfile(state, path)
33
+ result = api.luaL_loadfile(state[:lua], path)
31
34
  { state: state, error: Interpreter[:_error].(api, state, result, pull: true) }
32
35
  },
33
36
 
34
37
  push_chunk!: ->(api, state, value) {
35
- result = api.luaL_loadbuffer(state, value, value.size, value)
38
+ result = api.luaL_loadbuffer(state[:lua], value, value.size, value)
36
39
 
37
40
  { state: state, error: Interpreter[:_error].(api, state, result, pull: true) }
38
41
  },
39
42
 
40
- set_table!: ->(api, state, variable, value) {
41
- Table[:set!].(api, state, variable, value)
43
+ set_table!: ->(api, state) {
44
+ result = api.lua_settable(state[:lua], -3)
45
+
46
+ api.lua_settop(state[:lua], -2)
47
+
48
+ { state: state,
49
+ error: Interpreter[:_error].(api, state, result, pull: false) }
42
50
  },
43
51
 
44
52
  push_value!: ->(api, state, value) {
45
- Writer[:push!].(api, state, value)
53
+ Writer[:push!].(api, state, Component::V50, value)
46
54
  { state: state }
47
55
  },
48
56
 
49
57
  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])
58
+ api.lua_pushstring(state[:lua], variable)
59
+ api.lua_insert(state[:lua], -2)
60
+ api.lua_settable(state[:lua], Logic::V50::Interpreter[:LUA_GLOBALSINDEX])
53
61
  { state: state }
54
62
  },
55
63
 
56
64
  get_variable_and_push!: ->(api, state, variable, key = nil) {
57
- api.lua_pushstring(state, variable.to_s)
58
- api.lua_gettable(state, Logic::V50::Interpreter[:LUA_GLOBALSINDEX])
65
+ extra_pop = true
66
+ if variable == '_G'
67
+ variable = key
68
+ key = nil
69
+ extra_pop = false
70
+ end
59
71
 
60
- Table[:read_field_and_push!].(api, state, key, -1) unless key.nil?
72
+ api.lua_pushstring(state[:lua], variable.to_s)
73
+ api.lua_gettable(state[:lua], Logic::V50::Interpreter[:LUA_GLOBALSINDEX])
61
74
 
62
- { state: state }
75
+ unless key.nil?
76
+ Table[:read_field_and_push!].(api, state, Component::V50, key,
77
+ -1)
78
+ end
79
+
80
+ { state: state, extra_pop: extra_pop }
63
81
  },
64
82
 
65
83
  call!: ->(api, state, inputs = 0, outputs = 1) {
66
- result = api.lua_pcall(state, inputs, outputs, 0)
84
+ result = api.lua_pcall(state[:lua], inputs, outputs, 0)
67
85
  { state: state, error: Interpreter[:_error].(api, state, result, pull: true) }
68
86
  },
69
87
 
70
88
  read_and_pop!: ->(api, state, stack_index = -1, extra_pop: false) {
71
- result = Component::V50::Reader[:read!].(api, state, stack_index)
89
+ result = Component::V50::Reader[:read!].(api, state, Component::V50,
90
+ stack_index)
72
91
 
73
- api.lua_settop(state, -2) if result[:pop]
74
- api.lua_settop(state, -2) if extra_pop
92
+ api.lua_settop(state[:lua], -2) if result[:pop]
93
+ api.lua_settop(state[:lua], -2) if extra_pop
75
94
 
76
95
  { state: state, output: result[:value] }
77
96
  },
78
97
 
79
98
  read_all!: ->(api, state) {
80
- result = Reader[:read_all!].(api, state)
99
+ result = Reader[:read_all!].(api, state, Component::V50)
81
100
 
82
101
  { state: state, output: result }
83
102
  },
84
103
 
85
104
  destroy_state!: ->(api, state) {
86
- result = api.lua_close(state)
105
+ result = api.lua_close(state[:lua])
106
+
107
+ state.delete(:lua)
108
+ state.delete(:avoid_gc)
87
109
 
88
- { state: nil, error: Interpreter[:_error].(api, state, result) }
110
+ { state: nil, error: Interpreter[:_error].(api, nil, result) }
89
111
  },
90
112
 
91
113
  _error: ->(api, state, code, options = {}) {
@@ -94,7 +116,7 @@ module Component
94
116
  ] || :error
95
117
 
96
118
  if code.is_a?(Numeric) && code >= 1
97
- return { status: status } unless options[:pull]
119
+ return { status: status } unless options[:pull] && state
98
120
 
99
121
  { status: status,
100
122
  value: Interpreter[:read_and_pop!].(api, state, -1)[:output] }
@@ -1,65 +1,7 @@
1
- require 'ffi'
2
-
3
- require_relative 'interpreter'
4
- require_relative 'function'
5
- require_relative 'table'
1
+ require_relative '../54/reader'
6
2
 
7
3
  module Component
8
4
  module V50
9
- Reader = {
10
- read_all!: ->(api, state) {
11
- (1..api.lua_gettop(state)).map do
12
- Interpreter[:read_and_pop!].(api, state)[:output]
13
- end.reverse
14
- },
15
-
16
- read!: ->(api, state, stack_index = -1) {
17
- stack_index = api.lua_gettop(state) if stack_index == -1
18
-
19
- type = api.lua_typename(state, api.lua_type(state, stack_index)).read_string
20
-
21
- case type
22
- when 'string'
23
- Reader[:read_string!].(api, state, stack_index)
24
- when 'number'
25
- Reader[:read_number!].(api, state, stack_index)
26
- when 'no value'
27
- { value: nil, pop: true, type: type }
28
- when 'nil'
29
- { value: nil, pop: true }
30
- when 'boolean'
31
- Reader[:read_boolean!].(api, state, stack_index)
32
- when 'table'
33
- Table[:read!].(api, state, stack_index)
34
- when 'function'
35
- Function[:read!].(api, state, stack_index)
36
- else
37
- # none nil boolean lightuserdata number
38
- # string table function userdata thread
39
- { value: "#{type}: 0x#{api.lua_topointer(state, stack_index).address}",
40
- type: type, pop: true }
41
- end
42
- },
43
-
44
- read_string!: ->(api, state, stack_index) {
45
- { value: api.lua_tostring(state, stack_index).read_string,
46
- pop: true }
47
- },
48
-
49
- read_number!: ->(api, state, stack_index) {
50
- if api.respond_to?(:lua_isinteger) &&
51
- api.respond_to?(:lua_tointeger) &&
52
- api.lua_isinteger(state, stack_index) == 1
53
-
54
- return { value: api.lua_tointeger(state, stack_index), pop: true }
55
- end
56
-
57
- { value: api.lua_tonumber(state, stack_index), pop: true }
58
- },
59
-
60
- read_boolean!: ->(api, state, stack_index) {
61
- { value: api.lua_toboolean(state, stack_index) == 1, pop: true }
62
- }
63
- }
5
+ Reader = Component::V54::Reader
64
6
  end
65
7
  end