F: Update ConceptCore API for error messages

This commit is contained in:
Ivan 2024-09-22 19:02:17 +03:00
parent a69bedb033
commit 6b86dc3a16
9 changed files with 117 additions and 111 deletions

View File

@ -1,3 +1,5 @@
22.09.2024 Экстеор 4.9.5
• сообщения об ошибках при несоответствии выражения конституенте
30.08.2024 Экстеор 4.9.4
• исправлена загрузка файлов версий 2017-2020 годов
14.06.2024 Экстеор 4.9.3

View File

@ -1182,8 +1182,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,9,4,1000
PRODUCTVERSION 4,9,4,1000
FILEVERSION 4,9,5,1000
PRODUCTVERSION 4,9,5,1000
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -1201,13 +1201,13 @@ BEGIN
VALUE "Comments", "Ýêñïëèêàòîð òåîðèé "
VALUE "CompanyName", "ÍÏ ÖÈÂÒ ÊÎÍÖÅÏÒ"
VALUE "FileDescription", "Ýêñòåîð 4.9"
VALUE "FileVersion", "4.9.4.1000"
VALUE "FileVersion", "4.9.5.1000"
VALUE "InternalName", "Ýêñòåîð 4.9"
VALUE "LegalCopyright", "Copyright © NPMP CIHT CONCEPT 1994-2024"
VALUE "LegalTrademarks", "Ýêñòåîð™"
VALUE "OriginalFilename", "Exteor.exe"
VALUE "ProductName", "Ýêñòåîð 4.9"
VALUE "ProductVersion", "4.9.4.1000"
VALUE "ProductVersion", "4.9.5.1000"
END
END
BLOCK "VarFileInfo"
@ -3517,13 +3517,20 @@ BEGIN
IXTRS_PAR_SYNTHAXERROR "Ñèíòàêñè÷åñêàÿ îøèáêà"
IXTRS_RS_CHECK_SUCCESS "Ïðîâåðêà êîððåêòíîñòè âûðàæåíèÿ: ÎÊ"
IXTRS_PAR_FAILURE "Ñèíòàêñè÷åñêèé àíàëèç âûðàæåíèÿ: ÎØÈÁÊÀ"
IXTRS_TYPE_INCONSISTENT "Òèïèçàöèÿ âûðàæåíèÿ íå ñîîòâåòñòâóåò òèïó êîíñòèòóåíòû\n\n"
END
STRINGTABLE
BEGIN
IXTRS_CST_NONEMPTY_BASE "Непустое выражение базисного/константного множества"
IXTRS_CST_EMPTY_DERIVED "Пустое выражение для сложного понятия или утверждения"
IXTRS_CALLABLE_NO_ARGS "Отсутствуют аргументы для параметризованной конституенты"
IXTRS_CST_NONCALLABLE_ARGS
"Параметризованное выражение не подходит для данного типа конституенты"
IXTRS_CST_EXPECTED_LOGICAL
"Данный тип конституенты требует логического выражения"
IXTRS_CST_EXPECTED_TYPED
"Данный тип конституенты требует теоретико-множественного выражения"
IXTRS_TYPE_STRUCTURE "Âûðàæåíèå ðîäîâîé ñòðóêòóðû äîëæíî áûòü ñòóïåíüþ"
IXTRS_TYPE_FUNCTION "Îæèäàëîñü âûðàæåíèå îáúÿâëåíèÿ ôóíêöèè"
IXTRS_USE_RADICAL "Ðàäèêàëû çàïðåùåíû âíå äåêëàðàöèé òåðì-ôóíêöè: %1"
IXTRS_FILTER_ARGUMENT "Òèïèçàöèÿ àðãóìåíòà ôèëüòðà íå êîððåêòíà: %1(%2)"
IXTRS_FILTER_PARAM_ARITY

View File

@ -478,8 +478,13 @@
#define IXTRS_OSS_RUNALL_PROMPT 3209
#define IXTRS_OSS_RUNALL_SUCCESS 3210
#define IXTRE_CANNOT_SAVE_DATA 3211
#define IXTRS_CST_NONEMPTY_BASE 3470
#define IXTRS_CST_EMPTY_DERIVED 3471
#define IXTRS_CALLABLE_NO_ARGS 3472
#define IXTRS_CST_NONCALLABLE_ARGS 3473
#define IXTRS_CST_EXPECTED_LOGICAL 3474
#define IXTRS_CST_EXPECTED_TYPED 3475
#define IXTRS_TYPE_STRUCTURE 3480
#define IXTRS_TYPE_FUNCTION 3483
#define IXTRS_USE_RADICAL 3485
#define IXTRS_FILTER_ARGUMENT 3486
#define IXTRS_FILTER_PARAM_ARITY 3487
@ -493,7 +498,6 @@
#define IXTRS_PAR_SYNTHAXERROR 3500
#define IXTRS_RS_CHECK_SUCCESS 3501
#define IXTRS_PAR_FAILURE 3502
#define IXTRS_TYPE_INCONSISTENT 3503
#define IXTRS_PAR_EXPECTED_RP 3504
#define IXTRS_PAR_EXPECTED_RC 3505
#define IXTRS_PAR_QUANTDECL 3506

View File

@ -54,7 +54,7 @@ enum class ModelStatus : uint8_t {
[[nodiscard]] CString BasicDescriptionOf(ccl::oss::PictID pict, ccl::oss::OSSchema& oss);
[[nodiscard]] CString DescriptionOf(const ccl::rslang::Auditor& analytics, BOOL showAST);
[[nodiscard]] CString DescriptionOf(const ccl::semantic::SchemaAuditor& analytics, BOOL showAST);
[[nodiscard]] CString DescriptionOf(const ccl::rslang::Interpreter& calculator,
const std::optional<ccl::rslang::ExpressionValue>& result,
BOOL showAST);

View File

@ -75,8 +75,6 @@ DECLARE_MESSAGE_MAP()
afx_msg void OnSimpleSyntax();
private:
std::tuple<std::string, long> GetAnalyseExpr() const;
void UpdateStatus(ccl::semantic::ParsingStatus status, ccl::rslang::ValueClass vclass);
void SetModified(BOOL bChanged = TRUE);
BOOL IsModified() const noexcept;
@ -88,7 +86,7 @@ private:
void InitCstNameList();
void UpdateStatusBar();
void Analyse();
void ExpressAnalyse();
};
} // namespace xtr::dialog

View File

@ -11,7 +11,7 @@ class RSEdit : public BuffRichEdit {
EntityUID activeUID{};
ccl::rslang::Parser parser{};
std::unique_ptr<ccl::rslang::Auditor> checker{ nullptr };
std::unique_ptr<ccl::semantic::SchemaAuditor> checker{ nullptr };
CString astText{};
StrPos prefixLen{ 0 };

View File

@ -46,17 +46,17 @@ namespace {
}
}
[[nodiscard]] constexpr uint32_t MsgIDFor(const ccl::rslang::LexerEID error) noexcept {
switch (error) {
default:
case ccl::rslang::LexerEID::unknownSymbol: return IXTRS_LEX_UNKNOWN_SYM;
}
}
[[nodiscard]] constexpr uint32_t MsgIDFor(const ccl::rslang::ParseEID error) noexcept {
[[nodiscard]] constexpr uint32_t MsgIDFor(const uint32_t eid) noexcept {
using ccl::rslang::LexerEID;
using ccl::rslang::ParseEID;
switch (error) {
default:
using ccl::rslang::SemanticEID;
using ccl::rslang::ValueEID;
using ccl::semantic::CstTypeEID;
switch (static_cast<LexerEID>(eid)) {
case LexerEID::unknownSymbol: return IXTRS_LEX_UNKNOWN_SYM;
}
switch (static_cast<ParseEID>(eid)) {
case ParseEID::syntax: return IXTRS_PAR_SYNTHAXERROR;
case ParseEID::missingParenthesis: return IXTRS_PAR_EXPECTED_RP;
case ParseEID::missingCurlyBrace: return IXTRS_PAR_EXPECTED_RC;
@ -65,12 +65,8 @@ namespace {
case ParseEID::expectedDeclaration: return IXTRS_PAR_EXPECTED_ARGDECL;
case ParseEID::expectedLocal: return IXTRS_PAR_EXPECTED_VAR;
}
}
[[nodiscard]] constexpr uint32_t MsgIDFor(const ccl::rslang::SemanticEID error) noexcept {
using ccl::rslang::SemanticEID;
switch (error) {
default:
switch (static_cast<SemanticEID>(eid)) {
case SemanticEID::localUndeclared: return IXTRS_TYPE_NAME_UKNOWN;
case SemanticEID::localShadowing: return IXTRS_TYPE_NAME_DECLARED;
case SemanticEID::globalFuncMissing: return IXTRS_TYPE_UNKNOWN_FUNCTION;
@ -94,7 +90,6 @@ namespace {
case SemanticEID::invalidArgsArity: return IXTRS_TYPE_FUNC_ARGNUM;
case SemanticEID::invalidArgumentType: return IXTRS_TYPE_FUNC_WRONG_ARG;
case SemanticEID::globalStructure: return IXTRS_TYPE_STRUCTURE;
case SemanticEID::globalExpectedFunction: return IXTRS_TYPE_FUNCTION;
case SemanticEID::radicalUsage: return IXTRS_USE_RADICAL;
case SemanticEID::invalidFilterArgumentType: return IXTRS_FILTER_ARGUMENT;
case SemanticEID::invalidFilterArity: return IXTRS_FILTER_PARAM_ARITY;
@ -107,12 +102,17 @@ namespace {
case SemanticEID::globalMissingAST: return IXTRS_GLOBAL_NO_AST;
case SemanticEID::globalFuncNoInterpretation: return IXTRS_FUNCTION_CALL_INVALID;
}
}
[[nodiscard]] constexpr uint32_t MsgIDFor(const ccl::rslang::ValueEID error) noexcept {
using ccl::rslang::ValueEID;
switch (error) {
default:
switch (static_cast<CstTypeEID>(eid)) {
case CstTypeEID::cstNonemptyBase: return IXTRS_CST_NONEMPTY_BASE;
case CstTypeEID::cstEmptyDerived: return IXTRS_CST_EMPTY_DERIVED;
case CstTypeEID::cstCallableNoArgs: return IXTRS_CALLABLE_NO_ARGS;
case CstTypeEID::cstNonCallableHasArgs: return IXTRS_CST_NONCALLABLE_ARGS;
case CstTypeEID::cstExpectedLogical: return IXTRS_CST_EXPECTED_LOGICAL;
case CstTypeEID::cstExpectedTyped: return IXTRS_CST_EXPECTED_TYPED;
}
switch (static_cast<ValueEID>(eid)) {
case ValueEID::unknownError: return IXTRS_VALUE_UNKNOWN_ERROR;
case ValueEID::typedOverflow: return IXTRS_VALUE_SET_LIMIT;
case ValueEID::booleanLimit: return IXTRS_VALUE_BOOL_LIMIT;
@ -121,6 +121,8 @@ namespace {
case ValueEID::invalidDebool: return IXTRS_VALUE_DEBOOL;
case ValueEID::iterateInfinity: return IXTRS_ITERATE_INFINITY;
}
return 0;
}
[[nodiscard]] CString ErrorMessage(const uint32_t errorCode, const std::vector<std::string>& params) {
@ -128,16 +130,7 @@ namespace {
auto prefix = Label(errType);
prefix.AppendFormat(LR"(%04X)", errorCode);
prefix += LR"(: )";
const uint32_t msgID = [&]() noexcept -> uint32_t {
switch (errType) {
default:
case ErrorType::UNKNOWN: return 0;
case ErrorType::LEXER: return MsgIDFor(static_cast<ccl::rslang::LexerEID>(errorCode));
case ErrorType::PARSER: return MsgIDFor(static_cast<ccl::rslang::ParseEID>(errorCode));
case ErrorType::SEMANTIC: return MsgIDFor(static_cast<ccl::rslang::SemanticEID>(errorCode));
case ErrorType::VALUE: return MsgIDFor(static_cast<ccl::rslang::ValueEID>(errorCode));
}
}();
const uint32_t msgID = MsgIDFor(errorCode);
if (msgID == 0) {
return prefix;
} else {
@ -437,15 +430,15 @@ CString BasicDescriptionOf(const ccl::oss::PictID pict, ccl::oss::OSSchema& oss)
return infoStr;
}
CString DescriptionOf(const ccl::rslang::Auditor& analytics, const BOOL showAST) {
CString DescriptionOf(const ccl::semantic::SchemaAuditor& analytics, const BOOL showAST) {
CString msgLog{};
const ccl::rslang::ExpressionType* type = &analytics.GetType();
if (!analytics.isParsed) {
if (!analytics.IsParsed()) {
msgLog += mfc::LoadSID(IXTRS_PAR_FAILURE);
} else if (!analytics.isTypeCorrect) {
} else if (!analytics.IsTypeCorrect()) {
type = nullptr;
msgLog += mfc::LoadSID(IXTRS_TYPECHECK_FAILURE);
} else if (!analytics.isValueCorrect) {
} else if (!analytics.IsValueCorrect()) {
msgLog += mfc::LoadSID(IXTRS_VALUECHECK_FAILURE);
} else {
msgLog += mfc::LoadSID(IXTRS_RS_CHECK_SUCCESS);
@ -459,9 +452,9 @@ CString DescriptionOf(const ccl::rslang::Auditor& analytics, const BOOL showAST)
msgLog += '\n';
msgLog += mfc::FormatSID(IXTRS_REPORT_VALUE_CLASS, Label(analytics.GetValueClass()).GetString());
if (showAST && analytics.isParsed) {
if (showAST && analytics.IsParsed()) {
msgLog += '\n';
msgLog += mfc::FormatSID(IXTRS_REPORT_AST, mfc::ToMFC(AST2String::Apply(analytics.parser.AST())).GetString());
msgLog += mfc::FormatSID(IXTRS_REPORT_AST, mfc::ToMFC(AST2String::Apply(analytics.AST())).GetString());
}
return msgLog;

View File

@ -400,19 +400,18 @@ BOOL CstDataPage::OnInsertBtn(uint32_t command) {
}
void CstDataPage::OnAnalyse() {
auto [str, basePos] = GetAnalyseExpr();
const auto& cst = parent.editor->GetRS(parent.activeUID);
const auto definitionText = mfc::ToSTL(expressionCtrl.Text());
auto analyser = parent.editor->Core().RSLang().MakeAuditor();
const ccl::rslang::ExpressionType* type{ nullptr };
const auto typeOK = analyser->CheckType(str, ccl::rslang::Syntax::MATH);
const auto typeOK = analyser->CheckConstituenta(cst.alias, definitionText, cst.type);
if (typeOK) {
type = &analyser->GetType();
}
const auto rstype = parent.editor->GetRS(parent.activeUID).type;
const auto typeConsistent = typeOK
&& (!ccl::semantic::IsBaseSet(rstype) || expressionCtrl.Text().IsEmpty())
&& ccl::semantic::Schema::CheckTypeConstistency(analyser->GetType(), rstype);
if (!typeConsistent) {
if (!typeOK) {
UpdateStatus(ParsingStatus::INCORRECT, ValueClass::invalid);
} else {
if (!analyser->CheckValue()) {
@ -423,7 +422,7 @@ void CstDataPage::OnAnalyse() {
}
if (!empty(analyser->Errors().All())) {
auto errorPosition = std::max(analyser->Errors().FirstErrorPos() - basePos, 0L);
auto errorPosition = std::max(static_cast<long>(analyser->Errors().FirstErrorPos() - analyser->prefixLen), 0L);
auto* re = reinterpret_cast<ui::TextEdit*>(GetDlgItem(IXTRC_EXPRESSION));
re->SetFocus();
re->SetSel(errorPosition, errorPosition);
@ -431,9 +430,6 @@ void CstDataPage::OnAnalyse() {
typificationCtrl.SetWindowTextW(info::Label(type));
auto log = info::DescriptionOf(*analyser, XTROptions::ParseRSL().showAST);
if (typeOK && !typeConsistent) {
log = mfc::LoadSID(IXTRS_TYPE_INCONSISTENT) + log;
}
logCtrl.SetWindowTextW(log);
}
@ -450,15 +446,23 @@ void CstDataPage::OnCalculate() {
}
BeginWaitCursor();
auto[str, basePos] = GetAnalyseExpr();
const auto& cst = parent.editor->GetRS(parent.activeUID);
const auto expr = mfc::ToSTL(expressionCtrl.Text());
const auto fullExpr = ccl::rslang::Generator::GlobalDefinition(
cst.alias,
expr,
cst.type == CstType::structured
);
const auto basePos = static_cast<StrPos>(ssize(fullExpr) - ssize(expr));
ccl::rslang::Interpreter calculator{
parent.editor->Core().RSLang(),
parent.editor->Core().RSLang().ASTContext(),
parent.editor->Model().Calculations().Context()
};
const auto calcResult = calculator.Evaluate(str, ccl::rslang::Syntax::MATH);
const auto calcResult = calculator.Evaluate(fullExpr, ccl::rslang::Syntax::MATH);
if (!calcResult.has_value()) {
auto errorPosition = std::max(calculator.Errors().FirstErrorPos() - basePos, 0L);
auto errorPosition = std::max(static_cast<long>(calculator.Errors().FirstErrorPos() - basePos), 0L);
auto* re = reinterpret_cast<ui::TextEdit*>(GetDlgItem(IXTRC_EXPRESSION));
re->SetFocus();
re->SetSel(errorPosition, errorPosition);
@ -473,8 +477,8 @@ void CstDataPage::OnCalculate() {
}
void CstDataPage::OnSimpleSyntax() {
auto [expr, basePos] = GetAnalyseExpr();
const auto asciiExpr = ccl::rslang::ConvertTo(expr, ccl::rslang::Syntax::ASCII);
const auto definitionText = mfc::ToSTL(expressionCtrl.Text());
const auto asciiExpr = ccl::rslang::ConvertTo(definitionText, ccl::rslang::Syntax::ASCII);
logCtrl.SetWindowTextW(mfc::ToMFC(asciiExpr));
}
@ -487,14 +491,6 @@ BOOL CstDataPage::IsModified() const noexcept {
return isModified;
}
std::tuple<std::string, long> CstDataPage::GetAnalyseExpr() const {
const auto& cst = parent.editor->GetRS(parent.activeUID);
const auto expr = mfc::ToSTL(expressionCtrl.Text());
const auto fullExpr = ccl::rslang::Generator::GlobalDefinition(cst.alias, expr,
cst.type == CstType::structured);
return { fullExpr, static_cast<long>(ssize(fullExpr) - ssize(expr)) };
}
void CstDataPage::UpdateStatus(const ParsingStatus status, const ValueClass vclass) {
parseStatus = status;
valueStatus = vclass;
@ -525,7 +521,7 @@ void CstDataPage::ClearSyntaxWindow() {
void CstDataPage::RunAutocheck() {
if (parseStatus != ParsingStatus::VERIFIED && XTROptions::ParseRSL().autoCheck) {
Analyse();
ExpressAnalyse();
}
}
@ -558,10 +554,11 @@ void CstDataPage::InitCstNameList() {
namePicker.SetRedraw(TRUE);
}
void CstDataPage::Analyse() {
auto[str, basePos] = GetAnalyseExpr();
void CstDataPage::ExpressAnalyse() {
const auto& cst = parent.editor->GetRS(parent.activeUID);
const auto definitionText = mfc::ToSTL(expressionCtrl.Text());
auto analyser = parent.editor->Core().RSLang().MakeAuditor();
if (!analyser->CheckType(str, ccl::rslang::Syntax::MATH)) {
if (!analyser->CheckConstituenta(cst.alias, definitionText, cst.type)) {
UpdateStatus(ParsingStatus::INCORRECT, ValueClass::invalid);
} else if (!analyser->CheckValue()) {
UpdateStatus(ParsingStatus::VERIFIED, ValueClass::invalid);

View File

@ -425,8 +425,7 @@ BOOL RSEdit::UpdateAST() {
return FALSE;
} else {
const auto& cst = context->GetRS(activeUID);
const auto expression = Generator::GlobalDefinition(cst.alias, mfc::ToSTL(text), cst.type == CstType::structured);
checker->CheckType(expression, ccl::rslang::Syntax::MATH);
checker->CheckConstituenta(cst.alias, mfc::ToSTL(text), cst.type);
astText = text;
navigatorEnabled = FALSE;
activeNode = std::nullopt;
@ -438,25 +437,28 @@ void RSEdit::FormatSelectedBlock(const StrRange selection) {
static constexpr COLORREF clrBg{ RGB(235, 235, 235) };
static constexpr COLORREF clrReadOnlyBg{ RGB(255, 255, 211) };
if (XTROptions::ParseRSL().enableNavigator &&
GetFocus()->GetSafeHwnd() == m_hWnd &&
context != nullptr && UpdateAST() && checker->isParsed) {
auto selectedNode = activeNode;
if (!navigatorEnabled) {
const auto clientRange = StrRange{ selection.start + prefixLen, selection.finish + prefixLen };
selectedNode = ccl::rslang::FindMinimalNode(checker->parser.AST().Root(), clientRange);
}
if (selectedNode.has_value()) {
const auto start = std::max(selectedNode.value()->pos.start - prefixLen, 0);
const auto end = std::min(selectedNode.value()->pos.finish - prefixLen, astText.GetLength());
auto format = design::CharFormatRE();
format.dwMask = CFM_BACKCOLOR;
format.crBackColor = (GetStyle() & ES_READONLY) == 0 ? clrBg : clrReadOnlyBg;
SetSel(start, end);
SetSelectionCharFormat(format);
}
if (!XTROptions::ParseRSL().enableNavigator ||
GetFocus()->GetSafeHwnd() != m_hWnd ||
context == nullptr || !UpdateAST() || !checker->IsParsed()) {
return;
}
auto selectedNode = activeNode;
if (!navigatorEnabled) {
const auto clientRange = StrRange{ selection.start + prefixLen, selection.finish + prefixLen };
selectedNode = ccl::rslang::FindMinimalNode(checker->AST().Root(), clientRange);
}
if (selectedNode.has_value()) {
const auto start = std::max(selectedNode.value()->pos.start - prefixLen, 0);
const auto end = std::min(selectedNode.value()->pos.finish - prefixLen, astText.GetLength());
auto format = design::CharFormatRE();
format.dwMask = CFM_BACKCOLOR;
format.crBackColor = (GetStyle() & ES_READONLY) == 0 ? clrBg : clrReadOnlyBg;
SetSel(start, end);
SetSelectionCharFormat(format);
}
}
void RSEdit::FormatIdentifier(const ccl::rslang::TokenID tid, const StrRange pos) {
@ -506,21 +508,24 @@ void RSEdit::AddReference() {
}
BOOL RSEdit::NavigatorOn() {
using ccl::rslang::FindMinimalNode;
if (navigatorEnabled) {
return TRUE;
} else if (!checker->isParsed) {
}
if (!checker->IsParsed()) {
activeNode = std::nullopt;
MessageBeep(MB_ICONERROR);
return FALSE;
} else {
navigatorEnabled = TRUE;
const auto sel = GetSelectionRange();
activeNode = FindMinimalNode(checker->parser.AST().Root(),
StrRange{ sel.start + prefixLen, sel.finish + prefixLen });
return TRUE;
}
}
navigatorEnabled = TRUE;
const auto sel = GetSelectionRange();
activeNode = ccl::rslang::FindMinimalNode(
checker->AST().Root(),
StrRange{ sel.start + prefixLen, sel.finish + prefixLen }
);
return TRUE;
}
BOOL RSEdit::MoveUp() noexcept {
@ -529,13 +534,13 @@ BOOL RSEdit::MoveUp() noexcept {
BOOL RSEdit::MoveDown() {
if (!activeNode.has_value() || activeNode->ChildrenCount() == 0) {
return false;
return FALSE;
} else if (activeNode->IsRoot()) {
activeNode->MoveToChild(1); // Note: Для корневого узла перывым потомком является сама конституента
return true;
return TRUE;
} else {
activeNode->MoveToChild(0);
return true;
return TRUE;
}
}