summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/luat-usr.lua
blob: 071e3bf5bb988fa83c8232b83ca4d28203d94a5c (plain)
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
if not modules then modules = { } end modules ['luat-usr'] = {
    version   = 1.001,
    comment   = "companion to luat-lib.mkiv",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

local global            = global

local moduledata        = moduledata
local thirddata         = thirddata
local userdata          = userdata
local documentdata      = documentdata

local context           = context
local tostring          = tostring
local tonumber          = tonumber
local print             = print

local string            = string
local table             = table
local lpeg              = lpeg
local math              = math
local io                = io
local os                = os
local lpeg              = lpeg

local luanames          = lua.name -- luatex itself

local setmetatableindex = table.setmetatableindex
local load              = load
local xpcall            = xpcall
local instance_banner   = string.formatters["=[instance: %s]"] -- the = controls the lua error / see: lobject.c
local tex_errormessage  = context.errmessage

local implement         = interfaces.implement
local reporter          = logs.reporter

local report_instance   = reporter("lua instance")
local report_script     = reporter("lua script")
local report_thread     = reporter("lua thread")
local newline           = logs.newline

lua.numbers             = lua.numbers  or { }
lua.messages            = lua.messages or { }

local numbers           = lua.numbers
local messages          = lua.messages

storage.register("lua/numbers",  numbers,  "lua.numbers" )
storage.register("lua/messages", messages, "lua.messages")

-- First we implement a pure lua version of directlua and a persistent
-- variant of it:

local function runscript(code)
    local done, message = loadstring(code)
    if done then
        done()
    else
        newline()
        report_script("error : %s",message or "unknown")
        report_script()
        report_script("code  : %s",code)
        newline()
    end
end

local threads = setmetatableindex(function(t,k)
    local v = setmetatableindex({},global)
    t[k] = v
    return v
end)

local function runthread(name,code)
    if not code or code == "" then
        threads[name] = nil
    else
        local thread = threads[name]
        local done, message = loadstring(code,nil,nil,thread)
        if done then
            done()
        else
            newline()
            report_thread("thread: %s",name)
            report_thread("error : %s",message or "unknown")
            report_thread()
            report_thread("code  : %s",code)
            newline()
        end
    end
end

interfaces.implement {
    name      = "luascript",
    actions   = runscript,
    arguments = "string"
}

interfaces.implement {
    name      = "luathread",
    actions   = runthread,
    arguments = { "string", "string" }
}

-- local scanners = interfaces.scanners
--
-- local function ctxscanner(name)
--     local scanner = scanners[name]
--     if scanner then
--         scanner()
--     else
--         report("unknown scanner: %s",name)
--     end
-- end
--
-- interfaces.implement {
--     name      = "clfscanner",
--     actions   = ctxscanner,
--     arguments = "string",
-- }

local function registername(name,message)
    if not name or name == "" then
        report_instance("no valid name given")
        return
    end
    if not message or message == "" then
        message = name
    end
    local lnn = numbers[name]
    if not lnn then
        lnn = #messages + 1
        messages[lnn] = message
        numbers[name] = lnn
    end
    luanames[lnn] = instance_banner(message)
    local report = reporter("lua instance",message)
    local proxy = {
        -- we can access all via:
        global       = global, -- or maybe just a metatable
        -- some protected data
        moduledata   = setmetatableindex(moduledata),
        thirddata    = setmetatableindex(thirddata),
        -- less protected data
        userdata     = userdata,
        documentdata = documentdata,
        -- always there fast
        context      = context,
        tostring     = tostring,
        tonumber     = tonumber,
        -- standard lua modules
        string       = string,
        table        = table,
        lpeg         = lpeg,
        math         = math,
        io           = io,
        os           = os,
        lpeg         = lpeg,
        --
        print        = print,
        report       = report,
    }
    return function(code)
        local code, message = load(code,nil,nil,proxy)
        if not code then
            report_instance("error: %s",message or code)
        elseif not xpcall(code,report) then
            tex_errormessage("hit return to continue or quit this run")
        end
    end
end

lua.registername = registername

implement {
    name      = "registernamedlua",
    arguments = { "string", "string", "string" },
    actions   = function(name,message,csname)
        if csname and csname ~= "" then
            implement {
                name      = csname,
                arguments = "string",
                actions   = registername(name,message) or report,
                scope     = "private",
            }
        else
            report_instance("unvalid csname for %a",message or name or "?")
        end
    end
}