# Copyright 2022 Mattia Giambirtone & All Contributors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ## Utilities to print formatted error messages to stderr import ../frontend/compiler import ../frontend/parser import ../frontend/lexer import ../util/serializer import std/os import std/terminal import std/strutils import std/strformat proc printError(file, line: string, lineNo: int, pos: tuple[start, stop: int], fn: Declaration, msg: string) = ## Internal helper to print a formatted error message ## to stderr stderr.styledWrite(fgRed, styleBright, "Error in ", fgYellow, &"{file}:{lineNo}:{pos.start}") if not fn.isNil() and fn.kind == funDecl: stderr.styledWrite(fgRed, styleBright, " in function ", fgYellow, FunDecl(fn).name.token.lexeme) stderr.styledWriteLine(styleBright, fgDefault, ": ", msg) if line.len() > 0: stderr.styledWrite(fgRed, styleBright, "Source line: ", resetStyle, fgDefault, line[0..", ""]: file = relativePath(exc.file, getCurrentDir()) printError(file, exc.compiler.getSource().splitLines()[exc.line - 1].strip(chars={'\n'}), exc.line, exc.node.getRelativeBoundaries(), exc.compiler.getCurrentFunction(), exc.msg) proc print*(exc: ParseError) = ## Prints a formatted error message ## for parsing errors to stderr var file = exc.file if file notin ["", ""]: file = relativePath(exc.file, getCurrentDir()) printError(file, exc.parser.getSource().splitLines()[exc.line - 1].strip(chars={'\n'}), exc.line, exc.token.relPos, exc.parser.getCurrentFunction(), exc.msg) proc print*(exc: LexingError) = ## Prints a formatted error message ## for lexing errors to stderr var file = exc.file if file notin ["", ""]: file = relativePath(exc.file, getCurrentDir()) printError(file, exc.lexer.getSource().splitLines()[exc.line - 1].strip(chars={'\n'}), exc.line, exc.pos, nil, exc.msg) proc print*(exc: SerializationError) = ## Prints a formatted error message ## for serialization errors to stderr var file = exc.file if file notin ["", ""]: file = relativePath(exc.file, getCurrentDir()) stderr.styledWriteLine(fgRed, styleBright, "Error while (de-)serializing ", fgYellow, file, fgDefault, &": {exc.msg}") proc print*(exc: IOError, file: string) = ## Prints a formatted error message ## for nim I/O errors to stderr var file = file if file notin ["", ""]: file = relativePath(file, getCurrentDir()) stderr.styledWriteLine(fgRed, styleBright, "Error while trying to read ", fgYellow, file, fgDefault, &": {exc.msg}") proc print*(exc: OSError, file: string, errno: OSErrorCode) = ## Prints a formatted error message ## for nim OS errors to stderr var file = file if file notin ["", ""]: file = relativePath(file, getCurrentDir()) stderr.styledWriteLine(fgRed, styleBright, "Error while trying to read ", fgYellow, file, fgDefault, &": {exc.msg} ({osErrorMsg(errno)})", fgRed, "[errno ", fgYellow, $errno, fgRed, "]")