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.
@@ -1,55 +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
- 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
- }
11
+ push!: ->(api, state, component, closure) {
12
+ handler = component::Function[:build_handler!].(
13
+ api, state, component, closure
14
+ )
18
15
 
19
16
  state[:avoid_gc] << handler
20
17
 
18
+ lua_name = "_sweet_moon_ruby_#{handler.object_id}"
19
+
21
20
  api.lua_pushcclosure(state[:lua], handler, 0)
22
- },
21
+ component::Interpreter[:pop_and_set_as!].(api, state, lua_name)
23
22
 
24
- read!: ->(api, state, _stack_index) {
25
- reference = api.luaL_ref(
26
- state[:lua], Logic::V54::Interpreter[:LUA_REGISTRYINDEX]
23
+ result = component::Interpreter[:push_chunk!].(
24
+ api, state, component::LUA_HANDLER.sub('_ruby', lua_name)
27
25
  )
28
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
53
+ return 1
54
+ }
55
+ },
56
+
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)
63
+
29
64
  { value: ->(input = [], output = 1) {
30
- api.lua_rawgeti(
31
- state[:lua], Logic::V54::Interpreter[:LUA_REGISTRYINDEX], reference
32
- )
65
+ api.lua_rawgeti(state[:lua], lua_registry_index, reference)
33
66
 
34
67
  input.each do |value|
35
- Writer[:push!].(api, state, value)
68
+ component::Writer[:push!].(api, state, component, value)
36
69
  end
37
70
 
38
- result = Interpreter[:call!].(api, state, input.size, output)
71
+ result = component::Interpreter[:call!].(api, state, input.size, output)
39
72
 
40
- if result[:error]
41
- raise SweetMoon::Errors::SweetMoonErrorHelper.for(
42
- result[:error][:status]
43
- ), result[:error][:value]
44
- end
73
+ component::Function[:raise_error!].(state, result) if result[:error]
45
74
 
46
- result = Reader[:read_all!].(api, state)
75
+ result = component::Reader[:read_all!].(api, state, component)
47
76
 
48
77
  return result.first if output == 1
49
78
 
50
79
  result
51
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
52
96
  }
53
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
54
110
  end
55
111
  end
@@ -1,17 +1,19 @@
1
1
  require_relative '../../../logic/interpreters/interpreter_54'
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 V54
9
10
  Interpreter = {
10
11
  version: Logic::V54::Interpreter[:version],
12
+ logic: Logic::V54,
11
13
 
12
14
  create_state!: ->(api) {
13
15
  state = api.luaL_newstate
14
- { state: { lua: state, avoid_gc: [] },
16
+ { state: { lua: state, avoid_gc: [], ruby_error_info: nil },
15
17
  error: state ? nil : :MemoryAllocation }
16
18
  },
17
19
 
@@ -30,12 +32,17 @@ module Component
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::V54, value)
39
46
  { state: state }
40
47
  },
41
48
 
@@ -50,13 +57,13 @@ module Component
50
57
  unless key.nil?
51
58
  if api.lua_typename(state[:lua],
52
59
  api.lua_type(state[:lua], -1)).read_string == 'table'
53
- Table[:read_field!].(api, state, key, -1)
60
+ Table[:read_field!].(api, state, Component::V54, key, -1)
54
61
  else
55
62
  api.lua_pushnil(state[:lua])
56
63
  end
57
64
  end
58
65
 
59
- { state: state }
66
+ { state: state, extra_pop: true }
60
67
  },
61
68
 
62
69
  call!: ->(api, state, inputs = 0, outputs = 1) {
@@ -65,7 +72,8 @@ module Component
65
72
  },
66
73
 
67
74
  read_and_pop!: ->(api, state, stack_index = -1, extra_pop: false) {
68
- result = Component::V54::Reader[:read!].(api, state, stack_index)
75
+ result = Component::V54::Reader[:read!].(api, state, Component::V54,
76
+ stack_index)
69
77
 
70
78
  api.lua_settop(state[:lua], -2) if result[:pop]
71
79
  api.lua_settop(state[:lua], -2) if extra_pop
@@ -74,7 +82,7 @@ module Component
74
82
  },
75
83
 
76
84
  read_all!: ->(api, state) {
77
- result = Reader[:read_all!].(api, state)
85
+ result = Reader[:read_all!].(api, state, Component::V54)
78
86
 
79
87
  { state: state, output: result }
80
88
  },
@@ -7,33 +7,34 @@ require_relative 'table'
7
7
  module Component
8
8
  module V54
9
9
  Reader = {
10
- read_all!: ->(api, state) {
10
+ read_all!: ->(api, state, component) {
11
11
  (1..api.lua_gettop(state[:lua])).map do
12
- Interpreter[:read_and_pop!].(api, state)[:output]
12
+ component::Interpreter[:read_and_pop!].(api, state)[:output]
13
13
  end.reverse
14
14
  },
15
15
 
16
- read!: ->(api, state, stack_index = -1) {
16
+ read!: ->(api, state, component, stack_index = -1) {
17
17
  stack_index = api.lua_gettop(state[:lua]) if stack_index == -1
18
18
 
19
- type = api.lua_typename(state[:lua],
20
- api.lua_type(state[:lua], stack_index)).read_string
19
+ type = api.lua_typename(
20
+ state[:lua], api.lua_type(state[:lua], stack_index)
21
+ ).read_string
21
22
 
22
23
  case type
23
24
  when 'string'
24
- Reader[:read_string!].(api, state, stack_index)
25
+ component::Reader[:read_string!].(api, state, stack_index)
25
26
  when 'number'
26
- Reader[:read_number!].(api, state, stack_index)
27
+ component::Reader[:read_number!].(api, state, stack_index)
27
28
  when 'no value'
28
29
  { value: nil, pop: true, type: type }
29
30
  when 'nil'
30
31
  { value: nil, pop: true }
31
32
  when 'boolean'
32
- Reader[:read_boolean!].(api, state, stack_index)
33
+ component::Reader[:read_boolean!].(api, state, stack_index)
33
34
  when 'table'
34
- Table[:read!].(api, state, stack_index)
35
+ component::Table[:read!].(api, state, component, stack_index)
35
36
  when 'function'
36
- Function[:read!].(api, state, stack_index)
37
+ component::Function[:read!].(api, state, component, stack_index)
37
38
  else
38
39
  # none nil boolean lightuserdata number
39
40
  # string table function userdata thread
@@ -6,31 +6,36 @@ require_relative 'reader'
6
6
  module Component
7
7
  module V54
8
8
  Table = {
9
- push!: ->(api, state, list, stack_index = -1) {
9
+ create_table!: ->(api, state, list) {
10
+ api.lua_createtable(state[:lua], list.size, 0)
11
+ },
12
+
13
+ push!: ->(api, state, component, list, stack_index = -1) {
10
14
  stack_index = api.lua_gettop(state[:lua]) if stack_index == -1
11
15
 
12
- api.lua_createtable(state[:lua], list.size, 0)
16
+ component::Table[:create_table!].(api, state, list)
13
17
 
14
18
  if list.is_a? Hash
15
19
  list.each_key do |key|
16
- Writer[:push!].(api, state, key)
17
- Writer[:push!].(api, state, list[key])
20
+ component::Writer[:push!].(api, state, component, key)
21
+ component::Writer[:push!].(api, state, component, list[key])
18
22
  api.lua_settable(state[:lua], stack_index + 1)
19
23
  end
20
24
  else
21
25
  list.each_with_index do |value, index|
22
- Writer[:push!].(api, state, index + 1)
23
- Writer[:push!].(api, state, value)
26
+ component::Writer[:push!].(api, state, component, index + 1)
27
+ component::Writer[:push!].(api, state, component, value)
24
28
  api.lua_settable(state[:lua], stack_index + 1)
25
29
  end
26
30
  end
27
31
  },
28
32
 
29
- read!: ->(api, state, stack_index) {
33
+ read!: ->(api, state, component, stack_index) {
30
34
  stack_index = api.lua_gettop(state[:lua]) if stack_index == -1
31
35
 
32
- type = api.lua_typename(state[:lua],
33
- api.lua_type(state[:lua], stack_index)).read_string
36
+ type = api.lua_typename(
37
+ state[:lua], api.lua_type(state[:lua], stack_index)
38
+ ).read_string
34
39
 
35
40
  api.lua_pushnil(state[:lua])
36
41
 
@@ -39,8 +44,8 @@ module Component
39
44
  tuples = []
40
45
 
41
46
  while api.lua_next(state[:lua], stack_index).positive?
42
- value = Reader[:read!].(api, state, stack_index + 2)
43
- key = Reader[:read!].(api, state, stack_index + 1)
47
+ value = component::Reader[:read!].(api, state, component, stack_index + 2)
48
+ key = component::Reader[:read!].(api, state, component, stack_index + 1)
44
49
  api.lua_settop(state[:lua], -2) if value[:pop]
45
50
 
46
51
  tuples << [key[:value], value[:value]]
@@ -51,7 +56,7 @@ module Component
51
56
  { value: Logic::Tables[:to_hash_or_array].(tuples), pop: true }
52
57
  },
53
58
 
54
- read_field!: ->(api, state, expected_key, stack_index) {
59
+ read_field!: ->(api, state, _component, expected_key, stack_index) {
55
60
  expected_key = expected_key.to_s if expected_key.is_a? Symbol
56
61
 
57
62
  api.lua_getfield(state[:lua], stack_index, expected_key)
@@ -4,8 +4,8 @@ require_relative 'table'
4
4
  module Component
5
5
  module V54
6
6
  Writer = {
7
- push!: ->(api, state, value) {
8
- case Writer[:_to_lua_type].(value)
7
+ push!: ->(api, state, component, value) {
8
+ case component::Writer[:_to_lua_type].(value)
9
9
  when 'string'
10
10
  api.lua_pushstring(state[:lua], value.to_s)
11
11
  when 'number'
@@ -21,9 +21,9 @@ module Component
21
21
  when 'boolean'
22
22
  api.lua_pushboolean(state[:lua], value ? 1 : 0)
23
23
  when 'table'
24
- Table[:push!].(api, state, value)
24
+ component::Table[:push!].(api, state, component, value)
25
25
  when 'function'
26
- Function[:push!].(api, state, value)
26
+ component::Function[:push!].(api, state, component, value)
27
27
  else
28
28
  api.lua_pushstring(
29
29
  state[:lua], "#<#{value.class}:0x#{format('%016x', value.object_id)}>"
@@ -1,41 +1,44 @@
1
1
  # Available at https://github.com/gbaptista/sweet-moon-test
2
2
 
3
+ fennel-dev: '/home/me/sweet-moon-test/fennel/dev/?.lua'
4
+
3
5
  luarocks:
6
+ expected: ['dkjson', 'supernova', 'readline']
4
7
  path:
5
8
  - /home/me/.luarocks/share/lua/5.4/?.lua
6
9
  - /home/me/.luarocks/share/lua/5.4/?/init.lua
10
+ cpath:
7
11
  - /home/me/.luarocks/lib/lua/5.4/?.so
8
- expected: ['supernova', 'dkjson', 'lfs']
9
12
 
10
13
  jit:2.0.5:
11
14
  description: 'Lua Jit 2.0.5 + Fennel 1.0.0'
12
15
  shared_object: /home/me/sweet-moon-test/libluajit.so.2.0.5
13
- fennel: /home/me/sweet-moon-test/fennel-100.lua
16
+ fennel: /home/me/sweet-moon-test/fennel/100/?.lua
14
17
 
15
18
  5.4.4:
16
19
  description: 'Lua 5.4.4 + Fennel 1.0.0'
17
20
  shared_object: /home/me/sweet-moon-test/liblua.so.5.4.4
18
- fennel: /home/me/sweet-moon-test/fennel-100.lua
21
+ fennel: /home/me/sweet-moon-test/fennel/100/?.lua
19
22
 
20
23
  5.4.2:
21
24
  description: 'Lua 5.4.2 + Fennel 1.0.0'
22
25
  shared_object: /home/me/sweet-moon-test/liblua.so.5.4.2
23
- fennel: /home/me/sweet-moon-test/fennel-100.lua
26
+ fennel: /home/me/sweet-moon-test/fennel/100/?.lua
24
27
 
25
28
  5.3.3:
26
29
  description: 'Lua 5.3.3'
27
30
  shared_object: /home/me/sweet-moon-test/liblua.so.5.3.3
28
- fennel: /home/me/sweet-moon-test/fennel-100.lua
31
+ fennel: /home/me/sweet-moon-test/fennel/100/?.lua
29
32
 
30
33
  5.2.4:
31
34
  description: 'Lua 5.2.4'
32
35
  shared_object: /home/me/sweet-moon-test/liblua.so.5.2.4
33
- fennel: /home/me/sweet-moon-test/fennel-100.lua
36
+ fennel: /home/me/sweet-moon-test/fennel/100/?.lua
34
37
 
35
38
  5.1.5:
36
39
  description: 'Lua 5.1.5'
37
40
  shared_object: /home/me/sweet-moon-test/liblua.so.5.1.5
38
- fennel: /home/me/sweet-moon-test/fennel-100.lua
41
+ fennel: /home/me/sweet-moon-test/fennel/100/?.lua
39
42
 
40
43
  5.0.3:
41
44
  description: 'Lua 5.0.3'
data/controllers/api.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require_relative '../components/injections'
2
2
  require_relative '../components/api'
3
+ require_relative '../components/default'
3
4
  require_relative '../components/io'
4
5
  require_relative '../dsl/errors'
5
6
 
@@ -11,7 +12,9 @@ module Controller
11
12
  handle!: ->(options) {
12
13
  shared_objects = API[:elect_shared_objects!].(options[:shared_objects])
13
14
 
14
- api = Component::API[:open!].(shared_objects)
15
+ api = Component::API[:open!].(
16
+ shared_objects, options, Component::Default.instance.options
17
+ )
15
18
 
16
19
  api_reference = API[:elect_api_reference!].(
17
20
  api.ffi_libraries, options[:api_reference]
data/controllers/state.rb CHANGED
@@ -26,23 +26,48 @@ module Controller
26
26
  },
27
27
 
28
28
  get!: ->(api, interpreter, state, variable, key = nil) {
29
+ if key.nil?
30
+ key = variable
31
+ variable = '_G'
32
+ end
33
+
34
+ State[:_get_key!].(api, interpreter, state, variable, key)
35
+ },
36
+
37
+ _get_key!: ->(api, interpreter, state, variable, key) {
29
38
  result = State[:_check!].(
30
39
  interpreter[:get_variable_and_push!].(api, state, variable, key)
31
40
  )
32
41
 
33
- result = State[:_check!].(interpreter[:read_and_pop!].(
34
- api, result[:state], -1, extra_pop: !key.nil?
35
- ))
42
+ result = State[:_check!].(
43
+ interpreter[:read_and_pop!].(
44
+ api, result[:state], -1, extra_pop: result[:extra_pop]
45
+ )
46
+ )
36
47
 
37
48
  { state: result[:state], output: result[:output] }
38
49
  },
39
50
 
40
- set!: ->(api, interpreter, state, variable, value) {
41
- result = State[:_check!].(interpreter[:push_value!].(api, state, value))
42
-
43
- result = State[:_check!].(
44
- interpreter[:pop_and_set_as!].(api, result[:state], variable.to_s)
45
- )
51
+ set!: ->(api, interpreter, state, variable, key_or_value, value = nil) {
52
+ if value.nil?
53
+ result = State[:_check!].(interpreter[:push_value!].(api, state,
54
+ key_or_value))
55
+
56
+ result = State[:_check!].(
57
+ interpreter[:pop_and_set_as!].(api, result[:state], variable.to_s)
58
+ )
59
+ else
60
+ result = State[:_check!].(
61
+ interpreter[:get_variable_and_push!].(api, state, variable)
62
+ )
63
+
64
+ result = State[:_check!].(interpreter[:push_value!].(api, result[:state],
65
+ key_or_value))
66
+ result = State[:_check!].(interpreter[:push_value!].(api, result[:state],
67
+ value))
68
+
69
+ result = State[:_check!].(interpreter[:set_table!].(api, result[:state]))
70
+ end
46
71
 
47
72
  { state: result[:state], output: result[:output] }
48
73
  },
@@ -62,10 +87,20 @@ module Controller
62
87
  },
63
88
 
64
89
  _check!: ->(result) {
90
+ ruby_error = result[:state] && result[:state][:ruby_error_info]
91
+
92
+ result[:state][:ruby_error_info] = nil if ruby_error
93
+
65
94
  if result[:error]
66
- raise SweetMoon::Errors::SweetMoonErrorHelper.for(
67
- result[:error][:status]
68
- ), result[:error][:value]
95
+ if ruby_error
96
+ raise SweetMoon::Errors::SweetMoonErrorHelper.merge_traceback!(
97
+ ruby_error, result[:error][:value]
98
+ )
99
+ else
100
+ raise SweetMoon::Errors::SweetMoonErrorHelper.for(
101
+ result[:error][:status]
102
+ ), result[:error][:value]
103
+ end
69
104
  end
70
105
 
71
106
  result
data/dsl/api.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require_relative '../components/default'
2
+
1
3
  module DSL
2
4
  class Api
3
5
  attr_reader :functions, :meta
@@ -7,13 +9,31 @@ module DSL
7
9
 
8
10
  @functions = @component[:signatures].keys
9
11
 
10
- @meta = Struct.new(
11
- *@component[:meta][:elected].keys
12
- ).new(*@component[:meta][:elected].values)
12
+ build_meta
13
13
 
14
14
  extend @component[:api]
15
15
  end
16
16
 
17
+ def build_global_ffi
18
+ global_ffi = Component::Default.instance.options[:global_ffi]
19
+
20
+ unless @component[:meta][:options][:global_ffi].nil?
21
+ global_ffi = @component[:meta][:options][:global_ffi]
22
+ end
23
+
24
+ global_ffi
25
+ end
26
+
27
+ def build_meta
28
+ meta_data = @component[:meta][:elected].clone
29
+
30
+ meta_data[:global_ffi] = build_global_ffi
31
+
32
+ @meta = Struct.new(
33
+ *meta_data.keys
34
+ ).new(*meta_data.values)
35
+ end
36
+
17
37
  def signature_for(function)
18
38
  @component[:signatures][function.to_sym]
19
39
  end