diff options
author | Araq <rumpf_a@web.de> | 2014-02-02 00:45:47 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2014-02-02 00:45:47 +0100 |
commit | efcbaa965e84588c8ff9ed5a62b79820dd5ea5ca (patch) | |
tree | e64c2adccb071a06e6be6a0103a1c6433236bb98 | |
parent | d29aa4c5ac6950a9b8c53bedeb9dd0dd9b4f64a2 (diff) | |
parent | f9c2ec8d9238afaff285b2ba286f8c5534b05eec (diff) | |
download | Nim-efcbaa965e84588c8ff9ed5a62b79820dd5ea5ca.tar.gz |
remove the old tester
-rw-r--r-- | compiler/ast.nim | 59 | ||||
-rw-r--r-- | compiler/ccgutils.nim | 2 | ||||
-rw-r--r-- | compiler/jsgen.nim | 2 | ||||
-rw-r--r-- | compiler/semexprs.nim | 39 | ||||
-rw-r--r-- | compiler/semfold.nim | 3 | ||||
-rw-r--r-- | compiler/semstmts.nim | 2 | ||||
-rw-r--r-- | compiler/semtypes.nim | 11 | ||||
-rw-r--r-- | compiler/semtypinst.nim | 5 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 148 | ||||
-rw-r--r-- | compiler/transf.nim | 2 | ||||
-rw-r--r-- | compiler/types.nim | 55 | ||||
-rw-r--r-- | compiler/vm.nim | 2 | ||||
-rw-r--r-- | config/nimdoc.cfg | 2 | ||||
-rw-r--r-- | config/nimdoc.tex.cfg | 2 | ||||
-rw-r--r-- | devel/logging.nim | 210 | ||||
-rw-r--r-- | doc/lib.txt | 3 | ||||
-rw-r--r-- | lib/packages/docutils/highlite.nim | 8 | ||||
-rw-r--r-- | lib/pure/algorithm.nim | 33 | ||||
-rw-r--r-- | lib/pure/logging.nim | 267 | ||||
-rw-r--r-- | tests/stdlib/talgorithm.nim | 14 | ||||
-rw-r--r-- | web/nimrod.ini | 2 |
21 files changed, 523 insertions, 348 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 0e351a31a..7138b5f52 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -336,26 +336,52 @@ type tyConst, tyMutable, tyVarargs, tyIter, # unused tyProxy # used as errornous type (for idetools) - tyTypeClass - tyParametricTypeClass # structured similarly to tyGenericInst - # lastSon is the body of the type class - tyBuiltInTypeClass # Type such as the catch-all object, tuple, seq, etc + tyBuiltInTypeClass #\ + # Type such as the catch-all object, tuple, seq, etc - tyCompositeTypeClass # + tyUserTypeClass #\ + # the body of a user-defined type class + + tyUserTypeClassInst #\ + # Instance of a parametric user-defined type class. + # Structured similarly to tyGenericInst. + # tyGenericInst represents concrete types, while + # this is still a "generic param" that will bind types + # and resolves them during sigmatch and instantiation. - tyAnd, tyOr, tyNot # boolean type classes such as `string|int`,`not seq`, - # `Sortable and Enumable`, etc + tyCompositeTypeClass #\ + # Type such as seq[Number] + # The notes for tyUserTypeClassInst apply here as well + # sons[0]: the original expression used by the user. + # sons[1]: fully expanded and instantiated meta type + # (potentially following aliases) - tyAnything # a type class matching any type + tyAnd, tyOr, tyNot #\ + # boolean type classes such as `string|int`,`not seq`, + # `Sortable and Enumable`, etc - tyStatic # a value known at compile type (the underlying type is .base) + tyAnything #\ + # a type class matching any type - tyFromExpr # This is a type representing an expression that depends - # on generic parameters (the exprsesion is stored in t.n) - # It will be converted to a real type only during generic - # instantiation and prior to this it has the potential to - # be any type. + tyStatic #\ + # a value known at compile type (the underlying type is .base) + + tyFromExpr #\ + # This is a type representing an expression that depends + # on generic parameters (the exprsesion is stored in t.n) + # It will be converted to a real type only during generic + # instantiation and prior to this it has the potential to + # be any type. + + tyFieldAccessor #\ + # Expressions such as Type.field (valid in contexts such + # as the `is` operator and magics like `high` and `low`). + # Could be lifted to a single argument proc returning the + # field value. + # sons[0]: type of containing object or tuple + # sons[1]: field type + # .n: nkDotExpr storing the field name const tyPureObject* = tyTuple @@ -364,8 +390,9 @@ const tyUnknownTypes* = {tyError, tyFromExpr} - tyTypeClasses* = {tyTypeClass, tyBuiltInTypeClass, tyCompositeTypeClass, - tyParametricTypeClass, tyAnd, tyOr, tyNot, tyAnything} + tyTypeClasses* = {tyBuiltInTypeClass, tyCompositeTypeClass, + tyUserTypeClass, tyUserTypeClassInst, + tyAnd, tyOr, tyNot, tyAnything} tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyStatic, tyExpr} + tyTypeClasses diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index fe349174f..1129ecbef 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -87,7 +87,7 @@ proc getUniqueType*(key: PType): PType = gCanonicalTypes[k] = key result = key of tyTypeDesc, tyTypeClasses, tyGenericParam, - tyFromExpr, tyStatic: + tyFromExpr, tyStatic, tyFieldAccessor: internalError("GetUniqueType") of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter: result = getUniqueType(lastSon(key)) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 82c45059c..c0fc4131a 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -130,7 +130,7 @@ proc mapType(typ: PType): TJSTypeKind = result = etyObject of tyNil: result = etyNull of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation, - tyNone, tyFromExpr, tyForward, tyEmpty, + tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor, tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses: result = etyNone of tyProc: result = etyProc diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 432443dc6..a384c41fd 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -239,7 +239,8 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = localError(n.info, errXExpectsTypeOrValue, opToStr[m]) else: n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType}) - var typ = skipTypes(n.sons[1].typ, abstractVarRange+{tyTypeDesc}) + var typ = skipTypes(n.sons[1].typ, abstractVarRange + + {tyTypeDesc, tyFieldAccessor}) case typ.kind of tySequence, tyString, tyOpenArray, tyVarargs: n.typ = getSysType(tyInt) @@ -247,7 +248,7 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = n.typ = typ.sons[0] # indextype of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32: # do not skip the range! - n.typ = n.sons[1].typ.skipTypes(abstractVar) + n.typ = n.sons[1].typ.skipTypes(abstractVar + {tyFieldAccessor}) of tyGenericParam: # prepare this for resolving in semtypinst: # we must use copyTree here in order to avoid creating a cycle @@ -306,7 +307,7 @@ proc isOpImpl(c: PContext, n: PNode): PNode = n[1].typ != nil and n[1].typ.kind == tyTypeDesc and n[2].kind in {nkStrLit..nkTripleStrLit, nkType} - let t1 = n[1].typ.skipTypes({tyTypeDesc}) + let t1 = n[1].typ.skipTypes({tyTypeDesc, tyFieldAccessor}) if n[2].kind in {nkStrLit..nkTripleStrLit}: case n[2].strVal.normalize @@ -321,24 +322,13 @@ proc isOpImpl(c: PContext, n: PNode): PNode = t.callConv == ccClosure and tfIterator in t.flags)) else: - var match: bool - let t2 = n[2].typ - case t2.kind - of tyTypeClasses: - var m: TCandidate - initCandidate(c, m, t2) - match = matchUserTypeClass(c, m, emptyNode, t2, t1) != nil - of tyOrdinal: - var m: TCandidate - initCandidate(c, m, t2) - match = isOrdinalType(t1) - of tySequence, tyArray, tySet: - var m: TCandidate - initCandidate(c, m, t2) - match = typeRel(m, t2, t1) != isNone - else: - match = sameType(t1, t2) - + var t2 = n[2].typ.skipTypes({tyTypeDesc}) + let lifted = liftParamType(c, skType, newNodeI(nkArgList, n.info), + t2, ":anon", n.info) + if lifted != nil: t2 = lifted + var m: TCandidate + initCandidate(c, m, t2) + let match = typeRel(m, t2, t1) != isNone result = newIntNode(nkIntLit, ord(match)) result.typ = n.typ @@ -948,6 +938,13 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = let foundTyp = makeTypeDesc(c, rawTyp) return newSymNode(copySym(tParam.sym).linkTo(foundTyp), n.info) return + of tyObject, tyTuple: + if ty.n.kind == nkRecList: + for field in ty.n.sons: + if field.sym.name == i: + n.typ = newTypeWithSons(c, tyFieldAccessor, @[ty, field.sym.typ]) + n.typ.n = copyTree(n) + return n else: # echo "TYPE FIELD ACCESS" # debug ty diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 78e5cdd5e..4740ddcb3 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -252,8 +252,7 @@ proc evalIs(n, a: PNode): PNode = else: # XXX semexprs.isOpImpl is slightly different and requires a context. yay. let t2 = n[2].typ - var match = if t2.kind == tyTypeClass: true - else: sameType(t1, t2) + var match = sameType(t1, t2) result = newIntNode(nkIntLit, ord(match)) result.typ = n.typ diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index a26d89836..caa719c7e 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1247,7 +1247,7 @@ proc semStmtList(c: PContext, n: PNode): PNode = if n.sons[i].typ == enforceVoidContext or usesResult(n.sons[i]): voidContext = true n.typ = enforceVoidContext - if i != last or voidContext: + if i != last or voidContext or c.inTypeClass > 0: discardCheck(c, n.sons[i]) else: n.typ = n.sons[i].typ diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index d5a938a12..408b1b62e 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -710,6 +710,11 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, result = addImplicitGeneric(result) of tyGenericInst: + if paramType.lastSon.kind == tyUserTypeClass: + var cp = copyType(paramType, getCurrOwner(), false) + cp.kind = tyUserTypeClassInst + return addImplicitGeneric(cp) + for i in 1 .. (paramType.sons.len - 2): var lifted = liftingWalk(paramType.sons[i]) if lifted != nil: @@ -731,7 +736,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, allowMetaTypes = true) result = liftingWalk(expanded) - of tyTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot: + of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot: result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true)) of tyExpr: @@ -866,7 +871,7 @@ proc semGenericParamInInvokation(c: PContext, n: PNode): PType = proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = result = newOrPrevType(tyGenericInvokation, prev, c) addSonSkipIntLit(result, s.typ) - + template addToResult(typ) = if typ.isNil: internalAssert false @@ -923,7 +928,7 @@ proc freshType(res, prev: PType): PType {.inline.} = proc semTypeClass(c: PContext, n: PNode, prev: PType): PType = # if n.sonsLen == 0: return newConstraint(c, tyTypeClass) - result = newOrPrevType(tyTypeClass, prev, c) + result = newOrPrevType(tyUserTypeClass, prev, c) result.n = n let diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 9c6421315..1158335a8 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -360,7 +360,10 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = if tfUnresolved in t.flags: result = result.base elif t.sonsLen > 0: result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.sons[0])) - + + of tyUserTypeClass: + result = t + of tyGenericInst: result = instCopyType(cl, t) for i in 1 .. <result.sonsLen: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index bb70e0d6b..d269e9e69 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -140,7 +140,7 @@ proc sumGeneric(t: PType): int = result = ord(t.kind == tyGenericInvokation) for i in 0 .. <t.len: result += t.sons[i].sumGeneric break - of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc, tyTypeClass: break + of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break else: return 0 proc complexDisambiguation(a, b: PType): int = @@ -399,6 +399,70 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} = else: result = isNone +proc matchUserTypeClass*(c: PContext, m: var TCandidate, + ff, a: PType): TTypeRelation = + #if f.n == nil: + # let r = typeRel(m, f, a) + # return if r == isGeneric: arg else: nil + + var body = ff.skipTypes({tyUserTypeClassInst}) + + # var prev = PType(idTableGet(m.bindings, f)) + # if prev != nil: + # if sameType(prev, a): return arg + # else: return nil + + # pushInfoContext(arg.info) + openScope(c) + inc c.inTypeClass + + finally: + dec c.inTypeClass + closeScope(c) + + if ff.kind == tyUserTypeClassInst: + for i in 1 .. <(ff.len - 1): + var + typeParamName = ff.base.sons[i-1].sym.name + typ = ff.sons[i] + param = newSym(skType, typeParamName, body.sym, body.sym.info) + + param.typ = makeTypeDesc(c, typ) + addDecl(c, param) + + for param in body.n[0]: + var + dummyName: PNode + dummyType: PType + + if param.kind == nkVarTy: + dummyName = param[0] + dummyType = makeVarType(c, a) + else: + dummyName = param + dummyType = a + + internalAssert dummyName.kind == nkIdent + var dummyParam = newSym(skType, dummyName.ident, body.sym, body.sym.info) + dummyParam.typ = dummyType + addDecl(c, dummyParam) + + var checkedBody = c.semTryExpr(c, copyTree(body.n[3]), bufferErrors = false) + m.errors = bufferedMsgs + clearBufferedMsgs() + if checkedBody == nil: return isNone + + if checkedBody.kind == nkStmtList: + for stmt in checkedBody: + case stmt.kind + of nkReturnStmt: discard + of nkTypeSection: discard + of nkConstDef: discard + else: discard + + return isGeneric + # put(m.bindings, f, a) + proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = # typeRel can be used to establish various relationships between types: # @@ -418,6 +482,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = result = isNone assert(f != nil) + + if f.kind == tyExpr: + put(c.bindings, f, aOrig) + return isGeneric + assert(aOrig != nil) # var and static arguments match regular modifier-free types @@ -751,6 +820,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = else: return isNone + of tyUserTypeClass, tyUserTypeClassInst: + considerPreviousT: + result = matchUserTypeClass(c.c, c, f, a) + if result == isGeneric: + put(c.bindings, f, a) + of tyCompositeTypeClass: considerPreviousT: if typeRel(c, f.sons[1], a) != isNone: @@ -759,7 +834,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = else: return isNone - of tyGenericParam, tyTypeClass: + of tyGenericParam: var x = PType(idTableGet(c.bindings, f)) if x == nil: if c.calleeSym != nil and c.calleeSym.kind == skType and @@ -822,7 +897,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = else: a.sons[0] result = typeRel(c, prev.sons[0], toMatch) - of tyExpr, tyStmt: + of tyStmt: result = isGeneric of tyProxy: @@ -904,57 +979,6 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType, result.typ = getInstantiatedType(c, arg, m, base(f)) m.baseTypeMatch = true -proc matchUserTypeClass*(c: PContext, m: var TCandidate, - arg: PNode, f, a: PType): PNode = - if f.n == nil: - let r = typeRel(m, f, a) - return if r == isGeneric: arg else: nil - - var prev = PType(idTableGet(m.bindings, f)) - if prev != nil: - if sameType(prev, a): return arg - else: return nil - - # pushInfoContext(arg.info) - openScope(c) - inc c.inTypeClass - - finally: - dec c.inTypeClass - closeScope(c) - - for param in f.n[0]: - var - dummyName: PNode - dummyType: PType - - if param.kind == nkVarTy: - dummyName = param[0] - dummyType = makeVarType(c, a) - else: - dummyName = param - dummyType = a - - internalAssert dummyName.kind == nkIdent - var dummyParam = newSym(skType, dummyName.ident, f.sym, f.sym.info) - dummyParam.typ = dummyType - addDecl(c, dummyParam) - - for stmt in f.n[3]: - var e = c.semTryExpr(c, copyTree(stmt), bufferErrors = false) - m.errors = bufferedMsgs - clearBufferedMsgs() - if e == nil: return nil - - case e.kind - of nkReturnStmt: discard - of nkTypeSection: discard - of nkConstDef: discard - else: discard - - result = arg - put(m.bindings, f, a) - proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, argSemantized, argOrig: PNode): PNode = var @@ -975,25 +999,9 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, argType = arg.typ var - r: TTypeRelation a = if c.inTypeClass > 0: argType.skipTypes({tyTypeDesc}) else: argType - case fMaybeStatic.kind - of tyTypeClass, tyParametricTypeClass: - if fMaybeStatic.n != nil: - let match = matchUserTypeClass(c, m, arg, fMaybeStatic, a) - if match != nil: - r = isGeneric - arg = match - else: - r = isNone - else: - r = typeRel(m, f, a) - of tyExpr: - r = isGeneric - put(m.bindings, f, arg.typ) - else: r = typeRel(m, f, a) case r diff --git a/compiler/transf.nim b/compiler/transf.nim index cda611005..deb821eff 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -389,7 +389,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode = result[0] = transform(c, n.sons[1]) else: result = transform(c, n.sons[1]) - of tyGenericParam, tyOrdinal, tyTypeClass: + of tyGenericParam, tyOrdinal: result = transform(c, n.sons[1]) # happens sometimes for generated assignments, etc. else: diff --git a/compiler/types.nim b/compiler/types.nim index d7310596f..cd703474e 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -404,9 +404,10 @@ const "float", "float32", "float64", "float128", "uint", "uint8", "uint16", "uint32", "uint64", "bignum", "const ", - "!", "varargs[$1]", "iter[$1]", "Error Type", "TypeClass", - "ParametricTypeClass", "BuiltInTypeClass", "CompositeTypeClass", - "and", "or", "not", "any", "static", "TypeFromExpr"] + "!", "varargs[$1]", "iter[$1]", "Error Type", + "BuiltInTypeClass", "UserTypeClass", + "UserTypeClassInst", "CompositeTypeClass", + "and", "or", "not", "any", "static", "TypeFromExpr", "FieldAccessor"] proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = var t = typ @@ -434,11 +435,30 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = of tyStatic: internalAssert t.len > 0 result = "static[" & typeToString(t.sons[0]) & "]" - of tyTypeClass: + of tyUserTypeClass: internalAssert t.sym != nil and t.sym.owner != nil return t.sym.owner.name.s of tyBuiltInTypeClass: - return "TypeClass" + result = case t.base.kind: + of tyVar: "var" + of tyRef: "ref" + of tyPtr: "ptr" + of tySequence: "seq" + of tyArray: "array" + of tySet: "set" + of tyRange: "range" + of tyDistinct: "distinct" + of tyProc: "proc" + of tyObject: "object" + of tyTuple: "tuple" + else: (internalAssert(false); "") + of tyUserTypeClassInst: + let body = t.base + result = body.sym.name.s & "[" + for i in countup(1, sonsLen(t) - 2): + if i > 1: add(result, ", ") + add(result, typeToString(t.sons[i])) + result.add "]" of tyAnd: result = typeToString(t.sons[0]) & " and " & typeToString(t.sons[1]) of tyOr: @@ -448,7 +468,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = of tyExpr: internalAssert t.len == 0 result = "expr" - of tyFromExpr: + of tyFromExpr, tyFieldAccessor: result = renderTree(t.n) of tyArray: if t.sons[0].kind == tyRange: @@ -546,7 +566,8 @@ proc firstOrd(t: PType): BiggestInt = else: assert(t.n.sons[0].kind == nkSym) result = t.n.sons[0].sym.position - of tyGenericInst, tyDistinct, tyConst, tyMutable, tyTypeDesc: + of tyGenericInst, tyDistinct, tyConst, tyMutable, + tyTypeDesc, tyFieldAccessor: result = firstOrd(lastSon(t)) else: internalError("invalid kind for first(" & $t.kind & ')') @@ -579,7 +600,8 @@ proc lastOrd(t: PType): BiggestInt = of tyEnum: assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym) result = t.n.sons[sonsLen(t.n) - 1].sym.position - of tyGenericInst, tyDistinct, tyConst, tyMutable, tyTypeDesc: + of tyGenericInst, tyDistinct, tyConst, tyMutable, + tyTypeDesc, tyFieldAccessor: result = lastOrd(lastSon(t)) of tyProxy: result = 0 else: @@ -875,9 +897,9 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = of tyGenericInvokation, tyGenericBody, tySequence, tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr, tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter, - tyOrdinal, tyTypeClasses: + tyOrdinal, tyTypeClasses, tyFieldAccessor: cycleCheck() - if a.kind == tyTypeClass and a.n != nil: return a.n == b.n + if a.kind == tyUserTypeClass and a.n != nil: return a.n == b.n result = sameChildrenAux(a, b, c) and sameFlags(a, b) if result and a.kind == tyProc: result = ((IgnoreCC in c.flags) or a.callConv == b.callConv) and @@ -1021,7 +1043,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind, of tyTypeClasses: result = true of tyGenericBody, tyGenericParam, tyGenericInvokation, - tyNone, tyForward, tyFromExpr: + tyNone, tyForward, tyFromExpr, tyFieldAccessor: result = false of tyNil: result = kind == skConst @@ -1231,8 +1253,15 @@ proc getSize(typ: PType): BiggestInt = if result < 0: internalError("getSize: " & $typ.kind) proc containsGenericTypeIter(t: PType, closure: PObject): bool = - result = t.kind in GenericTypes + tyTypeClasses + {tyTypeDesc,tyFromExpr} or - t.kind == tyStatic and t.n == nil + if t.kind in GenericTypes + tyTypeClasses + {tyFromExpr}: + return true + + if t.kind == tyTypeDesc: + if t.sonsLen == 0: return true + if containsGenericTypeIter(t.base, closure): return true + return false + + return t.kind == tyStatic and t.n == nil proc containsGenericType*(t: PType): bool = result = iterOverType(t, containsGenericTypeIter, nil) diff --git a/compiler/vm.nim b/compiler/vm.nim index bc5320d9d..aec76f307 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -812,7 +812,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = let t1 = regs[rb].typ.skipTypes({tyTypeDesc}) let t2 = c.types[regs[rc].intVal.int] # XXX: This should use the standard isOpImpl - let match = if t2.kind == tyTypeClass: true + let match = if t2.kind == tyUserTypeClass: true else: sameType(t1, t2) regs[ra].intVal = ord(match) of opcSetLenSeq: diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index d47dccb63..63a3c30c4 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -76,7 +76,7 @@ span.LongStringLit {color: blue} span.CharLit {color: blue} span.EscapeSequence {color: black} span.Operator {color: black} -span.Punctation {color: black} +span.Punctuation {color: black} span.Comment, span.LongComment {font-style:italic; color: green} span.RegularExpression {color: DarkViolet} span.TagStart {color: DarkViolet} diff --git a/config/nimdoc.tex.cfg b/config/nimdoc.tex.cfg index 8b59f2ee9..599ede345 100644 --- a/config/nimdoc.tex.cfg +++ b/config/nimdoc.tex.cfg @@ -98,7 +98,7 @@ doc.file = """ \newcommand{\spanCharLit}[1]{#1} \newcommand{\spanEscapeSequence}[1]{#1} \newcommand{\spanOperator}[1]{#1} -\newcommand{\spanPunctation}[1]{#1} +\newcommand{\spanPunctuation}[1]{#1} \newcommand{\spanComment}[1]{\emph{#1}} \newcommand{\spanLongComment}[1]{\emph{#1}} \newcommand{\spanRegularExpression}[1]{#1} diff --git a/devel/logging.nim b/devel/logging.nim deleted file mode 100644 index a10478dab..000000000 --- a/devel/logging.nim +++ /dev/null @@ -1,210 +0,0 @@ -# -# -# Nimrod's Runtime Library -# (c) Copyright 2012 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module implements a simple logger. It is based on the following design: -## * Runtime log formating is a bug: Sooner or later every log file is parsed. -## * Keep it simple: If this library does not fullfill your needs, write your -## own. Trying to support every logging feature just leads to bloat. -## -## Format is:: -## -## DEBUG|INFO|... (2009-11-02 00:00:00)? (Component: )? Message -## -## - -import strutils, os, times - -type - TLevel* = enum ## logging level - lvlAll, ## all levels active - lvlDebug, ## debug level (and any above) active - lvlInfo, ## info level (and any above) active - lvlWarn, ## warn level (and any above) active - lvlError, ## error level (and any above) active - lvlFatal, ## fatal level (and any above) active - lvlNone - -const - LevelNames*: array [TLevel, string] = [ - "DEBUG", "DEBUG", "INFO", "WARN", "ERROR", "FATAL", "NONE" - ] - - defaultFmtStr = "" ## default string between log level and message per logger - verboseFmtStr = "$date $time " - -type - TLogger* = object of TObject ## abstract logger; the base type of all loggers - levelThreshold*: TLevel ## only messages of level >= levelThreshold - ## should be processed - fmtStr: string ## = defaultFmtStr by default, see substituteLog for $date etc. - - TConsoleLogger* = object of TLogger ## logger that writes the messages to the - ## console - - TFileLogger* = object of TLogger ## logger that writes the messages to a file - f: TFile - - # TODO: implement rolling log, will produce filename.1, filename.2 etc. - TRollingFileLogger* = object of TFileLogger ## logger that writes the - ## message to a file - maxLines: int # maximum number of lines - curLine : int - baseName: string # initial filename - logFiles: int # how many log files already created, e.g. basename.1, basename.2... - - - - -proc substituteLog*(frmt: string): string = - ## converts $date to the current date - ## converts $time to the current time - ## converts $app to getAppFilename() - ## converts - result = newStringOfCap(frmt.len + 20) - var i = 0 - while i < frmt.len: - if frmt[i] != '$': - result.add(frmt[i]) - inc(i) - else: - inc(i) - var v = "" - var app = getAppFilename() - while frmt[i] in IdentChars: - v.add(toLower(frmt[i])) - inc(i) - case v - of "date": result.add(getDateStr()) - of "time": result.add(getClockStr()) - of "app": result.add(app) - of "appdir": result.add(app.splitFile.dir) - of "appname": result.add(app.splitFile.name) - - - -method log*(L: ref TLogger, level: TLevel, - frmt: string, args: varargs[string, `$`]) = - ## override this method in custom loggers. Default implementation does - ## nothing. - nil - -method log*(L: ref TConsoleLogger, level: TLevel, - frmt: string, args: varargs[string, `$`]) = - Writeln(stdout, LevelNames[level], " ", substituteLog(L.fmtStr), frmt % args) - -method log*(L: ref TFileLogger, level: TLevel, - frmt: string, args: varargs[string, `$`]) = - Writeln(L.f, LevelNames[level], " ", substituteLog(L.fmtStr), frmt % args) - -proc defaultFilename*(): string = - ## returns the default filename for a logger - var (path, name, ext) = splitFile(getAppFilename()) - result = changeFileExt(path / name & "_" & getDateStr(), "log") - - - - -proc newConsoleLogger*(levelThreshold = lvlAll) : ref TConsoleLogger = - new result - result.fmtStr = defaultFmtStr - result.levelThreshold = levelThreshold - -proc newFileLogger*(filename = defaultFilename(), - mode: TFileMode = fmAppend, - levelThreshold = lvlAll): ref TFileLogger = - new(result) - result.levelThreshold = levelThreshold - result.f = open(filename, mode) - result.fmtStr = defaultFmtStr - -# ------ - -proc readLogLines(logger : ref TRollingFileLogger) = nil - #f.readLine # TODO read all lines, update curLine - - -proc newRollingFileLogger*(filename = defaultFilename(), - mode: TFileMode = fmReadWrite, - levelThreshold = lvlAll, - maxLines = 1000): ref TRollingFileLogger = - new(result) - result.levelThreshold = levelThreshold - result.fmtStr = defaultFmtStr - result.maxLines = maxLines - result.f = open(filename, mode) - result.curLine = 0 - - # TODO count all number files - # count lines in existing filename file - # if >= maxLines then rename to next numbered file and create new file - - #if mode in {fmReadWrite, fmReadWriteExisting}: - # readLogLines(result) - - - -method log*(L: ref TRollingFileLogger, level: TLevel, - frmt: string, args: varargs[string, `$`]) = - # TODO - # if more than maxlines, then set cursor to zero - - Writeln(L.f, LevelNames[level], " ", frmt % args) - -# -------- - -var - level* = lvlAll ## global log filter - handlers*: seq[ref TLogger] = @[] ## handlers with their own log levels - -proc logLoop(level: TLevel, frmt: string, args: varargs[string, `$`]) = - for logger in items(handlers): - if level >= logger.levelThreshold: - log(logger, level, frmt, args) - -template log*(level: TLevel, frmt: string, args: varargs[string, `$`]) = - ## logs a message of the given level - bind logLoop - bind `%` - bind logging.Level - - if level >= logging.Level: - logLoop(level, frmt, args) - -template debug*(frmt: string, args: varargs[string, `$`]) = - ## logs a debug message - log(lvlDebug, frmt, args) - -template info*(frmt: string, args: varargs[string, `$`]) = - ## logs an info message - log(lvlInfo, frmt, args) - -template warn*(frmt: string, args: varargs[string, `$`]) = - ## logs a warning message - log(lvlWarn, frmt, args) - -template error*(frmt: string, args: varargs[string, `$`]) = - ## logs an error message - log(lvlError, frmt, args) - -template fatal*(frmt: string, args: varargs[string, `$`]) = - ## logs a fatal error message - log(lvlFatal, frmt, args) - - -# -------------- - -when isMainModule: - var L = newConsoleLogger() - var fL = newFileLogger("test.log") - fL.fmtStr = verboseFmtStr - handlers.add(L) - handlers.add(fL) - info("hello", []) - - diff --git a/doc/lib.txt b/doc/lib.txt index ba0cb0a90..3214cdae2 100644 --- a/doc/lib.txt +++ b/doc/lib.txt @@ -341,6 +341,9 @@ Miscellaneous * `endians <endians.html>`_ This module contains helpers that deal with different byte orders. +* `logging <logging.html>`_ + This module implements a simple logger. + Database support ---------------- diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim index db7a63928..4ca0c79e0 100644 --- a/lib/packages/docutils/highlite.nim +++ b/lib/packages/docutils/highlite.nim @@ -19,7 +19,7 @@ type gtEof, gtNone, gtWhitespace, gtDecNumber, gtBinNumber, gtHexNumber, gtOctNumber, gtFloatNumber, gtIdentifier, gtKeyword, gtStringLit, gtLongStringLit, gtCharLit, gtEscapeSequence, # escape sequence like \xff - gtOperator, gtPunctation, gtComment, gtLongComment, gtRegularExpression, + gtOperator, gtPunctuation, gtComment, gtLongComment, gtRegularExpression, gtTagStart, gtTagEnd, gtKey, gtValue, gtRawData, gtAssembler, gtPreprocessor, gtDirective, gtCommand, gtRule, gtHyperlink, gtLabel, gtReference, gtOther @@ -39,7 +39,7 @@ const tokenClassToStr*: array[TTokenClass, string] = ["Eof", "None", "Whitespace", "DecNumber", "BinNumber", "HexNumber", "OctNumber", "FloatNumber", "Identifier", "Keyword", "StringLit", "LongStringLit", "CharLit", - "EscapeSequence", "Operator", "Punctation", "Comment", "LongComment", + "EscapeSequence", "Operator", "Punctuation", "Comment", "LongComment", "RegularExpression", "TagStart", "TagEnd", "Key", "Value", "RawData", "Assembler", "Preprocessor", "Directive", "Command", "Rule", "Hyperlink", "Label", "Reference", "Other"] @@ -258,7 +258,7 @@ proc nimNextToken(g: var TGeneralTokenizer) = else: inc(pos) of '(', ')', '[', ']', '{', '}', '`', ':', ',', ';': inc(pos) - g.kind = gtPunctation + g.kind = gtPunctuation of '\0': g.kind = gtEof else: @@ -473,7 +473,7 @@ proc clikeNextToken(g: var TGeneralTokenizer, keywords: openArray[string], else: inc(pos) of '(', ')', '[', ']', '{', '}', ':', ',', ';', '.': inc(pos) - g.kind = gtPunctation + g.kind = gtPunctuation of '\0': g.kind = gtEof else: diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index df7ae6d17..921c659de 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -131,3 +131,36 @@ proc sort*[T](a: var openArray[T], dec(m, s*2) s = s*2 +proc product*[T](x: openarray[seq[T]]): seq[seq[T]] = + ## produces the Cartesian product of the array. Warning: complexity + ## may explode. + result = @[] + if x.len == 0: + return + if x.len == 1: + result = @x + return + var + indexes = newSeq[int](x.len) + initial = newSeq[int](x.len) + index = 0 + # replace with newSeq as soon as #853 is fixed + var next: seq[T] = @[] + next.setLen(x.len) + for i in 0..(x.len-1): + if len(x[i]) == 0: return + initial[i] = len(x[i])-1 + indexes = initial + while true: + while indexes[index] == -1: + indexes[index] = initial[index] + index +=1 + if index == x.len: return + indexes[index] -=1 + for ni, i in indexes: + next[ni] = x[ni][i] + var res: seq[T] + shallowCopy(res, next) + result.add(res) + index = 0 + indexes[index] -=1 diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim new file mode 100644 index 000000000..8158cbc2a --- /dev/null +++ b/lib/pure/logging.nim @@ -0,0 +1,267 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2014 Andreas Rumpf, Dominik Picheta +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements a simple logger. It has been designed to be as simple +## as possible to avoid bloat, if this library does not fullfill your needs, +## write your own. +## +## Format strings support the following variables which must be prefixed with +## the dollar operator (``$``): +## +## ============ ======================= +## Operator Output +## ============ ======================= +## $date Current date +## $time Current time +## $app ``os.getAppFilename()`` +## ============ ======================= +## +## +## The following example demonstrates logging to three different handlers +## simultaneously: +## +## .. code-block:: nimrod +## +## var L = newConsoleLogger() +## var fL = newFileLogger("test.log", fmtStr = verboseFmtStr) +## var rL = newRollingFileLogger("rolling.log", fmtStr = verboseFmtStr) +## handlers.add(L) +## handlers.add(fL) +## handlers.add(rL) +## info("920410:52 accepted") +## warn("4 8 15 16 23 4-- Error") +## error("922044:16 SYSTEM FAILURE") +## fatal("SYSTEM FAILURE SYSTEM FAILURE") + +import strutils, os, times + +type + TLevel* = enum ## logging level + lvlAll, ## all levels active + lvlDebug, ## debug level (and any above) active + lvlInfo, ## info level (and any above) active + lvlWarn, ## warn level (and any above) active + lvlError, ## error level (and any above) active + lvlFatal, ## fatal level (and any above) active + lvlNone ## no levels active + +const + LevelNames*: array [TLevel, string] = [ + "DEBUG", "DEBUG", "INFO", "WARN", "ERROR", "FATAL", "NONE" + ] + + defaultFmtStr* = "" ## default string between log level and message per logger + verboseFmtStr* = "$date $time " + +type + PLogger* = ref object of PObject ## abstract logger; the base type of all loggers + levelThreshold*: TLevel ## only messages of level >= levelThreshold + ## should be processed + fmtStr: string ## = defaultFmtStr by default, see substituteLog for $date etc. + + PConsoleLogger* = ref object of PLogger ## logger that writes the messages to the + ## console + + PFileLogger* = ref object of PLogger ## logger that writes the messages to a file + f: TFile + + PRollingFileLogger* = ref object of PFileLogger ## logger that writes the + ## messages to a file and + ## performs log rotation + maxLines: int # maximum number of lines + curLine : int + baseName: string # initial filename + baseMode: TFileMode # initial file mode + logFiles: int # how many log files already created, e.g. basename.1, basename.2... + +proc substituteLog(frmt: string): string = + ## converts $date to the current date + ## converts $time to the current time + ## converts $app to getAppFilename() + ## converts + result = newStringOfCap(frmt.len + 20) + var i = 0 + while i < frmt.len: + if frmt[i] != '$': + result.add(frmt[i]) + inc(i) + else: + inc(i) + var v = "" + var app = getAppFilename() + while frmt[i] in IdentChars: + v.add(toLower(frmt[i])) + inc(i) + case v + of "date": result.add(getDateStr()) + of "time": result.add(getClockStr()) + of "app": result.add(app) + of "appdir": result.add(app.splitFile.dir) + of "appname": result.add(app.splitFile.name) + +method log*(logger: PLogger, level: TLevel, + frmt: string, args: varargs[string, `$`]) = + ## Override this method in custom loggers. Default implementation does + ## nothing. + nil + +method log*(logger: PConsoleLogger, level: TLevel, + frmt: string, args: varargs[string, `$`]) = + ## Logs to the console using ``logger`` only. + if level >= logger.levelThreshold: + writeln(stdout, LevelNames[level], " ", substituteLog(logger.fmtStr), + frmt % args) + +method log*(logger: PFileLogger, level: TLevel, + frmt: string, args: varargs[string, `$`]) = + ## Logs to a file using ``logger`` only. + if level >= logger.levelThreshold: + writeln(logger.f, LevelNames[level], " ", + substituteLog(logger.fmtStr), frmt % args) + +proc defaultFilename*(): string = + ## Returns the default filename for a logger. + var (path, name, ext) = splitFile(getAppFilename()) + result = changeFileExt(path / name, "log") + +proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): PConsoleLogger = + ## Creates a new console logger. This logger logs to the console. + new result + result.fmtStr = fmtStr + result.levelThreshold = levelThreshold + +proc newFileLogger*(filename = defaultFilename(), + mode: TFileMode = fmAppend, + levelThreshold = lvlAll, + fmtStr = defaultFmtStr): PFileLogger = + ## Creates a new file logger. This logger logs to a file. + new(result) + result.levelThreshold = levelThreshold + result.f = open(filename, mode) + result.fmtStr = fmtStr + +# ------ + +proc countLogLines(logger: PRollingFileLogger): int = + result = 0 + for line in logger.f.lines(): + result.inc() + +proc countFiles(filename: string): int = + # Example: file.log.1 + result = 0 + let (dir, name, ext) = splitFile(filename) + for kind, path in walkDir(dir): + if kind == pcFile: + let llfn = name & ext & ExtSep + if path.extractFilename.startsWith(llfn): + let numS = path.extractFilename[llfn.len .. -1] + try: + let num = parseInt(numS) + if num > result: + result = num + except EInvalidValue: discard + +proc newRollingFileLogger*(filename = defaultFilename(), + mode: TFileMode = fmReadWrite, + levelThreshold = lvlAll, + fmtStr = defaultFmtStr, + maxLines = 1000): PRollingFileLogger = + ## Creates a new rolling file logger. Once a file reaches ``maxLines`` lines + ## a new log file will be started and the old will be renamed. + new(result) + result.levelThreshold = levelThreshold + result.fmtStr = defaultFmtStr + result.maxLines = maxLines + result.f = open(filename, mode) + result.curLine = 0 + result.baseName = filename + result.baseMode = mode + + result.logFiles = countFiles(filename) + + if mode == fmAppend: + # We need to get a line count because we will be appending to the file. + result.curLine = countLogLines(result) + +proc rotate(logger: PRollingFileLogger) = + let (dir, name, ext) = splitFile(logger.baseName) + for i in countdown(logger.logFiles, 0): + let srcSuff = if i != 0: ExtSep & $i else: "" + moveFile(dir / (name & ext & srcSuff), + dir / (name & ext & ExtSep & $(i+1))) + +method log*(logger: PRollingFileLogger, level: TLevel, + frmt: string, args: varargs[string, `$`]) = + ## Logs to a file using rolling ``logger`` only. + if level >= logger.levelThreshold: + if logger.curLine >= logger.maxLines: + logger.f.close() + rotate(logger) + logger.logFiles.inc + logger.curLine = 0 + logger.f = open(logger.baseName, logger.baseMode) + + writeln(logger.f, LevelNames[level], " ", frmt % args) + logger.curLine.inc + +# -------- + +var + level* = lvlAll ## global log filter + handlers*: seq[PLogger] = @[] ## handlers with their own log levels + +proc logLoop(level: TLevel, frmt: string, args: varargs[string, `$`]) = + for logger in items(handlers): + if level >= logger.levelThreshold: + log(logger, level, frmt, args) + +template log*(level: TLevel, frmt: string, args: varargs[string, `$`]) = + ## Logs a message to all registered handlers at the given level. + bind logLoop + bind `%` + bind logging.Level + + if level >= logging.Level: + logLoop(level, frmt, args) + +template debug*(frmt: string, args: varargs[string, `$`]) = + ## Logs a debug message to all registered handlers. + log(lvlDebug, frmt, args) + +template info*(frmt: string, args: varargs[string, `$`]) = + ## Logs an info message to all registered handlers. + log(lvlInfo, frmt, args) + +template warn*(frmt: string, args: varargs[string, `$`]) = + ## Logs a warning message to all registered handlers. + log(lvlWarn, frmt, args) + +template error*(frmt: string, args: varargs[string, `$`]) = + ## Logs an error message to all registered handlers. + log(lvlError, frmt, args) + +template fatal*(frmt: string, args: varargs[string, `$`]) = + ## Logs a fatal error message to all registered handlers. + log(lvlFatal, frmt, args) + + +# -------------- + +when isMainModule: + var L = newConsoleLogger() + var fL = newFileLogger("test.log", fmtStr = verboseFmtStr) + var rL = newRollingFileLogger("rolling.log", fmtStr = verboseFmtStr) + handlers.add(L) + handlers.add(fL) + handlers.add(rL) + for i in 0 .. 25: + info("hello" & $i, []) + + diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim new file mode 100644 index 000000000..37de1262f --- /dev/null +++ b/tests/stdlib/talgorithm.nim @@ -0,0 +1,14 @@ +import unittest +import algorithm + +suite "product": + test "empty input": + check product[int](newSeq[seq[int]]()) == newSeq[seq[int]]() + test "bit more empty input": + check product[int](@[newSeq[int](), @[], @[]]) == newSeq[seq[int]]() + test "a simple case of one element": + check product(@[@[1,2]]) == @[@[1,2]] + test "two elements": + check product(@[@[1,2], @[3,4]]) == @[@[2,4],@[1,4],@[2,3],@[1,3]] + test "three elements": + check product(@[@[1,2], @[3,4], @[5,6]]) == @[@[2,4,6],@[1,4,6],@[2,3,6],@[1,3,6], @[2,4,5],@[1,4,5],@[2,3,5],@[1,3,5]] diff --git a/web/nimrod.ini b/web/nimrod.ini index 9af3bc226..71e36dcdc 100644 --- a/web/nimrod.ini +++ b/web/nimrod.ini @@ -62,7 +62,7 @@ srcdoc2: "pure/ftpclient;pure/memfiles;pure/subexes;pure/collections/critbits" srcdoc2: "pure/asyncio;pure/actors;core/locks;pure/oids;pure/endians;pure/uri" srcdoc2: "pure/nimprof;pure/unittest;packages/docutils/highlite" srcdoc2: "packages/docutils/rst;packages/docutils/rstast" -srcdoc2: "packages/docutils/rstgen" +srcdoc2: "packages/docutils/rstgen;pure/logging" webdoc: "wrappers/libcurl;pure/md5;wrappers/mysql;wrappers/iup" webdoc: "wrappers/sqlite3;wrappers/postgres;wrappers/tinyc" |