shenikan/dsl.nim
2024-04-12 01:05:15 -04:00

221 lines
6.3 KiB
Nim

import std/macros
import std/tables
import std/options
import std/strutils
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
Definition* = object
brief*: string
long*: Option[string]
Word* = object
spelling*: string
definitions*: Table[PartOfSpeech, Definition]
Extremes* = object
i*: Option[string]
u*: Option[string]
Penta*[T] = object
spelling*: string
name*: string
exts*: Extremes
i*: ptr T
e*: ptr T
a*: ptr T
o*: ptr T
u*: ptr T
Dictionary* = object
glyphs*: seq[Glyph]
dialects*: Table[string, seq[Replacement]]
words*: seq[Word]
pentas*: seq[Penta[Word]]
proc replaceFirst(haystack: string, needle: char, content: char): string =
let idx = haystack.find(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 = Word(spelling: ortho)
makeposprocs()
defns
dict.words.add w
template penta(ortho: string, pname: string, defns: untyped) =
block:
var p {.inject.}: Penta[Word]
p.spelling = ortho
proc extremes(i {.inject.}: string, u {.inject.}: string) {.used.} =
p.exts.i = some(i)
p.exts.u = some(u)
template i(defns2: untyped) {.used.} =
word ortho.replaceFirst(' ', 'i'): defns2; p.i = w.addr
template e(defns2: untyped) {.used.} =
word ortho.replaceFirst(' ', 'e'): defns2; p.e = w.addr
template a(defns2: untyped) {.used.} =
word ortho.replaceFirst(' ', 'a'): defns2; p.a = w.addr
template o(defns2: untyped) {.used.} =
word ortho.replaceFirst(' ', 'o'): defns2; p.o = w.addr
template u(defns2: untyped) {.used.} =
word ortho.replaceFirst(' ', 'u'): defns2; p.u = w.addr
p.spelling = ortho
p.name = pname
defns
dict.pentas.add p
wbody
# TODO: penta[X]s
body
proc toJSON*(dict: Dictionary): string =
return $dict
# TODO: stringify to JSON
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.toJSON