mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
138 lines
4.4 KiB
Python
138 lines
4.4 KiB
Python
#
|
|
# This file is distributed under the MIT License. See LICENSE.md for details.
|
|
#
|
|
|
|
from collections.abc import Sequence
|
|
from typing import Any, Generic, Optional, TypeVar, cast, overload
|
|
|
|
from ._capi import _api, ffi
|
|
from .exceptions import RevngDocumentException, RevngSimpleException
|
|
from .utils import make_python_string
|
|
|
|
|
|
class DocumentError:
|
|
def __init__(self, error: "Error"):
|
|
assert _api.rp_error_is_document_error(error._error), "Error is not a DocumentError"
|
|
|
|
# We must keep the original error to avoid destruction
|
|
self.base_error = error
|
|
self._document_error = _api.rp_error_get_document_error(error._error)
|
|
self.reasons = DocumentErrorReasonList(self)
|
|
|
|
@property
|
|
def error_type(self) -> str:
|
|
result = _api.rp_document_error_get_error_type(self._document_error)
|
|
return make_python_string(result)
|
|
|
|
@property
|
|
def location_type(self) -> str:
|
|
result = _api.rp_document_error_get_location_type(self._document_error)
|
|
return make_python_string(result)
|
|
|
|
|
|
class DocumentErrorReason:
|
|
def __init__(self, document_error: DocumentError, index: int):
|
|
self.document_error = document_error
|
|
self.index = index
|
|
|
|
@property
|
|
def message(self):
|
|
result = _api.rp_document_error_get_error_message(
|
|
self.document_error._document_error, self.index
|
|
)
|
|
return make_python_string(result)
|
|
|
|
@property
|
|
def location(self):
|
|
result = _api.rp_document_error_get_error_location(
|
|
self.document_error._document_error, self.index
|
|
)
|
|
return make_python_string(result)
|
|
|
|
|
|
class DocumentErrorReasonList(Sequence[DocumentErrorReason]):
|
|
def __init__(self, document_error: "DocumentError"):
|
|
self.document_error = document_error
|
|
|
|
def __len__(self) -> int:
|
|
return _api.rp_document_error_reasons_count(self.document_error._document_error)
|
|
|
|
@overload
|
|
def __getitem__(self, idx: int) -> DocumentErrorReason: ...
|
|
|
|
@overload
|
|
def __getitem__(self, idx: slice) -> Sequence[DocumentErrorReason]: ...
|
|
|
|
def __getitem__(self, idx: int | slice):
|
|
if isinstance(idx, int):
|
|
if idx < len(self):
|
|
return DocumentErrorReason(self.document_error, idx)
|
|
else:
|
|
raise IndexError("list index out of range")
|
|
elif isinstance(idx, slice):
|
|
return [self[i] for i in range(*idx.indices(len(self)))]
|
|
else:
|
|
raise TypeError("Invalid index type")
|
|
|
|
|
|
class SimpleError:
|
|
def __init__(self, error: "Error"):
|
|
assert not _api.rp_error_is_document_error(error._error), "Error is not a SimpleError"
|
|
|
|
# We must keep the original error to avoid destruction
|
|
self.base_error = error
|
|
self._simple_error = _api.rp_error_get_simple_error(error._error)
|
|
|
|
@property
|
|
def error_type(self) -> str:
|
|
result = _api.rp_simple_error_get_error_type(self._simple_error)
|
|
return make_python_string(result)
|
|
|
|
@property
|
|
def message(self) -> str:
|
|
result = _api.rp_simple_error_get_message(self._simple_error)
|
|
return make_python_string(result)
|
|
|
|
|
|
class Error:
|
|
def __init__(self, _error: Optional[Any] = None):
|
|
if _error is not None:
|
|
self._error = _error
|
|
else:
|
|
self._error = _api.rp_error_create()
|
|
|
|
def is_success(self) -> bool:
|
|
return _api.rp_error_is_success(self._error)
|
|
|
|
def unwrap(self) -> DocumentError | SimpleError:
|
|
if _api.rp_error_is_document_error(self._error):
|
|
return DocumentError(self)
|
|
else:
|
|
return SimpleError(self)
|
|
|
|
def to_exception(self) -> RevngDocumentException | RevngSimpleException:
|
|
unwrapped = self.unwrap()
|
|
if isinstance(unwrapped, DocumentError):
|
|
return RevngDocumentException(unwrapped)
|
|
else:
|
|
return RevngSimpleException(unwrapped)
|
|
|
|
|
|
T = TypeVar("T")
|
|
|
|
|
|
class Expected(Generic[T]):
|
|
def __init__(self, result: Any, error: Error):
|
|
self.result: Optional[T] = result if result != ffi.NULL else None
|
|
self.error = error
|
|
|
|
def __bool__(self):
|
|
return self.error.is_success() and self.result is not None
|
|
|
|
def unwrap(self) -> T:
|
|
"""Returns the wrapped object, unless there's an error, in that case
|
|
an exception is raised"""
|
|
if not bool(self):
|
|
raise self.error.to_exception()
|
|
return cast(T, self.result)
|