Compare commits
6 commits
master
...
opt_tuple_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75e79d9a82 | ||
|
|
66eaa619a3 | ||
|
|
d269c7ca20 | ||
|
|
54f8db8ce2 | ||
|
|
2dc3c4e50c | ||
|
|
133d082e4e |
|
|
@ -2709,9 +2709,12 @@ namespace PascalABCCompiler
|
||||||
|
|
||||||
if (!PCUFileNamesDictionary.TryGetValue(cacheKey, out var fileNameWithPriority))
|
if (!PCUFileNamesDictionary.TryGetValue(cacheKey, out var fileNameWithPriority))
|
||||||
{
|
{
|
||||||
if (FindFileWithExtensionInDirs(fileName, out _, currentPath) is string resultFileName1)
|
if (Path.GetExtension(fileName) != CompilerOptions.CompiledUnitExtension)
|
||||||
|
fileNameWithPriority = null;
|
||||||
|
|
||||||
|
else if (FindFileWithExtensionInDirs(fileName, out _, currentPath) is string resultFileName1)
|
||||||
fileNameWithPriority = Tuple.Create(resultFileName1, 1);
|
fileNameWithPriority = Tuple.Create(resultFileName1, 1);
|
||||||
else if (FindFileWithExtensionInDirs(Path.GetFileName(fileName), out _, CompilerOptions.OutputDirectory) is string resultFileName2)
|
else if (CompilerOptions.OutputDirectory != CompilerOptions.SourceFileDirectory && FindFileWithExtensionInDirs(Path.GetFileName(fileName), out _, CompilerOptions.OutputDirectory) is string resultFileName2)
|
||||||
fileNameWithPriority = Tuple.Create(resultFileName2, 2);
|
fileNameWithPriority = Tuple.Create(resultFileName2, 2);
|
||||||
else if (FindFileWithExtensionInDirs(fileName, out var dirIndex, CompilerOptions.SearchDirectories.ToArray()) is string resultFileName3)
|
else if (FindFileWithExtensionInDirs(fileName, out var dirIndex, CompilerOptions.SearchDirectories.ToArray()) is string resultFileName3)
|
||||||
fileNameWithPriority = Tuple.Create(resultFileName3, 3 + dirIndex);
|
fileNameWithPriority = Tuple.Create(resultFileName3, 3 + dirIndex);
|
||||||
|
|
@ -2731,6 +2734,7 @@ namespace PascalABCCompiler
|
||||||
|
|
||||||
if (!SourceFileNamesDictionary.TryGetValue(cacheKey, out var fileNameWithPriority))
|
if (!SourceFileNamesDictionary.TryGetValue(cacheKey, out var fileNameWithPriority))
|
||||||
{
|
{
|
||||||
|
|
||||||
if (FindSourceFileNameInDirs(fileName, out _, currentPath) is string resultFileName1)
|
if (FindSourceFileNameInDirs(fileName, out _, currentPath) is string resultFileName1)
|
||||||
fileNameWithPriority = Tuple.Create(resultFileName1, 1);
|
fileNameWithPriority = Tuple.Create(resultFileName1, 1);
|
||||||
else if (FindSourceFileNameInDirs(fileName, out var dirIndex, CompilerOptions.SearchDirectories.ToArray()) is string resultFileName2)
|
else if (FindSourceFileNameInDirs(fileName, out var dirIndex, CompilerOptions.SearchDirectories.ToArray()) is string resultFileName2)
|
||||||
|
|
@ -3362,7 +3366,17 @@ namespace PascalABCCompiler
|
||||||
// It's not always possible to solve by re-ordering the references, since there are cases of
|
// It's not always possible to solve by re-ordering the references, since there are cases of
|
||||||
// mutually-dependent assemblies (i.e. dependency loops) in the wild.
|
// mutually-dependent assemblies (i.e. dependency loops) in the wild.
|
||||||
foreach (var reference in referenceDirectives)
|
foreach (var reference in referenceDirectives)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
PreloadReference(reference);
|
PreloadReference(reference);
|
||||||
|
}
|
||||||
|
catch (FileLoadException ex)
|
||||||
|
{
|
||||||
|
throw new CommonCompilerError(ex.Message, compilationUnit.SyntaxTree.file_name, reference.location.begin_line_num, reference.location.end_line_num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
foreach (var reference in referenceDirectives)
|
foreach (var reference in referenceDirectives)
|
||||||
CompileReference(dlls, reference);
|
CompileReference(dlls, reference);
|
||||||
|
|
|
||||||
|
|
@ -1847,7 +1847,10 @@ namespace PascalABCCompiler.PCU
|
||||||
common_method_node raise_meth = null;
|
common_method_node raise_meth = null;
|
||||||
if (CanReadObject())
|
if (CanReadObject())
|
||||||
raise_meth = GetClassMethod(br.ReadInt32());
|
raise_meth = GetClassMethod(br.ReadInt32());
|
||||||
class_field cf = GetClassField(br.ReadInt32());
|
int field_off = br.ReadInt32();
|
||||||
|
class_field cf = null;
|
||||||
|
if (field_off > 0)
|
||||||
|
cf = GetClassField(field_off);
|
||||||
common_type_node cont = (common_type_node)GetTypeReference(br.ReadInt32());
|
common_type_node cont = (common_type_node)GetTypeReference(br.ReadInt32());
|
||||||
if (name==null)
|
if (name==null)
|
||||||
name = GetStringInClass(cont, name_ref);
|
name = GetStringInClass(cont, name_ref);
|
||||||
|
|
|
||||||
|
|
@ -3021,7 +3021,10 @@ namespace PascalABCCompiler.PCU
|
||||||
bw.Write(GetMemberOffset(_event.remove_method));
|
bw.Write(GetMemberOffset(_event.remove_method));
|
||||||
if (CanWriteObject(_event.raise_method))
|
if (CanWriteObject(_event.raise_method))
|
||||||
bw.Write(GetMemberOffset(_event.raise_method));
|
bw.Write(GetMemberOffset(_event.raise_method));
|
||||||
|
if (!_event.cont_type.IsInterface)
|
||||||
bw.Write(GetMemberOffset(_event.field));
|
bw.Write(GetMemberOffset(_event.field));
|
||||||
|
else
|
||||||
|
bw.Write(0);
|
||||||
bw.Write(offset);
|
bw.Write(offset);
|
||||||
bw.Write((byte)_event.field_access_level);
|
bw.Write((byte)_event.field_access_level);
|
||||||
bw.Write((byte)_event.polymorphic_state);
|
bw.Write((byte)_event.polymorphic_state);
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ internal static class RevisionClass
|
||||||
public const string Major = "3";
|
public const string Major = "3";
|
||||||
public const string Minor = "9";
|
public const string Minor = "9";
|
||||||
public const string Build = "0";
|
public const string Build = "0";
|
||||||
public const string Revision = "3488";
|
public const string Revision = "3494";
|
||||||
|
|
||||||
public const string MainVersion = Major + "." + Minor;
|
public const string MainVersion = Major + "." + Minor;
|
||||||
public const string FullVersion = Major + "." + Minor + "." + Build + "." + Revision;
|
public const string FullVersion = Major + "." + Minor + "." + Build + "." + Revision;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
%COREVERSION%=0
|
%COREVERSION%=0
|
||||||
%REVISION%=3488
|
%REVISION%=3494
|
||||||
%MINOR%=9
|
%MINOR%=9
|
||||||
%MAJOR%=3
|
%MAJOR%=3
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
//
|
//
|
||||||
// This CSharp output file generated by Gardens Point LEX
|
// This CSharp output file generated by Gardens Point LEX
|
||||||
// Version: 1.1.3.301
|
// Version: 1.1.3.301
|
||||||
// Machine: DESKTOP-V3E9T2U
|
// Machine: DESKTOP-G8V08V4
|
||||||
// DateTime: 25.05.2024 22:13:44
|
// DateTime: 17.06.2024 16:43:45
|
||||||
// UserName: alex
|
// UserName: ?????????
|
||||||
// GPLEX input file <ABCPascal.lex>
|
// GPLEX input file <ABCPascal.lex>
|
||||||
// GPLEX frame file <embedded resource>
|
// GPLEX frame file <embedded resource>
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -3373,8 +3373,6 @@ expr_l1_for_lambda
|
||||||
expr_dq
|
expr_dq
|
||||||
: relop_expr
|
: relop_expr
|
||||||
{ $$ = $1; }
|
{ $$ = $1; }
|
||||||
| tkAwait relop_expr
|
|
||||||
{ $$ = $2; }
|
|
||||||
| expr_dq tkDoubleQuestion relop_expr
|
| expr_dq tkDoubleQuestion relop_expr
|
||||||
{ $$ = new double_question_node($1 as expression, $3 as expression, @$);}
|
{ $$ = new double_question_node($1 as expression, $3 as expression, @$);}
|
||||||
;
|
;
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -377,6 +377,9 @@ script=
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,9 @@ namespace Languages.Pascal.Frontend.Converters
|
||||||
|
|
||||||
protected override syntax_tree_node ApplyConcreteConversions(syntax_tree_node root)
|
protected override syntax_tree_node ApplyConcreteConversions(syntax_tree_node root)
|
||||||
{
|
{
|
||||||
|
root.FillParentsInAllChilds();
|
||||||
|
|
||||||
|
var binder = new BindCollectLightSymInfo(root as compilation_unit);
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
// var stat = new ABCStatisticsVisitor();
|
// var stat = new ABCStatisticsVisitor();
|
||||||
// stat.ProcessNode(root);
|
// stat.ProcessNode(root);
|
||||||
|
|
@ -42,9 +44,9 @@ namespace Languages.Pascal.Frontend.Converters
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
//new SimplePrettyPrinterVisitor("D:/out.txt").ProcessNode(root);
|
//new SimplePrettyPrinterVisitor("D:/out.txt").ProcessNode(root);
|
||||||
#endif
|
#endif
|
||||||
|
bool optimize_tuple_assign = true;
|
||||||
// tuple_node
|
// tuple_node
|
||||||
TupleVisitor.New.ProcessNode(root);
|
TupleVisitor.Create(optimize_tuple_assign).ProcessNode(root);
|
||||||
|
|
||||||
// index
|
// index
|
||||||
IndexVisitor.New.ProcessNode(root);
|
IndexVisitor.New.ProcessNode(root);
|
||||||
|
|
@ -55,8 +57,10 @@ namespace Languages.Pascal.Frontend.Converters
|
||||||
|
|
||||||
// теперь коллизия с (a[1:6], a[6:11]):= (a[6:11], a[1:6]);
|
// теперь коллизия с (a[1:6], a[6:11]):= (a[6:11], a[1:6]);
|
||||||
// assign_tuple и assign_var_tuple
|
// assign_tuple и assign_var_tuple
|
||||||
|
if (!optimize_tuple_assign)
|
||||||
AssignTuplesDesugarVisitor.New.ProcessNode(root); // теперь это - на семантике
|
AssignTuplesDesugarVisitor.New.ProcessNode(root); // теперь это - на семантике
|
||||||
|
else
|
||||||
|
NewAssignTuplesDesugarVisitor.Create(binder).ProcessNode(root);
|
||||||
|
|
||||||
// question_point_desugar_visitor
|
// question_point_desugar_visitor
|
||||||
QuestionPointDesugarVisitor.New.ProcessNode(root);
|
QuestionPointDesugarVisitor.New.ProcessNode(root);
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -4707,9 +4707,12 @@ namespace PascalABCCompiler.NETGenerator
|
||||||
{
|
{
|
||||||
ICommonTypeNode ctn = init_value.type as ICommonTypeNode;
|
ICommonTypeNode ctn = init_value.type as ICommonTypeNode;
|
||||||
IExpressionNode[] FieldValues = init_value.FieldValues;
|
IExpressionNode[] FieldValues = init_value.FieldValues;
|
||||||
ICommonClassFieldNode[] Fields = ctn.fields;
|
List<ICommonClassFieldNode> Fields = new List<ICommonClassFieldNode>();
|
||||||
|
foreach (var field in ctn.fields)
|
||||||
|
if (field.polymorphic_state != polymorphic_state.ps_static)
|
||||||
|
Fields.Add(field);
|
||||||
|
|
||||||
for (int i = 0; i < Fields.Length; i++)
|
for (int i = 0; i < Fields.Count; i++)
|
||||||
{
|
{
|
||||||
FldInfo field = helper.GetField(Fields[i]);
|
FldInfo field = helper.GetField(Fields[i]);
|
||||||
if (FieldValues[i] is IArrayInitializer)
|
if (FieldValues[i] is IArrayInitializer)
|
||||||
|
|
@ -4750,9 +4753,12 @@ namespace PascalABCCompiler.NETGenerator
|
||||||
{
|
{
|
||||||
ICommonTypeNode ctn = init_value.type as ICommonTypeNode;
|
ICommonTypeNode ctn = init_value.type as ICommonTypeNode;
|
||||||
IConstantNode[] FieldValues = init_value.FieldValues;
|
IConstantNode[] FieldValues = init_value.FieldValues;
|
||||||
ICommonClassFieldNode[] Fields = ctn.fields;
|
List<ICommonClassFieldNode> Fields = new List<ICommonClassFieldNode>();
|
||||||
|
foreach (var field in ctn.fields)
|
||||||
|
if (field.polymorphic_state != polymorphic_state.ps_static)
|
||||||
|
Fields.Add(field);
|
||||||
|
|
||||||
for (int i = 0; i < Fields.Length; i++)
|
for (int i = 0; i < Fields.Count; i++)
|
||||||
{
|
{
|
||||||
FldInfo field = helper.GetField(Fields[i]);
|
FldInfo field = helper.GetField(Fields[i]);
|
||||||
if (FieldValues[i] is IArrayConstantNode)
|
if (FieldValues[i] is IArrayConstantNode)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 17
|
# Visual Studio Version 16
|
||||||
VisualStudioVersion = 17.8.34309.116
|
VisualStudioVersion = 16.0.34301.259
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VisualPascalABCNET", "VisualPascalABCNET", "{26843C5D-9D7E-4C2C-AC14-2D227FA5592E}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VisualPascalABCNET", "VisualPascalABCNET", "{26843C5D-9D7E-4C2C-AC14-2D227FA5592E}"
|
||||||
EndProject
|
EndProject
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
3.9.0.3488
|
3.9.0.3494
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
!define VERSION '3.9.0.3488'
|
!define VERSION '3.9.0.3494'
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace PascalABCCompiler.SyntaxTree
|
namespace PascalABCCompiler.SyntaxTree
|
||||||
{
|
{
|
||||||
|
|
@ -12,22 +13,23 @@ namespace PascalABCCompiler.SyntaxTree
|
||||||
{
|
{
|
||||||
Current = Root;
|
Current = Root;
|
||||||
visit(root);
|
visit(root);
|
||||||
|
Current = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SymInfoSyntax bind(ident node)
|
public BindResult bind(ident node)
|
||||||
{
|
{
|
||||||
///Console.WriteLine("searching " + node.ToString());
|
|
||||||
|
Current = null;
|
||||||
syntax_tree_node cur_node = node;
|
syntax_tree_node cur_node = node;
|
||||||
|
var path = new Queue<ScopeSyntax>();
|
||||||
while (cur_node != null)
|
while (cur_node != null)
|
||||||
{
|
{
|
||||||
// Console.WriteLine("cur_node: " + cur_node.ToString());
|
|
||||||
|
|
||||||
if (AbstractScopeCreator.IsScopeCreator(cur_node))
|
if (AbstractScopeCreator.IsScopeCreator(cur_node))
|
||||||
{
|
{
|
||||||
|
|
||||||
//Console.WriteLine("checking scope" + cur_node.ToString())
|
|
||||||
var cur_scope = scopeCreator.GetScope(cur_node);
|
var cur_scope = scopeCreator.GetScope(cur_node);
|
||||||
//Console.WriteLine(cur_scope.ToString() + ": " + cur_scope.Symbols.Count);
|
path.Enqueue(cur_scope);
|
||||||
var prev_scope = Current;
|
var prev_scope = Current;
|
||||||
|
|
||||||
if (prev_scope != null)
|
if (prev_scope != null)
|
||||||
|
|
@ -36,11 +38,10 @@ namespace PascalABCCompiler.SyntaxTree
|
||||||
Current = cur_scope;
|
Current = cur_scope;
|
||||||
if (cur_scope.Parent == null && !(Current is GlobalScopeSyntax))
|
if (cur_scope.Parent == null && !(Current is GlobalScopeSyntax))
|
||||||
{
|
{
|
||||||
//Console.WriteLine("visiting " + cur_node.ToString());
|
|
||||||
cur_node.visit(this);
|
cur_node.visit(this);
|
||||||
}
|
}
|
||||||
var res = Current.bind(node);
|
var res = Current.bind(node);
|
||||||
if (res != null) return res;
|
if (res != null) return new BindResult(res, path.ToList());
|
||||||
}
|
}
|
||||||
cur_node = cur_node.Parent;
|
cur_node = cur_node.Parent;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,20 @@ namespace PascalABCCompiler.SyntaxTree
|
||||||
AddSymbols(vd.vars.list, SymKind.var, vd.vars_type, attr);
|
AddSymbols(vd.vars.list, SymKind.var, vd.vars_type, attr);
|
||||||
base.visit(vd);
|
base.visit(vd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void visit(assign_var_tuple node)
|
||||||
|
{
|
||||||
|
AddSymbols(node.idents.idents, SymKind.var);
|
||||||
|
base.visit(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void visit(var_tuple_def_statement node)
|
||||||
|
{
|
||||||
|
var attr = node.var_attr == definition_attribute.Static ? SymbolAttributes.class_attr : 0;
|
||||||
|
AddSymbols(node.vars.list, SymKind.var, node.vars_type, attr);
|
||||||
|
base.visit(node);
|
||||||
|
}
|
||||||
|
|
||||||
public override void visit(formal_parameters fp)
|
public override void visit(formal_parameters fp)
|
||||||
{
|
{
|
||||||
foreach (var pg in fp.params_list)
|
foreach (var pg in fp.params_list)
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,19 @@ namespace PascalABCCompiler.SyntaxTree
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class BindResult {
|
||||||
|
|
||||||
|
public SymInfoSyntax symInfo;
|
||||||
|
public List<ScopeSyntax> path;
|
||||||
|
|
||||||
|
public BindResult(SymInfoSyntax s, List<ScopeSyntax> p)
|
||||||
|
{
|
||||||
|
symInfo = s;
|
||||||
|
path = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public abstract class ScopeSyntax
|
public abstract class ScopeSyntax
|
||||||
{
|
{
|
||||||
public syntax_tree_node node;
|
public syntax_tree_node node;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using AssignTupleDesugarAlgorithm;
|
||||||
|
using PascalABCCompiler.SyntaxTree;
|
||||||
|
|
||||||
|
namespace SyntaxVisitors.SugarVisitors
|
||||||
|
{
|
||||||
|
public class NewAssignTuplesDesugarVisitor : AssignTuplesDesugarVisitor
|
||||||
|
{
|
||||||
|
|
||||||
|
private BindCollectLightSymInfo binder;
|
||||||
|
|
||||||
|
|
||||||
|
public static NewAssignTuplesDesugarVisitor Create(BindCollectLightSymInfo binder)
|
||||||
|
{
|
||||||
|
return new NewAssignTuplesDesugarVisitor(binder);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NewAssignTuplesDesugarVisitor(BindCollectLightSymInfo binder)
|
||||||
|
{
|
||||||
|
this.binder = binder;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
List<statement> desugar(tuple_node tn, addressed_value_list vars)
|
||||||
|
{
|
||||||
|
var order = Assign.getAssignOrder(tn, vars, binder);
|
||||||
|
var assigns = new List<statement>();
|
||||||
|
foreach (var a in order)
|
||||||
|
{
|
||||||
|
if (a.to is TempSymbol ts)
|
||||||
|
{
|
||||||
|
var cur = new var_def_statement(ts.node as ident, a.from.node, tn.Parent.source_context);
|
||||||
|
assigns.Add(new var_statement(cur, tn.Parent.source_context));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var cur = new assign(a.to.node as addressed_value, a.from.node, tn.Parent.source_context);
|
||||||
|
assigns.Add(cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return assigns;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void visit(assign_tuple node)
|
||||||
|
{
|
||||||
|
if (node.expr is tuple_node tn)
|
||||||
|
{
|
||||||
|
var n = node.vars.variables.Count();
|
||||||
|
if (n > tn.el.Count)
|
||||||
|
throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", node.vars.variables[0]);
|
||||||
|
|
||||||
|
var assigns = desugar(tn, node.vars);
|
||||||
|
ReplaceStatementUsingParent(node, assigns);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
base.visit(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void visit(assign_var_tuple node)
|
||||||
|
{
|
||||||
|
if (node.expr is tuple_node tn)
|
||||||
|
{
|
||||||
|
var n = node.idents.idents.Count();
|
||||||
|
if (n > tn.el.Count)
|
||||||
|
throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", node.idents.idents[0]);
|
||||||
|
|
||||||
|
var assigns = new List<statement>();
|
||||||
|
for(var i =0; i < n; i++)
|
||||||
|
{
|
||||||
|
var cur = new var_def_statement(node.idents.idents[i], tn.el.expressions[i], tn.Parent.source_context);
|
||||||
|
assigns.Add(new var_statement(cur, node.source_context));
|
||||||
|
}
|
||||||
|
ReplaceStatementUsingParent(node, assigns);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
base.visit(node);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void visit(var_tuple_def_statement node)
|
||||||
|
{
|
||||||
|
if (node.inital_value is tuple_node tn)
|
||||||
|
{
|
||||||
|
var n = node.vars.idents.Count();
|
||||||
|
if (n > tn.el.Count)
|
||||||
|
throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", node.vars.idents[0]);
|
||||||
|
var assigns = new List<var_def_statement>();
|
||||||
|
for (var i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
var cur = new var_def_statement(node.vars.idents[i], tn.el.expressions[i], tn.Parent.source_context);
|
||||||
|
assigns.Add(cur);
|
||||||
|
}
|
||||||
|
ReplaceVarTupleDefStatementUsingParent(node, assigns);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
base.visit(node);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using PascalABCCompiler.SyntaxTree;
|
||||||
|
|
||||||
|
namespace AssignTupleDesugarAlgorithm
|
||||||
|
{
|
||||||
|
public class Assign
|
||||||
|
{
|
||||||
|
public Symbol from;
|
||||||
|
public Symbol to;
|
||||||
|
public Assign(Symbol to, Symbol from)
|
||||||
|
{
|
||||||
|
this.to = to;
|
||||||
|
this.from = from;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Assign> getAssignOrder(tuple_node tn, addressed_value_list vars, BindCollectLightSymInfo binder)
|
||||||
|
{
|
||||||
|
var left = new List<Symbol>();
|
||||||
|
var right = new List<Symbol>();
|
||||||
|
|
||||||
|
foreach (var ex in vars.variables)
|
||||||
|
{
|
||||||
|
var s = new Symbol(ex, binder);
|
||||||
|
left.Add(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var ex in tn.el.expressions)
|
||||||
|
{
|
||||||
|
var s = new Symbol(ex, binder);
|
||||||
|
right.Add(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var graph = GraphUtils.createAssignGraph(left, right);
|
||||||
|
//graph.drawGraph();
|
||||||
|
var order = graph.GetAssignOrder();
|
||||||
|
return order.Select(elem => new Assign(to: elem.to.symbol, from: elem.from.symbol)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,166 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace AssignTupleDesugarAlgorithm
|
||||||
|
{
|
||||||
|
internal class AssignGraph : IEnumerable<SymbolNode>
|
||||||
|
{
|
||||||
|
public readonly HashSet<SymbolNode> vertexes = new HashSet<SymbolNode>();
|
||||||
|
|
||||||
|
public readonly List<Edge> edges = new List<Edge>();
|
||||||
|
private bool AdjStructuresNeedSync = false;
|
||||||
|
|
||||||
|
public List<Edge> assignOrder = new List<Edge>();
|
||||||
|
public List<Edge> assignLast = new List<Edge>();
|
||||||
|
public List<Edge> assignFirst = new List<Edge>();
|
||||||
|
|
||||||
|
private Dictionary<SymbolNode, List<SymbolNode>> outAdjStructure = null;
|
||||||
|
|
||||||
|
public Dictionary<SymbolNode, List<SymbolNode>> OutAdjStructure
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (outAdjStructure == null || AdjStructuresNeedSync)
|
||||||
|
{
|
||||||
|
outAdjStructure = createOutAdjStructure();
|
||||||
|
inAdjStructure = createInAdjStructure();
|
||||||
|
AdjStructuresNeedSync = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return outAdjStructure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<SymbolNode, List<SymbolNode>> createOutAdjStructure()
|
||||||
|
{
|
||||||
|
Dictionary<SymbolNode, List<SymbolNode>> res = new Dictionary<SymbolNode, List<SymbolNode>>();
|
||||||
|
|
||||||
|
foreach (var vert in vertexes) res.Add(vert, new List<SymbolNode>());
|
||||||
|
|
||||||
|
foreach (Edge edge in edges) res[edge.from].Add(edge.to);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<SymbolNode, List<SymbolNode>> inAdjStructure = null;
|
||||||
|
|
||||||
|
public Dictionary<SymbolNode, List<SymbolNode>> InAdjStructure
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (inAdjStructure == null || AdjStructuresNeedSync)
|
||||||
|
{
|
||||||
|
outAdjStructure = createOutAdjStructure();
|
||||||
|
inAdjStructure = createInAdjStructure();
|
||||||
|
AdjStructuresNeedSync = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return inAdjStructure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<SymbolNode, List<SymbolNode>> createInAdjStructure()
|
||||||
|
{
|
||||||
|
Dictionary<SymbolNode, List<SymbolNode>> res = new Dictionary<SymbolNode, List<SymbolNode>>();
|
||||||
|
|
||||||
|
foreach (var vert in vertexes) res.Add(vert, new List<SymbolNode>());
|
||||||
|
|
||||||
|
foreach (Edge edge in edges) res[edge.to].Add(edge.from);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<Edge> GetInEdgesForVertex(SymbolNode v) => edges.FindAll(edge => edge.to == v);
|
||||||
|
public List<Edge> GetOutEdgesForVertex(SymbolNode v) => edges.FindAll(edge => edge.from == v);
|
||||||
|
|
||||||
|
public void resetVertexesColor()
|
||||||
|
{
|
||||||
|
foreach (SymbolNode v in vertexes) v.resetColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnsureThatEveryVertexHasOneOrZeroInEdge() =>
|
||||||
|
vertexes.All(vert => GetInEdgesForVertex(vert).Count <= 1);
|
||||||
|
|
||||||
|
internal List<Edge> GetAssignOrder()
|
||||||
|
{
|
||||||
|
List<Edge> assignOrder = new List<Edge>();
|
||||||
|
assignOrder.AddRange(assignFirst);
|
||||||
|
|
||||||
|
if (vertexes.Count == 0)
|
||||||
|
{
|
||||||
|
assignOrder.AddRange(assignLast);
|
||||||
|
this.assignOrder = assignOrder;
|
||||||
|
return this.assignOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
var s = vertexes.First();
|
||||||
|
|
||||||
|
if (!EnsureThatEveryVertexHasOneOrZeroInEdge()) throw new Exception("Invalid assign graph!");
|
||||||
|
|
||||||
|
var cycles = this.findAllUniqueElementaryCycles();
|
||||||
|
|
||||||
|
foreach (var cycle in cycles)
|
||||||
|
{
|
||||||
|
SymbolNode cut_place = cycle[0];
|
||||||
|
Edge edge_to_cut = GetInEdgesForVertex(cut_place).First();
|
||||||
|
|
||||||
|
SymbolNode temp_assign_from = edge_to_cut.from;
|
||||||
|
SymbolNode temp_vertex = new TempSymbolNode(new TempSymbol());
|
||||||
|
|
||||||
|
assignOrder.Add(new Edge(temp_assign_from, temp_vertex));
|
||||||
|
assignLast.Add(new Edge(temp_vertex, cut_place));
|
||||||
|
|
||||||
|
edges.Remove(edge_to_cut);
|
||||||
|
AdjStructuresNeedSync = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SymbolNode> roots = vertexes.ToList().FindAll(vertex => GetInEdgesForVertex(vertex).Count == 0);
|
||||||
|
|
||||||
|
void treeTraversal(SymbolNode root)
|
||||||
|
{
|
||||||
|
foreach (SymbolNode node in OutAdjStructure[root]) treeTraversal(node);
|
||||||
|
|
||||||
|
var inEdges = GetInEdgesForVertex(root);
|
||||||
|
if (inEdges.Count() > 0) assignOrder.Add(inEdges.First());
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (SymbolNode root in roots) treeTraversal(root);
|
||||||
|
|
||||||
|
assignOrder.AddRange(assignLast);
|
||||||
|
this.assignOrder = assignOrder;
|
||||||
|
return this.assignOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssignGraph(List<Edge> edges, List<SymbolNode> vertexes) : this(edges)
|
||||||
|
{
|
||||||
|
foreach (SymbolNode vert in vertexes) this.vertexes.Add(vert);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssignGraph()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssignGraph(List<Edge> e)
|
||||||
|
{
|
||||||
|
edges = e;
|
||||||
|
foreach (var edge in edges)
|
||||||
|
{
|
||||||
|
vertexes.Add(edge.from);
|
||||||
|
vertexes.Add(edge.to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public IEnumerator<SymbolNode> GetEnumerator()
|
||||||
|
{
|
||||||
|
return ((IEnumerable<SymbolNode>)vertexes).GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return ((IEnumerable)vertexes).GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace AssignTupleDesugarAlgorithm
|
||||||
|
{
|
||||||
|
internal class Cycle
|
||||||
|
{
|
||||||
|
List<SymbolNode> cycle;
|
||||||
|
|
||||||
|
|
||||||
|
public int Len => cycle.Count;
|
||||||
|
|
||||||
|
public Cycle(List<SymbolNode> c)
|
||||||
|
{
|
||||||
|
cycle = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SymbolNode this[int i] => cycle[i % Len];
|
||||||
|
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
string res = "";
|
||||||
|
foreach (var v in cycle)
|
||||||
|
{
|
||||||
|
res += v + "->";
|
||||||
|
}
|
||||||
|
|
||||||
|
return res + cycle[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AssignTupleDesugarAlgorithm
|
||||||
|
{
|
||||||
|
internal class Edge : IEquatable<Edge>, IComparable<Edge>
|
||||||
|
{
|
||||||
|
public SymbolNode from;
|
||||||
|
public SymbolNode to;
|
||||||
|
public int weight;
|
||||||
|
|
||||||
|
public Edge(SymbolNode f, SymbolNode t, int w = 0)
|
||||||
|
{
|
||||||
|
if (weight < 0) throw new ArgumentException("weight can't be negative!");
|
||||||
|
from = f;
|
||||||
|
to = t;
|
||||||
|
weight = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(Edge other)
|
||||||
|
{
|
||||||
|
return weight - other.weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(Edge other)
|
||||||
|
{
|
||||||
|
if (other is null) return false;
|
||||||
|
return from == other.from && to == other.to;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,525 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
|
||||||
|
namespace AssignTupleDesugarAlgorithm
|
||||||
|
{
|
||||||
|
internal static class GraphUtils
|
||||||
|
{
|
||||||
|
static private void dfs(this AssignGraph graph,
|
||||||
|
Action<AssignGraph> OnEnterGraph,
|
||||||
|
Func<AssignGraph, SymbolNode, bool> OnProcessVertex,
|
||||||
|
Action<AssignGraph, SymbolNode> OnEnterNode,
|
||||||
|
Func<AssignGraph, SymbolNode, SymbolNode, bool> OnProcessNodeChild,
|
||||||
|
Action<AssignGraph, SymbolNode> OnLeaveNode,
|
||||||
|
Action<AssignGraph> OnLeaveGraph,
|
||||||
|
Func<AssignGraph, SymbolNode, IEnumerable<SymbolNode>> vertexTraversalOrderFunc = null,
|
||||||
|
IEnumerable<SymbolNode> graphTraversalOrder = null)
|
||||||
|
{
|
||||||
|
void dfs(SymbolNode start_node,
|
||||||
|
Action<AssignGraph, SymbolNode> OnEnter,
|
||||||
|
Func<AssignGraph, SymbolNode, SymbolNode, bool> OnProcessChild,
|
||||||
|
Action<AssignGraph, SymbolNode> OnLeave
|
||||||
|
)
|
||||||
|
{
|
||||||
|
OnEnter(graph, start_node);
|
||||||
|
IEnumerable<SymbolNode> vertexTraversalOrder;
|
||||||
|
if (vertexTraversalOrderFunc == null) vertexTraversalOrder = graph.OutAdjStructure[start_node];
|
||||||
|
else vertexTraversalOrder = vertexTraversalOrderFunc(graph, start_node);
|
||||||
|
foreach (SymbolNode current_node in vertexTraversalOrder)
|
||||||
|
{
|
||||||
|
if (OnProcessChild(graph, start_node, current_node))
|
||||||
|
dfs(current_node, OnEnter, OnProcessChild, OnLeave);
|
||||||
|
}
|
||||||
|
|
||||||
|
OnLeave(graph, start_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (graphTraversalOrder == null) graphTraversalOrder = graph.vertexes;
|
||||||
|
|
||||||
|
OnEnterGraph(graph);
|
||||||
|
foreach (SymbolNode v in graphTraversalOrder)
|
||||||
|
{
|
||||||
|
if (OnProcessVertex(graph, v))
|
||||||
|
dfs(v, OnEnter: OnEnterNode, OnProcessChild: OnProcessNodeChild, OnLeave: OnLeaveNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
OnLeaveGraph(graph);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class SynonymsGraph {
|
||||||
|
|
||||||
|
public enum Type { SAME_NAME, INDEXER}
|
||||||
|
|
||||||
|
public HashSet<int> left = new HashSet<int>();
|
||||||
|
public HashSet<int> right = new HashSet<int>();
|
||||||
|
|
||||||
|
public Type type;
|
||||||
|
|
||||||
|
public SynonymsGraph(Type type)
|
||||||
|
{
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
var res = "";
|
||||||
|
if (type == Type.INDEXER)
|
||||||
|
res += "Indexer";
|
||||||
|
else
|
||||||
|
res += "Same_Name";
|
||||||
|
res += "graph(left[";
|
||||||
|
foreach (var i in left) res += i.ToString() + ",";
|
||||||
|
res += "], right[";
|
||||||
|
foreach(var i in right) res += i.ToString() + ",";
|
||||||
|
res += "])";
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AssignGraph createAssignGraph(List<Symbol> left, List<Symbol> right)
|
||||||
|
{
|
||||||
|
if (right.Count < left.Count) throw new Exception("AAAA");
|
||||||
|
|
||||||
|
|
||||||
|
List<SymbolNode> v_left = new List<SymbolNode>();
|
||||||
|
List<SymbolNode> v_right = new List<SymbolNode>();
|
||||||
|
List<Symbol> left_visited = new List<Symbol>();
|
||||||
|
List<Edge> assign_first = new List<Edge>();
|
||||||
|
List<Edge> assign_last = new List<Edge>();
|
||||||
|
|
||||||
|
var moved_first = new List<Edge>();
|
||||||
|
var moved_last = new LinkedList<Edge>();
|
||||||
|
var movedAssigns = new HashSet<int>();
|
||||||
|
|
||||||
|
|
||||||
|
void moveAssign(int i, bool toFirst)
|
||||||
|
{
|
||||||
|
Edge assign = new Edge(new SymbolNode(right[i]), new SymbolNode(left[i]));
|
||||||
|
if (toFirst)
|
||||||
|
moved_first.Add(assign);
|
||||||
|
else
|
||||||
|
moved_last.AddFirst(assign);
|
||||||
|
movedAssigns.Add(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addTemp(int i, bool toFirst)
|
||||||
|
{
|
||||||
|
if(toFirst)
|
||||||
|
{
|
||||||
|
var temp_symbol = new TempSymbol();
|
||||||
|
assign_first.Add(new Edge(new SymbolNode(right[i]), new TempSymbolNode(temp_symbol)));
|
||||||
|
right[i] = temp_symbol;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var temp_s = new TempSymbol();
|
||||||
|
assign_last.Add(new Edge(new TempSymbolNode(temp_s), new SymbolNode(left[i])));
|
||||||
|
left[i] = temp_s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if repeated assigns or pointers -> 2n
|
||||||
|
for (int i = 0; i < left.Count(); i++)
|
||||||
|
{
|
||||||
|
if (left_visited.Find(it => it.StructurallyEquals(left[i])) != null
|
||||||
|
|| right[i].type == Symbol.Type.POINTER
|
||||||
|
|| left[i].type == Symbol.Type.POINTER)
|
||||||
|
{
|
||||||
|
var res = new AssignGraph();
|
||||||
|
res.assignFirst = make2n(left, right);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
left_visited.Add(left[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//handle expressions and var params
|
||||||
|
for (int i = 0; i < left.Count(); i++)
|
||||||
|
{
|
||||||
|
if (right[i].type == Symbol.Type.EXPR || right[i].type == Symbol.Type.VAR_PARAM)
|
||||||
|
{
|
||||||
|
|
||||||
|
addTemp(i, true);
|
||||||
|
}
|
||||||
|
if (left[i].type == Symbol.Type.VAR_PARAM)
|
||||||
|
{
|
||||||
|
addTemp(i, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = left.Count - 1; i > -1; i--)
|
||||||
|
{
|
||||||
|
//handle loops
|
||||||
|
if (left[i].StructurallyEquals(right[i]))
|
||||||
|
{
|
||||||
|
var f = new SymbolNode(right[i]);
|
||||||
|
var t = new SymbolNode(left[i]);
|
||||||
|
assign_first.Add(new Edge(f, t));
|
||||||
|
left.RemoveAt(i);
|
||||||
|
right.RemoveAt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var indexerGraph = new SynonymsGraph(SynonymsGraph.Type.INDEXER);
|
||||||
|
var nameToGraph = new Dictionary<string, SynonymsGraph>();
|
||||||
|
|
||||||
|
|
||||||
|
for (int i = 0; i < left.Count; i++)
|
||||||
|
{
|
||||||
|
if (left[i].type == Symbol.Type.INDEXER)
|
||||||
|
indexerGraph.left.Add(i);
|
||||||
|
else if (left[i].type == Symbol.Type.FROM_OUTER_SCOPE || left[i].type == Symbol.Type.DOT_NODE)
|
||||||
|
{
|
||||||
|
var name = left[i].last_name;
|
||||||
|
if (!nameToGraph.ContainsKey(name))
|
||||||
|
nameToGraph.Add(name, new SynonymsGraph(SynonymsGraph.Type.SAME_NAME));
|
||||||
|
nameToGraph[name].left.Add(i);
|
||||||
|
}
|
||||||
|
if (right[i].type == Symbol.Type.INDEXER)
|
||||||
|
indexerGraph.right.Add(i);
|
||||||
|
else if (right[i].type == Symbol.Type.FROM_OUTER_SCOPE || right[i].type == Symbol.Type.DOT_NODE)
|
||||||
|
{
|
||||||
|
var name = right[i].last_name;
|
||||||
|
if (!nameToGraph.ContainsKey(name))
|
||||||
|
nameToGraph.Add(name, new SynonymsGraph(SynonymsGraph.Type.SAME_NAME));
|
||||||
|
nameToGraph[name].right.Add(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var leftSet = new HashSet<Symbol>(left);
|
||||||
|
var rightSet = new HashSet<Symbol>(right);
|
||||||
|
var graphs = new List<SynonymsGraph>();
|
||||||
|
graphs.AddRange(nameToGraph.Values);
|
||||||
|
graphs.Add(indexerGraph);
|
||||||
|
|
||||||
|
//Handle const
|
||||||
|
for (int i = 0; i < left.Count; i++)
|
||||||
|
{
|
||||||
|
if (right[i].type == Symbol.Type.CONST_EXPR)
|
||||||
|
{
|
||||||
|
moveAssign(i, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void resolveGraph(SynonymsGraph sGraph)
|
||||||
|
{
|
||||||
|
|
||||||
|
foreach (var i in sGraph.left)
|
||||||
|
{
|
||||||
|
var type = right[i].type;
|
||||||
|
if (type == Symbol.Type.LOCAL)
|
||||||
|
{
|
||||||
|
if (!leftSet.Contains(right[i]))
|
||||||
|
moveAssign(i, false);
|
||||||
|
}
|
||||||
|
else if (type == Symbol.Type.FROM_OUTER_SCOPE)
|
||||||
|
{
|
||||||
|
if (!(leftSet.Contains(right[i]) || nameToGraph[right[i].last_name].left.Count() != 0))
|
||||||
|
moveAssign(i, false);
|
||||||
|
}
|
||||||
|
else if (type == Symbol.Type.DOT_NODE)
|
||||||
|
{
|
||||||
|
if (nameToGraph[right[i].last_name].left.Count() == 0)
|
||||||
|
moveAssign(i, false);
|
||||||
|
}
|
||||||
|
else if (type == Symbol.Type.INDEXER)
|
||||||
|
{
|
||||||
|
if (indexerGraph.left.Count() == 0)
|
||||||
|
moveAssign(i, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var i in sGraph.right)
|
||||||
|
{
|
||||||
|
var type = left[i].type;
|
||||||
|
if (type == Symbol.Type.LOCAL)
|
||||||
|
{
|
||||||
|
if (!right.Contains(left[i]))
|
||||||
|
moveAssign(i, true);
|
||||||
|
}
|
||||||
|
else if (type == Symbol.Type.FROM_OUTER_SCOPE)
|
||||||
|
{
|
||||||
|
if (!(rightSet.Contains(left[i]) || nameToGraph[left[i].last_name].right.Count() != 0))
|
||||||
|
moveAssign(i, true);
|
||||||
|
}
|
||||||
|
else if (type == Symbol.Type.DOT_NODE)
|
||||||
|
{
|
||||||
|
if (nameToGraph[left[i].last_name].right.Count() == 0)
|
||||||
|
moveAssign(i, true);
|
||||||
|
}
|
||||||
|
else if (type == Symbol.Type.INDEXER)
|
||||||
|
{
|
||||||
|
if (indexerGraph.right.Count() == 0)
|
||||||
|
moveAssign(i, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach(int i in movedAssigns)
|
||||||
|
{
|
||||||
|
sGraph.left.Remove(i);
|
||||||
|
sGraph.right.Remove(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
var l_size = sGraph.left.Count;
|
||||||
|
var r_size = sGraph.right.Count;
|
||||||
|
if (r_size == 0 || l_size == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Edge movedFromThisGraph = null;
|
||||||
|
if (l_size < r_size)
|
||||||
|
{
|
||||||
|
foreach (var i in sGraph.left)
|
||||||
|
{
|
||||||
|
if (sGraph.right.Contains(i))
|
||||||
|
{
|
||||||
|
if (movedFromThisGraph == null)
|
||||||
|
{
|
||||||
|
movedFromThisGraph = new Edge(new SymbolNode(right[i]), new SymbolNode(left[i]));
|
||||||
|
movedAssigns.Add(i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
addTemp(i, false);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
addTemp(i, false);
|
||||||
|
}
|
||||||
|
if (movedFromThisGraph != null)
|
||||||
|
moved_last.AddFirst(movedFromThisGraph);
|
||||||
|
sGraph.left.Clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var i in sGraph.right)
|
||||||
|
{
|
||||||
|
if (sGraph.left.Contains(i))
|
||||||
|
{
|
||||||
|
|
||||||
|
if (movedFromThisGraph == null)
|
||||||
|
{
|
||||||
|
movedFromThisGraph = new Edge(new SymbolNode(right[i]), new SymbolNode(left[i]));
|
||||||
|
movedAssigns.Add(i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
addTemp(i, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
addTemp(i, true);
|
||||||
|
|
||||||
|
}
|
||||||
|
if (movedFromThisGraph != null)
|
||||||
|
moved_first.Add(movedFromThisGraph);
|
||||||
|
sGraph.right.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var g in graphs)
|
||||||
|
resolveGraph(g);
|
||||||
|
|
||||||
|
for (int i = left.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (movedAssigns.Contains(i))
|
||||||
|
{
|
||||||
|
left.RemoveAt(i);
|
||||||
|
right.RemoveAt(i);
|
||||||
|
movedAssigns.Remove(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var symbols = new Dictionary<string, SymbolNode>();
|
||||||
|
|
||||||
|
foreach (Symbol sym in left)
|
||||||
|
{
|
||||||
|
if (!symbols.ContainsKey(sym.name)) symbols[sym.name] = new SymbolNode(sym);
|
||||||
|
v_left.Add(symbols[sym.name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Symbol sym in right)
|
||||||
|
{
|
||||||
|
if (!symbols.ContainsKey(sym.name)) symbols[sym.name] = new SymbolNode(sym);
|
||||||
|
v_right.Add(symbols[sym.name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Edge> assigns = new List<Edge>();
|
||||||
|
|
||||||
|
for (int i = 0; i < v_left.Count; i++) assigns.Add(new Edge(v_right[i], v_left[i], i));
|
||||||
|
|
||||||
|
|
||||||
|
assign_first.AddRange(moved_first);
|
||||||
|
foreach(var assign in assign_last)
|
||||||
|
moved_last.AddLast(assign);
|
||||||
|
|
||||||
|
assign_last = moved_last.ToList();
|
||||||
|
|
||||||
|
var graph = new AssignGraph(assigns);
|
||||||
|
graph.assignFirst = assign_first;
|
||||||
|
graph.assignLast = assign_last;
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static List<Edge> make2n(List<Symbol> left, List<Symbol> right)
|
||||||
|
{
|
||||||
|
var temps = new List<SymbolNode>();
|
||||||
|
var res = new List<Edge>();
|
||||||
|
|
||||||
|
for(int i = 0; i < right.Count; i++)
|
||||||
|
{
|
||||||
|
var to = new SymbolNode(new TempSymbol());
|
||||||
|
var from = new SymbolNode(right[i]);
|
||||||
|
temps.Add(to);
|
||||||
|
res.Add(new Edge(from, to));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (int i = 0; i < left.Count; i++)
|
||||||
|
{
|
||||||
|
var to = new SymbolNode(left[i]);
|
||||||
|
res.Add(new Edge(temps[i], to));
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AssignGraph createReversedGraph(this AssignGraph g)
|
||||||
|
{
|
||||||
|
List<Edge> newEdges = new List<Edge>();
|
||||||
|
foreach (var edge in g.edges)
|
||||||
|
{
|
||||||
|
newEdges.Add(new Edge(f: edge.to, t: edge.from));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AssignGraph(newEdges, g.vertexes.ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<List<SymbolNode>> findStronglyConnectedComponets(this AssignGraph g)
|
||||||
|
{
|
||||||
|
List<List<SymbolNode>> res = new List<List<SymbolNode>>();
|
||||||
|
|
||||||
|
Stack<SymbolNode> route = new Stack<SymbolNode>();
|
||||||
|
HashSet<SymbolNode> visited = new HashSet<SymbolNode>();
|
||||||
|
|
||||||
|
Action<AssignGraph> onEnterGraph = (_) =>
|
||||||
|
{
|
||||||
|
route.Clear();
|
||||||
|
visited.Clear();
|
||||||
|
};
|
||||||
|
|
||||||
|
Action<AssignGraph, SymbolNode> onEnterNode = (graph, node) => { visited.Add(node); };
|
||||||
|
|
||||||
|
Action<AssignGraph, SymbolNode> onLeaveNode = (graph, node) => { route.Push(node); };
|
||||||
|
|
||||||
|
Func<AssignGraph, SymbolNode, SymbolNode, bool> onProcessChildNode = (graph, parent, childNode) =>
|
||||||
|
{
|
||||||
|
if (!visited.Contains(childNode))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
Func<AssignGraph, SymbolNode, bool> onProcessVertex = (graph, vert) => { return !visited.Contains(vert); };
|
||||||
|
|
||||||
|
g.dfs(OnEnterGraph: onEnterGraph, OnProcessVertex: onProcessVertex,
|
||||||
|
OnEnterNode: onEnterNode, OnProcessNodeChild: onProcessChildNode,
|
||||||
|
OnLeaveNode: onLeaveNode,
|
||||||
|
OnLeaveGraph: (_) => { }
|
||||||
|
);
|
||||||
|
|
||||||
|
Action<AssignGraph> onEnterGraphReversed = (_) => { visited.Clear(); };
|
||||||
|
|
||||||
|
Action<AssignGraph, SymbolNode> onEnterNodeReversed = (graph, node) =>
|
||||||
|
{
|
||||||
|
visited.Add(node);
|
||||||
|
res.Last().Add(node);
|
||||||
|
};
|
||||||
|
|
||||||
|
Action<AssignGraph, SymbolNode> onLeaveNodeReversed = (graph, node) => { };
|
||||||
|
|
||||||
|
Func<AssignGraph, SymbolNode, SymbolNode, bool> onProcessChildNodeReversed = (graph, parent, childNode) =>
|
||||||
|
{
|
||||||
|
if (!visited.Contains(childNode))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
Func<AssignGraph, SymbolNode, bool> onProcessVertexReversed = (graph, vert) =>
|
||||||
|
{
|
||||||
|
if (visited.Contains(vert)) return false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res.Add(new List<SymbolNode>());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var graphTraversalOrder = route.ToList();
|
||||||
|
|
||||||
|
var g_rev = g.createReversedGraph();
|
||||||
|
|
||||||
|
g_rev.dfs(OnEnterGraph: onEnterGraphReversed, OnProcessVertex: onProcessVertexReversed,
|
||||||
|
OnEnterNode: onEnterNodeReversed, OnProcessNodeChild: onProcessChildNodeReversed,
|
||||||
|
OnLeaveNode: onLeaveNodeReversed,
|
||||||
|
OnLeaveGraph: (_) => { },
|
||||||
|
graphTraversalOrder: graphTraversalOrder);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Cycle> findAllUniqueElementaryCycles(this AssignGraph g)
|
||||||
|
{
|
||||||
|
var res = new List<Cycle>();
|
||||||
|
var components = g.findStronglyConnectedComponets();
|
||||||
|
foreach (var component in components)
|
||||||
|
{
|
||||||
|
if (component.Count() > 1) res.Add(new Cycle(component));
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogGraph(this AssignGraph graph)
|
||||||
|
{
|
||||||
|
foreach (var vert in graph.vertexes)
|
||||||
|
{
|
||||||
|
Console.Write("{0}->[", vert);
|
||||||
|
graph.OutAdjStructure[vert].ForEach(v => Console.Write("{0}, ", v));
|
||||||
|
Console.WriteLine("]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void drawGraph(this AssignGraph g)
|
||||||
|
{
|
||||||
|
var writer = File.CreateText("graph.dot");
|
||||||
|
writer.WriteLine("digraph _graph {");
|
||||||
|
|
||||||
|
Action<AssignGraph> enterGraph = (graph) => { graph.resetVertexesColor(); };
|
||||||
|
|
||||||
|
Func<AssignGraph, SymbolNode, bool> ProcessNode = (graph, node) => node.color != SymbolNode.Color.GREY;
|
||||||
|
|
||||||
|
Action<AssignGraph, SymbolNode> EnterNode = (graph, vert) => { vert.color = SymbolNode.Color.GREY; };
|
||||||
|
|
||||||
|
Func<AssignGraph, SymbolNode, SymbolNode, bool> ProcessNodeChild = (graph, parent, child) =>
|
||||||
|
{
|
||||||
|
writer.WriteLine(parent.label + "->" + child.label);
|
||||||
|
return child.color == SymbolNode.Color.WHITE;
|
||||||
|
};
|
||||||
|
|
||||||
|
g.dfs(OnEnterGraph: enterGraph, OnEnterNode: EnterNode, OnProcessNodeChild: ProcessNodeChild,
|
||||||
|
OnProcessVertex: ProcessNode, OnLeaveGraph: (graph) => { graph.resetVertexesColor(); }, OnLeaveNode: (graph, vertex) => { });
|
||||||
|
writer.WriteLine("}");
|
||||||
|
writer.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,133 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using PascalABCCompiler.SyntaxTree;
|
||||||
|
|
||||||
|
namespace AssignTupleDesugarAlgorithm
|
||||||
|
{
|
||||||
|
public class Symbol
|
||||||
|
{
|
||||||
|
public enum Type
|
||||||
|
{
|
||||||
|
VAR_PARAM, FROM_OUTER_SCOPE, INDEXER, DOT_NODE, LOCAL, EXPR, POINTER, CONST_EXPR
|
||||||
|
}
|
||||||
|
public string name;
|
||||||
|
public string last_name;
|
||||||
|
|
||||||
|
//public bool canBeSynonym = false;
|
||||||
|
//public bool isIndexer = false;
|
||||||
|
//public bool isExpr = false;
|
||||||
|
public expression node;
|
||||||
|
public Type type;
|
||||||
|
|
||||||
|
public Symbol(expression ex, BindCollectLightSymInfo binder)
|
||||||
|
{
|
||||||
|
node = ex;
|
||||||
|
if (node is indexer ind)
|
||||||
|
{
|
||||||
|
name = ind.ToString();
|
||||||
|
last_name = name;
|
||||||
|
type = Type.INDEXER;
|
||||||
|
}
|
||||||
|
else if (node is dot_node dn)
|
||||||
|
{
|
||||||
|
var last = dn.right;
|
||||||
|
while (last is dot_node dn1)
|
||||||
|
last = dn1.right;
|
||||||
|
|
||||||
|
name = node.ToString();
|
||||||
|
last_name = last.ToString();
|
||||||
|
type = Type.DOT_NODE;
|
||||||
|
if (last is indexer)
|
||||||
|
type = Type.INDEXER;
|
||||||
|
}
|
||||||
|
else if (node is ident id)
|
||||||
|
{
|
||||||
|
name = id.name;
|
||||||
|
last_name = name;
|
||||||
|
if (binder != null)
|
||||||
|
{
|
||||||
|
var info = binder.bind(id);
|
||||||
|
if (isVarParam(info))
|
||||||
|
{
|
||||||
|
type = Type.VAR_PARAM;
|
||||||
|
}
|
||||||
|
else if (isFromOuterScope(info))
|
||||||
|
{
|
||||||
|
type = Type.FROM_OUTER_SCOPE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = Type.LOCAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (node is get_address || node is roof_dereference)
|
||||||
|
{
|
||||||
|
type = Type.POINTER;
|
||||||
|
}
|
||||||
|
else if(node is const_node)
|
||||||
|
{
|
||||||
|
type = Type.CONST_EXPR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = Type.EXPR;
|
||||||
|
name = node.ToString();
|
||||||
|
last_name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool StructurallyEquals(Symbol sym) => node.ToString() == sym.node.ToString();
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (obj is null) return false;
|
||||||
|
if (obj.GetType() != GetType()) return false;
|
||||||
|
return name == (obj as Symbol).name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return 363513814 + EqualityComparer<string>.Default.GetHashCode(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool isFromOuterScope(BindResult bindRes)
|
||||||
|
{
|
||||||
|
var symbol = bindRes.symInfo;
|
||||||
|
|
||||||
|
if (symbol == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (symbol.SK == SymKind.var && symbol.Attr.HasFlag(SymbolAttributes.varparam_attr))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (bindRes.path[bindRes.path.Count - 1] is GlobalScopeSyntax)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (var i = 0; i < bindRes.path.Count - 1; i++)
|
||||||
|
if (bindRes.path[i] is NamedScopeSyntax)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isVarParam(BindResult res)
|
||||||
|
{
|
||||||
|
if (res == null)
|
||||||
|
return true;
|
||||||
|
return res.symInfo.Attr.HasFlag(SymbolAttributes.varparam_attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TempSymbol : Symbol
|
||||||
|
{
|
||||||
|
private static int counter = 0;
|
||||||
|
private static string getTempPrefix => "<tup_opt>" + counter++;
|
||||||
|
public TempSymbol() : base(new ident(getTempPrefix), null)
|
||||||
|
{
|
||||||
|
type = Type.LOCAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AssignTupleDesugarAlgorithm
|
||||||
|
{
|
||||||
|
|
||||||
|
internal class SymbolNode : IEquatable<SymbolNode>
|
||||||
|
{
|
||||||
|
public readonly string label;
|
||||||
|
public int? number = null;
|
||||||
|
public readonly Symbol symbol;
|
||||||
|
|
||||||
|
public SymbolNode(Symbol s)
|
||||||
|
{
|
||||||
|
symbol = s;
|
||||||
|
label = s.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Color
|
||||||
|
{
|
||||||
|
WHITE,
|
||||||
|
GREY,
|
||||||
|
BLACK
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color color = Color.WHITE;
|
||||||
|
public void resetColor() => color = Color.WHITE;
|
||||||
|
|
||||||
|
public bool Equals(SymbolNode other)
|
||||||
|
{
|
||||||
|
if (other is null) return false;
|
||||||
|
|
||||||
|
return label == other.label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return label.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object other)
|
||||||
|
{
|
||||||
|
if (GetType() != other.GetType()) return false;
|
||||||
|
return Equals((SymbolNode)other);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
string n = "";
|
||||||
|
if (number != null)
|
||||||
|
{
|
||||||
|
n = "(" + number.ToString() + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
return label + n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class TempSymbolNode : SymbolNode
|
||||||
|
{
|
||||||
|
public TempSymbolNode(TempSymbol s) : base(s)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -14,11 +14,14 @@ namespace SyntaxVisitors.SugarVisitors
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TupleVisitor : BaseChangeVisitor
|
public class TupleVisitor : BaseChangeVisitor
|
||||||
{
|
{
|
||||||
public static TupleVisitor New
|
public bool optimize_tuple_assign;
|
||||||
|
|
||||||
|
public TupleVisitor(bool optimize_tup_opt)
|
||||||
{
|
{
|
||||||
get { return new TupleVisitor(); }
|
optimize_tuple_assign = optimize_tup_opt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TupleVisitor Create(bool optimize_tup_opt) => new TupleVisitor(optimize_tup_opt);
|
||||||
private int num = 0;
|
private int num = 0;
|
||||||
public string UniqueName()
|
public string UniqueName()
|
||||||
{
|
{
|
||||||
|
|
@ -59,7 +62,9 @@ namespace SyntaxVisitors.SugarVisitors
|
||||||
// Остальное раскрывается в AssignTuplesDesugarVisitor
|
// Остальное раскрывается в AssignTuplesDesugarVisitor
|
||||||
public override void visit(assign_var_tuple assvartup)
|
public override void visit(assign_var_tuple assvartup)
|
||||||
{
|
{
|
||||||
if (assvartup.expr is tuple_node tn && tn.el.expressions.All(ex => ex is const_node) && !tn.el.expressions.Any(ex => ex is nil_const))
|
if (assvartup.expr is tuple_node tn)
|
||||||
|
{
|
||||||
|
if (tn.el.expressions.All(ex => ex is const_node) && !tn.el.expressions.Any(ex => ex is nil_const))
|
||||||
{
|
{
|
||||||
var n = assvartup.idents.idents.Count();
|
var n = assvartup.idents.idents.Count();
|
||||||
if (n > tn.el.Count)
|
if (n > tn.el.Count)
|
||||||
|
|
@ -77,15 +82,23 @@ namespace SyntaxVisitors.SugarVisitors
|
||||||
}
|
}
|
||||||
ReplaceStatementUsingParent(assvartup, sl);
|
ReplaceStatementUsingParent(assvartup, sl);
|
||||||
}
|
}
|
||||||
|
else if (optimize_tuple_assign)
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
DefaultVisit(assvartup);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DefaultVisit(assvartup);
|
DefaultVisit(assvartup);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void visit(assign_tuple asstup)
|
public override void visit(assign_tuple asstup)
|
||||||
{
|
{
|
||||||
if (asstup.expr is tuple_node tn && tn.el.expressions.All(ex => ex is const_node) && !tn.el.expressions.Any(ex => ex is nil_const))
|
if (asstup.expr is tuple_node tn)
|
||||||
|
{
|
||||||
|
if (tn.el.expressions.All(ex => ex is const_node) && !tn.el.expressions.Any(ex => ex is nil_const))
|
||||||
{
|
{
|
||||||
var n = asstup.vars.variables.Count();
|
var n = asstup.vars.variables.Count();
|
||||||
if (n > tn.el.Count)
|
if (n > tn.el.Count)
|
||||||
|
|
@ -103,18 +116,20 @@ namespace SyntaxVisitors.SugarVisitors
|
||||||
}
|
}
|
||||||
ReplaceStatementUsingParent(asstup, sl);
|
ReplaceStatementUsingParent(asstup, sl);
|
||||||
}
|
}
|
||||||
else if (asstup.expr is tuple_node tn1 && !tn1.el.expressions.Any(ex => ex is nil_const))
|
else if (optimize_tuple_assign)
|
||||||
|
return;
|
||||||
|
else if (!tn.el.expressions.Any(ex => ex is nil_const))
|
||||||
{
|
{
|
||||||
var n = asstup.vars.variables.Count();
|
var n = asstup.vars.variables.Count();
|
||||||
if (n > tn1.el.Count)
|
if (n > tn.el.Count)
|
||||||
throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", asstup.vars.variables[0]);
|
throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", asstup.vars.variables[0]);
|
||||||
|
|
||||||
var sl = new List<statement>();
|
var sl = new List<statement>();
|
||||||
for (var i = 0; i < n; i++)
|
for (var i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
var temp_id = new ident(UniqueName(), tn1.el.expressions[i].source_context);
|
var temp_id = new ident(UniqueName(), tn.el.expressions[i].source_context);
|
||||||
var var_def = new var_def_statement(temp_id, tn1.el.expressions[i], tn1.el.expressions[i].source_context);
|
var var_def = new var_def_statement(temp_id, tn.el.expressions[i], tn.el.expressions[i].source_context);
|
||||||
var a = new var_statement(var_def, tn1.el.expressions[i].source_context);
|
var a = new var_statement(var_def, tn.el.expressions[i].source_context);
|
||||||
sl.Add(a);
|
sl.Add(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,10 +145,14 @@ namespace SyntaxVisitors.SugarVisitors
|
||||||
|
|
||||||
ReplaceStatementUsingParent(asstup, sl);
|
ReplaceStatementUsingParent(asstup, sl);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
DefaultVisit(asstup);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DefaultVisit(asstup);
|
DefaultVisit(asstup);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReplaceVarTupleDefStatementUsingParent(var_tuple_def_statement from, IEnumerable<var_def_statement> to)
|
public void ReplaceVarTupleDefStatementUsingParent(var_tuple_def_statement from, IEnumerable<var_def_statement> to)
|
||||||
|
|
@ -150,7 +169,8 @@ namespace SyntaxVisitors.SugarVisitors
|
||||||
// А это по идее до begin - там немного другие узлы и внешний контекст
|
// А это по идее до begin - там немного другие узлы и внешний контекст
|
||||||
public override void visit(var_tuple_def_statement vtd)
|
public override void visit(var_tuple_def_statement vtd)
|
||||||
{
|
{
|
||||||
if (vtd.inital_value is tuple_node tn && tn.el.expressions.All(ex => ex is const_node) && !tn.el.expressions.Any(ex => ex is nil_const))
|
if (vtd.inital_value is tuple_node tn) {
|
||||||
|
if (tn.el.expressions.All(ex => ex is const_node) && !tn.el.expressions.Any(ex => ex is nil_const))
|
||||||
{
|
{
|
||||||
var n = vtd.vars.idents.Count();
|
var n = vtd.vars.idents.Count();
|
||||||
if (n > tn.el.Count)
|
if (n > tn.el.Count)
|
||||||
|
|
@ -167,10 +187,16 @@ namespace SyntaxVisitors.SugarVisitors
|
||||||
ReplaceVarTupleDefStatementUsingParent(vtd, vd);
|
ReplaceVarTupleDefStatementUsingParent(vtd, vd);
|
||||||
visit(vtd.inital_value);
|
visit(vtd.inital_value);
|
||||||
}
|
}
|
||||||
|
else if (optimize_tuple_assign)
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
DefaultVisit(vtd);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DefaultVisit(vtd);
|
DefaultVisit(vtd);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void visit(tuple_node tup)
|
public override void visit(tuple_node tup)
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,14 @@
|
||||||
<Compile Include="LightSymInfoVisitors\CollectLightSymInfoVisitor.cs" />
|
<Compile Include="LightSymInfoVisitors\CollectLightSymInfoVisitor.cs" />
|
||||||
<Compile Include="LightSymInfoVisitors\LightScopeCreator.cs" />
|
<Compile Include="LightSymInfoVisitors\LightScopeCreator.cs" />
|
||||||
<Compile Include="LightSymInfoVisitors\LightScopeHelperClasses.cs" />
|
<Compile Include="LightSymInfoVisitors\LightScopeHelperClasses.cs" />
|
||||||
|
<Compile Include="SugarVisitors\AssignTuplesDesugarVisitor\desugarAlgoritm\Assign.cs" />
|
||||||
|
<Compile Include="SugarVisitors\AssignTuplesDesugarVisitor\desugarAlgoritm\AssignGraph.cs" />
|
||||||
|
<Compile Include="SugarVisitors\AssignTuplesDesugarVisitor\desugarAlgoritm\Cycle.cs" />
|
||||||
|
<Compile Include="SugarVisitors\AssignTuplesDesugarVisitor\desugarAlgoritm\Edge.cs" />
|
||||||
|
<Compile Include="SugarVisitors\AssignTuplesDesugarVisitor\desugarAlgoritm\GraphUtils.cs" />
|
||||||
|
<Compile Include="SugarVisitors\AssignTuplesDesugarVisitor\desugarAlgoritm\Symbol.cs" />
|
||||||
|
<Compile Include="SugarVisitors\AssignTuplesDesugarVisitor\desugarAlgoritm\SymbolNode.cs" />
|
||||||
|
<Compile Include="SugarVisitors\AssignTuplesDesugarVisitor\NewAssignTuplesDesugarVisitor.cs" />
|
||||||
<Compile Include="SugarVisitors\CacheFunctionVisitor.cs" />
|
<Compile Include="SugarVisitors\CacheFunctionVisitor.cs" />
|
||||||
<Compile Include="SugarVisitors\LetExprVisitor.cs" />
|
<Compile Include="SugarVisitors\LetExprVisitor.cs" />
|
||||||
<Compile Include="SugarVisitors\TestAssignIsDefVisitor.cs" />
|
<Compile Include="SugarVisitors\TestAssignIsDefVisitor.cs" />
|
||||||
|
|
@ -65,7 +73,7 @@
|
||||||
<Compile Include="PatternsVisitors\PatternsDesugaringVisitor.cs" />
|
<Compile Include="PatternsVisitors\PatternsDesugaringVisitor.cs" />
|
||||||
<Compile Include="PatternsVisitors\ReplaceNamesInIsVarVisitor.cs" />
|
<Compile Include="PatternsVisitors\ReplaceNamesInIsVarVisitor.cs" />
|
||||||
<Compile Include="PatternsVisitors\SingleDeconstructChecker.cs" />
|
<Compile Include="PatternsVisitors\SingleDeconstructChecker.cs" />
|
||||||
<Compile Include="SugarVisitors\AssignTuplesDesugarVisitor.cs" />
|
<Compile Include="SugarVisitors\AssignTuplesDesugarVisitor\AssignTuplesDesugarVisitor.cs" />
|
||||||
<Compile Include="SugarVisitors\DoubleQuestionDesugarVisitor.cs" />
|
<Compile Include="SugarVisitors\DoubleQuestionDesugarVisitor.cs" />
|
||||||
<Compile Include="SugarVisitors\IndexVisitor.cs" />
|
<Compile Include="SugarVisitors\IndexVisitor.cs" />
|
||||||
<Compile Include="SugarVisitors\LoopDesugarVisitor.cs" />
|
<Compile Include="SugarVisitors\LoopDesugarVisitor.cs" />
|
||||||
|
|
|
||||||
|
|
@ -113,13 +113,16 @@ namespace SyntaxVisitors
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var newNameCache = new Dictionary<string, string>();
|
||||||
|
|
||||||
var newLocalNames = var_def.vars.idents.Select(id =>
|
var newLocalNames = var_def.vars.idents.Select(id =>
|
||||||
{
|
{
|
||||||
var low = id.name.ToLower();
|
var low = id.name.ToLower();
|
||||||
|
|
||||||
var newName = this.CreateNewVariableName(low);
|
var newName = this.CreateNewVariableName(low);
|
||||||
//BlockNamesStack[CurrentLevel].Add(low, newName);
|
//BlockNamesStack[CurrentLevel].Add(low, newName);
|
||||||
BlockNamesStack[CurrentLevel][low] = newName;
|
//BlockNamesStack[CurrentLevel][low] = newName;
|
||||||
|
newNameCache[low] = newName;
|
||||||
return new ident(newName, id.source_context);
|
return new ident(newName, id.source_context);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -130,6 +133,8 @@ namespace SyntaxVisitors
|
||||||
Replace(var_def, newVS);
|
Replace(var_def, newVS);
|
||||||
listNodes[listNodes.Count - 1] = newVS; //SSM 8.11.18
|
listNodes[listNodes.Count - 1] = newVS; //SSM 8.11.18
|
||||||
ProcessNode(newVS.inital_value); // SSM 10.06.2020 #2103
|
ProcessNode(newVS.inital_value); // SSM 10.06.2020 #2103
|
||||||
|
foreach (var key in newNameCache.Keys)
|
||||||
|
BlockNamesStack[CurrentLevel][key] = newNameCache[key];
|
||||||
//base.visit(newVS); // SSM 10.06.2020 - зачем обходить всё?
|
//base.visit(newVS); // SSM 10.06.2020 - зачем обходить всё?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ unit ABCObjects;
|
||||||
//{$apptype windows}
|
//{$apptype windows}
|
||||||
{$reference '%GAC%\System.Windows.Forms.dll'}
|
{$reference '%GAC%\System.Windows.Forms.dll'}
|
||||||
{$reference '%GAC%\System.Drawing.dll'}
|
{$reference '%GAC%\System.Drawing.dll'}
|
||||||
{$gendoc true}
|
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
unit CRT;
|
unit CRT;
|
||||||
|
|
||||||
{$apptype console}
|
{$apptype console}
|
||||||
{$gendoc true}
|
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ unit GraphABC;
|
||||||
{$apptype windows}
|
{$apptype windows}
|
||||||
{$reference '%GAC%\System.Windows.Forms.dll'}
|
{$reference '%GAC%\System.Windows.Forms.dll'}
|
||||||
{$reference '%GAC%\System.Drawing.dll'}
|
{$reference '%GAC%\System.Drawing.dll'}
|
||||||
{$gendoc true}
|
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,6 @@ unit PABCSystem;
|
||||||
|
|
||||||
{$zerobasedstrings off}
|
{$zerobasedstrings off}
|
||||||
|
|
||||||
{$gendoc true}
|
|
||||||
|
|
||||||
// Default Application type
|
// Default Application type
|
||||||
{$apptype console}
|
{$apptype console}
|
||||||
|
|
||||||
|
|
@ -1432,24 +1430,26 @@ function ParamStr(i: integer): string;
|
||||||
/// Возвращает текущий каталог
|
/// Возвращает текущий каталог
|
||||||
function GetDir: string;
|
function GetDir: string;
|
||||||
/// Меняет текущий каталог
|
/// Меняет текущий каталог
|
||||||
procedure ChDir(s: string);
|
procedure ChDir(dirName: string);
|
||||||
/// Создает каталог
|
/// Создает каталог
|
||||||
procedure MkDir(s: string);
|
procedure MkDir(dirName: string);
|
||||||
/// Удаляет каталог
|
/// Удаляет каталог
|
||||||
procedure RmDir(s: string);
|
procedure RmDir(dirName: string);
|
||||||
|
|
||||||
/// Создает каталог. Возвращает True, если каталог успешно создан
|
/// Создает каталог. Возвращает True, если каталог успешно создан
|
||||||
function CreateDir(s: string): boolean;
|
function CreateDir(dirName: string): boolean;
|
||||||
/// Удаляет файл. Если файл не может быть удален, то возвращает False
|
/// Удаляет файл. Если файл не может быть удален, то возвращает False
|
||||||
function DeleteFile(fname: string): boolean;
|
function DeleteFile(fileName: string): boolean;
|
||||||
/// Возвращает текущий каталог
|
/// Возвращает текущий каталог
|
||||||
function GetCurrentDir: string;
|
function GetCurrentDir: string;
|
||||||
/// Удаляет каталог. Возвращает True, если каталог успешно удален
|
/// Удаляет каталог. Возвращает True, если каталог успешно удален
|
||||||
function RemoveDir(s: string): boolean;
|
function RemoveDir(dirName: string): boolean;
|
||||||
/// Переименовывает файл fileName, давая ему новое имя newfileName. Возвращает True, если файл успешно переименован
|
/// Переименовывает файл fileName, давая ему новое имя newfileName. Возвращает True, если файл успешно переименован
|
||||||
function RenameFile(fileName, newfileName: string): boolean;
|
function RenameFile(fileName, newfileName: string): boolean;
|
||||||
|
/// Переименовывает каталог dirName, давая ему новое имя newDirName. Возвращает True, если каталог успешно переименован
|
||||||
|
function RenameDirectory(dirName, newDirName: string): boolean;
|
||||||
/// Устанавливает текущий каталог. Возвращает True, если каталог успешно удален
|
/// Устанавливает текущий каталог. Возвращает True, если каталог успешно удален
|
||||||
function SetCurrentDir(s: string): boolean;
|
function SetCurrentDir(dirName: string): boolean;
|
||||||
|
|
||||||
/// Изменяет расширение файла с именем fileName на newExt
|
/// Изменяет расширение файла с именем fileName на newExt
|
||||||
function ChangeFileNameExtension(fileName, newExt: string): string;
|
function ChangeFileNameExtension(fileName, newExt: string): string;
|
||||||
|
|
@ -1464,9 +1464,9 @@ procedure Assert(cond: boolean; sourceFile: string := ''; line: integer := 0);
|
||||||
procedure Assert(cond: boolean; message: string; sourceFile: string := ''; line: integer := 0);
|
procedure Assert(cond: boolean; message: string; sourceFile: string := ''; line: integer := 0);
|
||||||
|
|
||||||
/// Возвращает свободное место в байтах на диске с именем diskname
|
/// Возвращает свободное место в байтах на диске с именем diskname
|
||||||
function DiskFree(diskname: string): int64;
|
function DiskFree(diskName: string): int64;
|
||||||
/// Возвращает размер в байтах на диске с именем diskname
|
/// Возвращает размер в байтах на диске с именем diskname
|
||||||
function DiskSize(diskname: string): int64;
|
function DiskSize(diskName: string): int64;
|
||||||
/// Возвращает свободное место в байтах на диске disk. disk=0 - текущий диск, disk=1 - диск A: , disk=2 - диск B: и т.д.
|
/// Возвращает свободное место в байтах на диске disk. disk=0 - текущий диск, disk=1 - диск A: , disk=2 - диск B: и т.д.
|
||||||
function DiskFree(disk: integer): int64;
|
function DiskFree(disk: integer): int64;
|
||||||
/// Возвращает размер в байтах на диске disk. disk=0 - текущий диск, disk=1 - диск A: , disk=2 - диск B: и т.д.
|
/// Возвращает размер в байтах на диске disk. disk=0 - текущий диск, disk=1 - диск A: , disk=2 - диск B: и т.д.
|
||||||
|
|
@ -8461,41 +8461,41 @@ begin
|
||||||
Result := Environment.CurrentDirectory;
|
Result := Environment.CurrentDirectory;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure ChDir(s: string);
|
procedure ChDir(dirName: string);
|
||||||
begin
|
begin
|
||||||
Environment.CurrentDirectory := s;
|
Environment.CurrentDirectory := dirName;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure MkDir(s: string);
|
procedure MkDir(dirName: string);
|
||||||
begin
|
begin
|
||||||
Directory.CreateDirectory(s);
|
Directory.CreateDirectory(dirName);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure RmDir(s: string);
|
procedure RmDir(dirName: string);
|
||||||
begin
|
begin
|
||||||
Directory.Delete(s);
|
Directory.Delete(dirName);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function CreateDir(s: string): boolean;
|
function CreateDir(dirName: string): boolean;
|
||||||
begin
|
begin
|
||||||
try
|
try
|
||||||
Result := True;
|
Result := True;
|
||||||
Directory.CreateDirectory(s);
|
Directory.CreateDirectory(dirName);
|
||||||
except
|
except
|
||||||
Result := False;
|
Result := False;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function DeleteFile(fname: string): boolean;
|
function DeleteFile(fileName: string): boolean;
|
||||||
begin
|
begin
|
||||||
if not &File.Exists(fname) then
|
if not &File.Exists(fileName) then
|
||||||
begin
|
begin
|
||||||
Result := False;
|
Result := False;
|
||||||
exit
|
exit
|
||||||
end;
|
end;
|
||||||
try
|
try
|
||||||
Result := True;
|
Result := True;
|
||||||
&File.Delete(fname);
|
&File.Delete(fileName);
|
||||||
except
|
except
|
||||||
Result := False;
|
Result := False;
|
||||||
end;
|
end;
|
||||||
|
|
@ -8506,11 +8506,11 @@ begin
|
||||||
Result := Environment.CurrentDirectory;
|
Result := Environment.CurrentDirectory;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function RemoveDir(s: string): boolean;
|
function RemoveDir(dirName: string): boolean;
|
||||||
begin
|
begin
|
||||||
try
|
try
|
||||||
Result := True;
|
Result := True;
|
||||||
Directory.Delete(s);
|
Directory.Delete(dirName);
|
||||||
except
|
except
|
||||||
Result := False;
|
Result := False;
|
||||||
end;
|
end;
|
||||||
|
|
@ -8526,11 +8526,21 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function SetCurrentDir(s: string): boolean;
|
function RenameDirectory(dirName, newDirName: string): boolean;
|
||||||
begin
|
begin
|
||||||
try
|
try
|
||||||
Result := True;
|
Result := True;
|
||||||
Environment.CurrentDirectory := s;
|
Directory.Move(dirName, newDirName);
|
||||||
|
except
|
||||||
|
Result := False;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function SetCurrentDir(dirName: string): boolean;
|
||||||
|
begin
|
||||||
|
try
|
||||||
|
Result := True;
|
||||||
|
Environment.CurrentDirectory := dirName;
|
||||||
except
|
except
|
||||||
Result := False;
|
Result := False;
|
||||||
end;
|
end;
|
||||||
|
|
@ -8598,7 +8608,7 @@ begin
|
||||||
System.Diagnostics.Contracts.Contract.Assert(cond,'Файл '+sourceFile+', строка '+line.ToString() + ': ' + message)
|
System.Diagnostics.Contracts.Contract.Assert(cond,'Файл '+sourceFile+', строка '+line.ToString() + ': ' + message)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function DiskFree(diskname: string): int64;
|
function DiskFree(diskName: string): int64;
|
||||||
begin
|
begin
|
||||||
try
|
try
|
||||||
var d := new System.IO.DriveInfo(diskname);
|
var d := new System.IO.DriveInfo(diskname);
|
||||||
|
|
@ -8608,7 +8618,7 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function DiskSize(diskname: string): int64;
|
function DiskSize(diskName: string): int64;
|
||||||
begin
|
begin
|
||||||
try
|
try
|
||||||
var d := new System.IO.DriveInfo(diskname);
|
var d := new System.IO.DriveInfo(diskname);
|
||||||
|
|
@ -13745,6 +13755,23 @@ begin
|
||||||
Result := Self.Split(delims.ToCharArray, System.StringSplitOptions.RemoveEmptyEntries);
|
Result := Self.Split(delims.ToCharArray, System.StringSplitOptions.RemoveEmptyEntries);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
/// Преобразует многострочную строку в массив строк
|
||||||
|
function ToLines(Self: string): array of string; extensionmethod;
|
||||||
|
begin
|
||||||
|
Result := Self.Split(|
|
||||||
|
#13#10, // CR+LF: Win
|
||||||
|
#10, // LF: Linux
|
||||||
|
#13 // CR: Mac
|
||||||
|
// https://en.m.wikipedia.org/wiki/Newline#Unicode
|
||||||
|
// But standard .Net things like System.IO.StringReader don't support these, so for now - commented out
|
||||||
|
// #11, // Vertical Tab
|
||||||
|
// #12, // Form feed
|
||||||
|
// char($85), // Next Line
|
||||||
|
// char($2028), // Line Separator
|
||||||
|
// char($2029), // Paragraph SeparatorS
|
||||||
|
|, System.StringSplitOptions.None);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure PassSpaces(var s: string; var from: integer);
|
procedure PassSpaces(var s: string; var from: integer);
|
||||||
begin
|
begin
|
||||||
while (from <= s.Length) and char.IsWhiteSpace(s[from]) do
|
while (from <= s.Length) and char.IsWhiteSpace(s[from]) do
|
||||||
|
|
|
||||||
8
TestSuite/errors/err0538.pas
Normal file
8
TestSuite/errors/err0538.pas
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
//!Повторно объявленный идентификатор name
|
||||||
|
type
|
||||||
|
name = (name);
|
||||||
|
|
||||||
|
begin
|
||||||
|
// Ожидался тип
|
||||||
|
var v1: name;
|
||||||
|
end.
|
||||||
11
TestSuite/errors/err0539.pas
Normal file
11
TestSuite/errors/err0539.pas
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
//!Количество полей не совпадает с количеством полей в записи
|
||||||
|
type
|
||||||
|
r1 = record
|
||||||
|
a: byte;
|
||||||
|
static b: word;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
// Работает, но не должно
|
||||||
|
var a: r1 := (a: 1; b: 2);
|
||||||
|
end.
|
||||||
11
TestSuite/recinit3.pas
Normal file
11
TestSuite/recinit3.pas
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
type
|
||||||
|
r1 = record
|
||||||
|
a: byte;
|
||||||
|
static b: word;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
//Ошибка: Количество полей не совпадает с количеством полей в записи
|
||||||
|
var a: r1 := (a: 1);
|
||||||
|
assert(a.a = 1);
|
||||||
|
end.
|
||||||
10
TestSuite/units/u_events6.pas
Normal file
10
TestSuite/units/u_events6.pas
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
unit u_events6;
|
||||||
|
|
||||||
|
uses System;
|
||||||
|
|
||||||
|
type
|
||||||
|
I1 = interface
|
||||||
|
event E1: Action;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
20
TestSuite/usesunits/use_events6.pas
Normal file
20
TestSuite/usesunits/use_events6.pas
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
uses u_events6, System;
|
||||||
|
|
||||||
|
type TClass = class(I1)
|
||||||
|
event E1: Action;
|
||||||
|
|
||||||
|
procedure RaiseMethod;
|
||||||
|
begin
|
||||||
|
if E1 <> nil then
|
||||||
|
E1();
|
||||||
|
end;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
var i := 0;
|
||||||
|
var o := new TClass;
|
||||||
|
o.E1 += () -> begin Inc(i) end;
|
||||||
|
o.RaiseMethod();
|
||||||
|
assert(i = 1);
|
||||||
|
end.
|
||||||
29
TestSuite/yield8.pas
Normal file
29
TestSuite/yield8.pas
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
function V(n: byte) := 1;
|
||||||
|
|
||||||
|
function f1: sequence of integer;
|
||||||
|
begin
|
||||||
|
//Ошибка: Ожидалось имя процедуры или функции
|
||||||
|
var v := V(0);
|
||||||
|
// Если закомментировать эту строчку - предыдущая строчка работает
|
||||||
|
yield v;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function f2: sequence of integer;
|
||||||
|
begin
|
||||||
|
//Ошибка: Ожидалось имя процедуры или функции
|
||||||
|
var v := V(0);
|
||||||
|
var w := v + 1;
|
||||||
|
// Если закомментировать эту строчку - предыдущая строчка работает
|
||||||
|
yield w;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
var i := 0;
|
||||||
|
foreach var j in f1 do
|
||||||
|
i := j;
|
||||||
|
assert(i = 1);
|
||||||
|
|
||||||
|
foreach var j in f2 do
|
||||||
|
i := j;
|
||||||
|
assert(i = 2);
|
||||||
|
end.
|
||||||
|
|
@ -12211,6 +12211,8 @@ namespace PascalABCCompiler.TreeConverter
|
||||||
context.check_name_free(name, loc);
|
context.check_name_free(name, loc);
|
||||||
is_direct_type_decl = true;
|
is_direct_type_decl = true;
|
||||||
type_node tn = convert_strong(_type_declaration.type_def);
|
type_node tn = convert_strong(_type_declaration.type_def);
|
||||||
|
if (_type_declaration.type_def is enum_type_definition)
|
||||||
|
context.check_name_free(name, loc);
|
||||||
assign_doc_info(tn,_type_declaration);
|
assign_doc_info(tn,_type_declaration);
|
||||||
is_direct_type_decl = false;
|
is_direct_type_decl = false;
|
||||||
if (_type_declaration.type_def is SyntaxTree.named_type_reference||
|
if (_type_declaration.type_def is SyntaxTree.named_type_reference||
|
||||||
|
|
@ -15595,13 +15597,14 @@ namespace PascalABCCompiler.TreeConverter
|
||||||
private record_initializer ConvertRecordInitializer(common_type_node ctn, record_initializer constant)
|
private record_initializer ConvertRecordInitializer(common_type_node ctn, record_initializer constant)
|
||||||
{
|
{
|
||||||
location loc = constant.location;
|
location loc = constant.location;
|
||||||
|
var non_static_fields = ctn.fields.Where(x => !x.IsStatic).ToArray();
|
||||||
if (!ctn.is_value_type)
|
if (!ctn.is_value_type)
|
||||||
AddError(loc, "RECORD_CONST_NOT_ALLOWED_{0}", ctn.name);
|
AddError(loc, "RECORD_CONST_NOT_ALLOWED_{0}", ctn.name);
|
||||||
if (ctn.fields.Count != constant.record_const_definition_list.Count)
|
if (non_static_fields.Length != constant.record_const_definition_list.Count)
|
||||||
AddError(loc, "INVALID_RECORD_CONST_FIELD_COUNT");
|
AddError(loc, "INVALID_RECORD_CONST_FIELD_COUNT");
|
||||||
constant.type = ctn;
|
constant.type = ctn;
|
||||||
constant.field_values.Clear();
|
constant.field_values.Clear();
|
||||||
for (int i = 0; i < ctn.fields.Count; i++)
|
for (int i = 0; i < non_static_fields.Length; i++)
|
||||||
{
|
{
|
||||||
class_field cf = ctn.fields[i];
|
class_field cf = ctn.fields[i];
|
||||||
if (cf.name.ToLower() != constant.record_const_definition_list[i].name.name.ToLower())
|
if (cf.name.ToLower() != constant.record_const_definition_list[i].name.name.ToLower())
|
||||||
|
|
|
||||||
BIN
bin/AssignTupleOptimizer.dll
Normal file
BIN
bin/AssignTupleOptimizer.dll
Normal file
Binary file not shown.
|
|
@ -1430,24 +1430,26 @@ function ParamStr(i: integer): string;
|
||||||
/// Возвращает текущий каталог
|
/// Возвращает текущий каталог
|
||||||
function GetDir: string;
|
function GetDir: string;
|
||||||
/// Меняет текущий каталог
|
/// Меняет текущий каталог
|
||||||
procedure ChDir(s: string);
|
procedure ChDir(dirName: string);
|
||||||
/// Создает каталог
|
/// Создает каталог
|
||||||
procedure MkDir(s: string);
|
procedure MkDir(dirName: string);
|
||||||
/// Удаляет каталог
|
/// Удаляет каталог
|
||||||
procedure RmDir(s: string);
|
procedure RmDir(dirName: string);
|
||||||
|
|
||||||
/// Создает каталог. Возвращает True, если каталог успешно создан
|
/// Создает каталог. Возвращает True, если каталог успешно создан
|
||||||
function CreateDir(s: string): boolean;
|
function CreateDir(dirName: string): boolean;
|
||||||
/// Удаляет файл. Если файл не может быть удален, то возвращает False
|
/// Удаляет файл. Если файл не может быть удален, то возвращает False
|
||||||
function DeleteFile(fname: string): boolean;
|
function DeleteFile(fileName: string): boolean;
|
||||||
/// Возвращает текущий каталог
|
/// Возвращает текущий каталог
|
||||||
function GetCurrentDir: string;
|
function GetCurrentDir: string;
|
||||||
/// Удаляет каталог. Возвращает True, если каталог успешно удален
|
/// Удаляет каталог. Возвращает True, если каталог успешно удален
|
||||||
function RemoveDir(s: string): boolean;
|
function RemoveDir(dirName: string): boolean;
|
||||||
/// Переименовывает файл fileName, давая ему новое имя newfileName. Возвращает True, если файл успешно переименован
|
/// Переименовывает файл fileName, давая ему новое имя newfileName. Возвращает True, если файл успешно переименован
|
||||||
function RenameFile(fileName, newfileName: string): boolean;
|
function RenameFile(fileName, newfileName: string): boolean;
|
||||||
|
/// Переименовывает каталог dirName, давая ему новое имя newDirName. Возвращает True, если каталог успешно переименован
|
||||||
|
function RenameDirectory(dirName, newDirName: string): boolean;
|
||||||
/// Устанавливает текущий каталог. Возвращает True, если каталог успешно удален
|
/// Устанавливает текущий каталог. Возвращает True, если каталог успешно удален
|
||||||
function SetCurrentDir(s: string): boolean;
|
function SetCurrentDir(dirName: string): boolean;
|
||||||
|
|
||||||
/// Изменяет расширение файла с именем fileName на newExt
|
/// Изменяет расширение файла с именем fileName на newExt
|
||||||
function ChangeFileNameExtension(fileName, newExt: string): string;
|
function ChangeFileNameExtension(fileName, newExt: string): string;
|
||||||
|
|
@ -1462,9 +1464,9 @@ procedure Assert(cond: boolean; sourceFile: string := ''; line: integer := 0);
|
||||||
procedure Assert(cond: boolean; message: string; sourceFile: string := ''; line: integer := 0);
|
procedure Assert(cond: boolean; message: string; sourceFile: string := ''; line: integer := 0);
|
||||||
|
|
||||||
/// Возвращает свободное место в байтах на диске с именем diskname
|
/// Возвращает свободное место в байтах на диске с именем diskname
|
||||||
function DiskFree(diskname: string): int64;
|
function DiskFree(diskName: string): int64;
|
||||||
/// Возвращает размер в байтах на диске с именем diskname
|
/// Возвращает размер в байтах на диске с именем diskname
|
||||||
function DiskSize(diskname: string): int64;
|
function DiskSize(diskName: string): int64;
|
||||||
/// Возвращает свободное место в байтах на диске disk. disk=0 - текущий диск, disk=1 - диск A: , disk=2 - диск B: и т.д.
|
/// Возвращает свободное место в байтах на диске disk. disk=0 - текущий диск, disk=1 - диск A: , disk=2 - диск B: и т.д.
|
||||||
function DiskFree(disk: integer): int64;
|
function DiskFree(disk: integer): int64;
|
||||||
/// Возвращает размер в байтах на диске disk. disk=0 - текущий диск, disk=1 - диск A: , disk=2 - диск B: и т.д.
|
/// Возвращает размер в байтах на диске disk. disk=0 - текущий диск, disk=1 - диск A: , disk=2 - диск B: и т.д.
|
||||||
|
|
@ -8459,41 +8461,41 @@ begin
|
||||||
Result := Environment.CurrentDirectory;
|
Result := Environment.CurrentDirectory;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure ChDir(s: string);
|
procedure ChDir(dirName: string);
|
||||||
begin
|
begin
|
||||||
Environment.CurrentDirectory := s;
|
Environment.CurrentDirectory := dirName;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure MkDir(s: string);
|
procedure MkDir(dirName: string);
|
||||||
begin
|
begin
|
||||||
Directory.CreateDirectory(s);
|
Directory.CreateDirectory(dirName);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure RmDir(s: string);
|
procedure RmDir(dirName: string);
|
||||||
begin
|
begin
|
||||||
Directory.Delete(s);
|
Directory.Delete(dirName);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function CreateDir(s: string): boolean;
|
function CreateDir(dirName: string): boolean;
|
||||||
begin
|
begin
|
||||||
try
|
try
|
||||||
Result := True;
|
Result := True;
|
||||||
Directory.CreateDirectory(s);
|
Directory.CreateDirectory(dirName);
|
||||||
except
|
except
|
||||||
Result := False;
|
Result := False;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function DeleteFile(fname: string): boolean;
|
function DeleteFile(fileName: string): boolean;
|
||||||
begin
|
begin
|
||||||
if not &File.Exists(fname) then
|
if not &File.Exists(fileName) then
|
||||||
begin
|
begin
|
||||||
Result := False;
|
Result := False;
|
||||||
exit
|
exit
|
||||||
end;
|
end;
|
||||||
try
|
try
|
||||||
Result := True;
|
Result := True;
|
||||||
&File.Delete(fname);
|
&File.Delete(fileName);
|
||||||
except
|
except
|
||||||
Result := False;
|
Result := False;
|
||||||
end;
|
end;
|
||||||
|
|
@ -8504,11 +8506,11 @@ begin
|
||||||
Result := Environment.CurrentDirectory;
|
Result := Environment.CurrentDirectory;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function RemoveDir(s: string): boolean;
|
function RemoveDir(dirName: string): boolean;
|
||||||
begin
|
begin
|
||||||
try
|
try
|
||||||
Result := True;
|
Result := True;
|
||||||
Directory.Delete(s);
|
Directory.Delete(dirName);
|
||||||
except
|
except
|
||||||
Result := False;
|
Result := False;
|
||||||
end;
|
end;
|
||||||
|
|
@ -8524,11 +8526,21 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function SetCurrentDir(s: string): boolean;
|
function RenameDirectory(dirName, newDirName: string): boolean;
|
||||||
begin
|
begin
|
||||||
try
|
try
|
||||||
Result := True;
|
Result := True;
|
||||||
Environment.CurrentDirectory := s;
|
Directory.Move(dirName, newDirName);
|
||||||
|
except
|
||||||
|
Result := False;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function SetCurrentDir(dirName: string): boolean;
|
||||||
|
begin
|
||||||
|
try
|
||||||
|
Result := True;
|
||||||
|
Environment.CurrentDirectory := dirName;
|
||||||
except
|
except
|
||||||
Result := False;
|
Result := False;
|
||||||
end;
|
end;
|
||||||
|
|
@ -8596,7 +8608,7 @@ begin
|
||||||
System.Diagnostics.Contracts.Contract.Assert(cond,'Файл '+sourceFile+', строка '+line.ToString() + ': ' + message)
|
System.Diagnostics.Contracts.Contract.Assert(cond,'Файл '+sourceFile+', строка '+line.ToString() + ': ' + message)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function DiskFree(diskname: string): int64;
|
function DiskFree(diskName: string): int64;
|
||||||
begin
|
begin
|
||||||
try
|
try
|
||||||
var d := new System.IO.DriveInfo(diskname);
|
var d := new System.IO.DriveInfo(diskname);
|
||||||
|
|
@ -8606,7 +8618,7 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function DiskSize(diskname: string): int64;
|
function DiskSize(diskName: string): int64;
|
||||||
begin
|
begin
|
||||||
try
|
try
|
||||||
var d := new System.IO.DriveInfo(diskname);
|
var d := new System.IO.DriveInfo(diskname);
|
||||||
|
|
@ -13743,6 +13755,23 @@ begin
|
||||||
Result := Self.Split(delims.ToCharArray, System.StringSplitOptions.RemoveEmptyEntries);
|
Result := Self.Split(delims.ToCharArray, System.StringSplitOptions.RemoveEmptyEntries);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
/// Преобразует многострочную строку в массив строк
|
||||||
|
function ToLines(Self: string): array of string; extensionmethod;
|
||||||
|
begin
|
||||||
|
Result := Self.Split(|
|
||||||
|
#13#10, // CR+LF: Win
|
||||||
|
#10, // LF: Linux
|
||||||
|
#13 // CR: Mac
|
||||||
|
// https://en.m.wikipedia.org/wiki/Newline#Unicode
|
||||||
|
// But standard .Net things like System.IO.StringReader don't support these, so for now - commented out
|
||||||
|
// #11, // Vertical Tab
|
||||||
|
// #12, // Form feed
|
||||||
|
// char($85), // Next Line
|
||||||
|
// char($2028), // Line Separator
|
||||||
|
// char($2029), // Paragraph SeparatorS
|
||||||
|
|, System.StringSplitOptions.None);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure PassSpaces(var s: string; var from: integer);
|
procedure PassSpaces(var s: string; var from: integer);
|
||||||
begin
|
begin
|
||||||
while (from <= s.Length) and char.IsWhiteSpace(s[from]) do
|
while (from <= s.Length) and char.IsWhiteSpace(s[from]) do
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue