pret-pas/pret-pas.lua

440 lines
13 KiB
Lua
Raw Normal View History

if not modules then modules = { } end modules ['pret-pas'] = {
version = 1.0,
comment = "custom pretty printer for Pascal code",
author = "Stefan Müller, Chemnitz DE",
copyright = "Stefan Müller",
license = "see context related readme files"
}
2010-10-02 11:53:54 +02:00
-- The code formatting is adapted from Lazarus, a Free Pascal RAD IDE, which
-- should be quite similar to the Delphi style. Please note that comments are
-- not typeset with bold fontface but slanted, which improves output when not
-- using colors.
2010-09-30 14:56:18 +02:00
-- http://lazarus.freepascal.org/
local visualizer = buffers.newvisualizer("pas")
2010-09-30 14:56:18 +02:00
-- The list of reserved words is taken from
-- http://www.freepascal.org/docs-html/ref/refse3.html
visualizer.reservedwords = {
-- Turbo Pascal
"absolute", "and", "array", "asm", "begin", "case", "const", "constructor",
"destructor", "div", "do", "downto", "else", "end", "file", "for",
"function", "goto", "if", "implementation", "in", "inherited", "inline",
"interface", "label", "mod", "nil", "not", "object", "of", "on", "operator",
"or", "packed", "procedure", "program", "record", "reintroduce", "repeat",
"self", "set", "shl", "shr", "string", "then", "to", "type", "unit",
"until", "uses", "var", "while", "with", "xor",
-- Free Pascal
-- these are not bold type (keeping them, just in case)
-- "dispose", "exit", "false", "new", "true",
-- Object Pascal
"as", "class", "dispinterface", "except", "exports", "finalization",
"finally", "initialization", "inline", "is", "library", "on", "out",
"packed", "property", "raise", "resourcestring", "threadvar", "try",
-- Modifiers
2010-09-30 14:56:18 +02:00
-- some of these are only bold in specific places (in the following, this is
-- deliberately ignored)
"absolute", "abstract", "alias", "assembler", "cdecl", "cppdecl", "default",
"export", "external", "far", "far16", "forward", "index", "local", "name",
"near", "nostackframe", "oldfpccall", "override", "pascal", "private",
"protected", "public", "published", "read", "register", "reintroduce",
"safecall", "softfloat", "stdcall", "virtual", "write"
}
local known_words = { }
for k,v in next, visualizer.reservedwords do
known_words[v] = k
end
local colors = {
"prettyone", -- red: compiler directive, symbol
"prettytwo", -- green: assembler (dark green)
"prettythree", -- blue: comment, number (dark blue)
"prettyfour", -- yellow
}
local states = {
['"']=1, ["'"]=1, ["[["] = 1, ["]]"] = 1,
['+']=1, ['-']=1, ['*']=1, ['/']=1, ['%']=1, ['^']=1,
["("] = 3, [")"] = 3, ["["] = 3, ["]"] = 3,
['--']=4,
}
local reserved_style = "\{\\bf "
local comment_style = "\{\\sl "
local function flush_pas_word(word)
if word then
local id = known_words[string.lower(word)]
if id then
tex.sprint(tex.ctxcatcodes, reserved_style)
tex.write(word)
2010-09-29 23:46:45 +02:00
tex.sprint(tex.ctxcatcodes, "\}")
else
tex.write(word)
end
end
end
local function flush_whatever(str)
if str then
for c in string.utfcharacters(str) do
if c == " " then
tex.sprint(tex.ctxcatcodes, "\\obs")
elseif c == "\t" then
tex.sprint(tex.ctxcatcodes, "\\obs")
if buffers.visualizers.enabletab then
tex.sprint(tex.ctxcatcodes,rep("\\obs ", buffers.visualizers.tablength))
end
else
tex.write(c);
end
end
end
end
local inlongcomment, inlongcomment_alt, incompdirec, inasm = false, 0, false, false
function visualizer.reset()
inlongcomment, inlongcomment_alt, incompdirec, inasm = false, 0, false, false
end
2010-09-29 23:46:45 +02:00
--[[local function written(state, c, i)
if c == " " then
2010-09-29 19:30:20 +02:00
state = buffers.finishstate(state)
tex.sprint(tex.ctxcatcodes,"\\obs")
elseif c == "\t" then
2010-09-29 19:30:20 +02:00
state = buffers.finishstate(state)
tex.sprint(tex.ctxcatcodes,"\\obs")
if buffers.visualizers.enabletab then
2010-09-29 19:30:20 +02:00
tex.sprint(tex.ctxcatcodes,rep("\\obs ",i%buffers.visualizers.tablength))
end
else
2010-09-29 19:30:20 +02:00
tex.write(c)
end
return state, 0
2010-09-29 23:46:45 +02:00
end]]
function visualizer.flush_line(str, nested)
local state = 0
local incomment, instring = false, false
--local code, comment = nil, nil
2010-09-29 19:43:27 +02:00
buffers.currentcolors = colors
2010-09-30 14:06:14 +02:00
--[[
print("SEARCHING FOR IDENTIFIERS IN: " .. str)
local remain = str
local identifier
repeat
identifier = nil
identifier, remain = string.match(remain, "^[^%a_]*([%a_]+[%a%d_]*)(.*)$")
if identifier then
print("IDENTIFIER: " .. identifier)
--print("REMAIN: " .. remain)
end
until not identifier
]]
--TODO: handle inlongcomment etc.
--[[
if inlongcomment then
comment, code = string.match(str,"^(.-})(.*)$")
if not comment then
comment = str
end
state = buffers.changestate(3, state)
tex.sprint(tex.ctxcatcodes, "\{\\bf")
flush_whatever(comment)
tex.sprint(tex.ctxcatcodes, "\}")
if code then
inlongcomment = false
else
code = ""
end
else
code = str
end
]]
if inlongcomment or (inlongcomment_alt == 2) or incompdirec then
incomment = true
if incompdirec then
state = buffers.changestate(1, state)
else
state = buffers.changestate(3, state)
end
tex.sprint(tex.ctxcatcodes, comment_style)
end
local c, word = nil, nil
for nextc in string.utfcharacters(str .. " ") do
if c then
if instring then
if c == "'" then
-- string ends
tex.write(c)
state = buffers.finishstate(state)
instring = false
else
-- inside the string
flush_whatever(c)
end
elseif incomment then
if ((inlongcomment or incompdirec) and (c == "}"))
or (inlongcomment_alt == 1) then
-- long comment/(alternative)/compiler directive ends
tex.write(c)
tex.sprint(tex.ctxcatcodes, "\}")
state = buffers.finishstate(state)
incompdirec = false
inlongcomment = false
inlongcomment_alt = 0
incomment = false
elseif (inlongcomment_alt == 2) and (c == "*") and (nextc == ")") then
-- long comment (alternative) ends after nextc
tex.write(c)
inlongcomment_alt = 1
else
-- inside the comment
flush_whatever(c)
end
elseif string.find(c, "^[%a_]$") then
-- char belongs to identifier
if word then
word = word .. c
else
word = c
end
elseif string.find(c, "^[%d]$") then
if word and (#word > 1) then
-- number, that belongs to identifier
word = word .. c
else
-- number
state = buffers.changestate(3, state)
tex.write(c)
end
else
state = buffers.finishstate(state)
-- identifier complete, check if it's a reserved word and flush
flush_pas_word(word)
word = nil
if c == " " then
tex.sprint(tex.ctxcatcodes, "\\obs")
elseif c == "\t" then
tex.sprint(tex.ctxcatcodes, "\\obs")
if buffers.visualizers.enabletab then
tex.sprint(tex.ctxcatcodes,rep("\\obs ", buffers.visualizers.tablength))
end
elseif c == "'" then
-- string starts
instring = true
state = buffers.changestate(3, state)
tex.write(c)
elseif (c == "/") and (nextc == "/") then
-- one-line comment starts
incomment = true
state = buffers.changestate(3, state)
tex.sprint(tex.ctxcatcodes, comment_style)
tex.write(c)
elseif c == "{" then
incomment = true
if nextc == "$" then
-- compiler directive starts
incompdirec = true
state = buffers.changestate(1, state)
else
-- long comment starts
inlongcomment = true
state = buffers.changestate(3, state)
end
tex.sprint(tex.ctxcatcodes, comment_style)
tex.write(c)
elseif (c == "(") and (nextc == "*") then
-- long comment (alternative) starts
incomment = true
inlongcomment_alt = 2
state = buffers.changestate(3, state)
tex.sprint(tex.ctxcatcodes, comment_style)
tex.write(c)
-- TODO: asm
else
-- symbol
state = buffers.changestate(1, state)
tex.write(c)
end
end
end
c = nextc
end
if not incomment then
state = buffers.finishstate(state)
end
-- maybe something left, check if it's a reserved word and flush
flush_pas_word(word)
if incomment then
-- end the comment-line
tex.sprint(tex.ctxcatcodes, "\}")
end
state = buffers.finishstate(state)
2010-09-30 12:02:22 +02:00
--[[
2010-09-29 19:30:20 +02:00
local code, comment = string.match(str,"^(.-)%-%-%[%[(.*)$")
if comment then
-- process the code and then flush the comment
elseif incomment then
2010-09-29 19:30:20 +02:00
comment, code = string.match(str,"^(.-)%]%](.*)$")
if comment then
-- flush the comment and then process the code
2010-09-29 19:30:20 +02:00
for c in string.utfcharacters(comment) do
if c == " " then tex.sprint(tex.ctxcatcodes,"\\obs") else tex.write(c) end
end
2010-09-29 19:30:20 +02:00
state = buffers.changestate(states['--'], state)
tex.write("KKK")
2010-09-29 19:30:20 +02:00
state = buffers.finishstate(state)
incomment = false
else
2010-09-29 19:30:20 +02:00
for c in string.utfcharacters(str) do
if c == " " then tex.sprint(tex.ctxcatcodes,"\\obs") else tex.write(c) end
end
end
comment = nil
else
code = str
end
if code and code ~= "" then
2010-09-29 19:30:20 +02:00
local pre, post = string.match(code,"^(.-)%-%-(.*)$")
if pre then
code = pre
end
local p, s, i = nil, nil, 0
2010-09-29 19:30:20 +02:00
for c in string.utfcharacters(code) do
i = i + 1
if instr then
if p then
2010-09-29 19:30:20 +02:00
tex.write(p)
p = nil
end
if c == s then
if inesc then
2010-09-29 19:30:20 +02:00
tex.write(c)
inesc = false
else
2010-09-29 19:30:20 +02:00
state = buffers.changestate(states[c],state)
instr = false
2010-09-29 19:30:20 +02:00
tex.write(c)
state = buffers.finishstate(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
2010-09-29 19:30:20 +02:00
tex.write(word)
word = nil
end
if p == "[" then
inlongstring = true
state = buffers.changestate(states["NRA"],state)
2010-09-29 19:30:20 +02:00
tex.write(p,c)
state = buffers.finishstate(state)
p = nil
else
if p then
state, i = written(state,p,i)
end
p = c
end
elseif c == "]" then
if word then
2010-09-29 19:30:20 +02:00
tex.write(word)
word = nil
end
if p == "]" then
inlongstring = false
state = buffers.changestate(states["KKK"],state)
2010-09-29 19:30:20 +02:00
tex.write(p,c)
state = buffers.finishstate(state)
p = nil
else
if p then
state, i = written(state,p,i)
end
p = c
end
else
if p then
2010-09-29 19:30:20 +02:00
state = buffers.changestate(states[p],state)
tex.write(p)
state = buffers.finishstate(state)
p = nil
end
if c == " " or c == "\t" then
if word then
flush_pas_word(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
flush_pas_word(word)
word = nil
end
instr = true
2010-09-29 19:30:20 +02:00
state = buffers.changestate(states[c],state)
state, i = written(state,c,i)
2010-09-29 19:30:20 +02:00
state = buffers.finishstate(state)
s = c
2010-09-29 19:30:20 +02:00
elseif string.find(c,"^[%a]$") then
state = buffers.finishstate(state)
if word then word = word .. c else word = c end
2010-09-29 19:30:20 +02:00
elseif word and (#word > 1) and string.find(c,"^[%d%.%_]$") then
if word then word = word .. c else word = c end
else
flush_pas_word(word)
word = nil
2010-09-29 19:30:20 +02:00
state = buffers.changestate(states[c],state)
tex.write(c)
instr = (c == '"')
end
end
end
if p then
2010-09-29 19:30:20 +02:00
tex.write(p)
-- state, i = written(state,p,i)
p = nil
end
flush_pas_word(word)
if post then
2010-09-29 19:30:20 +02:00
state = buffers.changestate(states['--'], state)
tex.write("--")
state = buffers.finishstate(state)
for c in string.utfcharacters(post) do
state, i = written(state,c,i)
end
end
end
if comment then
incomment = true
2010-09-29 19:30:20 +02:00
state = buffers.changestate(states['--'], state)
tex.write("NRA")
2010-09-29 19:30:20 +02:00
state = buffers.finishstate(state)
-- tex.write(comment) -- maybe also split and
for c in string.utfcharacters(comment) do
state, i = written(state,c,i)
end
end
]]
2010-09-29 19:30:20 +02:00
state = buffers.finishstate(state)
end