Merge branch 'devel' of github.com:nim-lang/Nim into devel

This commit is contained in:
Araq 2016-07-14 01:11:47 +02:00
commit 928ac1e994
34 changed files with 361 additions and 75 deletions

View file

@ -965,7 +965,6 @@ const
var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things
var var
gMainPackageId*: int gMainPackageId*: int
gMainPackageNotes*: TNoteKinds
proc isCallExpr*(n: PNode): bool = proc isCallExpr*(n: PNode): bool =
result = n.kind in nkCallKinds result = n.kind in nkCallKinds

View file

@ -150,6 +150,9 @@ proc mapType(typ: PType): TCTypeKind =
of tyCString: result = ctCString of tyCString: result = ctCString
of tyInt..tyUInt64: of tyInt..tyUInt64:
result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt)) result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
of tyStatic:
if typ.n != nil: result = mapType(lastSon typ)
else: internalError("mapType")
else: internalError("mapType") else: internalError("mapType")
proc mapReturnType(typ: PType): TCTypeKind = proc mapReturnType(typ: PType): TCTypeKind =
@ -256,6 +259,11 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
of tyInt..tyUInt64: of tyInt..tyUInt64:
result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.kind]) result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.kind])
of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.sons[0]) of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.sons[0])
of tyStatic:
if typ.n != nil: result = getSimpleTypeDesc(m, lastSon typ)
else: internalError("tyStatic for getSimpleTypeDesc")
of tyGenericInst:
result = getSimpleTypeDesc(m, lastSon typ)
else: result = nil else: result = nil
proc pushType(m: BModule, typ: PType) = proc pushType(m: BModule, typ: PType) =
@ -1025,6 +1033,9 @@ proc genTypeInfo(m: BModule, t: PType): Rope =
of tyEmpty, tyVoid: result = rope"0" of tyEmpty, tyVoid: result = rope"0"
of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar: of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar:
genTypeInfoAuxBase(m, t, t, result, rope"0") genTypeInfoAuxBase(m, t, t, result, rope"0")
of tyStatic:
if t.n != nil: result = genTypeInfo(m, lastSon t)
else: internalError("genTypeInfo(" & $t.kind & ')')
of tyProc: of tyProc:
if t.callConv != ccClosure: if t.callConv != ccClosure:
genTypeInfoAuxBase(m, t, t, result, rope"0") genTypeInfoAuxBase(m, t, t, result, rope"0")

View file

@ -181,9 +181,11 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
case whichKeyword(substr(arg, i)) case whichKeyword(substr(arg, i))
of wOn: of wOn:
incl(gNotes, n) incl(gNotes, n)
incl(gMainPackageNotes, n)
incl(enableNotes, n) incl(enableNotes, n)
of wOff: of wOff:
excl(gNotes, n) excl(gNotes, n)
excl(gMainPackageNotes, n)
incl(disableNotes, n) incl(disableNotes, n)
excl(ForeignPackageNotes, n) excl(ForeignPackageNotes, n)
else: localError(info, errOnOrOffExpectedButXFound, arg) else: localError(info, errOnOrOffExpectedButXFound, arg)
@ -548,6 +550,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
gNotes = NotesVerbosity[gVerbosity] gNotes = NotesVerbosity[gVerbosity]
incl(gNotes, enableNotes) incl(gNotes, enableNotes)
excl(gNotes, disableNotes) excl(gNotes, disableNotes)
gMainPackageNotes = gNotes
of "parallelbuild": of "parallelbuild":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
gNumberOfProcessors = parseInt(arg) gNumberOfProcessors = parseInt(arg)

View file

@ -14,7 +14,7 @@
import import
ast, strutils, strtabs, options, msgs, os, ropes, idents, ast, strutils, strtabs, options, msgs, os, ropes, idents,
wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite, wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite,
importer, sempass2, json, xmltree, cgi, typesrenderer importer, sempass2, json, xmltree, cgi, typesrenderer, astalgo
type type
TSections = array[TSymKind, Rope] TSections = array[TSymKind, Rope]
@ -25,9 +25,32 @@ type
indexValFilename: string indexValFilename: string
analytics: string # Google Analytics javascript, "" if doesn't exist analytics: string # Google Analytics javascript, "" if doesn't exist
seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML. seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML.
jArray: JsonNode
types: TStrTable
PDoc* = ref TDocumentor ## Alias to type less. PDoc* = ref TDocumentor ## Alias to type less.
proc whichType(d: PDoc; n: PNode): PSym =
if n.kind == nkSym:
if d.types.strTableContains(n.sym):
result = n.sym
else:
for i in 0..<safeLen(n):
let x = whichType(d, n[i])
if x != nil: return x
proc attachToType(d: PDoc; p: PSym): PSym =
let params = p.ast.sons[paramsPos]
# first check the first parameter, then the return type,
# then the other parameter:
template check(i) =
result = whichType(d, params[i])
if result != nil: return result
if params.len > 1: check(1)
if params.len > 0: check(0)
for i in 2..<params.len: check(i)
proc compilerMsgHandler(filename: string, line, col: int, proc compilerMsgHandler(filename: string, line, col: int,
msgKind: rst.MsgKind, arg: string) {.procvar.} = msgKind: rst.MsgKind, arg: string) {.procvar.} =
# translate msg kind: # translate msg kind:
@ -81,6 +104,8 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
result.seenSymbols = newStringTable(modeCaseInsensitive) result.seenSymbols = newStringTable(modeCaseInsensitive)
result.id = 100 result.id = 100
result.jArray = newJArray()
initStrTable result.types
proc dispA(dest: var Rope, xml, tex: string, args: openArray[Rope]) = proc dispA(dest: var Rope, xml, tex: string, args: openArray[Rope]) =
if gCmd != cmdRst2tex: addf(dest, xml, args) if gCmd != cmdRst2tex: addf(dest, xml, args)
@ -226,10 +251,27 @@ proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
result = esc(d.target, "`") result = esc(d.target, "`")
for i in 0.. <n.len: result.add(getName(d, n[i], splitAfter)) for i in 0.. <n.len: result.add(getName(d, n[i], splitAfter))
result.add esc(d.target, "`") result.add esc(d.target, "`")
of nkOpenSymChoice, nkClosedSymChoice:
result = getName(d, n[0], splitAfter)
else: else:
internalError(n.info, "getName()") internalError(n.info, "getName()")
result = "" result = ""
proc getNameIdent(n: PNode): PIdent =
case n.kind
of nkPostfix: result = getNameIdent(n.sons[1])
of nkPragmaExpr: result = getNameIdent(n.sons[0])
of nkSym: result = n.sym.name
of nkIdent: result = n.ident
of nkAccQuoted:
var r = ""
for i in 0.. <n.len: r.add(getNameIdent(n[i]).s)
result = getIdent(r)
of nkOpenSymChoice, nkClosedSymChoice:
result = getNameIdent(n[0])
else:
result = nil
proc getRstName(n: PNode): PRstNode = proc getRstName(n: PNode): PRstNode =
case n.kind case n.kind
of nkPostfix: result = getRstName(n.sons[1]) of nkPostfix: result = getRstName(n.sons[1])
@ -239,6 +281,8 @@ proc getRstName(n: PNode): PRstNode =
of nkAccQuoted: of nkAccQuoted:
result = getRstName(n.sons[0]) result = getRstName(n.sons[0])
for i in 1 .. <n.len: result.text.add(getRstName(n[i]).text) for i in 1 .. <n.len: result.text.add(getRstName(n[i]).text)
of nkOpenSymChoice, nkClosedSymChoice:
result = getRstName(n[0])
else: else:
internalError(n.info, "getRstName()") internalError(n.info, "getRstName()")
result = nil result = nil
@ -395,6 +439,12 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr: tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr:
dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}", dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
[rope(esc(d.target, literal))]) [rope(esc(d.target, literal))])
if k in routineKinds and nameNode.kind == nkSym:
let att = attachToType(d, nameNode.sym)
if att != nil:
dispA(result, """<span class="attachedType" style="visibility:hidden">$1</span>""", "",
[rope esc(d.target, att.name.s)])
inc(d.id) inc(d.id)
let let
plainNameRope = rope(xmltree.escape(plainName.strip)) plainNameRope = rope(xmltree.escape(plainName.strip))
@ -438,8 +488,10 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
setIndexTerm(d[], symbolOrId, name, linkTitle, setIndexTerm(d[], symbolOrId, name, linkTitle,
xmltree.escape(plainDocstring.docstringSummary)) xmltree.escape(plainDocstring.docstringSummary))
if k == skType and nameNode.kind == nkSym:
d.types.strTableAdd nameNode.sym
proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode = proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
if not isVisible(nameNode): return if not isVisible(nameNode): return
var var
name = getName(d, nameNode) name = getName(d, nameNode)
@ -499,46 +551,44 @@ proc generateDoc*(d: PDoc, n: PNode) =
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0]) of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0])
else: discard else: discard
proc generateJson(d: PDoc, n: PNode, jArray: JsonNode = nil): JsonNode = proc add(d: PDoc; j: JsonNode) =
if j != nil: d.jArray.add j
proc generateJson*(d: PDoc, n: PNode) =
case n.kind case n.kind
of nkCommentStmt: of nkCommentStmt:
if n.comment != nil and startsWith(n.comment, "##"): if n.comment != nil and startsWith(n.comment, "##"):
let stripped = n.comment.substr(2).strip let stripped = n.comment.substr(2).strip
result = %{ "comment": %stripped } d.add %{ "comment": %stripped }
of nkProcDef: of nkProcDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(n)
result = genJSONItem(d, n, n.sons[namePos], skProc) d.add genJsonItem(d, n, n.sons[namePos], skProc)
of nkMethodDef: of nkMethodDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(n)
result = genJSONItem(d, n, n.sons[namePos], skMethod) d.add genJsonItem(d, n, n.sons[namePos], skMethod)
of nkIteratorDef: of nkIteratorDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(n)
result = genJSONItem(d, n, n.sons[namePos], skIterator) d.add genJsonItem(d, n, n.sons[namePos], skIterator)
of nkMacroDef: of nkMacroDef:
result = genJSONItem(d, n, n.sons[namePos], skMacro) d.add genJsonItem(d, n, n.sons[namePos], skMacro)
of nkTemplateDef: of nkTemplateDef:
result = genJSONItem(d, n, n.sons[namePos], skTemplate) d.add genJsonItem(d, n, n.sons[namePos], skTemplate)
of nkConverterDef: of nkConverterDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(n)
result = genJSONItem(d, n, n.sons[namePos], skConverter) d.add genJsonItem(d, n, n.sons[namePos], skConverter)
of nkTypeSection, nkVarSection, nkLetSection, nkConstSection: of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if n.sons[i].kind != nkCommentStmt: if n.sons[i].kind != nkCommentStmt:
# order is always 'type var let const': # order is always 'type var let const':
result = genJSONItem(d, n.sons[i], n.sons[i].sons[0], d.add genJsonItem(d, n.sons[i], n.sons[i].sons[0],
succ(skType, ord(n.kind)-ord(nkTypeSection))) succ(skType, ord(n.kind)-ord(nkTypeSection)))
of nkStmtList: of nkStmtList:
result = if jArray != nil: jArray else: newJArray()
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var r = generateJson(d, n.sons[i], result) generateJson(d, n.sons[i])
if r != nil:
result.add(r)
of nkWhenStmt: of nkWhenStmt:
# generate documentation for the first branch only: # generate documentation for the first branch only:
if not checkForFalse(n.sons[0].sons[0]) and jArray != nil: if not checkForFalse(n.sons[0].sons[0]):
discard generateJson(d, lastSon(n.sons[0]), jArray) generateJson(d, lastSon(n.sons[0]))
else: discard else: discard
proc genSection(d: PDoc, kind: TSymKind) = proc genSection(d: PDoc, kind: TSymKind) =
@ -607,6 +657,19 @@ proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
else: else:
writeRope(content, getOutFile(filename, outExt), useWarning) writeRope(content, getOutFile(filename, outExt), useWarning)
proc writeOutputJson*(d: PDoc, filename, outExt: string,
useWarning = false) =
let content = $d.jArray
if optStdout in gGlobalOptions:
write(stdout, content)
else:
var f: File
if open(f, getOutFile(filename, outExt), fmWrite):
write(f, content)
close(f)
else:
discard "fixme: error report"
proc commandDoc*() = proc commandDoc*() =
var ast = parseFile(gProjectMainIdx) var ast = parseFile(gProjectMainIdx)
if ast == nil: return if ast == nil: return
@ -636,13 +699,14 @@ proc commandRst2TeX*() =
splitter = "\\-" splitter = "\\-"
commandRstAux(gProjectFull, TexExt) commandRstAux(gProjectFull, TexExt)
proc commandJSON*() = proc commandJson*() =
var ast = parseFile(gProjectMainIdx) var ast = parseFile(gProjectMainIdx)
if ast == nil: return if ast == nil: return
var d = newDocumentor(gProjectFull, options.gConfigVars) var d = newDocumentor(gProjectFull, options.gConfigVars)
d.hasToc = true d.hasToc = true
var json = generateJson(d, ast) generateJson(d, ast)
var content = rope(pretty(json)) let json = d.jArray
let content = rope(pretty(json))
if optStdout in gGlobalOptions: if optStdout in gGlobalOptions:
writeRope(stdout, content) writeRope(stdout, content)

View file

@ -29,11 +29,26 @@ proc close(p: PPassContext, n: PNode): PNode =
except IOError: except IOError:
discard discard
proc closeJson(p: PPassContext, n: PNode): PNode =
var g = PGen(p)
let useWarning = sfMainModule notin g.module.flags
if gWholeProject or sfMainModule in g.module.flags:
writeOutputJson(g.doc, g.module.filename, ".json", useWarning)
try:
generateIndex(g.doc)
except IOError:
discard
proc processNode(c: PPassContext, n: PNode): PNode = proc processNode(c: PPassContext, n: PNode): PNode =
result = n result = n
var g = PGen(c) var g = PGen(c)
generateDoc(g.doc, n) generateDoc(g.doc, n)
proc processNodeJson(c: PPassContext, n: PNode): PNode =
result = n
var g = PGen(c)
generateJson(g.doc, n)
proc myOpen(module: PSym): PPassContext = proc myOpen(module: PSym): PPassContext =
var g: PGen var g: PGen
new(g) new(g)
@ -44,6 +59,8 @@ proc myOpen(module: PSym): PPassContext =
result = g result = g
const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close) const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close)
const docgen2JsonPass* = makePass(open = myOpen, process = processNodeJson,
close = closeJson)
proc finishDoc2Pass*(project: string) = proc finishDoc2Pass*(project: string) =
discard discard

View file

@ -754,7 +754,7 @@ proc callCCompiler*(projectfile: string) =
"lib", quoteShell(libpath)]) "lib", quoteShell(libpath)])
if optCompileOnly notin gGlobalOptions: if optCompileOnly notin gGlobalOptions:
execExternalProgram(linkCmd, execExternalProgram(linkCmd,
if gVerbosity > 1: hintExecuting else: hintLinking) if optListCmd in gGlobalOptions or gVerbosity > 1: hintExecuting else: hintLinking)
else: else:
linkCmd = "" linkCmd = ""
if optGenScript in gGlobalOptions: if optGenScript in gGlobalOptions:

View file

@ -48,6 +48,7 @@ type
etyNull, # null type etyNull, # null type
etyProc, # proc type etyProc, # proc type
etyBool, # bool type etyBool, # bool type
etySeq, # Nim seq or string type
etyInt, # JavaScript's int etyInt, # JavaScript's int
etyFloat, # JavaScript's float etyFloat, # JavaScript's float
etyString, # JavaScript's string etyString, # JavaScript's string
@ -156,15 +157,18 @@ proc mapType(typ: PType): TJSTypeKind =
of tyBool: result = etyBool of tyBool: result = etyBool
of tyFloat..tyFloat128: result = etyFloat of tyFloat..tyFloat128: result = etyFloat
of tySet: result = etyObject # map a set to a table of tySet: result = etyObject # map a set to a table
of tyString, tySequence: result = etyInt # little hack to get right semantics of tyString, tySequence: result = etySeq
of tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, tyBigNum, of tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, tyBigNum,
tyVarargs: tyVarargs:
result = etyObject result = etyObject
of tyNil: result = etyNull of tyNil: result = etyNull
of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvocation, of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvocation,
tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor, tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor,
tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses, tyVoid: tyExpr, tyStmt, tyTypeDesc, tyTypeClasses, tyVoid:
result = etyNone result = etyNone
of tyStatic:
if t.n != nil: result = mapType(lastSon t)
else: result = etyNone
of tyProc: result = etyProc of tyProc: result = etyProc
of tyCString: result = etyString of tyCString: result = etyString
@ -817,7 +821,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
addf(p.body, "$#[$#] = chr($#);$n", [a.rdLoc, b.rdLoc, c.rdLoc]) addf(p.body, "$#[$#] = chr($#);$n", [a.rdLoc, b.rdLoc, c.rdLoc])
return return
let xtyp = mapType(p, x.typ) var xtyp = mapType(p, x.typ)
if x.kind == nkHiddenDeref and x.sons[0].kind == nkCall and xtyp != etyObject: if x.kind == nkHiddenDeref and x.sons[0].kind == nkCall and xtyp != etyObject:
gen(p, x.sons[0], a) gen(p, x.sons[0], a)
@ -829,7 +833,18 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
gen(p, y, b) gen(p, y, b)
# we don't care if it's an etyBaseIndex (global) of a string, it's
# still a string that needs to be copied properly:
if x.typ.skipTypes(abstractInst).kind in {tySequence, tyString}:
xtyp = etySeq
case xtyp case xtyp
of etySeq:
if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
else:
useMagic(p, "nimCopy")
addf(p.body, "$1 = nimCopy(null, $2, $3);$n",
[a.rdLoc, b.res, genTypeInfo(p, y.typ)])
of etyObject: of etyObject:
if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
@ -1049,6 +1064,8 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
else: internalError(n.sons[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')') else: internalError(n.sons[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
of nkObjDownConv: of nkObjDownConv:
gen(p, n.sons[0], r) gen(p, n.sons[0], r)
of nkHiddenDeref:
gen(p, n.sons[0].sons[0], r)
else: internalError(n.sons[0].info, "genAddr: " & $n.sons[0].kind) else: internalError(n.sons[0].info, "genAddr: " & $n.sons[0].kind)
proc thisParam(p: PProc; typ: PType): PType = proc thisParam(p: PProc; typ: PType): PType =
@ -1221,6 +1238,7 @@ proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType;
r: var TCompRes) = r: var TCompRes) =
var i = 0 var i = 0
var j = 1 var j = 1
r.kind = resExpr
while i < pat.len: while i < pat.len:
case pat[i] case pat[i]
of '@': of '@':
@ -1234,10 +1252,18 @@ proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType;
genOtherArg(p, n, j, typ, generated, r) genOtherArg(p, n, j, typ, generated, r)
inc j inc j
inc i inc i
of '\31':
# unit separator
add(r.res, "#")
inc i
of '\29':
# group separator
add(r.res, "@")
inc i
else: else:
let start = i let start = i
while i < pat.len: while i < pat.len:
if pat[i] notin {'@', '#'}: inc(i) if pat[i] notin {'@', '#', '\31', '\29'}: inc(i)
else: break else: break
if i - 1 >= start: if i - 1 >= start:
add(r.res, substr(pat, start, i - 1)) add(r.res, substr(pat, start, i - 1))
@ -1404,6 +1430,12 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
result = putToSeq("null", indirect) result = putToSeq("null", indirect)
of tySequence, tyString, tyCString, tyPointer, tyProc: of tySequence, tyString, tyCString, tyPointer, tyProc:
result = putToSeq("null", indirect) result = putToSeq("null", indirect)
of tyStatic:
if t.n != nil:
result = createVar(p, lastSon t, indirect)
else:
internalError("createVar: " & $t.kind)
result = nil
else: else:
internalError("createVar: " & $t.kind) internalError("createVar: " & $t.kind)
result = nil result = nil
@ -1419,7 +1451,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
discard mangleName(v, p.target) discard mangleName(v, p.target)
gen(p, n, a) gen(p, n, a)
case mapType(p, v.typ) case mapType(p, v.typ)
of etyObject: of etyObject, etySeq:
if needsNoCopy(p, n): if needsNoCopy(p, n):
s = a.res s = a.res
else: else:

View file

@ -165,4 +165,7 @@ proc genTypeInfo(p: PProc, typ: PType): Rope =
of tyEnum: genEnumInfo(p, t, result) of tyEnum: genEnumInfo(p, t, result)
of tyObject: genObjectInfo(p, t, result) of tyObject: genObjectInfo(p, t, result)
of tyTuple: genTupleInfo(p, t, result) of tyTuple: genTupleInfo(p, t, result)
of tyStatic:
if t.n != nil: result = genTypeInfo(p, lastSon t)
else: internalError("genTypeInfo(" & $t.kind & ')')
else: internalError("genTypeInfo(" & $t.kind & ')') else: internalError("genTypeInfo(" & $t.kind & ')')

View file

@ -735,7 +735,8 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
if c == '\226' and if c == '\226' and
buf[pos+1] == '\128' and buf[pos+1] == '\128' and
buf[pos+2] == '\147': # It's a 'magic separator' en-dash Unicode buf[pos+2] == '\147': # It's a 'magic separator' en-dash Unicode
if buf[pos + magicIdentSeparatorRuneByteWidth] notin SymChars: if buf[pos + magicIdentSeparatorRuneByteWidth] notin SymChars or
isMagicIdentSeparatorRune(buf, pos+magicIdentSeparatorRuneByteWidth) or pos == L.bufpos:
lexMessage(L, errInvalidToken, "–") lexMessage(L, errInvalidToken, "–")
break break
inc(pos, magicIdentSeparatorRuneByteWidth) inc(pos, magicIdentSeparatorRuneByteWidth)
@ -747,7 +748,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
h = h !& ord(c) h = h !& ord(c)
inc(pos) inc(pos)
of '_': of '_':
if buf[pos+1] notin SymChars: if buf[pos+1] notin SymChars or isMagicIdentSeparatorRune(buf, pos+1):
lexMessage(L, errInvalidToken, "_") lexMessage(L, errInvalidToken, "_")
break break
inc(pos) inc(pos)
@ -1056,7 +1057,8 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
inc(L.bufpos) inc(L.bufpos)
of '_': of '_':
inc(L.bufpos) inc(L.bufpos)
if L.buf[L.bufpos] notin SymChars: if L.buf[L.bufpos] notin SymChars+{'_'} and not
isMagicIdentSeparatorRune(L.buf, L.bufpos):
tok.tokType = tkSymbol tok.tokType = tkSymbol
tok.ident = getIdent("_") tok.ident = getIdent("_")
else: else:
@ -1077,6 +1079,9 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
tok.tokType = tkCharLit tok.tokType = tkCharLit
of '0'..'9': of '0'..'9':
getNumber(L, tok) getNumber(L, tok)
let c = L.buf[L.bufpos]
if c in SymChars+{'_'}:
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
else: else:
if c in OpChars: if c in OpChars:
getOperator(L, tok) getOperator(L, tok)

View file

@ -46,10 +46,11 @@ proc commandCheck =
rodPass() rodPass()
compileProject() compileProject()
proc commandDoc2 = proc commandDoc2(json: bool) =
msgs.gErrorMax = high(int) # do not stop after first error msgs.gErrorMax = high(int) # do not stop after first error
semanticPasses() semanticPasses()
registerPass(docgen2Pass) if json: registerPass(docgen2JsonPass)
else: registerPass(docgen2Pass)
#registerPass(cleanupPass()) #registerPass(cleanupPass())
compileProject() compileProject()
finishDoc2Pass(gProjectName) finishDoc2Pass(gProjectName)
@ -281,7 +282,7 @@ proc mainCommand* =
gCmd = cmdDoc gCmd = cmdDoc
loadConfigs(DocConfig) loadConfigs(DocConfig)
defineSymbol("nimdoc") defineSymbol("nimdoc")
commandDoc2() commandDoc2(false)
of "rst2html": of "rst2html":
gCmd = cmdRst2html gCmd = cmdRst2html
loadConfigs(DocConfig) loadConfigs(DocConfig)
@ -296,7 +297,13 @@ proc mainCommand* =
loadConfigs(DocConfig) loadConfigs(DocConfig)
wantMainModule() wantMainModule()
defineSymbol("nimdoc") defineSymbol("nimdoc")
commandJSON() commandJson()
of "jsondoc2":
gCmd = cmdDoc
loadConfigs(DocConfig)
wantMainModule()
defineSymbol("nimdoc")
commandDoc2(true)
of "buildindex": of "buildindex":
gCmd = cmdDoc gCmd = cmdDoc
loadConfigs(DocConfig) loadConfigs(DocConfig)

View file

@ -105,12 +105,13 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile =
resetModule(fileIdx) resetModule(fileIdx)
return Yes return Yes
if gMemCacheData[fileIdx].needsRecompile != Maybe: # cycle detection: We claim that a cycle does no harm.
return gMemCacheData[fileIdx].needsRecompile if gMemCacheData[fileIdx].needsRecompile == Probing:
return No
#return gMemCacheData[fileIdx].needsRecompile
if optForceFullMake in gGlobalOptions or if optForceFullMake in gGlobalOptions or hashChanged(fileIdx):
hashChanged(fileIdx): markDirty()
markDirty
if gMemCacheData[fileIdx].deps != nil: if gMemCacheData[fileIdx].deps != nil:
gMemCacheData[fileIdx].needsRecompile = Probing gMemCacheData[fileIdx].needsRecompile = Probing
@ -118,7 +119,7 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile =
let d = checkDepMem(dep) let d = checkDepMem(dep)
if d in {Yes, Recompiled}: if d in {Yes, Recompiled}:
# echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d # echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d
markDirty markDirty()
gMemCacheData[fileIdx].needsRecompile = No gMemCacheData[fileIdx].needsRecompile = No
return No return No

View file

@ -518,7 +518,6 @@ const
warnGcUnsafe, warnGcUnsafe,
hintPath, hintPath,
hintDependency, hintDependency,
hintExecuting,
hintCodeBegin, hintCodeEnd, hintCodeBegin, hintCodeEnd,
hintSource, hintStackTrace, hintSource, hintStackTrace,
hintGCStats}, hintGCStats},
@ -530,7 +529,7 @@ const
var var
ForeignPackageNotes*: TNoteKinds = {hintProcessing, warnUnknownMagic, ForeignPackageNotes*: TNoteKinds = {hintProcessing, warnUnknownMagic,
hintQuitCalled} hintQuitCalled, hintExecuting}
filenameToIndexTbl = initTable[string, int32]() filenameToIndexTbl = initTable[string, int32]()
fileInfos*: seq[TFileInfo] = @[] fileInfos*: seq[TFileInfo] = @[]
systemFileIdx*: int32 systemFileIdx*: int32
@ -621,6 +620,7 @@ var
gHintCounter*: int = 0 gHintCounter*: int = 0
gWarnCounter*: int = 0 gWarnCounter*: int = 0
gErrorMax*: int = 1 # stop after gErrorMax errors gErrorMax*: int = 1 # stop after gErrorMax errors
gMainPackageNotes*: TNoteKinds = NotesVerbosity[1]
proc unknownLineInfo*(): TLineInfo = proc unknownLineInfo*(): TLineInfo =
result.line = int16(-1) result.line = int16(-1)

View file

@ -151,6 +151,7 @@ const
var var
gConfigVars* = newStringTable(modeStyleInsensitive) gConfigVars* = newStringTable(modeStyleInsensitive)
gDllOverrides = newStringTable(modeCaseInsensitive) gDllOverrides = newStringTable(modeCaseInsensitive)
gModuleOverrides* = newStringTable(modeStyleInsensitive)
gPrefixDir* = "" # Overrides the default prefix dir in getPrefixDir proc. gPrefixDir* = "" # Overrides the default prefix dir in getPrefixDir proc.
libpath* = "" libpath* = ""
gProjectName* = "" # holds a name like 'nim' gProjectName* = "" # holds a name like 'nim'
@ -374,6 +375,13 @@ proc rawFindFile2(f: string): string =
it = PStrEntry(it.next) it = PStrEntry(it.next)
result = "" result = ""
template patchModule() {.dirty.} =
if result.len > 0 and gModuleOverrides.len > 0:
let key = getPackageName(result) & "_" & splitFile(result).name
if gModuleOverrides.hasKey(key):
let ov = gModuleOverrides[key]
if ov.len > 0: result = ov
proc findFile*(f: string): string {.procvar.} = proc findFile*(f: string): string {.procvar.} =
if f.isAbsolute: if f.isAbsolute:
result = if f.existsFile: f else: "" result = if f.existsFile: f else: ""
@ -385,6 +393,7 @@ proc findFile*(f: string): string {.procvar.} =
result = f.rawFindFile2 result = f.rawFindFile2
if result.len == 0: if result.len == 0:
result = f.toLower.rawFindFile2 result = f.toLower.rawFindFile2
patchModule()
proc findModule*(modulename, currentModule: string): string = proc findModule*(modulename, currentModule: string): string =
# returns path to module # returns path to module
@ -403,6 +412,7 @@ proc findModule*(modulename, currentModule: string): string =
result = currentPath / m result = currentPath / m
if not existsFile(result): if not existsFile(result):
result = findFile(m) result = findFile(m)
patchModule()
proc libCandidates*(s: string, dest: var seq[string]) = proc libCandidates*(s: string, dest: var seq[string]) =
var le = strutils.find(s, '(') var le = strutils.find(s, '(')

View file

@ -13,7 +13,7 @@
import import
ast, modules, passes, passaux, condsyms, ast, modules, passes, passaux, condsyms,
options, nimconf, lists, sem, semdata, llstream, vm, vmdef, commands, msgs, options, nimconf, lists, sem, semdata, llstream, vm, vmdef, commands, msgs,
os, times, osproc, wordrecg os, times, osproc, wordrecg, strtabs
# we support 'cmpIgnoreStyle' natively for efficiency: # we support 'cmpIgnoreStyle' natively for efficiency:
from strutils import cmpIgnoreStyle from strutils import cmpIgnoreStyle
@ -122,6 +122,12 @@ proc setupVM*(module: PSym; scriptName: string): PEvalContext =
cbconf warningImpl: cbconf warningImpl:
processSpecificNote(a.getString 0, wWarning, passPP, unknownLineInfo(), processSpecificNote(a.getString 0, wWarning, passPP, unknownLineInfo(),
a.getString 1) a.getString 1)
cbconf patchFile:
let key = a.getString(0) & "_" & a.getString(1)
var val = a.getString(2).addFileExt(NimExt)
if not isAbsolute(val):
val = vthisDir / val
gModuleOverrides[key] = val
proc runNimScript*(scriptName: string; freshDefines=true) = proc runNimScript*(scriptName: string; freshDefines=true) =
passes.gIncludeFile = includeModule passes.gIncludeFile = includeModule

View file

@ -1065,8 +1065,11 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
result.typ = makeTypeDesc(c, s.typ) result.typ = makeTypeDesc(c, s.typ)
of skField: of skField:
if c.p != nil and c.p.selfSym != nil: var p = c.p
var ty = skipTypes(c.p.selfSym.typ, {tyGenericInst, tyVar, tyPtr, tyRef}) while p != nil and p.selfSym == nil:
p = p.next
if p != nil and p.selfSym != nil:
var ty = skipTypes(p.selfSym.typ, {tyGenericInst, tyVar, tyPtr, tyRef})
while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct}) while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct})
var check: PNode = nil var check: PNode = nil
if ty.kind == tyObject: if ty.kind == tyObject:
@ -1079,7 +1082,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
markUsed(n.info, f) markUsed(n.info, f)
styleCheckUse(n.info, f) styleCheckUse(n.info, f)
result = newNodeIT(nkDotExpr, n.info, f.typ) result = newNodeIT(nkDotExpr, n.info, f.typ)
result.add makeDeref(newSymNode(c.p.selfSym)) result.add makeDeref(newSymNode(p.selfSym))
result.add newSymNode(f) # we now have the correct field result.add newSymNode(f) # we now have the correct field
if check != nil: if check != nil:
check.sons[0] = result check.sons[0] = result

View file

@ -411,6 +411,13 @@ proc semUsing(c: PContext; n: PNode): PNode =
if a.sons[length-1].kind != nkEmpty: if a.sons[length-1].kind != nkEmpty:
localError(a.info, "'using' sections cannot contain assignments") localError(a.info, "'using' sections cannot contain assignments")
proc hasEmpty(typ: PType): bool =
if typ.kind in {tySequence, tyArray, tySet}:
result = typ.lastSon.kind == tyEmpty
elif typ.kind == tyTuple:
for s in typ.sons:
result = result or hasEmpty(s)
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
var b: PNode var b: PNode
result = copyNode(n) result = copyNode(n)
@ -445,8 +452,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
#changeType(def.skipConv, typ, check=true) #changeType(def.skipConv, typ, check=true)
else: else:
typ = skipIntLit(def.typ) typ = skipIntLit(def.typ)
if typ.kind in {tySequence, tyArray, tySet} and if hasEmpty(typ):
typ.lastSon.kind == tyEmpty:
localError(def.info, errCannotInferTypeOfTheLiteral, localError(def.info, errCannotInferTypeOfTheLiteral,
($typ.kind).substr(2).toLower) ($typ.kind).substr(2).toLower)
else: else:

View file

@ -1746,8 +1746,8 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
if formal.ast == nil: if formal.ast == nil:
if formal.typ.kind == tyVarargs: if formal.typ.kind == tyVarargs:
var container = newNodeIT(nkBracket, n.info, arrayConstr(c, n.info)) var container = newNodeIT(nkBracket, n.info, arrayConstr(c, n.info))
addSon(m.call, implicitConv(nkHiddenStdConv, formal.typ, setSon(m.call, formal.position + 1,
container, m, c)) implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
else: else:
# no default value # no default value
m.state = csNoMatch m.state = csNoMatch

View file

@ -541,7 +541,9 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
else: else:
result.add typeToString(t.sons[0]) result.add typeToString(t.sons[0])
of tyRange: of tyRange:
result = "range " & rangeToStr(t.n) result = "range "
if t.n != nil and t.n.kind == nkRange:
result.add rangeToStr(t.n)
if prefer != preferExported: if prefer != preferExported:
result.add("(" & typeToString(t.sons[0]) & ")") result.add("(" & typeToString(t.sons[0]) & ")")
of tyProc: of tyProc:
@ -1315,6 +1317,9 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
of tyTypeDesc: of tyTypeDesc:
result = computeSizeAux(typ.base, a) result = computeSizeAux(typ.base, a)
of tyForward: return szIllegalRecursion of tyForward: return szIllegalRecursion
of tyStatic:
if typ.n != nil: result = computeSizeAux(lastSon(typ), a)
else: result = szUnknownSize
else: else:
#internalError("computeSizeAux()") #internalError("computeSizeAux()")
result = szUnknownSize result = szUnknownSize

View file

@ -1686,10 +1686,10 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
of skType: of skType:
genTypeLit(c, s.typ, dest) genTypeLit(c, s.typ, dest)
of skGenericParam: of skGenericParam:
if c.prc.sym.kind == skMacro: if c.prc.sym != nil and c.prc.sym.kind == skMacro:
genRdVar(c, n, dest, flags) genRdVar(c, n, dest, flags)
else: else:
internalError(n.info, "cannot generate code for: " & s.name.s) globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
else: else:
globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s) globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
of nkCallKinds: of nkCallKinds:

View file

@ -23,10 +23,6 @@ arm.linux.gcc.linkerexe = "arm-linux-gcc"
mips.linux.gcc.exe = "mips-openwrt-linux-gcc" mips.linux.gcc.exe = "mips-openwrt-linux-gcc"
mips.linux.gcc.linkerexe = "mips-openwrt-linux-gcc" mips.linux.gcc.linkerexe = "mips-openwrt-linux-gcc"
@if not nimfix:
cs:partial
@end
path="$lib/deprecated/core" path="$lib/deprecated/core"
path="$lib/deprecated/pure" path="$lib/deprecated/pure"
path="$lib/pure/collections" path="$lib/pure/collections"
@ -168,10 +164,5 @@ vcc.options.always = "/nologo"
vcc.options.speed = "/O2 /arch:SSE2" vcc.options.speed = "/O2 /arch:SSE2"
vcc.options.size = "/O1" vcc.options.size = "/O1"
# Configuration for the Digital Mars C/C++ compiler:
@if windows:
dmc.path = r"$nimrod\dist\dm\bin"
@end
# Configuration for the Tiny C Compiler: # Configuration for the Tiny C Compiler:
tcc.options.always = "-w" tcc.options.always = "-w"

View file

@ -6,6 +6,7 @@ Advanced commands:
//rst2html convert a reStructuredText file to HTML //rst2html convert a reStructuredText file to HTML
//rst2tex convert a reStructuredText file to TeX //rst2tex convert a reStructuredText file to TeX
//jsondoc extract the documentation to a json file //jsondoc extract the documentation to a json file
//jsondoc2 extract documentation to a json file (uses doc2)
//buildIndex build an index for the whole documentation //buildIndex build an index for the whole documentation
//run run the project (with Tiny C backend; buggy!) //run run the project (with Tiny C backend; buggy!)
//genDepend generate a DOT file containing the //genDepend generate a DOT file containing the

View file

@ -152,11 +152,13 @@ proc add*[T](q: var Queue[T], item: T) =
q.data[q.wr] = item q.data[q.wr] = item
q.wr = (q.wr + 1) and q.mask q.wr = (q.wr + 1) and q.mask
proc default[T](t: typedesc[T]): T {.inline.} = discard
proc pop*[T](q: var Queue[T]): T {.inline, discardable.} = proc pop*[T](q: var Queue[T]): T {.inline, discardable.} =
## Remove and returns the first (oldest) element of the queue `q`. ## Remove and returns the first (oldest) element of the queue `q`.
emptyCheck(q) emptyCheck(q)
dec q.count dec q.count
result = q.data[q.rd] result = q.data[q.rd]
q.data[q.rd] = default(type(result))
q.rd = (q.rd + 1) and q.mask q.rd = (q.rd + 1) and q.mask
proc enqueue*[T](q: var Queue[T], item: T) = proc enqueue*[T](q: var Queue[T], item: T) =

View file

@ -16,6 +16,39 @@
## semantics, this means that ``=`` performs a copy of the hash table. ## semantics, this means that ``=`` performs a copy of the hash table.
## For **reference** semantics use the ``Ref`` variant: ``TableRef``, ## For **reference** semantics use the ``Ref`` variant: ``TableRef``,
## ``OrderedTableRef``, ``CountTableRef``. ## ``OrderedTableRef``, ``CountTableRef``.
## To give an example, when `a` is a Table, then `var b = a` gives `b`
## as a new independent table. b is initialised with the contents of `a`.
## Changing `b` does not affect `a` and vice versa:
##
## .. code-block::
## import tables
##
## var
## a = {1: "one", 2: "two"}.toTable # creates a Table
## b = a
##
## echo a, b # output: {1: one, 2: two}{1: one, 2: two}
##
## b[3] = "three"
## echo a, b # output: {1: one, 2: two}{1: one, 2: two, 3: three}
## echo a == b # output: false
##
## On the other hand, when `a` is a TableRef instead, then changes to `b` also affect `a`.
## Both `a` and `b` reference the same data structure:
##
## .. code-block::
## import tables
##
## var
## a = {1: "one", 2: "two"}.newTable # creates a TableRef
## b = a
##
## echo a, b # output: {1: one, 2: two}{1: one, 2: two}
##
## b[3] = "three"
## echo a, b # output: {1: one, 2: two, 3: three}{1: one, 2: two, 3: three}
## echo a == b # output: true
##
## ##
## If you are using simple standard types like ``int`` or ``string`` for the ## If you are using simple standard types like ``int`` or ``string`` for the
## keys of the table you won't have any problems, but as soon as you try to use ## keys of the table you won't have any problems, but as soon as you try to use

View file

@ -1127,7 +1127,7 @@ proc parseJson(p: var JsonParser): JsonNode =
discard getTok(p) discard getTok(p)
while p.tok != tkCurlyRi: while p.tok != tkCurlyRi:
if p.tok != tkString: if p.tok != tkString:
raiseParseErr(p, "string literal as key expected") raiseParseErr(p, "string literal as key")
var key = p.a var key = p.a
discard getTok(p) discard getTok(p)
eat(p, tkColon) eat(p, tkColon)

View file

@ -452,10 +452,13 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2") gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
# now it is buffered in the ZCT # now it is buffered in the ZCT
res.typ = typ res.typ = typ
when leakDetector and not hasThreadSupport: when leakDetector:
if framePtr != nil and framePtr.prev != nil: res.filename = nil
res.filename = framePtr.prev.filename res.line = 0
res.line = framePtr.prev.line when not hasThreadSupport:
if framePtr != nil and framePtr.prev != nil:
res.filename = framePtr.prev.filename
res.line = framePtr.prev.line
# refcount is zero, color is black, but mark it to be in the ZCT # refcount is zero, color is black, but mark it to be in the ZCT
res.refcount = ZctFlag res.refcount = ZctFlag
sysAssert(isAllocatedPtr(gch.region, res), "newObj: 3") sysAssert(isAllocatedPtr(gch.region, res), "newObj: 3")
@ -503,10 +506,13 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2") sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
# now it is buffered in the ZCT # now it is buffered in the ZCT
res.typ = typ res.typ = typ
when leakDetector and not hasThreadSupport: when leakDetector:
if framePtr != nil and framePtr.prev != nil: res.filename = nil
res.filename = framePtr.prev.filename res.line = 0
res.line = framePtr.prev.line when not hasThreadSupport:
if framePtr != nil and framePtr.prev != nil:
res.filename = framePtr.prev.filename
res.line = framePtr.prev.line
res.refcount = rcIncrement # refcount is 1 res.refcount = rcIncrement # refcount is 1
sysAssert(isAllocatedPtr(gch.region, res), "newObj: 3") sysAssert(isAllocatedPtr(gch.region, res), "newObj: 3")
when logGC: writeCell("new cell", res) when logGC: writeCell("new cell", res)

View file

@ -65,6 +65,21 @@ proc hint*(name: string; val: bool) =
let v = if val: "on" else: "off" let v = if val: "on" else: "off"
hintImpl(name & "]:" & v, "hint[" & name & "]:" & v) hintImpl(name & "]:" & v, "hint[" & name & "]:" & v)
proc patchFile*(package, filename, replacement: string) =
## Overrides the location of a given file belonging to the
## passed package.
## If the ``replacement`` is not an absolute path, the path
## is interpreted to be local to the Nimscript file that contains
## the call to ``patchFile``, Nim's ``--path`` is not used at all
## to resolve the filename!
##
## Example:
##
## .. code-block:: nim
##
## patchFile("stdlib", "asyncdispatch", "patches/replacement")
discard
proc getCommand*(): string = proc getCommand*(): string =
## Gets the Nim command that the compiler has been invoked with, for example ## Gets the Nim command that the compiler has been invoked with, for example
## "c", "js", "build", "help". ## "c", "js", "build", "help".

View file

@ -0,0 +1,11 @@
discard """
output: '''true'''
"""
# bug #4471
when true:
let s1 = "123"
var s2 = s1
s2.setLen(0)
# fails - s1.len == 0
echo s1.len == 3

View file

@ -0,0 +1,20 @@
discard """
output: '''1 mod 7'''
"""
# bug #3706
type Modulo[M: static[int]] = distinct int
proc modulo(a: int, M: static[int]): Modulo[M] = Modulo[M](a %% M)
proc `+`[M: static[int]](a, b: Modulo[M]): Modulo[M] = (a.int + b.int).modulo(M)
proc `$`*[M: static[int]](a: Modulo[M]): string = $(a.int) & " mod " & $(M)
when isMainModule:
let
a = 3.modulo(7)
b = 5.modulo(7)
echo a + b

View file

@ -0,0 +1,4 @@
proc ln*(x: float): float =
return 0.5

View file

@ -1,10 +1,12 @@
discard """ discard """
cmd: "nim default $file" cmd: "nim default $file"
output: '''hello world!''' output: '''hello world! 0.5'''
msg: '''[NimScript] exec: gcc -v''' msg: '''[NimScript] exec: gcc -v'''
""" """
when not defined(definedefine): when not defined(definedefine):
{.fatal: "wrong nim script configuration".} {.fatal: "wrong nim script configuration".}
echo "hello world!" import math
echo "hello world! ", ln 2.0

View file

@ -10,6 +10,8 @@ import ospaths
warning("uninit", off) warning("uninit", off)
hint("processing", off) hint("processing", off)
#--verbosity:2
patchFile("stdlib", "math", "mymath")
task listDirs, "lists every subdirectory": task listDirs, "lists every subdirectory":
for x in listDirs("."): for x in listDirs("."):

View file

@ -0,0 +1,6 @@
# Bug: https://github.com/nim-lang/Nim/issues/4475
# Fix: https://github.com/nim-lang/Nim/pull/4477
proc test(x: varargs[string], y: int) = discard
test(y = 1)

View file

@ -0,0 +1,11 @@
discard """
file: "tassignemptytuple.nim"
line: 11
errormsg: "cannot infer the type of the tuple"
"""
var
foo: seq[int]
bar: tuple[a: seq[int], b: set[char]]
(foo, bar) = (@[], (@[], {}))

View file

@ -49,6 +49,16 @@ Compiler Additions
- The ``-d/--define`` flag can now optionally take a value to be used - The ``-d/--define`` flag can now optionally take a value to be used
by code at compile time. by code at compile time.
Nimscript Additions
-------------------
- Finally it's possible to dis/enable specific hints and warnings in
Nimscript via the procs ``warning`` and ``hint``.
- Nimscript exports a proc named ``patchFile`` which can be used to
patch modules or include files for different Nimble packages, including
the ``stdlib`` package.
Language Additions Language Additions
------------------ ------------------