258 lines
9.9 KiB
Plaintext
258 lines
9.9 KiB
Plaintext
package slangc.parser;
|
||
|
||
import slang.data.List;
|
||
import slangc.streams.LogWriter;
|
||
|
||
public class CleopatraModeLanguage extends Language {
|
||
private Option[] options = new Option[0];
|
||
private final boolean enableFallbacks;
|
||
|
||
public CleopatraModeLanguage(boolean enableFallbacks) {
|
||
this.enableFallbacks = enableFallbacks;
|
||
}
|
||
|
||
public static class Option {
|
||
public final String language;
|
||
public final Key key;
|
||
public final String value;
|
||
|
||
public Option(String language, Key key, String value) {
|
||
this.language = language;
|
||
this.key = key;
|
||
this.value = value;
|
||
}
|
||
}
|
||
|
||
public void addOption(Option o) {
|
||
Option[] newarr = new Option[options.length + 1];
|
||
for (int i = 0; i < newarr.length; i++) {
|
||
newarr[i] = (i < options.length ? options[i] : o);
|
||
}
|
||
options = newarr;
|
||
}
|
||
|
||
public void addOption(String language, Key key, String value) {
|
||
addOption(new Option(language, key, value));
|
||
}
|
||
|
||
public void addOption(Medu medu, Key key, String value) {
|
||
addOption(""+medu /*.name()*/, key, value);
|
||
}
|
||
|
||
String[] cachedKeywords = null;
|
||
|
||
@Override
|
||
public String[] getKeywords() {
|
||
if (cachedKeywords == null) {
|
||
cachedKeywords = recalculateKeywords();
|
||
}
|
||
return cachedKeywords;
|
||
}
|
||
|
||
public String[] recalculateKeywords() {
|
||
String[] initial;
|
||
if (enableFallbacks) {
|
||
initial = super.getKeywords();
|
||
} else {
|
||
initial = new String[0];
|
||
}
|
||
String[] result = new String[initial.length + options.length];
|
||
for (int i = 0; i < result.length; i++) {
|
||
result[i] = (i < initial.length ? initial[i] : options[i - initial.length].value);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
@Override
|
||
public boolean matches(Key key, String str) {
|
||
for (int i = 0; i < options.length; i++) {
|
||
if (options[i].key == key && options[i].value.equals(str)) {
|
||
return true;
|
||
}
|
||
}
|
||
if (enableFallbacks) {
|
||
return super.matches(key, str);
|
||
} else {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
public enum Medu {
|
||
USERDEFINED,
|
||
NETER,
|
||
NUBIAN,
|
||
COPTIC,
|
||
GREEK
|
||
}
|
||
|
||
public void addMedu(Medu m) {
|
||
switch (m) {
|
||
case Medu.NUBIAN:
|
||
addNubian();
|
||
break;
|
||
case Medu.COPTIC:
|
||
addCoptic();
|
||
break;
|
||
default:
|
||
throw new Error("TODO: This medu mode " + m + " is not implemented yet");
|
||
}
|
||
}
|
||
|
||
public void printTable(LogWriter out) {
|
||
/*
|
||
List<String> columns = new List<String>();
|
||
|
||
for (int i = 0; i < options.length; i++) {
|
||
if (!columns.contains(options[i].language)) {
|
||
columns.add(options[i].language);
|
||
}
|
||
}
|
||
|
||
out.print("[%header,cols=\"1,");
|
||
for (int i = 0; i < columns.size(); i++) {
|
||
if (i != 0) {
|
||
out.print(",");
|
||
}
|
||
out.print(2);
|
||
}
|
||
out.println("\"]");
|
||
out.println("|===");
|
||
out.print("|Keyword Id ");
|
||
for (int i = 0; i < columns.size(); i++) {
|
||
//if (i != 0) {
|
||
// out.print(",");
|
||
//}
|
||
out.print("|" + columns.get(i) + " ");
|
||
}
|
||
out.println();
|
||
out.println();
|
||
|
||
for (int i = 0; i < Key.values().length; i++) {
|
||
printTableRow(out, columns, Key.values()[i]);
|
||
out.println();
|
||
}
|
||
|
||
out.println("|===");
|
||
*/
|
||
throw new Error("TODO: Printing language tables");
|
||
}
|
||
|
||
public void printTableRow(LogWriter out, List<String> columns, Key key) {
|
||
out.print("|" + key + " ");
|
||
for (int i = 0; i < columns.count(); i++) {
|
||
out.print("| ");
|
||
boolean addedOne = false;
|
||
for (int j = 0; j < options.length; j++) {
|
||
Option o = options[j];
|
||
if (o.key == key && o.language.equals(columns.get(i))) {
|
||
if (addedOne) {
|
||
out.print(", ");
|
||
} else {
|
||
addedOne = true;
|
||
}
|
||
out.print("`" + o.value + "`");
|
||
}
|
||
}
|
||
if (addedOne) {
|
||
out.print(" ");
|
||
}
|
||
}
|
||
out.println();
|
||
}
|
||
|
||
public void addNubian() {
|
||
addOption(Medu.NUBIAN, Key.CLASS, "ⲕⲗⲁⲥⲥ");
|
||
addOption(Medu.NUBIAN, Key.PUBLIC, "ⲡⲩⲃⲗⲓⲕ");
|
||
|
||
// From "An English-Nubian Comparative Dictionary", 1923
|
||
// NOTE: There is a small but strong Nubian community on Twitter that can provide more links.
|
||
addOption(Medu.NUBIAN, Key.THIS, "ⲉⲓⲛ"); // p.xxxv, p.73 (note: "that" would be ⲙⲁⲛ)
|
||
addOption(Medu.NUBIAN, Key.BREAK, "ⲡⲁⲗ"); // p.49
|
||
addOption(Medu.NUBIAN, Key.TRUE, "ⲉⲩⲟ"); // ⲡ.48 ("yes", speculative spelling, only phonetics provided)
|
||
addOption(Medu.NUBIAN, Key.VOID, "ⲡⲁⲣⲕ"); //ⲡ.50 (a valley or place water goes without releasing)
|
||
addOption(Medu.NUBIAN, Key.IF, "ⲡⲉϣϣ"); //ⲡ.51 ("judge")
|
||
addOption(Medu.NUBIAN, Key.IF, "ⲟⲛ"); // p.188 (and/if)
|
||
addOption(Medu.NUBIAN, Key.STATIC, "ⲡⲓ"); //ⲡ.52 (i.e. to stay, as in the sentence "I'm staying at home")
|
||
addOption(Medu.NUBIAN, Key.RETURN, "ⳟⲓⲡⲓⲣⲧ"); //p.60 (repeat or return, NOTE: need to check first character)
|
||
addOption(Medu.NUBIAN, Key.THROW, "ⳝⲟⳝ"); //ⲡ.62 (kill/fight/sacrifice)
|
||
addOption(Medu.NUBIAN, Key.THROW, "ⲙⲟⲩⲣⲧ"); //ⲡ.125 (warn)
|
||
addOption(Medu.NUBIAN, Key.FOR, "ⲕⲉⲗ"); // p.95 (limit or boundary, related to the word used for WHILE)
|
||
addOption(Medu.NUBIAN, Key.WHILE, "ⲕⲉⲗⲗ"); //p.95 ("as much as", "sometimes", related to the word used for FOR)
|
||
addOption(Medu.NUBIAN, Key.DUCK, "ⲕⲉⲗⲁⲓ"); // p.95 (wild duck, speculative spelling, only phonetics provided)
|
||
addOption(Medu.NUBIAN, Key.NULL, "ⲕⲓⳡ"); // p.99 (empty or exhausted, NOTE: need to check last character)
|
||
addOption(Medu.NUBIAN, Key.FINAL, "ⲕⲓⲣⲓⳟ"); // p.100 (finished or complete, NOTE: need to check last character)
|
||
addOption(Medu.NUBIAN, Key.ABSTRACT, "ⲙⲓⲛⲇⲓ"); // ⲡ.122 (partial, incomplete, NOTE: this seems to be a rarely-used word)
|
||
addOption(Medu.NUBIAN, Key.NEW, "ⳟⲁⲓⲉⲣ"); // ⲡ.134 ("bring to life")
|
||
addOption(Medu.NUBIAN, Key.INT, "ⲥⲁⲗ"); // p.144 ("word", which fits with an old way of basically saying int - "machine word")
|
||
addOption(Medu.NUBIAN, Key.EXTENDS, "ⲥⲉⲩ"); // p.147 ("inherit")
|
||
addOption(Medu.NUBIAN, Key.MODULE, "ϣⲟⲗ"); // p.157 (a book or charm)
|
||
addOption(Medu.NUBIAN, Key.PRIVATE, "ⲧⲟⲩ"); // p.169 (internals, belly/guts)
|
||
addOption(Medu.NUBIAN, Key.THIS, "ⲟⲩⲣ"); // p. 178 ("self")
|
||
// p.161 for class/etc.?
|
||
// ⲉⲧⲉⲣ for "do"? p.48
|
||
}
|
||
|
||
public void addCoptic() {
|
||
// From "Aegyptisches Glossar", 1904
|
||
// NOTE: This source was chosen as the primary one because it focuses on words
|
||
// present in both Medu Neter and Coptic (also with many connections to Greek, Hebrew,
|
||
// Arabic and so on).
|
||
|
||
addOption(Medu.COPTIC, Key.WHILE, "ⲟⲩⲱϩⲙ"); // p.32, "repeat"/"to repeat"
|
||
addOption(Medu.COPTIC, Key.FOR, "ⲟⲩⲱϣ"); // p.32, "search"
|
||
// NOTE: See also p.56 for iteration-releated words
|
||
addOption(Medu.COPTIC, Key.RETURN, "ⲟⲩⲱϣⲃ"); // p.34, "answer"
|
||
addOption(Medu.COPTIC, Key.TRY, "ⲟⲩⲇⲁⲓ"); // p.35, "be safe"
|
||
// NOTE: See also p.56 for "witness", p.65 for "harness"
|
||
addOption(Medu.COPTIC, Key.THROW, "ⲕⲱ"); // p.90, literally "throw" or "leave"
|
||
|
||
addOption(Medu.COPTIC, Key.DO, "ⲃⲁⲕ"); // p.39, "work"
|
||
addOption(Medu.COPTIC, Key.CATCH, "ⲡⲏⲓ"); // p.41, "escaped" (fits with "catch" because that's why you need to catch it!)
|
||
addOption(Medu.COPTIC, Key.FINALLY, "ⲁϩⲟⲩ"); // p.43, "the end"/"the rear" (as in "reaching the end"? literally "ahoy"? The Euros seem to think not)
|
||
addOption(Medu.COPTIC, Key.FINALLY, "ⲡⲁϩⲟⲩ"); // Alternative spelling
|
||
// See also p.124 for a word for "tail"
|
||
addOption(Medu.COPTIC, Key.FINAL, "ⲙⲟⲩⲛⲕ"); // p.51, "complete" (literally "monk")
|
||
addOption(Medu.COPTIC, Key.FINAL, "ⲧⲱⲱⲃⲉ"); // p. 155, "seal"
|
||
addOption(Medu.COPTIC, Key.SUPER, "ⲡⲧⲁϩ"); // p.45 (Ptah = Phthah, we still use the same word "father" in English)
|
||
addOption(Medu.COPTIC, Key.SUPER, "ⲙⲁⲁⲩ"); // p.49, (Maa', from which mother is derived)
|
||
addOption(Medu.COPTIC, Key.ELSE, "ⲙ"); // p.46, "Negation of the Imperative" lmao perfect (ⲙ︦? needs line above?)
|
||
addOption(Medu.COPTIC, Key.TRUE, "ⲙⲉ"); // p.47, "true"
|
||
addOption(Medu.COPTIC, Key.TRUE, "ⲙⲏⲓ"); // Alternative spelling? (or I've interpreted this entry incorrectly...)
|
||
addOption(Medu.COPTIC, Key.STATIC, "ⲙⲟⲩⲛ"); // p.50, "stay"
|
||
addOption(Medu.COPTIC, Key.NEW, "ⲙⲓⲥⲉ"); // p.55, "give birth", "generate", "form"
|
||
addOption(Medu.COPTIC, Key.VOID, "ⲛⲟⲩϥⲉⲛ"); // p.62, spelling assumed based on nearby term. Intended meaning is "never", related to "nether".
|
||
addOption(Medu.COPTIC, Key.NULL, "ϣⲱⲩⲉⲓⲧ"); // p.127, "be empty of something"
|
||
addOption(Medu.COPTIC, Key.DUCK, "ⲣⲟ"); // p.70, slight pun (a goose is basically a duck right?)
|
||
addOption(Medu.COPTIC, Key.BREAK, "ⲗⲟ"); // p.71, "stop" or "flee"
|
||
addOption(Medu.COPTIC, Key.PRIVATE, "ϩⲱⲃⲥ"); // p.82, "conceal" or "dress"
|
||
addOption(Medu.COPTIC, Key.SWITCH, "ⲥⲱⲧⲡ"); // p.122, "choose"
|
||
addOption(Medu.COPTIC, Key.CASE, "ⲥⲟⲡ"); // p.103, "type of" or "case of" (note, type seems to be "Art" in German?)
|
||
addOption(Medu.COPTIC, Key.SHORT, "ϣⲓⲣⲉ"); // p.130, "be small"
|
||
addOption(Medu.COPTIC, Key.BYTE, "ϣⲏⲣⲉ"); // p.130, "smaller" (literally same as ϣⲓⲣⲉ except shorter "i" vowel)
|
||
addOption(Medu.COPTIC, Key.CLASS, "ⲕⲟⲧ"); // p.135, "circle", "shape", "kind", "essence"
|
||
// p.140 for "equip" as extends/implements? 151 for similar
|
||
// p.153 for "enter" as main?
|
||
// p.33 for "say" as logLine?
|
||
// p.45 for "run" ?
|
||
// p.58 for "depth" as length?
|
||
}
|
||
|
||
public boolean applySetting(String key, String value, boolean reset, boolean append) {
|
||
if (reset && key == "*") {
|
||
options = new Option[0];
|
||
return true;
|
||
} else if (append && value != null && !reset) {
|
||
Key k;
|
||
try {
|
||
k = (Key) Key.lookup(Key.class, key);
|
||
} catch (Error e) {
|
||
return false;
|
||
}
|
||
addOption(Medu.USERDEFINED, k, value);
|
||
return true;
|
||
} else {
|
||
return super.applySetting(key, value, reset, append);
|
||
}
|
||
}
|
||
}
|