Merge branch 'devel' into araq
This commit is contained in:
commit
2b862b74e0
165 changed files with 4572 additions and 920 deletions
|
|
@ -56,7 +56,7 @@ build_script:
|
||||||
|
|
||||||
test_script:
|
test_script:
|
||||||
- tests\testament\tester --pedantic all -d:nimCoroutines
|
- tests\testament\tester --pedantic all -d:nimCoroutines
|
||||||
- koch csource
|
# - koch csource
|
||||||
- koch zip
|
# - koch zip
|
||||||
|
|
||||||
deploy: off
|
deploy: off
|
||||||
|
|
|
||||||
|
|
@ -224,7 +224,7 @@ type
|
||||||
TNodeKinds* = set[TNodeKind]
|
TNodeKinds* = set[TNodeKind]
|
||||||
|
|
||||||
type
|
type
|
||||||
TSymFlag* = enum # already 32 flags!
|
TSymFlag* = enum # already 33 flags!
|
||||||
sfUsed, # read access of sym (for warnings) or simply used
|
sfUsed, # read access of sym (for warnings) or simply used
|
||||||
sfExported, # symbol is exported from module
|
sfExported, # symbol is exported from module
|
||||||
sfFromGeneric, # symbol is instantiation of a generic; this is needed
|
sfFromGeneric, # symbol is instantiation of a generic; this is needed
|
||||||
|
|
@ -453,9 +453,10 @@ type
|
||||||
nfIsRef # this node is a 'ref' node; used for the VM
|
nfIsRef # this node is a 'ref' node; used for the VM
|
||||||
nfPreventCg # this node should be ignored by the codegen
|
nfPreventCg # this node should be ignored by the codegen
|
||||||
nfBlockArg # this a stmtlist appearing in a call (e.g. a do block)
|
nfBlockArg # this a stmtlist appearing in a call (e.g. a do block)
|
||||||
|
nfFromTemplate # a top-level node returned from a template
|
||||||
|
|
||||||
TNodeFlags* = set[TNodeFlag]
|
TNodeFlags* = set[TNodeFlag]
|
||||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 30)
|
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: beyond that)
|
||||||
tfVarargs, # procedure has C styled varargs
|
tfVarargs, # procedure has C styled varargs
|
||||||
# tyArray type represeting a varargs list
|
# tyArray type represeting a varargs list
|
||||||
tfNoSideEffect, # procedure type does not allow side effects
|
tfNoSideEffect, # procedure type does not allow side effects
|
||||||
|
|
@ -508,6 +509,9 @@ type
|
||||||
tfTriggersCompileTime # uses the NimNode type which make the proc
|
tfTriggersCompileTime # uses the NimNode type which make the proc
|
||||||
# implicitly '.compiletime'
|
# implicitly '.compiletime'
|
||||||
tfRefsAnonObj # used for 'ref object' and 'ptr object'
|
tfRefsAnonObj # used for 'ref object' and 'ptr object'
|
||||||
|
tfCovariant # covariant generic param mimicing a ptr type
|
||||||
|
tfWeakCovariant # covariant generic param mimicing a seq/array type
|
||||||
|
tfContravariant # contravariant generic param
|
||||||
|
|
||||||
TTypeFlags* = set[TTypeFlag]
|
TTypeFlags* = set[TTypeFlag]
|
||||||
|
|
||||||
|
|
@ -956,7 +960,8 @@ const
|
||||||
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias}
|
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias}
|
||||||
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
|
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
|
||||||
nfDotSetter, nfDotField,
|
nfDotSetter, nfDotField,
|
||||||
nfIsRef, nfPreventCg, nfLL}
|
nfIsRef, nfPreventCg, nfLL,
|
||||||
|
nfFromTemplate}
|
||||||
namePos* = 0
|
namePos* = 0
|
||||||
patternPos* = 1 # empty except for term rewriting macros
|
patternPos* = 1 # empty except for term rewriting macros
|
||||||
genericParamsPos* = 2
|
genericParamsPos* = 2
|
||||||
|
|
@ -1007,15 +1012,17 @@ proc add*(father, son: PNode) =
|
||||||
if isNil(father.sons): father.sons = @[]
|
if isNil(father.sons): father.sons = @[]
|
||||||
add(father.sons, son)
|
add(father.sons, son)
|
||||||
|
|
||||||
proc `[]`*(n: PNode, i: int): PNode {.inline.} =
|
type Indexable = PNode | PType
|
||||||
result = n.sons[i]
|
|
||||||
|
template `[]`*(n: Indexable, i: int): Indexable =
|
||||||
|
n.sons[i]
|
||||||
|
|
||||||
template `-|`*(b, s: untyped): untyped =
|
template `-|`*(b, s: untyped): untyped =
|
||||||
(if b >= 0: b else: s.len + b)
|
(if b >= 0: b else: s.len + b)
|
||||||
|
|
||||||
# son access operators with support for negative indices
|
# son access operators with support for negative indices
|
||||||
template `{}`*(n: PNode, i: int): untyped = n[i -| n]
|
template `{}`*(n: Indexable, i: int): untyped = n[i -| n]
|
||||||
template `{}=`*(n: PNode, i: int, s: PNode) =
|
template `{}=`*(n: Indexable, i: int, s: Indexable) =
|
||||||
n.sons[i -| n] = s
|
n.sons[i -| n] = s
|
||||||
|
|
||||||
when defined(useNodeIds):
|
when defined(useNodeIds):
|
||||||
|
|
|
||||||
|
|
@ -219,7 +219,7 @@ proc rspaces(x: int): Rope =
|
||||||
|
|
||||||
proc toYamlChar(c: char): string =
|
proc toYamlChar(c: char): string =
|
||||||
case c
|
case c
|
||||||
of '\0'..'\x1F', '\x80'..'\xFF': result = "\\u" & strutils.toHex(ord(c), 4)
|
of '\0'..'\x1F', '\x7F'..'\xFF': result = "\\u" & strutils.toHex(ord(c), 4)
|
||||||
of '\'', '\"', '\\': result = '\\' & c
|
of '\'', '\"', '\\': result = '\\' & c
|
||||||
else: result = $c
|
else: result = $c
|
||||||
|
|
||||||
|
|
@ -407,6 +407,8 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
|
||||||
var istr = rspaces(indent + 2)
|
var istr = rspaces(indent + 2)
|
||||||
result = "{$N$1\"kind\": $2" %
|
result = "{$N$1\"kind\": $2" %
|
||||||
[istr, makeYamlString($n.kind)]
|
[istr, makeYamlString($n.kind)]
|
||||||
|
when defined(useNodeIds):
|
||||||
|
addf(result, ",$N$1\"id\": $2", [istr, rope(n.id)])
|
||||||
addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
|
addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
|
||||||
if maxRecDepth != 0:
|
if maxRecDepth != 0:
|
||||||
addf(result, ",$N$1\"flags\": $2", [istr, rope($n.flags)])
|
addf(result, ",$N$1\"flags\": $2", [istr, rope($n.flags)])
|
||||||
|
|
@ -574,12 +576,6 @@ proc strTableAdd(t: var TStrTable, n: PSym) =
|
||||||
strTableRawInsert(t.data, n)
|
strTableRawInsert(t.data, n)
|
||||||
inc(t.counter)
|
inc(t.counter)
|
||||||
|
|
||||||
proc reallySameIdent(a, b: string): bool {.inline.} =
|
|
||||||
when defined(nimfix):
|
|
||||||
result = a[0] == b[0]
|
|
||||||
else:
|
|
||||||
result = true
|
|
||||||
|
|
||||||
proc strTableIncl*(t: var TStrTable, n: PSym; onConflictKeepOld=false): bool {.discardable.} =
|
proc strTableIncl*(t: var TStrTable, n: PSym; onConflictKeepOld=false): bool {.discardable.} =
|
||||||
# returns true if n is already in the string table:
|
# returns true if n is already in the string table:
|
||||||
# It is essential that `n` is written nevertheless!
|
# It is essential that `n` is written nevertheless!
|
||||||
|
|
@ -594,7 +590,7 @@ proc strTableIncl*(t: var TStrTable, n: PSym; onConflictKeepOld=false): bool {.d
|
||||||
# and overloading: (var x=@[]; x).mapIt(it).
|
# and overloading: (var x=@[]; x).mapIt(it).
|
||||||
# So it is possible the very same sym is added multiple
|
# So it is possible the very same sym is added multiple
|
||||||
# times to the symbol table which we allow here with the 'it == n' check.
|
# times to the symbol table which we allow here with the 'it == n' check.
|
||||||
if it.name.id == n.name.id and reallySameIdent(it.name.s, n.name.s):
|
if it.name.id == n.name.id:
|
||||||
if it == n: return false
|
if it == n: return false
|
||||||
replaceSlot = h
|
replaceSlot = h
|
||||||
h = nextTry(h, high(t.data))
|
h = nextTry(h, high(t.data))
|
||||||
|
|
|
||||||
|
|
@ -78,8 +78,10 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
|
||||||
[p.module.tmpBase, rope(id)])
|
[p.module.tmpBase, rope(id)])
|
||||||
else:
|
else:
|
||||||
result = makeCString(n.strVal)
|
result = makeCString(n.strVal)
|
||||||
of nkFloatLit..nkFloat64Lit:
|
of nkFloatLit, nkFloat64Lit:
|
||||||
result = rope(n.floatVal.toStrMaxPrecision)
|
result = rope(n.floatVal.toStrMaxPrecision)
|
||||||
|
of nkFloat32Lit:
|
||||||
|
result = rope(n.floatVal.toStrMaxPrecision("f"))
|
||||||
else:
|
else:
|
||||||
internalError(n.info, "genLiteral(" & $n.kind & ')')
|
internalError(n.info, "genLiteral(" & $n.kind & ')')
|
||||||
result = nil
|
result = nil
|
||||||
|
|
@ -535,7 +537,7 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
"(($4)($1) * ($4)($2))", # MulF64
|
"(($4)($1) * ($4)($2))", # MulF64
|
||||||
"(($4)($1) / ($4)($2))", # DivF64
|
"(($4)($1) / ($4)($2))", # DivF64
|
||||||
|
|
||||||
"($4)((NU$3)($1) >> (NU$3)($2))", # ShrI
|
"($4)((NU$5)($1) >> (NU$3)($2))", # ShrI
|
||||||
"($4)((NU$3)($1) << (NU$3)($2))", # ShlI
|
"($4)((NU$3)($1) << (NU$3)($2))", # ShlI
|
||||||
"($4)($1 & $2)", # BitandI
|
"($4)($1 & $2)", # BitandI
|
||||||
"($4)($1 | $2)", # BitorI
|
"($4)($1 | $2)", # BitorI
|
||||||
|
|
@ -575,16 +577,17 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
"($1 != $2)"] # Xor
|
"($1 != $2)"] # Xor
|
||||||
var
|
var
|
||||||
a, b: TLoc
|
a, b: TLoc
|
||||||
s: BiggestInt
|
s, k: BiggestInt
|
||||||
assert(e.sons[1].typ != nil)
|
assert(e.sons[1].typ != nil)
|
||||||
assert(e.sons[2].typ != nil)
|
assert(e.sons[2].typ != nil)
|
||||||
initLocExpr(p, e.sons[1], a)
|
initLocExpr(p, e.sons[1], a)
|
||||||
initLocExpr(p, e.sons[2], b)
|
initLocExpr(p, e.sons[2], b)
|
||||||
# BUGFIX: cannot use result-type here, as it may be a boolean
|
# BUGFIX: cannot use result-type here, as it may be a boolean
|
||||||
s = max(getSize(a.t), getSize(b.t)) * 8
|
s = max(getSize(a.t), getSize(b.t)) * 8
|
||||||
|
k = getSize(a.t) * 8
|
||||||
putIntoDest(p, d, e.typ,
|
putIntoDest(p, d, e.typ,
|
||||||
binArithTab[op] % [rdLoc(a), rdLoc(b), rope(s),
|
binArithTab[op] % [rdLoc(a), rdLoc(b), rope(s),
|
||||||
getSimpleTypeDesc(p.module, e.typ)])
|
getSimpleTypeDesc(p.module, e.typ), rope(k)])
|
||||||
|
|
||||||
proc genEqProc(p: BProc, e: PNode, d: var TLoc) =
|
proc genEqProc(p: BProc, e: PNode, d: var TLoc) =
|
||||||
var a, b: TLoc
|
var a, b: TLoc
|
||||||
|
|
@ -654,7 +657,9 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
|
||||||
d.s = OnHeap
|
d.s = OnHeap
|
||||||
else:
|
else:
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
let typ = skipTypes(e.sons[0].typ, abstractInst)
|
var typ = skipTypes(e.sons[0].typ, abstractInst)
|
||||||
|
if typ.kind in {tyUserTypeClass, tyUserTypeClassInst} and typ.isResolvedUserTypeClass:
|
||||||
|
typ = typ.lastSon
|
||||||
if typ.kind == tyVar and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e.sons[0].kind == nkHiddenAddr:
|
if typ.kind == tyVar and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e.sons[0].kind == nkHiddenAddr:
|
||||||
initLocExprSingleUse(p, e[0][0], d)
|
initLocExprSingleUse(p, e[0][0], d)
|
||||||
return
|
return
|
||||||
|
|
@ -2132,6 +2137,13 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
genLineDir(p, n)
|
genLineDir(p, n)
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
|
if n[0].kind in nkCallKinds:
|
||||||
|
# bug #6037: do not assign to a temp in C++ mode:
|
||||||
|
incl a.flags, lfSingleUse
|
||||||
|
genCall(p, n[0], a)
|
||||||
|
if lfSingleUse notin a.flags:
|
||||||
|
line(p, cpsStmts, a.r & ";" & tnl)
|
||||||
|
else:
|
||||||
initLocExpr(p, n.sons[0], a)
|
initLocExpr(p, n.sons[0], a)
|
||||||
of nkAsmStmt: genAsmStmt(p, n)
|
of nkAsmStmt: genAsmStmt(p, n)
|
||||||
of nkTryStmt:
|
of nkTryStmt:
|
||||||
|
|
@ -2157,8 +2169,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
# are not transformed correctly. We work around this issue (#411) here
|
# are not transformed correctly. We work around this issue (#411) here
|
||||||
# by ensuring it's no inner proc (owner is a module):
|
# by ensuring it's no inner proc (owner is a module):
|
||||||
if prc.skipGenericOwner.kind == skModule and sfCompileTime notin prc.flags:
|
if prc.skipGenericOwner.kind == skModule and sfCompileTime notin prc.flags:
|
||||||
if (optDeadCodeElim notin gGlobalOptions and
|
if (not emitLazily(prc)) or
|
||||||
sfDeadCodeElim notin getModule(prc).flags) or
|
|
||||||
({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
|
({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
|
||||||
(sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
|
(sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
|
||||||
(prc.kind == skMethod):
|
(prc.kind == skMethod):
|
||||||
|
|
@ -2214,7 +2225,7 @@ proc getNullValueAux(p: BProc; obj, cons: PNode, result: var Rope) =
|
||||||
let field = obj.sym
|
let field = obj.sym
|
||||||
for i in 1..<cons.len:
|
for i in 1..<cons.len:
|
||||||
if cons[i].kind == nkExprColonExpr:
|
if cons[i].kind == nkExprColonExpr:
|
||||||
if cons[i][0].sym == field:
|
if cons[i][0].sym.name == field.name:
|
||||||
result.add genConstExpr(p, cons[i][1])
|
result.add genConstExpr(p, cons[i][1])
|
||||||
return
|
return
|
||||||
elif i == field.position:
|
elif i == field.position:
|
||||||
|
|
|
||||||
|
|
@ -39,13 +39,11 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||||
var L = sonsLen(n)
|
var L = sonsLen(n)
|
||||||
|
|
||||||
# if we have a something that's been captured, use the lowering instead:
|
# if we have a something that's been captured, use the lowering instead:
|
||||||
var useLowering = false
|
|
||||||
for i in countup(0, L-3):
|
for i in countup(0, L-3):
|
||||||
if n[i].kind != nkSym:
|
if n[i].kind != nkSym:
|
||||||
useLowering = true; break
|
|
||||||
if useLowering:
|
|
||||||
genStmts(p, lowerTupleUnpacking(n, p.prc))
|
genStmts(p, lowerTupleUnpacking(n, p.prc))
|
||||||
return
|
return
|
||||||
|
|
||||||
genLineDir(p, n)
|
genLineDir(p, n)
|
||||||
initLocExpr(p, n.sons[L-1], tup)
|
initLocExpr(p, n.sons[L-1], tup)
|
||||||
var t = tup.t.skipTypes(abstractInst)
|
var t = tup.t.skipTypes(abstractInst)
|
||||||
|
|
@ -182,10 +180,11 @@ proc genGotoVar(p: BProc; value: PNode) =
|
||||||
lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope])
|
lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope])
|
||||||
|
|
||||||
proc genSingleVar(p: BProc, a: PNode) =
|
proc genSingleVar(p: BProc, a: PNode) =
|
||||||
var v = a.sons[0].sym
|
let v = a.sons[0].sym
|
||||||
if {sfCompileTime, sfGoto} * v.flags != {}:
|
if sfCompileTime in v.flags: return
|
||||||
|
if sfGoto in v.flags:
|
||||||
# translate 'var state {.goto.} = X' into 'goto LX':
|
# translate 'var state {.goto.} = X' into 'goto LX':
|
||||||
if sfGoto in v.flags: genGotoVar(p, a.sons[2])
|
genGotoVar(p, a.sons[2])
|
||||||
return
|
return
|
||||||
var targetProc = p
|
var targetProc = p
|
||||||
if sfGlobal in v.flags:
|
if sfGlobal in v.flags:
|
||||||
|
|
|
||||||
|
|
@ -470,7 +470,12 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
|
||||||
let a = genRecordFieldsAux(m, k, "$1.$2" % [ae, sname], rectype,
|
let a = genRecordFieldsAux(m, k, "$1.$2" % [ae, sname], rectype,
|
||||||
check)
|
check)
|
||||||
if a != nil:
|
if a != nil:
|
||||||
|
if tfPacked notin rectype.flags:
|
||||||
add(unionBody, "struct {")
|
add(unionBody, "struct {")
|
||||||
|
else:
|
||||||
|
addf(unionBody, CC[cCompiler].structStmtFmt,
|
||||||
|
[rope"struct", nil, rope(CC[cCompiler].packedPragma)])
|
||||||
|
add(unionBody, "{")
|
||||||
add(unionBody, a)
|
add(unionBody, a)
|
||||||
addf(unionBody, "} $1;$n", [sname])
|
addf(unionBody, "} $1;$n", [sname])
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
ast, astalgo, ropes, hashes, strutils, types, msgs, wordrecg,
|
ast, astalgo, ropes, hashes, strutils, types, msgs, wordrecg,
|
||||||
platform, trees
|
platform, trees, options
|
||||||
|
|
||||||
proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
|
proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
@ -211,20 +211,8 @@ proc mangle*(name: string): string =
|
||||||
if requiresUnderscore:
|
if requiresUnderscore:
|
||||||
result.add "_"
|
result.add "_"
|
||||||
|
|
||||||
proc makeLLVMString*(s: string): Rope =
|
proc emitLazily*(s: PSym): bool {.inline.} =
|
||||||
const MaxLineLength = 64
|
result = optDeadCodeElim in gGlobalOptions or
|
||||||
result = nil
|
sfDeadCodeElim in getModule(s).flags
|
||||||
var res = "c\""
|
|
||||||
for i in countup(0, len(s) - 1):
|
|
||||||
if (i + 1) mod MaxLineLength == 0:
|
|
||||||
add(result, rope(res))
|
|
||||||
setLen(res, 0)
|
|
||||||
case s[i]
|
|
||||||
of '\0'..'\x1F', '\x80'..'\xFF', '\"', '\\':
|
|
||||||
add(res, '\\')
|
|
||||||
add(res, toHex(ord(s[i]), 2))
|
|
||||||
else: add(res, s[i])
|
|
||||||
add(res, "\\00\"")
|
|
||||||
add(result, rope(res))
|
|
||||||
|
|
||||||
initTypeTables()
|
initTypeTables()
|
||||||
|
|
|
||||||
|
|
@ -47,10 +47,6 @@ proc findPendingModule(m: BModule, s: PSym): BModule =
|
||||||
var ms = getModule(s)
|
var ms = getModule(s)
|
||||||
result = m.g.modules[ms.position]
|
result = m.g.modules[ms.position]
|
||||||
|
|
||||||
proc emitLazily(s: PSym): bool {.inline.} =
|
|
||||||
result = optDeadCodeElim in gGlobalOptions or
|
|
||||||
sfDeadCodeElim in getModule(s).flags
|
|
||||||
|
|
||||||
proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) =
|
proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) =
|
||||||
result.k = k
|
result.k = k
|
||||||
result.s = s
|
result.s = s
|
||||||
|
|
@ -142,6 +138,13 @@ proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope =
|
||||||
template rfmt(m: BModule, fmt: string, args: varargs[Rope]): untyped =
|
template rfmt(m: BModule, fmt: string, args: varargs[Rope]): untyped =
|
||||||
ropecg(m, fmt, args)
|
ropecg(m, fmt, args)
|
||||||
|
|
||||||
|
var indent = "\t".rope
|
||||||
|
|
||||||
|
proc indentLine(p: BProc, r: Rope): Rope =
|
||||||
|
result = r
|
||||||
|
for i in countup(0, p.blocks.len-1):
|
||||||
|
prepend(result, indent)
|
||||||
|
|
||||||
proc appcg(m: BModule, c: var Rope, frmt: FormatStr,
|
proc appcg(m: BModule, c: var Rope, frmt: FormatStr,
|
||||||
args: varargs[Rope]) =
|
args: varargs[Rope]) =
|
||||||
add(c, ropecg(m, frmt, args))
|
add(c, ropecg(m, frmt, args))
|
||||||
|
|
@ -154,11 +157,6 @@ proc appcg(p: BProc, s: TCProcSection, frmt: FormatStr,
|
||||||
args: varargs[Rope]) =
|
args: varargs[Rope]) =
|
||||||
add(p.s(s), ropecg(p.module, frmt, args))
|
add(p.s(s), ropecg(p.module, frmt, args))
|
||||||
|
|
||||||
var indent = "\t".rope
|
|
||||||
proc indentLine(p: BProc, r: Rope): Rope =
|
|
||||||
result = r
|
|
||||||
for i in countup(0, p.blocks.len-1): prepend(result, indent)
|
|
||||||
|
|
||||||
proc line(p: BProc, s: TCProcSection, r: Rope) =
|
proc line(p: BProc, s: TCProcSection, r: Rope) =
|
||||||
add(p.s(s), indentLine(p, r))
|
add(p.s(s), indentLine(p, r))
|
||||||
|
|
||||||
|
|
@ -612,8 +610,18 @@ proc generateHeaders(m: BModule) =
|
||||||
addf(m.s[cfsHeaders], "#include \"$1\"$N", [rope(it)])
|
addf(m.s[cfsHeaders], "#include \"$1\"$N", [rope(it)])
|
||||||
else:
|
else:
|
||||||
addf(m.s[cfsHeaders], "#include $1$N", [rope(it)])
|
addf(m.s[cfsHeaders], "#include $1$N", [rope(it)])
|
||||||
|
add(m.s[cfsHeaders], "#undef LANGUAGE_C" & tnl)
|
||||||
|
add(m.s[cfsHeaders], "#undef MIPSEB" & tnl)
|
||||||
|
add(m.s[cfsHeaders], "#undef MIPSEL" & tnl)
|
||||||
|
add(m.s[cfsHeaders], "#undef PPC" & tnl)
|
||||||
|
add(m.s[cfsHeaders], "#undef R3000" & tnl)
|
||||||
|
add(m.s[cfsHeaders], "#undef R4000" & tnl)
|
||||||
|
add(m.s[cfsHeaders], "#undef i386" & tnl)
|
||||||
add(m.s[cfsHeaders], "#undef linux" & tnl)
|
add(m.s[cfsHeaders], "#undef linux" & tnl)
|
||||||
|
add(m.s[cfsHeaders], "#undef mips" & tnl)
|
||||||
add(m.s[cfsHeaders], "#undef near" & tnl)
|
add(m.s[cfsHeaders], "#undef near" & tnl)
|
||||||
|
add(m.s[cfsHeaders], "#undef powerpc" & tnl)
|
||||||
|
add(m.s[cfsHeaders], "#undef unix" & tnl)
|
||||||
|
|
||||||
proc initFrame(p: BProc, procname, filename: Rope): Rope =
|
proc initFrame(p: BProc, procname, filename: Rope): Rope =
|
||||||
discard cgsym(p.module, "nimFrame")
|
discard cgsym(p.module, "nimFrame")
|
||||||
|
|
@ -898,14 +906,14 @@ proc genMainProc(m: BModule) =
|
||||||
# prevents inlining of the NimMainInner function and dependent
|
# prevents inlining of the NimMainInner function and dependent
|
||||||
# functions, which might otherwise merge their stack frames.
|
# functions, which might otherwise merge their stack frames.
|
||||||
PreMainBody =
|
PreMainBody =
|
||||||
"void PreMainInner() {$N" &
|
"void PreMainInner(void) {$N" &
|
||||||
"\tsystemInit000();$N" &
|
"\tsystemInit000();$N" &
|
||||||
"$1" &
|
"$1" &
|
||||||
"$2" &
|
"$2" &
|
||||||
"$3" &
|
"$3" &
|
||||||
"}$N$N" &
|
"}$N$N" &
|
||||||
"void PreMain() {$N" &
|
"void PreMain(void) {$N" &
|
||||||
"\tvoid (*volatile inner)();$N" &
|
"\tvoid (*volatile inner)(void);$N" &
|
||||||
"\tsystemDatInit000();$N" &
|
"\tsystemDatInit000();$N" &
|
||||||
"\tinner = PreMainInner;$N" &
|
"\tinner = PreMainInner;$N" &
|
||||||
"$4$5" &
|
"$4$5" &
|
||||||
|
|
@ -924,7 +932,7 @@ proc genMainProc(m: BModule) =
|
||||||
|
|
||||||
NimMainProc =
|
NimMainProc =
|
||||||
"N_CDECL(void, NimMain)(void) {$N" &
|
"N_CDECL(void, NimMain)(void) {$N" &
|
||||||
"\tvoid (*volatile inner)();$N" &
|
"\tvoid (*volatile inner)(void);$N" &
|
||||||
"\tPreMain();$N" &
|
"\tPreMain();$N" &
|
||||||
"\tinner = NimMainInner;$N" &
|
"\tinner = NimMainInner;$N" &
|
||||||
"$2" &
|
"$2" &
|
||||||
|
|
|
||||||
|
|
@ -257,13 +257,14 @@ proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym =
|
||||||
cond = a
|
cond = a
|
||||||
else:
|
else:
|
||||||
cond = isn
|
cond = isn
|
||||||
var call = newNodeI(nkCall, base.info)
|
let retTyp = base.typ.sons[0]
|
||||||
|
let call = newNodeIT(nkCall, base.info, retTyp)
|
||||||
addSon(call, newSymNode(curr))
|
addSon(call, newSymNode(curr))
|
||||||
for col in countup(1, paramLen - 1):
|
for col in countup(1, paramLen - 1):
|
||||||
addSon(call, genConv(newSymNode(base.typ.n.sons[col].sym),
|
addSon(call, genConv(newSymNode(base.typ.n.sons[col].sym),
|
||||||
curr.typ.sons[col], false))
|
curr.typ.sons[col], false))
|
||||||
var ret: PNode
|
var ret: PNode
|
||||||
if base.typ.sons[0] != nil:
|
if retTyp != nil:
|
||||||
var a = newNodeI(nkFastAsgn, base.info)
|
var a = newNodeI(nkFastAsgn, base.info)
|
||||||
addSon(a, newSymNode(base.ast.sons[resultPos].sym))
|
addSon(a, newSymNode(base.ast.sons[resultPos].sym))
|
||||||
addSon(a, call)
|
addSon(a, call)
|
||||||
|
|
|
||||||
|
|
@ -103,3 +103,4 @@ proc initDefines*() =
|
||||||
defineSymbol("nimNewShiftOps")
|
defineSymbol("nimNewShiftOps")
|
||||||
defineSymbol("nimDistros")
|
defineSymbol("nimDistros")
|
||||||
defineSymbol("nimHasCppDefine")
|
defineSymbol("nimHasCppDefine")
|
||||||
|
defineSymbol("nimGenericInOutFlags")
|
||||||
|
|
|
||||||
|
|
@ -155,5 +155,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode =
|
||||||
#if ctx.instLines: result.info = n.info
|
#if ctx.instLines: result.info = n.info
|
||||||
for i in countup(0, safeLen(body) - 1):
|
for i in countup(0, safeLen(body) - 1):
|
||||||
evalTemplateAux(body.sons[i], args, ctx, result)
|
evalTemplateAux(body.sons[i], args, ctx, result)
|
||||||
|
result.flags.incl nfFromTemplate
|
||||||
result = wrapInComesFrom(n.info, result)
|
result = wrapInComesFrom(n.info, result)
|
||||||
dec(evalTemplateCounter)
|
dec(evalTemplateCounter)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,8 @@ Files: "compiler"
|
||||||
Files: "doc"
|
Files: "doc"
|
||||||
Files: "doc/html"
|
Files: "doc/html"
|
||||||
Files: "tools"
|
Files: "tools"
|
||||||
|
Files: "nimsuggest"
|
||||||
|
Files: "nimsuggest/tests/*.nim"
|
||||||
Files: "web/website.ini"
|
Files: "web/website.ini"
|
||||||
Files: "web/ticker.html"
|
Files: "web/ticker.html"
|
||||||
Files: "web/*.nim"
|
Files: "web/*.nim"
|
||||||
|
|
|
||||||
|
|
@ -94,12 +94,39 @@ type
|
||||||
target: TTarget # duplicated here for faster dispatching
|
target: TTarget # duplicated here for faster dispatching
|
||||||
unique: int # for temp identifier generation
|
unique: int # for temp identifier generation
|
||||||
blocks: seq[TBlock]
|
blocks: seq[TBlock]
|
||||||
|
extraIndent: int
|
||||||
up: PProc # up the call chain; required for closure support
|
up: PProc # up the call chain; required for closure support
|
||||||
declaredGlobals: IntSet
|
declaredGlobals: IntSet
|
||||||
|
|
||||||
template `|`(a, b: untyped): untyped {.dirty.} =
|
template `|`(a, b: untyped): untyped {.dirty.} =
|
||||||
(if p.target == targetJS: a else: b)
|
(if p.target == targetJS: a else: b)
|
||||||
|
|
||||||
|
var indent = "\t".rope
|
||||||
|
|
||||||
|
proc indentLine(p: PProc, r: Rope): Rope =
|
||||||
|
result = r
|
||||||
|
var p = p
|
||||||
|
while true:
|
||||||
|
for i in countup(0, p.blocks.len - 1 + p.extraIndent):
|
||||||
|
prepend(result, indent)
|
||||||
|
if p.up == nil or p.up.prc != p.prc.owner:
|
||||||
|
break
|
||||||
|
p = p.up
|
||||||
|
|
||||||
|
template line(p: PProc, added: string) =
|
||||||
|
add(p.body, indentLine(p, rope(added)))
|
||||||
|
|
||||||
|
template line(p: PProc, added: Rope) =
|
||||||
|
add(p.body, indentLine(p, added))
|
||||||
|
|
||||||
|
template lineF(p: PProc, frmt: FormatStr, args: varargs[Rope]) =
|
||||||
|
add(p.body, indentLine(p, ropes.`%`(frmt, args)))
|
||||||
|
|
||||||
|
template nested(p, body) =
|
||||||
|
inc p.extraIndent
|
||||||
|
body
|
||||||
|
dec p.extraIndent
|
||||||
|
|
||||||
proc newGlobals(): PGlobals =
|
proc newGlobals(): PGlobals =
|
||||||
new(result)
|
new(result)
|
||||||
result.forwarded = @[]
|
result.forwarded = @[]
|
||||||
|
|
@ -129,7 +156,8 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
|
||||||
module: module,
|
module: module,
|
||||||
procDef: procDef,
|
procDef: procDef,
|
||||||
g: globals,
|
g: globals,
|
||||||
target: module.target)
|
target: module.target,
|
||||||
|
extraIndent: int(procDef != nil))
|
||||||
if procDef != nil: result.prc = procDef.sons[namePos].sym
|
if procDef != nil: result.prc = procDef.sons[namePos].sym
|
||||||
if result.target == targetPHP:
|
if result.target == targetPHP:
|
||||||
result.declaredGlobals = initIntSet()
|
result.declaredGlobals = initIntSet()
|
||||||
|
|
@ -290,7 +318,7 @@ proc getTemp(p: PProc, defineInLocals: bool = true): Rope =
|
||||||
if p.target == targetJS:
|
if p.target == targetJS:
|
||||||
result = "Tmp$1" % [rope(p.unique)]
|
result = "Tmp$1" % [rope(p.unique)]
|
||||||
if defineInLocals:
|
if defineInLocals:
|
||||||
addf(p.locals, "var $1;$n", [result])
|
add(p.locals, p.indentLine("var $1;$n" % [result]))
|
||||||
else:
|
else:
|
||||||
result = "$$Tmp$1" % [rope(p.unique)]
|
result = "$$Tmp$1" % [rope(p.unique)]
|
||||||
|
|
||||||
|
|
@ -315,9 +343,11 @@ proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
|
||||||
# tmp = b
|
# tmp = b
|
||||||
# tmp
|
# tmp
|
||||||
gen(p, a, x)
|
gen(p, a, x)
|
||||||
p.body.addf("if (!$1) $2 = false; else {", [x.rdLoc, r.rdLoc])
|
lineF(p, "if (!$1) $2 = false; else {", [x.rdLoc, r.rdLoc])
|
||||||
|
p.nested:
|
||||||
gen(p, b, y)
|
gen(p, b, y)
|
||||||
p.body.addf("$2 = $1; }", [y.rdLoc, r.rdLoc])
|
lineF(p, "$2 = $1;", [y.rdLoc, r.rdLoc])
|
||||||
|
line(p, "}")
|
||||||
|
|
||||||
proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
|
proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
|
||||||
assert r.kind == resNone
|
assert r.kind == resNone
|
||||||
|
|
@ -331,9 +361,11 @@ proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
|
||||||
r.res = p.getTemp
|
r.res = p.getTemp
|
||||||
r.kind = resVal
|
r.kind = resVal
|
||||||
gen(p, a, x)
|
gen(p, a, x)
|
||||||
p.body.addf("if ($1) $2 = true; else {", [x.rdLoc, r.rdLoc])
|
lineF(p, "if ($1) $2 = true; else {", [x.rdLoc, r.rdLoc])
|
||||||
|
p.nested:
|
||||||
gen(p, b, y)
|
gen(p, b, y)
|
||||||
p.body.addf("$2 = $1; }", [y.rdLoc, r.rdLoc])
|
lineF(p, "$2 = $1;", [y.rdLoc, r.rdLoc])
|
||||||
|
line(p, "}")
|
||||||
|
|
||||||
type
|
type
|
||||||
TMagicFrmt = array[0..3, string]
|
TMagicFrmt = array[0..3, string]
|
||||||
|
|
@ -415,12 +447,10 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
|
||||||
["", "", "Math.floor($1)", "Math.floor($1)"], # ToInt
|
["", "", "Math.floor($1)", "Math.floor($1)"], # ToInt
|
||||||
["", "", "Math.floor($1)", "Math.floor($1)"], # ToBiggestInt
|
["", "", "Math.floor($1)", "Math.floor($1)"], # ToBiggestInt
|
||||||
["nimCharToStr", "nimCharToStr", "nimCharToStr($1)", "nimCharToStr($1)"],
|
["nimCharToStr", "nimCharToStr", "nimCharToStr($1)", "nimCharToStr($1)"],
|
||||||
["nimBoolToStr", "nimBoolToStr", "nimBoolToStr($1)", "nimBoolToStr($1)"], [
|
["nimBoolToStr", "nimBoolToStr", "nimBoolToStr($1)", "nimBoolToStr($1)"],
|
||||||
"cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")",
|
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
|
||||||
"cstrToNimstr(($1)+\"\")"], ["cstrToNimstr", "cstrToNimstr",
|
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
|
||||||
"cstrToNimstr(($1)+\"\")",
|
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
|
||||||
"cstrToNimstr(($1)+\"\")"], ["cstrToNimstr",
|
|
||||||
"cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
|
|
||||||
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr($1)", "cstrToNimstr($1)"],
|
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr($1)", "cstrToNimstr($1)"],
|
||||||
["", "", "$1", "$1"]]
|
["", "", "$1", "$1"]]
|
||||||
|
|
||||||
|
|
@ -475,18 +505,18 @@ proc unaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
|
||||||
r.res = frmt % [r.rdLoc]
|
r.res = frmt % [r.rdLoc]
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
|
|
||||||
proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic, ops: TMagicOps) =
|
proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||||
var
|
var
|
||||||
x, y: TCompRes
|
x, y: TCompRes
|
||||||
let i = ord(optOverflowCheck notin p.options)
|
let i = ord(optOverflowCheck notin p.options)
|
||||||
useMagic(p, ops[op][i])
|
useMagic(p, jsOps[op][i])
|
||||||
if sonsLen(n) > 2:
|
if sonsLen(n) > 2:
|
||||||
gen(p, n.sons[1], x)
|
gen(p, n.sons[1], x)
|
||||||
gen(p, n.sons[2], y)
|
gen(p, n.sons[2], y)
|
||||||
r.res = ops[op][i + 2] % [x.rdLoc, y.rdLoc]
|
r.res = jsOps[op][i + 2] % [x.rdLoc, y.rdLoc]
|
||||||
else:
|
else:
|
||||||
gen(p, n.sons[1], r)
|
gen(p, n.sons[1], r)
|
||||||
r.res = ops[op][i + 2] % [r.rdLoc]
|
r.res = jsOps[op][i + 2] % [r.rdLoc]
|
||||||
|
|
||||||
proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||||
case op
|
case op
|
||||||
|
|
@ -501,7 +531,7 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||||
gen(p, n.sons[2], y)
|
gen(p, n.sons[2], y)
|
||||||
r.res = "intval($1 / $2)" % [x.rdLoc, y.rdLoc]
|
r.res = "intval($1 / $2)" % [x.rdLoc, y.rdLoc]
|
||||||
else:
|
else:
|
||||||
arithAux(p, n, r, op, jsOps)
|
arithAux(p, n, r, op)
|
||||||
of mModI:
|
of mModI:
|
||||||
if p.target == targetPHP:
|
if p.target == targetPHP:
|
||||||
var x, y: TCompRes
|
var x, y: TCompRes
|
||||||
|
|
@ -509,7 +539,7 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||||
gen(p, n.sons[2], y)
|
gen(p, n.sons[2], y)
|
||||||
r.res = "($1 % $2)" % [x.rdLoc, y.rdLoc]
|
r.res = "($1 % $2)" % [x.rdLoc, y.rdLoc]
|
||||||
else:
|
else:
|
||||||
arithAux(p, n, r, op, jsOps)
|
arithAux(p, n, r, op)
|
||||||
of mShrI:
|
of mShrI:
|
||||||
var x, y: TCompRes
|
var x, y: TCompRes
|
||||||
gen(p, n.sons[1], x)
|
gen(p, n.sons[1], x)
|
||||||
|
|
@ -534,9 +564,9 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||||
else:
|
else:
|
||||||
gen(p, n.sons[1], r)
|
gen(p, n.sons[1], r)
|
||||||
else:
|
else:
|
||||||
arithAux(p, n, r, op, jsOps)
|
arithAux(p, n, r, op)
|
||||||
else:
|
else:
|
||||||
arithAux(p, n, r, op, jsOps)
|
arithAux(p, n, r, op)
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
|
|
||||||
proc hasFrameInfo(p: PProc): bool =
|
proc hasFrameInfo(p: PProc): bool =
|
||||||
|
|
@ -546,14 +576,14 @@ proc hasFrameInfo(p: PProc): bool =
|
||||||
proc genLineDir(p: PProc, n: PNode) =
|
proc genLineDir(p: PProc, n: PNode) =
|
||||||
let line = toLinenumber(n.info)
|
let line = toLinenumber(n.info)
|
||||||
if optLineDir in p.options:
|
if optLineDir in p.options:
|
||||||
addf(p.body, "// line $2 \"$1\"$n",
|
lineF(p, "// line $2 \"$1\"$n",
|
||||||
[rope(toFilename(n.info)), rope(line)])
|
[rope(toFilename(n.info)), rope(line)])
|
||||||
if {optStackTrace, optEndb} * p.options == {optStackTrace, optEndb} and
|
if {optStackTrace, optEndb} * p.options == {optStackTrace, optEndb} and
|
||||||
((p.prc == nil) or sfPure notin p.prc.flags):
|
((p.prc == nil) or sfPure notin p.prc.flags):
|
||||||
useMagic(p, "endb")
|
useMagic(p, "endb")
|
||||||
addf(p.body, "endb($1);$n", [rope(line)])
|
lineF(p, "endb($1);$n", [rope(line)])
|
||||||
elif hasFrameInfo(p):
|
elif hasFrameInfo(p):
|
||||||
addf(p.body, "F.line = $1;$n" | "$$F['line'] = $1;$n", [rope(line)])
|
lineF(p, "F.line = $1;$n" | "$$F['line'] = $1;$n", [rope(line)])
|
||||||
|
|
||||||
proc genWhileStmt(p: PProc, n: PNode) =
|
proc genWhileStmt(p: PProc, n: PNode) =
|
||||||
var
|
var
|
||||||
|
|
@ -566,20 +596,20 @@ proc genWhileStmt(p: PProc, n: PNode) =
|
||||||
p.blocks[length].id = -p.unique
|
p.blocks[length].id = -p.unique
|
||||||
p.blocks[length].isLoop = true
|
p.blocks[length].isLoop = true
|
||||||
let labl = p.unique.rope
|
let labl = p.unique.rope
|
||||||
addf(p.body, "L$1: while (true) {$n" | "while (true) {$n", [labl])
|
lineF(p, "L$1: while (true) {$n" | "while (true) {$n", [labl])
|
||||||
gen(p, n.sons[0], cond)
|
p.nested: gen(p, n.sons[0], cond)
|
||||||
addf(p.body, "if (!$1) break L$2;$n" | "if (!$1) goto L$2;$n",
|
lineF(p, "if (!$1) break L$2;$n" | "if (!$1) goto L$2;$n",
|
||||||
[cond.res, labl])
|
[cond.res, labl])
|
||||||
genStmt(p, n.sons[1])
|
p.nested: genStmt(p, n.sons[1])
|
||||||
addf(p.body, "}$n" | "}L$#:;$n", [labl])
|
lineF(p, "}$n" | "}L$#:;$n", [labl])
|
||||||
setLen(p.blocks, length)
|
setLen(p.blocks, length)
|
||||||
|
|
||||||
proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
|
proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
|
||||||
if src.kind != resNone:
|
if src.kind != resNone:
|
||||||
if dest.kind != resNone:
|
if dest.kind != resNone:
|
||||||
p.body.addf("$1 = $2;$n", [dest.rdLoc, src.rdLoc])
|
lineF(p, "$1 = $2;$n", [dest.rdLoc, src.rdLoc])
|
||||||
else:
|
else:
|
||||||
p.body.addf("$1;$n", [src.rdLoc])
|
lineF(p, "$1;$n", [src.rdLoc])
|
||||||
src.kind = resNone
|
src.kind = resNone
|
||||||
src.res = nil
|
src.res = nil
|
||||||
|
|
||||||
|
|
@ -620,8 +650,8 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
var tmpFramePtr = rope"F"
|
var tmpFramePtr = rope"F"
|
||||||
if optStackTrace notin p.options:
|
if optStackTrace notin p.options:
|
||||||
tmpFramePtr = p.getTemp(true)
|
tmpFramePtr = p.getTemp(true)
|
||||||
add(p.body, tmpFramePtr & " = framePtr;" & tnl)
|
line(p, tmpFramePtr & " = framePtr;" & tnl)
|
||||||
addf(p.body, "try {$n", [])
|
lineF(p, "try {$n", [])
|
||||||
if p.target == targetPHP and p.globals == nil:
|
if p.target == targetPHP and p.globals == nil:
|
||||||
p.globals = "global $lastJSError; global $prevJSError;".rope
|
p.globals = "global $lastJSError; global $prevJSError;".rope
|
||||||
var a: TCompRes
|
var a: TCompRes
|
||||||
|
|
@ -632,18 +662,18 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
if p.target == targetJS and catchBranchesExist:
|
if p.target == targetJS and catchBranchesExist:
|
||||||
addf(p.body, "--excHandler;$n} catch (EXC) {$n var prevJSError = lastJSError;$n" &
|
addf(p.body, "--excHandler;$n} catch (EXC) {$n var prevJSError = lastJSError;$n" &
|
||||||
" lastJSError = EXC;$n --excHandler;$n", [])
|
" lastJSError = EXC;$n --excHandler;$n", [])
|
||||||
add(p.body, "framePtr = $1;$n" % [tmpFramePtr])
|
line(p, "framePtr = $1;$n" % [tmpFramePtr])
|
||||||
elif p.target == targetPHP:
|
elif p.target == targetPHP:
|
||||||
addf(p.body, "} catch (Exception $$EXC) {$n $$prevJSError = $$lastJSError;$n $$lastJSError = $$EXC;$n", [])
|
lineF(p, "} catch (Exception $$EXC) {$n $$prevJSError = $$lastJSError;$n $$lastJSError = $$EXC;$n", [])
|
||||||
while i < length and n.sons[i].kind == nkExceptBranch:
|
while i < length and n.sons[i].kind == nkExceptBranch:
|
||||||
let blen = sonsLen(n.sons[i])
|
let blen = sonsLen(n.sons[i])
|
||||||
if blen == 1:
|
if blen == 1:
|
||||||
# general except section:
|
# general except section:
|
||||||
generalCatchBranchExists = true
|
generalCatchBranchExists = true
|
||||||
if i > 1: addf(p.body, "else {$n", [])
|
if i > 1: lineF(p, "else {$n", [])
|
||||||
gen(p, n.sons[i].sons[0], a)
|
gen(p, n.sons[i].sons[0], a)
|
||||||
moveInto(p, a, r)
|
moveInto(p, a, r)
|
||||||
if i > 1: addf(p.body, "}$n", [])
|
if i > 1: lineF(p, "}$n", [])
|
||||||
else:
|
else:
|
||||||
var orExpr: Rope = nil
|
var orExpr: Rope = nil
|
||||||
useMagic(p, "isObj")
|
useMagic(p, "isObj")
|
||||||
|
|
@ -653,30 +683,32 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
if orExpr != nil: add(orExpr, "||")
|
if orExpr != nil: add(orExpr, "||")
|
||||||
addf(orExpr, "isObj($2lastJSError.m_type, $1)",
|
addf(orExpr, "isObj($2lastJSError.m_type, $1)",
|
||||||
[genTypeInfo(p, n.sons[i].sons[j].typ), dollar])
|
[genTypeInfo(p, n.sons[i].sons[j].typ), dollar])
|
||||||
if i > 1: add(p.body, "else ")
|
if i > 1: line(p, "else ")
|
||||||
addf(p.body, "if ($1lastJSError && ($2)) {$n", [dollar, orExpr])
|
lineF(p, "if ($1lastJSError && ($2)) {$n", [dollar, orExpr])
|
||||||
gen(p, n.sons[i].sons[blen - 1], a)
|
gen(p, n.sons[i].sons[blen - 1], a)
|
||||||
moveInto(p, a, r)
|
moveInto(p, a, r)
|
||||||
addf(p.body, "}$n", [])
|
lineF(p, "}$n", [])
|
||||||
inc(i)
|
inc(i)
|
||||||
if catchBranchesExist:
|
if catchBranchesExist:
|
||||||
if not generalCatchBranchExists:
|
if not generalCatchBranchExists:
|
||||||
useMagic(p, "reraiseException")
|
useMagic(p, "reraiseException")
|
||||||
add(p.body, "else {" & tnl & "reraiseException();" & tnl & "}" & tnl)
|
line(p, "else {" & tnl)
|
||||||
|
line(p, indent & "reraiseException();" & tnl)
|
||||||
|
line(p, "}" & tnl)
|
||||||
addf(p.body, "$1lastJSError = $1prevJSError;$n", [dollar])
|
addf(p.body, "$1lastJSError = $1prevJSError;$n", [dollar])
|
||||||
if p.target == targetJS:
|
if p.target == targetJS:
|
||||||
add(p.body, "} finally {" & tnl)
|
line(p, "} finally {" & tnl)
|
||||||
add(p.body, "framePtr = $1;$n" % [tmpFramePtr])
|
line(p, "framePtr = $1;$n" % [tmpFramePtr])
|
||||||
if p.target == targetPHP:
|
if p.target == targetPHP:
|
||||||
# XXX ugly hack for PHP codegen
|
# XXX ugly hack for PHP codegen
|
||||||
add(p.body, "}" & tnl)
|
line(p, "}" & tnl)
|
||||||
if i < length and n.sons[i].kind == nkFinally:
|
if i < length and n.sons[i].kind == nkFinally:
|
||||||
genStmt(p, n.sons[i].sons[0])
|
genStmt(p, n.sons[i].sons[0])
|
||||||
if p.target == targetPHP:
|
if p.target == targetPHP:
|
||||||
# XXX ugly hack for PHP codegen
|
# XXX ugly hack for PHP codegen
|
||||||
add(p.body, "if($lastJSError) throw($lastJSError);" & tnl)
|
line(p, "if($lastJSError) throw($lastJSError);" & tnl)
|
||||||
if p.target == targetJS:
|
if p.target == targetJS:
|
||||||
add(p.body, "}" & tnl)
|
line(p, "}" & tnl)
|
||||||
|
|
||||||
proc genRaiseStmt(p: PProc, n: PNode) =
|
proc genRaiseStmt(p: PProc, n: PNode) =
|
||||||
genLineDir(p, n)
|
genLineDir(p, n)
|
||||||
|
|
@ -685,11 +717,11 @@ proc genRaiseStmt(p: PProc, n: PNode) =
|
||||||
gen(p, n.sons[0], a)
|
gen(p, n.sons[0], a)
|
||||||
let typ = skipTypes(n.sons[0].typ, abstractPtrs)
|
let typ = skipTypes(n.sons[0].typ, abstractPtrs)
|
||||||
useMagic(p, "raiseException")
|
useMagic(p, "raiseException")
|
||||||
addf(p.body, "raiseException($1, $2);$n",
|
lineF(p, "raiseException($1, $2);$n",
|
||||||
[a.rdLoc, makeJSString(typ.sym.name.s)])
|
[a.rdLoc, makeJSString(typ.sym.name.s)])
|
||||||
else:
|
else:
|
||||||
useMagic(p, "reraiseException")
|
useMagic(p, "reraiseException")
|
||||||
add(p.body, "reraiseException();" & tnl)
|
line(p, "reraiseException();" & tnl)
|
||||||
|
|
||||||
proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
|
proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
var
|
var
|
||||||
|
|
@ -699,9 +731,9 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
let stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString
|
let stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString
|
||||||
if stringSwitch and p.target == targetJS:
|
if stringSwitch and p.target == targetJS:
|
||||||
useMagic(p, "toJSStr")
|
useMagic(p, "toJSStr")
|
||||||
addf(p.body, "switch (toJSStr($1)) {$n", [cond.rdLoc])
|
lineF(p, "switch (toJSStr($1)) {$n", [cond.rdLoc])
|
||||||
else:
|
else:
|
||||||
addf(p.body, "switch ($1) {$n", [cond.rdLoc])
|
lineF(p, "switch ($1) {$n", [cond.rdLoc])
|
||||||
if not isEmptyType(n.typ):
|
if not isEmptyType(n.typ):
|
||||||
r.kind = resVal
|
r.kind = resVal
|
||||||
r.res = getTemp(p)
|
r.res = getTemp(p)
|
||||||
|
|
@ -715,27 +747,29 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
var v = copyNode(e.sons[0])
|
var v = copyNode(e.sons[0])
|
||||||
while v.intVal <= e.sons[1].intVal:
|
while v.intVal <= e.sons[1].intVal:
|
||||||
gen(p, v, cond)
|
gen(p, v, cond)
|
||||||
addf(p.body, "case $1: ", [cond.rdLoc])
|
lineF(p, "case $1:$n", [cond.rdLoc])
|
||||||
inc(v.intVal)
|
inc(v.intVal)
|
||||||
else:
|
else:
|
||||||
if stringSwitch:
|
if stringSwitch:
|
||||||
case e.kind
|
case e.kind
|
||||||
of nkStrLit..nkTripleStrLit: addf(p.body, "case $1: ",
|
of nkStrLit..nkTripleStrLit: lineF(p, "case $1:$n",
|
||||||
[makeJSString(e.strVal, false)])
|
[makeJSString(e.strVal, false)])
|
||||||
else: internalError(e.info, "jsgen.genCaseStmt: 2")
|
else: internalError(e.info, "jsgen.genCaseStmt: 2")
|
||||||
else:
|
else:
|
||||||
gen(p, e, cond)
|
gen(p, e, cond)
|
||||||
addf(p.body, "case $1: ", [cond.rdLoc])
|
lineF(p, "case $1:$n", [cond.rdLoc])
|
||||||
|
p.nested:
|
||||||
gen(p, lastSon(it), stmt)
|
gen(p, lastSon(it), stmt)
|
||||||
moveInto(p, stmt, r)
|
moveInto(p, stmt, r)
|
||||||
addf(p.body, "$nbreak;$n", [])
|
lineF(p, "break;$n", [])
|
||||||
of nkElse:
|
of nkElse:
|
||||||
addf(p.body, "default: $n", [])
|
lineF(p, "default: $n", [])
|
||||||
|
p.nested:
|
||||||
gen(p, it.sons[0], stmt)
|
gen(p, it.sons[0], stmt)
|
||||||
moveInto(p, stmt, r)
|
moveInto(p, stmt, r)
|
||||||
addf(p.body, "break;$n", [])
|
lineF(p, "break;$n", [])
|
||||||
else: internalError(it.info, "jsgen.genCaseStmt")
|
else: internalError(it.info, "jsgen.genCaseStmt")
|
||||||
addf(p.body, "}$n", [])
|
lineF(p, "}$n", [])
|
||||||
|
|
||||||
proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
|
proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
inc(p.unique)
|
inc(p.unique)
|
||||||
|
|
@ -746,13 +780,13 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
var sym = n.sons[0].sym
|
var sym = n.sons[0].sym
|
||||||
sym.loc.k = locOther
|
sym.loc.k = locOther
|
||||||
sym.position = idx+1
|
sym.position = idx+1
|
||||||
|
let labl = p.unique
|
||||||
|
lineF(p, "L$1: do {$n" | "", [labl.rope])
|
||||||
setLen(p.blocks, idx + 1)
|
setLen(p.blocks, idx + 1)
|
||||||
p.blocks[idx].id = - p.unique # negative because it isn't used yet
|
p.blocks[idx].id = - p.unique # negative because it isn't used yet
|
||||||
let labl = p.unique
|
|
||||||
addf(p.body, "L$1: do {$n" | "", [labl.rope])
|
|
||||||
gen(p, n.sons[1], r)
|
gen(p, n.sons[1], r)
|
||||||
addf(p.body, "} while(false);$n" | "$nL$#:;$n", [labl.rope])
|
|
||||||
setLen(p.blocks, idx)
|
setLen(p.blocks, idx)
|
||||||
|
lineF(p, "} while(false);$n" | "$nL$#:;$n", [labl.rope])
|
||||||
|
|
||||||
proc genBreakStmt(p: PProc, n: PNode) =
|
proc genBreakStmt(p: PProc, n: PNode) =
|
||||||
var idx: int
|
var idx: int
|
||||||
|
|
@ -770,19 +804,31 @@ proc genBreakStmt(p: PProc, n: PNode) =
|
||||||
if idx < 0 or not p.blocks[idx].isLoop:
|
if idx < 0 or not p.blocks[idx].isLoop:
|
||||||
internalError(n.info, "no loop to break")
|
internalError(n.info, "no loop to break")
|
||||||
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
|
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
|
||||||
addf(p.body, "break L$1;$n" | "goto L$1;$n", [rope(p.blocks[idx].id)])
|
lineF(p, "break L$1;$n" | "goto L$1;$n", [rope(p.blocks[idx].id)])
|
||||||
|
|
||||||
proc genAsmOrEmitStmt(p: PProc, n: PNode) =
|
proc genAsmOrEmitStmt(p: PProc, n: PNode) =
|
||||||
genLineDir(p, n)
|
genLineDir(p, n)
|
||||||
|
p.body.add p.indentLine(nil)
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
case n.sons[i].kind
|
let it = n[i]
|
||||||
of nkStrLit..nkTripleStrLit: add(p.body, n.sons[i].strVal)
|
case it.kind
|
||||||
|
of nkStrLit..nkTripleStrLit:
|
||||||
|
p.body.add(it.strVal)
|
||||||
of nkSym:
|
of nkSym:
|
||||||
let v = n.sons[i].sym
|
let v = it.sym
|
||||||
if p.target == targetPHP and v.kind in {skVar, skLet, skTemp, skConst, skResult, skParam, skForVar}:
|
# for backwards compatibility we don't deref syms here :-(
|
||||||
add(p.body, "$")
|
if v.kind in {skVar, skLet, skTemp, skConst, skResult, skParam, skForVar}:
|
||||||
add(p.body, mangleName(v, p.target))
|
if p.target == targetPHP: p.body.add "$"
|
||||||
else: internalError(n.sons[i].info, "jsgen: genAsmOrEmitStmt()")
|
p.body.add mangleName(v, p.target)
|
||||||
|
else:
|
||||||
|
var r: TCompRes
|
||||||
|
gen(p, it, r)
|
||||||
|
p.body.add(r.rdLoc)
|
||||||
|
else:
|
||||||
|
var r: TCompRes
|
||||||
|
gen(p, it, r)
|
||||||
|
p.body.add(r.rdLoc)
|
||||||
|
p.body.add tnl
|
||||||
|
|
||||||
proc genIf(p: PProc, n: PNode, r: var TCompRes) =
|
proc genIf(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
var cond, stmt: TCompRes
|
var cond, stmt: TCompRes
|
||||||
|
|
@ -794,18 +840,18 @@ proc genIf(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
let it = n.sons[i]
|
let it = n.sons[i]
|
||||||
if sonsLen(it) != 1:
|
if sonsLen(it) != 1:
|
||||||
if i > 0:
|
if i > 0:
|
||||||
addf(p.body, "else {$n", [])
|
lineF(p, "else {$n", [])
|
||||||
inc(toClose)
|
inc(toClose)
|
||||||
gen(p, it.sons[0], cond)
|
p.nested: gen(p, it.sons[0], cond)
|
||||||
addf(p.body, "if ($1) {$n", [cond.rdLoc])
|
lineF(p, "if ($1) {$n", [cond.rdLoc])
|
||||||
gen(p, it.sons[1], stmt)
|
gen(p, it.sons[1], stmt)
|
||||||
else:
|
else:
|
||||||
# else part:
|
# else part:
|
||||||
addf(p.body, "else {$n", [])
|
lineF(p, "else {$n", [])
|
||||||
gen(p, it.sons[0], stmt)
|
p.nested: gen(p, it.sons[0], stmt)
|
||||||
moveInto(p, stmt, r)
|
moveInto(p, stmt, r)
|
||||||
addf(p.body, "}$n", [])
|
lineF(p, "}$n", [])
|
||||||
add(p.body, repeat('}', toClose) & tnl)
|
line(p, repeat('}', toClose) & tnl)
|
||||||
|
|
||||||
proc generateHeader(p: PProc, typ: PType): Rope =
|
proc generateHeader(p: PProc, typ: PType): Rope =
|
||||||
result = nil
|
result = nil
|
||||||
|
|
@ -834,6 +880,16 @@ proc generateHeader(p: PProc, typ: PType): Rope =
|
||||||
# add(result, name)
|
# add(result, name)
|
||||||
# add(result, "_Idx")
|
# add(result, "_Idx")
|
||||||
|
|
||||||
|
proc countJsParams(typ: PType): int =
|
||||||
|
for i in countup(1, sonsLen(typ.n) - 1):
|
||||||
|
assert(typ.n.sons[i].kind == nkSym)
|
||||||
|
var param = typ.n.sons[i].sym
|
||||||
|
if isCompileTimeOnly(param.typ): continue
|
||||||
|
if mapType(param.typ) == etyBaseIndex:
|
||||||
|
inc result, 2
|
||||||
|
else:
|
||||||
|
inc result
|
||||||
|
|
||||||
const
|
const
|
||||||
nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
|
nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
|
||||||
nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkObjConstr, nkStringToCString,
|
nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkObjConstr, nkStringToCString,
|
||||||
|
|
@ -854,7 +910,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
||||||
gen(p, x[0], a)
|
gen(p, x[0], a)
|
||||||
gen(p, x[1], b)
|
gen(p, x[1], b)
|
||||||
gen(p, y, c)
|
gen(p, y, c)
|
||||||
addf(p.body, "$#[$#] = chr($#);$n", [a.rdLoc, b.rdLoc, c.rdLoc])
|
lineF(p, "$#[$#] = chr($#);$n", [a.rdLoc, b.rdLoc, c.rdLoc])
|
||||||
return
|
return
|
||||||
|
|
||||||
var xtyp = mapType(p, x.typ)
|
var xtyp = mapType(p, x.typ)
|
||||||
|
|
@ -862,7 +918,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
||||||
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)
|
||||||
let tmp = p.getTemp(false)
|
let tmp = p.getTemp(false)
|
||||||
addf(p.body, "var $1 = $2;$n", [tmp, a.rdLoc])
|
lineF(p, "var $1 = $2;$n", [tmp, a.rdLoc])
|
||||||
a.res = "$1[0][$1[1]]" % [tmp]
|
a.res = "$1[0][$1[1]]" % [tmp]
|
||||||
else:
|
else:
|
||||||
gen(p, x, a)
|
gen(p, x, a)
|
||||||
|
|
@ -876,29 +932,31 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
||||||
case xtyp
|
case xtyp
|
||||||
of etySeq:
|
of etySeq:
|
||||||
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])
|
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
|
||||||
else:
|
else:
|
||||||
useMagic(p, "nimCopy")
|
useMagic(p, "nimCopy")
|
||||||
addf(p.body, "$1 = nimCopy(null, $2, $3);$n",
|
lineF(p, "$1 = nimCopy(null, $2, $3);$n",
|
||||||
[a.rdLoc, b.res, genTypeInfo(p, y.typ)])
|
[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])
|
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
|
||||||
else:
|
else:
|
||||||
useMagic(p, "nimCopy")
|
useMagic(p, "nimCopy")
|
||||||
addf(p.body, "nimCopy($1, $2, $3);$n",
|
lineF(p, "nimCopy($1, $2, $3);$n",
|
||||||
[a.res, b.res, genTypeInfo(p, y.typ)])
|
[a.res, b.res, genTypeInfo(p, y.typ)])
|
||||||
of etyBaseIndex:
|
of etyBaseIndex:
|
||||||
if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
|
if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
|
||||||
if y.kind == nkCall:
|
if y.kind == nkCall:
|
||||||
let tmp = p.getTemp(false)
|
let tmp = p.getTemp(false)
|
||||||
addf(p.body, "var $1 = $4; $2 = $1[0]; $3 = $1[1];$n", [tmp, a.address, a.res, b.rdLoc])
|
lineF(p, "var $1 = $4; $2 = $1[0]; $3 = $1[1];$n", [tmp, a.address, a.res, b.rdLoc])
|
||||||
|
elif b.typ == etyBaseIndex:
|
||||||
|
lineF(p, "$# = $#;$n", [a.res, b.rdLoc])
|
||||||
else:
|
else:
|
||||||
internalError(x.info, "genAsgn")
|
internalError(x.info, "genAsgn")
|
||||||
else:
|
else:
|
||||||
addf(p.body, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
|
lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
|
||||||
else:
|
else:
|
||||||
addf(p.body, "$1 = $2;$n", [a.res, b.res])
|
lineF(p, "$1 = $2;$n", [a.res, b.res])
|
||||||
|
|
||||||
proc genAsgn(p: PProc, n: PNode) =
|
proc genAsgn(p: PProc, n: PNode) =
|
||||||
genLineDir(p, n)
|
genLineDir(p, n)
|
||||||
|
|
@ -906,7 +964,15 @@ proc genAsgn(p: PProc, n: PNode) =
|
||||||
|
|
||||||
proc genFastAsgn(p: PProc, n: PNode) =
|
proc genFastAsgn(p: PProc, n: PNode) =
|
||||||
genLineDir(p, n)
|
genLineDir(p, n)
|
||||||
genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=true)
|
# 'shallowCopy' always produced 'noCopyNeeded = true' here but this is wrong
|
||||||
|
# for code like
|
||||||
|
# while j >= pos:
|
||||||
|
# dest[i].shallowCopy(dest[j])
|
||||||
|
# See bug #5933. So we try to be more compatible with the C backend semantics
|
||||||
|
# here for 'shallowCopy'. This is an educated guess and might require further
|
||||||
|
# changes later:
|
||||||
|
let noCopy = n[0].typ.skipTypes(abstractInst).kind in {tySequence, tyString}
|
||||||
|
genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=noCopy)
|
||||||
|
|
||||||
proc genSwap(p: PProc, n: PNode) =
|
proc genSwap(p: PProc, n: PNode) =
|
||||||
var a, b: TCompRes
|
var a, b: TCompRes
|
||||||
|
|
@ -917,12 +983,13 @@ proc genSwap(p: PProc, n: PNode) =
|
||||||
let tmp2 = p.getTemp(false)
|
let tmp2 = p.getTemp(false)
|
||||||
if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
|
if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
|
||||||
internalError(n.info, "genSwap")
|
internalError(n.info, "genSwap")
|
||||||
addf(p.body, "var $1 = $2; $2 = $3; $3 = $1;$n" |
|
lineF(p, "var $1 = $2; $2 = $3; $3 = $1;$n" |
|
||||||
"$1 = $2; $2 = $3; $3 = $1;$n", [
|
"$1 = $2; $2 = $3; $3 = $1;$n",
|
||||||
tmp, a.address, b.address])
|
[tmp, a.address, b.address])
|
||||||
tmp = tmp2
|
tmp = tmp2
|
||||||
addf(p.body, "var $1 = $2; $2 = $3; $3 = $1;" |
|
lineF(p, "var $1 = $2; $2 = $3; $3 = $1;" |
|
||||||
"$1 = $2; $2 = $3; $3 = $1;", [tmp, a.res, b.res])
|
"$1 = $2; $2 = $3; $3 = $1;",
|
||||||
|
[tmp, a.res, b.res])
|
||||||
|
|
||||||
proc getFieldPosition(f: PNode): int =
|
proc getFieldPosition(f: PNode): int =
|
||||||
case f.kind
|
case f.kind
|
||||||
|
|
@ -992,15 +1059,15 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
var typ = skipTypes(m.sons[0].typ, abstractPtrs)
|
var typ = skipTypes(m.sons[0].typ, abstractPtrs)
|
||||||
if typ.kind == tyArray: first = firstOrd(typ.sons[0])
|
if typ.kind == tyArray: first = firstOrd(typ.sons[0])
|
||||||
else: first = 0
|
else: first = 0
|
||||||
if optBoundsCheck in p.options and not isConstExpr(m.sons[1]):
|
if optBoundsCheck in p.options:
|
||||||
useMagic(p, "chckIndx")
|
useMagic(p, "chckIndx")
|
||||||
if p.target == targetPHP:
|
if p.target == targetPHP:
|
||||||
if typ.kind != tyString:
|
if typ.kind != tyString:
|
||||||
r.res = "chckIndx($1, $2, count($3))-$2" % [b.res, rope(first), a.res]
|
r.res = "chckIndx($1, $2, count($3)-1)-$2" % [b.res, rope(first), a.res]
|
||||||
else:
|
else:
|
||||||
r.res = "chckIndx($1, $2, strlen($3))-$2" % [b.res, rope(first), a.res]
|
r.res = "chckIndx($1, $2, strlen($3))-$2" % [b.res, rope(first), a.res]
|
||||||
else:
|
else:
|
||||||
r.res = "chckIndx($1, $2, $3.length)-$2" % [b.res, rope(first), a.res]
|
r.res = "chckIndx($1, $2, $3.length-1)-$2" % [b.res, rope(first), a.res]
|
||||||
elif first != 0:
|
elif first != 0:
|
||||||
r.res = "($1)-$2" % [b.res, rope(first)]
|
r.res = "($1)-$2" % [b.res, rope(first)]
|
||||||
else:
|
else:
|
||||||
|
|
@ -1193,17 +1260,21 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
r.kind = resVal
|
r.kind = resVal
|
||||||
|
|
||||||
proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
|
proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
if mapType(p, n.sons[0].typ) == etyObject:
|
let it = n.sons[0]
|
||||||
gen(p, n.sons[0], r)
|
let t = mapType(p, it.typ)
|
||||||
|
if t == etyObject:
|
||||||
|
gen(p, it, r)
|
||||||
else:
|
else:
|
||||||
var a: TCompRes
|
var a: TCompRes
|
||||||
gen(p, n.sons[0], a)
|
gen(p, it, a)
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
if a.typ == etyBaseIndex:
|
if a.typ == etyBaseIndex:
|
||||||
r.res = "$1[$2]" % [a.address, a.res]
|
r.res = "$1[$2]" % [a.address, a.res]
|
||||||
elif n.sons[0].kind == nkCall:
|
elif it.kind == nkCall:
|
||||||
let tmp = p.getTemp
|
let tmp = p.getTemp
|
||||||
r.res = "($1 = $2, $1[0])[$1[1]]" % [tmp, a.res]
|
r.res = "($1 = $2, $1[0])[$1[1]]" % [tmp, a.res]
|
||||||
|
elif t == etyBaseIndex:
|
||||||
|
r.res = "$1[0]" % [a.res]
|
||||||
else:
|
else:
|
||||||
internalError(n.info, "genDeref")
|
internalError(n.info, "genDeref")
|
||||||
|
|
||||||
|
|
@ -1217,7 +1288,7 @@ proc genArgNoParam(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
else:
|
else:
|
||||||
add(r.res, a.res)
|
add(r.res, a.res)
|
||||||
|
|
||||||
proc genArg(p: PProc, n: PNode, param: PSym, r: var TCompRes) =
|
proc genArg(p: PProc, n: PNode, param: PSym, r: var TCompRes; emitted: ptr int = nil) =
|
||||||
var a: TCompRes
|
var a: TCompRes
|
||||||
gen(p, n, a)
|
gen(p, n, a)
|
||||||
if skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs} and
|
if skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs} and
|
||||||
|
|
@ -1227,6 +1298,12 @@ proc genArg(p: PProc, n: PNode, param: PSym, r: var TCompRes) =
|
||||||
add(r.res, a.address)
|
add(r.res, a.address)
|
||||||
add(r.res, ", ")
|
add(r.res, ", ")
|
||||||
add(r.res, a.res)
|
add(r.res, a.res)
|
||||||
|
if emitted != nil: inc emitted[]
|
||||||
|
elif n.typ.kind == tyVar and n.kind in nkCallKinds and mapType(param.typ) == etyBaseIndex:
|
||||||
|
# this fixes bug #5608:
|
||||||
|
let tmp = getTemp(p)
|
||||||
|
add(r.res, "($1 = $2, $1[0]), $1[1]" % [tmp, a.rdLoc])
|
||||||
|
if emitted != nil: inc emitted[]
|
||||||
else:
|
else:
|
||||||
add(r.res, a.res)
|
add(r.res, a.res)
|
||||||
|
|
||||||
|
|
@ -1237,6 +1314,7 @@ proc genArgs(p: PProc, n: PNode, r: var TCompRes; start=1) =
|
||||||
var typ = skipTypes(n.sons[0].typ, abstractInst)
|
var typ = skipTypes(n.sons[0].typ, abstractInst)
|
||||||
assert(typ.kind == tyProc)
|
assert(typ.kind == tyProc)
|
||||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||||
|
var emitted = start-1
|
||||||
|
|
||||||
for i in countup(start, sonsLen(n) - 1):
|
for i in countup(start, sonsLen(n) - 1):
|
||||||
let it = n.sons[i]
|
let it = n.sons[i]
|
||||||
|
|
@ -1250,9 +1328,16 @@ proc genArgs(p: PProc, n: PNode, r: var TCompRes; start=1) =
|
||||||
if paramType.isNil:
|
if paramType.isNil:
|
||||||
genArgNoParam(p, it, r)
|
genArgNoParam(p, it, r)
|
||||||
else:
|
else:
|
||||||
genArg(p, it, paramType.sym, r)
|
genArg(p, it, paramType.sym, r, addr emitted)
|
||||||
|
inc emitted
|
||||||
hasArgs = true
|
hasArgs = true
|
||||||
add(r.res, ")")
|
add(r.res, ")")
|
||||||
|
when false:
|
||||||
|
# XXX look into this:
|
||||||
|
let jsp = countJsParams(typ)
|
||||||
|
if emitted != jsp and tfVarargs notin typ.flags:
|
||||||
|
localError(n.info, "wrong number of parameters emitted; expected: " & $jsp &
|
||||||
|
" but got: " & $emitted)
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
|
|
||||||
proc genOtherArg(p: PProc; n: PNode; i: int; typ: PType;
|
proc genOtherArg(p: PProc; n: PNode; i: int; typ: PType;
|
||||||
|
|
@ -1385,7 +1470,7 @@ proc createRecordVarAux(p: PProc, rec: PNode, excludedFieldIDs: IntSet, output:
|
||||||
|
|
||||||
proc createObjInitList(p: PProc, typ: PType, excludedFieldIDs: IntSet, output: var Rope) =
|
proc createObjInitList(p: PProc, typ: PType, excludedFieldIDs: IntSet, output: var Rope) =
|
||||||
var t = typ
|
var t = typ
|
||||||
if tfFinal notin t.flags or t.sons[0] != nil:
|
if objHasTypeField(t):
|
||||||
if output.len > 0: output.add(", ")
|
if output.len > 0: output.add(", ")
|
||||||
addf(output, "m_type: $1" | "'m_type' => $#", [genTypeInfo(p, t)])
|
addf(output, "m_type: $1" | "'m_type' => $#", [genTypeInfo(p, t)])
|
||||||
while t != nil:
|
while t != nil:
|
||||||
|
|
@ -1483,10 +1568,10 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
||||||
s: Rope
|
s: Rope
|
||||||
if n.kind == nkEmpty:
|
if n.kind == nkEmpty:
|
||||||
let mname = mangleName(v, p.target)
|
let mname = mangleName(v, p.target)
|
||||||
addf(p.body, "var $1 = $2;$n" | "$$$1 = $2;$n",
|
lineF(p, "var $1 = $2;$n" | "$$$1 = $2;$n",
|
||||||
[mname, createVar(p, v.typ, isIndirect(v))])
|
[mname, createVar(p, v.typ, isIndirect(v))])
|
||||||
if v.typ.kind in { tyVar, tyPtr, tyRef } and mapType(p, v.typ) == etyBaseIndex:
|
if v.typ.kind in { tyVar, tyPtr, tyRef } and mapType(p, v.typ) == etyBaseIndex:
|
||||||
addf(p.body, "var $1_Idx = 0;$n", [ mname ])
|
lineF(p, "var $1_Idx = 0;$n", [ mname ])
|
||||||
else:
|
else:
|
||||||
discard mangleName(v, p.target)
|
discard mangleName(v, p.target)
|
||||||
gen(p, n, a)
|
gen(p, n, a)
|
||||||
|
|
@ -1501,25 +1586,25 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
||||||
let targetBaseIndex = {sfAddrTaken, sfGlobal} * v.flags == {}
|
let targetBaseIndex = {sfAddrTaken, sfGlobal} * v.flags == {}
|
||||||
if a.typ == etyBaseIndex:
|
if a.typ == etyBaseIndex:
|
||||||
if targetBaseIndex:
|
if targetBaseIndex:
|
||||||
addf(p.body, "var $1 = $2, $1_Idx = $3;$n", [
|
lineF(p, "var $1 = $2, $1_Idx = $3;$n",
|
||||||
v.loc.r, a.address, a.res])
|
[v.loc.r, a.address, a.res])
|
||||||
else:
|
else:
|
||||||
addf(p.body, "var $1 = [$2, $3];$n",
|
lineF(p, "var $1 = [$2, $3];$n",
|
||||||
[v.loc.r, a.address, a.res])
|
[v.loc.r, a.address, a.res])
|
||||||
else:
|
else:
|
||||||
if targetBaseIndex:
|
if targetBaseIndex:
|
||||||
let tmp = p.getTemp
|
let tmp = p.getTemp
|
||||||
addf(p.body, "var $1 = $2, $3 = $1[0], $3_Idx = $1[1];$n",
|
lineF(p, "var $1 = $2, $3 = $1[0], $3_Idx = $1[1];$n",
|
||||||
[tmp, a.res, v.loc.r])
|
[tmp, a.res, v.loc.r])
|
||||||
else:
|
else:
|
||||||
addf(p.body, "var $1 = $2;$n", [v.loc.r, a.res])
|
lineF(p, "var $1 = $2;$n", [v.loc.r, a.res])
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
s = a.res
|
s = a.res
|
||||||
if isIndirect(v):
|
if isIndirect(v):
|
||||||
addf(p.body, "var $1 = /**/[$2];$n", [v.loc.r, s])
|
lineF(p, "var $1 = [$2];$n", [v.loc.r, s])
|
||||||
else:
|
else:
|
||||||
addf(p.body, "var $1 = $2;$n" | "$$$1 = $2;$n", [v.loc.r, s])
|
lineF(p, "var $1 = $2;$n" | "$$$1 = $2;$n", [v.loc.r, s])
|
||||||
|
|
||||||
proc genVarStmt(p: PProc, n: PNode) =
|
proc genVarStmt(p: PProc, n: PNode) =
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
|
|
@ -1550,16 +1635,16 @@ proc genNew(p: PProc, n: PNode) =
|
||||||
gen(p, n.sons[1], a)
|
gen(p, n.sons[1], a)
|
||||||
var t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
|
var t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
|
||||||
if p.target == targetJS:
|
if p.target == targetJS:
|
||||||
addf(p.body, "$1 = $2;$n", [a.res, createVar(p, t, false)])
|
lineF(p, "$1 = $2;$n", [a.res, createVar(p, t, false)])
|
||||||
else:
|
else:
|
||||||
addf(p.body, "$3 = $2; $1 = &$3;$n", [a.res, createVar(p, t, false), getTemp(p)])
|
lineF(p, "$3 = $2; $1 = &$3;$n", [a.res, createVar(p, t, false), getTemp(p)])
|
||||||
|
|
||||||
proc genNewSeq(p: PProc, n: PNode) =
|
proc genNewSeq(p: PProc, n: PNode) =
|
||||||
var x, y: TCompRes
|
var x, y: TCompRes
|
||||||
gen(p, n.sons[1], x)
|
gen(p, n.sons[1], x)
|
||||||
gen(p, n.sons[2], y)
|
gen(p, n.sons[2], y)
|
||||||
let t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
|
let t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
|
||||||
addf(p.body, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}" |
|
lineF(p, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}" |
|
||||||
"$1 = array(); for ($$i=0;$$i<$2;++$$i) {$1[]=$3;}", [
|
"$1 = array(); for ($$i=0;$$i<$2;++$$i) {$1[]=$3;}", [
|
||||||
x.rdLoc, y.rdLoc, createVar(p, t, false)])
|
x.rdLoc, y.rdLoc, createVar(p, t, false)])
|
||||||
|
|
||||||
|
|
@ -1716,8 +1801,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
binaryExpr(p, n, r, "addChar",
|
binaryExpr(p, n, r, "addChar",
|
||||||
"if ($1 != null) { addChar($1, $2); } else { $1 = [$2, 0]; }")
|
"if ($1 != null) { addChar($1, $2); } else { $1 = [$2, 0]; }")
|
||||||
else:
|
else:
|
||||||
binaryExpr(p, n, r, "",
|
binaryExpr(p, n, r, "", "$1 .= chr($2)")
|
||||||
"$1 .= chr($2)")
|
|
||||||
of mAppendStrStr:
|
of mAppendStrStr:
|
||||||
if p.target == targetJS:
|
if p.target == targetJS:
|
||||||
if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString:
|
if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString:
|
||||||
|
|
@ -1727,15 +1811,23 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
"if ($1 != null) { $1 = ($1.slice(0, -1)).concat($2); } else { $1 = $2;}")
|
"if ($1 != null) { $1 = ($1.slice(0, -1)).concat($2); } else { $1 = $2;}")
|
||||||
# XXX: make a copy of $2, because of Javascript's sucking semantics
|
# XXX: make a copy of $2, because of Javascript's sucking semantics
|
||||||
else:
|
else:
|
||||||
binaryExpr(p, n, r, "",
|
binaryExpr(p, n, r, "", "$1 .= $2;")
|
||||||
"$1 .= $2;")
|
|
||||||
of mAppendSeqElem:
|
of mAppendSeqElem:
|
||||||
if p.target == targetJS:
|
if p.target == targetJS:
|
||||||
binaryExpr(p, n, r, "",
|
var x, y: TCompRes
|
||||||
"if ($1 != null) { $1.push($2); } else { $1 = [$2]; }")
|
gen(p, n.sons[1], x)
|
||||||
|
gen(p, n.sons[2], y)
|
||||||
|
if needsNoCopy(p, n[2]):
|
||||||
|
r.res = "if ($1 != null) { $1.push($2); } else { $1 = [$2]; }" % [x.rdLoc, y.rdLoc]
|
||||||
else:
|
else:
|
||||||
binaryExpr(p, n, r, "",
|
useMagic(p, "nimCopy")
|
||||||
"$1[] = $2")
|
let c = getTemp(p, defineInLocals=false)
|
||||||
|
lineF(p, "var $1 = nimCopy(null, $2, $3);$n",
|
||||||
|
[c, y.rdLoc, genTypeInfo(p, n[2].typ)])
|
||||||
|
r.res = "if ($1 != null) { $1.push($2); } else { $1 = [$2]; }" % [x.rdLoc, c]
|
||||||
|
r.kind = resExpr
|
||||||
|
else:
|
||||||
|
binaryExpr(p, n, r, "", "$1[] = $2")
|
||||||
of mConStrStr:
|
of mConStrStr:
|
||||||
if p.target == targetJS:
|
if p.target == targetJS:
|
||||||
genConStrStr(p, n, r)
|
genConStrStr(p, n, r)
|
||||||
|
|
@ -1795,7 +1887,14 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)")
|
else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)")
|
||||||
of mSetLengthStr:
|
of mSetLengthStr:
|
||||||
binaryExpr(p, n, r, "", "$1.length = $2+1; $1[$1.length-1] = 0" | "$1 = substr($1, 0, $2)")
|
binaryExpr(p, n, r, "", "$1.length = $2+1; $1[$1.length-1] = 0" | "$1 = substr($1, 0, $2)")
|
||||||
of mSetLengthSeq: binaryExpr(p, n, r, "", "$1.length = $2" | "$1 = array_slice($1, 0, $2)")
|
of mSetLengthSeq:
|
||||||
|
var x, y: TCompRes
|
||||||
|
gen(p, n.sons[1], x)
|
||||||
|
gen(p, n.sons[2], y)
|
||||||
|
let t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
|
||||||
|
r.res = """if ($1.length < $2) { for (var i=$1.length;i<$2;++i) $1.push($3); }
|
||||||
|
else { $1.length = $2; }""" % [x.rdLoc, y.rdLoc, createVar(p, t, false)]
|
||||||
|
r.kind = resExpr
|
||||||
of mCard: unaryExpr(p, n, r, "SetCard", "SetCard($1)")
|
of mCard: unaryExpr(p, n, r, "SetCard", "SetCard($1)")
|
||||||
of mLtSet: binaryExpr(p, n, r, "SetLt", "SetLt($1, $2)")
|
of mLtSet: binaryExpr(p, n, r, "SetLt", "SetLt($1, $2)")
|
||||||
of mLeSet: binaryExpr(p, n, r, "SetLe", "SetLe($1, $2)")
|
of mLeSet: binaryExpr(p, n, r, "SetLe", "SetLe($1, $2)")
|
||||||
|
|
@ -1916,10 +2015,19 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
if i > 1: add(initList, ", ")
|
if i > 1: add(initList, ", ")
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
internalAssert it.kind == nkExprColonExpr
|
internalAssert it.kind == nkExprColonExpr
|
||||||
gen(p, it.sons[1], a)
|
let val = it.sons[1]
|
||||||
|
gen(p, val, a)
|
||||||
var f = it.sons[0].sym
|
var f = it.sons[0].sym
|
||||||
if f.loc.r == nil: f.loc.r = mangleName(f, p.target)
|
if f.loc.r == nil: f.loc.r = mangleName(f, p.target)
|
||||||
fieldIDs.incl(f.id)
|
fieldIDs.incl(f.id)
|
||||||
|
|
||||||
|
let typ = val.typ.skipTypes(abstractInst)
|
||||||
|
if (typ.kind in IntegralTypes+{tyCstring, tyRef, tyPtr} and
|
||||||
|
mapType(p, typ) != etyBaseIndex) or needsNoCopy(p, it.sons[1]):
|
||||||
|
discard
|
||||||
|
else:
|
||||||
|
useMagic(p, "nimCopy")
|
||||||
|
a.res = "nimCopy(null, $1, $2)" % [a.rdLoc, genTypeInfo(p, typ)]
|
||||||
addf(initList, "$#: $#" | "'$#' => $#" , [f.loc.r, a.res])
|
addf(initList, "$#: $#" | "'$#' => $#" , [f.loc.r, a.res])
|
||||||
let t = skipTypes(n.typ, abstractInst + skipPtrs)
|
let t = skipTypes(n.typ, abstractInst + skipPtrs)
|
||||||
createObjInitList(p, t, fieldIDs, initList)
|
createObjInitList(p, t, fieldIDs, initList)
|
||||||
|
|
@ -1986,15 +2094,18 @@ proc genReturnStmt(p: PProc, n: PNode) =
|
||||||
genStmt(p, n.sons[0])
|
genStmt(p, n.sons[0])
|
||||||
else:
|
else:
|
||||||
genLineDir(p, n)
|
genLineDir(p, n)
|
||||||
addf(p.body, "break BeforeRet;$n" | "goto BeforeRet;$n", [])
|
lineF(p, "break BeforeRet;$n" | "goto BeforeRet;$n", [])
|
||||||
|
|
||||||
proc frameCreate(p: PProc; procname, filename: Rope): Rope =
|
proc frameCreate(p: PProc; procname, filename: Rope): Rope =
|
||||||
result = (("var F={procname:$1,prev:framePtr,filename:$2,line:0};$nframePtr = F;$n" |
|
let frameFmt =
|
||||||
"global $$framePtr; $$F=array('procname'=>$#,'prev'=>$$framePtr,'filename'=>$#,'line'=>0);$n$$framePtr = &$$F;$n")) % [
|
"var F={procname:$1,prev:framePtr,filename:$2,line:0};$n" |
|
||||||
procname, filename]
|
"global $$framePtr; $$F=array('procname'=>$#,'prev'=>$$framePtr,'filename'=>$#,'line'=>0);$n"
|
||||||
|
|
||||||
|
result = p.indentLine(frameFmt % [procname, filename])
|
||||||
|
result.add p.indentLine(ropes.`%`("framePtr = F;$n" | "$$framePtr = &$$F;$n", []))
|
||||||
|
|
||||||
proc frameDestroy(p: PProc): Rope =
|
proc frameDestroy(p: PProc): Rope =
|
||||||
result = rope(("framePtr = F.prev;" | "$framePtr = $F['prev'];") & tnl)
|
result = p.indentLine rope(("framePtr = F.prev;" | "$framePtr = $F['prev'];") & tnl)
|
||||||
|
|
||||||
proc genProcBody(p: PProc, prc: PSym): Rope =
|
proc genProcBody(p: PProc, prc: PSym): Rope =
|
||||||
if hasFrameInfo(p):
|
if hasFrameInfo(p):
|
||||||
|
|
@ -2004,8 +2115,12 @@ proc genProcBody(p: PProc, prc: PSym): Rope =
|
||||||
else:
|
else:
|
||||||
result = nil
|
result = nil
|
||||||
if p.beforeRetNeeded:
|
if p.beforeRetNeeded:
|
||||||
addf(result, "BeforeRet: do {$n$1} while (false); $n" |
|
if p.target == targetJS:
|
||||||
"$# BeforeRet:;$n", [p.body])
|
result.add p.indentLine(~"BeforeRet: do {$n")
|
||||||
|
result.add p.body
|
||||||
|
result.add p.indentLine(~"} while (false);$n")
|
||||||
|
else:
|
||||||
|
addF(result, "$# BeforeRet:;$n", [p.body])
|
||||||
else:
|
else:
|
||||||
add(result, p.body)
|
add(result, p.body)
|
||||||
if prc.typ.callConv == ccSysCall and p.target == targetJS:
|
if prc.typ.callConv == ccSysCall and p.target == targetJS:
|
||||||
|
|
@ -2014,6 +2129,12 @@ proc genProcBody(p: PProc, prc: PSym): Rope =
|
||||||
if hasFrameInfo(p):
|
if hasFrameInfo(p):
|
||||||
add(result, frameDestroy(p))
|
add(result, frameDestroy(p))
|
||||||
|
|
||||||
|
proc optionaLine(p: Rope): Rope =
|
||||||
|
if p == nil:
|
||||||
|
return nil
|
||||||
|
else:
|
||||||
|
return p & tnl
|
||||||
|
|
||||||
proc genProc(oldProc: PProc, prc: PSym): Rope =
|
proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||||
var
|
var
|
||||||
resultSym: PSym
|
resultSym: PSym
|
||||||
|
|
@ -2029,29 +2150,37 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||||
if prc.typ.sons[0] != nil and sfPure notin prc.flags:
|
if prc.typ.sons[0] != nil and sfPure notin prc.flags:
|
||||||
resultSym = prc.ast.sons[resultPos].sym
|
resultSym = prc.ast.sons[resultPos].sym
|
||||||
let mname = mangleName(resultSym, p.target)
|
let mname = mangleName(resultSym, p.target)
|
||||||
resultAsgn = ("var $# = $#;$n" | "$$$# = $#;$n") % [
|
let resVar = createVar(p, resultSym.typ, isIndirect(resultSym))
|
||||||
mname,
|
resultAsgn = p.indentLine(("var $# = $#;$n" | "$$$# = $#;$n") % [mname, resVar])
|
||||||
createVar(p, resultSym.typ, isIndirect(resultSym))]
|
|
||||||
if resultSym.typ.kind in { tyVar, tyPtr, tyRef } and mapType(p, resultSym.typ) == etyBaseIndex:
|
if resultSym.typ.kind in { tyVar, tyPtr, tyRef } and mapType(p, resultSym.typ) == etyBaseIndex:
|
||||||
resultAsgn.add "var $#_Idx = 0;$n" % [
|
resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname])
|
||||||
mname ];
|
|
||||||
gen(p, prc.ast.sons[resultPos], a)
|
gen(p, prc.ast.sons[resultPos], a)
|
||||||
if mapType(p, resultSym.typ) == etyBaseIndex:
|
if mapType(p, resultSym.typ) == etyBaseIndex:
|
||||||
returnStmt = "return [$#, $#];$n" % [a.address, a.res]
|
returnStmt = "return [$#, $#];$n" % [a.address, a.res]
|
||||||
else:
|
else:
|
||||||
returnStmt = "return $#;$n" % [a.res]
|
returnStmt = "return $#;$n" % [a.res]
|
||||||
genStmt(p, prc.getBody)
|
|
||||||
|
|
||||||
result = "function $#($#) {$n$#$n$#$#$#$#}$n" %
|
p.nested: genStmt(p, prc.getBody)
|
||||||
[name, header, p.globals, p.locals, resultAsgn,
|
let def = "function $#($#) {$n$#$#$#$#$#" %
|
||||||
genProcBody(p, prc), returnStmt]
|
[name, header,
|
||||||
|
optionaLine(p.globals),
|
||||||
|
optionaLine(p.locals),
|
||||||
|
optionaLine(resultAsgn),
|
||||||
|
optionaLine(genProcBody(p, prc)),
|
||||||
|
optionaLine(p.indentLine(returnStmt))]
|
||||||
|
|
||||||
|
dec p.extraIndent
|
||||||
|
result = ~tnl
|
||||||
|
result.add p.indentLine(def)
|
||||||
|
result.add p.indentLine(~"}$n")
|
||||||
|
|
||||||
#if gVerbosity >= 3:
|
#if gVerbosity >= 3:
|
||||||
# echo "END generated code for: " & prc.name.s
|
# echo "END generated code for: " & prc.name.s
|
||||||
|
|
||||||
proc genStmt(p: PProc, n: PNode) =
|
proc genStmt(p: PProc, n: PNode) =
|
||||||
var r: TCompRes
|
var r: TCompRes
|
||||||
gen(p, n, r)
|
gen(p, n, r)
|
||||||
if r.res != nil: addf(p.body, "$#;$n", [r.res])
|
if r.res != nil: lineF(p, "$#;$n", [r.res])
|
||||||
|
|
||||||
proc genPragma(p: PProc, n: PNode) =
|
proc genPragma(p: PProc, n: PNode) =
|
||||||
for it in n.sons:
|
for it in n.sons:
|
||||||
|
|
@ -2211,7 +2340,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
of nkPragma: genPragma(p, n)
|
of nkPragma: genPragma(p, n)
|
||||||
of nkProcDef, nkMethodDef, nkConverterDef:
|
of nkProcDef, nkMethodDef, nkConverterDef:
|
||||||
var s = n.sons[namePos].sym
|
var s = n.sons[namePos].sym
|
||||||
if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}:
|
if sfExportc in s.flags and compilingLib:
|
||||||
genSym(p, n.sons[namePos], r)
|
genSym(p, n.sons[namePos], r)
|
||||||
r.res = nil
|
r.res = nil
|
||||||
of nkGotoState, nkState:
|
of nkGotoState, nkState:
|
||||||
|
|
@ -2342,3 +2471,4 @@ proc myOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext =
|
||||||
result = r
|
result = r
|
||||||
|
|
||||||
const JSgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
|
const JSgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,9 +67,13 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
|
||||||
rope(lengthOrd(field.typ)), makeJSString(field.name.s), result]
|
rope(lengthOrd(field.typ)), makeJSString(field.name.s), result]
|
||||||
else: internalError(n.info, "genObjectFields")
|
else: internalError(n.info, "genObjectFields")
|
||||||
|
|
||||||
|
proc objHasTypeField(t: PType): bool {.inline.} =
|
||||||
|
tfInheritable in t.flags or t.sons[0] != nil
|
||||||
|
|
||||||
proc genObjectInfo(p: PProc, typ: PType, name: Rope) =
|
proc genObjectInfo(p: PProc, typ: PType, name: Rope) =
|
||||||
|
let kind = if objHasTypeField(typ): tyObject else: tyTuple
|
||||||
var s = ("var $1 = {size: 0, kind: $2, base: null, node: null, " &
|
var s = ("var $1 = {size: 0, kind: $2, base: null, node: null, " &
|
||||||
"finalizer: null};$n") % [name, rope(ord(typ.kind))]
|
"finalizer: null};$n") % [name, rope(ord(kind))]
|
||||||
prepend(p.g.typeInfo, s)
|
prepend(p.g.typeInfo, s)
|
||||||
addf(p.g.typeInfo, "var NNI$1 = $2;$n",
|
addf(p.g.typeInfo, "var NNI$1 = $2;$n",
|
||||||
[rope(typ.id), genObjectFields(p, typ, typ.n)])
|
[rope(typ.id), genObjectFields(p, typ, typ.n)])
|
||||||
|
|
|
||||||
|
|
@ -386,11 +386,11 @@ proc getNumber(L: var TLexer, result: var TToken) =
|
||||||
else:
|
else:
|
||||||
matchUnderscoreChars(L, result, {'0'..'9'})
|
matchUnderscoreChars(L, result, {'0'..'9'})
|
||||||
if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}):
|
if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}):
|
||||||
result.tokType = tkFloat64Lit
|
result.tokType = tkFloatLit
|
||||||
eatChar(L, result, '.')
|
eatChar(L, result, '.')
|
||||||
matchUnderscoreChars(L, result, {'0'..'9'})
|
matchUnderscoreChars(L, result, {'0'..'9'})
|
||||||
if L.buf[L.bufpos] in {'e', 'E'}:
|
if L.buf[L.bufpos] in {'e', 'E'}:
|
||||||
result.tokType = tkFloat64Lit
|
result.tokType = tkFloatLit
|
||||||
eatChar(L, result, 'e')
|
eatChar(L, result, 'e')
|
||||||
if L.buf[L.bufpos] in {'+', '-'}:
|
if L.buf[L.bufpos] in {'+', '-'}:
|
||||||
eatChar(L, result)
|
eatChar(L, result)
|
||||||
|
|
@ -516,7 +516,8 @@ proc getNumber(L: var TLexer, result: var TToken) =
|
||||||
result.fNumber = (cast[PFloat32](addr(xi)))[]
|
result.fNumber = (cast[PFloat32](addr(xi)))[]
|
||||||
# note: this code is endian neutral!
|
# note: this code is endian neutral!
|
||||||
# XXX: Test this on big endian machine!
|
# XXX: Test this on big endian machine!
|
||||||
of tkFloat64Lit: result.fNumber = (cast[PFloat64](addr(xi)))[]
|
of tkFloat64Lit, tkFloatLit:
|
||||||
|
result.fNumber = (cast[PFloat64](addr(xi)))[]
|
||||||
else: internalError(getLineInfo(L), "getNumber")
|
else: internalError(getLineInfo(L), "getNumber")
|
||||||
|
|
||||||
# Bounds checks. Non decimal literals are allowed to overflow the range of
|
# Bounds checks. Non decimal literals are allowed to overflow the range of
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,7 @@ type
|
||||||
errGenericLambdaNotAllowed,
|
errGenericLambdaNotAllowed,
|
||||||
errProcHasNoConcreteType,
|
errProcHasNoConcreteType,
|
||||||
errCompilerDoesntSupportTarget,
|
errCompilerDoesntSupportTarget,
|
||||||
|
errInOutFlagNotExtern,
|
||||||
errUser,
|
errUser,
|
||||||
warnCannotOpenFile,
|
warnCannotOpenFile,
|
||||||
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
|
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
|
||||||
|
|
@ -380,6 +381,7 @@ const
|
||||||
"of the generic paramers can be inferred from the expected signature.",
|
"of the generic paramers can be inferred from the expected signature.",
|
||||||
errProcHasNoConcreteType: "'$1' doesn't have a concrete type, due to unspecified generic parameters.",
|
errProcHasNoConcreteType: "'$1' doesn't have a concrete type, due to unspecified generic parameters.",
|
||||||
errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target",
|
errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target",
|
||||||
|
errInOutFlagNotExtern: "The `$1` modifier can be used only with imported types",
|
||||||
errUser: "$1",
|
errUser: "$1",
|
||||||
warnCannotOpenFile: "cannot open \'$1\'",
|
warnCannotOpenFile: "cannot open \'$1\'",
|
||||||
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",
|
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",
|
||||||
|
|
@ -541,7 +543,7 @@ var
|
||||||
|
|
||||||
proc toCChar*(c: char): string =
|
proc toCChar*(c: char): string =
|
||||||
case c
|
case c
|
||||||
of '\0'..'\x1F', '\x80'..'\xFF': result = '\\' & toOctal(c)
|
of '\0'..'\x1F', '\x7F'..'\xFF': result = '\\' & toOctal(c)
|
||||||
of '\'', '\"', '\\', '?': result = '\\' & c
|
of '\'', '\"', '\\', '?': result = '\\' & c
|
||||||
else: result = $(c)
|
else: result = $(c)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -187,6 +187,9 @@ var
|
||||||
|
|
||||||
const oKeepVariableNames* = true
|
const oKeepVariableNames* = true
|
||||||
|
|
||||||
|
template compilingLib*: bool =
|
||||||
|
gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}
|
||||||
|
|
||||||
proc mainCommandArg*: string =
|
proc mainCommandArg*: string =
|
||||||
## This is intended for commands like check or parse
|
## This is intended for commands like check or parse
|
||||||
## which will work on the main project file unless
|
## which will work on the main project file unless
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,9 @@ type
|
||||||
inPragma*: int # Pragma level
|
inPragma*: int # Pragma level
|
||||||
inSemiStmtList*: int
|
inSemiStmtList*: int
|
||||||
|
|
||||||
|
SymbolMode = enum
|
||||||
|
smNormal, smAllowNil, smAfterDot
|
||||||
|
|
||||||
proc parseAll*(p: var TParser): PNode
|
proc parseAll*(p: var TParser): PNode
|
||||||
proc closeParser*(p: var TParser)
|
proc closeParser*(p: var TParser)
|
||||||
proc parseTopLevelStmt*(p: var TParser): PNode
|
proc parseTopLevelStmt*(p: var TParser): PNode
|
||||||
|
|
@ -62,7 +65,7 @@ proc optPar*(p: var TParser)
|
||||||
proc optInd*(p: var TParser, n: PNode)
|
proc optInd*(p: var TParser, n: PNode)
|
||||||
proc indAndComment*(p: var TParser, n: PNode)
|
proc indAndComment*(p: var TParser, n: PNode)
|
||||||
proc setBaseFlags*(n: PNode, base: TNumericalBase)
|
proc setBaseFlags*(n: PNode, base: TNumericalBase)
|
||||||
proc parseSymbol*(p: var TParser, allowNil = false): PNode
|
proc parseSymbol*(p: var TParser, mode = smNormal): PNode
|
||||||
proc parseTry(p: var TParser; isExpr: bool): PNode
|
proc parseTry(p: var TParser; isExpr: bool): PNode
|
||||||
proc parseCase(p: var TParser): PNode
|
proc parseCase(p: var TParser): PNode
|
||||||
proc parseStmtPragma(p: var TParser): PNode
|
proc parseStmtPragma(p: var TParser): PNode
|
||||||
|
|
@ -304,13 +307,24 @@ proc colcom(p: var TParser, n: PNode) =
|
||||||
eat(p, tkColon)
|
eat(p, tkColon)
|
||||||
skipComment(p, n)
|
skipComment(p, n)
|
||||||
|
|
||||||
proc parseSymbol(p: var TParser, allowNil = false): PNode =
|
proc parseSymbol(p: var TParser, mode = smNormal): PNode =
|
||||||
#| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
|
#| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
|
||||||
#| | IDENT | 'addr' | 'type'
|
#| | IDENT | KEYW
|
||||||
case p.tok.tokType
|
case p.tok.tokType
|
||||||
of tkSymbol, tkAddr, tkType:
|
of tkSymbol:
|
||||||
result = newIdentNodeP(p.tok.ident, p)
|
result = newIdentNodeP(p.tok.ident, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
|
of tokKeywordLow..tokKeywordHigh:
|
||||||
|
if p.tok.tokType == tkAddr or p.tok.tokType == tkType or mode == smAfterDot:
|
||||||
|
# for backwards compatibility these 2 are always valid:
|
||||||
|
result = newIdentNodeP(p.tok.ident, p)
|
||||||
|
getTok(p)
|
||||||
|
elif p.tok.tokType == tkNil and mode == smAllowNil:
|
||||||
|
result = newNodeP(nkNilLit, p)
|
||||||
|
getTok(p)
|
||||||
|
else:
|
||||||
|
parMessage(p, errIdentifierExpected, p.tok)
|
||||||
|
result = ast.emptyNode
|
||||||
of tkAccent:
|
of tkAccent:
|
||||||
result = newNodeP(nkAccQuoted, p)
|
result = newNodeP(nkAccQuoted, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
|
|
@ -335,10 +349,6 @@ proc parseSymbol(p: var TParser, allowNil = false): PNode =
|
||||||
parMessage(p, errIdentifierExpected, p.tok)
|
parMessage(p, errIdentifierExpected, p.tok)
|
||||||
break
|
break
|
||||||
eat(p, tkAccent)
|
eat(p, tkAccent)
|
||||||
else:
|
|
||||||
if allowNil and p.tok.tokType == tkNil:
|
|
||||||
result = newNodeP(nkNilLit, p)
|
|
||||||
getTok(p)
|
|
||||||
else:
|
else:
|
||||||
parMessage(p, errIdentifierExpected, p.tok)
|
parMessage(p, errIdentifierExpected, p.tok)
|
||||||
# BUGFIX: We must consume a token here to prevent endless loops!
|
# BUGFIX: We must consume a token here to prevent endless loops!
|
||||||
|
|
@ -390,7 +400,7 @@ proc dotExpr(p: var TParser, a: PNode): PNode =
|
||||||
result = newNodeI(nkDotExpr, info)
|
result = newNodeI(nkDotExpr, info)
|
||||||
optInd(p, result)
|
optInd(p, result)
|
||||||
addSon(result, a)
|
addSon(result, a)
|
||||||
addSon(result, parseSymbol(p))
|
addSon(result, parseSymbol(p, smAfterDot))
|
||||||
|
|
||||||
proc qualifiedIdent(p: var TParser): PNode =
|
proc qualifiedIdent(p: var TParser): PNode =
|
||||||
#| qualifiedIdent = symbol ('.' optInd symbol)?
|
#| qualifiedIdent = symbol ('.' optInd symbol)?
|
||||||
|
|
@ -846,6 +856,7 @@ type
|
||||||
TDeclaredIdentFlag = enum
|
TDeclaredIdentFlag = enum
|
||||||
withPragma, # identifier may have pragma
|
withPragma, # identifier may have pragma
|
||||||
withBothOptional # both ':' and '=' parts are optional
|
withBothOptional # both ':' and '=' parts are optional
|
||||||
|
withDot # allow 'var ident.ident = value'
|
||||||
TDeclaredIdentFlags = set[TDeclaredIdentFlag]
|
TDeclaredIdentFlags = set[TDeclaredIdentFlag]
|
||||||
|
|
||||||
proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
|
proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
|
||||||
|
|
@ -859,7 +870,7 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
|
||||||
while true:
|
while true:
|
||||||
case p.tok.tokType
|
case p.tok.tokType
|
||||||
of tkSymbol, tkAccent:
|
of tkSymbol, tkAccent:
|
||||||
if withPragma in flags: a = identWithPragma(p)
|
if withPragma in flags: a = identWithPragma(p, allowDot=withdot in flags)
|
||||||
else: a = parseSymbol(p)
|
else: a = parseSymbol(p)
|
||||||
if a.kind == nkEmpty: return
|
if a.kind == nkEmpty: return
|
||||||
else: break
|
else: break
|
||||||
|
|
@ -1004,10 +1015,10 @@ proc isExprStart(p: TParser): bool =
|
||||||
result = true
|
result = true
|
||||||
else: result = false
|
else: result = false
|
||||||
|
|
||||||
proc parseSymbolList(p: var TParser, result: PNode, allowNil = false) =
|
proc parseSymbolList(p: var TParser, result: PNode) =
|
||||||
# progress guaranteed
|
# progress guaranteed
|
||||||
while true:
|
while true:
|
||||||
var s = parseSymbol(p, allowNil)
|
var s = parseSymbol(p, smAllowNil)
|
||||||
if s.kind == nkEmpty: break
|
if s.kind == nkEmpty: break
|
||||||
addSon(result, s)
|
addSon(result, s)
|
||||||
if p.tok.tokType != tkComma: break
|
if p.tok.tokType != tkComma: break
|
||||||
|
|
@ -1028,7 +1039,7 @@ proc parseTypeDescKAux(p: var TParser, kind: TNodeKind,
|
||||||
getTok(p)
|
getTok(p)
|
||||||
let list = newNodeP(nodeKind, p)
|
let list = newNodeP(nodeKind, p)
|
||||||
result.addSon list
|
result.addSon list
|
||||||
parseSymbolList(p, list, allowNil = true)
|
parseSymbolList(p, list)
|
||||||
|
|
||||||
proc parseExpr(p: var TParser): PNode =
|
proc parseExpr(p: var TParser): PNode =
|
||||||
#| expr = (ifExpr
|
#| expr = (ifExpr
|
||||||
|
|
@ -1520,6 +1531,13 @@ proc parseGenericParam(p: var TParser): PNode =
|
||||||
# progress guaranteed
|
# progress guaranteed
|
||||||
while true:
|
while true:
|
||||||
case p.tok.tokType
|
case p.tok.tokType
|
||||||
|
of tkIn, tkOut:
|
||||||
|
let x = p.lex.cache.getIdent(if p.tok.tokType == tkIn: "in" else: "out")
|
||||||
|
a = newNodeP(nkPrefix, p)
|
||||||
|
a.addSon newIdentNodeP(x, p)
|
||||||
|
getTok(p)
|
||||||
|
expectIdent(p)
|
||||||
|
a.addSon(parseSymbol(p))
|
||||||
of tkSymbol, tkAccent:
|
of tkSymbol, tkAccent:
|
||||||
a = parseSymbol(p)
|
a = parseSymbol(p)
|
||||||
if a.kind == nkEmpty: return
|
if a.kind == nkEmpty: return
|
||||||
|
|
@ -1548,7 +1566,7 @@ proc parseGenericParamList(p: var TParser): PNode =
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, result)
|
optInd(p, result)
|
||||||
# progress guaranteed
|
# progress guaranteed
|
||||||
while p.tok.tokType in {tkSymbol, tkAccent}:
|
while p.tok.tokType in {tkSymbol, tkAccent, tkIn, tkOut}:
|
||||||
var a = parseGenericParam(p)
|
var a = parseGenericParam(p)
|
||||||
addSon(result, a)
|
addSon(result, a)
|
||||||
if p.tok.tokType notin {tkComma, tkSemiColon}: break
|
if p.tok.tokType notin {tkComma, tkSemiColon}: break
|
||||||
|
|
@ -1882,7 +1900,7 @@ proc parseVarTuple(p: var TParser): PNode =
|
||||||
optInd(p, result)
|
optInd(p, result)
|
||||||
# progress guaranteed
|
# progress guaranteed
|
||||||
while p.tok.tokType in {tkSymbol, tkAccent}:
|
while p.tok.tokType in {tkSymbol, tkAccent}:
|
||||||
var a = identWithPragma(p)
|
var a = identWithPragma(p, allowDot=true)
|
||||||
addSon(result, a)
|
addSon(result, a)
|
||||||
if p.tok.tokType != tkComma: break
|
if p.tok.tokType != tkComma: break
|
||||||
getTok(p)
|
getTok(p)
|
||||||
|
|
@ -1898,7 +1916,7 @@ proc parseVariable(p: var TParser): PNode =
|
||||||
#| colonBody = colcom stmt doBlocks?
|
#| colonBody = colcom stmt doBlocks?
|
||||||
#| variable = (varTuple / identColonEquals) colonBody? indAndComment
|
#| variable = (varTuple / identColonEquals) colonBody? indAndComment
|
||||||
if p.tok.tokType == tkParLe: result = parseVarTuple(p)
|
if p.tok.tokType == tkParLe: result = parseVarTuple(p)
|
||||||
else: result = parseIdentColonEquals(p, {withPragma})
|
else: result = parseIdentColonEquals(p, {withPragma, withDot})
|
||||||
result{-1} = postExprBlocks(p, result{-1})
|
result{-1} = postExprBlocks(p, result{-1})
|
||||||
indAndComment(p, result)
|
indAndComment(p, result)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1336,6 +1336,11 @@ proc parseGenericParam(p: var TParser): PNode =
|
||||||
result = newNodeP(nkIdentDefs, p)
|
result = newNodeP(nkIdentDefs, p)
|
||||||
while true:
|
while true:
|
||||||
case p.tok.tokType
|
case p.tok.tokType
|
||||||
|
of tkIn, tkOut:
|
||||||
|
let t = p.tok.tokType
|
||||||
|
getTok(p)
|
||||||
|
expectIdent(p)
|
||||||
|
a = parseSymbol(p)
|
||||||
of tkSymbol, tkAccent:
|
of tkSymbol, tkAccent:
|
||||||
a = parseSymbol(p)
|
a = parseSymbol(p)
|
||||||
if a.kind == nkEmpty: return
|
if a.kind == nkEmpty: return
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,7 @@ proc processImportCpp(s: PSym, extname: string, info: TLineInfo) =
|
||||||
incl(s.flags, sfImportc)
|
incl(s.flags, sfImportc)
|
||||||
incl(s.flags, sfInfixCall)
|
incl(s.flags, sfInfixCall)
|
||||||
excl(s.flags, sfForward)
|
excl(s.flags, sfForward)
|
||||||
|
if gCmd == cmdCompileToC:
|
||||||
let m = s.getModule()
|
let m = s.getModule()
|
||||||
incl(m.flags, sfCompileToCpp)
|
incl(m.flags, sfCompileToCpp)
|
||||||
extccomp.gMixedMode = true
|
extccomp.gMixedMode = true
|
||||||
|
|
|
||||||
|
|
@ -12,17 +12,17 @@ import strutils
|
||||||
|
|
||||||
proc c_sprintf(buf, frmt: cstring) {.importc: "sprintf", header: "<stdio.h>", nodecl, varargs.}
|
proc c_sprintf(buf, frmt: cstring) {.importc: "sprintf", header: "<stdio.h>", nodecl, varargs.}
|
||||||
|
|
||||||
proc toStrMaxPrecision*(f: BiggestFloat): string =
|
proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string =
|
||||||
if f != f:
|
if f != f:
|
||||||
result = "NAN"
|
result = "NAN"
|
||||||
elif f == 0.0:
|
elif f == 0.0:
|
||||||
result = "0.0"
|
result = "0.0" & literalPostfix
|
||||||
elif f == 0.5 * f:
|
elif f == 0.5 * f:
|
||||||
if f > 0.0: result = "INF"
|
if f > 0.0: result = "INF"
|
||||||
else: result = "-INF"
|
else: result = "-INF"
|
||||||
else:
|
else:
|
||||||
var buf: array[0..80, char]
|
var buf: array[0..80, char]
|
||||||
c_sprintf(buf, "%#.16e", f)
|
c_sprintf(buf, "%#.16e" & literalPostfix, f)
|
||||||
result = $buf
|
result = $buf
|
||||||
|
|
||||||
proc encodeStr*(s: string, result: var string) =
|
proc encodeStr*(s: string, result: var string) =
|
||||||
|
|
|
||||||
|
|
@ -442,6 +442,7 @@ proc semConstBoolExpr(c: PContext, n: PNode): PNode =
|
||||||
result = nn
|
result = nn
|
||||||
|
|
||||||
proc semGenericStmt(c: PContext, n: PNode): PNode
|
proc semGenericStmt(c: PContext, n: PNode): PNode
|
||||||
|
proc semConceptBody(c: PContext, n: PNode): PNode
|
||||||
|
|
||||||
include semtypes, semtempl, semgnrc, semstmts, semexprs
|
include semtypes, semtempl, semgnrc, semstmts, semexprs
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -408,6 +408,12 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
|
||||||
else:
|
else:
|
||||||
# get rid of the deref again for a better error message:
|
# get rid of the deref again for a better error message:
|
||||||
n.sons[1] = n.sons[1].sons[0]
|
n.sons[1] = n.sons[1].sons[0]
|
||||||
|
#notFoundError(c, n, errors)
|
||||||
|
if efExplain notin flags:
|
||||||
|
# repeat the overload resolution,
|
||||||
|
# this time enabling all the diagnostic output (this should fail again)
|
||||||
|
discard semOverloadedCall(c, n, nOrig, filter, flags + {efExplain})
|
||||||
|
else:
|
||||||
notFoundError(c, n, errors)
|
notFoundError(c, n, errors)
|
||||||
else:
|
else:
|
||||||
if efExplain notin flags:
|
if efExplain notin flags:
|
||||||
|
|
@ -429,7 +435,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
for i in 1..sonsLen(n)-1:
|
for i in 1..sonsLen(n)-1:
|
||||||
let formal = s.ast.sons[genericParamsPos].sons[i-1].typ
|
let formal = s.ast.sons[genericParamsPos].sons[i-1].typ
|
||||||
let arg = n[i].typ
|
let arg = n[i].typ
|
||||||
let tm = typeRel(m, formal, arg, true)
|
let tm = typeRel(m, formal, arg)
|
||||||
if tm in {isNone, isConvertible}: return nil
|
if tm in {isNone, isConvertible}: return nil
|
||||||
var newInst = generateInstance(c, s, m.bindings, n.info)
|
var newInst = generateInstance(c, s, m.bindings, n.info)
|
||||||
newInst.typ.flags.excl tfUnresolved
|
newInst.typ.flags.excl tfUnresolved
|
||||||
|
|
@ -440,7 +446,8 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
assert n.kind == nkBracketExpr
|
assert n.kind == nkBracketExpr
|
||||||
for i in 1..sonsLen(n)-1:
|
for i in 1..sonsLen(n)-1:
|
||||||
n.sons[i].typ = semTypeNode(c, n.sons[i], nil)
|
let e = semExpr(c, n.sons[i])
|
||||||
|
n.sons[i].typ = e.typ.skipTypes({tyTypeDesc})
|
||||||
var s = s
|
var s = s
|
||||||
var a = n.sons[0]
|
var a = n.sons[0]
|
||||||
if a.kind == nkSym:
|
if a.kind == nkSym:
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,11 @@ type
|
||||||
bracketExpr*: PNode # current bracket expression (for ^ support)
|
bracketExpr*: PNode # current bracket expression (for ^ support)
|
||||||
mapping*: TIdTable
|
mapping*: TIdTable
|
||||||
|
|
||||||
|
TMatchedConcept* = object
|
||||||
|
candidateType*: PType
|
||||||
|
prev*: ptr TMatchedConcept
|
||||||
|
depth*: int
|
||||||
|
|
||||||
TInstantiationPair* = object
|
TInstantiationPair* = object
|
||||||
genericSym*: PSym
|
genericSym*: PSym
|
||||||
inst*: PInstantiation
|
inst*: PInstantiation
|
||||||
|
|
@ -75,6 +80,7 @@ type
|
||||||
importTable*: PScope # scope for all imported symbols
|
importTable*: PScope # scope for all imported symbols
|
||||||
topLevelScope*: PScope # scope for all top-level symbols
|
topLevelScope*: PScope # scope for all top-level symbols
|
||||||
p*: PProcCon # procedure context
|
p*: PProcCon # procedure context
|
||||||
|
matchedConcept*: ptr TMatchedConcept # the current concept being matched
|
||||||
friendModules*: seq[PSym] # friend modules; may access private data;
|
friendModules*: seq[PSym] # friend modules; may access private data;
|
||||||
# this is used so that generic instantiations
|
# this is used so that generic instantiations
|
||||||
# can access private object fields
|
# can access private object fields
|
||||||
|
|
@ -82,7 +88,6 @@ type
|
||||||
|
|
||||||
ambiguousSymbols*: IntSet # ids of all ambiguous symbols (cannot
|
ambiguousSymbols*: IntSet # ids of all ambiguous symbols (cannot
|
||||||
# store this info in the syms themselves!)
|
# store this info in the syms themselves!)
|
||||||
inTypeClass*: int # > 0 if we are in a user-defined type class
|
|
||||||
inGenericContext*: int # > 0 if we are in a generic type
|
inGenericContext*: int # > 0 if we are in a generic type
|
||||||
inUnrolledContext*: int # > 0 if we are unrolling a loop
|
inUnrolledContext*: int # > 0 if we are unrolling a loop
|
||||||
compilesContextId*: int # > 0 if we are in a ``compiles`` magic
|
compilesContextId*: int # > 0 if we are in a ``compiles`` magic
|
||||||
|
|
@ -277,6 +282,10 @@ proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
|
||||||
assert n != nil
|
assert n != nil
|
||||||
result.n = n
|
result.n = n
|
||||||
|
|
||||||
|
proc newTypeWithSons*(owner: PSym, kind: TTypeKind, sons: seq[PType]): PType =
|
||||||
|
result = newType(kind, owner)
|
||||||
|
result.sons = sons
|
||||||
|
|
||||||
proc newTypeWithSons*(c: PContext, kind: TTypeKind,
|
proc newTypeWithSons*(c: PContext, kind: TTypeKind,
|
||||||
sons: seq[PType]): PType =
|
sons: seq[PType]): PType =
|
||||||
result = newType(kind, getCurrOwner(c))
|
result = newType(kind, getCurrOwner(c))
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,10 @@ proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus =
|
||||||
result = convNotNeedeed
|
result = convNotNeedeed
|
||||||
return
|
return
|
||||||
var d = skipTypes(castDest, abstractVar)
|
var d = skipTypes(castDest, abstractVar)
|
||||||
var s = skipTypes(src, abstractVar-{tyTypeDesc})
|
var s = src
|
||||||
|
if s.kind in tyUserTypeClasses and s.isResolvedUserTypeClass:
|
||||||
|
s = s.lastSon
|
||||||
|
s = skipTypes(s, abstractVar-{tyTypeDesc})
|
||||||
var pointers = 0
|
var pointers = 0
|
||||||
while (d != nil) and (d.kind in {tyPtr, tyRef}) and (d.kind == s.kind):
|
while (d != nil) and (d.kind in {tyPtr, tyRef}) and (d.kind == s.kind):
|
||||||
d = d.lastSon
|
d = d.lastSon
|
||||||
|
|
@ -152,6 +155,8 @@ proc isCastable(dst, src: PType): bool =
|
||||||
result = false
|
result = false
|
||||||
elif typeAllowed(dst, skParam) != nil:
|
elif typeAllowed(dst, skParam) != nil:
|
||||||
result = false
|
result = false
|
||||||
|
elif dst.kind == tyProc and dst.callConv == ccClosure:
|
||||||
|
result = src.kind == tyProc and src.callConv == ccClosure
|
||||||
else:
|
else:
|
||||||
result = (dstSize >= srcSize) or
|
result = (dstSize >= srcSize) or
|
||||||
(skipTypes(dst, abstractInst).kind in IntegralTypes) or
|
(skipTypes(dst, abstractInst).kind in IntegralTypes) or
|
||||||
|
|
@ -227,7 +232,10 @@ proc semCast(c: PContext, n: PNode): PNode =
|
||||||
if tfHasMeta in targetType.flags:
|
if tfHasMeta in targetType.flags:
|
||||||
localError(n.sons[0].info, errCastToANonConcreteType, $targetType)
|
localError(n.sons[0].info, errCastToANonConcreteType, $targetType)
|
||||||
if not isCastable(targetType, castedExpr.typ):
|
if not isCastable(targetType, castedExpr.typ):
|
||||||
localError(n.info, errExprCannotBeCastToX, $targetType)
|
let tar = $targetType
|
||||||
|
let alt = typeToString(targetType, preferDesc)
|
||||||
|
let msg = if tar != alt: tar & "=" & alt else: tar
|
||||||
|
localError(n.info, errExprCannotBeCastToX, msg)
|
||||||
result = newNodeI(nkCast, n.info)
|
result = newNodeI(nkCast, n.info)
|
||||||
result.typ = targetType
|
result.typ = targetType
|
||||||
addSon(result, copyTree(n.sons[0]))
|
addSon(result, copyTree(n.sons[0]))
|
||||||
|
|
@ -683,27 +691,9 @@ proc bracketedMacro(n: PNode): PSym =
|
||||||
if result.kind notin {skMacro, skTemplate}:
|
if result.kind notin {skMacro, skTemplate}:
|
||||||
result = nil
|
result = nil
|
||||||
|
|
||||||
proc semBracketedMacro(c: PContext; outer, inner: PNode; s: PSym;
|
proc setGenericParams(c: PContext, n: PNode) =
|
||||||
flags: TExprFlags): PNode =
|
for i in 1 .. <n.len:
|
||||||
# We received untransformed bracket expression coming from macroOrTmpl[].
|
n[i].typ = semTypeNode(c, n[i], nil)
|
||||||
# Transform it to macro or template call, where first come normal
|
|
||||||
# arguments, next come generic template arguments.
|
|
||||||
var sons = newSeq[PNode]()
|
|
||||||
sons.add inner.sons[0]
|
|
||||||
# Normal arguments:
|
|
||||||
for i in 1..<outer.len:
|
|
||||||
sons.add outer.sons[i]
|
|
||||||
# Generic template arguments from bracket expression:
|
|
||||||
for i in 1..<inner.len:
|
|
||||||
sons.add inner.sons[i]
|
|
||||||
shallowCopy(outer.sons, sons)
|
|
||||||
# FIXME: Shouldn't we check sfImmediate and call semDirectOp?
|
|
||||||
# However passing to semDirectOp doesn't work here.
|
|
||||||
case s.kind
|
|
||||||
of skMacro: result = semMacroExpr(c, outer, outer, s, flags)
|
|
||||||
of skTemplate: result = semTemplateExpr(c, outer, s, flags)
|
|
||||||
else: assert(false)
|
|
||||||
return
|
|
||||||
|
|
||||||
proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
|
proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
|
||||||
result = n
|
result = n
|
||||||
|
|
@ -718,7 +708,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
|
||||||
analyseIfAddressTakenInCall(c, result)
|
analyseIfAddressTakenInCall(c, result)
|
||||||
if callee.magic != mNone:
|
if callee.magic != mNone:
|
||||||
result = magicsAfterOverloadResolution(c, result, flags)
|
result = magicsAfterOverloadResolution(c, result, flags)
|
||||||
if c.inTypeClass == 0:
|
if c.matchedConcept == nil:
|
||||||
result = evalAtCompileTime(c, result)
|
result = evalAtCompileTime(c, result)
|
||||||
|
|
||||||
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
|
|
@ -745,7 +735,8 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
elif n.sons[0].kind == nkBracketExpr:
|
elif n.sons[0].kind == nkBracketExpr:
|
||||||
let s = bracketedMacro(n.sons[0])
|
let s = bracketedMacro(n.sons[0])
|
||||||
if s != nil:
|
if s != nil:
|
||||||
return semBracketedMacro(c, n, n.sons[0], s, flags)
|
setGenericParams(c, n[0])
|
||||||
|
return semDirectOp(c, n, flags)
|
||||||
|
|
||||||
let nOrig = n.copyTree
|
let nOrig = n.copyTree
|
||||||
semOpAux(c, n)
|
semOpAux(c, n)
|
||||||
|
|
@ -897,20 +888,6 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
|
||||||
if r.sym.name.id == field.id: result = r.sym
|
if r.sym.name.id == field.id: result = r.sym
|
||||||
else: illFormedAst(n)
|
else: illFormedAst(n)
|
||||||
|
|
||||||
proc makeDeref(n: PNode): PNode =
|
|
||||||
var t = skipTypes(n.typ, {tyGenericInst, tyAlias})
|
|
||||||
result = n
|
|
||||||
if t.kind == tyVar:
|
|
||||||
result = newNodeIT(nkHiddenDeref, n.info, t.sons[0])
|
|
||||||
addSon(result, n)
|
|
||||||
t = skipTypes(t.sons[0], {tyGenericInst, tyAlias})
|
|
||||||
while t.kind in {tyPtr, tyRef}:
|
|
||||||
var a = result
|
|
||||||
let baseTyp = t.lastSon
|
|
||||||
result = newNodeIT(nkHiddenDeref, n.info, baseTyp)
|
|
||||||
addSon(result, a)
|
|
||||||
t = skipTypes(baseTyp, {tyGenericInst, tyAlias})
|
|
||||||
|
|
||||||
const
|
const
|
||||||
tyTypeParamsHolders = {tyGenericInst, tyCompositeTypeClass}
|
tyTypeParamsHolders = {tyGenericInst, tyCompositeTypeClass}
|
||||||
tyDotOpTransparent = {tyVar, tyPtr, tyRef, tyAlias}
|
tyDotOpTransparent = {tyVar, tyPtr, tyRef, tyAlias}
|
||||||
|
|
@ -997,7 +974,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||||
of skParam:
|
of skParam:
|
||||||
markUsed(n.info, s, c.graph.usageSym)
|
markUsed(n.info, s, c.graph.usageSym)
|
||||||
styleCheckUse(n.info, s)
|
styleCheckUse(n.info, s)
|
||||||
if s.typ.kind == tyStatic and s.typ.n != nil:
|
if s.typ != nil and s.typ.kind == tyStatic and s.typ.n != nil:
|
||||||
# XXX see the hack in sigmatch.nim ...
|
# XXX see the hack in sigmatch.nim ...
|
||||||
return s.typ.n
|
return s.typ.n
|
||||||
elif sfGenSym in s.flags:
|
elif sfGenSym in s.flags:
|
||||||
|
|
@ -1155,9 +1132,9 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
# reset to prevent 'nil' bug: see "tests/reject/tenumitems.nim":
|
# reset to prevent 'nil' bug: see "tests/reject/tenumitems.nim":
|
||||||
ty = n.sons[0].typ
|
ty = n.sons[0].typ
|
||||||
return nil
|
return nil
|
||||||
ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef, tyAlias})
|
|
||||||
if ty.kind in tyUserTypeClasses and ty.isResolvedUserTypeClass:
|
if ty.kind in tyUserTypeClasses and ty.isResolvedUserTypeClass:
|
||||||
ty = ty.lastSon
|
ty = ty.lastSon
|
||||||
|
ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef, tyAlias})
|
||||||
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:
|
||||||
|
|
@ -2164,10 +2141,6 @@ proc shouldBeBracketExpr(n: PNode): bool =
|
||||||
n.sons[0] = be
|
n.sons[0] = be
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc setGenericParams(c: PContext, n: PNode) =
|
|
||||||
for i in 1 .. <n.len:
|
|
||||||
n[i].typ = semTypeNode(c, n[i], nil)
|
|
||||||
|
|
||||||
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
result = n
|
result = n
|
||||||
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
||||||
|
|
@ -2177,7 +2150,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
let checks = if efNoEvaluateGeneric in flags: {checkUndeclared}
|
let checks = if efNoEvaluateGeneric in flags: {checkUndeclared}
|
||||||
else: {checkUndeclared, checkModule, checkAmbiguity}
|
else: {checkUndeclared, checkModule, checkAmbiguity}
|
||||||
var s = qualifiedLookUp(c, n, checks)
|
var s = qualifiedLookUp(c, n, checks)
|
||||||
if c.inTypeClass == 0: semCaptureSym(s, c.p.owner)
|
if c.matchedConcept == nil: semCaptureSym(s, c.p.owner)
|
||||||
result = semSym(c, n, s, flags)
|
result = semSym(c, n, s, flags)
|
||||||
if s.kind in {skProc, skMethod, skConverter, skIterator}:
|
if s.kind in {skProc, skMethod, skConverter, skIterator}:
|
||||||
#performProcvarCheck(c, n, s)
|
#performProcvarCheck(c, n, s)
|
||||||
|
|
@ -2214,11 +2187,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
if result.typ == nil: result.typ = getSysType(tyUInt32)
|
if result.typ == nil: result.typ = getSysType(tyUInt32)
|
||||||
of nkUInt64Lit:
|
of nkUInt64Lit:
|
||||||
if result.typ == nil: result.typ = getSysType(tyUInt64)
|
if result.typ == nil: result.typ = getSysType(tyUInt64)
|
||||||
of nkFloatLit:
|
#of nkFloatLit:
|
||||||
if result.typ == nil: result.typ = getFloatLitType(result)
|
# if result.typ == nil: result.typ = getFloatLitType(result)
|
||||||
of nkFloat32Lit:
|
of nkFloat32Lit:
|
||||||
if result.typ == nil: result.typ = getSysType(tyFloat32)
|
if result.typ == nil: result.typ = getSysType(tyFloat32)
|
||||||
of nkFloat64Lit:
|
of nkFloat64Lit, nkFloatLit:
|
||||||
if result.typ == nil: result.typ = getSysType(tyFloat64)
|
if result.typ == nil: result.typ = getSysType(tyFloat64)
|
||||||
of nkFloat128Lit:
|
of nkFloat128Lit:
|
||||||
if result.typ == nil: result.typ = getSysType(tyFloat128)
|
if result.typ == nil: result.typ = getSysType(tyFloat128)
|
||||||
|
|
|
||||||
|
|
@ -594,8 +594,11 @@ proc foldConStrStr(m: PSym, n: PNode): PNode =
|
||||||
|
|
||||||
proc newSymNodeTypeDesc*(s: PSym; info: TLineInfo): PNode =
|
proc newSymNodeTypeDesc*(s: PSym; info: TLineInfo): PNode =
|
||||||
result = newSymNode(s, info)
|
result = newSymNode(s, info)
|
||||||
|
if s.typ.kind != tyTypeDesc:
|
||||||
result.typ = newType(tyTypeDesc, s.owner)
|
result.typ = newType(tyTypeDesc, s.owner)
|
||||||
result.typ.addSonSkipIntLit(s.typ)
|
result.typ.addSonSkipIntLit(s.typ)
|
||||||
|
else:
|
||||||
|
result.typ = s.typ
|
||||||
|
|
||||||
proc getConstExpr(m: PSym, n: PNode): PNode =
|
proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||||
result = nil
|
result = nil
|
||||||
|
|
@ -634,9 +637,11 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||||
result = newSymNodeTypeDesc(s, n.info)
|
result = newSymNodeTypeDesc(s, n.info)
|
||||||
of skGenericParam:
|
of skGenericParam:
|
||||||
if s.typ.kind == tyStatic:
|
if s.typ.kind == tyStatic:
|
||||||
if s.typ.n != nil:
|
if s.typ.n != nil and tfUnresolved notin s.typ.flags:
|
||||||
|
result = s.typ.n
|
||||||
|
result.typ = s.typ.base
|
||||||
|
elif s.typ.isIntLit:
|
||||||
result = s.typ.n
|
result = s.typ.n
|
||||||
result.typ = s.typ.sons[0]
|
|
||||||
else:
|
else:
|
||||||
result = newSymNodeTypeDesc(s, n.info)
|
result = newSymNodeTypeDesc(s, n.info)
|
||||||
else: discard
|
else: discard
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ type
|
||||||
|
|
||||||
type
|
type
|
||||||
TSemGenericFlag = enum
|
TSemGenericFlag = enum
|
||||||
withinBind, withinTypeDesc, withinMixin
|
withinBind, withinTypeDesc, withinMixin, withinConcept
|
||||||
TSemGenericFlags = set[TSemGenericFlag]
|
TSemGenericFlags = set[TSemGenericFlag]
|
||||||
|
|
||||||
proc semGenericStmt(c: PContext, n: PNode,
|
proc semGenericStmt(c: PContext, n: PNode,
|
||||||
|
|
@ -200,12 +200,13 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
checkMinSonsLen(n, 1)
|
checkMinSonsLen(n, 1)
|
||||||
let fn = n.sons[0]
|
let fn = n.sons[0]
|
||||||
var s = qualifiedLookUp(c, fn, {})
|
var s = qualifiedLookUp(c, fn, {})
|
||||||
if s == nil and withinMixin notin flags and
|
if s == nil and
|
||||||
|
{withinMixin, withinConcept}*flags == {} and
|
||||||
fn.kind in {nkIdent, nkAccQuoted} and
|
fn.kind in {nkIdent, nkAccQuoted} and
|
||||||
considerQuotedIdent(fn).id notin ctx.toMixin:
|
considerQuotedIdent(fn).id notin ctx.toMixin:
|
||||||
errorUndeclaredIdentifier(c, n.info, fn.renderTree)
|
errorUndeclaredIdentifier(c, n.info, fn.renderTree)
|
||||||
|
|
||||||
var first = 0
|
var first = ord(withinConcept in flags)
|
||||||
var mixinContext = false
|
var mixinContext = false
|
||||||
if s != nil:
|
if s != nil:
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
|
|
@ -471,3 +472,9 @@ proc semGenericStmt(c: PContext, n: PNode): PNode =
|
||||||
ctx.toMixin = initIntset()
|
ctx.toMixin = initIntset()
|
||||||
result = semGenericStmt(c, n, {}, ctx)
|
result = semGenericStmt(c, n, {}, ctx)
|
||||||
semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
|
semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
|
||||||
|
|
||||||
|
proc semConceptBody(c: PContext, n: PNode): PNode =
|
||||||
|
var ctx: GenericCtx
|
||||||
|
ctx.toMixin = initIntset()
|
||||||
|
result = semGenericStmt(c, n, {withinConcept}, ctx)
|
||||||
|
semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,8 @@ proc sameInstantiation(a, b: TInstantiation): bool =
|
||||||
if a.concreteTypes.len == b.concreteTypes.len:
|
if a.concreteTypes.len == b.concreteTypes.len:
|
||||||
for i in 0..a.concreteTypes.high:
|
for i in 0..a.concreteTypes.high:
|
||||||
if not compareTypes(a.concreteTypes[i], b.concreteTypes[i],
|
if not compareTypes(a.concreteTypes[i], b.concreteTypes[i],
|
||||||
flags = {ExactTypeDescValues}): return
|
flags = {ExactTypeDescValues,
|
||||||
|
ExactGcSafety}): return
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc genericCacheGet(genericSym: PSym, entry: TInstantiation;
|
proc genericCacheGet(genericSym: PSym, entry: TInstantiation;
|
||||||
|
|
@ -173,10 +174,14 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
|
||||||
|
|
||||||
proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
|
proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
|
||||||
allowMetaTypes = false): PType =
|
allowMetaTypes = false): PType =
|
||||||
var cl: TReplTypeVars
|
var
|
||||||
|
typeMap: LayeredIdTable
|
||||||
|
cl: TReplTypeVars
|
||||||
|
|
||||||
initIdTable(cl.symMap)
|
initIdTable(cl.symMap)
|
||||||
initIdTable(cl.typeMap)
|
|
||||||
initIdTable(cl.localCache)
|
initIdTable(cl.localCache)
|
||||||
|
initIdTable(typeMap.topLayer)
|
||||||
|
cl.typeMap = addr(typeMap)
|
||||||
cl.info = info
|
cl.info = info
|
||||||
cl.c = c
|
cl.c = c
|
||||||
cl.allowMetaTypes = allowMetaTypes
|
cl.allowMetaTypes = allowMetaTypes
|
||||||
|
|
@ -200,7 +205,8 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
|
||||||
#addDecl(c, prc)
|
#addDecl(c, prc)
|
||||||
|
|
||||||
pushInfoContext(info)
|
pushInfoContext(info)
|
||||||
var cl = initTypeVars(c, pt, info, nil)
|
var typeMap = initLayeredTypeMap(pt)
|
||||||
|
var cl = initTypeVars(c, addr(typeMap), info, nil)
|
||||||
var result = instCopyType(cl, prc.typ)
|
var result = instCopyType(cl, prc.typ)
|
||||||
let originalParams = result.n
|
let originalParams = result.n
|
||||||
result.n = originalParams.shallowCopy
|
result.n = originalParams.shallowCopy
|
||||||
|
|
@ -256,8 +262,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
# NOTE: for access of private fields within generics from a different module
|
# NOTE: for access of private fields within generics from a different module
|
||||||
# we set the friend module:
|
# we set the friend module:
|
||||||
c.friendModules.add(getModule(fn))
|
c.friendModules.add(getModule(fn))
|
||||||
let oldInTypeClass = c.inTypeClass
|
let oldMatchedConcept = c.matchedConcept
|
||||||
c.inTypeClass = 0
|
c.matchedConcept = nil
|
||||||
let oldScope = c.currentScope
|
let oldScope = c.currentScope
|
||||||
while not isTopLevel(c): c.currentScope = c.currentScope.parent
|
while not isTopLevel(c): c.currentScope = c.currentScope.parent
|
||||||
result = copySym(fn, false)
|
result = copySym(fn, false)
|
||||||
|
|
@ -318,5 +324,5 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
c.currentScope = oldScope
|
c.currentScope = oldScope
|
||||||
discard c.friendModules.pop()
|
discard c.friendModules.pop()
|
||||||
dec(c.instCounter)
|
dec(c.instCounter)
|
||||||
c.inTypeClass = oldInTypeClass
|
c.matchedConcept = oldMatchedConcept
|
||||||
if result.kind == skMethod: finishMethod(c, result)
|
if result.kind == skMethod: finishMethod(c, result)
|
||||||
|
|
|
||||||
|
|
@ -109,27 +109,43 @@ proc uninstantiate(t: PType): PType =
|
||||||
of tyCompositeTypeClass: uninstantiate t.sons[1]
|
of tyCompositeTypeClass: uninstantiate t.sons[1]
|
||||||
else: t
|
else: t
|
||||||
|
|
||||||
proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
|
proc evalTypeTrait(traitCall: PNode, operand: PType, context: PSym): PNode =
|
||||||
var typ = operand.skipTypes({tyTypeDesc})
|
const skippedTypes = {tyTypeDesc, tyAlias}
|
||||||
|
let trait = traitCall[0]
|
||||||
|
internalAssert trait.kind == nkSym
|
||||||
|
var operand = operand.skipTypes(skippedTypes)
|
||||||
|
|
||||||
|
template operand2: PType =
|
||||||
|
traitCall.sons[2].typ.skipTypes({tyTypeDesc})
|
||||||
|
|
||||||
|
template typeWithSonsResult(kind, sons): PNode =
|
||||||
|
newTypeWithSons(context, kind, sons).toNode(traitCall.info)
|
||||||
|
|
||||||
case trait.sym.name.s
|
case trait.sym.name.s
|
||||||
|
of "or", "|":
|
||||||
|
return typeWithSonsResult(tyOr, @[operand, operand2])
|
||||||
|
of "and":
|
||||||
|
return typeWithSonsResult(tyAnd, @[operand, operand2])
|
||||||
|
of "not":
|
||||||
|
return typeWithSonsResult(tyNot, @[operand])
|
||||||
of "name":
|
of "name":
|
||||||
result = newStrNode(nkStrLit, typ.typeToString(preferName))
|
result = newStrNode(nkStrLit, operand.typeToString(preferName))
|
||||||
result.typ = newType(tyString, context)
|
result.typ = newType(tyString, context)
|
||||||
result.info = trait.info
|
result.info = traitCall.info
|
||||||
of "arity":
|
of "arity":
|
||||||
result = newIntNode(nkIntLit, typ.len - ord(typ.kind==tyProc))
|
result = newIntNode(nkIntLit, operand.len - ord(operand.kind==tyProc))
|
||||||
result.typ = newType(tyInt, context)
|
result.typ = newType(tyInt, context)
|
||||||
result.info = trait.info
|
result.info = traitCall.info
|
||||||
of "genericHead":
|
of "genericHead":
|
||||||
var res = uninstantiate(typ)
|
var res = uninstantiate(operand)
|
||||||
if res == typ and res.kind notin tyMagicGenerics:
|
if res == operand and res.kind notin tyMagicGenerics:
|
||||||
localError(trait.info,
|
localError(traitCall.info,
|
||||||
"genericHead expects a generic type. The given type was " &
|
"genericHead expects a generic type. The given type was " &
|
||||||
typeToString(typ))
|
typeToString(operand))
|
||||||
return newType(tyError, context).toNode(trait.info)
|
return newType(tyError, context).toNode(traitCall.info)
|
||||||
result = res.base.toNode(trait.info)
|
result = res.base.toNode(traitCall.info)
|
||||||
of "stripGenericParams":
|
of "stripGenericParams":
|
||||||
result = uninstantiate(typ).toNode(trait.info)
|
result = uninstantiate(operand).toNode(traitCall.info)
|
||||||
else:
|
else:
|
||||||
internalAssert false
|
internalAssert false
|
||||||
|
|
||||||
|
|
@ -140,7 +156,7 @@ proc semTypeTraits(c: PContext, n: PNode): PNode =
|
||||||
if t.sonsLen > 0:
|
if t.sonsLen > 0:
|
||||||
# This is either a type known to sem or a typedesc
|
# This is either a type known to sem or a typedesc
|
||||||
# param to a regular proc (again, known at instantiation)
|
# param to a regular proc (again, known at instantiation)
|
||||||
result = evalTypeTrait(n[0], t, getCurrOwner(c))
|
result = evalTypeTrait(n, t, getCurrOwner(c))
|
||||||
else:
|
else:
|
||||||
# a typedesc variable, pass unmodified to evals
|
# a typedesc variable, pass unmodified to evals
|
||||||
result = n
|
result = n
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,8 @@ proc `==`(a, b: TLockLevel): bool {.borrow.}
|
||||||
proc max(a, b: TLockLevel): TLockLevel {.borrow.}
|
proc max(a, b: TLockLevel): TLockLevel {.borrow.}
|
||||||
|
|
||||||
proc isLocalVar(a: PEffects, s: PSym): bool =
|
proc isLocalVar(a: PEffects, s: PSym): bool =
|
||||||
s.kind in {skVar, skResult} and sfGlobal notin s.flags and s.owner == a.owner
|
s.kind in {skVar, skResult} and sfGlobal notin s.flags and
|
||||||
|
s.owner == a.owner and s.typ != nil
|
||||||
|
|
||||||
proc getLockLevel(t: PType): TLockLevel =
|
proc getLockLevel(t: PType): TLockLevel =
|
||||||
var t = t
|
var t = t
|
||||||
|
|
@ -218,12 +219,11 @@ proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet) =
|
||||||
message(s.info, msgKind,
|
message(s.info, msgKind,
|
||||||
"'$#' is not GC-safe as it calls '$#'" %
|
"'$#' is not GC-safe as it calls '$#'" %
|
||||||
[s.name.s, u.name.s])
|
[s.name.s, u.name.s])
|
||||||
of skParam:
|
of skParam, skForVar:
|
||||||
message(s.info, msgKind,
|
message(s.info, msgKind,
|
||||||
"'$#' is not GC-safe as it performs an indirect call via '$#'" %
|
"'$#' is not GC-safe as it performs an indirect call via '$#'" %
|
||||||
[s.name.s, u.name.s])
|
[s.name.s, u.name.s])
|
||||||
else:
|
else:
|
||||||
internalAssert u.kind == skUnknown
|
|
||||||
message(u.info, msgKind,
|
message(u.info, msgKind,
|
||||||
"'$#' is not GC-safe as it performs an indirect call here" % s.name.s)
|
"'$#' is not GC-safe as it performs an indirect call here" % s.name.s)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ proc fixNilType(n: PNode) =
|
||||||
n.typ = nil
|
n.typ = nil
|
||||||
|
|
||||||
proc discardCheck(c: PContext, result: PNode) =
|
proc discardCheck(c: PContext, result: PNode) =
|
||||||
if c.inTypeClass > 0: return
|
if c.matchedConcept != nil: return
|
||||||
if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}:
|
if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}:
|
||||||
if result.kind == nkNilLit:
|
if result.kind == nkNilLit:
|
||||||
result.typ = nil
|
result.typ = nil
|
||||||
|
|
@ -465,6 +465,47 @@ proc hasEmpty(typ: PType): bool =
|
||||||
for s in typ.sons:
|
for s in typ.sons:
|
||||||
result = result or hasEmpty(s)
|
result = result or hasEmpty(s)
|
||||||
|
|
||||||
|
proc makeDeref(n: PNode): PNode =
|
||||||
|
var t = skipTypes(n.typ, {tyGenericInst, tyAlias})
|
||||||
|
if t.kind in tyUserTypeClasses and t.isResolvedUserTypeClass:
|
||||||
|
t = t.lastSon
|
||||||
|
result = n
|
||||||
|
if t.kind == tyVar:
|
||||||
|
result = newNodeIT(nkHiddenDeref, n.info, t.sons[0])
|
||||||
|
addSon(result, n)
|
||||||
|
t = skipTypes(t.sons[0], {tyGenericInst, tyAlias})
|
||||||
|
while t.kind in {tyPtr, tyRef}:
|
||||||
|
var a = result
|
||||||
|
let baseTyp = t.lastSon
|
||||||
|
result = newNodeIT(nkHiddenDeref, n.info, baseTyp)
|
||||||
|
addSon(result, a)
|
||||||
|
t = skipTypes(baseTyp, {tyGenericInst, tyAlias})
|
||||||
|
|
||||||
|
proc fillPartialObject(c: PContext; n: PNode; typ: PType) =
|
||||||
|
if n.len == 2:
|
||||||
|
let x = semExprWithType(c, n[0])
|
||||||
|
let y = considerQuotedIdent(n[1])
|
||||||
|
let obj = x.typ.skipTypes(abstractPtrs)
|
||||||
|
if obj.kind == tyObject and tfPartial in obj.flags:
|
||||||
|
let field = newSym(skField, getIdent(y.s), obj.sym, n[1].info)
|
||||||
|
field.typ = skipIntLit(typ)
|
||||||
|
field.position = sonsLen(obj.n)
|
||||||
|
addSon(obj.n, newSymNode(field))
|
||||||
|
n.sons[0] = makeDeref x
|
||||||
|
n.sons[1] = newSymNode(field)
|
||||||
|
else:
|
||||||
|
localError(n.info, "implicit object field construction " &
|
||||||
|
"requires a .partial object, but got " & typeToString(obj))
|
||||||
|
else:
|
||||||
|
localError(n.info, "nkDotNode requires 2 children")
|
||||||
|
|
||||||
|
proc setVarType(v: PSym, typ: PType) =
|
||||||
|
if v.typ != nil and not sameTypeOrNil(v.typ, typ):
|
||||||
|
localError(v.info, "inconsistent typing for reintroduced symbol '" &
|
||||||
|
v.name.s & "': previous type was: " & typeToString(v.typ) &
|
||||||
|
"; new type is: " & typeToString(typ))
|
||||||
|
v.typ = typ
|
||||||
|
|
||||||
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)
|
||||||
|
|
@ -529,6 +570,11 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
message(a.info, warnEachIdentIsTuple)
|
message(a.info, warnEachIdentIsTuple)
|
||||||
|
|
||||||
for j in countup(0, length-3):
|
for j in countup(0, length-3):
|
||||||
|
if a[j].kind == nkDotExpr:
|
||||||
|
fillPartialObject(c, a[j],
|
||||||
|
if a.kind != nkVarTuple: typ else: tup.sons[j])
|
||||||
|
addToVarSection(c, result, n, a)
|
||||||
|
continue
|
||||||
var v = semIdentDef(c, a.sons[j], symkind)
|
var v = semIdentDef(c, a.sons[j], symkind)
|
||||||
if sfGenSym notin v.flags and not isDiscardUnderscore(v):
|
if sfGenSym notin v.flags and not isDiscardUnderscore(v):
|
||||||
addInterfaceDecl(c, v)
|
addInterfaceDecl(c, v)
|
||||||
|
|
@ -549,7 +595,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
# this is needed for the evaluation pass and for the guard checking:
|
# this is needed for the evaluation pass and for the guard checking:
|
||||||
v.ast = def
|
v.ast = def
|
||||||
if sfThread in v.flags: localError(def.info, errThreadvarCannotInit)
|
if sfThread in v.flags: localError(def.info, errThreadvarCannotInit)
|
||||||
v.typ = typ
|
setVarType(v, typ)
|
||||||
b = newNodeI(nkIdentDefs, a.info)
|
b = newNodeI(nkIdentDefs, a.info)
|
||||||
if importantComments():
|
if importantComments():
|
||||||
# keep documentation information:
|
# keep documentation information:
|
||||||
|
|
@ -560,7 +606,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
addToVarSection(c, result, n, b)
|
addToVarSection(c, result, n, b)
|
||||||
else:
|
else:
|
||||||
if def.kind == nkPar: v.ast = def[j]
|
if def.kind == nkPar: v.ast = def[j]
|
||||||
v.typ = tup.sons[j]
|
setVarType(v, tup.sons[j])
|
||||||
b.sons[j] = newSymNode(v)
|
b.sons[j] = newSymNode(v)
|
||||||
addDefer(c, result, v)
|
addDefer(c, result, v)
|
||||||
checkNilable(v)
|
checkNilable(v)
|
||||||
|
|
@ -594,7 +640,7 @@ proc semConst(c: PContext, n: PNode): PNode =
|
||||||
if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit:
|
if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit:
|
||||||
localError(a.info, "invalid type for const: " & typeToString(typ))
|
localError(a.info, "invalid type for const: " & typeToString(typ))
|
||||||
continue
|
continue
|
||||||
v.typ = typ
|
setVarType(v, typ)
|
||||||
v.ast = def # no need to copy
|
v.ast = def # no need to copy
|
||||||
if sfGenSym notin v.flags: addInterfaceDecl(c, v)
|
if sfGenSym notin v.flags: addInterfaceDecl(c, v)
|
||||||
var b = newNodeI(nkConstDef, a.info)
|
var b = newNodeI(nkConstDef, a.info)
|
||||||
|
|
@ -730,7 +776,9 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
|
||||||
var s: PSym
|
var s: PSym
|
||||||
if name.kind == nkDotExpr:
|
if name.kind == nkDotExpr:
|
||||||
s = qualifiedLookUp(c, name, {checkUndeclared, checkModule})
|
s = qualifiedLookUp(c, name, {checkUndeclared, checkModule})
|
||||||
if s.kind != skType or s.typ.skipTypes(abstractPtrs).kind != tyObject or tfPartial notin s.typ.skipTypes(abstractPtrs).flags:
|
if s.kind != skType or
|
||||||
|
s.typ.skipTypes(abstractPtrs).kind != tyObject or
|
||||||
|
tfPartial notin s.typ.skipTypes(abstractPtrs).flags:
|
||||||
localError(name.info, "only .partial objects can be extended")
|
localError(name.info, "only .partial objects can be extended")
|
||||||
else:
|
else:
|
||||||
s = semIdentDef(c, name, skType)
|
s = semIdentDef(c, name, skType)
|
||||||
|
|
@ -742,6 +790,87 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
|
||||||
if sfGenSym notin s.flags: addInterfaceDecl(c, s)
|
if sfGenSym notin s.flags: addInterfaceDecl(c, s)
|
||||||
a.sons[0] = newSymNode(s)
|
a.sons[0] = newSymNode(s)
|
||||||
|
|
||||||
|
proc checkCovariantParamsUsages(genericType: PType) =
|
||||||
|
var body = genericType{-1}
|
||||||
|
|
||||||
|
proc traverseSubTypes(t: PType): bool =
|
||||||
|
template error(msg) = localError(genericType.sym.info, msg)
|
||||||
|
|
||||||
|
result = false
|
||||||
|
|
||||||
|
template subresult(r) =
|
||||||
|
let sub = r
|
||||||
|
result = result or sub
|
||||||
|
|
||||||
|
case t.kind
|
||||||
|
of tyGenericParam:
|
||||||
|
t.flags.incl tfWeakCovariant
|
||||||
|
return true
|
||||||
|
|
||||||
|
of tyObject:
|
||||||
|
for field in t.n:
|
||||||
|
subresult traverseSubTypes(field.typ)
|
||||||
|
|
||||||
|
of tyArray:
|
||||||
|
return traverseSubTypes(t[1])
|
||||||
|
|
||||||
|
of tyProc:
|
||||||
|
for subType in t.sons:
|
||||||
|
if subType != nil:
|
||||||
|
subresult traverseSubTypes(subType)
|
||||||
|
if result:
|
||||||
|
error("non-invariant type param used in a proc type: " & $t)
|
||||||
|
|
||||||
|
of tySequence:
|
||||||
|
return traverseSubTypes(t[0])
|
||||||
|
|
||||||
|
of tyGenericInvocation:
|
||||||
|
let targetBody = t[0]
|
||||||
|
for i in 1 .. <t.len:
|
||||||
|
let param = t[i]
|
||||||
|
if param.kind == tyGenericParam:
|
||||||
|
if tfCovariant in param.flags:
|
||||||
|
let formalFlags = targetBody[i-1].flags
|
||||||
|
if tfCovariant notin formalFlags:
|
||||||
|
error("covariant param '" & param.sym.name.s &
|
||||||
|
"' used in a non-covariant position")
|
||||||
|
elif tfWeakCovariant in formalFlags:
|
||||||
|
param.flags.incl tfWeakCovariant
|
||||||
|
result = true
|
||||||
|
elif tfContravariant in param.flags:
|
||||||
|
let formalParam = targetBody[i-1].sym
|
||||||
|
if tfContravariant notin formalParam.typ.flags:
|
||||||
|
error("contravariant param '" & param.sym.name.s &
|
||||||
|
"' used in a non-contravariant position")
|
||||||
|
result = true
|
||||||
|
else:
|
||||||
|
subresult traverseSubTypes(param)
|
||||||
|
|
||||||
|
of tyAnd, tyOr, tyNot, tyStatic, tyBuiltInTypeClass, tyCompositeTypeClass:
|
||||||
|
error("non-invariant type parameters cannot be used with types such '" & $t & "'")
|
||||||
|
|
||||||
|
of tyUserTypeClass, tyUserTypeClassInst:
|
||||||
|
error("non-invariant type parameters are not supported in concepts")
|
||||||
|
|
||||||
|
of tyTuple:
|
||||||
|
for fieldType in t.sons:
|
||||||
|
subresult traverseSubTypes(fieldType)
|
||||||
|
|
||||||
|
of tyPtr, tyRef, tyVar:
|
||||||
|
if t.base.kind == tyGenericParam: return true
|
||||||
|
return traverseSubTypes(t.base)
|
||||||
|
|
||||||
|
of tyDistinct, tyAlias:
|
||||||
|
return traverseSubTypes(t.lastSon)
|
||||||
|
|
||||||
|
of tyGenericInst:
|
||||||
|
internalAssert false
|
||||||
|
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
|
||||||
|
discard traverseSubTypes(body)
|
||||||
|
|
||||||
proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
|
|
@ -782,6 +911,22 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
||||||
body.sym = s
|
body.sym = s
|
||||||
body.size = -1 # could not be computed properly
|
body.size = -1 # could not be computed properly
|
||||||
s.typ.sons[sonsLen(s.typ) - 1] = body
|
s.typ.sons[sonsLen(s.typ) - 1] = body
|
||||||
|
if tfCovariant in s.typ.flags:
|
||||||
|
checkCovariantParamsUsages(s.typ)
|
||||||
|
# XXX: This is a temporary limitation:
|
||||||
|
# The codegen currently produces various failures with
|
||||||
|
# generic imported types that have fields, but we need
|
||||||
|
# the fields specified in order to detect weak covariance.
|
||||||
|
# The proper solution is to teach the codegen how to handle
|
||||||
|
# such types, because this would offer various interesting
|
||||||
|
# possibilities such as instantiating C++ generic types with
|
||||||
|
# garbage collected Nim types.
|
||||||
|
if sfImportc in s.flags:
|
||||||
|
var body = s.typ.lastSon
|
||||||
|
if body.kind == tyObject:
|
||||||
|
# erases all declared fields
|
||||||
|
body.n.sons = nil
|
||||||
|
|
||||||
popOwner(c)
|
popOwner(c)
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
elif a.sons[2].kind != nkEmpty:
|
elif a.sons[2].kind != nkEmpty:
|
||||||
|
|
@ -985,12 +1130,15 @@ proc semProcAnnotation(c: PContext, prc: PNode;
|
||||||
var x = newNodeI(nkCall, n.info)
|
var x = newNodeI(nkCall, n.info)
|
||||||
x.add(newSymNode(m))
|
x.add(newSymNode(m))
|
||||||
prc.sons[pragmasPos] = copyExcept(n, i)
|
prc.sons[pragmasPos] = copyExcept(n, i)
|
||||||
|
if prc[pragmasPos].kind != nkEmpty and prc[pragmasPos].len == 0:
|
||||||
|
prc.sons[pragmasPos] = emptyNode
|
||||||
|
|
||||||
if it.kind == nkExprColonExpr:
|
if it.kind == nkExprColonExpr:
|
||||||
# pass pragma argument to the macro too:
|
# pass pragma argument to the macro too:
|
||||||
x.add(it.sons[1])
|
x.add(it.sons[1])
|
||||||
x.add(prc)
|
x.add(prc)
|
||||||
# recursion assures that this works for multiple macro annotations too:
|
# recursion assures that this works for multiple macro annotations too:
|
||||||
result = semStmt(c, x)
|
result = semExpr(c, x)
|
||||||
# since a proc annotation can set pragmas, we process these here again.
|
# since a proc annotation can set pragmas, we process these here again.
|
||||||
# This is required for SqueakNim-like export pragmas.
|
# This is required for SqueakNim-like export pragmas.
|
||||||
if result.kind in procDefs and result[namePos].kind == nkSym and
|
if result.kind in procDefs and result[namePos].kind == nkSym and
|
||||||
|
|
@ -1322,6 +1470,14 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
implicitPragmas(c, s, n, validPragmas)
|
implicitPragmas(c, s, n, validPragmas)
|
||||||
else:
|
else:
|
||||||
if n.sons[pragmasPos].kind != nkEmpty:
|
if n.sons[pragmasPos].kind != nkEmpty:
|
||||||
|
pragma(c, s, n.sons[pragmasPos], validPragmas)
|
||||||
|
# To ease macro generation that produce forwarded .async procs we now
|
||||||
|
# allow a bit redudancy in the pragma declarations. The rule is
|
||||||
|
# a prototype's pragma list must be a superset of the current pragma
|
||||||
|
# list.
|
||||||
|
# XXX This needs more checks eventually, for example that external
|
||||||
|
# linking names do agree:
|
||||||
|
if proto.typ.callConv != s.typ.callConv or proto.typ.flags < s.typ.flags:
|
||||||
localError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProcX,
|
localError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProcX,
|
||||||
"'" & proto.name.s & "' from " & $proto.info)
|
"'" & proto.name.s & "' from " & $proto.info)
|
||||||
if sfForward notin proto.flags:
|
if sfForward notin proto.flags:
|
||||||
|
|
@ -1402,7 +1558,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
popOwner(c)
|
popOwner(c)
|
||||||
if n.sons[patternPos].kind != nkEmpty:
|
if n.sons[patternPos].kind != nkEmpty:
|
||||||
c.patterns.add(s)
|
c.patterns.add(s)
|
||||||
if isAnon: result.typ = s.typ
|
if isAnon:
|
||||||
|
n.kind = nkLambda
|
||||||
|
result.typ = s.typ
|
||||||
if isTopLevel(c) and s.kind != skIterator and
|
if isTopLevel(c) and s.kind != skIterator and
|
||||||
s.typ.callConv == ccClosure:
|
s.typ.callConv == ccClosure:
|
||||||
localError(s.info, "'.closure' calling convention for top level routines is invalid")
|
localError(s.info, "'.closure' calling convention for top level routines is invalid")
|
||||||
|
|
@ -1614,7 +1772,8 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
else:
|
else:
|
||||||
var expr = semExpr(c, n.sons[i], flags)
|
var expr = semExpr(c, n.sons[i], flags)
|
||||||
n.sons[i] = expr
|
n.sons[i] = expr
|
||||||
if c.inTypeClass > 0 and expr.typ != nil:
|
if c.matchedConcept != nil and expr.typ != nil and
|
||||||
|
(nfFromTemplate notin n.flags or i != last):
|
||||||
case expr.typ.kind
|
case expr.typ.kind
|
||||||
of tyBool:
|
of tyBool:
|
||||||
if expr.kind == nkInfix and
|
if expr.kind == nkInfix and
|
||||||
|
|
@ -1629,7 +1788,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
|
|
||||||
let verdict = semConstExpr(c, n[i])
|
let verdict = semConstExpr(c, n[i])
|
||||||
if verdict.intVal == 0:
|
if verdict.intVal == 0:
|
||||||
localError(result.info, "type class predicate failed")
|
localError(result.info, "concept predicate failed")
|
||||||
of tyUnknown: continue
|
of tyUnknown: continue
|
||||||
else: discard
|
else: discard
|
||||||
if n.sons[i].typ == enforceVoidContext: #or usesResult(n.sons[i]):
|
if n.sons[i].typ == enforceVoidContext: #or usesResult(n.sons[i]):
|
||||||
|
|
@ -1653,7 +1812,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
|
|
||||||
if result.len == 1 and
|
if result.len == 1 and
|
||||||
# concept bodies should be preserved as a stmt list:
|
# concept bodies should be preserved as a stmt list:
|
||||||
c.inTypeClass == 0 and
|
c.matchedConcept == nil and
|
||||||
# also, don't make life complicated for macros.
|
# also, don't make life complicated for macros.
|
||||||
# they will always expect a proper stmtlist:
|
# they will always expect a proper stmtlist:
|
||||||
nfBlockArg notin n.flags and
|
nfBlockArg notin n.flags and
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,8 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
||||||
counter = lastOrd(base) + 1
|
counter = lastOrd(base) + 1
|
||||||
rawAddSon(result, base)
|
rawAddSon(result, base)
|
||||||
let isPure = result.sym != nil and sfPure in result.sym.flags
|
let isPure = result.sym != nil and sfPure in result.sym.flags
|
||||||
|
var symbols: TStrTable
|
||||||
|
if isPure: initStrTable(symbols)
|
||||||
var hasNull = false
|
var hasNull = false
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
for i in countup(1, sonsLen(n) - 1):
|
||||||
case n.sons[i].kind
|
case n.sons[i].kind
|
||||||
|
|
@ -87,6 +89,8 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
||||||
addSon(result.n, newSymNode(e))
|
addSon(result.n, newSymNode(e))
|
||||||
styleCheckDef(e)
|
styleCheckDef(e)
|
||||||
if sfGenSym notin e.flags and not isPure: addDecl(c, e)
|
if sfGenSym notin e.flags and not isPure: addDecl(c, e)
|
||||||
|
if isPure and strTableIncl(symbols, e):
|
||||||
|
wrongRedefinition(e.info, e.name.s)
|
||||||
inc(counter)
|
inc(counter)
|
||||||
if not hasNull: incl(result.flags, tfNeedsInit)
|
if not hasNull: incl(result.flags, tfNeedsInit)
|
||||||
|
|
||||||
|
|
@ -152,6 +156,8 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
|
||||||
message n[i].info, errGenerated, "region needs to be an object type"
|
message n[i].info, errGenerated, "region needs to be an object type"
|
||||||
addSonSkipIntLit(result, region)
|
addSonSkipIntLit(result, region)
|
||||||
addSonSkipIntLit(result, t)
|
addSonSkipIntLit(result, t)
|
||||||
|
if tfPartial in result.flags:
|
||||||
|
if result.lastSon.kind == tyObject: incl(result.lastSon.flags, tfPartial)
|
||||||
#if not isNilable: result.flags.incl tfNotNil
|
#if not isNilable: result.flags.incl tfNotNil
|
||||||
|
|
||||||
proc semVarType(c: PContext, n: PNode, prev: PType): PType =
|
proc semVarType(c: PContext, n: PNode, prev: PType): PType =
|
||||||
|
|
@ -1129,7 +1135,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||||
m.isNoCall = true
|
m.isNoCall = true
|
||||||
matches(c, n, copyTree(n), m)
|
matches(c, n, copyTree(n), m)
|
||||||
|
|
||||||
if m.state != csMatch and not m.typedescMatched:
|
if m.state != csMatch:
|
||||||
let err = "cannot instantiate " & typeToString(t) & "\n" &
|
let err = "cannot instantiate " & typeToString(t) & "\n" &
|
||||||
"got: (" & describeArgs(c, n) & ")\n" &
|
"got: (" & describeArgs(c, n) & ")\n" &
|
||||||
"but expected: (" & describeArgs(c, t.n, 0) & ")"
|
"but expected: (" & describeArgs(c, t.n, 0) & ")"
|
||||||
|
|
@ -1200,17 +1206,51 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
|
||||||
# if n.sonsLen == 0: return newConstraint(c, tyTypeClass)
|
# if n.sonsLen == 0: return newConstraint(c, tyTypeClass)
|
||||||
if nfBase2 in n.flags:
|
if nfBase2 in n.flags:
|
||||||
message(n.info, warnDeprecated, "use 'concept' instead; 'generic'")
|
message(n.info, warnDeprecated, "use 'concept' instead; 'generic'")
|
||||||
result = newOrPrevType(tyUserTypeClass, prev, c)
|
|
||||||
result.n = n
|
|
||||||
|
|
||||||
let
|
let
|
||||||
pragmas = n[1]
|
pragmas = n[1]
|
||||||
inherited = n[2]
|
inherited = n[2]
|
||||||
|
|
||||||
|
result = newOrPrevType(tyUserTypeClass, prev, c)
|
||||||
|
var owner = getCurrOwner(c)
|
||||||
|
var candidateTypeSlot = newTypeWithSons(owner, tyAlias, @[c.errorType])
|
||||||
|
result.sons = @[candidateTypeSlot]
|
||||||
|
result.n = n
|
||||||
|
|
||||||
if inherited.kind != nkEmpty:
|
if inherited.kind != nkEmpty:
|
||||||
for n in inherited.sons:
|
for n in inherited.sons:
|
||||||
let typ = semTypeNode(c, n, nil)
|
let typ = semTypeNode(c, n, nil)
|
||||||
result.sons.safeAdd(typ)
|
result.sons.add(typ)
|
||||||
|
|
||||||
|
openScope(c)
|
||||||
|
for param in n[0]:
|
||||||
|
var
|
||||||
|
dummyName: PNode
|
||||||
|
dummyType: PType
|
||||||
|
|
||||||
|
let modifier = case param.kind
|
||||||
|
of nkVarTy: tyVar
|
||||||
|
of nkRefTy: tyRef
|
||||||
|
of nkPtrTy: tyPtr
|
||||||
|
of nkStaticTy: tyStatic
|
||||||
|
of nkTypeOfExpr: tyTypeDesc
|
||||||
|
else: tyNone
|
||||||
|
|
||||||
|
if modifier != tyNone:
|
||||||
|
dummyName = param[0]
|
||||||
|
dummyType = c.makeTypeWithModifier(modifier, candidateTypeSlot)
|
||||||
|
if modifier == tyTypeDesc: dummyType.flags.incl tfExplicit
|
||||||
|
else:
|
||||||
|
dummyName = param
|
||||||
|
dummyType = candidateTypeSlot
|
||||||
|
|
||||||
|
internalAssert dummyName.kind == nkIdent
|
||||||
|
var dummyParam = newSym(if modifier == tyTypeDesc: skType else: skVar,
|
||||||
|
dummyName.ident, owner, owner.info)
|
||||||
|
dummyParam.typ = dummyType
|
||||||
|
addDecl(c, dummyParam)
|
||||||
|
|
||||||
|
result.n.sons[3] = semConceptBody(c, n[3])
|
||||||
|
closeScope(c)
|
||||||
|
|
||||||
proc semProcTypeWithScope(c: PContext, n: PNode,
|
proc semProcTypeWithScope(c: PContext, n: PNode,
|
||||||
prev: PType, kind: TSymKind): PType =
|
prev: PType, kind: TSymKind): PType =
|
||||||
|
|
@ -1379,7 +1419,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = errorType(c)
|
result = errorType(c)
|
||||||
else:
|
else:
|
||||||
result = typeExpr.typ.base
|
result = typeExpr.typ.base
|
||||||
if result.isMetaType:
|
if result.isMetaType and
|
||||||
|
result.kind != tyUserTypeClass:
|
||||||
|
# the dot expression may refer to a concept type in
|
||||||
|
# a different module. allow a normal alias then.
|
||||||
let preprocessed = semGenericStmt(c, n)
|
let preprocessed = semGenericStmt(c, n)
|
||||||
result = makeTypeFromExpr(c, preprocessed.copyTree)
|
result = makeTypeFromExpr(c, preprocessed.copyTree)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1584,10 +1627,24 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||||
# type for each generic param. the index
|
# type for each generic param. the index
|
||||||
# of the parameter will be stored in the
|
# of the parameter will be stored in the
|
||||||
# attached symbol.
|
# attached symbol.
|
||||||
|
var paramName = a.sons[j]
|
||||||
|
var covarianceFlag = tfUnresolved
|
||||||
|
|
||||||
|
if paramName.safeLen == 2:
|
||||||
|
if not nimEnableCovariance or paramName[0].ident.s == "in":
|
||||||
|
if father == nil or sfImportc notin father.sym.flags:
|
||||||
|
localError(paramName.info, errInOutFlagNotExtern, paramName[0].ident.s)
|
||||||
|
covarianceFlag = if paramName[0].ident.s == "in": tfContravariant
|
||||||
|
else: tfCovariant
|
||||||
|
if father != nil: father.flags.incl tfCovariant
|
||||||
|
paramName = paramName[1]
|
||||||
|
|
||||||
var s = if finalType.kind == tyStatic or tfWildcard in typ.flags:
|
var s = if finalType.kind == tyStatic or tfWildcard in typ.flags:
|
||||||
newSymG(skGenericParam, a.sons[j], c).linkTo(finalType)
|
newSymG(skGenericParam, paramName, c).linkTo(finalType)
|
||||||
else:
|
else:
|
||||||
newSymG(skType, a.sons[j], c).linkTo(finalType)
|
newSymG(skType, paramName, c).linkTo(finalType)
|
||||||
|
|
||||||
|
if covarianceFlag != tfUnresolved: s.typ.flags.incl(covarianceFlag)
|
||||||
if def.kind != nkEmpty: s.ast = def
|
if def.kind != nkEmpty: s.ast = def
|
||||||
if father != nil: addSonSkipIntLit(father, s.typ)
|
if father != nil: addSonSkipIntLit(father, s.typ)
|
||||||
s.position = result.len
|
s.position = result.len
|
||||||
|
|
|
||||||
|
|
@ -73,9 +73,13 @@ proc cacheTypeInst*(inst: PType) =
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
|
LayeredIdTable* = object
|
||||||
|
topLayer*: TIdTable
|
||||||
|
nextLayer*: ptr LayeredIdTable
|
||||||
|
|
||||||
TReplTypeVars* {.final.} = object
|
TReplTypeVars* {.final.} = object
|
||||||
c*: PContext
|
c*: PContext
|
||||||
typeMap*: TIdTable # map PType to PType
|
typeMap*: ptr LayeredIdTable # map PType to PType
|
||||||
symMap*: TIdTable # map PSym to PSym
|
symMap*: TIdTable # map PSym to PSym
|
||||||
localCache*: TIdTable # local cache for remembering alraedy replaced
|
localCache*: TIdTable # local cache for remembering alraedy replaced
|
||||||
# types during instantiation of meta types
|
# types during instantiation of meta types
|
||||||
|
|
@ -91,6 +95,23 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType
|
||||||
proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
|
proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
|
||||||
proc replaceTypeVarsN*(cl: var TReplTypeVars, n: PNode; start=0): PNode
|
proc replaceTypeVarsN*(cl: var TReplTypeVars, n: PNode; start=0): PNode
|
||||||
|
|
||||||
|
proc initLayeredTypeMap*(pt: TIdTable): LayeredIdTable =
|
||||||
|
copyIdTable(result.topLayer, pt)
|
||||||
|
|
||||||
|
proc newTypeMapLayer*(cl: var TReplTypeVars): LayeredIdTable =
|
||||||
|
result.nextLayer = cl.typeMap
|
||||||
|
initIdTable(result.topLayer)
|
||||||
|
|
||||||
|
proc lookup(typeMap: ptr LayeredIdTable, key: PType): PType =
|
||||||
|
var tm = typeMap
|
||||||
|
while tm != nil:
|
||||||
|
result = PType(idTableGet(tm.topLayer, key))
|
||||||
|
if result != nil: return
|
||||||
|
tm = tm.nextLayer
|
||||||
|
|
||||||
|
template put(typeMap: ptr LayeredIdTable, key, value: PType) =
|
||||||
|
idTablePut(typeMap.topLayer, key, value)
|
||||||
|
|
||||||
template checkMetaInvariants(cl: TReplTypeVars, t: PType) =
|
template checkMetaInvariants(cl: TReplTypeVars, t: PType) =
|
||||||
when false:
|
when false:
|
||||||
if t != nil and tfHasMeta in t.flags and
|
if t != nil and tfHasMeta in t.flags and
|
||||||
|
|
@ -106,7 +127,8 @@ proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
|
||||||
proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
|
proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
|
||||||
let t = replaceTypeVarsT(cl, n.typ)
|
let t = replaceTypeVarsT(cl, n.typ)
|
||||||
if t != nil and t.kind == tyStatic and t.n != nil:
|
if t != nil and t.kind == tyStatic and t.n != nil:
|
||||||
return t.n
|
return if tfUnresolved in t.flags: prepareNode(cl, t.n)
|
||||||
|
else: t.n
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
result.typ = t
|
result.typ = t
|
||||||
if result.kind == nkSym: result.sym = replaceTypeVarsS(cl, n.sym)
|
if result.kind == nkSym: result.sym = replaceTypeVarsS(cl, n.sym)
|
||||||
|
|
@ -219,7 +241,7 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
|
||||||
result.ast = replaceTypeVarsN(cl, s.ast)
|
result.ast = replaceTypeVarsN(cl, s.ast)
|
||||||
|
|
||||||
proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
|
proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
|
||||||
result = PType(idTableGet(cl.typeMap, t))
|
result = cl.typeMap.lookup(t)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
if cl.allowMetaTypes or tfRetType in t.flags: return
|
if cl.allowMetaTypes or tfRetType in t.flags: return
|
||||||
localError(t.sym.info, errCannotInstantiateX, typeToString(t))
|
localError(t.sym.info, errCannotInstantiateX, typeToString(t))
|
||||||
|
|
@ -227,7 +249,7 @@ proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
|
||||||
# In order to prevent endless recursions, we must remember
|
# In order to prevent endless recursions, we must remember
|
||||||
# this bad lookup and replace it with errorType everywhere.
|
# this bad lookup and replace it with errorType everywhere.
|
||||||
# These code paths are only active in "nim check"
|
# These code paths are only active in "nim check"
|
||||||
idTablePut(cl.typeMap, t, result)
|
cl.typeMap.put(t, result)
|
||||||
elif result.kind == tyGenericParam and not cl.allowMetaTypes:
|
elif result.kind == tyGenericParam and not cl.allowMetaTypes:
|
||||||
internalError(cl.info, "substitution with generic parameter")
|
internalError(cl.info, "substitution with generic parameter")
|
||||||
|
|
||||||
|
|
@ -243,6 +265,7 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
|
||||||
proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
# tyGenericInvocation[A, tyGenericInvocation[A, B]]
|
# tyGenericInvocation[A, tyGenericInvocation[A, B]]
|
||||||
# is difficult to handle:
|
# is difficult to handle:
|
||||||
|
const eqFlags = eqTypeFlags + {tfGcSafe}
|
||||||
var body = t.sons[0]
|
var body = t.sons[0]
|
||||||
if body.kind != tyGenericBody: internalError(cl.info, "no generic body")
|
if body.kind != tyGenericBody: internalError(cl.info, "no generic body")
|
||||||
var header: PType = t
|
var header: PType = t
|
||||||
|
|
@ -252,7 +275,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
else:
|
else:
|
||||||
result = searchInstTypes(t)
|
result = searchInstTypes(t)
|
||||||
|
|
||||||
if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return
|
if result != nil and eqFlags*result.flags == eqFlags*t.flags: return
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
for i in countup(1, sonsLen(t) - 1):
|
||||||
var x = t.sons[i]
|
var x = t.sons[i]
|
||||||
if x.kind in {tyGenericParam}:
|
if x.kind in {tyGenericParam}:
|
||||||
|
|
@ -267,7 +290,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
if header != t:
|
if header != t:
|
||||||
# search again after first pass:
|
# search again after first pass:
|
||||||
result = searchInstTypes(header)
|
result = searchInstTypes(header)
|
||||||
if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return
|
if result != nil and eqFlags*result.flags == eqFlags*t.flags: return
|
||||||
else:
|
else:
|
||||||
header = instCopyType(cl, t)
|
header = instCopyType(cl, t)
|
||||||
|
|
||||||
|
|
@ -285,12 +308,16 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
|
|
||||||
let oldSkipTypedesc = cl.skipTypedesc
|
let oldSkipTypedesc = cl.skipTypedesc
|
||||||
cl.skipTypedesc = true
|
cl.skipTypedesc = true
|
||||||
|
|
||||||
|
var typeMapLayer = newTypeMapLayer(cl)
|
||||||
|
cl.typeMap = addr(typeMapLayer)
|
||||||
|
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
for i in countup(1, sonsLen(t) - 1):
|
||||||
var x = replaceTypeVarsT(cl, t.sons[i])
|
var x = replaceTypeVarsT(cl, t.sons[i])
|
||||||
assert x.kind != tyGenericInvocation
|
assert x.kind != tyGenericInvocation
|
||||||
header.sons[i] = x
|
header.sons[i] = x
|
||||||
propagateToOwner(header, x)
|
propagateToOwner(header, x)
|
||||||
idTablePut(cl.typeMap, body.sons[i-1], x)
|
cl.typeMap.put(body.sons[i-1], x)
|
||||||
|
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
for i in countup(1, sonsLen(t) - 1):
|
||||||
# if one of the params is not concrete, we cannot do anything
|
# if one of the params is not concrete, we cannot do anything
|
||||||
|
|
@ -303,6 +330,9 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
cl.skipTypedesc = oldSkipTypedesc
|
cl.skipTypedesc = oldSkipTypedesc
|
||||||
newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
|
newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
|
||||||
result.flags = result.flags + newbody.flags - tfInstClearedFlags
|
result.flags = result.flags + newbody.flags - tfInstClearedFlags
|
||||||
|
|
||||||
|
cl.typeMap = cl.typeMap.nextLayer
|
||||||
|
|
||||||
# This is actually wrong: tgeneric_closure fails with this line:
|
# This is actually wrong: tgeneric_closure fails with this line:
|
||||||
#newbody.callConv = body.callConv
|
#newbody.callConv = body.callConv
|
||||||
# This type may be a generic alias and we want to resolve it here.
|
# This type may be a generic alias and we want to resolve it here.
|
||||||
|
|
@ -404,7 +434,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||||
if t == nil: return
|
if t == nil: return
|
||||||
|
|
||||||
if t.kind in {tyStatic, tyGenericParam} + tyTypeClasses:
|
if t.kind in {tyStatic, tyGenericParam} + tyTypeClasses:
|
||||||
let lookup = PType(idTableGet(cl.typeMap, t))
|
let lookup = cl.typeMap.lookup(t)
|
||||||
if lookup != nil: return lookup
|
if lookup != nil: return lookup
|
||||||
|
|
||||||
case t.kind
|
case t.kind
|
||||||
|
|
@ -446,7 +476,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||||
result = skipIntLit(t)
|
result = skipIntLit(t)
|
||||||
|
|
||||||
of tyTypeDesc:
|
of tyTypeDesc:
|
||||||
let lookup = PType(idTableGet(cl.typeMap, t)) # lookupTypeVar(cl, t)
|
let lookup = cl.typeMap.lookup(t)
|
||||||
if lookup != nil:
|
if lookup != nil:
|
||||||
result = lookup
|
result = lookup
|
||||||
if tfUnresolved in t.flags or cl.skipTypedesc: result = result.base
|
if tfUnresolved in t.flags or cl.skipTypedesc: result = result.base
|
||||||
|
|
@ -485,7 +515,6 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||||
propagateToOwner(result, r)
|
propagateToOwner(result, r)
|
||||||
# bug #4677: Do not instantiate effect lists
|
# bug #4677: Do not instantiate effect lists
|
||||||
result.n = replaceTypeVarsN(cl, result.n, ord(result.kind==tyProc))
|
result.n = replaceTypeVarsN(cl, result.n, ord(result.kind==tyProc))
|
||||||
|
|
||||||
case result.kind
|
case result.kind
|
||||||
of tyArray:
|
of tyArray:
|
||||||
let idx = result.sons[0]
|
let idx = result.sons[0]
|
||||||
|
|
@ -500,18 +529,19 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||||
|
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
proc initTypeVars*(p: PContext, pt: TIdTable, info: TLineInfo;
|
proc initTypeVars*(p: PContext, typeMap: ptr LayeredIdTable, info: TLineInfo;
|
||||||
owner: PSym): TReplTypeVars =
|
owner: PSym): TReplTypeVars =
|
||||||
initIdTable(result.symMap)
|
initIdTable(result.symMap)
|
||||||
copyIdTable(result.typeMap, pt)
|
|
||||||
initIdTable(result.localCache)
|
initIdTable(result.localCache)
|
||||||
|
result.typeMap = typeMap
|
||||||
result.info = info
|
result.info = info
|
||||||
result.c = p
|
result.c = p
|
||||||
result.owner = owner
|
result.owner = owner
|
||||||
|
|
||||||
proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode;
|
proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode;
|
||||||
owner: PSym, allowMetaTypes = false): PNode =
|
owner: PSym, allowMetaTypes = false): PNode =
|
||||||
var cl = initTypeVars(p, pt, n.info, owner)
|
var typeMap = initLayeredTypeMap(pt)
|
||||||
|
var cl = initTypeVars(p, addr(typeMap), n.info, owner)
|
||||||
cl.allowMetaTypes = allowMetaTypes
|
cl.allowMetaTypes = allowMetaTypes
|
||||||
pushInfoContext(n.info)
|
pushInfoContext(n.info)
|
||||||
result = replaceTypeVarsN(cl, n)
|
result = replaceTypeVarsN(cl, n)
|
||||||
|
|
@ -519,7 +549,8 @@ proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode;
|
||||||
|
|
||||||
proc replaceTypesForLambda*(p: PContext, pt: TIdTable, n: PNode;
|
proc replaceTypesForLambda*(p: PContext, pt: TIdTable, n: PNode;
|
||||||
original, new: PSym): PNode =
|
original, new: PSym): PNode =
|
||||||
var cl = initTypeVars(p, pt, n.info, original)
|
var typeMap = initLayeredTypeMap(pt)
|
||||||
|
var cl = initTypeVars(p, addr(typeMap), n.info, original)
|
||||||
idTablePut(cl.symMap, original, new)
|
idTablePut(cl.symMap, original, new)
|
||||||
pushInfoContext(n.info)
|
pushInfoContext(n.info)
|
||||||
result = replaceTypeVarsN(cl, n)
|
result = replaceTypeVarsN(cl, n)
|
||||||
|
|
@ -527,14 +558,16 @@ proc replaceTypesForLambda*(p: PContext, pt: TIdTable, n: PNode;
|
||||||
|
|
||||||
proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
|
proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
|
||||||
t: PType): PType =
|
t: PType): PType =
|
||||||
var cl = initTypeVars(p, pt, info, nil)
|
var typeMap = initLayeredTypeMap(pt)
|
||||||
|
var cl = initTypeVars(p, addr(typeMap), info, nil)
|
||||||
pushInfoContext(info)
|
pushInfoContext(info)
|
||||||
result = replaceTypeVarsT(cl, t)
|
result = replaceTypeVarsT(cl, t)
|
||||||
popInfoContext()
|
popInfoContext()
|
||||||
|
|
||||||
proc prepareMetatypeForSigmatch*(p: PContext, pt: TIdTable, info: TLineInfo,
|
proc prepareMetatypeForSigmatch*(p: PContext, pt: TIdTable, info: TLineInfo,
|
||||||
t: PType): PType =
|
t: PType): PType =
|
||||||
var cl = initTypeVars(p, pt, info, nil)
|
var typeMap = initLayeredTypeMap(pt)
|
||||||
|
var cl = initTypeVars(p, addr(typeMap), info, nil)
|
||||||
cl.allowMetaTypes = true
|
cl.allowMetaTypes = true
|
||||||
pushInfoContext(info)
|
pushInfoContext(info)
|
||||||
result = replaceTypeVarsT(cl, t)
|
result = replaceTypeVarsT(cl, t)
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,12 @@ type
|
||||||
mutabilityProblem*: uint8 # tyVar mismatch
|
mutabilityProblem*: uint8 # tyVar mismatch
|
||||||
inheritancePenalty: int # to prefer closest father object type
|
inheritancePenalty: int # to prefer closest father object type
|
||||||
|
|
||||||
|
TTypeRelFlag* = enum
|
||||||
|
trDontBind
|
||||||
|
trNoCovariance
|
||||||
|
|
||||||
|
TTypeRelFlags* = set[TTypeRelFlag]
|
||||||
|
|
||||||
TTypeRelation* = enum # order is important!
|
TTypeRelation* = enum # order is important!
|
||||||
isNone, isConvertible,
|
isNone, isConvertible,
|
||||||
isIntConv,
|
isIntConv,
|
||||||
|
|
@ -198,7 +204,9 @@ proc sumGeneric(t: PType): int =
|
||||||
if t.sons[i] != nil:
|
if t.sons[i] != nil:
|
||||||
result += t.sons[i].sumGeneric
|
result += t.sons[i].sumGeneric
|
||||||
break
|
break
|
||||||
of tyGenericParam, tyExpr, tyStatic, tyStmt: break
|
of tyStatic:
|
||||||
|
return t.sons[0].sumGeneric + 1
|
||||||
|
of tyGenericParam, tyExpr, tyStmt: break
|
||||||
of tyAlias: t = t.lastSon
|
of tyAlias: t = t.lastSon
|
||||||
of tyBool, tyChar, tyEnum, tyObject, tyPointer,
|
of tyBool, tyChar, tyEnum, tyObject, tyPointer,
|
||||||
tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
|
tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
|
||||||
|
|
@ -296,7 +304,33 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
|
||||||
add(result, argTypeToString(arg, prefer))
|
add(result, argTypeToString(arg, prefer))
|
||||||
if i != sonsLen(n) - 1: add(result, ", ")
|
if i != sonsLen(n) - 1: add(result, ", ")
|
||||||
|
|
||||||
proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation
|
proc typeRelImpl*(c: var TCandidate, f, aOrig: PType,
|
||||||
|
flags: TTypeRelFlags = {}): TTypeRelation
|
||||||
|
|
||||||
|
const traceTypeRel = false
|
||||||
|
|
||||||
|
when traceTypeRel:
|
||||||
|
var nextTypeRel = 0
|
||||||
|
|
||||||
|
template typeRel*(c: var TCandidate, f, aOrig: PType,
|
||||||
|
flags: TTypeRelFlags = {}): TTypeRelation =
|
||||||
|
when traceTypeRel:
|
||||||
|
var enteringAt = nextTypeRel
|
||||||
|
if mdbg:
|
||||||
|
inc nextTypeRel
|
||||||
|
echo "----- TYPE REL ", enteringAt
|
||||||
|
debug f
|
||||||
|
debug aOrig
|
||||||
|
# writeStackTrace()
|
||||||
|
|
||||||
|
let r = typeRelImpl(c, f, aOrig, flags)
|
||||||
|
|
||||||
|
when traceTypeRel:
|
||||||
|
if enteringAt != nextTypeRel:
|
||||||
|
echo "----- TYPE REL ", enteringAt, " RESULT: ", r
|
||||||
|
|
||||||
|
r
|
||||||
|
|
||||||
proc concreteType(c: TCandidate, t: PType): PType =
|
proc concreteType(c: TCandidate, t: PType): PType =
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyNil:
|
of tyNil:
|
||||||
|
|
@ -594,19 +628,29 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
|
||||||
else:
|
else:
|
||||||
result = isNone
|
result = isNone
|
||||||
|
|
||||||
proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
|
||||||
ff, a: PType): PType =
|
|
||||||
var
|
var
|
||||||
|
c = m.c
|
||||||
typeClass = ff.skipTypes({tyUserTypeClassInst})
|
typeClass = ff.skipTypes({tyUserTypeClassInst})
|
||||||
body = typeClass.n[3]
|
body = typeClass.n[3]
|
||||||
if c.inTypeClass > 4:
|
matchedConceptContext: TMatchedConcept
|
||||||
|
prevMatchedConcept = c.matchedConcept
|
||||||
|
prevCandidateType = typeClass[0][0]
|
||||||
|
|
||||||
|
if prevMatchedConcept != nil:
|
||||||
|
matchedConceptContext.prev = prevMatchedConcept
|
||||||
|
matchedConceptContext.depth = prevMatchedConcept.depth + 1
|
||||||
|
if prevMatchedConcept.depth > 4:
|
||||||
localError(body.info, $body & " too nested for type matching")
|
localError(body.info, $body & " too nested for type matching")
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
openScope(c)
|
openScope(c)
|
||||||
inc c.inTypeClass
|
matchedConceptContext.candidateType = a
|
||||||
|
typeClass[0].sons[0] = a
|
||||||
|
c.matchedConcept = addr(matchedConceptContext)
|
||||||
defer:
|
defer:
|
||||||
dec c.inTypeClass
|
c.matchedConcept = prevMatchedConcept
|
||||||
|
typeClass[0].sons[0] = prevCandidateType
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
|
|
||||||
var typeParams: seq[(PSym, PType)]
|
var typeParams: seq[(PSym, PType)]
|
||||||
|
|
@ -617,6 +661,9 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||||
typeParamName = ff.base.sons[i-1].sym.name
|
typeParamName = ff.base.sons[i-1].sym.name
|
||||||
typ = ff.sons[i]
|
typ = ff.sons[i]
|
||||||
param: PSym
|
param: PSym
|
||||||
|
alreadyBound = PType(idTableGet(m.bindings, typ))
|
||||||
|
|
||||||
|
if alreadyBound != nil: typ = alreadyBound
|
||||||
|
|
||||||
template paramSym(kind): untyped =
|
template paramSym(kind): untyped =
|
||||||
newSym(kind, typeParamName, typeClass.sym, typeClass.sym.info)
|
newSym(kind, typeParamName, typeClass.sym, typeClass.sym.info)
|
||||||
|
|
@ -650,33 +697,6 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||||
|
|
||||||
addDecl(c, param)
|
addDecl(c, param)
|
||||||
|
|
||||||
for param in typeClass.n[0]:
|
|
||||||
var
|
|
||||||
dummyName: PNode
|
|
||||||
dummyType: PType
|
|
||||||
|
|
||||||
let modifier = case param.kind
|
|
||||||
of nkVarTy: tyVar
|
|
||||||
of nkRefTy: tyRef
|
|
||||||
of nkPtrTy: tyPtr
|
|
||||||
of nkStaticTy: tyStatic
|
|
||||||
of nkTypeOfExpr: tyTypeDesc
|
|
||||||
else: tyNone
|
|
||||||
|
|
||||||
if modifier != tyNone:
|
|
||||||
dummyName = param[0]
|
|
||||||
dummyType = c.makeTypeWithModifier(modifier, a)
|
|
||||||
if modifier == tyTypeDesc: dummyType.flags.incl tfExplicit
|
|
||||||
else:
|
|
||||||
dummyName = param
|
|
||||||
dummyType = a
|
|
||||||
|
|
||||||
internalAssert dummyName.kind == nkIdent
|
|
||||||
var dummyParam = newSym(if modifier == tyTypeDesc: skType else: skVar,
|
|
||||||
dummyName.ident, typeClass.sym, typeClass.sym.info)
|
|
||||||
dummyParam.typ = dummyType
|
|
||||||
addDecl(c, dummyParam)
|
|
||||||
|
|
||||||
var
|
var
|
||||||
oldWriteHook: type(writelnHook)
|
oldWriteHook: type(writelnHook)
|
||||||
diagnostics: seq[string]
|
diagnostics: seq[string]
|
||||||
|
|
@ -818,7 +838,7 @@ proc inferStaticParam*(c: var TCandidate, lhs: PNode, rhs: BiggestInt): bool =
|
||||||
var inferred = newTypeWithSons(c.c, tyStatic, lhs.typ.sons)
|
var inferred = newTypeWithSons(c.c, tyStatic, lhs.typ.sons)
|
||||||
inferred.n = newIntNode(nkIntLit, rhs)
|
inferred.n = newIntNode(nkIntLit, rhs)
|
||||||
put(c, lhs.typ, inferred)
|
put(c, lhs.typ, inferred)
|
||||||
if c.c.inTypeClass > 0:
|
if c.c.matchedConcept != nil:
|
||||||
# inside concepts, binding is currently done with
|
# inside concepts, binding is currently done with
|
||||||
# direct mutation of the involved types:
|
# direct mutation of the involved types:
|
||||||
lhs.typ.n = inferred.n
|
lhs.typ.n = inferred.n
|
||||||
|
|
@ -860,7 +880,28 @@ template subtypeCheck() =
|
||||||
if result <= isSubrange and f.lastSon.skipTypes(abstractInst).kind in {tyRef, tyPtr, tyVar}:
|
if result <= isSubrange and f.lastSon.skipTypes(abstractInst).kind in {tyRef, tyPtr, tyVar}:
|
||||||
result = isNone
|
result = isNone
|
||||||
|
|
||||||
proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
proc isCovariantPtr(c: var TCandidate, f, a: PType): bool =
|
||||||
|
# this proc is always called for a pair of matching types
|
||||||
|
assert f.kind == a.kind
|
||||||
|
|
||||||
|
template baseTypesCheck(lhs, rhs: PType): bool =
|
||||||
|
lhs.kind notin {tyPtr, tyRef, tyVar} and
|
||||||
|
typeRel(c, lhs, rhs, {trNoCovariance}) == isSubtype
|
||||||
|
|
||||||
|
case f.kind
|
||||||
|
of tyRef, tyPtr:
|
||||||
|
return baseTypesCheck(f.base, a.base)
|
||||||
|
of tyGenericInst:
|
||||||
|
let body = f.base
|
||||||
|
return body == a.base and
|
||||||
|
a.sonsLen == 3 and
|
||||||
|
tfWeakCovariant notin body.sons[0].flags and
|
||||||
|
baseTypesCheck(f.sons[1], a.sons[1])
|
||||||
|
else:
|
||||||
|
return false
|
||||||
|
|
||||||
|
proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
|
||||||
|
flags: TTypeRelFlags = {}): TTypeRelation =
|
||||||
# typeRel can be used to establish various relationships between types:
|
# typeRel can be used to establish various relationships between types:
|
||||||
#
|
#
|
||||||
# 1) When used with concrete types, it will check for type equivalence
|
# 1) When used with concrete types, it will check for type equivalence
|
||||||
|
|
@ -887,7 +928,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
assert(aOrig != nil)
|
assert(aOrig != nil)
|
||||||
|
|
||||||
var
|
var
|
||||||
useTypeLoweringRuleInTypeClass = c.c.inTypeClass > 0 and
|
useTypeLoweringRuleInTypeClass = c.c.matchedConcept != nil and
|
||||||
not c.isNoCall and
|
not c.isNoCall and
|
||||||
f.kind != tyTypeDesc and
|
f.kind != tyTypeDesc and
|
||||||
tfExplicit notin aOrig.flags
|
tfExplicit notin aOrig.flags
|
||||||
|
|
@ -927,6 +968,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
result = isEqual
|
result = isEqual
|
||||||
return
|
return
|
||||||
|
|
||||||
|
template doBind: bool = trDontBind notin flags
|
||||||
|
|
||||||
# var and static arguments match regular modifier-free types
|
# var and static arguments match regular modifier-free types
|
||||||
var a = aOrig.skipTypes({tyStatic, tyVar}).maybeSkipDistinct(c.calleeSym)
|
var a = aOrig.skipTypes({tyStatic, tyVar}).maybeSkipDistinct(c.calleeSym)
|
||||||
# XXX: Theoretically, maybeSkipDistinct could be called before we even
|
# XXX: Theoretically, maybeSkipDistinct could be called before we even
|
||||||
|
|
@ -934,7 +977,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
# for example, but unfortunately `prepareOperand` is not called in certain
|
# for example, but unfortunately `prepareOperand` is not called in certain
|
||||||
# situation when nkDotExpr are rotated to nkDotCalls
|
# situation when nkDotExpr are rotated to nkDotCalls
|
||||||
|
|
||||||
if a.kind in {tyGenericInst, tyAlias} and
|
if aOrig.kind == tyAlias:
|
||||||
|
return typeRel(c, f, lastSon(aOrig))
|
||||||
|
|
||||||
|
if a.kind == tyGenericInst and
|
||||||
skipTypes(f, {tyVar}).kind notin {
|
skipTypes(f, {tyVar}).kind notin {
|
||||||
tyGenericBody, tyGenericInvocation,
|
tyGenericBody, tyGenericInvocation,
|
||||||
tyGenericInst, tyGenericParam} + tyTypeClasses:
|
tyGenericInst, tyGenericParam} + tyTypeClasses:
|
||||||
|
|
@ -956,23 +1002,28 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
|
|
||||||
case a.kind
|
case a.kind
|
||||||
of tyOr:
|
of tyOr:
|
||||||
|
# XXX: deal with the current dual meaning of tyGenericParam
|
||||||
|
c.typedescMatched = true
|
||||||
# seq[int|string] vs seq[number]
|
# seq[int|string] vs seq[number]
|
||||||
# both int and string must match against number
|
# both int and string must match against number
|
||||||
# but ensure that '[T: A|A]' matches as good as '[T: A]' (bug #2219):
|
# but ensure that '[T: A|A]' matches as good as '[T: A]' (bug #2219):
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
for branch in a.sons:
|
for branch in a.sons:
|
||||||
let x = typeRel(c, f, branch, false)
|
let x = typeRel(c, f, branch, flags + {trDontBind})
|
||||||
if x == isNone: return isNone
|
if x == isNone: return isNone
|
||||||
if x < result: result = x
|
if x < result: result = x
|
||||||
|
return
|
||||||
|
|
||||||
of tyAnd:
|
of tyAnd:
|
||||||
|
# XXX: deal with the current dual meaning of tyGenericParam
|
||||||
|
c.typedescMatched = true
|
||||||
# seq[Sortable and Iterable] vs seq[Sortable]
|
# seq[Sortable and Iterable] vs seq[Sortable]
|
||||||
# only one match is enough
|
# only one match is enough
|
||||||
for branch in a.sons:
|
for branch in a.sons:
|
||||||
let x = typeRel(c, f, branch, false)
|
let x = typeRel(c, f, branch, flags + {trDontBind})
|
||||||
if x != isNone:
|
if x != isNone:
|
||||||
return if x >= isGeneric: isGeneric else: x
|
return if x >= isGeneric: isGeneric else: x
|
||||||
result = isNone
|
return isNone
|
||||||
|
|
||||||
of tyNot:
|
of tyNot:
|
||||||
case f.kind
|
case f.kind
|
||||||
|
|
@ -994,9 +1045,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
else: isNone
|
else: isNone
|
||||||
|
|
||||||
of tyUserTypeClass, tyUserTypeClassInst:
|
of tyUserTypeClass, tyUserTypeClassInst:
|
||||||
|
if c.c.matchedConcept != nil:
|
||||||
# consider this: 'var g: Node' *within* a concept where 'Node'
|
# consider this: 'var g: Node' *within* a concept where 'Node'
|
||||||
# is a concept too (tgraph)
|
# is a concept too (tgraph)
|
||||||
let x = typeRel(c, a, f, false)
|
let x = typeRel(c, a, f, flags + {trDontBind})
|
||||||
if x >= isGeneric:
|
if x >= isGeneric:
|
||||||
return isGeneric
|
return isGeneric
|
||||||
else: discard
|
else: discard
|
||||||
|
|
@ -1042,7 +1094,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
of tyFloat128: result = handleFloatRange(f, a)
|
of tyFloat128: result = handleFloatRange(f, a)
|
||||||
of tyVar:
|
of tyVar:
|
||||||
if aOrig.kind == tyVar: result = typeRel(c, f.base, aOrig.base)
|
if aOrig.kind == tyVar: result = typeRel(c, f.base, aOrig.base)
|
||||||
else: result = typeRel(c, f.base, aOrig)
|
else: result = typeRel(c, f.base, aOrig, flags + {trNoCovariance})
|
||||||
subtypeCheck()
|
subtypeCheck()
|
||||||
of tyArray:
|
of tyArray:
|
||||||
case a.kind
|
case a.kind
|
||||||
|
|
@ -1056,13 +1108,21 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
fRange = a
|
fRange = a
|
||||||
else:
|
else:
|
||||||
fRange = prev
|
fRange = prev
|
||||||
result = typeRel(c, f.sons[1].skipTypes({tyTypeDesc}),
|
let ff = f.sons[1].skipTypes({tyTypeDesc})
|
||||||
a.sons[1].skipTypes({tyTypeDesc}))
|
let aa = a.sons[1].skipTypes({tyTypeDesc})
|
||||||
if result < isGeneric: return isNone
|
result = typeRel(c, ff, aa)
|
||||||
|
if result < isGeneric:
|
||||||
|
if nimEnableCovariance and
|
||||||
|
trNoCovariance notin flags and
|
||||||
|
ff.kind == aa.kind and
|
||||||
|
isCovariantPtr(c, ff, aa):
|
||||||
|
result = isSubtype
|
||||||
|
else:
|
||||||
|
return isNone
|
||||||
|
|
||||||
if fRange.rangeHasUnresolvedStatic:
|
if fRange.rangeHasUnresolvedStatic:
|
||||||
return inferStaticsInRange(c, fRange, a)
|
return inferStaticsInRange(c, fRange, a)
|
||||||
elif c.c.inTypeClass > 0 and aRange.rangeHasUnresolvedStatic:
|
elif c.c.matchedConcept != nil and aRange.rangeHasUnresolvedStatic:
|
||||||
return inferStaticsInRange(c, aRange, f)
|
return inferStaticsInRange(c, aRange, f)
|
||||||
else:
|
else:
|
||||||
if lengthOrd(fRange) != lengthOrd(aRange):
|
if lengthOrd(fRange) != lengthOrd(aRange):
|
||||||
|
|
@ -1077,20 +1137,31 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
if tfOldSchoolExprStmt in f.sons[0].flags:
|
if tfOldSchoolExprStmt in f.sons[0].flags:
|
||||||
if f.sons[0].kind == tyExpr: return
|
if f.sons[0].kind == tyExpr: return
|
||||||
elif f.sons[0].kind == tyStmt: return
|
elif f.sons[0].kind == tyStmt: return
|
||||||
|
|
||||||
|
template matchArrayOrSeq(aBase: PType) =
|
||||||
|
let ff = f.base
|
||||||
|
let aa = aBase
|
||||||
|
let baseRel = typeRel(c, ff, aa)
|
||||||
|
if baseRel >= isGeneric:
|
||||||
|
result = isConvertible
|
||||||
|
elif nimEnableCovariance and
|
||||||
|
trNoCovariance notin flags and
|
||||||
|
ff.kind == aa.kind and
|
||||||
|
isCovariantPtr(c, ff, aa):
|
||||||
|
result = isConvertible
|
||||||
|
|
||||||
case a.kind
|
case a.kind
|
||||||
of tyOpenArray, tyVarargs:
|
of tyOpenArray, tyVarargs:
|
||||||
result = typeRel(c, base(f), base(a))
|
result = typeRel(c, base(f), base(a))
|
||||||
if result < isGeneric: result = isNone
|
if result < isGeneric: result = isNone
|
||||||
of tyArray:
|
of tyArray:
|
||||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
|
if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
|
||||||
result = isSubtype
|
return isSubtype
|
||||||
elif typeRel(c, base(f), a.sons[1]) >= isGeneric:
|
matchArrayOrSeq(a.sons[1])
|
||||||
result = isConvertible
|
|
||||||
of tySequence:
|
of tySequence:
|
||||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
|
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
|
||||||
result = isConvertible
|
return isConvertible
|
||||||
elif typeRel(c, base(f), a.sons[0]) >= isGeneric:
|
matchArrayOrSeq(a.sons[0])
|
||||||
result = isConvertible
|
|
||||||
of tyString:
|
of tyString:
|
||||||
if f.kind == tyOpenArray:
|
if f.kind == tyOpenArray:
|
||||||
if f.sons[0].kind == tyChar:
|
if f.sons[0].kind == tyChar:
|
||||||
|
|
@ -1105,8 +1176,17 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
|
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
|
||||||
result = isSubtype
|
result = isSubtype
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, f.sons[0], a.sons[0])
|
let ff = f.sons[0]
|
||||||
if result < isGeneric: result = isNone
|
let aa = a.sons[0]
|
||||||
|
result = typeRel(c, ff, aa)
|
||||||
|
if result < isGeneric:
|
||||||
|
if nimEnableCovariance and
|
||||||
|
trNoCovariance notin flags and
|
||||||
|
ff.kind == aa.kind and
|
||||||
|
isCovariantPtr(c, ff, aa):
|
||||||
|
result = isSubtype
|
||||||
|
else:
|
||||||
|
result = isNone
|
||||||
elif tfNotNil in f.flags and tfNotNil notin a.flags:
|
elif tfNotNil in f.flags and tfNotNil notin a.flags:
|
||||||
result = isNilConversion
|
result = isNilConversion
|
||||||
of tyNil: result = f.allowsNil
|
of tyNil: result = f.allowsNil
|
||||||
|
|
@ -1158,7 +1238,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
if a.len < f.len: return isNone
|
if a.len < f.len: return isNone
|
||||||
for i in 0..f.len-2:
|
for i in 0..f.len-2:
|
||||||
if typeRel(c, f.sons[i], a.sons[i]) == isNone: return isNone
|
if typeRel(c, f.sons[i], a.sons[i]) == isNone: return isNone
|
||||||
result = typeRel(c, f.lastSon, a.lastSon)
|
result = typeRel(c, f.lastSon, a.lastSon, flags + {trNoCovariance})
|
||||||
subtypeCheck()
|
subtypeCheck()
|
||||||
if result <= isConvertible: result = isNone
|
if result <= isConvertible: result = isNone
|
||||||
elif tfNotNil in f.flags and tfNotNil notin a.flags:
|
elif tfNotNil in f.flags and tfNotNil notin a.flags:
|
||||||
|
|
@ -1230,13 +1310,28 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
var m = c
|
var m = c
|
||||||
if a.kind == tyGenericInst:
|
if a.kind == tyGenericInst:
|
||||||
if roota.base == rootf.base:
|
if roota.base == rootf.base:
|
||||||
|
let nextFlags = flags + {trNoCovariance}
|
||||||
|
var hasCovariance = false
|
||||||
for i in 1 .. rootf.sonsLen-2:
|
for i in 1 .. rootf.sonsLen-2:
|
||||||
let ff = rootf.sons[i]
|
let ff = rootf.sons[i]
|
||||||
let aa = roota.sons[i]
|
let aa = roota.sons[i]
|
||||||
result = typeRel(c, ff, aa)
|
result = typeRel(c, ff, aa, nextFlags)
|
||||||
if result notin {isEqual, isGeneric}: return isNone
|
if result notin {isEqual, isGeneric}:
|
||||||
# if ff.kind == tyRange and result != isEqual: return isNone
|
if trNoCovariance notin flags and ff.kind == aa.kind:
|
||||||
|
let paramFlags = rootf.base.sons[i-1].flags
|
||||||
|
hasCovariance =
|
||||||
|
if tfCovariant in paramFlags:
|
||||||
|
if tfWeakCovariant in paramFlags:
|
||||||
|
isCovariantPtr(c, ff, aa)
|
||||||
|
else:
|
||||||
|
ff.kind notin {tyRef, tyPtr} and result == isSubtype
|
||||||
|
else:
|
||||||
|
tfContravariant in paramFlags and
|
||||||
|
typeRel(c, aa, ff) == isSubtype
|
||||||
|
if hasCovariance:
|
||||||
|
continue
|
||||||
|
|
||||||
|
return isNone
|
||||||
if prev == nil: put(c, f, a)
|
if prev == nil: put(c, f, a)
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
else:
|
else:
|
||||||
|
|
@ -1260,7 +1355,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
result = isNone
|
result = isNone
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, lastSon(f), a)
|
result = typeRel(c, lastSon(f), a)
|
||||||
if result != isNone: put(c, f, a)
|
if result != isNone and a.kind != tyNil:
|
||||||
|
put(c, f, a)
|
||||||
|
|
||||||
of tyGenericBody:
|
of tyGenericBody:
|
||||||
considerPreviousT:
|
considerPreviousT:
|
||||||
|
|
@ -1396,7 +1492,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
result = typeRel(c, f.lastSon, a)
|
result = typeRel(c, f.lastSon, a)
|
||||||
else:
|
else:
|
||||||
considerPreviousT:
|
considerPreviousT:
|
||||||
var matched = matchUserTypeClass(c.c, c, f, aOrig)
|
if aOrig == f: return isEqual
|
||||||
|
var matched = matchUserTypeClass(c, f, aOrig)
|
||||||
if matched != nil:
|
if matched != nil:
|
||||||
bindConcreteTypeToUserTypeClass(matched, a)
|
bindConcreteTypeToUserTypeClass(matched, a)
|
||||||
if doBind: put(c, f, matched)
|
if doBind: put(c, f, matched)
|
||||||
|
|
@ -1450,7 +1547,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
result = isNone
|
result = isNone
|
||||||
else:
|
else:
|
||||||
if f.sonsLen > 0 and f.sons[0].kind != tyNone:
|
if f.sonsLen > 0 and f.sons[0].kind != tyNone:
|
||||||
result = typeRel(c, f.lastSon, a, false)
|
result = typeRel(c, f.lastSon, a, flags + {trDontBind})
|
||||||
if doBind and result notin {isNone, isGeneric}:
|
if doBind and result notin {isNone, isGeneric}:
|
||||||
let concrete = concreteType(c, a)
|
let concrete = concreteType(c, a)
|
||||||
if concrete == nil: return isNone
|
if concrete == nil: return isNone
|
||||||
|
|
@ -1488,6 +1585,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
if not exprStructuralEquivalent(f.n, aOrig.n):
|
if not exprStructuralEquivalent(f.n, aOrig.n):
|
||||||
result = isNone
|
result = isNone
|
||||||
if result != isNone: put(c, f, aOrig)
|
if result != isNone: put(c, f, aOrig)
|
||||||
|
elif aOrig.n != nil:
|
||||||
|
result = typeRel(c, f.lastSon, aOrig.n.typ)
|
||||||
|
if result != isNone:
|
||||||
|
var boundType = newTypeWithSons(c.c, tyStatic, @[aOrig.n.typ])
|
||||||
|
boundType.n = aOrig.n
|
||||||
|
put(c, f, boundType)
|
||||||
else:
|
else:
|
||||||
result = isNone
|
result = isNone
|
||||||
elif prev.kind == tyStatic:
|
elif prev.kind == tyStatic:
|
||||||
|
|
@ -1691,6 +1794,13 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
|
||||||
arg.typ.sons = @[evaluated.typ]
|
arg.typ.sons = @[evaluated.typ]
|
||||||
arg.typ.n = evaluated
|
arg.typ.n = evaluated
|
||||||
a = arg.typ
|
a = arg.typ
|
||||||
|
else:
|
||||||
|
if m.callee.kind == tyGenericBody:
|
||||||
|
if f.kind == tyStatic and typeRel(m, f.base, a) != isNone:
|
||||||
|
result = makeStaticExpr(m.c, arg)
|
||||||
|
result.typ.flags.incl tfUnresolved
|
||||||
|
result.typ.n = arg
|
||||||
|
return
|
||||||
|
|
||||||
var r = typeRel(m, f, a)
|
var r = typeRel(m, f, a)
|
||||||
|
|
||||||
|
|
@ -2140,6 +2250,8 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
|
||||||
var def = copyTree(formal.ast)
|
var def = copyTree(formal.ast)
|
||||||
if def.kind == nkNilLit:
|
if def.kind == nkNilLit:
|
||||||
def = implicitConv(nkHiddenStdConv, formal.typ, def, m, c)
|
def = implicitConv(nkHiddenStdConv, formal.typ, def, m, c)
|
||||||
|
if {tfImplicitTypeParam, tfGenericTypeParam} * formal.typ.flags != {}:
|
||||||
|
put(m, formal.typ, def.typ)
|
||||||
setSon(m.call, formal.position + 1, def)
|
setSon(m.call, formal.position + 1, def)
|
||||||
inc(f)
|
inc(f)
|
||||||
# forget all inferred types if the overload matching failed
|
# forget all inferred types if the overload matching failed
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ proc exprStructuralEquivalent*(a, b: PNode; strictSymEquality=false): bool =
|
||||||
of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal
|
of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal
|
||||||
of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
|
of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
|
||||||
of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
|
of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
|
||||||
|
of nkCommentStmt: result = a.comment == b.comment
|
||||||
of nkEmpty, nkNilLit, nkType: result = true
|
of nkEmpty, nkNilLit, nkType: result = true
|
||||||
else:
|
else:
|
||||||
if sonsLen(a) == sonsLen(b):
|
if sonsLen(a) == sonsLen(b):
|
||||||
|
|
@ -109,9 +110,11 @@ proc isDeepConstExpr*(n: PNode): bool =
|
||||||
|
|
||||||
proc isRange*(n: PNode): bool {.inline.} =
|
proc isRange*(n: PNode): bool {.inline.} =
|
||||||
if n.kind in nkCallKinds:
|
if n.kind in nkCallKinds:
|
||||||
if n[0].kind == nkIdent and n[0].ident.id == ord(wDotDot) or
|
let callee = n[0]
|
||||||
n[0].kind in {nkClosedSymChoice, nkOpenSymChoice} and
|
if (callee.kind == nkIdent and callee.ident.id == ord(wDotDot)) or
|
||||||
n[0][1].sym.name.id == ord(wDotDot):
|
(callee.kind == nkSym and callee.sym.name.id == ord(wDotDot)) or
|
||||||
|
(callee.kind in {nkClosedSymChoice, nkOpenSymChoice} and
|
||||||
|
callee[1].sym.name.id == ord(wDotDot)):
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc whichPragma*(n: PNode): TSpecialWord =
|
proc whichPragma*(n: PNode): TSpecialWord =
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,9 @@ proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string =
|
||||||
add(result, ')')
|
add(result, ')')
|
||||||
if n.sons[0].typ != nil:
|
if n.sons[0].typ != nil:
|
||||||
result.add(": " & typeToString(n.sons[0].typ, prefer))
|
result.add(": " & typeToString(n.sons[0].typ, prefer))
|
||||||
|
result.add "[declared in "
|
||||||
|
result.add($sym.info)
|
||||||
|
result.add "]"
|
||||||
|
|
||||||
proc elemType*(t: PType): PType =
|
proc elemType*(t: PType): PType =
|
||||||
assert(t != nil)
|
assert(t != nil)
|
||||||
|
|
@ -421,6 +424,12 @@ template bindConcreteTypeToUserTypeClass*(tc, concrete: PType) =
|
||||||
tc.sons.safeAdd concrete
|
tc.sons.safeAdd concrete
|
||||||
tc.flags.incl tfResolved
|
tc.flags.incl tfResolved
|
||||||
|
|
||||||
|
# TODO: It would be a good idea to kill the special state of a resolved
|
||||||
|
# concept by switching to tyAlias within the instantiated procs.
|
||||||
|
# Currently, tyAlias is always skipped with lastSon, which means that
|
||||||
|
# we can store information about the matched concept in another position.
|
||||||
|
# Then builtInFieldAccess can be modified to properly read the derived
|
||||||
|
# consts and types stored within the concept.
|
||||||
template isResolvedUserTypeClass*(t: PType): bool =
|
template isResolvedUserTypeClass*(t: PType): bool =
|
||||||
tfResolved in t.flags
|
tfResolved in t.flags
|
||||||
|
|
||||||
|
|
@ -437,6 +446,13 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
result = t.sym.name.s & " literal(" & $t.n.intVal & ")"
|
result = t.sym.name.s & " literal(" & $t.n.intVal & ")"
|
||||||
elif prefer == preferName or t.sym.owner.isNil:
|
elif prefer == preferName or t.sym.owner.isNil:
|
||||||
result = t.sym.name.s
|
result = t.sym.name.s
|
||||||
|
if t.kind == tyGenericParam and t.sons != nil and t.sonsLen > 0:
|
||||||
|
result.add ": "
|
||||||
|
var first = true
|
||||||
|
for son in t.sons:
|
||||||
|
if not first: result.add " or "
|
||||||
|
result.add son.typeToString
|
||||||
|
first = false
|
||||||
else:
|
else:
|
||||||
result = t.sym.owner.name.s & '.' & t.sym.name.s
|
result = t.sym.owner.name.s & '.' & t.sym.name.s
|
||||||
result.addTypeFlags(t)
|
result.addTypeFlags(t)
|
||||||
|
|
@ -458,7 +474,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
add(result, ']')
|
add(result, ']')
|
||||||
of tyTypeDesc:
|
of tyTypeDesc:
|
||||||
if t.sons[0].kind == tyNone: result = "typedesc"
|
if t.sons[0].kind == tyNone: result = "typedesc"
|
||||||
else: result = "typedesc[" & typeToString(t.sons[0]) & "]"
|
else: result = "type " & typeToString(t.sons[0])
|
||||||
of tyStatic:
|
of tyStatic:
|
||||||
internalAssert t.len > 0
|
internalAssert t.len > 0
|
||||||
if prefer == preferGenericArg and t.n != nil:
|
if prefer == preferGenericArg and t.n != nil:
|
||||||
|
|
@ -688,6 +704,7 @@ type
|
||||||
ExactTypeDescValues
|
ExactTypeDescValues
|
||||||
ExactGenericParams
|
ExactGenericParams
|
||||||
ExactConstraints
|
ExactConstraints
|
||||||
|
ExactGcSafety
|
||||||
AllowCommonBase
|
AllowCommonBase
|
||||||
|
|
||||||
TTypeCmpFlags* = set[TTypeCmpFlag]
|
TTypeCmpFlags* = set[TTypeCmpFlag]
|
||||||
|
|
@ -976,6 +993,8 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||||
cycleCheck()
|
cycleCheck()
|
||||||
if a.kind == tyUserTypeClass and a.n != nil: return a.n == b.n
|
if a.kind == tyUserTypeClass and a.n != nil: return a.n == b.n
|
||||||
result = sameChildrenAux(a, b, c) and sameFlags(a, b)
|
result = sameChildrenAux(a, b, c) and sameFlags(a, b)
|
||||||
|
if result and ExactGcSafety in c.flags:
|
||||||
|
result = a.flags * {tfThread} == b.flags * {tfThread}
|
||||||
if result and a.kind == tyProc:
|
if result and a.kind == tyProc:
|
||||||
result = ((IgnoreCC in c.flags) or a.callConv == b.callConv) and
|
result = ((IgnoreCC in c.flags) or a.callConv == b.callConv) and
|
||||||
((ExactConstraints notin c.flags) or sameConstraints(a.n, b.n))
|
((ExactConstraints notin c.flags) or sameConstraints(a.n, b.n))
|
||||||
|
|
|
||||||
|
|
@ -52,13 +52,16 @@ proc renderType(n: PNode): string =
|
||||||
else:
|
else:
|
||||||
result = "ptr"
|
result = "ptr"
|
||||||
of nkProcTy:
|
of nkProcTy:
|
||||||
assert len(n) > 1
|
assert len(n) != 1
|
||||||
|
if len(n) > 1:
|
||||||
let params = n[0]
|
let params = n[0]
|
||||||
assert params.kind == nkFormalParams
|
assert params.kind == nkFormalParams
|
||||||
assert len(params) > 0
|
assert len(params) > 0
|
||||||
result = "proc("
|
result = "proc("
|
||||||
for i in 1 .. <len(params): result.add(renderType(params[i]) & ',')
|
for i in 1 .. <len(params): result.add(renderType(params[i]) & ',')
|
||||||
result[<len(result)] = ')'
|
result[<len(result)] = ')'
|
||||||
|
else:
|
||||||
|
result = "proc"
|
||||||
of nkIdentDefs:
|
of nkIdentDefs:
|
||||||
assert len(n) >= 3
|
assert len(n) >= 3
|
||||||
let typePos = len(n) - 2
|
let typePos = len(n) - 2
|
||||||
|
|
|
||||||
|
|
@ -1406,6 +1406,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
if dest.kind in {nkStrLit..nkTripleStrLit} and
|
if dest.kind in {nkStrLit..nkTripleStrLit} and
|
||||||
regs[rb].kind in {rkNode}:
|
regs[rb].kind in {rkNode}:
|
||||||
dest.strVal = regs[rb].node.strVal
|
dest.strVal = regs[rb].node.strVal
|
||||||
|
elif dest.kind == nkCommentStmt and regs[rb].kind in {rkNode}:
|
||||||
|
dest.comment = regs[rb].node.strVal
|
||||||
else:
|
else:
|
||||||
stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
|
stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
|
||||||
of opcNNewNimNode:
|
of opcNNewNimNode:
|
||||||
|
|
@ -1609,8 +1611,9 @@ proc setupMacroParam(x: PNode, typ: PType): TFullReg =
|
||||||
iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) =
|
iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) =
|
||||||
let gp = macroSym.ast[genericParamsPos]
|
let gp = macroSym.ast[genericParamsPos]
|
||||||
for i in 0 .. <gp.len:
|
for i in 0 .. <gp.len:
|
||||||
let idx = macroSym.typ.len + i
|
let genericParam = gp[i].sym
|
||||||
yield (gp[i].sym, call.sons[idx])
|
let posInCall = macroSym.typ.len + i
|
||||||
|
yield (genericParam, call[posInCall])
|
||||||
|
|
||||||
var evalMacroCounter: int
|
var evalMacroCounter: int
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -826,7 +826,23 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||||
of mSubF64: genBinaryABC(c, n, dest, opcSubFloat)
|
of mSubF64: genBinaryABC(c, n, dest, opcSubFloat)
|
||||||
of mMulF64: genBinaryABC(c, n, dest, opcMulFloat)
|
of mMulF64: genBinaryABC(c, n, dest, opcMulFloat)
|
||||||
of mDivF64: genBinaryABC(c, n, dest, opcDivFloat)
|
of mDivF64: genBinaryABC(c, n, dest, opcDivFloat)
|
||||||
of mShrI: genBinaryABCnarrowU(c, n, dest, opcShrInt)
|
of mShrI:
|
||||||
|
# the idea here is to narrow type if needed before executing right shift
|
||||||
|
# inlined modified: genNarrowU(c, n, dest)
|
||||||
|
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
|
||||||
|
# uint is uint64 in the VM, we we only need to mask the result for
|
||||||
|
# other unsigned types:
|
||||||
|
let tmp = c.genx(n.sons[1])
|
||||||
|
if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32}:
|
||||||
|
c.gABC(n, opcNarrowU, tmp, TRegister(t.size*8))
|
||||||
|
|
||||||
|
# inlined modified: genBinaryABC(c, n, dest, opcShrInt)
|
||||||
|
let tmp2 = c.genx(n.sons[2])
|
||||||
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
|
c.gABC(n, opcShrInt, dest, tmp, tmp2)
|
||||||
|
c.freeTemp(tmp)
|
||||||
|
c.freeTemp(tmp2)
|
||||||
|
|
||||||
of mShlI: genBinaryABCnarrowU(c, n, dest, opcShlInt)
|
of mShlI: genBinaryABCnarrowU(c, n, dest, opcShlInt)
|
||||||
of mBitandI: genBinaryABCnarrowU(c, n, dest, opcBitandInt)
|
of mBitandI: genBinaryABCnarrowU(c, n, dest, opcBitandInt)
|
||||||
of mBitorI: genBinaryABCnarrowU(c, n, dest, opcBitorInt)
|
of mBitorI: genBinaryABCnarrowU(c, n, dest, opcBitorInt)
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ Advanced commands:
|
||||||
//check checks the project for syntax and semantic
|
//check checks the project for syntax and semantic
|
||||||
|
|
||||||
Advanced options:
|
Advanced options:
|
||||||
-o, --out:FILE set the output filename
|
-o:FILE, --out:FILE set the output filename
|
||||||
--stdout output to stdout
|
--stdout output to stdout
|
||||||
--colors:on|off turn compiler messages coloring on|off
|
--colors:on|off turn compiler messages coloring on|off
|
||||||
--listFullPaths list full paths in messages
|
--listFullPaths list full paths in messages
|
||||||
|
|
|
||||||
|
|
@ -461,8 +461,8 @@ Documentation Comments
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
Double-hash (``##``) comments in the code actually have their own format,
|
Double-hash (``##``) comments in the code actually have their own format,
|
||||||
but the comments do not yet show up in the AST, which will only show that
|
using ``strVal`` to get and set the comment text. Single-hash (``#``)
|
||||||
a comment exists, not what it contains. Single-hash (``#``) comments are ignored.
|
comments are ignored.
|
||||||
|
|
||||||
Concrete syntax:
|
Concrete syntax:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ plusExpr = mulExpr (OP8 optInd mulExpr)*
|
||||||
mulExpr = dollarExpr (OP9 optInd dollarExpr)*
|
mulExpr = dollarExpr (OP9 optInd dollarExpr)*
|
||||||
dollarExpr = primary (OP10 optInd primary)*
|
dollarExpr = primary (OP10 optInd primary)*
|
||||||
symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
|
symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
|
||||||
| IDENT | 'addr' | 'type'
|
| IDENT | KEYW
|
||||||
exprColonEqExpr = expr (':'|'=' expr)?
|
exprColonEqExpr = expr (':'|'=' expr)?
|
||||||
exprList = expr ^+ comma
|
exprList = expr ^+ comma
|
||||||
dotExpr = expr '.' optInd symbol
|
dotExpr = expr '.' optInd symbol
|
||||||
|
|
@ -81,7 +81,6 @@ paramList = '(' declColonEquals ^* (comma/semicolon) ')'
|
||||||
paramListArrow = paramList? ('->' optInd typeDesc)?
|
paramListArrow = paramList? ('->' optInd typeDesc)?
|
||||||
paramListColon = paramList? (':' optInd typeDesc)?
|
paramListColon = paramList? (':' optInd typeDesc)?
|
||||||
doBlock = 'do' paramListArrow pragmas? colcom stmt
|
doBlock = 'do' paramListArrow pragmas? colcom stmt
|
||||||
doBlocks = doBlock ^* IND{=}
|
|
||||||
procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
|
procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
|
||||||
distinct = 'distinct' optInd typeDesc
|
distinct = 'distinct' optInd typeDesc
|
||||||
expr = (ifExpr
|
expr = (ifExpr
|
||||||
|
|
@ -98,7 +97,8 @@ primary = typeKeyw typeDescK
|
||||||
typeDesc = simpleExpr
|
typeDesc = simpleExpr
|
||||||
typeDefAux = simpleExpr
|
typeDefAux = simpleExpr
|
||||||
| 'concept' typeClass
|
| 'concept' typeClass
|
||||||
macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt
|
postExprBlocks = ':' stmt? ( IND{=} doBlock
|
||||||
|
| IND{=} 'of' exprList ':' stmt
|
||||||
| IND{=} 'elif' expr ':' stmt
|
| IND{=} 'elif' expr ':' stmt
|
||||||
| IND{=} 'except' exprList ':' stmt
|
| IND{=} 'except' exprList ':' stmt
|
||||||
| IND{=} 'else' ':' stmt )*
|
| IND{=} 'else' ':' stmt )*
|
||||||
|
|
|
||||||
|
|
@ -1006,16 +1006,37 @@ CodegenDecl pragma
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
The ``codegenDecl`` pragma can be used to directly influence Nim's code
|
The ``codegenDecl`` pragma can be used to directly influence Nim's code
|
||||||
generator. It receives a format string that determines how the variable or
|
generator. It receives a format string that determines how the variable
|
||||||
proc is declared in the generated code:
|
or proc is declared in the generated code.
|
||||||
|
|
||||||
|
For variables $1 in the format string represents the type of the variable
|
||||||
|
and $2 is the name of the variable.
|
||||||
|
|
||||||
|
The following Nim code:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
var
|
var
|
||||||
a {.codegenDecl: "$# progmem $#".}: int
|
a {.codegenDecl: "$# progmem $#".}: int
|
||||||
|
|
||||||
|
will generate this C code:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
int progmem a
|
||||||
|
|
||||||
|
For procedures $1 is the return type of the procedure, $2 is the name of
|
||||||
|
the procedure and $3 is the parameter list.
|
||||||
|
|
||||||
|
The following nim code:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
proc myinterrupt() {.codegenDecl: "__interrupt $# $#$#".} =
|
proc myinterrupt() {.codegenDecl: "__interrupt $# $#$#".} =
|
||||||
echo "realistic interrupt handler"
|
echo "realistic interrupt handler"
|
||||||
|
|
||||||
|
will generate this code:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
__interrupt void myinterrupt()
|
||||||
|
|
||||||
|
|
||||||
InjectStmt pragma
|
InjectStmt pragma
|
||||||
-----------------
|
-----------------
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,105 @@ relation is extended to the types ``var``, ``ref``, ``ptr``:
|
||||||
.. XXX nil is a special value!
|
.. XXX nil is a special value!
|
||||||
|
|
||||||
|
|
||||||
|
Covariance
|
||||||
|
----------
|
||||||
|
|
||||||
|
Covariance in Nim can be introduced only though pointer-like types such
|
||||||
|
as ``ptr`` and ``ref``. Sequence, Array and OpenArray types, instantiated
|
||||||
|
with pointer-like types will be considered covariant if and only if they
|
||||||
|
are also immutable. The introduction of a ``var`` modifier or additional
|
||||||
|
``ptr`` or ``ref`` indirections would result in invariant treatment of
|
||||||
|
these types.
|
||||||
|
|
||||||
|
``proc`` types are currently always invariant, but future versions of Nim
|
||||||
|
may relax this rule.
|
||||||
|
|
||||||
|
User-defined generic types may also be covariant with respect to some of
|
||||||
|
their parameters. By default, all generic params are considered invariant,
|
||||||
|
but you may choose the apply the prefix modifier ``in`` to a parameter to
|
||||||
|
make it contravariant or ``out`` to make it covariant:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
type
|
||||||
|
AnnotatedPtr[out T] =
|
||||||
|
metadata: MyTypeInfo
|
||||||
|
p: ref T
|
||||||
|
|
||||||
|
RingBuffer[out T] =
|
||||||
|
startPos: int
|
||||||
|
data: seq[T]
|
||||||
|
|
||||||
|
Action {.importcpp: "std::function<void ('0)>".} [in T] = object
|
||||||
|
|
||||||
|
When the designated generic parameter is used to instantiate a pointer-like
|
||||||
|
type as in the case of `AnnotatedPtr` above, the resulting generic type will
|
||||||
|
also have pointer-like covariance:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
type
|
||||||
|
GuiWidget = object of RootObj
|
||||||
|
Button = object of GuiWidget
|
||||||
|
ComboBox = object of GuiWidget
|
||||||
|
|
||||||
|
var
|
||||||
|
widgetPtr: AnnotatedPtr[GuiWidget]
|
||||||
|
buttonPtr: AnnotatedPtr[Button]
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
proc drawWidget[T](x: AnnotatedPtr[GuiWidget]) = ...
|
||||||
|
|
||||||
|
# you can call procs expecting base types by supplying a derived type
|
||||||
|
drawWidget(buttonPtr)
|
||||||
|
|
||||||
|
# and you can convert more-specific pointer types to more general ones
|
||||||
|
widgetPtr = buttonPtr
|
||||||
|
|
||||||
|
Just like with regular pointers, covariance will be enabled only for immutable
|
||||||
|
values:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
proc makeComboBox[T](x: var AnnotatedPtr[GuiWidget]) =
|
||||||
|
x.p = new(ComboBox)
|
||||||
|
|
||||||
|
makeComboBox(buttonPtr) # Error, AnnotatedPtr[Button] cannot be modified
|
||||||
|
# to point to a ComboBox
|
||||||
|
|
||||||
|
On the other hand, in the `RingBuffer` example above, the designated generic
|
||||||
|
param is used to instantiate the non-pointer ``seq`` type, which means that
|
||||||
|
the resulting generic type will have covariance that mimics an array or
|
||||||
|
sequence (i.e. it will be covariant only when instantiated with ``ptr`` and
|
||||||
|
``ref`` types):
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
|
||||||
|
type
|
||||||
|
Base = object of RootObj
|
||||||
|
Derived = object of Base
|
||||||
|
|
||||||
|
proc consumeBaseValues(b: RingBuffer[Base]) = ...
|
||||||
|
|
||||||
|
var derivedValues: RingBuffer[Derived]
|
||||||
|
|
||||||
|
consumeBaseValues(derivedValues) # Error, Base and Derived values may differ
|
||||||
|
# in size
|
||||||
|
|
||||||
|
proc consumeBasePointers(b: RingBuffer[ptr Base]) = ...
|
||||||
|
|
||||||
|
var derivedPointers: RingBuffer[ptr Derived]
|
||||||
|
|
||||||
|
consumeBaseValues(derivedPointers) # This is legal
|
||||||
|
|
||||||
|
Please note that Nim will treat the user-defined pointer-like types as
|
||||||
|
proper alternatives to the built-in pointer types. That is, types such
|
||||||
|
as `seq[AnnotatedPtr[T]]` or `RingBuffer[AnnotatedPtr[T]]` will also be
|
||||||
|
considered covariant and you can create new pointer-like types by instantiating
|
||||||
|
other user-defined pointer-like types.
|
||||||
|
|
||||||
|
The contravariant parameters introduced with the ``in`` modifier are currently
|
||||||
|
useful only when interfacing with imported types having such semantics.
|
||||||
|
|
||||||
|
|
||||||
Convertible relation
|
Convertible relation
|
||||||
--------------------
|
--------------------
|
||||||
A type ``a`` is **implicitly** convertible to type ``b`` iff the following
|
A type ``a`` is **implicitly** convertible to type ``b`` iff the following
|
||||||
|
|
@ -119,6 +218,8 @@ algorithm returns true:
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
# XXX range types?
|
# XXX range types?
|
||||||
proc isImplicitlyConvertible(a, b: PType): bool =
|
proc isImplicitlyConvertible(a, b: PType): bool =
|
||||||
|
if isSubtype(a, b) or isCovariant(a, b):
|
||||||
|
return true
|
||||||
case a.kind
|
case a.kind
|
||||||
of int: result = b in {int8, int16, int32, int64, uint, uint8, uint16,
|
of int: result = b in {int8, int16, int32, int64, uint, uint8, uint16,
|
||||||
uint32, uint64, float, float32, float64}
|
uint32, uint64, float, float32, float64}
|
||||||
|
|
|
||||||
|
|
@ -108,3 +108,12 @@ installation of Nimble is done with this simple script:
|
||||||
|
|
||||||
mvFile "nimble" & $id & "/src/nimble".toExe, "bin/nimble".toExe
|
mvFile "nimble" & $id & "/src/nimble".toExe, "bin/nimble".toExe
|
||||||
|
|
||||||
|
You can also use the shebang ``#!/usr/bin/env nim``, as long as your filename
|
||||||
|
ends with ``.nims``:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
|
||||||
|
#!/usr/bin/env nim
|
||||||
|
mode = ScriptMode.Silent
|
||||||
|
|
||||||
|
echo "hello world"
|
||||||
|
|
|
||||||
14
doc/tut1.rst
14
doc/tut1.rst
|
|
@ -1492,20 +1492,6 @@ variables! For example:
|
||||||
echo badname
|
echo badname
|
||||||
echo badext
|
echo badext
|
||||||
|
|
||||||
Tuple unpacking **only** works in ``var`` or ``let`` blocks. The following code
|
|
||||||
won't compile:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
var
|
|
||||||
path = "usr/local/nimc.html"
|
|
||||||
dir, name, ext = ""
|
|
||||||
|
|
||||||
(dir, name, ext) = splitFile(path)
|
|
||||||
# --> Error: '(dir, name, ext)' cannot be assigned to
|
|
||||||
|
|
||||||
|
|
||||||
Reference and pointer types
|
Reference and pointer types
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,7 @@ for any type:
|
||||||
|
|
||||||
echo "abc".len # is the same as echo len("abc")
|
echo "abc".len # is the same as echo len("abc")
|
||||||
echo "abc".toUpper()
|
echo "abc".toUpper()
|
||||||
echo {'a', 'b', 'c'}.card
|
echo({'a', 'b', 'c'}.card)
|
||||||
stdout.writeLine("Hallo") # the same as writeLine(stdout, "Hallo")
|
stdout.writeLine("Hallo") # the same as writeLine(stdout, "Hallo")
|
||||||
|
|
||||||
(Another way to look at the method call syntax is that it provides the missing
|
(Another way to look at the method call syntax is that it provides the missing
|
||||||
|
|
|
||||||
49
koch.nim
49
koch.nim
|
|
@ -152,6 +152,10 @@ proc tryExec(cmd: string): bool =
|
||||||
proc safeRemove(filename: string) =
|
proc safeRemove(filename: string) =
|
||||||
if existsFile(filename): removeFile(filename)
|
if existsFile(filename): removeFile(filename)
|
||||||
|
|
||||||
|
proc overwriteFile(source, dest: string) =
|
||||||
|
safeRemove(dest)
|
||||||
|
moveFile(source, dest)
|
||||||
|
|
||||||
proc copyExe(source, dest: string) =
|
proc copyExe(source, dest: string) =
|
||||||
safeRemove(dest)
|
safeRemove(dest)
|
||||||
copyFile(dest=dest, source=source)
|
copyFile(dest=dest, source=source)
|
||||||
|
|
@ -388,48 +392,25 @@ proc clean(args: string) =
|
||||||
|
|
||||||
# -------------- builds a release ---------------------------------------------
|
# -------------- builds a release ---------------------------------------------
|
||||||
|
|
||||||
proc patchConfig(lookFor, replaceBy: string) =
|
|
||||||
const
|
|
||||||
cfgFile = "config/nim.cfg"
|
|
||||||
try:
|
|
||||||
let cfg = readFile(cfgFile)
|
|
||||||
let newCfg = cfg.replace(lookFor, replaceBy)
|
|
||||||
if newCfg == cfg:
|
|
||||||
echo "Could not patch 'config/nim.cfg' [Error]"
|
|
||||||
echo "Reason: patch substring not found:"
|
|
||||||
echo lookFor
|
|
||||||
else:
|
|
||||||
writeFile(cfgFile, newCfg)
|
|
||||||
except IOError:
|
|
||||||
quit "Could not access 'config/nim.cfg' [Error]"
|
|
||||||
|
|
||||||
proc winReleaseArch(arch: string) =
|
proc winReleaseArch(arch: string) =
|
||||||
doAssert arch in ["32", "64"]
|
doAssert arch in ["32", "64"]
|
||||||
let cpu = if arch == "32": "i386" else: "amd64"
|
let cpu = if arch == "32": "i386" else: "amd64"
|
||||||
|
|
||||||
template withMingw(path, body) =
|
template withMingw(path, body) =
|
||||||
const orig = """#gcc.path = r"$nim\dist\mingw\bin""""
|
let prevPath = getEnv("PATH")
|
||||||
let replacePattern = """gcc.path = r"..\mingw$1\bin" # winrelease""" % arch
|
putEnv("PATH", path & PathSep & prevPath)
|
||||||
patchConfig(orig, replacePattern)
|
|
||||||
try:
|
try:
|
||||||
body
|
body
|
||||||
finally:
|
finally:
|
||||||
patchConfig(replacePattern, orig)
|
putEnv("PATH", prevPath)
|
||||||
|
|
||||||
withMingw r"..\mingw" & arch & r"\bin":
|
withMingw r"..\mingw" & arch & r"\bin":
|
||||||
# Rebuilding koch is necessary because it uses its pointer size to
|
# Rebuilding koch is necessary because it uses its pointer size to
|
||||||
# determine which mingw link to put in the NSIS installer.
|
# determine which mingw link to put in the NSIS installer.
|
||||||
nimexec "c --out:koch_temp --cpu:$# koch" % cpu
|
nimexec "c --out:koch_temp --cpu:$# koch" % cpu
|
||||||
exec "koch_temp boot -d:release --cpu:$#" % cpu
|
exec "koch_temp boot -d:release --cpu:$#" % cpu
|
||||||
exec "koch_temp nsis -d:release"
|
|
||||||
exec "koch_temp zip -d:release"
|
exec "koch_temp zip -d:release"
|
||||||
|
overwriteFile r"build\nim-$#.zip" % VersionAsString,
|
||||||
when false:
|
|
||||||
# we now disable the NSIS installer as it cannot download from https
|
|
||||||
# and is broken in so many different ways it's not funny anymore:
|
|
||||||
moveFile r"build\nim_$#.exe" % VersionAsString,
|
|
||||||
r"web\upload\download\nim-$#_x$#.exe" % [VersionAsString, arch]
|
|
||||||
moveFile r"build\nim-$#.zip" % VersionAsString,
|
|
||||||
r"web\upload\download\nim-$#_x$#.zip" % [VersionAsString, arch]
|
r"web\upload\download\nim-$#_x$#.zip" % [VersionAsString, arch]
|
||||||
|
|
||||||
proc winRelease() =
|
proc winRelease() =
|
||||||
|
|
@ -438,7 +419,7 @@ proc winRelease() =
|
||||||
web(gaCode)
|
web(gaCode)
|
||||||
withDir "web/upload/" & VersionAsString:
|
withDir "web/upload/" & VersionAsString:
|
||||||
exec "7z a -tzip docs-$#.zip *.html" % VersionAsString
|
exec "7z a -tzip docs-$#.zip *.html" % VersionAsString
|
||||||
moveFile "web/upload/$1/docs-$1.zip" % VersionAsString,
|
overwriteFile "web/upload/$1/docs-$1.zip" % VersionAsString,
|
||||||
"web/upload/download/docs-$1.zip" % VersionAsString
|
"web/upload/download/docs-$1.zip" % VersionAsString
|
||||||
when true:
|
when true:
|
||||||
csource("-d:release")
|
csource("-d:release")
|
||||||
|
|
@ -489,6 +470,17 @@ proc temp(args: string) =
|
||||||
copyExe(output, finalDest)
|
copyExe(output, finalDest)
|
||||||
if programArgs.len > 0: exec(finalDest & " " & programArgs)
|
if programArgs.len > 0: exec(finalDest & " " & programArgs)
|
||||||
|
|
||||||
|
proc xtemp(cmd: string) =
|
||||||
|
let d = getAppDir()
|
||||||
|
copyExe(d / "bin" / "nim".exe, d / "bin" / "nim_backup".exe)
|
||||||
|
try:
|
||||||
|
withDir(d):
|
||||||
|
temp"-d:debug"
|
||||||
|
copyExe(d / "bin" / "nim_temp".exe, d / "bin" / "nim".exe)
|
||||||
|
exec(cmd)
|
||||||
|
finally:
|
||||||
|
copyExe(d / "bin" / "nim_backup".exe, d / "bin" / "nim".exe)
|
||||||
|
|
||||||
proc pushCsources() =
|
proc pushCsources() =
|
||||||
if not dirExists("../csources/.git"):
|
if not dirExists("../csources/.git"):
|
||||||
quit "[Error] no csources git repository found"
|
quit "[Error] no csources git repository found"
|
||||||
|
|
@ -564,6 +556,7 @@ of cmdArgument:
|
||||||
of "testinstall": testUnixInstall()
|
of "testinstall": testUnixInstall()
|
||||||
of "test", "tests": tests(op.cmdLineRest)
|
of "test", "tests": tests(op.cmdLineRest)
|
||||||
of "temp": temp(op.cmdLineRest)
|
of "temp": temp(op.cmdLineRest)
|
||||||
|
of "xtemp": xtemp(op.cmdLineRest)
|
||||||
of "winrelease": winRelease()
|
of "winrelease": winRelease()
|
||||||
of "wintools": bundleWinTools()
|
of "wintools": bundleWinTools()
|
||||||
of "nimble": buildNimble(existsDir(".git"))
|
of "nimble": buildNimble(existsDir(".git"))
|
||||||
|
|
|
||||||
|
|
@ -225,7 +225,13 @@ proc `ident=`*(n: NimNode, val: NimIdent) {.magic: "NSetIdent", noSideEffect.}
|
||||||
proc `strVal=`*(n: NimNode, val: string) {.magic: "NSetStrVal", noSideEffect.}
|
proc `strVal=`*(n: NimNode, val: string) {.magic: "NSetStrVal", noSideEffect.}
|
||||||
|
|
||||||
proc newNimNode*(kind: NimNodeKind,
|
proc newNimNode*(kind: NimNodeKind,
|
||||||
n: NimNode=nil): NimNode {.magic: "NNewNimNode", noSideEffect.}
|
lineInfoFrom: NimNode=nil): NimNode
|
||||||
|
{.magic: "NNewNimNode", noSideEffect.}
|
||||||
|
## Creates a new AST node of the specified kind.
|
||||||
|
##
|
||||||
|
## The ``lineInfoFrom`` parameter is used for line information when the
|
||||||
|
## produced code crashes. You should ensure that it is set to a node that
|
||||||
|
## you are transforming.
|
||||||
|
|
||||||
proc copyNimNode*(n: NimNode): NimNode {.magic: "NCopyNimNode", noSideEffect.}
|
proc copyNimNode*(n: NimNode): NimNode {.magic: "NCopyNimNode", noSideEffect.}
|
||||||
proc copyNimTree*(n: NimNode): NimNode {.magic: "NCopyNimTree", noSideEffect.}
|
proc copyNimTree*(n: NimNode): NimNode {.magic: "NCopyNimTree", noSideEffect.}
|
||||||
|
|
@ -249,6 +255,11 @@ proc newStrLitNode*(s: string): NimNode {.compileTime, noSideEffect.} =
|
||||||
result = newNimNode(nnkStrLit)
|
result = newNimNode(nnkStrLit)
|
||||||
result.strVal = s
|
result.strVal = s
|
||||||
|
|
||||||
|
proc newCommentStmtNode*(s: string): NimNode {.compileTime, noSideEffect.} =
|
||||||
|
## creates a comment statement node
|
||||||
|
result = newNimNode(nnkCommentStmt)
|
||||||
|
result.strVal = s
|
||||||
|
|
||||||
proc newIntLitNode*(i: BiggestInt): NimNode {.compileTime.} =
|
proc newIntLitNode*(i: BiggestInt): NimNode {.compileTime.} =
|
||||||
## creates a int literal node from `i`
|
## creates a int literal node from `i`
|
||||||
result = newNimNode(nnkIntLit)
|
result = newNimNode(nnkIntLit)
|
||||||
|
|
@ -269,6 +280,7 @@ proc newIdentNode*(i: string): NimNode {.compileTime.} =
|
||||||
result = newNimNode(nnkIdent)
|
result = newNimNode(nnkIdent)
|
||||||
result.ident = !i
|
result.ident = !i
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
BindSymRule* = enum ## specifies how ``bindSym`` behaves
|
BindSymRule* = enum ## specifies how ``bindSym`` behaves
|
||||||
brClosed, ## only the symbols in current scope are bound
|
brClosed, ## only the symbols in current scope are bound
|
||||||
|
|
@ -426,20 +438,105 @@ proc newLit*(c: char): NimNode {.compileTime.} =
|
||||||
result = newNimNode(nnkCharLit)
|
result = newNimNode(nnkCharLit)
|
||||||
result.intVal = ord(c)
|
result.intVal = ord(c)
|
||||||
|
|
||||||
proc newLit*(i: BiggestInt): NimNode {.compileTime.} =
|
|
||||||
|
proc newLit*(i: int): NimNode {.compileTime.} =
|
||||||
## produces a new integer literal node.
|
## produces a new integer literal node.
|
||||||
result = newNimNode(nnkIntLit)
|
result = newNimNode(nnkIntLit)
|
||||||
result.intVal = i
|
result.intVal = i
|
||||||
|
|
||||||
|
proc newLit*(i: int8): NimNode {.compileTime.} =
|
||||||
|
## produces a new integer literal node.
|
||||||
|
result = newNimNode(nnkInt8Lit)
|
||||||
|
result.intVal = i
|
||||||
|
|
||||||
|
proc newLit*(i: int16): NimNode {.compileTime.} =
|
||||||
|
## produces a new integer literal node.
|
||||||
|
result = newNimNode(nnkInt16Lit)
|
||||||
|
result.intVal = i
|
||||||
|
|
||||||
|
proc newLit*(i: int32): NimNode {.compileTime.} =
|
||||||
|
## produces a new integer literal node.
|
||||||
|
result = newNimNode(nnkInt32Lit)
|
||||||
|
result.intVal = i
|
||||||
|
|
||||||
|
proc newLit*(i: int64): NimNode {.compileTime.} =
|
||||||
|
## produces a new integer literal node.
|
||||||
|
result = newNimNode(nnkInt64Lit)
|
||||||
|
result.intVal = i
|
||||||
|
|
||||||
|
proc newLit*(i: uint): NimNode {.compileTime.} =
|
||||||
|
## produces a new unsigned integer literal node.
|
||||||
|
result = newNimNode(nnkUIntLit)
|
||||||
|
result.intVal = BiggestInt(i)
|
||||||
|
|
||||||
|
proc newLit*(i: uint8): NimNode {.compileTime.} =
|
||||||
|
## produces a new unsigned integer literal node.
|
||||||
|
result = newNimNode(nnkUInt8Lit)
|
||||||
|
result.intVal = BiggestInt(i)
|
||||||
|
|
||||||
|
proc newLit*(i: uint16): NimNode {.compileTime.} =
|
||||||
|
## produces a new unsigned integer literal node.
|
||||||
|
result = newNimNode(nnkUInt16Lit)
|
||||||
|
result.intVal = BiggestInt(i)
|
||||||
|
|
||||||
|
proc newLit*(i: uint32): NimNode {.compileTime.} =
|
||||||
|
## produces a new unsigned integer literal node.
|
||||||
|
result = newNimNode(nnkUInt32Lit)
|
||||||
|
result.intVal = BiggestInt(i)
|
||||||
|
|
||||||
|
proc newLit*(i: uint64): NimNode {.compileTime.} =
|
||||||
|
## produces a new unsigned integer literal node.
|
||||||
|
result = newNimNode(nnkUInt64Lit)
|
||||||
|
result.intVal = BiggestInt(i)
|
||||||
|
|
||||||
proc newLit*(b: bool): NimNode {.compileTime.} =
|
proc newLit*(b: bool): NimNode {.compileTime.} =
|
||||||
## produces a new boolean literal node.
|
## produces a new boolean literal node.
|
||||||
result = if b: bindSym"true" else: bindSym"false"
|
result = if b: bindSym"true" else: bindSym"false"
|
||||||
|
|
||||||
proc newLit*(f: BiggestFloat): NimNode {.compileTime.} =
|
when false:
|
||||||
|
# the float type is not really a distinct type as described in https://github.com/nim-lang/Nim/issues/5875
|
||||||
|
proc newLit*(f: float): NimNode {.compileTime.} =
|
||||||
## produces a new float literal node.
|
## produces a new float literal node.
|
||||||
result = newNimNode(nnkFloatLit)
|
result = newNimNode(nnkFloatLit)
|
||||||
result.floatVal = f
|
result.floatVal = f
|
||||||
|
|
||||||
|
proc newLit*(f: float32): NimNode {.compileTime.} =
|
||||||
|
## produces a new float literal node.
|
||||||
|
result = newNimNode(nnkFloat32Lit)
|
||||||
|
result.floatVal = f
|
||||||
|
|
||||||
|
proc newLit*(f: float64): NimNode {.compileTime.} =
|
||||||
|
## produces a new float literal node.
|
||||||
|
result = newNimNode(nnkFloat64Lit)
|
||||||
|
result.floatVal = f
|
||||||
|
|
||||||
|
when compiles(float128):
|
||||||
|
proc newLit*(f: float128): NimNode {.compileTime.} =
|
||||||
|
## produces a new float literal node.
|
||||||
|
result = newNimNode(nnkFloat128Lit)
|
||||||
|
result.floatVal = f
|
||||||
|
|
||||||
|
proc newLit*(arg: object): NimNode {.compileTime.} =
|
||||||
|
result = nnkObjConstr.newTree(arg.type.getTypeInst[1])
|
||||||
|
for a, b in arg.fieldPairs:
|
||||||
|
result.add nnkExprColonExpr.newTree( newIdentNode(a), newLit(b) )
|
||||||
|
|
||||||
|
proc newLit*[N,T](arg: array[N,T]): NimNode {.compileTime.} =
|
||||||
|
result = nnkBracket.newTree
|
||||||
|
for x in arg:
|
||||||
|
result.add newLit(x)
|
||||||
|
|
||||||
|
proc newLit*[T](arg: seq[T]): NimNode {.compileTime.} =
|
||||||
|
result = nnkBracket.newTree
|
||||||
|
for x in arg:
|
||||||
|
result.add newLit(x)
|
||||||
|
result = nnkPrefix.newTree(bindSym"@", result)
|
||||||
|
|
||||||
|
proc newLit*(arg: tuple): NimNode {.compileTime.} =
|
||||||
|
result = nnkPar.newTree
|
||||||
|
for a,b in arg.fieldPairs:
|
||||||
|
result.add nnkExprColonExpr.newTree( newIdentNode(a), newLit(b) )
|
||||||
|
|
||||||
proc newLit*(s: string): NimNode {.compileTime.} =
|
proc newLit*(s: string): NimNode {.compileTime.} =
|
||||||
## produces a new string literal node.
|
## produces a new string literal node.
|
||||||
result = newNimNode(nnkStrLit)
|
result = newNimNode(nnkStrLit)
|
||||||
|
|
@ -744,6 +841,8 @@ proc `$`*(node: NimNode): string {.compileTime.} =
|
||||||
result = $node[0]
|
result = $node[0]
|
||||||
of nnkAccQuoted:
|
of nnkAccQuoted:
|
||||||
result = $node[0]
|
result = $node[0]
|
||||||
|
of nnkCommentStmt:
|
||||||
|
result = node.strVal
|
||||||
else:
|
else:
|
||||||
badNodeKind node.kind, "$"
|
badNodeKind node.kind, "$"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,9 @@ const
|
||||||
DT_SOCK* = 12 ## UNIX domain socket.
|
DT_SOCK* = 12 ## UNIX domain socket.
|
||||||
DT_WHT* = 14
|
DT_WHT* = 14
|
||||||
|
|
||||||
|
# Special types
|
||||||
|
type Sighandler = proc (a: cint) {.noconv.}
|
||||||
|
|
||||||
# Platform specific stuff
|
# Platform specific stuff
|
||||||
|
|
||||||
when defined(linux) and defined(amd64):
|
when defined(linux) and defined(amd64):
|
||||||
|
|
@ -86,6 +89,9 @@ when defined(linux) and defined(amd64):
|
||||||
else:
|
else:
|
||||||
include posix_other
|
include posix_other
|
||||||
|
|
||||||
|
# There used to be this name in posix.nim a long time ago, not sure why!
|
||||||
|
{.deprecated: [cSIG_HOLD: SIG_HOLD].}
|
||||||
|
|
||||||
when not defined(macosx):
|
when not defined(macosx):
|
||||||
proc st_atime*(s: Stat): Time {.inline.} =
|
proc st_atime*(s: Stat): Time {.inline.} =
|
||||||
## Second-granularity time of last access
|
## Second-granularity time of last access
|
||||||
|
|
@ -659,7 +665,7 @@ proc sighold*(a1: cint): cint {.importc, header: "<signal.h>".}
|
||||||
proc sigignore*(a1: cint): cint {.importc, header: "<signal.h>".}
|
proc sigignore*(a1: cint): cint {.importc, header: "<signal.h>".}
|
||||||
proc siginterrupt*(a1, a2: cint): cint {.importc, header: "<signal.h>".}
|
proc siginterrupt*(a1, a2: cint): cint {.importc, header: "<signal.h>".}
|
||||||
proc sigismember*(a1: var Sigset, a2: cint): cint {.importc, header: "<signal.h>".}
|
proc sigismember*(a1: var Sigset, a2: cint): cint {.importc, header: "<signal.h>".}
|
||||||
proc signal*(a1: cint, a2: proc (x: cint) {.noconv.}) {.
|
proc signal*(a1: cint, a2: Sighandler) {.
|
||||||
importc, header: "<signal.h>".}
|
importc, header: "<signal.h>".}
|
||||||
proc sigpause*(a1: cint): cint {.importc, header: "<signal.h>".}
|
proc sigpause*(a1: cint): cint {.importc, header: "<signal.h>".}
|
||||||
proc sigpending*(a1: var Sigset): cint {.importc, header: "<signal.h>".}
|
proc sigpending*(a1: var Sigset): cint {.importc, header: "<signal.h>".}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,9 @@ type
|
||||||
|
|
||||||
{.deprecated: [TSocketHandle: SocketHandle].}
|
{.deprecated: [TSocketHandle: SocketHandle].}
|
||||||
|
|
||||||
|
# not detected by detect.nim, guarded by #ifdef __USE_UNIX98 in glibc
|
||||||
|
const SIG_HOLD* = cast[SigHandler](2)
|
||||||
|
|
||||||
type
|
type
|
||||||
Timespec* {.importc: "struct timespec",
|
Timespec* {.importc: "struct timespec",
|
||||||
header: "<time.h>", final, pure.} = object ## struct timespec
|
header: "<time.h>", final, pure.} = object ## struct timespec
|
||||||
|
|
|
||||||
|
|
@ -399,6 +399,9 @@ const SS_ONSTACK* = cint(1)
|
||||||
const SS_DISABLE* = cint(2)
|
const SS_DISABLE* = cint(2)
|
||||||
const MINSIGSTKSZ* = cint(2048)
|
const MINSIGSTKSZ* = cint(2048)
|
||||||
const SIGSTKSZ* = cint(8192)
|
const SIGSTKSZ* = cint(8192)
|
||||||
|
const SIG_DFL* = cast[Sighandler](0)
|
||||||
|
const SIG_ERR* = cast[Sighandler](-1)
|
||||||
|
const SIG_IGN* = cast[Sighandler](1)
|
||||||
|
|
||||||
# <sys/ipc.h>
|
# <sys/ipc.h>
|
||||||
const IPC_CREAT* = cint(512)
|
const IPC_CREAT* = cint(512)
|
||||||
|
|
|
||||||
|
|
@ -414,6 +414,10 @@ var SS_ONSTACK* {.importc: "SS_ONSTACK", header: "<signal.h>".}: cint
|
||||||
var SS_DISABLE* {.importc: "SS_DISABLE", header: "<signal.h>".}: cint
|
var SS_DISABLE* {.importc: "SS_DISABLE", header: "<signal.h>".}: cint
|
||||||
var MINSIGSTKSZ* {.importc: "MINSIGSTKSZ", header: "<signal.h>".}: cint
|
var MINSIGSTKSZ* {.importc: "MINSIGSTKSZ", header: "<signal.h>".}: cint
|
||||||
var SIGSTKSZ* {.importc: "SIGSTKSZ", header: "<signal.h>".}: cint
|
var SIGSTKSZ* {.importc: "SIGSTKSZ", header: "<signal.h>".}: cint
|
||||||
|
var SIG_HOLD* {.importc: "SIG_HOLD", header: "<signal.h>".}: Sighandler
|
||||||
|
var SIG_DFL* {.importc: "SIG_DFL", header: "<signal.h>".}: Sighandler
|
||||||
|
var SIG_ERR* {.importc: "SIG_ERR", header: "<signal.h>".}: Sighandler
|
||||||
|
var SIG_IGN* {.importc: "SIG_IGN", header: "<signal.h>".}: Sighandler
|
||||||
|
|
||||||
# <sys/ipc.h>
|
# <sys/ipc.h>
|
||||||
var IPC_CREAT* {.importc: "IPC_CREAT", header: "<sys/ipc.h>".}: cint
|
var IPC_CREAT* {.importc: "IPC_CREAT", header: "<sys/ipc.h>".}: cint
|
||||||
|
|
|
||||||
|
|
@ -163,8 +163,8 @@ include includes/asyncfutures
|
||||||
|
|
||||||
type
|
type
|
||||||
PDispatcherBase = ref object of RootRef
|
PDispatcherBase = ref object of RootRef
|
||||||
timers: HeapQueue[tuple[finishAt: float, fut: Future[void]]]
|
timers*: HeapQueue[tuple[finishAt: float, fut: Future[void]]]
|
||||||
callbacks: Deque[proc ()]
|
callbacks*: Deque[proc ()]
|
||||||
|
|
||||||
proc processTimers(p: PDispatcherBase) {.inline.} =
|
proc processTimers(p: PDispatcherBase) {.inline.} =
|
||||||
#Process just part if timers at a step
|
#Process just part if timers at a step
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] =
|
||||||
i.inc protocol.parseInt(result.minor, i)
|
i.inc protocol.parseInt(result.minor, i)
|
||||||
|
|
||||||
proc sendStatus(client: AsyncSocket, status: string): Future[void] =
|
proc sendStatus(client: AsyncSocket, status: string): Future[void] =
|
||||||
client.send("HTTP/1.1 " & status & "\c\L")
|
client.send("HTTP/1.1 " & status & "\c\L\c\L")
|
||||||
|
|
||||||
proc processClient(client: AsyncSocket, address: string,
|
proc processClient(client: AsyncSocket, address: string,
|
||||||
callback: proc (request: Request):
|
callback: proc (request: Request):
|
||||||
|
|
|
||||||
|
|
@ -301,13 +301,13 @@ proc verifyReturnType(typeName: string) {.compileTime.} =
|
||||||
proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
|
proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
|
||||||
## This macro transforms a single procedure into a closure iterator.
|
## This macro transforms a single procedure into a closure iterator.
|
||||||
## The ``async`` macro supports a stmtList holding multiple async procedures.
|
## The ``async`` macro supports a stmtList holding multiple async procedures.
|
||||||
if prc.kind notin {nnkProcDef, nnkLambda, nnkMethodDef}:
|
if prc.kind notin {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}:
|
||||||
error("Cannot transform this node kind into an async proc." &
|
error("Cannot transform this node kind into an async proc." &
|
||||||
" proc/method definition or lambda node expected.")
|
" proc/method definition or lambda node expected.")
|
||||||
|
|
||||||
hint("Processing " & prc[0].getName & " as an async proc.")
|
let prcName = prc.name.getName
|
||||||
|
|
||||||
let returnType = prc[3][0]
|
let returnType = prc.params[0]
|
||||||
var baseType: NimNode
|
var baseType: NimNode
|
||||||
# Verify that the return type is a Future[T]
|
# Verify that the return type is a Future[T]
|
||||||
if returnType.kind == nnkBracketExpr:
|
if returnType.kind == nnkBracketExpr:
|
||||||
|
|
@ -326,9 +326,9 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
|
||||||
let subtypeIsVoid = returnType.kind == nnkEmpty or
|
let subtypeIsVoid = returnType.kind == nnkEmpty or
|
||||||
(baseType.kind == nnkIdent and returnType[1].ident == !"void")
|
(baseType.kind == nnkIdent and returnType[1].ident == !"void")
|
||||||
|
|
||||||
let futureVarIdents = getFutureVarIdents(prc[3])
|
let futureVarIdents = getFutureVarIdents(prc.params)
|
||||||
|
|
||||||
var outerProcBody = newNimNode(nnkStmtList, prc[6])
|
var outerProcBody = newNimNode(nnkStmtList, prc.body)
|
||||||
|
|
||||||
# -> var retFuture = newFuture[T]()
|
# -> var retFuture = newFuture[T]()
|
||||||
var retFutureSym = genSym(nskVar, "retFuture")
|
var retFutureSym = genSym(nskVar, "retFuture")
|
||||||
|
|
@ -338,10 +338,10 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
|
||||||
outerProcBody.add(
|
outerProcBody.add(
|
||||||
newVarStmt(retFutureSym,
|
newVarStmt(retFutureSym,
|
||||||
newCall(
|
newCall(
|
||||||
newNimNode(nnkBracketExpr, prc[6]).add(
|
newNimNode(nnkBracketExpr, prc.body).add(
|
||||||
newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`.
|
newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`.
|
||||||
subRetType),
|
subRetType),
|
||||||
newLit(prc[0].getName)))) # Get type from return type of this proc
|
newLit(prcName)))) # Get type from return type of this proc
|
||||||
|
|
||||||
# -> iterator nameIter(): FutureBase {.closure.} =
|
# -> iterator nameIter(): FutureBase {.closure.} =
|
||||||
# -> {.push warning[resultshadowed]: off.}
|
# -> {.push warning[resultshadowed]: off.}
|
||||||
|
|
@ -349,8 +349,8 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
|
||||||
# -> {.pop.}
|
# -> {.pop.}
|
||||||
# -> <proc_body>
|
# -> <proc_body>
|
||||||
# -> complete(retFuture, result)
|
# -> complete(retFuture, result)
|
||||||
var iteratorNameSym = genSym(nskIterator, $prc[0].getName & "Iter")
|
var iteratorNameSym = genSym(nskIterator, $prcName & "Iter")
|
||||||
var procBody = prc[6].processBody(retFutureSym, subtypeIsVoid,
|
var procBody = prc.body.processBody(retFutureSym, subtypeIsVoid,
|
||||||
futureVarIdents, nil)
|
futureVarIdents, nil)
|
||||||
# don't do anything with forward bodies (empty)
|
# don't do anything with forward bodies (empty)
|
||||||
if procBody.kind != nnkEmpty:
|
if procBody.kind != nnkEmpty:
|
||||||
|
|
@ -362,7 +362,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
|
||||||
newIdentNode("warning"), newIdentNode("resultshadowed")),
|
newIdentNode("warning"), newIdentNode("resultshadowed")),
|
||||||
newIdentNode("off")))) # -> {.push warning[resultshadowed]: off.}
|
newIdentNode("off")))) # -> {.push warning[resultshadowed]: off.}
|
||||||
|
|
||||||
procBody.insert(1, newNimNode(nnkVarSection, prc[6]).add(
|
procBody.insert(1, newNimNode(nnkVarSection, prc.body).add(
|
||||||
newIdentDefs(newIdentNode("result"), baseType))) # -> var result: T
|
newIdentDefs(newIdentNode("result"), baseType))) # -> var result: T
|
||||||
|
|
||||||
procBody.insert(2, newNimNode(nnkPragma).add(
|
procBody.insert(2, newNimNode(nnkPragma).add(
|
||||||
|
|
@ -377,35 +377,32 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
|
||||||
|
|
||||||
var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")],
|
var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")],
|
||||||
procBody, nnkIteratorDef)
|
procBody, nnkIteratorDef)
|
||||||
closureIterator[4] = newNimNode(nnkPragma, prc[6]).add(newIdentNode("closure"))
|
closureIterator.pragma = newNimNode(nnkPragma, lineInfoFrom=prc.body)
|
||||||
|
closureIterator.addPragma(newIdentNode("closure"))
|
||||||
|
closureIterator.addPragma(newIdentNode("gcsafe"))
|
||||||
outerProcBody.add(closureIterator)
|
outerProcBody.add(closureIterator)
|
||||||
|
|
||||||
# -> createCb(retFuture)
|
# -> createCb(retFuture)
|
||||||
#var cbName = newIdentNode("cb")
|
#var cbName = newIdentNode("cb")
|
||||||
var procCb = getAst createCb(retFutureSym, iteratorNameSym,
|
var procCb = getAst createCb(retFutureSym, iteratorNameSym,
|
||||||
newStrLitNode(prc[0].getName),
|
newStrLitNode(prcName),
|
||||||
createFutureVarCompletions(futureVarIdents, nil))
|
createFutureVarCompletions(futureVarIdents, nil))
|
||||||
outerProcBody.add procCb
|
outerProcBody.add procCb
|
||||||
|
|
||||||
# -> return retFuture
|
# -> return retFuture
|
||||||
outerProcBody.add newNimNode(nnkReturnStmt, prc[6][prc[6].len-1]).add(retFutureSym)
|
outerProcBody.add newNimNode(nnkReturnStmt, prc.body[^1]).add(retFutureSym)
|
||||||
|
|
||||||
result = prc
|
result = prc
|
||||||
|
|
||||||
# Remove the 'async' pragma.
|
|
||||||
for i in 0 .. <result[4].len:
|
|
||||||
if result[4][i].kind == nnkIdent and result[4][i].ident == !"async":
|
|
||||||
result[4].del(i)
|
|
||||||
result[4] = newEmptyNode()
|
|
||||||
if subtypeIsVoid:
|
if subtypeIsVoid:
|
||||||
# Add discardable pragma.
|
# Add discardable pragma.
|
||||||
if returnType.kind == nnkEmpty:
|
if returnType.kind == nnkEmpty:
|
||||||
# Add Future[void]
|
# Add Future[void]
|
||||||
result[3][0] = parseExpr("Future[void]")
|
result.params[0] = parseExpr("Future[void]")
|
||||||
if procBody.kind != nnkEmpty:
|
if procBody.kind != nnkEmpty:
|
||||||
result[6] = outerProcBody
|
result.body = outerProcBody
|
||||||
#echo(treeRepr(result))
|
#echo(treeRepr(result))
|
||||||
#if prc[0].getName == "recvLineInto":
|
#if prcName == "recvLineInto":
|
||||||
# echo(toStrLit(result))
|
# echo(toStrLit(result))
|
||||||
|
|
||||||
macro async*(prc: untyped): untyped =
|
macro async*(prc: untyped): untyped =
|
||||||
|
|
@ -529,8 +526,6 @@ macro multisync*(prc: untyped): untyped =
|
||||||
##
|
##
|
||||||
## The generated async procedures use the ``async`` macro, whereas the
|
## The generated async procedures use the ``async`` macro, whereas the
|
||||||
## generated synchronous procedures simply strip off the ``await`` calls.
|
## generated synchronous procedures simply strip off the ``await`` calls.
|
||||||
hint("Processing " & prc[0].getName & " as a multisync proc.")
|
|
||||||
|
|
||||||
let (sync, asyncPrc) = splitProc(prc)
|
let (sync, asyncPrc) = splitProc(prc)
|
||||||
result = newStmtList()
|
result = newStmtList()
|
||||||
result.add(asyncSingleProc(asyncPrc))
|
result.add(asyncSingleProc(asyncPrc))
|
||||||
|
|
|
||||||
|
|
@ -533,15 +533,13 @@ proc recvLineInto*(socket: AsyncSocket, resString: FutureVar[string],
|
||||||
else:
|
else:
|
||||||
var c = ""
|
var c = ""
|
||||||
while true:
|
while true:
|
||||||
let recvFut = recv(socket, 1, flags)
|
c = await recv(socket, 1, flags)
|
||||||
c = recvFut.read()
|
|
||||||
if c.len == 0:
|
if c.len == 0:
|
||||||
resString.mget.setLen(0)
|
resString.mget.setLen(0)
|
||||||
resString.complete()
|
resString.complete()
|
||||||
return
|
return
|
||||||
if c == "\r":
|
if c == "\r":
|
||||||
let recvFut = recv(socket, 1, flags) # Skip \L
|
c = await recv(socket, 1, flags) # Skip \L
|
||||||
c = recvFut.read()
|
|
||||||
assert c == "\L"
|
assert c == "\L"
|
||||||
addNLIfEmpty()
|
addNLIfEmpty()
|
||||||
resString.complete()
|
resString.complete()
|
||||||
|
|
|
||||||
|
|
@ -590,8 +590,11 @@ proc enlarge[A, B](t: var OrderedTable[A, B]) =
|
||||||
swap(t.data, n)
|
swap(t.data, n)
|
||||||
while h >= 0:
|
while h >= 0:
|
||||||
var nxt = n[h].next
|
var nxt = n[h].next
|
||||||
if isFilled(n[h].hcode):
|
let eh = n[h].hcode
|
||||||
var j = -1 - rawGetKnownHC(t, n[h].key, n[h].hcode)
|
if isFilled(eh):
|
||||||
|
var j: Hash = eh and maxHash(t)
|
||||||
|
while isFilled(t.data[j].hcode):
|
||||||
|
j = nextTry(j, maxHash(t))
|
||||||
rawInsert(t, t.data, n[h].key, n[h].val, n[h].hcode, j)
|
rawInsert(t, t.data, n[h].key, n[h].val, n[h].hcode, j)
|
||||||
h = nxt
|
h = nxt
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,4 +69,4 @@ proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
|
||||||
result = affinitySpaceTotal().int
|
result = affinitySpaceTotal().int
|
||||||
else:
|
else:
|
||||||
result = sysconf(SC_NPROCESSORS_ONLN)
|
result = sysconf(SC_NPROCESSORS_ONLN)
|
||||||
if result <= 0: result = 1
|
if result <= 0: result = 0
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,7 @@ proc detectOsImpl(d: Distribution): bool =
|
||||||
of Distribution.ArchLinux:
|
of Distribution.ArchLinux:
|
||||||
result = "arch" in toLowerAscii(uname())
|
result = "arch" in toLowerAscii(uname())
|
||||||
of Distribution.OpenSUSE:
|
of Distribution.OpenSUSE:
|
||||||
result = "suse" in toLowerAscii(uname())
|
result = "suse" in toLowerAscii(uname()) or "suse" in toLowerAscii(release())
|
||||||
of Distribution.GoboLinux:
|
of Distribution.GoboLinux:
|
||||||
result = "-Gobo " in uname()
|
result = "-Gobo " in uname()
|
||||||
of Distribution.OpenMandriva:
|
of Distribution.OpenMandriva:
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,11 @@ proc hash*(x: cstring): Hash =
|
||||||
## efficient hashing of null-terminated strings
|
## efficient hashing of null-terminated strings
|
||||||
var h: Hash = 0
|
var h: Hash = 0
|
||||||
var i = 0
|
var i = 0
|
||||||
|
when defined(js):
|
||||||
|
while i < x.len:
|
||||||
|
h = h !& ord(x[i])
|
||||||
|
inc i
|
||||||
|
else:
|
||||||
while x[i] != 0.char:
|
while x[i] != 0.char:
|
||||||
h = h !& ord(x[i])
|
h = h !& ord(x[i])
|
||||||
inc i
|
inc i
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,8 @@
|
||||||
## let body = %*{
|
## let body = %*{
|
||||||
## "data": "some text"
|
## "data": "some text"
|
||||||
## }
|
## }
|
||||||
## echo client.request("http://some.api", httpMethod = HttpPost, body = $body)
|
## let response = client.request("http://some.api", httpMethod = HttpPost, body = $body)
|
||||||
|
## echo response.status
|
||||||
##
|
##
|
||||||
## Progress reporting
|
## Progress reporting
|
||||||
## ==================
|
## ==================
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ template newAsyncNativeSocketImpl(domain, sockType, protocol) =
|
||||||
if handle == osInvalidSocket:
|
if handle == osInvalidSocket:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
handle.setBlocking(false)
|
handle.setBlocking(false)
|
||||||
when defined(macosx):
|
when defined(macosx) and not defined(nimdoc):
|
||||||
handle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
|
handle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
|
||||||
result = handle.AsyncFD
|
result = handle.AsyncFD
|
||||||
register(result)
|
register(result)
|
||||||
|
|
|
||||||
|
|
@ -1001,7 +1001,7 @@ proc escapeJson*(s: string; result: var string) =
|
||||||
result.add("\"")
|
result.add("\"")
|
||||||
for x in runes(s):
|
for x in runes(s):
|
||||||
var r = int(x)
|
var r = int(x)
|
||||||
if r >= 32 and r <= 127:
|
if r >= 32 and r <= 126:
|
||||||
var c = chr(r)
|
var c = chr(r)
|
||||||
case c
|
case c
|
||||||
of '"': result.add("\\\"")
|
of '"': result.add("\\\"")
|
||||||
|
|
@ -1608,7 +1608,7 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
|
||||||
result = processType(newIdentNode(typeName), obj, jsonNode, true)
|
result = processType(newIdentNode(typeName), obj, jsonNode, true)
|
||||||
of "seq":
|
of "seq":
|
||||||
let seqT = typeSym[1]
|
let seqT = typeSym[1]
|
||||||
let forLoopI = newIdentNode("i")
|
let forLoopI = genSym(nskForVar, "i")
|
||||||
let indexerNode = createJsonIndexer(jsonNode, forLoopI)
|
let indexerNode = createJsonIndexer(jsonNode, forLoopI)
|
||||||
let constructorNode = createConstructor(seqT, indexerNode)
|
let constructorNode = createConstructor(seqT, indexerNode)
|
||||||
|
|
||||||
|
|
@ -1616,12 +1616,25 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
|
||||||
result = quote do:
|
result = quote do:
|
||||||
(
|
(
|
||||||
var list: `typeSym` = @[];
|
var list: `typeSym` = @[];
|
||||||
# if `jsonNode`.kind != JArray:
|
verifyJsonKind(`jsonNode`, {JArray}, astToStr(`jsonNode`));
|
||||||
# # TODO: Improve error message.
|
|
||||||
# raise newException(ValueError, "Expected a list")
|
|
||||||
for `forLoopI` in 0 .. <`jsonNode`.len: list.add(`constructorNode`);
|
for `forLoopI` in 0 .. <`jsonNode`.len: list.add(`constructorNode`);
|
||||||
list
|
list
|
||||||
)
|
)
|
||||||
|
of "array":
|
||||||
|
let arrayT = typeSym[2]
|
||||||
|
let forLoopI = genSym(nskForVar, "i")
|
||||||
|
let indexerNode = createJsonIndexer(jsonNode, forLoopI)
|
||||||
|
let constructorNode = createConstructor(arrayT, indexerNode)
|
||||||
|
|
||||||
|
# Create a statement expression containing a for loop.
|
||||||
|
result = quote do:
|
||||||
|
(
|
||||||
|
var list: `typeSym`;
|
||||||
|
verifyJsonKind(`jsonNode`, {JArray}, astToStr(`jsonNode`));
|
||||||
|
for `forLoopI` in 0 .. <`jsonNode`.len: list[`forLoopI`] =`constructorNode`;
|
||||||
|
list
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Generic type.
|
# Generic type.
|
||||||
let obj = getType(typeSym)
|
let obj = getType(typeSym)
|
||||||
|
|
|
||||||
|
|
@ -395,6 +395,12 @@ proc radToDeg*[T: float32|float64](d: T): T {.inline.} =
|
||||||
## Convert from radians to degrees
|
## Convert from radians to degrees
|
||||||
result = T(d) / RadPerDeg
|
result = T(d) / RadPerDeg
|
||||||
|
|
||||||
|
proc sgn*[T: SomeNumber](x: T): int {.inline.} =
|
||||||
|
## Sign function. Returns -1 for negative numbers and `NegInf`, 1 for
|
||||||
|
## positive numbers and `Inf`, and 0 for positive zero, negative zero and
|
||||||
|
## `NaN`.
|
||||||
|
ord(T(0) < x) - ord(x < T(0))
|
||||||
|
|
||||||
proc `mod`*[T: float32|float64](x, y: T): T =
|
proc `mod`*[T: float32|float64](x, y: T): T =
|
||||||
## Computes the modulo operation for float operators. Equivalent
|
## Computes the modulo operation for float operators. Equivalent
|
||||||
## to ``x - y * floor(x/y)``. Note that the remainder will always
|
## to ``x - y * floor(x/y)``. Note that the remainder will always
|
||||||
|
|
@ -407,10 +413,13 @@ proc `mod`*[T: float32|float64](x, y: T): T =
|
||||||
{.pop.}
|
{.pop.}
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
proc `^`*[T](x, y: T): T =
|
proc `^`*[T](x: T, y: Natural): T =
|
||||||
## Computes ``x`` to the power ``y`. ``x`` must be non-negative, use
|
## Computes ``x`` to the power ``y`. ``x`` must be non-negative, use
|
||||||
## `pow <#pow,float,float>` for negative exponents.
|
## `pow <#pow,float,float>` for negative exponents.
|
||||||
|
when compiles(y >= T(0)):
|
||||||
assert y >= T(0)
|
assert y >= T(0)
|
||||||
|
else:
|
||||||
|
assert T(y) >= T(0)
|
||||||
var (x, y) = (x, y)
|
var (x, y) = (x, y)
|
||||||
result = 1
|
result = 1
|
||||||
|
|
||||||
|
|
@ -447,6 +456,7 @@ when isMainModule and not defined(JS):
|
||||||
assert(lgamma(1.0) == 0.0) # ln(1.0) == 0.0
|
assert(lgamma(1.0) == 0.0) # ln(1.0) == 0.0
|
||||||
assert(erf(6.0) > erf(5.0))
|
assert(erf(6.0) > erf(5.0))
|
||||||
assert(erfc(6.0) < erfc(5.0))
|
assert(erfc(6.0) < erfc(5.0))
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
# Function for approximate comparison of floats
|
# Function for approximate comparison of floats
|
||||||
proc `==~`(x, y: float): bool = (abs(x-y) < 1e-9)
|
proc `==~`(x, y: float): bool = (abs(x-y) < 1e-9)
|
||||||
|
|
@ -509,3 +519,21 @@ when isMainModule:
|
||||||
doAssert(classify(trunc(-1e1000000'f32)) == fcNegInf)
|
doAssert(classify(trunc(-1e1000000'f32)) == fcNegInf)
|
||||||
doAssert(classify(trunc(f_nan.float32)) == fcNan)
|
doAssert(classify(trunc(f_nan.float32)) == fcNan)
|
||||||
doAssert(classify(trunc(0.0'f32)) == fcZero)
|
doAssert(classify(trunc(0.0'f32)) == fcZero)
|
||||||
|
|
||||||
|
block: # sgn() tests
|
||||||
|
assert sgn(1'i8) == 1
|
||||||
|
assert sgn(1'i16) == 1
|
||||||
|
assert sgn(1'i32) == 1
|
||||||
|
assert sgn(1'i64) == 1
|
||||||
|
assert sgn(1'u8) == 1
|
||||||
|
assert sgn(1'u16) == 1
|
||||||
|
assert sgn(1'u32) == 1
|
||||||
|
assert sgn(1'u64) == 1
|
||||||
|
assert sgn(-12342.8844'f32) == -1
|
||||||
|
assert sgn(123.9834'f64) == 1
|
||||||
|
assert sgn(0'i32) == 0
|
||||||
|
assert sgn(0'f32) == 0
|
||||||
|
assert sgn(NegInf) == -1
|
||||||
|
assert sgn(Inf) == 1
|
||||||
|
assert sgn(NaN) == 0
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -666,20 +666,31 @@ proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].}
|
||||||
else:
|
else:
|
||||||
raiseOSError(osLastError(), $strerror(errno))
|
raiseOSError(osLastError(), $strerror(errno))
|
||||||
|
|
||||||
proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
|
proc tryMoveFSObject(source, dest: string): bool =
|
||||||
tags: [ReadIOEffect, WriteIOEffect].} =
|
## Moves a file or directory from `source` to `dest`. Returns false in case
|
||||||
## Moves a file from `source` to `dest`. If this fails, `OSError` is raised.
|
## of `EXDEV` error. In case of other errors `OSError` is raised. Returns
|
||||||
|
## true in case of success.
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
when useWinUnicode:
|
when useWinUnicode:
|
||||||
let s = newWideCString(source)
|
let s = newWideCString(source)
|
||||||
let d = newWideCString(dest)
|
let d = newWideCString(dest)
|
||||||
if moveFileW(s, d) == 0'i32: raiseOSError(osLastError())
|
if moveFileExW(s, d, MOVEFILE_COPY_ALLOWED) == 0'i32: raiseOSError(osLastError())
|
||||||
else:
|
else:
|
||||||
if moveFileA(source, dest) == 0'i32: raiseOSError(osLastError())
|
if moveFileExA(source, dest, MOVEFILE_COPY_ALLOWED) == 0'i32: raiseOSError(osLastError())
|
||||||
else:
|
else:
|
||||||
if c_rename(source, dest) != 0'i32:
|
if c_rename(source, dest) != 0'i32:
|
||||||
let err = osLastError()
|
let err = osLastError()
|
||||||
if err == EXDEV.OSErrorCode:
|
if err == EXDEV.OSErrorCode:
|
||||||
|
return false
|
||||||
|
else:
|
||||||
|
raiseOSError(err, $strerror(errno))
|
||||||
|
return true
|
||||||
|
|
||||||
|
proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||||
|
tags: [ReadIOEffect, WriteIOEffect].} =
|
||||||
|
## Moves a file from `source` to `dest`. If this fails, `OSError` is raised.
|
||||||
|
if not tryMoveFSObject(source, dest):
|
||||||
|
when not defined(windows):
|
||||||
# Fallback to copy & del
|
# Fallback to copy & del
|
||||||
copyFile(source, dest)
|
copyFile(source, dest)
|
||||||
try:
|
try:
|
||||||
|
|
@ -687,8 +698,6 @@ proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||||
except:
|
except:
|
||||||
discard tryRemoveFile(dest)
|
discard tryRemoveFile(dest)
|
||||||
raise
|
raise
|
||||||
else:
|
|
||||||
raiseOSError(err, $strerror(errno))
|
|
||||||
|
|
||||||
proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
|
proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
|
||||||
tags: [ExecIOEffect].} =
|
tags: [ExecIOEffect].} =
|
||||||
|
|
@ -1369,6 +1378,14 @@ proc exclFilePermissions*(filename: string,
|
||||||
## setFilePermissions(filename, getFilePermissions(filename)-permissions)
|
## setFilePermissions(filename, getFilePermissions(filename)-permissions)
|
||||||
setFilePermissions(filename, getFilePermissions(filename)-permissions)
|
setFilePermissions(filename, getFilePermissions(filename)-permissions)
|
||||||
|
|
||||||
|
proc moveDir*(source, dest: string) {.tags: [ReadIOEffect, WriteIOEffect].} =
|
||||||
|
## Moves a directory from `source` to `dest`. If this fails, `OSError` is raised.
|
||||||
|
if not tryMoveFSObject(source, dest):
|
||||||
|
when not defined(windows):
|
||||||
|
# Fallback to copy & del
|
||||||
|
copyDir(source, dest)
|
||||||
|
removeDir(source)
|
||||||
|
|
||||||
include ospaths
|
include ospaths
|
||||||
|
|
||||||
proc expandSymlink*(symlinkPath: string): string =
|
proc expandSymlink*(symlinkPath: string): string =
|
||||||
|
|
@ -1412,7 +1429,7 @@ when defined(nimdoc):
|
||||||
proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} =
|
proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} =
|
||||||
## Returns the `i`-th `command line argument`:idx: given to the application.
|
## Returns the `i`-th `command line argument`:idx: given to the application.
|
||||||
##
|
##
|
||||||
## `i` should be in the range `1..paramCount()`, the `EInvalidIndex`
|
## `i` should be in the range `1..paramCount()`, the `IndexError`
|
||||||
## exception will be raised for invalid values. Instead of iterating over
|
## exception will be raised for invalid values. Instead of iterating over
|
||||||
## `paramCount() <#paramCount>`_ with this proc you can call the
|
## `paramCount() <#paramCount>`_ with this proc you can call the
|
||||||
## convenience `commandLineParams() <#commandLineParams>`_.
|
## convenience `commandLineParams() <#commandLineParams>`_.
|
||||||
|
|
@ -1450,7 +1467,8 @@ elif defined(windows):
|
||||||
tags: [ReadIOEffect].} =
|
tags: [ReadIOEffect].} =
|
||||||
# Docstring in nimdoc block.
|
# Docstring in nimdoc block.
|
||||||
if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLine())
|
if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLine())
|
||||||
return TaintedString(ownArgv[i])
|
if i < ownArgv.len and i >= 0: return TaintedString(ownArgv[i])
|
||||||
|
raise newException(IndexError, "invalid index")
|
||||||
|
|
||||||
elif not defined(createNimRtl) and
|
elif not defined(createNimRtl) and
|
||||||
not(defined(posix) and appType == "lib") and
|
not(defined(posix) and appType == "lib") and
|
||||||
|
|
|
||||||
|
|
@ -516,7 +516,16 @@ when declared(getEnv) or defined(nimscript):
|
||||||
proc getConfigDir*(): string {.rtl, extern: "nos$1",
|
proc getConfigDir*(): string {.rtl, extern: "nos$1",
|
||||||
tags: [ReadEnvEffect, ReadIOEffect].} =
|
tags: [ReadEnvEffect, ReadIOEffect].} =
|
||||||
## Returns the config directory of the current user for applications.
|
## Returns the config directory of the current user for applications.
|
||||||
|
##
|
||||||
|
## On non-Windows OSs, this proc conforms to the XDG Base Directory
|
||||||
|
## spec. Thus, this proc returns the value of the XDG_CONFIG_DIR environment
|
||||||
|
## variable if it is set, and returns the default configuration directory,
|
||||||
|
## "~/.config/", otherwise.
|
||||||
|
##
|
||||||
|
## An OS-dependent trailing slash is always present at the end of the
|
||||||
|
## returned string; `\\` on Windows and `/` on all other OSs.
|
||||||
when defined(windows): return string(getEnv("APPDATA")) & "\\"
|
when defined(windows): return string(getEnv("APPDATA")) & "\\"
|
||||||
|
elif getEnv("XDG_CONFIG_DIR"): return string(getEnv("XDG_CONFIG_DIR")) & "/"
|
||||||
else: return string(getEnv("HOME")) & "/.config/"
|
else: return string(getEnv("HOME")) & "/.config/"
|
||||||
|
|
||||||
proc getTempDir*(): string {.rtl, extern: "nos$1",
|
proc getTempDir*(): string {.rtl, extern: "nos$1",
|
||||||
|
|
|
||||||
|
|
@ -863,18 +863,15 @@ elif not defined(useNimRtl):
|
||||||
if data.workingDir.len > 0:
|
if data.workingDir.len > 0:
|
||||||
setCurrentDir($data.workingDir)
|
setCurrentDir($data.workingDir)
|
||||||
var pid: Pid
|
var pid: Pid
|
||||||
var err: OSErrorCode
|
|
||||||
|
|
||||||
if data.optionPoUsePath:
|
if data.optionPoUsePath:
|
||||||
res = posix_spawnp(pid, data.sysCommand, fops, attr, data.sysArgs, data.sysEnv)
|
res = posix_spawnp(pid, data.sysCommand, fops, attr, data.sysArgs, data.sysEnv)
|
||||||
if res != 0'i32: err = osLastError()
|
|
||||||
else:
|
else:
|
||||||
res = posix_spawn(pid, data.sysCommand, fops, attr, data.sysArgs, data.sysEnv)
|
res = posix_spawn(pid, data.sysCommand, fops, attr, data.sysArgs, data.sysEnv)
|
||||||
if res != 0'i32: err = osLastError()
|
|
||||||
|
|
||||||
discard posix_spawn_file_actions_destroy(fops)
|
discard posix_spawn_file_actions_destroy(fops)
|
||||||
discard posix_spawnattr_destroy(attr)
|
discard posix_spawnattr_destroy(attr)
|
||||||
if res != 0'i32: raiseOSError(err)
|
if res != 0'i32: raiseOSError(OSErrorCode(res))
|
||||||
|
|
||||||
return pid
|
return pid
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -540,8 +540,8 @@ proc writeConfig*(dict: Config, filename: string) =
|
||||||
## Writes the contents of the table to the specified configuration file.
|
## Writes the contents of the table to the specified configuration file.
|
||||||
## Note: Comment statement will be ignored.
|
## Note: Comment statement will be ignored.
|
||||||
let file = open(filename, fmWrite)
|
let file = open(filename, fmWrite)
|
||||||
let fileStream = newFileStream(filename)
|
defer: file.close()
|
||||||
defer: fileStream.close()
|
let fileStream = newFileStream(file)
|
||||||
dict.writeConfig(fileStream)
|
dict.writeConfig(fileStream)
|
||||||
|
|
||||||
proc getSectionValue*(dict: Config, section, key: string): string =
|
proc getSectionValue*(dict: Config, section, key: string): string =
|
||||||
|
|
|
||||||
|
|
@ -149,15 +149,13 @@ proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1".} =
|
||||||
## retrieves the rest of the command line that has not been parsed yet.
|
## retrieves the rest of the command line that has not been parsed yet.
|
||||||
result = strip(substr(p.cmd, p.pos, len(p.cmd) - 1)).TaintedString
|
result = strip(substr(p.cmd, p.pos, len(p.cmd) - 1)).TaintedString
|
||||||
|
|
||||||
when declared(initOptParser):
|
iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key, val: TaintedString] =
|
||||||
iterator getopt*(): tuple[kind: CmdLineKind, key, val: TaintedString] =
|
## This is an convenience iterator for iterating over the given OptParser object.
|
||||||
## This is an convenience iterator for iterating over the command line.
|
## Example:
|
||||||
## This uses the OptParser object. Example:
|
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
## var
|
## var p = initOptParser("--left --debug:3 -l=4 -r:2")
|
||||||
## filename = ""
|
## for kind, key, val in p.getopt():
|
||||||
## for kind, key, val in getopt():
|
|
||||||
## case kind
|
## case kind
|
||||||
## of cmdArgument:
|
## of cmdArgument:
|
||||||
## filename = key
|
## filename = key
|
||||||
|
|
@ -169,6 +167,23 @@ when declared(initOptParser):
|
||||||
## if filename == "":
|
## if filename == "":
|
||||||
## # no filename has been given, so we show the help:
|
## # no filename has been given, so we show the help:
|
||||||
## writeHelp()
|
## writeHelp()
|
||||||
|
p.pos = 0
|
||||||
|
while true:
|
||||||
|
next(p)
|
||||||
|
if p.kind == cmdEnd: break
|
||||||
|
yield (p.kind, p.key, p.val)
|
||||||
|
|
||||||
|
when declared(initOptParser):
|
||||||
|
iterator getopt*(): tuple[kind: CmdLineKind, key, val: TaintedString] =
|
||||||
|
## This is an convenience iterator for iterating over the command line arguments.
|
||||||
|
## This create a new OptParser object.
|
||||||
|
## See above for a more detailed example
|
||||||
|
##
|
||||||
|
## .. code-block:: nim
|
||||||
|
## for kind, key, val in getopt():
|
||||||
|
## # this will iterate over all arguments passed to the cmdline.
|
||||||
|
## continue
|
||||||
|
##
|
||||||
var p = initOptParser()
|
var p = initOptParser()
|
||||||
while true:
|
while true:
|
||||||
next(p)
|
next(p)
|
||||||
|
|
|
||||||
|
|
@ -123,15 +123,13 @@ type
|
||||||
|
|
||||||
{.deprecated: [TGetoptResult: GetoptResult].}
|
{.deprecated: [TGetoptResult: GetoptResult].}
|
||||||
|
|
||||||
when declared(paramCount):
|
iterator getopt*(p: var OptParser): GetoptResult =
|
||||||
iterator getopt*(): GetoptResult =
|
## This is an convenience iterator for iterating over the given OptParser object.
|
||||||
## This is an convenience iterator for iterating over the command line.
|
## Example:
|
||||||
## This uses the OptParser object. Example:
|
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
## var
|
## var p = initOptParser("--left --debug:3 -l=4 -r:2")
|
||||||
## filename = ""
|
## for kind, key, val in p.getopt():
|
||||||
## for kind, key, val in getopt():
|
|
||||||
## case kind
|
## case kind
|
||||||
## of cmdArgument:
|
## of cmdArgument:
|
||||||
## filename = key
|
## filename = key
|
||||||
|
|
@ -143,6 +141,23 @@ when declared(paramCount):
|
||||||
## if filename == "":
|
## if filename == "":
|
||||||
## # no filename has been given, so we show the help:
|
## # no filename has been given, so we show the help:
|
||||||
## writeHelp()
|
## writeHelp()
|
||||||
|
p.pos = 0
|
||||||
|
while true:
|
||||||
|
next(p)
|
||||||
|
if p.kind == cmdEnd: break
|
||||||
|
yield (p.kind, p.key, p.val)
|
||||||
|
|
||||||
|
when declared(paramCount):
|
||||||
|
iterator getopt*(): GetoptResult =
|
||||||
|
## This is an convenience iterator for iterating over the command line arguments.
|
||||||
|
## This create a new OptParser object.
|
||||||
|
## See above for a more detailed example
|
||||||
|
##
|
||||||
|
## .. code-block:: nim
|
||||||
|
## for kind, key, val in getopt():
|
||||||
|
## # this will iterate over all arguments passed to the cmdline.
|
||||||
|
## continue
|
||||||
|
##
|
||||||
var p = initOptParser()
|
var p = initOptParser()
|
||||||
while true:
|
while true:
|
||||||
next(p)
|
next(p)
|
||||||
|
|
|
||||||
|
|
@ -371,7 +371,7 @@ proc esc(c: char, reserved = {'\0'..'\255'}): string =
|
||||||
of '\a': result = "\\a"
|
of '\a': result = "\\a"
|
||||||
of '\\': result = "\\\\"
|
of '\\': result = "\\\\"
|
||||||
of 'a'..'z', 'A'..'Z', '0'..'9', '_': result = $c
|
of 'a'..'z', 'A'..'Z', '0'..'9', '_': result = $c
|
||||||
elif c < ' ' or c >= '\128': result = '\\' & $ord(c)
|
elif c < ' ' or c >= '\127': result = '\\' & $ord(c)
|
||||||
elif c in reserved: result = '\\' & c
|
elif c in reserved: result = '\\' & c
|
||||||
else: result = $c
|
else: result = $c
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,8 @@ when not defined(nimscript):
|
||||||
proc getMil(t: Time): int {.importcpp: "getTime", nodecl.}
|
proc getMil(t: Time): int {.importcpp: "getTime", nodecl.}
|
||||||
randomize(getMil times.getTime())
|
randomize(getMil times.getTime())
|
||||||
else:
|
else:
|
||||||
randomize(int times.getTime())
|
let time = int(times.epochTime() * 1_000_000_000)
|
||||||
|
randomize(time)
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -334,12 +334,16 @@ when not defined(js):
|
||||||
if result > 0:
|
if result > 0:
|
||||||
copyMem(buffer, addr(s.data[s.pos]), result)
|
copyMem(buffer, addr(s.data[s.pos]), result)
|
||||||
inc(s.pos, result)
|
inc(s.pos, result)
|
||||||
|
else:
|
||||||
|
result = 0
|
||||||
|
|
||||||
proc ssPeekData(s: Stream, buffer: pointer, bufLen: int): int =
|
proc ssPeekData(s: Stream, buffer: pointer, bufLen: int): int =
|
||||||
var s = StringStream(s)
|
var s = StringStream(s)
|
||||||
result = min(bufLen, s.data.len - s.pos)
|
result = min(bufLen, s.data.len - s.pos)
|
||||||
if result > 0:
|
if result > 0:
|
||||||
copyMem(buffer, addr(s.data[s.pos]), result)
|
copyMem(buffer, addr(s.data[s.pos]), result)
|
||||||
|
else:
|
||||||
|
result = 0
|
||||||
|
|
||||||
proc ssWriteData(s: Stream, buffer: pointer, bufLen: int) =
|
proc ssWriteData(s: Stream, buffer: pointer, bufLen: int) =
|
||||||
var s = StringStream(s)
|
var s = StringStream(s)
|
||||||
|
|
|
||||||
|
|
@ -1643,7 +1643,7 @@ proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
|
||||||
## * replaces any ``\`` by ``\\``
|
## * replaces any ``\`` by ``\\``
|
||||||
## * replaces any ``'`` by ``\'``
|
## * replaces any ``'`` by ``\'``
|
||||||
## * replaces any ``"`` by ``\"``
|
## * replaces any ``"`` by ``\"``
|
||||||
## * replaces any other character in the set ``{'\0'..'\31', '\128'..'\255'}``
|
## * replaces any other character in the set ``{'\0'..'\31', '\127'..'\255'}``
|
||||||
## by ``\xHH`` where ``HH`` is its hexadecimal value.
|
## by ``\xHH`` where ``HH`` is its hexadecimal value.
|
||||||
## The procedure has been designed so that its output is usable for many
|
## The procedure has been designed so that its output is usable for many
|
||||||
## different common syntaxes. The resulting string is prefixed with
|
## different common syntaxes. The resulting string is prefixed with
|
||||||
|
|
@ -1653,7 +1653,7 @@ proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
|
||||||
result.add(prefix)
|
result.add(prefix)
|
||||||
for c in items(s):
|
for c in items(s):
|
||||||
case c
|
case c
|
||||||
of '\0'..'\31', '\128'..'\255':
|
of '\0'..'\31', '\127'..'\255':
|
||||||
add(result, "\\x")
|
add(result, "\\x")
|
||||||
add(result, toHex(ord(c), 2))
|
add(result, toHex(ord(c), 2))
|
||||||
of '\\': add(result, "\\\\")
|
of '\\': add(result, "\\\\")
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ when defined(posix) and not defined(JS):
|
||||||
elif defined(windows):
|
elif defined(windows):
|
||||||
import winlean
|
import winlean
|
||||||
|
|
||||||
when defined(vcc) or defined(bcc):
|
when defined(vcc) or defined(bcc) or defined(icl):
|
||||||
# newest version of Visual C++ defines time_t to be of 64 bits
|
# newest version of Visual C++ defines time_t to be of 64 bits
|
||||||
type TimeImpl {.importc: "time_t", header: "<time.h>".} = int64
|
type TimeImpl {.importc: "time_t", header: "<time.h>".} = int64
|
||||||
# visual c's c runtime exposes these under a different name
|
# visual c's c runtime exposes these under a different name
|
||||||
|
|
@ -98,46 +98,47 @@ elif defined(windows):
|
||||||
|
|
||||||
elif defined(JS):
|
elif defined(JS):
|
||||||
type
|
type
|
||||||
Time* = ref TimeObj
|
TimeBase = float
|
||||||
TimeObj {.importc.} = object
|
Time* = distinct TimeBase
|
||||||
getDay: proc (): int {.tags: [], raises: [], benign.}
|
|
||||||
getFullYear: proc (): int {.tags: [], raises: [], benign.}
|
proc getDay(t: Time): int {.tags: [], raises: [], benign, importcpp.}
|
||||||
getHours: proc (): int {.tags: [], raises: [], benign.}
|
proc getFullYear(t: Time): int {.tags: [], raises: [], benign, importcpp.}
|
||||||
getMilliseconds: proc (): int {.tags: [], raises: [], benign.}
|
proc getHours(t: Time): int {.tags: [], raises: [], benign, importcpp.}
|
||||||
getMinutes: proc (): int {.tags: [], raises: [], benign.}
|
proc getMilliseconds(t: Time): int {.tags: [], raises: [], benign, importcpp.}
|
||||||
getMonth: proc (): int {.tags: [], raises: [], benign.}
|
proc getMinutes(t: Time): int {.tags: [], raises: [], benign, importcpp.}
|
||||||
getSeconds: proc (): int {.tags: [], raises: [], benign.}
|
proc getMonth(t: Time): int {.tags: [], raises: [], benign, importcpp.}
|
||||||
getTime: proc (): int {.tags: [], raises: [], noSideEffect, benign.}
|
proc getSeconds(t: Time): int {.tags: [], raises: [], benign, importcpp.}
|
||||||
getTimezoneOffset: proc (): int {.tags: [], raises: [], benign.}
|
proc getTime(t: Time): int {.tags: [], raises: [], noSideEffect, benign, importcpp.}
|
||||||
getDate: proc (): int {.tags: [], raises: [], benign.}
|
proc getTimezoneOffset(t: Time): int {.tags: [], raises: [], benign, importcpp.}
|
||||||
getUTCDate: proc (): int {.tags: [], raises: [], benign.}
|
proc getDate(t: Time): int {.tags: [], raises: [], benign, importcpp.}
|
||||||
getUTCFullYear: proc (): int {.tags: [], raises: [], benign.}
|
proc getUTCDate(t: Time): int {.tags: [], raises: [], benign, importcpp.}
|
||||||
getUTCHours: proc (): int {.tags: [], raises: [], benign.}
|
proc getUTCFullYear(t: Time): int {.tags: [], raises: [], benign, importcpp.}
|
||||||
getUTCMilliseconds: proc (): int {.tags: [], raises: [], benign.}
|
proc getUTCHours(t: Time): int {.tags: [], raises: [], benign, importcpp.}
|
||||||
getUTCMinutes: proc (): int {.tags: [], raises: [], benign.}
|
proc getUTCMilliseconds(t: Time): int {.tags: [], raises: [], benign, importcpp.}
|
||||||
getUTCMonth: proc (): int {.tags: [], raises: [], benign.}
|
proc getUTCMinutes(t: Time): int {.tags: [], raises: [], benign, importcpp.}
|
||||||
getUTCSeconds: proc (): int {.tags: [], raises: [], benign.}
|
proc getUTCMonth(t: Time): int {.tags: [], raises: [], benign, importcpp.}
|
||||||
getUTCDay: proc (): int {.tags: [], raises: [], benign.}
|
proc getUTCSeconds(t: Time): int {.tags: [], raises: [], benign, importcpp.}
|
||||||
getYear: proc (): int {.tags: [], raises: [], benign.}
|
proc getUTCDay(t: Time): int {.tags: [], raises: [], benign, importcpp.}
|
||||||
parse: proc (s: cstring): Time {.tags: [], raises: [], benign.}
|
proc getYear(t: Time): int {.tags: [], raises: [], benign, importcpp.}
|
||||||
setDate: proc (x: int) {.tags: [], raises: [], benign.}
|
proc parse(t: Time; s: cstring): Time {.tags: [], raises: [], benign, importcpp.}
|
||||||
setFullYear: proc (x: int) {.tags: [], raises: [], benign.}
|
proc setDate(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
|
||||||
setHours: proc (x: int) {.tags: [], raises: [], benign.}
|
proc setFullYear(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
|
||||||
setMilliseconds: proc (x: int) {.tags: [], raises: [], benign.}
|
proc setHours(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
|
||||||
setMinutes: proc (x: int) {.tags: [], raises: [], benign.}
|
proc setMilliseconds(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
|
||||||
setMonth: proc (x: int) {.tags: [], raises: [], benign.}
|
proc setMinutes(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
|
||||||
setSeconds: proc (x: int) {.tags: [], raises: [], benign.}
|
proc setMonth(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
|
||||||
setTime: proc (x: int) {.tags: [], raises: [], benign.}
|
proc setSeconds(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
|
||||||
setUTCDate: proc (x: int) {.tags: [], raises: [], benign.}
|
proc setTime(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
|
||||||
setUTCFullYear: proc (x: int) {.tags: [], raises: [], benign.}
|
proc setUTCDate(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
|
||||||
setUTCHours: proc (x: int) {.tags: [], raises: [], benign.}
|
proc setUTCFullYear(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
|
||||||
setUTCMilliseconds: proc (x: int) {.tags: [], raises: [], benign.}
|
proc setUTCHours(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
|
||||||
setUTCMinutes: proc (x: int) {.tags: [], raises: [], benign.}
|
proc setUTCMilliseconds(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
|
||||||
setUTCMonth: proc (x: int) {.tags: [], raises: [], benign.}
|
proc setUTCMinutes(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
|
||||||
setUTCSeconds: proc (x: int) {.tags: [], raises: [], benign.}
|
proc setUTCMonth(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
|
||||||
setYear: proc (x: int) {.tags: [], raises: [], benign.}
|
proc setUTCSeconds(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
|
||||||
toGMTString: proc (): cstring {.tags: [], raises: [], benign.}
|
proc setYear(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
|
||||||
toLocaleString: proc (): cstring {.tags: [], raises: [], benign.}
|
proc toGMTString(t: Time): cstring {.tags: [], raises: [], benign, importcpp.}
|
||||||
|
proc toLocaleString(t: Time): cstring {.tags: [], raises: [], benign, importcpp.}
|
||||||
|
|
||||||
type
|
type
|
||||||
TimeInfo* = object of RootObj ## represents a time in different parts
|
TimeInfo* = object of RootObj ## represents a time in different parts
|
||||||
|
|
@ -225,16 +226,25 @@ proc `-`*(a, b: Time): int64 {.
|
||||||
proc `<`*(a, b: Time): bool {.
|
proc `<`*(a, b: Time): bool {.
|
||||||
rtl, extern: "ntLtTime", tags: [], raises: [], noSideEffect.} =
|
rtl, extern: "ntLtTime", tags: [], raises: [], noSideEffect.} =
|
||||||
## returns true iff ``a < b``, that is iff a happened before b.
|
## returns true iff ``a < b``, that is iff a happened before b.
|
||||||
|
when defined(js):
|
||||||
|
result = TimeBase(a) < TimeBase(b)
|
||||||
|
else:
|
||||||
result = a - b < 0
|
result = a - b < 0
|
||||||
|
|
||||||
proc `<=` * (a, b: Time): bool {.
|
proc `<=` * (a, b: Time): bool {.
|
||||||
rtl, extern: "ntLeTime", tags: [], raises: [], noSideEffect.}=
|
rtl, extern: "ntLeTime", tags: [], raises: [], noSideEffect.}=
|
||||||
## returns true iff ``a <= b``.
|
## returns true iff ``a <= b``.
|
||||||
|
when defined(js):
|
||||||
|
result = TimeBase(a) <= TimeBase(b)
|
||||||
|
else:
|
||||||
result = a - b <= 0
|
result = a - b <= 0
|
||||||
|
|
||||||
proc `==`*(a, b: Time): bool {.
|
proc `==`*(a, b: Time): bool {.
|
||||||
rtl, extern: "ntEqTime", tags: [], raises: [], noSideEffect.} =
|
rtl, extern: "ntEqTime", tags: [], raises: [], noSideEffect.} =
|
||||||
## returns true if ``a == b``, that is if both times represent the same value
|
## returns true if ``a == b``, that is if both times represent the same value
|
||||||
|
when defined(js):
|
||||||
|
result = TimeBase(a) == TimeBase(b)
|
||||||
|
else:
|
||||||
result = a - b == 0
|
result = a - b == 0
|
||||||
|
|
||||||
proc getTimezone*(): int {.tags: [TimeEffect], raises: [], benign.}
|
proc getTimezone*(): int {.tags: [TimeEffect], raises: [], benign.}
|
||||||
|
|
@ -479,7 +489,7 @@ proc `-=`*(t: var Time, ti: TimeInterval) =
|
||||||
t = toTime(getLocalTime(t) - ti)
|
t = toTime(getLocalTime(t) - ti)
|
||||||
|
|
||||||
proc `-`*(t: Time, ti: TimeInterval): Time =
|
proc `-`*(t: Time, ti: TimeInterval): Time =
|
||||||
## adds the interval `ti` to Time `t`
|
## subtracts the interval `ti` from Time `t`
|
||||||
##
|
##
|
||||||
## ``echo getTime() - 1.day``
|
## ``echo getTime() - 1.day``
|
||||||
result = toTime(getLocalTime(t) - ti)
|
result = toTime(getLocalTime(t) - ti)
|
||||||
|
|
|
||||||
103
lib/system.nim
103
lib/system.nim
|
|
@ -49,6 +49,9 @@ type
|
||||||
cstring* {.magic: Cstring.} ## built-in cstring (*compatible string*) type
|
cstring* {.magic: Cstring.} ## built-in cstring (*compatible string*) type
|
||||||
pointer* {.magic: Pointer.} ## built-in pointer type, use the ``addr``
|
pointer* {.magic: Pointer.} ## built-in pointer type, use the ``addr``
|
||||||
## operator to get a pointer to a variable
|
## operator to get a pointer to a variable
|
||||||
|
|
||||||
|
typedesc* {.magic: TypeDesc.} ## meta type to denote a type description
|
||||||
|
|
||||||
const
|
const
|
||||||
on* = true ## alias for ``true``
|
on* = true ## alias for ``true``
|
||||||
off* = false ## alias for ``false``
|
off* = false ## alias for ``false``
|
||||||
|
|
@ -56,6 +59,15 @@ const
|
||||||
{.push warning[GcMem]: off, warning[Uninit]: off.}
|
{.push warning[GcMem]: off, warning[Uninit]: off.}
|
||||||
{.push hints: off.}
|
{.push hints: off.}
|
||||||
|
|
||||||
|
proc `or` *(a, b: typedesc): typedesc {.magic: "TypeTrait", noSideEffect.}
|
||||||
|
## Constructs an `or` meta class
|
||||||
|
|
||||||
|
proc `and` *(a, b: typedesc): typedesc {.magic: "TypeTrait", noSideEffect.}
|
||||||
|
## Constructs an `and` meta class
|
||||||
|
|
||||||
|
proc `not` *(a: typedesc): typedesc {.magic: "TypeTrait", noSideEffect.}
|
||||||
|
## Constructs an `not` meta class
|
||||||
|
|
||||||
type
|
type
|
||||||
Ordinal* {.magic: Ordinal.}[T] ## Generic ordinal type. Includes integer,
|
Ordinal* {.magic: Ordinal.}[T] ## Generic ordinal type. Includes integer,
|
||||||
## bool, character, and enumeration types
|
## bool, character, and enumeration types
|
||||||
|
|
@ -66,11 +78,11 @@ type
|
||||||
`ref`* {.magic: Pointer.}[T] ## built-in generic traced pointer type
|
`ref`* {.magic: Pointer.}[T] ## built-in generic traced pointer type
|
||||||
|
|
||||||
`nil` {.magic: "Nil".}
|
`nil` {.magic: "Nil".}
|
||||||
|
|
||||||
expr* {.magic: Expr, deprecated.} ## meta type to denote an expression (for templates)
|
expr* {.magic: Expr, deprecated.} ## meta type to denote an expression (for templates)
|
||||||
## **Deprecated** since version 0.15. Use ``untyped`` instead.
|
## **Deprecated** since version 0.15. Use ``untyped`` instead.
|
||||||
stmt* {.magic: Stmt, deprecated.} ## meta type to denote a statement (for templates)
|
stmt* {.magic: Stmt, deprecated.} ## meta type to denote a statement (for templates)
|
||||||
## **Deprecated** since version 0.15. Use ``typed`` instead.
|
## **Deprecated** since version 0.15. Use ``typed`` instead.
|
||||||
typedesc* {.magic: TypeDesc.} ## meta type to denote a type description
|
|
||||||
void* {.magic: "VoidType".} ## meta type to denote the absence of any type
|
void* {.magic: "VoidType".} ## meta type to denote the absence of any type
|
||||||
auto* {.magic: Expr.} ## meta type for automatic type determination
|
auto* {.magic: Expr.} ## meta type for automatic type determination
|
||||||
any* = distinct auto ## meta type for any supported type
|
any* = distinct auto ## meta type for any supported type
|
||||||
|
|
@ -430,6 +442,7 @@ type
|
||||||
## providing an exception message
|
## providing an exception message
|
||||||
## is bad style.
|
## is bad style.
|
||||||
trace: string
|
trace: string
|
||||||
|
up: ref Exception # used for stacking exceptions. Not exported!
|
||||||
|
|
||||||
SystemError* = object of Exception ## \
|
SystemError* = object of Exception ## \
|
||||||
## Abstract class for exceptions that the runtime system raises.
|
## Abstract class for exceptions that the runtime system raises.
|
||||||
|
|
@ -1056,7 +1069,7 @@ proc `div`*[T: SomeUnsignedInt](x, y: T): T {.magic: "DivU", noSideEffect.}
|
||||||
## ``floor(x/y)``.
|
## ``floor(x/y)``.
|
||||||
##
|
##
|
||||||
## .. code-block:: Nim
|
## .. code-block:: Nim
|
||||||
## (7 div 5) == 2
|
## (7 div 5) == 1
|
||||||
|
|
||||||
proc `mod`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ModU", noSideEffect.}
|
proc `mod`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ModU", noSideEffect.}
|
||||||
## computes the integer modulo operation (remainder).
|
## computes the integer modulo operation (remainder).
|
||||||
|
|
@ -1332,6 +1345,7 @@ const
|
||||||
hasThreadSupport = compileOption("threads") and not defined(nimscript)
|
hasThreadSupport = compileOption("threads") and not defined(nimscript)
|
||||||
hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own
|
hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own
|
||||||
taintMode = compileOption("taintmode")
|
taintMode = compileOption("taintmode")
|
||||||
|
nimEnableCovariance* = defined(nimEnableCovariance) # or true
|
||||||
|
|
||||||
when hasThreadSupport and defined(tcc) and not compileOption("tlsEmulation"):
|
when hasThreadSupport and defined(tcc) and not compileOption("tlsEmulation"):
|
||||||
# tcc doesn't support TLS
|
# tcc doesn't support TLS
|
||||||
|
|
@ -1879,7 +1893,7 @@ const
|
||||||
NimMajor*: int = 0
|
NimMajor*: int = 0
|
||||||
## is the major number of Nim's version.
|
## is the major number of Nim's version.
|
||||||
|
|
||||||
NimMinor*: int = 16
|
NimMinor*: int = 17
|
||||||
## is the minor number of Nim's version.
|
## is the minor number of Nim's version.
|
||||||
|
|
||||||
NimPatch*: int = 1
|
NimPatch*: int = 1
|
||||||
|
|
@ -2034,6 +2048,14 @@ proc clamp*[T](x, a, b: T): T =
|
||||||
if x > b: return b
|
if x > b: return b
|
||||||
return x
|
return x
|
||||||
|
|
||||||
|
proc len*[T: Ordinal](x: Slice[T]): int {.noSideEffect, inline.} =
|
||||||
|
## length of ordinal slice, when x.b < x.a returns zero length
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## assert((0..5).len == 6)
|
||||||
|
## assert((5..2).len == 0)
|
||||||
|
result = max(0, ord(x.b) - ord(x.a) + 1)
|
||||||
|
|
||||||
iterator items*[T](a: openArray[T]): T {.inline.} =
|
iterator items*[T](a: openArray[T]): T {.inline.} =
|
||||||
## iterates over each item of `a`.
|
## iterates over each item of `a`.
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
@ -2428,6 +2450,16 @@ when false:
|
||||||
# ----------------- GC interface ---------------------------------------------
|
# ----------------- GC interface ---------------------------------------------
|
||||||
|
|
||||||
when not defined(nimscript) and hasAlloc:
|
when not defined(nimscript) and hasAlloc:
|
||||||
|
type
|
||||||
|
GC_Strategy* = enum ## the strategy the GC should use for the application
|
||||||
|
gcThroughput, ## optimize for throughput
|
||||||
|
gcResponsiveness, ## optimize for responsiveness (default)
|
||||||
|
gcOptimizeTime, ## optimize for speed
|
||||||
|
gcOptimizeSpace ## optimize for memory footprint
|
||||||
|
|
||||||
|
{.deprecated: [TGC_Strategy: GC_Strategy].}
|
||||||
|
|
||||||
|
when not defined(JS):
|
||||||
proc GC_disable*() {.rtl, inl, benign.}
|
proc GC_disable*() {.rtl, inl, benign.}
|
||||||
## disables the GC. If called n-times, n calls to `GC_enable` are needed to
|
## disables the GC. If called n-times, n calls to `GC_enable` are needed to
|
||||||
## reactivate the GC. Note that in most circumstances one should only disable
|
## reactivate the GC. Note that in most circumstances one should only disable
|
||||||
|
|
@ -2440,15 +2472,6 @@ when not defined(nimscript) and hasAlloc:
|
||||||
## forces a full garbage collection pass.
|
## forces a full garbage collection pass.
|
||||||
## Ordinary code does not need to call this (and should not).
|
## Ordinary code does not need to call this (and should not).
|
||||||
|
|
||||||
type
|
|
||||||
GC_Strategy* = enum ## the strategy the GC should use for the application
|
|
||||||
gcThroughput, ## optimize for throughput
|
|
||||||
gcResponsiveness, ## optimize for responsiveness (default)
|
|
||||||
gcOptimizeTime, ## optimize for speed
|
|
||||||
gcOptimizeSpace ## optimize for memory footprint
|
|
||||||
|
|
||||||
{.deprecated: [TGC_Strategy: GC_Strategy].}
|
|
||||||
|
|
||||||
proc GC_setStrategy*(strategy: GC_Strategy) {.rtl, deprecated, benign.}
|
proc GC_setStrategy*(strategy: GC_Strategy) {.rtl, deprecated, benign.}
|
||||||
## tells the GC the desired strategy for the application.
|
## tells the GC the desired strategy for the application.
|
||||||
## **Deprecated** since version 0.8.14. This has always been a nop.
|
## **Deprecated** since version 0.8.14. This has always been a nop.
|
||||||
|
|
@ -2477,6 +2500,47 @@ when not defined(nimscript) and hasAlloc:
|
||||||
proc GC_unref*(x: string) {.magic: "GCunref", benign.}
|
proc GC_unref*(x: string) {.magic: "GCunref", benign.}
|
||||||
## see the documentation of `GC_ref`.
|
## see the documentation of `GC_ref`.
|
||||||
|
|
||||||
|
else:
|
||||||
|
template GC_disable* =
|
||||||
|
{.warning: "GC_disable is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_enable* =
|
||||||
|
{.warning: "GC_enable is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_fullCollect* =
|
||||||
|
{.warning: "GC_fullCollect is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_setStrategy* =
|
||||||
|
{.warning: "GC_setStrategy is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_enableMarkAndSweep* =
|
||||||
|
{.warning: "GC_enableMarkAndSweep is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_disableMarkAndSweep* =
|
||||||
|
{.warning: "GC_disableMarkAndSweep is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_ref*[T](x: ref T) =
|
||||||
|
{.warning: "GC_ref is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_ref*[T](x: seq[T]) =
|
||||||
|
{.warning: "GC_ref is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_ref*(x: string) =
|
||||||
|
{.warning: "GC_ref is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_unref*[T](x: ref T) =
|
||||||
|
{.warning: "GC_unref is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_unref*[T](x: seq[T]) =
|
||||||
|
{.warning: "GC_unref is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_unref*(x: string) =
|
||||||
|
{.warning: "GC_unref is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_getStatistics*(): string =
|
||||||
|
{.warning: "GC_disableMarkAndSweep is a no-op in JavaScript".}
|
||||||
|
""
|
||||||
|
|
||||||
template accumulateResult*(iter: untyped) =
|
template accumulateResult*(iter: untyped) =
|
||||||
## helps to convert an iterator to a proc.
|
## helps to convert an iterator to a proc.
|
||||||
result = @[]
|
result = @[]
|
||||||
|
|
@ -3210,16 +3274,6 @@ when not defined(JS): #and not defined(nimscript):
|
||||||
|
|
||||||
elif defined(JS):
|
elif defined(JS):
|
||||||
# Stubs:
|
# Stubs:
|
||||||
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} = discard
|
|
||||||
|
|
||||||
proc GC_disable() = discard
|
|
||||||
proc GC_enable() = discard
|
|
||||||
proc GC_fullCollect() = discard
|
|
||||||
proc GC_setStrategy(strategy: GC_Strategy) = discard
|
|
||||||
proc GC_enableMarkAndSweep() = discard
|
|
||||||
proc GC_disableMarkAndSweep() = discard
|
|
||||||
proc GC_getStatistics(): string = return ""
|
|
||||||
|
|
||||||
proc getOccupiedMem(): int = return -1
|
proc getOccupiedMem(): int = return -1
|
||||||
proc getFreeMem(): int = return -1
|
proc getFreeMem(): int = return -1
|
||||||
proc getTotalMem(): int = return -1
|
proc getTotalMem(): int = return -1
|
||||||
|
|
@ -3458,7 +3512,7 @@ proc `*=`*[T: SomeOrdinal|uint|uint64](x: var T, y: T) {.
|
||||||
|
|
||||||
proc `+=`*[T: float|float32|float64] (x: var T, y: T) {.
|
proc `+=`*[T: float|float32|float64] (x: var T, y: T) {.
|
||||||
inline, noSideEffect.} =
|
inline, noSideEffect.} =
|
||||||
## Increments in placee a floating point number
|
## Increments in place a floating point number
|
||||||
x = x + y
|
x = x + y
|
||||||
|
|
||||||
proc `-=`*[T: float|float32|float64] (x: var T, y: T) {.
|
proc `-=`*[T: float|float32|float64] (x: var T, y: T) {.
|
||||||
|
|
@ -3721,7 +3775,8 @@ proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} =
|
||||||
|
|
||||||
when hasAlloc and not defined(nimscript) and not defined(JS):
|
when hasAlloc and not defined(nimscript) and not defined(JS):
|
||||||
proc deepCopy*[T](x: var T, y: T) {.noSideEffect, magic: "DeepCopy".} =
|
proc deepCopy*[T](x: var T, y: T) {.noSideEffect, magic: "DeepCopy".} =
|
||||||
## performs a deep copy of `x`. This is also used by the code generator
|
## performs a deep copy of `y` and copies it into `x`.
|
||||||
|
## This is also used by the code generator
|
||||||
## for the implementation of ``spawn``.
|
## for the implementation of ``spawn``.
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
# Low level allocator for Nim. Has been designed to support the GC.
|
# Low level allocator for Nim. Has been designed to support the GC.
|
||||||
# TODO:
|
# TODO:
|
||||||
# - eliminate "used" field
|
|
||||||
# - make searching for block O(1)
|
# - make searching for block O(1)
|
||||||
{.push profiler:off.}
|
{.push profiler:off.}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,12 +90,11 @@ proc popSafePoint {.compilerRtl, inl.} =
|
||||||
excHandler = excHandler.prev
|
excHandler = excHandler.prev
|
||||||
|
|
||||||
proc pushCurrentException(e: ref Exception) {.compilerRtl, inl.} =
|
proc pushCurrentException(e: ref Exception) {.compilerRtl, inl.} =
|
||||||
#if e.parent.isNil:
|
e.up = currException
|
||||||
# e.parent = currException
|
|
||||||
currException = e
|
currException = e
|
||||||
|
|
||||||
proc popCurrentException {.compilerRtl, inl.} =
|
proc popCurrentException {.compilerRtl, inl.} =
|
||||||
currException = nil # currException.parent
|
currException = currException.up
|
||||||
|
|
||||||
# some platforms have native support for stack traces:
|
# some platforms have native support for stack traces:
|
||||||
const
|
const
|
||||||
|
|
@ -247,6 +246,18 @@ when false:
|
||||||
pushCurrentException(e)
|
pushCurrentException(e)
|
||||||
c_longjmp(excHandler.context, 1)
|
c_longjmp(excHandler.context, 1)
|
||||||
|
|
||||||
|
var onUnhandledException*: (proc (errorMsg: string) {.
|
||||||
|
nimcall.}) ## set this error \
|
||||||
|
## handler to override the existing behaviour on an unhandled exception.
|
||||||
|
## The default is to write a stacktrace to ``stderr`` and then call ``quit(1)``.
|
||||||
|
## Unstable API.
|
||||||
|
|
||||||
|
template unhandled(buf, body) =
|
||||||
|
if onUnhandledException != nil:
|
||||||
|
onUnhandledException($buf)
|
||||||
|
else:
|
||||||
|
body
|
||||||
|
|
||||||
proc raiseExceptionAux(e: ref Exception) =
|
proc raiseExceptionAux(e: ref Exception) =
|
||||||
if localRaiseHook != nil:
|
if localRaiseHook != nil:
|
||||||
if not localRaiseHook(e): return
|
if not localRaiseHook(e): return
|
||||||
|
|
@ -277,7 +288,9 @@ proc raiseExceptionAux(e: ref Exception) =
|
||||||
add(buf, " [")
|
add(buf, " [")
|
||||||
add(buf, $e.name)
|
add(buf, $e.name)
|
||||||
add(buf, "]\n")
|
add(buf, "]\n")
|
||||||
|
unhandled(buf):
|
||||||
showErrorMessage(buf)
|
showErrorMessage(buf)
|
||||||
|
quitOrDebug()
|
||||||
else:
|
else:
|
||||||
# ugly, but avoids heap allocations :-)
|
# ugly, but avoids heap allocations :-)
|
||||||
template xadd(buf, s, slen: expr) =
|
template xadd(buf, s, slen: expr) =
|
||||||
|
|
@ -293,6 +306,7 @@ proc raiseExceptionAux(e: ref Exception) =
|
||||||
add(buf, " [")
|
add(buf, " [")
|
||||||
xadd(buf, e.name, e.name.len)
|
xadd(buf, e.name, e.name.len)
|
||||||
add(buf, "]\n")
|
add(buf, "]\n")
|
||||||
|
unhandled(buf):
|
||||||
showErrorMessage(buf)
|
showErrorMessage(buf)
|
||||||
quitOrDebug()
|
quitOrDebug()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,13 @@ when defined(nimTypeNames):
|
||||||
c_fprintf(stdout, "[Heap] %s: #%ld; bytes: %ld\n", it.name, it.instances, it.sizes)
|
c_fprintf(stdout, "[Heap] %s: #%ld; bytes: %ld\n", it.name, it.instances, it.sizes)
|
||||||
it = it.nextType
|
it = it.nextType
|
||||||
|
|
||||||
|
when defined(nimGcRefLeak):
|
||||||
|
proc oomhandler() =
|
||||||
|
c_fprintf(stdout, "[Heap] ROOTS: #%ld\n", gch.additionalRoots.len)
|
||||||
|
writeLeaks()
|
||||||
|
|
||||||
|
outOfMemHook = oomhandler
|
||||||
|
|
||||||
template decTypeSize(cell, t) =
|
template decTypeSize(cell, t) =
|
||||||
# XXX this needs to use atomics for multithreaded apps!
|
# XXX this needs to use atomics for multithreaded apps!
|
||||||
when defined(nimTypeNames):
|
when defined(nimTypeNames):
|
||||||
|
|
|
||||||
|
|
@ -142,11 +142,54 @@ proc doOperation(p: pointer, op: WalkOp) {.benign.}
|
||||||
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.}
|
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.}
|
||||||
# we need the prototype here for debugging purposes
|
# we need the prototype here for debugging purposes
|
||||||
|
|
||||||
|
when defined(nimGcRefLeak):
|
||||||
|
const
|
||||||
|
MaxTraceLen = 20 # tracking the last 20 calls is enough
|
||||||
|
|
||||||
|
type
|
||||||
|
GcStackTrace = object
|
||||||
|
lines: array[0..MaxTraceLen-1, cstring]
|
||||||
|
files: array[0..MaxTraceLen-1, cstring]
|
||||||
|
|
||||||
|
proc captureStackTrace(f: PFrame, st: var GcStackTrace) =
|
||||||
|
const
|
||||||
|
firstCalls = 5
|
||||||
|
var
|
||||||
|
it = f
|
||||||
|
i = 0
|
||||||
|
total = 0
|
||||||
|
while it != nil and i <= high(st.lines)-(firstCalls-1):
|
||||||
|
# the (-1) is for the "..." entry
|
||||||
|
st.lines[i] = it.procname
|
||||||
|
st.files[i] = it.filename
|
||||||
|
inc(i)
|
||||||
|
inc(total)
|
||||||
|
it = it.prev
|
||||||
|
var b = it
|
||||||
|
while it != nil:
|
||||||
|
inc(total)
|
||||||
|
it = it.prev
|
||||||
|
for j in 1..total-i-(firstCalls-1):
|
||||||
|
if b != nil: b = b.prev
|
||||||
|
if total != i:
|
||||||
|
st.lines[i] = "..."
|
||||||
|
st.files[i] = "..."
|
||||||
|
inc(i)
|
||||||
|
while b != nil and i <= high(st.lines):
|
||||||
|
st.lines[i] = b.procname
|
||||||
|
st.files[i] = b.filename
|
||||||
|
inc(i)
|
||||||
|
b = b.prev
|
||||||
|
|
||||||
|
var ax: array[10_000, GcStackTrace]
|
||||||
|
|
||||||
proc nimGCref(p: pointer) {.compilerProc.} =
|
proc nimGCref(p: pointer) {.compilerProc.} =
|
||||||
# we keep it from being collected by pretending it's not even allocated:
|
# we keep it from being collected by pretending it's not even allocated:
|
||||||
when false:
|
when false:
|
||||||
when withBitvectors: excl(gch.allocated, usrToCell(p))
|
when withBitvectors: excl(gch.allocated, usrToCell(p))
|
||||||
else: usrToCell(p).refcount = rcBlack
|
else: usrToCell(p).refcount = rcBlack
|
||||||
|
when defined(nimGcRefLeak):
|
||||||
|
captureStackTrace(framePtr, ax[gch.additionalRoots.len])
|
||||||
add(gch.additionalRoots, usrToCell(p))
|
add(gch.additionalRoots, usrToCell(p))
|
||||||
|
|
||||||
proc nimGCunref(p: pointer) {.compilerProc.} =
|
proc nimGCunref(p: pointer) {.compilerProc.} =
|
||||||
|
|
@ -157,6 +200,8 @@ proc nimGCunref(p: pointer) {.compilerProc.} =
|
||||||
while i >= 0:
|
while i >= 0:
|
||||||
if d[i] == cell:
|
if d[i] == cell:
|
||||||
d[i] = d[L]
|
d[i] = d[L]
|
||||||
|
when defined(nimGcRefLeak):
|
||||||
|
ax[i] = ax[L]
|
||||||
dec gch.additionalRoots.len
|
dec gch.additionalRoots.len
|
||||||
break
|
break
|
||||||
dec(i)
|
dec(i)
|
||||||
|
|
@ -164,6 +209,16 @@ proc nimGCunref(p: pointer) {.compilerProc.} =
|
||||||
when withBitvectors: incl(gch.allocated, usrToCell(p))
|
when withBitvectors: incl(gch.allocated, usrToCell(p))
|
||||||
else: usrToCell(p).refcount = rcWhite
|
else: usrToCell(p).refcount = rcWhite
|
||||||
|
|
||||||
|
when defined(nimGcRefLeak):
|
||||||
|
proc writeLeaks() =
|
||||||
|
for i in 0..gch.additionalRoots.len-1:
|
||||||
|
c_fprintf(stdout, "[Heap] NEW STACK TRACE\n")
|
||||||
|
for ii in 0..MaxTraceLen-1:
|
||||||
|
let line = ax[i].lines[ii]
|
||||||
|
let file = ax[i].files[ii]
|
||||||
|
if isNil(line): break
|
||||||
|
c_fprintf(stdout, "[Heap] %s(%s)\n", file, line)
|
||||||
|
|
||||||
include gc_common
|
include gc_common
|
||||||
|
|
||||||
proc prepareDealloc(cell: PCell) =
|
proc prepareDealloc(cell: PCell) =
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ template withRegion*(r: MemRegion; body: untyped) =
|
||||||
try:
|
try:
|
||||||
body
|
body
|
||||||
finally:
|
finally:
|
||||||
r = tlRegion
|
#r = tlRegion
|
||||||
tlRegion = oldRegion
|
tlRegion = oldRegion
|
||||||
|
|
||||||
template inc(p: pointer, s: int) =
|
template inc(p: pointer, s: int) =
|
||||||
|
|
|
||||||
|
|
@ -446,7 +446,7 @@ when defined(kwin):
|
||||||
print(buf);
|
print(buf);
|
||||||
"""
|
"""
|
||||||
|
|
||||||
elif defined(nodejs):
|
elif not defined(nimOldEcho):
|
||||||
proc ewriteln(x: cstring) = log(x)
|
proc ewriteln(x: cstring) = log(x)
|
||||||
|
|
||||||
proc rawEcho {.compilerproc, asmNoStackFrame.} =
|
proc rawEcho {.compilerproc, asmNoStackFrame.} =
|
||||||
|
|
|
||||||
|
|
@ -255,12 +255,21 @@ elif defined(gogc):
|
||||||
next_gc: uint64 # next GC (in heap_alloc time)
|
next_gc: uint64 # next GC (in heap_alloc time)
|
||||||
last_gc: uint64 # last GC (in absolute time)
|
last_gc: uint64 # last GC (in absolute time)
|
||||||
pause_total_ns: uint64
|
pause_total_ns: uint64
|
||||||
pause_ns: array[256, uint64]
|
pause_ns: array[256, uint64] # circular buffer of recent gc pause lengths
|
||||||
|
pause_end: array[256, uint64] # circular buffer of recent gc end times (nanoseconds since 1970)
|
||||||
numgc: uint32
|
numgc: uint32
|
||||||
|
numforcedgc: uint32 # number of user-forced GCs
|
||||||
|
gc_cpu_fraction: float64 # fraction of CPU time used by GC
|
||||||
enablegc: cbool
|
enablegc: cbool
|
||||||
debuggc: cbool
|
debuggc: cbool
|
||||||
# Statistics about allocation size classes.
|
# Statistics about allocation size classes.
|
||||||
by_size: array[goNumSizeClasses, goMStats_inner_struct]
|
by_size: array[goNumSizeClasses, goMStats_inner_struct]
|
||||||
|
# Statistics below here are not exported to MemStats directly.
|
||||||
|
tinyallocs: uint64 # number of tiny allocations that didn't cause actual allocation; not exported to go directly
|
||||||
|
gc_trigger: uint64
|
||||||
|
heap_live: uint64
|
||||||
|
heap_scan: uint64
|
||||||
|
heap_marked: uint64
|
||||||
|
|
||||||
proc goRuntime_ReadMemStats(a2: ptr goMStats) {.cdecl,
|
proc goRuntime_ReadMemStats(a2: ptr goMStats) {.cdecl,
|
||||||
importc: "runtime_ReadMemStats",
|
importc: "runtime_ReadMemStats",
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ proc reprStrAux(result: var string, s: cstring; len: int) =
|
||||||
of '"': add result, "\\\""
|
of '"': add result, "\\\""
|
||||||
of '\\': add result, "\\\\" # BUGFIX: forgotten
|
of '\\': add result, "\\\\" # BUGFIX: forgotten
|
||||||
of '\10': add result, "\\10\"\n\"" # " \n " # better readability
|
of '\10': add result, "\\10\"\n\"" # " \n " # better readability
|
||||||
of '\128' .. '\255', '\0'..'\9', '\11'..'\31':
|
of '\127' .. '\255', '\0'..'\9', '\11'..'\31':
|
||||||
add result, "\\" & reprInt(ord(c))
|
add result, "\\" & reprInt(ord(c))
|
||||||
else:
|
else:
|
||||||
result.add(c)
|
result.add(c)
|
||||||
|
|
@ -68,7 +68,7 @@ proc reprChar(x: char): string {.compilerRtl.} =
|
||||||
case x
|
case x
|
||||||
of '"': add result, "\\\""
|
of '"': add result, "\\\""
|
||||||
of '\\': add result, "\\\\"
|
of '\\': add result, "\\\\"
|
||||||
of '\128' .. '\255', '\0'..'\31': add result, "\\" & reprInt(ord(x))
|
of '\127' .. '\255', '\0'..'\31': add result, "\\" & reprInt(ord(x))
|
||||||
else: add result, x
|
else: add result, x
|
||||||
add result, "\'"
|
add result, "\'"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ proc reprChar(x: char): string {.compilerRtl.} =
|
||||||
case x
|
case x
|
||||||
of '"': add(result, "\\\"")
|
of '"': add(result, "\\\"")
|
||||||
of '\\': add(result, "\\\\")
|
of '\\': add(result, "\\\\")
|
||||||
of '\128'..'\255', '\0'..'\31': add( result, "\\" & reprInt(ord(x)) )
|
of '\127'..'\255', '\0'..'\31': add( result, "\\" & reprInt(ord(x)) )
|
||||||
else: add(result, x)
|
else: add(result, x)
|
||||||
add(result, "\'")
|
add(result, "\'")
|
||||||
|
|
||||||
|
|
@ -56,7 +56,7 @@ proc reprStrAux(result: var string, s: cstring, len: int) =
|
||||||
of '"': add(result, "\\\"")
|
of '"': add(result, "\\\"")
|
||||||
of '\\': add(result, "\\\\")
|
of '\\': add(result, "\\\\")
|
||||||
of '\10': add(result, "\\10\"\n\"")
|
of '\10': add(result, "\\10\"\n\"")
|
||||||
of '\128'..'\255', '\0'..'\9', '\11'..'\31':
|
of '\127'..'\255', '\0'..'\9', '\11'..'\31':
|
||||||
add( result, "\\" & reprInt(ord(c)) )
|
add( result, "\\" & reprInt(ord(c)) )
|
||||||
else:
|
else:
|
||||||
add( result, reprInt(ord(c)) ) # Not sure about this.
|
add( result, reprInt(ord(c)) ) # Not sure about this.
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,12 @@ else:
|
||||||
when defined(linux) and defined(amd64):
|
when defined(linux) and defined(amd64):
|
||||||
abi: array[48 div sizeof(clonglong), clonglong]
|
abi: array[48 div sizeof(clonglong), clonglong]
|
||||||
|
|
||||||
|
SysCondAttr {.importc: "pthread_condattr_t", pure, final
|
||||||
|
header: """#include <sys/types.h>
|
||||||
|
#include <pthread.h>""".} = object
|
||||||
|
when defined(linux) and defined(amd64):
|
||||||
|
abi: array[4 div sizeof(cint), cint] # actually a cint
|
||||||
|
|
||||||
SysLockType = distinct cint
|
SysLockType = distinct cint
|
||||||
|
|
||||||
proc initSysLockAux(L: var SysLockObj, attr: ptr SysLockAttr) {.
|
proc initSysLockAux(L: var SysLockObj, attr: ptr SysLockAttr) {.
|
||||||
|
|
@ -185,7 +191,7 @@ else:
|
||||||
importc: "pthread_mutexattr_settype", header: "<pthread.h>", noSideEffect.}
|
importc: "pthread_mutexattr_settype", header: "<pthread.h>", noSideEffect.}
|
||||||
|
|
||||||
else:
|
else:
|
||||||
proc initSysCondAux(cond: var SysCondObj, cond_attr: pointer) {.
|
proc initSysCondAux(cond: var SysCondObj, cond_attr: ptr SysCondAttr = nil) {.
|
||||||
importc: "pthread_cond_init", header: "<pthread.h>", noSideEffect.}
|
importc: "pthread_cond_init", header: "<pthread.h>", noSideEffect.}
|
||||||
proc deinitSysCondAux(cond: var SysCondObj) {.noSideEffect,
|
proc deinitSysCondAux(cond: var SysCondObj) {.noSideEffect,
|
||||||
importc: "pthread_cond_destroy", header: "<pthread.h>".}
|
importc: "pthread_cond_destroy", header: "<pthread.h>".}
|
||||||
|
|
@ -196,7 +202,7 @@ else:
|
||||||
importc: "pthread_cond_signal", header: "<pthread.h>", noSideEffect.}
|
importc: "pthread_cond_signal", header: "<pthread.h>", noSideEffect.}
|
||||||
|
|
||||||
when defined(ios):
|
when defined(ios):
|
||||||
proc initSysCond(cond: var SysCond, cond_attr: pointer = nil) =
|
proc initSysCond(cond: var SysCond, cond_attr: ptr SysCondAttr = nil) =
|
||||||
cond = cast[SysCond](c_malloc(sizeof(SysCondObj)))
|
cond = cast[SysCond](c_malloc(sizeof(SysCondObj)))
|
||||||
initSysCondAux(cond[], cond_attr)
|
initSysCondAux(cond[], cond_attr)
|
||||||
|
|
||||||
|
|
@ -209,7 +215,7 @@ else:
|
||||||
template signalSysCond(cond: var SysCond) =
|
template signalSysCond(cond: var SysCond) =
|
||||||
signalSysCondAux(cond[])
|
signalSysCondAux(cond[])
|
||||||
else:
|
else:
|
||||||
template initSysCond(cond: var SysCond, cond_attr: pointer = nil) =
|
template initSysCond(cond: var SysCond, cond_attr: ptr SysCondAttr = nil) =
|
||||||
initSysCondAux(cond, cond_attr)
|
initSysCondAux(cond, cond_attr)
|
||||||
template deinitSysCond(cond: var SysCond) =
|
template deinitSysCond(cond: var SysCond) =
|
||||||
deinitSysCondAux(cond)
|
deinitSysCondAux(cond)
|
||||||
|
|
|
||||||
|
|
@ -264,7 +264,17 @@ else:
|
||||||
|
|
||||||
proc getThreadId*(): int =
|
proc getThreadId*(): int =
|
||||||
result = int(lwp_gettid())
|
result = int(lwp_gettid())
|
||||||
elif defined(macosx) or defined(freebsd) or defined(openbsd) or defined(netbsd):
|
elif defined(openbsd):
|
||||||
|
proc getthrid(): int32 {.importc: "getthrid", header: "<unistd.h>".}
|
||||||
|
|
||||||
|
proc getThreadId*(): int =
|
||||||
|
result = int(getthrid())
|
||||||
|
elif defined(netbsd):
|
||||||
|
proc lwp_self(): int32 {.importc: "_lwp_self", header: "<lwp.h>".}
|
||||||
|
|
||||||
|
proc getThreadId*(): int =
|
||||||
|
result = int(lwp_self())
|
||||||
|
elif defined(macosx) or defined(freebsd):
|
||||||
proc pthread_threadid_np(y: pointer; x: var uint64): cint {.importc, header: "pthread.h".}
|
proc pthread_threadid_np(y: pointer; x: var uint64): cint {.importc, header: "pthread.h".}
|
||||||
|
|
||||||
proc getThreadId*(): int =
|
proc getThreadId*(): int =
|
||||||
|
|
|
||||||
|
|
@ -291,6 +291,14 @@ const
|
||||||
FILE_ATTRIBUTE_TEMPORARY* = 256'i32
|
FILE_ATTRIBUTE_TEMPORARY* = 256'i32
|
||||||
|
|
||||||
MAX_PATH* = 260
|
MAX_PATH* = 260
|
||||||
|
|
||||||
|
MOVEFILE_COPY_ALLOWED* = 0x2'i32
|
||||||
|
MOVEFILE_CREATE_HARDLINK* = 0x10'i32
|
||||||
|
MOVEFILE_DELAY_UNTIL_REBOOT* = 0x4'i32
|
||||||
|
MOVEFILE_FAIL_IF_NOT_TRACKABLE* = 0x20'i32
|
||||||
|
MOVEFILE_REPLACE_EXISTING* = 0x1'i32
|
||||||
|
MOVEFILE_WRITE_THROUGH* = 0x8'i32
|
||||||
|
|
||||||
type
|
type
|
||||||
WIN32_FIND_DATA* {.pure.} = object
|
WIN32_FIND_DATA* {.pure.} = object
|
||||||
dwFileAttributes*: int32
|
dwFileAttributes*: int32
|
||||||
|
|
@ -342,6 +350,9 @@ when useWinUnicode:
|
||||||
|
|
||||||
proc moveFileW*(lpExistingFileName, lpNewFileName: WideCString): WINBOOL {.
|
proc moveFileW*(lpExistingFileName, lpNewFileName: WideCString): WINBOOL {.
|
||||||
importc: "MoveFileW", stdcall, dynlib: "kernel32".}
|
importc: "MoveFileW", stdcall, dynlib: "kernel32".}
|
||||||
|
proc moveFileExW*(lpExistingFileName, lpNewFileName: WideCString,
|
||||||
|
flags: DWORD): WINBOOL {.
|
||||||
|
importc: "MoveFileExW", stdcall, dynlib: "kernel32".}
|
||||||
|
|
||||||
proc getEnvironmentStringsW*(): WideCString {.
|
proc getEnvironmentStringsW*(): WideCString {.
|
||||||
stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsW".}
|
stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsW".}
|
||||||
|
|
@ -369,6 +380,9 @@ else:
|
||||||
|
|
||||||
proc moveFileA*(lpExistingFileName, lpNewFileName: cstring): WINBOOL {.
|
proc moveFileA*(lpExistingFileName, lpNewFileName: cstring): WINBOOL {.
|
||||||
importc: "MoveFileA", stdcall, dynlib: "kernel32".}
|
importc: "MoveFileA", stdcall, dynlib: "kernel32".}
|
||||||
|
proc moveFileExA*(lpExistingFileName, lpNewFileName: WideCString,
|
||||||
|
flags: DWORD): WINBOOL {.
|
||||||
|
importc: "MoveFileExA", stdcall, dynlib: "kernel32".}
|
||||||
|
|
||||||
proc getEnvironmentStringsA*(): cstring {.
|
proc getEnvironmentStringsA*(): cstring {.
|
||||||
stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsA".}
|
stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsA".}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ when useWinVersion:
|
||||||
from winlean import SocketHandle
|
from winlean import SocketHandle
|
||||||
else:
|
else:
|
||||||
const
|
const
|
||||||
versions = "(|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8)"
|
versions = "(|.38|.39|.41|.43|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8)"
|
||||||
when defined(macosx):
|
when defined(macosx):
|
||||||
const
|
const
|
||||||
DLLSSLName = "libssl" & versions & ".dylib"
|
DLLSSLName = "libssl" & versions & ".dylib"
|
||||||
|
|
|
||||||
|
|
@ -96,9 +96,8 @@ started contributing, you should familiarize yourself with the repository struct
|
||||||
|
|
||||||
* ``bin/``, ``build/`` - these directories are empty, but are used when Nim is built.
|
* ``bin/``, ``build/`` - these directories are empty, but are used when Nim is built.
|
||||||
* ``compiler/`` - the compiler source code. Also includes nimfix, and plugins within
|
* ``compiler/`` - the compiler source code. Also includes nimfix, and plugins within
|
||||||
``compiler/nimfix`` and ``compiler/plugins`` respectively. Nimsuggest was moved to
|
``compiler/nimfix`` and ``compiler/plugins`` respectively.
|
||||||
the [``nim-lang/nimsuggest``][nimsuggest-repo] repository, though it previously also
|
* ``nimsuggest`` - the nimsuggest tool that previously lived in the [``nim-lang/nimsuggest``][nimsuggest-repo] repository.
|
||||||
lived within the ``compiler/`` directory.
|
|
||||||
* ``config/`` - the configuration for the compiler and documentation generator.
|
* ``config/`` - the configuration for the compiler and documentation generator.
|
||||||
* ``doc/`` - the documentation files in reStructuredText format.
|
* ``doc/`` - the documentation files in reStructuredText format.
|
||||||
* ``lib/`` - the standard library, including:
|
* ``lib/`` - the standard library, including:
|
||||||
|
|
|
||||||
20
tests/arithm/tshr.nim
Normal file
20
tests/arithm/tshr.nim
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
discard """
|
||||||
|
output: ''''''
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc T() =
|
||||||
|
let VI = -8
|
||||||
|
let VI64 = -8'i64
|
||||||
|
let VI32 = -8'i32
|
||||||
|
let VI16 = -8'i16
|
||||||
|
let VI8 = -8'i8
|
||||||
|
doAssert( (VI shr 1) == 9223372036854775804)
|
||||||
|
doAssert( (VI64 shr 1) == 9223372036854775804)
|
||||||
|
doAssert( (VI32 shr 1) == 2147483644)
|
||||||
|
doAssert( (VI16 shr 1) == 32764)
|
||||||
|
doAssert( (VI8 shr 1) == 124)
|
||||||
|
|
||||||
|
|
||||||
|
T()
|
||||||
|
static:
|
||||||
|
T()
|
||||||
54
tests/async/tasyncRecvLine.nim
Normal file
54
tests/async/tasyncRecvLine.nim
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
discard """
|
||||||
|
file: "tasyncRecvLine.nim"
|
||||||
|
output: '''
|
||||||
|
Hello World
|
||||||
|
Hello World
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncdispatch, asyncnet
|
||||||
|
|
||||||
|
const recvLinePort = Port(6047)
|
||||||
|
|
||||||
|
proc setupTestServer(): AsyncSocket =
|
||||||
|
result = newAsyncSocket()
|
||||||
|
result.setSockOpt(OptReuseAddr, true)
|
||||||
|
result.bindAddr(recvLinePort)
|
||||||
|
result.listen()
|
||||||
|
|
||||||
|
proc testUnbuffered(): Future[void] {.async.} =
|
||||||
|
let serverSock = setupTestServer()
|
||||||
|
let serverAcceptClientFut = serverSock.accept()
|
||||||
|
|
||||||
|
let clientSock = newAsyncSocket(buffered = false)
|
||||||
|
let clientConnectFut = clientSock.connect("localhost", recvLinePort)
|
||||||
|
|
||||||
|
let serverAcceptedClient = await serverAcceptClientFut
|
||||||
|
await clientConnectFut
|
||||||
|
|
||||||
|
await serverAcceptedClient.send("Hello World\c\L")
|
||||||
|
|
||||||
|
echo await clientSock.recvLine()
|
||||||
|
|
||||||
|
clientSock.close()
|
||||||
|
serverSock.close()
|
||||||
|
|
||||||
|
proc testBuffered(): Future[void] {.async.} =
|
||||||
|
let serverSock = setupTestServer()
|
||||||
|
let serverAcceptClientFut = serverSock.accept()
|
||||||
|
|
||||||
|
let clientSock = newAsyncSocket(buffered = true)
|
||||||
|
let clientConnectFut = clientSock.connect("localhost", recvLinePort)
|
||||||
|
|
||||||
|
let serverAcceptedClient = await serverAcceptClientFut
|
||||||
|
await clientConnectFut
|
||||||
|
|
||||||
|
await serverAcceptedClient.send("Hello World\c\L")
|
||||||
|
|
||||||
|
echo await clientSock.recvLine()
|
||||||
|
|
||||||
|
clientSock.close()
|
||||||
|
serverSock.close()
|
||||||
|
|
||||||
|
waitFor testUnbuffered()
|
||||||
|
waitFor testBuffered()
|
||||||
|
|
@ -7,3 +7,12 @@ proc foo {.async.}
|
||||||
|
|
||||||
proc foo {.async.} =
|
proc foo {.async.} =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
# With additional pragmas:
|
||||||
|
proc bar {.async, cdecl.}
|
||||||
|
|
||||||
|
proc bar {.async.} =
|
||||||
|
discard
|
||||||
|
|
||||||
|
proc verifyCdeclPresent(p: proc : Future[void] {.cdecl.}) = discard
|
||||||
|
verifyCdeclPresent(bar)
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,19 @@ discard """
|
||||||
file: "tasyncall.nim"
|
file: "tasyncall.nim"
|
||||||
exitcode: 0
|
exitcode: 0
|
||||||
"""
|
"""
|
||||||
import times, sequtils
|
import times, sequtils, unittest
|
||||||
import asyncdispatch
|
import asyncdispatch
|
||||||
|
|
||||||
const
|
const
|
||||||
taskCount = 10
|
taskCount = 10
|
||||||
sleepDuration = 500
|
sleepDuration = 50
|
||||||
|
|
||||||
proc futureWithValue(x: int): Future[int] {.async.} =
|
proc futureWithValue(x: int): Future[int] {.async.} =
|
||||||
await sleepAsync(sleepDuration)
|
await sleepAsync(sleepDuration)
|
||||||
return x
|
return x
|
||||||
|
|
||||||
proc futureWithoutValue() {.async.} =
|
proc futureWithoutValue() {.async.} =
|
||||||
await sleepAsync(1000)
|
await sleepAsync(sleepDuration)
|
||||||
|
|
||||||
proc testFuturesWithValue(x: int): seq[int] =
|
proc testFuturesWithValue(x: int): seq[int] =
|
||||||
var tasks = newSeq[Future[int]](taskCount)
|
var tasks = newSeq[Future[int]](taskCount)
|
||||||
|
|
@ -40,7 +40,8 @@ proc testVarargs(x, y, z: int): seq[int] =
|
||||||
|
|
||||||
result = waitFor all(a, b, c)
|
result = waitFor all(a, b, c)
|
||||||
|
|
||||||
block:
|
suite "tasyncall":
|
||||||
|
test "testFuturesWithValue":
|
||||||
let
|
let
|
||||||
startTime = cpuTime()
|
startTime = cpuTime()
|
||||||
results = testFuturesWithValue(42)
|
results = testFuturesWithValue(42)
|
||||||
|
|
@ -50,14 +51,14 @@ block:
|
||||||
doAssert execTime * 1000 < taskCount * sleepDuration
|
doAssert execTime * 1000 < taskCount * sleepDuration
|
||||||
doAssert results == expected
|
doAssert results == expected
|
||||||
|
|
||||||
block:
|
test "testFuturesWithoutValues":
|
||||||
let startTime = cpuTime()
|
let startTime = cpuTime()
|
||||||
testFuturesWithoutValues()
|
testFuturesWithoutValues()
|
||||||
let execTime = cpuTime() - startTime
|
let execTime = cpuTime() - startTime
|
||||||
|
|
||||||
doAssert execTime * 1000 < taskCount * sleepDuration
|
doAssert execTime * 1000 < taskCount * sleepDuration
|
||||||
|
|
||||||
block:
|
test "testVarargs":
|
||||||
let
|
let
|
||||||
startTime = cpuTime()
|
startTime = cpuTime()
|
||||||
results = testVarargs(1, 2, 3)
|
results = testVarargs(1, 2, 3)
|
||||||
|
|
@ -67,7 +68,7 @@ block:
|
||||||
doAssert execTime * 100 < taskCount * sleepDuration
|
doAssert execTime * 100 < taskCount * sleepDuration
|
||||||
doAssert results == expected
|
doAssert results == expected
|
||||||
|
|
||||||
block:
|
test "all on seq[Future]":
|
||||||
let
|
let
|
||||||
noIntFuturesFut = all(newSeq[Future[int]]())
|
noIntFuturesFut = all(newSeq[Future[int]]())
|
||||||
noVoidFuturesFut = all(newSeq[Future[void]]())
|
noVoidFuturesFut = all(newSeq[Future[void]]())
|
||||||
|
|
|
||||||
|
|
@ -508,10 +508,14 @@ else:
|
||||||
freeAddrInfo(aiList)
|
freeAddrInfo(aiList)
|
||||||
# for some reason Windows select doesn't return both
|
# for some reason Windows select doesn't return both
|
||||||
# descriptors from first call, so we need to make 2 calls
|
# descriptors from first call, so we need to make 2 calls
|
||||||
var rcm1 = selector.select(1000)
|
var n = 0
|
||||||
var rcm2 = selector.select(1000)
|
var rcm = selector.select(1000)
|
||||||
let rcm = len(rcm1) + len(rcm2)
|
while n < 10 and len(rcm) < 2:
|
||||||
assert(rcm >= 2 and rcm <= 4)
|
sleep(1000)
|
||||||
|
rcm = selector.select(1000)
|
||||||
|
inc(n)
|
||||||
|
|
||||||
|
assert(len(rcm) == 2)
|
||||||
|
|
||||||
var sockAddress = SockAddr()
|
var sockAddress = SockAddr()
|
||||||
var addrLen = sizeof(sockAddress).Socklen
|
var addrLen = sizeof(sockAddress).Socklen
|
||||||
|
|
|
||||||
|
|
@ -51,5 +51,8 @@ proc main() =
|
||||||
|
|
||||||
var builder = newBuilder()
|
var builder = newBuilder()
|
||||||
|
|
||||||
|
# Test {.async.} pragma with do notation: #5995
|
||||||
|
builder.client = newClient("builder") do(client: Client, msg: JsonNode) {.async.}:
|
||||||
|
await onMessage(builder, msg)
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
line: 10
|
line: 10
|
||||||
errormsg: "type mismatch: got (typedesc[float], string)"
|
errormsg: "type mismatch: got (type float, string)"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc foo(T: typedesc; some: T) =
|
proc foo(T: typedesc; some: T) =
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
line: 18
|
line: 18
|
||||||
errormsg: "type mismatch: got (proc (s: TScgi) | proc (client: AsyncSocket, headers: StringTableRef, input: string){.noSideEffect, gcsafe, locks: 0.}"
|
errormsg: "type mismatch: got (proc (s: TScgi: ScgiState or AsyncScgiState) | proc (client: AsyncSocket, headers: StringTableRef, input: string){.noSideEffect, gcsafe, locks: 0.}"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#bug #442
|
#bug #442
|
||||||
|
|
|
||||||
22
tests/concepts/t3414.nim
Normal file
22
tests/concepts/t3414.nim
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
type
|
||||||
|
View[T] = concept v
|
||||||
|
v.empty is bool
|
||||||
|
v.front is T
|
||||||
|
popFront v
|
||||||
|
|
||||||
|
proc find(view: View; target: View.T): View =
|
||||||
|
result = view
|
||||||
|
|
||||||
|
while not result.empty:
|
||||||
|
if view.front == target:
|
||||||
|
return
|
||||||
|
|
||||||
|
mixin popFront
|
||||||
|
popFront result
|
||||||
|
|
||||||
|
proc popFront[T](s: var seq[T]) = discard
|
||||||
|
proc empty[T](s: seq[T]): bool = false
|
||||||
|
|
||||||
|
var s1 = @[1, 2, 3]
|
||||||
|
let s2 = s1.find(10)
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue