diff options
author | Zahary Karadjov <zahary@gmail.com> | 2012-04-13 16:01:26 +0300 |
---|---|---|
committer | Zahary Karadjov <zahary@gmail.com> | 2012-04-13 21:03:49 +0300 |
commit | f25c638dc4109445ce1476d6e6f18be034805a0a (patch) | |
tree | 9ce68a56248a03ca6a97a4a80b1cf376f66ec531 /compiler | |
parent | caf78780096c157560f50cf0a4958fdf07d09a7d (diff) | |
download | Nim-f25c638dc4109445ce1476d6e6f18be034805a0a.tar.gz |
experimental support for preserving local variable names in the generated code
Diffstat (limited to 'compiler')
-rwxr-xr-x | compiler/ast.nim | 28 | ||||
-rwxr-xr-x | compiler/ccgtypes.nim | 70 | ||||
-rwxr-xr-x | compiler/options.nim | 4 | ||||
-rwxr-xr-x | compiler/semgnrc.nim | 2 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 12 | ||||
-rwxr-xr-x | compiler/wordrecg.nim | 52 |
6 files changed, 146 insertions, 22 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index c6a2b32e7..10a3d8039 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -244,12 +244,17 @@ const sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher sfNoInit* = sfMainModule # don't generate code to init the variable - sfImmediate* = sfDeadCodeElim # macro or template is immediately expanded - # without considering any possible overloads + sfImmediate* = sfDeadCodeElim + # macro or template is immediately expanded + # without considering any possible overloads - sfAnon* = sfCompilerProc # symbol name that was generated by the compiler - # the compiler will avoid printing such names - # in user messages. + sfAnon* = sfDiscardable + # symbol name that was generated by the compiler + # the compiler will avoid printing such names + # in user messages. + + sfShadowed* = sfInnerProc + # a variable that was shadowed in some inner scope const # getting ready for the future expr/stmt merge @@ -647,6 +652,14 @@ const resultPos* = 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: proc NewSym*(symKind: TSymKind, Name: PIdent, owner: PSym): PSym proc NewType*(kind: TTypeKind, owner: PSym): PType @@ -691,11 +704,6 @@ proc copyNode*(src: PNode): PNode proc copyTree*(src: PNode): PNode # does copy its sons! -const nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, - nkCallStrLit} - -const nkLambdaKinds* = {nkLambda, nkDo} - proc isCallExpr*(n: PNode): bool = result = n.kind in nkCallKinds diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 6195ff2f4..3578b1f5e 100755 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -32,6 +32,15 @@ proc mangle(name: string): string = add(result, "HEX") 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 = result = s.loc.r if result == nil: @@ -45,9 +54,64 @@ proc mangleName(s: PSym): PRope = of skTemp, skParam, skType, skEnumField, skModule: result = toRope("%") else: InternalError(s.info, "mangleName") - app(result, toRope(mangle(s.name.s))) - app(result, "_") - app(result, toRope(s.id)) + 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, "_") + app(result, toRope(s.id)) s.loc.r = result proc isCompileTimeOnly(t: PType): bool = diff --git a/compiler/options.nim b/compiler/options.nim index 0d7763be0..3a2352c7f 100755 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -113,7 +113,9 @@ var gKeepComments*: bool = true # whether the parser needs to keep comments implicitImports*: seq[string] = @[] # modules that are to be implicitly imported implicitIncludes*: seq[string] = @[] # modules that are to be implicitly included - + +const oKeepVariableNames* = true + proc mainCommandArg*: string = ## This is intended for commands like check or parse ## which will work on the main project file unless diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 6a1c2f529..d8f017c4c 100755 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -15,6 +15,8 @@ # So we have to eval templates/macros right here so that symbol # lookup can be accurate. +# included from sem.nim + type TSemGenericFlag = enum withinBind, withinTypeDesc diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 0449c5644..d729a691f 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -216,7 +216,14 @@ proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode = result = result.sons[1] elif not sameType(result.typ, 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 = if isTopLevel(c): 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): var v = semIdentDef(c, a.sons[j], symkind) addInterfaceDecl(c, v) + when oKeepVariableNames: + let shadowed = findShadowedVar(c, v) + if shadowed != nil: shadowed.flags.incl(sfShadowed) if def != nil and def.kind != nkEmpty: # this is only needed for the evaluation pass: v.ast = def diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index f96ba7751..3ae9f7be9 100755 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -38,8 +38,8 @@ type wMagic, wThread, wFinal, wProfiler, wObjChecks, wImmediate, wImportCpp, wImportObjC, wImportCompilerProc, - wImportc, wExportc, wExtern, wIncompleteStruct, - wAlign, wNodecl, wPure, wVolatile, wRegister, wSideeffect, wHeader, + wImportc, wExportc, wIncompleteStruct, + wAlign, wNodecl, wPure, wSideeffect, wHeader, wNosideeffect, wNoreturn, wMerge, wLib, wDynlib, wCompilerproc, wProcVar, wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef, wLinedir, wStacktrace, wLinetrace, wLink, wCompile, @@ -58,13 +58,36 @@ type wWatchPoint, wSubsChar, wAcyclic, wShallow, wUnroll, wLinearScanEnd, 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] const oprLow* = ord(wColon) 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] = ["", "addr", "and", "as", "asm", "atomic", @@ -86,14 +109,14 @@ const "magic", "thread", "final", "profiler", "objchecks", "immediate", "importcpp", "importobjc", - "importcompilerproc", "importc", "exportc", "extern", "incompletestruct", - "align", "nodecl", "pure", "volatile", "register", "sideeffect", + "importcompilerproc", "importc", "exportc", "incompletestruct", + "align", "nodecl", "pure", "sideeffect", "header", "nosideeffect", "noreturn", "merge", "lib", "dynlib", "compilerproc", "procvar", "fatal", "error", "warning", "hint", "line", "push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace", "link", "compile", "linksys", "deprecated", "varargs", "byref", "callconv", "breakpoint", "debugger", "nimcall", "stdcall", - "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "closure", + "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "closure", "noconv", "on", "off", "checks", "rangechecks", "boundchecks", "overflowchecks", "nilchecks", "floatchecks", "nanchecks", "infchecks", @@ -107,7 +130,22 @@ const "watchpoint", "subschar", "acyclic", "shallow", "unroll", "linearscanend", "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 = for i in countup(low(a), high(a)): |