diff options
Diffstat (limited to 'compiler')
55 files changed, 886 insertions, 394 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 73c99c0b1..4c98219f9 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -395,6 +395,9 @@ type # sons[1]: field type # .n: nkDotExpr storing the field name + tyVoid #\ + # now different from tyEmpty, hurray! + static: # remind us when TTypeKind stops to fit in a single 64-bit word assert TTypeKind.high.ord <= 63 @@ -528,8 +531,6 @@ const tfOldSchoolExprStmt* = tfVarargs # for now used to distinguish \ # 'varargs[expr]' from 'varargs[untyped]'. Eventually 'expr' will be # deprecated and this mess can be cleaned up. - tfVoid* = tfVarargs # for historical reasons we conflated 'void' with - # 'empty' ('@[]' has the type 'seq[empty]'). tfReturnsNew* = tfInheritable skError* = skUnknown @@ -544,7 +545,7 @@ type mEcho, mShallowCopy, mSlurp, mStaticExec, mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst, mUnaryLt, mInc, mDec, mOrd, - mNew, mNewFinalize, mNewSeq, + mNew, mNewFinalize, mNewSeq, mNewSeqOfCap, mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq, mXLenStr, mXLenSeq, mIncl, mExcl, mCard, mChr, @@ -590,6 +591,7 @@ type mNewString, mNewStringOfCap, mParseBiggestFloat, mReset, mArray, mOpenArray, mRange, mSet, mSeq, mVarargs, + mRef, mPtr, mVar, mDistinct, mVoid, mTuple, mOrdinal, mInt, mInt8, mInt16, mInt32, mInt64, mUInt, mUInt8, mUInt16, mUInt32, mUInt64, @@ -609,7 +611,7 @@ type mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mNHint, mNWarning, mNError, mInstantiationInfo, mGetTypeInfo, mNGenSym, - mNimvm + mNimvm, mIntDefine, mStrDefine # things that we can evaluate safely at compile time, even if not asked for it: const @@ -769,7 +771,7 @@ type procInstCache*: seq[PInstantiation] gcUnsafetyReason*: PSym # for better error messages wrt gcsafe #scope*: PScope # the scope where the proc was defined - of skModule: + of skModule, skPackage: # modules keep track of the generic symbols they use from other modules. # this is because in incremental compilation, when a module is about to # be replaced with a newer version, we must decrement the usage count @@ -848,6 +850,7 @@ type # see instantiateDestructor in semdestruct.nim deepCopy*: PSym # overriden 'deepCopy' operation assignment*: PSym # overriden '=' operator + methods*: seq[(int,PSym)] # attached methods size*: BiggestInt # the size of the type in bytes # -1 means that the size is unkwown align*: int16 # the type's alignment requirements @@ -963,7 +966,6 @@ const var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things var gMainPackageId*: int - gMainPackageNotes*: TNoteKinds proc isCallExpr*(n: PNode): bool = result = n.kind in nkCallKinds @@ -1587,7 +1589,7 @@ proc isAtom*(n: PNode): bool {.inline.} = proc isEmptyType*(t: PType): bool {.inline.} = ## 'void' and 'stmt' types are often equivalent to 'nil' these days: - result = t == nil or t.kind in {tyEmpty, tyStmt} + result = t == nil or t.kind in {tyVoid, tyStmt} proc makeStmtList*(n: PNode): PNode = if n.kind == nkStmtList: diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index bd17f85e4..dffb8a9a5 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -124,7 +124,7 @@ proc openArrayLoc(p: BProc, n: PNode): Rope = result = "(*$1)->data, (*$1)->$2" % [a.rdLoc, lenField(p)] of tyArray, tyArrayConstr: result = "$1, $2" % [rdLoc(a), rope(lengthOrd(lastSon(a.t)))] - else: + else: internalError("openArrayLoc: " & typeToString(a.t)) else: internalError("openArrayLoc: " & typeToString(a.t)) @@ -260,7 +260,11 @@ proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope = else: result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym) else: - result = genArgNoParam(p, ri.sons[i]) + if tfVarargs notin typ.flags: + localError(ri.info, "wrong argument count") + result = nil + else: + result = genArgNoParam(p, ri.sons[i]) discard """ Dot call syntax in C++ diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 8fe9cdb72..3f12fed2c 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -45,7 +45,7 @@ proc genHexLiteral(v: PNode): Rope = proc getStrLit(m: BModule, s: string): Rope = discard cgsym(m, "TGenericSeq") - result = "TMP" & rope(backendId()) + result = getTempName(m) addf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n", [result, makeCString(s), rope(len(s))]) @@ -67,11 +67,11 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope = of nkNilLit: let t = skipTypes(ty, abstractVarRange) if t.kind == tyProc and t.callConv == ccClosure: - var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) - result = "TMP" & rope(id) - if id == gBackendId: + let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels) + result = p.module.tmpBase & rope(id) + if id == p.module.labels: # not found in cache: - inc(gBackendId) + inc(p.module.labels) addf(p.module.s[cfsData], "static NIM_CONST $1 $2 = {NIM_NIL,NIM_NIL};$n", [getTypeDesc(p.module, t), result]) @@ -81,13 +81,14 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope = if n.strVal.isNil: result = ropecg(p.module, "((#NimStringDesc*) NIM_NIL)", []) elif skipTypes(ty, abstractVarRange).kind == tyString: - var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) - if id == gBackendId: + let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels) + if id == p.module.labels: # string literal not found in the cache: result = ropecg(p.module, "((#NimStringDesc*) &$1)", [getStrLit(p.module, n.strVal)]) else: - result = ropecg(p.module, "((#NimStringDesc*) &TMP$1)", [rope(id)]) + result = ropecg(p.module, "((#NimStringDesc*) &$1$2)", + [p.module.tmpBase, rope(id)]) else: result = makeCString(n.strVal) of nkFloatLit..nkFloat64Lit: @@ -134,11 +135,11 @@ proc genSetNode(p: BProc, n: PNode): Rope = var size = int(getSize(n.typ)) toBitSet(n, cs) if size > 8: - var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) - result = "TMP" & rope(id) - if id == gBackendId: + let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels) + result = p.module.tmpBase & rope(id) + if id == p.module.labels: # not found in cache: - inc(gBackendId) + inc(p.module.labels) addf(p.module.s[cfsData], "static NIM_CONST $1 $2 = $3;$n", [getTypeDesc(p.module, n.typ), result, genRawSetData(cs, size)]) else: @@ -490,7 +491,7 @@ proc binaryArithOverflowRaw(p: BProc, t: PType, a, b: TLoc; var size = getSize(t) let storage = if size < platform.intSize: rope("NI") else: getTypeDesc(p.module, t) - result = getTempName() + result = getTempName(p.module) linefmt(p, cpsLocals, "$1 $2;$n", storage, result) lineCg(p, cpsStmts, frmt, result, rdCharLoc(a), rdCharLoc(b)) if size < platform.intSize or t.kind in {tyRange, tyEnum}: @@ -801,9 +802,9 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym; v.r.add(d.loc.r) genInExprAux(p, it, u, v, test) let id = nodeTableTestOrSet(p.module.dataCache, - newStrNode(nkStrLit, field.name.s), gBackendId) - let strLit = if id == gBackendId: getStrLit(p.module, field.name.s) - else: "TMP" & rope(id) + newStrNode(nkStrLit, field.name.s), p.module.labels) + let strLit = if id == p.module.labels: getStrLit(p.module, field.name.s) + else: p.module.tmpBase & rope(id) if op.magic == mNot: linefmt(p, cpsStmts, "if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n", @@ -1140,6 +1141,16 @@ proc genNewSeq(p: BProc, e: PNode) = genNewSeqAux(p, a, b.rdLoc) gcUsage(e) +proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) = + let seqtype = skipTypes(e.typ, abstractVarRange) + var a: TLoc + initLocExpr(p, e.sons[1], a) + putIntoDest(p, d, e.typ, ropecg(p.module, + "($1)#nimNewSeqOfCap($2, $3)", [ + getTypeDesc(p.module, seqtype), + genTypeInfo(p.module, seqtype), a.rdLoc])) + gcUsage(e) + proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = var tmp: TLoc var t = e.typ.skipTypes(abstractInst) @@ -1319,7 +1330,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) = putIntoDest(p, d, e.typ, ropecg(p.module, "#reprAny($1, $2)", [ rdLoc(a), genTypeInfo(p.module, t)]), a.s) - of tyEmpty: + of tyEmpty, tyVoid: localError(e.info, "'repr' doesn't support 'void' type") else: putIntoDest(p, d, e.typ, ropecg(p.module, "#reprAny($1, $2)", @@ -1557,11 +1568,12 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) = [getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.s) proc genCast(p: BProc, e: PNode, d: var TLoc) = - const floatTypes = {tyFloat..tyFloat128} + const ValueTypes = {tyFloat..tyFloat128, tyTuple, tyObject, + tyArray, tyArrayConstr} let destt = skipTypes(e.typ, abstractRange) srct = skipTypes(e.sons[1].typ, abstractRange) - if destt.kind in floatTypes or srct.kind in floatTypes: + if destt.kind in ValueTypes or srct.kind in ValueTypes: # 'cast' and some float type involved? --> use a union. inc(p.labels) var lbl = p.labels.rope @@ -1667,10 +1679,10 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = if optOverflowCheck notin p.options: unaryExpr(p, e, d, "($1 - 1)") else: unaryExpr(p, e, d, "#subInt($1, 1)") of mInc, mDec: - const opr: array [mInc..mDec, string] = ["$1 += $2;$n", "$1 -= $2;$n"] - const fun64: array [mInc..mDec, string] = ["$# = #addInt64($#, $#);$n", + const opr: array[mInc..mDec, string] = ["$1 += $2;$n", "$1 -= $2;$n"] + const fun64: array[mInc..mDec, string] = ["$# = #addInt64($#, $#);$n", "$# = #subInt64($#, $#);$n"] - const fun: array [mInc..mDec, string] = ["$# = #addInt($#, $#);$n", + const fun: array[mInc..mDec, string] = ["$# = #addInt($#, $#);$n", "$# = #subInt($#, $#);$n"] let underlying = skipTypes(e.sons[1].typ, {tyGenericInst, tyVar, tyRange}) if optOverflowCheck notin p.options or underlying.kind in {tyUInt..tyUInt64}: @@ -1711,6 +1723,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mNew: genNew(p, e) of mNewFinalize: genNewFinalize(p, e) of mNewSeq: genNewSeq(p, e) + of mNewSeqOfCap: genNewSeqOfCap(p, e, d) of mSizeOf: let t = e.sons[1].typ.skipTypes({tyTypeDesc}) putIntoDest(p, d, e.typ, "((NI)sizeof($1))" % [getTypeDesc(p.module, t)]) @@ -1761,11 +1774,11 @@ proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool = if nfAllConst in n.flags and d.k == locNone and n.len > 0 and n.isDeepConstExpr: var t = getUniqueType(n.typ) discard getTypeDesc(p.module, t) # so that any fields are initialized - var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) - fillLoc(d, locData, t, "TMP" & rope(id), OnStatic) - if id == gBackendId: + let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels) + fillLoc(d, locData, t, p.module.tmpBase & rope(id), OnStatic) + if id == p.module.labels: # expression not found in the cache: - inc(gBackendId) + inc(p.module.labels) addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n", [getTypeDesc(p.module, t), d.r, genConstExpr(p, n)]) result = true @@ -1952,12 +1965,12 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) = proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) = var t = getUniqueType(n.typ) discard getTypeDesc(p.module, t) # so that any fields are initialized - var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) - var tmp = "TMP" & rope(id) + let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels) + let tmp = p.module.tmpBase & rope(id) - if id == gBackendId: + if id == p.module.labels: # expression not found in the cache: - inc(gBackendId) + inc(p.module.labels) addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n", [getTypeDesc(p.module, t), tmp, genConstExpr(p, n)]) @@ -2179,8 +2192,7 @@ proc genConstSeq(p: BProc, n: PNode, t: PType): Rope = data.add("}") data.add("}") - inc(gBackendId) - result = "CNSTSEQ" & gBackendId.rope + result = getTempName(p.module) appcg(p.module, cfsData, "NIM_CONST struct {$n" & diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 64933df78..70d50b060 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -793,7 +793,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = if not isEmptyType(t.typ) and d.k == locNone: getTemp(p, t.typ, d) genLineDir(p, t) - let exc = getTempName() + let exc = getTempName(p.module) if getCompilerProc("Exception") != nil: discard cgsym(p.module, "Exception") else: @@ -886,7 +886,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) = getTemp(p, t.typ, d) discard lists.includeStr(p.module.headerFiles, "<setjmp.h>") genLineDir(p, t) - var safePoint = getTempName() + var safePoint = getTempName(p.module) if getCompilerProc("Exception") != nil: discard cgsym(p.module, "Exception") else: diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim index 0da6396ea..dfefc4b63 100644 --- a/compiler/ccgtrav.nim +++ b/compiler/ccgtrav.nim @@ -100,7 +100,7 @@ proc genTraverseProcSeq(c: var TTraversalClosure, accessor: Rope, typ: PType) = proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): Rope = var c: TTraversalClosure var p = newProc(nil, m) - result = getGlobalTempName() + result = getTempName(m) case reason of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n" @@ -135,7 +135,7 @@ proc genTraverseProcForGlobal(m: BModule, s: PSym): Rope = var c: TTraversalClosure var p = newProc(nil, m) var sLoc = s.loc.r - result = getGlobalTempName() + result = getTempName(m) if sfThread in s.flags and emulatedThreadVars(): accessThreadLocalVar(p, s) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 4de196fe0..3d1c2affc 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -25,8 +25,9 @@ proc isKeyword(w: PIdent): bool = proc mangleField(name: PIdent): string = result = mangle(name.s) if isKeyword(name): - result[0] = result[0].toUpper # Mangling makes everything lowercase, - # but some identifiers are C keywords + result[0] = result[0].toUpperAscii + # Mangling makes everything lowercase, + # but some identifiers are C keywords proc hashOwner(s: PSym): FilenameHash = var m = s @@ -150,6 +151,9 @@ proc mapType(typ: PType): TCTypeKind = of tyCString: result = ctCString of tyInt..tyUInt64: result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt)) + of tyStatic: + if typ.n != nil: result = mapType(lastSon typ) + else: internalError("mapType") else: internalError("mapType") proc mapReturnType(typ: PType): TCTypeKind = @@ -202,11 +206,9 @@ proc cacheGetType(tab: TIdTable, key: PType): Rope = # linear search is not necessary anymore: result = Rope(idTableGet(tab, key)) -proc getTempName(): Rope = - result = rfmt(nil, "TMP$1", rope(backendId())) - -proc getGlobalTempName(): Rope = - result = rfmt(nil, "TMP$1", rope(backendId())) +proc getTempName(m: BModule): Rope = + result = m.tmpBase & rope(m.labels) + inc m.labels proc ccgIntroducedPtr(s: PSym): bool = var pt = skipTypes(s.typ, typedescInst) @@ -258,6 +260,11 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope = of tyInt..tyUInt64: result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.kind]) of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.sons[0]) + of tyStatic: + if typ.n != nil: result = getSimpleTypeDesc(m, lastSon typ) + else: internalError("tyStatic for getSimpleTypeDesc") + of tyGenericInst: + result = getSimpleTypeDesc(m, lastSon typ) else: result = nil proc pushType(m: BModule, typ: PType) = @@ -418,7 +425,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode, addf(result, "union{$n$1} $2;$n", [unionBody, uname]) of nkSym: field = n.sym - if field.typ.kind == tyEmpty: return + if field.typ.kind == tyVoid: return #assert(field.ast == nil) sname = mangleRecFieldName(field, rectype) if accessExpr != nil: ae = "$1.$2" % [accessExpr, sname] @@ -665,7 +672,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope = chunkStart = i let typeInSlot = resolveStarsInCppType(typ, idx + 1, stars) - if typeInSlot == nil or typeInSlot.kind == tyEmpty: + if typeInSlot == nil or typeInSlot.kind == tyVoid: result.add(~"void") else: result.add getTypeDescAux(m, typeInSlot, check) @@ -724,7 +731,7 @@ type proc getClosureType(m: BModule, t: PType, kind: TClosureTypeKind): Rope = assert t.kind == tyProc var check = initIntSet() - result = getTempName() + result = getTempName(m) var rettype, desc: Rope genProcParams(m, t, rettype, desc, check, declareEnvironment=kind != clHalf) if not isImportedType(t): @@ -839,7 +846,7 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: Rope) = if L == 1: genObjectFields(m, typ, n.sons[0], expr) elif L > 0: - var tmp = getTempName() + var tmp = getTempName(m) addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(L)]) for i in countup(0, L-1): var tmp2 = getNimNode(m) @@ -911,7 +918,7 @@ proc genTupleInfo(m: BModule, typ: PType, name: Rope) = var expr = getNimNode(m) var length = sonsLen(typ) if length > 0: - var tmp = getTempName() + var tmp = getTempName(m) addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(length)]) for i in countup(0, length - 1): var a = typ.sons[i] @@ -935,7 +942,7 @@ proc genEnumInfo(m: BModule, typ: PType, name: Rope) = # anyway. We generate a cstring array and a loop over it. Exceptional # positions will be reset after the loop. genTypeInfoAux(m, typ, typ, name) - var nodePtrs = getTempName() + var nodePtrs = getTempName(m) var length = sonsLen(typ.n) addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [nodePtrs, rope(length)]) @@ -955,8 +962,8 @@ proc genEnumInfo(m: BModule, typ: PType, name: Rope) = if field.position != i or tfEnumHasHoles in typ.flags: addf(specialCases, "$1.offset = $2;$n", [elemNode, rope(field.position)]) hasHoles = true - var enumArray = getTempName() - var counter = getTempName() + var enumArray = getTempName(m) + var counter = getTempName(m) addf(m.s[cfsTypeInit1], "NI $1;$n", [counter]) addf(m.s[cfsTypeInit1], "static char* NIM_CONST $1[$2] = {$n$3};$n", [enumArray, rope(length), enumNames]) @@ -1024,9 +1031,12 @@ proc genTypeInfo(m: BModule, t: PType): Rope = [result, rope(typeToString(t))]) return "(&".rope & result & ")".rope case t.kind - of tyEmpty: result = rope"0" + of tyEmpty, tyVoid: result = rope"0" of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar: genTypeInfoAuxBase(m, t, t, result, rope"0") + of tyStatic: + if t.n != nil: result = genTypeInfo(m, lastSon t) + else: internalError("genTypeInfo(" & $t.kind & ')') of tyProc: if t.callConv != ccClosure: genTypeInfoAuxBase(m, t, t, result, rope"0") diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index 6dfd7b52c..ecd98a2bf 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -93,7 +93,7 @@ proc getUniqueType*(key: PType): PType = # produced instead of ``NI``. result = key of tyEmpty, tyNil, tyExpr, tyStmt, tyPointer, tyString, - tyCString, tyNone, tyBigNum: + tyCString, tyNone, tyBigNum, tyVoid: result = gCanonicalTypes[k] if result == nil: gCanonicalTypes[k] = key @@ -188,7 +188,7 @@ proc mangle*(name: string): string = let c = name[i] case c of 'A'..'Z': - add(result, c.toLower) + add(result, c.toLowerAscii) of '_': discard of 'a'..'z', '0'..'9': diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 3334f047f..589fcb515 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -500,7 +500,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) = assert(lib != nil) if not lib.generated: lib.generated = true - var tmp = getGlobalTempName() + var tmp = getTempName(m) assert(lib.name == nil) lib.name = tmp # BUGFIX: cgsym has awful side-effects addf(m.s[cfsVars], "static void* $1;$n", [tmp]) @@ -1084,6 +1084,7 @@ proc initProcOptions(m: BModule): TOptions = proc rawNewModule(module: PSym, filename: string): BModule = new(result) + result.tmpBase = rope("T" & $hashOwner(module) & "_") initLinkedList(result.headerFiles) result.declaredThings = initIntSet() result.declaredProtos = initIntSet() @@ -1100,8 +1101,8 @@ proc rawNewModule(module: PSym, filename: string): BModule = initNodeTable(result.dataCache) result.typeStack = @[] result.forwardedProcs = @[] - result.typeNodesName = getTempName() - result.nimTypesName = getTempName() + result.typeNodesName = getTempName(result) + result.nimTypesName = getTempName(result) # no line tracing for the init sections of the system module so that we # don't generate a TFrame which can confuse the stack botton initialization: if sfSystemModule in module.flags: @@ -1126,8 +1127,8 @@ proc resetModule*(m: BModule) = initNodeTable(m.dataCache) m.typeStack = @[] m.forwardedProcs = @[] - m.typeNodesName = getTempName() - m.nimTypesName = getTempName() + m.typeNodesName = getTempName(m) + m.nimTypesName = getTempName(m) if sfSystemModule in m.module.flags: incl m.flags, preventStackTrace else: diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index c098902a6..c027bb451 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -102,12 +102,13 @@ type includesStringh, # C source file already includes ``<string.h>`` objHasKidsValid # whether we can rely on tfObjHasKids TCGen = object of TPassContext # represents a C source file - module*: PSym - filename*: string s*: TCFileSections # sections of the C file flags*: set[Codegenflag] + module*: PSym + filename*: string cfilename*: string # filename of the module (including path, # without extension) + tmpBase*: Rope # base for temp identifier generation typeCache*: TIdTable # cache the generated types forwTypeCache*: TIdTable # cache for forward declarations of types declaredThings*: IntSet # things we have declared in this .c file diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index 312afec1a..624c5b183 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -63,19 +63,25 @@ proc sameMethodBucket(a, b: PSym): MethodResult = while true: aa = skipTypes(aa, {tyGenericInst}) bb = skipTypes(bb, {tyGenericInst}) - if (aa.kind == bb.kind) and (aa.kind in {tyVar, tyPtr, tyRef}): + if aa.kind == bb.kind and aa.kind in {tyVar, tyPtr, tyRef}: aa = aa.lastSon bb = bb.lastSon else: break if sameType(aa, bb): - if aa.kind == tyObject and result != Invalid: result = Yes + if aa.kind == tyObject and result != Invalid: + result = Yes elif aa.kind == tyObject and bb.kind == tyObject: let diff = inheritanceDiff(bb, aa) if diff < 0: - if result != Invalid: result = Yes + if result != Invalid: + result = Yes + else: + return No elif diff != high(int): result = Invalid + else: + return No else: return No @@ -181,7 +187,7 @@ proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int = var aa = skipTypes(a.typ.sons[col], skipPtrs) var bb = skipTypes(b.typ.sons[col], skipPtrs) var d = inheritanceDiff(aa, bb) - if (d != high(int)): + if (d != high(int)) and d != 0: return d proc sortBucket(a: var TSymSeq, relevantCols: IntSet) = diff --git a/compiler/commands.nim b/compiler/commands.nim index 5601ef662..b468dd6b8 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -158,7 +158,7 @@ var enableNotes: TNoteKinds disableNotes: TNoteKinds -proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass, +proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, info: TLineInfo; orig: string) = var id = "" # arg = "X]:on|off" var i = 0 @@ -181,10 +181,13 @@ proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass, case whichKeyword(substr(arg, i)) of wOn: incl(gNotes, n) + incl(gMainPackageNotes, n) incl(enableNotes, n) of wOff: excl(gNotes, n) + excl(gMainPackageNotes, n) incl(disableNotes, n) + excl(ForeignPackageNotes, n) else: localError(info, errOnOrOffExpectedButXFound, arg) proc processCompile(filename: string) = @@ -341,7 +344,11 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = discard "allow for backwards compatibility, but don't do anything" of "define", "d": expectArg(switch, arg, pass, info) - defineSymbol(arg) + if {':', '='} in arg: + splitSwitch(arg, key, val, pass, info) + defineSymbol(key, val) + else: + defineSymbol(arg) of "undef", "u": expectArg(switch, arg, pass, info) undefSymbol(arg) @@ -543,6 +550,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = gNotes = NotesVerbosity[gVerbosity] incl(gNotes, enableNotes) excl(gNotes, disableNotes) + gMainPackageNotes = gNotes of "parallelbuild": expectArg(switch, arg, pass, info) gNumberOfProcessors = parseInt(arg) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 60e8f2826..02f7e764d 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -19,8 +19,8 @@ var gSymbols: StringTableRef const catNone = "false" -proc defineSymbol*(symbol: string) = - gSymbols[symbol] = "true" +proc defineSymbol*(symbol: string, value: string = "true") = + gSymbols[symbol] = value proc undefSymbol*(symbol: string) = gSymbols[symbol] = catNone @@ -62,6 +62,11 @@ proc isDefined*(symbol: string): bool = proc isDefined*(symbol: PIdent): bool = isDefined(symbol.s) +proc lookupSymbol*(symbol: string): string = + result = if isDefined(symbol): gSymbols[symbol] else: nil + +proc lookupSymbol*(symbol: PIdent): string = lookupSymbol(symbol.s) + iterator definedSymbolNames*: string = for key, val in pairs(gSymbols): if val != catNone: yield key diff --git a/compiler/docgen.nim b/compiler/docgen.nim index d954b897b..bbbec081a 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -14,7 +14,7 @@ import ast, strutils, strtabs, options, msgs, os, ropes, idents, wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite, - importer, sempass2, json, xmltree, cgi, typesrenderer + importer, sempass2, json, xmltree, cgi, typesrenderer, astalgo type TSections = array[TSymKind, Rope] @@ -25,9 +25,32 @@ type indexValFilename: string analytics: string # Google Analytics javascript, "" if doesn't exist seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML. + jArray: JsonNode + types: TStrTable PDoc* = ref TDocumentor ## Alias to type less. +proc whichType(d: PDoc; n: PNode): PSym = + if n.kind == nkSym: + if d.types.strTableContains(n.sym): + result = n.sym + else: + for i in 0..<safeLen(n): + let x = whichType(d, n[i]) + if x != nil: return x + +proc attachToType(d: PDoc; p: PSym): PSym = + let params = p.ast.sons[paramsPos] + # first check the first parameter, then the return type, + # then the other parameter: + template check(i) = + result = whichType(d, params[i]) + if result != nil: return result + + if params.len > 1: check(1) + if params.len > 0: check(0) + for i in 2..<params.len: check(i) + proc compilerMsgHandler(filename: string, line, col: int, msgKind: rst.MsgKind, arg: string) {.procvar.} = # translate msg kind: @@ -81,6 +104,8 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc = result.seenSymbols = newStringTable(modeCaseInsensitive) result.id = 100 + result.jArray = newJArray() + initStrTable result.types proc dispA(dest: var Rope, xml, tex: string, args: openArray[Rope]) = if gCmd != cmdRst2tex: addf(dest, xml, args) @@ -226,10 +251,27 @@ proc getName(d: PDoc, n: PNode, splitAfter = -1): string = result = esc(d.target, "`") for i in 0.. <n.len: result.add(getName(d, n[i], splitAfter)) result.add esc(d.target, "`") + of nkOpenSymChoice, nkClosedSymChoice: + result = getName(d, n[0], splitAfter) else: internalError(n.info, "getName()") result = "" +proc getNameIdent(n: PNode): PIdent = + case n.kind + of nkPostfix: result = getNameIdent(n.sons[1]) + of nkPragmaExpr: result = getNameIdent(n.sons[0]) + of nkSym: result = n.sym.name + of nkIdent: result = n.ident + of nkAccQuoted: + var r = "" + for i in 0.. <n.len: r.add(getNameIdent(n[i]).s) + result = getIdent(r) + of nkOpenSymChoice, nkClosedSymChoice: + result = getNameIdent(n[0]) + else: + result = nil + proc getRstName(n: PNode): PRstNode = case n.kind of nkPostfix: result = getRstName(n.sons[1]) @@ -239,6 +281,8 @@ proc getRstName(n: PNode): PRstNode = of nkAccQuoted: result = getRstName(n.sons[0]) for i in 1 .. <n.len: result.text.add(getRstName(n[i]).text) + of nkOpenSymChoice, nkClosedSymChoice: + result = getRstName(n[0]) else: internalError(n.info, "getRstName()") result = nil @@ -311,7 +355,7 @@ proc docstringSummary(rstText: string): string = ## Also, we hope to not break the rst, but maybe we do. If there is any ## trimming done, an ellipsis unicode char is added. const maxDocstringChars = 100 - assert (rstText.len < 2 or (rstText[0] == '#' and rstText[1] == '#')) + assert(rstText.len < 2 or (rstText[0] == '#' and rstText[1] == '#')) result = rstText.substr(2).strip var pos = result.find('\L') if pos > 0: @@ -380,13 +424,27 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = "\\spanIdentifier{$1}", [rope(esc(d.target, literal))]) of tkSpaces, tkInvalid: add(result, literal) + of tkCurlyDotLe: + dispA(result, """<span class="Other pragmabegin">$1</span><div class="pragma">""", + "\\spanOther{$1}", + [rope(esc(d.target, literal))]) + of tkCurlyDotRi: + dispA(result, "</div><span class=\"Other pragmaend\">$1</span>", + "\\spanOther{$1}", + [rope(esc(d.target, literal))]) of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi, - tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe, + tkBracketDotLe, tkBracketDotRi, tkParDotLe, tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot, tkAccent, tkColonColon, tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr: dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}", [rope(esc(d.target, literal))]) + + if k in routineKinds and nameNode.kind == nkSym: + let att = attachToType(d, nameNode.sym) + if att != nil: + dispA(result, """<span class="attachedType" style="visibility:hidden">$1</span>""", "", + [rope esc(d.target, att.name.s)]) inc(d.id) let plainNameRope = rope(xmltree.escape(plainName.strip)) @@ -430,8 +488,10 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = setIndexTerm(d[], symbolOrId, name, linkTitle, xmltree.escape(plainDocstring.docstringSummary)) + if k == skType and nameNode.kind == nkSym: + d.types.strTableAdd nameNode.sym -proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode = +proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode = if not isVisible(nameNode): return var name = getName(d, nameNode) @@ -440,8 +500,8 @@ proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode = initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments}) - result = %{ "name": %name, "type": %($k) } - + result = %{ "name": %name, "type": %($k), "line": %n.info.line, + "col": %n.info.col} if comm != nil and comm != "": result["description"] = %comm if r.buf != nil: @@ -491,46 +551,45 @@ proc generateDoc*(d: PDoc, n: PNode) = of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0]) else: discard -proc generateJson(d: PDoc, n: PNode, jArray: JsonNode = nil): JsonNode = +proc add(d: PDoc; j: JsonNode) = + if j != nil: d.jArray.add j + +proc generateJson*(d: PDoc, n: PNode) = case n.kind of nkCommentStmt: if n.comment != nil and startsWith(n.comment, "##"): let stripped = n.comment.substr(2).strip - result = %{ "comment": %stripped } + d.add %{ "comment": %stripped, "line": %n.info.line, + "col": %n.info.col } of nkProcDef: when useEffectSystem: documentRaises(n) - result = genJSONItem(d, n, n.sons[namePos], skProc) + d.add genJsonItem(d, n, n.sons[namePos], skProc) of nkMethodDef: when useEffectSystem: documentRaises(n) - result = genJSONItem(d, n, n.sons[namePos], skMethod) + d.add genJsonItem(d, n, n.sons[namePos], skMethod) of nkIteratorDef: when useEffectSystem: documentRaises(n) - result = genJSONItem(d, n, n.sons[namePos], skIterator) + d.add genJsonItem(d, n, n.sons[namePos], skIterator) of nkMacroDef: - result = genJSONItem(d, n, n.sons[namePos], skMacro) + d.add genJsonItem(d, n, n.sons[namePos], skMacro) of nkTemplateDef: - result = genJSONItem(d, n, n.sons[namePos], skTemplate) + d.add genJsonItem(d, n, n.sons[namePos], skTemplate) of nkConverterDef: when useEffectSystem: documentRaises(n) - result = genJSONItem(d, n, n.sons[namePos], skConverter) + d.add genJsonItem(d, n, n.sons[namePos], skConverter) of nkTypeSection, nkVarSection, nkLetSection, nkConstSection: for i in countup(0, sonsLen(n) - 1): if n.sons[i].kind != nkCommentStmt: # order is always 'type var let const': - result = genJSONItem(d, n.sons[i], n.sons[i].sons[0], + d.add genJsonItem(d, n.sons[i], n.sons[i].sons[0], succ(skType, ord(n.kind)-ord(nkTypeSection))) of nkStmtList: - result = if jArray != nil: jArray else: newJArray() - for i in countup(0, sonsLen(n) - 1): - var r = generateJson(d, n.sons[i], result) - if r != nil: - result.add(r) - + generateJson(d, n.sons[i]) of nkWhenStmt: # generate documentation for the first branch only: - if not checkForFalse(n.sons[0].sons[0]) and jArray != nil: - discard generateJson(d, lastSon(n.sons[0]), jArray) + if not checkForFalse(n.sons[0].sons[0]): + generateJson(d, lastSon(n.sons[0])) else: discard proc genSection(d: PDoc, kind: TSymKind) = @@ -592,12 +651,36 @@ proc generateIndex*(d: PDoc) = writeIndexFile(d[], splitFile(options.outFile).dir / splitFile(d.filename).name & IndexExt) +proc getOutFile2(filename, ext, dir: string): string = + if gWholeProject: + let d = if options.outFile != "": options.outFile else: dir + createDir(d) + result = d / changeFileExt(filename, ext) + else: + result = getOutFile(filename, ext) + proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) = var content = genOutFile(d) if optStdout in gGlobalOptions: writeRope(stdout, content) else: - writeRope(content, getOutFile(filename, outExt), useWarning) + writeRope(content, getOutFile2(filename, outExt, "htmldocs"), useWarning) + +proc writeOutputJson*(d: PDoc, filename, outExt: string, + useWarning = false) = + let content = %*{"orig": d.filename, + "nimble": getPackageName(d.filename), + "entries": d.jArray} + if optStdout in gGlobalOptions: + write(stdout, $content) + else: + var f: File + if open(f, getOutFile2(splitFile(filename).name, + outExt, "jsondocs"), fmWrite): + write(f, $content) + close(f) + else: + discard "fixme: error report" proc commandDoc*() = var ast = parseFile(gProjectMainIdx) @@ -628,18 +711,19 @@ proc commandRst2TeX*() = splitter = "\\-" commandRstAux(gProjectFull, TexExt) -proc commandJSON*() = +proc commandJson*() = var ast = parseFile(gProjectMainIdx) if ast == nil: return var d = newDocumentor(gProjectFull, options.gConfigVars) d.hasToc = true - var json = generateJson(d, ast) - var content = rope(pretty(json)) + generateJson(d, ast) + let json = d.jArray + let content = rope(pretty(json)) if optStdout in gGlobalOptions: writeRope(stdout, content) else: - echo getOutFile(gProjectFull, JsonExt) + #echo getOutFile(gProjectFull, JsonExt) writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false) proc commandBuildIndex*() = diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim index 27de06811..d70d5406c 100644 --- a/compiler/docgen2.nim +++ b/compiler/docgen2.nim @@ -19,21 +19,36 @@ type module: PSym PGen = ref TGen -proc close(p: PPassContext, n: PNode): PNode = +template closeImpl(body: untyped) {.dirty.} = var g = PGen(p) let useWarning = sfMainModule notin g.module.flags - if gWholeProject or sfMainModule in g.module.flags: - writeOutput(g.doc, g.module.filename, HtmlExt, useWarning) + #echo g.module.name.s, " ", g.module.owner.id, " ", gMainPackageId + if (g.module.owner.id == gMainPackageId and gWholeProject) or + sfMainModule in g.module.flags: + body try: generateIndex(g.doc) except IOError: discard +proc close(p: PPassContext, n: PNode): PNode = + closeImpl: + writeOutput(g.doc, g.module.filename, HtmlExt, useWarning) + +proc closeJson(p: PPassContext, n: PNode): PNode = + closeImpl: + writeOutputJson(g.doc, g.module.filename, ".json", useWarning) + proc processNode(c: PPassContext, n: PNode): PNode = result = n var g = PGen(c) generateDoc(g.doc, n) +proc processNodeJson(c: PPassContext, n: PNode): PNode = + result = n + var g = PGen(c) + generateJson(g.doc, n) + proc myOpen(module: PSym): PPassContext = var g: PGen new(g) @@ -44,6 +59,8 @@ proc myOpen(module: PSym): PPassContext = result = g const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close) +const docgen2JsonPass* = makePass(open = myOpen, process = processNodeJson, + close = closeJson) proc finishDoc2Pass*(project: string) = discard diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index b2ee9c7f1..eb9aac490 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -754,7 +754,7 @@ proc callCCompiler*(projectfile: string) = "lib", quoteShell(libpath)]) if optCompileOnly notin gGlobalOptions: execExternalProgram(linkCmd, - if gVerbosity > 1: hintExecuting else: hintLinking) + if optListCmd in gGlobalOptions or gVerbosity > 1: hintExecuting else: hintLinking) else: linkCmd = "" if optGenScript in gGlobalOptions: diff --git a/compiler/idgen.nim b/compiler/idgen.nim index 906c16546..333772705 100644 --- a/compiler/idgen.nim +++ b/compiler/idgen.nim @@ -11,7 +11,7 @@ import idents, strutils, os, options -var gFrontEndId, gBackendId*: int +var gFrontEndId*: int const debugIds* = false @@ -30,10 +30,6 @@ proc getID*(): int {.inline.} = result = gFrontEndId inc(gFrontEndId) -proc backendId*(): int {.inline.} = - result = gBackendId - inc(gBackendId) - proc setId*(id: int) {.inline.} = gFrontEndId = max(gFrontEndId, id + 1) @@ -49,7 +45,6 @@ proc toGid(f: string): string = proc saveMaxIds*(project: string) = var f = open(project.toGid, fmWrite) f.writeLine($gFrontEndId) - f.writeLine($gBackendId) f.close() proc loadMaxIds*(project: string) = @@ -61,5 +56,4 @@ proc loadMaxIds*(project: string) = if f.readLine(line): var backEndId = parseInt(line) gFrontEndId = max(gFrontEndId, frontEndId) - gBackendId = max(gBackendId, backEndId) f.close() diff --git a/compiler/installer.ini b/compiler/installer.ini index 07fdb13b5..b802f08f1 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -8,7 +8,7 @@ Platforms: """ windows: i386;amd64 linux: i386;amd64;powerpc64;arm;sparc;mips;mipsel;powerpc;powerpc64el;arm64 macosx: i386;amd64;powerpc64 - solaris: i386;amd64;sparc + solaris: i386;amd64;sparc;sparc64 freebsd: i386;amd64 netbsd: i386;amd64 openbsd: i386;amd64 diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 41e42b825..a60b0cc5e 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -48,6 +48,7 @@ type etyNull, # null type etyProc, # proc type etyBool, # bool type + etySeq, # Nim seq or string type etyInt, # JavaScript's int etyFloat, # JavaScript's float etyString, # JavaScript's string @@ -156,15 +157,18 @@ proc mapType(typ: PType): TJSTypeKind = of tyBool: result = etyBool of tyFloat..tyFloat128: result = etyFloat of tySet: result = etyObject # map a set to a table - of tyString, tySequence: result = etyInt # little hack to get right semantics + of tyString, tySequence: result = etySeq of tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, tyBigNum, tyVarargs: result = etyObject of tyNil: result = etyNull of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvocation, tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor, - tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses: + tyExpr, tyStmt, tyTypeDesc, tyTypeClasses, tyVoid: result = etyNone + of tyStatic: + if t.n != nil: result = mapType(lastSon t) + else: result = etyNone of tyProc: result = etyProc of tyCString: result = etyString @@ -817,7 +821,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = addf(p.body, "$#[$#] = chr($#);$n", [a.rdLoc, b.rdLoc, c.rdLoc]) return - let xtyp = mapType(p, x.typ) + var xtyp = mapType(p, x.typ) if x.kind == nkHiddenDeref and x.sons[0].kind == nkCall and xtyp != etyObject: gen(p, x.sons[0], a) @@ -829,7 +833,18 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = gen(p, y, b) + # we don't care if it's an etyBaseIndex (global) of a string, it's + # still a string that needs to be copied properly: + if x.typ.skipTypes(abstractInst).kind in {tySequence, tyString}: + xtyp = etySeq case xtyp + of etySeq: + if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: + addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) + else: + useMagic(p, "nimCopy") + addf(p.body, "$1 = nimCopy(null, $2, $3);$n", + [a.rdLoc, b.res, genTypeInfo(p, y.typ)]) of etyObject: if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) @@ -1049,6 +1064,8 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) = else: internalError(n.sons[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')') of nkObjDownConv: gen(p, n.sons[0], r) + of nkHiddenDeref: + gen(p, n.sons[0].sons[0], r) else: internalError(n.sons[0].info, "genAddr: " & $n.sons[0].kind) proc thisParam(p: PProc; typ: PType): PType = @@ -1215,11 +1232,13 @@ proc genOtherArg(p: PProc; n: PNode; i: int; typ: PType; genArgNoParam(p, it, r) else: genArg(p, it, paramType.sym, r) + inc generated proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType; r: var TCompRes) = var i = 0 var j = 1 + r.kind = resExpr while i < pat.len: case pat[i] of '@': @@ -1233,10 +1252,18 @@ proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType; genOtherArg(p, n, j, typ, generated, r) inc j inc i + of '\31': + # unit separator + add(r.res, "#") + inc i + of '\29': + # group separator + add(r.res, "@") + inc i else: let start = i while i < pat.len: - if pat[i] notin {'@', '#'}: inc(i) + if pat[i] notin {'@', '#', '\31', '\29'}: inc(i) else: break if i - 1 >= start: add(r.res, substr(pat, start, i - 1)) @@ -1403,6 +1430,12 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope = result = putToSeq("null", indirect) of tySequence, tyString, tyCString, tyPointer, tyProc: result = putToSeq("null", indirect) + of tyStatic: + if t.n != nil: + result = createVar(p, lastSon t, indirect) + else: + internalError("createVar: " & $t.kind) + result = nil else: internalError("createVar: " & $t.kind) result = nil @@ -1418,7 +1451,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) = discard mangleName(v, p.target) gen(p, n, a) case mapType(p, v.typ) - of etyObject: + of etyObject, etySeq: if needsNoCopy(p, n): s = a.res else: @@ -1557,8 +1590,16 @@ proc genRepr(p: PProc, n: PNode, r: var TCompRes) = of tyEnum, tyOrdinal: gen(p, n.sons[1], r) useMagic(p, "cstrToNimstr") + var offset = "" + if t.kind == tyEnum: + let firstFieldOffset = t.n.sons[0].sym.position + if firstFieldOffset < 0: + offset = "+" & $(-firstFieldOffset) + elif firstFieldOffset > 0: + offset = "-" & $firstFieldOffset + r.kind = resExpr - r.res = "cstrToNimstr($1.node.sons[$2].name)" % [genTypeInfo(p, t), r.res] + r.res = "cstrToNimstr($1.node.sons[$2$3].name)" % [genTypeInfo(p, t), r.res, rope(offset)] else: # XXX: internalError(n.info, "genRepr: Not implemented") @@ -1678,8 +1719,9 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = else: if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2") else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)") - of mSetLengthStr: binaryExpr(p, n, r, "", "$1.length = $2+1; $1[$1.length-1] = 0" | "") - of mSetLengthSeq: binaryExpr(p, n, r, "", "$1.length = $2" | "") + of mSetLengthStr: + binaryExpr(p, n, r, "", "$1.length = $2+1; $1[$1.length-1] = 0" | "$1 = substr($1, 0, $2)") + of mSetLengthSeq: binaryExpr(p, n, r, "", "$1.length = $2" | "$1 = array_slice($1, 0, $2)") of mCard: unaryExpr(p, n, r, "SetCard", "SetCard($1)") of mLtSet: binaryExpr(p, n, r, "SetLt", "SetLt($1, $2)") of mLeSet: binaryExpr(p, n, r, "SetLe", "SetLe($1, $2)") @@ -1689,8 +1731,31 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = of mMinusSet: binaryExpr(p, n, r, "SetMinus", "SetMinus($1, $2)") of mIncl: binaryExpr(p, n, r, "", "$1[$2] = true") of mExcl: binaryExpr(p, n, r, "", "delete $1[$2]" | "unset $1[$2]") - of mInSet: binaryExpr(p, n, r, "", "($1[$2] != undefined)" | "isset($1[$2])") + of mInSet: + if p.target == targetJS: + binaryExpr(p, n, r, "", "($1[$2] != undefined)") + else: + let s = n.sons[1] + if s.kind == nkCurly: + var a, b, x: TCompRes + gen(p, n.sons[2], x) + r.res = rope("(") + r.kind = resExpr + for i in countup(0, sonsLen(s) - 1): + if i > 0: add(r.res, " || ") + var it = s.sons[i] + if it.kind == nkRange: + gen(p, it.sons[0], a) + gen(p, it.sons[1], b) + addf(r.res, "($1 >= $2 && $1 <= $3)", [x.res, a.res, b.res,]) + else: + gen(p, it, a) + addf(r.res, "($1 == $2)", [x.res, a.res]) + add(r.res, ")") + else: + binaryExpr(p, n, r, "", "isset($1[$2])") of mNewSeq: genNewSeq(p, n) + of mNewSeqOfCap: unaryExpr(p, n, r, "", "[]" | "array()") of mOf: genOf(p, n, r) of mReset: genReset(p, n) of mEcho: genEcho(p, n, r) @@ -1989,7 +2054,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone): genMagic(p, n, r) elif n.sons[0].kind == nkSym and sfInfixCall in n.sons[0].sym.flags and - n.len >= 2: + n.len >= 1: genInfixCall(p, n, r) else: genCall(p, n, r) diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim index 8d109e48a..cf1679ee4 100644 --- a/compiler/jstypes.nim +++ b/compiler/jstypes.nim @@ -165,4 +165,7 @@ proc genTypeInfo(p: PProc, typ: PType): Rope = of tyEnum: genEnumInfo(p, t, result) of tyObject: genObjectInfo(p, t, result) of tyTuple: genTupleInfo(p, t, result) + of tyStatic: + if t.n != nil: result = genTypeInfo(p, lastSon t) + else: internalError("genTypeInfo(" & $t.kind & ')') else: internalError("genTypeInfo(" & $t.kind & ')') diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 8b201431e..0a96ed0ba 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -735,7 +735,8 @@ proc getSymbol(L: var TLexer, tok: var TToken) = if c == '\226' and buf[pos+1] == '\128' and buf[pos+2] == '\147': # It's a 'magic separator' en-dash Unicode - if buf[pos + magicIdentSeparatorRuneByteWidth] notin SymChars: + if buf[pos + magicIdentSeparatorRuneByteWidth] notin SymChars or + isMagicIdentSeparatorRune(buf, pos+magicIdentSeparatorRuneByteWidth) or pos == L.bufpos: lexMessage(L, errInvalidToken, "–") break inc(pos, magicIdentSeparatorRuneByteWidth) @@ -747,7 +748,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) = h = h !& ord(c) inc(pos) of '_': - if buf[pos+1] notin SymChars: + if buf[pos+1] notin SymChars or isMagicIdentSeparatorRune(buf, pos+1): lexMessage(L, errInvalidToken, "_") break inc(pos) @@ -1056,7 +1057,8 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) = inc(L.bufpos) of '_': inc(L.bufpos) - if L.buf[L.bufpos] notin SymChars: + if L.buf[L.bufpos] notin SymChars+{'_'} and not + isMagicIdentSeparatorRune(L.buf, L.bufpos): tok.tokType = tkSymbol tok.ident = getIdent("_") else: @@ -1077,6 +1079,9 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) = tok.tokType = tkCharLit of '0'..'9': getNumber(L, tok) + let c = L.buf[L.bufpos] + if c in SymChars+{'_'}: + lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')') else: if c in OpChars: getOperator(L, tok) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 962c28613..ba2358b86 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -153,7 +153,8 @@ proc ensureNoMissingOrUnusedSymbols(scope: PScope) = if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}: # XXX: implicit type params are currently skTypes # maybe they can be made skGenericParam as well. - if s.typ != nil and tfImplicitTypeParam notin s.typ.flags: + if s.typ != nil and tfImplicitTypeParam notin s.typ.flags and + s.typ.kind != tyGenericParam: message(s.info, hintXDeclaredButNotUsed, getSymRepr(s)) s = nextIter(it, scope.symbols) diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 7a5c7f44b..cdea2a4ff 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -471,6 +471,7 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym; let slice = newNodeI(nkCall, n.info, 4) slice.typ = n.typ slice.sons[0] = newSymNode(createMagic("slice", mSlice)) + slice.sons[0].typ = getSysType(tyInt) # fake type var fieldB = newSym(skField, tmpName, objType.owner, n.info) fieldB.typ = getSysType(tyInt) objType.addField(fieldB) diff --git a/compiler/main.nim b/compiler/main.nim index b1b9006bd..0db66b53e 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -46,10 +46,11 @@ proc commandCheck = rodPass() compileProject() -proc commandDoc2 = +proc commandDoc2(json: bool) = msgs.gErrorMax = high(int) # do not stop after first error semanticPasses() - registerPass(docgen2Pass) + if json: registerPass(docgen2JsonPass) + else: registerPass(docgen2Pass) #registerPass(cleanupPass()) compileProject() finishDoc2Pass(gProjectName) @@ -281,7 +282,7 @@ proc mainCommand* = gCmd = cmdDoc loadConfigs(DocConfig) defineSymbol("nimdoc") - commandDoc2() + commandDoc2(false) of "rst2html": gCmd = cmdRst2html loadConfigs(DocConfig) @@ -296,7 +297,13 @@ proc mainCommand* = loadConfigs(DocConfig) wantMainModule() defineSymbol("nimdoc") - commandJSON() + commandJson() + of "jsondoc2": + gCmd = cmdDoc + loadConfigs(DocConfig) + wantMainModule() + defineSymbol("nimdoc") + commandDoc2(true) of "buildindex": gCmd = cmdDoc loadConfigs(DocConfig) diff --git a/compiler/modules.nim b/compiler/modules.nim index 8ac964321..8df300f5f 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -29,6 +29,10 @@ var gMemCacheData*: seq[TModuleInMemory] = @[] ## XXX: we should implement recycling of file IDs ## if the user keeps renaming modules, the file IDs will keep growing + gFuzzyGraphChecking*: bool # nimsuggest uses this. XXX figure out why. + packageSyms: TStrTable + +initStrTable(packageSyms) proc getModule*(fileIdx: int32): PSym = if fileIdx >= 0 and fileIdx < gCompiledModules.len: @@ -90,6 +94,7 @@ proc resetAllModules* = if gCompiledModules[i] != nil: resetModule(i.int32) resetPackageCache() + initStrTable(packageSyms) # for m in cgenModules(): echo "CGEN MODULE FOUND" proc resetAllModulesHard* = @@ -97,6 +102,7 @@ proc resetAllModulesHard* = gCompiledModules.setLen 0 gMemCacheData.setLen 0 magicsys.resetSysTypes() + initStrTable(packageSyms) # XXX #gOwners = @[] @@ -105,12 +111,16 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile = resetModule(fileIdx) return Yes - if gMemCacheData[fileIdx].needsRecompile != Maybe: - return gMemCacheData[fileIdx].needsRecompile + if gFuzzyGraphChecking: + if gMemCacheData[fileIdx].needsRecompile != Maybe: + return gMemCacheData[fileIdx].needsRecompile + else: + # cycle detection: We claim that a cycle does no harm. + if gMemCacheData[fileIdx].needsRecompile == Probing: + return No - if optForceFullMake in gGlobalOptions or - hashChanged(fileIdx): - markDirty + if optForceFullMake in gGlobalOptions or hashChanged(fileIdx): + markDirty() if gMemCacheData[fileIdx].deps != nil: gMemCacheData[fileIdx].needsRecompile = Probing @@ -118,7 +128,7 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile = let d = checkDepMem(dep) if d in {Yes, Recompiled}: # echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d - markDirty + markDirty() gMemCacheData[fileIdx].needsRecompile = No return No @@ -135,8 +145,16 @@ proc newModule(fileIdx: int32): PSym = rawMessage(errInvalidModuleName, result.name.s) result.info = newLineInfo(fileIdx, 1, 1) - result.owner = newSym(skPackage, getIdent(getPackageName(filename)), nil, - result.info) + let pack = getIdent(getPackageName(filename)) + var packSym = packageSyms.strTableGet(pack) + if packSym == nil: + let pck = getPackageName(filename) + let pck2 = if pck.len > 0: pck else: "unknown" + packSym = newSym(skPackage, getIdent(pck2), nil, result.info) + initStrTable(packSym.tab) + packageSyms.strTableAdd(packSym) + + result.owner = packSym result.position = fileIdx growCache gMemCacheData, fileIdx @@ -146,6 +164,11 @@ proc newModule(fileIdx: int32): PSym = incl(result.flags, sfUsed) initStrTable(result.tab) strTableAdd(result.tab, result) # a module knows itself + let existing = strTableGet(packSym.tab, result.name) + if existing != nil and existing.info.fileIndex != result.info.fileIndex: + localError(result.info, "module names need to be unique per Nimble package; module clashes with " & existing.info.fileIndex.toFullPath) + # strTableIncl() for error corrections: + discard strTableIncl(packSym.tab, result) proc compileModule*(fileIdx: int32, flags: TSymFlags): PSym = result = getModule(fileIdx) @@ -184,8 +207,8 @@ proc importModule*(s: PSym, fileIdx: int32): PSym {.procvar.} = # this is called by the semantic checking phase result = compileModule(fileIdx, {}) if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx) - if sfSystemModule in result.flags: - localError(result.info, errAttemptToRedefine, result.name.s) + #if sfSystemModule in result.flags: + # localError(result.info, errAttemptToRedefine, result.name.s) # restore the notes for outer module: gNotes = if s.owner.id == gMainPackageId: gMainPackageNotes else: ForeignPackageNotes diff --git a/compiler/msgs.nim b/compiler/msgs.nim index ce9d8c8b6..83914753f 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -502,8 +502,6 @@ type ESuggestDone* = object of Exception const - ForeignPackageNotes*: TNoteKinds = {hintProcessing, warnUnknownMagic, - hintQuitCalled} NotesVerbosity*: array[0..3, TNoteKinds] = [ {low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit, warnProveField, warnProveIndex, @@ -520,7 +518,6 @@ const warnGcUnsafe, hintPath, hintDependency, - hintExecuting, hintCodeBegin, hintCodeEnd, hintSource, hintStackTrace, hintGCStats}, @@ -531,6 +528,8 @@ const InvalidFileIDX* = int32(-1) var + ForeignPackageNotes*: TNoteKinds = {hintProcessing, warnUnknownMagic, + hintQuitCalled, hintExecuting} filenameToIndexTbl = initTable[string, int32]() fileInfos*: seq[TFileInfo] = @[] systemFileIdx*: int32 @@ -621,6 +620,7 @@ var gHintCounter*: int = 0 gWarnCounter*: int = 0 gErrorMax*: int = 1 # stop after gErrorMax errors + gMainPackageNotes*: TNoteKinds = NotesVerbosity[1] proc unknownLineInfo*(): TLineInfo = result.line = int16(-1) diff --git a/compiler/nimfix/pretty.nim b/compiler/nimfix/pretty.nim index 1123afb9e..8ba922927 100644 --- a/compiler/nimfix/pretty.nim +++ b/compiler/nimfix/pretty.nim @@ -66,7 +66,7 @@ proc beautifyName(s: string, k: TSymKind): string = ]: result.add s[i] else: - result.add toUpper(s[i]) + result.add toUpperAscii(s[i]) of skConst, skEnumField: # for 'const' we keep how it's spelt; either upper case or lower case: result.add s[0] @@ -74,7 +74,7 @@ proc beautifyName(s: string, k: TSymKind): string = # as a special rule, don't transform 'L' to 'l' if s.len == 1 and s[0] == 'L': result.add 'L' elif '_' in s: result.add(s[i]) - else: result.add toLower(s[0]) + else: result.add toLowerAscii(s[0]) inc i while i < s.len: if s[i] == '_': @@ -85,9 +85,9 @@ proc beautifyName(s: string, k: TSymKind): string = result.add s[i] else: inc i - result.add toUpper(s[i]) + result.add toUpperAscii(s[i]) elif allUpper: - result.add toLower(s[i]) + result.add toLowerAscii(s[i]) else: result.add s[i] inc i diff --git a/compiler/options.nim b/compiler/options.nim index 7797a4c82..dbd8ca2b9 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -151,6 +151,7 @@ const var gConfigVars* = newStringTable(modeStyleInsensitive) gDllOverrides = newStringTable(modeCaseInsensitive) + gModuleOverrides* = newStringTable(modeStyleInsensitive) gPrefixDir* = "" # Overrides the default prefix dir in getPrefixDir proc. libpath* = "" gProjectName* = "" # holds a name like 'nim' @@ -211,9 +212,7 @@ proc setDefaultLibpath*() = # Special rule to support other tools (nimble) which import the compiler # modules and make use of them. - let realNimPath = # Make sure we expand the symlink - if symlinkExists(findExe("nim")): expandSymlink(findExe("nim")) - else: findExe("nim") + let realNimPath = findExe("nim") # Find out if $nim/../../lib/system.nim exists. let parentNimLibPath = realNimPath.parentDir().parentDir() / "lib" if not fileExists(libpath / "system.nim") and @@ -221,7 +220,7 @@ proc setDefaultLibpath*() = libpath = parentNimLibPath proc canonicalizePath*(path: string): string = - when not FileSystemCaseSensitive: result = path.expandFilename.toLower + when not FileSystemCaseSensitive: result = path.expandFilename.toLowerAscii else: result = path.expandFilename proc shortenDir*(dir: string): string = @@ -240,6 +239,8 @@ proc removeTrailingDirSep*(path: string): string = else: result = path +include packagehandling + proc getNimcacheDir*: string = result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir / genSubDir @@ -259,54 +260,6 @@ proc pathSubs*(p, config: string): string = if '~' in result: result = result.replace("~", home) -template newPackageCache(): expr = - newStringTable(when FileSystemCaseSensitive: - modeCaseInsensitive - else: - modeCaseSensitive) - -var packageCache = newPackageCache() - -proc resetPackageCache*() = packageCache = newPackageCache() - -iterator myParentDirs(p: string): string = - # XXX os's parentDirs is stupid (multiple yields) and triggers an old bug... - var current = p - while true: - current = current.parentDir - if current.len == 0: break - yield current - -proc getPackageName*(path: string): string = - var parents = 0 - block packageSearch: - for d in myParentDirs(path): - if packageCache.hasKey(d): - #echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name - return packageCache[d] - inc parents - for file in walkFiles(d / "*.nimble"): - result = file.splitFile.name - break packageSearch - for file in walkFiles(d / "*.babel"): - result = file.splitFile.name - break packageSearch - # we also store if we didn't find anything: - if result.isNil: result = "" - for d in myParentDirs(path): - #echo "set cache ", d, " |", result, "|", parents - packageCache[d] = result - dec parents - if parents <= 0: break - -proc withPackageName*(path: string): string = - let x = path.getPackageName - if x.len == 0: - result = path - else: - let (p, file, ext) = path.splitFile - result = (p / (x & '_' & file)) & ext - proc toGeneratedFile*(path, ext: string): string = ## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod" var (head, tail) = splitPath(path) @@ -374,17 +327,25 @@ proc rawFindFile2(f: string): string = it = PStrEntry(it.next) result = "" +template patchModule() {.dirty.} = + if result.len > 0 and gModuleOverrides.len > 0: + let key = getPackageName(result) & "_" & splitFile(result).name + if gModuleOverrides.hasKey(key): + let ov = gModuleOverrides[key] + if ov.len > 0: result = ov + proc findFile*(f: string): string {.procvar.} = if f.isAbsolute: result = if f.existsFile: f else: "" else: result = f.rawFindFile if result.len == 0: - result = f.toLower.rawFindFile + result = f.toLowerAscii.rawFindFile if result.len == 0: result = f.rawFindFile2 if result.len == 0: - result = f.toLower.rawFindFile2 + result = f.toLowerAscii.rawFindFile2 + patchModule() proc findModule*(modulename, currentModule: string): string = # returns path to module @@ -403,6 +364,7 @@ proc findModule*(modulename, currentModule: string): string = result = currentPath / m if not existsFile(result): result = findFile(m) + patchModule() proc libCandidates*(s: string, dest: var seq[string]) = var le = strutils.find(s, '(') diff --git a/compiler/packagehandling.nim b/compiler/packagehandling.nim new file mode 100644 index 000000000..c42a4d763 --- /dev/null +++ b/compiler/packagehandling.nim @@ -0,0 +1,56 @@ +# +# +# The Nim Compiler +# (c) Copyright 2016 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +iterator myParentDirs(p: string): string = + # XXX os's parentDirs is stupid (multiple yields) and triggers an old bug... + var current = p + while true: + current = current.parentDir + if current.len == 0: break + yield current + +template newPackageCache(): expr = + newStringTable(when FileSystemCaseSensitive: + modeCaseInsensitive + else: + modeCaseSensitive) + +var packageCache = newPackageCache() + +proc resetPackageCache*() = packageCache = newPackageCache() + +proc getPackageName*(path: string): string = + var parents = 0 + block packageSearch: + for d in myParentDirs(path): + if packageCache.hasKey(d): + #echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name + return packageCache[d] + inc parents + for file in walkFiles(d / "*.nimble"): + result = file.splitFile.name + break packageSearch + for file in walkFiles(d / "*.babel"): + result = file.splitFile.name + break packageSearch + # we also store if we didn't find anything: + if result.isNil: result = "" + for d in myParentDirs(path): + #echo "set cache ", d, " |", result, "|", parents + packageCache[d] = result + dec parents + if parents <= 0: break + +proc withPackageName*(path: string): string = + let x = path.getPackageName + if x.len == 0: + result = path + else: + let (p, file, ext) = path.splitFile + result = (p / (x & '_' & file)) & ext diff --git a/compiler/parser.nim b/compiler/parser.nim index 6132216e1..8b20b56db 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -686,11 +686,19 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode = #| | '{' optInd indexExprList optPar '}' #| | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax result = r + + template somePar() = + if p.tok.strongSpaceA > 0: + if p.strongSpaces: + break + else: + parMessage(p, warnDeprecated, + "a [b] will be parsed as command syntax; spacing") while p.tok.indent < 0 or (p.tok.tokType == tkDot and p.tok.indent >= baseIndent): case p.tok.tokType of tkParLe: - if p.strongSpaces and p.tok.strongSpaceA > 0: break + somePar() result = namedParams(p, result, nkCall, tkParRi) if result.len > 1 and result.sons[1].kind == nkExprColonExpr: result.kind = nkObjConstr @@ -705,10 +713,10 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode = result = dotExpr(p, result) result = parseGStrLit(p, result) of tkBracketLe: - if p.strongSpaces and p.tok.strongSpaceA > 0: break + somePar() result = namedParams(p, result, nkBracketExpr, tkBracketRi) of tkCurlyLe: - if p.strongSpaces and p.tok.strongSpaceA > 0: break + somePar() result = namedParams(p, result, nkCurlyExpr, tkCurlyRi) of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType: if p.inPragma == 0: diff --git a/compiler/passaux.nim b/compiler/passaux.nim index 9b9fdca4e..d4361a671 100644 --- a/compiler/passaux.nim +++ b/compiler/passaux.nim @@ -24,7 +24,7 @@ proc verboseProcess(context: PPassContext, n: PNode): PNode = # system.nim deactivates all hints, for verbosity:3 we want the processing # messages nonetheless, so we activate them again unconditionally: incl(msgs.gNotes, hintProcessing) - message(n.info, hintProcessing, $idgen.gBackendId) + message(n.info, hintProcessing, $idgen.gFrontendId) const verbosePass* = makePass(open = verboseOpen, process = verboseProcess) diff --git a/compiler/patterns.nim b/compiler/patterns.nim index 2336e44e7..09b8d3305 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -75,7 +75,7 @@ proc checkTypes(c: PPatternContext, p: PSym, n: PNode): bool = result = matchNodeKinds(p.constraint, n) if not result: return if isNil(n.typ): - result = p.typ.kind in {tyEmpty, tyStmt} + result = p.typ.kind in {tyVoid, tyStmt} else: result = sigmatch.argtypeMatches(c.c, p.typ, n.typ) diff --git a/compiler/platform.nim b/compiler/platform.nim index dc414bfeb..36ec10477 100644 --- a/compiler/platform.nim +++ b/compiler/platform.nim @@ -159,7 +159,7 @@ type # alias conditionals to condsyms (end of module). cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64, cpuPowerpc64el, cpuSparc, cpuVm, cpuIa64, cpuAmd64, cpuMips, cpuMipsel, - cpuArm, cpuArm64, cpuJS, cpuNimrodVM, cpuAVR, cpuMSP430 + cpuArm, cpuArm64, cpuJS, cpuNimrodVM, cpuAVR, cpuMSP430, cpuSparc64 type TEndian* = enum @@ -187,7 +187,8 @@ const (name: "js", intSize: 32, endian: bigEndian,floatSize: 64,bit: 32), (name: "nimrodvm", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32), (name: "avr", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16), - (name: "msp430", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16)] + (name: "msp430", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16), + (name: "sparc64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64)] var targetCPU*, hostCPU*: TSystemCPU diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index dc618d9aa..d7d1ed838 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -63,11 +63,12 @@ const wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal, wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims} constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl, - wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims} + wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims, + wIntDefine, wStrDefine} letPragmas* = varPragmas procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect, wThread, wRaises, wLocks, wTags, wGcSafe} - allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas + allRoutinePragmas* = methodPragmas + iteratorPragmas + lambdaPragmas proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) # implementation @@ -898,6 +899,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, of wBase: noVal(it) sym.flags.incl sfBase + of wIntDefine: + sym.magic = mIntDefine + of wStrDefine: + sym.magic = mStrDefine else: invalidPragma(it) else: invalidPragma(it) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index e1db327f4..0e733d643 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -704,7 +704,10 @@ proc gcase(g: var TSrcGen, n: PNode) = proc gproc(g: var TSrcGen, n: PNode) = var c: TContext if n.sons[namePos].kind == nkSym: - put(g, tkSymbol, renderDefinitionName(n.sons[namePos].sym)) + let s = n.sons[namePos].sym + put(g, tkSymbol, renderDefinitionName(s)) + if sfGenSym in s.flags: + put(g, tkIntLit, $s.id) else: gsub(g, n.sons[namePos]) @@ -798,7 +801,8 @@ proc gident(g: var TSrcGen, n: PNode) = else: t = tkOpr put(g, t, s) - if n.kind == nkSym and renderIds in g.flags: put(g, tkIntLit, $n.sym.id) + if n.kind == nkSym and (renderIds in g.flags or sfGenSym in n.sym.flags): + put(g, tkIntLit, $n.sym.id) proc doParamsAux(g: var TSrcGen, params: PNode) = if params.len > 1: diff --git a/compiler/rodutils.nim b/compiler/rodutils.nim index 91f93d279..945c94bc6 100644 --- a/compiler/rodutils.nim +++ b/compiler/rodutils.nim @@ -21,7 +21,7 @@ proc toStrMaxPrecision*(f: BiggestFloat): string = if f > 0.0: result = "INF" else: result = "-INF" else: - var buf: array [0..80, char] + var buf: array[0..80, char] c_sprintf(buf, "%#.16e", f) result = $buf diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index d04fd5231..833444788 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -13,10 +13,10 @@ import ast, modules, passes, passaux, condsyms, options, nimconf, lists, sem, semdata, llstream, vm, vmdef, commands, msgs, - os, times, osproc + os, times, osproc, wordrecg, strtabs # we support 'cmpIgnoreStyle' natively for efficiency: -from strutils import cmpIgnoreStyle +from strutils import cmpIgnoreStyle, contains proc listDirs(a: VmArgs, filter: set[PathComponent]) = let dir = getString(a, 0) @@ -116,7 +116,20 @@ proc setupVM*(module: PSym; scriptName: string): PEvalContext = setResult(a, options.command) cbconf switch: processSwitch(a.getString 0, a.getString 1, passPP, unknownLineInfo()) - + cbconf hintImpl: + processSpecificNote(a.getString 0, wHint, passPP, unknownLineInfo(), + a.getString 1) + cbconf warningImpl: + processSpecificNote(a.getString 0, wWarning, passPP, unknownLineInfo(), + a.getString 1) + cbconf patchFile: + let key = a.getString(0) & "_" & a.getString(1) + var val = a.getString(2).addFileExt(NimExt) + if {'$', '~'} in val: + val = pathSubs(val, vthisDir) + elif not isAbsolute(val): + val = vthisDir / val + gModuleOverrides[key] = val proc runNimScript*(scriptName: string; freshDefines=true) = passes.gIncludeFile = includeModule diff --git a/compiler/sem.nim b/compiler/sem.nim index a8ec2229f..7db4ae47e 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -59,8 +59,7 @@ template semIdeForTemplateOrGeneric(c: PContext; n: PNode; # templates perform some quick check whether the cursor is actually in # the generic or template. when defined(nimsuggest): - assert gCmd == cmdIdeTools - if requiresCheck: + if gCmd == cmdIdeTools and requiresCheck: #if optIdeDebug in gGlobalOptions: # echo "passing to safeSemExpr: ", renderTree(n) discard safeSemExpr(c, n) @@ -165,7 +164,7 @@ proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info) proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = - proc `$`(kind: TSymKind): string = substr(system.`$`(kind), 2).toLower + proc `$`(kind: TSymKind): string = substr(system.`$`(kind), 2).toLowerAscii # like newSymS, but considers gensym'ed symbols if n.kind == nkSym: @@ -307,6 +306,13 @@ proc semConstExpr(c: PContext, n: PNode): PNode = include hlo, seminst, semcall +when false: + # hopefully not required: + proc resetSemFlag(n: PNode) = + excl n.flags, nfSem + for i in 0 ..< n.safeLen: + resetSemFlag(n[i]) + proc semAfterMacroCall(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = ## Semantically check the output of a macro. @@ -320,6 +326,8 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym, c.friendModules.add(s.owner.getModule) result = n + excl(n.flags, nfSem) + #resetSemFlag n if s.typ.sons[0] == nil: result = semStmt(c, result) else: @@ -409,9 +417,6 @@ proc myOpen(module: PSym): PPassContext = c.importTable.addSym(module) # a module knows itself if sfSystemModule in module.flags: magicsys.systemModule = module # set global variable! - else: - c.importTable.addSym magicsys.systemModule # import the "System" identifier - importAllSymbols(c, magicsys.systemModule) c.topLevelScope = openScope(c) # don't be verbose unless the module belongs to the main package: if module.owner.id == gMainPackageId: @@ -425,7 +430,29 @@ proc myOpenCached(module: PSym, rd: PRodReader): PPassContext = result = myOpen(module) for m in items(rd.methods): methodDef(m, true) +proc isImportSystemStmt(n: PNode): bool = + if magicsys.systemModule == nil: return false + case n.kind + of nkImportStmt: + for x in n: + let f = checkModuleName(x) + if f == magicsys.systemModule.info.fileIndex: + return true + of nkImportExceptStmt, nkFromStmt: + let f = checkModuleName(n[0]) + if f == magicsys.systemModule.info.fileIndex: + return true + else: discard + proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode = + if c.topStmts == 0 and not isImportSystemStmt(n): + if sfSystemModule notin c.module.flags and + n.kind notin {nkEmpty, nkCommentStmt}: + c.importTable.addSym magicsys.systemModule # import the "System" identifier + importAllSymbols(c, magicsys.systemModule) + inc c.topStmts + else: + inc c.topStmts if sfNoForward in c.module.flags: result = semAllTypeSections(c, n) else: diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim index a1e209263..9702128ba 100644 --- a/compiler/semasgn.nim +++ b/compiler/semasgn.nim @@ -183,7 +183,7 @@ proc newSeqCall(c: PContext; x, y: PNode): PNode = proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) = case t.kind - of tyNone, tyEmpty: discard + of tyNone, tyEmpty, tyVoid: discard of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString, tyPtr, tyString, tyRef: defaultOp(c, t, body, x, y) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 65aa5fd58..87a34ca4a 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -69,7 +69,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, # gDebug = true matches(c, n, orig, z) if errors != nil: - errors.safeAdd(sym) + errors.safeAdd((sym, int z.mutabilityProblem)) if z.errors != nil: for err in z.errors: errors.add(err) @@ -111,7 +111,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) = let proto = describeArgs(c, n, 1, preferName) var prefer = preferName - for err in errors: + for err, mut in items(errors): var errProto = "" let n = err.typ.n for i in countup(1, n.len - 1): @@ -123,18 +123,21 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) = if errProto == proto: prefer = preferModuleInfo break + # now use the information stored in 'prefer' to produce a nice error message: var result = msgKindToString(errTypeMismatch) add(result, describeArgs(c, n, 1, prefer)) add(result, ')') var candidates = "" - for err in errors: + for err, mut in items(errors): if err.kind in routineKinds and err.ast != nil: add(candidates, renderTree(err.ast, {renderNoBody, renderNoComments,renderNoPragmas})) else: add(candidates, err.getProcHeader(prefer)) add(candidates, "\n") + if mut != 0 and mut < n.len: + add(candidates, "for a 'var' type a variable needs to be passed, but '" & renderTree(n[mut]) & "' is immutable\n") if candidates != "": add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates) if c.compilesContextId > 0 and optReportConceptFailures in gGlobalOptions: @@ -142,6 +145,20 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) = else: localError(n.info, errGenerated, result) +proc bracketNotFoundError(c: PContext; n: PNode) = + var errors: CandidateErrors = @[] + var o: TOverloadIter + let headSymbol = n[0] + var symx = initOverloadIter(o, c, headSymbol) + while symx != nil: + if symx.kind in routineKinds: + errors.add((symx, 0)) + symx = nextOverloadIter(o, c, headSymbol) + if errors.len == 0: + localError(n.info, "could not resolve: " & $n) + else: + notFoundError(c, n, errors) + proc resolveOverloads(c: PContext, n, orig: PNode, filter: TSymKinds; errors: var CandidateErrors): TCandidate = @@ -158,8 +175,6 @@ proc resolveOverloads(c: PContext, n, orig: PNode, template pickBest(headSymbol) = pickBestCandidate(c, headSymbol, n, orig, initialBinding, filter, result, alt, errors) - - pickBest(f) let overloadsState = result.state @@ -230,7 +245,6 @@ proc resolveOverloads(c: PContext, n, orig: PNode, #notFoundError(c, n, errors) return - if alt.state == csMatch and cmpCandidates(result, alt) == 0 and not sameMethodDispatcher(result.calleeSym, alt.calleeSym): internalAssert result.state == csMatch @@ -299,8 +313,7 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode = var finalCallee = x.calleeSym markUsed(n.sons[0].info, finalCallee) styleCheckUse(n.sons[0].info, finalCallee) - if finalCallee.ast == nil: - internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check! + assert finalCallee.ast != nil if x.hasFauxMatch: result = x.call result.sons[0] = newSymNode(finalCallee, result.sons[0].info) @@ -319,12 +332,12 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode = # are added as normal params. for s in instantiateGenericParamList(c, gp, x.bindings): case s.kind - of skConst: - x.call.add s.ast - of skType: - x.call.add newSymNode(s, n.info) - else: - internalAssert false + of skConst: + x.call.add s.ast + of skType: + x.call.add newSymNode(s, n.info) + else: + internalAssert false result = x.call instGenericConvertersSons(c, result, x) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 91a1ebf86..30b6e261d 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -99,11 +99,12 @@ type unknownIdents*: IntSet # ids of all unknown identifiers to prevent # naming it multiple times generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile + topStmts*: int # counts the number of encountered top level statements lastGenericIdx*: int # used for the generics stack hloLoopDetector*: int # used to prevent endless loops in the HLO inParallelStmt*: int instTypeBoundOp*: proc (c: PContext; dc: PSym; t: PType; info: TLineInfo; - op: TTypeAttachedOp): PSym {.nimcall.} + op: TTypeAttachedOp; col: int): PSym {.nimcall.} selfName*: PIdent signatures*: TStrTable diff --git a/compiler/semdestruct.nim b/compiler/semdestruct.nim index 1261dd460..18a1c262f 100644 --- a/compiler/semdestruct.nim +++ b/compiler/semdestruct.nim @@ -139,6 +139,7 @@ proc instantiateDestructor(c: PContext, typ: PType): PType = t = t.skipTypes({tyGenericInst}) case t.kind of tySequence, tyArray, tyArrayConstr, tyOpenArray, tyVarargs: + t.destructor = analyzingDestructor if instantiateDestructor(c, t.sons[0]) != nil: t.destructor = getCompilerProc"nimDestroyRange" return t diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 57fb3ceed..9f0696252 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -32,8 +32,7 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # XXX tyGenericInst here? if result.typ.kind == tyVar: result = newDeref(result) elif {efWantStmt, efAllowStmt} * flags != {}: - result.typ = newTypeS(tyEmpty, c) - result.typ.flags.incl tfVoid + result.typ = newTypeS(tyVoid, c) else: localError(n.info, errExprXHasNoType, renderTree(result, {renderNoComments})) @@ -51,7 +50,6 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = renderTree(result, {renderNoComments})) result.typ = errorType(c) else: - # XXX tyGenericInst here? if efNoProcvarCheck notin flags: semProcvarCheck(c, result) if result.typ.kind == tyVar: result = newDeref(result) semDestructorCheck(c, result, flags) @@ -199,6 +197,8 @@ proc semConv(c: PContext, n: PNode): PNode = # separate proc from fitNode? if op.kind == nkSym and op.sym.isGenericRoutine: result.sons[1] = fitNode(c, result.typ, result.sons[1]) + elif op.kind == nkPar and targetType.kind == tyTuple: + op = fitNode(c, targetType, op) of convNotNeedeed: message(n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString) of convNotLegal: @@ -601,6 +601,9 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = result = n if n.kind notin nkCallKinds or n.sons[0].kind != nkSym: return var callee = n.sons[0].sym + # workaround for bug #537 (overly aggressive inlining leading to + # wrong NimNode semantics): + if n.typ != nil and tfTriggersCompileTime in n.typ.flags: return # constant folding that is necessary for correctness of semantic pass: if callee.magic != mNone and callee.magic in ctfeWhitelist and n.typ != nil: @@ -1063,8 +1066,11 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = result = newSymNode(s, n.info) result.typ = makeTypeDesc(c, s.typ) of skField: - if c.p != nil and c.p.selfSym != nil: - var ty = skipTypes(c.p.selfSym.typ, {tyGenericInst, tyVar, tyPtr, tyRef}) + var p = c.p + while p != nil and p.selfSym == nil: + p = p.next + if p != nil and p.selfSym != nil: + var ty = skipTypes(p.selfSym.typ, {tyGenericInst, tyVar, tyPtr, tyRef}) while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct}) var check: PNode = nil if ty.kind == tyObject: @@ -1077,7 +1083,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = markUsed(n.info, f) styleCheckUse(n.info, f) result = newNodeIT(nkDotExpr, n.info, f.typ) - result.add makeDeref(newSymNode(c.p.selfSym)) + result.add makeDeref(newSymNode(p.selfSym)) result.add newSymNode(f) # we now have the correct field if check != nil: check.sons[0] = result @@ -1385,15 +1391,16 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = # --> `[]=`(a, i, x) let oldBracketExpr = c.p.bracketExpr a = semSubscript(c, a, {efLValue}) - if a == nil and mode != noOverloadedSubscript: + if a == nil: result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=") add(result, n[1]) - result = semExprNoType(c, result) - c.p.bracketExpr = oldBracketExpr - return result - elif a == nil: - localError(n.info, "could not resolve: " & $n[0]) - return n + if mode == noOverloadedSubscript: + bracketNotFoundError(c, result) + return n + else: + result = semExprNoType(c, result) + c.p.bracketExpr = oldBracketExpr + return result c.p.bracketExpr = oldBracketExpr of nkCurlyExpr: # a{i} = x --> `{}=`(a, i, x) @@ -1629,8 +1636,8 @@ proc newAnonSym(kind: TSymKind, info: TLineInfo, result.flags = {sfGenSym} proc semExpandToAst(c: PContext, n: PNode): PNode = - var macroCall = n[1] - var expandedSym = expectMacroOrTemplateCall(c, macroCall) + let macroCall = n[1] + let expandedSym = expectMacroOrTemplateCall(c, macroCall) if expandedSym.kind == skError: return n macroCall.sons[0] = newSymNode(expandedSym, macroCall.info) @@ -1638,11 +1645,12 @@ proc semExpandToAst(c: PContext, n: PNode): PNode = styleCheckUse(n.info, expandedSym) for i in countup(1, macroCall.len-1): + #if macroCall.sons[0].typ.sons[i].kind != tyExpr: macroCall.sons[i] = semExprWithType(c, macroCall[i], {}) # Preserve the magic symbol in order to be handled in evals.nim internalAssert n.sons[0].sym.magic == mExpandToAst - #n.typ = getSysSym("PNimrodNode").typ # expandedSym.getReturnType + #n.typ = getSysSym("NimNode").typ # expandedSym.getReturnType n.typ = if getCompilerProc("NimNode") != nil: sysTypeFromName"NimNode" else: sysTypeFromName"PNimrodNode" result = n diff --git a/compiler/semfold.nim b/compiler/semfold.nim index feea6ce34..e9ee50d74 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -286,13 +286,14 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = of mNot: result = newIntNodeT(1 - getInt(a), n) of mCard: result = newIntNodeT(nimsets.cardSet(a), n) of mBitnotI: result = newIntNodeT(not getInt(a), n) - of mLengthStr, mXLenStr: - if a.kind == nkNilLit: result = newIntNodeT(0, n) - else: result = newIntNodeT(len(getStr(a)), n) of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n) - of mLengthSeq, mLengthOpenArray, mXLenSeq: - if a.kind == nkNilLit: result = newIntNodeT(0, n) - else: result = newIntNodeT(sonsLen(a), n) # BUGFIX + of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr: + if a.kind == nkNilLit: + result = newIntNodeT(0, n) + elif a.kind in {nkStrLit..nkTripleStrLit}: + result = newIntNodeT(len a.strVal, n) + else: + result = newIntNodeT(sonsLen(a), n) # BUGFIX of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away of mToFloat, mToBiggestFloat: result = newFloatNodeT(toFloat(int(getInt(a))), n) @@ -634,12 +635,18 @@ proc getConstExpr(m: PSym, n: PNode): PNode = of mCompileDate: result = newStrNodeT(times.getDateStr(), n) of mCompileTime: result = newStrNodeT(times.getClockStr(), n) of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n) - of mHostOS: result = newStrNodeT(toLower(platform.OS[targetOS].name), n) - of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLower, n) + of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[targetOS].name), n) + of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLowerAscii, n) of mAppType: result = getAppType(n) of mNaN: result = newFloatNodeT(NaN, n) of mInf: result = newFloatNodeT(Inf, n) of mNegInf: result = newFloatNodeT(NegInf, n) + of mIntDefine: + if isDefined(s.name): + result = newIntNodeT(lookupSymbol(s.name).parseInt, n) + of mStrDefine: + if isDefined(s.name): + result = newStrNodeT(lookupSymbol(s.name), n) else: if sfFakeConst notin s.flags: result = copyTree(s.ast) of {skProc, skMethod}: diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 0ba76ccd3..b78679411 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -426,7 +426,12 @@ proc semGenericStmt(c: PContext, n: PNode, n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx) n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags, ctx) var body: PNode - if n.sons[namePos].kind == nkSym: body = n.sons[namePos].sym.getBody + if n.sons[namePos].kind == nkSym: + let s = n.sons[namePos].sym + if sfGenSym in s.flags and s.ast == nil: + body = n.sons[bodyPos] + else: + body = s.getBody else: body = n.sons[bodyPos] n.sons[bodyPos] = semGenericStmtScope(c, body, flags, ctx) closeScope(c) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index e4ac56cd6..460db4f7c 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -205,7 +205,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable, # The solution would be to move this logic into semtypinst, but # at this point semtypinst have to become part of sem, because it # will need to use openScope, addDecl, etc. - addDecl(c, prc) + #addDecl(c, prc) pushInfoContext(info) var cl = initTypeVars(c, pt, info, nil) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 1945d87eb..451745884 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -42,7 +42,10 @@ proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode = result = semSubscript(c, result, flags) c.p.bracketExpr = oldBracketExpr if result.isNil: - localError(n.info, "could not resolve: " & $n) + let x = copyTree(n) + x.sons[0] = newIdentNode(getIdent"[]", n.info) + bracketNotFoundError(c, x) + #localError(n.info, "could not resolve: " & $n) result = n proc semArrPut(c: PContext; n: PNode; flags: TExprFlags): PNode = diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim index b04ba4657..a4ec14250 100644 --- a/compiler/semparallel.nim +++ b/compiler/semparallel.nim @@ -74,8 +74,6 @@ type currentSpawnId: int inLoop: int -let opSlice = createMagic("slice", mSlice) - proc initAnalysisCtx(): AnalysisCtx = result.locals = @[] result.slices = @[] @@ -399,7 +397,9 @@ proc transformSlices(n: PNode): PNode = let op = n[0].sym if op.name.s == "[]" and op.fromSystem: result = copyNode(n) - result.add opSlice.newSymNode + let opSlice = newSymNode(createMagic("slice", mSlice)) + opSlice.typ = getSysType(tyInt) + result.add opSlice result.add n[1] let slice = n[2].skipStmtList result.add slice[1] diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 7155f9c7a..1f076aa31 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -138,7 +138,7 @@ proc fixNilType(n: PNode) = proc discardCheck(c: PContext, result: PNode) = if c.inTypeClass > 0: return - if result.typ != nil and result.typ.kind notin {tyStmt, tyEmpty}: + if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}: if result.kind == nkNilLit: result.typ = nil message(result.info, warnNilStatement) @@ -411,6 +411,13 @@ proc semUsing(c: PContext; n: PNode): PNode = if a.sons[length-1].kind != nkEmpty: localError(a.info, "'using' sections cannot contain assignments") +proc hasEmpty(typ: PType): bool = + if typ.kind in {tySequence, tyArray, tySet}: + result = typ.lastSon.kind == tyEmpty + elif typ.kind == tyTuple: + for s in typ.sons: + result = result or hasEmpty(s) + proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = var b: PNode result = copyNode(n) @@ -445,10 +452,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = #changeType(def.skipConv, typ, check=true) else: typ = skipIntLit(def.typ) - if typ.kind in {tySequence, tyArray, tySet} and - typ.lastSon.kind == tyEmpty: + if hasEmpty(typ): localError(def.info, errCannotInferTypeOfTheLiteral, - ($typ.kind).substr(2).toLower) + ($typ.kind).substr(2).toLowerAscii) else: def = ast.emptyNode if symkind == skLet: localError(a.info, errLetNeedsInit) @@ -711,7 +717,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = a.sons[1] = s.typ.n s.typ.size = -1 # could not be computed properly # we fill it out later. For magic generics like 'seq', it won't be filled - # so we use tyEmpty instead of nil to not crash for strange conversions + # so we use tyNone instead of nil to not crash for strange conversions # like: mydata.seq rawAddSon(s.typ, newTypeS(tyNone, c)) s.ast = a @@ -1246,6 +1252,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, pushOwner(s) s.options = gOptions if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n) + if s.name.s[0] in {'.', '('}: + if s.name.s in [".", ".()", ".=", "()"] and not experimentalMode(c): + message(n.info, warnDeprecated, "overloaded '.' and '()' operators are now .experimental; " & s.name.s) if n.sons[bodyPos].kind != nkEmpty: # for DLL generation it is annoying to check for sfImportc! if sfBorrow in s.flags: @@ -1343,7 +1352,19 @@ proc semMethod(c: PContext, n: PNode): PNode = # macros can transform methods to nothing: if namePos >= result.safeLen: return result var s = result.sons[namePos].sym - if not isGenericRoutine(s): + if isGenericRoutine(s): + let tt = s.typ + var foundObj = false + for col in countup(0, sonsLen(tt)-1): + let t = tt.sons[col] + if t != nil and t.kind == tyGenericInvocation: + var x = skipTypes(t.sons[0], {tyVar, tyPtr, tyRef, tyGenericInst, tyGenericInvocation, tyGenericBody}) + if x.kind == tyObject: + foundObj = true + x.methods.safeAdd((col,s)) + if not foundObj: + message(n.info, warnDeprecated, "generic method not attachable to object type") + else: # why check for the body? bug #2400 has none. Checking for sfForward makes # no sense either. # and result.sons[bodyPos].kind != nkEmpty: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 13b283fe5..26ce28852 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -130,7 +130,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType = if n.len < 1: result = newConstraint(c, kind) else: - let isCall = ord(n.kind in nkCallKinds) + let isCall = ord(n.kind in nkCallKinds+{nkBracketExpr}) let n = if n[0].kind == nkBracket: n[0] else: n checkMinSonsLen(n, 1) var base = semTypeNode(c, n.lastSon, nil) @@ -370,7 +370,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType = result.n = newNodeI(nkRecList, n.info) var check = initIntSet() var counter = 0 - for i in countup(0, sonsLen(n) - 1): + for i in countup(ord(n.kind == nkBracketExpr), sonsLen(n) - 1): var a = n.sons[i] if (a.kind != nkIdentDefs): illFormedAst(a) checkMinSonsLen(a, 3) @@ -945,7 +945,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, if isType: localError(a.info, "':' expected") if kind in {skTemplate, skMacro}: typ = newTypeS(tyExpr, c) - elif skipTypes(typ, {tyGenericInst}).kind == tyEmpty: + elif skipTypes(typ, {tyGenericInst}).kind == tyVoid: continue for j in countup(0, length-3): var arg = newSymG(skParam, a.sons[j], c) @@ -977,7 +977,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, if r != nil: # turn explicit 'void' return type into 'nil' because the rest of the # compiler only checks for 'nil': - if skipTypes(r, {tyGenericInst}).kind != tyEmpty: + if skipTypes(r, {tyGenericInst}).kind != tyVoid: # 'auto' as a return type does not imply a generic: if r.kind == tyAnything: # 'p(): auto' and 'p(): expr' are equivalent, but the rest of the @@ -1038,7 +1038,7 @@ proc semGenericParamInInvocation(c: PContext, n: PNode): PType = proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = if s.typ == nil: localError(n.info, "cannot instantiate the '$1' $2" % - [s.name.s, ($s.kind).substr(2).toLower]) + [s.name.s, ($s.kind).substr(2).toLowerAscii]) return newOrPrevType(tyError, prev, c) var t = s.typ @@ -1248,6 +1248,19 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = copyType(result, getCurrOwner(), false) for i in countup(1, n.len - 1): result.rawAddSon(semTypeNode(c, n.sons[i], nil)) + of mDistinct: + result = newOrPrevType(tyDistinct, prev, c) + addSonSkipIntLit(result, semTypeNode(c, n[1], nil)) + of mVar: + result = newOrPrevType(tyVar, prev, c) + var base = semTypeNode(c, n.sons[1], nil) + if base.kind == tyVar: + localError(n.info, errVarVarTypeNotAllowed) + base = base.sons[0] + addSonSkipIntLit(result, base) + of mRef: result = semAnyRef(c, n, tyRef, prev) + of mPtr: result = semAnyRef(c, n, tyPtr, prev) + of mTuple: result = semTuple(c, n, prev) else: result = semGeneric(c, n, s, prev) of nkDotExpr: var typeExpr = semExpr(c, n) @@ -1377,10 +1390,7 @@ proc processMagicType(c: PContext, m: PSym) = setMagicType(m, tyTypeDesc, 0) rawAddSon(m.typ, newTypeS(tyNone, c)) of mVoidType: - setMagicType(m, tyEmpty, 0) - # for historical reasons we conflate 'void' with 'empty' so that '@[]' - # has the type 'seq[void]'. - m.typ.flags.incl tfVoid + setMagicType(m, tyVoid, 0) of mArray: setMagicType(m, tyArray, 0) of mOpenArray: diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 7ff33f918..076679bbf 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -162,7 +162,7 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode = discard of nkSym: result.sym = replaceTypeVarsS(cl, n.sym) - if result.sym.typ.kind == tyEmpty: + if result.sym.typ.kind == tyVoid: # don't add the 'void' field result = newNode(nkRecList, n.info) of nkRecWhen: @@ -289,7 +289,8 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = # but we already raised an error! rawAddSon(result, header.sons[i]) - var newbody = replaceTypeVarsT(cl, lastSon(body)) + let bbody = lastSon body + var newbody = replaceTypeVarsT(cl, bbody) cl.skipTypedesc = oldSkipTypedesc newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags) result.flags = result.flags + newbody.flags - tfInstClearedFlags @@ -306,25 +307,31 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = # 'deepCopy' needs to be instantiated for # generics *when the type is constructed*: newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info, - attachedDeepCopy) + attachedDeepCopy, 1) let asgn = newbody.assignment if asgn != nil and sfFromGeneric notin asgn.flags: # '=' needs to be instantiated for generics when the type is constructed: newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info, - attachedAsgn) + attachedAsgn, 1) + let methods = skipTypes(bbody, abstractPtrs).methods + for col, meth in items(methods): + # we instantiate the known methods belonging to that type, this causes + # them to be registered and that's enough, so we 'discard' the result. + discard cl.c.instTypeBoundOp(cl.c, meth, result, cl.info, + attachedAsgn, col) proc eraseVoidParams*(t: PType) = # transform '(): void' into '()' because old parts of the compiler really # don't deal with '(): void': - if t.sons[0] != nil and t.sons[0].kind == tyEmpty: + if t.sons[0] != nil and t.sons[0].kind == tyVoid: t.sons[0] = nil for i in 1 .. <t.sonsLen: # don't touch any memory unless necessary - if t.sons[i].kind == tyEmpty: + if t.sons[i].kind == tyVoid: var pos = i for j in i+1 .. <t.sonsLen: - if t.sons[j].kind != tyEmpty: + if t.sons[j].kind != tyVoid: t.sons[pos] = t.sons[j] t.n.sons[pos] = t.n.sons[j] inc pos diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index df27e3c1d..9a8f865a6 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -22,7 +22,7 @@ type TCandidateState* = enum csEmpty, csMatch, csNoMatch - CandidateErrors* = seq[PSym] + CandidateErrors* = seq[(PSym,int)] TCandidate* = object c*: PContext exactMatches*: int # also misused to prefer iters over procs @@ -49,6 +49,7 @@ type # a distrinct type typedescMatched*: bool isNoCall*: bool # misused for generic type instantiations C[T] + mutabilityProblem*: uint8 # tyVar mismatch inheritancePenalty: int # to prefer closest father object type errors*: CandidateErrors # additional clarifications to be displayed to the # user if overload resolution fails @@ -363,6 +364,46 @@ proc isObjectSubtype(a, f: PType): int = if t != nil: result = depth +type + SkippedPtr = enum skippedNone, skippedRef, skippedPtr + +proc skipToGenericBody(t: PType; skipped: var SkippedPtr): PType = + var r = t + # we're allowed to skip one level of ptr/ref: + var ptrs = 0 + while r != nil: + case r.kind + of tyGenericInst, tyGenericInvocation: + result = r.sons[0] + break + of tyRef: + inc ptrs + skipped = skippedRef + r = r.lastSon + of tyPtr: + inc ptrs + skipped = skippedPtr + r = r.lastSon + of tyGenericBody, tyObject: + r = r.lastSon + else: + break + if ptrs > 1: result = nil + +proc isGenericSubtype(a, f: PType, d: var int): bool = + assert f.kind in {tyGenericInst, tyGenericInvocation, tyGenericBody} + var askip = skippedNone + var fskip = skippedNone + var t = if a.kind == tyGenericBody: a else: a.skipToGenericBody(askip) + var r = if f.kind == tyGenericBody: f else: f.skipToGenericBody(fskip) + var depth = 0 + while t != nil and not sameObjectTypes(r, t) and askip == fskip: + t = t.skipToGenericBody(askip) + inc depth + if t != nil and askip == fskip: + d = depth + result = true + proc minRel(a, b: TTypeRelation): TTypeRelation = if a <= b: result = a else: result = b @@ -647,7 +688,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = template bindingRet(res) = if doBind: let bound = aOrig.skipTypes({tyRange}).skipIntLit - if doBind: put(c.bindings, f, bound) + put(c.bindings, f, bound) return res template considerPreviousT(body: stmt) {.immediate.} = @@ -930,8 +971,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = result = isConvertible else: discard - of tyEmpty: - if a.kind == tyEmpty: result = isEqual + of tyEmpty, tyVoid: + if a.kind == f.kind: result = isEqual of tyGenericInst: result = typeRel(c, lastSon(f), a) @@ -945,17 +986,19 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = of tyGenericInvocation: var x = a.skipGenericAlias + var depth = 0 if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody: #InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation") # simply no match for now: discard elif x.kind == tyGenericInst and - (f.sons[0] == x.sons[0]) and + ((f.sons[0] == x.sons[0]) or isGenericSubtype(x, f, depth)) and (sonsLen(x) - 1 == sonsLen(f)): for i in countup(1, sonsLen(f) - 1): if x.sons[i].kind == tyGenericParam: internalError("wrong instantiated type!") elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return + c.inheritancePenalty += depth result = isGeneric else: let genericBody = f.sons[0] @@ -1408,7 +1451,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, if skipTypes(f, abstractVar-{tyTypeDesc}).kind in {tyTuple}: result = implicitConv(nkHiddenSubConv, f, arg, m, c) of isNone: - # do not do this in ``typeRel`` as it then can't infere T in ``ref T``: + # do not do this in ``typeRel`` as it then can't infer T in ``ref T``: if a.kind in {tyProxy, tyUnknown}: inc(m.genericMatches) m.fauxMatch = a.kind @@ -1429,6 +1472,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, m.baseTypeMatch = true else: result = userConvMatch(c, m, base(f), a, arg) + if result != nil: m.baseTypeMatch = true proc paramTypesMatch*(m: var TCandidate, f, a: PType, arg, argOrig: PNode): PNode = @@ -1558,6 +1602,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, if formal.typ.kind == tyVar: if not n.isLValue: m.state = csNoMatch + m.mutabilityProblem = uint8(f-1) return var @@ -1577,6 +1622,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, while a < n.len: if a >= formalLen-1 and formal != nil and formal.typ.isVarargsUntyped: + incl(marker, formal.position) if container.isNil: container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, n.info)) setSon(m.call, formal.position + 1, container) @@ -1639,6 +1685,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, # beware of the side-effects in 'prepareOperand'! So only do it for # varargs matching. See tests/metatype/tstatic_overloading. m.baseTypeMatch = false + incl(marker, formal.position) n.sons[a] = prepareOperand(c, formal.typ, n.sons[a]) var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ, n.sons[a], nOrig.sons[a]) @@ -1725,15 +1772,18 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) = if formal.ast == nil: if formal.typ.kind == tyVarargs: var container = newNodeIT(nkBracket, n.info, arrayConstr(c, n.info)) - addSon(m.call, implicitConv(nkHiddenStdConv, formal.typ, - container, m, c)) + setSon(m.call, formal.position + 1, + implicitConv(nkHiddenStdConv, formal.typ, container, m, c)) else: # no default value m.state = csNoMatch break else: # use default value: - setSon(m.call, formal.position + 1, copyTree(formal.ast)) + var def = copyTree(formal.ast) + if def.kind == nkNilLit: + def = implicitConv(nkHiddenStdConv, formal.typ, def, m, c) + setSon(m.call, formal.position + 1, def) inc(f) proc argtypeMatches*(c: PContext, f, a: PType): bool = @@ -1746,16 +1796,19 @@ proc argtypeMatches*(c: PContext, f, a: PType): bool = result = res != nil proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo; - op: TTypeAttachedOp): PSym {.procvar.} = + op: TTypeAttachedOp; col: int): PSym {.procvar.} = var m: TCandidate initCandidate(c, m, dc.typ) - var f = dc.typ.sons[1] + if col >= dc.typ.len: + localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'") + return nil + var f = dc.typ.sons[col] if op == attachedDeepCopy: if f.kind in {tyRef, tyPtr}: f = f.lastSon else: if f.kind == tyVar: f = f.lastSon if typeRel(m, f, t) == isNone: - localError(info, errGenerated, "cannot instantiate 'deepCopy'") + localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'") else: result = c.semGenerateInstance(c, dc, m.bindings, info) assert sfFromGeneric in result.flags diff --git a/compiler/types.nim b/compiler/types.nim index bada47075..5fbab85b9 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -407,7 +407,8 @@ const "!", "varargs[$1]", "iter[$1]", "Error Type", "BuiltInTypeClass", "UserTypeClass", "UserTypeClassInst", "CompositeTypeClass", - "and", "or", "not", "any", "static", "TypeFromExpr", "FieldAccessor"] + "and", "or", "not", "any", "static", "TypeFromExpr", "FieldAccessor", + "void"] const preferToResolveSymbols = {preferName, preferModuleInfo, preferGenericArg} @@ -540,7 +541,9 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = else: result.add typeToString(t.sons[0]) of tyRange: - result = "range " & rangeToStr(t.n) + result = "range " + if t.n != nil and t.n.kind == nkRange: + result.add rangeToStr(t.n) if prefer != preferExported: result.add("(" & typeToString(t.sons[0]) & ")") of tyProc: @@ -727,6 +730,7 @@ proc equalParam(a, b: PSym): TParamsEquality = result = paramsNotEqual proc sameConstraints(a, b: PNode): bool = + if isNil(a) and isNil(b): return true internalAssert a.len == b.len for i in 1 .. <a.len: if not exprStructuralEquivalent(a[i].sym.constraint, @@ -799,6 +803,8 @@ proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool = result = x.name.id == y.name.id if not result: break else: internalError(a.n.info, "sameTuple") + elif a.n != b.n and (a.n == nil or b.n == nil) and IgnoreTupleFields notin c.flags: + result = false template ifFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} = if tfFromGeneric notin a.flags + b.flags: @@ -922,7 +928,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = case a.kind of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString, - tyInt..tyBigNum, tyStmt, tyExpr: + tyInt..tyBigNum, tyStmt, tyExpr, tyVoid: result = sameFlags(a, b) of tyStatic, tyFromExpr: result = exprStructuralEquivalent(a.n, b.n) and sameFlags(a, b) @@ -1108,7 +1114,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, result = nil of tyExpr, tyStmt, tyStatic: if kind notin {skParam, skResult}: result = t - of tyEmpty: + of tyVoid: if taField notin flags: result = t of tyTypeClasses: if not (tfGenericTypeParam in t.flags or taField notin flags): result = t @@ -1153,7 +1159,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, if result != nil: break if result.isNil and t.n != nil: result = typeAllowedNode(marker, t.n, kind, flags) - of tyProxy: + of tyProxy, tyEmpty: # for now same as error node; we say it's a valid type as it should # prevent cascading errors: result = nil @@ -1313,6 +1319,9 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt = of tyTypeDesc: result = computeSizeAux(typ.base, a) of tyForward: return szIllegalRecursion + of tyStatic: + if typ.n != nil: result = computeSizeAux(lastSon(typ), a) + else: result = szUnknownSize else: #internalError("computeSizeAux()") result = szUnknownSize diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 678a765f4..a10e7c12e 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -63,8 +63,9 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym): string = localError(info, errCannotOpenFile, file) result = "" -proc atomicTypeX(name: string; t: PType; info: TLineInfo): PNode = +proc atomicTypeX(name: string; m: TMagic; t: PType; info: TLineInfo): PNode = let sym = newSym(skType, getIdent(name), t.owner, info) + sym.magic = m sym.typ = t result = newSymNode(sym) result.typ = t @@ -72,14 +73,14 @@ proc atomicTypeX(name: string; t: PType; info: TLineInfo): PNode = proc mapTypeToAstX(t: PType; info: TLineInfo; inst=false; allowRecursionX=false): PNode -proc mapTypeToBracketX(name: string; t: PType; info: TLineInfo; +proc mapTypeToBracketX(name: string; m: TMagic; t: PType; info: TLineInfo; inst=false): PNode = result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t) - result.add atomicTypeX(name, t, info) + result.add atomicTypeX(name, m, t, info) for i in 0 .. < t.len: if t.sons[i] == nil: - let void = atomicTypeX("void", t, info) - void.typ = newType(tyEmpty, t.owner) + let void = atomicTypeX("void", mVoid, t, info) + void.typ = newType(tyVoid, t.owner) result.add void else: result.add mapTypeToAstX(t.sons[i], info, inst) @@ -87,14 +88,14 @@ proc mapTypeToBracketX(name: string; t: PType; info: TLineInfo; proc mapTypeToAstX(t: PType; info: TLineInfo; inst=false; allowRecursionX=false): PNode = var allowRecursion = allowRecursionX - template atomicType(name): expr = atomicTypeX(name, t, info) + template atomicType(name, m): expr = atomicTypeX(name, m, t, info) template mapTypeToAst(t,info): expr = mapTypeToAstX(t, info, inst) template mapTypeToAstR(t,info): expr = mapTypeToAstX(t, info, inst, true) template mapTypeToAst(t,i,info): expr = if i<t.len and t.sons[i]!=nil: mapTypeToAstX(t.sons[i], info, inst) else: ast.emptyNode - template mapTypeToBracket(name,t,info): expr = - mapTypeToBracketX(name, t, info, inst) + template mapTypeToBracket(name, m, t, info): expr = + mapTypeToBracketX(name, m, t, info, inst) template newNodeX(kind):expr = newNodeIT(kind, if t.n.isNil: info else: t.n.info, t) template newIdent(s):expr = @@ -114,19 +115,20 @@ proc mapTypeToAstX(t: PType; info: TLineInfo; if allowRecursion: # getTypeImpl behavior: turn off recursion allowRecursion = false else: # getTypeInst behavior: return symbol - return atomicType(t.sym.name.s) + return atomicType(t.sym.name.s, t.sym.magic) case t.kind - of tyNone: result = atomicType("none") - of tyBool: result = atomicType("bool") - of tyChar: result = atomicType("char") - of tyNil: result = atomicType("nil") - of tyExpr: result = atomicType("expr") - of tyStmt: result = atomicType("stmt") - of tyEmpty: result = atomicType"void" + of tyNone: result = atomicType("none", mNone) + of tyBool: result = atomicType("bool", mBool) + of tyChar: result = atomicType("char", mChar) + of tyNil: result = atomicType("nil", mNil) + of tyExpr: result = atomicType("expr", mExpr) + of tyStmt: result = atomicType("stmt", mStmt) + of tyVoid: result = atomicType("void", mVoid) + of tyEmpty: result = atomicType("empty", mNone) of tyArrayConstr, tyArray: result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t) - result.add atomicType("array") + result.add atomicType("array", mArray) if inst and t.sons[0].kind == tyRange: var rng = newNodeX(nkInfix) rng.add newIdentNode(getIdent(".."), info) @@ -139,10 +141,10 @@ proc mapTypeToAstX(t: PType; info: TLineInfo; of tyTypeDesc: if t.base != nil: result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t) - result.add atomicType("typeDesc") + result.add atomicType("typeDesc", mTypeDesc) result.add mapTypeToAst(t.base, info) else: - result = atomicType"typeDesc" + result = atomicType("typeDesc", mTypeDesc) of tyGenericInvocation: result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t) for i in 0 .. < t.len: @@ -166,10 +168,11 @@ proc mapTypeToAstX(t: PType; info: TLineInfo; result.add mapTypeToAst(t.sons[0], info) else: if allowRecursion or t.sym==nil: - result = mapTypeToBracket("distinct", t, info) + result = mapTypeToBracket("distinct", mDistinct, t, info) else: - result = atomicType(t.sym.name.s) - of tyGenericParam, tyForward: result = atomicType(t.sym.name.s) + result = atomicType(t.sym.name.s, t.sym.magic) + of tyGenericParam, tyForward: + result = atomicType(t.sym.name.s, t.sym.magic) of tyObject: if inst: result = newNodeX(nkObjectTy) @@ -196,7 +199,7 @@ proc mapTypeToAstX(t: PType; info: TLineInfo; result.add mapTypeToAst(t.sons[0], info) result.add copyTree(t.n) else: - result = atomicType(t.sym.name.s) + result = atomicType(t.sym.name.s, t.sym.magic) of tyEnum: result = newNodeIT(nkEnumTy, if t.n.isNil: info else: t.n.info, t) result.add copyTree(t.n) @@ -206,22 +209,22 @@ proc mapTypeToAstX(t: PType; info: TLineInfo; for s in t.n.sons: result.add newIdentDefs(s) else: - result = mapTypeToBracket("tuple", t, info) - of tySet: result = mapTypeToBracket("set", t, info) + result = mapTypeToBracket("tuple", mTuple, t, info) + of tySet: result = mapTypeToBracket("set", mSet, t, info) of tyPtr: if inst: result = newNodeX(nkPtrTy) result.add mapTypeToAst(t.sons[0], info) else: - result = mapTypeToBracket("ptr", t, info) + result = mapTypeToBracket("ptr", mPtr, t, info) of tyRef: if inst: result = newNodeX(nkRefTy) result.add mapTypeToAst(t.sons[0], info) else: - result = mapTypeToBracket("ref", t, info) - of tyVar: result = mapTypeToBracket("var", t, info) - of tySequence: result = mapTypeToBracket("seq", t, info) + result = mapTypeToBracket("ref", mRef, t, info) + of tyVar: result = mapTypeToBracket("var", mVar, t, info) + of tySequence: result = mapTypeToBracket("seq", mSeq, t, info) of tyProc: if inst: result = newNodeX(nkProcTy) @@ -235,52 +238,54 @@ proc mapTypeToAstX(t: PType; info: TLineInfo; result.add fp result.add ast.emptyNode # pragmas aren't reconstructed yet else: - result = mapTypeToBracket("proc", t, info) - of tyOpenArray: result = mapTypeToBracket("openArray", t, info) + result = mapTypeToBracket("proc", mNone, t, info) + of tyOpenArray: result = mapTypeToBracket("openArray", mOpenArray, t, info) of tyRange: result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t) - result.add atomicType("range") + result.add atomicType("range", mRange) result.add t.n.sons[0].copyTree result.add t.n.sons[1].copyTree - of tyPointer: result = atomicType"pointer" - of tyString: result = atomicType"string" - of tyCString: result = atomicType"cstring" - of tyInt: result = atomicType"int" - of tyInt8: result = atomicType"int8" - of tyInt16: result = atomicType"int16" - of tyInt32: result = atomicType"int32" - of tyInt64: result = atomicType"int64" - of tyFloat: result = atomicType"float" - of tyFloat32: result = atomicType"float32" - of tyFloat64: result = atomicType"float64" - of tyFloat128: result = atomicType"float128" - of tyUInt: result = atomicType"uint" - of tyUInt8: result = atomicType"uint8" - of tyUInt16: result = atomicType"uint16" - of tyUInt32: result = atomicType"uint32" - of tyUInt64: result = atomicType"uint64" - of tyBigNum: result = atomicType"bignum" - of tyConst: result = mapTypeToBracket("const", t, info) - of tyMutable: result = mapTypeToBracket("mutable", t, info) - of tyVarargs: result = mapTypeToBracket("varargs", t, info) - of tyIter: result = mapTypeToBracket("iter", t, info) - of tyProxy: result = atomicType"error" - of tyBuiltInTypeClass: result = mapTypeToBracket("builtinTypeClass", t, info) + of tyPointer: result = atomicType("pointer", mPointer) + of tyString: result = atomicType("string", mString) + of tyCString: result = atomicType("cstring", mCString) + of tyInt: result = atomicType("int", mInt) + of tyInt8: result = atomicType("int8", mInt8) + of tyInt16: result = atomicType("int16", mInt16) + of tyInt32: result = atomicType("int32", mInt32) + of tyInt64: result = atomicType("int64", mInt64) + of tyFloat: result = atomicType("float", mFloat) + of tyFloat32: result = atomicType("float32", mFloat32) + of tyFloat64: result = atomicType("float64", mFloat64) + of tyFloat128: result = atomicType("float128", mFloat128) + of tyUInt: result = atomicType("uint", mUint) + of tyUInt8: result = atomicType("uint8", mUint8) + of tyUInt16: result = atomicType("uint16", mUint16) + of tyUInt32: result = atomicType("uint32", mUint32) + of tyUInt64: result = atomicType("uint64", mUint64) + of tyBigNum: result = atomicType("bignum", mNone) + of tyConst: result = mapTypeToBracket("const", mNone, t, info) + of tyMutable: result = mapTypeToBracket("mutable", mNone, t, info) + of tyVarargs: result = mapTypeToBracket("varargs", mVarargs, t, info) + of tyIter: result = mapTypeToBracket("iter", mNone, t, info) + of tyProxy: result = atomicType("error", mNone) + of tyBuiltInTypeClass: + result = mapTypeToBracket("builtinTypeClass", mNone, t, info) of tyUserTypeClass: - result = mapTypeToBracket("concept", t, info) + result = mapTypeToBracket("concept", mNone, t, info) result.add t.n.copyTree - of tyCompositeTypeClass: result = mapTypeToBracket("compositeTypeClass", t, info) - of tyAnd: result = mapTypeToBracket("and", t, info) - of tyOr: result = mapTypeToBracket("or", t, info) - of tyNot: result = mapTypeToBracket("not", t, info) - of tyAnything: result = atomicType"anything" + of tyCompositeTypeClass: + result = mapTypeToBracket("compositeTypeClass", mNone, t, info) + of tyAnd: result = mapTypeToBracket("and", mAnd, t, info) + of tyOr: result = mapTypeToBracket("or", mOr, t, info) + of tyNot: result = mapTypeToBracket("not", mNot, t, info) + of tyAnything: result = atomicType("anything", mNone) of tyStatic, tyFromExpr, tyFieldAccessor: if inst: if t.n != nil: result = t.n.copyTree - else: result = atomicType "void" + else: result = atomicType("void", mVoid) else: result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t) - result.add atomicType "static" + result.add atomicType("static", mNone) if t.n != nil: result.add t.n.copyTree diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index d4966b3e3..1c1d03a4f 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -267,7 +267,7 @@ proc genx(c: PCtx; n: PNode; flags: TGenFlags = {}): TRegister = proc clearDest(c: PCtx; n: PNode; dest: var TDest) {.inline.} = # stmt is different from 'void' in meta programming contexts. # So we only set dest to -1 if 'void': - if dest >= 0 and (n.typ.isNil or n.typ.kind == tyEmpty): + if dest >= 0 and (n.typ.isNil or n.typ.kind == tyVoid): c.freeTemp(dest) dest = -1 @@ -374,7 +374,7 @@ proc canonValue*(n: PNode): PNode = proc rawGenLiteral(c: PCtx; n: PNode): int = result = c.constants.len - assert(n.kind != nkCall) + #assert(n.kind != nkCall) n.flags.incl nfAllConst c.constants.add n.canonValue internalAssert result < 0x7fff @@ -497,12 +497,30 @@ proc genReturn(c: PCtx; n: PNode) = gen(c, n.sons[0]) c.gABC(n, opcRet) + +proc genLit(c: PCtx; n: PNode; dest: var TDest) = + # opcLdConst is now always valid. We produce the necessary copy in the + # assignments now: + #var opc = opcLdConst + if dest < 0: dest = c.getTemp(n.typ) + #elif c.prc.slots[dest].kind == slotFixedVar: opc = opcAsgnConst + let lit = genLiteral(c, n) + c.gABx(n, opcLdConst, dest, lit) + proc genCall(c: PCtx; n: PNode; dest: var TDest) = + # it can happen that due to inlining we have a 'n' that should be + # treated as a constant (see issue #537). + #if n.typ != nil and n.typ.sym != nil and n.typ.sym.magic == mPNimrodNode: + # genLit(c, n, dest) + # return if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ) let x = c.getTempRange(n.len, slotTempUnknown) # varargs need 'opcSetType' for the FFI support: - let fntyp = n.sons[0].typ + let fntyp = skipTypes(n.sons[0].typ, abstractInst) for i in 0.. <n.len: + #if i > 0 and i < sonsLen(fntyp): + # let paramType = fntyp.n.sons[i] + # if paramType.typ.isCompileTimeOnly: continue var r: TRegister = x+i c.gen(n.sons[i], r) if i >= fntyp.len: @@ -579,16 +597,27 @@ proc genNew(c: PCtx; n: PNode) = c.freeTemp(dest) proc genNewSeq(c: PCtx; n: PNode) = - let dest = if needsAsgnPatch(n.sons[1]): c.getTemp(n.sons[1].typ) + let t = n.sons[1].typ + let dest = if needsAsgnPatch(n.sons[1]): c.getTemp(t) else: c.genx(n.sons[1]) let tmp = c.genx(n.sons[2]) - c.gABx(n, opcNewSeq, dest, c.genType(n.sons[1].typ.skipTypes( + c.gABx(n, opcNewSeq, dest, c.genType(t.skipTypes( abstractVar-{tyTypeDesc}))) c.gABx(n, opcNewSeq, tmp, 0) c.freeTemp(tmp) c.genAsgnPatch(n.sons[1], dest) c.freeTemp(dest) +proc genNewSeqOfCap(c: PCtx; n: PNode; dest: var TDest) = + let t = n.typ + let tmp = c.getTemp(n.sons[1].typ) + c.gABx(n, opcLdNull, dest, c.genType(t)) + c.gABx(n, opcLdImmInt, tmp, 0) + c.gABx(n, opcNewSeq, dest, c.genType(t.skipTypes( + abstractVar-{tyTypeDesc}))) + c.gABx(n, opcNewSeq, tmp, 0) + c.freeTemp(tmp) + proc genUnaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = let tmp = c.genx(n.sons[1]) if dest < 0: dest = c.getTemp(n.typ) @@ -764,6 +793,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mNewSeq: unused(n, dest) c.genNewSeq(n) + of mNewSeqOfCap: c.genNewSeqOfCap(n, dest) of mNewString: genUnaryABC(c, n, dest, opcNewStr) # XXX buggy @@ -1307,15 +1337,6 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) = let dest = c.genx(le, {gfAddrOf}) genAsgn(c, dest, ri, requiresCopy) -proc genLit(c: PCtx; n: PNode; dest: var TDest) = - # opcLdConst is now always valid. We produce the necessary copy in the - # assignments now: - #var opc = opcLdConst - if dest < 0: dest = c.getTemp(n.typ) - #elif c.prc.slots[dest].kind == slotFixedVar: opc = opcAsgnConst - let lit = genLiteral(c, n) - c.gABx(n, opcLdConst, dest, lit) - proc genTypeLit(c: PCtx; t: PType; dest: var TDest) = var n = newNode(nkType) n.typ = t @@ -1677,10 +1698,10 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = of skType: genTypeLit(c, s.typ, dest) of skGenericParam: - if c.prc.sym.kind == skMacro: + if c.prc.sym != nil and c.prc.sym.kind == skMacro: genRdVar(c, n, dest, flags) else: - internalError(n.info, "cannot generate code for: " & s.name.s) + globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s) else: globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s) of nkCallKinds: @@ -1788,6 +1809,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = genConv(c, n, n.sons[1], dest, opcCast) else: globalError(n.info, errGenerated, "VM is not allowed to 'cast'") + of nkTypeOfExpr: + genTypeLit(c, n.typ, dest) else: globalError(n.info, errGenerated, "cannot generate VM code for " & $n) diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 3e0e05a94..b5ffd51c2 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -36,6 +36,7 @@ type wColon, wColonColon, wEquals, wDot, wDotDot, wStar, wMinus, wMagic, wThread, wFinal, wProfiler, wObjChecks, + wIntDefine, wStrDefine, wDestroy, @@ -121,7 +122,7 @@ const ":", "::", "=", ".", "..", "*", "-", - "magic", "thread", "final", "profiler", "objchecks", + "magic", "thread", "final", "profiler", "objchecks", "intdefine", "strdefine", "destroy", |