rwx/sh/core/code.awk
2025-08-02 17:50:04 +02:00

305 lines
5.8 KiB
Awk

# 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)
}
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)
# 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["function"])) {
f = extract($0, "function")
} 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
}