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.
@@ -6,82 +6,47 @@ require_relative 'reader'
6
6
  module Component
7
7
  module V50
8
8
  Table = {
9
- push!: ->(api, state, list, stack_index = -1) {
10
- stack_index = api.lua_gettop(state) if stack_index == -1
11
-
12
- api.lua_newtable(state)
13
-
14
- if list.is_a? Hash
15
- list.each_key do |key|
16
- Writer[:push!].(api, state, key)
17
- Writer[:push!].(api, state, list[key])
18
- api.lua_settable(state, stack_index + 1)
19
- end
20
- else
21
- list.each_with_index do |value, index|
22
- Writer[:push!].(api, state, index + 1)
23
- Writer[:push!].(api, state, value)
24
- api.lua_settable(state, stack_index + 1)
25
- end
26
- end
9
+ create_table!: ->(api, state, _list) {
10
+ api.lua_newtable(state[:lua])
27
11
  },
28
12
 
29
- read!: ->(api, state, stack_index) {
30
- stack_index = api.lua_gettop(state) if stack_index == -1
31
-
32
- type = api.lua_typename(state, api.lua_type(state, stack_index)).read_string
33
-
34
- api.lua_pushnil(state)
35
-
36
- return nil if type != 'table'
37
-
38
- tuples = []
39
-
40
- while api.lua_next(state, stack_index).positive?
41
- value = Reader[:read!].(api, state, stack_index + 2)
42
- key = Reader[:read!].(api, state, stack_index + 1)
43
- api.lua_settop(state, -2) if value[:pop]
44
-
45
- tuples << [key[:value], value[:value]]
46
-
47
- break if value[:type] == 'no value'
48
- end
49
-
50
- { value: Logic::Tables[:to_hash_or_array].(tuples), pop: true }
51
- },
13
+ push!: Component::V54::Table[:push!],
14
+ read!: Component::V54::Table[:read!],
52
15
 
53
- read_field_and_push!: ->(api, state, expected_key, stack_index) {
54
- stack_index = api.lua_gettop(state) if stack_index == -1
16
+ read_field_and_push!: ->(api, state, component, expected_key, stack_index) {
17
+ stack_index = api.lua_gettop(state[:lua]) if stack_index == -1
55
18
 
56
- type = api.lua_typename(state, api.lua_type(state, stack_index)).read_string
19
+ type = api.lua_typename(
20
+ state[:lua], api.lua_type(state[:lua], stack_index)
21
+ ).read_string
57
22
 
58
- api.lua_pushnil(state)
23
+ api.lua_pushnil(state[:lua])
59
24
 
60
25
  return nil if type != 'table'
61
26
 
62
27
  result = nil
63
28
 
64
- while api.lua_next(state, stack_index).positive?
65
- value = Reader[:read!].(api, state, stack_index + 2)
66
- key = Reader[:read!].(api, state, stack_index + 1)
29
+ while api.lua_next(state[:lua], stack_index).positive?
30
+ value = component::Reader[:read!].(api, state, component, stack_index + 2)
31
+ key = component::Reader[:read!].(api, state, component, stack_index + 1)
67
32
 
68
- api.lua_settop(state, -2) if value[:pop]
33
+ api.lua_settop(state[:lua], -2) if value[:pop]
69
34
 
70
35
  key_type = api.lua_typename(
71
- state, api.lua_type(state, stack_index + 1)
36
+ state[:lua], api.lua_type(state[:lua], stack_index + 1)
72
37
  ).read_string
73
38
 
74
- if Table[:is_same_key].(key_type, key[:value], expected_key)
39
+ if component::Table[:is_same_key].(key_type, key[:value], expected_key)
75
40
  result = value[:value]
76
41
  break
77
42
  end
78
43
 
79
- break if value[:type] == 'no value'
44
+ break if value[:type] == 'no value' || key[:value].instance_of?(Proc)
80
45
  end
81
46
 
82
- api.lua_settop(state, -2)
47
+ api.lua_settop(state[:lua], -2)
83
48
 
84
- Writer[:push!].(api, state, result)
49
+ component::Writer[:push!].(api, state, component, result)
85
50
  },
86
51
 
87
52
  is_same_key: ->(lua_key_type, lua_key, ruby_key) {
@@ -1,45 +1,7 @@
1
- require_relative 'function'
2
- require_relative 'table'
1
+ require_relative '../54/writer'
3
2
 
4
3
  module Component
5
4
  module V50
6
- Writer = {
7
- push!: ->(api, state, value) {
8
- case Writer[:_to_lua_type].(value)
9
- when 'string'
10
- api.lua_pushstring(state, value.to_s)
11
- when 'number'
12
- api.lua_pushnumber(state, value)
13
- when 'integer'
14
- if api.respond_to? :lua_pushinteger
15
- api.lua_pushinteger(state, value)
16
- else
17
- api.lua_pushnumber(state, value)
18
- end
19
- when 'nil'
20
- api.lua_pushnil(state)
21
- when 'boolean'
22
- api.lua_pushboolean(state, value ? 1 : 0)
23
- when 'table'
24
- Table[:push!].(api, state, value)
25
- when 'function'
26
- Function[:push!].(api, state, value)
27
- else
28
- api.lua_pushstring(
29
- state, "#<#{value.class}:0x#{format('%016x', value.object_id)}>"
30
- )
31
- end
32
- },
33
-
34
- _to_lua_type: ->(value) {
35
- return 'nil' if value.nil?
36
- return 'function' if value.is_a?(Proc)
37
- return 'integer' if value.is_a? Integer
38
- return 'number' if value.is_a? Float
39
- return 'table' if value.is_a?(Hash) || value.is_a?(Array)
40
- return 'string' if value.is_a?(String) || value.instance_of?(Symbol)
41
- return 'boolean' if [true, false].include? value
42
- }
43
- }
5
+ Writer = Component::V54::Writer
44
6
  end
45
7
  end
@@ -1,52 +1,9 @@
1
- require_relative '../../../logic/interpreters/interpreter_51'
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 V51
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::V51::Interpreter[:LUA_REGISTRYINDEX]
24
- )
25
-
26
- { value: ->(input = [], output = 1) {
27
- api.lua_rawgeti(
28
- state, Logic::V51::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
5
+ Function = Component::V54::Function
46
6
 
47
- result
48
- }, pop: false }
49
- }
50
- }
7
+ LUA_HANDLER = Component::V54::LUA_HANDLER
51
8
  end
52
9
  end
@@ -1,90 +1,101 @@
1
1
  require_relative '../../../logic/interpreters/interpreter_51'
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 V51
9
10
  Interpreter = {
10
11
  version: Logic::V51::Interpreter[:version],
12
+ logic: Logic::V51,
11
13
 
12
14
  create_state!: ->(api) {
13
15
  state = api.luaL_newstate
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.luaL_openlibs(state)
19
-
21
+ api.luaL_openlibs(state[:lua])
20
22
  { state: state }
21
23
  },
22
24
 
23
25
  load_file_and_push_chunck!: ->(api, state, path) {
24
- result = api.luaL_loadfile(state, path)
26
+ result = api.luaL_loadfile(state[:lua], path)
25
27
  { state: state, error: Interpreter[:_error].(api, state, result, pull: true) }
26
28
  },
27
29
 
28
30
  push_chunk!: ->(api, state, value) {
29
- result = api.luaL_loadstring(state, value)
31
+ result = api.luaL_loadstring(state[:lua], value)
30
32
  { state: state, error: Interpreter[:_error].(api, state, result, pull: true) }
31
33
  },
32
34
 
33
- set_table!: ->(api, state, variable, value) {
34
- Table[:set!].(api, state, variable, value)
35
+ set_table!: ->(api, state) {
36
+ result = api.lua_settable(state[:lua], -3)
37
+
38
+ api.lua_settop(state[:lua], -2)
39
+
40
+ { state: state,
41
+ error: Interpreter[:_error].(api, state, result, pull: false) }
35
42
  },
36
43
 
37
44
  push_value!: ->(api, state, value) {
38
- Writer[:push!].(api, state, value)
45
+ Writer[:push!].(api, state, Component::V51, value)
39
46
  { state: state }
40
47
  },
41
48
 
42
49
  pop_and_set_as!: ->(api, state, variable) {
43
- api.lua_pushstring(state, variable)
44
- api.lua_insert(state, -2)
45
- api.lua_settable(state, Logic::V51::Interpreter[:LUA_GLOBALSINDEX])
50
+ api.lua_pushstring(state[:lua], variable)
51
+ api.lua_insert(state[:lua], -2)
52
+ api.lua_settable(state[:lua], Logic::V51::Interpreter[:LUA_GLOBALSINDEX])
46
53
  { state: state }
47
54
  },
48
55
 
49
56
  get_variable_and_push!: ->(api, state, variable, key = nil) {
50
- api.lua_pushstring(state, variable.to_s)
51
- api.lua_gettable(state, Logic::V51::Interpreter[:LUA_GLOBALSINDEX])
57
+ api.lua_pushstring(state[:lua], variable.to_s)
58
+ api.lua_gettable(state[:lua], Logic::V51::Interpreter[:LUA_GLOBALSINDEX])
52
59
 
53
60
  unless key.nil?
54
- if api.lua_typename(state, api.lua_type(state, -1)).read_string == 'table'
55
- Table[:read_field!].(api, state, key, -1)
61
+ if api.lua_typename(state[:lua],
62
+ api.lua_type(state[:lua], -1)).read_string == 'table'
63
+ Table[:read_field!].(api, state, Component::V51, key, -1)
56
64
  else
57
- api.lua_pushnil(state)
65
+ api.lua_pushnil(state[:lua])
58
66
  end
59
67
  end
60
68
 
61
- { state: state }
69
+ { state: state, extra_pop: true }
62
70
  },
63
71
 
64
72
  call!: ->(api, state, inputs = 0, outputs = 1) {
65
- result = api.lua_pcall(state, inputs, outputs, 0)
73
+ result = api.lua_pcall(state[:lua], inputs, outputs, 0)
66
74
  { state: state, error: Interpreter[:_error].(api, state, result, pull: true) }
67
75
  },
68
76
 
69
77
  read_and_pop!: ->(api, state, stack_index = -1, extra_pop: false) {
70
- result = Component::V51::Reader[:read!].(api, state, stack_index)
78
+ result = Reader[:read!].(api, state, Component::V51, stack_index)
71
79
 
72
- api.lua_settop(state, -2) if result[:pop]
73
- api.lua_settop(state, -2) if extra_pop
80
+ api.lua_settop(state[:lua], -2) if result[:pop]
81
+ api.lua_settop(state[:lua], -2) if extra_pop
74
82
 
75
83
  { state: state, output: result[:value] }
76
84
  },
77
85
 
78
86
  read_all!: ->(api, state) {
79
- result = Reader[:read_all!].(api, state)
87
+ result = Reader[:read_all!].(api, state, Component::V51)
80
88
 
81
89
  { state: state, output: result }
82
90
  },
83
91
 
84
92
  destroy_state!: ->(api, state) {
85
- result = api.lua_close(state)
93
+ result = api.lua_close(state[:lua])
94
+
95
+ state.delete(:lua)
96
+ state.delete(:avoid_gc)
86
97
 
87
- { state: nil, error: Interpreter[:_error].(api, state, result) }
98
+ { state: nil, error: Interpreter[:_error].(api, nil, result) }
88
99
  },
89
100
 
90
101
  _error: ->(api, state, code, options = {}) {
@@ -93,7 +104,7 @@ module Component
93
104
  ] || :error
94
105
 
95
106
  if code.is_a?(Numeric) && code >= 2
96
- return { status: status } unless options[:pull]
107
+ return { status: status } unless options[:pull] && state
97
108
 
98
109
  { status: status,
99
110
  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 V51
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
@@ -1,60 +1,7 @@
1
- require_relative '../../../logic/tables'
2
-
3
- require_relative 'writer'
4
- require_relative 'reader'
1
+ require_relative '../54/table'
5
2
 
6
3
  module Component
7
4
  module V51
8
- Table = {
9
- push!: ->(api, state, list, stack_index = -1) {
10
- stack_index = api.lua_gettop(state) if stack_index == -1
11
-
12
- api.lua_createtable(state, list.size, 0)
13
-
14
- if list.is_a? Hash
15
- list.each_key do |key|
16
- Writer[:push!].(api, state, key)
17
- Writer[:push!].(api, state, list[key])
18
- api.lua_settable(state, stack_index + 1)
19
- end
20
- else
21
- list.each_with_index do |value, index|
22
- Writer[:push!].(api, state, index + 1)
23
- Writer[:push!].(api, state, value)
24
- api.lua_settable(state, stack_index + 1)
25
- end
26
- end
27
- },
28
-
29
- read!: ->(api, state, stack_index) {
30
- stack_index = api.lua_gettop(state) if stack_index == -1
31
-
32
- type = api.lua_typename(state, api.lua_type(state, stack_index)).read_string
33
-
34
- api.lua_pushnil(state)
35
-
36
- return nil if type != 'table'
37
-
38
- tuples = []
39
-
40
- while api.lua_next(state, stack_index).positive?
41
- value = Reader[:read!].(api, state, stack_index + 2)
42
- key = Reader[:read!].(api, state, stack_index + 1)
43
- api.lua_settop(state, -2) if value[:pop]
44
-
45
- tuples << [key[:value], value[:value]]
46
-
47
- break if value[:type] == 'no value'
48
- end
49
-
50
- { value: Logic::Tables[:to_hash_or_array].(tuples), pop: true }
51
- },
52
-
53
- read_field!: ->(api, state, expected_key, stack_index) {
54
- expected_key = expected_key.to_s if expected_key.is_a? Symbol
55
-
56
- api.lua_getfield(state, stack_index, expected_key)
57
- }
58
- }
5
+ Table = Component::V54::Table
59
6
  end
60
7
  end
@@ -1,45 +1,7 @@
1
- require_relative 'function'
2
- require_relative 'table'
1
+ require_relative '../54/writer'
3
2
 
4
3
  module Component
5
4
  module V51
6
- Writer = {
7
- push!: ->(api, state, value) {
8
- case Writer[:_to_lua_type].(value)
9
- when 'string'
10
- api.lua_pushstring(state, value.to_s)
11
- when 'number'
12
- api.lua_pushnumber(state, value)
13
- when 'integer'
14
- if api.respond_to? :lua_pushinteger
15
- api.lua_pushinteger(state, value)
16
- else
17
- api.lua_pushnumber(state, value)
18
- end
19
- when 'nil'
20
- api.lua_pushnil(state)
21
- when 'boolean'
22
- api.lua_pushboolean(state, value ? 1 : 0)
23
- when 'table'
24
- Table[:push!].(api, state, value)
25
- when 'function'
26
- Function[:push!].(api, state, value)
27
- else
28
- api.lua_pushstring(
29
- state, "#<#{value.class}:0x#{format('%016x', value.object_id)}>"
30
- )
31
- end
32
- },
33
-
34
- _to_lua_type: ->(value) {
35
- return 'nil' if value.nil?
36
- return 'function' if value.is_a?(Proc)
37
- return 'integer' if value.is_a? Integer
38
- return 'number' if value.is_a? Float
39
- return 'table' if value.is_a?(Hash) || value.is_a?(Array)
40
- return 'string' if value.is_a?(String) || value.instance_of?(Symbol)
41
- return 'boolean' if [true, false].include? value
42
- }
43
- }
5
+ Writer = Component::V54::Writer
44
6
  end
45
7
  end
@@ -1,52 +1,111 @@
1
1
  require_relative '../../../logic/interpreters/interpreter_54'
2
2
  require_relative '../../../dsl/errors'
3
3
 
4
- require_relative 'writer'
4
+ require_relative 'interpreter'
5
5
  require_relative 'reader'
6
+ require_relative 'writer'
6
7
 
7
8
  module Component
8
9
  module V54
9
10
  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)
11
+ push!: ->(api, state, component, closure) {
12
+ handler = component::Function[:build_handler!].(
13
+ api, state, component, closure
14
+ )
15
+
16
+ state[:avoid_gc] << handler
17
+
18
+ lua_name = "_sweet_moon_ruby_#{handler.object_id}"
19
+
20
+ api.lua_pushcclosure(state[:lua], handler, 0)
21
+ component::Interpreter[:pop_and_set_as!].(api, state, lua_name)
22
+
23
+ result = component::Interpreter[:push_chunk!].(
24
+ api, state, component::LUA_HANDLER.sub('_ruby', lua_name)
25
+ )
26
+
27
+ unless result[:error].nil?
28
+ raise SweetMoon::Errors::SweetMoonErrorHelper.for(
29
+ result[:error][:status]
30
+ ), result[:error][:value]
31
+ end
32
+
33
+ component::Interpreter[:call!].(api, state, 0, 1)
34
+ },
35
+
36
+ build_handler!: ->(api, state, component, closure) {
37
+ ->(current_state) {
38
+ updated_state = state.merge(lua: current_state)
39
+ input = component::Reader[:read_all!].(api, updated_state, component)
40
+ begin
41
+ result = closure.(*input)
42
+ component::Writer[:push!].(
43
+ api, updated_state, component, { error: nil, output: result }
44
+ )
45
+ rescue Exception => e
46
+ state[:ruby_error_info] = e
47
+ component::Writer[:push!].(
48
+ api, updated_state, component, {
49
+ error: true, output: "#{e.class}: #{e.message}"
50
+ }
51
+ )
52
+ end
15
53
  return 1
16
54
  }
17
-
18
- api.lua_pushcclosure(state, handler, 0)
19
55
  },
20
56
 
21
- read!: ->(api, state, _stack_index) {
22
- reference = api.luaL_ref(
23
- state, Logic::V54::Interpreter[:LUA_REGISTRYINDEX]
24
- )
57
+ read!: ->(api, state, component, _stack_index) {
58
+ lua_registry_index = component::Interpreter[:logic]::Interpreter[
59
+ :LUA_REGISTRYINDEX
60
+ ]
61
+
62
+ reference = api.luaL_ref(state[:lua], lua_registry_index)
25
63
 
26
64
  { value: ->(input = [], output = 1) {
27
- api.lua_rawgeti(
28
- state, Logic::V54::Interpreter[:LUA_REGISTRYINDEX], reference
29
- )
65
+ api.lua_rawgeti(state[:lua], lua_registry_index, reference)
30
66
 
31
67
  input.each do |value|
32
- Writer[:push!].(api, state, value)
68
+ component::Writer[:push!].(api, state, component, value)
33
69
  end
34
70
 
35
- result = Interpreter[:call!].(api, state, input.size, output)
71
+ result = component::Interpreter[:call!].(api, state, input.size, output)
36
72
 
37
- if result[:error]
38
- raise SweetMoon::Errors::SweetMoonErrorHelper.for(
39
- result[:error][:status]
40
- ), result[:error][:value]
41
- end
73
+ component::Function[:raise_error!].(state, result) if result[:error]
42
74
 
43
- result = Reader[:read_all!].(api, state)
75
+ result = component::Reader[:read_all!].(api, state, component)
44
76
 
45
77
  return result.first if output == 1
46
78
 
47
79
  result
48
80
  }, pop: false }
81
+ },
82
+
83
+ raise_error!: ->(state, result) {
84
+ if state[:ruby_error_info].nil?
85
+ raise SweetMoon::Errors::SweetMoonErrorHelper.for(
86
+ result[:error][:status]
87
+ ), result[:error][:value]
88
+ else
89
+ ruby_error = state[:ruby_error_info]
90
+ state[:ruby_error_info] = nil
91
+
92
+ raise SweetMoon::Errors::SweetMoonErrorHelper.merge_traceback!(
93
+ ruby_error, result[:error][:value]
94
+ )
95
+ end
49
96
  }
50
97
  }
98
+
99
+ LUA_HANDLER = <<LUA
100
+ return function (...)
101
+ result = _ruby(...)
102
+
103
+ if result['error'] then
104
+ error(result['output'] .. ' ' .. debug.traceback())
105
+ else
106
+ return result['output']
107
+ end
108
+ end
109
+ LUA
51
110
  end
52
111
  end