scansion/parser.lua

Fri, 28 Dec 2018 04:41:09 -0500

author
Waqas Hussain <waqas20@gmail.com>
date
Fri, 28 Dec 2018 04:41:09 -0500
changeset 160
28aa762f11c7
parent 147
db39e8e9146c
child 162
f888f236321f
permissions
-rw-r--r--

Include line_start and line_end in action objects and action log events for /run end-point

local function parse(data)
	local parsed = {
		objects = {};
		actions = {};
		tags = {};
	};
	
	local line_number = 0;
	local last_object;
	local annotation;

	for line in data:gmatch("([^\r\n]*)\r?\n") do
		line_number = line_number + 1;
		if line:sub(1,1) == "[" then
			local obj_type, name = line:match("^%[(%a+)%] (.+)$");
			
			if parsed.objects[name] then
				return nil, "Duplicate definition of "..name.." on line "..line_number;
			end
			parsed.objects[name] = {
				type = obj_type:lower();
				name = name;
				defined_line = line_number;
			};
			last_object = parsed.objects[name];
		elseif line:match("^%s+[%a_]+:.+$") then
			if not last_object then
				return nil, "Line "..line_number.. "unexpected outside of an object definition";
			end
			local k, v = line:match("^%s+([%a_]+):%s*(.+)$")
			last_object[k] = v;
		elseif #parsed.actions > 0 and line:sub(1,1) == "\t" then
			table.insert(parsed.actions[#parsed.actions].extra, line:sub(2));
			parsed.actions[#parsed.actions].line_end = line_number;
		elseif line:match("^%s*$") or line:match("^#") or line:match("^([/-])%1") then
			-- Blank line or comment
			local in_header = (next(parsed.objects) == nil) and (next(parsed.actions) == nil);
			if in_header and #line > 0 then
				if not parsed.title and not line:match("^#!") then
					parsed.title = line:gsub("^[#-]+%s*", "");
				elseif line:match("^##") then
					local tag = line:gsub("^##%s*", "");
					local k, v = tag:match("^([^:]+):%s*(.+)$");
					if k then
						-- Tag format: ## tagkey:tagvalue
						parsed.tags[k] = v;
					else
						-- Tag format: ## tagfoobar
						parsed.tags[tag] = true;
					end
				else
					parsed.summary = (parsed.summary and parsed.summary.."\n" or "")..line:gsub("^[#-]+%s*", "");
				end
			else
				-- Save as annotation for the following action
				if #line == 0 then
					if annotation then
						annotation.closed = true;
					end
				elseif annotation or not line:match("^%-+$") then
					if (not annotation) or annotation.closed then
						annotation = { line };
					else
						table.insert(annotation, line);
					end
				end
			end
		else
			last_object = nil;
			local name, action, extra = line:match("^([^:]+) (%a+):?%s?(.*)$");
			if not name then
				return nil, "Unable to parse action on line "..line_number;
			end
			if not parsed.objects[name] then
				return nil, "The object '"..name.."' used on line "..line_number.." was not declared";
			end
			table.insert(parsed.actions, {
				object_name = name;
				action = action:lower();
				extra = {#extra>0 and extra or nil};
				annotation = annotation and table.concat(annotation, "\n") or nil;
				line_start = line_number;
				line_end = line_number;
			});
			annotation = nil;
		end
	end
	return parsed;
end

return {
	parse = parse;
};

mercurial