summaryrefslogtreecommitdiff
path: root/tex/context/base/pret-lua.lua
blob: 8803971f3eb93c82712196178a8262429a096482 (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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
if not modules then modules = { } end modules ['pret-lua'] = {
    version   = 1.001,
    comment   = "companion to buff-ver.mkiv",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

-- this is not a real parser as we also want to typeset wrong output
-- and a real parser would choke on that

local utf = unicode.utf8

local utfcharacters, utfvalues = string.utfcharacters, string.utfvalues
local utfbyte, utffind = utf.byte, utf.find
local byte, sub, find, match = string.byte, string.sub, string.find, string.match
local texsprint, texwrite = tex.sprint, tex.write
local ctxcatcodes = tex.ctxcatcodes

local visualizer = buffers.newvisualizer("lua")

visualizer.identifiers = { }

-- borrowed from scite
--
-- depricated:
--
-- gcinfo unpack getfenv setfenv loadlib
-- table.maxn table.getn table.setn
-- math.log10 math.mod math.modf math.fmod

visualizer.identifiers.core = {
    "and", "break", "do", "else", "elseif", "end", "false", "for", "function",
    "if", "in", "local", "nil", "not", "or", "repeat", "return", "then",
    "true", "until", "while"
}

visualizer.identifiers.base = {
    "assert", "collectgarbage", "dofile", "error", "loadfile",
    "loadstring", "print", "rawget", "rawset", "require", "tonumber",
    "tostring", "type",
}

visualizer.identifiers.five = {
    "_G", "getmetatable", "ipairs", "next", "pairs",
    "pcall", "rawequal", "setmetatable", "xpcall", "string", "table",
    "math", "coroutine", "io", "os", "debug", "load", "module", "select",
}

visualizer.identifiers.libs = {
    -- coroutine
    "coroutine.create", "coroutine.resume", "coroutine.status", "coroutine.wrap",
    "coroutine.yield", "coroutine.running",
    -- package
    "package.cpath", "package.loaded", "package.loadlib", "package.path", "package.config",
    -- io
    "io.close", "io.flush", "io.input", "io.lines", "io.open", "io.output",
    "io.read", "io.tmpfile", "io.type", "io.write", "io.stdin", "io.stdout",
    "io.stderr", "io.popen",
    -- math
    "math.abs", "math.acos", "math.asin", "math.atan", "math.atan2", "math.ceil",
    "math.cos", "math.deg", "math.exp", "math.floor math.", "math.ldexp",
    "math.log", "math.max", "math.min", "math.pi", "math.pow",
    "math.rad", "math.random", "math.randomseed", "math.sin", "math.sqrt",
    "math.tan", "math.cosh", "math.sinh", "math.tanh",
    "math.huge",
    -- string
    "string.byte", "string.char", "string.dump", "string.find", "string.len",
    "string.lower", "string.rep", "string.sub", "string.upper", "string.format",
    "string.gfind", "string.gsub", "string.gmatch", "string.match", "string.reverse",
    -- table
    "table.concat", "table.foreach", "table.foreachi",
    "table.sort", "table.insert", "table.remove",
    "table.pack", "table.unpack",
    -- os
    "os.clock", "os.date", "os.difftime", "os.execute", "os.exit", "os.getenv",
    "os.remove", "os.rename", "os.setlocale", "os.time", "os.tmpname",
    -- package
    "package.preload", "package.seeall",
    -- bit
    -- ... todo ...
}

local known_words = { }

for k,v in next, visualizer.identifiers do
    for _,w in next, v do
        known_words[w] = k
    end
end

visualizer.styles = {
    core = "",
    base = "\\sl ",
    five = "\\sl ",
    libs = "\\sl ",
}

local styles = visualizer.styles

local colors = {
    "prettyone",
    "prettytwo",
    "prettythree",
    "prettyfour",
}

local states = {
    ['"']=1, ["'"]=1, ["[["] = 1, ["]]"] = 1,
    ['+']=1, ['-']=1, ['*']=1, ['/']=1, ['%']=1, ['^']=1,
    ["("] = 3, [")"] = 3, ["["] = 3, ["]"] = 3,
    ['--']=4,
}

local change_state, finish_state = buffers.change_state, buffers.finish_state

local function flush_lua_word(state, word)
    if word then
        local id = known_words[word]
        if id then
            state = change_state(2,state)
            if styles[id] then
                texsprint(ctxcatcodes,styles[id])
            end
            texwrite(word)
            state = finish_state(state)
        else
            state = finish_state(state) -- ?
            texwrite(word)
        end
    else
        state = finish_state(state)
    end
    return state
end

local incomment, inlongstring = false, false

function visualizer.reset()
    incomment, inlongstring = false, false -- needs to be hooked into flusher
end

-- we will also provide a proper parser based pretty printer although normaly
-- a pretty printer should handle faulty code too (educational purposes)

local function written(state,c,i)
    if c == " " then
        state = finish_state(state)
        texsprint(ctxcatcodes,"\\obs")
    elseif c == "\t" then
        state = finish_state(state)
        texsprint(ctxcatcodes,"\\obs")
        if buffers.visualizers.enabletab then
            texsprint(ctxcatcodes,rep("\\obs ",i%buffers.visualizers.tablength))
        end
    else
        texwrite(c)
    end
    return state, 0
end

function visualizer.flush_line(str, nested)
    local state, instr, inesc, word = 0, false, false, nil
    buffers.currentcolors = colors
    local code, comment = match(str,"^(.-)%-%-%[%[(.*)$")
    if comment then
        -- process the code and then flush the comment
    elseif incomment then
        comment, code = match(str,"^(.-)%]%](.*)$")
        if comment then
            -- flush the comment and then process the code
            for c in utfcharacters(comment) do
                if c == " " then texsprint(ctxcatcodes,"\\obs") else texwrite(c) end
            end
            state = change_state(states['--'], state)
            texwrite("]]")
            state = finish_state(state)
            incomment = false
        else
            for c in utfcharacters(str) do
                if c == " " then texsprint(ctxcatcodes,"\\obs") else texwrite(c) end
            end
        end
        comment = nil
    else
        code = str
    end
    if code and code ~= "" then
        local pre, post = match(code,"^(.-)%-%-(.*)$")
        if pre then
            code = pre
        end
        local p, s, i = nil, nil, 0
        for c in utfcharacters(code) do
            i = i + 1
            if instr then
                if p then
                    texwrite(p)
                    p = nil
                end
                if c == s then
                    if inesc then
                        texwrite(c)
                        inesc = false
                    else
                        state = change_state(states[c],state)
                        instr = false
                        texwrite(c)
                        state = finish_state(state)
                    end
                    s = nil
                else
                    if c == "\\" then
                        inesc = not inesc
                    else
                        inesc = false
                    end
                    state, i = written(state,c,i)
                end
            elseif c == "[" then
                if word then
                    texwrite(word)
                    word = nil
                end
                if p == "[" then
                    inlongstring = true
                    state = change_state(states["[["],state)
                    texwrite(p,c)
                    state = finish_state(state)
                    p = nil
                else
                    if p then
                        state, i = written(state,p,i)
                    end
                    p = c
                end
            elseif c == "]" then
                if word then
                    texwrite(word)
                    word = nil
                end
                if p == "]" then
                    inlongstring = false
                    state = change_state(states["]]"],state)
                    texwrite(p,c)
                    state = finish_state(state)
                    p = nil
                else
                    if p then
                        state, i = written(state,p,i)
                    end
                    p = c
                end
            else
                if p then
                    state = change_state(states[p],state)
                    texwrite(p)
                    state = finish_state(state)
                    p = nil
                end
                if c == " " or c == "\t" then
                    if word then
                        state = flush_lua_word(state,word)
                        word = nil
                    end
                    state, i = written(state,c,i)
                elseif inlongstring then
                    state, i = written(state,c,i)
                elseif c == '"' or c == "'" then
if word then
    state = flush_lua_word(state,word)
    word = nil
end
                    instr = true
                    state = change_state(states[c],state)
                    state, i = written(state,c,i)
                    state = finish_state(state)
                    s = c
                elseif find(c,"^[%a]$") then
                    state = finish_state(state)
                    if word then word = word .. c else word = c end
                elseif word and (#word > 1) and find(c,"^[%d%.%_]$") then
                    if word then word = word .. c else word = c end
                else
                    state = flush_lua_word(state,word)
                    word = nil
                    state = change_state(states[c],state)
                    texwrite(c)
                    instr = (c == '"')
                end
            end
        end
        if p then
            texwrite(p)
            -- state, i = written(state,p,i)
            p = nil
        end
        state = flush_lua_word(state,word)
        if post then
            state = change_state(states['--'], state)
            texwrite("--")
            state = finish_state(state)
            for c in utfcharacters(post) do
                state, i = written(state,c,i)
            end
        end
    end
    if comment then
        incomment = true
        state = change_state(states['--'], state)
        texwrite("[[")
        state = finish_state(state)
     -- texwrite(comment) -- maybe also split and
        for c in utfcharacters(comment) do
            state, i = written(state,c,i)
        end
    end
    state = finish_state(state)
end