diff --git a/Configuration/GlobalAssemblyInfo.cs b/Configuration/GlobalAssemblyInfo.cs index d9ea0f95f..86609996b 100644 --- a/Configuration/GlobalAssemblyInfo.cs +++ b/Configuration/GlobalAssemblyInfo.cs @@ -14,8 +14,8 @@ internal static class RevisionClass { public const string Major = "3"; public const string Minor = "8"; - public const string Build = "0"; - public const string Revision = "2966"; + public const string Build = "1"; + public const string Revision = "2975"; public const string MainVersion = Major + "." + Minor; public const string FullVersion = Major + "." + Minor + "." + Build + "." + Revision; diff --git a/Configuration/Version.defs b/Configuration/Version.defs index 222f97885..8e1c9d231 100644 --- a/Configuration/Version.defs +++ b/Configuration/Version.defs @@ -1,4 +1,4 @@ -%COREVERSION%=0 -%REVISION%=2966 %MINOR%=8 +%REVISION%=2975 +%COREVERSION%=1 %MAJOR%=3 diff --git a/Localization/DefaultLang.resources b/Localization/DefaultLang.resources index 2bdbd6093..00c23fbf5 100644 Binary files a/Localization/DefaultLang.resources and b/Localization/DefaultLang.resources differ diff --git a/PABCNetHelp/LangGuide/CompilerDirectives/index_directives.html b/PABCNetHelp/LangGuide/CompilerDirectives/index_directives.html index d3ef2edba..1b5b1e6b7 100644 --- a/PABCNetHelp/LangGuide/CompilerDirectives/index_directives.html +++ b/PABCNetHelp/LangGuide/CompilerDirectives/index_directives.html @@ -45,6 +45,28 @@

{$apptype < >} - (windows/console).

{$reference < >} - .

+

{$include < >} - + .

+

{$define <>} - , + $ifdef, $ifndef.

+

{$undef <>} - , + $define.

+

{$ifdef <>} - +( : " ").

+

{$ifndef <>} - +( : " ").

+

{$else} - "" .

+

{$endif} - .

+

{$faststrings} - , + .

+

{$zerobasedstrings} - , 0.

+

{$zerobasedstrings on} - , 0.

+

{$zerobasedstrings off} - , 0.

+

{$platformtarget +x86} - 32- ( +32- dll)

+

{$platformtarget +x64} - 64-

{$gendoc <>} - XML . : true, false.

{$mainresource < >} - .res @@ -62,27 +84,6 @@

{$company <>} -

{$copyright <>} -

{$trademark < >} -

-

{$include < >} - - .

-

{$define <>} - , - $ifdef, $ifndef.

-

{$undef <>} - , - $define.

-

{$ifdef <>} - -( : " ").

-

{$ifndef <>} - -( : " ").

-

{$else} - "" .

-

{$endif} - .

-

{$faststrings} - , - .

-

{$string_nullbased+} - , 0.

-

{$string_nullbased-} - , 0.

-

{$platformtarget -x86} - 32- ( -32- dll)

-

{$platformtarget -x64} - 64-

$ifdef, $ifndef $else $endif . $ifdef, $ifndef diff --git a/Release/pabcversion.txt b/Release/pabcversion.txt index 745f9384b..2c9106842 100644 --- a/Release/pabcversion.txt +++ b/Release/pabcversion.txt @@ -1 +1 @@ -3.8.0.2966 +3.8.1.2975 diff --git a/ReleaseGenerators/PascalABCNET_version.nsh b/ReleaseGenerators/PascalABCNET_version.nsh index c96ccae72..2c0e6ef58 100644 --- a/ReleaseGenerators/PascalABCNET_version.nsh +++ b/ReleaseGenerators/PascalABCNET_version.nsh @@ -1 +1 @@ -!define VERSION '3.8.0.2966' +!define VERSION '3.8.1.2975' diff --git a/SyntaxVisitors/SugarVisitors/CacheFunctionVisitor.cs b/SyntaxVisitors/SugarVisitors/CacheFunctionVisitor.cs index 650b02e56..d9b75340a 100644 --- a/SyntaxVisitors/SugarVisitors/CacheFunctionVisitor.cs +++ b/SyntaxVisitors/SugarVisitors/CacheFunctionVisitor.cs @@ -19,6 +19,11 @@ namespace SyntaxVisitors.SugarVisitors { get { return new CacheFunctionVisitor(); } } + + public override void visit(simple_attribute_list al) + { + base.visit(al); + } public override void visit(procedure_definition pd) { var attrs = pd.proc_header.attributes; @@ -36,7 +41,7 @@ namespace SyntaxVisitors.SugarVisitors //if (attrs?.attributes?[0].attributes?[0]?.type?.names?[0]?.name?.ToLower()=="cache") // слишком быстро if (qq != null && qq.Any(nm=>nm.name.ToLower()=="cache")) { - // проверить, что + // проверить, что // это функция + // это не метод расширения + // параметры есть (хоть один) + @@ -46,15 +51,17 @@ namespace SyntaxVisitors.SugarVisitors // отсутствие var и const в параметрах + // функция определена глобально + if (pd.DescendantNodes().OfType().Count() > 0) + throw new SyntaxVisitorError("FUNCTIONS_WITH_CACHE_ATTRIBUTE_CANNOT_HAVE_YIELD", pd.proc_header); var fh = pd.proc_header as function_header; if (fh == null) throw new SyntaxVisitorError("ONLY_FUNCTION_SHOULD_HAVE_CACHE_ATTRIBUTE",pd.proc_header); var isExtension = fh.proc_attributes.proc_attributes.Any(attr => attr.name == "extensionmethod"); if (isExtension) throw new SyntaxVisitorError("EXTENSION_FUNCTIONS_SHOULD_NOT_HAVE_CACHE_ATTRIBUTE", fh); - if (fh.parameters != null && fh.parameters.Count == 0) + if (fh.parameters == null || fh.parameters != null && fh.parameters.Count == 0) throw new SyntaxVisitorError("FUNCTIONS_WITH_CACHE_ATTRIBUTE_SHOULD_HAVE_PARAMETERS", fh); - if (fh.parameters != null && fh.parameters.Count > 7) + if (fh.parameters != null && fh.parameters.params_list.Sum(tp => tp.idents.idents.Count) > 7) throw new SyntaxVisitorError("FUNCTIONS_WITH_CACHE_ATTRIBUTE_SHOULD_HAVE_LESSTHEN8_PARAMETERS", fh); if (fh.return_type == null) throw new SyntaxVisitorError("FUNCTIONS_WITH_CACHE_ATTRIBUTE_SHOULD_HAVE_EXPLICIT_RETURN_TYPE", fh); @@ -74,7 +81,10 @@ namespace SyntaxVisitors.SugarVisitors new expression_list(pp.Select(pair => pair.Item1 as expression).ToList()) ) ); - (pd.proc_body as block).program_code.list.Insert(0, vs); + var proc_code = (pd.proc_body as block).program_code; + proc_code.list.Insert(0, vs); + if (proc_code.list[proc_code.list.Count - 1] is empty_statement) + proc_code.list.RemoveAt(proc_code.list.Count - 1); // var @ИмяФункцииDict := new Dictionary<типTuple, тип возвр значения функции> // var d := new PABCSystem.Dictionary,integer>; @@ -103,17 +113,39 @@ namespace SyntaxVisitors.SugarVisitors // Result := d[tup]; // exit; // end; - var indr = new indexer(dictIdent, new expression_list(tupleIdent)); + // а надо другой код + + /*var indr = new indexer(dictIdent, new expression_list(tupleIdent)); var assRes = new assign("Result", indr); var exitst = new procedure_call(new ident("exit")); var stlst = new statement_list(assRes, exitst); var cond = new method_call(new dot_node(dictIdent, new ident("ContainsKey")), new expression_list(tupleIdent)); - var ifstatement = new if_node(cond, stlst); - (pd.proc_body as block).program_code.list.Insert(1, ifstatement); - // В конец: d[tup] := Result + var ifstatement = new if_node(cond, stlst);*/ + + // if d.TryGetValue(tup,Result) then exit; + + var indr = new indexer(dictIdent, new expression_list(tupleIdent)); + var exitst = new procedure_call(new ident("exit")); + var cond = new method_call(new dot_node(dictIdent, new ident("TryGetValue")), + new expression_list(new List { tupleIdent, new ident("Result") })); + var ifstatement = new if_node(cond, exitst); + proc_code.list.Insert(1, ifstatement); + + // В конец: d[tup] := Result. И надо то же после каждого exit var assEnd = new assign(indr, new ident("Result")); - (pd.proc_body as block).program_code.list.Add(assEnd); + // Вставить d[tup] := Result перед каждым exit начиная с конца + var pcc = pd.DescendantNodes().OfType().Where(pc => pc.func_name is ident id && id.name.ToLower() == "exit" && pc.source_context != null).ToArray(); + foreach (var p in pcc.Reverse()) + { + var ae = assEnd.Clone() as assign; + if (p.Parent is statement_list sl) + sl.ReplaceInList(p, new List { ae, p}); + else p.Parent.ReplaceDescendant(p as statement, new statement_list(new List { ae, p })); + } + if (proc_code.list[proc_code.list.Count - 1] is procedure_call pcall && pcall.func_name is ident idd && idd.name.ToLower() == "exit") + ; // ничего не добавлять - т.к. перед exit всё добавлено + else proc_code.list.Add(assEnd); // Добавить в начало функции семантические проверки: // отсутствие делегатов и pointer в параметрах diff --git a/TestSuite/Cache_exit_test.pas b/TestSuite/Cache_exit_test.pas new file mode 100644 index 000000000..f3d329c5a --- /dev/null +++ b/TestSuite/Cache_exit_test.pas @@ -0,0 +1,19 @@ +[Cache] +function f1(q: byte): byte; +begin + var a := q; + Result := 1; + if a > 2 then + begin + Result := 2; + exit; + end; + //exit(5); + Result := 3; + a := 5; + exit; +end; + +begin + Assert(f1(3)=f1(3)); +end. \ No newline at end of file diff --git a/TestSuite/CompilationSamples/PABCExtensions.pas b/TestSuite/CompilationSamples/PABCExtensions.pas index 2a6a3b506..a6018e862 100644 --- a/TestSuite/CompilationSamples/PABCExtensions.pas +++ b/TestSuite/CompilationSamples/PABCExtensions.pas @@ -3,7 +3,7 @@ ///-- unit PABCExtensions; -{$string_nullbased-} +{$zerobasedstrings off} uses PABCSystem; diff --git a/TestSuite/CompilationSamples/PABCSystem.pas b/TestSuite/CompilationSamples/PABCSystem.pas index ca80b2440..77a491343 100644 --- a/TestSuite/CompilationSamples/PABCSystem.pas +++ b/TestSuite/CompilationSamples/PABCSystem.pas @@ -5,7 +5,7 @@ /// !! System unit unit PABCSystem; -{$string_nullbased-} +{$zerobasedstrings off} {$gendoc true} @@ -12867,7 +12867,7 @@ end; procedure PassSpaces(var s: string; var from: integer); begin - while (from <= s.Length) and (s[from]=' ') do + while (from <= s.Length) and char.IsWhiteSpace(s[from]) do from += 1; end; @@ -13083,7 +13083,7 @@ end; ///-- function SystemSlice0(Self: string; situation: integer; from, &to: integer; step: integer := 1): string; extensionmethod; begin - Result := SystemSliceStringImpl(Self, situation, from, &to, step, 0); // 0 - NullBased + Result := SystemSliceStringImpl(Self, situation, from, &to, step, 0); // 0 - ZeroBased end; ///-- diff --git a/TestSuite/slice_string_nullbased.pas b/TestSuite/slice_string_nullbased.pas index 62e2f9cae..98cd40238 100644 --- a/TestSuite/slice_string_nullbased.pas +++ b/TestSuite/slice_string_nullbased.pas @@ -1,4 +1,4 @@ -{$string_nullbased+} +{$zerobasedstrings} uses PABCExtensions; diff --git a/TreeConverter/TreeConversion/SemanticRules.cs b/TreeConverter/TreeConversion/SemanticRules.cs index db9a85117..e05c22e12 100644 --- a/TreeConverter/TreeConversion/SemanticRules.cs +++ b/TreeConverter/TreeConversion/SemanticRules.cs @@ -30,7 +30,7 @@ namespace PascalABCCompiler.TreeConverter ///

/// Индексировать строки с 0 /// - public static bool NullBasedStrings = false; + public static bool ZeroBasedStrings = false; /// /// Строгая проверка типа указателя diff --git a/TreeConverter/TreeConversion/SyntaxTreeToSemanticTreeConverter.cs b/TreeConverter/TreeConversion/SyntaxTreeToSemanticTreeConverter.cs index 3aeb89309..15494bbab 100644 --- a/TreeConverter/TreeConversion/SyntaxTreeToSemanticTreeConverter.cs +++ b/TreeConverter/TreeConversion/SyntaxTreeToSemanticTreeConverter.cs @@ -40,7 +40,7 @@ namespace PascalABCCompiler.TreeConverter { case PascalABCCompiler.SyntaxTree.LanguageId.PascalABCNET: SemanticRules.AddResultVariable = true; - SemanticRules.NullBasedStrings = false; + SemanticRules.ZeroBasedStrings = false; SemanticRules.FastStrings = false; SemanticRules.InitStringAsEmptyString = true; SemanticRules.UseDivisionAssignmentOperatorsForIntegerTypes = false; @@ -55,7 +55,7 @@ namespace PascalABCCompiler.TreeConverter break; case PascalABCCompiler.SyntaxTree.LanguageId.C: SemanticRules.AddResultVariable = false; - SemanticRules.NullBasedStrings = true; + SemanticRules.ZeroBasedStrings = true; SemanticRules.InitStringAsEmptyString = false; SemanticRules.UseDivisionAssignmentOperatorsForIntegerTypes = true; SemanticRules.ManyVariablesOneInitializator = false; diff --git a/TreeConverter/TreeConversion/compiler_string_consts.cs b/TreeConverter/TreeConversion/compiler_string_consts.cs index c63db88e0..754baf67e 100644 --- a/TreeConverter/TreeConversion/compiler_string_consts.cs +++ b/TreeConverter/TreeConversion/compiler_string_consts.cs @@ -322,9 +322,11 @@ namespace PascalABCCompiler.TreeConverter public static string compiler_directive_reference = "reference"; public static string include_namespace_directive = "includenamespace"; public static string compiler_savepcu = "savepcu"; - public static string compiler_directive_nullbasedstrings = "nullbasedstrings"; - public static string compiler_directive_nullbasedstrings_ON = "string_nullbased+"; - public static string compiler_directive_nullbasedstrings_OFF = "string_nullbased-"; + public static string compiler_directive_zerobasedstrings = "zerobasedstrings"; + public static string compiler_directive_zerobasedstrings_ON = "string_zerobased+"; + public static string compiler_directive_zerobasedstrings_OFF = "string_zerobased-"; + public static string compiler_directive_nullbasedstrings_ON = "string_nullbased+"; // для совместимости. Deprecated + public static string compiler_directive_nullbasedstrings_OFF = "string_nullbased-"; // для совместимости. Deprecated public static string compiler_directive_initstring_as_empty_ON = "string_initempty+"; public static string compiler_directive_initstring_as_empty_OFF = "string_initempty-"; public static string compiler_directive_resource = "resource"; diff --git a/TreeConverter/TreeConversion/syntax_tree_visitor.cs b/TreeConverter/TreeConversion/syntax_tree_visitor.cs index dc6ab7202..9797f7e9d 100644 --- a/TreeConverter/TreeConversion/syntax_tree_visitor.cs +++ b/TreeConverter/TreeConversion/syntax_tree_visitor.cs @@ -5404,9 +5404,9 @@ namespace PascalABCCompiler.TreeConverter bool has_extension_overload = false; semantic_node sn = convert_semantic_strong(_dot_node.left); - // SSM 17/07/21 учёт NullBasedStrings в семантике срезов строк + // SSM 17/07/21 учёт ZeroBasedStrings в семантике срезов строк // Пока не получилось - if (SemanticRules.NullBasedStrings + if (SemanticRules.ZeroBasedStrings && (sn as expression_node)?.type is compiled_type_node ctn && ctn.compiled_type == typeof(string) && _dot_node.right is ident id0 ) @@ -16202,7 +16202,7 @@ namespace PascalABCCompiler.TreeConverter //String 1 based if (parameters.expressions.Count == 1 && nspr.property.comprehensive_type == SystemLibrary.SystemLibrary.string_type && - !SemanticRules.NullBasedStrings && (lbvr == null || !lbvr.var.name.StartsWith("<>match"))) + !SemanticRules.ZeroBasedStrings && (lbvr == null || !lbvr.var.name.StartsWith("<>match"))) { nspr.fact_parametres.AddElement( ConstructDecExpr( @@ -19420,19 +19420,34 @@ namespace PascalABCCompiler.TreeConverter SemanticRules.FastStrings = true; return; } - if (node.Name.text.ToLower() == compiler_string_consts.compiler_directive_nullbasedstrings) + if (node.Name.text.ToLower() == compiler_string_consts.compiler_directive_zerobasedstrings) { - SemanticRules.NullBasedStrings = node.Directive.text.ToLower() == compiler_string_consts.true_const_name; + var paramOnOff = node.Directive.text.ToLower(); + if (paramOnOff == "on" || paramOnOff == "") + SemanticRules.ZeroBasedStrings = true; + else if (paramOnOff == "off") + SemanticRules.ZeroBasedStrings = false; + //SemanticRules.ZeroBasedStrings = node.Directive.text.ToLower() == compiler_string_consts.true_const_name; + return; + } + if (node.Name.text.ToLower() == compiler_string_consts.compiler_directive_zerobasedstrings_ON) + { + SemanticRules.ZeroBasedStrings = true; + return; + } + if (node.Name.text.ToLower() == compiler_string_consts.compiler_directive_zerobasedstrings_OFF) + { + SemanticRules.ZeroBasedStrings = false; return; } if (node.Name.text.ToLower() == compiler_string_consts.compiler_directive_nullbasedstrings_ON) { - SemanticRules.NullBasedStrings = true; + SemanticRules.ZeroBasedStrings = true; return; } if (node.Name.text.ToLower() == compiler_string_consts.compiler_directive_nullbasedstrings_OFF) { - SemanticRules.NullBasedStrings = false; + SemanticRules.ZeroBasedStrings = false; return; } if (node.Name.text.ToLower() == compiler_string_consts.compiler_directive_initstring_as_empty_ON) diff --git a/bin/Lib/PABCExtensions.pas b/bin/Lib/PABCExtensions.pas index ebc00cdd1..ac66024ed 100644 --- a/bin/Lib/PABCExtensions.pas +++ b/bin/Lib/PABCExtensions.pas @@ -3,7 +3,7 @@ ///-- unit PABCExtensions; -{$string_nullbased-} +{$zerobasedstrings off} uses PABCSystem; diff --git a/bin/Lib/PABCSystem.pas b/bin/Lib/PABCSystem.pas index ca80b2440..77a491343 100644 --- a/bin/Lib/PABCSystem.pas +++ b/bin/Lib/PABCSystem.pas @@ -5,7 +5,7 @@ /// !! System unit unit PABCSystem; -{$string_nullbased-} +{$zerobasedstrings off} {$gendoc true} @@ -12867,7 +12867,7 @@ end; procedure PassSpaces(var s: string; var from: integer); begin - while (from <= s.Length) and (s[from]=' ') do + while (from <= s.Length) and char.IsWhiteSpace(s[from]) do from += 1; end; @@ -13083,7 +13083,7 @@ end; ///-- function SystemSlice0(Self: string; situation: integer; from, &to: integer; step: integer := 1): string; extensionmethod; begin - Result := SystemSliceStringImpl(Self, situation, from, &to, step, 0); // 0 - NullBased + Result := SystemSliceStringImpl(Self, situation, from, &to, step, 0); // 0 - ZeroBased end; ///-- diff --git a/bin/Lng/Eng/SyntaxTreeVisitorsErrors.dat b/bin/Lng/Eng/SyntaxTreeVisitorsErrors.dat index d913809f4..2741491ed 100644 --- a/bin/Lng/Eng/SyntaxTreeVisitorsErrors.dat +++ b/bin/Lng/Eng/SyntaxTreeVisitorsErrors.dat @@ -46,4 +46,5 @@ FUNCTIONS_WITH_CACHE_ATTRIBUTE_SHOULD_HAVE_LESSTHEN8_PARAMETERS=Functions with [ FUNCTIONS_WITH_CACHE_ATTRIBUTE_SHOULD_HAVE_EXPLICIT_RETURN_TYPE=Functions with [Cache] attribute must have explicitely specified return type FUNCTIONS_WITH_CACHE_ATTRIBUTE_SHOULD_NOT_HAVE_COMPOUND_NAME=Functions with [Cache] should not have compound name FUNCTIONS_WITH_CACHE_ATTRIBUTE_SHOULD_NOT_HAVE_VAR_CONST_PARAMS_MODIFIERS=Functions with [Cache] should not have var, const or params modifier -FUNCTIONS_WITH_CACHE_ATTRIBUTE_SHOULD_BE_DEFINED_GLOBALLY=Functions with [Cache] attribute must be defined globally \ No newline at end of file +FUNCTIONS_WITH_CACHE_ATTRIBUTE_SHOULD_BE_DEFINED_GLOBALLY=Functions with [Cache] attribute must be defined globally +FUNCTIONS_WITH_CACHE_ATTRIBUTE_CANNOT_HAVE_YIELD=Functions with [Cache] attribute must not contain yield statements \ No newline at end of file diff --git a/bin/Lng/Rus/SyntaxTreeVisitorsErrors.dat b/bin/Lng/Rus/SyntaxTreeVisitorsErrors.dat index 33ef97f56..cd664bd19 100644 --- a/bin/Lng/Rus/SyntaxTreeVisitorsErrors.dat +++ b/bin/Lng/Rus/SyntaxTreeVisitorsErrors.dat @@ -50,4 +50,5 @@ FUNCTIONS_WITH_CACHE_ATTRIBUTE_SHOULD_HAVE_LESSTHEN8_PARAMETERS=Функции FUNCTIONS_WITH_CACHE_ATTRIBUTE_SHOULD_HAVE_EXPLICIT_RETURN_TYPE=Функции с атрибутом [Cache] должны иметь явно указанный возвращаемый тип FUNCTIONS_WITH_CACHE_ATTRIBUTE_SHOULD_NOT_HAVE_COMPOUND_NAME=Функции с атрибутом [Cache] не должны иметь составное имя FUNCTIONS_WITH_CACHE_ATTRIBUTE_SHOULD_NOT_HAVE_VAR_CONST_PARAMS_MODIFIERS=Функции с атрибутом [Cache] не должны иметь var, const и params-параметры -FUNCTIONS_WITH_CACHE_ATTRIBUTE_SHOULD_BE_DEFINED_GLOBALLY=Функции с атрибутом [Cache] должны быть определены глобально \ No newline at end of file +FUNCTIONS_WITH_CACHE_ATTRIBUTE_SHOULD_BE_DEFINED_GLOBALLY=Функции с атрибутом [Cache] должны быть определены глобально +FUNCTIONS_WITH_CACHE_ATTRIBUTE_CANNOT_HAVE_YIELD=Функции с атрибутом [Cache] не должны содержать оператор yield \ No newline at end of file diff --git a/bin/PascalABCNET.chm b/bin/PascalABCNET.chm index 5a42c7a36..959f346d5 100644 Binary files a/bin/PascalABCNET.chm and b/bin/PascalABCNET.chm differ