Beispiel #1
0
        public static LNode match(LNode node, IMacroContext context)
        {
            {
                LNode         input;
                VList <LNode> contents;
                if (node.Args.Count == 2 && (input = node.Args[0]) != null && node.Args[1].Calls(CodeSymbols.Braces))
                {
                    contents = node.Args[1].Args;
                    var outputs = new WList <LNode>();
                    input = MaybeAddTempVarDecl(context, input, outputs);

                    int next_i = 0;
                    for (int case_i = 0; case_i < contents.Count; case_i = next_i)
                    {
                        var @case = contents[case_i];
                        if (!IsCaseLabel(@case))
                        {
                            return(Reject(context, contents[0], "In 'match': expected 'case' statement"));
                        }
                        for (next_i = case_i + 1; next_i < contents.Count; next_i++)
                        {
                            var stmt = contents[next_i];
                            if (IsCaseLabel(stmt))
                            {
                                break;
                            }
                            if (stmt.Calls(S.Break, 0))
                            {
                                next_i++;
                                break;
                            }
                        }
                        var handler = new VList <LNode>(contents.Slice(case_i + 1, next_i - (case_i + 1)));

                        if (@case.Calls(S.Case) && @case.Args.Count > 0)
                        {
                            var codeGen = new CodeGeneratorForMatchCase(context, input, handler);
                            foreach (var pattern in @case.Args)
                            {
                                outputs.Add(codeGen.GenCodeForPattern(pattern));
                            }
                        }
                        else                                    // default:
                        // Note: the extra {braces} around the handler are rarely
                        // needed. They are added just in case the handler declares a
                        // variable and a different handler declares another variable
                        // by the same name, which is illegal unless we add braces.
                        {
                            outputs.Add(LNode.Call(CodeSymbols.Braces, LNode.List(handler)).SetStyle(NodeStyle.Statement));
                            if (next_i < contents.Count)
                            {
                                context.Sink.Error(contents[next_i], "The default branch must be the final branch in a 'match' statement.");
                            }
                        }
                    }
                    return(LNode.Call(CodeSymbols.DoWhile, LNode.List(outputs.ToVList().AsLNode(S.Braces), LNode.Literal(false))));
                }
            }
            return(null);
        }
Beispiel #2
0
 [LexicalMacro("match (var) { case ...: ... }; // In LES, use a => b instead of case a: b", "Attempts to match and deconstruct an object against a \"pattern\", such as a tuple or an algebraic data type. Example:\n" + "match (obj) {  \n" + "   case is Shape(ShapeType.Circle, $size, Location: $p is Point<int>($x, $y)): \n" + "      Circle(size, x, y); \n" + "}\n\n" + "This is translated to the following C# code: \n" + "do { \n" + "   Point<int> p; \n" + "   Shape tmp1; \n" + "   if (obj is Shape) { \n" + "      var tmp1 = (Shape)obj; \n" + "      if (tmp1.Item1 == ShapeType.Circle) { \n" + "         var size = tmp1.Item2; \n" + "         var tmp2 = tmp1.Location; \n" + "         if (tmp2 is Point<int>) { \n" + "            var p = (Point<int>)tmp2; \n" + "            var x = p.Item1; \n" + "            var y = p.Item2; \n" + "            Circle(size, x, y); \n" + "            break; \n" + "         } \n" + "      }\n" + "   }\n" + "} while(false); \n" + "`break` is not expected at the end of each handler (`case` code block), but it can " + "be used to exit early from a `case`. You can associate multiple patterns with the same " + "handler using `case pattern1, pattern2:` in EC#, but please note that (due to a " + "limitation of plain C#) this causes code duplication since the handler will be repeated " + "for each pattern.")] public static LNode match(LNode node, IMacroContext context)
 {
     {
         LNode         input;
         VList <LNode> contents;
         if (node.Args.Count == 2 && (input = node.Args[0]) != null && node.Args[1].Calls(CodeSymbols.Braces))
         {
             contents = node.Args[1].Args;
             var outputs = new WList <LNode>();
             input = MaybeAddTempVarDecl(input, outputs);
             int next_i = 0;
             for (int case_i = 0; case_i < contents.Count; case_i = next_i)
             {
                 var @case = contents[case_i];
                 if (!IsCaseLabel(@case))
                 {
                     return(Reject(context, contents[0], "In 'match': expected 'case' statement"));
                 }
                 for (next_i = case_i + 1; next_i < contents.Count; next_i++)
                 {
                     var stmt = contents[next_i];
                     if (IsCaseLabel(stmt))
                     {
                         break;
                     }
                     if (stmt.Calls(S.Break, 0))
                     {
                         next_i++;
                         break;
                     }
                 }
                 var handler = new VList <LNode>(contents.Slice(case_i + 1, next_i - (case_i + 1)));
                 if (@case.Calls(S.Case) && @case.Args.Count > 0)
                 {
                     var codeGen = new CodeGeneratorForMatchCase(context, input, handler);
                     foreach (var pattern in @case.Args)
                     {
                         outputs.Add(codeGen.GenCodeForPattern(pattern));
                     }
                 }
                 else
                 {
                     outputs.Add(LNode.Call(CodeSymbols.Braces, LNode.List(handler)).SetStyle(NodeStyle.Statement));
                     if (next_i < contents.Count)
                     {
                         context.Write(Severity.Error, contents[next_i], "The default branch must be the final branch in a 'match' statement.");
                     }
                 }
             }
             return(LNode.Call(CodeSymbols.DoWhile, LNode.List(outputs.ToVList().AsLNode(S.Braces), LNode.Literal(false))));
         }
     }
     return(null);
 }
Beispiel #3
0
 public static LNode match(LNode node, IMacroContext context)
 {
     {
         LNode         input;
         VList <LNode> contents;
         if (node.Args.Count == 2 && (input = node.Args[0]) != null && node.Args[1].Calls(CodeSymbols.Braces))
         {
             contents = node.Args[1].Args;
             var outputs = new WList <LNode>();
             input = MaybeAddTempVarDecl(context, input, outputs);
             int next_i = 0;
             for (int case_i = 0; case_i < contents.Count; case_i = next_i)
             {
                 var @case = contents[case_i];
                 if (!IsCaseLabel(@case))
                 {
                     return(Reject(context, contents[0], "In 'match': expected 'case' statement"));
                 }
                 for (next_i = case_i + 1; next_i < contents.Count; next_i++)
                 {
                     var stmt = contents[next_i];
                     if (IsCaseLabel(stmt))
                     {
                         break;
                     }
                     if (stmt.Calls(S.Break, 0))
                     {
                         next_i++;
                         break;
                     }
                 }
                 var handler = new VList <LNode>(contents.Slice(case_i + 1, next_i - (case_i + 1)));
                 if (@case.Calls(S.Case) && @case.Args.Count > 0)
                 {
                     var codeGen = new CodeGeneratorForMatchCase(context, input, handler);
                     foreach (var pattern in @case.Args)
                     {
                         outputs.Add(codeGen.GenCodeForPattern(pattern));
                     }
                 }
                 else
                 {
                     outputs.Add(LNode.Call(CodeSymbols.Braces, LNode.List(handler)).SetStyle(NodeStyle.Statement));
                     if (next_i < contents.Count)
                     {
                         context.Write(Severity.Error, contents[next_i], "The default branch must be the final branch in a 'match' statement.");
                     }
                 }
             }
             return(LNode.Call(CodeSymbols.DoWhile, LNode.List(outputs.ToVList().AsLNode(S.Braces), LNode.Literal(false))));
         }
     }
     return(null);
 }
Beispiel #4
0
		public static LNode match(LNode node, IMacroContext context)
		{
			{
				LNode input;
				VList<LNode> contents;
				if (node.Args.Count == 2 && (input = node.Args[0]) != null && node.Args[1].Calls(CodeSymbols.Braces)) {
					contents = node.Args[1].Args;
					var outputs = new WList<LNode>();
					input = MaybeAddTempVarDecl(context, input, outputs);
				
					int next_i = 0;
					for (int case_i = 0; case_i < contents.Count; case_i = next_i) {
						var @case = contents[case_i];
						if (!IsCaseLabel(@case))
							return Reject(context, contents[0], "In 'match': expected 'case' statement");
						for (next_i = case_i + 1; next_i < contents.Count; next_i++) {
							var stmt = contents[next_i];
							if (IsCaseLabel(stmt))
								break;
							if (stmt.Calls(S.Break, 0)) {
								next_i++;
								break;
							}
						}
						var handler = new VList<LNode>(contents.Slice(case_i + 1, next_i - (case_i + 1)));
					
						if (@case.Calls(S.Case) && @case.Args.Count > 0) {
							var codeGen = new CodeGeneratorForMatchCase(context, input, handler);
							foreach (var pattern in @case.Args)
								outputs.Add(codeGen.GenCodeForPattern(pattern));
						} else {	// default:
							// Note: the extra {braces} around the handler are rarely 
							// needed. They are added just in case the handler declares a 
							// variable and a different handler declares another variable 
							// by the same name, which is illegal unless we add braces.
							outputs.Add(LNode.Call(CodeSymbols.Braces, LNode.List(handler)).SetStyle(NodeStyle.Statement));
							if (next_i < contents.Count)
								context.Sink.Error(contents[next_i], "The default branch must be the final branch in a 'match' statement.");
						}
					}
					return LNode.Call(CodeSymbols.DoWhile, LNode.List(outputs.ToVList().AsLNode(S.Braces), LNode.Literal(false)));
				}
			}
			return null;
		}
Beispiel #5
0
		[LexicalMacro("match (var) { case ...: ... }; // In LES, use a => b instead of case a: b", "Attempts to match and deconstruct an object against a \"pattern\", such as a tuple or an algebraic data type. Example:\n" + "match (obj) {  \n" + "   case is Shape(ShapeType.Circle, $size, Location: $p is Point<int>($x, $y)): \n" + "      Circle(size, x, y); \n" + "}\n\n" + "This is translated to the following C# code: \n" + "do { \n" + "   Point<int> p; \n" + "   Shape tmp1; \n" + "   if (obj is Shape) { \n" + "      var tmp1 = (Shape)obj; \n" + "      if (tmp1.Item1 == ShapeType.Circle) { \n" + "         var size = tmp1.Item2; \n" + "         var tmp2 = tmp1.Location; \n" + "         if (tmp2 is Point<int>) { \n" + "            var p = (Point<int>)tmp2; \n" + "            var x = p.Item1; \n" + "            var y = p.Item2; \n" + "            Circle(size, x, y); \n" + "            break; \n" + "         } \n" + "      }\n" + "   }\n" + "} while(false); \n" + "`break` is not expected at the end of each handler (`case` code block), but it can " + "be used to exit early from a `case`. You can associate multiple patterns with the same " + "handler using `case pattern1, pattern2:` in EC#, but please note that (due to a " + "limitation of plain C#) this causes code duplication since the handler will be repeated " + "for each pattern.")] public static LNode match(LNode node, IMacroContext context)
		{
			{
				LNode input;
				VList<LNode> contents;
				if (node.Args.Count == 2 && (input = node.Args[0]) != null && node.Args[1].Calls(CodeSymbols.Braces)) {
					contents = node.Args[1].Args;
					var outputs = new WList<LNode>();
					input = MaybeAddTempVarDecl(input, outputs);
					int next_i = 0;
					for (int case_i = 0; case_i < contents.Count; case_i = next_i) {
						var @case = contents[case_i];
						if (!IsCaseLabel(@case))
							return Reject(context, contents[0], "In 'match': expected 'case' statement");
						for (next_i = case_i + 1; next_i < contents.Count; next_i++) {
							var stmt = contents[next_i];
							if (IsCaseLabel(stmt))
								break;
							if (stmt.Calls(S.Break, 0)) {
								next_i++;
								break;
							}
						}
						var handler = new VList<LNode>(contents.Slice(case_i + 1, next_i - (case_i + 1)));
						if (@case.Calls(S.Case) && @case.Args.Count > 0) {
							var codeGen = new CodeGeneratorForMatchCase(context, input, handler);
							foreach (var pattern in @case.Args)
								outputs.Add(codeGen.GenCodeForPattern(pattern));
						} else {
							outputs.Add(LNode.Call(CodeSymbols.Braces, LNode.List(handler)).SetStyle(NodeStyle.Statement));
							if (next_i < contents.Count)
								context.Write(Severity.Error, contents[next_i], "The default branch must be the final branch in a 'match' statement.");
						}
					}
					return LNode.Call(CodeSymbols.DoWhile, LNode.List(outputs.ToVList().AsLNode(S.Braces), LNode.Literal(false)));
				}
			}
			return null;
		}