348 lines
10 KiB
Nim
348 lines
10 KiB
Nim
import std/macros
|
|
import std/tables
|
|
import std/options
|
|
import std/strutils
|
|
import std/[json, jsonutils]
|
|
import std/sequtils
|
|
|
|
type
|
|
GlyphAttribute* = enum
|
|
# Vowel Attributes
|
|
outer, slashed, inner,
|
|
|
|
# Cluster/Punctuation Attributes
|
|
left, center, right,
|
|
top, middle, bottom,
|
|
tall, wide, both,
|
|
|
|
# Numeric Attributes
|
|
circle, dash, vee, hump, dot,
|
|
|
|
|
|
GlyphKind* = enum Vowel, Cluster, Punctuation, Syllable, Numeric
|
|
Glyph* = object
|
|
spelling*: string
|
|
kind*: GlyphKind
|
|
attrs*: set[GlyphAttribute]
|
|
|
|
Replacement* = object
|
|
original*: string
|
|
replaced*: string
|
|
|
|
PartOfSpeech* = enum Noun, Pronoun, Verb, Adjective, Adverb, Syntactic
|
|
|
|
V* = enum
|
|
V_I, V_E, V_A, V_O, V_U
|
|
|
|
Definition* = object
|
|
brief*: string
|
|
long*: Option[string]
|
|
|
|
Word* = ref object
|
|
spelling*: string
|
|
definitions*: Table[PartOfSpeech, Definition]
|
|
|
|
Extremes* = object
|
|
i*: Option[string]
|
|
u*: Option[string]
|
|
|
|
Penta* = ref object
|
|
spelling*: string
|
|
name*: string
|
|
exts*: Extremes
|
|
elems*: array[V, Word]
|
|
|
|
BiExtremes* = object
|
|
first*: Extremes
|
|
second*: Extremes
|
|
|
|
Icosapenta* = ref object
|
|
spelling*: string
|
|
name*: string
|
|
exts*: BiExtremes
|
|
first*: array[V, Penta]
|
|
second*: array[V, Penta]
|
|
|
|
Dictionary* = object
|
|
glyphs*: seq[Glyph]
|
|
dialects*: Table[string, seq[Replacement]]
|
|
words*: seq[Word]
|
|
pentas*: seq[Penta]
|
|
icosipentas*: seq[Icosapenta]
|
|
|
|
const
|
|
Vowel2Char*: array[V, char] = [
|
|
V_I: 'i',
|
|
V_E: 'e',
|
|
V_A: 'a',
|
|
V_O: 'o',
|
|
V_U: 'u'
|
|
]
|
|
|
|
proc replaceFirst(haystack: string, needle: char, content: char): string =
|
|
let idx = haystack.find(needle)
|
|
result = haystack
|
|
result[idx] = content
|
|
|
|
proc replaceLast(haystack: string, needle: char, content: char): string =
|
|
let idx = haystack.rfind(needle)
|
|
result = haystack
|
|
result[idx] = content
|
|
|
|
macro makeposprocs(): untyped =
|
|
result = nnkStmtList.newNimNode
|
|
|
|
for pos in PartOfSpeech:
|
|
let w = ident("w")
|
|
let defns = ident("definitions")
|
|
let name = ident(($pos).toLowerAscii)
|
|
let vpos = pos.newLit
|
|
|
|
result.add quote do:
|
|
proc `name`(short: string) {.used.} =
|
|
`w`.`defns`[`vpos`] = Definition(brief: short, long: string.none)
|
|
|
|
proc `name`(short: string, long: string) {.used.} =
|
|
`w`.`defns`[`vpos`] = Definition(brief: short, long: long.some)
|
|
|
|
template dictionary*(body: untyped) =
|
|
var dict {.inject.}: Dictionary
|
|
dict.glyphs = @[]
|
|
|
|
template glyphs(gbody: untyped) =
|
|
block:
|
|
proc vowel(spelling: string, attrs: varargs[GlyphAttribute]) =
|
|
var v: Glyph = Glyph(spelling: spelling, kind: Vowel)
|
|
for attr in attrs:
|
|
v.attrs.incl attr
|
|
dict.glyphs.add v
|
|
|
|
proc cluster(spelling: string, attrs: varargs[GlyphAttribute]) =
|
|
var c: Glyph = Glyph(spelling: spelling, kind: Cluster)
|
|
for attr in attrs:
|
|
c.attrs.incl attr
|
|
dict.glyphs.add c
|
|
|
|
proc punctuation(spelling: string, attrs: varargs[GlyphAttribute]) =
|
|
var p: Glyph = Glyph(spelling: spelling, kind: Punctuation)
|
|
for attr in attrs:
|
|
p.attrs.incl attr
|
|
dict.glyphs.add p
|
|
|
|
proc numeric(spelling: string, attrs: varargs[GlyphAttribute]) =
|
|
var n: Glyph = Glyph(spelling: spelling, kind: Numeric)
|
|
for attr in attrs:
|
|
n.attrs.incl attr
|
|
dict.glyphs.add n
|
|
|
|
proc syllables() =
|
|
var newglyphs: seq[Glyph]
|
|
for v in dict.glyphs:
|
|
if v.kind != Vowel:
|
|
continue
|
|
|
|
for c in dict.glyphs:
|
|
if c.kind != Cluster:
|
|
continue
|
|
|
|
newglyphs.add Glyph(
|
|
spelling: c.spelling & v.spelling,
|
|
kind: Syllable,
|
|
attrs: v.attrs + c.attrs
|
|
)
|
|
|
|
dict.glyphs.add newglyphs
|
|
|
|
gbody
|
|
|
|
template dialect(name: string, dbody: untyped) =
|
|
block:
|
|
var dial: seq[Replacement]
|
|
proc replace(orig: string, by: string) =
|
|
dial.add Replacement(original: orig, replaced: by)
|
|
|
|
dbody
|
|
|
|
dict.dialects[name] = dial
|
|
|
|
template words(wbody: untyped) =
|
|
block:
|
|
template word(ortho: string, defns: untyped) =
|
|
block:
|
|
var w {.inject.} = Word(spelling: ortho)
|
|
|
|
makeposprocs()
|
|
|
|
defns
|
|
|
|
dict.words.add w
|
|
|
|
template edit_word(theword: Word, defns: untyped) =
|
|
block:
|
|
var w {.inject.}: Word = theword
|
|
|
|
makeposprocs()
|
|
|
|
defns
|
|
|
|
template penta(ortho: string, pname: string, defns: untyped) =
|
|
block:
|
|
var p {.inject.}: Penta = Penta(
|
|
spelling: ortho,
|
|
name: pname,
|
|
exts: Extremes(i: string.none, u: string.none)
|
|
)
|
|
for v in V:
|
|
word ortho.replaceFirst(' ', Vowel2Char[v]):
|
|
p.elems[v] = w
|
|
|
|
proc extremes(i {.inject.}: string, u {.inject.}: string) {.used.} =
|
|
p.exts.i = some(i)
|
|
p.exts.u = some(u)
|
|
|
|
template i(defns2: untyped) {.used.} =
|
|
edit_word p.elems[V_I]: defns2
|
|
template e(defns2: untyped) {.used.} =
|
|
edit_word p.elems[V_E]: defns2
|
|
template a(defns2: untyped) {.used.} =
|
|
edit_word p.elems[V_A]: defns2
|
|
template o(defns2: untyped) {.used.} =
|
|
edit_word p.elems[V_O]: defns2
|
|
template u(defns2: untyped) {.used.} =
|
|
edit_word p.elems[V_U]: defns2
|
|
|
|
defns
|
|
|
|
dict.pentas.add p
|
|
|
|
template icosipenta(iortho: string, iname: string, idefns: untyped) =
|
|
block:
|
|
var i {.inject.}: Icosapenta = Icosapenta(
|
|
spelling: iortho,
|
|
name: iname,
|
|
exts: BiExtremes(
|
|
first: Extremes(i: string.none, u: string.none),
|
|
second: Extremes(i: string.none, u: string.none)
|
|
)
|
|
)
|
|
for v in V:
|
|
penta iortho.replaceFirst(' ', Vowel2Char[v]), Vowel2Char[v] & "x " & iname:
|
|
i.first[v] = p
|
|
|
|
penta iortho.replaceLast(' ', Vowel2Char[v]), "x" & Vowel2Char[v] & " " & iname:
|
|
i.second[v] = p
|
|
|
|
proc firsts(i {.inject.}: string, u {.inject.}: string) {.used.} =
|
|
i.exts.first.i = some(i)
|
|
i.exts.first.u = some(u)
|
|
|
|
proc seconds(i {.inject.}: string, u {.inject.}: string) {.used.} =
|
|
i.exts.second.i = some(i)
|
|
i.exts.second.u = some(u)
|
|
|
|
template ix(defns2: untyped) {.used.} =
|
|
edit_penta i.first[V_I]: defns2
|
|
|
|
# TODO: rest of the -x and x-, plus write edit_penta
|
|
|
|
template ii(defns2: untyped) {.used.} =
|
|
edit_word i.first[V_I].elems[V_I]: defns2
|
|
# TODO: check that this also edits i.second[V_I].elems[V_I]
|
|
|
|
# TODO: rest of the --
|
|
|
|
# NOTE: first extremes is exts, second extremes is elems[*].exts
|
|
|
|
|
|
wbody
|
|
|
|
body
|
|
|
|
proc toJsonHook(attrs: set[GlyphAttribute]): JsonNode =
|
|
newJString(attrs.toSeq.join("-"))
|
|
|
|
proc toJsonHook(glyphs: seq[Glyph]): JsonNode =
|
|
result = newJObject()
|
|
for glyph in glyphs:
|
|
let kindname = ($glyph.kind).toLowerAscii
|
|
if kindname notin result:
|
|
result[kindname] = newJObject()
|
|
result[kindname][glyph.spelling] = glyph.attrs.toJson
|
|
|
|
proc toJsonHook(defns: Table[PartOfSpeech, Definition]): JsonNode =
|
|
result = newJObject()
|
|
for pos, defn in defns:
|
|
result[($pos).toLowerAscii] = defn.toJson
|
|
|
|
proc toJsonHook(words: seq[Word]): JsonNode =
|
|
result = newJObject()
|
|
for word in words:
|
|
result[word.spelling] = word.definitions.toJson
|
|
|
|
proc toJsonHook(exts: Extremes): JsonNode =
|
|
result = newJObject()
|
|
if exts.i.isSome:
|
|
result["i"] = newJString(exts.i.get)
|
|
if exts.u.isSome:
|
|
result["u"] = newJString(exts.u.get)
|
|
|
|
|
|
proc toJson(penta: Penta, dict: Dictionary): JsonNode =
|
|
result = newJObject()
|
|
|
|
result["extremes"] = penta.exts.toJson
|
|
result["name"] = newJString(penta.name)
|
|
# TODO: Consider looking up i/e/a/o/u in dict
|
|
|
|
|
|
proc toJson(pentas: seq[Penta], dict: Dictionary): JsonNode =
|
|
result = newJObject()
|
|
|
|
for penta in pentas:
|
|
result[penta.spelling] = penta.toJson(dict)
|
|
|
|
|
|
proc toJsonHook(dict: Dictionary): JsonNode =
|
|
result = newJObject()
|
|
|
|
result["glyphs"] = dict.glyphs.toJson
|
|
result["dialects"] = dict.dialects.toJson
|
|
result["words"] = dict.words.toJson
|
|
result["pentas"] = dict.pentas.toJson(dict)
|
|
|
|
proc jsonify*(dict: Dictionary): string =
|
|
return $(dict.toJson)
|
|
|
|
when isMainModule:
|
|
dictionary:
|
|
glyphs:
|
|
vowel "i", outer
|
|
vowel "y", both
|
|
|
|
cluster "θ", left, top
|
|
cluster "∫", left, middle
|
|
|
|
syllables()
|
|
|
|
punctuation "«", left
|
|
|
|
numeric "0", circle
|
|
|
|
dialect "jukashenikan":
|
|
replace "x", "ç"
|
|
|
|
dialect "gazhenigan":
|
|
replace "k", "g"
|
|
|
|
words:
|
|
word "t":
|
|
noun "thing", "See t - dmPenta for better meaning."
|
|
# verb "be"
|
|
|
|
penta "n x", "Pronouns":
|
|
extremes(i="Fully proximal", u="Fully distal")
|
|
|
|
i: pronoun "I/me"
|
|
|
|
echo dict.jsonify
|