summaryrefslogtreecommitdiff
path: root/macros/luatex/generic/luatexja/src/ltj-debug.lua
blob: c337c014fe65d132f75c0b0630852ecb2d39f33e (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
--
-- ltj-debug.lua
--
local ltjdbg = {}
luatexja.debug = ltjdbg
local table, string = table, string

-------------------- pretty-print

local function get_serialize_param()
  return table.serialize_functions,
         table.serialize_compact,
         table.serialize_inline
end
local function set_serialize_param(s_f, s_c, s_i)
  table.serialize_functions = s_f
  table.serialize_compact = s_c
  table.serialize_inline = s_i
end

local function normal_serialize(t)
  local s_f, s_c, s_i = get_serialize_param()
  set_serialize_param(true, true, true)
  local ret = table.serialize(t, false, false, true)
  set_serialize_param(s_f, s_c, s_i)
  return ret
end

local function table_tosource(t)
  if not next(t) then return "{}" end
  local res_n = "\127"..normal_serialize({t}).."\127"
  local s, e, cap = res_n:find("\127{\n ({ .* }),\n}\127")
  if s == 1 and e == res_n:len() then return cap
  else return normal_serialize(t)
  end
end
ltjdbg.table_tosource = table_tosource

local function function_tosource(f)
  local res = normal_serialize({f})
  return res:sub(4, res:len() - 3)
end
ltjdbg.function_tosource = function_tosource

--! 値 v をそれを表すソース文字列に変換する.
--! lualibs の table.serialize() の処理を利用している.
local function tosource(v)
  local tv = type(v)
  if tv == "function" then return function_tosource(v)
  elseif tv == "table" then return table_tosource(v)
  elseif tv == "string" then return string.format('%q', v)
  else return tostring(v)
  end
end
ltjdbg.tosource = tosource

local function coerce(f, v)
  if f == "q" then return "s", tosource(v)
  elseif f == "s" then return f, tostring(v)
  else return f, tonumber(v) or 0
  end
end

local function do_pformat(fmt, ...)
  fmt = fmt:gsub("``", "\127"):gsub("`", "%%"):gsub("\127", "`")
  local i, na, a = 0, {}, {...}
  local function proc(p, f)
    i = i + 1; f, na[i] = coerce(f, a[i])
    return p..f
  end
  fmt = fmt:gsub("(%%[-+#]?[%d%.]*)([a-zA-Z])", proc)
  return fmt:format(unpack(na))
end

--! string.format() の拡張版. 以下の点が異なる.
--!  - %q は全ての型について tosource() に変換
--!  - <%> の代わりに <`> も使える (TeX での使用のため)
--!  - %d, %s 等でキャストを行う
local function pformat(fmt, ...)
  if type(fmt) == "string" then
    return do_pformat(fmt, ...)
  else 
    return tosource(fmt)
  end
end
ltjdbg.pformat = pformat

-------------------- 所要時間合計
require("socket")
do
   local max = math.max
   local gettime = socket.gettime
   local time_stat = {}
   local function start_time_measure(n)
      if not time_stat[n] then
	 time_stat[n] = {1, -gettime()}
      else
	 local t = time_stat[n]
	 t[1], t[2] = t[1]+1, t[2]-gettime()
      end
   end
   local function stop_time_measure(n)
      local t = time_stat[n]
      t[2] = t[2] + gettime()
   end

   local function print_measure()
      stop_time_measure('RUN')
      local temp = {}
      for i,v in pairs(time_stat) do
	 temp[#temp+1] = { i, v[1], v[2], v[2]/v[1] }
      end
      table.sort(temp, function (a,b) return (a[4]>b[4]) end)
      print()
      print('desc', 'ave. (us)', 'times', 'total (ms)')
      for _,v in ipairs(temp) do
	 print ((v[1] .. '                '):sub(1,16), 1000000*v[4], v[2], 1000*v[3])
      end
   end
   if luatexja.base then
      luatexja.base.start_time_measure = start_time_measure
      luatexja.base.stop_time_measure = stop_time_measure
      luatexbase.add_to_callback('stop_run', print_measure, 'luatexja.time_measure', 1)
      luatexbase.add_to_callback('pre_linebreak_filter', 
				 function(p) 
				    start_time_measure('tex_linebreak'); return p 
				 end, 
				 'measure_tex_linebreak', 20000)
   end
end

-------------------- debug logging
do
local debug_show_term = true
local debug_show_log = true
--! デバッグログを端末に出力するか
local function show_term(v)
  debug_show_term = v
end
ltjdbg.show_term = show_term
--! デバッグログをログファイルに出力するか
function show_log(v)
  debug_show_log = v
end
ltjdbg.show_log = show_log

local function write_debug_log(s)
  local target
  if debug_show_term and debug_show_log then
    texio.write_nl("term and log", s)
  elseif debug_show_term and not debug_show_log then
    texio.write_nl("term", s)
  elseif not debug_show_term and debug_show_log then
    texio.write_nl("log", s)
  end
end

--! デバッグログ出力. 引数は pformat() と同じ.
local function out_debug(...)
  if debug_show_term or debug_show_log then
    write_debug_log("%DEBUG:"..pformat(...))
  end
end

--! デバッグログ出力, パッケージ名付き.
local function package_debug(pkg, ...)
  if debug_show_term or debug_show_log then
    write_debug_log("%DEBUG("..pkg.."):"..pformat(...))
  end
end

--! パッケージ名付きデバッグログ出力器を得る.
local function debug_logger(pkg)
  return function(...) package_debug(pkg, ...) end
end

if luatexja.base then
  luatexja.base.out_debug = out_debug
  luatexja.base.package_debug = package_debug
  luatexja.base.debug_logger = debug_logger
  luatexja.base.show_term = show_term
  luatexja.base.show_log = show_log
end
end

-------------------- all done
-- EOF