Add else case and tests
This commit is contained in:
parent
f5cf7d8179
commit
d257bbd52f
|
|
@ -2,7 +2,7 @@
|
|||
// This CSharp output file generated by Gardens Point LEX
|
||||
// Version: 1.1.3.301
|
||||
// Machine: ALEXANDER-PC
|
||||
// DateTime: 11.05.2018 13:59:31
|
||||
// DateTime: 11.05.2018 18:06:46
|
||||
// UserName: Alexander
|
||||
// GPLEX input file <ABCPascal.lex>
|
||||
// GPLEX frame file <embedded resource>
|
||||
|
|
|
|||
|
|
@ -2537,9 +2537,9 @@ if_stmt
|
|||
;
|
||||
|
||||
match_with
|
||||
: tkMatch expr_l1 tkWith pattern_cases tkEnd
|
||||
: tkMatch expr_l1 tkWith pattern_cases else_case tkEnd
|
||||
{
|
||||
$$ = new match_with($2, $4 as pattern_cases);
|
||||
$$ = new match_with($2, $4 as pattern_cases, $5 as statement, @$);
|
||||
}
|
||||
;
|
||||
|
||||
|
|
@ -2559,11 +2559,11 @@ pattern_case
|
|||
{ $$ = new empty_statement(); }
|
||||
| pattern tkWhen expr_l1 tkColon unlabelled_stmt
|
||||
{
|
||||
$$ = new pattern_case($1 as pattern_node, $5 as statement, $3);
|
||||
$$ = new pattern_case($1 as pattern_node, $5 as statement, $3, @$);
|
||||
}
|
||||
| pattern tkColon unlabelled_stmt
|
||||
{
|
||||
$$ = new pattern_case($1 as pattern_node, $3 as statement, null);
|
||||
$$ = new pattern_case($1 as pattern_node, $3 as statement, null, @$);
|
||||
}
|
||||
;
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -3787,6 +3787,7 @@ namespace PascalABCCompiler.SyntaxTree
|
|||
pre_do_visit(_match_with);
|
||||
visit(match_with.expr);
|
||||
visit(match_with.case_list);
|
||||
visit(match_with.defaultAction);
|
||||
post_do_visit(_match_with);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3986,6 +3986,7 @@ namespace PascalABCCompiler.SyntaxTree
|
|||
read_statement(_match_with);
|
||||
_match_with.expr = _read_node() as expression;
|
||||
_match_with.case_list = _read_node() as pattern_cases;
|
||||
_match_with.defaultAction = _read_node() as statement;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6239,6 +6239,15 @@ namespace PascalABCCompiler.SyntaxTree
|
|||
bw.Write((byte)1);
|
||||
_match_with.case_list.visit(this);
|
||||
}
|
||||
if (_match_with.defaultAction == null)
|
||||
{
|
||||
bw.Write((byte)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
bw.Write((byte)1);
|
||||
_match_with.defaultAction.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -47878,25 +47878,28 @@ namespace PascalABCCompiler.SyntaxTree
|
|||
///<summary>
|
||||
///Конструктор с параметрами.
|
||||
///</summary>
|
||||
public match_with(expression _expr,pattern_cases _case_list)
|
||||
public match_with(expression _expr,pattern_cases _case_list,statement _defaultAction)
|
||||
{
|
||||
this._expr=_expr;
|
||||
this._case_list=_case_list;
|
||||
this._defaultAction=_defaultAction;
|
||||
FillParentsInDirectChilds();
|
||||
}
|
||||
|
||||
///<summary>
|
||||
///Конструктор с параметрами.
|
||||
///</summary>
|
||||
public match_with(expression _expr,pattern_cases _case_list,SourceContext sc)
|
||||
public match_with(expression _expr,pattern_cases _case_list,statement _defaultAction,SourceContext sc)
|
||||
{
|
||||
this._expr=_expr;
|
||||
this._case_list=_case_list;
|
||||
this._defaultAction=_defaultAction;
|
||||
source_context = sc;
|
||||
FillParentsInDirectChilds();
|
||||
}
|
||||
protected expression _expr;
|
||||
protected pattern_cases _case_list;
|
||||
protected statement _defaultAction;
|
||||
|
||||
///<summary>
|
||||
///
|
||||
|
|
@ -47928,6 +47931,21 @@ namespace PascalABCCompiler.SyntaxTree
|
|||
}
|
||||
}
|
||||
|
||||
///<summary>
|
||||
///
|
||||
///</summary>
|
||||
public statement defaultAction
|
||||
{
|
||||
get
|
||||
{
|
||||
return _defaultAction;
|
||||
}
|
||||
set
|
||||
{
|
||||
_defaultAction=value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary> Создает копию узла </summary>
|
||||
public override syntax_tree_node Clone()
|
||||
|
|
@ -47951,6 +47969,11 @@ namespace PascalABCCompiler.SyntaxTree
|
|||
copy.case_list = (pattern_cases)case_list.Clone();
|
||||
copy.case_list.Parent = copy;
|
||||
}
|
||||
if (defaultAction != null)
|
||||
{
|
||||
copy.defaultAction = (statement)defaultAction.Clone();
|
||||
copy.defaultAction.Parent = copy;
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
|
@ -47969,6 +47992,8 @@ namespace PascalABCCompiler.SyntaxTree
|
|||
expr.Parent = this;
|
||||
if (case_list != null)
|
||||
case_list.Parent = this;
|
||||
if (defaultAction != null)
|
||||
defaultAction.Parent = this;
|
||||
}
|
||||
|
||||
///<summary> Заполняет поля Parent во всем поддереве </summary>
|
||||
|
|
@ -47978,6 +48003,7 @@ namespace PascalABCCompiler.SyntaxTree
|
|||
attributes?.FillParentsInAllChilds();
|
||||
expr?.FillParentsInAllChilds();
|
||||
case_list?.FillParentsInAllChilds();
|
||||
defaultAction?.FillParentsInAllChilds();
|
||||
}
|
||||
|
||||
///<summary>
|
||||
|
|
@ -47987,7 +48013,7 @@ namespace PascalABCCompiler.SyntaxTree
|
|||
{
|
||||
get
|
||||
{
|
||||
return 2;
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
///<summary>
|
||||
|
|
@ -47997,7 +48023,7 @@ namespace PascalABCCompiler.SyntaxTree
|
|||
{
|
||||
get
|
||||
{
|
||||
return 2;
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
///<summary>
|
||||
|
|
@ -48015,6 +48041,8 @@ namespace PascalABCCompiler.SyntaxTree
|
|||
return expr;
|
||||
case 1:
|
||||
return case_list;
|
||||
case 2:
|
||||
return defaultAction;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -48030,6 +48058,9 @@ namespace PascalABCCompiler.SyntaxTree
|
|||
case 1:
|
||||
case_list = (pattern_cases)value;
|
||||
break;
|
||||
case 2:
|
||||
defaultAction = (statement)value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -382,6 +382,11 @@ namespace PascalABCCompiler.SyntaxTree
|
|||
return new bin_expr(left, right, Operators.Less);
|
||||
}
|
||||
|
||||
public static bin_expr LogicalAnd(expression left, expression right)
|
||||
{
|
||||
return new bin_expr(left, right, Operators.LogicalAND);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0} {2} {1}", left, right, OperatorServices.ToString(operation_type, LanguageId.PascalABCNET));
|
||||
|
|
|
|||
|
|
@ -2901,6 +2901,7 @@
|
|||
<Fields>
|
||||
<SyntaxField Name="expr" SyntaxType="expression" />
|
||||
<SyntaxField Name="case_list" SyntaxType="pattern_cases" />
|
||||
<SyntaxField Name="defaultAction" SyntaxType="statement" />
|
||||
</Fields>
|
||||
<Methods />
|
||||
<Tags>
|
||||
|
|
@ -3680,6 +3681,7 @@
|
|||
<HelpData Key="loop_stmt.stmt" Value="" />
|
||||
<HelpData Key="match_with" Value="" />
|
||||
<HelpData Key="match_with.case_list" Value="" />
|
||||
<HelpData Key="match_with.defaultAction" Value="" />
|
||||
<HelpData Key="match_with.expr" Value="" />
|
||||
<HelpData Key="matching_expression" Value="" />
|
||||
<HelpData Key="matching_expression.left" Value="" />
|
||||
|
|
@ -3841,6 +3843,7 @@
|
|||
<HelpData Key="pattern_case" Value="" />
|
||||
<HelpData Key="pattern_case.case_action" Value="" />
|
||||
<HelpData Key="pattern_case.condition" Value="" />
|
||||
<HelpData Key="pattern_case.isDefault" Value="" />
|
||||
<HelpData Key="pattern_case.pattern" Value="" />
|
||||
<HelpData Key="pattern_cases" Value="" />
|
||||
<HelpData Key="pattern_cases.elements" Value="" />
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ namespace SyntaxVisitors.SugarVisitors
|
|||
|
||||
private int _variableCounter = 0;
|
||||
private if_node _previousIf;
|
||||
private statement_list desugaredMatchWith;
|
||||
private statement desugaredMatchWith;
|
||||
|
||||
public static MatchWithVisitor New => new MatchWithVisitor();
|
||||
|
||||
|
|
@ -67,8 +67,11 @@ namespace SyntaxVisitors.SugarVisitors
|
|||
DesugarDeconstructorPatternCase(matchWith.expr, patternCase);
|
||||
}
|
||||
|
||||
if (matchWith.defaultAction != null)
|
||||
AddDefaultCase(matchWith.defaultAction as statement_list);
|
||||
|
||||
if (desugaredMatchWith == null)
|
||||
return;
|
||||
desugaredMatchWith = new empty_statement();
|
||||
|
||||
// Замена выражения match with на новое несахарное поддерево и его обход
|
||||
ReplaceUsingParent(matchWith, desugaredMatchWith);
|
||||
|
|
@ -116,18 +119,23 @@ namespace SyntaxVisitors.SugarVisitors
|
|||
var desugaredPattern = DesugarPattern(pattern, matchingExpression);
|
||||
result.Add(desugaredPattern.CastVariableDefinition);
|
||||
|
||||
if (patternCase.condition != null)
|
||||
// Если есть секция when - добавляем ее в условие
|
||||
{
|
||||
// TODO: generate check for 'when'
|
||||
}
|
||||
|
||||
|
||||
// Создание тела if из объявлений переменных, вызова Deconstruct и соответствующего тела case
|
||||
var ifBody = new statement_list();
|
||||
ifBody.Add(new desugared_deconstruction(desugaredPattern.DeconstructionVariables, desugaredPattern.CastVariable, patternCase.pattern.source_context));
|
||||
ifBody.Add(desugaredPattern.DeconstructCall);
|
||||
ifBody.Add(patternCase.case_action);
|
||||
var ifCheck = SubtreeCreator.CreateIf(desugaredPattern.TypeCastCheck, ifBody);
|
||||
|
||||
if (patternCase.condition != null)
|
||||
{
|
||||
// Выполняем тело, если выполняется условие when
|
||||
ifBody.Add(SubtreeCreator.CreateIf(patternCase.condition, patternCase.case_action));
|
||||
}
|
||||
else
|
||||
ifBody.Add(patternCase.case_action);
|
||||
|
||||
var ifCondition = desugaredPattern.TypeCastCheck;
|
||||
var ifCheck = SubtreeCreator.CreateIf(ifCondition, ifBody);
|
||||
|
||||
result.Add(ifCheck);
|
||||
|
||||
|
|
@ -140,13 +148,21 @@ namespace SyntaxVisitors.SugarVisitors
|
|||
return new ident("<>patternGenVar" + _variableCounter++);
|
||||
}
|
||||
|
||||
private void AddDefaultCase(statement_list statements)
|
||||
{
|
||||
AddDesugaredCaseToResult(statements, _previousIf);
|
||||
}
|
||||
|
||||
private void AddDesugaredCaseToResult(statement_list statements, if_node newIf)
|
||||
{
|
||||
// Если результат пустой, значит это первый case
|
||||
if (desugaredMatchWith == null)
|
||||
desugaredMatchWith = statements;
|
||||
else
|
||||
{
|
||||
_previousIf.else_body = statements;
|
||||
_previousIf.FillParentsInDirectChilds();
|
||||
}
|
||||
|
||||
// Запоминаем только что сгенерированный if
|
||||
_previousIf = newIf;
|
||||
|
|
|
|||
15
TestSuite/patterns-deconstruct-default.pas
Normal file
15
TestSuite/patterns-deconstruct-default.pas
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
begin
|
||||
match 'asd' with
|
||||
string(s):
|
||||
match s with
|
||||
integer(i): Assert(false);
|
||||
string(s1) when s.Length > 1: ;
|
||||
else Assert(false);
|
||||
end;
|
||||
end;
|
||||
|
||||
match 'asd' with
|
||||
integer(i): Assert(false);
|
||||
string(s1) when s1.Length > 3: Assert(false);
|
||||
end;
|
||||
end.
|
||||
34
TestSuite/patterns-deconstruct-generic-extension.pas
Normal file
34
TestSuite/patterns-deconstruct-generic-extension.pas
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
|
||||
procedure Deconstruct<T>(self: List<T>; var f: T); extensionmethod;
|
||||
begin
|
||||
if self.Count > 0 then f := self[0];
|
||||
end;
|
||||
|
||||
procedure Deconstruct<T>(self: Dictionary<integer,List<T>>; var f: T); extensionmethod;
|
||||
begin
|
||||
var fst := self.First;
|
||||
var lst := fst.Value;
|
||||
if not (lst = nil) and (lst.Count > 0) then
|
||||
f := lst[0];
|
||||
end;
|
||||
|
||||
procedure Deconstruct<K,V>(self: Dictionary<K,V>; var kk: Dictionary<List<K>, V>; var vv: V); extensionmethod;
|
||||
begin
|
||||
kk := Dict((self.Keys.ToList, self.Values.First));
|
||||
end;
|
||||
|
||||
begin
|
||||
var pair := ('asd', Arr(1,2,3).ToList);
|
||||
var lst := Arr(4,5,6).ToList as object;
|
||||
var d := Dict(Arr(pair)) as object;
|
||||
var d2 := Dict((7, 8.0)) as object;
|
||||
var collection := Arr(lst, d, d2);
|
||||
foreach var x in collection do
|
||||
match x with
|
||||
Dictionary<integer,real>(s; k): Assert((s is Dictionary<List<integer>, real>) and (k is real));
|
||||
Dictionary<string,List<integer>>(first): Assert(first['asd'][0] = 1);
|
||||
List<real>(l: real): Assert(false);
|
||||
List<integer>(first: integer): Assert(first = 4);
|
||||
else Assert(false)
|
||||
end;
|
||||
end.
|
||||
38
TestSuite/patterns-lambda-test.pas
Normal file
38
TestSuite/patterns-lambda-test.pas
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
uses System.Linq;
|
||||
|
||||
begin
|
||||
match 'a b c'.Any(x -> x = 'a') with
|
||||
string(s): Assert(false);
|
||||
boolean(b): Assert(b);
|
||||
integer(i): Assert(false);
|
||||
else Assert(false)
|
||||
end;
|
||||
|
||||
var count := 0;
|
||||
match Arr('aa', 'bb').Select(x -> x = 'aa' ? x : nil).ToList with
|
||||
List<string>(l):
|
||||
foreach var x in l do
|
||||
if not (x = nil) then
|
||||
loop 5 do count += 1;
|
||||
end;
|
||||
Assert(count = 5);
|
||||
|
||||
match 'a b c'.Any(x -> x = 'a') with
|
||||
string(s): Assert(false);
|
||||
boolean(b):
|
||||
begin
|
||||
var r := Enumerable
|
||||
.Repeat(b, 3)
|
||||
.Select(
|
||||
x ->
|
||||
begin
|
||||
match x with
|
||||
boolean(b): Result := not b;
|
||||
end;
|
||||
end);
|
||||
Assert(Enumerable.Repeat(false, 3).SequenceEqual(r));
|
||||
end;
|
||||
integer(i): Assert(false);
|
||||
else Assert(false);
|
||||
end;
|
||||
end.
|
||||
6
TestSuite/patterns-nil-test.pas
Normal file
6
TestSuite/patterns-nil-test.pas
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
begin
|
||||
match nil with
|
||||
List<integer>(s): Assert(false);
|
||||
integer(i): Assert(false);
|
||||
end;
|
||||
end.
|
||||
28
TestSuite/patterns-overloading-and-ambiguity.pas
Normal file
28
TestSuite/patterns-overloading-and-ambiguity.pas
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
type
|
||||
My<T> = class
|
||||
public
|
||||
_a: T;
|
||||
|
||||
private
|
||||
procedure Deconstruct(var a: T);
|
||||
begin
|
||||
Println('Instance');
|
||||
a := _a;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure Deconstruct<T>(self: My<T>; var a: T);
|
||||
begin
|
||||
Println('Ext');
|
||||
a := self._a;
|
||||
end;
|
||||
|
||||
begin
|
||||
var l := new My<List<integer>>;
|
||||
l._a := Arr(1, 2, 3).ToList;
|
||||
match l with
|
||||
My<real>(a): Assert(false);
|
||||
My<integer>(a): Assert(false);
|
||||
My<List<integer>>(a): Assert(a[0] = 1);
|
||||
end;
|
||||
end.
|
||||
|
|
@ -69,6 +69,14 @@ namespace TreeConverter.LambdaExpressions
|
|||
syntaxTreeVisitor.visit(varStmt);
|
||||
}
|
||||
|
||||
// Patterns
|
||||
public override void visit(desugared_deconstruction _desugared_deconstruction)
|
||||
{
|
||||
// позволяем вывести типы объявленных переменных
|
||||
syntaxTreeVisitor.visit(_desugared_deconstruction);
|
||||
}
|
||||
// !Patterns
|
||||
|
||||
public override void visit(assign assignment)
|
||||
{
|
||||
var to = assignment.to as ident;
|
||||
|
|
|
|||
|
|
@ -11,16 +11,6 @@ namespace PascalABCCompiler.TreeConverter
|
|||
// Patterns
|
||||
public partial class syntax_tree_visitor
|
||||
{
|
||||
private void CheckWhenExpression(SyntaxTree.expression when)
|
||||
{
|
||||
if (when == null)
|
||||
return;
|
||||
|
||||
var convertedWhen = convert_strong(when);
|
||||
if (!convertion_data_and_alghoritms.can_convert_type(convertedWhen, SystemLibrary.SystemLibrary.bool_type))
|
||||
AddError(get_location(when), "WHEN_EXPRESSION_SHOULD_HAVE_BOOL_TYPE");
|
||||
}
|
||||
|
||||
public override void visit(desugared_deconstruction deconstruction)
|
||||
{
|
||||
var invokationTarget = convert_strong(deconstruction.deconstruction_target as expression);
|
||||
|
|
@ -94,7 +84,7 @@ namespace PascalABCCompiler.TreeConverter
|
|||
{
|
||||
parameterTypes = new type_node[givenParameterTypes.Length];
|
||||
var selfParameter = candidate.is_extension_method ? candidate.parameters.First(IsSelfParameter) : null;
|
||||
Debug.Assert(!candidate.is_extension_method || selfParameter != null, "Couldn't find self in extension method");
|
||||
Debug.Assert(!candidate.is_extension_method || selfParameter != null, "Couldn't find self parameter in extension method");
|
||||
var candidateParameterTypes =
|
||||
candidate.is_extension_method ?
|
||||
candidate.parameters.Where(x => !IsSelfParameter(x)).ToArray() :
|
||||
|
|
@ -111,10 +101,11 @@ namespace PascalABCCompiler.TreeConverter
|
|||
var nils = new List<int>();
|
||||
var deduceSucceded = generic_convertions.DeduceInstanceTypes(selfParameter.type, patternInstance.type, deducedGenerics, nils);
|
||||
if (!deduceSucceded || deducedGenerics.Contains(null))
|
||||
{
|
||||
AddError(deconstructionLocation, "COULDNT_DEDUCE_DECONSTRUCT_GENERIC_TYPE");
|
||||
// Проверка на то, что в Deconstruct все дженерики выводятся по self делается в другом месте
|
||||
// TODO: сделать проверку
|
||||
// TODO: запретить дженерик методы в классах. Можно использовать только дженерик-типы самого класса в качестве параметров
|
||||
//AddError(deconstructionLocation, "COULDNT_DEDUCE_DECONSTRUCT_GENERIC_TYPE");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < givenParameterTypes.Length; i++)
|
||||
|
|
@ -122,7 +113,7 @@ namespace PascalABCCompiler.TreeConverter
|
|||
var givenParameter = givenParameterTypes[i];
|
||||
var candidateParameter = candidateParameterTypes[i].type;
|
||||
if (genericDeduceNeeded && (candidateParameter.is_generic_parameter || candidateParameter.is_generic_type_instance))
|
||||
candidateParameter = InstantiateParameter(candidateParameter, deducedGenerics);//candidateParameter.get_instance(deducedGenerics.ToList());
|
||||
candidateParameter = InstantiateParameter(candidateParameter, deducedGenerics);
|
||||
|
||||
if (givenParameter != null && !AreTheSameTypes(candidateParameter, givenParameter))
|
||||
return false;
|
||||
|
|
@ -183,11 +174,6 @@ namespace PascalABCCompiler.TreeConverter
|
|||
var genericNode = (genericType as generic_instance_type_node);
|
||||
if (genericNode != null)
|
||||
{
|
||||
//var genericParameters = genericNode.instance_params;
|
||||
|
||||
//for (int i = 0; i < genericParameters.Count; i++)
|
||||
// genericParameters[i] = InstantiateParameter(genericParameters[i], instances);
|
||||
|
||||
var parameters = genericNode.instance_params.Select(x => InstantiateParameter(x, instances)).ToList();
|
||||
genericNode.instance_params = parameters;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue