$$ = new Unary (Unary.Operator.UnaryNegation, (Expression) $2, GetLocation ($1));
}
| sizeof_expression
- | invocation_expression
| default_value_expression
| STAR
{
$$ = new WildcardPattern (GetLocation ($1));
}
- | type_name_expression OPEN_PARENS opt_pattern_list CLOSE_PARENS
+ | pattern_expr_invocation
+ ;
+
+pattern_expr_invocation
+ : type_name_expression OPEN_PARENS opt_pattern_list CLOSE_PARENS
{
$$ = new RecursivePattern ((ATypeNameExpression) $1, (Arguments) $3, GetLocation ($2));
}
: pattern_expr
| pattern_type_expr opt_identifier
{
- var lt = (LocatedToken) $2;
- var variable = new LocalVariable (current_block, lt.Value, lt.Location);
- current_block.AddLocalName (variable);
+ if ($2 != null) {
+ var lt = (LocatedToken) $2;
+ var variable = new LocalVariable (current_block, lt.Value, lt.Location);
+ current_block.AddLocalName (variable);
+ }
}
;
Error_SyntaxError (yyToken);
$$ = new SwitchLabel ((Expression) $2, GetLocation ($1));
}
+ | CASE pattern_expr_invocation COLON
+ {
+ if (lang_version != LanguageVersion.Experimental)
+ FeatureIsNotAvailable (GetLocation ($2), "pattern matching");
+
+ $$ = new SwitchLabel ((Expression) $2, GetLocation ($1)) {
+ PatternMatching = true
+ };
+ lbag.AddLocation ($$, GetLocation ($3));
+ }
| DEFAULT_COLON
{
$$ = new SwitchLabel (null, GetLocation ($1));
var system_convert = new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "Convert", loc);
+ var expl_block = new ExplicitBlock (top_block, loc, loc);
//
// var converted = System.Convert.ChangeType (obj, System.Convert.GetTypeCode (value));
var changetype = new Invocation (new MemberAccess (system_convert, "ChangeType", loc), arguments_changetype);
- top_block.AddStatement (new StatementExpression (new SimpleAssign (new LocalVariableReference (lv_converted, loc), changetype, loc)));
+ expl_block.AddStatement (new StatementExpression (new SimpleAssign (new LocalVariableReference (lv_converted, loc), changetype, loc)));
//
var equals_arguments = new Arguments (1);
equals_arguments.Add (new Argument (top_block.GetParameterReference (1, loc)));
var equals_invocation = new Invocation (new MemberAccess (new LocalVariableReference (lv_converted, loc), "Equals"), equals_arguments);
- top_block.AddStatement (new Return (equals_invocation, loc));
+ expl_block.AddStatement (new Return (equals_invocation, loc));
+
+ var catch_block = new ExplicitBlock (top_block, loc, loc);
+ catch_block.AddStatement (new Return (new BoolLiteral (Compiler.BuiltinTypes, false, loc), loc));
+ top_block.AddStatement (new TryCatch (expl_block, new List<Catch> () {
+ new Catch (catch_block, loc)
+ }, loc, false));
m.Define ();
m.PrepareEmit ();
}
}
+ public bool PatternMatching { get; set; }
+
public bool SectionStart { get; set; }
public Label GetILLabel (EmitContext ec)
// Resolves the expression, reduces it to a literal if possible
// and then converts it to the requested type.
//
- bool ResolveAndReduce (BlockContext rc)
+ bool ResolveAndReduce (BlockContext bc)
{
if (IsDefault)
return true;
- var c = label.ResolveLabelConstant (rc);
+ var switch_statement = bc.Switch;
+
+ if (PatternMatching) {
+ label = new Is (switch_statement.ExpressionValue, label, loc).Resolve (bc);
+ return label != null;
+ }
+
+ var c = label.ResolveLabelConstant (bc);
if (c == null)
return false;
- if (rc.Switch.IsNullable && c is NullLiteral) {
+ if (switch_statement.IsNullable && c is NullLiteral) {
converted = c;
return true;
}
- converted = c.ImplicitConversionRequired (rc, rc.Switch.SwitchType);
+ if (switch_statement.IsPatternMatching) {
+ label = new Is (switch_statement.ExpressionValue, label, loc).Resolve (bc);
+ return true;
+ }
+
+ converted = c.ImplicitConversionRequired (bc, switch_statement.SwitchType);
return converted != null;
}
}
}
+ public bool IsPatternMatching {
+ get {
+ return new_expr == null && SwitchType != null;
+ }
+ }
+
public List<SwitchLabel> RegisteredLabels {
get {
return case_labels;
}
}
+ public VariableReference ExpressionValue {
+ get {
+ return value;
+ }
+ }
+
//
// Determines the governing type for a switch. The returned
// expression might be the expression from the switch, or an
return;
}
+ if (sl.Converted == null)
+ return;
+
try {
if (string_labels != null) {
string string_value = sl.Converted.GetValue () as string;
else
string_labels.Add (string_value, sl);
} else {
- if (sl.Converted is NullLiteral) {
+ if (sl.Converted.IsNull) {
case_null = sl;
} else {
labels.Add (sl.Converted.GetValueAsLong (), sl);
}
}
+ Expression switch_expr;
if (new_expr == null) {
- if (Expr.Type != InternalType.ErrorType) {
- ec.Report.Error (151, loc,
- "A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type",
- Expr.Type.GetSignatureForError ());
- }
+ if (ec.Module.Compiler.Settings.Version != LanguageVersion.Experimental) {
+ if (Expr.Type != InternalType.ErrorType) {
+ ec.Report.Error (151, loc,
+ "A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type",
+ Expr.Type.GetSignatureForError ());
+ }
- return false;
- }
+ return false;
+ }
- SwitchType = new_expr.Type;
- if (SwitchType.IsNullableType) {
- new_expr = unwrap = Nullable.Unwrap.Create (new_expr, true);
- SwitchType = Nullable.NullableInfo.GetUnderlyingType (SwitchType);
- }
+ switch_expr = Expr;
+ SwitchType = Expr.Type;
+ } else {
+ switch_expr = new_expr;
+ SwitchType = new_expr.Type;
+ if (SwitchType.IsNullableType) {
+ new_expr = unwrap = Nullable.Unwrap.Create (new_expr, true);
+ SwitchType = Nullable.NullableInfo.GetUnderlyingType (SwitchType);
+ }
- if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.Bool && ec.Module.Compiler.Settings.Version == LanguageVersion.ISO_1) {
- ec.Report.FeatureIsNotAvailable (ec.Module.Compiler, loc, "switch expression of boolean type");
- return false;
- }
+ if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.Bool && ec.Module.Compiler.Settings.Version == LanguageVersion.ISO_1) {
+ ec.Report.FeatureIsNotAvailable (ec.Module.Compiler, loc, "switch expression of boolean type");
+ return false;
+ }
- if (block.Statements.Count == 0)
- return true;
+ if (block.Statements.Count == 0)
+ return true;
- if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
- string_labels = new Dictionary<string, SwitchLabel> ();
- } else {
- labels = new Dictionary<long, SwitchLabel> ();
+ if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
+ string_labels = new Dictionary<string, SwitchLabel> ();
+ } else {
+ labels = new Dictionary<long, SwitchLabel> ();
+ }
}
- case_labels = new List<SwitchLabel> ();
-
- var constant = new_expr as Constant;
+ var constant = switch_expr as Constant;
//
// Don't need extra variable for constant switch or switch with
//
// Store switch expression for comparison purposes
//
- value = new_expr as VariableReference;
+ value = switch_expr as VariableReference;
if (value == null && !HasOnlyDefaultSection ()) {
var current_block = ec.CurrentBlock;
ec.CurrentBlock = Block;
}
}
+ case_labels = new List<SwitchLabel> ();
+
Switch old_switch = ec.Switch;
ec.Switch = this;
var parent_los = ec.EnclosingLoopOrSwitch;
var constant = label.Converted;
+ if (constant == null) {
+ label.Label.EmitBranchable (ec, label.GetILLabel (ec), true);
+ continue;
+ }
+
if (equal_method != null) {
value.Emit (ec);
constant.Emit (ec);
void EmitDispatch (EmitContext ec)
{
+ if (IsPatternMatching) {
+ EmitShortSwitch (ec);
+ return;
+ }
+
if (value == null) {
//
// Constant switch, we've already done the work if there is only 1 label
if (value != null) {
ec.Mark (loc);
+
+ var switch_expr = new_expr ?? Expr;
if (IsNullable) {
unwrap.EmitCheck (ec);
ec.Emit (OpCodes.Brfalse, nullLabel);
- value.EmitAssign (ec, new_expr, false, false);
- } else if (new_expr != value) {
- value.EmitAssign (ec, new_expr, false, false);
+ value.EmitAssign (ec, switch_expr, false, false);
+ } else if (switch_expr != value) {
+ value.EmitAssign (ec, switch_expr, false, false);
}