1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
package.noompath = './?.moon;./?/init.moon'
export __FNDEF_NOOM_CACHE
__FNDEF_NOOM_CACHE = setmetatable {}, __mode: 'k'
assert MODE == 'SERVER', "duct_tape only works on the server"
compile = require 'moonscript.compile'
parse = require 'moonscript.parse'
import smart_node, build from require 'moonscript.types'
import dirsep from require 'moonscript.base'
import get_options, unpack from require 'moonscript.util'
line_tables = require 'moonscript.line_tables'
lua = :loadstring, :load
local *
escape_str = (str) -> (str\gsub('\\', '\\\\')\gsub '"', '\\"'), nil
deep_clone = (value) ->
if 'table' == type value
{ deep_clone(k), deep_clone(v) for k,v in pairs value }
else -- number, string, boolean, etc
value
transform_fndef = (fndef, parent, i) ->
-- compile the function to Lua separately
code, ltable, pos = compile.tree { deep_clone fndef }
if not code
return compile.format_error(ltable, pos, text)
code = "(function() #{code} end)()"
-- assign the lua code to __FNDEF_NOOM_CACHE[function] so it can be retrieved by `compile`
fn = -> { 'ref', 'fn' }
cache = build.chain {
base: '__FNDEF_NOOM_CACHE',
{ 'index', fn! }
}
parent[i] = build.do {
{ 'declare_with_shadows', { 'fn' } }
build.assign_one fn!, fndef
build.assign_one cache, { 'string', '"', escape_str code }
-- build.assign_one cache, { 'string', '[[', code }
fn!
}
nil
find_fndefs = (node, p, i) ->
if node[1] == "fndef"
transform_fndef node, p, i
else
for i = 1,#node
v = node[i]
find_fndefs v, node, i if 'table' == type v
to_lua = (text, options={}) ->
if "string" != type text
t = type text
return nil, "expecting string (got ".. t ..")"
tree, err = parse.string text
if not tree
return nil, err
find_fndefs tree
code, ltable, pos = compile.tree tree, options
if not code
return nil, compile.format_error(ltable, pos, text)
code, ltable
noom_loader = (name, ...) ->
name_path = name\gsub "%.", dirsep
local file, file_path
for path in package.noompath\gmatch "[^;]+"
file_path = path\gsub "?", name_path
file = io.open file_path
break if file
if file
text = file\read "*a"
file\close!
res, err = loadstring text, "@#{file_path}"
if not res
error file_path .. ": " .. err
return res
return nil, "Could not find noom file"
loadstring = (...) ->
options, str, chunk_name, mode, env = get_options ...
chunk_name or= "=(noom.loadstring)"
code, ltable_or_err = to_lua str, options
unless code
return nil, ltable_or_err
line_tables[chunk_name] = ltable_or_err if chunk_name
-- the unpack prevents us from passing nil
(lua.loadstring or lua.load) code, chunk_name, unpack { mode, env }
do
local compile
insert_loader = (pos=2) ->
-- if not package.moonpath
-- package.moonpath = create_moonpath package.path
loaders = package.loaders or package.searchers
for loader in *loaders
return false if loader == noom_loader
table.insert loaders, pos, noom_loader
true
compile = (fn) -> with code = __FNDEF_NOOM_CACHE[fn]
assert code, 'cannot compile function not loaded from noomscript source.'
{
:insert_loader
:compile
}
|