tcustom_numeric_literals.nim 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. discard """
  2. targets: "c cpp js"
  3. """
  4. # Test tkStrNumLit
  5. import std/[macros, strutils]
  6. import mlexerutils
  7. # AST checks
  8. assertAST dedent """
  9. StmtList
  10. ProcDef
  11. AccQuoted
  12. Ident "\'"
  13. Ident "wrap"
  14. Empty
  15. Empty
  16. FormalParams
  17. Ident "string"
  18. IdentDefs
  19. Ident "number"
  20. Ident "string"
  21. Empty
  22. Empty
  23. Empty
  24. StmtList
  25. Asgn
  26. Ident "result"
  27. Infix
  28. Ident "&"
  29. Infix
  30. Ident "&"
  31. StrLit "[["
  32. Ident "number"
  33. StrLit "]]"""":
  34. proc `'wrap`(number: string): string =
  35. result = "[[" & number & "]]"
  36. assertAST dedent """
  37. StmtList
  38. DotExpr
  39. RStrLit "-38383839292839283928392839283928392839283.928493849385935898243e-50000"
  40. Ident "\'wrap"""":
  41. -38383839292839283928392839283928392839283.928493849385935898243e-50000'wrap
  42. proc `'wrap`(number: string): string = "[[" & number & "]]"
  43. proc wrap2(number: string): string = "[[" & number & "]]"
  44. doAssert lispReprStr(-1'wrap) == """(DotExpr (RStrLit "-1") (Ident "\'wrap"))"""
  45. template main =
  46. block: # basic suffix usage
  47. template `'twrap`(number: string): untyped =
  48. number.`'wrap`
  49. proc extraContext(): string =
  50. 22.40'wrap
  51. proc `*`(left, right: string): string =
  52. result = left & "times" & right
  53. proc `+`(left, right: string): string =
  54. result = left & "plus" & right
  55. doAssert 1'wrap == "[[1]]"
  56. doAssert -1'wrap == "[[-1]]":
  57. "unable to resolve a negative integer-suffix pattern"
  58. doAssert 12345.67890'wrap == "[[12345.67890]]"
  59. doAssert 1'wrap*1'wrap == "[[1]]times[[1]]":
  60. "unable to resolve an operator between two suffixed numeric literals"
  61. doAssert 1'wrap+ -1'wrap == "[[1]]plus[[-1]]": # will generate a compiler warning about inconsistent spacing
  62. "unable to resolve a negative suffixed numeric literal following an operator"
  63. doAssert 1'wrap + -1'wrap == "[[1]]plus[[-1]]"
  64. doAssert 1'twrap == "[[1]]"
  65. doAssert extraContext() == "[[22.40]]":
  66. "unable to return a suffixed numeric literal by an implicit return"
  67. doAssert 0x5a3a'wrap == "[[0x5a3a]]"
  68. doAssert 0o5732'wrap == "[[0o5732]]"
  69. doAssert 0b0101111010101'wrap == "[[0b0101111010101]]"
  70. doAssert -38383839292839283928392839283928392839283.928493849385935898243e-50000'wrap == "[[-38383839292839283928392839283928392839283.928493849385935898243e-50000]]"
  71. doAssert 1234.56'wrap == "[[1234.56]]":
  72. "unable to properly account for context with suffixed numeric literals"
  73. block: # verify that the i64, f32, etc builtin suffixes still parse correctly
  74. const expectedF32: float32 = 123.125
  75. proc `'f9`(number: string): string = # proc starts with 'f' just like 'f32'
  76. "[[" & number & "]]"
  77. proc `'f32a`(number: string): string = # looks even more like 'f32'
  78. "[[" & number & "]]"
  79. proc `'d9`(number: string): string = # proc starts with 'd' just like the d suffix
  80. "[[" & number & "]]"
  81. proc `'i9`(number: string): string = # proc starts with 'i' just like 'i64'
  82. "[[" & number & "]]"
  83. proc `'u9`(number: string): string = # proc starts with 'u' just like 'u8'
  84. "[[" & number & "]]"
  85. doAssert 123.125f32 == expectedF32:
  86. "failing to support non-quoted legacy f32 floating point suffix"
  87. doAssert 123.125'f32 == expectedF32
  88. doAssert 123.125e0'f32 == expectedF32
  89. doAssert 1234.56'wrap == 1234.56'f9
  90. doAssert 1234.56'wrap == 1234.56'f32a
  91. doAssert 1234.56'wrap == 1234.56'd9
  92. doAssert 1234.56'wrap == 1234.56'i9
  93. doAssert 1234.56'wrap == 1234.56'u9
  94. doAssert lispReprStr(1234.56'u9) == """(DotExpr (RStrLit "1234.56") (Ident "\'u9"))""":
  95. "failed to properly build AST for suffix that starts with u"
  96. doAssert -128'i8 == (-128).int8
  97. block: # case checks
  98. doAssert 1E2 == 100:
  99. "lexer not handling upper-case exponent"
  100. doAssert 1.0E2 == 100.0
  101. doAssert 1e2 == 100
  102. doAssert 0xdeadBEEF'wrap == "[[0xdeadBEEF]]":
  103. "lexer not maintaining original case"
  104. doAssert 0.1E12'wrap == "[[0.1E12]]"
  105. doAssert 0.0e12'wrap == "[[0.0e12]]"
  106. doAssert 0.0e+12'wrap == "[[0.0e+12]]"
  107. doAssert 0.0e-12'wrap == "[[0.0e-12]]"
  108. doAssert 0e-12'wrap == "[[0e-12]]"
  109. block: # macro and template usage
  110. template `'foo`(a: string): untyped = (a, 2)
  111. doAssert -12'foo == ("-12", 2)
  112. template `'fooplus`(a: string, b: int): untyped = (a, b)
  113. doAssert -12'fooplus(2) == ("-12", 2)
  114. template `'fooplusopt`(a: string, b: int = 99): untyped = (a, b)
  115. doAssert -12'fooplusopt(2) == ("-12", 2)
  116. doAssert -12'fooplusopt() == ("-12", 99)
  117. doAssert -12'fooplusopt == ("-12", 99)
  118. macro `'bar`(a: static string): untyped = newLit(a.repr)
  119. doAssert -12'bar == "\"-12\""
  120. macro deb(a): untyped = newLit(a.repr)
  121. doAssert deb(-12'bar) == "-12'bar"
  122. block: # bug 1 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947
  123. macro deb1(a): untyped = newLit a.repr
  124. macro deb2(a): untyped = newLit a.lispRepr
  125. doAssert deb1(-12'wrap) == "-12'wrap"
  126. doAssert deb1(-12'nonexistent) == "-12'nonexistent"
  127. doAssert deb2(-12'nonexistent) == """(DotExpr (RStrLit "-12") (Ident "\'nonexistent"))"""
  128. when false: # xxx bug:
  129. # this holds:
  130. doAssert deb2(-12.wrap2) == """(DotExpr (IntLit -12) (Sym "wrap2"))"""
  131. doAssert deb2(-12'wrap) == """(DotExpr (RStrLit "-12") (Sym "\'wrap"))"""
  132. # but instead this should hold:
  133. doAssert deb2(-12.wrap2) == """(DotExpr (IntLit -12) (Ident "wrap2"))"""
  134. doAssert deb2(-12'wrap) == """(DotExpr (RStrLit "-12") (Ident "\'wrap"))"""
  135. block: # bug 2 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947
  136. template toSuf(`'suf`): untyped =
  137. let x = -12'suf
  138. x
  139. doAssert toSuf(`'wrap`) == "[[-12]]"
  140. block: # bug 10 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947
  141. proc `myecho`(a: auto): auto = a
  142. template fn1(): untyped =
  143. let a = "abc"
  144. -12'wrap
  145. template fn2(): untyped =
  146. `myecho` -12'wrap
  147. template fn3(): untyped =
  148. -12'wrap
  149. doAssert fn1() == "[[-12]]"
  150. doAssert fn2() == "[[-12]]"
  151. doAssert fn3() == "[[-12]]"
  152. when false: # xxx this fails; bug 9 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947
  153. #[
  154. possible workaround: use `genAst` (https://github.com/nim-lang/Nim/pull/17426) and this:
  155. let a3 = `'wrap3`("-128")
  156. ]#
  157. block:
  158. macro metawrap(): untyped =
  159. func wrap1(a: string): string = "{" & a & "}"
  160. func `'wrap3`(a: string): string = "{" & a & "}"
  161. result = quote do:
  162. let a1 = wrap1"-128"
  163. let a2 = -128'wrap3
  164. metawrap()
  165. doAssert a1 == "{-128}"
  166. doAssert a2 == "{-128}"
  167. static: main()
  168. main()