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