A list of common symbols that have special meaning somewhere in Loyc or EC#: operators, built-in data types, keywords, trivia, etc.
예제 #1
0
        public static LNode of(LNode node, IMessageSink sink)
        {
            LNode kind;

            if (node.ArgCount == 2 && (kind = node.Args[0]).IsId)
            {
                if (kind.IsIdNamed(_array))
                {
                    return(node.WithArgChanged(0, kind.WithName(S.Array)));
                }
                if (kind.IsIdNamed(_opt))
                {
                    return(node.WithArgChanged(0, kind.WithName(S.QuestionMark)));
                }
                if (kind.IsIdNamed(_ptr))
                {
                    return(node.WithArgChanged(0, kind.WithName(S._Pointer)));
                }
            }
            else if (node.ArgCount == 3 && (kind = node.Args[0]).IsIdNamed(_array) && node.Args[1].IsLiteral)
            {
                return(node.WithArgs(kind.WithName(S.GetArrayKeyword((int)node.Args[1].Value)), node.Args[2]));
            }
            return(null);
        }
예제 #2
0
        int CountDimensionsIfArrayType(LNode type)
        {
            LNode dimsNode;

            if (type.Calls(S.Of, 2) && (dimsNode = type.Args[0]).IsId)
            {
                return(S.CountArrayDimensions(dimsNode.Name));
            }
            return(0);
        }
예제 #3
0
 public void CsDataTypes()
 {
     Stmt("double x;", F.Vars(F.Double, x));
     Stmt("int[] x;", F.Vars(F.Of(S.Array, S.Int32), x));
     Stmt("long* x;", F.Vars(F.Of(S._Pointer, S.Int64), x));
     Stmt("string[][,] x;", F.Vars(F.Of(_(S.Array), F.Of(S.TwoDimensionalArray, S.String)), x));
     Stmt("typeof(float*);", F.Call(S.Typeof, F.Of(S._Pointer, S.Single)));
     Stmt("decimal[,,,] x;", F.Vars(F.Of(S.GetArrayKeyword(4), S.Decimal), x));
     Stmt("double? x;", F.Vars(F.Of(S.QuestionMark, S.Double), x));
     Stmt("Foo<a.b.c>? x;", F.Vars(F.Of(_(S.QuestionMark), F.Of(Foo, F.Dot(a, b, c))), x));
     Stmt("Foo<a?,b.c[,]>[] x;", F.Vars(F.Of(_(S.Array), F.Of(Foo, F.Of(_(S.QuestionMark), a), F.Of(_(S.TwoDimensionalArray), F.Dot(b, c)))), x));
 }
예제 #4
0
        private void PrintTypeWithArraySizes(LNode cons)
        {
            LNode type = cons.Target;

            // Called by AutoPrintNewOperator; type is already validated.
            Debug.Assert(type.Calls(S.Of, 2) && S.IsArrayKeyword(type.Args[0].Name));
            // We have to deal with the "constructor arguments" specially.
            // First of all, the constructor arguments appear inside the
            // square brackets, which is unusual: int[x + y]. But there's
            // something much more strange in case of arrays of arrays: the
            // order of the square brackets must be reversed. If the
            // constructor argument is 10, an array of two-dimensional
            // arrays of int is written int[10][,], rather than int[,][10]
            // which would be easier to handle.
            int   dims = cons.ArgCount, innerDims;
            LNode elemType = type.Args[1];
            var   dimStack = InternalList <int> .Empty;

            while ((innerDims = CountDimensionsIfArrayType(elemType)) != 0)
            {
                dimStack.Add(innerDims);
                elemType = elemType.Args[1];
            }

            PrintType(elemType, EP.Primary.LeftContext(ContinueExpr));

            _out.Write('[', true);
            bool first = true;

            foreach (var arg in cons.Args)
            {
                if (first)
                {
                    first = false;
                }
                else
                {
                    WriteThenSpace(',', SpaceOpt.AfterComma);
                }
                PrintExpr(arg, StartExpr, 0);
            }
            _out.Write(']', true);

            // Write the brackets for the inner array types
            for (int i = dimStack.Count - 1; i >= 0; i--)
            {
                _out.Write(S.GetArrayKeyword(dimStack[i]).Name, true);
            }
        }
예제 #5
0
        static Symbol SpecialTypeKind(LNode n, Ambiguity flags, Precedence context)
        {
            // detects when notation for special types applies: Foo[], Foo*, Foo?
            // assumes IsComplexIdentifier() is already known to be true
            LNode first;

            if (n.Calls(S.Of, 2) && (first = n.Args[0]).IsId && (flags & Ambiguity.TypeContext) != 0)
            {
                var kind = first.Name;
                if (S.IsArrayKeyword(kind) || kind == S.QuestionMark)
                {
                    return(kind);
                }
                if (kind == S._Pointer && ((flags & Ambiguity.AllowPointer) != 0 || context.Left == StartStmt.Left))
                {
                    return(kind);
                }
            }
            return(null);
        }
예제 #6
0
 public void CsOperatorNew()
 {
     Expr("new Foo(x)", F.Call(S.New, F.Call(Foo, x)));
     Expr("new Foo(x) { a }", F.Call(S.New, F.Call(Foo, x), a));
     Expr("new Foo()", F.Call(S.New, F.Call(Foo)));
     Expr("new Foo { a }", F.Call(S.New, F.Call(Foo), a));                          // new Foo() { a } would also be ok
     Expr("new int[] { a, b }", F.Call(S.New, F.Call(F.Of(S.Array, S.Int32)), a, b));
     Expr("new[] { a, b }", F.Call(S.New, F.Call(S.Array), a, b));
     Expr("new[] { }", F.Call(S.New, F.Call(S.Array)));
     Expr("new int[][,] { a }", F.Call(S.New, F.Call(F.Of(_(S.Array), F.Of(S.TwoDimensionalArray, S.Int32))), a));
     // This expression is illegal since it requires an initializer list, but it's parsable so should print ok
     Expr("new int[][,][,,]", F.Call(S.New, F.Call(F.Of(_(S.Array), F.Of(_(S.TwoDimensionalArray), F.Of(S.GetArrayKeyword(3), S.Int32))))), Mode.Both | Mode.ExpectAndDropParserError);
     Expr("new int[10][,] { a }", F.Call(S.New, F.Call(F.Of(_(S.Array), F.Of(S.TwoDimensionalArray, S.Int32)), F.Literal(10)), a));
     Expr("new int[x, x][]", F.Call(S.New, F.Call(F.Of(_(S.TwoDimensionalArray), F.Of(S.Array, S.Int32)), x, x)));
     Expr("new int[,]", F.Call(S.New, F.Call(F.Of(S.TwoDimensionalArray, S.Int32))), Mode.Both | Mode.ExpectAndDropParserError);
     Option(Mode.PrintBothParseFirst, "#new(@`[,]`!([Foo] int)());", "new int[,];",
            F.Call(S.New, F.Call(F.Of(_(S.TwoDimensionalArray), Attr(Foo, F.Int32)))), p => p.DropNonDeclarationAttributes = true);
     Expr("new { a = 1, b = 2 }", F.Call(S.New, F.Missing, F.Call(S.Assign, a, one), F.Call(S.Assign, b, two)));
 }
예제 #7
0
 public static bool IsTrivia(this ILNode node)
 {
     return(CodeSymbols.IsTriviaSymbol(node.Name));
 }
예제 #8
0
        public bool AutoPrintNewOperator(Precedence precedence, Precedence context, Ambiguity flags)
        {
            // Prints the new Xyz(...) {...} operator
            Debug.Assert(_n.Name == S.New);
            int argCount = _n.ArgCount;

            if (argCount == 0)
            {
                return(false);
            }
            bool needParens;

            Debug.Assert(CanAppearIn(precedence, context, out needParens) && !needParens);

            LNode cons     = _n.Args[0];
            LNode type     = cons.Target;
            var   consArgs = cons.Args;

            // There are two basic uses of new: for objects, and for arrays.
            // In all cases, #new has 1 arg plus optional initializer arguments,
            // and there's always a list of "constructor args" even if it is empty
            // (exception: new {...}).
            // 1. Init an object: 1a. new Foo<Bar>() { ... }  <=> #new(Foo<bar>(...), ...)
            //                    1b. new { ... }             <=> #new(@``, ...)
            // 2. Init an array:  2a. new int[] { ... },      <=> #new(int[](), ...) <=> #new(#of(@`[]`, int)(), ...)
            //                    2b. new[,] { ... }.         <=> #new(@`[,]`(), ...)
            //                    2c. new int[10,10] { ... }, <=> #new(#of(@`[,]`, int)(10,10), ...)
            //                    2d. new int[10][] { ... },  <=> #new(#of(@`[]`, #of(@`[]`, int))(10), ...)
            if (HasPAttrs(cons))
            {
                return(false);
            }
            if (type == null ? !cons.IsIdNamed(S.Missing) : HasPAttrs(type) || !IsComplexIdentifier(type))
            {
                return(false);
            }

            // Okay, we can now be sure that it's printable, but is it an array decl?
            if (type == null)
            {
                // 1b, new {...}
                _out.Write("new ", true);
                PrintBracedBlockInNewExpr();
            }
            else if (type != null && type.IsId && S.CountArrayDimensions(type.Name) > 0)                 // 2b
            {
                _out.Write("new", true);
                _out.Write(type.Name.Name, true);
                Space(SpaceOpt.Default);
                PrintBracedBlockInNewExpr();
            }
            else
            {
                _out.Write("new ", true);
                int dims = CountDimensionsIfArrayType(type);
                if (dims > 0 && cons.Args.Count == dims)
                {
                    PrintTypeWithArraySizes(cons);
                }
                else
                {
                    // Otherwise we can print the type name without caring if it's an array or not.
                    PrintType(type, EP.Primary.LeftContext(context));
                    if (cons.ArgCount != 0 || (argCount == 1 && dims == 0))
                    {
                        PrintArgList(cons, ParenFor.MethodCall, cons.ArgCount, 0, OmitMissingArguments);
                    }
                }
                if (_n.Args.Count > 1)
                {
                    PrintBracedBlockInNewExpr();
                }
            }
            return(true);
        }
예제 #9
0
        public bool AutoPrintComplexIdentOperator(Precedence precedence, Precedence context, Ambiguity flags)
        {
            // Handles #of and @`.`, including array types
            int    argCount = _n.ArgCount;
            Symbol name     = _n.Name;

            Debug.Assert((name == S.Of || name == S.Dot) && _n.IsCall);

            var first = _n.Args[0, null];

            if (first == null)
            {
                return(false);                // no args
            }
            bool needParens, needSpecialOfNotation = false;

            if (!CanAppearIn(precedence, context, out needParens) || needParens)
            {
                return(false);                // this only happens inside $ operator, e.g. $(a.b)
            }
            if (name == S.Dot)
            {
                // The trouble with the dot is its high precedence; because of
                // this, arguments after a dot cannot use prefix notation as a
                // fallback. For example "@.(a, b(c))" cannot be printed "a.b(c)"
                // since that means @.(a, b)(c)". The first argument to non-
                // unary "." can use prefix notation safely though, e.g.
                // "@.(b(c), a)" can (and must) be printed "b(c).a".
                if (argCount > 2)
                {
                    return(false);
                }
                if (HasPAttrs(first))
                {
                    return(false);
                }
                LNode afterDot = _n.Args.Last;
                // Unary dot is no problem: .(a) is parsed the same as .a, i.e.
                // the parenthesis are ignored, so we can print an expr like
                // @`.`(a+b) as .(a+b), but the parser counts parens on binary
                // dot, so in that case the argument after the dot must not be any
                // kind of call (except substitution) and must not have attributes,
                // unless it is in parens.
                if (argCount == 2 && !afterDot.IsParenthesizedExpr())
                {
                    if (HasPAttrs(afterDot))
                    {
                        return(false);
                    }
                    if (afterDot.IsCall && afterDot.Name != S.Substitute)
                    {
                        return(false);
                    }
                }
                else if ((flags & Ambiguity.CastRhs) != 0)
                {
                    return(false);                    // cannot print (Foo) @`.`(x) as (Foo) .x
                }
            }
            else if (name == S.Of)
            {
                var ici = ICI.Default | ICI.AllowAttrs;
                if ((flags & Ambiguity.InDefinitionName) != 0)
                {
                    ici |= ICI.NameDefinition;
                }
                if (!IsComplexIdentifier(_n, ici))
                {
                    if (IsComplexIdentifier(_n, ici | ICI.AllowAnyExprInOf))
                    {
                        needSpecialOfNotation = true;
                    }
                    else
                    {
                        return(false);
                    }
                }
            }

            if (name == S.Dot)
            {
                if (argCount == 1)
                {
                    _out.Write('.', true);
                    PrintExpr(first, EP.Substitute);
                }
                else
                {
                    PrintExpr(first, precedence.LeftContext(context), flags & Ambiguity.TypeContext);
                    _out.Write('.', true);
                    PrintExpr(_n.Args[1], precedence.RightContext(context));
                }
            }
            else if (_n.Name == S.Of)
            {
                // Check for special type names such as Foo? or Foo[]
                Symbol stk = SpecialTypeKind(_n, flags, context);
                if (stk != null)
                {
                    if (S.IsArrayKeyword(stk))
                    {
                        // We do something very strange in case of arrays of arrays:
                        // the order of the square brackets must be reversed when
                        // arrays are nested. For example, an array of two-dimensional
                        // arrays of int is written int[][,], rather than int[,][]
                        // which would be much easier to handle.
                        var stack     = InternalList <Symbol> .Empty;
                        var innerType = _n;
                        do
                        {
                            stack.Add(stk);
                            innerType = innerType.Args[1];
                        } while (S.IsArrayKeyword(stk = SpecialTypeKind(innerType, flags, context) ?? GSymbol.Empty));

                        PrintType(innerType, EP.Primary.LeftContext(context), (flags & Ambiguity.AllowPointer));

                        for (int i = 0; i < stack.Count; i++)
                        {
                            _out.Write(stack[i].Name, true);                             // e.g. [] or [,]
                        }
                    }
                    else
                    {
                        PrintType(_n.Args[1], EP.Primary.LeftContext(context), (flags & Ambiguity.AllowPointer));
                        _out.Write(stk == S._Pointer ? '*' : '?', true);
                    }
                    return(true);
                }

                PrintExpr(first, precedence.LeftContext(context));

                _out.Write(needSpecialOfNotation ? "!(" : "<", true);
                for (int i = 1; i < argCount; i++)
                {
                    if (i > 1)
                    {
                        WriteThenSpace(',', SpaceOpt.AfterCommaInOf);
                    }
                    PrintType(_n.Args[i], StartExpr, Ambiguity.InOf | Ambiguity.AllowPointer | (flags & Ambiguity.InDefinitionName));
                }
                _out.Write(needSpecialOfNotation ? ')' : '>', true);
            }
            else
            {
                Debug.Assert(_n.Name == S.Substitute);
                G.Verify(AutoPrintOperator(ContinueExpr, 0));
            }
            return(true);
        }