summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2021-03-29 16:23:19 +0200
committerGitHub <noreply@github.com>2021-03-29 16:23:19 +0200
commitcfff27529e4ec129daad602d945a2b222145e922 (patch)
treebfbdcd036d07c282865531e1ede7864263e9ba12
parent1a407402a4614fc9100617f71c2d3c9b8a8367a5 (diff)
downloadNim-cfff27529e4ec129daad602d945a2b222145e922.tar.gz
added nkError to the AST (#17567)
* added nkError to the AST

* Update lib/core/macros.nim

Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com>

* Update compiler/ast.nim

Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com>

Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com>
-rw-r--r--compiler/ast.nim1
-rw-r--r--compiler/errorhandling.nim79
-rw-r--r--compiler/renderer.nim4
-rw-r--r--compiler/sempass2.nim4
-rw-r--r--lib/core/macros.nim3
-rw-r--r--tests/misc/tinvalidnewseq.nim2
6 files changed, 90 insertions, 3 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 1f3d5f129..7d13956e9 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -221,6 +221,7 @@ type
     nkBreakState,         # special break statement for easier code generation
     nkFuncDef,            # a func
     nkTupleConstr         # a tuple constructor
+    nkError               # erroneous AST node
     nkModuleRef           # for .rod file support: A (moduleId, itemId) pair
     nkReplayAction        # for .rod file support: A replay action
     nkNilRodNode          # for .rod file support: a 'nil' PNode
diff --git a/compiler/errorhandling.nim b/compiler/errorhandling.nim
new file mode 100644
index 000000000..d7092d477
--- /dev/null
+++ b/compiler/errorhandling.nim
@@ -0,0 +1,79 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2021 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains support code for new-styled error
+## handling via an `nkError` node kind.
+
+import ast, renderer, options, lineinfos, strutils, types
+
+type
+  ErrorKind* = enum ## expand as you need.
+    RawTypeMismatchError
+    ExpressionCannotBeCalled
+    CustomError
+    WrongNumberOfArguments
+    AmbiguousCall
+
+proc errorSubNode*(n: PNode): PNode =
+  case n.kind
+  of nkEmpty..nkNilLit:
+    result = nil
+  of nkError:
+    result = n
+  else:
+    result = nil
+    for i in 0..<n.len:
+      result = errorSubNode(n[i])
+      if result != nil: break
+
+proc newError*(wrongNode: PNode; k: ErrorKind; args: varargs[PNode]): PNode =
+  assert wrongNode.kind != nkError
+  let innerError = errorSubNode(wrongNode)
+  if innerError != nil:
+    return innerError
+  result = newNodeIT(nkError, wrongNode.info, newType(tyError, ItemId(module: -1, item: -1), nil))
+  result.add wrongNode
+  result.add newIntNode(nkIntLit, ord(k))
+  for a in args: result.add a
+
+proc newError*(wrongNode: PNode; msg: string): PNode =
+  assert wrongNode.kind != nkError
+  let innerError = errorSubNode(wrongNode)
+  if innerError != nil:
+    return innerError
+  result = newNodeIT(nkError, wrongNode.info, newType(tyError, ItemId(module: -1, item: -1), nil))
+  result.add wrongNode
+  result.add newIntNode(nkIntLit, ord(CustomError))
+  result.add newStrNode(msg, wrongNode.info)
+
+proc errorToString*(config: ConfigRef; n: PNode): string =
+  assert n.kind == nkError
+  assert n.len > 1
+  let wrongNode = n[0]
+  case ErrorKind(n[1].intVal)
+  of RawTypeMismatchError:
+    result = "type mismatch"
+  of ExpressionCannotBeCalled:
+    result = "expression '$1' cannot be called" % wrongNode[0].renderTree
+  of CustomError:
+    result = n[2].strVal
+  of WrongNumberOfArguments:
+    result = "wrong number of arguments"
+  of AmbiguousCall:
+    let a = n[2].sym
+    let b = n[3].sym
+    var args = "("
+    for i in 1..<wrongNode.len:
+      if i > 1: args.add(", ")
+      args.add(typeToString(wrongNode[i].typ))
+    args.add(")")
+    result = "ambiguous call; both $1 and $2 match for: $3" % [
+      getProcHeader(config, a),
+      getProcHeader(config, b),
+      args]
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index 9ca485f6e..9a599f6fc 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -1645,6 +1645,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
       gsons(g, n, c, 0)
   of nkTypeClassTy:
     gTypeClassTy(g, n)
+  of nkError:
+    putWithSpace(g, tkSymbol, "error")
+    #gcomma(g, n, c)
+    gsub(g, n[0], c)
   else:
     #nkNone, nkExplicitTypeListCall:
     internalError(g.config, n.info, "rnimsyn.gsub(" & $n.kind & ')')
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index f269afe4c..a1572c85e 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -10,7 +10,7 @@
 import
   intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
   wordrecg, strutils, options, guards, lineinfos, semfold, semdata,
-  modulegraphs, varpartitions, typeallowed, nilcheck
+  modulegraphs, varpartitions, typeallowed, nilcheck, errorhandling
 
 when defined(useDfa):
   import dfa
@@ -1136,6 +1136,8 @@ proc track(tracked: PEffects, n: PNode) =
     dec tracked.leftPartOfAsgn
     for i in 1 ..< n.len: track(tracked, n[i])
     inc tracked.leftPartOfAsgn
+  of nkError:
+    localError(tracked.config, n.info, errorToString(tracked.config, n))
   else:
     for i in 0..<n.safeLen: track(tracked, n[i])
 
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 8d6258e80..795909c6b 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -85,7 +85,8 @@ type
     nnkState,
     nnkBreakState,
     nnkFuncDef,
-    nnkTupleConstr
+    nnkTupleConstr,
+    nnkError,  ## erroneous AST node
 
   NimNodeKinds* = set[NimNodeKind]
   NimTypeKind* = enum  # some types are no longer used, see ast.nim
diff --git a/tests/misc/tinvalidnewseq.nim b/tests/misc/tinvalidnewseq.nim
index dec00fd4a..7a95db020 100644
--- a/tests/misc/tinvalidnewseq.nim
+++ b/tests/misc/tinvalidnewseq.nim
@@ -13,7 +13,7 @@ proc parseURL(url: string): TURL =
   var pattern: string = r"([a-zA-Z]+://)?(\w+?\.)?(\w+)(\.\w+)(:[0-9]+)?(/.+)?"
   var m: array[0..6, string] #Array with the matches
   newSeq(m, 7) #ERROR
-  discard regexprs.match(url, re(pattern), m)
+  discard re.match(url, re(pattern), m)
 
   result = (protocol: m[1], subdomain: m[2], domain: m[3] & m[4],
             port: m[5], path: m[6].split('/'))