Многомерные срезы без семантических проверок

Разрешил a as array [,] of T
This commit is contained in:
Mikhalkovich Stanislav 2021-02-24 00:47:39 +03:00
parent b1323a6e0e
commit 7c3273aae8
12 changed files with 2674 additions and 2039 deletions

View file

@ -15,7 +15,7 @@ internal static class RevisionClass
public const string Major = "3";
public const string Minor = "7";
public const string Build = "2";
public const string Revision = "2823";
public const string Revision = "2827";
public const string MainVersion = Major + "." + Minor;
public const string FullVersion = Major + "." + Minor + "." + Build + "." + Revision;

View file

@ -1,4 +1,4 @@
%MINOR%=7
%REVISION%=2823
%REVISION%=2827
%COREVERSION%=2
%MAJOR%=3

View file

@ -2,7 +2,7 @@
// This CSharp output file generated by Gardens Point LEX
// Version: 1.1.3.301
// Machine: DESKTOP-G8V08V4
// DateTime: 22.02.2021 17:50:28
// DateTime: 24.02.2021 0:24:55
// UserName: ?????????
// GPLEX input file <ABCPascal.lex>
// GPLEX frame file <embedded resource>

View file

@ -3907,6 +3907,10 @@ as_expr
{
$$ = NewAsIsExpr($1, op_typecast.as_op, $3, @$);
}
| term tkAs array_type
{
$$ = NewAsIsExpr($1, op_typecast.as_op, $3, @$);
}
;
is_type_expr
@ -3914,6 +3918,10 @@ is_type_expr
{
$$ = NewAsIsExpr($1, op_typecast.is_op, $3, @$);
}
| term tkIs array_type
{
$$ = NewAsIsExpr($1, op_typecast.as_op, $3, @$);
}
;
power_expr
@ -4159,6 +4167,31 @@ variable
}
$$ = new slice_expr($1 as addressed_value,fe.expr,fe.format1,fe.format2,@$);
}
// ìíîãîìåðíûå ñðåçû
else if (el.expressions.Any(e => e is format_expr))
{
var ll = new List<Tuple<expression, expression, expression>>();
foreach (var ex in el.expressions)
{
if (ex is format_expr fe)
{
if (fe.expr == null)
fe.expr = new int32_const(int.MaxValue, fe.source_context);
if (fe.format1 == null)
fe.format1 = new int32_const(int.MaxValue, fe.source_context);
if (fe.format2 == null)
fe.format2 = new int32_const(1, fe.source_context);
ll.Add(Tuple.Create(fe.expr, fe.format1, fe.format2));
}
else
{
ll.Add(Tuple.Create(ex, ex, (expression)new int32_const(int.MaxValue, ex.source_context))); // ñêàëÿðíîå çíà÷åíèå âìåñòî ñðåçà
}
}
var sle = new slice_expr($1 as addressed_value,null,null,null,@$);
sle.slices = ll;
$$ = sle;
}
else $$ = new indexer($1 as addressed_value, el, @$);
}
| variable_or_literal_or_number tkQuestionSquareOpen format_expr tkSquareClose

File diff suppressed because it is too large Load diff

View file

@ -306,6 +306,10 @@ script=

View file

@ -1 +1 @@
3.7.2.2823
3.7.2.2827

View file

@ -1 +1 @@
!define VERSION '3.7.2.2823'
!define VERSION '3.7.2.2827'

View file

@ -1769,7 +1769,7 @@ namespace PascalABCCompiler.SyntaxTree
public partial class slice_expr
{
public List<System.Tuple<expression, expression, expression>> slices = new List<Tuple<expression, expression, expression>>();
public List<System.Tuple<expression, expression, expression>> slices; // = new List<Tuple<expression, expression, expression>>();
public override string ToString() => this.v + "[" + this.from + ":" + this.to + ":" + this.step + "]";
}

View file

@ -16,6 +16,26 @@ namespace SyntaxVisitors.SugarVisitors
get { return new SliceDesugarVisitor(); }
}
expression_list construct_expression_list_for_slice_expr_multi(slice_expr sl)
{
if (sl.slices == null)
return null; // упадёт - это ошибка компилятора
var el = new expression_list(); // будем наполнять кортежами - самое простое
var sc = sl.source_context;
foreach (var slice in sl.slices)
{
var tup = new dot_node(new dot_node(new ident("?System",sc), new ident("Tuple",sc), sc), new ident("Create",sc), sc);
// пока без ^1
var eel = new expression_list();
eel.Add(slice.Item1);
eel.Add(slice.Item2);
eel.Add(slice.Item3);
var mc = new method_call(tup, eel, sc); // sc - не очень хорошо - ошибка будет в общем месте
el.Add(mc);
// по идее все параметры готовы. Надо только проверить, что они целые
}
return el;
}
expression_list construct_expression_list_for_slice_expr(slice_expr sl)
{
// situation = 0 - ничего не пропущено
@ -80,9 +100,19 @@ namespace SyntaxVisitors.SugarVisitors
public override void visit(slice_expr sl)
{
var el = construct_expression_list_for_slice_expr(sl);
expression_list el = null;
if (sl.slices == null)
el = construct_expression_list_for_slice_expr(sl);
else el = construct_expression_list_for_slice_expr_multi(sl); // то это многомерный массив
// надо как-то запретить многомерные слайсы в левой части присваивания
if (sl.Parent is assign parent_assign && parent_assign.to == sl)
{
// если это многомерный слайс - кинуть ошибку
if (sl.slices != null)
{
// запретим пока или вовсе
throw new SyntaxVisitorError("MULTIDIMENSIONAL_SLICES_FORBIDDEN_IN_LEFT_SIDE_OF_ASSIGNMENT", sl.source_context);
}
el.Insert(0, parent_assign.from);
var mc = method_call.NewP(
dot_node.NewP(
@ -99,10 +129,23 @@ namespace SyntaxVisitors.SugarVisitors
}
else
{
var mc = method_call.NewP(dot_node.NewP(sl.v, new ident("SystemSlice", sl.v.source_context), sl.v.source_context), el, sl.source_context);
var sug = sugared_addressed_value.NewP(sl, mc, sl.source_context);
ReplaceUsingParent(sl, sug);
visit(mc); // обойти заменённое на предмет наличия такого же синтаксического сахара
if (sl.slices == null) // значит, это одномерный слайс - вызываем старый код
{
var mc = method_call.NewP(dot_node.NewP(sl.v, new ident("SystemSlice", sl.v.source_context), sl.v.source_context), el, sl.source_context);
var sug = sugared_addressed_value.NewP(sl, mc, sl.source_context);
ReplaceUsingParent(sl, sug);
visit(mc); // обойти заменённое на предмет наличия такого же синтаксического сахара
}
else // многомерный слайс на чтение - вызываем груду новых функций
{
// Определим, сколько размерностей надо оставлять в многомерном слайсе
// Столько - сколько в sl.slices кортежей с шагом int.MaxValue. Считаем:
var N = sl.slices.Count(s => { var u = s.Item3 as int32_const; return u == null || u.val != int.MaxValue; });
var mc = method_call.NewP(dot_node.NewP(sl.v, new ident("SystemSliceN"+N, sl.v.source_context), sl.v.source_context), el, sl.source_context);
// пока без семантической проверки
ReplaceUsingParent(sl, mc);
visit(mc);
}
}
}

View file

@ -12042,6 +12042,264 @@ begin
Result := SystemSliceArrayImplQuestion(Self, situation, from, &to, step);
end;
// Срезы многомерных массивов - вспомогательные типы и функции
type
SliceType = class
situation,from, &to, step, count: integer;
oneelem: boolean;
constructor (sit,f,t: integer; st: integer := 1; oneel: boolean := false);
begin
situation := sit;
from := f;
&to := t;
step := st;
count := -1; // заполняется во внешней функции
oneelem := oneel;
if step = integer.MaxValue then
oneelem := True;
end;
procedure CorrectSliceAndCalcCount(len: integer);
begin
if oneelem then
count := 1
else count := CheckAndCorrectFromToAndCalcCountForSystemSlice(situation, len, from, &to, step);
end;
static function operator implicit(i: integer): SliceType;
static function operator implicit(ir: IntRange): SliceType;
static function operator implicit(sl: (integer,integer,integer)): SliceType;
end;
function Diap(f, t: integer) := new SliceType(0, f, t, 1, false);
function Elem(ind: integer) := new SliceType(0, ind, ind+1, 1, true);
function Slice(f, t: integer; st: integer := 1; oneel: boolean := false): SliceType;
begin
var sit := 0;
if f = integer.MaxValue then
sit += 1;
if t = integer.MaxValue then
sit += 2;
if st = integer.MaxValue then
oneel := True;
Result := new SliceType(sit, f, t, st, oneel);
end;
static function SliceType.operator implicit(i: integer): SliceType;
begin
Result := Elem(i);
end;
static function SliceType.operator implicit(ir: IntRange): SliceType;
begin
Result := Diap(ir.Low,ir.High);
end;
static function SliceType.operator implicit(sl: (integer,integer,integer)): SliceType;
begin
Result := Slice(sl[0],sl[1],sl[2]);
end;
function ToOneDim<T>(a: array [,] of T; l: array of SliceType): array of T;
begin
for var i:=0 to l.Length-1 do
l[i].CorrectSliceAndCalcCount(a.GetLength(i));
var onedimsz := l[0].count * l[1].count;
var res := new T[onedimsz];
if onedimsz>0 then
begin
var cur := 0;
var i0 := l[0].from;
loop l[0].count do
begin
var i1:=l[1].from;
loop l[1].count do
begin
res[cur] := a[i0,i1];
cur += 1;
i1 += l[1].step;
end;
i0 += l[0].step;
end;
end;
Result := res;
end;
function ToOneDim<T>(a: array [,,] of T; l: array of SliceType): array of T;
begin
for var i:=0 to l.Length-1 do
l[i].CorrectSliceAndCalcCount(a.GetLength(i));
var onedimsz := l[0].count * l[1].count * l[2].count;
var res := new T[onedimsz];
if onedimsz>0 then
begin
var cur := 0;
var i0 := l[0].from;
loop l[0].count do
begin
var i1:=l[1].from;
loop l[1].count do
begin
var i2 := l[2].from;
loop l[2].count do
begin
res[cur] := a[i0,i1,i2];
cur += 1;
i2 += l[2].step;
end;
i1 += l[1].step;
end;
i0 += l[0].step;
end;
end;
Result := res;
end;
function ToOneDim<T>(a: array [,,,] of T; l: array of SliceType): array of T;
begin
for var i:=0 to l.Length-1 do
l[i].CorrectSliceAndCalcCount(a.GetLength(i));
var onedimsz := l[0].count * l[1].count * l[2].count * l[3].count;
var res := new T[onedimsz];
if onedimsz>0 then
begin
var cur := 0;
var i0 := l[0].from;
loop l[0].count do
begin
var i1:=l[1].from;
loop l[1].count do
begin
var i2 := l[2].from;
loop l[2].count do
begin
var i3 := l[3].from;
loop l[3].count do
begin
res[cur] := a[i0,i1,i2,i3];
cur += 1;
i3 += l[3].step;
end;
i2 += l[2].step;
end;
i1 += l[1].step;
end;
i0 += l[0].step;
end;
end;
Result := res;
end;
function FromOneDim2<T>(r: array of T; l: array of SliceType): array [,] of T;
begin
var dims := l.FindAll(x -> x.oneelem = False).ConvertAll(x -> x.count);
Assert(dims.Length = 2);
var cur := 0;
var res := new T[dims[0],dims[1]];
for var i0:=0 to dims[0]-1 do
for var i1:=0 to dims[1]-1 do
begin
res[i0,i1] := r[cur];
cur += 1;
end;
Result := res;
end;
function FromOneDim3<T>(r: array of T; l: array of SliceType): array [,,] of T;
begin
var dims := l.FindAll(x -> x.oneelem = False).ConvertAll(x -> x.count);
Assert(dims.Length = 3);
var cur := 0;
var res := new T[dims[0],dims[1],dims[2]];
for var i0:=0 to dims[0]-1 do
for var i1:=0 to dims[1]-1 do
for var i2:=0 to dims[2]-1 do
begin
res[i0,i1,i2] := r[cur];
cur += 1;
end;
Result := res;
end;
function FromOneDim4<T>(r: array of T; l: array of SliceType): array [,,,] of T;
begin
var dims := l.FindAll(x -> x.oneelem = False).ConvertAll(x -> x.count);
Assert(dims.Length = 4);
var cur := 0;
var res := new T[dims[0],dims[1],dims[2],dims[3]];
for var i0:=0 to dims[0]-1 do
for var i1:=0 to dims[1]-1 do
for var i2:=0 to dims[2]-1 do
for var i3:=0 to dims[3]-1 do
begin
res[i0,i1,i2,i3] := r[cur];
cur += 1;
end;
Result := res;
end;
function FromOneDimN<T>(r: array of T; l: array of SliceType): System.Array;
begin
var rank := l.Count(x -> x.oneelem = False);
case rank of
1: Result := r;
2: Result := FromOneDim2(r,l);
3: Result := FromOneDim3(r,l);
4: Result := FromOneDim4(r,l);
end;
end;
function SliceN<T>(a: array[,] of T; l: array of SliceType): System.Array;
begin
var r := ToOneDim(a,l);
Result := FromOneDimN(r,l);
end;
function SliceN<T>(a: array[,,] of T; l: array of SliceType): System.Array;
begin
var r := ToOneDim(a,l);
Result := FromOneDimN(r,l);
end;
function SliceN<T>(a: array[,,,] of T; l: array of SliceType): System.Array;
begin
var r := ToOneDim(a,l);
Result := FromOneDimN(r,l);
end;
{type
ArrT<T> = array of T;
Arr2T<T> = array [,] of T;
Arr3T<T> = array [,,] of T;
Arr4T<T> = array [,,,] of T;}
///--
function SystemSliceN1<T>(Self: array[,] of T; params l: array of SliceType): array of T; extensionmethod
:= SliceN(Self,l) as array of T;
///--
function SystemSliceN1<T>(Self: array[,,] of T; params l: array of SliceType): array of T; extensionmethod
:= SliceN(Self,l) as array of T;
///--
function SystemSliceN1<T>(Self: array[,,,] of T; params l: array of SliceType): array of T; extensionmethod
:= SliceN(Self,l) as array of T;
///--
function SystemSliceN2<T>(Self: array[,] of T; params l: array of SliceType): array[,] of T; extensionmethod
:= SliceN(Self,l) as array [,] of T;
///--
function SystemSliceN2<T>(Self: array[,,] of T; params l: array of SliceType): array[,] of T; extensionmethod
:= SliceN(Self,l) as array [,] of T;
///--
function SystemSliceN2<T>(Self: array[,,,] of T; params l: array of SliceType): array[,] of T; extensionmethod
:= SliceN(Self,l) as array [,] of T;
///--
function SystemSliceN3<T>(Self: array[,,] of T; params l: array of SliceType): array[,,] of T; extensionmethod
:= SliceN(Self,l) as array [,,] of T;
///--
function SystemSliceN3<T>(Self: array[,,,] of T; params l: array of SliceType): array[,,] of T; extensionmethod
:= SliceN(Self,l) as array [,,] of T;
///--
function SystemSliceN4<T>(Self: array[,,,] of T; params l: array of SliceType): array[,,,] of T; extensionmethod
:= SliceN(Self,l) as array [,,,] of T;
// -----------------------------------------------------
//>> Методы расширения типа integer # Extension methods for integer
// -----------------------------------------------------

View file

@ -12042,6 +12042,264 @@ begin
Result := SystemSliceArrayImplQuestion(Self, situation, from, &to, step);
end;
// Срезы многомерных массивов - вспомогательные типы и функции
type
SliceType = class
situation,from, &to, step, count: integer;
oneelem: boolean;
constructor (sit,f,t: integer; st: integer := 1; oneel: boolean := false);
begin
situation := sit;
from := f;
&to := t;
step := st;
count := -1; // заполняется во внешней функции
oneelem := oneel;
if step = integer.MaxValue then
oneelem := True;
end;
procedure CorrectSliceAndCalcCount(len: integer);
begin
if oneelem then
count := 1
else count := CheckAndCorrectFromToAndCalcCountForSystemSlice(situation, len, from, &to, step);
end;
static function operator implicit(i: integer): SliceType;
static function operator implicit(ir: IntRange): SliceType;
static function operator implicit(sl: (integer,integer,integer)): SliceType;
end;
function Diap(f, t: integer) := new SliceType(0, f, t, 1, false);
function Elem(ind: integer) := new SliceType(0, ind, ind+1, 1, true);
function Slice(f, t: integer; st: integer := 1; oneel: boolean := false): SliceType;
begin
var sit := 0;
if f = integer.MaxValue then
sit += 1;
if t = integer.MaxValue then
sit += 2;
if st = integer.MaxValue then
oneel := True;
Result := new SliceType(sit, f, t, st, oneel);
end;
static function SliceType.operator implicit(i: integer): SliceType;
begin
Result := Elem(i);
end;
static function SliceType.operator implicit(ir: IntRange): SliceType;
begin
Result := Diap(ir.Low,ir.High);
end;
static function SliceType.operator implicit(sl: (integer,integer,integer)): SliceType;
begin
Result := Slice(sl[0],sl[1],sl[2]);
end;
function ToOneDim<T>(a: array [,] of T; l: array of SliceType): array of T;
begin
for var i:=0 to l.Length-1 do
l[i].CorrectSliceAndCalcCount(a.GetLength(i));
var onedimsz := l[0].count * l[1].count;
var res := new T[onedimsz];
if onedimsz>0 then
begin
var cur := 0;
var i0 := l[0].from;
loop l[0].count do
begin
var i1:=l[1].from;
loop l[1].count do
begin
res[cur] := a[i0,i1];
cur += 1;
i1 += l[1].step;
end;
i0 += l[0].step;
end;
end;
Result := res;
end;
function ToOneDim<T>(a: array [,,] of T; l: array of SliceType): array of T;
begin
for var i:=0 to l.Length-1 do
l[i].CorrectSliceAndCalcCount(a.GetLength(i));
var onedimsz := l[0].count * l[1].count * l[2].count;
var res := new T[onedimsz];
if onedimsz>0 then
begin
var cur := 0;
var i0 := l[0].from;
loop l[0].count do
begin
var i1:=l[1].from;
loop l[1].count do
begin
var i2 := l[2].from;
loop l[2].count do
begin
res[cur] := a[i0,i1,i2];
cur += 1;
i2 += l[2].step;
end;
i1 += l[1].step;
end;
i0 += l[0].step;
end;
end;
Result := res;
end;
function ToOneDim<T>(a: array [,,,] of T; l: array of SliceType): array of T;
begin
for var i:=0 to l.Length-1 do
l[i].CorrectSliceAndCalcCount(a.GetLength(i));
var onedimsz := l[0].count * l[1].count * l[2].count * l[3].count;
var res := new T[onedimsz];
if onedimsz>0 then
begin
var cur := 0;
var i0 := l[0].from;
loop l[0].count do
begin
var i1:=l[1].from;
loop l[1].count do
begin
var i2 := l[2].from;
loop l[2].count do
begin
var i3 := l[3].from;
loop l[3].count do
begin
res[cur] := a[i0,i1,i2,i3];
cur += 1;
i3 += l[3].step;
end;
i2 += l[2].step;
end;
i1 += l[1].step;
end;
i0 += l[0].step;
end;
end;
Result := res;
end;
function FromOneDim2<T>(r: array of T; l: array of SliceType): array [,] of T;
begin
var dims := l.FindAll(x -> x.oneelem = False).ConvertAll(x -> x.count);
Assert(dims.Length = 2);
var cur := 0;
var res := new T[dims[0],dims[1]];
for var i0:=0 to dims[0]-1 do
for var i1:=0 to dims[1]-1 do
begin
res[i0,i1] := r[cur];
cur += 1;
end;
Result := res;
end;
function FromOneDim3<T>(r: array of T; l: array of SliceType): array [,,] of T;
begin
var dims := l.FindAll(x -> x.oneelem = False).ConvertAll(x -> x.count);
Assert(dims.Length = 3);
var cur := 0;
var res := new T[dims[0],dims[1],dims[2]];
for var i0:=0 to dims[0]-1 do
for var i1:=0 to dims[1]-1 do
for var i2:=0 to dims[2]-1 do
begin
res[i0,i1,i2] := r[cur];
cur += 1;
end;
Result := res;
end;
function FromOneDim4<T>(r: array of T; l: array of SliceType): array [,,,] of T;
begin
var dims := l.FindAll(x -> x.oneelem = False).ConvertAll(x -> x.count);
Assert(dims.Length = 4);
var cur := 0;
var res := new T[dims[0],dims[1],dims[2],dims[3]];
for var i0:=0 to dims[0]-1 do
for var i1:=0 to dims[1]-1 do
for var i2:=0 to dims[2]-1 do
for var i3:=0 to dims[3]-1 do
begin
res[i0,i1,i2,i3] := r[cur];
cur += 1;
end;
Result := res;
end;
function FromOneDimN<T>(r: array of T; l: array of SliceType): System.Array;
begin
var rank := l.Count(x -> x.oneelem = False);
case rank of
1: Result := r;
2: Result := FromOneDim2(r,l);
3: Result := FromOneDim3(r,l);
4: Result := FromOneDim4(r,l);
end;
end;
function SliceN<T>(a: array[,] of T; l: array of SliceType): System.Array;
begin
var r := ToOneDim(a,l);
Result := FromOneDimN(r,l);
end;
function SliceN<T>(a: array[,,] of T; l: array of SliceType): System.Array;
begin
var r := ToOneDim(a,l);
Result := FromOneDimN(r,l);
end;
function SliceN<T>(a: array[,,,] of T; l: array of SliceType): System.Array;
begin
var r := ToOneDim(a,l);
Result := FromOneDimN(r,l);
end;
{type
ArrT<T> = array of T;
Arr2T<T> = array [,] of T;
Arr3T<T> = array [,,] of T;
Arr4T<T> = array [,,,] of T;}
///--
function SystemSliceN1<T>(Self: array[,] of T; params l: array of SliceType): array of T; extensionmethod
:= SliceN(Self,l) as array of T;
///--
function SystemSliceN1<T>(Self: array[,,] of T; params l: array of SliceType): array of T; extensionmethod
:= SliceN(Self,l) as array of T;
///--
function SystemSliceN1<T>(Self: array[,,,] of T; params l: array of SliceType): array of T; extensionmethod
:= SliceN(Self,l) as array of T;
///--
function SystemSliceN2<T>(Self: array[,] of T; params l: array of SliceType): array[,] of T; extensionmethod
:= SliceN(Self,l) as array [,] of T;
///--
function SystemSliceN2<T>(Self: array[,,] of T; params l: array of SliceType): array[,] of T; extensionmethod
:= SliceN(Self,l) as array [,] of T;
///--
function SystemSliceN2<T>(Self: array[,,,] of T; params l: array of SliceType): array[,] of T; extensionmethod
:= SliceN(Self,l) as array [,] of T;
///--
function SystemSliceN3<T>(Self: array[,,] of T; params l: array of SliceType): array[,,] of T; extensionmethod
:= SliceN(Self,l) as array [,,] of T;
///--
function SystemSliceN3<T>(Self: array[,,,] of T; params l: array of SliceType): array[,,] of T; extensionmethod
:= SliceN(Self,l) as array [,,] of T;
///--
function SystemSliceN4<T>(Self: array[,,,] of T; params l: array of SliceType): array[,,,] of T; extensionmethod
:= SliceN(Self,l) as array [,,,] of T;
// -----------------------------------------------------
//>> Методы расширения типа integer # Extension methods for integer
// -----------------------------------------------------