summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2018-01-27 07:59:40 +0100
committerAndreas Rumpf <rumpf_a@web.de>2018-01-27 07:59:40 +0100
commit68dfd1729e22835d9596b20d419a720ba6452781 (patch)
tree8d4729202e066b0f535aff618afd6f7002c0c77f
parent394757dbf521b8b4a16dd694a687039faeb21682 (diff)
downloadNim-68dfd1729e22835d9596b20d419a720ba6452781.tar.gz
fixes #6989
-rw-r--r--compiler/semfold.nim7
-rw-r--r--lib/system.nim12
-rw-r--r--tests/array/troofregression2.nim104
3 files changed, 116 insertions, 7 deletions
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index f690615ac..55cdc334c 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -30,7 +30,12 @@ proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode =
   case skipTypes(n.typ, abstractVarRange).kind
   of tyInt:
     result = newIntNode(nkIntLit, intVal)
-    result.typ = getIntLitType(result)
+    # See bug #6989. 'pred' et al only produce an int literal type if the
+    # original type was 'int', not a distinct int etc.
+    if n.typ.kind == tyInt:
+      result.typ = getIntLitType(result)
+    else:
+      result.typ = n.typ
     # hrm, this is not correct: 1 + high(int) shouldn't produce tyInt64 ...
     #setIntLitType(result)
   of tyChar:
diff --git a/lib/system.nim b/lib/system.nim
index 2c0617e4d..4e071e802 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -318,7 +318,7 @@ type
   Slice*[T] = HSlice[T, T] ## an alias for ``HSlice[T, T]``
 
 proc `..`*[T, U](a: T, b: U): HSlice[T, U] {.noSideEffect, inline, magic: "DotDot".} =
-  ## `slice`:idx: operator that constructs an interval ``[a, b]``, both `a`
+  ## binary `slice`:idx: operator that constructs an interval ``[a, b]``, both `a`
   ## and `b` are inclusive. Slices can also be used in the set constructor
   ## and in ordinal case statements, but then they are special-cased by the
   ## compiler.
@@ -326,7 +326,7 @@ proc `..`*[T, U](a: T, b: U): HSlice[T, U] {.noSideEffect, inline, magic: "DotDo
   result.b = b
 
 proc `..`*[T](b: T): HSlice[int, T] {.noSideEffect, inline, magic: "DotDot".} =
-  ## `slice`:idx: operator that constructs an interval ``[default(int), b]``
+  ## unary `slice`:idx: operator that constructs an interval ``[default(int), b]``
   result.b = b
 
 when not defined(niminheritable):
@@ -677,12 +677,12 @@ proc `<`*[T](x: Ordinal[T]): T {.magic: "UnaryLt", noSideEffect, deprecated.}
   ## write ``0 ..< 10`` instead of ``0 .. < 10`` (look at the spacing).
   ## For ``<x`` write ``pred(x)``.
 
-proc succ*[T](x: Ordinal[T], y = 1): T {.magic: "Succ", noSideEffect.}
+proc succ*[T: Ordinal](x: T, y = 1): T {.magic: "Succ", noSideEffect.}
   ## returns the ``y``-th successor of the value ``x``. ``T`` has to be
   ## an ordinal type. If such a value does not exist, ``EOutOfRange`` is raised
   ## or a compile time error occurs.
 
-proc pred*[T](x: Ordinal[T], y = 1): T {.magic: "Pred", noSideEffect.}
+proc pred*[T: Ordinal](x: T, y = 1): T {.magic: "Pred", noSideEffect.}
   ## returns the ``y``-th predecessor of the value ``x``. ``T`` has to be
   ## an ordinal type. If such a value does not exist, ``EOutOfRange`` is raised
   ## or a compile time error occurs.
@@ -3505,8 +3505,8 @@ template `..^`*(a, b: untyped): untyped =
   a .. ^b
 
 template `..<`*(a, b: untyped): untyped =
-  ## a shortcut for 'a..pred(b)'.
-  a .. pred(b)
+  ## a shortcut for 'a .. (when b is BackwardsIndex: succ(b) else: pred(b))'.
+  a .. (when b is BackwardsIndex: succ(b) else: pred(b))
 
 when defined(nimNewRoof):
   iterator `..<`*[T](a, b: T): T =
diff --git a/tests/array/troofregression2.nim b/tests/array/troofregression2.nim
new file mode 100644
index 000000000..78d9b9718
--- /dev/null
+++ b/tests/array/troofregression2.nim
@@ -0,0 +1,104 @@
+discard """
+  output: '''OK
+OK
+OK
+OK
+OK
+dflfdjkl__abcdefgasfsgdfgsgdfggsdfasdfsafewfkljdsfajs
+dflfdjkl__abcdefgasfsgdfgsgdfggsdfasdfsafewfkljdsfajsdf
+kgdchlfniambejop
+fjpmholcibdgeakn
+'''
+"""
+
+import strutils, sequtils
+# bug #6989
+
+import typetraits
+
+type Dist = distinct int
+
+proc mypred[T: Ordinal](x: T): T = T(int(x)-1)
+proc cons(x: int): Dist = Dist(x)
+
+var d: Dist
+
+template `^+`(s, i: untyped): untyped =
+  (when i is BackwardsIndex: s.len - int(i) else: int(i))
+
+proc `...`*[T, U](a: T, b: U): HSlice[T, U] =
+  result.a = a
+  result.b = b
+
+proc `...`*[T](b: T): HSlice[int, T] =
+  result.b = b
+
+template `...<`*(a, b: untyped): untyped =
+  ## a shortcut for 'a..pred(b)'.
+  a ... pred(b)
+
+template check(a, b) =
+  if $a == b: echo "OK"
+  else: echo "Failure ", a, " != ", b
+
+check type(4 ...< 1), "HSlice[system.int, system.int]"
+
+check type(4 ...< ^1), "HSlice[system.int, system.BackwardsIndex]"
+check type(4 ... pred(^1)), "HSlice[system.int, system.BackwardsIndex]"
+
+check type(4 ... mypred(8)), "HSlice[system.int, system.int]"
+
+check type(4 ... mypred(^1)), "HSlice[system.int, system.BackwardsIndex]"
+
+var rot = 8
+
+proc bug(s: string): string =
+  result = s
+  result = result[result.len - rot .. ^1] & "__" & result[0 ..< ^rot]
+
+const testStr = "abcdefgasfsgdfgsgdfggsdfasdfsafewfkljdsfajsdflfdjkl"
+
+echo bug(testStr)
+echo testStr[testStr.len - 8 .. testStr.len - 1] & "__" & testStr[0 .. testStr.len - pred(rot)]
+
+
+
+const
+  instructions = readFile("./inputs/16.txt").split(',')
+  programs = "abcdefghijklmnop"
+
+proc dance(dancers: string): string =
+  result = dancers
+  for instr in instructions:
+    let rem = instr[1 .. instr.high]
+    case instr[0]
+    of 's':
+      let rot = rem.parseInt
+      result = result[result.len - rot .. ^1] & result[0 ..< ^rot]
+    of 'x':
+      let
+        x = rem.split('/')
+        a = x[0].parseInt
+        b = x[1].parseInt
+      swap(result[a], result[b])
+    of 'p':
+      let
+        a = result.find(rem[0])
+        b = result.find(rem[^1])
+      result[a] = rem[^1]
+      result[b] = rem[0]
+    else: discard
+
+proc longDance(dancers: string, iterations = 1_000_000_000): string =
+  var
+    dancers = dancers
+    seen = @[dancers]
+  for i in 1 .. iterations:
+    dancers = dancers.dance()
+    if dancers in seen:
+      return seen[iterations mod i]
+    seen.add(dancers)
+
+
+echo dance(programs)
+echo longDance(programs)
ref='#n9'>9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
           

                   



                                
                                                       
                                                                              

                           




                             
 


                                                                      

                                           
                                                                






                                                           
                               


                                           
                                                                   
 
                                        
                    


















                                                   
                              


                                                                      

                                                      





                                        

   










                                     
        

            
discard """
  output: "34[]o 5"
"""
# Test the stuff in the tutorial
import macros

type
  TFigure = object of RootObj    # abstract base class:
    draw: proc (my: var TFigure) {.nimcall.} # concrete classes implement this

proc init(f: var TFigure) =
  f.draw = nil

type
  TCircle = object of TFigure
    radius: int

proc drawCircle(my: var TCircle) = stdout.writeLine("o " & $my.radius)

proc init(my: var TCircle) =
  init(TFigure(my)) # call base constructor
  my.radius = 5
  my.draw = cast[proc (my: var TFigure) {.nimcall.}](drawCircle)

type
  TRectangle = object of TFigure
    width, height: int

proc drawRectangle(my: var TRectangle) = stdout.write("[]")

proc init(my: var TRectangle) =
  init(TFigure(my)) # call base constructor
  my.width = 5
  my.height = 10
  my.draw = cast[proc (my: var TFigure) {.nimcall.}](drawRectangle)

macro `!` (n: varargs[untyped]): typed =
  let n = callsite()
  result = newNimNode(nnkCall, n)
  var dot = newNimNode(nnkDotExpr, n)
  dot.add(n[1])    # obj
  if n[2].kind == nnkCall:
    # transforms ``obj!method(arg1, arg2, ...)`` to
    # ``(obj.method)(obj, arg1, arg2, ...)``
    dot.add(n[2][0]) # method
    result.add(dot)
    result.add(n[1]) # obj
    for i in 1..n[2].len-1:
      result.add(n[2][i])
  else:
    # transforms ``obj!method`` to
    # ``(obj.method)(obj)``
    dot.add(n[2]) # method
    result.add(dot)
    result.add(n[1]) # obj

type
  TSocket* = object of RootObj
    FHost: int # cannot be accessed from the outside of the module
               # the `F` prefix is a convention to avoid clashes since
               # the accessors are named `host`

proc `host=`*(s: var TSocket, value: int) {.inline.} =
  ## setter of hostAddr
  s.FHost = value

proc host*(s: TSocket): int {.inline.} =
  ## getter of hostAddr
  return s.FHost

var
  s: TSocket
s.host = 34  # same as `host=`(s, 34)
stdout.write(s.host)

# now use these classes:
var
  r: TRectangle
  c: TCircle
init(r)
init(c)
r!draw
c!draw()

#OUT 34[]o 5