From 0494a67b325f09bbaf10f5981d0aa00a9ca536ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=BD=D0=B4=D0=B0=D1=80=D0=B5=D0=B2=20=D0=98?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD?= Date: Thu, 25 May 2017 19:44:06 +0200 Subject: [PATCH] full support of Nullable (bug fix #405) --- NETGenerator/NETGenerator.cs | 241 +++++++++++++++----- PluginsSupport/Interfaces.cs | 13 +- SemanticTree/SemanticTree.cs | 7 +- TestSuite/nullable.pas | 166 ++++++++++++++ TreeConverter/TreeRealization/type_table.cs | 4 + TreeConverter/TreeRealization/types.cs | 22 +- VisualPascalABCNET/IB/Debugger/Debugger.cs | 52 +++++ VisualPlugins/TestPlugin/TestPlugin.cs | 1 - 8 files changed, 444 insertions(+), 62 deletions(-) create mode 100644 TestSuite/nullable.pas diff --git a/NETGenerator/NETGenerator.cs b/NETGenerator/NETGenerator.cs index cd8f81ede..89f3fdc48 100644 --- a/NETGenerator/NETGenerator.cs +++ b/NETGenerator/NETGenerator.cs @@ -6598,8 +6598,19 @@ namespace PascalABCCompiler.NETGenerator il.Emit(OpCodes.Stloc, start_index_lb); il.MarkLabel(lbl); } + //len_lb = EmitArguments(parameters, real_parameters, mi); + for (int i = 0; i < real_parameters.Length; i++) { + if (real_parameters[i] is INullConstantNode && parameters[i].type.is_nullable_type) + { + Type tp = helper.GetTypeReference(parameters[i].type).tp; + LocalBuilder lb = il.DeclareLocal(tp); + il.Emit(OpCodes.Ldloca, lb); + il.Emit(OpCodes.Initobj, tp); + il.Emit(OpCodes.Ldloc, lb); + continue; + } if (parameters[i].parameter_type == parameter_type.var) is_addr = true; //TODO:Переделать. @@ -6695,7 +6706,8 @@ namespace PascalABCCompiler.NETGenerator il.Emit(OpCodes.Ldloca, lb); } is_dot_expr = false; - for (int i = 0; i < real_parameters.Length; i++) + EmitArguments(parameters, real_parameters); + /*for (int i = 0; i < real_parameters.Length; i++) { if (parameters[i].parameter_type == parameter_type.var) is_addr = true; @@ -6707,7 +6719,7 @@ namespace PascalABCCompiler.NETGenerator if (ctn2 != null && (ctn3.is_value_type || ctn3.is_generic_parameter) && ctn2.compiled_type == TypeFactory.ObjectType) il.Emit(OpCodes.Box, helper.GetTypeReference(ctn3).tp); is_addr = false; - } + }*/ MethodInfo mi = value.compiled_method.method_info; if (value.compiled_method.comperehensive_type.is_value_type || !value.virtual_call && value.compiled_method.polymorphic_state == polymorphic_state.ps_virtual || value.compiled_method.polymorphic_state == polymorphic_state.ps_static) { @@ -6751,7 +6763,8 @@ namespace PascalABCCompiler.NETGenerator is_dot_expr = false; bool is_comp_gen = false; IParameterNode[] parameters = value.static_method.parameters; - for (int i = 0; i < real_parameters.Length; i++) + EmitArguments(parameters, real_parameters); + /*for (int i = 0; i < real_parameters.Length; i++) { if (parameters[i].parameter_type == parameter_type.var) is_addr = true; @@ -6779,7 +6792,7 @@ namespace PascalABCCompiler.NETGenerator if (box_awaited) il.Emit(OpCodes.Box, helper.GetTypeReference(ctn3).tp); is_addr = false; - } + }*/ //if (save_debug_info && need_fee) // MarkSequencePoint(il, value.Location); il.EmitCall(OpCodes.Call, mi, null); @@ -6851,7 +6864,8 @@ namespace PascalABCCompiler.NETGenerator //bool is_comp_gen = false; //bool need_fee = false; IParameterNode[] parameters = value.method.parameters; - for (int i = 0; i < real_parameters.Length; i++) + EmitArguments(parameters, real_parameters); + /*for (int i = 0; i < real_parameters.Length; i++) { if (parameters[i].parameter_type == parameter_type.var) is_addr = true; @@ -6881,7 +6895,7 @@ namespace PascalABCCompiler.NETGenerator if (box_awaited) il.Emit(OpCodes.Box, helper.GetTypeReference(ctn3).tp); is_addr = false; - } + }*/ //вызов метода //(ssyy) Функции размерных типов всегда вызываются через call if (value.method.comperehensive_type.is_value_type || !value.virtual_call && value.method.polymorphic_state == polymorphic_state.ps_virtual || value.method.polymorphic_state == polymorphic_state.ps_static /*|| !value.virtual_call || (value.method.polymorphic_state != polymorphic_state.ps_virtual && value.method.polymorphic_state != polymorphic_state.ps_virtual_abstract && !value.method.common_comprehensive_type.IsInterface)*/) @@ -7241,41 +7255,10 @@ namespace PascalABCCompiler.NETGenerator } bool tmp_dot = is_dot_expr; is_dot_expr = false; - bool is_comp_gen = false; + MethodInfo mi = meth.mi; IParameterNode[] parameters = value.namespace_function.parameters; - for (int i = 0; i < real_parameters.Length; i++) - { - if (parameters[i].parameter_type == parameter_type.var) - is_addr = true; - ITypeNode ctn = real_parameters[i].type; - TypeInfo ti = null; - - //(ssyy) moved up - ITypeNode tn2 = parameters[i].type; - ICompiledTypeNode ctn2 = tn2 as ICompiledTypeNode; - ITypeNode ctn3 = real_parameters[i].type; - //(ssyy) 07.12.2007 При боксировке нужно вызывать Ldsfld вместо Ldsflda. - //Дополнительная проверка введена именно для этого. - bool box_awaited = - (ctn2 != null && ctn2.compiled_type == TypeFactory.ObjectType || tn2.IsInterface) && !(real_parameters[i] is SemanticTree.INullConstantNode) && (ctn3.is_value_type || ctn3.is_generic_parameter); - if (!(real_parameters[i] is INullConstantNode)) - { - ti = helper.GetTypeReference(ctn); - if (ti.clone_meth != null && ti.tp != null && ti.tp.IsValueType && !box_awaited && !parameters[i].is_const) - is_dot_expr = true; - } - //if (is_comp_gen == false) - is_comp_gen = CheckForCompilerGenerated(real_parameters[i]); - real_parameters[i].visit(this); - is_dot_expr = false; - CallCloneIfNeed(il, parameters[i], real_parameters[i]); - if (box_awaited) - { - il.Emit(OpCodes.Box, helper.GetTypeReference(ctn3).tp); - } - is_addr = false; - } + EmitArguments(parameters, real_parameters); il.EmitCall(OpCodes.Call, mi, null); EmitFreePinnedVariables(); if (tmp_dot == true) @@ -7295,7 +7278,52 @@ namespace PascalABCCompiler.NETGenerator il.Emit(OpCodes.Nop); //if (is_stmt == true) il.Emit(OpCodes.Pop); } + + private void EmitArguments(IParameterNode[] parameters, IExpressionNode[] real_parameters) + { + bool is_comp_gen = false; + for (int i = 0; i < real_parameters.Length; i++) + { + if (real_parameters[i] is INullConstantNode && parameters[i].type.is_nullable_type) + { + Type tp = helper.GetTypeReference(parameters[i].type).tp; + LocalBuilder lb = il.DeclareLocal(tp); + il.Emit(OpCodes.Ldloca, lb); + il.Emit(OpCodes.Initobj, tp); + il.Emit(OpCodes.Ldloc, lb); + continue; + } + if (parameters[i].parameter_type == parameter_type.var) + is_addr = true; + ITypeNode ctn = real_parameters[i].type; + TypeInfo ti = null; + //(ssyy) moved up + ITypeNode tn2 = parameters[i].type; + ICompiledTypeNode ctn2 = tn2 as ICompiledTypeNode; + ITypeNode ctn3 = real_parameters[i].type; + //(ssyy) 07.12.2007 При боксировке нужно вызывать Ldsfld вместо Ldsflda. + //Дополнительная проверка введена именно для этого. + bool box_awaited = + (ctn2 != null && ctn2.compiled_type == TypeFactory.ObjectType || tn2.IsInterface) && !(real_parameters[i] is SemanticTree.INullConstantNode) && (ctn3.is_value_type || ctn3.is_generic_parameter); + if (!(real_parameters[i] is INullConstantNode)) + { + ti = helper.GetTypeReference(ctn); + if (ti.clone_meth != null && ti.tp != null && ti.tp.IsValueType && !box_awaited && !parameters[i].is_const) + is_dot_expr = true; + } + is_comp_gen = CheckForCompilerGenerated(real_parameters[i]); + real_parameters[i].visit(this); + is_dot_expr = false; + CallCloneIfNeed(il, parameters[i], real_parameters[i]); + if (box_awaited) + { + il.Emit(OpCodes.Box, helper.GetTypeReference(ctn3).tp); + } + is_addr = false; + } + } + private void EmitFreePinnedVariables() { /*foreach (LocalBuilder lb in pinned_variables) @@ -7317,7 +7345,7 @@ namespace PascalABCCompiler.NETGenerator if (to.type.is_value_type) { //ti = helper.GetTypeReference(to.type); - if (ti.assign_meth != null) + if (ti.assign_meth != null || from is INullConstantNode && to.type.is_nullable_type) il.Emit(OpCodes.Ldsflda, fb); } else if (to.type.type_special_kind == type_special_kind.set_type && !in_var_init) @@ -7328,6 +7356,11 @@ namespace PascalABCCompiler.NETGenerator return; } else ti = null; + if (from is INullConstantNode && to.type.is_nullable_type) + { + il.Emit(OpCodes.Initobj, ti.tp); + return; + } //что присвоить from.visit(this); if (ti != null && ti.assign_meth != null) @@ -7335,7 +7368,7 @@ namespace PascalABCCompiler.NETGenerator il.Emit(OpCodes.Call, ti.assign_meth); return; } - + //это если например переменной типа object присваивается число EmitBox(from, fb.FieldType); @@ -7409,8 +7442,9 @@ namespace PascalABCCompiler.NETGenerator if (to.type.is_value_type) { //ti = helper.GetTypeReference(to.type); - if (ti.assign_meth != null) + if (ti.assign_meth != null || from is INullConstantNode && to.type.is_nullable_type) il.Emit(OpCodes.Ldloca, lb); + } else if (to.type.type_special_kind == type_special_kind.set_type && !in_var_init) { @@ -7420,6 +7454,11 @@ namespace PascalABCCompiler.NETGenerator return; } else ti = null; + if (from is INullConstantNode && to.type.is_nullable_type) + { + il.Emit(OpCodes.Initobj, ti.tp); + return; + } //что присвоить from.visit(this); if (ti != null && ti.assign_meth != null) @@ -7446,7 +7485,8 @@ namespace PascalABCCompiler.NETGenerator if (to.type.is_value_type) { //ti = helper.GetTypeReference(to.type); - if (ti.assign_meth != null) il.Emit(OpCodes.Ldflda, fb); + if (ti.assign_meth != null || from is INullConstantNode && to.type.is_nullable_type) + il.Emit(OpCodes.Ldflda, fb); } else if (to.type.type_special_kind == type_special_kind.set_type && !in_var_init) { @@ -7456,6 +7496,11 @@ namespace PascalABCCompiler.NETGenerator return; } else ti = null; + if (from is INullConstantNode && to.type.is_nullable_type) + { + il.Emit(OpCodes.Initobj, ti.tp); + return; + } //что присвоить from.visit(this); if (ti != null && ti.assign_meth != null) @@ -7463,6 +7508,7 @@ namespace PascalABCCompiler.NETGenerator il.Emit(OpCodes.Call, ti.assign_meth); return; } + EmitBox(from, fb.FieldType); CheckArrayAssign(to, from, il); il.Emit(OpCodes.Stfld, fb); @@ -7506,7 +7552,8 @@ namespace PascalABCCompiler.NETGenerator TypeInfo ti = helper.GetTypeReference(to.type); if (to.type.is_value_type) { - if (ti.assign_meth != null) il.Emit(OpCodes.Ldarga, pos); + if (ti.assign_meth != null || from is INullConstantNode && to.type.is_nullable_type) + il.Emit(OpCodes.Ldarga, pos); } else if (to.type.type_special_kind == type_special_kind.set_type) { @@ -7516,6 +7563,11 @@ namespace PascalABCCompiler.NETGenerator return; } else ti = null; + if (from is INullConstantNode && to.type.is_nullable_type) + { + il.Emit(OpCodes.Initobj, ti.tp); + return; + } //что присвоить from.visit(this); if (ti != null && ti.assign_meth != null) @@ -7523,10 +7575,13 @@ namespace PascalABCCompiler.NETGenerator il.Emit(OpCodes.Call, ti.assign_meth); return; } + BoxAssignToParameter(to, from); //il.Emit(OpCodes.Dup); - if (pos <= 255) il.Emit(OpCodes.Starg_S, pos); - else il.Emit(OpCodes.Starg, pos); + if (pos <= 255) + il.Emit(OpCodes.Starg_S, pos); + else + il.Emit(OpCodes.Starg, pos); } else { @@ -7542,6 +7597,12 @@ namespace PascalABCCompiler.NETGenerator il.Emit(OpCodes.Call, ti.assign_meth); return; } + if (from is INullConstantNode && to.type.is_nullable_type) + { + il.Emit(OpCodes.Ldarg, pos); + il.Emit(OpCodes.Initobj, ti.tp); + return; + } } else if (to.type.type_special_kind == type_special_kind.set_type) { @@ -7578,7 +7639,8 @@ namespace PascalABCCompiler.NETGenerator if (to.type.is_value_type) { //ti = helper.GetTypeReference(to.type); - if (ti.assign_meth != null) il.Emit(OpCodes.Ldflda, fb); + if (ti.assign_meth != null || from is INullConstantNode && to.type.is_nullable_type) + il.Emit(OpCodes.Ldflda, fb); } else if (to.type.type_special_kind == type_special_kind.set_type) { @@ -7588,6 +7650,11 @@ namespace PascalABCCompiler.NETGenerator return; } else ti = null; + if (from is INullConstantNode && to.type.is_nullable_type) + { + il.Emit(OpCodes.Initobj, ti.tp); + return; + } //что присвоить from.visit(this); if (ti != null && ti.assign_meth != null) @@ -7595,6 +7662,7 @@ namespace PascalABCCompiler.NETGenerator il.Emit(OpCodes.Call, ti.assign_meth); return; } + BoxAssignToParameter(to, from); //il.Emit(OpCodes.Dup); il.Emit(OpCodes.Stfld, fb); @@ -7612,6 +7680,11 @@ namespace PascalABCCompiler.NETGenerator il.Emit(OpCodes.Call, ti.assign_meth); return; } + if (from is INullConstantNode && to.type.is_nullable_type) + { + il.Emit(OpCodes.Initobj, ti.tp); + return; + } } else if (to.type.type_special_kind == type_special_kind.set_type) { @@ -7648,7 +7721,7 @@ namespace PascalABCCompiler.NETGenerator TypeInfo ti = helper.GetTypeReference(to.type); if (to.type.is_value_type) { - if (ti.assign_meth != null) + if (ti.assign_meth != null || from is INullConstantNode && to.type.is_nullable_type) il.Emit(OpCodes.Ldflda, fi); } else if (to.type.type_special_kind == type_special_kind.set_type && !in_var_init) @@ -7659,6 +7732,11 @@ namespace PascalABCCompiler.NETGenerator return; } else ti = null; + if (from is INullConstantNode && to.type.is_nullable_type) + { + il.Emit(OpCodes.Initobj, ti.tp); + return; + } //что присвоить from.visit(this); if (ti != null && ti.assign_meth != null) @@ -7677,6 +7755,7 @@ namespace PascalABCCompiler.NETGenerator } return; } + EmitBox(from, fi_info.field_type); CheckArrayAssign(to, from, il); il.Emit(OpCodes.Stfld, fi); @@ -7699,7 +7778,8 @@ namespace PascalABCCompiler.NETGenerator if (to.type.is_value_type) { //ti = helper.GetTypeReference(to.type); - if (ti.assign_meth != null) il.Emit(OpCodes.Ldsflda, fi); + if (ti.assign_meth != null || from is INullConstantNode && to.type.is_nullable_type) + il.Emit(OpCodes.Ldsflda, fi); } else if (to.type.type_special_kind == type_special_kind.set_type) { @@ -7709,6 +7789,11 @@ namespace PascalABCCompiler.NETGenerator return; } else ti = null; + if (from is INullConstantNode && to.type.is_nullable_type) + { + il.Emit(OpCodes.Initobj, ti.tp); + return; + } //что присвоить from.visit(this); if (ti != null && ti.assign_meth != null) @@ -7716,6 +7801,7 @@ namespace PascalABCCompiler.NETGenerator il.Emit(OpCodes.Call, ti.assign_meth); return; } + EmitBox(from, fi.FieldType); CheckArrayAssign(to, from, il); il.Emit(OpCodes.Stsfld, fi); @@ -7794,12 +7880,10 @@ namespace PascalABCCompiler.NETGenerator for (int i = 0; i < value.indices.Length; i++) value.indices[i].visit(this); } - if (elem_type.IsValueType == true && TypeFactory.IsStandType(elem_type) == false && !TypeIsEnum(elem_type)) + if (elem_type.IsValueType && !TypeFactory.IsStandType(elem_type) && !TypeIsEnum(elem_type) || to.type.is_nullable_type) { if (value.indices == null) il.Emit(OpCodes.Ldelema, elem_type); - //else - // il.Emit(OpCodes.Call, addr_meth); } else if (elem_ti != null && elem_ti.assign_meth != null) { @@ -7808,6 +7892,11 @@ namespace PascalABCCompiler.NETGenerator else il.Emit(OpCodes.Call, get_meth); } + if (from is INullConstantNode && to.type.is_nullable_type) + { + il.Emit(OpCodes.Initobj, elem_ti.tp); + return; + } from.visit(this); if (elem_ti != null && elem_ti.assign_meth != null) { @@ -8258,6 +8347,43 @@ namespace PascalABCCompiler.NETGenerator case basic_function_type.booldec: case basic_function_type.cdec: ConvertDec(real_parameters[0]); return; } + if (real_parameters.Length > 1) + { + if (real_parameters[0].type.is_nullable_type && real_parameters[1] is INullConstantNode) + { + bool tmp = is_dot_expr; + is_dot_expr = true; + TypeInfo ti = helper.GetTypeReference(real_parameters[0].type); + real_parameters[0].visit(this); + is_dot_expr = tmp; + MethodInfo mi = null; + if (real_parameters[0].type is IGenericTypeInstance) + mi = TypeBuilder.GetMethod(ti.tp, typeof(Nullable<>).GetMethod("get_HasValue")); + else + mi = ti.tp.GetMethod("get_HasValue"); + il.Emit(OpCodes.Call, mi); + if (ft == basic_function_type.objeq) + il.Emit(OpCodes.Not); + return; + } + else if (real_parameters[1].type.is_nullable_type && real_parameters[0] is INullConstantNode) + { + bool tmp = is_dot_expr; + is_dot_expr = true; + TypeInfo ti = helper.GetTypeReference(real_parameters[1].type); + real_parameters[1].visit(this); + is_dot_expr = tmp; + MethodInfo mi = null; + if (real_parameters[1].type is IGenericTypeInstance) + mi = TypeBuilder.GetMethod(ti.tp, typeof(Nullable<>).GetMethod("get_HasValue")); + else + mi = ti.tp.GetMethod("get_HasValue"); + il.Emit(OpCodes.Call, mi); + if (ft == basic_function_type.objeq) + il.Emit(OpCodes.Not); + return; + } + } real_parameters[0].visit(this); if (real_parameters.Length > 1) real_parameters[1].visit(this); @@ -9138,8 +9264,8 @@ namespace PascalABCCompiler.NETGenerator is_dot_expr = false; bool need_fee = false; bool is_comp_gen = false; - - for (int i = 0; i < real_parameters.Length; i++) + EmitArguments(parameters, real_parameters); + /*for (int i = 0; i < real_parameters.Length; i++) { if (parameters[i].parameter_type == parameter_type.var) is_addr = true; @@ -9175,7 +9301,7 @@ namespace PascalABCCompiler.NETGenerator if (box_awaited) il.Emit(OpCodes.Box, helper.GetTypeReference(ctn3).tp); is_addr = false; - } + }*/ /*if (save_debug_info && need_fee) { MarkSequencePoint(il, value.Location); @@ -9255,7 +9381,8 @@ namespace PascalABCCompiler.NETGenerator //\ssyy is_dot_expr = false; - for (int i = 0; i < real_parameters.Length; i++) + EmitArguments(parameters, real_parameters); + /*for (int i = 0; i < real_parameters.Length; i++) { if (parameters[i].parameter_type == parameter_type.var) is_addr = true; @@ -9265,7 +9392,7 @@ namespace PascalABCCompiler.NETGenerator if (ctn2 != null && !(real_parameters[i] is SemanticTree.INullConstantNode) && value.type != null && (ctn3.is_value_type || ctn3.is_generic_parameter) && ctn2.compiled_type == TypeFactory.ObjectType) il.Emit(OpCodes.Box, helper.GetTypeReference(ctn3).tp); is_addr = false; - } + }*/ //ssyy изменил if (value.new_obj_awaited()) { diff --git a/PluginsSupport/Interfaces.cs b/PluginsSupport/Interfaces.cs index 0a2731388..b5485a89d 100644 --- a/PluginsSupport/Interfaces.cs +++ b/PluginsSupport/Interfaces.cs @@ -477,7 +477,17 @@ namespace VisualPascalABCPlugins IValue ObjectValue { get; } object PrimitiveValue { get; } } - + + public interface IProcess + { + bool HasExited { get; } + } + + public interface IProcessEventArgs + { + IProcess Process { get; } + } + public interface IDebuggerManager { bool IsRunning { get; } @@ -491,6 +501,7 @@ namespace VisualPascalABCPlugins void StepInto(); void StepOver(); void RunToCursor(); + event EventHandler DebuggeeStateChanged; } public interface ILanguageManager diff --git a/SemanticTree/SemanticTree.cs b/SemanticTree/SemanticTree.cs index 584dbd6e9..19796c70b 100644 --- a/SemanticTree/SemanticTree.cs +++ b/SemanticTree/SemanticTree.cs @@ -166,7 +166,12 @@ namespace PascalABCCompiler.SemanticTree { get; } - + + bool is_nullable_type + { + get; + } + type_special_kind type_special_kind { get; diff --git a/TestSuite/nullable.pas b/TestSuite/nullable.pas new file mode 100644 index 000000000..f9f649a74 --- /dev/null +++ b/TestSuite/nullable.pas @@ -0,0 +1,166 @@ +type TRec = record +a: integer; +b: real; +end; + +type TClass = class +v1: System.Nullable; +v2: System.Nullable; +constructor; +begin + v1 := nil; + assert(v1 = nil); + v1 := 4; + assert(v1 <> nil); + v2 := nil; + assert(v2 = nil); + v2 := new TRec; + assert(v2 <> nil); +end; + +procedure Test(v1 : System.Nullable; v2: System.Nullable); +begin + assert(v1 = nil); + v1 := 4; + assert(v1 <> nil); + assert(v2 = nil); + v2 := new TRec; + assert(v2 <> nil); +end; +end; + +type TClass2 = class +class v1: System.Nullable; +class v2: System.Nullable; +class procedure Test; +begin + v1 := nil; + assert(v1 = nil); + v1 := 4; + assert(v1 <> nil); + v2 := nil; + assert(v2 = nil); + v2 := new TRec; + assert(v2 <> nil); +end; +class procedure Test2(v1 : System.Nullable; v2: System.Nullable); +begin + assert(v1 = nil); + v1 := 4; + assert(v1 <> nil); + assert(v2 = nil); + v2 := new TRec; + assert(v2 <> nil); +end; +end; + +procedure Test3(v1 : System.Nullable; v2: System.Nullable); +begin + v1 := nil; + assert(v1 = nil); + v1 := 4; + assert(v1 <> nil); + v2 := nil; + assert(v2 = nil); + v2 := new TRec; + assert(v2 <> nil); +end; + +procedure Test4(var v1 : System.Nullable; var v2: System.Nullable); +begin + v1 := nil; + assert(v1 = nil); + v1 := 4; + assert(v1 <> nil); + v2 := nil; + assert(v2 = nil); + v2 := new TRec; + assert(v2 <> nil); +end; + +procedure Test2; +begin + var v1 : System.Nullable; + var v2 : System.Nullable; + v1 := nil; + assert(v1 = nil); + v1 := 4; + assert(v1 <> nil); + v2 := nil; + assert(v2 = nil); + v2 := new TRec; + assert(v2 <> nil); +end; + +procedure Test; +var + v1 : System.Nullable; + v2 : System.Nullable; +begin + v1 := nil; + assert(v1 = nil); + v1 := 4; + assert(v1 <> nil); + v2 := nil; + assert(v2 = nil); + v2 := new TRec; + assert(v2 <> nil); +end; + +procedure Test6; +var + v1 : System.Nullable; + v2 : System.Nullable; + +procedure Nested; +begin + v1 := nil; + assert(v1 = nil); + v1 := 4; + assert(v1 <> nil); + v2 := nil; + assert(v2 = nil); + v2 := new TRec; + assert(v2 <> nil); +end; +begin + Nested; +end; + +procedure Test5(v1 : System.Nullable; v2: System.Nullable); +begin + assert(v1 = nil); + v1 := 4; + assert(v1 <> nil); + assert(v2 = nil); + v2 := new TRec; + assert(v2 <> nil); +end; + +var + v1 : System.Nullable; + v2 : System.Nullable; + +begin + v1 := nil; + assert(v1 = nil); + v1 := 4; + assert(v1 <> nil); + v2 := nil; + assert(v2 = nil); + v2 := new TRec; + assert(v2 <> nil); + Test; + Test2; + var obj := new TClass; + obj.Test(nil, nil); + TClass2.Test; + Test3(v1, v2); + Test4(v1, v2); + v1 := nil; + v2 := nil; + Test5(v1, v2); + Test6; + Test5(nil, nil); + TClass2.Test2(nil, nil); +end. \ No newline at end of file diff --git a/TreeConverter/TreeRealization/type_table.cs b/TreeConverter/TreeRealization/type_table.cs index 9172eb37d..04673dbb6 100644 --- a/TreeConverter/TreeRealization/type_table.cs +++ b/TreeConverter/TreeRealization/type_table.cs @@ -282,6 +282,10 @@ namespace PascalABCCompiler.TreeRealization { return true; } + else if (tn.is_nullable_type) + { + return true; + } else { return !tn.is_value || tn is null_type_node; diff --git a/TreeConverter/TreeRealization/types.cs b/TreeConverter/TreeRealization/types.cs index b9d1b34b6..e5a212bbc 100644 --- a/TreeConverter/TreeRealization/types.cs +++ b/TreeConverter/TreeRealization/types.cs @@ -53,7 +53,9 @@ namespace PascalABCCompiler.TreeRealization } */ internal bool is_ref_inited; - + internal bool is_nullable_inited; + private bool _is_nullable_type; + public virtual bool IsSealed { get { return false; } @@ -64,6 +66,22 @@ namespace PascalABCCompiler.TreeRealization get { return false; } } + public bool is_nullable_type + { + get + { + if (is_nullable_inited) + return _is_nullable_type; + string fname = full_name; + if (this is compiled_type_node) + _is_nullable_type = fname != null && fname.StartsWith("System.Nullable"); + else if (original_generic != null) + return original_generic.is_nullable_type; + is_nullable_inited = true; + return _is_nullable_type; + } + } + public virtual bool IsInterface { get @@ -1734,7 +1752,7 @@ namespace PascalABCCompiler.TreeRealization public override string full_name { get { - if (!string.IsNullOrEmpty(_comprehensive_namespace.namespace_name)) + if (_comprehensive_namespace != null && !string.IsNullOrEmpty(_comprehensive_namespace.namespace_name)) return _comprehensive_namespace.namespace_name+"."+_name; return _name; } diff --git a/VisualPascalABCNET/IB/Debugger/Debugger.cs b/VisualPascalABCNET/IB/Debugger/Debugger.cs index 9ce13d632..471f9468d 100644 --- a/VisualPascalABCNET/IB/Debugger/Debugger.cs +++ b/VisualPascalABCNET/IB/Debugger/Debugger.cs @@ -239,6 +239,42 @@ namespace VisualPascalABC } } + public class ProcessDelegator : IProcess + { + private Process process; + + public ProcessDelegator(Process process) + { + this.process = process; + } + + public bool HasExited + { + get + { + return process.HasExited; + } + } + } + + public class ProcessEventArgsDelegator : EventArgs, IProcessEventArgs + { + private ProcessDelegator process; + + public ProcessEventArgsDelegator(ProcessDelegator process) + { + this.process = process; + } + + public IProcess Process + { + get + { + return process; + } + } + } + /// /// Класс для отладки программ /// @@ -259,6 +295,7 @@ namespace VisualPascalABC public string ExeFileName; public bool show_debug_tabs=true; public PascalABCCompiler.Parsers.IParser parser = null; + EventHandler debuggerStateEvent; public DebugHelper() { @@ -275,7 +312,20 @@ namespace VisualPascalABC return debuggedProcess; } } + + event EventHandler IDebuggerManager.DebuggeeStateChanged + { + add + { + debuggerStateEvent += value; + } + remove + { + debuggerStateEvent -= value; + } + } + public Breakpoint CurrentBreakpoint { get { return currentBreakpoint; } @@ -434,6 +484,8 @@ namespace VisualPascalABC //if (e.Process.IsPaused) WorkbenchServiceFactory.DebuggerOperationsService.RefreshPad(new FunctionItem(e.Process.SelectedFunction).SubItems); workbench.WidgetController.SetStartDebugEnabled(); + if (debuggerStateEvent != null) + debuggerStateEvent(this, new ProcessEventArgsDelegator(new ProcessDelegator(this.debuggedProcess))); } private void debugBreakpointHit(object sender, BreakpointEventArgs e) diff --git a/VisualPlugins/TestPlugin/TestPlugin.cs b/VisualPlugins/TestPlugin/TestPlugin.cs index 3c984b210..5fae3f90b 100644 --- a/VisualPlugins/TestPlugin/TestPlugin.cs +++ b/VisualPlugins/TestPlugin/TestPlugin.cs @@ -43,7 +43,6 @@ namespace VisualPascalABCPlugins this.Workbench = Workbench; VisualEnvironmentCompiler = Workbench.VisualEnvironmentCompiler; testForm.VisualEnvironmentCompiler = VisualEnvironmentCompiler; - } public void GetGUI(List MenuItems, List ToolBarItems)