generic define pragma + string alias (#20979)

* generic `define` pragma + string alias

* clean

* add tests and document

* remove char/float, minimize changelog
This commit is contained in:
metagn 2022-12-13 23:20:55 +03:00 • committed by GitHub
commit 9a50033d5b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 218 additions and 53 deletions

View file

@ -712,7 +712,7 @@ type
mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mNGenSym,
mNHint, mNWarning, mNError,
mInstantiationInfo, mGetTypeInfo, mGetTypeInfoV2,
mNimvm, mIntDefine, mStrDefine, mBoolDefine, mRunnableExamples,
mNimvm, mIntDefine, mStrDefine, mBoolDefine, mGenericDefine, mRunnableExamples,
mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf,
mSymIsInstantiationOf, mNodeId, mPrivateAccess, mZeroDefault

View file

@ -149,3 +149,5 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasOutParams")
defineSymbol("nimHasSystemRaisesDefect")
defineSymbol("nimHasWarnUnnamedBreak")
defineSymbol("nimHasGenericDefine")
defineSymbol("nimHasDefineAliases")

View file

@ -81,7 +81,8 @@ const
wGuard, wGoto, wCursor, wNoalias, wAlign}
constPragmas* = declPragmas + {wHeader, wMagic,
wGensym, wInject,
wIntDefine, wStrDefine, wBoolDefine, wCompilerProc, wCore}
wIntDefine, wStrDefine, wBoolDefine, wDefine,
wCompilerProc, wCore}
paramPragmas* = {wNoalias, wInject, wGensym}
letPragmas* = varPragmas
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNoSideEffect,
@ -476,8 +477,16 @@ proc processPop(c: PContext, n: PNode) =
when defined(debugOptions):
echo c.config $ n.info, " POP config is now ", c.config.options
proc processDefine(c: PContext, n: PNode) =
if (n.kind in nkPragmaCallKinds and n.len == 2) and (n[1].kind == nkIdent):
proc processDefineConst(c: PContext, n: PNode, sym: PSym, kind: TMagic) =
sym.magic = kind
if n.kind in nkPragmaCallKinds and n.len == 2:
# could also use TLib
n[1] = getStrLitNode(c, n)
proc processDefine(c: PContext, n: PNode, sym: PSym) =
if sym != nil and sym.kind == skConst:
processDefineConst(c, n, sym, mGenericDefine)
elif (n.kind in nkPragmaCallKinds and n.len == 2) and (n[1].kind == nkIdent):
defineSymbol(c.config.symbols, n[1].ident.s)
else:
invalidPragma(c, n)
@ -1066,7 +1075,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
recordPragma(c, it, "error", s)
localError(c.config, it.info, errUser, s)
of wFatal: fatal(c.config, it.info, expectStrLit(c, it))
of wDefine: processDefine(c, it)
of wDefine: processDefine(c, it, sym)
of wUndef: processUndef(c, it)
of wCompile: processCompile(c, it)
of wLink: processLink(c, it)
@ -1213,11 +1222,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
noVal(c, it)
sym.flags.incl sfBase
of wIntDefine:
sym.magic = mIntDefine
processDefineConst(c, n, sym, mIntDefine)
of wStrDefine:
sym.magic = mStrDefine
processDefineConst(c, n, sym, mStrDefine)
of wBoolDefine:
sym.magic = mBoolDefine
processDefineConst(c, n, sym, mBoolDefine)
of wUsed:
noVal(c, it)
if sym == nil: invalidPragma(c, it)

View file

@ -13,7 +13,7 @@
import
strutils, options, ast, trees, nimsets,
platform, math, msgs, idents, renderer, types,
commands, magicsys, modulegraphs, strtabs, lineinfos
commands, magicsys, modulegraphs, strtabs, lineinfos, wordrecg
from system/memory import nimCStrLen
@ -371,6 +371,11 @@ proc rangeCheck(n: PNode, value: Int128; g: ModuleGraph) =
localError(g.config, n.info, "cannot convert " & $value &
" to " & typeToString(n.typ))
proc floatRangeCheck(n: PNode, value: BiggestFloat; g: ModuleGraph) =
if value < firstFloat(n.typ) or value > lastFloat(n.typ):
localError(g.config, n.info, "cannot convert " & $value &
" to " & typeToString(n.typ))
proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): PNode =
let dstTyp = skipTypes(n.typ, abstractRange - {tyTypeDesc})
let srcTyp = skipTypes(a.typ, abstractRange - {tyTypeDesc})
@ -490,6 +495,81 @@ proc newSymNodeTypeDesc*(s: PSym; idgen: IdGenerator; info: TLineInfo): PNode =
else:
result.typ = s.typ
proc foldDefine(m, s: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
var name = s.name.s
let prag = extractPragma(s)
if prag != nil:
for it in prag:
if it.kind in nkPragmaCallKinds and it.len == 2 and it[0].kind == nkIdent:
let word = whichKeyword(it[0].ident)
if word in {wStrDefine, wIntDefine, wBoolDefine, wDefine}:
# should be processed in pragmas.nim already
if it[1].kind in {nkStrLit, nkRStrLit, nkTripleStrLit}:
name = it[1].strVal
if isDefined(g.config, name):
let str = g.config.symbols[name]
case s.magic
of mIntDefine:
try:
result = newIntNodeT(toInt128(str.parseInt), n, idgen, g)
except ValueError:
localError(g.config, s.info,
"{.intdefine.} const was set to an invalid integer: '" &
str & "'")
of mStrDefine:
result = newStrNodeT(str, n, g)
of mBoolDefine:
try:
result = newIntNodeT(toInt128(str.parseBool.int), n, idgen, g)
except ValueError:
localError(g.config, s.info,
"{.booldefine.} const was set to an invalid bool: '" &
str & "'")
of mGenericDefine:
let rawTyp = s.typ
# pretend we don't support distinct types
let typ = rawTyp.skipTypes(abstractVarRange-{tyDistinct})
try:
template intNode(value): PNode =
let val = toInt128(value)
rangeCheck(n, val, g)
newIntNodeT(val, n, idgen, g)
case typ.kind
of tyString, tyCstring:
result = newStrNodeT(str, n, g)
of tyInt..tyInt64:
result = intNode(str.parseBiggestInt)
of tyUInt..tyUInt64:
result = intNode(str.parseBiggestUInt)
of tyBool:
result = intNode(str.parseBool.int)
of tyEnum:
# compile time parseEnum
let ident = getIdent(g.cache, str)
for e in typ.n:
if e.kind != nkSym: internalError(g.config, "foldDefine for enum")
let es = e.sym
let match =
if es.ast.isNil:
es.name.id == ident.id
else:
es.ast.strVal == str
if match:
result = intNode(es.position)
break
if result.isNil:
raise newException(ValueError, "invalid enum value: " & str)
else:
localError(g.config, s.info, "unsupported type $1 for define '$2'" %
[name, typeToString(rawTyp)])
except ValueError as e:
localError(g.config, s.info,
"could not process define '$1' of type $2; $3" %
[name, typeToString(rawTyp), e.msg])
else: result = copyTree(s.astdef) # unreachable
else:
result = copyTree(s.astdef)
proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
result = nil
case n.kind
@ -509,31 +589,8 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
of mBuildOS: result = newStrNodeT(toLowerAscii(platform.OS[g.config.target.hostOS].name), n, g)
of mBuildCPU: result = newStrNodeT(platform.CPU[g.config.target.hostCPU].name.toLowerAscii, n, g)
of mAppType: result = getAppType(n, g)
of mIntDefine:
if isDefined(g.config, s.name.s):
try:
result = newIntNodeT(toInt128(g.config.symbols[s.name.s].parseInt), n, idgen, g)
except ValueError:
localError(g.config, s.info,
"{.intdefine.} const was set to an invalid integer: '" &
g.config.symbols[s.name.s] & "'")
else:
result = copyTree(s.astdef)
of mStrDefine:
if isDefined(g.config, s.name.s):
result = newStrNodeT(g.config.symbols[s.name.s], n, g)
else:
result = copyTree(s.astdef)
of mBoolDefine:
if isDefined(g.config, s.name.s):
try:
result = newIntNodeT(toInt128(g.config.symbols[s.name.s].parseBool.int), n, idgen, g)
except ValueError:
localError(g.config, s.info,
"{.booldefine.} const was set to an invalid bool: '" &
g.config.symbols[s.name.s] & "'")
else:
result = copyTree(s.astdef)
of mIntDefine, mStrDefine, mBoolDefine, mGenericDefine:
result = foldDefine(m, s, n, idgen, g)
else:
result = copyTree(s.astdef)
of skProc, skFunc, skMethod: