simple unit test and better documentation for the user defined type classes
This commit is contained in:
parent
4cea15d274
commit
a068aaed3c
8 changed files with 113 additions and 57 deletions
|
|
@ -436,7 +436,14 @@ type
|
|||
# only 8 bytes.
|
||||
line*, col*: int16
|
||||
fileIndex*: int32
|
||||
|
||||
|
||||
TErrorOutput* = enum
|
||||
eStdOut
|
||||
eStdErr
|
||||
eInMemory
|
||||
|
||||
TErrorOutputs* = set[TErrorOutput]
|
||||
|
||||
ERecoverableError* = object of EInvalidValue
|
||||
ESuggestDone* = object of EBase
|
||||
|
||||
|
|
@ -534,13 +541,27 @@ var
|
|||
gHintCounter*: int = 0
|
||||
gWarnCounter*: int = 0
|
||||
gErrorMax*: int = 1 # stop after gErrorMax errors
|
||||
gSilence*: int # == 0 if we produce any output at all
|
||||
|
||||
when useCaas:
|
||||
var stdoutSocket*: TSocket
|
||||
|
||||
proc UnknownLineInfo*(): TLineInfo =
|
||||
result.line = int16(-1)
|
||||
result.col = int16(-1)
|
||||
result.fileIndex = -1
|
||||
|
||||
var
|
||||
msgContext: seq[TLineInfo] = @[]
|
||||
lastError = UnknownLineInfo()
|
||||
bufferedMsgs*: seq[string]
|
||||
|
||||
errorOutputs* = {eStdOut, eStdErr}
|
||||
|
||||
proc clearBufferedMsgs* =
|
||||
bufferedMsgs = nil
|
||||
|
||||
proc SuggestWriteln*(s: string) =
|
||||
if gSilence == 0:
|
||||
if eStdOut in errorOutputs:
|
||||
when useCaas:
|
||||
if isNil(stdoutSocket): Writeln(stdout, s)
|
||||
else:
|
||||
|
|
@ -548,6 +569,9 @@ proc SuggestWriteln*(s: string) =
|
|||
stdoutSocket.send(s & "\c\L")
|
||||
else:
|
||||
Writeln(stdout, s)
|
||||
|
||||
if eInMemory in errorOutputs:
|
||||
bufferedMsgs.safeAdd(s)
|
||||
|
||||
proc SuggestQuit*() =
|
||||
if not isServing:
|
||||
|
|
@ -570,14 +594,6 @@ const
|
|||
RawWarningFormat* = "Warning: $1"
|
||||
RawHintFormat* = "Hint: $1"
|
||||
|
||||
proc UnknownLineInfo*(): TLineInfo =
|
||||
result.line = int16(-1)
|
||||
result.col = int16(-1)
|
||||
result.fileIndex = -1
|
||||
|
||||
var
|
||||
msgContext: seq[TLineInfo] = @[]
|
||||
|
||||
proc getInfoContextLen*(): int = return msgContext.len
|
||||
proc setInfoContextLen*(L: int) = setLen(msgContext, L)
|
||||
|
||||
|
|
@ -642,14 +658,18 @@ proc addCheckpoint*(filename: string, line: int) =
|
|||
|
||||
proc OutWriteln*(s: string) =
|
||||
## Writes to stdout. Always.
|
||||
if gSilence == 0: Writeln(stdout, s)
|
||||
if eStdOut in errorOutputs: Writeln(stdout, s)
|
||||
|
||||
proc MsgWriteln*(s: string) =
|
||||
## Writes to stdout. If --stdout option is given, writes to stderr instead.
|
||||
if gSilence == 0:
|
||||
if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
|
||||
if optStdout in gGlobalOptions: Writeln(stderr, s)
|
||||
else: Writeln(stdout, s)
|
||||
if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
|
||||
|
||||
if optStdout in gGlobalOptions:
|
||||
if eStdErr in errorOutputs: Writeln(stderr, s)
|
||||
else:
|
||||
if eStdOut in errorOutputs: Writeln(stdout, s)
|
||||
|
||||
if eInMemory in errorOutputs: bufferedMsgs.safeAdd(s)
|
||||
|
||||
proc coordToStr(coord: int): string =
|
||||
if coord == -1: result = "???"
|
||||
|
|
@ -736,9 +756,6 @@ proc rawMessage*(msg: TMsgKind, args: openarray[string]) =
|
|||
proc rawMessage*(msg: TMsgKind, arg: string) =
|
||||
rawMessage(msg, [arg])
|
||||
|
||||
var
|
||||
lastError = UnknownLineInfo()
|
||||
|
||||
proc writeSurroundingSrc(info: TLineInfo) =
|
||||
const indent = " "
|
||||
MsgWriteln(indent & info.sourceLine.ropeToStr)
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ proc semParamList(c: PContext, n, genericParams: PNode, s: PSym)
|
|||
proc addParams(c: PContext, n: PNode, kind: TSymKind)
|
||||
proc maybeAddResult(c: PContext, s: PSym, n: PNode)
|
||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
|
||||
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||
proc tryExpr(c: PContext, n: PNode,
|
||||
flags: TExprFlags = {}, bufferErrors = false): PNode
|
||||
proc fixImmediateParams(n: PNode): PNode
|
||||
proc activate(c: PContext, n: PNode)
|
||||
proc semQuoteAst(c: PContext, n: PNode): PNode
|
||||
|
|
|
|||
|
|
@ -73,7 +73,8 @@ type
|
|||
libs*: TLinkedList # all libs used by this module
|
||||
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
|
||||
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||
semTryExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||
semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {},
|
||||
bufferErrors = false): PNode {.nimcall.}
|
||||
semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
|
||||
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
|
||||
|
|
|
|||
|
|
@ -824,7 +824,7 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode =
|
|||
|
||||
proc semExprNoType(c: PContext, n: PNode): PNode =
|
||||
result = semExpr(c, n, {efWantStmt})
|
||||
discardCheck(result)
|
||||
discardCheck(c, result)
|
||||
|
||||
proc isTypeExpr(n: PNode): bool =
|
||||
case n.kind
|
||||
|
|
@ -1218,7 +1218,7 @@ proc semProcBody(c: PContext, n: PNode): PNode =
|
|||
a.sons[1] = result
|
||||
result = semAsgn(c, a)
|
||||
else:
|
||||
discardCheck(result)
|
||||
discardCheck(c, result)
|
||||
closeScope(c)
|
||||
|
||||
proc SemYieldVarResult(c: PContext, n: PNode, restype: PType) =
|
||||
|
|
@ -1439,12 +1439,12 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
|
|||
newNode(nkCall, n.info, quotes)])
|
||||
result = semExpandToAst(c, result)
|
||||
|
||||
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
proc tryExpr(c: PContext, n: PNode,
|
||||
flags: TExprFlags = {}, bufferErrors = false): PNode =
|
||||
# watch out, hacks ahead:
|
||||
let oldErrorCount = msgs.gErrorCounter
|
||||
let oldErrorMax = msgs.gErrorMax
|
||||
inc c.InCompilesContext
|
||||
inc msgs.gSilence
|
||||
# do not halt after first error:
|
||||
msgs.gErrorMax = high(int)
|
||||
|
||||
|
|
@ -1453,6 +1453,8 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
openScope(c)
|
||||
let oldOwnerLen = len(gOwners)
|
||||
let oldGenerics = c.generics
|
||||
let oldErrorOutputs = errorOutputs
|
||||
errorOutputs = if bufferErrors: {eInMemory} else: {}
|
||||
let oldContextLen = msgs.getInfoContextLen()
|
||||
|
||||
let oldInGenericContext = c.InGenericContext
|
||||
|
|
@ -1475,7 +1477,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
setlen(gOwners, oldOwnerLen)
|
||||
c.currentScope = oldScope
|
||||
dec c.InCompilesContext
|
||||
dec msgs.gSilence
|
||||
errorOutputs = oldErrorOutputs
|
||||
msgs.gErrorCounter = oldErrorCount
|
||||
msgs.gErrorMax = oldErrorMax
|
||||
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ proc fixNilType(n: PNode) =
|
|||
for it in n: fixNilType(it)
|
||||
n.typ = nil
|
||||
|
||||
proc discardCheck(result: PNode) =
|
||||
proc discardCheck(c: PContext, result: PNode) =
|
||||
if result.typ != nil and result.typ.kind notin {tyStmt, tyEmpty}:
|
||||
if result.kind == nkNilLit:
|
||||
result.typ = nil
|
||||
|
|
@ -142,6 +142,10 @@ proc discardCheck(result: PNode) =
|
|||
while n.kind in skipForDiscardable:
|
||||
n = n.lastSon
|
||||
n.typ = nil
|
||||
elif c.InTypeClass > 0 and result.typ.kind == tyBool:
|
||||
let verdict = semConstExpr(c, result)
|
||||
if verdict.intVal == 0:
|
||||
localError(result.info, "type class predicate failed.")
|
||||
elif result.typ.kind != tyError and gCmd != cmdInteractive:
|
||||
if result.typ.kind == tyNil:
|
||||
fixNilType(result)
|
||||
|
|
@ -169,7 +173,7 @@ proc semIf(c: PContext, n: PNode): PNode =
|
|||
typ = commonType(typ, it.sons[0].typ)
|
||||
else: illFormedAst(it)
|
||||
if isEmptyType(typ) or typ.kind == tyNil or not hasElse:
|
||||
for it in n: discardCheck(it.lastSon)
|
||||
for it in n: discardCheck(c, it.lastSon)
|
||||
result.kind = nkIfStmt
|
||||
# propagate any enforced VoidContext:
|
||||
if typ == EnforceVoidContext: result.typ = EnforceVoidContext
|
||||
|
|
@ -230,7 +234,7 @@ proc semCase(c: PContext, n: PNode): PNode =
|
|||
localError(n.info, errNotAllCasesCovered)
|
||||
closeScope(c)
|
||||
if isEmptyType(typ) or typ.kind == tyNil or not hasElse:
|
||||
for i in 1..n.len-1: discardCheck(n.sons[i].lastSon)
|
||||
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
|
||||
# propagate any enforced VoidContext:
|
||||
if typ == EnforceVoidContext:
|
||||
result.typ = EnforceVoidContext
|
||||
|
|
@ -275,8 +279,8 @@ proc semTry(c: PContext, n: PNode): PNode =
|
|||
typ = commonType(typ, a.sons[length-1].typ)
|
||||
dec c.p.inTryStmt
|
||||
if isEmptyType(typ) or typ.kind == tyNil:
|
||||
discardCheck(n.sons[0])
|
||||
for i in 1..n.len-1: discardCheck(n.sons[i].lastSon)
|
||||
discardCheck(c, n.sons[0])
|
||||
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
|
||||
if typ == EnforceVoidContext:
|
||||
result.typ = EnforceVoidContext
|
||||
else:
|
||||
|
|
@ -1221,7 +1225,7 @@ proc semStmtList(c: PContext, n: PNode): PNode =
|
|||
voidContext = true
|
||||
n.typ = EnforceVoidContext
|
||||
if i != last or voidContext:
|
||||
discardCheck(n.sons[i])
|
||||
discardCheck(c, n.sons[i])
|
||||
else:
|
||||
n.typ = n.sons[i].typ
|
||||
if not isEmptyType(n.typ):
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode,
|
|||
c.calleeSym = callee
|
||||
c.calleeScope = calleeScope
|
||||
initIdTable(c.bindings)
|
||||
c.errors = nil
|
||||
if binding != nil and callee.kind in RoutineKinds:
|
||||
var typeParams = callee.ast[genericParamsPos]
|
||||
for i in 1..min(sonsLen(typeParams), sonsLen(binding)-1):
|
||||
|
|
@ -774,23 +775,16 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
|||
addDecl(c, dummyParam)
|
||||
|
||||
for stmt in f.n[3]:
|
||||
var e = c.semTryExpr(c, copyTree(stmt))
|
||||
if e == nil:
|
||||
let expStr = renderTree(stmt, {renderNoComments})
|
||||
m.errors.safeAdd("can't compile " & expStr & " for " & a.typeToString)
|
||||
return nil
|
||||
var e = c.semTryExpr(c, copyTree(stmt), bufferErrors = false)
|
||||
m.errors = bufferedMsgs
|
||||
clearBufferedMsgs()
|
||||
if e == nil: return nil
|
||||
|
||||
case e.kind
|
||||
of nkReturnStmt:
|
||||
nil
|
||||
of nkReturnStmt: nil
|
||||
of nkTypeSection: nil
|
||||
of nkConstDef: nil
|
||||
else:
|
||||
if e.typ != nil and e.typ.kind == tyBool:
|
||||
let verdict = c.semConstExpr(c, e)
|
||||
if verdict.intVal == 0:
|
||||
let expStr = renderTree(stmt, {renderNoComments})
|
||||
m.errors.safeAdd(expStr & " doesn't hold for " & a.typeToString)
|
||||
return nil
|
||||
else: nil
|
||||
|
||||
result = arg
|
||||
put(m.bindings, f, a)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue