mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-29 09:24:36 +00:00
various bugfixes for generics; added generic sort proc
This commit is contained in:
@@ -62,7 +62,7 @@ proc finalizeRegEx(x: TRegEx) =
|
||||
|
||||
proc re*(s: string, flags = {reExtended}): TRegEx =
|
||||
## Constructor of regular expressions. Note that Nimrod's
|
||||
## extended raw string literals supports this syntax ``re"[abc]"`` as
|
||||
## extended raw string literals support this syntax ``re"[abc]"`` as
|
||||
## a short form for ``re(r"[abc]")``.
|
||||
new(result, finalizeRegEx)
|
||||
result.h = rawCompile(s, cast[cint](flags))
|
||||
@@ -152,8 +152,12 @@ proc find*(s: string, pattern: TRegEx, matches: var openarray[string],
|
||||
proc find*(s: string, pattern: TRegEx, start = 0): int =
|
||||
## returns the starting position of ``pattern`` in ``s``. If it does not
|
||||
## match, -1 is returned.
|
||||
var matches: array[0..maxSubpatterns-1, string]
|
||||
result = find(s, pattern, matches, start)
|
||||
var
|
||||
rawMatches: array[0..3 - 1, cint]
|
||||
res = pcre.Exec(pattern.h, nil, s, len(s), start, 0'i32,
|
||||
cast[ptr cint](addr(rawMatches)), 3)
|
||||
if res < 0'i32: return res
|
||||
return rawMatches[0]
|
||||
|
||||
iterator findAll*(s: string, pattern: TRegEx, start = 0): string =
|
||||
## yields all matching captures of pattern in `s`.
|
||||
|
||||
101
lib/pure/algorithm.nim
Normal file
101
lib/pure/algorithm.nim
Normal file
@@ -0,0 +1,101 @@
|
||||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2010 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module implements some common generic algorithms.
|
||||
|
||||
type
|
||||
TSortOrder* = enum ## sort order
|
||||
Descending, Ascending
|
||||
|
||||
proc `*`*(x: int, order: TSortOrder): int {.inline.} =
|
||||
## flips `x` if ``order == Descending``;
|
||||
## if ``order == Ascending`` then `x` is returned.
|
||||
## `x` is supposed to be the result of a comparator.
|
||||
var y = order.ord - 1
|
||||
result = (x xor y) - y
|
||||
|
||||
proc reverse*[T](a: var openArray[T], first, last: int) =
|
||||
## reverses the array ``a[first..last]``.
|
||||
var x = first
|
||||
var y = last
|
||||
while x < y:
|
||||
swap(a[x], a[y])
|
||||
dec(y)
|
||||
inc(x)
|
||||
|
||||
proc reverse*[T](a: var openArray[T]) =
|
||||
## reverses the array `a`.
|
||||
reverse(a, 0, a.high)
|
||||
|
||||
const
|
||||
onlySafeCode = false
|
||||
|
||||
proc merge[T](a, b: var openArray[T], lo, m, hi: int,
|
||||
cmp: proc (x, y: T): int, order: TSortOrder) =
|
||||
template `<-` (a, b: expr) =
|
||||
when onlySafeCode:
|
||||
a = b
|
||||
else:
|
||||
copyMem(addr(a), addr(b), sizeof(T))
|
||||
# optimization: If max(left) <= min(right) there is nothing to do!
|
||||
# 1 2 3 4 ## 5 6 7 8
|
||||
# -> O(n) for sorted arrays.
|
||||
# On random data this safes up to 40% of merge calls
|
||||
if cmp(a[m], a[m+1]) * order <= 0: return
|
||||
var j = lo
|
||||
# copy a[j..m] into b:
|
||||
assert j <= m
|
||||
when onlySafeCode:
|
||||
var bb = 0
|
||||
while j <= m:
|
||||
b[bb] = a[j]
|
||||
inc(bb)
|
||||
inc(j)
|
||||
else:
|
||||
CopyMem(addr(b[0]), addr(a[j]), sizeof(T)*(m-j+1))
|
||||
j = m+1
|
||||
var i = 0
|
||||
var k = lo
|
||||
# copy proper element back:
|
||||
while k < j and j <= hi:
|
||||
if cmp(b[i], a[j]) * order <= 0:
|
||||
a[k] <- b[i]
|
||||
inc(i)
|
||||
else:
|
||||
a[k] <- a[j]
|
||||
inc(j)
|
||||
inc(k)
|
||||
# copy rest of b:
|
||||
when onlySafeCode:
|
||||
while k < j:
|
||||
a[k] = b[i]
|
||||
inc(k)
|
||||
inc(i)
|
||||
else:
|
||||
if k < j: copyMem(addr(a[k]), addr(b[i]), sizeof(T)*(j-k))
|
||||
|
||||
proc sort*[T](a: var openArray[T],
|
||||
cmp: proc (x, y: T): int = cmp,
|
||||
order = TSortOrder.Ascending) =
|
||||
## Default Nimrod sort. The sorting is guaranteed to be stable and
|
||||
## the worst case is guaranteed to be O(n log n).
|
||||
## The current implementation uses an iterative
|
||||
## mergesort to achieve this. It uses a temporary sequence of
|
||||
## length ``a.len div 2``.
|
||||
var n = a.len
|
||||
var b: seq[T]
|
||||
newSeq(b, n div 2)
|
||||
var s = 1
|
||||
while s < n:
|
||||
var m = n-1-s
|
||||
while m >= 0:
|
||||
merge(a, b, max(m-s+1, 0), m, m+s, cmp, order)
|
||||
dec(m, s*2)
|
||||
s = s*2
|
||||
|
||||
@@ -97,14 +97,15 @@ proc normalize*(s: string): string {.noSideEffect, procvar,
|
||||
add result, s[i]
|
||||
|
||||
proc cmpIgnoreCase*(a, b: string): int {.noSideEffect,
|
||||
rtl, extern: "nsuCmpIgnoreCase".} =
|
||||
rtl, extern: "nsuCmpIgnoreCase", procvar.} =
|
||||
## Compares two strings in a case insensitive manner. Returns:
|
||||
##
|
||||
## | 0 iff a == b
|
||||
## | < 0 iff a < b
|
||||
## | > 0 iff a > b
|
||||
var i = 0
|
||||
while i < a.len and i < b.len:
|
||||
var i = 0
|
||||
var m = min(a.len, b.len)
|
||||
while i < m:
|
||||
result = ord(toLower(a[i])) - ord(toLower(b[i]))
|
||||
if result != 0: return
|
||||
inc(i)
|
||||
@@ -114,7 +115,7 @@ proc cmpIgnoreCase*(a, b: string): int {.noSideEffect,
|
||||
# thus we compile without checks here
|
||||
|
||||
proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,
|
||||
rtl, extern: "nsuCmpIgnoreStyle".} =
|
||||
rtl, extern: "nsuCmpIgnoreStyle", procvar.} =
|
||||
## Compares two strings normalized (i.e. case and
|
||||
## underscores do not matter). Returns:
|
||||
##
|
||||
|
||||
@@ -1075,7 +1075,7 @@ proc binarySearch(c: irune, tab: openArray[iRune], len, stride: int): int =
|
||||
return t
|
||||
return -1
|
||||
|
||||
proc toLower*(c: TRune): TRune {.rtl, extern: "nuc$1".} =
|
||||
proc toLower*(c: TRune): TRune {.rtl, extern: "nuc$1", procvar.} =
|
||||
## Converts `c` into lower case. This works for any Unicode character.
|
||||
## If possible, prefer `toLower` over `toUpper`.
|
||||
var c = irune(c)
|
||||
@@ -1087,7 +1087,7 @@ proc toLower*(c: TRune): TRune {.rtl, extern: "nuc$1".} =
|
||||
return TRune(c + toLowerSinglets[p+1] - 500)
|
||||
return TRune(c)
|
||||
|
||||
proc toUpper*(c: TRune): TRune {.rtl, extern: "nuc$1".} =
|
||||
proc toUpper*(c: TRune): TRune {.rtl, extern: "nuc$1", procvar.} =
|
||||
## Converts `c` into upper case. This works for any Unicode character.
|
||||
## If possible, prefer `toLower` over `toUpper`.
|
||||
var c = irune(c)
|
||||
@@ -1099,14 +1099,14 @@ proc toUpper*(c: TRune): TRune {.rtl, extern: "nuc$1".} =
|
||||
return TRune(c + toUpperSinglets[p+1] - 500)
|
||||
return TRune(c)
|
||||
|
||||
proc toTitle*(c: TRune): TRune {.rtl, extern: "nuc$1".} =
|
||||
proc toTitle*(c: TRune): TRune {.rtl, extern: "nuc$1", procvar.} =
|
||||
var c = irune(c)
|
||||
var p = binarySearch(c, toTitleSinglets, len(toTitleSinglets) div 2, 2)
|
||||
if p >= 0 and c == toTitleSinglets[p]:
|
||||
return TRune(c + toTitleSinglets[p+1] - 500)
|
||||
return TRune(c)
|
||||
|
||||
proc isLower*(c: TRune): bool {.rtl, extern: "nuc$1".} =
|
||||
proc isLower*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
|
||||
## returns true iff `c` is a lower case Unicode character
|
||||
## If possible, prefer `isLower` over `isUpper`.
|
||||
var c = irune(c)
|
||||
@@ -1118,7 +1118,7 @@ proc isLower*(c: TRune): bool {.rtl, extern: "nuc$1".} =
|
||||
if p >= 0 and c == toUpperSinglets[p]:
|
||||
return true
|
||||
|
||||
proc isUpper*(c: TRune): bool {.rtl, extern: "nuc$1".} =
|
||||
proc isUpper*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
|
||||
## returns true iff `c` is a upper case Unicode character
|
||||
## If possible, prefer `isLower` over `isUpper`.
|
||||
var c = irune(c)
|
||||
@@ -1130,7 +1130,7 @@ proc isUpper*(c: TRune): bool {.rtl, extern: "nuc$1".} =
|
||||
if p >= 0 and c == toLowerSinglets[p]:
|
||||
return true
|
||||
|
||||
proc isAlpha*(c: TRune): bool {.rtl, extern: "nuc$1".} =
|
||||
proc isAlpha*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
|
||||
## returns true iff `c` is an *alpha* Unicode character (i.e. a letter)
|
||||
if isUpper(c) or isLower(c):
|
||||
return true
|
||||
@@ -1142,10 +1142,10 @@ proc isAlpha*(c: TRune): bool {.rtl, extern: "nuc$1".} =
|
||||
if p >= 0 and c == alphaSinglets[p]:
|
||||
return true
|
||||
|
||||
proc isTitle*(c: TRune): bool {.rtl, extern: "nuc$1".} =
|
||||
proc isTitle*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
|
||||
return isUpper(c) and isLower(c)
|
||||
|
||||
proc isWhiteSpace*(c: TRune): bool {.rtl, extern: "nuc$1".} =
|
||||
proc isWhiteSpace*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
|
||||
## returns true iff `c` is a Unicode whitespace character
|
||||
var c = irune(c)
|
||||
var p = binarySearch(c, spaceRanges, len(spaceRanges) div 2, 2)
|
||||
@@ -1161,7 +1161,7 @@ iterator runes*(s: string): TRune =
|
||||
fastRuneAt(s, i, result, true)
|
||||
yield result
|
||||
|
||||
proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1".} =
|
||||
proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1", procvar.} =
|
||||
## compares two UTF8 strings and ignores the case. Returns:
|
||||
##
|
||||
## | 0 iff a == b
|
||||
|
||||
@@ -623,7 +623,7 @@ template `not_in` * (x, y: expr): expr = not contains(y, x)
|
||||
proc `is` *[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.}
|
||||
template `is_not` *(x, y: expr): expr = not (x is y)
|
||||
|
||||
proc cmp*[T, S: typeDesc](x: T, y: S): int =
|
||||
proc cmp*[T, S: typeDesc](x: T, y: S): int {.procvar.} =
|
||||
## Generic compare proc. Returns a value < 0 iff x < y, a value > 0 iff x > y
|
||||
## and 0 iff x == y. This is useful for writing generic algorithms without
|
||||
## performance loss. This generic implementation uses the `==` and `<`
|
||||
@@ -632,7 +632,7 @@ proc cmp*[T, S: typeDesc](x: T, y: S): int =
|
||||
if x < y: return -1
|
||||
return 1
|
||||
|
||||
proc cmp*(x, y: string): int {.noSideEffect.}
|
||||
proc cmp*(x, y: string): int {.noSideEffect, procvar.}
|
||||
## Compare proc for strings. More efficient than the generic version.
|
||||
|
||||
proc `@` * [IDX, T](a: array[IDX, T]): seq[T] {.
|
||||
@@ -714,7 +714,8 @@ const
|
||||
|
||||
cpuEndian* {.magic: "CpuEndian"}: TEndian = littleEndian
|
||||
## is the endianness of the target CPU. This is a valuable piece of
|
||||
## information for low-level code only. This works thanks to compiler magic.
|
||||
## information for low-level code only. This works thanks to compiler
|
||||
## magic.
|
||||
|
||||
hostOS* {.magic: "HostOS"}: string = ""
|
||||
## a string that describes the host operating system. Possible values:
|
||||
@@ -1307,7 +1308,7 @@ proc echo*[Ty](x: openarray[Ty]) {.magic: "Echo".}
|
||||
## available for the ECMAScript target too!
|
||||
|
||||
template newException*(exceptn, message: expr): expr =
|
||||
## creates an exception object of type "exceptn" and sets its ``msg`` field
|
||||
## creates an exception object of type ``exceptn`` and sets its ``msg`` field
|
||||
## to `message`. Returns the new exception object.
|
||||
block: # open a new scope
|
||||
var
|
||||
@@ -1365,7 +1366,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||
include "system/ansi_c"
|
||||
|
||||
proc cmp(x, y: string): int =
|
||||
return int(c_strcmp(x, y))
|
||||
result = int(c_strcmp(x, y))
|
||||
|
||||
const pccHack = if defined(pcc): "_" else: "" # Hack for PCC
|
||||
when defined(windows):
|
||||
@@ -1419,8 +1420,9 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||
## stream* is a good idea, but since it is named ``stderr`` there are few
|
||||
## programs out there that distinguish properly between ``stdout`` and
|
||||
## ``stderr``. So, that's what you get if you don't name your variables
|
||||
## appropriately. It also annoys people if redirection via ``>output.txt``
|
||||
## does not work because the program writes to ``stderr``.
|
||||
## appropriately. It also annoys people if redirection
|
||||
## via ``>output.txt`` does not work because the program writes
|
||||
## to ``stderr``.
|
||||
|
||||
proc Open*(f: var TFile, filename: string,
|
||||
mode: TFileMode = fmRead, bufSize: int = -1): Bool
|
||||
|
||||
11
rod/ast.nim
11
rod/ast.nim
@@ -750,6 +750,12 @@ proc newSymNode(sym: PSym): PNode =
|
||||
result.typ = sym.typ
|
||||
result.info = sym.info
|
||||
|
||||
proc newSymNode*(sym: PSym, info: TLineInfo): PNode =
|
||||
result = newNode(nkSym)
|
||||
result.sym = sym
|
||||
result.typ = sym.typ
|
||||
result.info = info
|
||||
|
||||
proc newNodeI(kind: TNodeKind, info: TLineInfo): PNode =
|
||||
result = newNode(kind)
|
||||
result.info = info
|
||||
@@ -869,6 +875,11 @@ proc len*(n: PNode): int {.inline.} =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
proc safeLen*(n: PNode): int {.inline.} =
|
||||
## works even for leaves.
|
||||
if n.kind in {nkNone..nkNilLit} or isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
proc add*(father, son: PNode) =
|
||||
assert son != nil
|
||||
if isNil(father.sons): father.sons = @[]
|
||||
|
||||
@@ -79,20 +79,42 @@ proc semDirectCall(c: PContext, n: PNode, filter: TSymKinds): PNode =
|
||||
initialBinding = nil
|
||||
result = semDirectCallWithBinding(c, n, f, filter, initialBinding)
|
||||
|
||||
proc explictGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
proc explicitGenericInstError(n: PNode): PNode =
|
||||
LocalError(n.info, errCannotInstantiateX, renderTree(n))
|
||||
result = n
|
||||
|
||||
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
assert n.kind == nkBracketExpr
|
||||
for i in 1..sonsLen(n)-1:
|
||||
n.sons[i].typ = semTypeNode(c, n.sons[i], nil)
|
||||
# we cannot check for the proper number of type parameters because in
|
||||
# `f[a,b](x, y)` `f` is not resolved yet properly.
|
||||
# XXX: BUG this should be checked somehow!
|
||||
assert n.sons[0].kind == nkSym
|
||||
var s = s
|
||||
var a = n.sons[0]
|
||||
if a.kind == nkSym:
|
||||
# common case; check the only candidate has the right
|
||||
# number of generic type parameters:
|
||||
if safeLen(s.ast.sons[genericParamsPos]) != n.len-1:
|
||||
return explicitGenericInstError(n)
|
||||
elif a.kind == nkSymChoice:
|
||||
# choose the generic proc with the proper number of type parameters.
|
||||
# XXX I think this could be improved by reusing sigmatch.ParamTypesMatch.
|
||||
# It's good enough for now.
|
||||
var candidateCount = 0
|
||||
for i in countup(0, len(a)-1):
|
||||
var candidate = a.sons[i].sym
|
||||
if candidate.kind in {skProc, skMethod, skConverter, skIterator}:
|
||||
# if suffices that the candidate has the proper number of generic
|
||||
# type parameters:
|
||||
if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1:
|
||||
s = candidate
|
||||
inc(candidateCount)
|
||||
if candidateCount != 1: return explicitGenericInstError(n)
|
||||
else:
|
||||
assert false
|
||||
|
||||
var x: TCandidate
|
||||
initCandidate(x, s, n)
|
||||
var newInst = generateInstance(c, s, x.bindings, n.info)
|
||||
|
||||
markUsed(n, s)
|
||||
result = newSymNode(newInst)
|
||||
result.info = n.info
|
||||
result = newSymNode(newInst, n.info)
|
||||
|
||||
|
||||
@@ -61,24 +61,22 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||
if s.typ.kind in ConstAbstractTypes:
|
||||
result = copyTree(s.ast)
|
||||
result.typ = s.typ
|
||||
result.info = n.info
|
||||
else:
|
||||
result = newSymNode(s)
|
||||
result.info = n.info
|
||||
result = newSymNode(s, n.info)
|
||||
of skMacro: result = semMacroExpr(c, n, s)
|
||||
of skTemplate: result = semTemplateExpr(c, n, s)
|
||||
of skVar:
|
||||
markUsed(n, s)
|
||||
# if a proc accesses a global variable, it is not side effect free:
|
||||
if sfGlobal in s.flags: incl(c.p.owner.flags, sfSideEffect)
|
||||
result = newSymNode(s)
|
||||
result.info = n.info
|
||||
result = newSymNode(s, n.info)
|
||||
of skGenericParam:
|
||||
if s.ast == nil: InternalError(n.info, "no default for")
|
||||
result = semExpr(c, s.ast)
|
||||
else:
|
||||
markUsed(n, s)
|
||||
result = newSymNode(s)
|
||||
result.info = n.info
|
||||
result = newSymNode(s, n.info)
|
||||
|
||||
proc checkConversionBetweenObjects(info: TLineInfo, castDest, src: PType) =
|
||||
var diff = inheritanceDiff(castDest, src)
|
||||
@@ -645,23 +643,22 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
var ty = n.sons[0].Typ
|
||||
var f: PSym = nil
|
||||
result = nil
|
||||
if ty.kind == tyEnum:
|
||||
# look up if the identifier belongs to the enum:
|
||||
while ty != nil:
|
||||
f = getSymFromList(ty.n, i)
|
||||
if f != nil: break
|
||||
ty = ty.sons[0] # enum inheritance
|
||||
if f != nil:
|
||||
result = newSymNode(f)
|
||||
result.info = n.info
|
||||
result.typ = ty
|
||||
markUsed(n, f)
|
||||
else:
|
||||
GlobalError(n.sons[1].info, errEnumHasNoValueX, i.s)
|
||||
return
|
||||
elif not (efAllowType in flags) and isTypeExpr(n.sons[0]):
|
||||
GlobalError(n.sons[0].info, errATypeHasNoValue)
|
||||
return
|
||||
if isTypeExpr(n.sons[0]):
|
||||
if ty.kind == tyEnum:
|
||||
# look up if the identifier belongs to the enum:
|
||||
while ty != nil:
|
||||
f = getSymFromList(ty.n, i)
|
||||
if f != nil: break
|
||||
ty = ty.sons[0] # enum inheritance
|
||||
if f != nil:
|
||||
result = newSymNode(f)
|
||||
result.info = n.info
|
||||
result.typ = ty
|
||||
markUsed(n, f)
|
||||
return
|
||||
elif efAllowType notin flags:
|
||||
GlobalError(n.sons[0].info, errATypeHasNoValue)
|
||||
return
|
||||
ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef})
|
||||
var check: PNode = nil
|
||||
if ty.kind == tyObject:
|
||||
@@ -1027,7 +1024,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
var s = qualifiedLookup(c, n.sons[0], {checkUndeclared})
|
||||
if s != nil and s.kind in {skProc, skMethod, skConverter, skIterator}:
|
||||
# type parameters: partial generic specialization
|
||||
result = explictGenericInstantiation(c, n, s)
|
||||
n.sons[0] = semSym(c, n.sons[0], s, flags)
|
||||
result = explicitGenericInstantiation(c, n, s)
|
||||
else:
|
||||
result = semArrayAccess(c, n, flags)
|
||||
of nkPragmaExpr:
|
||||
|
||||
@@ -40,13 +40,15 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
|
||||
of skMacro:
|
||||
result = semMacroExpr(c, n, s, false)
|
||||
of skGenericParam:
|
||||
result = newSymNode(s)
|
||||
result = newSymNode(s, n.info)
|
||||
of skParam:
|
||||
result = n
|
||||
of skType:
|
||||
if (s.typ != nil) and (s.typ.kind != tyGenericParam): result = newSymNode(s)
|
||||
else: result = n
|
||||
else: result = newSymNode(s)
|
||||
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
|
||||
result = newSymNode(s, n.info)
|
||||
else:
|
||||
result = n
|
||||
else: result = newSymNode(s, n.info)
|
||||
|
||||
proc getIdentNode(n: PNode): PNode =
|
||||
case n.kind
|
||||
@@ -101,12 +103,12 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
|
||||
of skProc, skMethod, skIterator, skConverter:
|
||||
n.sons[0] = symChoice(c, n.sons[0], s)
|
||||
of skGenericParam:
|
||||
n.sons[0] = newSymNode(s)
|
||||
n.sons[0] = newSymNode(s, n.sons[0].info)
|
||||
of skType:
|
||||
# bad hack for generics:
|
||||
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
|
||||
n.sons[0] = newSymNode(s)
|
||||
else: n.sons[0] = newSymNode(s)
|
||||
n.sons[0] = newSymNode(s, n.sons[0].info)
|
||||
else: n.sons[0] = newSymNode(s, n.sons[0].info)
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
n.sons[i] = semGenericStmt(c, n.sons[i], flags)
|
||||
of nkMacroStmt:
|
||||
@@ -221,9 +223,9 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
|
||||
if (a.kind != nkIdentDefs): IllFormedAst(a)
|
||||
checkMinSonsLen(a, 3)
|
||||
L = sonsLen(a)
|
||||
a.sons[L - 1] = semGenericStmt(c, a.sons[L - 2], {withinTypeDesc})
|
||||
a.sons[L - 1] = semGenericStmt(c, a.sons[L - 1])
|
||||
for j in countup(0, L - 3):
|
||||
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], {withinTypeDesc})
|
||||
a.sons[L-1] = semGenericStmt(c, a.sons[L-1])
|
||||
for j in countup(0, L-3):
|
||||
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
|
||||
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
||||
nkIteratorDef, nkLambda:
|
||||
|
||||
@@ -522,11 +522,15 @@ proc SemTypeSection(c: PContext, n: PNode): PNode =
|
||||
InternalError(a.info, "semTypeSection: containerID")
|
||||
s.typ.containerID = getID()
|
||||
a.sons[1] = semGenericParamList(c, a.sons[1], s.typ)
|
||||
addSon(s.typ, nil) # to be filled out later
|
||||
|
||||
# we fill it out later. For magic generics like 'seq', it won't be filled
|
||||
# so we use tyEmpty instead of nil to not crash for strange conversions
|
||||
# like: mydata.seq
|
||||
addSon(s.typ, newTypeS(tyEmpty, c))
|
||||
s.ast = a
|
||||
body = semTypeNode(c, a.sons[2], nil)
|
||||
if body != nil: body.sym = s
|
||||
s.typ.sons[sonsLen(s.typ) - 1] = body #debug(s.typ);
|
||||
s.typ.sons[sonsLen(s.typ) - 1] = body
|
||||
popOwner()
|
||||
closeScope(c.tab)
|
||||
elif a.sons[2].kind != nkEmpty:
|
||||
|
||||
@@ -488,7 +488,8 @@ proc paramType(c: PContext, n, genericParams: PNode, cl: var TIntSet): PType =
|
||||
result = addTypeVarsOfGenericBody(c, result, genericParams, cl)
|
||||
#if result.kind == tyGenericInvokation: debug(result)
|
||||
|
||||
proc semProcTypeNode(c: PContext, n, genericParams: PNode, prev: PType): PType =
|
||||
proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
prev: PType): PType =
|
||||
var
|
||||
def, res: PNode
|
||||
typ: PType
|
||||
@@ -515,12 +516,12 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, prev: PType): PType =
|
||||
if a.sons[length - 1].kind != nkEmpty:
|
||||
def = semExprWithType(c, a.sons[length - 1])
|
||||
# check type compability between def.typ and typ:
|
||||
if typ != nil:
|
||||
if cmpTypes(typ, def.typ) < isConvertible:
|
||||
typeMismatch(a.sons[length - 1], typ, def.typ)
|
||||
def = fitNode(c, typ, def)
|
||||
else:
|
||||
if typ == nil:
|
||||
typ = def.typ
|
||||
elif def != nil and def.typ != nil and def.typ.kind != tyNone:
|
||||
# example code that triggers it:
|
||||
# proc sort[T](cmp: proc(a, b: T): int = cmp)
|
||||
def = fitNode(c, typ, def)
|
||||
else:
|
||||
def = ast.emptyNode
|
||||
for j in countup(0, length - 3):
|
||||
|
||||
@@ -130,8 +130,11 @@ proc concreteType(mapping: TIdTable, t: PType): PType =
|
||||
result = t
|
||||
while true:
|
||||
result = PType(idTableGet(mapping, t))
|
||||
if result == nil: InternalError("lookup failed")
|
||||
if result.kind != tyGenericParam: break
|
||||
if result == nil:
|
||||
break # it's ok, no match
|
||||
# example code that triggers it:
|
||||
# proc sort[T](cmp: proc(a, b: T): int = cmp)
|
||||
if result.kind != tyGenericParam: break
|
||||
else:
|
||||
result = t # Note: empty is valid here
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ proc suggestFieldAccess(c: PContext, n: PNode) =
|
||||
else:
|
||||
# fallback:
|
||||
suggestEverything(c, n)
|
||||
elif typ.kind == tyEnum:
|
||||
elif typ.kind == tyEnum and n.kind == nkSym and n.sym.kind == skType:
|
||||
# look up if the identifier belongs to the enum:
|
||||
var t = typ
|
||||
while t != nil:
|
||||
|
||||
69
tests/accept/compile/tsortdev.nim
Normal file
69
tests/accept/compile/tsortdev.nim
Normal file
@@ -0,0 +1,69 @@
|
||||
|
||||
import math, algorithm
|
||||
|
||||
proc sorted[T](a: openArray[T], order: TSortOrder): bool =
|
||||
result = true
|
||||
for i in 0 .. < a.high:
|
||||
if cmp(a[i], a[i+1]) * order > 0:
|
||||
echo "Out of order: ", a[i], " ", a[i+1]
|
||||
result = false
|
||||
|
||||
proc bubbleSort[T](a: var openArray[T],
|
||||
cmp: proc (x, y: T): int = cmp,
|
||||
order = TSortOrder.Ascending) =
|
||||
while true:
|
||||
var sorted = true
|
||||
for i in 0 .. a.len-2:
|
||||
if cmp(a[i], a[i+1]) * order > 0:
|
||||
swap(a[i], a[i+1])
|
||||
sorted = false
|
||||
if sorted: break
|
||||
|
||||
when isMainModule:
|
||||
proc main() =
|
||||
const order = Ascending
|
||||
var data: seq[string] = @[]
|
||||
|
||||
for i in 0..10_000:
|
||||
var L = random(59)
|
||||
setLen(data, L)
|
||||
for j in 0 .. L-1:
|
||||
data[j] = $(math.random(90) - 10)
|
||||
var copy = data
|
||||
sort(data, cmp, order)
|
||||
if not sorted(data, order):
|
||||
#for x in items(data): echo x
|
||||
break
|
||||
else:
|
||||
echo "SUCCESS!"
|
||||
bubblesort(copy, cmp, order)
|
||||
if copy.len != data.len:
|
||||
quit "lengths differ!"
|
||||
for i in 0 .. copy.high:
|
||||
if copy[i] != data[i]:
|
||||
quit "algorithms differ!"
|
||||
|
||||
for i in 0..10_000:
|
||||
var data: seq[int] = @[]
|
||||
var L = random(59)
|
||||
setLen(data, L)
|
||||
for j in 0 .. L-1:
|
||||
data[j] = (math.random(90) - 10)
|
||||
var copy = data
|
||||
sort(data, cmp[int, int], order)
|
||||
if not sorted(data, order):
|
||||
#for x in items(data): echo x
|
||||
break
|
||||
else:
|
||||
echo "SUCCESS!"
|
||||
bubblesort(copy)
|
||||
if copy.len != data.len:
|
||||
quit "lengths differ!"
|
||||
for i in 0 .. copy.high:
|
||||
if copy[i] != data[i]:
|
||||
quit "algorithms differ!"
|
||||
|
||||
main()
|
||||
|
||||
echo "done"
|
||||
|
||||
@@ -4,51 +4,47 @@ discard """
|
||||
|
||||
# A min-heap.
|
||||
type
|
||||
TNode[T] = tuple[priority: int, data: T]
|
||||
TNode[T] = tuple[priority: int, data: T]
|
||||
|
||||
TBinHeap[T] = object
|
||||
heap: seq[TNode[T]]
|
||||
last: int
|
||||
|
||||
PBinHeap[T] = ref TBinHeap[T]
|
||||
TBinHeap[T] = object
|
||||
heap: seq[TNode[T]]
|
||||
last: int
|
||||
|
||||
PBinHeap[T] = ref TBinHeap[T]
|
||||
|
||||
proc newBinHeap*[T](heap: var PBinHeap[T], size: int) =
|
||||
new(heap)
|
||||
heap.last = 0
|
||||
newSeq(heap.seq, size)
|
||||
new(heap)
|
||||
heap.last = 0
|
||||
newSeq(heap.heap, size)
|
||||
#newSeq(heap.seq, size)
|
||||
|
||||
proc parent(elem: int): int {.inline.} =
|
||||
return (elem-1) div 2
|
||||
|
||||
when false:
|
||||
proc siftUp[T](heap: PBinHeap[T], elem: int) =
|
||||
var idx = elem
|
||||
while idx != 0:
|
||||
var p = parent(idx)
|
||||
if heap.heap[idx].priority < heap.heap[p].priority:
|
||||
swap(heap.heap[idx], heap.heap[p])
|
||||
idx = p
|
||||
else:
|
||||
break
|
||||
|
||||
proc parent(elem: int): int =
|
||||
return (elem-1) div 2
|
||||
proc add*[T](heap: PBinHeap[T], priority: int, data: T) =
|
||||
var node: TNode[T]
|
||||
node.priority = priority
|
||||
node.data = data
|
||||
heap.heap[heap.last] = node
|
||||
siftUp(heap, heap.last)
|
||||
inc(heap.last)
|
||||
|
||||
proc siftUp[T](heap: PBinHeap[T], elem: int) =
|
||||
var idx = elem
|
||||
while idx != 0:
|
||||
var p = parent(idx)
|
||||
if heap.heap[idx] < heap.heap[p]:
|
||||
var tmp = heap.heap[idx]
|
||||
heap.heap[idx] = heap.heap[p]
|
||||
heap.heap[p] = tmp
|
||||
idx = p
|
||||
else:
|
||||
break
|
||||
|
||||
proc add*[T](heap: PBinHeap[T], priority: int, data: T) =
|
||||
var node: TNode
|
||||
new(node)
|
||||
node.priority = int
|
||||
node.data = data
|
||||
heap.heap[heap.last] = node
|
||||
siftUp(heap, heap.last)
|
||||
inc(heap.last)
|
||||
|
||||
proc print*[T](heap: PBinHeap[T]) =
|
||||
for i in countup(0, heap.last):
|
||||
echo($heap.heap[i])
|
||||
proc print*[T](heap: PBinHeap[T]) =
|
||||
for i in countup(0, heap.last):
|
||||
echo heap.heap[i].data
|
||||
|
||||
var
|
||||
heap: PBinHeap[int]
|
||||
heap: PBinHeap[int]
|
||||
|
||||
newBinHeap(heap, 256)
|
||||
add(heap, 1, 100)
|
||||
|
||||
11
tests/gc/gcleak.nim
Normal file
11
tests/gc/gcleak.nim
Normal file
@@ -0,0 +1,11 @@
|
||||
type
|
||||
TTestObj = object of TObject
|
||||
x: string
|
||||
|
||||
proc MakeObj(): TTestObj =
|
||||
result.x = "Hello"
|
||||
|
||||
while true:
|
||||
var obj = MakeObj()
|
||||
|
||||
|
||||
55
tests/reject/ttypenoval.nim
Normal file
55
tests/reject/ttypenoval.nim
Normal file
@@ -0,0 +1,55 @@
|
||||
discard """
|
||||
file: "tambsym.nim"
|
||||
line: 36
|
||||
errormsg: "a type has no value"
|
||||
"""
|
||||
|
||||
# A min-heap.
|
||||
type
|
||||
TNode[T] = tuple[priority: int, data: T]
|
||||
|
||||
TBinHeap[T] = object
|
||||
heap: seq[TNode[T]]
|
||||
last: int
|
||||
|
||||
PBinHeap[T] = ref TBinHeap[T]
|
||||
|
||||
proc newBinHeap*[T](heap: var PBinHeap[T], size: int) =
|
||||
new(heap)
|
||||
heap.last = 0
|
||||
newSeq(heap.heap, size)
|
||||
#newSeq(heap.seq, size)
|
||||
|
||||
proc parent(elem: int): int {.inline.} =
|
||||
return (elem-1) div 2
|
||||
|
||||
proc siftUp[T](heap: PBinHeap[T], elem: int) =
|
||||
var idx = elem
|
||||
while idx != 0:
|
||||
var p = parent(idx)
|
||||
if heap.heap[idx] < heap.heap[p]:
|
||||
swap(heap.heap[idx], heap.heap[p])
|
||||
idx = p
|
||||
else:
|
||||
break
|
||||
|
||||
proc add*[T](heap: PBinHeap[T], priority: int, data: T) =
|
||||
var node: TNode[T]
|
||||
node.priority = int
|
||||
node.data = data
|
||||
heap.heap[heap.last] = node
|
||||
siftUp(heap, heap.last)
|
||||
inc(heap.last)
|
||||
|
||||
proc print*[T](heap: PBinHeap[T]) =
|
||||
for i in countup(0, heap.last):
|
||||
echo($heap.heap[i])
|
||||
|
||||
var
|
||||
heap: PBinHeap[int]
|
||||
|
||||
newBinHeap(heap, 256)
|
||||
add(heap, 1, 100)
|
||||
print(heap)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user