discard """
output: '''
i2416
33
foo55
foo8.0
fooaha
bar7
10
4true
132
20
1
-1
4
11
26
57
-1-1-1
  4
4
  4
  11
11
  4
  11
  26
26
  4
  11
  26
  57
57
-1-1-1
'''
"""

import macros




import i2416
i2416()


import mcan_access_hidden_field
var myfoo = createFoo(33, 44)
echo myfoo.geta


import mgensym_generic_cross_module
foo(55)
foo 8.0
foo "aha"
bar 7



block generic_templates:
  type
    SomeObj = object of RootObj
    Foo[T, U] = object
      x: T
      y: U

  template someTemplate[T](): tuple[id: int32, obj: T] =
    var result: tuple[id: int32, obj: T] = (0'i32, T())
    result

  let ret = someTemplate[SomeObj]()

  # https://github.com/nim-lang/Nim/issues/7829
  proc inner[T](): int =
    discard

  template outer[A](): untyped =
    inner[A]()

  template outer[B](x: int): untyped =
    inner[B]()

  var i1 = outer[int]()
  var i2 = outer[int](i1)

  # https://github.com/nim-lang/Nim/issues/7883
  template t1[T: int|int64](s: string): T =
     var t: T
     t

  template t1[T: int|int64](x: int, s: string): T =
     var t: T
     t

  var i3: int = t1[int]("xx")

from strutils import contains

block tgetast_typeliar:
  proc error(s: string) = quit s

  macro assertOrReturn2(condition: bool; message: string) =
    var line = condition.lineInfo()
    result = quote do:
      block:
        if not likely(`condition`):
          error("Assertion failed: " & $(`message`) & "\n" & `line`)
          return

  macro assertOrReturn(condition: bool) =
    var message : NimNode = newLit(condition.repr)
    # echo message
    result = getAst assertOrReturn2(condition, message)
    # echo result.repr
    let s = result.repr
    doAssert """error("Assertion failed:""" in s

  proc point(size: int16): tuple[x, y: int16] =
    # returns random point in square area with given `size`
    assertOrReturn size > 0



type
  MyFloat = object
    val: float
converter to_myfloat(x: float): MyFloat {.inline.} =
  MyFloat(val: x)

block pattern_with_converter:
  proc `+`(x1, x2: MyFloat): MyFloat =
    MyFloat(val: x1.val + x2.val)

  proc `*`(x1, x2: MyFloat): MyFloat =
      MyFloat(val: x1.val * x2.val)

  template optMul{`*`(a, 2.0)}(a: MyFloat): MyFloat =
    a + a

  func floatMyFloat(x: MyFloat): MyFloat =
    result = x * 2.0

  func floatDouble(x: float): float =
    result = x * 2.0

  doAssert floatDouble(5) == 10.0




block procparshadow:
  template something(name: untyped) =
    proc name(x: int) =
      var x = x # this one should not be rejected by the compiler (#5225)
      echo x

  something(what)
  what(10)

  # bug #4750
  type
    O = object
      i: int
    OP = ptr O

  template alf(p: pointer): untyped =
    cast[OP](p)

  proc t1(al: pointer) =
    var o = alf(al)

  proc t2(alf: pointer) =
    var x = alf
    var o = alf(x)



block symchoicefield:
  type Foo = object
    len: int

  var f = Foo(len: 40)

  template getLen(f: Foo): int = f.len

  doAssert f.getLen == 40
  # This fails, because `len` gets the nkOpenSymChoice
  # treatment inside the template early pass and then
  # it can't be recognized as a field anymore



import os, times
include "sunset.nimf"
block ttempl:
  const
    tabs = [["home", "index"],
            ["news", "news"],
            ["documentation", "documentation"],
            ["download", "download"],
            ["FAQ", "question"],
            ["links", "links"]]


  var i = 0
  for item in items(tabs):
    var content = $i
    var file: File
    if open(file, changeFileExt(item[1], "html"), fmWrite):
      write(file, sunsetTemplate(current=item[1], ticker="", content=content,
                                  tabs=tabs))
      close(file)
    else:
      write(stdout, "cannot open file for writing")
    inc(i)



block ttempl4:
  template `:=`(name, val: untyped) =
    var name = val

  ha := 1 * 4
  hu := "ta-da" == "ta-da"
  echo ha, hu




import mtempl5
block ttempl5:
  echo templ()

  #bug #892
  proc parse_to_close(value: string, index: int, open='(', close=')'): int =
      discard

  # Call parse_to_close
  template get_next_ident =
      discard "{something}".parse_to_close(0, open = '{', close = '}')

  get_next_ident()

  #identifier expected, but found '(open|open|open)'
  #bug #880 (also example in the manual!)
  template typedef(name: untyped, typ: typedesc) =
    type
      `T name` {.inject.} = typ
      `P name` {.inject.} = ref `T name`

  typedef(myint, int)
  var x: PMyInt



block templreturntype:
  template `=~` (a: int, b: int): bool = false
  var foo = 2 =~ 3

# bug #7117
template parse9(body: untyped): untyped =

  template val9(arg: string): int {.inject.} =
    var b: bool
    if b: 10
    else: 20

  body

parse9:
  echo val9("1")


block gensym1:
  template x: untyped = -1
  template t1() =
    template x: untyped {.gensym, redefine.} = 1
    echo x()  # 1
  template t2() =
    template x: untyped {.redefine.} = 1  # defaults to {.inject.}
    echo x()  # -1  injected x not available during template definition
  t1()
  t2()

block gensym2:
  let x,y,z = -1
  template `!`(xx,yy: typed): untyped =
    template x: untyped {.gensym.} = xx
    template y: untyped {.gensym.} = yy
    let z = x + x + y
    z
  var
    a = 1
    b = 2
    c = 3
    d = 4
    e = 5
  echo a ! b
  echo a ! b ! c
  echo a ! b ! c ! d
  echo a ! b ! c ! d ! e
  echo x,y,z

block gensym3:
  macro liftStmts(body: untyped): auto =
    # convert
    #   template x: untyped {.gensym.} =
    #     let z = a + a + b
    #     echo z
    #     z
    # to
    #   let z = a + a + b
    #   echo z
    #   template x: untyped {.gensym.} =
    #     z
    #echo body.repr
    body.expectKind nnkStmtList
    result = newNimNode nnkStmtList
    for s in body:
      s.expectKind nnkTemplateDef
      var sle = s[6]
      while sle.kind == nnkStmtList:
        doAssert(sle.len==1)
        sle = sle[0]
      if sle.kind == nnkStmtListExpr:
        let n = sle.len
        for i in 0..(n-2):
          result.add sle[i]
        var td = newNimNode nnkTemplateDef
        for i in 0..5:
          td.add s[i]
        td.add sle[n-1]
        result.add td
      else:
        result.add s
    #echo result.repr
  let x,y,z = -1
  template `!`(xx,yy: typed): untyped =
    liftStmts:
      template x: untyped {.gensym.} = xx
      template y: untyped {.gensym.} = yy
    let z = x + x + y
    echo "  ", z
    z
  var
    a = 1
    b = 2
    c = 3
    d = 4
    e = 5
  echo a ! b
  echo a ! b ! c
  echo a ! b ! c ! d
  echo a ! b ! c ! d ! e
  echo x,y,z

block: # issue #2465
  template t() =
    template declX(str: string) {.gensym.} =
      var x {.inject.} : string = str

  t()
  doAssert not declared(declX)
  doAssert not compiles(declX("a string"))

  template t2() =
    template fooGensym() {.gensym.} =
      echo 42

  t2()
  doAssert not declared(fooGensym)
  doAssert not compiles(fooGensym())


block identifier_construction_with_overridden_symbol:
  # could use add, but wanna make sure it's an override no matter what
  func examplefn = discard
  func examplefn(x: int) = discard

  # the function our template wants to use
  func examplefn1 = discard

  template exampletempl(n) =
    # attempt to build a name using the overridden symbol "examplefn"
    `examplefn n`()

  exampletempl(1)

import typetraits

block: # issue #4596
  type
    T0 = object
    T1 = object

  template printFuncsT() =
    proc getV[A](a: typedesc[A]): string =
      var s {. global .} = name(A)
      return s

  printFuncsT()

  doAssert getV(T1) == "T1"
  doAssert getV(T0) == "T0"
  doAssert getV(T0) == "T0"
  doAssert getV(T1) == "T1"
