basic continue after error works; interactive mode more useful
This commit is contained in:
parent
5b28d08203
commit
627e192f64
12 changed files with 58 additions and 40 deletions
|
|
@ -37,7 +37,7 @@ Installation on the Macintosh
|
||||||
|
|
||||||
Only MacOS X is supported.
|
Only MacOS X is supported.
|
||||||
Since MacOS X is UNIX based too, it works like the installation on Linux.
|
Since MacOS X is UNIX based too, it works like the installation on Linux.
|
||||||
However, for unknown reasons the symbolic link method does not work MacOS X.
|
However, for unknown reasons the symbolic link method does not work on MacOS X.
|
||||||
You need to install Apple's developer's tools for the GNU Compiler Collection.
|
You need to install Apple's developer's tools for the GNU Compiler Collection.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -747,7 +747,7 @@ proc compileOption*(option, arg: string): bool {.
|
||||||
|
|
||||||
include "system/inclrtl"
|
include "system/inclrtl"
|
||||||
|
|
||||||
when not defined(ecmascript):
|
when not defined(ecmascript) and not defined(nimrodVm):
|
||||||
include "system/cgprocs"
|
include "system/cgprocs"
|
||||||
|
|
||||||
proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.}
|
proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.}
|
||||||
|
|
@ -1334,10 +1334,6 @@ proc quit*(errorcode: int = QuitSuccess) {.
|
||||||
## It does *not* call the garbage collector to free all the memory,
|
## It does *not* call the garbage collector to free all the memory,
|
||||||
## unless a quit procedure calls ``GC_collect``.
|
## unless a quit procedure calls ``GC_collect``.
|
||||||
|
|
||||||
when not defined(EcmaScript) and not defined(NimrodVM):
|
|
||||||
proc quit*(errormsg: string) {.noReturn.}
|
|
||||||
## a shorthand for ``echo(errormsg); quit(quitFailure)``.
|
|
||||||
|
|
||||||
when not defined(EcmaScript) and not defined(NimrodVM):
|
when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
|
|
||||||
proc atomicInc*(memLoc: var int, x: int): int {.inline.}
|
proc atomicInc*(memLoc: var int, x: int): int {.inline.}
|
||||||
|
|
@ -1558,10 +1554,6 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
## returns the OS file handle of the file ``f``. This is only useful for
|
## returns the OS file handle of the file ``f``. This is only useful for
|
||||||
## platform specific programming.
|
## platform specific programming.
|
||||||
|
|
||||||
proc quit(errormsg: string) =
|
|
||||||
echo(errormsg)
|
|
||||||
quit(quitFailure)
|
|
||||||
|
|
||||||
proc cstringArrayToSeq*(a: cstringArray, len: int): seq[string] =
|
proc cstringArrayToSeq*(a: cstringArray, len: int): seq[string] =
|
||||||
## converts a ``cstringArray`` to a ``seq[string]``. `a` is supposed to be
|
## converts a ``cstringArray`` to a ``seq[string]``. `a` is supposed to be
|
||||||
## of length ``len``.
|
## of length ``len``.
|
||||||
|
|
@ -1669,5 +1661,10 @@ elif defined(ecmaScript) or defined(NimrodVM):
|
||||||
if x < y: return -1
|
if x < y: return -1
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
proc quit*(errormsg: string) {.noReturn.} =
|
||||||
|
## a shorthand for ``echo(errormsg); quit(quitFailure)``.
|
||||||
|
echo(errormsg)
|
||||||
|
quit(quitFailure)
|
||||||
|
|
||||||
{.pop.} # checks
|
{.pop.} # checks
|
||||||
{.pop.} # hints
|
{.pop.} # hints
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,9 @@ var
|
||||||
gOutOfMem: ref EOutOfMemory
|
gOutOfMem: ref EOutOfMemory
|
||||||
|
|
||||||
proc raiseOutOfMem() {.noreturn.} =
|
proc raiseOutOfMem() {.noreturn.} =
|
||||||
if gOutOfMem == nil: quit("out of memory; cannot even throw an exception")
|
if gOutOfMem == nil:
|
||||||
|
echo("out of memory; cannot even throw an exception")
|
||||||
|
quit(1)
|
||||||
gOutOfMem.msg = "out of memory"
|
gOutOfMem.msg = "out of memory"
|
||||||
raise gOutOfMem
|
raise gOutOfMem
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,8 +78,9 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode
|
||||||
proc stackTraceAux(x: PStackFrame) =
|
proc stackTraceAux(x: PStackFrame) =
|
||||||
if x != nil:
|
if x != nil:
|
||||||
stackTraceAux(x.next)
|
stackTraceAux(x.next)
|
||||||
|
var info = if x.call != nil: x.call.info else: UnknownLineInfo()
|
||||||
messageOut(`%`("file: $1, line: $2",
|
messageOut(`%`("file: $1, line: $2",
|
||||||
[toFilename(x.call.info), $(toLineNumber(x.call.info))]))
|
[toFilename(info), $(toLineNumber(info))]))
|
||||||
|
|
||||||
proc stackTrace(c: PEvalContext, n: PNode, msg: TMsgKind, arg: string = "") =
|
proc stackTrace(c: PEvalContext, n: PNode, msg: TMsgKind, arg: string = "") =
|
||||||
messageOut("stack trace: (most recent call last)")
|
messageOut("stack trace: (most recent call last)")
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ type
|
||||||
f*: tfile
|
f*: tfile
|
||||||
s*: string
|
s*: string
|
||||||
rd*, wr*: int # for string streams
|
rd*, wr*: int # for string streams
|
||||||
|
lineOffset*: int # for fake stdin line numbers
|
||||||
|
|
||||||
PLLStream* = ref TLLStream
|
PLLStream* = ref TLLStream
|
||||||
|
|
||||||
|
|
@ -65,6 +66,7 @@ proc LLStreamOpenStdIn(): PLLStream =
|
||||||
new(result)
|
new(result)
|
||||||
result.kind = llsStdIn
|
result.kind = llsStdIn
|
||||||
result.s = ""
|
result.s = ""
|
||||||
|
result.lineOffset = -1
|
||||||
|
|
||||||
proc LLStreamClose(s: PLLStream) =
|
proc LLStreamClose(s: PLLStream) =
|
||||||
case s.kind
|
case s.kind
|
||||||
|
|
@ -86,6 +88,7 @@ proc LLreadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
|
||||||
add(s.s, line)
|
add(s.s, line)
|
||||||
add(s.s, "\n")
|
add(s.s, "\n")
|
||||||
if (L > 0) and (line[L - 1 + 0] == '#'): break
|
if (L > 0) and (line[L - 1 + 0] == '#'): break
|
||||||
|
inc(s.lineOffset)
|
||||||
result = min(bufLen, len(s.s) - s.rd)
|
result = min(bufLen, len(s.s) - s.rd)
|
||||||
if result > 0:
|
if result > 0:
|
||||||
copyMem(buf, addr(s.s[0 + s.rd]), result)
|
copyMem(buf, addr(s.s[0 + s.rd]), result)
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,7 @@ proc CommandCompileToEcmaScript(filename: string) =
|
||||||
compileProject(filename)
|
compileProject(filename)
|
||||||
|
|
||||||
proc CommandInteractive() =
|
proc CommandInteractive() =
|
||||||
|
msgs.gErrorMax = high(int) # do not stop after first error
|
||||||
incl(gGlobalOptions, optSafeCode)
|
incl(gGlobalOptions, optSafeCode)
|
||||||
setTarget(osNimrodVM, cpuNimrodVM)
|
setTarget(osNimrodVM, cpuNimrodVM)
|
||||||
initDefines()
|
initDefines()
|
||||||
|
|
|
||||||
29
rod/msgs.nim
29
rod/msgs.nim
|
|
@ -373,6 +373,8 @@ type
|
||||||
|
|
||||||
ERecoverableError* = object of EInvalidValue
|
ERecoverableError* = object of EInvalidValue
|
||||||
|
|
||||||
|
proc raiseRecoverableError*() {.noinline, noreturn.} =
|
||||||
|
raise newException(ERecoverableError, "")
|
||||||
|
|
||||||
var
|
var
|
||||||
gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)}
|
gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)}
|
||||||
|
|
@ -485,7 +487,7 @@ proc handleError(msg: TMsgKind, eh: TErrorHandling) =
|
||||||
if gVerbosity >= 3: assert(false)
|
if gVerbosity >= 3: assert(false)
|
||||||
quit(1) # one error stops the compiler
|
quit(1) # one error stops the compiler
|
||||||
elif eh == doRaise:
|
elif eh == doRaise:
|
||||||
raise newException(ERecoverableError, "")
|
raiseRecoverableError()
|
||||||
|
|
||||||
proc sameLineInfo(a, b: TLineInfo): bool =
|
proc sameLineInfo(a, b: TLineInfo): bool =
|
||||||
result = (a.line == b.line) and (a.fileIndex == b.fileIndex)
|
result = (a.line == b.line) and (a.fileIndex == b.fileIndex)
|
||||||
|
|
@ -518,36 +520,39 @@ proc rawMessage*(msg: TMsgKind, args: openarray[string]) =
|
||||||
if not (msg in gNotes): return
|
if not (msg in gNotes): return
|
||||||
frmt = rawHintFormat
|
frmt = rawHintFormat
|
||||||
inc(gHintCounter)
|
inc(gHintCounter)
|
||||||
else:
|
|
||||||
assert(false) # cannot happen
|
|
||||||
MessageOut(`%`(frmt, `%`(msgKindToString(msg), args)))
|
MessageOut(`%`(frmt, `%`(msgKindToString(msg), args)))
|
||||||
handleError(msg, doAbort)
|
handleError(msg, doAbort)
|
||||||
|
|
||||||
proc rawMessage*(msg: TMsgKind, arg: string) =
|
proc rawMessage*(msg: TMsgKind, arg: string) =
|
||||||
rawMessage(msg, [arg])
|
rawMessage(msg, [arg])
|
||||||
|
|
||||||
|
var
|
||||||
|
lastError = UnknownLineInfo()
|
||||||
|
|
||||||
proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
||||||
eh: TErrorHandling) =
|
eh: TErrorHandling) =
|
||||||
var frmt: string
|
var frmt: string
|
||||||
|
var ignoreMsg = false
|
||||||
case msg
|
case msg
|
||||||
of errMin..errMax:
|
of errMin..errMax:
|
||||||
writeContext(info)
|
writeContext(info)
|
||||||
frmt = posErrorFormat
|
frmt = posErrorFormat
|
||||||
|
# we try to filter error messages so that not two error message
|
||||||
|
# in the same file and line are produced:
|
||||||
|
ignoreMsg = sameLineInfo(lastError, info)
|
||||||
|
lastError = info
|
||||||
of warnMin..warnMax:
|
of warnMin..warnMax:
|
||||||
if not (optWarns in gOptions): return
|
ignoreMsg = optWarns notin gOptions or msg notin gNotes
|
||||||
if not (msg in gNotes): return
|
|
||||||
frmt = posWarningFormat
|
frmt = posWarningFormat
|
||||||
inc(gWarnCounter)
|
inc(gWarnCounter)
|
||||||
of hintMin..hintMax:
|
of hintMin..hintMax:
|
||||||
if not (optHints in gOptions): return
|
ignoreMsg = optHints notin gOptions or msg notin gNotes
|
||||||
if not (msg in gNotes): return
|
|
||||||
frmt = posHintFormat
|
frmt = posHintFormat
|
||||||
inc(gHintCounter)
|
inc(gHintCounter)
|
||||||
else:
|
if not ignoreMsg:
|
||||||
assert(false) # cannot happen
|
MessageOut(frmt % [toFilename(info), coordToStr(info.line),
|
||||||
MessageOut(`%`(frmt, [toFilename(info), coordToStr(info.line),
|
coordToStr(info.col), getMessageStr(msg, arg)])
|
||||||
coordToStr(info.col), getMessageStr(msg, arg)]))
|
handleError(msg, eh)
|
||||||
handleError(msg, doAbort)
|
|
||||||
|
|
||||||
proc Fatal*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
proc Fatal*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||||
liMessage(info, msg, arg, doAbort)
|
liMessage(info, msg, arg, doAbort)
|
||||||
|
|
|
||||||
|
|
@ -68,10 +68,11 @@ proc HandleCmdLine() =
|
||||||
ProcessCmdLine(passCmd2, command, filename)
|
ProcessCmdLine(passCmd2, command, filename)
|
||||||
MainCommand(command, filename)
|
MainCommand(command, filename)
|
||||||
if gVerbosity >= 2: echo(GC_getStatistics())
|
if gVerbosity >= 2: echo(GC_getStatistics())
|
||||||
|
if msgs.gErrorCounter == 0:
|
||||||
when hasTinyCBackend:
|
when hasTinyCBackend:
|
||||||
if gCmd == cmdRun:
|
if gCmd == cmdRun:
|
||||||
tccgen.run()
|
tccgen.run()
|
||||||
if gCmd notin {cmdInterpret, cmdRun} and msgs.gErrorCounter == 0:
|
if gCmd notin {cmdInterpret, cmdRun}:
|
||||||
rawMessage(hintSuccessX, [$gLinesCompiled, $(getTime() - start)])
|
rawMessage(hintSuccessX, [$gLinesCompiled, $(getTime() - start)])
|
||||||
if optRun in gGlobalOptions:
|
if optRun in gGlobalOptions:
|
||||||
when defined(unix):
|
when defined(unix):
|
||||||
|
|
|
||||||
|
|
@ -211,6 +211,7 @@ proc openLexer(lex: var TLexer, filename: string, inputstream: PLLStream) =
|
||||||
lex.indentStack = @[0]
|
lex.indentStack = @[0]
|
||||||
lex.filename = filename
|
lex.filename = filename
|
||||||
lex.indentAhead = - 1
|
lex.indentAhead = - 1
|
||||||
|
inc(lex.Linenumber, inputstream.lineOffset)
|
||||||
|
|
||||||
proc closeLexer(lex: var TLexer) =
|
proc closeLexer(lex: var TLexer) =
|
||||||
inc(gLinesCompiled, lex.LineNumber)
|
inc(gLinesCompiled, lex.LineNumber)
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,12 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
|
||||||
popInfoContext()
|
popInfoContext()
|
||||||
|
|
||||||
proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||||
|
|
||||||
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
result = semExpr(c, n, flags)
|
result = semExpr(c, n, flags)
|
||||||
if result.kind == nkEmpty: InternalError("semExprWithType")
|
if result.kind == nkEmpty:
|
||||||
|
# do not produce another redundant error message:
|
||||||
|
raiseRecoverableError()
|
||||||
if result.typ != nil:
|
if result.typ != nil:
|
||||||
if result.typ.kind == tyVar:
|
if result.typ.kind == tyVar:
|
||||||
var d = newNodeIT(nkHiddenDeref, result.info, result.typ.sons[0])
|
var d = newNodeIT(nkHiddenDeref, result.info, result.typ.sons[0])
|
||||||
|
|
|
||||||
|
|
@ -276,6 +276,8 @@ proc semVar(c: PContext, n: PNode): PNode =
|
||||||
else: typ = def.typ
|
else: typ = def.typ
|
||||||
else:
|
else:
|
||||||
def = ast.emptyNode
|
def = ast.emptyNode
|
||||||
|
# this can only happen for errornous var statements:
|
||||||
|
if typ == nil: continue
|
||||||
if not typeAllowed(typ, skVar):
|
if not typeAllowed(typ, skVar):
|
||||||
GlobalError(a.info, errXisNoType, typeToString(typ))
|
GlobalError(a.info, errXisNoType, typeToString(typ))
|
||||||
var tup = skipTypes(typ, {tyGenericInst})
|
var tup = skipTypes(typ, {tyGenericInst})
|
||||||
|
|
|
||||||
|
|
@ -723,7 +723,9 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
result = PTransNode(cnst) # do not miss an optimization
|
result = PTransNode(cnst) # do not miss an optimization
|
||||||
|
|
||||||
proc processTransf(context: PPassContext, n: PNode): PNode =
|
proc processTransf(context: PPassContext, n: PNode): PNode =
|
||||||
if passes.skipCodegen(n): return n
|
# Note: For interactive mode we cannot call 'passes.skipCodegen' and skip
|
||||||
|
# this step! We have to rely that the semantic pass transforms too errornous
|
||||||
|
# nodes into an empty node.
|
||||||
var c = PTransf(context)
|
var c = PTransf(context)
|
||||||
pushTransCon(c, newTransCon(getCurrOwner(c)))
|
pushTransCon(c, newTransCon(getCurrOwner(c)))
|
||||||
result = PNode(transform(c, n))
|
result = PNode(transform(c, n))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue