1#
2#
3#           The Nim Compiler
4#        (c) Copyright 2021 Andreas Rumpf
5#
6#    See the file "copying.txt", included in this
7#    distribution, for details about the copyright.
8#
9
10## This module contains support code for new-styled error
11## handling via an `nkError` node kind.
12
13import ast, renderer, options, strutils, types
14
15type
16  ErrorKind* = enum ## expand as you need.
17    RawTypeMismatchError
18    ExpressionCannotBeCalled
19    CustomError
20    WrongNumberOfArguments
21    AmbiguousCall
22
23proc errorSubNode*(n: PNode): PNode =
24  case n.kind
25  of nkEmpty..nkNilLit:
26    result = nil
27  of nkError:
28    result = n
29  else:
30    result = nil
31    for i in 0..<n.len:
32      result = errorSubNode(n[i])
33      if result != nil: break
34
35proc newError*(wrongNode: PNode; k: ErrorKind; args: varargs[PNode]): PNode =
36  assert wrongNode.kind != nkError
37  let innerError = errorSubNode(wrongNode)
38  if innerError != nil:
39    return innerError
40  result = newNodeIT(nkError, wrongNode.info, newType(tyError, ItemId(module: -1, item: -1), nil))
41  result.add wrongNode
42  result.add newIntNode(nkIntLit, ord(k))
43  for a in args: result.add a
44
45proc newError*(wrongNode: PNode; msg: string): PNode =
46  assert wrongNode.kind != nkError
47  let innerError = errorSubNode(wrongNode)
48  if innerError != nil:
49    return innerError
50  result = newNodeIT(nkError, wrongNode.info, newType(tyError, ItemId(module: -1, item: -1), nil))
51  result.add wrongNode
52  result.add newIntNode(nkIntLit, ord(CustomError))
53  result.add newStrNode(msg, wrongNode.info)
54
55proc errorToString*(config: ConfigRef; n: PNode): string =
56  assert n.kind == nkError
57  assert n.len > 1
58  let wrongNode = n[0]
59  case ErrorKind(n[1].intVal)
60  of RawTypeMismatchError:
61    result = "type mismatch"
62  of ExpressionCannotBeCalled:
63    result = "expression '$1' cannot be called" % wrongNode[0].renderTree
64  of CustomError:
65    result = n[2].strVal
66  of WrongNumberOfArguments:
67    result = "wrong number of arguments"
68  of AmbiguousCall:
69    let a = n[2].sym
70    let b = n[3].sym
71    var args = "("
72    for i in 1..<wrongNode.len:
73      if i > 1: args.add(", ")
74      args.add(typeToString(wrongNode[i].typ))
75    args.add(")")
76    result = "ambiguous call; both $1 and $2 match for: $3" % [
77      getProcHeader(config, a),
78      getProcHeader(config, b),
79      args]
80