Compare commits
6 commits
master
...
opt_tuple_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75e79d9a82 | ||
|
|
66eaa619a3 | ||
|
|
d269c7ca20 | ||
|
|
54f8db8ce2 | ||
|
|
2dc3c4e50c | ||
|
|
133d082e4e |
|
|
@ -2709,16 +2709,19 @@ namespace PascalABCCompiler
|
|||
|
||||
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);
|
||||
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);
|
||||
else if (FindFileWithExtensionInDirs(fileName, out var dirIndex, CompilerOptions.SearchDirectories.ToArray()) is string resultFileName3)
|
||||
fileNameWithPriority = Tuple.Create(resultFileName3, 3 + dirIndex);
|
||||
else
|
||||
fileNameWithPriority = null;
|
||||
|
||||
PCUFileNamesDictionary[cacheKey] = fileNameWithPriority;
|
||||
PCUFileNamesDictionary[cacheKey] = fileNameWithPriority;
|
||||
}
|
||||
|
||||
folderPriority = fileNameWithPriority?.Item2 ?? 0;
|
||||
|
|
@ -2730,8 +2733,9 @@ namespace PascalABCCompiler
|
|||
var cacheKey = Tuple.Create(fileName.ToLower(), currentPath?.ToLower());
|
||||
|
||||
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);
|
||||
else if (FindSourceFileNameInDirs(fileName, out var dirIndex, CompilerOptions.SearchDirectories.ToArray()) is string resultFileName2)
|
||||
fileNameWithPriority = Tuple.Create(resultFileName2, 3 + dirIndex);
|
||||
|
|
@ -3362,8 +3366,18 @@ namespace PascalABCCompiler
|
|||
// 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.
|
||||
foreach (var reference in referenceDirectives)
|
||||
PreloadReference(reference);
|
||||
|
||||
{
|
||||
try
|
||||
{
|
||||
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)
|
||||
CompileReference(dlls, reference);
|
||||
|
||||
|
|
|
|||
|
|
@ -1847,7 +1847,10 @@ namespace PascalABCCompiler.PCU
|
|||
common_method_node raise_meth = null;
|
||||
if (CanReadObject())
|
||||
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());
|
||||
if (name==null)
|
||||
name = GetStringInClass(cont, name_ref);
|
||||
|
|
|
|||
|
|
@ -3021,7 +3021,10 @@ namespace PascalABCCompiler.PCU
|
|||
bw.Write(GetMemberOffset(_event.remove_method));
|
||||
if (CanWriteObject(_event.raise_method))
|
||||
bw.Write(GetMemberOffset(_event.raise_method));
|
||||
bw.Write(GetMemberOffset(_event.field));
|
||||
if (!_event.cont_type.IsInterface)
|
||||
bw.Write(GetMemberOffset(_event.field));
|
||||
else
|
||||
bw.Write(0);
|
||||
bw.Write(offset);
|
||||
bw.Write((byte)_event.field_access_level);
|
||||
bw.Write((byte)_event.polymorphic_state);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ internal static class RevisionClass
|
|||
public const string Major = "3";
|
||||
public const string Minor = "9";
|
||||
public const string Build = "0";
|
||||
public const string Revision = "3488";
|
||||
public const string Revision = "3494";
|
||||
|
||||
public const string MainVersion = Major + "." + Minor;
|
||||
public const string FullVersion = Major + "." + Minor + "." + Build + "." + Revision;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
%COREVERSION%=0
|
||||
%REVISION%=3488
|
||||
%REVISION%=3494
|
||||
%MINOR%=9
|
||||
%MAJOR%=3
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
//
|
||||
// This CSharp output file generated by Gardens Point LEX
|
||||
// Version: 1.1.3.301
|
||||
// Machine: DESKTOP-V3E9T2U
|
||||
// DateTime: 25.05.2024 22:13:44
|
||||
// UserName: alex
|
||||
// Machine: DESKTOP-G8V08V4
|
||||
// DateTime: 17.06.2024 16:43:45
|
||||
// UserName: ?????????
|
||||
// GPLEX input file <ABCPascal.lex>
|
||||
// GPLEX frame file <embedded resource>
|
||||
//
|
||||
|
|
|
|||
|
|
@ -3373,8 +3373,6 @@ expr_l1_for_lambda
|
|||
expr_dq
|
||||
: relop_expr
|
||||
{ $$ = $1; }
|
||||
| tkAwait relop_expr
|
||||
{ $$ = $2; }
|
||||
| expr_dq tkDoubleQuestion relop_expr
|
||||
{ $$ = 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)
|
||||
{
|
||||
root.FillParentsInAllChilds();
|
||||
|
||||
var binder = new BindCollectLightSymInfo(root as compilation_unit);
|
||||
#if DEBUG
|
||||
// var stat = new ABCStatisticsVisitor();
|
||||
// stat.ProcessNode(root);
|
||||
|
|
@ -42,9 +44,9 @@ namespace Languages.Pascal.Frontend.Converters
|
|||
#if DEBUG
|
||||
//new SimplePrettyPrinterVisitor("D:/out.txt").ProcessNode(root);
|
||||
#endif
|
||||
|
||||
bool optimize_tuple_assign = true;
|
||||
// tuple_node
|
||||
TupleVisitor.New.ProcessNode(root);
|
||||
TupleVisitor.Create(optimize_tuple_assign).ProcessNode(root);
|
||||
|
||||
// index
|
||||
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]);
|
||||
// assign_tuple и assign_var_tuple
|
||||
AssignTuplesDesugarVisitor.New.ProcessNode(root); // теперь это - на семантике
|
||||
|
||||
if (!optimize_tuple_assign)
|
||||
AssignTuplesDesugarVisitor.New.ProcessNode(root); // теперь это - на семантике
|
||||
else
|
||||
NewAssignTuplesDesugarVisitor.Create(binder).ProcessNode(root);
|
||||
|
||||
// question_point_desugar_visitor
|
||||
QuestionPointDesugarVisitor.New.ProcessNode(root);
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -4707,9 +4707,12 @@ namespace PascalABCCompiler.NETGenerator
|
|||
{
|
||||
ICommonTypeNode ctn = init_value.type as ICommonTypeNode;
|
||||
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]);
|
||||
if (FieldValues[i] is IArrayInitializer)
|
||||
|
|
@ -4750,9 +4753,12 @@ namespace PascalABCCompiler.NETGenerator
|
|||
{
|
||||
ICommonTypeNode ctn = init_value.type as ICommonTypeNode;
|
||||
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]);
|
||||
if (FieldValues[i] is IArrayConstantNode)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.8.34309.116
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.34301.259
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VisualPascalABCNET", "VisualPascalABCNET", "{26843C5D-9D7E-4C2C-AC14-2D227FA5592E}"
|
||||
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
|
||||
{
|
||||
|
|
@ -12,22 +13,23 @@ namespace PascalABCCompiler.SyntaxTree
|
|||
{
|
||||
Current = 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;
|
||||
var path = new Queue<ScopeSyntax>();
|
||||
while (cur_node != null)
|
||||
{
|
||||
// Console.WriteLine("cur_node: " + cur_node.ToString());
|
||||
|
||||
if (AbstractScopeCreator.IsScopeCreator(cur_node))
|
||||
{
|
||||
|
||||
//Console.WriteLine("checking scope" + cur_node.ToString())
|
||||
var cur_scope = scopeCreator.GetScope(cur_node);
|
||||
//Console.WriteLine(cur_scope.ToString() + ": " + cur_scope.Symbols.Count);
|
||||
path.Enqueue(cur_scope);
|
||||
var prev_scope = Current;
|
||||
|
||||
if (prev_scope != null)
|
||||
|
|
@ -36,11 +38,10 @@ namespace PascalABCCompiler.SyntaxTree
|
|||
Current = cur_scope;
|
||||
if (cur_scope.Parent == null && !(Current is GlobalScopeSyntax))
|
||||
{
|
||||
//Console.WriteLine("visiting " + cur_node.ToString());
|
||||
cur_node.visit(this);
|
||||
}
|
||||
var res = Current.bind(node);
|
||||
if (res != null) return res;
|
||||
if (res != null) return new BindResult(res, path.ToList());
|
||||
}
|
||||
cur_node = cur_node.Parent;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,20 @@ namespace PascalABCCompiler.SyntaxTree
|
|||
AddSymbols(vd.vars.list, SymKind.var, vd.vars_type, attr);
|
||||
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)
|
||||
{
|
||||
foreach (var pg in fp.params_list)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace PascalABCCompiler.SyntaxTree
|
|||
recordname, interfacename, template_param, type_alias, const_var, property };
|
||||
|
||||
[Flags]
|
||||
public enum SymbolAttributes { class_attr = 1, varparam_attr = 2, private_attr = 4};
|
||||
public enum SymbolAttributes { class_attr = 1, varparam_attr = 2, private_attr = 4 };
|
||||
|
||||
public class SymInfoSyntax
|
||||
{
|
||||
|
|
@ -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 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>
|
||||
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;
|
||||
public string UniqueName()
|
||||
{
|
||||
|
|
@ -59,81 +62,97 @@ namespace SyntaxVisitors.SugarVisitors
|
|||
// Остальное раскрывается в AssignTuplesDesugarVisitor
|
||||
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)
|
||||
{
|
||||
var n = assvartup.idents.idents.Count();
|
||||
if (n > tn.el.Count)
|
||||
throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", assvartup.idents[0]);
|
||||
|
||||
// Оптимизация, т.к. все - константы
|
||||
var sl = new List<statement>();
|
||||
for (var i = 0; i < n; i++)
|
||||
if (tn.el.expressions.All(ex => ex is const_node) && !tn.el.expressions.Any(ex => ex is nil_const))
|
||||
{
|
||||
var a = new var_statement(
|
||||
assvartup.idents.idents[i],
|
||||
tn.el.expressions[i],
|
||||
assvartup.idents.idents[i].source_context);
|
||||
sl.Add(a);
|
||||
var n = assvartup.idents.idents.Count();
|
||||
if (n > tn.el.Count)
|
||||
throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", assvartup.idents[0]);
|
||||
|
||||
// Оптимизация, т.к. все - константы
|
||||
var sl = new List<statement>();
|
||||
for (var i = 0; i < n; i++)
|
||||
{
|
||||
var a = new var_statement(
|
||||
assvartup.idents.idents[i],
|
||||
tn.el.expressions[i],
|
||||
assvartup.idents.idents[i].source_context);
|
||||
sl.Add(a);
|
||||
}
|
||||
ReplaceStatementUsingParent(assvartup, sl);
|
||||
}
|
||||
ReplaceStatementUsingParent(assvartup, sl);
|
||||
else if (optimize_tuple_assign)
|
||||
return;
|
||||
else
|
||||
DefaultVisit(assvartup);
|
||||
}
|
||||
else
|
||||
{
|
||||
DefaultVisit(assvartup);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
var n = asstup.vars.variables.Count();
|
||||
if (n > tn.el.Count)
|
||||
throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", asstup.vars.variables[0]);
|
||||
|
||||
// Оптимизация, т.к. все - константы
|
||||
var sl = new List<statement>();
|
||||
for (var i = 0; i < n; i++)
|
||||
if (tn.el.expressions.All(ex => ex is const_node) && !tn.el.expressions.Any(ex => ex is nil_const))
|
||||
{
|
||||
var a = new assign(asstup.vars.variables[i],
|
||||
tn.el.expressions[i],
|
||||
Operators.Assignment,
|
||||
asstup.vars.variables[i].source_context);
|
||||
sl.Add(a);
|
||||
}
|
||||
ReplaceStatementUsingParent(asstup, sl);
|
||||
}
|
||||
else if (asstup.expr is tuple_node tn1 && !tn1.el.expressions.Any(ex => ex is nil_const))
|
||||
{
|
||||
var n = asstup.vars.variables.Count();
|
||||
if (n > tn1.el.Count)
|
||||
throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", asstup.vars.variables[0]);
|
||||
var n = asstup.vars.variables.Count();
|
||||
if (n > tn.el.Count)
|
||||
throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", asstup.vars.variables[0]);
|
||||
|
||||
var sl = new List<statement>();
|
||||
for (var i = 0; i < n; i++)
|
||||
// Оптимизация, т.к. все - константы
|
||||
var sl = new List<statement>();
|
||||
for (var i = 0; i < n; i++)
|
||||
{
|
||||
var a = new assign(asstup.vars.variables[i],
|
||||
tn.el.expressions[i],
|
||||
Operators.Assignment,
|
||||
asstup.vars.variables[i].source_context);
|
||||
sl.Add(a);
|
||||
}
|
||||
ReplaceStatementUsingParent(asstup, sl);
|
||||
}
|
||||
else if (optimize_tuple_assign)
|
||||
return;
|
||||
else if (!tn.el.expressions.Any(ex => ex is nil_const))
|
||||
{
|
||||
var temp_id = new ident(UniqueName(), tn1.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 a = new var_statement(var_def, tn1.el.expressions[i].source_context);
|
||||
sl.Add(a);
|
||||
}
|
||||
var n = asstup.vars.variables.Count();
|
||||
if (n > tn.el.Count)
|
||||
throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", asstup.vars.variables[0]);
|
||||
|
||||
//for (var i = 0; i < n; i++)
|
||||
for (var i = n-1; i >= 0; i--)
|
||||
{
|
||||
var a = new assign(asstup.vars.variables[i],
|
||||
(sl[i] as var_statement).var_def.vars.idents[0],
|
||||
Operators.Assignment,
|
||||
asstup.vars.variables[i].source_context);
|
||||
sl.Add(a);
|
||||
}
|
||||
var sl = new List<statement>();
|
||||
for (var i = 0; i < n; i++)
|
||||
{
|
||||
var temp_id = new ident(UniqueName(), tn.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, tn.el.expressions[i].source_context);
|
||||
sl.Add(a);
|
||||
}
|
||||
|
||||
ReplaceStatementUsingParent(asstup, sl);
|
||||
//for (var i = 0; i < n; i++)
|
||||
for (var i = n - 1; i >= 0; i--)
|
||||
{
|
||||
var a = new assign(asstup.vars.variables[i],
|
||||
(sl[i] as var_statement).var_def.vars.idents[0],
|
||||
Operators.Assignment,
|
||||
asstup.vars.variables[i].source_context);
|
||||
sl.Add(a);
|
||||
}
|
||||
|
||||
ReplaceStatementUsingParent(asstup, sl);
|
||||
}
|
||||
else
|
||||
DefaultVisit(asstup);
|
||||
}
|
||||
else
|
||||
{
|
||||
DefaultVisit(asstup);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void ReplaceVarTupleDefStatementUsingParent(var_tuple_def_statement from, IEnumerable<var_def_statement> to)
|
||||
|
|
@ -150,27 +169,34 @@ namespace SyntaxVisitors.SugarVisitors
|
|||
// А это по идее до begin - там немного другие узлы и внешний контекст
|
||||
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))
|
||||
{
|
||||
var n = vtd.vars.idents.Count();
|
||||
if (n > tn.el.Count)
|
||||
throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", vtd.vars.idents[0]);
|
||||
|
||||
var vd = new List<var_def_statement>();
|
||||
for (var i = 0; i < n; i++)
|
||||
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 a = new var_def_statement(vtd.vars.idents[i],
|
||||
tn.el.expressions[i],
|
||||
vtd.vars.idents[i].source_context);
|
||||
vd.Add(a);
|
||||
var n = vtd.vars.idents.Count();
|
||||
if (n > tn.el.Count)
|
||||
throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", vtd.vars.idents[0]);
|
||||
|
||||
var vd = new List<var_def_statement>();
|
||||
for (var i = 0; i < n; i++)
|
||||
{
|
||||
var a = new var_def_statement(vtd.vars.idents[i],
|
||||
tn.el.expressions[i],
|
||||
vtd.vars.idents[i].source_context);
|
||||
vd.Add(a);
|
||||
}
|
||||
ReplaceVarTupleDefStatementUsingParent(vtd, vd);
|
||||
visit(vtd.inital_value);
|
||||
}
|
||||
ReplaceVarTupleDefStatementUsingParent(vtd, vd);
|
||||
visit(vtd.inital_value);
|
||||
else if (optimize_tuple_assign)
|
||||
return;
|
||||
else
|
||||
DefaultVisit(vtd);
|
||||
}
|
||||
else
|
||||
{
|
||||
DefaultVisit(vtd);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override void visit(tuple_node tup)
|
||||
|
|
|
|||
|
|
@ -52,6 +52,14 @@
|
|||
<Compile Include="LightSymInfoVisitors\CollectLightSymInfoVisitor.cs" />
|
||||
<Compile Include="LightSymInfoVisitors\LightScopeCreator.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\LetExprVisitor.cs" />
|
||||
<Compile Include="SugarVisitors\TestAssignIsDefVisitor.cs" />
|
||||
|
|
@ -65,7 +73,7 @@
|
|||
<Compile Include="PatternsVisitors\PatternsDesugaringVisitor.cs" />
|
||||
<Compile Include="PatternsVisitors\ReplaceNamesInIsVarVisitor.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\IndexVisitor.cs" />
|
||||
<Compile Include="SugarVisitors\LoopDesugarVisitor.cs" />
|
||||
|
|
|
|||
|
|
@ -113,13 +113,16 @@ namespace SyntaxVisitors
|
|||
return;
|
||||
}
|
||||
|
||||
var newNameCache = new Dictionary<string, string>();
|
||||
|
||||
var newLocalNames = var_def.vars.idents.Select(id =>
|
||||
{
|
||||
var low = id.name.ToLower();
|
||||
|
||||
var newName = this.CreateNewVariableName(low);
|
||||
//BlockNamesStack[CurrentLevel].Add(low, newName);
|
||||
BlockNamesStack[CurrentLevel][low] = newName;
|
||||
//BlockNamesStack[CurrentLevel][low] = newName;
|
||||
newNameCache[low] = newName;
|
||||
return new ident(newName, id.source_context);
|
||||
});
|
||||
|
||||
|
|
@ -130,6 +133,8 @@ namespace SyntaxVisitors
|
|||
Replace(var_def, newVS);
|
||||
listNodes[listNodes.Count - 1] = newVS; //SSM 8.11.18
|
||||
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 - зачем обходить всё?
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ unit ABCObjects;
|
|||
//{$apptype windows}
|
||||
{$reference '%GAC%\System.Windows.Forms.dll'}
|
||||
{$reference '%GAC%\System.Drawing.dll'}
|
||||
{$gendoc true}
|
||||
|
||||
interface
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
unit CRT;
|
||||
|
||||
{$apptype console}
|
||||
{$gendoc true}
|
||||
|
||||
interface
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ unit GraphABC;
|
|||
{$apptype windows}
|
||||
{$reference '%GAC%\System.Windows.Forms.dll'}
|
||||
{$reference '%GAC%\System.Drawing.dll'}
|
||||
{$gendoc true}
|
||||
|
||||
interface
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@ unit PABCSystem;
|
|||
|
||||
{$zerobasedstrings off}
|
||||
|
||||
{$gendoc true}
|
||||
|
||||
// Default Application type
|
||||
{$apptype console}
|
||||
|
||||
|
|
@ -1432,24 +1430,26 @@ function ParamStr(i: integer): 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, если каталог успешно создан
|
||||
function CreateDir(s: string): boolean;
|
||||
function CreateDir(dirName: string): boolean;
|
||||
/// Удаляет файл. Если файл не может быть удален, то возвращает False
|
||||
function DeleteFile(fname: string): boolean;
|
||||
function DeleteFile(fileName: string): boolean;
|
||||
/// Возвращает текущий каталог
|
||||
function GetCurrentDir: string;
|
||||
/// Удаляет каталог. Возвращает True, если каталог успешно удален
|
||||
function RemoveDir(s: string): boolean;
|
||||
function RemoveDir(dirName: string): boolean;
|
||||
/// Переименовывает файл fileName, давая ему новое имя newfileName. Возвращает True, если файл успешно переименован
|
||||
function RenameFile(fileName, newfileName: string): boolean;
|
||||
/// Переименовывает каталог dirName, давая ему новое имя newDirName. Возвращает True, если каталог успешно переименован
|
||||
function RenameDirectory(dirName, newDirName: string): boolean;
|
||||
/// Устанавливает текущий каталог. Возвращает True, если каталог успешно удален
|
||||
function SetCurrentDir(s: string): boolean;
|
||||
function SetCurrentDir(dirName: string): boolean;
|
||||
|
||||
/// Изменяет расширение файла с именем fileName на newExt
|
||||
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);
|
||||
|
||||
/// Возвращает свободное место в байтах на диске с именем diskname
|
||||
function DiskFree(diskname: string): int64;
|
||||
function DiskFree(diskName: string): int64;
|
||||
/// Возвращает размер в байтах на диске с именем diskname
|
||||
function DiskSize(diskname: string): int64;
|
||||
function DiskSize(diskName: string): int64;
|
||||
/// Возвращает свободное место в байтах на диске disk. disk=0 - текущий диск, disk=1 - диск A: , disk=2 - диск B: и т.д.
|
||||
function DiskFree(disk: integer): int64;
|
||||
/// Возвращает размер в байтах на диске disk. disk=0 - текущий диск, disk=1 - диск A: , disk=2 - диск B: и т.д.
|
||||
|
|
@ -8461,41 +8461,41 @@ begin
|
|||
Result := Environment.CurrentDirectory;
|
||||
end;
|
||||
|
||||
procedure ChDir(s: string);
|
||||
procedure ChDir(dirName: string);
|
||||
begin
|
||||
Environment.CurrentDirectory := s;
|
||||
Environment.CurrentDirectory := dirName;
|
||||
end;
|
||||
|
||||
procedure MkDir(s: string);
|
||||
procedure MkDir(dirName: string);
|
||||
begin
|
||||
Directory.CreateDirectory(s);
|
||||
Directory.CreateDirectory(dirName);
|
||||
end;
|
||||
|
||||
procedure RmDir(s: string);
|
||||
procedure RmDir(dirName: string);
|
||||
begin
|
||||
Directory.Delete(s);
|
||||
Directory.Delete(dirName);
|
||||
end;
|
||||
|
||||
function CreateDir(s: string): boolean;
|
||||
function CreateDir(dirName: string): boolean;
|
||||
begin
|
||||
try
|
||||
Result := True;
|
||||
Directory.CreateDirectory(s);
|
||||
Directory.CreateDirectory(dirName);
|
||||
except
|
||||
Result := False;
|
||||
end;
|
||||
end;
|
||||
|
||||
function DeleteFile(fname: string): boolean;
|
||||
function DeleteFile(fileName: string): boolean;
|
||||
begin
|
||||
if not &File.Exists(fname) then
|
||||
if not &File.Exists(fileName) then
|
||||
begin
|
||||
Result := False;
|
||||
exit
|
||||
end;
|
||||
try
|
||||
Result := True;
|
||||
&File.Delete(fname);
|
||||
&File.Delete(fileName);
|
||||
except
|
||||
Result := False;
|
||||
end;
|
||||
|
|
@ -8506,11 +8506,11 @@ begin
|
|||
Result := Environment.CurrentDirectory;
|
||||
end;
|
||||
|
||||
function RemoveDir(s: string): boolean;
|
||||
function RemoveDir(dirName: string): boolean;
|
||||
begin
|
||||
try
|
||||
Result := True;
|
||||
Directory.Delete(s);
|
||||
Directory.Delete(dirName);
|
||||
except
|
||||
Result := False;
|
||||
end;
|
||||
|
|
@ -8526,11 +8526,21 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
function SetCurrentDir(s: string): boolean;
|
||||
function RenameDirectory(dirName, newDirName: string): boolean;
|
||||
begin
|
||||
try
|
||||
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
|
||||
Result := False;
|
||||
end;
|
||||
|
|
@ -8598,7 +8608,7 @@ begin
|
|||
System.Diagnostics.Contracts.Contract.Assert(cond,'Файл '+sourceFile+', строка '+line.ToString() + ': ' + message)
|
||||
end;
|
||||
|
||||
function DiskFree(diskname: string): int64;
|
||||
function DiskFree(diskName: string): int64;
|
||||
begin
|
||||
try
|
||||
var d := new System.IO.DriveInfo(diskname);
|
||||
|
|
@ -8608,7 +8618,7 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
function DiskSize(diskname: string): int64;
|
||||
function DiskSize(diskName: string): int64;
|
||||
begin
|
||||
try
|
||||
var d := new System.IO.DriveInfo(diskname);
|
||||
|
|
@ -13745,6 +13755,23 @@ begin
|
|||
Result := Self.Split(delims.ToCharArray, System.StringSplitOptions.RemoveEmptyEntries);
|
||||
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);
|
||||
begin
|
||||
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);
|
||||
is_direct_type_decl = true;
|
||||
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);
|
||||
is_direct_type_decl = false;
|
||||
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)
|
||||
{
|
||||
location loc = constant.location;
|
||||
var non_static_fields = ctn.fields.Where(x => !x.IsStatic).ToArray();
|
||||
if (!ctn.is_value_type)
|
||||
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");
|
||||
constant.type = ctn;
|
||||
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];
|
||||
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;
|
||||
/// Меняет текущий каталог
|
||||
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, если каталог успешно создан
|
||||
function CreateDir(s: string): boolean;
|
||||
function CreateDir(dirName: string): boolean;
|
||||
/// Удаляет файл. Если файл не может быть удален, то возвращает False
|
||||
function DeleteFile(fname: string): boolean;
|
||||
function DeleteFile(fileName: string): boolean;
|
||||
/// Возвращает текущий каталог
|
||||
function GetCurrentDir: string;
|
||||
/// Удаляет каталог. Возвращает True, если каталог успешно удален
|
||||
function RemoveDir(s: string): boolean;
|
||||
function RemoveDir(dirName: string): boolean;
|
||||
/// Переименовывает файл fileName, давая ему новое имя newfileName. Возвращает True, если файл успешно переименован
|
||||
function RenameFile(fileName, newfileName: string): boolean;
|
||||
/// Переименовывает каталог dirName, давая ему новое имя newDirName. Возвращает True, если каталог успешно переименован
|
||||
function RenameDirectory(dirName, newDirName: string): boolean;
|
||||
/// Устанавливает текущий каталог. Возвращает True, если каталог успешно удален
|
||||
function SetCurrentDir(s: string): boolean;
|
||||
function SetCurrentDir(dirName: string): boolean;
|
||||
|
||||
/// Изменяет расширение файла с именем fileName на newExt
|
||||
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);
|
||||
|
||||
/// Возвращает свободное место в байтах на диске с именем diskname
|
||||
function DiskFree(diskname: string): int64;
|
||||
function DiskFree(diskName: string): int64;
|
||||
/// Возвращает размер в байтах на диске с именем diskname
|
||||
function DiskSize(diskname: string): int64;
|
||||
function DiskSize(diskName: string): int64;
|
||||
/// Возвращает свободное место в байтах на диске disk. disk=0 - текущий диск, disk=1 - диск A: , disk=2 - диск B: и т.д.
|
||||
function DiskFree(disk: integer): int64;
|
||||
/// Возвращает размер в байтах на диске disk. disk=0 - текущий диск, disk=1 - диск A: , disk=2 - диск B: и т.д.
|
||||
|
|
@ -8459,41 +8461,41 @@ begin
|
|||
Result := Environment.CurrentDirectory;
|
||||
end;
|
||||
|
||||
procedure ChDir(s: string);
|
||||
procedure ChDir(dirName: string);
|
||||
begin
|
||||
Environment.CurrentDirectory := s;
|
||||
Environment.CurrentDirectory := dirName;
|
||||
end;
|
||||
|
||||
procedure MkDir(s: string);
|
||||
procedure MkDir(dirName: string);
|
||||
begin
|
||||
Directory.CreateDirectory(s);
|
||||
Directory.CreateDirectory(dirName);
|
||||
end;
|
||||
|
||||
procedure RmDir(s: string);
|
||||
procedure RmDir(dirName: string);
|
||||
begin
|
||||
Directory.Delete(s);
|
||||
Directory.Delete(dirName);
|
||||
end;
|
||||
|
||||
function CreateDir(s: string): boolean;
|
||||
function CreateDir(dirName: string): boolean;
|
||||
begin
|
||||
try
|
||||
Result := True;
|
||||
Directory.CreateDirectory(s);
|
||||
Directory.CreateDirectory(dirName);
|
||||
except
|
||||
Result := False;
|
||||
end;
|
||||
end;
|
||||
|
||||
function DeleteFile(fname: string): boolean;
|
||||
function DeleteFile(fileName: string): boolean;
|
||||
begin
|
||||
if not &File.Exists(fname) then
|
||||
if not &File.Exists(fileName) then
|
||||
begin
|
||||
Result := False;
|
||||
exit
|
||||
end;
|
||||
try
|
||||
Result := True;
|
||||
&File.Delete(fname);
|
||||
&File.Delete(fileName);
|
||||
except
|
||||
Result := False;
|
||||
end;
|
||||
|
|
@ -8504,11 +8506,11 @@ begin
|
|||
Result := Environment.CurrentDirectory;
|
||||
end;
|
||||
|
||||
function RemoveDir(s: string): boolean;
|
||||
function RemoveDir(dirName: string): boolean;
|
||||
begin
|
||||
try
|
||||
Result := True;
|
||||
Directory.Delete(s);
|
||||
Directory.Delete(dirName);
|
||||
except
|
||||
Result := False;
|
||||
end;
|
||||
|
|
@ -8524,11 +8526,21 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
function SetCurrentDir(s: string): boolean;
|
||||
function RenameDirectory(dirName, newDirName: string): boolean;
|
||||
begin
|
||||
try
|
||||
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
|
||||
Result := False;
|
||||
end;
|
||||
|
|
@ -8596,7 +8608,7 @@ begin
|
|||
System.Diagnostics.Contracts.Contract.Assert(cond,'Файл '+sourceFile+', строка '+line.ToString() + ': ' + message)
|
||||
end;
|
||||
|
||||
function DiskFree(diskname: string): int64;
|
||||
function DiskFree(diskName: string): int64;
|
||||
begin
|
||||
try
|
||||
var d := new System.IO.DriveInfo(diskname);
|
||||
|
|
@ -8606,7 +8618,7 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
function DiskSize(diskname: string): int64;
|
||||
function DiskSize(diskName: string): int64;
|
||||
begin
|
||||
try
|
||||
var d := new System.IO.DriveInfo(diskname);
|
||||
|
|
@ -13743,6 +13755,23 @@ begin
|
|||
Result := Self.Split(delims.ToCharArray, System.StringSplitOptions.RemoveEmptyEntries);
|
||||
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);
|
||||
begin
|
||||
while (from <= s.Length) and char.IsWhiteSpace(s[from]) do
|
||||
|
|
|
|||
Loading…
Reference in a new issue