Merge branch 'devel' into araq
This commit is contained in:
commit
2b862b74e0
165 changed files with 4572 additions and 920 deletions
|
|
@ -224,7 +224,7 @@ type
|
|||
TNodeKinds* = set[TNodeKind]
|
||||
|
||||
type
|
||||
TSymFlag* = enum # already 32 flags!
|
||||
TSymFlag* = enum # already 33 flags!
|
||||
sfUsed, # read access of sym (for warnings) or simply used
|
||||
sfExported, # symbol is exported from module
|
||||
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
|
||||
nfPreventCg # this node should be ignored by the codegen
|
||||
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]
|
||||
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
|
||||
# tyArray type represeting a varargs list
|
||||
tfNoSideEffect, # procedure type does not allow side effects
|
||||
|
|
@ -508,6 +509,9 @@ type
|
|||
tfTriggersCompileTime # uses the NimNode type which make the proc
|
||||
# implicitly '.compiletime'
|
||||
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]
|
||||
|
||||
|
|
@ -956,7 +960,8 @@ const
|
|||
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias}
|
||||
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
|
||||
nfDotSetter, nfDotField,
|
||||
nfIsRef, nfPreventCg, nfLL}
|
||||
nfIsRef, nfPreventCg, nfLL,
|
||||
nfFromTemplate}
|
||||
namePos* = 0
|
||||
patternPos* = 1 # empty except for term rewriting macros
|
||||
genericParamsPos* = 2
|
||||
|
|
@ -1007,15 +1012,17 @@ proc add*(father, son: PNode) =
|
|||
if isNil(father.sons): father.sons = @[]
|
||||
add(father.sons, son)
|
||||
|
||||
proc `[]`*(n: PNode, i: int): PNode {.inline.} =
|
||||
result = n.sons[i]
|
||||
type Indexable = PNode | PType
|
||||
|
||||
template `[]`*(n: Indexable, i: int): Indexable =
|
||||
n.sons[i]
|
||||
|
||||
template `-|`*(b, s: untyped): untyped =
|
||||
(if b >= 0: b else: s.len + b)
|
||||
|
||||
# son access operators with support for negative indices
|
||||
template `{}`*(n: PNode, i: int): untyped = n[i -| n]
|
||||
template `{}=`*(n: PNode, i: int, s: PNode) =
|
||||
template `{}`*(n: Indexable, i: int): untyped = n[i -| n]
|
||||
template `{}=`*(n: Indexable, i: int, s: Indexable) =
|
||||
n.sons[i -| n] = s
|
||||
|
||||
when defined(useNodeIds):
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ proc rspaces(x: int): Rope =
|
|||
|
||||
proc toYamlChar(c: char): string =
|
||||
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
|
||||
else: result = $c
|
||||
|
||||
|
|
@ -407,6 +407,8 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
|
|||
var istr = rspaces(indent + 2)
|
||||
result = "{$N$1\"kind\": $2" %
|
||||
[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)])
|
||||
if maxRecDepth != 0:
|
||||
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)
|
||||
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.} =
|
||||
# returns true if n is already in the string table:
|
||||
# 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).
|
||||
# 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.
|
||||
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
|
||||
replaceSlot = h
|
||||
h = nextTry(h, high(t.data))
|
||||
|
|
|
|||
|
|
@ -78,8 +78,10 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
|
|||
[p.module.tmpBase, rope(id)])
|
||||
else:
|
||||
result = makeCString(n.strVal)
|
||||
of nkFloatLit..nkFloat64Lit:
|
||||
of nkFloatLit, nkFloat64Lit:
|
||||
result = rope(n.floatVal.toStrMaxPrecision)
|
||||
of nkFloat32Lit:
|
||||
result = rope(n.floatVal.toStrMaxPrecision("f"))
|
||||
else:
|
||||
internalError(n.info, "genLiteral(" & $n.kind & ')')
|
||||
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))", # 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)($1 & $2)", # BitandI
|
||||
"($4)($1 | $2)", # BitorI
|
||||
|
|
@ -575,16 +577,17 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
|||
"($1 != $2)"] # Xor
|
||||
var
|
||||
a, b: TLoc
|
||||
s: BiggestInt
|
||||
s, k: BiggestInt
|
||||
assert(e.sons[1].typ != nil)
|
||||
assert(e.sons[2].typ != nil)
|
||||
initLocExpr(p, e.sons[1], a)
|
||||
initLocExpr(p, e.sons[2], b)
|
||||
# BUGFIX: cannot use result-type here, as it may be a boolean
|
||||
s = max(getSize(a.t), getSize(b.t)) * 8
|
||||
k = getSize(a.t) * 8
|
||||
putIntoDest(p, d, e.typ,
|
||||
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) =
|
||||
var a, b: TLoc
|
||||
|
|
@ -654,7 +657,9 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
|
|||
d.s = OnHeap
|
||||
else:
|
||||
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:
|
||||
initLocExprSingleUse(p, e[0][0], d)
|
||||
return
|
||||
|
|
@ -2132,7 +2137,14 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
|||
if n.sons[0].kind != nkEmpty:
|
||||
genLineDir(p, n)
|
||||
var a: TLoc
|
||||
initLocExpr(p, n.sons[0], a)
|
||||
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)
|
||||
of nkAsmStmt: genAsmStmt(p, n)
|
||||
of nkTryStmt:
|
||||
if p.module.compileToCpp and optNoCppExceptions notin gGlobalOptions:
|
||||
|
|
@ -2157,8 +2169,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
|||
# are not transformed correctly. We work around this issue (#411) here
|
||||
# by ensuring it's no inner proc (owner is a module):
|
||||
if prc.skipGenericOwner.kind == skModule and sfCompileTime notin prc.flags:
|
||||
if (optDeadCodeElim notin gGlobalOptions and
|
||||
sfDeadCodeElim notin getModule(prc).flags) or
|
||||
if (not emitLazily(prc)) or
|
||||
({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
|
||||
(sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
|
||||
(prc.kind == skMethod):
|
||||
|
|
@ -2214,7 +2225,7 @@ proc getNullValueAux(p: BProc; obj, cons: PNode, result: var Rope) =
|
|||
let field = obj.sym
|
||||
for i in 1..<cons.len:
|
||||
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])
|
||||
return
|
||||
elif i == field.position:
|
||||
|
|
|
|||
|
|
@ -39,13 +39,11 @@ proc genVarTuple(p: BProc, n: PNode) =
|
|||
var L = sonsLen(n)
|
||||
|
||||
# if we have a something that's been captured, use the lowering instead:
|
||||
var useLowering = false
|
||||
for i in countup(0, L-3):
|
||||
if n[i].kind != nkSym:
|
||||
useLowering = true; break
|
||||
if useLowering:
|
||||
genStmts(p, lowerTupleUnpacking(n, p.prc))
|
||||
return
|
||||
genStmts(p, lowerTupleUnpacking(n, p.prc))
|
||||
return
|
||||
|
||||
genLineDir(p, n)
|
||||
initLocExpr(p, n.sons[L-1], tup)
|
||||
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])
|
||||
|
||||
proc genSingleVar(p: BProc, a: PNode) =
|
||||
var v = a.sons[0].sym
|
||||
if {sfCompileTime, sfGoto} * v.flags != {}:
|
||||
let v = a.sons[0].sym
|
||||
if sfCompileTime in v.flags: return
|
||||
if sfGoto in v.flags:
|
||||
# translate 'var state {.goto.} = X' into 'goto LX':
|
||||
if sfGoto in v.flags: genGotoVar(p, a.sons[2])
|
||||
genGotoVar(p, a.sons[2])
|
||||
return
|
||||
var targetProc = p
|
||||
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,
|
||||
check)
|
||||
if a != nil:
|
||||
add(unionBody, "struct {")
|
||||
if tfPacked notin rectype.flags:
|
||||
add(unionBody, "struct {")
|
||||
else:
|
||||
addf(unionBody, CC[cCompiler].structStmtFmt,
|
||||
[rope"struct", nil, rope(CC[cCompiler].packedPragma)])
|
||||
add(unionBody, "{")
|
||||
add(unionBody, a)
|
||||
addf(unionBody, "} $1;$n", [sname])
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
import
|
||||
ast, astalgo, ropes, hashes, strutils, types, msgs, wordrecg,
|
||||
platform, trees
|
||||
platform, trees, options
|
||||
|
||||
proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
|
||||
case n.kind
|
||||
|
|
@ -211,20 +211,8 @@ proc mangle*(name: string): string =
|
|||
if requiresUnderscore:
|
||||
result.add "_"
|
||||
|
||||
proc makeLLVMString*(s: string): Rope =
|
||||
const MaxLineLength = 64
|
||||
result = nil
|
||||
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))
|
||||
proc emitLazily*(s: PSym): bool {.inline.} =
|
||||
result = optDeadCodeElim in gGlobalOptions or
|
||||
sfDeadCodeElim in getModule(s).flags
|
||||
|
||||
initTypeTables()
|
||||
|
|
|
|||
|
|
@ -47,10 +47,6 @@ proc findPendingModule(m: BModule, s: PSym): BModule =
|
|||
var ms = getModule(s)
|
||||
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) =
|
||||
result.k = k
|
||||
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 =
|
||||
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,
|
||||
args: varargs[Rope]) =
|
||||
add(c, ropecg(m, frmt, args))
|
||||
|
|
@ -154,11 +157,6 @@ proc appcg(p: BProc, s: TCProcSection, frmt: FormatStr,
|
|||
args: varargs[Rope]) =
|
||||
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) =
|
||||
add(p.s(s), indentLine(p, r))
|
||||
|
||||
|
|
@ -612,8 +610,18 @@ proc generateHeaders(m: BModule) =
|
|||
addf(m.s[cfsHeaders], "#include \"$1\"$N", [rope(it)])
|
||||
else:
|
||||
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 mips" & 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 =
|
||||
discard cgsym(p.module, "nimFrame")
|
||||
|
|
@ -898,14 +906,14 @@ proc genMainProc(m: BModule) =
|
|||
# prevents inlining of the NimMainInner function and dependent
|
||||
# functions, which might otherwise merge their stack frames.
|
||||
PreMainBody =
|
||||
"void PreMainInner() {$N" &
|
||||
"void PreMainInner(void) {$N" &
|
||||
"\tsystemInit000();$N" &
|
||||
"$1" &
|
||||
"$2" &
|
||||
"$3" &
|
||||
"}$N$N" &
|
||||
"void PreMain() {$N" &
|
||||
"\tvoid (*volatile inner)();$N" &
|
||||
"void PreMain(void) {$N" &
|
||||
"\tvoid (*volatile inner)(void);$N" &
|
||||
"\tsystemDatInit000();$N" &
|
||||
"\tinner = PreMainInner;$N" &
|
||||
"$4$5" &
|
||||
|
|
@ -924,7 +932,7 @@ proc genMainProc(m: BModule) =
|
|||
|
||||
NimMainProc =
|
||||
"N_CDECL(void, NimMain)(void) {$N" &
|
||||
"\tvoid (*volatile inner)();$N" &
|
||||
"\tvoid (*volatile inner)(void);$N" &
|
||||
"\tPreMain();$N" &
|
||||
"\tinner = NimMainInner;$N" &
|
||||
"$2" &
|
||||
|
|
|
|||
|
|
@ -257,13 +257,14 @@ proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym =
|
|||
cond = a
|
||||
else:
|
||||
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))
|
||||
for col in countup(1, paramLen - 1):
|
||||
addSon(call, genConv(newSymNode(base.typ.n.sons[col].sym),
|
||||
curr.typ.sons[col], false))
|
||||
var ret: PNode
|
||||
if base.typ.sons[0] != nil:
|
||||
if retTyp != nil:
|
||||
var a = newNodeI(nkFastAsgn, base.info)
|
||||
addSon(a, newSymNode(base.ast.sons[resultPos].sym))
|
||||
addSon(a, call)
|
||||
|
|
|
|||
|
|
@ -103,3 +103,4 @@ proc initDefines*() =
|
|||
defineSymbol("nimNewShiftOps")
|
||||
defineSymbol("nimDistros")
|
||||
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
|
||||
for i in countup(0, safeLen(body) - 1):
|
||||
evalTemplateAux(body.sons[i], args, ctx, result)
|
||||
result.flags.incl nfFromTemplate
|
||||
result = wrapInComesFrom(n.info, result)
|
||||
dec(evalTemplateCounter)
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ Files: "compiler"
|
|||
Files: "doc"
|
||||
Files: "doc/html"
|
||||
Files: "tools"
|
||||
Files: "nimsuggest"
|
||||
Files: "nimsuggest/tests/*.nim"
|
||||
Files: "web/website.ini"
|
||||
Files: "web/ticker.html"
|
||||
Files: "web/*.nim"
|
||||
|
|
|
|||
|
|
@ -94,12 +94,39 @@ type
|
|||
target: TTarget # duplicated here for faster dispatching
|
||||
unique: int # for temp identifier generation
|
||||
blocks: seq[TBlock]
|
||||
extraIndent: int
|
||||
up: PProc # up the call chain; required for closure support
|
||||
declaredGlobals: IntSet
|
||||
|
||||
template `|`(a, b: untyped): untyped {.dirty.} =
|
||||
(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 =
|
||||
new(result)
|
||||
result.forwarded = @[]
|
||||
|
|
@ -129,7 +156,8 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
|
|||
module: module,
|
||||
procDef: procDef,
|
||||
g: globals,
|
||||
target: module.target)
|
||||
target: module.target,
|
||||
extraIndent: int(procDef != nil))
|
||||
if procDef != nil: result.prc = procDef.sons[namePos].sym
|
||||
if result.target == targetPHP:
|
||||
result.declaredGlobals = initIntSet()
|
||||
|
|
@ -290,7 +318,7 @@ proc getTemp(p: PProc, defineInLocals: bool = true): Rope =
|
|||
if p.target == targetJS:
|
||||
result = "Tmp$1" % [rope(p.unique)]
|
||||
if defineInLocals:
|
||||
addf(p.locals, "var $1;$n", [result])
|
||||
add(p.locals, p.indentLine("var $1;$n" % [result]))
|
||||
else:
|
||||
result = "$$Tmp$1" % [rope(p.unique)]
|
||||
|
||||
|
|
@ -315,9 +343,11 @@ proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
|
|||
# tmp = b
|
||||
# tmp
|
||||
gen(p, a, x)
|
||||
p.body.addf("if (!$1) $2 = false; else {", [x.rdLoc, r.rdLoc])
|
||||
gen(p, b, y)
|
||||
p.body.addf("$2 = $1; }", [y.rdLoc, r.rdLoc])
|
||||
lineF(p, "if (!$1) $2 = false; else {", [x.rdLoc, r.rdLoc])
|
||||
p.nested:
|
||||
gen(p, b, y)
|
||||
lineF(p, "$2 = $1;", [y.rdLoc, r.rdLoc])
|
||||
line(p, "}")
|
||||
|
||||
proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
|
||||
assert r.kind == resNone
|
||||
|
|
@ -331,9 +361,11 @@ proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
|
|||
r.res = p.getTemp
|
||||
r.kind = resVal
|
||||
gen(p, a, x)
|
||||
p.body.addf("if ($1) $2 = true; else {", [x.rdLoc, r.rdLoc])
|
||||
gen(p, b, y)
|
||||
p.body.addf("$2 = $1; }", [y.rdLoc, r.rdLoc])
|
||||
lineF(p, "if ($1) $2 = true; else {", [x.rdLoc, r.rdLoc])
|
||||
p.nested:
|
||||
gen(p, b, y)
|
||||
lineF(p, "$2 = $1;", [y.rdLoc, r.rdLoc])
|
||||
line(p, "}")
|
||||
|
||||
type
|
||||
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)"], # ToBiggestInt
|
||||
["nimCharToStr", "nimCharToStr", "nimCharToStr($1)", "nimCharToStr($1)"],
|
||||
["nimBoolToStr", "nimBoolToStr", "nimBoolToStr($1)", "nimBoolToStr($1)"], [
|
||||
"cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")",
|
||||
"cstrToNimstr(($1)+\"\")"], ["cstrToNimstr", "cstrToNimstr",
|
||||
"cstrToNimstr(($1)+\"\")",
|
||||
"cstrToNimstr(($1)+\"\")"], ["cstrToNimstr",
|
||||
"cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
|
||||
["nimBoolToStr", "nimBoolToStr", "nimBoolToStr($1)", "nimBoolToStr($1)"],
|
||||
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
|
||||
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
|
||||
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
|
||||
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr($1)", "cstrToNimstr($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.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
|
||||
x, y: TCompRes
|
||||
let i = ord(optOverflowCheck notin p.options)
|
||||
useMagic(p, ops[op][i])
|
||||
useMagic(p, jsOps[op][i])
|
||||
if sonsLen(n) > 2:
|
||||
gen(p, n.sons[1], x)
|
||||
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:
|
||||
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) =
|
||||
case op
|
||||
|
|
@ -501,7 +531,7 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
|||
gen(p, n.sons[2], y)
|
||||
r.res = "intval($1 / $2)" % [x.rdLoc, y.rdLoc]
|
||||
else:
|
||||
arithAux(p, n, r, op, jsOps)
|
||||
arithAux(p, n, r, op)
|
||||
of mModI:
|
||||
if p.target == targetPHP:
|
||||
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)
|
||||
r.res = "($1 % $2)" % [x.rdLoc, y.rdLoc]
|
||||
else:
|
||||
arithAux(p, n, r, op, jsOps)
|
||||
arithAux(p, n, r, op)
|
||||
of mShrI:
|
||||
var x, y: TCompRes
|
||||
gen(p, n.sons[1], x)
|
||||
|
|
@ -534,9 +564,9 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
|||
else:
|
||||
gen(p, n.sons[1], r)
|
||||
else:
|
||||
arithAux(p, n, r, op, jsOps)
|
||||
arithAux(p, n, r, op)
|
||||
else:
|
||||
arithAux(p, n, r, op, jsOps)
|
||||
arithAux(p, n, r, op)
|
||||
r.kind = resExpr
|
||||
|
||||
proc hasFrameInfo(p: PProc): bool =
|
||||
|
|
@ -546,14 +576,14 @@ proc hasFrameInfo(p: PProc): bool =
|
|||
proc genLineDir(p: PProc, n: PNode) =
|
||||
let line = toLinenumber(n.info)
|
||||
if optLineDir in p.options:
|
||||
addf(p.body, "// line $2 \"$1\"$n",
|
||||
lineF(p, "// line $2 \"$1\"$n",
|
||||
[rope(toFilename(n.info)), rope(line)])
|
||||
if {optStackTrace, optEndb} * p.options == {optStackTrace, optEndb} and
|
||||
((p.prc == nil) or sfPure notin p.prc.flags):
|
||||
useMagic(p, "endb")
|
||||
addf(p.body, "endb($1);$n", [rope(line)])
|
||||
lineF(p, "endb($1);$n", [rope(line)])
|
||||
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) =
|
||||
var
|
||||
|
|
@ -566,20 +596,20 @@ proc genWhileStmt(p: PProc, n: PNode) =
|
|||
p.blocks[length].id = -p.unique
|
||||
p.blocks[length].isLoop = true
|
||||
let labl = p.unique.rope
|
||||
addf(p.body, "L$1: while (true) {$n" | "while (true) {$n", [labl])
|
||||
gen(p, n.sons[0], cond)
|
||||
addf(p.body, "if (!$1) break L$2;$n" | "if (!$1) goto L$2;$n",
|
||||
lineF(p, "L$1: while (true) {$n" | "while (true) {$n", [labl])
|
||||
p.nested: gen(p, n.sons[0], cond)
|
||||
lineF(p, "if (!$1) break L$2;$n" | "if (!$1) goto L$2;$n",
|
||||
[cond.res, labl])
|
||||
genStmt(p, n.sons[1])
|
||||
addf(p.body, "}$n" | "}L$#:;$n", [labl])
|
||||
p.nested: genStmt(p, n.sons[1])
|
||||
lineF(p, "}$n" | "}L$#:;$n", [labl])
|
||||
setLen(p.blocks, length)
|
||||
|
||||
proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
|
||||
if src.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:
|
||||
p.body.addf("$1;$n", [src.rdLoc])
|
||||
lineF(p, "$1;$n", [src.rdLoc])
|
||||
src.kind = resNone
|
||||
src.res = nil
|
||||
|
||||
|
|
@ -620,8 +650,8 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
|||
var tmpFramePtr = rope"F"
|
||||
if optStackTrace notin p.options:
|
||||
tmpFramePtr = p.getTemp(true)
|
||||
add(p.body, tmpFramePtr & " = framePtr;" & tnl)
|
||||
addf(p.body, "try {$n", [])
|
||||
line(p, tmpFramePtr & " = framePtr;" & tnl)
|
||||
lineF(p, "try {$n", [])
|
||||
if p.target == targetPHP and p.globals == nil:
|
||||
p.globals = "global $lastJSError; global $prevJSError;".rope
|
||||
var a: TCompRes
|
||||
|
|
@ -632,18 +662,18 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
|||
if p.target == targetJS and catchBranchesExist:
|
||||
addf(p.body, "--excHandler;$n} catch (EXC) {$n var prevJSError = lastJSError;$n" &
|
||||
" lastJSError = EXC;$n --excHandler;$n", [])
|
||||
add(p.body, "framePtr = $1;$n" % [tmpFramePtr])
|
||||
line(p, "framePtr = $1;$n" % [tmpFramePtr])
|
||||
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:
|
||||
let blen = sonsLen(n.sons[i])
|
||||
if blen == 1:
|
||||
# general except section:
|
||||
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)
|
||||
moveInto(p, a, r)
|
||||
if i > 1: addf(p.body, "}$n", [])
|
||||
if i > 1: lineF(p, "}$n", [])
|
||||
else:
|
||||
var orExpr: Rope = nil
|
||||
useMagic(p, "isObj")
|
||||
|
|
@ -653,30 +683,32 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
|||
if orExpr != nil: add(orExpr, "||")
|
||||
addf(orExpr, "isObj($2lastJSError.m_type, $1)",
|
||||
[genTypeInfo(p, n.sons[i].sons[j].typ), dollar])
|
||||
if i > 1: add(p.body, "else ")
|
||||
addf(p.body, "if ($1lastJSError && ($2)) {$n", [dollar, orExpr])
|
||||
if i > 1: line(p, "else ")
|
||||
lineF(p, "if ($1lastJSError && ($2)) {$n", [dollar, orExpr])
|
||||
gen(p, n.sons[i].sons[blen - 1], a)
|
||||
moveInto(p, a, r)
|
||||
addf(p.body, "}$n", [])
|
||||
lineF(p, "}$n", [])
|
||||
inc(i)
|
||||
if catchBranchesExist:
|
||||
if not generalCatchBranchExists:
|
||||
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])
|
||||
if p.target == targetJS:
|
||||
add(p.body, "} finally {" & tnl)
|
||||
add(p.body, "framePtr = $1;$n" % [tmpFramePtr])
|
||||
line(p, "} finally {" & tnl)
|
||||
line(p, "framePtr = $1;$n" % [tmpFramePtr])
|
||||
if p.target == targetPHP:
|
||||
# XXX ugly hack for PHP codegen
|
||||
add(p.body, "}" & tnl)
|
||||
line(p, "}" & tnl)
|
||||
if i < length and n.sons[i].kind == nkFinally:
|
||||
genStmt(p, n.sons[i].sons[0])
|
||||
if p.target == targetPHP:
|
||||
# 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:
|
||||
add(p.body, "}" & tnl)
|
||||
line(p, "}" & tnl)
|
||||
|
||||
proc genRaiseStmt(p: PProc, n: PNode) =
|
||||
genLineDir(p, n)
|
||||
|
|
@ -685,11 +717,11 @@ proc genRaiseStmt(p: PProc, n: PNode) =
|
|||
gen(p, n.sons[0], a)
|
||||
let typ = skipTypes(n.sons[0].typ, abstractPtrs)
|
||||
useMagic(p, "raiseException")
|
||||
addf(p.body, "raiseException($1, $2);$n",
|
||||
[a.rdLoc, makeJSString(typ.sym.name.s)])
|
||||
lineF(p, "raiseException($1, $2);$n",
|
||||
[a.rdLoc, makeJSString(typ.sym.name.s)])
|
||||
else:
|
||||
useMagic(p, "reraiseException")
|
||||
add(p.body, "reraiseException();" & tnl)
|
||||
line(p, "reraiseException();" & tnl)
|
||||
|
||||
proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var
|
||||
|
|
@ -699,9 +731,9 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
|
|||
let stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString
|
||||
if stringSwitch and p.target == targetJS:
|
||||
useMagic(p, "toJSStr")
|
||||
addf(p.body, "switch (toJSStr($1)) {$n", [cond.rdLoc])
|
||||
lineF(p, "switch (toJSStr($1)) {$n", [cond.rdLoc])
|
||||
else:
|
||||
addf(p.body, "switch ($1) {$n", [cond.rdLoc])
|
||||
lineF(p, "switch ($1) {$n", [cond.rdLoc])
|
||||
if not isEmptyType(n.typ):
|
||||
r.kind = resVal
|
||||
r.res = getTemp(p)
|
||||
|
|
@ -715,27 +747,29 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
|
|||
var v = copyNode(e.sons[0])
|
||||
while v.intVal <= e.sons[1].intVal:
|
||||
gen(p, v, cond)
|
||||
addf(p.body, "case $1: ", [cond.rdLoc])
|
||||
lineF(p, "case $1:$n", [cond.rdLoc])
|
||||
inc(v.intVal)
|
||||
else:
|
||||
if stringSwitch:
|
||||
case e.kind
|
||||
of nkStrLit..nkTripleStrLit: addf(p.body, "case $1: ",
|
||||
of nkStrLit..nkTripleStrLit: lineF(p, "case $1:$n",
|
||||
[makeJSString(e.strVal, false)])
|
||||
else: internalError(e.info, "jsgen.genCaseStmt: 2")
|
||||
else:
|
||||
gen(p, e, cond)
|
||||
addf(p.body, "case $1: ", [cond.rdLoc])
|
||||
gen(p, lastSon(it), stmt)
|
||||
moveInto(p, stmt, r)
|
||||
addf(p.body, "$nbreak;$n", [])
|
||||
lineF(p, "case $1:$n", [cond.rdLoc])
|
||||
p.nested:
|
||||
gen(p, lastSon(it), stmt)
|
||||
moveInto(p, stmt, r)
|
||||
lineF(p, "break;$n", [])
|
||||
of nkElse:
|
||||
addf(p.body, "default: $n", [])
|
||||
gen(p, it.sons[0], stmt)
|
||||
moveInto(p, stmt, r)
|
||||
addf(p.body, "break;$n", [])
|
||||
lineF(p, "default: $n", [])
|
||||
p.nested:
|
||||
gen(p, it.sons[0], stmt)
|
||||
moveInto(p, stmt, r)
|
||||
lineF(p, "break;$n", [])
|
||||
else: internalError(it.info, "jsgen.genCaseStmt")
|
||||
addf(p.body, "}$n", [])
|
||||
lineF(p, "}$n", [])
|
||||
|
||||
proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
|
||||
inc(p.unique)
|
||||
|
|
@ -746,13 +780,13 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
|
|||
var sym = n.sons[0].sym
|
||||
sym.loc.k = locOther
|
||||
sym.position = idx+1
|
||||
let labl = p.unique
|
||||
lineF(p, "L$1: do {$n" | "", [labl.rope])
|
||||
setLen(p.blocks, idx + 1)
|
||||
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)
|
||||
addf(p.body, "} while(false);$n" | "$nL$#:;$n", [labl.rope])
|
||||
setLen(p.blocks, idx)
|
||||
lineF(p, "} while(false);$n" | "$nL$#:;$n", [labl.rope])
|
||||
|
||||
proc genBreakStmt(p: PProc, n: PNode) =
|
||||
var idx: int
|
||||
|
|
@ -770,19 +804,31 @@ proc genBreakStmt(p: PProc, n: PNode) =
|
|||
if idx < 0 or not p.blocks[idx].isLoop:
|
||||
internalError(n.info, "no loop to break")
|
||||
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) =
|
||||
genLineDir(p, n)
|
||||
p.body.add p.indentLine(nil)
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
case n.sons[i].kind
|
||||
of nkStrLit..nkTripleStrLit: add(p.body, n.sons[i].strVal)
|
||||
let it = n[i]
|
||||
case it.kind
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
p.body.add(it.strVal)
|
||||
of nkSym:
|
||||
let v = n.sons[i].sym
|
||||
if p.target == targetPHP and v.kind in {skVar, skLet, skTemp, skConst, skResult, skParam, skForVar}:
|
||||
add(p.body, "$")
|
||||
add(p.body, mangleName(v, p.target))
|
||||
else: internalError(n.sons[i].info, "jsgen: genAsmOrEmitStmt()")
|
||||
let v = it.sym
|
||||
# for backwards compatibility we don't deref syms here :-(
|
||||
if v.kind in {skVar, skLet, skTemp, skConst, skResult, skParam, skForVar}:
|
||||
if p.target == targetPHP: p.body.add "$"
|
||||
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) =
|
||||
var cond, stmt: TCompRes
|
||||
|
|
@ -794,18 +840,18 @@ proc genIf(p: PProc, n: PNode, r: var TCompRes) =
|
|||
let it = n.sons[i]
|
||||
if sonsLen(it) != 1:
|
||||
if i > 0:
|
||||
addf(p.body, "else {$n", [])
|
||||
lineF(p, "else {$n", [])
|
||||
inc(toClose)
|
||||
gen(p, it.sons[0], cond)
|
||||
addf(p.body, "if ($1) {$n", [cond.rdLoc])
|
||||
p.nested: gen(p, it.sons[0], cond)
|
||||
lineF(p, "if ($1) {$n", [cond.rdLoc])
|
||||
gen(p, it.sons[1], stmt)
|
||||
else:
|
||||
# else part:
|
||||
addf(p.body, "else {$n", [])
|
||||
gen(p, it.sons[0], stmt)
|
||||
lineF(p, "else {$n", [])
|
||||
p.nested: gen(p, it.sons[0], stmt)
|
||||
moveInto(p, stmt, r)
|
||||
addf(p.body, "}$n", [])
|
||||
add(p.body, repeat('}', toClose) & tnl)
|
||||
lineF(p, "}$n", [])
|
||||
line(p, repeat('}', toClose) & tnl)
|
||||
|
||||
proc generateHeader(p: PProc, typ: PType): Rope =
|
||||
result = nil
|
||||
|
|
@ -834,6 +880,16 @@ proc generateHeader(p: PProc, typ: PType): Rope =
|
|||
# add(result, name)
|
||||
# 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
|
||||
nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
|
||||
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[1], b)
|
||||
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
|
||||
|
||||
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:
|
||||
gen(p, x.sons[0], a)
|
||||
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]
|
||||
else:
|
||||
gen(p, x, a)
|
||||
|
|
@ -876,29 +932,31 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
|||
case xtyp
|
||||
of etySeq:
|
||||
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:
|
||||
useMagic(p, "nimCopy")
|
||||
addf(p.body, "$1 = nimCopy(null, $2, $3);$n",
|
||||
[a.rdLoc, b.res, genTypeInfo(p, y.typ)])
|
||||
lineF(p, "$1 = nimCopy(null, $2, $3);$n",
|
||||
[a.rdLoc, b.res, genTypeInfo(p, y.typ)])
|
||||
of etyObject:
|
||||
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:
|
||||
useMagic(p, "nimCopy")
|
||||
addf(p.body, "nimCopy($1, $2, $3);$n",
|
||||
[a.res, b.res, genTypeInfo(p, y.typ)])
|
||||
lineF(p, "nimCopy($1, $2, $3);$n",
|
||||
[a.res, b.res, genTypeInfo(p, y.typ)])
|
||||
of etyBaseIndex:
|
||||
if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
|
||||
if y.kind == nkCall:
|
||||
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:
|
||||
internalError(x.info, "genAsgn")
|
||||
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:
|
||||
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) =
|
||||
genLineDir(p, n)
|
||||
|
|
@ -906,7 +964,15 @@ proc genAsgn(p: PProc, n: PNode) =
|
|||
|
||||
proc genFastAsgn(p: PProc, n: PNode) =
|
||||
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) =
|
||||
var a, b: TCompRes
|
||||
|
|
@ -917,12 +983,13 @@ proc genSwap(p: PProc, n: PNode) =
|
|||
let tmp2 = p.getTemp(false)
|
||||
if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
|
||||
internalError(n.info, "genSwap")
|
||||
addf(p.body, "var $1 = $2; $2 = $3; $3 = $1;$n" |
|
||||
"$1 = $2; $2 = $3; $3 = $1;$n", [
|
||||
tmp, a.address, b.address])
|
||||
lineF(p, "var $1 = $2; $2 = $3; $3 = $1;$n" |
|
||||
"$1 = $2; $2 = $3; $3 = $1;$n",
|
||||
[tmp, a.address, b.address])
|
||||
tmp = tmp2
|
||||
addf(p.body, "var $1 = $2; $2 = $3; $3 = $1;" |
|
||||
"$1 = $2; $2 = $3; $3 = $1;", [tmp, a.res, b.res])
|
||||
lineF(p, "var $1 = $2; $2 = $3; $3 = $1;" |
|
||||
"$1 = $2; $2 = $3; $3 = $1;",
|
||||
[tmp, a.res, b.res])
|
||||
|
||||
proc getFieldPosition(f: PNode): int =
|
||||
case f.kind
|
||||
|
|
@ -992,15 +1059,15 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
|
|||
var typ = skipTypes(m.sons[0].typ, abstractPtrs)
|
||||
if typ.kind == tyArray: first = firstOrd(typ.sons[0])
|
||||
else: first = 0
|
||||
if optBoundsCheck in p.options and not isConstExpr(m.sons[1]):
|
||||
if optBoundsCheck in p.options:
|
||||
useMagic(p, "chckIndx")
|
||||
if p.target == targetPHP:
|
||||
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:
|
||||
r.res = "chckIndx($1, $2, strlen($3))-$2" % [b.res, rope(first), a.res]
|
||||
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:
|
||||
r.res = "($1)-$2" % [b.res, rope(first)]
|
||||
else:
|
||||
|
|
@ -1193,17 +1260,21 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
|||
r.kind = resVal
|
||||
|
||||
proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
|
||||
if mapType(p, n.sons[0].typ) == etyObject:
|
||||
gen(p, n.sons[0], r)
|
||||
let it = n.sons[0]
|
||||
let t = mapType(p, it.typ)
|
||||
if t == etyObject:
|
||||
gen(p, it, r)
|
||||
else:
|
||||
var a: TCompRes
|
||||
gen(p, n.sons[0], a)
|
||||
gen(p, it, a)
|
||||
r.kind = resExpr
|
||||
if a.typ == etyBaseIndex:
|
||||
r.res = "$1[$2]" % [a.address, a.res]
|
||||
elif n.sons[0].kind == nkCall:
|
||||
elif it.kind == nkCall:
|
||||
let tmp = p.getTemp
|
||||
r.res = "($1 = $2, $1[0])[$1[1]]" % [tmp, a.res]
|
||||
elif t == etyBaseIndex:
|
||||
r.res = "$1[0]" % [a.res]
|
||||
else:
|
||||
internalError(n.info, "genDeref")
|
||||
|
||||
|
|
@ -1217,7 +1288,7 @@ proc genArgNoParam(p: PProc, n: PNode, r: var TCompRes) =
|
|||
else:
|
||||
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
|
||||
gen(p, n, a)
|
||||
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, ", ")
|
||||
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:
|
||||
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)
|
||||
assert(typ.kind == tyProc)
|
||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
var emitted = start-1
|
||||
|
||||
for i in countup(start, sonsLen(n) - 1):
|
||||
let it = n.sons[i]
|
||||
|
|
@ -1250,9 +1328,16 @@ proc genArgs(p: PProc, n: PNode, r: var TCompRes; start=1) =
|
|||
if paramType.isNil:
|
||||
genArgNoParam(p, it, r)
|
||||
else:
|
||||
genArg(p, it, paramType.sym, r)
|
||||
genArg(p, it, paramType.sym, r, addr emitted)
|
||||
inc emitted
|
||||
hasArgs = true
|
||||
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
|
||||
|
||||
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) =
|
||||
var t = typ
|
||||
if tfFinal notin t.flags or t.sons[0] != nil:
|
||||
if objHasTypeField(t):
|
||||
if output.len > 0: output.add(", ")
|
||||
addf(output, "m_type: $1" | "'m_type' => $#", [genTypeInfo(p, t)])
|
||||
while t != nil:
|
||||
|
|
@ -1483,10 +1568,10 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
|||
s: Rope
|
||||
if n.kind == nkEmpty:
|
||||
let mname = mangleName(v, p.target)
|
||||
addf(p.body, "var $1 = $2;$n" | "$$$1 = $2;$n",
|
||||
[mname, createVar(p, v.typ, isIndirect(v))])
|
||||
lineF(p, "var $1 = $2;$n" | "$$$1 = $2;$n",
|
||||
[mname, createVar(p, v.typ, isIndirect(v))])
|
||||
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:
|
||||
discard mangleName(v, p.target)
|
||||
gen(p, n, a)
|
||||
|
|
@ -1501,25 +1586,25 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
|||
let targetBaseIndex = {sfAddrTaken, sfGlobal} * v.flags == {}
|
||||
if a.typ == etyBaseIndex:
|
||||
if targetBaseIndex:
|
||||
addf(p.body, "var $1 = $2, $1_Idx = $3;$n", [
|
||||
v.loc.r, a.address, a.res])
|
||||
lineF(p, "var $1 = $2, $1_Idx = $3;$n",
|
||||
[v.loc.r, a.address, a.res])
|
||||
else:
|
||||
addf(p.body, "var $1 = [$2, $3];$n",
|
||||
[v.loc.r, a.address, a.res])
|
||||
lineF(p, "var $1 = [$2, $3];$n",
|
||||
[v.loc.r, a.address, a.res])
|
||||
else:
|
||||
if targetBaseIndex:
|
||||
let tmp = p.getTemp
|
||||
addf(p.body, "var $1 = $2, $3 = $1[0], $3_Idx = $1[1];$n",
|
||||
[tmp, a.res, v.loc.r])
|
||||
lineF(p, "var $1 = $2, $3 = $1[0], $3_Idx = $1[1];$n",
|
||||
[tmp, a.res, v.loc.r])
|
||||
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
|
||||
else:
|
||||
s = a.res
|
||||
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:
|
||||
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) =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
|
|
@ -1550,17 +1635,17 @@ proc genNew(p: PProc, n: PNode) =
|
|||
gen(p, n.sons[1], a)
|
||||
var t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
|
||||
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:
|
||||
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) =
|
||||
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]
|
||||
addf(p.body, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}" |
|
||||
"$1 = array(); for ($$i=0;$$i<$2;++$$i) {$1[]=$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;}", [
|
||||
x.rdLoc, y.rdLoc, createVar(p, t, false)])
|
||||
|
||||
proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
|
||||
|
|
@ -1716,8 +1801,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
|||
binaryExpr(p, n, r, "addChar",
|
||||
"if ($1 != null) { addChar($1, $2); } else { $1 = [$2, 0]; }")
|
||||
else:
|
||||
binaryExpr(p, n, r, "",
|
||||
"$1 .= chr($2)")
|
||||
binaryExpr(p, n, r, "", "$1 .= chr($2)")
|
||||
of mAppendStrStr:
|
||||
if p.target == targetJS:
|
||||
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;}")
|
||||
# XXX: make a copy of $2, because of Javascript's sucking semantics
|
||||
else:
|
||||
binaryExpr(p, n, r, "",
|
||||
"$1 .= $2;")
|
||||
binaryExpr(p, n, r, "", "$1 .= $2;")
|
||||
of mAppendSeqElem:
|
||||
if p.target == targetJS:
|
||||
binaryExpr(p, n, r, "",
|
||||
"if ($1 != null) { $1.push($2); } else { $1 = [$2]; }")
|
||||
var x, y: TCompRes
|
||||
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:
|
||||
useMagic(p, "nimCopy")
|
||||
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")
|
||||
binaryExpr(p, n, r, "", "$1[] = $2")
|
||||
of mConStrStr:
|
||||
if p.target == targetJS:
|
||||
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)")
|
||||
of mSetLengthStr:
|
||||
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 mLtSet: binaryExpr(p, n, r, "SetLt", "SetLt($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, ", ")
|
||||
var it = n.sons[i]
|
||||
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
|
||||
if f.loc.r == nil: f.loc.r = mangleName(f, p.target)
|
||||
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])
|
||||
let t = skipTypes(n.typ, abstractInst + skipPtrs)
|
||||
createObjInitList(p, t, fieldIDs, initList)
|
||||
|
|
@ -1986,15 +2094,18 @@ proc genReturnStmt(p: PProc, n: PNode) =
|
|||
genStmt(p, n.sons[0])
|
||||
else:
|
||||
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 =
|
||||
result = (("var F={procname:$1,prev:framePtr,filename:$2,line:0};$nframePtr = F;$n" |
|
||||
"global $$framePtr; $$F=array('procname'=>$#,'prev'=>$$framePtr,'filename'=>$#,'line'=>0);$n$$framePtr = &$$F;$n")) % [
|
||||
procname, filename]
|
||||
let frameFmt =
|
||||
"var F={procname:$1,prev:framePtr,filename:$2,line:0};$n" |
|
||||
"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 =
|
||||
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 =
|
||||
if hasFrameInfo(p):
|
||||
|
|
@ -2004,8 +2115,12 @@ proc genProcBody(p: PProc, prc: PSym): Rope =
|
|||
else:
|
||||
result = nil
|
||||
if p.beforeRetNeeded:
|
||||
addf(result, "BeforeRet: do {$n$1} while (false); $n" |
|
||||
"$# BeforeRet:;$n", [p.body])
|
||||
if p.target == targetJS:
|
||||
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:
|
||||
add(result, p.body)
|
||||
if prc.typ.callConv == ccSysCall and p.target == targetJS:
|
||||
|
|
@ -2014,6 +2129,12 @@ proc genProcBody(p: PProc, prc: PSym): Rope =
|
|||
if hasFrameInfo(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 =
|
||||
var
|
||||
resultSym: PSym
|
||||
|
|
@ -2029,29 +2150,37 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
|
|||
if prc.typ.sons[0] != nil and sfPure notin prc.flags:
|
||||
resultSym = prc.ast.sons[resultPos].sym
|
||||
let mname = mangleName(resultSym, p.target)
|
||||
resultAsgn = ("var $# = $#;$n" | "$$$# = $#;$n") % [
|
||||
mname,
|
||||
createVar(p, resultSym.typ, isIndirect(resultSym))]
|
||||
let resVar = createVar(p, resultSym.typ, isIndirect(resultSym))
|
||||
resultAsgn = p.indentLine(("var $# = $#;$n" | "$$$# = $#;$n") % [mname, resVar])
|
||||
if resultSym.typ.kind in { tyVar, tyPtr, tyRef } and mapType(p, resultSym.typ) == etyBaseIndex:
|
||||
resultAsgn.add "var $#_Idx = 0;$n" % [
|
||||
mname ];
|
||||
resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname])
|
||||
gen(p, prc.ast.sons[resultPos], a)
|
||||
if mapType(p, resultSym.typ) == etyBaseIndex:
|
||||
returnStmt = "return [$#, $#];$n" % [a.address, a.res]
|
||||
else:
|
||||
returnStmt = "return $#;$n" % [a.res]
|
||||
genStmt(p, prc.getBody)
|
||||
|
||||
result = "function $#($#) {$n$#$n$#$#$#$#}$n" %
|
||||
[name, header, p.globals, p.locals, resultAsgn,
|
||||
genProcBody(p, prc), returnStmt]
|
||||
p.nested: genStmt(p, prc.getBody)
|
||||
let def = "function $#($#) {$n$#$#$#$#$#" %
|
||||
[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:
|
||||
# echo "END generated code for: " & prc.name.s
|
||||
|
||||
proc genStmt(p: PProc, n: PNode) =
|
||||
var r: TCompRes
|
||||
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) =
|
||||
for it in n.sons:
|
||||
|
|
@ -2211,7 +2340,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
|||
of nkPragma: genPragma(p, n)
|
||||
of nkProcDef, nkMethodDef, nkConverterDef:
|
||||
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)
|
||||
r.res = nil
|
||||
of nkGotoState, nkState:
|
||||
|
|
@ -2342,3 +2471,4 @@ proc myOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext =
|
|||
result = r
|
||||
|
||||
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]
|
||||
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) =
|
||||
let kind = if objHasTypeField(typ): tyObject else: tyTuple
|
||||
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)
|
||||
addf(p.g.typeInfo, "var NNI$1 = $2;$n",
|
||||
[rope(typ.id), genObjectFields(p, typ, typ.n)])
|
||||
|
|
|
|||
|
|
@ -386,11 +386,11 @@ proc getNumber(L: var TLexer, result: var TToken) =
|
|||
else:
|
||||
matchUnderscoreChars(L, result, {'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, '.')
|
||||
matchUnderscoreChars(L, result, {'0'..'9'})
|
||||
if L.buf[L.bufpos] in {'e', 'E'}:
|
||||
result.tokType = tkFloat64Lit
|
||||
result.tokType = tkFloatLit
|
||||
eatChar(L, result, 'e')
|
||||
if L.buf[L.bufpos] in {'+', '-'}:
|
||||
eatChar(L, result)
|
||||
|
|
@ -516,7 +516,8 @@ proc getNumber(L: var TLexer, result: var TToken) =
|
|||
result.fNumber = (cast[PFloat32](addr(xi)))[]
|
||||
# note: this code is endian neutral!
|
||||
# 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")
|
||||
|
||||
# Bounds checks. Non decimal literals are allowed to overflow the range of
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ type
|
|||
errGenericLambdaNotAllowed,
|
||||
errProcHasNoConcreteType,
|
||||
errCompilerDoesntSupportTarget,
|
||||
errInOutFlagNotExtern,
|
||||
errUser,
|
||||
warnCannotOpenFile,
|
||||
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
|
||||
|
|
@ -380,6 +381,7 @@ const
|
|||
"of the generic paramers can be inferred from the expected signature.",
|
||||
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",
|
||||
errInOutFlagNotExtern: "The `$1` modifier can be used only with imported types",
|
||||
errUser: "$1",
|
||||
warnCannotOpenFile: "cannot open \'$1\'",
|
||||
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",
|
||||
|
|
@ -541,7 +543,7 @@ var
|
|||
|
||||
proc toCChar*(c: char): string =
|
||||
case c
|
||||
of '\0'..'\x1F', '\x80'..'\xFF': result = '\\' & toOctal(c)
|
||||
of '\0'..'\x1F', '\x7F'..'\xFF': result = '\\' & toOctal(c)
|
||||
of '\'', '\"', '\\', '?': result = '\\' & c
|
||||
else: result = $(c)
|
||||
|
||||
|
|
|
|||
|
|
@ -187,6 +187,9 @@ var
|
|||
|
||||
const oKeepVariableNames* = true
|
||||
|
||||
template compilingLib*: bool =
|
||||
gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}
|
||||
|
||||
proc mainCommandArg*: string =
|
||||
## This is intended for commands like check or parse
|
||||
## which will work on the main project file unless
|
||||
|
|
|
|||
|
|
@ -39,6 +39,9 @@ type
|
|||
inPragma*: int # Pragma level
|
||||
inSemiStmtList*: int
|
||||
|
||||
SymbolMode = enum
|
||||
smNormal, smAllowNil, smAfterDot
|
||||
|
||||
proc parseAll*(p: var TParser): PNode
|
||||
proc closeParser*(p: var TParser)
|
||||
proc parseTopLevelStmt*(p: var TParser): PNode
|
||||
|
|
@ -62,7 +65,7 @@ proc optPar*(p: var TParser)
|
|||
proc optInd*(p: var TParser, n: PNode)
|
||||
proc indAndComment*(p: var TParser, n: PNode)
|
||||
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 parseCase(p: var TParser): PNode
|
||||
proc parseStmtPragma(p: var TParser): PNode
|
||||
|
|
@ -304,13 +307,24 @@ proc colcom(p: var TParser, n: PNode) =
|
|||
eat(p, tkColon)
|
||||
skipComment(p, n)
|
||||
|
||||
proc parseSymbol(p: var TParser, allowNil = false): PNode =
|
||||
proc parseSymbol(p: var TParser, mode = smNormal): PNode =
|
||||
#| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
|
||||
#| | IDENT | 'addr' | 'type'
|
||||
#| | IDENT | KEYW
|
||||
case p.tok.tokType
|
||||
of tkSymbol, tkAddr, tkType:
|
||||
of tkSymbol:
|
||||
result = newIdentNodeP(p.tok.ident, 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:
|
||||
result = newNodeP(nkAccQuoted, p)
|
||||
getTok(p)
|
||||
|
|
@ -336,16 +350,12 @@ proc parseSymbol(p: var TParser, allowNil = false): PNode =
|
|||
break
|
||||
eat(p, tkAccent)
|
||||
else:
|
||||
if allowNil and p.tok.tokType == tkNil:
|
||||
result = newNodeP(nkNilLit, p)
|
||||
getTok(p)
|
||||
else:
|
||||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
# BUGFIX: We must consume a token here to prevent endless loops!
|
||||
# But: this really sucks for idetools and keywords, so we don't do it
|
||||
# if it is a keyword:
|
||||
#if not isKeyword(p.tok.tokType): getTok(p)
|
||||
result = ast.emptyNode
|
||||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
# BUGFIX: We must consume a token here to prevent endless loops!
|
||||
# But: this really sucks for idetools and keywords, so we don't do it
|
||||
# if it is a keyword:
|
||||
#if not isKeyword(p.tok.tokType): getTok(p)
|
||||
result = ast.emptyNode
|
||||
|
||||
proc colonOrEquals(p: var TParser, a: PNode): PNode =
|
||||
if p.tok.tokType == tkColon:
|
||||
|
|
@ -390,7 +400,7 @@ proc dotExpr(p: var TParser, a: PNode): PNode =
|
|||
result = newNodeI(nkDotExpr, info)
|
||||
optInd(p, result)
|
||||
addSon(result, a)
|
||||
addSon(result, parseSymbol(p))
|
||||
addSon(result, parseSymbol(p, smAfterDot))
|
||||
|
||||
proc qualifiedIdent(p: var TParser): PNode =
|
||||
#| qualifiedIdent = symbol ('.' optInd symbol)?
|
||||
|
|
@ -846,6 +856,7 @@ type
|
|||
TDeclaredIdentFlag = enum
|
||||
withPragma, # identifier may have pragma
|
||||
withBothOptional # both ':' and '=' parts are optional
|
||||
withDot # allow 'var ident.ident = value'
|
||||
TDeclaredIdentFlags = set[TDeclaredIdentFlag]
|
||||
|
||||
proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
|
||||
|
|
@ -859,7 +870,7 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
|
|||
while true:
|
||||
case p.tok.tokType
|
||||
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)
|
||||
if a.kind == nkEmpty: return
|
||||
else: break
|
||||
|
|
@ -1004,10 +1015,10 @@ proc isExprStart(p: TParser): bool =
|
|||
result = true
|
||||
else: result = false
|
||||
|
||||
proc parseSymbolList(p: var TParser, result: PNode, allowNil = false) =
|
||||
proc parseSymbolList(p: var TParser, result: PNode) =
|
||||
# progress guaranteed
|
||||
while true:
|
||||
var s = parseSymbol(p, allowNil)
|
||||
var s = parseSymbol(p, smAllowNil)
|
||||
if s.kind == nkEmpty: break
|
||||
addSon(result, s)
|
||||
if p.tok.tokType != tkComma: break
|
||||
|
|
@ -1028,7 +1039,7 @@ proc parseTypeDescKAux(p: var TParser, kind: TNodeKind,
|
|||
getTok(p)
|
||||
let list = newNodeP(nodeKind, p)
|
||||
result.addSon list
|
||||
parseSymbolList(p, list, allowNil = true)
|
||||
parseSymbolList(p, list)
|
||||
|
||||
proc parseExpr(p: var TParser): PNode =
|
||||
#| expr = (ifExpr
|
||||
|
|
@ -1520,6 +1531,13 @@ proc parseGenericParam(p: var TParser): PNode =
|
|||
# progress guaranteed
|
||||
while true:
|
||||
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:
|
||||
a = parseSymbol(p)
|
||||
if a.kind == nkEmpty: return
|
||||
|
|
@ -1548,7 +1566,7 @@ proc parseGenericParamList(p: var TParser): PNode =
|
|||
getTok(p)
|
||||
optInd(p, result)
|
||||
# progress guaranteed
|
||||
while p.tok.tokType in {tkSymbol, tkAccent}:
|
||||
while p.tok.tokType in {tkSymbol, tkAccent, tkIn, tkOut}:
|
||||
var a = parseGenericParam(p)
|
||||
addSon(result, a)
|
||||
if p.tok.tokType notin {tkComma, tkSemiColon}: break
|
||||
|
|
@ -1882,7 +1900,7 @@ proc parseVarTuple(p: var TParser): PNode =
|
|||
optInd(p, result)
|
||||
# progress guaranteed
|
||||
while p.tok.tokType in {tkSymbol, tkAccent}:
|
||||
var a = identWithPragma(p)
|
||||
var a = identWithPragma(p, allowDot=true)
|
||||
addSon(result, a)
|
||||
if p.tok.tokType != tkComma: break
|
||||
getTok(p)
|
||||
|
|
@ -1898,7 +1916,7 @@ proc parseVariable(p: var TParser): PNode =
|
|||
#| colonBody = colcom stmt doBlocks?
|
||||
#| variable = (varTuple / identColonEquals) colonBody? indAndComment
|
||||
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})
|
||||
indAndComment(p, result)
|
||||
|
||||
|
|
|
|||
|
|
@ -1336,6 +1336,11 @@ proc parseGenericParam(p: var TParser): PNode =
|
|||
result = newNodeP(nkIdentDefs, p)
|
||||
while true:
|
||||
case p.tok.tokType
|
||||
of tkIn, tkOut:
|
||||
let t = p.tok.tokType
|
||||
getTok(p)
|
||||
expectIdent(p)
|
||||
a = parseSymbol(p)
|
||||
of tkSymbol, tkAccent:
|
||||
a = parseSymbol(p)
|
||||
if a.kind == nkEmpty: return
|
||||
|
|
|
|||
|
|
@ -125,8 +125,9 @@ proc processImportCpp(s: PSym, extname: string, info: TLineInfo) =
|
|||
incl(s.flags, sfImportc)
|
||||
incl(s.flags, sfInfixCall)
|
||||
excl(s.flags, sfForward)
|
||||
let m = s.getModule()
|
||||
incl(m.flags, sfCompileToCpp)
|
||||
if gCmd == cmdCompileToC:
|
||||
let m = s.getModule()
|
||||
incl(m.flags, sfCompileToCpp)
|
||||
extccomp.gMixedMode = true
|
||||
|
||||
proc processImportObjC(s: PSym, extname: string, info: TLineInfo) =
|
||||
|
|
|
|||
|
|
@ -12,17 +12,17 @@ import strutils
|
|||
|
||||
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:
|
||||
result = "NAN"
|
||||
elif f == 0.0:
|
||||
result = "0.0"
|
||||
result = "0.0" & literalPostfix
|
||||
elif f == 0.5 * f:
|
||||
if f > 0.0: result = "INF"
|
||||
else: result = "-INF"
|
||||
else:
|
||||
var buf: array[0..80, char]
|
||||
c_sprintf(buf, "%#.16e", f)
|
||||
c_sprintf(buf, "%#.16e" & literalPostfix, f)
|
||||
result = $buf
|
||||
|
||||
proc encodeStr*(s: string, result: var string) =
|
||||
|
|
|
|||
|
|
@ -442,6 +442,7 @@ proc semConstBoolExpr(c: PContext, n: PNode): PNode =
|
|||
result = nn
|
||||
|
||||
proc semGenericStmt(c: PContext, n: PNode): PNode
|
||||
proc semConceptBody(c: PContext, n: PNode): PNode
|
||||
|
||||
include semtypes, semtempl, semgnrc, semstmts, semexprs
|
||||
|
||||
|
|
|
|||
|
|
@ -408,7 +408,13 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
|
|||
else:
|
||||
# get rid of the deref again for a better error message:
|
||||
n.sons[1] = n.sons[1].sons[0]
|
||||
notFoundError(c, n, errors)
|
||||
#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)
|
||||
else:
|
||||
if efExplain notin flags:
|
||||
# repeat the overload resolution,
|
||||
|
|
@ -429,7 +435,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
|
|||
for i in 1..sonsLen(n)-1:
|
||||
let formal = s.ast.sons[genericParamsPos].sons[i-1].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
|
||||
var newInst = generateInstance(c, s, m.bindings, n.info)
|
||||
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 =
|
||||
assert n.kind == nkBracketExpr
|
||||
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 a = n.sons[0]
|
||||
if a.kind == nkSym:
|
||||
|
|
|
|||
|
|
@ -40,6 +40,11 @@ type
|
|||
bracketExpr*: PNode # current bracket expression (for ^ support)
|
||||
mapping*: TIdTable
|
||||
|
||||
TMatchedConcept* = object
|
||||
candidateType*: PType
|
||||
prev*: ptr TMatchedConcept
|
||||
depth*: int
|
||||
|
||||
TInstantiationPair* = object
|
||||
genericSym*: PSym
|
||||
inst*: PInstantiation
|
||||
|
|
@ -75,6 +80,7 @@ type
|
|||
importTable*: PScope # scope for all imported symbols
|
||||
topLevelScope*: PScope # scope for all top-level symbols
|
||||
p*: PProcCon # procedure context
|
||||
matchedConcept*: ptr TMatchedConcept # the current concept being matched
|
||||
friendModules*: seq[PSym] # friend modules; may access private data;
|
||||
# this is used so that generic instantiations
|
||||
# can access private object fields
|
||||
|
|
@ -82,7 +88,6 @@ type
|
|||
|
||||
ambiguousSymbols*: IntSet # ids of all ambiguous symbols (cannot
|
||||
# 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
|
||||
inUnrolledContext*: int # > 0 if we are unrolling a loop
|
||||
compilesContextId*: int # > 0 if we are in a ``compiles`` magic
|
||||
|
|
@ -277,6 +282,10 @@ proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
|
|||
assert n != nil
|
||||
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,
|
||||
sons: seq[PType]): PType =
|
||||
result = newType(kind, getCurrOwner(c))
|
||||
|
|
|
|||
|
|
@ -106,7 +106,10 @@ proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus =
|
|||
result = convNotNeedeed
|
||||
return
|
||||
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
|
||||
while (d != nil) and (d.kind in {tyPtr, tyRef}) and (d.kind == s.kind):
|
||||
d = d.lastSon
|
||||
|
|
@ -152,6 +155,8 @@ proc isCastable(dst, src: PType): bool =
|
|||
result = false
|
||||
elif typeAllowed(dst, skParam) != nil:
|
||||
result = false
|
||||
elif dst.kind == tyProc and dst.callConv == ccClosure:
|
||||
result = src.kind == tyProc and src.callConv == ccClosure
|
||||
else:
|
||||
result = (dstSize >= srcSize) or
|
||||
(skipTypes(dst, abstractInst).kind in IntegralTypes) or
|
||||
|
|
@ -227,7 +232,10 @@ proc semCast(c: PContext, n: PNode): PNode =
|
|||
if tfHasMeta in targetType.flags:
|
||||
localError(n.sons[0].info, errCastToANonConcreteType, $targetType)
|
||||
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.typ = targetType
|
||||
addSon(result, copyTree(n.sons[0]))
|
||||
|
|
@ -683,27 +691,9 @@ proc bracketedMacro(n: PNode): PSym =
|
|||
if result.kind notin {skMacro, skTemplate}:
|
||||
result = nil
|
||||
|
||||
proc semBracketedMacro(c: PContext; outer, inner: PNode; s: PSym;
|
||||
flags: TExprFlags): PNode =
|
||||
# We received untransformed bracket expression coming from macroOrTmpl[].
|
||||
# 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 setGenericParams(c: PContext, n: PNode) =
|
||||
for i in 1 .. <n.len:
|
||||
n[i].typ = semTypeNode(c, n[i], nil)
|
||||
|
||||
proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
|
||||
result = n
|
||||
|
|
@ -718,7 +708,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
|
|||
analyseIfAddressTakenInCall(c, result)
|
||||
if callee.magic != mNone:
|
||||
result = magicsAfterOverloadResolution(c, result, flags)
|
||||
if c.inTypeClass == 0:
|
||||
if c.matchedConcept == nil:
|
||||
result = evalAtCompileTime(c, result)
|
||||
|
||||
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:
|
||||
let s = bracketedMacro(n.sons[0])
|
||||
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
|
||||
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
|
||||
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
|
||||
tyTypeParamsHolders = {tyGenericInst, tyCompositeTypeClass}
|
||||
tyDotOpTransparent = {tyVar, tyPtr, tyRef, tyAlias}
|
||||
|
|
@ -937,7 +914,7 @@ proc readTypeParameter(c: PContext, typ: PType,
|
|||
|
||||
else:
|
||||
discard
|
||||
|
||||
|
||||
if typ.kind != tyUserTypeClass:
|
||||
let ty = if typ.kind == tyCompositeTypeClass: typ.sons[1].skipGenericAlias
|
||||
else: typ.skipGenericAlias
|
||||
|
|
@ -997,7 +974,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
|||
of skParam:
|
||||
markUsed(n.info, s, c.graph.usageSym)
|
||||
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 ...
|
||||
return s.typ.n
|
||||
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":
|
||||
ty = n.sons[0].typ
|
||||
return nil
|
||||
ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef, tyAlias})
|
||||
if ty.kind in tyUserTypeClasses and ty.isResolvedUserTypeClass:
|
||||
ty = ty.lastSon
|
||||
ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef, tyAlias})
|
||||
while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct})
|
||||
var check: PNode = nil
|
||||
if ty.kind == tyObject:
|
||||
|
|
@ -2164,10 +2141,6 @@ proc shouldBeBracketExpr(n: PNode): bool =
|
|||
n.sons[0] = be
|
||||
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 =
|
||||
result = 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}
|
||||
else: {checkUndeclared, checkModule, checkAmbiguity}
|
||||
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)
|
||||
if s.kind in {skProc, skMethod, skConverter, skIterator}:
|
||||
#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)
|
||||
of nkUInt64Lit:
|
||||
if result.typ == nil: result.typ = getSysType(tyUInt64)
|
||||
of nkFloatLit:
|
||||
if result.typ == nil: result.typ = getFloatLitType(result)
|
||||
#of nkFloatLit:
|
||||
# if result.typ == nil: result.typ = getFloatLitType(result)
|
||||
of nkFloat32Lit:
|
||||
if result.typ == nil: result.typ = getSysType(tyFloat32)
|
||||
of nkFloat64Lit:
|
||||
of nkFloat64Lit, nkFloatLit:
|
||||
if result.typ == nil: result.typ = getSysType(tyFloat64)
|
||||
of nkFloat128Lit:
|
||||
if result.typ == nil: result.typ = getSysType(tyFloat128)
|
||||
|
|
@ -2306,14 +2279,14 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
pragma = n[1]
|
||||
pragmaName = considerQuotedIdent(pragma[0])
|
||||
flags = flags
|
||||
|
||||
|
||||
case whichKeyword(pragmaName)
|
||||
of wExplain:
|
||||
flags.incl efExplain
|
||||
else:
|
||||
# what other pragmas are allowed for expressions? `likely`, `unlikely`
|
||||
invalidPragma(n)
|
||||
|
||||
|
||||
result = semExpr(c, n[0], flags)
|
||||
of nkPar:
|
||||
case checkPar(n)
|
||||
|
|
|
|||
|
|
@ -594,8 +594,11 @@ proc foldConStrStr(m: PSym, n: PNode): PNode =
|
|||
|
||||
proc newSymNodeTypeDesc*(s: PSym; info: TLineInfo): PNode =
|
||||
result = newSymNode(s, info)
|
||||
result.typ = newType(tyTypeDesc, s.owner)
|
||||
result.typ.addSonSkipIntLit(s.typ)
|
||||
if s.typ.kind != tyTypeDesc:
|
||||
result.typ = newType(tyTypeDesc, s.owner)
|
||||
result.typ.addSonSkipIntLit(s.typ)
|
||||
else:
|
||||
result.typ = s.typ
|
||||
|
||||
proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||
result = nil
|
||||
|
|
@ -634,9 +637,11 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
|||
result = newSymNodeTypeDesc(s, n.info)
|
||||
of skGenericParam:
|
||||
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.sons[0]
|
||||
result.typ = s.typ.base
|
||||
elif s.typ.isIntLit:
|
||||
result = s.typ.n
|
||||
else:
|
||||
result = newSymNodeTypeDesc(s, n.info)
|
||||
else: discard
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ type
|
|||
|
||||
type
|
||||
TSemGenericFlag = enum
|
||||
withinBind, withinTypeDesc, withinMixin
|
||||
withinBind, withinTypeDesc, withinMixin, withinConcept
|
||||
TSemGenericFlags = set[TSemGenericFlag]
|
||||
|
||||
proc semGenericStmt(c: PContext, n: PNode,
|
||||
|
|
@ -200,12 +200,13 @@ proc semGenericStmt(c: PContext, n: PNode,
|
|||
checkMinSonsLen(n, 1)
|
||||
let fn = n.sons[0]
|
||||
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
|
||||
considerQuotedIdent(fn).id notin ctx.toMixin:
|
||||
errorUndeclaredIdentifier(c, n.info, fn.renderTree)
|
||||
|
||||
var first = 0
|
||||
var first = ord(withinConcept in flags)
|
||||
var mixinContext = false
|
||||
if s != nil:
|
||||
incl(s.flags, sfUsed)
|
||||
|
|
@ -471,3 +472,9 @@ proc semGenericStmt(c: PContext, n: PNode): PNode =
|
|||
ctx.toMixin = initIntset()
|
||||
result = semGenericStmt(c, n, {}, ctx)
|
||||
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:
|
||||
for i in 0..a.concreteTypes.high:
|
||||
if not compareTypes(a.concreteTypes[i], b.concreteTypes[i],
|
||||
flags = {ExactTypeDescValues}): return
|
||||
flags = {ExactTypeDescValues,
|
||||
ExactGcSafety}): return
|
||||
result = true
|
||||
|
||||
proc genericCacheGet(genericSym: PSym, entry: TInstantiation;
|
||||
|
|
@ -173,10 +174,14 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
|
|||
|
||||
proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
|
||||
allowMetaTypes = false): PType =
|
||||
var cl: TReplTypeVars
|
||||
var
|
||||
typeMap: LayeredIdTable
|
||||
cl: TReplTypeVars
|
||||
|
||||
initIdTable(cl.symMap)
|
||||
initIdTable(cl.typeMap)
|
||||
initIdTable(cl.localCache)
|
||||
initIdTable(typeMap.topLayer)
|
||||
cl.typeMap = addr(typeMap)
|
||||
cl.info = info
|
||||
cl.c = c
|
||||
cl.allowMetaTypes = allowMetaTypes
|
||||
|
|
@ -200,7 +205,8 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
|
|||
#addDecl(c, prc)
|
||||
|
||||
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)
|
||||
let originalParams = result.n
|
||||
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
|
||||
# we set the friend module:
|
||||
c.friendModules.add(getModule(fn))
|
||||
let oldInTypeClass = c.inTypeClass
|
||||
c.inTypeClass = 0
|
||||
let oldMatchedConcept = c.matchedConcept
|
||||
c.matchedConcept = nil
|
||||
let oldScope = c.currentScope
|
||||
while not isTopLevel(c): c.currentScope = c.currentScope.parent
|
||||
result = copySym(fn, false)
|
||||
|
|
@ -318,5 +324,5 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
|||
c.currentScope = oldScope
|
||||
discard c.friendModules.pop()
|
||||
dec(c.instCounter)
|
||||
c.inTypeClass = oldInTypeClass
|
||||
c.matchedConcept = oldMatchedConcept
|
||||
if result.kind == skMethod: finishMethod(c, result)
|
||||
|
|
|
|||
|
|
@ -89,9 +89,9 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
|
|||
proc toNode(t: PType, i: TLineInfo): PNode =
|
||||
result = newNodeIT(nkType, i, t)
|
||||
|
||||
const
|
||||
const
|
||||
# these are types that use the bracket syntax for instantiation
|
||||
# they can be subjected to the type traits `genericHead` and
|
||||
# they can be subjected to the type traits `genericHead` and
|
||||
# `Uninstantiated`
|
||||
tyUserDefinedGenerics* = {tyGenericInst, tyGenericInvocation,
|
||||
tyUserTypeClassInst}
|
||||
|
|
@ -109,27 +109,43 @@ proc uninstantiate(t: PType): PType =
|
|||
of tyCompositeTypeClass: uninstantiate t.sons[1]
|
||||
else: t
|
||||
|
||||
proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
|
||||
var typ = operand.skipTypes({tyTypeDesc})
|
||||
proc evalTypeTrait(traitCall: PNode, operand: PType, context: PSym): PNode =
|
||||
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
|
||||
of "or", "|":
|
||||
return typeWithSonsResult(tyOr, @[operand, operand2])
|
||||
of "and":
|
||||
return typeWithSonsResult(tyAnd, @[operand, operand2])
|
||||
of "not":
|
||||
return typeWithSonsResult(tyNot, @[operand])
|
||||
of "name":
|
||||
result = newStrNode(nkStrLit, typ.typeToString(preferName))
|
||||
result = newStrNode(nkStrLit, operand.typeToString(preferName))
|
||||
result.typ = newType(tyString, context)
|
||||
result.info = trait.info
|
||||
result.info = traitCall.info
|
||||
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.info = trait.info
|
||||
result.info = traitCall.info
|
||||
of "genericHead":
|
||||
var res = uninstantiate(typ)
|
||||
if res == typ and res.kind notin tyMagicGenerics:
|
||||
localError(trait.info,
|
||||
var res = uninstantiate(operand)
|
||||
if res == operand and res.kind notin tyMagicGenerics:
|
||||
localError(traitCall.info,
|
||||
"genericHead expects a generic type. The given type was " &
|
||||
typeToString(typ))
|
||||
return newType(tyError, context).toNode(trait.info)
|
||||
result = res.base.toNode(trait.info)
|
||||
typeToString(operand))
|
||||
return newType(tyError, context).toNode(traitCall.info)
|
||||
result = res.base.toNode(traitCall.info)
|
||||
of "stripGenericParams":
|
||||
result = uninstantiate(typ).toNode(trait.info)
|
||||
result = uninstantiate(operand).toNode(traitCall.info)
|
||||
else:
|
||||
internalAssert false
|
||||
|
||||
|
|
@ -140,7 +156,7 @@ proc semTypeTraits(c: PContext, n: PNode): PNode =
|
|||
if t.sonsLen > 0:
|
||||
# This is either a type known to sem or a typedesc
|
||||
# param to a regular proc (again, known at instantiation)
|
||||
result = evalTypeTrait(n[0], t, getCurrOwner(c))
|
||||
result = evalTypeTrait(n, t, getCurrOwner(c))
|
||||
else:
|
||||
# a typedesc variable, pass unmodified to evals
|
||||
result = n
|
||||
|
|
|
|||
|
|
@ -69,7 +69,8 @@ proc `==`(a, b: TLockLevel): bool {.borrow.}
|
|||
proc max(a, b: TLockLevel): TLockLevel {.borrow.}
|
||||
|
||||
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 =
|
||||
var t = t
|
||||
|
|
@ -218,12 +219,11 @@ proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet) =
|
|||
message(s.info, msgKind,
|
||||
"'$#' is not GC-safe as it calls '$#'" %
|
||||
[s.name.s, u.name.s])
|
||||
of skParam:
|
||||
of skParam, skForVar:
|
||||
message(s.info, msgKind,
|
||||
"'$#' is not GC-safe as it performs an indirect call via '$#'" %
|
||||
[s.name.s, u.name.s])
|
||||
else:
|
||||
internalAssert u.kind == skUnknown
|
||||
message(u.info, msgKind,
|
||||
"'$#' 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
|
||||
|
||||
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.kind == nkNilLit:
|
||||
result.typ = nil
|
||||
|
|
@ -465,6 +465,47 @@ proc hasEmpty(typ: PType): bool =
|
|||
for s in typ.sons:
|
||||
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 =
|
||||
var b: PNode
|
||||
result = copyNode(n)
|
||||
|
|
@ -529,6 +570,11 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
|||
message(a.info, warnEachIdentIsTuple)
|
||||
|
||||
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)
|
||||
if sfGenSym notin v.flags and not isDiscardUnderscore(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:
|
||||
v.ast = def
|
||||
if sfThread in v.flags: localError(def.info, errThreadvarCannotInit)
|
||||
v.typ = typ
|
||||
setVarType(v, typ)
|
||||
b = newNodeI(nkIdentDefs, a.info)
|
||||
if importantComments():
|
||||
# keep documentation information:
|
||||
|
|
@ -560,7 +606,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
|||
addToVarSection(c, result, n, b)
|
||||
else:
|
||||
if def.kind == nkPar: v.ast = def[j]
|
||||
v.typ = tup.sons[j]
|
||||
setVarType(v, tup.sons[j])
|
||||
b.sons[j] = newSymNode(v)
|
||||
addDefer(c, result, v)
|
||||
checkNilable(v)
|
||||
|
|
@ -594,7 +640,7 @@ proc semConst(c: PContext, n: PNode): PNode =
|
|||
if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit:
|
||||
localError(a.info, "invalid type for const: " & typeToString(typ))
|
||||
continue
|
||||
v.typ = typ
|
||||
setVarType(v, typ)
|
||||
v.ast = def # no need to copy
|
||||
if sfGenSym notin v.flags: addInterfaceDecl(c, v)
|
||||
var b = newNodeI(nkConstDef, a.info)
|
||||
|
|
@ -730,7 +776,9 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
|
|||
var s: PSym
|
||||
if name.kind == nkDotExpr:
|
||||
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")
|
||||
else:
|
||||
s = semIdentDef(c, name, skType)
|
||||
|
|
@ -742,6 +790,87 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
|
|||
if sfGenSym notin s.flags: addInterfaceDecl(c, 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) =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
|
|
@ -782,6 +911,22 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
|||
body.sym = s
|
||||
body.size = -1 # could not be computed properly
|
||||
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)
|
||||
closeScope(c)
|
||||
elif a.sons[2].kind != nkEmpty:
|
||||
|
|
@ -985,12 +1130,15 @@ proc semProcAnnotation(c: PContext, prc: PNode;
|
|||
var x = newNodeI(nkCall, n.info)
|
||||
x.add(newSymNode(m))
|
||||
prc.sons[pragmasPos] = copyExcept(n, i)
|
||||
if prc[pragmasPos].kind != nkEmpty and prc[pragmasPos].len == 0:
|
||||
prc.sons[pragmasPos] = emptyNode
|
||||
|
||||
if it.kind == nkExprColonExpr:
|
||||
# pass pragma argument to the macro too:
|
||||
x.add(it.sons[1])
|
||||
x.add(prc)
|
||||
# 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.
|
||||
# This is required for SqueakNim-like export pragmas.
|
||||
if result.kind in procDefs and result[namePos].kind == nkSym and
|
||||
|
|
@ -1322,8 +1470,16 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
|||
implicitPragmas(c, s, n, validPragmas)
|
||||
else:
|
||||
if n.sons[pragmasPos].kind != nkEmpty:
|
||||
localError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProcX,
|
||||
"'" & proto.name.s & "' from " & $proto.info)
|
||||
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,
|
||||
"'" & proto.name.s & "' from " & $proto.info)
|
||||
if sfForward notin proto.flags:
|
||||
wrongRedefinition(n.info, proto.name.s)
|
||||
excl(proto.flags, sfForward)
|
||||
|
|
@ -1402,7 +1558,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
|||
popOwner(c)
|
||||
if n.sons[patternPos].kind != nkEmpty:
|
||||
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
|
||||
s.typ.callConv == ccClosure:
|
||||
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:
|
||||
var expr = semExpr(c, n.sons[i], flags)
|
||||
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
|
||||
of tyBool:
|
||||
if expr.kind == nkInfix and
|
||||
|
|
@ -1629,7 +1788,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
|
||||
let verdict = semConstExpr(c, n[i])
|
||||
if verdict.intVal == 0:
|
||||
localError(result.info, "type class predicate failed")
|
||||
localError(result.info, "concept predicate failed")
|
||||
of tyUnknown: continue
|
||||
else: discard
|
||||
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
|
||||
# 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.
|
||||
# they will always expect a proper stmtlist:
|
||||
nfBlockArg notin n.flags and
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
|||
counter = lastOrd(base) + 1
|
||||
rawAddSon(result, base)
|
||||
let isPure = result.sym != nil and sfPure in result.sym.flags
|
||||
var symbols: TStrTable
|
||||
if isPure: initStrTable(symbols)
|
||||
var hasNull = false
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
case n.sons[i].kind
|
||||
|
|
@ -87,6 +89,8 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
|||
addSon(result.n, newSymNode(e))
|
||||
styleCheckDef(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)
|
||||
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"
|
||||
addSonSkipIntLit(result, region)
|
||||
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
|
||||
|
||||
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
|
||||
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" &
|
||||
"got: (" & describeArgs(c, n) & ")\n" &
|
||||
"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 nfBase2 in n.flags:
|
||||
message(n.info, warnDeprecated, "use 'concept' instead; 'generic'")
|
||||
result = newOrPrevType(tyUserTypeClass, prev, c)
|
||||
result.n = n
|
||||
|
||||
let
|
||||
pragmas = n[1]
|
||||
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:
|
||||
for n in inherited.sons:
|
||||
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,
|
||||
prev: PType, kind: TSymKind): PType =
|
||||
|
|
@ -1379,7 +1419,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
|||
result = errorType(c)
|
||||
else:
|
||||
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)
|
||||
result = makeTypeFromExpr(c, preprocessed.copyTree)
|
||||
else:
|
||||
|
|
@ -1584,10 +1627,24 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
|||
# type for each generic param. the index
|
||||
# of the parameter will be stored in the
|
||||
# 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:
|
||||
newSymG(skGenericParam, a.sons[j], c).linkTo(finalType)
|
||||
newSymG(skGenericParam, paramName, c).linkTo(finalType)
|
||||
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 father != nil: addSonSkipIntLit(father, s.typ)
|
||||
s.position = result.len
|
||||
|
|
|
|||
|
|
@ -73,9 +73,13 @@ proc cacheTypeInst*(inst: PType) =
|
|||
|
||||
|
||||
type
|
||||
LayeredIdTable* = object
|
||||
topLayer*: TIdTable
|
||||
nextLayer*: ptr LayeredIdTable
|
||||
|
||||
TReplTypeVars* {.final.} = object
|
||||
c*: PContext
|
||||
typeMap*: TIdTable # map PType to PType
|
||||
typeMap*: ptr LayeredIdTable # map PType to PType
|
||||
symMap*: TIdTable # map PSym to PSym
|
||||
localCache*: TIdTable # local cache for remembering alraedy replaced
|
||||
# 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 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) =
|
||||
when false:
|
||||
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 =
|
||||
let t = replaceTypeVarsT(cl, n.typ)
|
||||
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.typ = t
|
||||
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)
|
||||
|
||||
proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
|
||||
result = PType(idTableGet(cl.typeMap, t))
|
||||
result = cl.typeMap.lookup(t)
|
||||
if result == nil:
|
||||
if cl.allowMetaTypes or tfRetType in t.flags: return
|
||||
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
|
||||
# this bad lookup and replace it with errorType everywhere.
|
||||
# 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:
|
||||
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 =
|
||||
# tyGenericInvocation[A, tyGenericInvocation[A, B]]
|
||||
# is difficult to handle:
|
||||
const eqFlags = eqTypeFlags + {tfGcSafe}
|
||||
var body = t.sons[0]
|
||||
if body.kind != tyGenericBody: internalError(cl.info, "no generic body")
|
||||
var header: PType = t
|
||||
|
|
@ -252,7 +275,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
|||
else:
|
||||
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):
|
||||
var x = t.sons[i]
|
||||
if x.kind in {tyGenericParam}:
|
||||
|
|
@ -267,7 +290,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
|||
if header != t:
|
||||
# search again after first pass:
|
||||
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:
|
||||
header = instCopyType(cl, t)
|
||||
|
||||
|
|
@ -285,12 +308,16 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
|||
|
||||
let oldSkipTypedesc = cl.skipTypedesc
|
||||
cl.skipTypedesc = true
|
||||
|
||||
var typeMapLayer = newTypeMapLayer(cl)
|
||||
cl.typeMap = addr(typeMapLayer)
|
||||
|
||||
for i in countup(1, sonsLen(t) - 1):
|
||||
var x = replaceTypeVarsT(cl, t.sons[i])
|
||||
assert x.kind != tyGenericInvocation
|
||||
header.sons[i] = 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):
|
||||
# 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
|
||||
newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
|
||||
result.flags = result.flags + newbody.flags - tfInstClearedFlags
|
||||
|
||||
cl.typeMap = cl.typeMap.nextLayer
|
||||
|
||||
# This is actually wrong: tgeneric_closure fails with this line:
|
||||
#newbody.callConv = body.callConv
|
||||
# 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.kind in {tyStatic, tyGenericParam} + tyTypeClasses:
|
||||
let lookup = PType(idTableGet(cl.typeMap, t))
|
||||
let lookup = cl.typeMap.lookup(t)
|
||||
if lookup != nil: return lookup
|
||||
|
||||
case t.kind
|
||||
|
|
@ -446,7 +476,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
|||
result = skipIntLit(t)
|
||||
|
||||
of tyTypeDesc:
|
||||
let lookup = PType(idTableGet(cl.typeMap, t)) # lookupTypeVar(cl, t)
|
||||
let lookup = cl.typeMap.lookup(t)
|
||||
if lookup != nil:
|
||||
result = lookup
|
||||
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)
|
||||
# bug #4677: Do not instantiate effect lists
|
||||
result.n = replaceTypeVarsN(cl, result.n, ord(result.kind==tyProc))
|
||||
|
||||
case result.kind
|
||||
of tyArray:
|
||||
let idx = result.sons[0]
|
||||
|
|
@ -500,18 +529,19 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
|||
|
||||
else: discard
|
||||
|
||||
proc initTypeVars*(p: PContext, pt: TIdTable, info: TLineInfo;
|
||||
proc initTypeVars*(p: PContext, typeMap: ptr LayeredIdTable, info: TLineInfo;
|
||||
owner: PSym): TReplTypeVars =
|
||||
initIdTable(result.symMap)
|
||||
copyIdTable(result.typeMap, pt)
|
||||
initIdTable(result.localCache)
|
||||
result.typeMap = typeMap
|
||||
result.info = info
|
||||
result.c = p
|
||||
result.owner = owner
|
||||
|
||||
proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: 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
|
||||
pushInfoContext(n.info)
|
||||
result = replaceTypeVarsN(cl, n)
|
||||
|
|
@ -519,7 +549,8 @@ proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode;
|
|||
|
||||
proc replaceTypesForLambda*(p: PContext, pt: TIdTable, n: 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)
|
||||
pushInfoContext(n.info)
|
||||
result = replaceTypeVarsN(cl, n)
|
||||
|
|
@ -527,14 +558,16 @@ proc replaceTypesForLambda*(p: PContext, pt: TIdTable, n: PNode;
|
|||
|
||||
proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
|
||||
t: PType): PType =
|
||||
var cl = initTypeVars(p, pt, info, nil)
|
||||
var typeMap = initLayeredTypeMap(pt)
|
||||
var cl = initTypeVars(p, addr(typeMap), info, nil)
|
||||
pushInfoContext(info)
|
||||
result = replaceTypeVarsT(cl, t)
|
||||
popInfoContext()
|
||||
|
||||
proc prepareMetatypeForSigmatch*(p: PContext, pt: TIdTable, info: TLineInfo,
|
||||
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
|
||||
pushInfoContext(info)
|
||||
result = replaceTypeVarsT(cl, t)
|
||||
|
|
|
|||
|
|
@ -69,6 +69,12 @@ type
|
|||
mutabilityProblem*: uint8 # tyVar mismatch
|
||||
inheritancePenalty: int # to prefer closest father object type
|
||||
|
||||
TTypeRelFlag* = enum
|
||||
trDontBind
|
||||
trNoCovariance
|
||||
|
||||
TTypeRelFlags* = set[TTypeRelFlag]
|
||||
|
||||
TTypeRelation* = enum # order is important!
|
||||
isNone, isConvertible,
|
||||
isIntConv,
|
||||
|
|
@ -198,7 +204,9 @@ proc sumGeneric(t: PType): int =
|
|||
if t.sons[i] != nil:
|
||||
result += t.sons[i].sumGeneric
|
||||
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 tyBool, tyChar, tyEnum, tyObject, tyPointer,
|
||||
tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
|
||||
|
|
@ -296,7 +304,33 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
|
|||
add(result, argTypeToString(arg, prefer))
|
||||
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 =
|
||||
case t.kind
|
||||
of tyNil:
|
||||
|
|
@ -594,19 +628,29 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
|
|||
else:
|
||||
result = isNone
|
||||
|
||||
proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||
ff, a: PType): PType =
|
||||
proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
|
||||
var
|
||||
c = m.c
|
||||
typeClass = ff.skipTypes({tyUserTypeClassInst})
|
||||
body = typeClass.n[3]
|
||||
if c.inTypeClass > 4:
|
||||
localError(body.info, $body & " too nested for type matching")
|
||||
return nil
|
||||
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")
|
||||
return nil
|
||||
|
||||
openScope(c)
|
||||
inc c.inTypeClass
|
||||
matchedConceptContext.candidateType = a
|
||||
typeClass[0].sons[0] = a
|
||||
c.matchedConcept = addr(matchedConceptContext)
|
||||
defer:
|
||||
dec c.inTypeClass
|
||||
c.matchedConcept = prevMatchedConcept
|
||||
typeClass[0].sons[0] = prevCandidateType
|
||||
closeScope(c)
|
||||
|
||||
var typeParams: seq[(PSym, PType)]
|
||||
|
|
@ -617,6 +661,9 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
|||
typeParamName = ff.base.sons[i-1].sym.name
|
||||
typ = ff.sons[i]
|
||||
param: PSym
|
||||
alreadyBound = PType(idTableGet(m.bindings, typ))
|
||||
|
||||
if alreadyBound != nil: typ = alreadyBound
|
||||
|
||||
template paramSym(kind): untyped =
|
||||
newSym(kind, typeParamName, typeClass.sym, typeClass.sym.info)
|
||||
|
|
@ -650,33 +697,6 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
|||
|
||||
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
|
||||
oldWriteHook: type(writelnHook)
|
||||
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)
|
||||
inferred.n = newIntNode(nkIntLit, rhs)
|
||||
put(c, lhs.typ, inferred)
|
||||
if c.c.inTypeClass > 0:
|
||||
if c.c.matchedConcept != nil:
|
||||
# inside concepts, binding is currently done with
|
||||
# direct mutation of the involved types:
|
||||
lhs.typ.n = inferred.n
|
||||
|
|
@ -860,7 +880,28 @@ template subtypeCheck() =
|
|||
if result <= isSubrange and f.lastSon.skipTypes(abstractInst).kind in {tyRef, tyPtr, tyVar}:
|
||||
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:
|
||||
#
|
||||
# 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)
|
||||
|
||||
var
|
||||
useTypeLoweringRuleInTypeClass = c.c.inTypeClass > 0 and
|
||||
useTypeLoweringRuleInTypeClass = c.c.matchedConcept != nil and
|
||||
not c.isNoCall and
|
||||
f.kind != tyTypeDesc and
|
||||
tfExplicit notin aOrig.flags
|
||||
|
|
@ -927,6 +968,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
result = isEqual
|
||||
return
|
||||
|
||||
template doBind: bool = trDontBind notin flags
|
||||
|
||||
# var and static arguments match regular modifier-free types
|
||||
var a = aOrig.skipTypes({tyStatic, tyVar}).maybeSkipDistinct(c.calleeSym)
|
||||
# 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
|
||||
# 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 {
|
||||
tyGenericBody, tyGenericInvocation,
|
||||
tyGenericInst, tyGenericParam} + tyTypeClasses:
|
||||
|
|
@ -956,23 +1002,28 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
|
||||
case a.kind
|
||||
of tyOr:
|
||||
# XXX: deal with the current dual meaning of tyGenericParam
|
||||
c.typedescMatched = true
|
||||
# seq[int|string] vs seq[number]
|
||||
# both int and string must match against number
|
||||
# but ensure that '[T: A|A]' matches as good as '[T: A]' (bug #2219):
|
||||
result = isGeneric
|
||||
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 < result: result = x
|
||||
return
|
||||
|
||||
of tyAnd:
|
||||
# XXX: deal with the current dual meaning of tyGenericParam
|
||||
c.typedescMatched = true
|
||||
# seq[Sortable and Iterable] vs seq[Sortable]
|
||||
# only one match is enough
|
||||
for branch in a.sons:
|
||||
let x = typeRel(c, f, branch, false)
|
||||
let x = typeRel(c, f, branch, flags + {trDontBind})
|
||||
if x != isNone:
|
||||
return if x >= isGeneric: isGeneric else: x
|
||||
result = isNone
|
||||
return isNone
|
||||
|
||||
of tyNot:
|
||||
case f.kind
|
||||
|
|
@ -994,11 +1045,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
else: isNone
|
||||
|
||||
of tyUserTypeClass, tyUserTypeClassInst:
|
||||
# consider this: 'var g: Node' *within* a concept where 'Node'
|
||||
# is a concept too (tgraph)
|
||||
let x = typeRel(c, a, f, false)
|
||||
if x >= isGeneric:
|
||||
return isGeneric
|
||||
if c.c.matchedConcept != nil:
|
||||
# consider this: 'var g: Node' *within* a concept where 'Node'
|
||||
# is a concept too (tgraph)
|
||||
let x = typeRel(c, a, f, flags + {trDontBind})
|
||||
if x >= isGeneric:
|
||||
return isGeneric
|
||||
else: discard
|
||||
|
||||
case f.kind
|
||||
|
|
@ -1042,7 +1094,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
of tyFloat128: result = handleFloatRange(f, a)
|
||||
of tyVar:
|
||||
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()
|
||||
of tyArray:
|
||||
case a.kind
|
||||
|
|
@ -1056,13 +1108,21 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
fRange = a
|
||||
else:
|
||||
fRange = prev
|
||||
result = typeRel(c, f.sons[1].skipTypes({tyTypeDesc}),
|
||||
a.sons[1].skipTypes({tyTypeDesc}))
|
||||
if result < isGeneric: return isNone
|
||||
let ff = f.sons[1].skipTypes({tyTypeDesc})
|
||||
let aa = a.sons[1].skipTypes({tyTypeDesc})
|
||||
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:
|
||||
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)
|
||||
else:
|
||||
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 f.sons[0].kind == tyExpr: 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
|
||||
of tyOpenArray, tyVarargs:
|
||||
result = typeRel(c, base(f), base(a))
|
||||
if result < isGeneric: result = isNone
|
||||
of tyArray:
|
||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
|
||||
result = isSubtype
|
||||
elif typeRel(c, base(f), a.sons[1]) >= isGeneric:
|
||||
result = isConvertible
|
||||
return isSubtype
|
||||
matchArrayOrSeq(a.sons[1])
|
||||
of tySequence:
|
||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
|
||||
result = isConvertible
|
||||
elif typeRel(c, base(f), a.sons[0]) >= isGeneric:
|
||||
result = isConvertible
|
||||
return isConvertible
|
||||
matchArrayOrSeq(a.sons[0])
|
||||
of tyString:
|
||||
if f.kind == tyOpenArray:
|
||||
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):
|
||||
result = isSubtype
|
||||
else:
|
||||
result = typeRel(c, f.sons[0], a.sons[0])
|
||||
if result < isGeneric: result = isNone
|
||||
let ff = f.sons[0]
|
||||
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:
|
||||
result = isNilConversion
|
||||
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
|
||||
for i in 0..f.len-2:
|
||||
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()
|
||||
if result <= isConvertible: result = isNone
|
||||
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
|
||||
if a.kind == tyGenericInst:
|
||||
if roota.base == rootf.base:
|
||||
let nextFlags = flags + {trNoCovariance}
|
||||
var hasCovariance = false
|
||||
for i in 1 .. rootf.sonsLen-2:
|
||||
let ff = rootf.sons[i]
|
||||
let aa = roota.sons[i]
|
||||
result = typeRel(c, ff, aa)
|
||||
if result notin {isEqual, isGeneric}: return isNone
|
||||
# if ff.kind == tyRange and result != isEqual: return isNone
|
||||
result = typeRel(c, ff, aa, nextFlags)
|
||||
if result notin {isEqual, isGeneric}:
|
||||
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)
|
||||
result = isGeneric
|
||||
else:
|
||||
|
|
@ -1260,7 +1355,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
result = isNone
|
||||
else:
|
||||
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:
|
||||
considerPreviousT:
|
||||
|
|
@ -1396,7 +1492,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
result = typeRel(c, f.lastSon, a)
|
||||
else:
|
||||
considerPreviousT:
|
||||
var matched = matchUserTypeClass(c.c, c, f, aOrig)
|
||||
if aOrig == f: return isEqual
|
||||
var matched = matchUserTypeClass(c, f, aOrig)
|
||||
if matched != nil:
|
||||
bindConcreteTypeToUserTypeClass(matched, a)
|
||||
if doBind: put(c, f, matched)
|
||||
|
|
@ -1450,7 +1547,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
result = isNone
|
||||
else:
|
||||
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}:
|
||||
let concrete = concreteType(c, a)
|
||||
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):
|
||||
result = isNone
|
||||
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:
|
||||
result = isNone
|
||||
elif prev.kind == tyStatic:
|
||||
|
|
@ -1691,6 +1794,13 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
|
|||
arg.typ.sons = @[evaluated.typ]
|
||||
arg.typ.n = evaluated
|
||||
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)
|
||||
|
||||
|
|
@ -2140,6 +2250,8 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
|
|||
var def = copyTree(formal.ast)
|
||||
if def.kind == nkNilLit:
|
||||
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)
|
||||
inc(f)
|
||||
# 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 nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
|
||||
of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
|
||||
of nkCommentStmt: result = a.comment == b.comment
|
||||
of nkEmpty, nkNilLit, nkType: result = true
|
||||
else:
|
||||
if sonsLen(a) == sonsLen(b):
|
||||
|
|
@ -109,9 +110,11 @@ proc isDeepConstExpr*(n: PNode): bool =
|
|||
|
||||
proc isRange*(n: PNode): bool {.inline.} =
|
||||
if n.kind in nkCallKinds:
|
||||
if n[0].kind == nkIdent and n[0].ident.id == ord(wDotDot) or
|
||||
n[0].kind in {nkClosedSymChoice, nkOpenSymChoice} and
|
||||
n[0][1].sym.name.id == ord(wDotDot):
|
||||
let callee = n[0]
|
||||
if (callee.kind == nkIdent and callee.ident.id == ord(wDotDot)) or
|
||||
(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
|
||||
|
||||
proc whichPragma*(n: PNode): TSpecialWord =
|
||||
|
|
|
|||
|
|
@ -139,6 +139,9 @@ proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string =
|
|||
add(result, ')')
|
||||
if n.sons[0].typ != nil:
|
||||
result.add(": " & typeToString(n.sons[0].typ, prefer))
|
||||
result.add "[declared in "
|
||||
result.add($sym.info)
|
||||
result.add "]"
|
||||
|
||||
proc elemType*(t: PType): PType =
|
||||
assert(t != nil)
|
||||
|
|
@ -421,6 +424,12 @@ template bindConcreteTypeToUserTypeClass*(tc, concrete: PType) =
|
|||
tc.sons.safeAdd concrete
|
||||
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 =
|
||||
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 & ")"
|
||||
elif prefer == preferName or t.sym.owner.isNil:
|
||||
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:
|
||||
result = t.sym.owner.name.s & '.' & t.sym.name.s
|
||||
result.addTypeFlags(t)
|
||||
|
|
@ -458,7 +474,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
|||
add(result, ']')
|
||||
of tyTypeDesc:
|
||||
if t.sons[0].kind == tyNone: result = "typedesc"
|
||||
else: result = "typedesc[" & typeToString(t.sons[0]) & "]"
|
||||
else: result = "type " & typeToString(t.sons[0])
|
||||
of tyStatic:
|
||||
internalAssert t.len > 0
|
||||
if prefer == preferGenericArg and t.n != nil:
|
||||
|
|
@ -688,6 +704,7 @@ type
|
|||
ExactTypeDescValues
|
||||
ExactGenericParams
|
||||
ExactConstraints
|
||||
ExactGcSafety
|
||||
AllowCommonBase
|
||||
|
||||
TTypeCmpFlags* = set[TTypeCmpFlag]
|
||||
|
|
@ -976,6 +993,8 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
|||
cycleCheck()
|
||||
if a.kind == tyUserTypeClass and a.n != nil: return a.n == b.n
|
||||
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:
|
||||
result = ((IgnoreCC in c.flags) or a.callConv == b.callConv) and
|
||||
((ExactConstraints notin c.flags) or sameConstraints(a.n, b.n))
|
||||
|
|
|
|||
|
|
@ -52,13 +52,16 @@ proc renderType(n: PNode): string =
|
|||
else:
|
||||
result = "ptr"
|
||||
of nkProcTy:
|
||||
assert len(n) > 1
|
||||
let params = n[0]
|
||||
assert params.kind == nkFormalParams
|
||||
assert len(params) > 0
|
||||
result = "proc("
|
||||
for i in 1 .. <len(params): result.add(renderType(params[i]) & ',')
|
||||
result[<len(result)] = ')'
|
||||
assert len(n) != 1
|
||||
if len(n) > 1:
|
||||
let params = n[0]
|
||||
assert params.kind == nkFormalParams
|
||||
assert len(params) > 0
|
||||
result = "proc("
|
||||
for i in 1 .. <len(params): result.add(renderType(params[i]) & ',')
|
||||
result[<len(result)] = ')'
|
||||
else:
|
||||
result = "proc"
|
||||
of nkIdentDefs:
|
||||
assert len(n) >= 3
|
||||
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
|
||||
regs[rb].kind in {rkNode}:
|
||||
dest.strVal = regs[rb].node.strVal
|
||||
elif dest.kind == nkCommentStmt and regs[rb].kind in {rkNode}:
|
||||
dest.comment = regs[rb].node.strVal
|
||||
else:
|
||||
stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
|
||||
of opcNNewNimNode:
|
||||
|
|
@ -1609,8 +1611,9 @@ proc setupMacroParam(x: PNode, typ: PType): TFullReg =
|
|||
iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) =
|
||||
let gp = macroSym.ast[genericParamsPos]
|
||||
for i in 0 .. <gp.len:
|
||||
let idx = macroSym.typ.len + i
|
||||
yield (gp[i].sym, call.sons[idx])
|
||||
let genericParam = gp[i].sym
|
||||
let posInCall = macroSym.typ.len + i
|
||||
yield (genericParam, call[posInCall])
|
||||
|
||||
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 mMulF64: genBinaryABC(c, n, dest, opcMulFloat)
|
||||
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 mBitandI: genBinaryABCnarrowU(c, n, dest, opcBitandInt)
|
||||
of mBitorI: genBinaryABCnarrowU(c, n, dest, opcBitorInt)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue