Пример #1
0
        /// <summary>
        /// Parses a string representation into a KFF file. Throws an exception if the string is malformed.
        /// </summary>
        /// <param name="fileName">The name of the file that will be parsed.</param>
        /// <param name="s">The string to parse.</param>
        public KFFFile Parse(string fileName, string s)
        {
            if (s == null)
            {
                throw new ArgumentNullException("The string to parse can't be null.");
            }
            if (s == "")
            {
                return(new KFFFile(fileName));
            }

            this.fileName = fileName;
            this.s        = s;
            this.pos      = 0;

            KFFFile f = new KFFFile(fileName);

            SkipWhiteSpacesAndComments();

            while (pos < s.Length)
            {
                int begin  = pos;
                Tag newTag = Tag();
                if (f.Has(newTag.name))
                {
                    throw new KFFParseException("Found duplicated Tag '" + newTag.name + "' (" + TextFileData.Calculate(this.fileName, this.s, begin) + ").");
                }
                f.Set(newTag);
            }
            return(f);
        }
Пример #2
0
 private PayloadInteger TryParseInteger(string numberText)
 {
     if (!long.TryParse(numberText, Syntax.numberStyle, Syntax.numberFormat, out long num))
     {
         throw new KFFParseException("The value '" + numberText + "' can't be represented by a Integer datatype ('long') (" + TextFileData.Calculate(this.fileName, this.s, this.pos) + ").");
     }
     return(new PayloadInteger(num));
 }
Пример #3
0
 private PayloadDecimal TryParseDecimal(string numberText)
 {
     if (!double.TryParse(numberText, Syntax.numberStyle, Syntax.numberFormat, out double num))
     {
         throw new KFFParseException("The value '" + numberText + "' can't be represented by a Decimal datatype ('double') (" + TextFileData.Calculate(this.fileName, this.s, this.pos) + ").");
     }
     return(new PayloadDecimal(num));
 }
Пример #4
0
        private Payload Payload()
        {
            // Start at the beginning char, whitespaces need to be skipped earlier.

            //
            //	CLASS
            //
            if (currentChar == Syntax.CLASS_OPENING)
            {
                return(PayloadClass());
            }

            //
            //	LIST
            //
            if (currentChar == Syntax.LIST_OPENING)
            {
                return(PayloadList());
            }

            //
            //	STRING
            //
            if (currentChar == Syntax.STRING_CONTAINER)
            {
                return(PayloadString());
            }

            //
            //	BOOLEAN
            //
            if (currentChar == Syntax.TOKEN_TRUE[0])
            {
                return(True());
            }
            if (currentChar == Syntax.TOKEN_FALSE[0])
            {
                return(False());
            }

            //
            //	NUMBER (Integer / Decimal)
            //
            // NaN
            if (currentChar == Syntax.TOKEN_NOT_A_NUMBER[0])
            {
                return(NumberNaN());
            }
            bool negativeSignFlag = false;

            if (currentChar == Syntax.NEGATIVE_SIGN)
            {
                negativeSignFlag = true;

                pos++;                 // '-'
            }
            if (currentChar == Syntax.TOKEN_INFINITY[0])
            {
                return(NumberInfinityPosNeg(negativeSignFlag));
            }
            if (Syntax.IsDigit(currentChar))                // tagi numeryczne zaczynają się liczbą lub minusem w wypadku ujemnego tagu.
            {
                return(NumericLiteral(negativeSignFlag));
            }
            else
            {
                // If the parser found non-digits after the '-' (negative sign).
                // Throw an exception.
                if (negativeSignFlag)
                {
                    throw new KFFParseException("Expected to find [0-9], but found '" + currentChar + "' (" + TextFileData.Calculate(this.fileName, this.s, this.pos) + ").");
                }
            }

            throw new KFFParseException("Unexpected char. '" + currentChar + "' (" + TextFileData.Calculate(this.fileName, this.s, this.pos) + ").");
        }
Пример #5
0
        private Tag Tag()
        {
            // we start directly at the name.
            string name = Name();

            this.SkipWhiteSpacesAndComments();

            if (this.currentChar != Syntax.NAME_PAYLOAD_SEPARATOR)
            {
                throw new KFFParseException("Expected to find '" + Syntax.NAME_PAYLOAD_SEPARATOR + "', but found '" + currentChar + "' (" + TextFileData.Calculate(this.fileName, this.s, this.pos) + ").");
            }
            pos++;             // '='

            this.SkipWhiteSpacesAndComments();

            Payload payload = Payload();

            this.SkipWhiteSpacesAndComments();

            if (this.currentChar != Syntax.TAG_END)
            {
                throw new KFFParseException("Expected to find '" + Syntax.TAG_END + "', but found '" + currentChar + "' (" + TextFileData.Calculate(this.fileName, this.s, this.pos) + ").");
            }
            pos++;             // ';'

            this.SkipWhiteSpacesAndComments();

            if (payload.type == DataType.Boolean)
            {
                return(new TagBoolean(name, (PayloadBoolean)payload));
            }
            if (payload.type == DataType.Integer)
            {
                return(new TagInteger(name, (PayloadInteger)payload));
            }
            if (payload.type == DataType.Decimal)
            {
                return(new TagDecimal(name, (PayloadDecimal)payload));
            }
            if (payload.type == DataType.String)
            {
                return(new TagString(name, (PayloadString)payload));
            }
            if (payload.type == DataType.Class)
            {
                return(new TagClass(name, (PayloadClass)payload));
            }
            if (payload.type == DataType.List)
            {
                return(new TagList(name, (PayloadList)payload));
            }
            throw new KFFParseException("Invalid payload type '" + payload.type.ToString() + "' (" + TextFileData.Calculate(this.fileName, this.s, this.pos) + ").");
        }
Пример #6
0
        private PayloadDecimal NumberInfinityPosNeg(bool isNegative)
        {
            // This function assumes that the pos is at the 1st character of the "Infinity" keyword (minus needs to be skipped earlier).

            pos++;
            for (int i = 1; i < Syntax.TOKEN_INFINITY.Length; pos++, i++)
            {
                // If any of the chars is not valid, throw an exception.
                if (currentChar != Syntax.TOKEN_INFINITY[i])
                {
                    throw new KFFParseException("Expected to find '" + Syntax.TOKEN_INFINITY[i] + "', but found '" + currentChar + "' (" + TextFileData.Calculate(this.fileName, this.s, this.pos) + ").");
                }
            }

            SkipWhiteSpacesAndComments();

            if (isNegative)
            {
                return(new PayloadDecimal(double.NegativeInfinity));
            }
            return(new PayloadDecimal(double.PositiveInfinity));
        }
Пример #7
0
        private Payload NumericLiteral(bool isNegative)
        {
            // This function assumes that the pos is at the 1st character of a numeric literal.

            StringBuilder sb = new StringBuilder();

            // If has encountered negative sign, append it as it's a part of the number.
            if (isNegative)
            {
                sb.Append(Syntax.NEGATIVE_SIGN);
            }

            Digits(ref sb);

            bool isDecimal = false;

            //	Decimal
            //
            if (currentChar == Syntax.DECIMAL_SEPARATOR)
            {
                isDecimal = true;

                sb.Append(currentChar);                     // '.'
                pos++;                                      // '.'

                if (Syntax.IsDigit(currentChar))
                {
                    Digits(ref sb);
                }
                else
                {
                    throw new KFFParseException("Expected to find [0-9], but found '" + currentChar + "' (" + TextFileData.Calculate(this.fileName, this.s, this.pos) + ").");
                }
            }

            //	Decimal (exponential)
            //
            if (currentChar == 'e' || currentChar == 'E')
            {
                isDecimal = true;

                sb.Append(currentChar);

                pos++;

                if (currentChar == Syntax.NEGATIVE_SIGN)
                {
                    sb.Append(currentChar);

                    pos++;
                }
                if (Syntax.IsDigit(currentChar))
                {
                    do
                    {
                        sb.Append(currentChar);
                        pos++;
                    } while(Syntax.IsDigit(currentChar));
                }
                else
                {
                    throw new KFFParseException("Expected to find [0-9], but found '" + currentChar + "' (" + TextFileData.Calculate(this.fileName, this.s, this.pos) + ").");
                }
            }

            SkipWhiteSpacesAndComments();             // right before the ; char

            //	Decimal
            //
            if (isDecimal)
            {
                return(TryParseDecimal(sb.ToString()));
            }

            //	Integer
            //
            else
            {
                return(TryParseInteger(sb.ToString()));
            }
        }
Пример #8
0
        private PayloadList PayloadList()
        {
            PayloadList payload = new PayloadList();

            pos++;             // '['

            SkipWhiteSpacesAndComments();

            // If there are no payloads inside of the list, return an empty list.
            if (currentChar == Syntax.LIST_CLOSING)
            {
                pos++;                 // ']'

                SkipWhiteSpacesAndComments();

                return(payload);
            }


funcPayload_AnotherPayload:

            Payload p = Payload();

            // If the list has a type assigned and the payload is not of this type.
            if (payload.listType != DataType.EmptyList && p.type != payload.listType)
            {
                throw new KFFParseException("Found mismatched payload '" + p.type.ToString() + "' (" + TextFileData.Calculate(this.fileName, this.s, this.pos) + ").");
            }
            payload.Add(p);

            if (currentChar == Syntax.LIST_ELEMENT_SEPARATOR)
            {
                pos++;                 // ','

                SkipWhiteSpacesAndComments();

                goto funcPayload_AnotherPayload;
            }

            if (currentChar == Syntax.LIST_CLOSING)
            {
                pos++;                 // ']'

                SkipWhiteSpacesAndComments();

                return(payload);
            }

            throw new KFFParseException("Expected to find '" + Syntax.LIST_ELEMENT_SEPARATOR + "' or '" + Syntax.LIST_CLOSING + "', but found '" + currentChar + "' (" + TextFileData.Calculate(this.fileName, this.s, pos) + ").");
        }
Пример #9
0
        private PayloadDecimal NumberNaN()
        {
            pos++;
            for (int i = 1; i < Syntax.TOKEN_NOT_A_NUMBER.Length; pos++, i++)
            {
                // If any of the chars is not valid, throw an exception.
                if (currentChar != Syntax.TOKEN_NOT_A_NUMBER[i])
                {
                    throw new KFFParseException("Expected to find '" + Syntax.TOKEN_NOT_A_NUMBER[i] + "', but found '" + currentChar + "' (" + TextFileData.Calculate(this.fileName, this.s, this.pos) + ").");
                }
            }

            SkipWhiteSpacesAndComments();

            return(new PayloadDecimal(double.NaN));
        }
Пример #10
0
        private PayloadClass PayloadClass()
        {
            PayloadClass payload = new PayloadClass();

            pos++;                        // '{'

            SkipWhiteSpacesAndComments(); // to ustawi na pierwszym tagu, a każdy kolejny będzie z automatu bo tagi skipują WS'y za sobą.

            while (currentChar != Syntax.CLASS_CLOSING)
            {
                int begin  = pos;
                Tag newTag = Tag();
                if (payload.Has(newTag.name))
                {
                    throw new KFFParseException("Found duplicated Tag '" + newTag.name + "' (" + TextFileData.Calculate(this.fileName, this.s, begin) + ").");
                }
                payload.Set(newTag);
            }

            pos++;             // '}'

            SkipWhiteSpacesAndComments();

            return(payload);
        }
Пример #11
0
        private PayloadString PayloadString()
        {
            pos++;             // '"'

            StringBuilder sb = new StringBuilder();

            do
            {
                // If right after the '"' is another '"' - we got an empty string payload.
                if (currentChar == Syntax.STRING_CONTAINER)
                {
                    pos++;

                    SkipWhiteSpacesAndComments();

                    return(new PayloadString(""));
                }
                // If the char is escaping something...
                if (currentChar == Syntax.ESCAPE_CHAR)
                {
                    pos++;                     // '\'

                    // If it is escaping something that can be escaped...
                    // Append the real char which that sequence is escaping.
                    if (Syntax.IsEscapable(currentChar))                       // currentChar == KFFSyntax.STRING_CONTAINER )
                    {
                        sb.Append(Syntax.GetUnescaped(s.Substring(pos - 1, 2)));
                        pos++;
                    }
                    // If it is escaping an unescapable char...
                    else
                    {
                        throw new KFFParseException("The char. '" + currentChar + "' isn't escapable (" + TextFileData.Calculate(this.fileName, this.s, this.pos) + ").");
                    }
                }
                // If the char is NOT escaping anything...
                else
                {
                    sb.Append(currentChar);
                    pos++;
                }
            } while(currentChar != Syntax.STRING_CONTAINER);

            pos++;             // '"'

            SkipWhiteSpacesAndComments();

            return(new PayloadString(sb.ToString()));
        }
Пример #12
0
        private PayloadBoolean False()
        {
            pos++;
            for (int i = 1; i < Syntax.TOKEN_FALSE.Length; pos++, i++)
            {
                // If any of the chars is not valid, throw an exception.
                if (currentChar != Syntax.TOKEN_FALSE[i])
                {
                    throw new KFFParseException("Expected to find '" + Syntax.TOKEN_FALSE[i] + "', but found '" + currentChar + "' (" + TextFileData.Calculate(this.fileName, this.s, this.pos) + ").");
                }
            }

            SkipWhiteSpacesAndComments();
            // If no exception was thrown, that means there is a 'true' boolean value.
            return(new PayloadBoolean(false));
        }
Пример #13
0
        private string Name()
        {
            if (Syntax.IsAlphabetical(currentChar) || currentChar == '_')                // Nazwy TAG'ów zaczynają się literą lub '_'.
            {
                StringBuilder sb = new StringBuilder();

                do
                {
                    sb.Append(currentChar);
                    pos++;
                } while(Syntax.IsAlphaNumerical(currentChar) || currentChar == '_');

                return(sb.ToString());
            }
            throw new KFFParseException("Expected to find [A-Za-z_], but found '" + currentChar + "' (" + TextFileData.Calculate(this.fileName, this.s, this.pos) + ").");
        }
Пример #14
0
 private void SkipWhiteSpacesAndComments()
 {
     while (this.pos < this.s.Length && (Syntax.IsWhiteSpace(currentChar) || currentChar == Syntax.COMMENT[0]))
     {
         if (SilentPeek(Syntax.COMMENT))
         {
             Comment();
             continue;
         }
         if (Syntax.IsWhiteSpace(currentChar))
         {
             this.pos++;
             continue;
         }
         throw new KFFParseException("Invalid token '" + currentChar + "' (" + TextFileData.Calculate(this.fileName, this.s, this.pos) + ").");
     }
 }