cortav  Check-in [0c6a784678]

Overview
Comment:add --version -V flag
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 0c6a7846785c6aa3dbf9875546d9c41d78c1f7a7632473672727214618c9fb06
User & Date: lexi on 2021-12-21 05:04:57
Other Links: manifest | tags
Context
2021-12-22
10:19
add extension mechanism, move toc to extensions, update docs, fix bugs check-in: 330e1ecfdb user: lexi tags: trunk
2021-12-21
05:04
add --version -V flag check-in: 0c6a784678 user: lexi tags: trunk
03:26
fix embarassing typobug check-in: d5e8521d30 user: lexi tags: trunk
Changes

Modified cli.lua from [37b0a0a8ee] to [bdd85f20a4].

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
..
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
...
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
...
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
local ss = require 'sirsem'

local default_mode = {
	['render:format'] = 'html';
	['html:gen-styles'] = true;
}

local function
kmap(fn, list)
	local new = {}
	for k, v in pairs(list) do
		local nk,nv = fn(k,v)
		new[nk or k] = nv or v
	end
	return new
end

local function
kfilter(list, fn)
	local new = {}
	for k, v in pairs(list) do
		if fn(k,v) then new[k] = v end
	end
	return new
end

local function
main(input, output, log, mode, suggestions, vars)
	local doc = ct.parse(input.stream, input.src, mode)
	input.stream:close()
	if mode['parse:show-tree'] then
		log:write(dump(doc))
	end
................................................................................
		error 'what output format should i translate the input to?'
	end
	if mode['render:format'] == 'none' then return 0 end
	if not ct.render[mode['render:format']] then
		ct.exns.unimpl('output format “%s” unsupported', mode['render:format']):throw()
	end
	
	local render_opts = kmap(function(k,v)
		return k:sub(2+#mode['render:format'])
	end, kfilter(mode, function(m)
		return ss.str.begins(m, mode['render:format']..':')
	end))

	doc.vars = vars
	
	-- this is kind of gross but the context object belongs to the parser,
	-- not the renderer, so that's not a suitable place for this information
................................................................................
		mode = function(key,value) mode[checkmodekey(key)] = value end;
		['mode-set'] = function(key) mode[checkmodekey(key)] = true end;
		['mode-clear'] = function(key) mode[checkmodekey(key)] = false end;

		['mode-weak'] = function(key,value) suggestions[checkmodekey(key)] = value end;
		['mode-set-weak'] = function(key) suggestions[checkmodekey(key)] = true end;
		['mode-clear-weak'] = function(key) suggestions[checkmodekey(key)] = false end;























	}

	local args = {}
	local keepParsing = true
	do local i = 1 while i <= #arg do local v = arg[i]
		local execLongOpt = function(longopt)
			if not onswitch[longopt] then
				ct.exns.cli('switch --%s unrecognized', longopt):throw()
			end
			local nargs = optnparams(longopt)

			if nargs > 1 then
				if i + nargs > #arg then
					ct.exns.cli('not enough arguments for switch --%s (%u expected)', longopt, nargs):throw()
				end
				local nt = {}
				for j = i+1, i+nargs do
					table.insert(nt, arg[j])
				end
				onswitch[longopt](table.unpack(nt))
			elseif nargs == 1 then
				onswitch[longopt](arg[i+1])


			end
			i = i + nargs
		end
		if v == '--' then
			keepParsing = false
		else
			local longopt = v:match '^%-%-(.+)$'
................................................................................
				execLongOpt(longopt)
			else
				if keepParsing and v:sub(1,1) == '-' then
					for c,p in ss.str.enc.utf8.each(v:sub(2)) do
						if optmap[c] then
							execLongOpt(optmap[c])
						else
							ct.exns.cli('switch -%i unrecognized', c):throw()
						end
					end
				else
					table.insert(args, v)
				end
			end








<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







|

|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>













|





|


>
>







 







|







2
3
4
5
6
7
8



















9
10
11
12
13
14
15
..
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
...
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
...
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
local ss = require 'sirsem'

local default_mode = {
	['render:format'] = 'html';
	['html:gen-styles'] = true;
}




















local function
main(input, output, log, mode, suggestions, vars)
	local doc = ct.parse(input.stream, input.src, mode)
	input.stream:close()
	if mode['parse:show-tree'] then
		log:write(dump(doc))
	end
................................................................................
		error 'what output format should i translate the input to?'
	end
	if mode['render:format'] == 'none' then return 0 end
	if not ct.render[mode['render:format']] then
		ct.exns.unimpl('output format “%s” unsupported', mode['render:format']):throw()
	end
	
	local render_opts = ss.kmap(function(k,v)
		return k:sub(2+#mode['render:format'])
	end, ss.kfilter(mode, function(m)
		return ss.str.begins(m, mode['render:format']..':')
	end))

	doc.vars = vars
	
	-- this is kind of gross but the context object belongs to the parser,
	-- not the renderer, so that's not a suitable place for this information
................................................................................
		mode = function(key,value) mode[checkmodekey(key)] = value end;
		['mode-set'] = function(key) mode[checkmodekey(key)] = true end;
		['mode-clear'] = function(key) mode[checkmodekey(key)] = false end;

		['mode-weak'] = function(key,value) suggestions[checkmodekey(key)] = value end;
		['mode-set-weak'] = function(key) suggestions[checkmodekey(key)] = true end;
		['mode-clear-weak'] = function(key) suggestions[checkmodekey(key)] = false end;

		['version'] = function()
			outp:write(ct.info:about())
			if next(ct.ext.loaded) then
				outp:write('\nactive extensions:\n')
				for k,v in pairs(ct.ext.loaded) do
					outp:write(string.format(' * %s', v.id ..
						(v.version and (' ' .. v.version:string()) or '')))
					if v.desc then
						outp:write(string.format(': %s', v.desc))
						if v.contributors then
							outp:write(string.format(' [%s]', table.concat(
								ss.map(function(ctr)
									return ctr.name or ctr.handle
								end, v.contributors), ', ')))
						end
					else
						outp:write'\n'
					end
				end
			end
			os.exit(0)
		end
	}

	local args = {}
	local keepParsing = true
	do local i = 1 while i <= #arg do local v = arg[i]
		local execLongOpt = function(longopt)
			if not onswitch[longopt] then
				ct.exns.cli('switch --%s unrecognized', longopt):throw()
			end
			local nargs = optnparams(longopt)

			if nargs > 1 then
				if i + nargs > #arg then
					ct.exns.cli('not enough arguments for switch --%s (%s expected)', longopt, nargs):throw()
				end
				local nt = {}
				for j = i+1, i+nargs do
					table.insert(nt, arg[j])
				end
				print('onsw')
			elseif nargs == 1 then
				onswitch[longopt](arg[i+1])
			else
				onswitch[longopt]()
			end
			i = i + nargs
		end
		if v == '--' then
			keepParsing = false
		else
			local longopt = v:match '^%-%-(.+)$'
................................................................................
				execLongOpt(longopt)
			else
				if keepParsing and v:sub(1,1) == '-' then
					for c,p in ss.str.enc.utf8.each(v:sub(2)) do
						if optmap[c] then
							execLongOpt(optmap[c])
						else
							ct.exns.cli('switch -%s unrecognized', c):throw()
						end
					end
				else
					table.insert(args, v)
				end
			end

Modified cortav.lua from [70cf5fbd0d] to [7d896a453b].

8
9
10
11
12
13
14


























































15
16
17
18
19
20
21
local startswith = ss.str.begins
local eachcode = ss.str.enc.utf8.each
local dump = ss.dump
local declare = ss.declare

-- make this module available to require() when linked into a lua bytecode program with luac
local ct = ss.namespace 'cortav'


























































ct.render = {}

ct.exns = {
	tx = ss.exnkind('translation error', function(msg,...)
		return string.format("(%s:%u) "..msg, ...)
	end);
	io = ss.exnkind('IO error', function(msg, ...)







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
local startswith = ss.str.begins
local eachcode = ss.str.enc.utf8.each
local dump = ss.dump
local declare = ss.declare

-- make this module available to require() when linked into a lua bytecode program with luac
local ct = ss.namespace 'cortav'
ct.info = {
	version = ss.version {0,1; 'devel'};
	package_name = 'cortav';
	contributors = {
		{ name = 'lexi hale', handle = 'velartrill';
		  mail = 'lexi@hale.su', homepage = 'https://hale.su' };
	};
	ident_string = function(i)
		return string.format('%s %s', i.package_name, i.version)
	end;
	credits = function(i)
		local all = ss.copy(i.contributors)
		for i,who in pairs(all) do
			who.role = who.role or 'core functionality'
		end
		for name,ext in pairs(ct.ext.loaded) do
			if ext.contributors then
				for _,c in pairs(ext.contributors) do
					local ofs, ref = ss.find(all, function(a)
						return a.handle == c.handle
					end)
					if ofs then
						ref.role = string.format('%s; %s extension', ref.role, name)
					else
						local c = ss.clone(ext.author)
						c.role = name .. ' extension'
					end
				end
			end
		end
		return all
	end;
	credits_ascii = function(contributors)
		local body = ''
		for _, c in pairs(contributors) do
			local str
			if c.handle then
				str = string.format('%s “%s” <%s>', c.name, c.handle, c.mail)
			else
				str = string.format('%s <%s>', c.name, c.mail)
			end
			if c.homepage then
				str = string.format('%s (%s)', str, c.homepage)
			end
			if c.role then
				str = string.format('%s: %s', str, c.role)
			end
			body = body .. string.format(' ~ %s\n', str)
		end
		return body
	end;
	about = function(i)
		return i:ident_string() .. '\n' ..
		       i.credits_ascii(i:credits())
	end;
}


ct.render = {}

ct.exns = {
	tx = ss.exnkind('translation error', function(msg,...)
		return string.format("(%s:%u) "..msg, ...)
	end);
	io = ss.exnkind('IO error', function(msg, ...)

Modified ext/toc.lua from [a3dcc0807f] to [ed743c91e7].

1
2
3
4
5
6


7
8
9
10
local ct = require 'cortav'
local ss = require 'sirsem'

ct.ext.install {
	id = 'toc';
	desc = 'provides a table of contents for HTML renderer plus generic fallback';


	directive = function(words)

	end;
}






>
>




1
2
3
4
5
6
7
8
9
10
11
12
local ct = require 'cortav'
local ss = require 'sirsem'

ct.ext.install {
	id = 'toc';
	desc = 'provides a table of contents for HTML renderer plus generic fallback';
	version = ss.version {0,1; 'devel'};
	contributors = {{name='lexi hale', handle='velartrill', mail='lexi@hale.su', homepage='https://hale.su'}};
	directive = function(words)

	end;
}

Modified sirsem.lua from [a1f6282434] to [8f6ee343ec].

35
36
37
38
39
40
41

























































42
43
44
45
46
47
48
...
268
269
270
271
272
273
274







































function ss.filter(list, fn)
	local new = {}
	for i, v in ipairs(list) do
		if fn(v,i) then table.insert(new, v) end
	end
	return new
end


























































ss.str = {}

function ss.str.begins(str, pfx)
	return string.sub(str, 1, #pfx) == pfx
end

................................................................................
				ss.str.exn('out of place token “%s”', stop):throw()
			end
		end
	end

	ss.str.exn('token “%s” expected before end of line', stop):throw()
end














































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
...
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
function ss.filter(list, fn)
	local new = {}
	for i, v in ipairs(list) do
		if fn(v,i) then table.insert(new, v) end
	end
	return new
end
function ss.kmap(fn, list)
	local new = {}
	for k, v in pairs(list) do
		local nk,nv = fn(k,v)
		new[nk or k] = nv or v
	end
	return new
end

function ss.kfilter(list, fn)
	local new = {}
	for k, v in pairs(list) do
		if fn(k,v) then new[k] = v end
	end
	return new
end

function ss.find(tbl, pred, ...)
	pred = pred or function(a,b)
		return a == b
	end
	for k,v in pairs(tbl) do
		if pred(v,k,...) then return k,v end
	end
	return nil
end

function ss.clone(tbl) -- performs a shallow copy
	if tbl.clone then return tbl:clone() end
	local new = {}
	for k,v in pairs(tbl) do
		new[k] = v
	end
	return new
end

function ss.copy(tbl) -- performs a deep copy
	local new = {}
	for k,v in pairs(tbl) do
		if type(v) == 'table' then
			if v.clone then
				new[k] = v:clone() -- this may or may not do a deep copy!
			else
				new[k] = ss.copy(v)
			end
		else
			new[k] = v
		end
	end
	return new
end

function ss.delegate(tbl,tpl) -- returns a table that looks up keys it lacks from
                              -- tbl (lightweight alternative to shallow copies)
	tpl = tpl or {}
	return setmetatable({}, {__index=tbl})
end

ss.str = {}

function ss.str.begins(str, pfx)
	return string.sub(str, 1, #pfx) == pfx
end

................................................................................
				ss.str.exn('out of place token “%s”', stop):throw()
			end
		end
	end

	ss.str.exn('token “%s” expected before end of line', stop):throw()
end

ss.version = ss.declare {
	name = 'version';
	mk = function(tbl) return tbl end;
	fns = {
		pre = function(self,other) end;
		post = function(self,other) end;
		string = function(self) return tostring(self) end;		
	};
	cast = {
		string = function(vers)
			if not(next(vers)) then return '0.0' end
			local str = ''
			for _,v in pairs(vers) do
				if type(v) == 'string' then
					if str ~= '' then str = str .. '-' end
					str = str .. v
				else
					if str ~= '' then str = str .. '.' end
					str = str .. tostring(v)
				end
			end
			return str
		end
	};
}

function ss.classinstance(o)
	local g = getmetatable(o)
	if not o then return nil end
	local mm = getmetatable(g)
	if not o then return nil end
	if mm.__name == 'class' then
		return g
	else
		return nil
	end
end