예제 #1
0
파일: Parser.cs 프로젝트: Timwi/ParseCs
        private static CsIdentifier parseExpressionIdentifier(TokenJar tok, ref int i)
        {
            var startIndex = tok[i].StartIndex;

            // Check if this can be parsed as a type identifier. If it can't, don't throw; if it failed because of a malformed generic type parameter, it could still be a less-than operator.
            CsTypeName ty;
            var j = i;
            try
            {
                ty = parseTypeName(tok, ref j, typeIdentifierFlags.AllowKeywords | typeIdentifierFlags.DontAllowDot).Item1;
            }
            catch (ParseException)
            {
                goto afterTy;
            }

            // Since we didn't allow dot and we didn't allow arrays, nullables or pointers, we should get a simple name
            if (!(ty is CsConcreteTypeName) || ((CsConcreteTypeName) ty).Parts.Count != 1)
                throw new ParseException("Unexpected internal error: Expected simple name, received '{0}'.".Fmt(ty), i);
            var simpleName = ((CsConcreteTypeName) ty).Parts[0];

            // Special case: only accept an identifier with generic type parameters if it has one of a special set of tokens following it; otherwise, reject it so that it is parsed as a less-than operator
            // (this is so that a generic method group expression is correctly parsed, but two less-than/greater-than or less-than/shift-right expressions are not mistaken for a generic method group expression)
            if (!simpleName.EndsWithGenerics || (tok.IndexExists(j) && tok[j].Type == TokenType.Builtin && _genericMethodGroupMagicalTokens.Contains(tok[j].TokenStr)))
            {
                i = j;
                return simpleName;
            }

            afterTy:
            var ret = new CsNameIdentifier { StartIndex = startIndex, EndIndex = tok[i].EndIndex, Name = tok[i].Identifier("Identifier expected.") };
            i++;
            return ret;
        }
예제 #2
0
파일: Parser.cs 프로젝트: Timwi/ParseCs
        private static Tuple<CsTypeName, bool> parseTypeName(TokenJar tok, ref int i, typeIdentifierFlags flags, bool tryNotToThrow = false)
        {
            var ty = new CsConcreteTypeName { StartIndex = tok[i].StartIndex };
            if (tok[i].IsIdentifier("global") && tok[i + 1].IsBuiltin("::"))
            {
                ty.HasGlobal = true;
                i += 2;
            }

            var j = i;
            bool onShr = false;
            while (true)
            {
                CsIdentifier partAbstract;
                if (tok[j].Type == TokenType.Builtin && (flags & typeIdentifierFlags.AllowKeywords) == typeIdentifierFlags.AllowKeywords && builtinTypes.Contains(tok[j].TokenStr))
                    partAbstract = new CsKeywordIdentifier { StartIndex = tok[j].StartIndex, EndIndex = tok[j].EndIndex, Keyword = tok[j].TokenStr };
                else if (ty.Parts.Count > 0 && (flags & typeIdentifierFlags.Lenient) != 0 && tok[j].Type != TokenType.Identifier)
                {
                    ty.EndIndex = tok[j].EndIndex;
                    return Tuple.Create((CsTypeName) ty, false);
                }
                else if (tok[j].Type != TokenType.Identifier && tryNotToThrow)
                    return null;
                else
                    partAbstract = new CsNameIdentifier { StartIndex = tok[j].StartIndex, EndIndex = tok[j].EndIndex, Name = tok[j].Identifier("Type expected.") };
                j++;
                ty.Parts.Add(partAbstract);
                i = j;

                if (tok[j].IsBuiltin("<"))
                {
                    if (!(partAbstract is CsNameIdentifier))
                        throw new ParseException("'{0}' cannot have generic arguments.".Fmt(partAbstract.ToString()), tok[j].StartIndex, ty);
                    var part = (CsNameIdentifier) partAbstract;
                    part.GenericTypeArguments = new List<CsTypeName>();
                    j++;
                    if ((flags & typeIdentifierFlags.AllowEmptyGenerics) != 0 && (tok[j].IsBuiltin(",") || tok[j].IsBuiltin(">")))
                    {
                        part.GenericTypeArguments.Add(new CsEmptyGenericParameter { StartIndex = tok[j].StartIndex, EndIndex = tok[j].StartIndex });
                        while (tok[j].IsBuiltin(","))
                        {
                            j++;
                            part.GenericTypeArguments.Add(new CsEmptyGenericParameter { StartIndex = tok[j].StartIndex, EndIndex = tok[j].StartIndex });
                        }
                        if (!tok[j].IsBuiltin(">"))
                            throw new ParseException("',' or '>' expected.", tok[j].StartIndex, ty);
                        j++;
                    }
                    else
                    {
                        try
                        {
                            var result = parseTypeName(tok, ref j, (flags & typeIdentifierFlags.Lenient) | typeIdentifierFlags.AllowNullablesAndPointers | typeIdentifierFlags.AllowArrays | typeIdentifierFlags.AllowKeywords | typeIdentifierFlags.AllowShr);
                            part.GenericTypeArguments.Add(result.Item1);
                            while (tok[j].IsBuiltin(","))
                            {
                                j++;
                                result = parseTypeName(tok, ref j, (flags & typeIdentifierFlags.Lenient) | typeIdentifierFlags.AllowNullablesAndPointers | typeIdentifierFlags.AllowArrays | typeIdentifierFlags.AllowKeywords | typeIdentifierFlags.AllowShr);
                                part.GenericTypeArguments.Add(result.Item1);
                            }
                            if (result.Item2)
                                // We're definitely on a ">>" token
                                j++;
                            else
                            {
                                if (tok[j].IsBuiltin(">"))
                                    j++;
                                else if (tok[j].IsBuiltin(">>") && (flags & typeIdentifierFlags.AllowShr) != 0)
                                    onShr = true;
                                else
                                    throw new ParseException("',' or '>' expected. (3)", tok[j].StartIndex, ty);
                            }
                        }
                        catch (ParseException)
                        {
                            if ((flags & typeIdentifierFlags.Lenient) != 0)
                            {
                                part.GenericTypeArguments = null;
                                return Tuple.Create((CsTypeName) ty, false);
                            }
                            throw;
                        }
                    }
                }
                i = j;
                if (!onShr && (flags & typeIdentifierFlags.DontAllowDot) == 0 && tok[j].IsBuiltin("."))
                    j++;
                else
                    break;
            }

            ty.EndIndex = tok[j - 1].EndIndex + (onShr ? 1 : 0);
            CsTypeName ret = ty;

            try
            {
                if ((flags & typeIdentifierFlags.AllowNullablesAndPointers) != 0 && !onShr)
                {
                    while (tok[j].IsBuiltin("*"))
                    {
                        ret = new CsPointerTypeName { StartIndex = ret.StartIndex, EndIndex = tok[j].EndIndex, InnerType = ret };
                        j++;
                    }
                    if (tok[j].IsBuiltin("?"))
                    {
                        ret = new CsNullableTypeName { StartIndex = ret.StartIndex, EndIndex = tok[j].EndIndex, InnerType = ret };
                        j++;
                    }
                }
                i = j;
                if ((flags & typeIdentifierFlags.AllowArrays) != 0 && !onShr)
                {
                    var arrayRanks = new List<int>();
                    while (tok[j].IsBuiltin("[") && (tok[j + 1].IsBuiltin("]") || tok[j + 1].IsBuiltin(",")))
                    {
                        j++;
                        int num = 1;
                        while (tok[j].IsBuiltin(","))
                        {
                            num++;
                            j++;
                        }
                        if (!tok[j].IsBuiltin("]"))
                        {
                            if ((flags & typeIdentifierFlags.Lenient) == 0)
                                throw new ParseException("',' or ']' expected.", tok[j].StartIndex, ret);
                            if (arrayRanks.Count > 0)
                                ret = new CsArrayTypeName { StartIndex = ret.StartIndex, EndIndex = tok[j - 1].EndIndex, ArrayRanks = arrayRanks, InnerType = ret };
                            return Tuple.Create(ret, false);
                        }
                        j++;
                        i = j;
                        arrayRanks.Add(num);
                    }
                    if (arrayRanks.Count > 0)
                        ret = new CsArrayTypeName { StartIndex = ret.StartIndex, EndIndex = tok[j - 1].EndIndex, ArrayRanks = arrayRanks, InnerType = ret };
                }
            }
            catch (ParseException e)
            {
                if ((flags & typeIdentifierFlags.Lenient) != 0)
                    return Tuple.Create(ret, false);
                if (e.IncompleteResult is CsTypeName)
                    throw;
                throw new ParseException(e.Message, e.Index, ret, e);
            }
            i = j;
            return Tuple.Create(ret, onShr);
        }