104 lines
3.4 KiB
Nim
Raw Normal View History

import std/os
import std/osproc
import std/strutils
import std/streams
import std/pegs
type
CompileInfo* = object
templFile*: string
errorFile*: string
errorLine*, errorColumn*: int
templLine*, templColumn*: int
msg*: string
fullMsg*: string
compileTime*: float
exitCode*: int
let
# Error pegs, taken from testament tester
pegLineTemplate =
peg"{[^(]*} '(' {\d+} ', ' {\d+} ') ' 'template/generic instantiation from here'.*"
pegLineError =
peg"{[^(]*} '(' {\d+} ', ' {\d+} ') ' ('Error') ':' \s* {.*}"
pegOtherError = peg"'Error:' \s* {.*}"
pegError = pegLineError / pegOtherError
pegSuccess = peg"'Hint: operation successful' {[^;]*} '; ' {\d+} '.' {\d+} .*"
# Timestamp pegs
# peg for unix timestamp, basically any float with 6 digits after the decimal
# Not ideal - could also improve by checking for the location in the line
pegUnixTimestamp = peg"{\d+} '.' {\d\d\d\d\d\d} \s"
# peg for timestamp with format yyyy-MM-dd HH:mm:sszzz
pegRfcTimestamp = peg"{\d\d\d\d} '-' {\d\d} '-' {\d\d} ' ' {\d\d} ':' {\d\d} ':' {\d\d} {'+' / '-'} {\d\d} ':' {\d\d} \s"
# Thread/process id is unpredictable..
pegXid* = peg"""'tid' (('=') / ('":') / (': ') / (': ') / ('=') / ('>')) \d+"""
proc cmpIgnorePegs*(a, b: string, pegs: varargs[Peg]): bool =
## true when input strings are equal without regard to supplied pegs
var
aa = a
bb = b
for peg in pegs:
aa = aa.replace(peg, "dummy")
bb = bb.replace(peg, "dummy")
result = aa == bb
proc cmpIgnoreTimestamp*(a, b: string, timestamp = ""): bool =
## true when input strings are equal without regard to supplied timestamp form
if timestamp.len == 0:
result = cmpIgnorePegs(a, b, pegXid)
elif timestamp == "RfcTime":
result = cmpIgnorePegs(a, b, pegRfcTimestamp, pegXid)
elif timestamp == "UnixTime":
result = cmpIgnorePegs(a, b, pegUnixTimestamp, pegXid)
proc cmpIgnoreDefaultTimestamps*(a, b: string): bool =
## true when input strings are equal without regard to timestamp
if cmpIgnorePegs(a, b, pegRfcTimestamp, pegXid):
result = true
elif cmpIgnorePegs(a, b, pegUnixTimestamp, pegXid):
result = true
proc parseCompileStream*(p: Process, output: Stream): CompileInfo =
## parsing compiler output (based on testament tester)
result.exitCode = -1
var
line = newStringOfCap(120).TaintedString
suc, err, tmpl = ""
while true:
if output.readLine(line):
if line =~ pegError:
# `err` should contain the last error/warning message
err = line
elif line =~ pegLineTemplate and err == "":
# `tmpl` contains the last template expansion before the error
tmpl = line
elif line =~ pegSuccess:
suc = line
if err != "":
result.fullMsg.add(line.string & "\p")
else:
result.exitCode = peekExitCode(p)
if result.exitCode != -1:
break
if tmpl =~ pegLineTemplate:
result.templFile = extractFilename(matches[0])
result.templLine = parseInt(matches[1])
result.templColumn = parseInt(matches[2])
if err =~ pegLineError:
result.errorFile = extractFilename(matches[0])
result.errorLine = parseInt(matches[1])
result.errorColumn = parseInt(matches[2])
result.msg = matches[3]
elif err =~ pegOtherError:
result.msg = matches[0]
elif suc =~ pegSuccess:
result.msg = suc
result.compileTime = parseFloat(matches[1] & "." & matches[2])
proc parseExecuteOutput*() = discard