diff options
author | Araq <rumpf_a@web.de> | 2011-04-01 15:07:16 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2011-04-01 15:07:16 +0200 |
commit | 4741e8f9a1d1148d58e129626952219e14ede255 (patch) | |
tree | db2eca2249ccc3230dc6c0a7359986198cab4048 | |
parent | dc669155e39007f1b584eef247dff90523f836bf (diff) | |
download | Nim-4741e8f9a1d1148d58e129626952219e14ede255.tar.gz |
ugh, maybe broke git
-rwxr-xr-x | doc/grammar.txt | 6 | ||||
-rwxr-xr-x | lib/pure/hashes.nim | 38 | ||||
-rwxr-xr-x | lib/pure/httpclient.nim | 5 | ||||
-rwxr-xr-x | lib/pure/json.nim | 14 | ||||
-rwxr-xr-x | lib/pure/os.nim | 6 | ||||
-rwxr-xr-x | lib/pure/parsexml.nim | 2 | ||||
-rwxr-xr-x | lib/pure/xmlparser.nim | 4 | ||||
-rwxr-xr-x | lib/pure/xmltree.nim | 19 | ||||
-rwxr-xr-x | lib/system.nim | 69 | ||||
-rwxr-xr-x | lib/wrappers/gtk/gtk2.nim | 5 | ||||
-rwxr-xr-x | rod/ast.nim | 6 | ||||
-rwxr-xr-x | rod/pnimsyn.nim | 67 | ||||
-rwxr-xr-x | rod/rnimsyn.nim | 76 | ||||
-rwxr-xr-x | rod/seminst.nim | 2 | ||||
-rwxr-xr-x | rod/semstmts.nim | 171 | ||||
-rwxr-xr-x | rod/semtypes.nim | 77 | ||||
-rwxr-xr-x | rod/sigmatch.nim | 42 | ||||
-rw-r--r-- | tests/accept/compile/tconstraints.nim | 15 | ||||
-rw-r--r-- | tests/accept/compile/tgenericmatcher.nim | 19 | ||||
-rw-r--r-- | tests/accept/compile/tgenericrefs.nim | 24 | ||||
-rw-r--r-- | tests/accept/run/tfielditerator.nim | 46 | ||||
-rw-r--r-- | tests/accept/run/tkoeniglookup.nim | 17 | ||||
-rw-r--r-- | tests/reject/tconstraints.nim | 18 | ||||
-rwxr-xr-x | todo.txt | 9 | ||||
-rwxr-xr-x | tools/buildsh.tmpl | 2 |
25 files changed, 587 insertions, 172 deletions
diff --git a/doc/grammar.txt b/doc/grammar.txt index c84caec49..062698690 100755 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -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 ']' diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 1593119bd..87d672ae7 100755 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -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) + diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 092d8e5c6..39ceb5f68 100755 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -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") diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 7fbc8bfcf..c90c071b6 100755 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -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)) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index f7d22ca06..d9b81365f 100755 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -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 diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim index 8551dda90..c49986087 100755 --- a/lib/pure/parsexml.nim +++ b/lib/pure/parsexml.nim @@ -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] == '>': diff --git a/lib/pure/xmlparser.nim b/lib/pure/xmlparser.nim index ad28bf618..8c5c5f5ab 100755 --- a/lib/pure/xmlparser.nim +++ b/lib/pure/xmlparser.nim @@ -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) diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index 57988698b..41765b87a 100755 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -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] diff --git a/lib/system.nim b/lib/system.nim index 09b85d32b..daf0c5423 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -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.} diff --git a/lib/wrappers/gtk/gtk2.nim b/lib/wrappers/gtk/gtk2.nim index 7bfed2d64..f1e4ec13f 100755 --- a/lib/wrappers/gtk/gtk2.nim +++ b/lib/wrappers/gtk/gtk2.nim @@ -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] diff --git a/rod/ast.nim b/rod/ast.nim index e19192f1f..fb610f565 100755 --- a/rod/ast.nim +++ b/rod/ast.nim @@ -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, diff --git a/rod/pnimsyn.nim b/rod/pnimsyn.nim index fb2b7429e..869d968b6 100755 --- a/rod/pnimsyn.nim +++ b/rod/pnimsyn.nim @@ -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) diff --git a/rod/rnimsyn.nim b/rod/rnimsyn.nim index 2c97876b1..01d3e066c 100755 --- a/rod/rnimsyn.nim +++ b/rod/rnimsyn.nim @@ -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 & ')') diff --git a/rod/seminst.nim b/rod/seminst.nim index 2f26026ad..99fd1fb87 100755 --- a/rod/seminst.nim +++ b/rod/seminst.nim @@ -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) diff --git a/rod/semstmts.nim b/rod/semstmts.nim index 176fdad1b..b2fae3f31 100755 --- a/rod/semstmts.nim +++ b/rod/semstmts.nim @@ -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 = diff --git a/rod/semtypes.nim b/rod/semtypes.nim index 90a774645..79511b716 100755 --- a/rod/semtypes.nim +++ b/rod/semtypes.nim @@ -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) + + diff --git a/rod/sigmatch.nim b/rod/sigmatch.nim index 8144cff0b..1e61ddfe0 100755 --- a/rod/sigmatch.nim +++ b/rod/sigmatch.nim @@ -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) diff --git a/tests/accept/compile/tconstraints.nim b/tests/accept/compile/tconstraints.nim new file mode 100644 index 000000000..7aef0d645 --- /dev/null +++ b/tests/accept/compile/tconstraints.nim @@ -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)" + + diff --git a/tests/accept/compile/tgenericmatcher.nim b/tests/accept/compile/tgenericmatcher.nim new file mode 100644 index 000000000..eaf3da67c --- /dev/null +++ b/tests/accept/compile/tgenericmatcher.nim @@ -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] + + diff --git a/tests/accept/compile/tgenericrefs.nim b/tests/accept/compile/tgenericrefs.nim new file mode 100644 index 000000000..b0e77cef5 --- /dev/null +++ b/tests/accept/compile/tgenericrefs.nim @@ -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 + + diff --git a/tests/accept/run/tfielditerator.nim b/tests/accept/run/tfielditerator.nim new file mode 100644 index 000000000..2919aab41 --- /dev/null +++ b/tests/accept/run/tfielditerator.nim @@ -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 + diff --git a/tests/accept/run/tkoeniglookup.nim b/tests/accept/run/tkoeniglookup.nim new file mode 100644 index 000000000..07c5b46be --- /dev/null +++ b/tests/accept/run/tkoeniglookup.nim @@ -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) + diff --git a/tests/reject/tconstraints.nim b/tests/reject/tconstraints.nim new file mode 100644 index 000000000..aafe86911 --- /dev/null +++ b/tests/reject/tconstraints.nim @@ -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)" + + diff --git a/todo.txt b/todo.txt index 3853d0f20..09a9117dd 100755 --- a/todo.txt +++ b/todo.txt @@ -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 diff --git a/tools/buildsh.tmpl b/tools/buildsh.tmpl index e763a5c05..8893f4da0 100755 --- a/tools/buildsh.tmpl +++ b/tools/buildsh.tmpl @@ -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 |