diff --git a/distr/app/UpdateLog.txt b/distr/app/UpdateLog.txt index 2cdfaf2..5a88209 100644 --- a/distr/app/UpdateLog.txt +++ b/distr/app/UpdateLog.txt @@ -1,3 +1,5 @@ +22.09.2024 Экстеор 4.9.5 +• сообщения об ошибках при несоответствии выражения конституенте 30.08.2024 Экстеор 4.9.4 • исправлена загрузка файлов версий 2017-2020 годов 14.06.2024 Экстеор 4.9.3 diff --git a/include/Exteor.RC b/include/Exteor.RC index 5714b63..7045519 100644 --- a/include/Exteor.RC +++ b/include/Exteor.RC @@ -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 diff --git a/include/resource.h b/include/resource.h index 308e2c8..9816560 100644 --- a/include/resource.h +++ b/include/resource.h @@ -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 diff --git a/include/xtr/cclDescriptor.h b/include/xtr/cclDescriptor.h index 1cb3d4f..c83f004 100644 --- a/include/xtr/cclDescriptor.h +++ b/include/xtr/cclDescriptor.h @@ -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& result, BOOL showAST); diff --git a/include/xtr/dialog/CstDataPage.h b/include/xtr/dialog/CstDataPage.h index 9e09219..cf5aed4 100644 --- a/include/xtr/dialog/CstDataPage.h +++ b/include/xtr/dialog/CstDataPage.h @@ -75,8 +75,6 @@ DECLARE_MESSAGE_MAP() afx_msg void OnSimpleSyntax(); private: - std::tuple 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 \ No newline at end of file diff --git a/include/xtr/ui/RSEdit.h b/include/xtr/ui/RSEdit.h index 34dbf3d..8df3983 100644 --- a/include/xtr/ui/RSEdit.h +++ b/include/xtr/ui/RSEdit.h @@ -11,7 +11,7 @@ class RSEdit : public BuffRichEdit { EntityUID activeUID{}; ccl::rslang::Parser parser{}; - std::unique_ptr checker{ nullptr }; + std::unique_ptr checker{ nullptr }; CString astText{}; StrPos prefixLen{ 0 }; diff --git a/src/cclDescriptor.cpp b/src/cclDescriptor.cpp index 047ec9b..bcba0d0 100644 --- a/src/cclDescriptor.cpp +++ b/src/cclDescriptor.cpp @@ -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(eid)) { + case LexerEID::unknownSymbol: return IXTRS_LEX_UNKNOWN_SYM; + } + + switch (static_cast(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(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(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(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& 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(errorCode)); - case ErrorType::PARSER: return MsgIDFor(static_cast(errorCode)); - case ErrorType::SEMANTIC: return MsgIDFor(static_cast(errorCode)); - case ErrorType::VALUE: return MsgIDFor(static_cast(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; diff --git a/src/dialog/CstDataPage.cpp b/src/dialog/CstDataPage.cpp index e98431e..2dcdb84 100644 --- a/src/dialog/CstDataPage.cpp +++ b/src/dialog/CstDataPage.cpp @@ -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(analyser->Errors().FirstErrorPos() - analyser->prefixLen), 0L); auto* re = reinterpret_cast(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(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(calculator.Errors().FirstErrorPos() - basePos), 0L); auto* re = reinterpret_cast(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 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(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); diff --git a/src/ui/RSEdit.cpp b/src/ui/RSEdit.cpp index b50c502..e05a4b8 100644 --- a/src/ui/RSEdit.cpp +++ b/src/ui/RSEdit.cpp @@ -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; } }