[show modes: view edit] [begin mode view] <pre>[replace(info_display(_body), "<br>", "")]</pre> [end mode view] [begin preamble] linebreak = { }; parse = function(rules) {[ reduce(rules) ?(context, rule) {[ mute line++; if(asc(substr(rule, 0, 1)) == 9) rule = " " & substr(rule, 1); if(asc(substr(rule, -1)) == 13) rule = substr(rule, 0, -2); if(rule == "") {[ ]} else if(asc(substr(rule, 0, 1)) == 32) {[ if(current_definition != "") {[ definitions[current_definition] &= list(trim(rule)); ]} else {[ return context & linebreak & "No active definition preceding rule: '" & rule & "' (line " & line & ")"; ]}; ]} else {[ current_definition = rule; if(start == "") start = rule; if(has_key(definitions, current_definition)) {[ return context & linebreak & "Duplicate definition: '" & rule & "' (line " & line & ")"; ]} else {[ definitions[current_definition] = list(); ]}; ]}; ]}; ]}; predicate = function(form, definition) {[ if(!has_key(definitions, definition)) {[ debuglog &= linebreak & "Missing definition '" & definition & "' (form '" & form & "')"; return list(); ]}; rules = list(list()) & definitions[definition]; output = reduce(rules) ?(context, rule) {[ if(rule == "") return context; if(rule == " ") return context; if(rule == " ") return context; rule = rule & " "; name = substr(rule, 0, strpos(rule, " ")); tail = trim(substr(rule, strpos(rule, " ") + 1)); rule = trim(rule); if(name == "include:") {[ return context; ]} else if(name == "part:") {[ if(part != tail) answer 0 else return context; ]} else if(name == "match:") {[ tailparts = split(tail, "/"); var k = count(tailparts); matches = 0; while(k > 1) {[ k -= 2; matches += regmatch(form, "/" & tailparts[k] & "/" & tailparts[k+1]); ]}; if(matches == 0) answer 0 else return context; ]} else if(name == "tag:") {[ tails = split(tail, ", "); var k = count(tails); matches = 0; while(k > 0) {[ k -= 1; if(find(tags, tails[k]) >= 0) matches += 1; ]}; // debug("Found " & matches & " hit(s) for " & tail & " in " & concat(tags, ", ")); if(matches == 0) answer 0 else return context; ]} else {[ return context; ]}; answer 1; ]}; return output; ]}; modify = function(form, definition) {[ if(!has_key(definitions, definition)) {[ debuglog &= linebreak & "Missing definition '" & definition & "' (form '" & form & "')"; return list(); ]}; rules = list(list()) & definitions[definition]; output = reduce(rules) ?(context, rule) {[ if(rule == "") return context; if(rule == " ") return context; if(rule == " ") return context; rule = rule & " "; name = substr(rule, 0, strpos(rule, " ")); tail = trim(substr(rule, strpos(rule, " ") + 1)); rule = trim(rule); if(name == "include:") {[ g = modify(form, tail); ks = keys(g); form = g[ks.0]; return context; ]} else if(name == "part:") {[ if(part != tail) answer list() else return context; ]} else if(name == "match:") {[ tailparts = split(tail, "/"); var k = count(tailparts); matches = 0; while(k > 1) {[ k -= 2; matches += regmatch(form, "/" & tailparts[k] & "/" & tailparts[k+1]); ]}; if(matches == 0) answer list() else return context; ]} else if(name == "tag:") {[ if(find(tags, tail) < 0) answer list() else return context; ]} else if(name == "label:") {[ tail = replace(tail, ".", "!"); no_headings &= list(definition); if(find(labels, tail) < 0) labels &= list(tail); context[tail] = form; return context; ]} else if(name == "-") {[ section_break &= list(definition); return context; ]} else if(name == "#") {[ return context; ]} else if(substr(name, 0, 1) == "/") {[ tailparts = split(rule, "/"); var k = count(tailparts); final = form; while(k > 0) {[ k -= 3; final = regreplace(final, "/" & tailparts[k] & "/" & tailparts[k + 2], tailparts[k+1]); ]}; form = final; return context; ]} else {[ context[rule] = modify(form, rule); return context; ]}; ]}; return output; ]}; display = function(subtree) {[ rows = each(subtree) ?(val, name) {[ if(!is_array(val)) {[ // leaf return "[tr][th:text-align: right; padding: 0 10px; font-weight: normal; font-style: italic]" & replace(replace(name, "!", "."), "_", " ") & "[td: text-align: left; padding: 0 10px]" & val; ]} else if(count(val) == 0) {[ return ""; ]} else if(find(no_headings, name) >= 0) {[ // hidden return display(val); ]} else if(find(section_break, name) >= 0) {[ // force vertical break after return "[td][table: border-collapse: collapse][tr][th: text-align: left]" & replace(name, "_", " ") & "[tr][td][table: border-top: 1px rgba(255, 255, 255, 0.25) solid; border-collapse: collapse]" & display(val) & "[/table][/table][tr]"; ]} else {[ // generic return "[td][table: border-collapse: collapse][tr][th]" & replace(name, "_", " ") & "[tr][td][table: border-top: 1px rgba(255, 255, 255, 0.25) solid; border-collapse: collapse]" & display(val) & "[/table][/table]"; ]}; ]}; return concat(rows, ""); ]}; [end preamble] [begin mode include][ entry = import _args.0; tags = split(getva("categories", entry._body), linebreak); part = getva("part", entry._body); root = entry._title; if(strpos(root, "<!>") > 0) root = substr(root, 0, strpos(root, "<!>")); definitions = list(); rules = split(_body, linebreak); rules = merge(list(""), rules); current_definition = ""; start = ""; line = 0; debuglog = parse(rules); if(debuglog != "") return "[box]" & debuglog & "[/box]"; // apply: labels = list(); no_headings = list(); section_break = list(); // support = predicate(root, start); if(support == 0) return ""; "[transclude:id=" & _id & "&entry=" & _args.0 & "&mode=apply|See inflection scheme: " & _title & "]"; ][end mode include] [begin mode apply] [ linebreak = { }; suppress_template(); entry = import _params.entry; tags = split(getva("categories", entry._body), linebreak); part = getva("part", entry._body); root = entry._title; if(strpos(root, "<!>") > 0) root = substr(root, 0, strpos(root, "<!>")); definitions = list(); rules = split(_body, linebreak); rules = merge(list(""), rules); current_definition = ""; start = ""; line = 0; debuglog = parse(rules); if(debuglog != "") return msg(replace(debuglog, linebreak, "<br>")); // apply: labels = list(); no_headings = list(); section_break = list(); tree = modify(root, start); if(count(tree) == 0) return ""; if(debuglog != "") return msg(replace(debuglog, linebreak, "<br>")); _wiki_format("[table][tr][th]" & _title & "[tr][table: border-top: 1px rgba(255, 255, 255, 0.25) solid; font-size: 80%; border-collapse: collapse][tr]" & display(tree) & "[/table][/table]", "inline"); ][end mode apply]