diff options
Diffstat (limited to 'testament/specs.nim')
-rw-r--r-- | testament/specs.nim | 95 |
1 files changed, 86 insertions, 9 deletions
diff --git a/testament/specs.nim b/testament/specs.nim index acffbf8be..e0b9cbeec 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -7,8 +7,8 @@ # distribution, for details about the copyright. # -import sequtils, parseutils, strutils, os, streams, parsecfg -from hashes import hash +import sequtils, parseutils, strutils, os, streams, parsecfg, + tables, hashes type TestamentData* = ref object # better to group globals under 1 object; could group the other ones here too @@ -62,6 +62,11 @@ type targetObjC = "ObjC" targetJS = "JS" + InlineError* = object + kind*: string + msg*: string + line*, col*: int + TSpec* = object action*: TTestAction file*, cmd*: string @@ -90,6 +95,7 @@ type useValgrind*: bool timeout*: float # in seconds, fractions possible, # but don't rely on much precision + inlineErrors*: seq[InlineError] # line information to error message proc getCmd*(s: TSpec): string = if s.cmd.len == 0: @@ -116,14 +122,85 @@ when not declared(parseCfgBool): of "n", "no", "false", "0", "off": result = false else: raise newException(ValueError, "cannot interpret as a bool: " & s) -proc extractSpec(filename: string): string = - const tripleQuote = "\"\"\"" - var x = readFile(filename).string - var a = x.find(tripleQuote) - var b = x.find(tripleQuote, a+3) +const + inlineErrorMarker = "#[tt." + +proc extractErrorMsg(s: string; i: int; line: var int; col: var int; spec: var TSpec): int = + result = i + len(inlineErrorMarker) + inc col, len(inlineErrorMarker) + var kind = "" + while result < s.len and s[result] in IdentChars: + kind.add s[result] + inc result + inc col + + var caret = (line, -1) + + template skipWhitespace = + while result < s.len and s[result] in Whitespace: + if s[result] == '\n': + col = 1 + inc line + else: + inc col + inc result + + skipWhitespace() + if result < s.len and s[result] == '^': + caret = (line-1, col) + inc result + inc col + skipWhitespace() + + var msg = "" + while result < s.len-1: + if s[result] == '\n': + inc result + inc line + col = 1 + elif s[result] == ']' and s[result+1] == '#': + while msg.len > 0 and msg[^1] in Whitespace: + setLen msg, msg.len - 1 + + inc result + inc col, 2 + if kind == "Error": spec.action = actionReject + spec.unjoinable = true + spec.inlineErrors.add InlineError(kind: kind, msg: msg, line: caret[0], col: caret[1]) + break + else: + msg.add s[result] + inc result + inc col + +proc extractSpec(filename: string; spec: var TSpec): string = + const + tripleQuote = "\"\"\"" + var s = readFile(filename).string + + var i = 0 + var a = -1 + var b = -1 + var line = 1 + var col = 1 + while i < s.len: + if s.continuesWith(tripleQuote, i): + if a < 0: a = i + elif b < 0: b = i + inc i, 2 + inc col + elif s[i] == '\n': + inc line + col = 1 + elif s.continuesWith(inlineErrorMarker, i): + i = extractErrorMsg(s, i, line, col, spec) + else: + inc col + inc i + # look for """ only in the first section if a >= 0 and b > a and a < 40: - result = x.substr(a+3, b-1).replace("'''", tripleQuote) + result = s.substr(a+3, b-1).replace("'''", tripleQuote) else: #echo "warning: file does not contain spec: " & filename result = "" @@ -160,7 +237,7 @@ proc isCurrentBatch(testamentData: TestamentData, filename: string): bool = proc parseSpec*(filename: string): TSpec = result.file = filename - let specStr = extractSpec(filename) + let specStr = extractSpec(filename, result) var ss = newStringStream(specStr) var p: CfgParser open(p, ss, filename, 1) |