ugh, maybe broke git

This commit is contained in:
Araq
2011-04-01 15:07:16 +02:00
parent dc669155e3
commit 4741e8f9a1
25 changed files with 587 additions and 172 deletions

View File

@@ -137,7 +137,11 @@ pragma ::= '{.' optInd (colonExpr [comma])* optPar ('.}' | '}')
param ::= symbol (comma symbol)* (':' typeDesc ['=' expr] | '=' expr)
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 ']'

View File

@@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2008 Andreas Rumpf
# (c) Copyright 2011 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -30,14 +30,10 @@ proc finishHash(h: THash): THash {.inline.} =
proc hashData*(Data: Pointer, Size: int): THash =
## hashes an array of bytes of size `size`
var
h: THash
p: cstring
i, s: int
h = 0
p = cast[cstring](Data)
i = 0
s = size
var h: THash = 0
var p = cast[cstring](Data)
var i = 0
var s = size
while s > 0:
h = concHash(h, ord(p[i]))
Inc(i)
@@ -62,20 +58,16 @@ proc hash*(x: char): THash {.inline.} =
proc hash*(x: string): THash =
## efficient hashing of strings
var h: THash
h = 0
var h: THash = 0
for i in 0..x.len-1:
h = concHash(h, ord(x[i]))
result = finishHash(h)
proc hashIgnoreStyle*(x: string): THash =
## efficient hashing of strings; style is ignored
var
h: THash
c: Char
h = 0
var h: THash = 0
for i in 0..x.len-1:
c = x[i]
var c = x[i]
if c == '_':
continue # skip _
if c in {'A'..'Z'}:
@@ -85,13 +77,17 @@ proc hashIgnoreStyle*(x: string): THash =
proc hashIgnoreCase*(x: string): THash =
## efficient hashing of strings; case is ignored
var
h: THash
c: Char
h = 0
var h: THash = 0
for i in 0..x.len-1:
c = x[i]
var c = x[i]
if c in {'A'..'Z'}:
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
h = concHash(h, ord(c))
result = finishHash(h)
proc hash*[T: tuple](x: T): THash =
## efficient hashing of tuples.
for f in fields(x):
result = concHash(result, hash(f))
result = finishHash(result)

View File

@@ -237,10 +237,7 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
var r = parseUrl(url)
var headers = copy($httpMethod, len("http"))
if r.path != "":
headers.add(" /" & r.path & r.query)
else:
headers.add(" /")
headers.add(" /" & r.path & r.query)
headers.add(" HTTP/1.1\c\L")
add(headers, "Host: " & r.hostname & "\c\L")

View File

@@ -700,6 +700,18 @@ proc `$`*(node: PJsonNode): String =
result = ""
toPretty(result, node, 1, False)
iterator items*(node: PJsonNode): PJSonNode =
## Iterator for the items of `node`. `node` has to be a JArray.
assert node.kind == JArray
for i in items(node.elems):
yield i
iterator pairs*(node: PJsonNode): tuple[key: string, val: PJsonNode] =
## Iterator for the child elements of `node`. `node` has to be a JObject.
assert node.kind == JObject
for key, val in items(node.fields):
yield (key, val)
proc eat(p: var TJsonParser, tok: TTokKind) =
if p.tok == tok: discard getTok(p)
else: raiseParseErr(p, tokToStr[tok])
@@ -711,7 +723,7 @@ proc parseJson(p: var TJsonParser): PJsonNode =
result = newJString(p.a)
discard getTok(p)
of tkInt:
result = newJInt(parseInt(p.a))
result = newJInt(parseBiggestInt(p.a))
discard getTok(p)
of tkFloat:
result = newJFloat(parseFloat(p.a))

View File

@@ -1130,6 +1130,12 @@ proc getConfigDir*(): string {.rtl, extern: "nos$1".} =
when defined(windows): return getEnv("APPDATA") & "\\"
else: return getEnv("HOME") & "/.config/"
proc getTempDir*(): string {.rtl, extern: "nos$1".} =
## Returns the temporary directory of the current user for applications to
## save temporary files in.
when defined(windows): return getEnv("TEMP") & "\\"
else: return "/tmp/"
when defined(windows):
# Since we support GUI applications with Nimrod, we sometimes generate
# a WinMain entry proc. But a WinMain proc has no access to the parsed

View File

@@ -586,11 +586,11 @@ proc next*(my: var TXmlParser) =
of stateNormal:
getTok(my)
of stateStart:
my.state = stateNormal
getTok(my)
if my.kind == xmlPI and my.a == "xml":
# just skip the first ``<?xml >`` processing instruction
getTok(my)
my.state = stateNormal
of stateAttr:
# parse an attribute key-value pair:
if my.buf[my.bufpos] == '>':

View File

@@ -68,11 +68,11 @@ proc parse(x: var TXmlParser, errors: var seq[string]): PXmlNode =
of xmlElementOpen:
result = newElement(x.elementName)
next(x)
result.attr = newStringTable()
result.attrs = newStringTable()
while true:
case x.kind
of xmlAttribute:
result.attr[x.attrKey] = x.attrValue
result.attrs[x.attrKey] = x.attrValue
next(x)
of xmlElementClose:
next(x)

View File

@@ -98,17 +98,17 @@ iterator items*(n: PXmlNode): PXmlNode {.inline.} =
assert n.k == xnElement
for i in 0 .. n.len-1: yield n[i]
proc attr*(n: PXmlNode): PXmlAttributes {.inline.} =
proc attrs*(n: PXmlNode): PXmlAttributes {.inline.} =
## gets the attributes belonging to `n`.
assert n.k == xnElement
result = n.fAttr
proc `attr=`*(n: PXmlNode, attr: PXmlAttributes) {.inline.} =
proc `attrs=`*(n: PXmlNode, attr: PXmlAttributes) {.inline.} =
## sets the attributes belonging to `n`.
assert n.k == xnElement
n.fAttr = attr
proc attrLen*(n: PXmlNode): int {.inline.} =
proc attrsLen*(n: PXmlNode): int {.inline.} =
## returns the number of `n`'s attributes.
assert n.k == xnElement
if not isNil(n.fAttr): result = len(n.fAttr)
@@ -262,3 +262,16 @@ macro `<>`*(x: expr): expr =
##
result = xmlConstructor(x)
proc child*(n: PXmlNode, name: string): PXmlNode =
## Finds the first child element of `n` with a name of `name`.
## Returns `nil` on failure.
assert n.kind == xnElement
for i in items(n):
if i.kind == xnElement:
if i.tag == name:
return i
proc attr*(n: PXmlNode, name: string): string =
## Finds the first attribute of `n` with a name of `name`.
assert n.kind == xnElement
return n.attrs[name]

View File

@@ -765,7 +765,7 @@ proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} =
setLen(x, xl + y.len)
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`.
## This is an O(1) operation.
var xl = x.len
@@ -1111,15 +1111,6 @@ iterator items*(a: cstring): char {.inline.} =
yield a[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: ref T): 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.}=
## 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):
if i == item: return
inc(result)
@@ -1200,6 +1191,62 @@ proc each*[T](data: var openArray[T], op: proc (x: var T)) =
## `op` to every item in `data`.
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 ---------------------------------------------
proc GC_disable*() {.rtl, inl.}

View File

@@ -1059,7 +1059,7 @@ type
TResponseType* = int32
PDialog* = ptr TDialog
TDialog* = object of TWindow
vbox*: PWidget
vbox*: PBox
action_area*: PWidget
separator*: PWidget
@@ -16866,6 +16866,9 @@ proc set_do_overwrite_confirmation*(chooser: PFileChooser,
do_overwrite_confirmation: gboolean){.cdecl, dynlib: lib,
importc: "gtk_file_chooser_set_do_overwrite_confirmation".}
proc get_realized*(w: PWidget): gboolean {.cdecl, dynlib: lib,
importc: "gtk_widget_get_realized".}
proc nimrod_init*() =
var
cmdLine{.importc: "cmdLine".}: array[0..255, cstring]

View File

@@ -237,7 +237,7 @@ type
tyGenericParam, # ``a`` in the example
tyDistinct,
tyEnum,
tyOrdinal,
tyOrdinal, # misnamed: should become 'tyConstraint'
tyArray,
tyObject,
tyTuple,
@@ -329,7 +329,9 @@ type
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
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,
mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, mNewString, mReset,
mArray, mOpenArray, mRange, mSet, mSeq,

View File

@@ -1014,12 +1014,77 @@ proc parseAsm(p: var TParser): PNode =
return
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 =
result = newNodeP(nkGenericParams, p)
getTok(p)
optInd(p, result)
while (p.tok.tokType == tkSymbol) or (p.tok.tokType == tkAccent):
var a = parseIdentColonEquals(p, {withBothOptional})
var a = parseGenericParam(p)
addSon(result, a)
if p.tok.tokType != tkComma: break
getTok(p)

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2010 Andreas Rumpf
# (c) Copyright 2011 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -839,17 +839,29 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
putWithSpace(g, tkType, "type")
gsub(g, n.sons[0])
of nkRefTy:
putWithSpace(g, tkRef, "ref")
gsub(g, n.sons[0])
if sonsLen(n) > 0:
putWithSpace(g, tkRef, "ref")
gsub(g, n.sons[0])
else:
put(g, tkRef, "ref")
of nkPtrTy:
putWithSpace(g, tkPtr, "ptr")
gsub(g, n.sons[0])
if sonsLen(n) > 0:
putWithSpace(g, tkPtr, "ptr")
gsub(g, n.sons[0])
else:
put(g, tkPtr, "ptr")
of nkVarTy:
putWithSpace(g, tkVar, "var")
gsub(g, n.sons[0])
if sonsLen(n) > 0:
putWithSpace(g, tkVar, "var")
gsub(g, n.sons[0])
else:
put(g, tkVar, "var")
of nkDistinctTy:
putWithSpace(g, tkDistinct, "distinct")
gsub(g, n.sons[0])
if sonsLen(n) > 0:
putWithSpace(g, tkDistinct, "distinct")
gsub(g, n.sons[0])
else:
put(g, tkDistinct, "distinct")
of nkTypeDef:
gsub(g, n.sons[0])
gsub(g, n.sons[1])
@@ -858,11 +870,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
putWithSpace(g, tkEquals, "=")
gsub(g, n.sons[2])
of nkObjectTy:
putWithSpace(g, tkObject, "object")
gsub(g, n.sons[0])
gsub(g, n.sons[1])
gcoms(g)
gsub(g, n.sons[2])
if sonsLen(n) > 0:
putWithSpace(g, tkObject, "object")
gsub(g, n.sons[0])
gsub(g, n.sons[1])
gcoms(g)
gsub(g, n.sons[2])
else:
put(g, tkObject, "object")
of nkRecList:
indentNL(g)
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")
gsub(g, n.sons[0])
of nkProcTy:
putWithSpace(g, tkProc, "proc")
gsub(g, n.sons[0])
gsub(g, n.sons[1])
if sonsLen(n) > 0:
putWithSpace(g, tkProc, "proc")
gsub(g, n.sons[0])
gsub(g, n.sons[1])
else:
put(g, tkProc, "proc")
of nkEnumTy:
putWithSpace(g, tkEnum, "enum")
gsub(g, n.sons[0])
gcoms(g)
indentNL(g)
gcommaAux(g, n, g.indent, 1)
gcoms(g) # BUGFIX: comment for the last enum field
dedent(g)
if sonsLen(n) > 0:
putWithSpace(g, tkEnum, "enum")
gsub(g, n.sons[0])
gcoms(g)
indentNL(g)
gcommaAux(g, n, g.indent, 1)
gcoms(g) # BUGFIX: comment for the last enum field
dedent(g)
else:
put(g, tkEnum, "enum")
of nkEnumFieldDef:
gsub(g, n.sons[0])
put(g, tkSpaces, Space)
@@ -1033,9 +1054,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
gsub(g, n.sons[0])
of nkTupleTy:
put(g, tkTuple, "tuple")
put(g, tkBracketLe, "[")
gcomma(g, n)
put(g, tkBracketRi, "]")
if sonsLen(n) > 0:
put(g, tkBracketLe, "[")
gcomma(g, n)
put(g, tkBracketRi, "]")
else:
#nkNone, nkMetaNode, nkTableConstr, nkExplicitTypeListCall:
InternalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')

View File

@@ -118,7 +118,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
c.p = oldP # restore
c.module = oldMod
dec(c.InstCounter)
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
var cl: TReplTypeVars
InitIdTable(cl.symMap)

View File

@@ -358,49 +358,120 @@ proc semConst(c: PContext, n: PNode): PNode =
addSon(b, copyTree(def))
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 =
var
v, countup: PSym
iter: PType
countupNode, call: PNode
result = n
checkMinSonsLen(n, 3)
var length = sonsLen(n)
openScope(c.tab)
if n.sons[length - 2].kind == nkRange:
checkSonsLen(n.sons[length - 2], 2)
# convert ``in 3..5`` to ``in countup(3, 5)``
countupNode = newNodeI(nkCall, n.sons[length - 2].info)
countUp = StrTableGet(magicsys.systemModule.Tab, getIdent("countup"))
if countUp == nil: GlobalError(countupNode.info, errSystemNeeds, "countup")
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):
if n.sons[length-2].kind == nkRange:
n.sons[length-2] = createCountupNode(c, n.sons[length-2])
n.sons[length-2] = semExprWithType(c, n.sons[length-2], {efWantIterator})
var 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)
iter = skipTypes(n.sons[length - 2].typ, {tyGenericInst})
if iter.kind != tyTuple:
if length != 3: GlobalError(n.info, errWrongNumberOfVariables)
v = newSymS(skForVar, n.sons[0], c)
v.typ = iter
n.sons[0] = newSymNode(v)
addDecl(c, v)
else:
if length-2 != sonsLen(iter): GlobalError(n.info, errWrongNumberOfVariables)
for i in countup(0, length - 3):
v = newSymS(skForVar, n.sons[i], c)
v.typ = iter.sons[i]
n.sons[i] = newSymNode(v)
elif call.sons[0].sym.magic != mNone:
result = semForFields(c, n, call.sons[0].sym.magic)
else:
var iter = skipTypes(n.sons[length-2].typ, {tyGenericInst})
if iter.kind != tyTuple:
if length != 3: GlobalError(n.info, errWrongNumberOfVariables)
var v = newSymS(skForVar, n.sons[0], c)
v.typ = iter
n.sons[0] = newSymNode(v)
addDecl(c, v)
Inc(c.p.nestedLoopCounter)
n.sons[length - 1] = SemStmt(c, n.sons[length - 1])
else:
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)
Dec(c.p.nestedLoopCounter)
proc semRaise(c: PContext, n: PNode): PNode =
result = n
@@ -436,34 +507,6 @@ proc semTry(c: PContext, n: PNode): PNode =
# last child of an nkExcept/nkFinally branch is a statement:
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) =
if n.kind != nkGenericParams:
InternalError(n.info, "addGenericParamListToScope")
@@ -741,7 +784,7 @@ proc semIterator(c: PContext, n: PNode): PNode =
var t = s.typ
if t.sons[0] == nil:
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)
proc semProc(c: PContext, n: PNode): PNode =

View File

@@ -173,12 +173,12 @@ proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
else:
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})
if (result != nil):
if result != nil:
markUsed(n, result)
if result.kind != skType: GlobalError(n.info, errTypeExpected)
else:
else:
GlobalError(n.info, errIdentifierExpected)
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:
addInheritedFields(c, check, pos, concreteBase)
else:
debug base
debug concreteBase
localError(n.sons[1].info, errInheritanceOnlyWithNonFinalObjects)
if n.kind != nkObjectTy: InternalError(n.info, "semObjectNode")
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) =
m.typ.kind = kind
m.typ.align = size
m.typ.size = size #m.typ.sym := nil;
m.typ.size = size
proc processMagicType(c: PContext, m: PSym) =
case m.magic #registerSysType(m.typ);
case m.magic
of mInt: setMagicType(m, tyInt, intSize)
of mInt8: setMagicType(m, tyInt8, 1)
of mInt16: setMagicType(m, tyInt16, 2)
@@ -656,13 +654,70 @@ proc processMagicType(c: PContext, m: PSym) =
of mEmptySet:
setMagicType(m, tySet, 1)
addSon(m.typ, newTypeS(tyEmpty, c))
of mIntSetBaseType:
setMagicType(m, tyRange, intSize) #intSetBaseType := m.typ;
return
of mIntSetBaseType: setMagicType(m, tyRange, intSize)
of mNil: setMagicType(m, tyNil, ptrSize)
of mExpr: setMagicType(m, tyExpr, 0)
of mStmt: setMagicType(m, tyStmt, 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)
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)

View File

@@ -32,7 +32,10 @@ type
# for example
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.} =
c.exactMatches = 0
@@ -144,8 +147,8 @@ proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
else:
var k = skipTypes(a, {tyRange}).kind
if k == f.kind: result = isSubtype
elif (f.kind == tyInt) and (k in {tyInt..tyInt32}): result = isIntConv
elif (k >= min) and (k <= max): result = isConvertible
elif f.kind == tyInt and k in {tyInt..tyInt32}: result = isIntConv
elif k >= min and k <= max: result = isConvertible
else: result = isNone
proc handleFloatRange(f, a: PType): TTypeRelation =
@@ -159,7 +162,7 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
proc isObjectSubtype(a, f: PType): bool =
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
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 y = a.n.sons[i].sym
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 =
var
x, concrete: PType
m: TTypeRelation
# is a subtype of f?
result = isNone
assert(f != nil)
@@ -272,9 +279,11 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
if result < isGeneric: result = isNone
else: nil
of tyOrdinal:
if isOrdinalType(a):
if a.kind == tyOrdinal: x = a.sons[0]
else: x = a
if f.sons[0].kind != tyGenericParam:
# some constraint:
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)
if result < isGeneric: result = isNone
of tyForward: InternalError("forward type in typeRel()")
@@ -319,6 +328,7 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
# return type!
result = isEqual # start with maximum; also correct for no
# params at all
var m: TTypeRelation
for i in countup(1, sonsLen(f) - 1):
m = typeRel(mapping, f.sons[i], a.sons[i])
if (m == isNone) and
@@ -392,26 +402,25 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
if result != isNone:
# we steal the generic parameters from the tyGenericBody:
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):
InternalError("wrong instantiated type!")
idTablePut(mapping, f.sons[i], x)
of tyGenericParam:
x = PType(idTableGet(mapping, f))
var x = PType(idTableGet(mapping, f))
if x == nil:
if sonsLen(f) == 0:
# no constraints
concrete = concreteType(mapping, a)
var concrete = concreteType(mapping, a)
if concrete != nil:
#MessageOut('putting: ' + f.sym.name.s);
idTablePut(mapping, f, concrete)
result = isGeneric
else:
InternalError(f.sym.info, "has constraints: " & f.sym.name.s)
# check constraints:
for i in countup(0, sonsLen(f) - 1):
if typeRel(mapping, f.sons[i], a) >= isSubtype:
concrete = concreteType(mapping, a)
var concrete = concreteType(mapping, a)
if concrete != nil:
idTablePut(mapping, f, concrete)
result = isGeneric
@@ -484,6 +493,9 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
of isSubtype:
inc(m.subtypeMatches)
result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c)
of isLifted:
inc(m.genericMatches)
result = copyTree(arg)
of isGeneric:
inc(m.genericMatches)
result = copyTree(arg)

View 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)"

View 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]

View 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

View 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

View 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)

View 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)"

View File

@@ -1,13 +1,8 @@
- 'nimrod def': does not always work
- thread support: threadvar on Windows seems broken;
add --deadlock_prevention:on|off switch
- built-in serialization
- deprecate ^ and make it available as operator
- test branch coverage
- checked exceptions
- slicing
High priority (version 0.9.0)
@@ -61,6 +56,10 @@ Low priority
- nested tuple unpacking; no auto-unpacking in 'for' loops!
- better error messages for used keywords as identifiers
- case statement branches should support constant sets
- 'nimrod def': does not always work
- test branch coverage
- checked exceptions
- slicing
Library

View File

@@ -12,7 +12,7 @@ ucpu=`uname -m`
uos=`uname`
# add(result, "# convert to lower case:\n")
upcu=`echo $ucpu | tr "[:upper:]" "[:lower:]"`
ucpu=`echo $ucpu | tr "[:upper:]" "[:lower:]"`
uos=`echo $uos | tr "[:upper:]" "[:lower:]"`
case $uos in