experimental support for preserving local variable names in the generated code
This commit is contained in:
parent
caf7878009
commit
f25c638dc4
6 changed files with 146 additions and 22 deletions
|
|
@ -244,13 +244,18 @@ const
|
||||||
sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher
|
sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher
|
||||||
sfNoInit* = sfMainModule # don't generate code to init the variable
|
sfNoInit* = sfMainModule # don't generate code to init the variable
|
||||||
|
|
||||||
sfImmediate* = sfDeadCodeElim # macro or template is immediately expanded
|
sfImmediate* = sfDeadCodeElim
|
||||||
|
# macro or template is immediately expanded
|
||||||
# without considering any possible overloads
|
# without considering any possible overloads
|
||||||
|
|
||||||
sfAnon* = sfCompilerProc # symbol name that was generated by the compiler
|
sfAnon* = sfDiscardable
|
||||||
|
# symbol name that was generated by the compiler
|
||||||
# the compiler will avoid printing such names
|
# the compiler will avoid printing such names
|
||||||
# in user messages.
|
# in user messages.
|
||||||
|
|
||||||
|
sfShadowed* = sfInnerProc
|
||||||
|
# a variable that was shadowed in some inner scope
|
||||||
|
|
||||||
const
|
const
|
||||||
# getting ready for the future expr/stmt merge
|
# getting ready for the future expr/stmt merge
|
||||||
nkWhen* = nkWhenStmt
|
nkWhen* = nkWhenStmt
|
||||||
|
|
@ -647,6 +652,14 @@ const
|
||||||
resultPos* = 5
|
resultPos* = 5
|
||||||
dispatcherPos* = 6 # caution: if method has no 'result' it can be position 5!
|
dispatcherPos* = 6 # caution: if method has no 'result' it can be position 5!
|
||||||
|
|
||||||
|
nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix,
|
||||||
|
nkCommand, nkCallStrLit}
|
||||||
|
|
||||||
|
nkLambdaKinds* = {nkLambda, nkDo}
|
||||||
|
|
||||||
|
skLocalVars* = {skVar, skLet, skForVar, skParam}
|
||||||
|
|
||||||
|
|
||||||
# creator procs:
|
# creator procs:
|
||||||
proc NewSym*(symKind: TSymKind, Name: PIdent, owner: PSym): PSym
|
proc NewSym*(symKind: TSymKind, Name: PIdent, owner: PSym): PSym
|
||||||
proc NewType*(kind: TTypeKind, owner: PSym): PType
|
proc NewType*(kind: TTypeKind, owner: PSym): PType
|
||||||
|
|
@ -691,11 +704,6 @@ proc copyNode*(src: PNode): PNode
|
||||||
proc copyTree*(src: PNode): PNode
|
proc copyTree*(src: PNode): PNode
|
||||||
# does copy its sons!
|
# does copy its sons!
|
||||||
|
|
||||||
const nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand,
|
|
||||||
nkCallStrLit}
|
|
||||||
|
|
||||||
const nkLambdaKinds* = {nkLambda, nkDo}
|
|
||||||
|
|
||||||
proc isCallExpr*(n: PNode): bool =
|
proc isCallExpr*(n: PNode): bool =
|
||||||
result = n.kind in nkCallKinds
|
result = n.kind in nkCallKinds
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,15 @@ proc mangle(name: string): string =
|
||||||
add(result, "HEX")
|
add(result, "HEX")
|
||||||
add(result, toHex(ord(name[i]), 2))
|
add(result, toHex(ord(name[i]), 2))
|
||||||
|
|
||||||
|
proc isCKeyword(w: PIdent): bool =
|
||||||
|
# nimrod and C++ share some keywords
|
||||||
|
# it's more efficient to test the whole nimrod keywords range
|
||||||
|
case w.id
|
||||||
|
of cppKeywordsLow..cppKeywordsHigh,
|
||||||
|
nimKeywordsLow..nimKeywordsHigh,
|
||||||
|
ord(wInline): return true
|
||||||
|
else: return false
|
||||||
|
|
||||||
proc mangleName(s: PSym): PRope =
|
proc mangleName(s: PSym): PRope =
|
||||||
result = s.loc.r
|
result = s.loc.r
|
||||||
if result == nil:
|
if result == nil:
|
||||||
|
|
@ -45,6 +54,61 @@ proc mangleName(s: PSym): PRope =
|
||||||
of skTemp, skParam, skType, skEnumField, skModule:
|
of skTemp, skParam, skType, skEnumField, skModule:
|
||||||
result = toRope("%")
|
result = toRope("%")
|
||||||
else: InternalError(s.info, "mangleName")
|
else: InternalError(s.info, "mangleName")
|
||||||
|
when oKeepVariableNames:
|
||||||
|
let keepOrigName = s.kind in skLocalVars - {skForVar} and
|
||||||
|
{sfFromGeneric, sfGlobal, sfShadowed} * s.flags == {} and
|
||||||
|
not isCKeyword(s.name)
|
||||||
|
# XXX: This is still very experimental
|
||||||
|
#
|
||||||
|
# Even with all these inefficient checks, the bootstrap
|
||||||
|
# time is actually improved. This is probably because so many
|
||||||
|
# rope concatenations and are now eliminated.
|
||||||
|
#
|
||||||
|
# Future notes:
|
||||||
|
# sfFromGeneric seems to be needed in order to avoid multiple
|
||||||
|
# definitions of certain varialbes generated in transf with
|
||||||
|
# names such as:
|
||||||
|
# `r`, `res`
|
||||||
|
# I need to study where these come from.
|
||||||
|
#
|
||||||
|
# about sfShadowed:
|
||||||
|
# consider the following nimrod code:
|
||||||
|
# var x = 10
|
||||||
|
# block:
|
||||||
|
# var x = something(x)
|
||||||
|
# The generated C code will be:
|
||||||
|
# NI x;
|
||||||
|
# x = 10;
|
||||||
|
# {
|
||||||
|
# NI x;
|
||||||
|
# x = something(x); // Oops, x is already shadowed here
|
||||||
|
# }
|
||||||
|
# Right now, we work-around by not keeping the original name
|
||||||
|
# of the shadowed variable, but we can do better - we can
|
||||||
|
# create an alternative reference to it in the outer scope and
|
||||||
|
# use that in the inner scope.
|
||||||
|
#
|
||||||
|
# about isCKeyword:
|
||||||
|
# nimrod variable names can be C keywords.
|
||||||
|
# We need to avoid such names in the generated code.
|
||||||
|
# XXX: Study whether mangleName is called just once per variable.
|
||||||
|
# Otherwise, there might be better place to do this.
|
||||||
|
#
|
||||||
|
# about sfGlobal:
|
||||||
|
# This seems to be harder - a top level extern variable from
|
||||||
|
# another modules can have the same name as a local one.
|
||||||
|
# Maybe we should just implement sfShadowed for them too.
|
||||||
|
#
|
||||||
|
# about skForVar:
|
||||||
|
# These are not properly scoped now - we need to add blocks
|
||||||
|
# around for loops in transf
|
||||||
|
if keepOrigName:
|
||||||
|
result = s.name.s.toRope
|
||||||
|
else:
|
||||||
|
app(result, toRope(mangle(s.name.s)))
|
||||||
|
app(result, "_")
|
||||||
|
app(result, toRope(s.id))
|
||||||
|
else:
|
||||||
app(result, toRope(mangle(s.name.s)))
|
app(result, toRope(mangle(s.name.s)))
|
||||||
app(result, "_")
|
app(result, "_")
|
||||||
app(result, toRope(s.id))
|
app(result, toRope(s.id))
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,8 @@ var
|
||||||
implicitImports*: seq[string] = @[] # modules that are to be implicitly imported
|
implicitImports*: seq[string] = @[] # modules that are to be implicitly imported
|
||||||
implicitIncludes*: seq[string] = @[] # modules that are to be implicitly included
|
implicitIncludes*: seq[string] = @[] # modules that are to be implicitly included
|
||||||
|
|
||||||
|
const oKeepVariableNames* = true
|
||||||
|
|
||||||
proc mainCommandArg*: string =
|
proc mainCommandArg*: string =
|
||||||
## This is intended for commands like check or parse
|
## This is intended for commands like check or parse
|
||||||
## which will work on the main project file unless
|
## which will work on the main project file unless
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@
|
||||||
# So we have to eval templates/macros right here so that symbol
|
# So we have to eval templates/macros right here so that symbol
|
||||||
# lookup can be accurate.
|
# lookup can be accurate.
|
||||||
|
|
||||||
|
# included from sem.nim
|
||||||
|
|
||||||
type
|
type
|
||||||
TSemGenericFlag = enum
|
TSemGenericFlag = enum
|
||||||
withinBind, withinTypeDesc
|
withinBind, withinTypeDesc
|
||||||
|
|
|
||||||
|
|
@ -217,6 +217,13 @@ proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode =
|
||||||
elif not sameType(result.typ, typ):
|
elif not sameType(result.typ, typ):
|
||||||
changeType(result, typ)
|
changeType(result, typ)
|
||||||
|
|
||||||
|
proc findShadowedVar(c: PContext, v: PSym): PSym =
|
||||||
|
for i in countdown(c.tab.tos - 2, 0):
|
||||||
|
let shadowed = StrTableGet(c.tab.stack[i], v.name)
|
||||||
|
if shadowed != nil:
|
||||||
|
if shadowed.kind in skLocalVars:
|
||||||
|
return shadowed
|
||||||
|
|
||||||
proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
|
proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
|
||||||
if isTopLevel(c):
|
if isTopLevel(c):
|
||||||
result = semIdentWithPragma(c, kind, n, {sfExported})
|
result = semIdentWithPragma(c, kind, n, {sfExported})
|
||||||
|
|
@ -267,6 +274,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
for j in countup(0, length-3):
|
for j in countup(0, length-3):
|
||||||
var v = semIdentDef(c, a.sons[j], symkind)
|
var v = semIdentDef(c, a.sons[j], symkind)
|
||||||
addInterfaceDecl(c, v)
|
addInterfaceDecl(c, v)
|
||||||
|
when oKeepVariableNames:
|
||||||
|
let shadowed = findShadowedVar(c, v)
|
||||||
|
if shadowed != nil: shadowed.flags.incl(sfShadowed)
|
||||||
if def != nil and def.kind != nkEmpty:
|
if def != nil and def.kind != nkEmpty:
|
||||||
# this is only needed for the evaluation pass:
|
# this is only needed for the evaluation pass:
|
||||||
v.ast = def
|
v.ast = def
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,8 @@ type
|
||||||
wMagic, wThread, wFinal, wProfiler, wObjChecks,
|
wMagic, wThread, wFinal, wProfiler, wObjChecks,
|
||||||
wImmediate, wImportCpp, wImportObjC,
|
wImmediate, wImportCpp, wImportObjC,
|
||||||
wImportCompilerProc,
|
wImportCompilerProc,
|
||||||
wImportc, wExportc, wExtern, wIncompleteStruct,
|
wImportc, wExportc, wIncompleteStruct,
|
||||||
wAlign, wNodecl, wPure, wVolatile, wRegister, wSideeffect, wHeader,
|
wAlign, wNodecl, wPure, wSideeffect, wHeader,
|
||||||
wNosideeffect, wNoreturn, wMerge, wLib, wDynlib, wCompilerproc, wProcVar,
|
wNosideeffect, wNoreturn, wMerge, wLib, wDynlib, wCompilerproc, wProcVar,
|
||||||
wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef,
|
wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef,
|
||||||
wLinedir, wStacktrace, wLinetrace, wLink, wCompile,
|
wLinedir, wStacktrace, wLinetrace, wLink, wCompile,
|
||||||
|
|
@ -58,13 +58,36 @@ type
|
||||||
wWatchPoint, wSubsChar,
|
wWatchPoint, wSubsChar,
|
||||||
wAcyclic, wShallow, wUnroll, wLinearScanEnd,
|
wAcyclic, wShallow, wUnroll, wLinearScanEnd,
|
||||||
wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wNoStackFrame,
|
wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wNoStackFrame,
|
||||||
wImplicitStatic, wGlobal
|
wImplicitStatic, wGlobal,
|
||||||
|
|
||||||
|
wAuto, wBool, wCatch, wChar, wClass,
|
||||||
|
wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast,
|
||||||
|
wExplicit, wExtern, wFalse, wFloat, wFriend,
|
||||||
|
wGoto, wInt, wLong, wMutable, wNamespace, wNew, wOperator,
|
||||||
|
wPrivate, wProtected, wPublic, wRegister, wReinterpret_cast,
|
||||||
|
wShort, wSigned, wSizeof, wStatic_cast, wStruct, wSwitch,
|
||||||
|
wThis, wThrow, wTrue, wTypedef, wTypeid, wTypename,
|
||||||
|
wUnion, wUnsigned, wUsing, wVirtual, wVoid, wVolatile, wWchar_t,
|
||||||
|
|
||||||
|
wAlignas, wAlignof, wConstexpr, wDecltype, wNullptr, wNoexcept,
|
||||||
|
wThread_local, wStatic_assert, wChar16_t, wChar32_t,
|
||||||
|
|
||||||
TSpecialWords* = set[TSpecialWord]
|
TSpecialWords* = set[TSpecialWord]
|
||||||
|
|
||||||
const
|
const
|
||||||
oprLow* = ord(wColon)
|
oprLow* = ord(wColon)
|
||||||
oprHigh* = ord(wDotDot)
|
oprHigh* = ord(wDotDot)
|
||||||
|
|
||||||
|
nimKeywordsLow* = ord(wAsm)
|
||||||
|
nimKeywordsHigh* = ord(wYield)
|
||||||
|
|
||||||
|
cppKeywordsLow* = ord(wAuto)
|
||||||
|
cppKeywordsHigh* = ord(wChar32_t)
|
||||||
|
|
||||||
|
cppNimSharedKeywords* = {
|
||||||
|
wAsm, wBreak, wCase, wConst, wContinue, wDo, wElse, wEnum, wExport,
|
||||||
|
wFor, wIf, wReturn, wStatic, wTemplate, wTry, wWhile }
|
||||||
|
|
||||||
specialWords*: array[low(TSpecialWord)..high(TSpecialWord), string] = ["",
|
specialWords*: array[low(TSpecialWord)..high(TSpecialWord), string] = ["",
|
||||||
|
|
||||||
"addr", "and", "as", "asm", "atomic",
|
"addr", "and", "as", "asm", "atomic",
|
||||||
|
|
@ -86,8 +109,8 @@ const
|
||||||
"magic", "thread", "final", "profiler", "objchecks",
|
"magic", "thread", "final", "profiler", "objchecks",
|
||||||
|
|
||||||
"immediate", "importcpp", "importobjc",
|
"immediate", "importcpp", "importobjc",
|
||||||
"importcompilerproc", "importc", "exportc", "extern", "incompletestruct",
|
"importcompilerproc", "importc", "exportc", "incompletestruct",
|
||||||
"align", "nodecl", "pure", "volatile", "register", "sideeffect",
|
"align", "nodecl", "pure", "sideeffect",
|
||||||
"header", "nosideeffect", "noreturn", "merge", "lib", "dynlib",
|
"header", "nosideeffect", "noreturn", "merge", "lib", "dynlib",
|
||||||
"compilerproc", "procvar", "fatal", "error", "warning", "hint", "line",
|
"compilerproc", "procvar", "fatal", "error", "warning", "hint", "line",
|
||||||
"push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace",
|
"push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace",
|
||||||
|
|
@ -107,7 +130,22 @@ const
|
||||||
"watchpoint",
|
"watchpoint",
|
||||||
"subschar", "acyclic", "shallow", "unroll", "linearscanend",
|
"subschar", "acyclic", "shallow", "unroll", "linearscanend",
|
||||||
"write", "putenv", "prependenv", "appendenv", "threadvar", "emit",
|
"write", "putenv", "prependenv", "appendenv", "threadvar", "emit",
|
||||||
"nostackframe", "implicitstatic", "global"]
|
"nostackframe", "implicitstatic", "global",
|
||||||
|
|
||||||
|
"auto", "bool", "catch", "char", "class",
|
||||||
|
"const_cast", "default", "delete", "double",
|
||||||
|
"dynamic_cast", "explicit", "extern", "false",
|
||||||
|
"float", "friend", "goto", "int", "long", "mutable",
|
||||||
|
"namespace", "new", "operator",
|
||||||
|
"private", "protected", "public", "register", "reinterpret_cast",
|
||||||
|
"short", "signed", "sizeof", "static_cast", "struct", "switch",
|
||||||
|
"this", "throw", "true", "typedef", "typeid",
|
||||||
|
"typename", "union", "unsigned", "using", "virtual", "void", "volatile",
|
||||||
|
"wchar_t",
|
||||||
|
|
||||||
|
"alignas", "alignof", "constexpr", "decltype", "nullptr", "noexcept",
|
||||||
|
"thread_local", "static_assert", "char16_t", "char32_t",
|
||||||
|
]
|
||||||
|
|
||||||
proc findStr*(a: openarray[string], s: string): int =
|
proc findStr*(a: openarray[string], s: string): int =
|
||||||
for i in countup(low(a), high(a)):
|
for i in countup(low(a), high(a)):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue