Inflection Scheme
Site Infrastructure / Inflection Scheme

[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]