Exemple #1
0
        Ast.StringLiteral _GetString(FtlParserStream ps)
        {
            var val = new StringBuilder();

            ps.ExpectChar('"');

            int ch;

            while ((ch = ps.TakeChar(x => x != '"' && x != '\r' && x != '\n')) != Eof)
            {
                if (ch == '\\')
                {
                    GetEscapeSequence(ps, new int[] { '{', '\\', '"' }, val);
                }
                else
                {
                    val.Append((char)ch);
                }
            }

            if (ps.CurrentIs('\r') || ps.CurrentIs('\n'))
            {
                throw new ParseException("E0020");
            }

            ps.Next();

            return(new Ast.StringLiteral(val.ToString()));
        }
Exemple #2
0
        Ast.Variant _GetVariant(FtlParserStream ps, bool hasDefault)
        {
            bool defaultIndex = false;

            if (ps.CurrentIs('*'))
            {
                if (hasDefault)
                {
                    throw new ParseException("E0015");
                }
                ps.Next();
                defaultIndex = true;
                hasDefault   = true;
            }

            ps.ExpectChar('[');

            var key = GetVariantKey(ps);

            ps.ExpectChar(']');

            if (ps.IsPeekValueStart())
            {
                ps.SkipIndent();
                var value = GetValue(ps);
                return(new Ast.Variant(key, value, defaultIndex));
            }

            throw new ParseException("E0012");
        }
Exemple #3
0
        public Ast.BaseComment _GetComment(FtlParserStream ps)
        {
            // 0 - comment
            // 1 - group comment
            // 2 - resource comment
            int level   = -1;
            var content = new StringBuilder();

            while (true)
            {
                int i = -1;
                while (ps.CurrentIs('#') && (i < (level == -1 ? 2 : level)))
                {
                    ps.Next();
                    i++;
                }

                if (level == -1)
                {
                    level = i;
                }

                if (!ps.IsPeekNewLine())
                {
                    ps.ExpectChar(' ');
                    int ch;
                    while ((ch = ps.TakeChar(x => x != '\r' && x != '\n')) != Eof)
                    {
                        content.Append((char)ch);
                    }
                }

                if (ps.IsPeekNextLineComment(level))
                {
                    content.Append('\n');
                    ps.SkipNewLine();
                }
                else
                {
                    break;
                }
            }

            var text = content.ToString();

            switch (level)
            {
            case 0:
                return(new Ast.Comment(text));

            case 1:
                return(new Ast.GroupComment(text));

            case 2:
                return(new Ast.ResourceComment(text));
            }
            throw new InvalidOperationException($"Unknown level value '{level}'");
        }
Exemple #4
0
        public Ast.Entry GetEntry(FtlParserStream ps)
        {
            if (ps.CurrentIs('#'))
            {
                return(GetComment(ps));
            }

            if (ps.CurrentIs('-'))
            {
                return(GetTerm(ps));
            }

            if (ps.IsIdentifierStart())
            {
                return(GetMessage(ps));
            }

            throw new ParseException("E0002");
        }
Exemple #5
0
 Ast.Expression GetArgVal(FtlParserStream ps)
 {
     if (ps.IsNumberStart())
     {
         return(GetNumber(ps));
     }
     else if (ps.CurrentIs('"'))
     {
         return(GetString(ps));
     }
     throw new ParseException("E0012");
 }
Exemple #6
0
        Ast.NumberLiteral _GetNumber(FtlParserStream ps)
        {
            var num = new StringBuilder();

            if (ps.CurrentIs('-'))
            {
                num.Append('-');
                ps.Next();
            }

            num.Append(GetDigits(ps));

            if (ps.CurrentIs('.'))
            {
                num.Append('.');
                ps.Next();
                num.Append(GetDigits(ps));
            }

            return(new Ast.NumberLiteral(num.ToString()));
        }
Exemple #7
0
 Ast.SyntaxNode _GetValue(FtlParserStream ps)
 {
     if (ps.CurrentIs('{'))
     {
         ps.Peek();
         ps.PeekInlineWs();
         if (ps.IsPeekNextLineVariantStart())
         {
             return(GetVariantList(ps));
         }
     }
     return(GetPattern(ps));
 }
Exemple #8
0
        /// <summary>
        /// Parse the first Message or Term in `source`.
        ///
        /// Skip all encountered comments and start parsing at the first Message or
        /// Term start. Return Junk if the parsing is not successful.
        ///
        /// Preceding comments are ignored unless they contain syntax errors
        /// themselves, in which case Junk for the invalid comment is returned.
        /// </summary>
        public Ast.Entry ParseEntry(TextReader source)
        {
            var ps = new FtlParserStream(source);

            ps.SkipBlankLines();

            while (ps.CurrentIs('#'))
            {
                var skipped = GetEntryOrJunk(ps);
                if (skipped is Ast.Junk)
                {
                    // Don't skip Junk comments.
                    return(skipped);
                }
                ps.SkipBlankLines();
            }

            return(GetEntryOrJunk(ps));
        }
Exemple #9
0
        Ast.SyntaxNode _GetSelectorExpression(FtlParserStream ps)
        {
            if (ps.CurrentIs('{'))
            {
                return(GetPlaceable(ps));
            }

            var literal = GetLiteral(ps);

            var mtReference = literal as Ast.MessageTermReference;

            if (mtReference == null)
            {
                return(literal);
            }

            var ch = ps.Current;

            if (ch == '.')
            {
                ps.Next();

                var attr = GetIdentifier(ps);
                return(new Ast.AttributeExpression(mtReference, attr));
            }

            if (ch == '[')
            {
                ps.Next();

                if (mtReference is Ast.MessageReference)
                {
                    throw new ParseException("E0024");
                }

                var key = GetVariantKey(ps);

                ps.ExpectChar(']');

                return(new Ast.VariantExpression(literal, key));
            }

            if (ch == '(')
            {
                ps.Next();

                if (!s_fnName.IsMatch(mtReference.Id.Name))
                {
                    throw new ParseException("E0008");
                }

                var args = GetCallArgs(ps);

                ps.ExpectChar(')');

                var func = new Ast.Function(mtReference.Id.Name);
                if (_withSpans)
                {
                    func.AddSpan(mtReference.Span.Start, mtReference.Span.End);
                }

                return(new Ast.CallExpression(func, args.Positional, args.Named));
            }

            return(literal);
        }
Exemple #10
0
        Ast.SyntaxNode _GetExpression(FtlParserStream ps)
        {
            ps.SkipInlineWs();

            var selector = GetSelectorExpression(ps);

            ps.SkipInlineWs();

            if (ps.CurrentIs('-'))
            {
                ps.Peek();

                if (!ps.CurrentPeekIs('>'))
                {
                    ps.ResetPeek();
                    return(selector);
                }

                if (selector is Ast.MessageReference)
                {
                    throw new ParseException("E0016");
                }

                if (selector is Ast.AttributeExpression ae &&
                    ae.Ref is Ast.MessageReference)
                {
                    throw new ParseException("E0018");
                }

                if (selector is Ast.VariantExpression)
                {
                    throw new ParseException("E0017");
                }

                ps.Next();
                ps.Next();

                ps.SkipInlineWs();

                var variants = GetVariants(ps);

                if (variants.Count == 0)
                {
                    throw new ParseException("E0011");
                }

                // VariantLists are only allowed in other VariantLists.
                if (variants.Any(v => v.Value is Ast.VariantList))
                {
                    throw new ParseException("E0023");
                }

                ps.ExpectIndent();

                return(new Ast.SelectExpression(selector, variants));
            }
            else if (selector is Ast.AttributeExpression ae &&
                     ae.Ref is Ast.TermReference)
            {
                throw new ParseException("E0019");
            }

            return(selector);
        }