ugh, maybe broke git

This commit is contained in:
Araq 2011-04-01 15:07:16 +02:00
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) 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 ']'

View file

@ -1,7 +1,7 @@
# #
# #
# Nimrod's Runtime Library # Nimrod's Runtime Library
# (c) Copyright 2008 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.
@ -30,14 +30,10 @@ proc finishHash(h: THash): THash {.inline.} =
proc hashData*(Data: Pointer, Size: int): THash = proc hashData*(Data: Pointer, Size: int): THash =
## hashes an array of bytes of size `size` ## hashes an array of bytes of size `size`
var var h: THash = 0
h: THash var p = cast[cstring](Data)
p: cstring var i = 0
i, s: int var s = size
h = 0
p = cast[cstring](Data)
i = 0
s = size
while s > 0: while s > 0:
h = concHash(h, ord(p[i])) h = concHash(h, ord(p[i]))
Inc(i) Inc(i)
@ -62,20 +58,16 @@ proc hash*(x: char): THash {.inline.} =
proc hash*(x: string): THash = proc hash*(x: string): THash =
## efficient hashing of strings ## efficient hashing of strings
var h: THash var h: THash = 0
h = 0
for i in 0..x.len-1: for i in 0..x.len-1:
h = concHash(h, ord(x[i])) h = concHash(h, ord(x[i]))
result = finishHash(h) result = finishHash(h)
proc hashIgnoreStyle*(x: string): THash = proc hashIgnoreStyle*(x: string): THash =
## efficient hashing of strings; style is ignored ## efficient hashing of strings; style is ignored
var var h: THash = 0
h: THash
c: Char
h = 0
for i in 0..x.len-1: for i in 0..x.len-1:
c = x[i] var c = x[i]
if c == '_': if c == '_':
continue # skip _ continue # skip _
if c in {'A'..'Z'}: if c in {'A'..'Z'}:
@ -85,13 +77,17 @@ proc hashIgnoreStyle*(x: string): THash =
proc hashIgnoreCase*(x: string): THash = proc hashIgnoreCase*(x: string): THash =
## efficient hashing of strings; case is ignored ## efficient hashing of strings; case is ignored
var var h: THash = 0
h: THash
c: Char
h = 0
for i in 0..x.len-1: for i in 0..x.len-1:
c = x[i] var c = x[i]
if c in {'A'..'Z'}: if c in {'A'..'Z'}:
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower() c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
h = concHash(h, ord(c)) h = concHash(h, ord(c))
result = finishHash(h) 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 r = parseUrl(url)
var headers = copy($httpMethod, len("http")) var headers = copy($httpMethod, len("http"))
if r.path != "": headers.add(" /" & r.path & r.query)
headers.add(" /" & r.path & r.query)
else:
headers.add(" /")
headers.add(" HTTP/1.1\c\L") headers.add(" HTTP/1.1\c\L")
add(headers, "Host: " & r.hostname & "\c\L") add(headers, "Host: " & r.hostname & "\c\L")

View file

@ -700,6 +700,18 @@ proc `$`*(node: PJsonNode): String =
result = "" result = ""
toPretty(result, node, 1, False) 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) = proc eat(p: var TJsonParser, tok: TTokKind) =
if p.tok == tok: discard getTok(p) if p.tok == tok: discard getTok(p)
else: raiseParseErr(p, tokToStr[tok]) else: raiseParseErr(p, tokToStr[tok])
@ -711,7 +723,7 @@ proc parseJson(p: var TJsonParser): PJsonNode =
result = newJString(p.a) result = newJString(p.a)
discard getTok(p) discard getTok(p)
of tkInt: of tkInt:
result = newJInt(parseInt(p.a)) result = newJInt(parseBiggestInt(p.a))
discard getTok(p) discard getTok(p)
of tkFloat: of tkFloat:
result = newJFloat(parseFloat(p.a)) result = newJFloat(parseFloat(p.a))

View file

@ -1130,6 +1130,12 @@ proc getConfigDir*(): string {.rtl, extern: "nos$1".} =
when defined(windows): return getEnv("APPDATA") & "\\" when defined(windows): return getEnv("APPDATA") & "\\"
else: return getEnv("HOME") & "/.config/" 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): when defined(windows):
# Since we support GUI applications with Nimrod, we sometimes generate # Since we support GUI applications with Nimrod, we sometimes generate
# a WinMain entry proc. But a WinMain proc has no access to the parsed # 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: 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] == '>':

View file

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

View file

@ -98,17 +98,17 @@ iterator items*(n: PXmlNode): PXmlNode {.inline.} =
assert n.k == xnElement assert n.k == xnElement
for i in 0 .. n.len-1: yield n[i] 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`. ## gets the attributes belonging to `n`.
assert n.k == xnElement assert n.k == xnElement
result = n.fAttr result = n.fAttr
proc `attr=`*(n: PXmlNode, attr: PXmlAttributes) {.inline.} = proc `attrs=`*(n: PXmlNode, attr: PXmlAttributes) {.inline.} =
## sets the attributes belonging to `n`. ## sets the attributes belonging to `n`.
assert n.k == xnElement assert n.k == xnElement
n.fAttr = attr n.fAttr = attr
proc attrLen*(n: PXmlNode): int {.inline.} = proc attrsLen*(n: PXmlNode): int {.inline.} =
## returns the number of `n`'s attributes. ## returns the number of `n`'s attributes.
assert n.k == xnElement assert n.k == xnElement
if not isNil(n.fAttr): result = len(n.fAttr) if not isNil(n.fAttr): result = len(n.fAttr)
@ -262,3 +262,16 @@ macro `<>`*(x: expr): expr =
## ##
result = xmlConstructor(x) 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) 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.}

View file

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

View file

@ -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,

View file

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

View file

@ -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 & ')')

View file

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

View file

@ -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 =

View file

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

View file

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

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; - 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

View file

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