type constraints; tuple lifting
This commit is contained in:
parent
dc669155e3
commit
4d91c9d887
17 changed files with 527 additions and 139 deletions
|
|
@ -137,7 +137,11 @@ pragma ::= '{.' optInd (colonExpr [comma])* optPar ('.}' | '}')
|
||||||
param ::= symbol (comma symbol)* (':' typeDesc ['=' expr] | '=' expr)
|
param ::= symbol (comma symbol)* (':' typeDesc ['=' expr] | '=' expr)
|
||||||
paramList ::= ['(' [param (comma param)*] optPar ')'] [':' typeDesc]
|
paramList ::= ['(' [param (comma param)*] optPar ')'] [':' typeDesc]
|
||||||
|
|
||||||
genericParam ::= symbol [':' typeDesc] ['=' expr]
|
genericConstraint ::= 'object' | 'tuple' | 'enum' | 'proc' | 'ref' | 'ptr'
|
||||||
|
| 'var' | 'distinct' | primary
|
||||||
|
genericConstraints ::= genericConstraint ( '|' optInd genericConstraint )*
|
||||||
|
|
||||||
|
genericParam ::= symbol [':' genericConstraints] ['=' expr]
|
||||||
genericParams ::= '[' genericParam (comma genericParam)* optPar ']'
|
genericParams ::= '[' genericParam (comma genericParam)* optPar ']'
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -586,11 +586,11 @@ proc next*(my: var TXmlParser) =
|
||||||
of stateNormal:
|
of stateNormal:
|
||||||
getTok(my)
|
getTok(my)
|
||||||
of stateStart:
|
of stateStart:
|
||||||
|
my.state = stateNormal
|
||||||
getTok(my)
|
getTok(my)
|
||||||
if my.kind == xmlPI and my.a == "xml":
|
if my.kind == xmlPI and my.a == "xml":
|
||||||
# just skip the first ``<?xml >`` processing instruction
|
# just skip the first ``<?xml >`` processing instruction
|
||||||
getTok(my)
|
getTok(my)
|
||||||
my.state = stateNormal
|
|
||||||
of stateAttr:
|
of stateAttr:
|
||||||
# parse an attribute key-value pair:
|
# parse an attribute key-value pair:
|
||||||
if my.buf[my.bufpos] == '>':
|
if my.buf[my.bufpos] == '>':
|
||||||
|
|
|
||||||
|
|
@ -765,7 +765,7 @@ proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} =
|
||||||
setLen(x, xl + y.len)
|
setLen(x, xl + y.len)
|
||||||
for i in 0..high(y): x[xl+i] = y[i]
|
for i in 0..high(y): x[xl+i] = y[i]
|
||||||
|
|
||||||
proc del* [T](x: var seq[T], i: int) {.noSideEffect.} =
|
proc del*[T](x: var seq[T], i: int) {.noSideEffect.} =
|
||||||
## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`.
|
## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`.
|
||||||
## This is an O(1) operation.
|
## This is an O(1) operation.
|
||||||
var xl = x.len
|
var xl = x.len
|
||||||
|
|
@ -1111,15 +1111,6 @@ iterator items*(a: cstring): char {.inline.} =
|
||||||
yield a[i]
|
yield a[i]
|
||||||
inc(i)
|
inc(i)
|
||||||
|
|
||||||
iterator enumerate*[TContainer, TItem](a: TContainer): tuple[
|
|
||||||
index: int, item: TItem] {.inline.} =
|
|
||||||
## iterates over each item of `a` via `items` and yields an additional
|
|
||||||
## counter/index starting from 0.
|
|
||||||
var j = 0
|
|
||||||
for it in items(a):
|
|
||||||
yield (j, a)
|
|
||||||
inc j
|
|
||||||
|
|
||||||
proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil".}
|
proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil".}
|
||||||
proc isNil*[T](x: ref T): bool {.noSideEffect, magic: "IsNil".}
|
proc isNil*[T](x: ref T): bool {.noSideEffect, magic: "IsNil".}
|
||||||
proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil".}
|
proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil".}
|
||||||
|
|
@ -1170,7 +1161,7 @@ when not defined(NimrodVM):
|
||||||
|
|
||||||
proc find*[T, S: typeDesc](a: T, item: S): int {.inline.}=
|
proc find*[T, S: typeDesc](a: T, item: S): int {.inline.}=
|
||||||
## Returns the first index of `item` in `a` or -1 if not found. This requires
|
## Returns the first index of `item` in `a` or -1 if not found. This requires
|
||||||
## appropriate `items` and `==` procs to work.
|
## appropriate `items` and `==` operations to work.
|
||||||
for i in items(a):
|
for i in items(a):
|
||||||
if i == item: return
|
if i == item: return
|
||||||
inc(result)
|
inc(result)
|
||||||
|
|
@ -1200,6 +1191,62 @@ proc each*[T](data: var openArray[T], op: proc (x: var T)) =
|
||||||
## `op` to every item in `data`.
|
## `op` to every item in `data`.
|
||||||
for i in 0..data.len-1: op(data[i])
|
for i in 0..data.len-1: op(data[i])
|
||||||
|
|
||||||
|
iterator fields*(x: tuple[]): expr {.magic: "Fields", noSideEffect.}
|
||||||
|
## iterates over every field of `x`. Warning: This is really transforms
|
||||||
|
## the 'for' and unrolls the loop. The current implementation also has a bug
|
||||||
|
## that affects symbol binding in the loop body.
|
||||||
|
iterator fields*(x, y: tuple[]): tuple[a, b: expr] {.
|
||||||
|
magic: "Fields", noSideEffect.}
|
||||||
|
## iterates over every field of `x` and `y`.
|
||||||
|
## Warning: This is really transforms the 'for' and unrolls the loop.
|
||||||
|
## The current implementation also has a bug that affects symbol binding
|
||||||
|
## in the loop body.
|
||||||
|
iterator fieldPairs*(x: tuple[]): expr {.magic: "FieldPairs", noSideEffect.}
|
||||||
|
## iterates over every field of `x`. Warning: This is really transforms
|
||||||
|
## the 'for' and unrolls the loop. The current implementation also has a bug
|
||||||
|
## that affects symbol binding in the loop body.
|
||||||
|
iterator fieldPairs*(x, y: tuple[]): tuple[a, b: expr] {.
|
||||||
|
magic: "FieldPairs", noSideEffect.}
|
||||||
|
## iterates over every field of `x` and `y`.
|
||||||
|
## Warning: This is really transforms the 'for' and unrolls the loop.
|
||||||
|
## The current implementation also has a bug that affects symbol binding
|
||||||
|
## in the loop body.
|
||||||
|
|
||||||
|
proc `==`*[T: tuple](x, y: T): bool =
|
||||||
|
## generic ``==`` operator that is lifted from the components
|
||||||
|
## of `x` and `y`.
|
||||||
|
for a, b in fields(x, y):
|
||||||
|
if a != b: return false
|
||||||
|
return true
|
||||||
|
|
||||||
|
proc `<=`*[T: tuple](x, y: T): bool =
|
||||||
|
## generic ``<=`` operator that is lifted from the components
|
||||||
|
## of `x` and `y`. This implementation uses `cmp`.
|
||||||
|
for a, b in fields(x, y):
|
||||||
|
var c = cmp(a, b)
|
||||||
|
if c < 0: return true
|
||||||
|
if c > 0: return false
|
||||||
|
return true
|
||||||
|
|
||||||
|
proc `<`*[T: tuple](x, y: T): bool =
|
||||||
|
## generic ``<`` operator that is lifted from the components
|
||||||
|
## of `x` and `y`. This implementation uses `cmp`.
|
||||||
|
for a, b in fields(x, y):
|
||||||
|
var c = cmp(a, b)
|
||||||
|
if c < 0: return true
|
||||||
|
if c > 0: return false
|
||||||
|
return false
|
||||||
|
|
||||||
|
proc `$`*[T: tuple](x: T): string =
|
||||||
|
## generic ``$`` operator that is lifted from the components of `x`.
|
||||||
|
result = "("
|
||||||
|
for name, value in fieldPairs(x):
|
||||||
|
if result.len > 1: result.add(", ")
|
||||||
|
result.add(name)
|
||||||
|
result.add(": ")
|
||||||
|
result.add($value)
|
||||||
|
result.add(")")
|
||||||
|
|
||||||
# ----------------- GC interface ---------------------------------------------
|
# ----------------- GC interface ---------------------------------------------
|
||||||
|
|
||||||
proc GC_disable*() {.rtl, inl.}
|
proc GC_disable*() {.rtl, inl.}
|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,7 @@ type
|
||||||
tyGenericParam, # ``a`` in the example
|
tyGenericParam, # ``a`` in the example
|
||||||
tyDistinct,
|
tyDistinct,
|
||||||
tyEnum,
|
tyEnum,
|
||||||
tyOrdinal,
|
tyOrdinal, # misnamed: should become 'tyConstraint'
|
||||||
tyArray,
|
tyArray,
|
||||||
tyObject,
|
tyObject,
|
||||||
tyTuple,
|
tyTuple,
|
||||||
|
|
@ -329,7 +329,9 @@ type
|
||||||
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
|
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
|
||||||
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
|
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
|
||||||
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
|
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
|
||||||
mConTArr, mConTT, mSlice, mAppendStrCh, mAppendStrStr, mAppendSeqElem,
|
mConTArr, mConTT, mSlice,
|
||||||
|
mFields, mFieldPairs,
|
||||||
|
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
|
||||||
mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq, mAssert,
|
mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq, mAssert,
|
||||||
mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, mNewString, mReset,
|
mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, mNewString, mReset,
|
||||||
mArray, mOpenArray, mRange, mSet, mSeq,
|
mArray, mOpenArray, mRange, mSet, mSeq,
|
||||||
|
|
|
||||||
|
|
@ -1014,12 +1014,77 @@ proc parseAsm(p: var TParser): PNode =
|
||||||
return
|
return
|
||||||
getTok(p)
|
getTok(p)
|
||||||
|
|
||||||
|
proc parseGenericConstraint(p: var TParser): PNode =
|
||||||
|
case p.tok.tokType
|
||||||
|
of tkObject:
|
||||||
|
result = newNodeP(nkObjectTy, p)
|
||||||
|
getTok(p)
|
||||||
|
of tkTuple:
|
||||||
|
result = newNodeP(nkTupleTy, p)
|
||||||
|
getTok(p)
|
||||||
|
of tkEnum:
|
||||||
|
result = newNodeP(nkEnumTy, p)
|
||||||
|
getTok(p)
|
||||||
|
of tkProc:
|
||||||
|
result = newNodeP(nkProcTy, p)
|
||||||
|
getTok(p)
|
||||||
|
of tkVar:
|
||||||
|
result = newNodeP(nkVarTy, p)
|
||||||
|
getTok(p)
|
||||||
|
of tkPtr:
|
||||||
|
result = newNodeP(nkPtrTy, p)
|
||||||
|
getTok(p)
|
||||||
|
of tkRef:
|
||||||
|
result = newNodeP(nkRefTy, p)
|
||||||
|
getTok(p)
|
||||||
|
of tkDistinct:
|
||||||
|
result = newNodeP(nkDistinctTy, p)
|
||||||
|
getTok(p)
|
||||||
|
else: result = primary(p)
|
||||||
|
|
||||||
|
proc parseGenericConstraintList(p: var TParser): PNode =
|
||||||
|
result = parseGenericConstraint(p)
|
||||||
|
while p.tok.tokType == tkOpr:
|
||||||
|
var a = result
|
||||||
|
result = newNodeP(nkInfix, p)
|
||||||
|
addSon(result, newIdentNodeP(p.tok.ident, p))
|
||||||
|
addSon(result, a)
|
||||||
|
getTok(p)
|
||||||
|
optInd(p, result)
|
||||||
|
addSon(result, parseGenericConstraint(p))
|
||||||
|
|
||||||
|
proc parseGenericParam(p: var TParser): PNode =
|
||||||
|
var a: PNode
|
||||||
|
result = newNodeP(nkIdentDefs, p)
|
||||||
|
while true:
|
||||||
|
case p.tok.tokType
|
||||||
|
of tkSymbol, tkAccent:
|
||||||
|
a = parseSymbol(p)
|
||||||
|
if a.kind == nkEmpty: return
|
||||||
|
else: break
|
||||||
|
addSon(result, a)
|
||||||
|
if p.tok.tokType != tkComma: break
|
||||||
|
getTok(p)
|
||||||
|
optInd(p, a)
|
||||||
|
if p.tok.tokType == tkColon:
|
||||||
|
getTok(p)
|
||||||
|
optInd(p, result)
|
||||||
|
addSon(result, parseGenericConstraintList(p))
|
||||||
|
else:
|
||||||
|
addSon(result, ast.emptyNode)
|
||||||
|
if p.tok.tokType == tkEquals:
|
||||||
|
getTok(p)
|
||||||
|
optInd(p, result)
|
||||||
|
addSon(result, parseExpr(p))
|
||||||
|
else:
|
||||||
|
addSon(result, ast.emptyNode)
|
||||||
|
|
||||||
proc parseGenericParamList(p: var TParser): PNode =
|
proc parseGenericParamList(p: var TParser): PNode =
|
||||||
result = newNodeP(nkGenericParams, p)
|
result = newNodeP(nkGenericParams, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, result)
|
optInd(p, result)
|
||||||
while (p.tok.tokType == tkSymbol) or (p.tok.tokType == tkAccent):
|
while (p.tok.tokType == tkSymbol) or (p.tok.tokType == tkAccent):
|
||||||
var a = parseIdentColonEquals(p, {withBothOptional})
|
var a = parseGenericParam(p)
|
||||||
addSon(result, a)
|
addSon(result, a)
|
||||||
if p.tok.tokType != tkComma: break
|
if p.tok.tokType != tkComma: break
|
||||||
getTok(p)
|
getTok(p)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nimrod Compiler
|
||||||
# (c) Copyright 2010 Andreas Rumpf
|
# (c) Copyright 2011 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
|
|
@ -839,17 +839,29 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
putWithSpace(g, tkType, "type")
|
putWithSpace(g, tkType, "type")
|
||||||
gsub(g, n.sons[0])
|
gsub(g, n.sons[0])
|
||||||
of nkRefTy:
|
of nkRefTy:
|
||||||
putWithSpace(g, tkRef, "ref")
|
if sonsLen(n) > 0:
|
||||||
gsub(g, n.sons[0])
|
putWithSpace(g, tkRef, "ref")
|
||||||
|
gsub(g, n.sons[0])
|
||||||
|
else:
|
||||||
|
put(g, tkRef, "ref")
|
||||||
of nkPtrTy:
|
of nkPtrTy:
|
||||||
putWithSpace(g, tkPtr, "ptr")
|
if sonsLen(n) > 0:
|
||||||
gsub(g, n.sons[0])
|
putWithSpace(g, tkPtr, "ptr")
|
||||||
|
gsub(g, n.sons[0])
|
||||||
|
else:
|
||||||
|
put(g, tkPtr, "ptr")
|
||||||
of nkVarTy:
|
of nkVarTy:
|
||||||
putWithSpace(g, tkVar, "var")
|
if sonsLen(n) > 0:
|
||||||
gsub(g, n.sons[0])
|
putWithSpace(g, tkVar, "var")
|
||||||
|
gsub(g, n.sons[0])
|
||||||
|
else:
|
||||||
|
put(g, tkVar, "var")
|
||||||
of nkDistinctTy:
|
of nkDistinctTy:
|
||||||
putWithSpace(g, tkDistinct, "distinct")
|
if sonsLen(n) > 0:
|
||||||
gsub(g, n.sons[0])
|
putWithSpace(g, tkDistinct, "distinct")
|
||||||
|
gsub(g, n.sons[0])
|
||||||
|
else:
|
||||||
|
put(g, tkDistinct, "distinct")
|
||||||
of nkTypeDef:
|
of nkTypeDef:
|
||||||
gsub(g, n.sons[0])
|
gsub(g, n.sons[0])
|
||||||
gsub(g, n.sons[1])
|
gsub(g, n.sons[1])
|
||||||
|
|
@ -858,11 +870,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
putWithSpace(g, tkEquals, "=")
|
putWithSpace(g, tkEquals, "=")
|
||||||
gsub(g, n.sons[2])
|
gsub(g, n.sons[2])
|
||||||
of nkObjectTy:
|
of nkObjectTy:
|
||||||
putWithSpace(g, tkObject, "object")
|
if sonsLen(n) > 0:
|
||||||
gsub(g, n.sons[0])
|
putWithSpace(g, tkObject, "object")
|
||||||
gsub(g, n.sons[1])
|
gsub(g, n.sons[0])
|
||||||
gcoms(g)
|
gsub(g, n.sons[1])
|
||||||
gsub(g, n.sons[2])
|
gcoms(g)
|
||||||
|
gsub(g, n.sons[2])
|
||||||
|
else:
|
||||||
|
put(g, tkObject, "object")
|
||||||
of nkRecList:
|
of nkRecList:
|
||||||
indentNL(g)
|
indentNL(g)
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
|
|
@ -875,17 +890,23 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
putWithSpace(g, tkOf, "of")
|
putWithSpace(g, tkOf, "of")
|
||||||
gsub(g, n.sons[0])
|
gsub(g, n.sons[0])
|
||||||
of nkProcTy:
|
of nkProcTy:
|
||||||
putWithSpace(g, tkProc, "proc")
|
if sonsLen(n) > 0:
|
||||||
gsub(g, n.sons[0])
|
putWithSpace(g, tkProc, "proc")
|
||||||
gsub(g, n.sons[1])
|
gsub(g, n.sons[0])
|
||||||
|
gsub(g, n.sons[1])
|
||||||
|
else:
|
||||||
|
put(g, tkProc, "proc")
|
||||||
of nkEnumTy:
|
of nkEnumTy:
|
||||||
putWithSpace(g, tkEnum, "enum")
|
if sonsLen(n) > 0:
|
||||||
gsub(g, n.sons[0])
|
putWithSpace(g, tkEnum, "enum")
|
||||||
gcoms(g)
|
gsub(g, n.sons[0])
|
||||||
indentNL(g)
|
gcoms(g)
|
||||||
gcommaAux(g, n, g.indent, 1)
|
indentNL(g)
|
||||||
gcoms(g) # BUGFIX: comment for the last enum field
|
gcommaAux(g, n, g.indent, 1)
|
||||||
dedent(g)
|
gcoms(g) # BUGFIX: comment for the last enum field
|
||||||
|
dedent(g)
|
||||||
|
else:
|
||||||
|
put(g, tkEnum, "enum")
|
||||||
of nkEnumFieldDef:
|
of nkEnumFieldDef:
|
||||||
gsub(g, n.sons[0])
|
gsub(g, n.sons[0])
|
||||||
put(g, tkSpaces, Space)
|
put(g, tkSpaces, Space)
|
||||||
|
|
@ -1033,9 +1054,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
gsub(g, n.sons[0])
|
gsub(g, n.sons[0])
|
||||||
of nkTupleTy:
|
of nkTupleTy:
|
||||||
put(g, tkTuple, "tuple")
|
put(g, tkTuple, "tuple")
|
||||||
put(g, tkBracketLe, "[")
|
if sonsLen(n) > 0:
|
||||||
gcomma(g, n)
|
put(g, tkBracketLe, "[")
|
||||||
put(g, tkBracketRi, "]")
|
gcomma(g, n)
|
||||||
|
put(g, tkBracketRi, "]")
|
||||||
else:
|
else:
|
||||||
#nkNone, nkMetaNode, nkTableConstr, nkExplicitTypeListCall:
|
#nkNone, nkMetaNode, nkTableConstr, nkExplicitTypeListCall:
|
||||||
InternalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
|
InternalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
c.p = oldP # restore
|
c.p = oldP # restore
|
||||||
c.module = oldMod
|
c.module = oldMod
|
||||||
dec(c.InstCounter)
|
dec(c.InstCounter)
|
||||||
|
|
||||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
|
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
|
||||||
var cl: TReplTypeVars
|
var cl: TReplTypeVars
|
||||||
InitIdTable(cl.symMap)
|
InitIdTable(cl.symMap)
|
||||||
|
|
|
||||||
171
rod/semstmts.nim
171
rod/semstmts.nim
|
|
@ -358,49 +358,120 @@ proc semConst(c: PContext, n: PNode): PNode =
|
||||||
addSon(b, copyTree(def))
|
addSon(b, copyTree(def))
|
||||||
addSon(result, b)
|
addSon(result, b)
|
||||||
|
|
||||||
|
proc transfFieldLoopBody(n: PNode, forLoop: PNode,
|
||||||
|
tupleType: PType,
|
||||||
|
tupleIndex, first: int): PNode =
|
||||||
|
case n.kind
|
||||||
|
of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n
|
||||||
|
of nkIdent:
|
||||||
|
result = n
|
||||||
|
var L = sonsLen(forLoop)
|
||||||
|
# field name:
|
||||||
|
if first > 0:
|
||||||
|
if n.ident.id == forLoop[0].ident.id:
|
||||||
|
if tupleType.n == nil:
|
||||||
|
# ugh, there are no field names:
|
||||||
|
result = newStrNode(nkStrLit, "")
|
||||||
|
else:
|
||||||
|
result = newStrNode(nkStrLit, tupleType.n.sons[tupleIndex].sym.name.s)
|
||||||
|
return
|
||||||
|
# other fields:
|
||||||
|
for i in first..L-3:
|
||||||
|
if n.ident.id == forLoop[i].ident.id:
|
||||||
|
var call = forLoop.sons[L-2]
|
||||||
|
var tupl = call.sons[i+1-first]
|
||||||
|
result = newNodeI(nkBracketExpr, n.info)
|
||||||
|
result.add(tupl)
|
||||||
|
result.add(newIntNode(nkIntLit, tupleIndex))
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
result = copyNode(n)
|
||||||
|
newSons(result, sonsLen(n))
|
||||||
|
for i in countup(0, sonsLen(n)-1):
|
||||||
|
result.sons[i] = transfFieldLoopBody(n.sons[i], forLoop,
|
||||||
|
tupleType, tupleIndex, first)
|
||||||
|
|
||||||
|
proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
|
||||||
|
# so that 'break' etc. work as expected, we produce
|
||||||
|
# a 'while true: stmt; break' loop ...
|
||||||
|
result = newNodeI(nkWhileStmt, n.info)
|
||||||
|
var trueSymbol = StrTableGet(magicsys.systemModule.Tab, getIdent"true")
|
||||||
|
if trueSymbol == nil: GlobalError(n.info, errSystemNeeds, "true")
|
||||||
|
|
||||||
|
result.add(newSymNode(trueSymbol, n.info))
|
||||||
|
var stmts = newNodeI(nkStmtList, n.info)
|
||||||
|
result.add(stmts)
|
||||||
|
|
||||||
|
var length = sonsLen(n)
|
||||||
|
var call = n.sons[length-2]
|
||||||
|
if length-2 != sonsLen(call)-1 + ord(m==mFieldPairs):
|
||||||
|
GlobalError(n.info, errWrongNumberOfVariables)
|
||||||
|
|
||||||
|
var tupleTypeA = skipTypes(call.sons[1].typ, abstractVar)
|
||||||
|
if tupleTypeA.kind != tyTuple: InternalError(n.info, "no tuple type!")
|
||||||
|
for i in 1..call.len-1:
|
||||||
|
var tupleTypeB = skipTypes(call.sons[i].typ, abstractVar)
|
||||||
|
if not SameType(tupleTypeA, tupleTypeB):
|
||||||
|
typeMismatch(call.sons[i], tupleTypeA, tupleTypeB)
|
||||||
|
|
||||||
|
Inc(c.p.nestedLoopCounter)
|
||||||
|
var loopBody = n.sons[length-1]
|
||||||
|
for i in 0..sonsLen(tupleTypeA)-1:
|
||||||
|
openScope(c.tab)
|
||||||
|
var body = transfFieldLoopBody(loopBody, n, tupleTypeA, i,
|
||||||
|
ord(m==mFieldPairs))
|
||||||
|
stmts.add(SemStmt(c, body))
|
||||||
|
closeScope(c.tab)
|
||||||
|
Dec(c.p.nestedLoopCounter)
|
||||||
|
var b = newNodeI(nkBreakStmt, n.info)
|
||||||
|
b.add(ast.emptyNode)
|
||||||
|
stmts.add(b)
|
||||||
|
|
||||||
|
proc createCountupNode(c: PContext, rangeNode: PNode): PNode =
|
||||||
|
# convert ``in 3..5`` to ``in countup(3, 5)``
|
||||||
|
checkSonsLen(rangeNode, 2)
|
||||||
|
result = newNodeI(nkCall, rangeNode.info)
|
||||||
|
var countUp = StrTableGet(magicsys.systemModule.Tab, getIdent"countup")
|
||||||
|
if countUp == nil: GlobalError(rangeNode.info, errSystemNeeds, "countup")
|
||||||
|
newSons(result, 3)
|
||||||
|
result.sons[0] = newSymNode(countup)
|
||||||
|
result.sons[1] = rangeNode.sons[0]
|
||||||
|
result.sons[2] = rangeNode.sons[1]
|
||||||
|
|
||||||
proc semFor(c: PContext, n: PNode): PNode =
|
proc semFor(c: PContext, n: PNode): PNode =
|
||||||
var
|
|
||||||
v, countup: PSym
|
|
||||||
iter: PType
|
|
||||||
countupNode, call: PNode
|
|
||||||
result = n
|
result = n
|
||||||
checkMinSonsLen(n, 3)
|
checkMinSonsLen(n, 3)
|
||||||
var length = sonsLen(n)
|
var length = sonsLen(n)
|
||||||
openScope(c.tab)
|
openScope(c.tab)
|
||||||
if n.sons[length - 2].kind == nkRange:
|
if n.sons[length-2].kind == nkRange:
|
||||||
checkSonsLen(n.sons[length - 2], 2)
|
n.sons[length-2] = createCountupNode(c, n.sons[length-2])
|
||||||
# convert ``in 3..5`` to ``in countup(3, 5)``
|
n.sons[length-2] = semExprWithType(c, n.sons[length-2], {efWantIterator})
|
||||||
countupNode = newNodeI(nkCall, n.sons[length - 2].info)
|
var call = n.sons[length-2]
|
||||||
countUp = StrTableGet(magicsys.systemModule.Tab, getIdent("countup"))
|
if call.kind != nkCall or call.sons[0].kind != nkSym or
|
||||||
if countUp == nil: GlobalError(countupNode.info, errSystemNeeds, "countup")
|
call.sons[0].sym.kind != skIterator:
|
||||||
newSons(countupNode, 3)
|
|
||||||
countupnode.sons[0] = newSymNode(countup)
|
|
||||||
countupNode.sons[1] = n.sons[length - 2].sons[0]
|
|
||||||
countupNode.sons[2] = n.sons[length - 2].sons[1]
|
|
||||||
n.sons[length - 2] = countupNode
|
|
||||||
n.sons[length - 2] = semExprWithType(c, n.sons[length - 2], {efWantIterator})
|
|
||||||
call = n.sons[length - 2]
|
|
||||||
if (call.kind != nkCall) or (call.sons[0].kind != nkSym) or
|
|
||||||
(call.sons[0].sym.kind != skIterator):
|
|
||||||
GlobalError(n.sons[length - 2].info, errIteratorExpected)
|
GlobalError(n.sons[length - 2].info, errIteratorExpected)
|
||||||
iter = skipTypes(n.sons[length - 2].typ, {tyGenericInst})
|
elif call.sons[0].sym.magic != mNone:
|
||||||
if iter.kind != tyTuple:
|
result = semForFields(c, n, call.sons[0].sym.magic)
|
||||||
if length != 3: GlobalError(n.info, errWrongNumberOfVariables)
|
else:
|
||||||
v = newSymS(skForVar, n.sons[0], c)
|
var iter = skipTypes(n.sons[length-2].typ, {tyGenericInst})
|
||||||
v.typ = iter
|
if iter.kind != tyTuple:
|
||||||
n.sons[0] = newSymNode(v)
|
if length != 3: GlobalError(n.info, errWrongNumberOfVariables)
|
||||||
addDecl(c, v)
|
var v = newSymS(skForVar, n.sons[0], c)
|
||||||
else:
|
v.typ = iter
|
||||||
if length-2 != sonsLen(iter): GlobalError(n.info, errWrongNumberOfVariables)
|
n.sons[0] = newSymNode(v)
|
||||||
for i in countup(0, length - 3):
|
|
||||||
v = newSymS(skForVar, n.sons[i], c)
|
|
||||||
v.typ = iter.sons[i]
|
|
||||||
n.sons[i] = newSymNode(v)
|
|
||||||
addDecl(c, v)
|
addDecl(c, v)
|
||||||
Inc(c.p.nestedLoopCounter)
|
else:
|
||||||
n.sons[length - 1] = SemStmt(c, n.sons[length - 1])
|
if length-2 != sonsLen(iter):
|
||||||
|
GlobalError(n.info, errWrongNumberOfVariables)
|
||||||
|
for i in countup(0, length - 3):
|
||||||
|
var v = newSymS(skForVar, n.sons[i], c)
|
||||||
|
v.typ = iter.sons[i]
|
||||||
|
n.sons[i] = newSymNode(v)
|
||||||
|
addDecl(c, v)
|
||||||
|
Inc(c.p.nestedLoopCounter)
|
||||||
|
n.sons[length-1] = SemStmt(c, n.sons[length-1])
|
||||||
|
Dec(c.p.nestedLoopCounter)
|
||||||
closeScope(c.tab)
|
closeScope(c.tab)
|
||||||
Dec(c.p.nestedLoopCounter)
|
|
||||||
|
|
||||||
proc semRaise(c: PContext, n: PNode): PNode =
|
proc semRaise(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
|
|
@ -436,34 +507,6 @@ proc semTry(c: PContext, n: PNode): PNode =
|
||||||
# last child of an nkExcept/nkFinally branch is a statement:
|
# last child of an nkExcept/nkFinally branch is a statement:
|
||||||
a.sons[length - 1] = semStmtScope(c, a.sons[length - 1])
|
a.sons[length - 1] = semStmtScope(c, a.sons[length - 1])
|
||||||
|
|
||||||
proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
|
||||||
result = copyNode(n)
|
|
||||||
if n.kind != nkGenericParams: InternalError(n.info, "semGenericParamList")
|
|
||||||
for i in countup(0, sonsLen(n)-1):
|
|
||||||
var a = n.sons[i]
|
|
||||||
if a.kind != nkIdentDefs: illFormedAst(n)
|
|
||||||
var L = sonsLen(a)
|
|
||||||
var def = a.sons[L-1]
|
|
||||||
var typ: PType
|
|
||||||
if a.sons[L-2].kind != nkEmpty: typ = semTypeNode(c, a.sons[L-2], nil)
|
|
||||||
elif def.kind != nkEmpty: typ = newTypeS(tyExpr, c)
|
|
||||||
else: typ = nil
|
|
||||||
for j in countup(0, L-3):
|
|
||||||
var s: PSym
|
|
||||||
if (typ == nil) or (typ.kind == tyTypeDesc):
|
|
||||||
s = newSymS(skType, a.sons[j], c)
|
|
||||||
s.typ = newTypeS(tyGenericParam, c)
|
|
||||||
else:
|
|
||||||
# not a type param, but an expression
|
|
||||||
s = newSymS(skGenericParam, a.sons[j], c)
|
|
||||||
s.typ = typ
|
|
||||||
if def.kind != nkEmpty: s.ast = def
|
|
||||||
s.typ.sym = s
|
|
||||||
if father != nil: addSon(father, s.typ)
|
|
||||||
s.position = i
|
|
||||||
addSon(result, newSymNode(s))
|
|
||||||
addDecl(c, s)
|
|
||||||
|
|
||||||
proc addGenericParamListToScope(c: PContext, n: PNode) =
|
proc addGenericParamListToScope(c: PContext, n: PNode) =
|
||||||
if n.kind != nkGenericParams:
|
if n.kind != nkGenericParams:
|
||||||
InternalError(n.info, "addGenericParamListToScope")
|
InternalError(n.info, "addGenericParamListToScope")
|
||||||
|
|
@ -741,7 +784,7 @@ proc semIterator(c: PContext, n: PNode): PNode =
|
||||||
var t = s.typ
|
var t = s.typ
|
||||||
if t.sons[0] == nil:
|
if t.sons[0] == nil:
|
||||||
LocalError(n.info, errXNeedsReturnType, "iterator")
|
LocalError(n.info, errXNeedsReturnType, "iterator")
|
||||||
if n.sons[codePos].kind == nkEmpty:
|
if n.sons[codePos].kind == nkEmpty and s.magic == mNone:
|
||||||
LocalError(n.info, errImplOfXexpected, s.name.s)
|
LocalError(n.info, errImplOfXexpected, s.name.s)
|
||||||
|
|
||||||
proc semProc(c: PContext, n: PNode): PNode =
|
proc semProc(c: PContext, n: PNode): PNode =
|
||||||
|
|
|
||||||
|
|
@ -173,12 +173,12 @@ proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
|
||||||
else:
|
else:
|
||||||
GlobalError(n.info, errXExpectsOneTypeParam, "ordinal")
|
GlobalError(n.info, errXExpectsOneTypeParam, "ordinal")
|
||||||
|
|
||||||
proc semTypeIdent(c: PContext, n: PNode): PSym =
|
proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||||
result = qualifiedLookup(c, n, {checkAmbiguity, checkUndeclared})
|
result = qualifiedLookup(c, n, {checkAmbiguity, checkUndeclared})
|
||||||
if (result != nil):
|
if result != nil:
|
||||||
markUsed(n, result)
|
markUsed(n, result)
|
||||||
if result.kind != skType: GlobalError(n.info, errTypeExpected)
|
if result.kind != skType: GlobalError(n.info, errTypeExpected)
|
||||||
else:
|
else:
|
||||||
GlobalError(n.info, errIdentifierExpected)
|
GlobalError(n.info, errIdentifierExpected)
|
||||||
|
|
||||||
proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||||
|
|
@ -441,8 +441,6 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
|
if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
|
||||||
addInheritedFields(c, check, pos, concreteBase)
|
addInheritedFields(c, check, pos, concreteBase)
|
||||||
else:
|
else:
|
||||||
debug base
|
|
||||||
debug concreteBase
|
|
||||||
localError(n.sons[1].info, errInheritanceOnlyWithNonFinalObjects)
|
localError(n.sons[1].info, errInheritanceOnlyWithNonFinalObjects)
|
||||||
if n.kind != nkObjectTy: InternalError(n.info, "semObjectNode")
|
if n.kind != nkObjectTy: InternalError(n.info, "semObjectNode")
|
||||||
result = newOrPrevType(tyObject, prev, c)
|
result = newOrPrevType(tyObject, prev, c)
|
||||||
|
|
@ -632,10 +630,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
|
proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
|
||||||
m.typ.kind = kind
|
m.typ.kind = kind
|
||||||
m.typ.align = size
|
m.typ.align = size
|
||||||
m.typ.size = size #m.typ.sym := nil;
|
m.typ.size = size
|
||||||
|
|
||||||
proc processMagicType(c: PContext, m: PSym) =
|
proc processMagicType(c: PContext, m: PSym) =
|
||||||
case m.magic #registerSysType(m.typ);
|
case m.magic
|
||||||
of mInt: setMagicType(m, tyInt, intSize)
|
of mInt: setMagicType(m, tyInt, intSize)
|
||||||
of mInt8: setMagicType(m, tyInt8, 1)
|
of mInt8: setMagicType(m, tyInt8, 1)
|
||||||
of mInt16: setMagicType(m, tyInt16, 2)
|
of mInt16: setMagicType(m, tyInt16, 2)
|
||||||
|
|
@ -656,13 +654,70 @@ proc processMagicType(c: PContext, m: PSym) =
|
||||||
of mEmptySet:
|
of mEmptySet:
|
||||||
setMagicType(m, tySet, 1)
|
setMagicType(m, tySet, 1)
|
||||||
addSon(m.typ, newTypeS(tyEmpty, c))
|
addSon(m.typ, newTypeS(tyEmpty, c))
|
||||||
of mIntSetBaseType:
|
of mIntSetBaseType: setMagicType(m, tyRange, intSize)
|
||||||
setMagicType(m, tyRange, intSize) #intSetBaseType := m.typ;
|
|
||||||
return
|
|
||||||
of mNil: setMagicType(m, tyNil, ptrSize)
|
of mNil: setMagicType(m, tyNil, ptrSize)
|
||||||
of mExpr: setMagicType(m, tyExpr, 0)
|
of mExpr: setMagicType(m, tyExpr, 0)
|
||||||
of mStmt: setMagicType(m, tyStmt, 0)
|
of mStmt: setMagicType(m, tyStmt, 0)
|
||||||
of mTypeDesc: setMagicType(m, tyTypeDesc, 0)
|
of mTypeDesc: setMagicType(m, tyTypeDesc, 0)
|
||||||
of mArray, mOpenArray, mRange, mSet, mSeq, mOrdinal: return
|
of mArray, mOpenArray, mRange, mSet, mSeq, mOrdinal: nil
|
||||||
else: GlobalError(m.info, errTypeExpected)
|
else: GlobalError(m.info, errTypeExpected)
|
||||||
|
|
||||||
|
proc newConstraint(c: PContext, k: TTypeKind): PType =
|
||||||
|
result = newTypeS(tyOrdinal, c)
|
||||||
|
result.addSon(newTypeS(k, c))
|
||||||
|
|
||||||
|
proc semGenericConstraints(c: PContext, n: PNode, result: PType) =
|
||||||
|
case n.kind
|
||||||
|
of nkProcTy: result.addSon(newConstraint(c, tyProc))
|
||||||
|
of nkEnumTy: result.addSon(newConstraint(c, tyEnum))
|
||||||
|
of nkObjectTy: result.addSon(newConstraint(c, tyObject))
|
||||||
|
of nkTupleTy: result.addSon(newConstraint(c, tyTuple))
|
||||||
|
of nkDistinctTy: result.addSon(newConstraint(c, tyDistinct))
|
||||||
|
of nkVarTy: result.addSon(newConstraint(c, tyVar))
|
||||||
|
of nkPtrTy: result.addSon(newConstraint(c, tyPtr))
|
||||||
|
of nkRefTy: result.addSon(newConstraint(c, tyRef))
|
||||||
|
of nkInfix:
|
||||||
|
semGenericConstraints(c, n.sons[1], result)
|
||||||
|
semGenericConstraints(c, n.sons[2], result)
|
||||||
|
else:
|
||||||
|
result.addSon(semTypeNode(c, n, nil))
|
||||||
|
|
||||||
|
proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||||
|
result = copyNode(n)
|
||||||
|
if n.kind != nkGenericParams: InternalError(n.info, "semGenericParamList")
|
||||||
|
for i in countup(0, sonsLen(n)-1):
|
||||||
|
var a = n.sons[i]
|
||||||
|
if a.kind != nkIdentDefs: illFormedAst(n)
|
||||||
|
var L = sonsLen(a)
|
||||||
|
var def = a.sons[L-1]
|
||||||
|
var typ: PType
|
||||||
|
if a.sons[L-2].kind != nkEmpty:
|
||||||
|
typ = newTypeS(tyGenericParam, c)
|
||||||
|
semGenericConstraints(c, a.sons[L-2], typ)
|
||||||
|
elif def.kind != nkEmpty: typ = newTypeS(tyExpr, c)
|
||||||
|
else: typ = nil
|
||||||
|
for j in countup(0, L-3):
|
||||||
|
var s: PSym
|
||||||
|
if typ == nil:
|
||||||
|
s = newSymS(skType, a.sons[j], c)
|
||||||
|
s.typ = newTypeS(tyGenericParam, c)
|
||||||
|
else:
|
||||||
|
case typ.kind
|
||||||
|
of tyTypeDesc:
|
||||||
|
s = newSymS(skType, a.sons[j], c)
|
||||||
|
s.typ = newTypeS(tyGenericParam, c)
|
||||||
|
of tyExpr:
|
||||||
|
# not a type param, but an expression
|
||||||
|
s = newSymS(skGenericParam, a.sons[j], c)
|
||||||
|
s.typ = typ
|
||||||
|
else:
|
||||||
|
s = newSymS(skType, a.sons[j], c)
|
||||||
|
s.typ = typ
|
||||||
|
if def.kind != nkEmpty: s.ast = def
|
||||||
|
s.typ.sym = s
|
||||||
|
if father != nil: addSon(father, s.typ)
|
||||||
|
s.position = i
|
||||||
|
addSon(result, newSymNode(s))
|
||||||
|
addDecl(c, s)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,10 @@ type
|
||||||
# for example
|
# for example
|
||||||
|
|
||||||
TTypeRelation* = enum # order is important!
|
TTypeRelation* = enum # order is important!
|
||||||
isNone, isConvertible, isIntConv, isSubtype, isGeneric, isEqual
|
isNone, isConvertible, isIntConv, isSubtype,
|
||||||
|
isLifted, # match, but do not change argument type to formal's type!
|
||||||
|
isGeneric,
|
||||||
|
isEqual
|
||||||
|
|
||||||
proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
|
proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
|
||||||
c.exactMatches = 0
|
c.exactMatches = 0
|
||||||
|
|
@ -144,8 +147,8 @@ proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
|
||||||
else:
|
else:
|
||||||
var k = skipTypes(a, {tyRange}).kind
|
var k = skipTypes(a, {tyRange}).kind
|
||||||
if k == f.kind: result = isSubtype
|
if k == f.kind: result = isSubtype
|
||||||
elif (f.kind == tyInt) and (k in {tyInt..tyInt32}): result = isIntConv
|
elif f.kind == tyInt and k in {tyInt..tyInt32}: result = isIntConv
|
||||||
elif (k >= min) and (k <= max): result = isConvertible
|
elif k >= min and k <= max: result = isConvertible
|
||||||
else: result = isNone
|
else: result = isNone
|
||||||
|
|
||||||
proc handleFloatRange(f, a: PType): TTypeRelation =
|
proc handleFloatRange(f, a: PType): TTypeRelation =
|
||||||
|
|
@ -159,7 +162,7 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
|
||||||
|
|
||||||
proc isObjectSubtype(a, f: PType): bool =
|
proc isObjectSubtype(a, f: PType): bool =
|
||||||
var t = a
|
var t = a
|
||||||
while (t != nil) and (t.id != f.id): t = base(t)
|
while t != nil and t.id != f.id: t = base(t)
|
||||||
result = t != nil
|
result = t != nil
|
||||||
|
|
||||||
proc minRel(a, b: TTypeRelation): TTypeRelation =
|
proc minRel(a, b: TTypeRelation): TTypeRelation =
|
||||||
|
|
@ -182,11 +185,15 @@ proc tupleRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||||
var x = f.n.sons[i].sym
|
var x = f.n.sons[i].sym
|
||||||
var y = a.n.sons[i].sym
|
var y = a.n.sons[i].sym
|
||||||
if x.name.id != y.name.id: return isNone
|
if x.name.id != y.name.id: return isNone
|
||||||
|
elif sonsLen(f) == 0:
|
||||||
|
idTablePut(mapping, f, a)
|
||||||
|
result = isLifted
|
||||||
|
|
||||||
|
proc constraintRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||||
|
result = isNone
|
||||||
|
if f.kind == a.kind: result = isGeneric
|
||||||
|
|
||||||
proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||||
var
|
|
||||||
x, concrete: PType
|
|
||||||
m: TTypeRelation
|
|
||||||
# is a subtype of f?
|
# is a subtype of f?
|
||||||
result = isNone
|
result = isNone
|
||||||
assert(f != nil)
|
assert(f != nil)
|
||||||
|
|
@ -272,9 +279,11 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||||
if result < isGeneric: result = isNone
|
if result < isGeneric: result = isNone
|
||||||
else: nil
|
else: nil
|
||||||
of tyOrdinal:
|
of tyOrdinal:
|
||||||
if isOrdinalType(a):
|
if f.sons[0].kind != tyGenericParam:
|
||||||
if a.kind == tyOrdinal: x = a.sons[0]
|
# some constraint:
|
||||||
else: x = a
|
result = constraintRel(mapping, f.sons[0], a)
|
||||||
|
elif isOrdinalType(a):
|
||||||
|
var x = if a.kind == tyOrdinal: a.sons[0] else: a
|
||||||
result = typeRel(mapping, f.sons[0], x)
|
result = typeRel(mapping, f.sons[0], x)
|
||||||
if result < isGeneric: result = isNone
|
if result < isGeneric: result = isNone
|
||||||
of tyForward: InternalError("forward type in typeRel()")
|
of tyForward: InternalError("forward type in typeRel()")
|
||||||
|
|
@ -319,6 +328,7 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||||
# return type!
|
# return type!
|
||||||
result = isEqual # start with maximum; also correct for no
|
result = isEqual # start with maximum; also correct for no
|
||||||
# params at all
|
# params at all
|
||||||
|
var m: TTypeRelation
|
||||||
for i in countup(1, sonsLen(f) - 1):
|
for i in countup(1, sonsLen(f) - 1):
|
||||||
m = typeRel(mapping, f.sons[i], a.sons[i])
|
m = typeRel(mapping, f.sons[i], a.sons[i])
|
||||||
if (m == isNone) and
|
if (m == isNone) and
|
||||||
|
|
@ -392,26 +402,25 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||||
if result != isNone:
|
if result != isNone:
|
||||||
# we steal the generic parameters from the tyGenericBody:
|
# we steal the generic parameters from the tyGenericBody:
|
||||||
for i in countup(1, sonsLen(f) - 1):
|
for i in countup(1, sonsLen(f) - 1):
|
||||||
x = PType(idTableGet(mapping, f.sons[0].sons[i - 1]))
|
var x = PType(idTableGet(mapping, f.sons[0].sons[i - 1]))
|
||||||
if (x == nil) or (x.kind == tyGenericParam):
|
if (x == nil) or (x.kind == tyGenericParam):
|
||||||
InternalError("wrong instantiated type!")
|
InternalError("wrong instantiated type!")
|
||||||
idTablePut(mapping, f.sons[i], x)
|
idTablePut(mapping, f.sons[i], x)
|
||||||
of tyGenericParam:
|
of tyGenericParam:
|
||||||
x = PType(idTableGet(mapping, f))
|
var x = PType(idTableGet(mapping, f))
|
||||||
if x == nil:
|
if x == nil:
|
||||||
if sonsLen(f) == 0:
|
if sonsLen(f) == 0:
|
||||||
# no constraints
|
# no constraints
|
||||||
concrete = concreteType(mapping, a)
|
var concrete = concreteType(mapping, a)
|
||||||
if concrete != nil:
|
if concrete != nil:
|
||||||
#MessageOut('putting: ' + f.sym.name.s);
|
#MessageOut('putting: ' + f.sym.name.s);
|
||||||
idTablePut(mapping, f, concrete)
|
idTablePut(mapping, f, concrete)
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
else:
|
else:
|
||||||
InternalError(f.sym.info, "has constraints: " & f.sym.name.s)
|
|
||||||
# check constraints:
|
# check constraints:
|
||||||
for i in countup(0, sonsLen(f) - 1):
|
for i in countup(0, sonsLen(f) - 1):
|
||||||
if typeRel(mapping, f.sons[i], a) >= isSubtype:
|
if typeRel(mapping, f.sons[i], a) >= isSubtype:
|
||||||
concrete = concreteType(mapping, a)
|
var concrete = concreteType(mapping, a)
|
||||||
if concrete != nil:
|
if concrete != nil:
|
||||||
idTablePut(mapping, f, concrete)
|
idTablePut(mapping, f, concrete)
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
|
|
@ -484,6 +493,9 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
of isSubtype:
|
of isSubtype:
|
||||||
inc(m.subtypeMatches)
|
inc(m.subtypeMatches)
|
||||||
result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c)
|
result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c)
|
||||||
|
of isLifted:
|
||||||
|
inc(m.genericMatches)
|
||||||
|
result = copyTree(arg)
|
||||||
of isGeneric:
|
of isGeneric:
|
||||||
inc(m.genericMatches)
|
inc(m.genericMatches)
|
||||||
result = copyTree(arg)
|
result = copyTree(arg)
|
||||||
|
|
|
||||||
15
tests/accept/compile/tconstraints.nim
Normal file
15
tests/accept/compile/tconstraints.nim
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
|
||||||
|
proc myGenericProc[T: object|tuple|int|ptr|ref|distinct](x: T): string =
|
||||||
|
result = $x
|
||||||
|
|
||||||
|
type
|
||||||
|
TMyObj = tuple[x, y: int]
|
||||||
|
|
||||||
|
var
|
||||||
|
x: TMyObj
|
||||||
|
|
||||||
|
assert myGenericProc(232) == "232"
|
||||||
|
assert myGenericProc(x) == "(x: 0, y: 0)"
|
||||||
|
|
||||||
|
|
||||||
19
tests/accept/compile/tgenericmatcher.nim
Normal file
19
tests/accept/compile/tgenericmatcher.nim
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
type
|
||||||
|
TMatcherKind = enum
|
||||||
|
mkTerminal, mkSequence, mkAlternation, mkRepeat
|
||||||
|
TMatcher[T] = object
|
||||||
|
case kind: TMatcherKind
|
||||||
|
of mkTerminal:
|
||||||
|
value: T
|
||||||
|
of mkSequence, mkAlternation:
|
||||||
|
matchers: seq[TMatcher[T]]
|
||||||
|
of mkRepeat:
|
||||||
|
matcher: PMatcher[T]
|
||||||
|
min, max: int
|
||||||
|
PMatcher[T] = ref TMatcher[T]
|
||||||
|
|
||||||
|
var
|
||||||
|
m: PMatcher[int]
|
||||||
|
|
||||||
|
|
||||||
24
tests/accept/compile/tgenericrefs.nim
Normal file
24
tests/accept/compile/tgenericrefs.nim
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Compiles:
|
||||||
|
|
||||||
|
type
|
||||||
|
TA[T] = object
|
||||||
|
PA[T] = ref TA[T]
|
||||||
|
var a: PA[string]
|
||||||
|
|
||||||
|
# Compiles unless you use var a: PA[string]
|
||||||
|
type
|
||||||
|
PA = ref TA
|
||||||
|
TA[T] = object
|
||||||
|
|
||||||
|
|
||||||
|
# Cannot instanciate:
|
||||||
|
type
|
||||||
|
TA[T] = object
|
||||||
|
a: PA[T]
|
||||||
|
PA[T] = ref TA[T]
|
||||||
|
|
||||||
|
type
|
||||||
|
PA[T] = ref TA[T]
|
||||||
|
TA[T] = object
|
||||||
|
|
||||||
|
|
||||||
46
tests/accept/run/tfielditerator.nim
Normal file
46
tests/accept/run/tfielditerator.nim
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
discard """
|
||||||
|
output: '''
|
||||||
|
a char: true
|
||||||
|
a char: false
|
||||||
|
an int: 5
|
||||||
|
an int: 6
|
||||||
|
a string: abc
|
||||||
|
false
|
||||||
|
true
|
||||||
|
true
|
||||||
|
false
|
||||||
|
true
|
||||||
|
a: a
|
||||||
|
b: b
|
||||||
|
x: 5
|
||||||
|
y: 6
|
||||||
|
z: abc
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
TMyTuple = tuple[a, b: char, x, y: int, z: string]
|
||||||
|
|
||||||
|
proc p(x: char) = echo "a char: ", x <= 'a'
|
||||||
|
proc p(x: int) = echo "an int: ", x
|
||||||
|
proc p(x: string) = echo "a string: ", x
|
||||||
|
|
||||||
|
var x: TMyTuple = ('a', 'b', 5, 6, "abc")
|
||||||
|
var y: TMyTuple = ('A', 'b', 5, 9, "abc")
|
||||||
|
|
||||||
|
for f in fields(x):
|
||||||
|
p f
|
||||||
|
|
||||||
|
for a, b in fields(x, y):
|
||||||
|
echo a == b
|
||||||
|
|
||||||
|
for key, val in fieldPairs(x):
|
||||||
|
echo key, ": ", val
|
||||||
|
|
||||||
|
assert x != y
|
||||||
|
assert x == x
|
||||||
|
assert(not (x < x))
|
||||||
|
assert x <= x
|
||||||
|
assert y < x
|
||||||
|
assert y <= x
|
||||||
|
|
||||||
17
tests/accept/run/tkoeniglookup.nim
Normal file
17
tests/accept/run/tkoeniglookup.nim
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
discard """
|
||||||
|
output: '''x: 0 y: 0'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc ToString[T]*(x: T): string = return $x
|
||||||
|
|
||||||
|
|
||||||
|
type
|
||||||
|
TMyObj = object
|
||||||
|
x, y: int
|
||||||
|
|
||||||
|
proc `$`*(a: TMyObj): bool =
|
||||||
|
result = "x: " & a.x & " y: " & a.y
|
||||||
|
|
||||||
|
var a: TMyObj
|
||||||
|
echo toString(a)
|
||||||
|
|
||||||
18
tests/reject/tconstraints.nim
Normal file
18
tests/reject/tconstraints.nim
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
discard """
|
||||||
|
line: 15
|
||||||
|
errormsg: "type mismatch: got (int)"
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc myGenericProc[T: object|tuple|ptr|ref|distinct](x: T): string =
|
||||||
|
result = $x
|
||||||
|
|
||||||
|
type
|
||||||
|
TMyObj = tuple[x, y: int]
|
||||||
|
|
||||||
|
var
|
||||||
|
x: TMyObj
|
||||||
|
|
||||||
|
assert myGenericProc(232) == "232"
|
||||||
|
assert myGenericProc(x) == "(x: 0, y: 0)"
|
||||||
|
|
||||||
|
|
||||||
9
todo.txt
9
todo.txt
|
|
@ -1,13 +1,8 @@
|
||||||
- 'nimrod def': does not always work
|
|
||||||
|
|
||||||
- thread support: threadvar on Windows seems broken;
|
- thread support: threadvar on Windows seems broken;
|
||||||
add --deadlock_prevention:on|off switch
|
add --deadlock_prevention:on|off switch
|
||||||
- built-in serialization
|
- built-in serialization
|
||||||
|
|
||||||
- deprecate ^ and make it available as operator
|
- deprecate ^ and make it available as operator
|
||||||
- test branch coverage
|
|
||||||
- checked exceptions
|
|
||||||
- slicing
|
|
||||||
|
|
||||||
|
|
||||||
High priority (version 0.9.0)
|
High priority (version 0.9.0)
|
||||||
|
|
@ -61,6 +56,10 @@ Low priority
|
||||||
- nested tuple unpacking; no auto-unpacking in 'for' loops!
|
- nested tuple unpacking; no auto-unpacking in 'for' loops!
|
||||||
- better error messages for used keywords as identifiers
|
- better error messages for used keywords as identifiers
|
||||||
- case statement branches should support constant sets
|
- case statement branches should support constant sets
|
||||||
|
- 'nimrod def': does not always work
|
||||||
|
- test branch coverage
|
||||||
|
- checked exceptions
|
||||||
|
- slicing
|
||||||
|
|
||||||
|
|
||||||
Library
|
Library
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue