mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-04 20:17:42 +00:00
302 lines
8.5 KiB
Nim
302 lines
8.5 KiB
Nim
## Generate effective NIF representation for `Enum`
|
|
|
|
import ".." / compiler / [astdef, options]
|
|
|
|
import std / [syncio, assertions, strutils, tables]
|
|
|
|
# We need to duplicate this type here as ast.nim's version of it does not work
|
|
# as it sets the string values explicitly breaking our logic...
|
|
type
|
|
TCallingConventionMirror = enum
|
|
ccNimCall
|
|
ccStdCall
|
|
ccCDecl
|
|
ccSafeCall
|
|
ccSysCall
|
|
ccInline
|
|
ccNoInline
|
|
ccFastCall
|
|
ccThisCall
|
|
ccClosure
|
|
ccNoConvention
|
|
ccMember
|
|
|
|
const
|
|
SpecialCases = [
|
|
("nkCommand", "cmd"),
|
|
("nkIfStmt", "if"),
|
|
("nkError", "err"),
|
|
("nkType", "onlytype"),
|
|
("nkTypeSection", "type"),
|
|
("nkExprEqExpr", "vv"),
|
|
("nkExprColonExpr", "kv"),
|
|
("nkDerefExpr", "deref"),
|
|
("nkReturnStmt", "ret"),
|
|
("nkBreakStmt", "brk"),
|
|
("nkStmtListExpr", "expr"),
|
|
("nkEnumFieldDef", "efld"),
|
|
("nkNilLit", "nil"),
|
|
("ccNoConvention", "noconv"),
|
|
("mExpr", "exprm"),
|
|
("mStmt", "stmtm"),
|
|
("mEqNimrodNode", "eqnimnode"),
|
|
("mPNimrodNode", "nimnode"),
|
|
("mNone", "nonem"),
|
|
("mAsgn", "asgnm"),
|
|
("mOf", "ofm"),
|
|
("mAddr", "addrm"),
|
|
("mType", "typem"),
|
|
("mStatic", "staticm"),
|
|
("mRange", "rangem"),
|
|
("mVar", "varm"),
|
|
("mInSet", "contains"),
|
|
("mNil", "nilm"),
|
|
("nkStmtList", "stmts"),
|
|
("nkDotExpr", "dot"),
|
|
("nkBracketExpr", "at"),
|
|
|
|
("tyNone", "n0"), # we always use a digit for type kinds so there can be no overlap with node kinds
|
|
("tyBool", "b0"),
|
|
("tyChar", "c0"),
|
|
("tyEmpty", "e0"),
|
|
("tyAlias", "a0"),
|
|
("tyNil", "n1"),
|
|
("tyUntyped", "U0"),
|
|
("tyTyped", "t0"),
|
|
("tyTypeDesc", "t1"),
|
|
("tyGenericInvocation", "g0"),
|
|
("tyGenericBody", "g1"),
|
|
("tyGenericInst", "g2"),
|
|
("tyGenericParam", "g4"),
|
|
("tyDistinct", "d0"),
|
|
("tyEnum", "e1"),
|
|
("tyOrdinal", "o0"),
|
|
("tyArray", "a1"),
|
|
("tyObject", "o1"),
|
|
("tyTuple", "t2"),
|
|
("tySet", "s0"),
|
|
("tyRange", "r0"),
|
|
("tyPtr", "p0"),
|
|
("tyRef", "r1"),
|
|
("tyVar", "v0"),
|
|
("tySequence", "s1"),
|
|
("tyProc", "p1"),
|
|
("tyPointer", "p2"),
|
|
("tyOpenArray", "o3"),
|
|
("tyString", "s2"),
|
|
("tyCstring", "c1"),
|
|
("tyForward", "F0"),
|
|
("tyInt", "i0"),
|
|
("tyInt8", "i1"),
|
|
("tyInt16", "i2"),
|
|
("tyInt32", "i3"),
|
|
("tyInt64", "i4"),
|
|
("tyFloat", "f0"),
|
|
("tyFloat32", "f1"),
|
|
("tyFloat64", "f2"),
|
|
("tyFloat128", "f3"),
|
|
("tyUInt", "u0"),
|
|
("tyUInt8", "u1"),
|
|
("tyUInt16", "u2"),
|
|
("tyUInt32", "u3"),
|
|
("tyUInt64", "u4"),
|
|
("tyOwned", "o2"),
|
|
("tySink", "s3"),
|
|
("tyLent", "L0"),
|
|
("tyVarargs", "v1"),
|
|
("tyUncheckedArray", "U1"),
|
|
("tyError", "e2"),
|
|
("tyBuiltInTypeClass", "b1"),
|
|
("tyUserTypeClass", "U2"),
|
|
("tyUserTypeClassInst", "U3"),
|
|
("tyCompositeTypeClass", "c2"),
|
|
("tyInferred", "I0"),
|
|
("tyAnd", "a2"),
|
|
("tyOr", "o4"),
|
|
("tyNot", "n2"),
|
|
("tyAnything", "a3"),
|
|
("tyStatic", "s4"),
|
|
("tyFromExpr", "F1"),
|
|
("tyConcept", "c3"),
|
|
("tyVoid", "v2"),
|
|
("tyIterable", "I1")
|
|
]
|
|
SuffixesToReplace = [
|
|
("Section", ""), ("Branch", ""), ("Stmt", ""), ("I", ""),
|
|
("Expr", "x"), ("Def", "")
|
|
]
|
|
PrefixesToReplace = [
|
|
("Length", "len"),
|
|
("SetLength", "setlen"),
|
|
("Append", "add")
|
|
]
|
|
AdditionalNodes = [
|
|
"nf", # "node flag"
|
|
"tf", # "type flag"
|
|
"sf", # "sym flag"
|
|
"htype", # annotated with a hidden type
|
|
"missing"
|
|
]
|
|
|
|
proc genEnum[E](f: var File; enumName: string; known: var OrderedTable[string, bool]; prefixLen = 2) =
|
|
var mappingA = initOrderedTable[string, E]()
|
|
var cases = ""
|
|
for e in low(E)..high(E):
|
|
var es = $e
|
|
if es.startsWith("nkHidden"):
|
|
es = es.replace("nkHidden", "nkh") # prefix will be removed
|
|
else:
|
|
for (suffix, repl) in items SuffixesToReplace:
|
|
if es.len - prefixLen > suffix.len and es.endsWith(suffix):
|
|
es.setLen es.len - len(suffix)
|
|
es.add repl
|
|
break
|
|
for (suffix, repl) in items PrefixesToReplace:
|
|
if es.len - prefixLen > suffix.len and es.substr(prefixLen).startsWith(suffix):
|
|
es = es.substr(0, prefixLen-1) & repl & es.substr(prefixLen+suffix.len)
|
|
break
|
|
|
|
let s = es.substr(prefixLen)
|
|
var done = false
|
|
for enu, key in items SpecialCases:
|
|
if $e == enu:
|
|
assert(not mappingA.hasKey(key))
|
|
if known.hasKey(key): echo "conflict: ", key
|
|
known[key] = true
|
|
assert key.len > 0
|
|
mappingA[key] = e
|
|
cases.add " of " & $e & ": " & escape(key) & "\n"
|
|
done = true
|
|
break
|
|
if not done:
|
|
let key = s.toLowerAscii
|
|
if not mappingA.hasKey(key):
|
|
assert key.len > 0, $e
|
|
if known.hasKey(key): echo "conflict: ", key
|
|
known[key] = true
|
|
mappingA[key] = e
|
|
cases.add " of " & $e & ": " & escape(key) & "\n"
|
|
done = true
|
|
if not done:
|
|
var d = 0
|
|
while d < 10:
|
|
let key = s.toLowerAscii & $d
|
|
if not mappingA.hasKey(key):
|
|
assert key.len > 0
|
|
mappingA[key] = e
|
|
cases.add " of " & $e & ": " & escape(key) & "\n"
|
|
done = true
|
|
break
|
|
inc d
|
|
if not done:
|
|
echo "Could not map: " & s
|
|
#echo mapping
|
|
var code = ""
|
|
code.add "proc toNifTag*(s: " & enumName & "): string =\n"
|
|
code.add " case s\n"
|
|
code.add cases
|
|
code.add "\n\n"
|
|
let procname = "parse" # & enumName.substr(1)
|
|
code.add "proc " & procname & "*(t: typedesc[" & enumName & "]; s: string): " & enumName & " =\n"
|
|
code.add " case s\n"
|
|
for (k, v) in pairs mappingA:
|
|
code.add " of " & escape(k) & ": " & $v & "\n"
|
|
code.add " else: " & $low(E) & "\n\n\n"
|
|
f.write code
|
|
|
|
proc genEnum[E](f: var File; enumName: string; prefixLen = 2) =
|
|
var known = initOrderedTable[string, bool]()
|
|
genEnum[E](f, enumName, known, prefixLen)
|
|
|
|
|
|
proc genFlags[E](f: var File; enumName: string; prefixLen = 2) =
|
|
var mappingA = initOrderedTable[string, E]()
|
|
var mappingB = initOrderedTable[string, E]()
|
|
var cases = ""
|
|
for e in low(E)..high(E):
|
|
let s = ($e).substr(prefixLen)
|
|
var done = false
|
|
for c in s:
|
|
if c in {'A'..'Z'}:
|
|
let key = $c.toLowerAscii
|
|
if not mappingA.hasKey(key):
|
|
mappingA[key] = e
|
|
cases.add " of " & $e & ": dest.add " & escape(key) & "\n"
|
|
done = true
|
|
break
|
|
if not done:
|
|
var d = 0
|
|
while d < 10:
|
|
let key = $s[0].toLowerAscii & $d
|
|
if not mappingB.hasKey(key):
|
|
mappingB[key] = e
|
|
cases.add " of " & $e & ": dest.add " & escape(key) & "\n"
|
|
done = true
|
|
break
|
|
inc d
|
|
if not done:
|
|
quit "Could not map: " & s
|
|
#echo mapping
|
|
var code = ""
|
|
code.add "proc genFlags*(s: set[" & enumName & "]; dest: var string) =\n"
|
|
code.add " for e in s:\n"
|
|
code.add " case e\n"
|
|
code.add cases
|
|
code.add "\n\n"
|
|
code.add "proc parse*(t: typedesc[" & enumName & "]; s: string): set[" & enumName & "] =\n"
|
|
code.add " result = {}\n"
|
|
code.add " var i = 0\n"
|
|
code.add " while i < s.len:\n"
|
|
code.add " case s[i]\n"
|
|
for c in 'a'..'z':
|
|
var letterFound = false
|
|
var digitsFound = 0
|
|
for d in '0'..'9':
|
|
if mappingB.hasKey($c & $d):
|
|
if not letterFound:
|
|
letterFound = true
|
|
code.add " of '" & c & "':\n"
|
|
if digitsFound == 0:
|
|
code.add " if"
|
|
else:
|
|
code.add " elif"
|
|
inc digitsFound
|
|
code.add " i+1 < s.len and s[i+1] == '" & d & "':\n"
|
|
code.add " result.incl " & $mappingB[$c & $d] & "\n"
|
|
code.add " inc i\n"
|
|
|
|
if mappingA.hasKey($c):
|
|
if digitsFound == 0:
|
|
code.add " of '" & c & "': "
|
|
else:
|
|
code.add " else: "
|
|
code.add "result.incl " & $mappingA[$c] & "\n"
|
|
|
|
code.add " else: discard\n"
|
|
code.add " inc i\n\n"
|
|
f.write code
|
|
|
|
var f = open("compiler/ic/enum2nif.nim", fmWrite)
|
|
f.write "# Generated by tools/enumgen.nim. DO NOT EDIT!\n\n"
|
|
f.write "import \"..\" / [ast, options]\n\n"
|
|
# use the same mapping for TNodeKind and TMagic so that we can detect conflicts!
|
|
var nodeTags = initOrderedTable[string, bool]()
|
|
for a in AdditionalNodes:
|
|
nodeTags[a] = true
|
|
|
|
genEnum[TNodeKind](f, "TNodeKind", nodeTags)
|
|
genEnum[TSymKind](f, "TSymKind")
|
|
genEnum[TTypeKind](f, "TTypeKind")
|
|
genEnum[TLocKind](f, "TLocKind", 3)
|
|
genEnum[TCallingConventionMirror](f, "TCallingConvention", 2)
|
|
genEnum[TMagic](f, "TMagic", nodeTags, 1)
|
|
genEnum[TStorageLoc](f, "TStorageLoc")
|
|
genEnum[TLibKind](f, "TLibKind")
|
|
genFlags[TSymFlag](f, "TSymFlag")
|
|
genFlags[TNodeFlag](f, "TNodeFlag")
|
|
genFlags[TTypeFlag](f, "TTypeFlag")
|
|
genFlags[TLocFlag](f, "TLocFlag")
|
|
genFlags[TOption](f, "TOption", 3)
|
|
|
|
f.close()
|