diff options
-rw-r--r-- | compiler/jsgen.nim | 42 | ||||
-rw-r--r-- | compiler/msgs.nim | 258 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 6 | ||||
-rw-r--r-- | lib/pure/math.nim | 56 | ||||
-rw-r--r-- | lib/pure/terminal.nim | 35 | ||||
-rw-r--r-- | lib/system/jssys.nim | 41 | ||||
-rw-r--r-- | tests/typerel/tstr_as_openarray.nim | 22 |
7 files changed, 303 insertions, 157 deletions
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index f6ec256d2..d84b0f2f9 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -505,12 +505,12 @@ proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) = proc genTry(p: PProc, n: PNode, r: var TCompRes) = # code to generate: # - # var sp = {prev: excHandler, exc: null}; - # excHandler = sp; + # ++excHandler; # try { # stmts; - # TMP = e - # } catch (e) { + # } catch (EXC) { + # var prevJSError = lastJSError; lastJSError = EXC; + # --excHandler; # if (e.typ && e.typ == NTI433 || e.typ == NTI2321) { # stmts; # } else if (e.typ && e.typ == NTI32342) { @@ -518,35 +518,41 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) = # } else { # stmts; # } + # lastJSError = prevJSError; # } finally { # stmts; - # excHandler = excHandler.prev; # } genLineDir(p, n) if not isEmptyType(n.typ): r.kind = resVal r.res = getTemp(p) inc(p.unique) + var i = 1 + var length = sonsLen(n) + var catchBranchesExist = length > 1 and n.sons[i].kind == nkExceptBranch + if catchBranchesExist: + add(p.body, "++excHandler;" & tnl) var safePoint = "Tmp$1" % [rope(p.unique)] addf(p.body, - "var $1 = {prev: excHandler, exc: null};$nexcHandler = $1;$n" | + "" | "local $1 = pcall(", [safePoint]) if optStackTrace in p.options: add(p.body, "framePtr = F;" & tnl) addf(p.body, "try {$n" | "function()$n", []) - var length = sonsLen(n) var a: TCompRes gen(p, n.sons[0], a) moveInto(p, a, r) - var i = 1 - if p.target == targetJS and length > 1 and n.sons[i].kind == nkExceptBranch: - addf(p.body, "} catch (EXC) {$n lastJSError = EXC;$n", []) + var generalCatchBranchExists = false + if p.target == targetJS and catchBranchesExist: + addf(p.body, "} catch (EXC) {$n var prevJSError = lastJSError;$n" & + " lastJSError = EXC;$n --excHandler;$n", []) elif p.target == targetLua: addf(p.body, "end)$n", []) while i < length and n.sons[i].kind == nkExceptBranch: let blen = sonsLen(n.sons[i]) if blen == 1: # general except section: + generalCatchBranchExists = true if i > 1: addf(p.body, "else {$n" | "else$n", []) gen(p, n.sons[i].sons[0], a) moveInto(p, a, r) @@ -558,17 +564,22 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) = if n.sons[i].sons[j].kind != nkType: internalError(n.info, "genTryStmt") if orExpr != nil: add(orExpr, "||" | " or ") - addf(orExpr, "isObj($1.exc.m_type, $2)", - [safePoint, genTypeInfo(p, n.sons[i].sons[j].typ)]) + addf(orExpr, "isObj(lastJSError.m_type, $1)", + [genTypeInfo(p, n.sons[i].sons[j].typ)]) if i > 1: add(p.body, "else ") - addf(p.body, "if ($1.exc && ($2)) {$n" | "if $1.exc and ($2) then$n", + addf(p.body, "if (lastJSError && ($2)) {$n" | "if $1.exc and ($2) then$n", [safePoint, orExpr]) gen(p, n.sons[i].sons[blen - 1], a) moveInto(p, a, r) addf(p.body, "}$n" | "end$n", []) inc(i) if p.target == targetJS: - add(p.body, "} finally {" & tnl & "excHandler = excHandler.prev;" & tnl) + if catchBranchesExist: + if not generalCatchBranchExists: + useMagic(p, "reraiseException") + add(p.body, "else {" & tnl & "reraiseException();" & tnl & "}" & tnl) + add(p.body, "lastJSError = prevJSError;" & tnl) + add(p.body, "} finally {" & tnl) if i < length and n.sons[i].kind == nkFinally: genStmt(p, n.sons[i].sons[0]) if p.target == targetJS: @@ -1067,6 +1078,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) = r.kind = resExpr proc genEcho(p: PProc, n: PNode, r: var TCompRes) = + useMagic(p, "toJSStr") # Used in rawEcho useMagic(p, "rawEcho") add(r.res, "rawEcho(") let n = n[1].skipConv @@ -1676,7 +1688,7 @@ proc genHeader(): Rope = result = ("/* Generated by the Nim Compiler v$1 */$n" & "/* (c) 2015 Andreas Rumpf */$n$n" & "var framePtr = null;$n" & - "var excHandler = null;$n" & + "var excHandler = 0;$n" & "var lastJSError = null;$n") % [rope(VersionAsString)] diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 4df4430d7..6b71b7159 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -8,7 +8,7 @@ # import - options, strutils, os, tables, ropes, platform, terminal + options, strutils, os, tables, ropes, platform, terminal, macros type TMsgKind* = enum @@ -367,54 +367,54 @@ const "of the generic paramers can be inferred from the expected signature.", errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target", errUser: "$1", - warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]", - warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored [OctalEscape]", - warnXIsNeverRead: "\'$1\' is never read [XIsNeverRead]", - warnXmightNotBeenInit: "\'$1\' might not have been initialized [XmightNotBeenInit]", - warnDeprecated: "$1 is deprecated [Deprecated]", - warnConfigDeprecated: "config file '$1' is deprecated [ConfigDeprecated]", - warnSmallLshouldNotBeUsed: "\'l\' should not be used as an identifier; may look like \'1\' (one) [SmallLshouldNotBeUsed]", - warnUnknownMagic: "unknown magic \'$1\' might crash the compiler [UnknownMagic]", - warnRedefinitionOfLabel: "redefinition of label \'$1\' [RedefinitionOfLabel]", - warnUnknownSubstitutionX: "unknown substitution \'$1\' [UnknownSubstitutionX]", - warnLanguageXNotSupported: "language \'$1\' not supported [LanguageXNotSupported]", - warnFieldXNotSupported: "field \'$1\' not supported [FieldXNotSupported]", - warnCommentXIgnored: "comment \'$1\' ignored [CommentXIgnored]", - warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead [NilStmt]", - warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template' [TypelessParam]", - warnDifferentHeaps: "possible inconsistency of thread local heaps [DifferentHeaps]", - warnWriteToForeignHeap: "write to foreign heap [WriteToForeignHeap]", - warnUnsafeCode: "unsafe code: '$1' [UnsafeCode]", - warnEachIdentIsTuple: "each identifier is a tuple [EachIdentIsTuple]", - warnShadowIdent: "shadowed identifier: '$1' [ShadowIdent]", - warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future. [ProveInit]", - warnProveField: "cannot prove that field '$1' is accessible [ProveField]", - warnProveIndex: "cannot prove index '$1' is valid [ProveIndex]", - warnGcUnsafe: "not GC-safe: '$1' [GcUnsafe]", + warnCannotOpenFile: "cannot open \'$1\'", + warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored", + warnXIsNeverRead: "\'$1\' is never read", + warnXmightNotBeenInit: "\'$1\' might not have been initialized", + warnDeprecated: "$1 is deprecated", + warnConfigDeprecated: "config file '$1' is deprecated", + warnSmallLshouldNotBeUsed: "\'l\' should not be used as an identifier; may look like \'1\' (one)", + warnUnknownMagic: "unknown magic \'$1\' might crash the compiler", + warnRedefinitionOfLabel: "redefinition of label \'$1\'", + warnUnknownSubstitutionX: "unknown substitution \'$1\'", + warnLanguageXNotSupported: "language \'$1\' not supported", + warnFieldXNotSupported: "field \'$1\' not supported", + warnCommentXIgnored: "comment \'$1\' ignored", + warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead", + warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'", + warnDifferentHeaps: "possible inconsistency of thread local heaps", + warnWriteToForeignHeap: "write to foreign heap", + warnUnsafeCode: "unsafe code: '$1'", + warnEachIdentIsTuple: "each identifier is a tuple", + warnShadowIdent: "shadowed identifier: '$1'", + warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future.", + warnProveField: "cannot prove that field '$1' is accessible", + warnProveIndex: "cannot prove index '$1' is valid", + warnGcUnsafe: "not GC-safe: '$1'", warnGcUnsafe2: "$1", - warnUninit: "'$1' might not have been initialized [Uninit]", - warnGcMem: "'$1' uses GC'ed memory [GcMem]", - warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future. [Destructor]", - warnLockLevel: "$1 [LockLevel]", - warnResultShadowed: "Special variable 'result' is shadowed. [ResultShadowed]", - warnUser: "$1 [User]", - hintSuccess: "operation successful [Success]", - hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#) [SuccessX]", - hintLineTooLong: "line too long [LineTooLong]", - hintXDeclaredButNotUsed: "\'$1\' is declared but not used [XDeclaredButNotUsed]", - hintConvToBaseNotNeeded: "conversion to base object is not needed [ConvToBaseNotNeeded]", - hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless [ConvFromXtoItselfNotNeeded]", - hintExprAlwaysX: "expression evaluates always to \'$1\' [ExprAlwaysX]", - hintQuitCalled: "quit() called [QuitCalled]", - hintProcessing: "$1 [Processing]", - hintCodeBegin: "generated code listing: [CodeBegin]", - hintCodeEnd: "end of listing [CodeEnd]", - hintConf: "used config file \'$1\' [Conf]", - hintPath: "added path: '$1' [Path]", - hintConditionAlwaysTrue: "condition is always true: '$1' [CondTrue]", - hintName: "name should be: '$1' [Name]", - hintPattern: "$1 [Pattern]", - hintUser: "$1 [User]"] + warnUninit: "'$1' might not have been initialized", + warnGcMem: "'$1' uses GC'ed memory", + warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future.", + warnLockLevel: "$1", + warnResultShadowed: "Special variable 'result' is shadowed.", + warnUser: "$1", + hintSuccess: "operation successful", + hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)", + hintLineTooLong: "line too long", + hintXDeclaredButNotUsed: "\'$1\' is declared but not used", + hintConvToBaseNotNeeded: "conversion to base object is not needed", + hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless", + hintExprAlwaysX: "expression evaluates always to \'$1\'", + hintQuitCalled: "quit() called", + hintProcessing: "$1", + hintCodeBegin: "generated code listing:", + hintCodeEnd: "end of listing", + hintConf: "used config file \'$1\'", + hintPath: "added path: '$1'", + hintConditionAlwaysTrue: "condition is always true: '$1'", + hintName: "name should be: '$1'", + hintPattern: "$1", + hintUser: "$1"] const WarningsToStr*: array[0..30, string] = ["CannotOpenFile", "OctalEscape", @@ -605,13 +605,17 @@ proc suggestQuit*() = # this format is understood by many text editors: it is the same that # Borland and Freepascal use const - PosErrorFormat* = "$1($2, $3) Error: " - PosWarningFormat* = "$1($2, $3) Warning: " - PosHintFormat* = "$1($2, $3) Hint: " - PosContextFormat = "$1($2, $3) Info: " - RawError* = "Error: " - RawWarning* = "Warning: " - RawHint* = "Hint: " + PosFormat = "$1($2, $3) " + KindFormat = " [$1]" + KindColor = fgCyan + ErrorTitle = "Error: " + ErrorColor = fgRed + WarningTitle = "Warning: " + WarningColor = fgYellow + HintTitle = "Hint: " + HintColor = fgGreen + InfoTitle = "Info: " + InfoColor = fgCyan proc getInfoContextLen*(): int = return msgContext.len proc setInfoContextLen*(L: int) = setLen(msgContext, L) @@ -686,27 +690,58 @@ proc outWriteln*(s: string) = ## Writes to stdout. Always. if eStdOut in errorOutputs: writeln(stdout, s) -proc msgWriteln*(s: string, color: ForegroundColor = fgWhite, coloredText: string = "") = - ## Writes to stdout. If --stderr option is given, writes to stderr instead. +proc msgWriteln*(s: string) = + ## Writes to stdout. If --stdout option is given, writes to stderr instead. #if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return - var hasColor = optUseColors in gGlobalOptions if not isNil(writelnHook): - writelnHook(coloredText & s) + writelnHook(s) + elif optStdout in gGlobalOptions: + if eStdErr in errorOutputs: writeln(stderr, s) else: - if optStdout in gGlobalOptions: - if eStdErr in errorOutputs: - if hasColor: setForegroundColor(color) - write(stderr, coloredText) - if hasColor: resetAttributes() - writeln(stderr, s) - else: - if eStdOut in errorOutputs: - if hasColor: setForegroundColor(color) - write(stdout, coloredText) - if hasColor: resetAttributes() - writeln(stdout, s) + if eStdOut in errorOutputs: writeln(stdout, s) + +macro callIgnoringStyle(theProc: typed, first: typed, + args: varargs[expr]): stmt = + let typForegroundColor = bindSym"ForegroundColor".getType + let typBackgroundColor = bindSym"BackgroundColor".getType + let typStyle = bindSym"Style".getType + let typTerminalCmd = bindSym"TerminalCmd".getType + result = newCall(theProc) + if first.kind != nnkNilLit: result.add(first) + for arg in children(args[0][1]): + if arg.kind == nnkNilLit: continue + let typ = arg.getType + if typ.kind != nnkEnumTy or + typ != typForegroundColor and + typ != typBackgroundColor and + typ != typStyle and + typ != typTerminalCmd: + result.add(arg) + +macro callStyledEcho(args: varargs[expr]): stmt = + result = newCall(bindSym"styledEcho") + for arg in children(args[0][1]): + result.add(arg) + +template callWritelnHook(args: varargs[string, `$`]) = + var s = "" + for arg in args: + s.add arg + writelnHook s + +template styledMsgWriteln*(args: varargs[expr]) = + if not isNil(writelnHook): + callIgnoringStyle(callWritelnHook, nil, args) + elif optStdout in gGlobalOptions: + if eStdErr in errorOutputs: callIgnoringStyle(writeln, stderr, args) + else: + if eStdOut in errorOutputs: + if optUseColors in gGlobalOptions: + callStyledEcho(args) + else: + callIgnoringStyle(writeln, stdout, args) proc coordToStr(coord: int): string = if coord == -1: result = "???" @@ -728,7 +763,7 @@ proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) = if stackTraceAvailable() and isNil(writelnHook): writeStackTrace() else: - msgWriteln("", fgRed, "No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp " & options.command & " <file>") + styledMsgWriteln(fgRed, "No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp " & options.command & " <file>") quit 1 if msg >= fatalMin and msg <= fatalMax: @@ -750,10 +785,12 @@ proc writeContext(lastinfo: TLineInfo) = var info = lastinfo for i in countup(0, len(msgContext) - 1): if msgContext[i] != lastinfo and msgContext[i] != info: - msgWriteln(PosContextFormat % [toMsgFilename(msgContext[i]), - coordToStr(msgContext[i].line), - coordToStr(msgContext[i].col+1), - getMessageStr(errInstantiationFrom, "")]) + styledMsgWriteln(styleBright, + PosFormat % [toMsgFilename(msgContext[i]), + coordToStr(msgContext[i].line), + coordToStr(msgContext[i].col+1)], + styleDim, + getMessageStr(errInstantiationFrom, "")) info = msgContext[i] proc ignoreMsgBecauseOfIdeTools(msg: TMsgKind): bool = @@ -761,29 +798,36 @@ proc ignoreMsgBecauseOfIdeTools(msg: TMsgKind): bool = proc rawMessage*(msg: TMsgKind, args: openArray[string]) = var - frmt: string + title: string color: ForegroundColor + kind: string case msg of errMin..errMax: writeContext(unknownLineInfo()) - frmt = RawError - color = fgRed + title = ErrorTitle + color = ErrorColor of warnMin..warnMax: if optWarns notin gOptions: return if msg notin gNotes: return writeContext(unknownLineInfo()) - frmt = RawWarning + title = WarningTitle + color = WarningColor + kind = WarningsToStr[ord(msg) - ord(warnMin)] inc(gWarnCounter) - color = fgYellow of hintMin..hintMax: if optHints notin gOptions: return if msg notin gNotes: return - frmt = RawHint + title = HintTitle + color = HintColor + kind = HintsToStr[ord(msg) - ord(hintMin)] inc(gHintCounter) - color = fgGreen let s = `%`(msgKindToString(msg), args) if not ignoreMsgBecauseOfIdeTools(msg): - msgWriteln(s, color, frmt) + if kind != nil: + styledMsgWriteln(color, title, resetStyle, s, + KindColor, `%`(KindFormat, kind)) + else: + styledMsgWriteln(color, title, resetStyle, s) handleError(msg, doAbort, s) proc rawMessage*(msg: TMsgKind, arg: string) = @@ -795,47 +839,56 @@ proc writeSurroundingSrc(info: TLineInfo) = msgWriteln(indent & spaces(info.col) & '^') proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string = - let frmt = case msg - of warnMin..warnMax: PosWarningFormat - of hintMin..hintMax: PosHintFormat - else: PosErrorFormat - result = frmt % [toMsgFilename(info), coordToStr(info.line), - coordToStr(info.col+1), getMessageStr(msg, arg)] + let title = case msg + of warnMin..warnMax: WarningTitle + of hintMin..hintMax: HintTitle + else: ErrorTitle + result = PosFormat % [toMsgFilename(info), coordToStr(info.line), + coordToStr(info.col+1)] & + title & + getMessageStr(msg, arg) proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string, eh: TErrorHandling) = var - frmt: string - ignoreMsg = false + title: string color: ForegroundColor + kind: string + ignoreMsg = false case msg of errMin..errMax: writeContext(info) - frmt = PosErrorFormat + title = ErrorTitle + color = ErrorColor # we try to filter error messages so that not two error message # in the same file and line are produced: #ignoreMsg = lastError == info and eh != doAbort lastError = info - color = fgRed of warnMin..warnMax: ignoreMsg = optWarns notin gOptions or msg notin gNotes if not ignoreMsg: writeContext(info) - frmt = PosWarningFormat + title = WarningTitle + color = WarningColor + kind = WarningsToStr[ord(msg) - ord(warnMin)] inc(gWarnCounter) - color = fgYellow of hintMin..hintMax: ignoreMsg = optHints notin gOptions or msg notin gNotes - frmt = PosHintFormat + title = HintTitle + color = HintColor + kind = HintsToStr[ord(msg) - ord(hintMin)] inc(gHintCounter) - color = fgGreen # NOTE: currently line info line numbers start with 1, # but column numbers start with 0, however most editors expect # first column to be 1, so we need to +1 here - let x = frmt % [toMsgFilename(info), coordToStr(info.line), - coordToStr(info.col+1)] + let x = PosFormat % [toMsgFilename(info), coordToStr(info.line), + coordToStr(info.col+1)] let s = getMessageStr(msg, arg) if not ignoreMsg and not ignoreMsgBecauseOfIdeTools(msg): - msgWriteln(s, color, x) + if kind != nil: + styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s, + KindColor, `%`(KindFormat, kind)) + else: + styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s) if optPrintSurroundingSrc and msg in errMin..errMax: info.writeSurroundingSrc handleError(msg, eh, s) @@ -907,3 +960,6 @@ ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) = of rCannotOpenFile: rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg) +# enable colors by default on terminals +if terminal.isatty(stdout): + incl(gGlobalOptions, optUseColors) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 7ea2c3d6f..f506e3ff5 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -748,6 +748,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = result = isConvertible elif typeRel(c, base(f), a.sons[0]) >= isGeneric: result = isConvertible + of tyString: + if f.kind == tyOpenArray: + if f.sons[0].kind == tyChar: + result = isConvertible + elif f.sons[0].kind == tyGenericParam and typeRel(c, base(f), base(a)) >= isGeneric: + result = isConvertible else: discard of tySequence: case a.kind diff --git a/lib/pure/math.nim b/lib/pure/math.nim index a9e9010f6..b91c7f0d8 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -202,28 +202,52 @@ when not defined(JS): ## computes x to power raised of y. # C procs: - proc srand(seed: cint) {.importc: "srand", header: "<stdlib.h>".} - proc rand(): cint {.importc: "rand", header: "<stdlib.h>".} + when defined(vcc): + # The "secure" random, available from Windows XP + # https://msdn.microsoft.com/en-us/library/sxtz2fa8.aspx + # Present in some variants of MinGW but not enough to justify + # `when defined(windows)` yet + proc rand_s(val: var cuint) {.importc: "rand_s", header: "<stdlib.h>".} + # To behave like the normal version + proc rand(): cuint = rand_s(result) + else: + proc srand(seed: cint) {.importc: "srand", header: "<stdlib.h>".} + proc rand(): cint {.importc: "rand", header: "<stdlib.h>".} when not defined(windows): proc srand48(seed: clong) {.importc: "srand48", header: "<stdlib.h>".} proc drand48(): float {.importc: "drand48", header: "<stdlib.h>".} proc random(max: float): float = result = drand48() * max - when defined(windows): - proc random(max: float): float = - # we are hardcodeing this because - # importcing macros is extremely problematic - # and because the value is publicly documented - # on MSDN and very unlikely to change - const rand_max = 32767 - result = (float(rand()) / float(rand_max)) * max - proc randomize() = - randomize(cast[int](epochTime())) - - proc randomize(seed: int) = - srand(cint(seed)) - when declared(srand48): srand48(seed) + else: + when defined(vcc): # Windows with Visual C + proc random(max: float): float = + # we are hardcoding this because + # importc-ing macros is extremely problematic + # and because the value is publicly documented + # on MSDN and very unlikely to change + # See https://msdn.microsoft.com/en-us/library/296az74e.aspx + const rand_max = 4294967295 # UINT_MAX + result = (float(rand()) / float(rand_max)) * max + proc randomize() = discard + proc randomize(seed: int) = discard + else: # Windows with another compiler + proc random(max: float): float = + # we are hardcoding this because + # importc-ing macros is extremely problematic + # and because the value is publicly documented + # on MSDN and very unlikely to change + const rand_max = 32767 + result = (float(rand()) / float(rand_max)) * max + + when not defined(vcc): # the above code for vcc uses `discard` instead + # this is either not Windows or is Windows without vcc + proc randomize() = + randomize(cast[int](epochTime())) + proc randomize(seed: int) = + srand(cint(seed)) # rand_s doesn't use srand + when declared(srand48): srand48(seed) + proc random(max: int): int = result = int(rand()) mod max diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 15e2eefec..2efdf72d5 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -406,22 +406,43 @@ proc isatty*(f: File): bool = result = isatty(getFileHandle(f)) != 0'i32 -proc styledEchoProcessArg(s: string) = write stdout, s -proc styledEchoProcessArg(style: Style) = setStyle({style}) -proc styledEchoProcessArg(style: set[Style]) = setStyle style -proc styledEchoProcessArg(color: ForegroundColor) = setForegroundColor color -proc styledEchoProcessArg(color: BackgroundColor) = setBackgroundColor color +type + TerminalCmd* = enum ## commands that can be expressed as arguments + resetStyle ## reset attributes + +template styledEchoProcessArg(s: string) = write stdout, s +template styledEchoProcessArg(style: Style) = setStyle({style}) +template styledEchoProcessArg(style: set[Style]) = setStyle style +template styledEchoProcessArg(color: ForegroundColor) = setForegroundColor color +template styledEchoProcessArg(color: BackgroundColor) = setBackgroundColor color +template styledEchoProcessArg(cmd: TerminalCmd) = + when cmd == resetStyle: + resetAttributes() macro styledEcho*(m: varargs[expr]): stmt = ## to be documented. let m = callsite() + var reset = false result = newNimNode(nnkStmtList) for i in countup(1, m.len - 1): - result.add(newCall(bindSym"styledEchoProcessArg", m[i])) + let item = m[i] + case item.kind + of nnkStrLit..nnkTripleStrLit: + if i == m.len - 1: + # optimize if string literal is last, just call writeln + result.add(newCall(bindSym"writeln", bindSym"stdout", item)) + if reset: result.add(newCall(bindSym"resetAttributes")) + return + else: + # if it is string literal just call write, do not enable reset + result.add(newCall(bindSym"write", bindSym"stdout", item)) + else: + result.add(newCall(bindSym"styledEchoProcessArg", item)) + reset = true result.add(newCall(bindSym"write", bindSym"stdout", newStrLitNode("\n"))) - result.add(newCall(bindSym"resetAttributes")) + if reset: result.add(newCall(bindSym"resetAttributes")) when defined(nimdoc): proc getch*(): char = diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index f082023ee..5a9333a0e 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -37,9 +37,7 @@ type var framePtr {.importc, nodecl, volatile.}: PCallFrame - excHandler {.importc, nodecl, volatile.}: PSafePoint = nil - # list of exception handlers - # a global variable for the root of all try blocks + excHandler {.importc, nodecl, volatile.}: int = 0 lastJSError {.importc, nodecl, volatile.}: PJSError = nil {.push stacktrace: off, profiler:off.} @@ -52,9 +50,7 @@ proc nimCharToStr(x: char): string {.compilerproc.} = result[0] = x proc getCurrentExceptionMsg*(): string = - if excHandler != nil and excHandler.exc != nil: - return $excHandler.exc.msg - elif lastJSError != nil: + if lastJSError != nil: return $lastJSError.message else: return "" @@ -99,32 +95,41 @@ proc rawWriteStackTrace(): string = else: result = "No stack traceback available\n" -proc raiseException(e: ref Exception, ename: cstring) {. +proc unhandledException(e: ref Exception) {. compilerproc, asmNoStackFrame.} = - e.name = ename - if excHandler != nil: - excHandler.exc = e + when NimStackTrace: + var buf = rawWriteStackTrace() else: - when NimStackTrace: - var buf = rawWriteStackTrace() - else: - var buf = "" + var buf = "" if e.msg != nil and e.msg[0] != '\0': add(buf, "Error: unhandled exception: ") add(buf, e.msg) else: add(buf, "Error: unhandled exception") add(buf, " [") - add(buf, ename) + add(buf, e.name) add(buf, "]\n") alert(buf) - asm """throw `e`;""" + +proc raiseException(e: ref Exception, ename: cstring) {. + compilerproc, asmNoStackFrame.} = + e.name = ename + when not defined(noUnhandledHandler): + if excHandler == 0: + unhandledException(e) + asm "throw `e`;" proc reraiseException() {.compilerproc, asmNoStackFrame.} = - if excHandler == nil: + if lastJSError == nil: raise newException(ReraiseError, "no exception to reraise") else: - asm """throw excHandler.exc;""" + when not defined(noUnhandledHandler): + if excHandler == 0: + var isNimException : bool + asm "`isNimException` = lastJSError.m_type;" + if isNimException: + unhandledException(cast[ref Exception](lastJSError)) + asm "throw lastJSError;" proc raiseOverflow {.exportc: "raiseOverflow", noreturn.} = raise newException(OverflowError, "over- or underflow") diff --git a/tests/typerel/tstr_as_openarray.nim b/tests/typerel/tstr_as_openarray.nim new file mode 100644 index 000000000..fc28d6c93 --- /dev/null +++ b/tests/typerel/tstr_as_openarray.nim @@ -0,0 +1,22 @@ +discard """ + output: '''success''' +""" +var s = "HI" + +proc x (zz: openarray[char]) = + discard + +x s + +proc z [T] (zz: openarray[T]) = + discard + +z s +z([s,s,s]) + +proc y [T] (arg: var openarray[T]) = + arg[0] = 'X' +y s +doAssert s == "XI" + +echo "success" |