2019-07-28 23:53:15 +03:00
// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt)
2017-02-19 16:29:24 +03:00
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System ;
2017-01-20 19:56:43 +03:00
using System.Collections.Generic ;
using System.Linq ;
using System.Text ;
using PascalABCCompiler.SyntaxTree ;
namespace SyntaxVisitors.SugarVisitors
{
2017-01-26 15:47:13 +03:00
public class SliceDesugarVisitor : BaseChangeVisitor
2017-01-20 19:56:43 +03:00
{
2017-01-26 15:47:13 +03:00
public static SliceDesugarVisitor New
2017-01-20 19:56:43 +03:00
{
2017-01-26 15:47:13 +03:00
get { return new SliceDesugarVisitor ( ) ; }
2017-01-20 19:56:43 +03:00
}
2021-02-24 00:47:39 +03:00
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 ) ;
var eel = new expression_list ( ) ;
2021-02-24 18:41:51 +03:00
// пытаемся разобраться с ^1
var sl1 = slice . Item1 ;
eel . Add ( sl1 ) ;
IndexVisitor . New . ProcessNode ( sl1 ) ; // индексный визитор сам не вызывается поскольку в многомерных срезах хранится List кортежей троек expression, который сам не обходится
var sl2 = slice . Item2 ;
2021-02-27 23:44:07 +03:00
eel . Add ( sl2 ) ;
2021-02-24 18:41:51 +03:00
IndexVisitor . New . ProcessNode ( sl2 ) ;
2021-02-27 23:44:07 +03:00
var sl3 = slice . Item3 ; // и step тоже надо обходить!!!
eel . Add ( sl3 ) ;
IndexVisitor . New . ProcessNode ( sl3 ) ;
2021-02-24 18:41:51 +03:00
2021-02-24 00:47:39 +03:00
var mc = new method_call ( tup , eel , sc ) ; // sc - не очень хорошо - ошибка будет в общем месте
el . Add ( mc ) ;
// по идее все параметры готовы. Надо только проверить, что они целые
}
return el ;
}
2017-01-20 19:56:43 +03:00
expression_list construct_expression_list_for_slice_expr ( slice_expr sl )
{
// situation = 0 - ничего не пропущено
// situation = 1 - пропущен from
// situation = 2 - пропущен to
// situation = 3 - пропущены from и to
// Пропущенность кодируется тем, что в соответствующем поле - int.MaxValue
// step может просто отсутствовать - это параметр по умолчанию в SystemSlice
int situation = 0 ;
2020-05-02 11:44:20 +03:00
var fromInverted = false ;
var fromExpr = sl . from ;
2017-01-20 19:56:43 +03:00
2020-05-02 11:44:20 +03:00
if ( sl . from is index fromInd )
{
2021-02-24 18:41:51 +03:00
fromInverted = fromInd . inverted ; // странно, но не используется
2020-05-02 11:44:20 +03:00
fromExpr = fromInd . index_expr ;
}
var toInverted = false ;
var toExpr = sl . to ;
if ( sl . to is index toInd )
{
2021-02-24 18:41:51 +03:00
toInverted = toInd . inverted ; // странно, но не используется
2020-05-02 11:44:20 +03:00
toExpr = toInd . index_expr ;
}
if ( ( fromExpr is int32_const ) & & ( fromExpr as int32_const ) . val = = int . MaxValue )
2017-01-20 19:56:43 +03:00
situation + = 1 ;
2020-05-02 11:44:20 +03:00
if ( ( toExpr is int32_const ) & & ( toExpr as int32_const ) . val = = int . MaxValue )
2017-01-20 19:56:43 +03:00
situation + = 2 ;
var el = new expression_list ( ) ;
el . Add ( new int32_const ( situation ) ) ;
2020-05-02 11:44:20 +03:00
el . Add ( sl . from ) ;
// Это плохо - считается 2 раза. Надо делать semantic_expr_node !!!? Нет!!!
// Если там будет лямбда, то не будет работать - известно, что semantic_expr_node не работает с лямбдами
// т.к. они несколько раз обходят код.
2017-01-20 19:56:43 +03:00
el . Add ( sl . to ) ;
if ( sl . step ! = null )
el . Add ( sl . step ) ;
return el ;
}
2020-05-05 18:58:06 +03:00
/ *
2020-05-02 11:44:20 +03:00
public override void Exit ( syntax_tree_node st )
2020-04-03 11:48:15 +03:00
{
2020-05-02 11:44:20 +03:00
if ( st is slice_expr_question )
{
ProceedSliceQuestionExpr ( st as slice_expr_question ) ;
} else if ( st is slice_expr )
2020-04-03 11:48:15 +03:00
{
2020-05-02 11:44:20 +03:00
ProceedSliceExpr ( st as slice_expr ) ;
2020-04-03 11:48:15 +03:00
}
2020-05-05 18:58:06 +03:00
} * /
2020-05-02 11:44:20 +03:00
public override void visit ( assign _assign )
{
2020-05-05 18:58:06 +03:00
_assign . from . visit ( this ) ;
_assign . to . visit ( this ) ;
2020-05-02 11:44:20 +03:00
}
2020-05-05 18:58:06 +03:00
public override void visit ( slice_expr sl )
2017-01-21 00:33:12 +03:00
{
2021-02-24 00:47:39 +03:00
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 ) ; // то это многомерный массив
// надо как-то запретить многомерные слайсы в левой части присваивания
2019-12-27 10:23:08 +03:00
if ( sl . Parent is assign parent_assign & & parent_assign . to = = sl )
{
2021-02-24 00:47:39 +03:00
// если это многомерный слайс - кинуть ошибку
if ( sl . slices ! = null )
{
// запретим пока или вовсе
throw new SyntaxVisitorError ( "MULTIDIMENSIONAL_SLICES_FORBIDDEN_IN_LEFT_SIDE_OF_ASSIGNMENT" , sl . source_context ) ;
}
2019-12-27 10:23:08 +03:00
el . Insert ( 0 , parent_assign . from ) ;
2020-03-19 12:43:07 +03:00
var mc = method_call . NewP (
2019-12-27 10:23:08 +03:00
dot_node . NewP (
sl . v ,
new ident ( "SystemSliceAssignment" , sl . v . source_context ) ,
sl . v . source_context ) ,
2020-03-19 12:43:07 +03:00
el , sl . source_context ) ;
var systemSliceAssignmentCall = new procedure_call ( mc , sl . source_context ) ;
var typeCompatibilityCheck = GetAssignmentTypeCompatibilityCheck ( sl , parent_assign . from , mc ) ;
2019-12-27 10:23:08 +03:00
var checkAndDesugaredSliceBlock = new statement_list ( typeCompatibilityCheck , systemSliceAssignmentCall ) ;
checkAndDesugaredSliceBlock . source_context = sl . source_context ;
ReplaceUsingParent ( parent_assign , checkAndDesugaredSliceBlock ) ;
2020-03-19 12:43:07 +03:00
visit ( systemSliceAssignmentCall ) ; // обойти заменённое на предмет наличия такого же синтаксического с а х а р а
2019-12-27 10:23:08 +03:00
}
else
{
2021-02-24 00:47:39 +03:00
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 ) ;
2021-02-24 18:41:51 +03:00
var sug = sugared_addressed_value . NewP ( sl , mc , sl . source_context ) ;
2021-02-24 00:47:39 +03:00
// пока без семантической проверки
2021-02-24 18:41:51 +03:00
ReplaceUsingParent ( sl , sug ) ;
2021-02-24 00:47:39 +03:00
visit ( mc ) ;
}
2019-12-27 10:23:08 +03:00
}
2017-01-21 00:33:12 +03:00
}
2020-05-05 18:58:06 +03:00
public override void visit ( slice_expr_question sl )
2017-01-20 19:56:43 +03:00
{
2020-03-19 12:43:07 +03:00
if ( sl . Parent is assign parent_assign & & parent_assign . to = = sl )
{
throw new SyntaxVisitorError ( "CAN_NOT_ASSIGN_TO_LEFT_PART" , sl . source_context ) ;
}
2017-01-20 19:56:43 +03:00
var el = construct_expression_list_for_slice_expr ( sl ) ;
2017-02-06 11:02:42 +03:00
var mc = method_call . NewP ( dot_node . NewP ( sl . v , new ident ( "SystemSliceQuestion" , sl . v . source_context ) , sl . v . source_context ) , el , sl . source_context ) ;
var sug = sugared_addressed_value . NewP ( sl , mc , sl . source_context ) ;
2017-01-21 00:33:12 +03:00
ReplaceUsingParent ( sl , sug ) ;
2017-01-20 19:56:43 +03:00
visit ( mc ) ; // обойти заменённое на предмет наличия такого же синтаксического с а х а р а
}
2020-03-19 12:43:07 +03:00
private semantic_check_sugared_statement_node GetAssignmentTypeCompatibilityCheck ( expression expression1 , expression expression2 , expression expression3 ) = >
new semantic_check_sugared_statement_node ( SemanticCheckType . SliceAssignmentTypeCompatibility , new List < syntax_tree_node > ( ) { expression1 , expression2 , expression3 } ) ;
2017-01-20 19:56:43 +03:00
}
}