This commit is contained in:
Ivan Bondarev 2020-12-27 12:18:28 +01:00
parent b87ceaeff2
commit 460247ccc6
20 changed files with 347 additions and 36 deletions

View file

@ -6,6 +6,6 @@ namespace PascalABCCompiler.PCU
{
public static class PCUFileFormatVersion
{
public static System.Int16 Version = 116;
public static System.Int16 Version = 117;
}
}

View file

@ -3502,7 +3502,12 @@ namespace PascalABCCompiler.PCU
{
return new question_colon_expression(CreateExpression(), CreateExpression(), CreateExpression(), null);
}
private double_question_colon_expression CreateDoubleQuestionColonExpression()
{
return new double_question_colon_expression(CreateExpression(), CreateExpression(), null);
}
private statements_expression_node CreateStatementsExpressionNode()
{
statement_node_list sl = new statement_node_list();
@ -3551,6 +3556,8 @@ namespace PascalABCCompiler.PCU
return CreateStatementsExpressionNode();
case semantic_node_type.question_colon_expression:
return CreateQuestionColonExpression();
case semantic_node_type.double_question_colon_expression:
return CreateDoubleQuestionColonExpression();
case semantic_node_type.sizeof_operator:
return CreateSizeOfOperator();
case semantic_node_type.is_node:

View file

@ -3634,7 +3634,13 @@ namespace PascalABCCompiler.PCU
VisitExpression(node.internal_ret_if_true);
VisitExpression(node.internal_ret_if_false);
}
private void VisitDoubleQuestionColonExpression(double_question_colon_expression node)
{
VisitExpression(node.internal_condition);
VisitExpression(node.internal_ret_if_null);
}
private void VisitStatementsExpressionNode(statements_expression_node node)
{
bw.Write(node.internal_statements.Count);
@ -3677,6 +3683,8 @@ namespace PascalABCCompiler.PCU
VisitStatementsExpressionNode((statements_expression_node)en); break;
case semantic_node_type.question_colon_expression:
VisitQuestionColonExpression((question_colon_expression)en); break;
case semantic_node_type.double_question_colon_expression:
VisitDoubleQuestionColonExpression((double_question_colon_expression)en); break;
case semantic_node_type.sizeof_operator:
VisitSizeOfOperator((sizeof_operator)en); break;
case semantic_node_type.is_node:

View file

@ -10411,6 +10411,57 @@ namespace PascalABCCompiler.NETGenerator
}
public override void visit(IDoubleQuestionColonExpressionNode value)
{
Label EndLabel = il.DefineLabel();
Label NullLabel = il.DefineLabel();
bool tmp_is_dot_expr = is_dot_expr;
bool tmp_is_addr = is_addr;
is_dot_expr = false;//don't box the condition expression
is_addr = false;
LocalBuilder tmp_lb = null;
if (value.condition is IBasicFunctionCallNode &&
(value.condition as IBasicFunctionCallNode).real_parameters[0].type.IsDelegate &&
(value.condition as IBasicFunctionCallNode).real_parameters[1] is INullConstantNode &&
(value.condition as IBasicFunctionCallNode).basic_function.basic_function_type == basic_function_type.objeq)
{
IBasicFunctionCallNode eq = (value.condition as IBasicFunctionCallNode);
tmp_lb = il.DeclareLocal(helper.GetTypeReference((value.condition as IBasicFunctionCallNode).real_parameters[0].type).tp);
eq.real_parameters[0].visit(this);
il.Emit(OpCodes.Stloc, tmp_lb);
il.Emit(OpCodes.Ldloc, tmp_lb);
il.Emit(OpCodes.Ldnull);
il.Emit(OpCodes.Ceq);
}
else
{
value.condition.visit(this);
tmp_lb = il.DeclareLocal(helper.GetTypeReference(value.type).tp);
il.Emit(OpCodes.Stloc, tmp_lb);
il.Emit(OpCodes.Ldloc, tmp_lb);
il.Emit(OpCodes.Ldnull);
il.Emit(OpCodes.Ceq);
}
is_dot_expr = tmp_is_dot_expr;
is_addr = tmp_is_addr;
il.Emit(OpCodes.Brtrue, NullLabel);
il.Emit(OpCodes.Ldloc, tmp_lb);
TypeInfo ti = helper.GetTypeReference(value.condition.type);
if (ti != null)
EmitBox(value.condition, ti.tp);
il.Emit(OpCodes.Br, EndLabel);
il.MarkLabel(NullLabel);
value.ret_if_null.visit(this);
ti = helper.GetTypeReference(value.ret_if_null.type);
if (ti != null)
EmitBox(value.ret_if_null, ti.tp);
il.MarkLabel(EndLabel);
}
private Hashtable range_stmts_labels = new Hashtable();
//перевод селекторов-диапазонов case

View file

@ -646,6 +646,11 @@ namespace PascalABCCompiler.SemanticTree
{
}
public virtual void visit(IDoubleQuestionColonExpressionNode value)
{
}
}
}

View file

@ -299,6 +299,8 @@ namespace PascalABCCompiler.SemanticTree
void visit(ICommonNamespaceEventNode value);
void visit(IDefaultOperatorNodeAsConstant value);
}
void visit(IDoubleQuestionColonExpressionNode value);
}
}

View file

@ -2241,7 +2241,20 @@ namespace PascalABCCompiler.SemanticTree
}
}
public interface ILabelNode : IDefinitionNode, ILocated
public interface IDoubleQuestionColonExpressionNode : IExpressionNode
{
IExpressionNode condition
{
get;
}
IExpressionNode ret_if_null
{
get;
}
}
public interface ILabelNode : IDefinitionNode, ILocated
{
//Имя метки. Для языков не чувствительных к регистрам хранит имя в том виде, в каком тип объявлен.
string name

View file

@ -22,7 +22,7 @@ namespace SyntaxVisitors.SugarVisitors
return num.ToString();
}
public override void visit(double_question_node dqn)
/*public override void visit(double_question_node dqn)
{
var st = dqn.Parent;
while (!(st is statement))
@ -42,6 +42,6 @@ namespace SyntaxVisitors.SugarVisitors
visit(qce);
ReplaceStatementUsingParent(st as statement, l);
visit(tt);
}
}*/
}
}

View file

@ -67,6 +67,9 @@ const
/// Константа перехода на новую строку
/// !! The newline string defined for this environment.
NewLine = System.Environment.NewLine;
/// Константа - символы-разделители слов
/// !! symbols - word delimiters
AllDelimiters = ' <>=^`|~$№§!"#%&''()*,+-./:;?@[\]_{}«­·»'#9#10#13;
//{{{--doc: Конец секции стандартных констант для документации }}}
@ -4064,20 +4067,25 @@ function CharRange.Reverse: sequence of char := Range(l,h).Reverse;
//------------------------------------------------------------------------------
// Операции для string и char
//------------------------------------------------------------------------------
///--
procedure string.operator+=(var left: string; right: string);
begin
left := left + right;
end;
///--
function string.operator<(left, right: string) := string.CompareOrdinal(left, right) < 0;
///--
function string.operator<=(left, right: string) := string.CompareOrdinal(left, right) <= 0;
///--
function string.operator>(left, right: string) := string.CompareOrdinal(left, right) > 0;
///--
function string.operator>=(left, right: string) := string.CompareOrdinal(left, right) >= 0;
/// Повторяет строку str n раз
///--
function string.operator*(str: string; n: integer): string;
begin
var sb := new StringBuilder;
@ -4086,7 +4094,7 @@ begin
Result := sb.ToString;
end;
/// Повторяет строку str n раз
///--
function string.operator*(n: integer; str: string): string;
begin
var sb := new StringBuilder;
@ -4095,7 +4103,7 @@ begin
Result := sb.ToString;
end;
/// Повторяет символ c n раз
///--
function char.operator*(c: char; n: integer): string;
begin
if n <= 0 then
@ -4109,7 +4117,7 @@ begin
Result := sb.ToString;
end;
/// Повторяет символ c n раз
///--
function char.operator*(n: integer; c: char): string;
begin
if n <= 0 then
@ -4123,18 +4131,23 @@ begin
Result := sb.ToString;
end;
/// Добавляет к строке str строковое представление числа n
// Добавляет к строке str строковое представление числа n
///--
function string.operator+(str: string; n: integer) := str + n.ToString;
/// Добавляет к строке str строковое представление числа n
// Добавляет к строке str строковое представление числа n
///--
function string.operator+(n: integer; str: string) := n.ToString + str;
/// Добавляет к строке str строковое представление числа r
// Добавляет к строке str строковое представление числа r
///--
function string.operator+(str: string; r: real) := str + r.ToString(nfi);
/// Добавляет к строке str строковое представление числа r
// Добавляет к строке str строковое представление числа r
///--
function string.operator+(r: real; str: string) := r.ToString(nfi) + str;
///--
procedure string.operator+=(var left: string; right: integer);
begin
left := left + right.ToString;
@ -12349,10 +12362,10 @@ begin
Result := Self.Split(delim, System.StringSplitOptions.RemoveEmptyEntries);
end;
const AllWordDelimiters = ' <>=^`|~$№§!"#%&''()*,+-./:;?@[\]_{}«­·»'#9#10#13;
const SpaceDelimiters = ' '+#9#10#13;
/// Преобразует строку в массив слов, используя в качестве разделителей символы из строки delim
function ToWords(Self: string; delim: string := AllWordDelimiters): array of string; extensionmethod;
function ToWords(Self: string; delim: string := SpaceDelimiters): array of string; extensionmethod;
begin
Result := Self.Split(delim.ToCharArray, System.StringSplitOptions.RemoveEmptyEntries);
end;
@ -12859,59 +12872,59 @@ function operator>=<T1,T2,T3,T4,T5,T6,T7>(Self: (T1, T2, T3, T4,T5,T6,T7); v: (T
// -------------------------------------------
// Дополнения февраль 2016
// Добавляет поле к кортежу
/// Добавляет поле к кортежу
function Add<T1, T2, T3>(Self: (T1, T2); v: T3): (T1, T2, T3); extensionmethod;
begin
Result := (Self[0], Self[1], v);
end;
// Добавляет поле к кортежу
/// Добавляет поле к кортежу
function Add<T1, T2, T3, T4>(Self: (T1, T2, T3); v: T4): (T1, T2, T3, T4); extensionmethod;
begin
Result := (Self[0], Self[1], Self[2], v);
end;
// Добавляет поле к кортежу
/// Добавляет поле к кортежу
function Add<T1, T2, T3, T4, T5>(Self: (T1, T2, T3, T4); v: T5): (T1, T2, T3, T4, T5); extensionmethod;
begin
Result := (Self[0], Self[1], Self[2], Self[3], v);
end;
// Добавляет поле к кортежу
/// Добавляет поле к кортежу
function Add<T1, T2, T3, T4, T5, T6>(Self: (T1, T2, T3, T4, T5); v: T6): (T1, T2, T3, T4, T5, T6); extensionmethod;
begin
Result := (Self[0], Self[1], Self[2], Self[3], Self[4], v);
end;
// Добавляет поле к кортежу
/// Добавляет поле к кортежу
function Add<T1, T2, T3, T4, T5, T6, T7>(Self: (T1, T2, T3, T4, T5, T6); v: T7): (T1, T2, T3, T4, T5, T6, T7); extensionmethod;
begin
Result := (Self[0], Self[1], Self[2], Self[3], Self[4], Self[5], v);
end;
// Выводит кортеж
/// Выводит кортеж
procedure Print<T1, T2>(Self: (T1, T2)); extensionmethod := Print(Self);
// Выводит кортеж
/// Выводит кортеж
procedure Print<T1, T2, T3>(Self: (T1, T2, T3)); extensionmethod := Print(Self);
// Выводит кортеж
/// Выводит кортеж
procedure Print<T1, T2, T3, T4>(Self: (T1, T2, T3, T4)); extensionmethod := Print(Self);
// Выводит кортеж
/// Выводит кортеж
procedure Print<T1, T2, T3, T4, T5>(Self: (T1, T2, T3, T4, T5)); extensionmethod := Print(Self);
// Выводит кортеж
/// Выводит кортеж
procedure Print<T1, T2, T3, T4, T5, T6>(Self: (T1, T2, T3, T4, T5, T6)); extensionmethod := Print(Self);
// Выводит кортеж
/// Выводит кортеж
procedure Print<T1, T2, T3, T4, T5, T6, T7>(Self: (T1, T2, T3, T4, T5, T6, T7)); extensionmethod := Print(Self);
// Выводит кортеж и переходит на новую строку
/// Выводит кортеж и переходит на новую строку
procedure Println<T1, T2>(Self: (T1, T2)); extensionmethod := Println(Self);
// Выводит кортеж и переходит на новую строку
/// Выводит кортеж и переходит на новую строку
procedure Println<T1, T2, T3>(Self: (T1, T2, T3)); extensionmethod := Println(Self);
// Выводит кортеж и переходит на новую строку
/// Выводит кортеж и переходит на новую строку
procedure Println<T1, T2, T3, T4>(Self: (T1, T2, T3, T4)); extensionmethod := Println(Self);
// Выводит кортеж и переходит на новую строку
/// Выводит кортеж и переходит на новую строку
procedure Println<T1, T2, T3, T4, T5>(Self: (T1, T2, T3, T4, T5)); extensionmethod := Println(Self);
// Выводит кортеж и переходит на новую строку
/// Выводит кортеж и переходит на новую строку
procedure Println<T1, T2, T3, T4, T5, T6>(Self: (T1, T2, T3, T4, T5, T6)); extensionmethod := Println(Self);
// Выводит кортеж и переходит на новую строку
/// Выводит кортеж и переходит на новую строку
procedure Println<T1, T2, T3, T4, T5, T6, T7>(Self: (T1, T2, T3, T4, T5, T6, T7)); extensionmethod := Println(Self);

View file

@ -0,0 +1,10 @@
begin
var o := new object;
var s := o ?? nil;
assert(s = o);
o := nil;
s := o ?? new object;
assert(s <> nil);
var x := nil ?? 'abc';
assert(x = 'abc');
end.

View file

@ -0,0 +1,3 @@
begin
var x := 'aaa'??2;
end.

View file

@ -0,0 +1,3 @@
begin
var x := 3??2;
end.

View file

@ -0,0 +1,3 @@
begin
var x := nil??nil;
end.

View file

@ -0,0 +1,12 @@
unit u_doublequestion1;
begin
var o := new object;
var s := o ?? nil;
assert(s = o);
o := nil;
s := o ?? new object;
assert(s <> nil);
var x := nil ?? 'abc';
assert(x = 'abc');
end.

View file

@ -0,0 +1,2 @@
//winonly
uses u_doublequestion1; begin end.

View file

@ -18059,6 +18059,115 @@ namespace PascalABCCompiler.TreeConverter
throw new NotSupportedError(get_location(_template_param_list));
}
public override void visit(double_question_node node)
{
expression_node condition = convert_strong(node.left);
convertion_data_and_alghoritms.convert_type(new null_const_node(null_type_node.get_type_node(), condition.location), condition.type);
expression_node left = condition;
expression_node right = convert_strong(node.right);
if (condition is null_const_node)
convertion_data_and_alghoritms.convert_type(new null_const_node(null_type_node.get_type_node(), right.location), right.type);
try_convert_typed_expression_to_function_call(ref left);
try_convert_typed_expression_to_function_call(ref right);
if (left is null_const_node && right.type.is_value_type)
{
if (right.type is compiled_type_node)
{
var rt = right.type as compiled_type_node;
if (!rt.compiled_type.IsGenericType || rt.compiled_type.GetGenericTypeDefinition() != typeof(System.Nullable<>))
{
right = convert_strong(ToNullable(node.right));
}
}
}
else
if (right is null_const_node && left.type.is_value_type)
{
if (left.type is compiled_type_node)
{
var lt = left.type as compiled_type_node;
if (!lt.compiled_type.IsGenericType || lt.compiled_type.GetGenericTypeDefinition() != typeof(System.Nullable<>))
{
left = convert_strong(ToNullable(node.left));
}
}
}
/*var typeComparisonResult = type_table.compare_types(left.type, right.type);
if (typeComparisonResult == type_compare.greater_type)
right = convertion_data_and_alghoritms.convert_type(right, left.type);
else left = convertion_data_and_alghoritms.convert_type(left, right.type);*/
if (left is null_const_node)
{
left = convertion_data_and_alghoritms.convert_type(left, right.type);
}
else
{
delegated_methods del_left = left.type as delegated_methods;
delegated_methods del_right = right.type as delegated_methods;
if (del_left != null && del_right != null && del_left.empty_param_method == null && del_right.empty_param_method == null)
{
base_function_call bfc = del_left.proper_methods[0];
common_type_node del =
convertion_data_and_alghoritms.type_constructor.create_delegate(context.get_delegate_type_name(), bfc.simple_function_node.return_value_type, bfc.simple_function_node.parameters, context.converted_namespace, null);
context.converted_namespace.types.AddElement(del);
right = convertion_data_and_alghoritms.explicit_convert_type(right, del);
left = convertion_data_and_alghoritms.explicit_convert_type(left, del);
}
else
{
var rtl = type_table.get_convertions(right.type, left.type);
var ltr = type_table.get_convertions(left.type, right.type);
if (ltr.first != null && rtl.first == null)
{
left = convertion_data_and_alghoritms.convert_type(left, right.type);
}
else if (ltr.first == null && rtl.first != null)
{
right = convertion_data_and_alghoritms.convert_type(right, left.type);
}
else
{
// если оба типа - целые
if (convertion_data_and_alghoritms.is_value_int_type(left.type) && convertion_data_and_alghoritms.is_value_int_type(right.type))
{
var lub = convertion_data_and_alghoritms.least_upper_bound_value_int_type(left.type, right.type);
if (lub == left.type)
right = convertion_data_and_alghoritms.convert_type(right, left.type);
else if (lub == right.type)
left = convertion_data_and_alghoritms.convert_type(left, right.type);
else
{
right = convertion_data_and_alghoritms.convert_type(right, lub);
left = convertion_data_and_alghoritms.convert_type(right, lub);
}
}
else if (left.type == SystemLibrary.SystemLibrary.float_type && right.type == SystemLibrary.SystemLibrary.double_type)
left = convertion_data_and_alghoritms.convert_type(left, right.type);
else if (right.type == SystemLibrary.SystemLibrary.float_type && left.type == SystemLibrary.SystemLibrary.double_type)
right = convertion_data_and_alghoritms.convert_type(right, left.type);
else if (left.type == right.type)
{ }
else // Это было - для совместимости. Что-то может не учтено
{
right = convertion_data_and_alghoritms.convert_type(right, left.type);
}
}
}
}
//right = convertion_data_and_alghoritms.convert_type(right, left.type);
return_value(new double_question_colon_expression(condition, right, get_location(node)));
}
public override void visit(SyntaxTree.question_colon_expression node)
{
expression_node condition = convert_strong(node.condition);

View file

@ -340,7 +340,67 @@ namespace PascalABCCompiler.TreeRealization
visitor.visit(this);
}
}
public class double_question_colon_expression : expression_node, SemanticTree.IDoubleQuestionColonExpressionNode
{
private expression_node _condition;
private expression_node _ret_if_null;
public double_question_colon_expression(expression_node condition, expression_node ret_if_null,
location loc)
: base(condition is null_const_node ? ret_if_null.type : condition.type, loc)
{
this._condition = condition;
this._ret_if_null = ret_if_null;
}
public expression_node internal_condition
{
get
{
return _condition;
}
}
public expression_node internal_ret_if_null
{
get
{
return _ret_if_null;
}
}
public SemanticTree.IExpressionNode condition
{
get
{
return _condition;
}
}
public SemanticTree.IExpressionNode ret_if_null
{
get
{
return _ret_if_null;
}
}
public override semantic_node_type semantic_node_type
{
get
{
return semantic_node_type.double_question_colon_expression;
}
}
public override void visit(SemanticTree.ISemanticVisitor visitor)
{
visitor.visit(this);
}
}
public class array_initializer : expression_node, SemanticTree.IArrayInitializer
{
private List<expression_node> _element_values;

View file

@ -38,7 +38,7 @@ namespace PascalABCCompiler.TreeRealization
common_constructor_call_as_constant, array_initializer, record_initializer, default_operator, attribute_node,
pinvoke_node, basic_function_call_node_as_constant, compiled_static_field_reference_as_constant,
common_namespace_event, indefinite_definition_node, indefinite_type, indefinite_function_call, indefinite_reference,
wrapped_statement, wrapped_expression, default_operator_node_as_constant
wrapped_statement, wrapped_expression, default_operator_node_as_constant, double_question_colon_expression
};
/// <summary>

View file

@ -1554,5 +1554,10 @@ namespace VisualPascalABCPlugins
{
throw new System.NotImplementedException();
}
public void visit(IDoubleQuestionColonExpressionNode value)
{
throw new System.NotImplementedException();
}
}
}

View file

@ -2560,5 +2560,10 @@ namespace VisualPascalABCPlugins
{
throw new System.NotImplementedException();
}
public void visit(IDoubleQuestionColonExpressionNode value)
{
throw new System.NotImplementedException();
}
}
}