Fri, 01 Feb 2019 11:22:20 +0000
docs: Add initial documentation
local function parse(data) local parsed = { objects = {}; actions = {}; tags = {}; }; local line_number = 0; local last_object; local annotation; local function parse_error(text) return nil, "ParseError: " .. text .. " (line " .. line_number .. ")"; end 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 parse_error("Duplicate definition of '"..name.."'"); 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 parse_error("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 parse_error("Unable to parse action"); end if not parsed.objects[name] then return parse_error("The object '"..name.."' 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; };