summary refs log tree commit diff stats
path: root/nimsuggest/tests
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2017-03-09 14:58:14 +0100
committerAraq <rumpf_a@web.de>2017-03-09 14:58:14 +0100
commit475579541621ca83cfcbb35df7f5d9ef4236cdfa (patch)
tree81f95f9ae846b61c7f2878a275413f5a3fc9bea3 /nimsuggest/tests
parentda821a22d9e390d59f66018630fb4c39ba83eaf3 (diff)
downloadNim-475579541621ca83cfcbb35df7f5d9ef4236cdfa.tar.gz
nimsuggest: more precise cursor tracking
Diffstat (limited to 'nimsuggest/tests')
-rw-r--r--nimsuggest/tests/dep_v1.nim8
-rw-r--r--nimsuggest/tests/dep_v2.nim9
-rw-r--r--nimsuggest/tests/tchk1.nim27
-rw-r--r--nimsuggest/tests/tcursor_at_end.nim12
-rw-r--r--nimsuggest/tests/tdef1.nim16
-rw-r--r--nimsuggest/tests/tdot1.nim14
-rw-r--r--nimsuggest/tests/tdot2.nim29
-rw-r--r--nimsuggest/tests/tdot3.nim27
-rw-r--r--nimsuggest/tests/tinclude.nim7
-rw-r--r--nimsuggest/tests/tno_deref.nim14
-rw-r--r--nimsuggest/tests/tstrutils.nim9
-rw-r--r--nimsuggest/tests/tsug_regression.nim28
-rw-r--r--nimsuggest/tests/twithin_macro.nim213
-rw-r--r--nimsuggest/tests/twithin_macro_prefix.nim209
14 files changed, 622 insertions, 0 deletions
diff --git a/nimsuggest/tests/dep_v1.nim b/nimsuggest/tests/dep_v1.nim
new file mode 100644
index 000000000..eae230e85
--- /dev/null
+++ b/nimsuggest/tests/dep_v1.nim
@@ -0,0 +1,8 @@
+
+
+
+
+
+type
+  Foo* = object
+    x*, y*: int
diff --git a/nimsuggest/tests/dep_v2.nim b/nimsuggest/tests/dep_v2.nim
new file mode 100644
index 000000000..ab39721c4
--- /dev/null
+++ b/nimsuggest/tests/dep_v2.nim
@@ -0,0 +1,9 @@
+
+
+
+
+
+type
+  Foo* = object
+    x*, y*: int
+    z*: string
diff --git a/nimsuggest/tests/tchk1.nim b/nimsuggest/tests/tchk1.nim
new file mode 100644
index 000000000..f9f0dc8fe
--- /dev/null
+++ b/nimsuggest/tests/tchk1.nim
@@ -0,0 +1,27 @@
+# test we get some suggestion at the end of the file
+
+
+
+
+
+
+
+type
+
+
+template foo() =
+
+proc main =
+
+#[!]#
+discard """
+$nimsuggest --tester $file
+>chk $1
+chk;;skUnknown;;;;Hint;;???;;-1;;-1;;"tchk1 [Processing]";;0
+chk;;skUnknown;;;;Error;;$file;;12;;0;;"identifier expected, but found \'keyword template\'";;0
+chk;;skUnknown;;;;Error;;$file;;14;;0;;"complex statement requires indentation";;0
+chk;;skUnknown;;;;Error;;$file;;12;;0;;"implementation of \'foo\' expected";;0
+chk;;skUnknown;;;;Error;;$file;;17;;0;;"invalid indentation";;0
+chk;;skUnknown;;;;Hint;;$file;;12;;9;;"\'foo\' is declared but not used [XDeclaredButNotUsed]";;0
+chk;;skUnknown;;;;Hint;;$file;;14;;5;;"\'tchk1.main()\' is declared but not used [XDeclaredButNotUsed]";;0
+"""
diff --git a/nimsuggest/tests/tcursor_at_end.nim b/nimsuggest/tests/tcursor_at_end.nim
new file mode 100644
index 000000000..b3a0d1133
--- /dev/null
+++ b/nimsuggest/tests/tcursor_at_end.nim
@@ -0,0 +1,12 @@
+# test we get some suggestion at the end of the file
+
+discard """
+$nimsuggest --tester $file
+>sug $1
+sug;;skProc;;tcursor_at_end.main;;proc ();;$file;;10;;5;;"";;*
+"""
+
+
+proc main = discard
+
+#[!]#
diff --git a/nimsuggest/tests/tdef1.nim b/nimsuggest/tests/tdef1.nim
new file mode 100644
index 000000000..2cd040ea1
--- /dev/null
+++ b/nimsuggest/tests/tdef1.nim
@@ -0,0 +1,16 @@
+discard """
+$nimsuggest --tester $file
+>def $1
+def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe, locks: 0.};;$file;;9;;5;;"Return hello";;100
+>def $1
+def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe, locks: 0.};;$file;;9;;5;;"Return hello";;100
+"""
+
+proc hello(): string =
+  ## Return hello
+  "Hello"
+
+hel#[!]#lo()
+
+# v uncompleted id for sug (13,2)
+he
diff --git a/nimsuggest/tests/tdot1.nim b/nimsuggest/tests/tdot1.nim
new file mode 100644
index 000000000..9ac92f8a5
--- /dev/null
+++ b/nimsuggest/tests/tdot1.nim
@@ -0,0 +1,14 @@
+discard """
+$nimsuggest --tester $file
+>sug $1
+sug;;skField;;x;;int;;$file;;11;;4;;"";;100;;None
+sug;;skField;;y;;int;;$file;;11;;7;;"";;100;;None
+sug;;skProc;;tdot1.main;;proc (f: Foo);;$file;;13;;5;;"";;100;;None
+"""
+
+type
+  Foo = object
+    x, y: int
+
+proc main(f: Foo) =
+  if f.#[!]#:
diff --git a/nimsuggest/tests/tdot2.nim b/nimsuggest/tests/tdot2.nim
new file mode 100644
index 000000000..f02b5cf16
--- /dev/null
+++ b/nimsuggest/tests/tdot2.nim
@@ -0,0 +1,29 @@
+# Test basic editing. We replace the 'false' by 'true' to
+# see whether then the z field is suggested.
+
+const zField = 0i32
+
+type
+  Foo = object
+    x, y: int
+    when zField == 1i32:
+      z: string
+
+proc main(f: Foo) =
+  f.#[!]#
+
+# the tester supports the spec section at the bottom of the file and
+# this way, the line numbers more often stay the same
+discard """
+$nimsuggest --tester $file
+>sug $1
+sug;;skField;;x;;int;;$file;;8;;4;;"";;100;;None
+sug;;skField;;y;;int;;$file;;8;;7;;"";;100;;None
+sug;;skProc;;tdot2.main;;proc (f: Foo);;$file;;12;;5;;"";;100;;None
+!edit 0i32 1i32
+>sug $1
+sug;;skField;;x;;int;;$file;;8;;4;;"";;100;;None
+sug;;skField;;y;;int;;$file;;8;;7;;"";;100;;None
+sug;;skField;;z;;string;;$file;;10;;6;;"";;100;;None
+sug;;skProc;;tdot2.main;;proc (f: Foo);;$file;;12;;5;;"";;100;;None
+"""
diff --git a/nimsuggest/tests/tdot3.nim b/nimsuggest/tests/tdot3.nim
new file mode 100644
index 000000000..15fc1cd1c
--- /dev/null
+++ b/nimsuggest/tests/tdot3.nim
@@ -0,0 +1,27 @@
+# Test basic module dependency recompilations.
+
+import dep
+
+proc main(f: Foo) =
+  f.#[!]#
+
+# the tester supports the spec section at the bottom of the file and
+# this way, the line numbers more often stay the same
+
+discard """
+!copy dep_v1.nim dep.nim
+$nimsuggest --tester $file
+>sug $1
+sug;;skField;;x;;int;;*dep.nim;;8;;4;;"";;100;;None
+sug;;skField;;y;;int;;*dep.nim;;8;;8;;"";;100;;None
+sug;;skProc;;tdot3.main;;proc (f: Foo);;$file;;5;;5;;"";;100;;None
+
+!copy dep_v2.nim dep.nim
+>mod $path/dep.nim
+>sug $1
+sug;;skField;;x;;int;;*dep.nim;;8;;4;;"";;100;;None
+sug;;skField;;y;;int;;*dep.nim;;8;;8;;"";;100;;None
+sug;;skField;;z;;string;;*dep.nim;;9;;4;;"";;100;;None
+sug;;skProc;;tdot3.main;;proc (f: Foo);;$file;;5;;5;;"";;100;;None
+!del dep.nim
+"""
diff --git a/nimsuggest/tests/tinclude.nim b/nimsuggest/tests/tinclude.nim
new file mode 100644
index 000000000..27391c522
--- /dev/null
+++ b/nimsuggest/tests/tinclude.nim
@@ -0,0 +1,7 @@
+discard """
+$nimsuggest --tester compiler/nim.nim
+>def compiler/semexprs.nim:13:50
+def;;skType;;ast.PSym;;PSym;;*ast.nim;;669;;2;;"";;100
+>def compiler/semexprs.nim:13:50
+def;;skType;;ast.PSym;;PSym;;*ast.nim;;669;;2;;"";;100
+"""
diff --git a/nimsuggest/tests/tno_deref.nim b/nimsuggest/tests/tno_deref.nim
new file mode 100644
index 000000000..05cffa507
--- /dev/null
+++ b/nimsuggest/tests/tno_deref.nim
@@ -0,0 +1,14 @@
+
+var x: ptr int
+
+proc foo(y: ptr int) =
+    discard
+
+x.#[!]#
+
+discard """
+$nimsuggest --tester $file
+>sug $1
+sug;;skProc;;tno_deref.foo;;proc (y: ptr int)*;;$file;;4;;5;;"";;100;;None
+*
+"""
diff --git a/nimsuggest/tests/tstrutils.nim b/nimsuggest/tests/tstrutils.nim
new file mode 100644
index 000000000..34da8cb53
--- /dev/null
+++ b/nimsuggest/tests/tstrutils.nim
@@ -0,0 +1,9 @@
+discard """
+$nimsuggest --tester lib/pure/strutils.nim
+>def lib/pure/strutils.nim:2300:6
+def;;skTemplate;;system.doAssert;;proc (cond: bool, msg: string): typed;;*/lib/system.nim;;*;;9;;"same as `assert` but is always turned on and not affected by the\x0A``--assertions`` command line switch.";;100
+"""
+
+# Line 2300 in strutils.nim is doAssert and this is unlikely to change
+# soon since there are a whole lot of doAsserts there.
+
diff --git a/nimsuggest/tests/tsug_regression.nim b/nimsuggest/tests/tsug_regression.nim
new file mode 100644
index 000000000..1e440db2d
--- /dev/null
+++ b/nimsuggest/tests/tsug_regression.nim
@@ -0,0 +1,28 @@
+# test we only get suggestions, not error messages:
+
+import tables, sets, parsecfg
+
+type X = object
+
+proc main =
+  # bug #52
+  var
+    set0 = initSet[int]()
+    set1 = initSet[X]()
+    set2 = initSet[ref int]()
+
+    map0 = initTable[int, int]()
+    map1 = initOrderedTable[string, int]()
+    cfg = loadConfig("file")
+  map0.#[!]#
+
+discard """
+$nimsuggest --tester $file
+>sug $1
+sug;;skProc;;tables.getOrDefault;;proc (t: Table[getOrDefault.A, getOrDefault.B], key: A): B;;$lib/pure/collections/tables.nim;;178;;5;;"";;100;;None
+sug;;skProc;;tables.hasKey;;proc (t: Table[hasKey.A, hasKey.B], key: A): bool;;$lib/pure/collections/tables.nim;;233;;5;;"returns true iff `key` is in the table `t`.";;100;;None
+sug;;skProc;;tables.add;;proc (t: var Table[add.A, add.B], key: A, val: B);;$lib/pure/collections/tables.nim;;297;;5;;"puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.";;100;;None
+sug;;skIterator;;tables.allValues;;iterator (t: Table[allValues.A, allValues.B], key: A): B{.inline.};;$lib/pure/collections/tables.nim;;225;;9;;"iterates over any value in the table `t` that belongs to the given `key`.";;100;;None
+sug;;skProc;;tables.clear;;proc (t: var Table[clear.A, clear.B]);;$lib/pure/collections/tables.nim;;121;;5;;"Resets the table so that it is empty.";;100;;None
+*
+"""
diff --git a/nimsuggest/tests/twithin_macro.nim b/nimsuggest/tests/twithin_macro.nim
new file mode 100644
index 000000000..e0df03542
--- /dev/null
+++ b/nimsuggest/tests/twithin_macro.nim
@@ -0,0 +1,213 @@
+
+import macros
+
+macro class*(head, body: untyped): untyped =
+  # The macro is immediate, since all its parameters are untyped.
+  # This means, it doesn't resolve identifiers passed to it.
+
+  var typeName, baseName: NimNode
+
+  # flag if object should be exported
+  var exported: bool
+
+  if head.kind == nnkInfix and head[0].ident == !"of":
+    # `head` is expression `typeName of baseClass`
+    # echo head.treeRepr
+    # --------------------
+    # Infix
+    #   Ident !"of"
+    #   Ident !"Animal"
+    #   Ident !"RootObj"
+    typeName = head[1]
+    baseName = head[2]
+
+  elif head.kind == nnkInfix and head[0].ident == !"*" and
+       head[2].kind == nnkPrefix and head[2][0].ident == !"of":
+    # `head` is expression `typeName* of baseClass`
+    # echo head.treeRepr
+    # --------------------
+    # Infix
+    #   Ident !"*"
+    #   Ident !"Animal"
+    #   Prefix
+    #     Ident !"of"
+    #     Ident !"RootObj"
+    typeName = head[1]
+    baseName = head[2][1]
+    exported = true
+
+  else:
+    quit "Invalid node: " & head.lispRepr
+
+  # The following prints out the AST structure:
+  #
+  # import macros
+  # dumptree:
+  #   type X = ref object of Y
+  #     z: int
+  # --------------------
+  # StmtList
+  #   TypeSection
+  #     TypeDef
+  #       Ident !"X"
+  #       Empty
+  #       RefTy
+  #         ObjectTy
+  #           Empty
+  #           OfInherit
+  #             Ident !"Y"
+  #           RecList
+  #             IdentDefs
+  #               Ident !"z"
+  #               Ident !"int"
+  #               Empty
+
+  # create a type section in the result
+  result =
+    if exported:
+      # mark `typeName` with an asterisk
+      quote do:
+        type `typeName`* = ref object of `baseName`
+    else:
+      quote do:
+        type `typeName` = ref object of `baseName`
+
+  # echo treeRepr(body)
+  # --------------------
+  # StmtList
+  #   VarSection
+  #     IdentDefs
+  #       Ident !"name"
+  #       Ident !"string"
+  #       Empty
+  #     IdentDefs
+  #       Ident !"age"
+  #       Ident !"int"
+  #       Empty
+  #   MethodDef
+  #     Ident !"vocalize"
+  #     Empty
+  #     Empty
+  #     FormalParams
+  #       Ident !"string"
+  #     Empty
+  #     Empty
+  #     StmtList
+  #       StrLit ...
+  #   MethodDef
+  #     Ident !"age_human_yrs"
+  #     Empty
+  #     Empty
+  #     FormalParams
+  #       Ident !"int"
+  #     Empty
+  #     Empty
+  #     StmtList
+  #       DotExpr
+  #         Ident !"this"
+  #         Ident !"age"
+
+  # var declarations will be turned into object fields
+  var recList = newNimNode(nnkRecList)
+
+  # expected name of constructor
+  let ctorName = newIdentNode("new" & $typeName)
+
+  # Iterate over the statements, adding `this: T`
+  # to the parameters of functions, unless the
+  # function is a constructor
+  for node in body.children:
+    case node.kind:
+
+      of nnkMethodDef, nnkProcDef:
+        # check if it is the ctor proc
+        if node.name.kind != nnkAccQuoted and node.name.basename == ctorName:
+          # specify the return type of the ctor proc
+          node.params[0] = typeName
+        else:
+          # inject `self: T` into the arguments
+          node.params.insert(1, newIdentDefs(ident("self"), typeName))
+        result.add(node)
+
+      of nnkVarSection:
+        # variables get turned into fields of the type.
+        for n in node.children:
+          recList.add(n)
+
+      else:
+        result.add(node)
+
+  # Inspect the tree structure:
+  #
+  # echo result.treeRepr
+  # --------------------
+  # StmtList
+  #   TypeSection
+  #     TypeDef
+  #       Ident !"Animal"
+  #       Empty
+  #       RefTy
+  #         ObjectTy
+  #           Empty
+  #           OfInherit
+  #             Ident !"RootObj"
+  #           Empty   <= We want to replace this
+  # MethodDef
+  # ...
+
+  result[0][0][2][0][2] = recList
+
+  # Lets inspect the human-readable version of the output
+  #echo repr(result)
+
+# ---
+
+class Animal of RootObj:
+  var name: string
+  var age: int
+  method vocalize: string {.base.} = "..." # use `base` pragma to annonate base methods
+  method age_human_yrs: int {.base.} = self.age # `this` is injected
+  proc `$`: string = "animal:" & self.name & ":" & $self.age
+
+class Dog of Animal:
+  method vocalize: string = "woof"
+  method age_human_yrs: int = self.age * 7
+  proc `$`: string = "dog:" & self.name & ":" & $self.age
+
+class Cat of Animal:
+  method vocalize: string = "meow"
+  proc `$`: string = "cat:" & self.name & ":" & $self.age
+
+class Rabbit of Animal:
+  proc newRabbit(name: string, age: int) = # the constructor doesn't need a return type
+    result = Rabbit(name: name, age: age)
+  method vocalize: string = "meep"
+  proc `$`: string =
+    self.#[!]#
+    result = "rabbit:" & self.name & ":" & $self.age
+
+# ---
+
+var animals: seq[Animal] = @[]
+animals.add(Dog(name: "Sparky", age: 10))
+animals.add(Cat(name: "Mitten", age: 10))
+
+for a in animals:
+  echo a.vocalize()
+  echo a.age_human_yrs()
+
+let r = newRabbit("Fluffy", 3)
+echo r.vocalize()
+echo r.age_human_yrs()
+echo r
+
+discard """
+$nimsuggest --tester $file
+>sug $1
+sug;;skField;;age;;int;;$file;;167;;6;;"";;100;;None
+sug;;skField;;name;;string;;$file;;166;;6;;"";;100;;None
+sug;;skMethod;;twithin_macro.age_human_yrs;;proc (self: Animal): int;;$file;;169;;9;;"";;100;;None
+sug;;skMethod;;twithin_macro.vocalize;;proc (self: Animal): string;;$file;;168;;9;;"";;100;;None
+sug;;skMethod;;twithin_macro.vocalize;;proc (self: Rabbit): string;;$file;;184;;9;;"";;100;;None
+sug;;skMacro;;twithin_macro.class;;proc (head: untyped, body: untyped): untyped{.gcsafe, locks: <unknown>.};;$file;;4;;6;;"";;50;;None*
+"""
diff --git a/nimsuggest/tests/twithin_macro_prefix.nim b/nimsuggest/tests/twithin_macro_prefix.nim
new file mode 100644
index 000000000..86e406c5d
--- /dev/null
+++ b/nimsuggest/tests/twithin_macro_prefix.nim
@@ -0,0 +1,209 @@
+
+import macros
+
+macro class*(head, body: untyped): untyped =
+  # The macro is immediate, since all its parameters are untyped.
+  # This means, it doesn't resolve identifiers passed to it.
+
+  var typeName, baseName: NimNode
+
+  # flag if object should be exported
+  var exported: bool
+
+  if head.kind == nnkInfix and head[0].ident == !"of":
+    # `head` is expression `typeName of baseClass`
+    # echo head.treeRepr
+    # --------------------
+    # Infix
+    #   Ident !"of"
+    #   Ident !"Animal"
+    #   Ident !"RootObj"
+    typeName = head[1]
+    baseName = head[2]
+
+  elif head.kind == nnkInfix and head[0].ident == !"*" and
+       head[2].kind == nnkPrefix and head[2][0].ident == !"of":
+    # `head` is expression `typeName* of baseClass`
+    # echo head.treeRepr
+    # --------------------
+    # Infix
+    #   Ident !"*"
+    #   Ident !"Animal"
+    #   Prefix
+    #     Ident !"of"
+    #     Ident !"RootObj"
+    typeName = head[1]
+    baseName = head[2][1]
+    exported = true
+
+  else:
+    quit "Invalid node: " & head.lispRepr
+
+  # The following prints out the AST structure:
+  #
+  # import macros
+  # dumptree:
+  #   type X = ref object of Y
+  #     z: int
+  # --------------------
+  # StmtList
+  #   TypeSection
+  #     TypeDef
+  #       Ident !"X"
+  #       Empty
+  #       RefTy
+  #         ObjectTy
+  #           Empty
+  #           OfInherit
+  #             Ident !"Y"
+  #           RecList
+  #             IdentDefs
+  #               Ident !"z"
+  #               Ident !"int"
+  #               Empty
+
+  # create a type section in the result
+  result =
+    if exported:
+      # mark `typeName` with an asterisk
+      quote do:
+        type `typeName`* = ref object of `baseName`
+    else:
+      quote do:
+        type `typeName` = ref object of `baseName`
+
+  # echo treeRepr(body)
+  # --------------------
+  # StmtList
+  #   VarSection
+  #     IdentDefs
+  #       Ident !"name"
+  #       Ident !"string"
+  #       Empty
+  #     IdentDefs
+  #       Ident !"age"
+  #       Ident !"int"
+  #       Empty
+  #   MethodDef
+  #     Ident !"vocalize"
+  #     Empty
+  #     Empty
+  #     FormalParams
+  #       Ident !"string"
+  #     Empty
+  #     Empty
+  #     StmtList
+  #       StrLit ...
+  #   MethodDef
+  #     Ident !"age_human_yrs"
+  #     Empty
+  #     Empty
+  #     FormalParams
+  #       Ident !"int"
+  #     Empty
+  #     Empty
+  #     StmtList
+  #       DotExpr
+  #         Ident !"this"
+  #         Ident !"age"
+
+  # var declarations will be turned into object fields
+  var recList = newNimNode(nnkRecList)
+
+  # expected name of constructor
+  let ctorName = newIdentNode("new" & $typeName)
+
+  # Iterate over the statements, adding `this: T`
+  # to the parameters of functions, unless the
+  # function is a constructor
+  for node in body.children:
+    case node.kind:
+
+      of nnkMethodDef, nnkProcDef:
+        # check if it is the ctor proc
+        if node.name.kind != nnkAccQuoted and node.name.basename == ctorName:
+          # specify the return type of the ctor proc
+          node.params[0] = typeName
+        else:
+          # inject `self: T` into the arguments
+          node.params.insert(1, newIdentDefs(ident("self"), typeName))
+        result.add(node)
+
+      of nnkVarSection:
+        # variables get turned into fields of the type.
+        for n in node.children:
+          recList.add(n)
+
+      else:
+        result.add(node)
+
+  # Inspect the tree structure:
+  #
+  # echo result.treeRepr
+  # --------------------
+  # StmtList
+  #   TypeSection
+  #     TypeDef
+  #       Ident !"Animal"
+  #       Empty
+  #       RefTy
+  #         ObjectTy
+  #           Empty
+  #           OfInherit
+  #             Ident !"RootObj"
+  #           Empty   <= We want to replace this
+  # MethodDef
+  # ...
+
+  result[0][0][2][0][2] = recList
+
+  # Lets inspect the human-readable version of the output
+  #echo repr(result)
+
+# ---
+
+class Animal of RootObj:
+  var name: string
+  var age: int
+  method vocalize: string {.base.} = "..." # use `base` pragma to annonate base methods
+  method age_human_yrs: int {.base.} = self.age # `this` is injected
+  proc `$`: string = "animal:" & self.name & ":" & $self.age
+
+class Dog of Animal:
+  method vocalize: string = "woof"
+  method age_human_yrs: int = self.age * 7
+  proc `$`: string = "dog:" & self.name & ":" & $self.age
+
+class Cat of Animal:
+  method vocalize: string = "meow"
+  proc `$`: string = "cat:" & self.name & ":" & $self.age
+
+class Rabbit of Animal:
+  proc newRabbit(name: string, age: int) = # the constructor doesn't need a return type
+    result = Rabbit(name: name, age: age)
+  method vocalize: string = "meep"
+  proc `$`: string =
+    self.ag#[!]#
+    result = "rabbit:" & self.name & ":" & $self.age
+
+# ---
+
+var animals: seq[Animal] = @[]
+animals.add(Dog(name: "Sparky", age: 10))
+animals.add(Cat(name: "Mitten", age: 10))
+
+for a in animals:
+  echo a.vocalize()
+  echo a.age_human_yrs()
+
+let r = newRabbit("Fluffy", 3)
+echo r.vocalize()
+echo r.age_human_yrs()
+echo r
+
+discard """
+$nimsuggest --tester $file
+>sug $1
+sug;;skField;;age;;int;;$file;;167;;6;;"";;100;;Prefix
+sug;;skMethod;;twithin_macro_prefix.age_human_yrs;;proc (self: Animal): int;;$file;;169;;9;;"";;100;;Prefix
+"""