# code # functions function alias_eval(alias, name, type) { text = alias "() { " if (type == "function") { text = text name " \"${@}\"" } else if (type == "variable") { text = text "echo \"${" name "}\"" } print text "; }" } function doc_append(string) { if (doc) { doc = doc "\n" } doc = doc string } function doc_output(name, type) { print "↙ " type print name print doc exit } function doc_reset() { if (current_function == "") { doc = "" } } # TODO delete when useless function extract(string, type) { if (type == "alias") { split(string, array, "#=") return trim(array[2]) } else if (type == "command") { split(string, array, "#/") return trim(array[2]) } else if (type == "doc") { split(string, array, "#") return trim(array[2]) } else if (type == "function") { split(string, array, "(") return trim(array[1]) } else if (type == "module") { split(string, array, "#\\.") return trim(array[2]) } else if (type == "shebang") { split(string, array, "#!") return trim(array[2]) } else if ((type == "constant") || (type == "variable")) { split(string, array, "=") return trim(array[1]) } } function remove_first(string, target, tmp) { tmp = string sub(target, "", tmp) return trim(tmp) } # TODO parent function function strip_function(string, tmp) { split(string, tmp, "(") return trim(tmp[1]) } function strip_value(string, tmp) { split(string, tmp, "=") return trim(tmp[1]) } function trim(string) { text = string sub("^[\t ]*", "", text) sub("[\t ]*$", "", text) return text } # → begin BEGIN { RE_ANY = "(.*)" RE_BEGIN = "^" RE_CONST = "([_A-Z][_0-9A-Z]*)" RE_SET = "=.*" RE_SPACE = "[[:space:]]" RE_TSK = "(FIXME|TODO)" RE_VAR = "([_a-z][_0-9a-z]*)" RE_SPACES = RE_SPACE "*" RE_END = RE_SPACES "$" RE_FUNC = RE_SPACES "\\(" RE_SPACES "\\)" RE_SPACES "{" re["alias"] = RE_BEGIN "#=" RE_SPACES RE_VAR RE_END re["binary"] = RE_BEGIN "#\\|" RE_SPACES RE_VAR RE_END RE_CLOSE = RE_BEGIN "}" RE_SPACES RE_END re["command"] = RE_BEGIN "#/" RE_SPACES RE_VAR RE_END RE_COMMENT = RE_BEGIN "#" RE_ANY RE_END re["constant"] = RE_BEGIN RE_CONST RE_SET RE_END RE_DOC = RE_BEGIN RE_SPACES "#" RE_SPACE RE_ANY RE_END re["function"] = RE_BEGIN RE_VAR RE_FUNC RE_END RE_MODULE = RE_BEGIN "#\\." RE_SPACES RE_ANY RE_END RE_SHEBANG = RE_BEGIN "#!" RE_SPACES RE_ANY RE_END RE_TASK = RE_BEGIN RE_SPACES "#" RE_SPACES RE_TSK RE_ANY RE_END re["variable"] = RE_BEGIN RE_VAR RE_SET RE_END match_task = 0 doc_reset() # ← begin } # parse function parse(string) { # module if (match(string, RE_MODULE)) { current_match = "module" module = remove_first(string, "#\\.") doc_reset() shebang = "" # shebang } else if (match(string, RE_SHEBANG)) { current_match = "shebang" shebang = remove_first(string, "#!") # constant } else if (match(string, re["constant"])) { current_match = "constant" constant = strip_value(string) # variable } else if (match(string, re["variable"])) { current_match = "variable" variable = strip_value(string) # alias } else if (match(string, re["alias"])) { current_match = "alias" alias = remove_first(string, "#=") aliases[alias] = "" doc_append("= " alias) # command } else if (match(string, re["command"])) { current_match = "command" command = remove_first(string, "#/") commands[command] = "" doc_append("/ " command) # function } else if (match(string, re["function"])) { current_match = "function" current_function = strip_function(string) # other } else { if (module == target) { doc_output(target, "module") } else { doc_reset() } } } # → main { # doc if (action == "doc") { parse($0) # doc if (match($0, RE_DOC)) { if (current_function) { doc_append($0) } else { doc_append(extract($0, "doc")) } # constant } else if (current_match == "constant") { if (constant == target) { doc_output(constant, "constant") } else { doc_reset() constant = "" } # variable } else if (current_match == "variable") { if (variable == target) { doc_output(variable, "variable") } else { doc_reset() variable = "" } # others } else if (match($0, RE_CLOSE)) { if (match_alias) { print "= " target doc_output(current_function, "function") } else if (match_command) { print "/ " target doc_output(current_function, "function") } else if (current_function == target) { doc_output(current_function, "function") } else { current_function = "" doc_reset() } } # tasks } else if (action == "tasks") { line++ if (match($0, RE_MODULE)) { line = 1 if (output_tasks) { print "" print output_module print output_tasks output_tasks = "" } doc = "" match_task = 0 output_module = ". " extract($0, "module") } else if (match($0, RE_TASK)) { if (target) { if (target == extract($0, "task")) { match_task = 1 } } else { match_task = 1 } doc_append(line ": " $0) } else if (match($0, RE_COMMENT)) { doc_append(line ": " $0) } else { if (match_task) { output_tasks = output_tasks "\n" doc } doc = "" match_task = 0 } # function } else if (action == "function") { if (match($0, re["command"])) { doc_append(extract($0, "command")) } else if (match($0, re["function"])) { split(doc, array, "\n") for (item in array) { if (array[item] == target) { print extract($0, "function") exit } } doc_reset() } else { doc_reset() } # eval } else if (action == "eval") { if (match($0, re[target])) { doc_append(extract($0, target)) } else if (match($0, re["function"])) { split(doc, array, "\n") for (item in array) { alias_eval(array[item], extract($0, "function"), "function") } doc_reset() } else { doc_reset() } # filter } else if (action == "filter") { if (match($0, re[target])) { unique[extract($0, target)] = "" } # unknown } else { print "unknown action: " action exit 1 # ← action } # ← main } # → end END { # filter if (action == "filter") { for (item in unique) { print item } # ← end / action } # ← end }