summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/condsyms.nim1
-rw-r--r--compiler/ic/packed_ast.nim1
-rw-r--r--compiler/lexer.nim25
-rw-r--r--doc/manual.rst2
-rw-r--r--tests/lexer/tcustom_numeric_literals.nim69
-rw-r--r--tests/lexer/tstrlits.nim19
-rw-r--r--tests/lexer/tunary_minus.nim10
7 files changed, 94 insertions, 33 deletions
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index aa955e763..8d11dae7c 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -130,3 +130,4 @@ proc initDefines*(symbols: StringTableRef) =
   defineSymbol("nimHasWarningAsError")
   defineSymbol("nimHasHintAsError")
   defineSymbol("nimHasSpellSuggest")
+  defineSymbol("nimHasCustomLiterals")
diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim
index 353cc3a42..1075664cb 100644
--- a/compiler/ic/packed_ast.nim
+++ b/compiler/ic/packed_ast.nim
@@ -333,6 +333,7 @@ template symId*(n: NodePos): SymId = SymId tree.nodes[n.int].operand
 proc firstSon*(n: NodePos): NodePos {.inline.} = NodePos(n.int+1)
 
 when false:
+  # xxx `nkStrLit` or `nkStrLit..nkTripleStrLit:` below?
   proc strLit*(tree: PackedTree; n: NodePos): lent string =
     assert n.kind == nkStrLit
     result = tree.sh.strings[LitId tree.nodes[n.int].operand]
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index ecf6cb0d9..cca7765e5 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -412,14 +412,12 @@ proc getNumber(L: var Lexer, result: var Token) =
       customLitPossible = true
 
     if L.buf[postPos] in SymChars:
-      var suffixAsLower = newStringOfCap(10)
       var suffix = newStringOfCap(10)
       while true:
-        let c = L.buf[postPos]
-        suffix.add c
-        suffixAsLower.add toLowerAscii(c)
+        suffix.add L.buf[postPos]
         inc postPos
         if L.buf[postPos] notin SymChars+{'_'}: break
+      let suffixAsLower = suffix.toLowerAscii
       case suffixAsLower
       of "f", "f32": result.tokType = tkFloat32Lit
       of "d", "f64": result.tokType = tkFloat64Lit
@@ -433,16 +431,15 @@ proc getNumber(L: var Lexer, result: var Token) =
       of "u16": result.tokType = tkUInt16Lit
       of "u32": result.tokType = tkUInt32Lit
       of "u64": result.tokType = tkUInt64Lit
+      elif customLitPossible:
+        # remember the position of the `'` so that the parser doesn't
+        # have to reparse the custom literal:
+        result.iNumber = len(result.literal)
+        result.literal.add '\''
+        result.literal.add suffix
+        result.tokType = tkCustomLit
       else:
-        if customLitPossible:
-          # remember the position of the ``'`` so that the parser doesn't
-          # have to reparse the custom literal:
-          result.iNumber = len(result.literal)
-          result.literal.add '\''
-          result.literal.add suffix
-          result.tokType = tkCustomLit
-        else:
-          lexMessageLitNum(L, "invalid number suffix: '$1'", errPos)
+        lexMessageLitNum(L, "invalid number suffix: '$1'", errPos)
     else:
       lexMessageLitNum(L, "invalid number suffix: '$1'", errPos)
 
@@ -467,7 +464,7 @@ proc getNumber(L: var Lexer, result: var Token) =
             if L.buf[pos] != '_':
               xi = `shl`(xi, 1) or (ord(L.buf[pos]) - ord('0'))
             inc(pos)
-        # 'c', 'C' is deprecated
+        # 'c', 'C' is deprecated (a warning is issued elsewhere)
         of 'o', 'c', 'C':
           result.base = base8
           while pos < endpos:
diff --git a/doc/manual.rst b/doc/manual.rst
index 51c434c7b..fdc744bc7 100644
--- a/doc/manual.rst
+++ b/doc/manual.rst
@@ -536,7 +536,7 @@ Numeric literals have the form::
   FLOAT64_LIT = HEX_LIT '\'' FLOAT64_SUFFIX
               | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] FLOAT64_SUFFIX
 
-  CUSTOM_NUMERIC_LIT = (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) '\'' CUSTOM_NUMERIC_SUFFIX
+  CUSTOM_NUMERIC_LIT = (FLOAT_LIT | INT_LIT) '\'' CUSTOM_NUMERIC_SUFFIX
 
   # CUSTOM_NUMERIC_SUFFIX is any Nim identifier that is not
   # a pre-defined type suffix.
diff --git a/tests/lexer/tcustom_numeric_literals.nim b/tests/lexer/tcustom_numeric_literals.nim
index a2f355b4d..17933950a 100644
--- a/tests/lexer/tcustom_numeric_literals.nim
+++ b/tests/lexer/tcustom_numeric_literals.nim
@@ -46,6 +46,7 @@ assertAST dedent """
   -38383839292839283928392839283928392839283.928493849385935898243e-50000'wrap
 
 proc `'wrap`(number: string): string = "[[" & number & "]]"
+proc wrap2(number: string): string = "[[" & number & "]]"
 doAssert lispReprStr(-1'wrap) == """(DotExpr (RStrLit "-1") (Ident "\'wrap"))"""
 
 template main =
@@ -126,25 +127,59 @@ template main =
     doAssert -12'fooplusopt(2) == ("-12", 2)
     doAssert -12'fooplusopt() == ("-12", 99)
     doAssert -12'fooplusopt == ("-12", 99)
-    macro `'bar`(a: static string): untyped =
-      var infix = newNimNode(nnkInfix)
-      infix.add newIdentNode("&")
-      infix.add newLit("got ")
-      infix.add newLit(a.repr)
-      result = newNimNode(nnkStmtList)
-      result.add infix
-    doAssert -12'bar == "got \"-12\""
+    macro `'bar`(a: static string): untyped = newLit(a.repr)
+    doAssert -12'bar == "\"-12\""
     macro deb(a): untyped = newLit(a.repr)
     doAssert deb(-12'bar) == "-12'bar"
-    # macro metawrap(): untyped =
-    #   func wrap1(a: string): string = "{" & a & "}"
-    #   func `'wrap2`(a: string): string = "{" & a & "}"
-    #   result = quote do:
-    #     let a1 = wrap1"-128"
-    #     let a2 = -128'wrap2
-    # metawrap()
-    # doAssert a1 == "{-128}"
-    # doAssert a2 == "{-128}"
+
+  block: # bug 1 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947
+    macro deb1(a): untyped = newLit a.repr
+    macro deb2(a): untyped = newLit a.lispRepr
+    doAssert deb1(-12'wrap) == "-12'wrap"
+    doAssert deb1(-12'nonexistant) == "-12'nonexistant"
+    doAssert deb2(-12'nonexistant) == """(DotExpr (RStrLit "-12") (Ident "\'nonexistant"))"""
+    when false: # xxx bug:
+      # this holds:
+      doAssert deb2(-12.wrap2) == """(DotExpr (IntLit -12) (Sym "wrap2"))"""
+      doAssert deb2(-12'wrap) == """(DotExpr (RStrLit "-12") (Sym "\'wrap"))"""
+      # but instead this should hold:
+      doAssert deb2(-12.wrap2) == """(DotExpr (IntLit -12) (Ident "wrap2"))"""
+      doAssert deb2(-12'wrap) == """(DotExpr (RStrLit "-12") (Ident "\'wrap"))"""
+
+  block: # bug 2 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947
+    template toSuf(`'suf`): untyped =
+      let x = -12'suf
+      x
+    doAssert toSuf(`'wrap`) == "[[-12]]"
+
+  block: # bug 10 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947
+    proc `myecho`(a: auto): auto = a
+    template fn1(): untyped =
+      let a = "abc"
+      -12'wrap
+    template fn2(): untyped =
+      `myecho` -12'wrap
+    template fn3(): untyped =
+      -12'wrap
+    doAssert fn1() == "[[-12]]"
+    doAssert fn2() == "[[-12]]"
+    doAssert fn3() == "[[-12]]"
+
+    when false: # xxx this fails; bug 9 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947
+      #[
+      possible workaround: use `genAst` (https://github.com/nim-lang/Nim/pull/17426) and this:
+      let a3 = `'wrap3`("-128")
+      ]#
+      block:
+        macro metawrap(): untyped =
+          func wrap1(a: string): string = "{" & a & "}"
+          func `'wrap3`(a: string): string = "{" & a & "}"
+          result = quote do:
+            let a1 = wrap1"-128"
+            let a2 = -128'wrap3
+        metawrap()
+        doAssert a1 == "{-128}"
+        doAssert a2 == "{-128}"
 
 static: main()
 main()
diff --git a/tests/lexer/tstrlits.nim b/tests/lexer/tstrlits.nim
new file mode 100644
index 000000000..8e8250a5b
--- /dev/null
+++ b/tests/lexer/tstrlits.nim
@@ -0,0 +1,19 @@
+discard """
+  output: "a\"\"long string\"\"\"\"\"abc\"def_'2'●𝌆𝌆A"
+"""
+# Test the new different string literals
+
+const
+  tripleEmpty = """"long string"""""""" # "long string """""
+
+  rawQuote = r"a"""
+
+  raw = r"abc""def"
+
+  escaped = "\x5f'\50'\u25cf\u{1D306}\u{1d306}\u{41}"
+
+
+stdout.write(rawQuote)
+stdout.write(tripleEmpty)
+stdout.write(raw)
+stdout.writeLine(escaped)
diff --git a/tests/lexer/tunary_minus.nim b/tests/lexer/tunary_minus.nim
index 639911fcd..87b3cb52d 100644
--- a/tests/lexer/tunary_minus.nim
+++ b/tests/lexer/tunary_minus.nim
@@ -51,8 +51,17 @@ template main =
     doAssert x() == minusOne:
       "unable to handle negatives after semi-colon"
 
+  block:
     doAssert -0b111 == -7
     doAssert -0xff == -255
+    doAssert -128'i8 == (-128).int8
+    doAssert $(-128'i8) == "-128"
+    doAssert -32768'i16 == int16.low
+    doAssert -2147483648'i32 == int32.low
+    when int.sizeof > 4:
+      doAssert -9223372036854775808 == int.low
+    when not defined(js):
+      doAssert -9223372036854775808 == int64.low
 
   block: # check when a minus (-) is an unary op
     doAssert -one == minusOne:
@@ -68,6 +77,5 @@ template main =
     doAssert 4 - one == 3:
       "unable to handle subtraction with surrounding spaces with an identifier"
 
-
 static: main()
 main()