示例#1
0
        // returns the part of the string remaining
        // will load into self, setting up everything. Assumes we're mpty/null to start.
        private string p_parseFromString(string str, ParseFlags parseFlags, Internal.ParserState parserState)
        {
            if (str.Length == 0)
            {
                throw new EmptyStringException(parserState.Line, parserState.Column, "Was told to parse an empty string");
            }

            str = s_trimFrontOfString(str, parserState);
            if (str.Length == 0)
            {
                return("");
            }

            // start parsing types:
            // if first two characters are #(, we're an array.
            // if @( we're a map.
            // if [] we're a ref.
            // if < we're a binary string
            // otherwise, we're a value.

            if (str.Length >= 2 && str.Substring(0, 2) == "#(")
            {
                // We're an array
                m_type = ExpressionType.Array;
                m_array.Init();

                // move our string forward
                str = str.Substring(2);
                parserState.Column += 2;

                // continue building children as needed
                while (true)
                {
                    str = s_trimFrontOfString(str, parserState);

                    if (str.Length == 0)
                    {
                        throw new ArrayMissingEndParenException(parserState.Line, parserState.Column, "An Array was missing its ending paren");
                    }

                    if (str.Substring(0, 1) == ")")    // end array
                    {
                        break;                         // done
                    }
                    else
                    {
                        // parse as a new expression
                        var newExpression = CreateNull();
                        str = newExpression.p_parseFromString(str, parseFlags, parserState);

                        // add it to our array
                        ArrayAddElementToEnd(newExpression);
                    }
                }

                str = str.Substring(1);                 // remove the end array
                parserState.Column += 1;

                // done with array
                return(str);
            }

            else if (str.Length >= 2 && str.Substring(0, 2) == "@(")
            {
                // We're a map
                m_type = ExpressionType.Map;
                m_map.Init();

                // move our string accordingly
                str = str.Substring(2);
                parserState.Column += 2;

                // build our children as needed
                while (true)
                {
                    str = s_trimFrontOfString(str, parserState);

                    if (str.Length == 0)
                    {
                        throw new MapMissingEndParenException(parserState.Line, parserState.Column, "A Map was missing its ending paren");
                    }

                    if (str.Length >= 1 && str.Substring(0, 1) == ")")                     // end map
                    {
                        break;
                    }
                    else
                    {
                        // parse as a new expression - we'll alternate keys and values
                        // keep our previous position just in case the value is bad.
                        int prevLine   = parserState.Line;
                        int prevColumn = parserState.Column;

                        var keyExpression = CreateNull();
                        str = keyExpression.p_parseFromString(str, parseFlags, parserState);

                        if (keyExpression.ExpressionType != ExpressionType.Value)
                        {
                            throw new MapKeyMustBeAValueException(prevLine, prevColumn, "Map keys must be a value");
                        }

                        var valueExpression = CreateInvalid();
                        try
                        {
                            str = valueExpression.p_parseFromString(str, parseFlags, parserState);
                        }
                        catch (EmptyStringException)
                        {
                            // we ignore ESEs because we want to consider that no value for a better error.
                            // if not, the exception is good.
                        }

                        if (valueExpression.ExpressionType == ExpressionType.Invalid)
                        {
                            throw new MapNoValueException(prevLine, prevColumn, "Map key must have a value");
                        }

                        // ok now we have the key and the value
                        // both malloc so we can free later
                        MapSetValueForKey(keyExpression.Value, valueExpression);
                    }
                }

                // remove the end map
                str = str.Substring(1);
                parserState.Column += 1;

                // done with map
                return(str);
            }

            else if (str.Length >= 1 && str.Substring(0, 1) == "[")
            {
                // the current expression being processed is the one the attribute will be linked to.

                // process till the closing ]
                var endingBracketIndex = str.IndexOf(']');
                if (endingBracketIndex == -1)
                {
                    throw new ReferenceMissingEndBracketException(parserState.Line, parserState.Column, "A reference [] is missing its ending bracket");
                }

                var refName = str.Substring(1, endingBracketIndex - 1);

                // validate the contents
                var invalidName = false;
                for (int i = 0; i < refName.Length; ++i)
                {
                    char v = refName[i];

                    bool isAlpha  = (v >= 'a' && v <= 'z') || (v >= 'A' && v <= 'Z');
                    bool isNumber = (v >= '0' && v <= '9');
                    bool isUnder  = (v == '_');

                    if (i == 0 && (isAlpha || isUnder))
                    {
                    }
                    else if (i != 0 && (isAlpha || isNumber || isUnder))
                    {
                    }
                    else
                    {
                        invalidName = true;
                        break;
                    }
                }

                if (invalidName)
                {
                    throw new ReferenceInvalidNameException(parserState.Line, parserState.Column, "A reference doesn't have a valid name");
                }

                // move forward
                parserState.MoveForwardBasedOnString(str.Substring(0, endingBracketIndex + 1));
                str = str.Substring(endingBracketIndex + 1);

                // continue parsing at the same level : stored the reference name
                var resultString = p_parseFromString(str, parseFlags, parserState);

                // now bind the ref - creating a copy of what was made. This will be used for the template.
                parserState.InternalReferenceMap.SetExpressionForKey(refName, Copy());

                // and continue
                return(resultString);
            }

            else if (str.Length >= 2 && str.Substring(0, 2) == "*[")
            {
                // parse the reference name
                var endingBracketIndex = str.IndexOf(']');
                if (endingBracketIndex == -1)
                {
                    throw new ReferenceInsertMissingEndBracketException(parserState.Line, parserState.Column, "A reference insert *[] is missing its ending bracket");
                }

                var refName = str.Substring(2, endingBracketIndex - 2);

                // move forward
                parserState.MoveForwardBasedOnString(str.Substring(0, endingBracketIndex + 1));
                str = str.Substring(endingBracketIndex + 1);

                var referenceExpr = parserState.InternalReferenceMap.ExpressionForKey(refName);
                if (referenceExpr == null)
                {
                    // try again with the external if we have it
                    if (parserState.ExternalReferenceMap != null)
                    {
                        referenceExpr = parserState.ExternalReferenceMap.ExpressionForKey(refName);
                    }
                }

                if (referenceExpr == null)
                {
                    // not found
                    throw new ReferenceUnknownReferenceException(parserState.Line, parserState.Column, "Tried to insert a reference, but couldn't find it.");
                }

                // copy this into ourself
                p_copyFrom(referenceExpr);

                return(str);
            }

            // null expressions will be treated as a value, and then parsed seperately.

            else if (
                str.Length >= 1 && str.Substring(0, 1) == "<"
                )
            {
                // look for the ending <
                var endingQuote = str.IndexOf('>');
                if (endingQuote == -1)
                {
                    // not found
                    throw new BinaryDataNoEndingException(parserState.Line, parserState.Column, "Tried to find the ending > for binary data, but not found.");
                }

                byte[] data;
                try
                {
                    data = System.Convert.FromBase64String(str.Substring(1, endingQuote - 1));                     // -1 for starting quote. ending was not part.
                }
                catch (Exception)
                {
                    throw new BinaryDataInvalidBase64Exception(parserState.Line, parserState.Column, "Unable to decode the base64 data.");
                }

                m_type            = ExpressionType.BinaryData;
                m_binaryData.data = data;

                parserState.MoveForwardBasedOnString(str.Substring(0, endingQuote + 1));

                return(str.Substring(endingQuote + 1));
            }

            else if (str.Length >= 1)             // its a value: must be at least one character
            {
                var val = s_createValueOfString(str, parserState);

                // was it a null/nil string?
                if (val.value == "nil" || val.value == "null")
                {
                    m_type = ExpressionType.Null;
                }
                else
                {
                    m_type       = ExpressionType.Value;
                    m_value.data = val.value;
                }

                parserState.MoveForwardBasedOnString(str.Substring(0, val.endIndex));

                return(str.Substring(val.endIndex));
            }

            // otherwise we have no idea what happened
            return("");
        }
示例#2
0
        // Trims the given string by removing whitespace or comments from the beginning of the string
        private static string s_trimFrontOfString(string str, Internal.ParserState parserState)
        {
            while (true)
            {
                if (str.Length == 0)                 // trimmed everything
                {
                    return(str);
                }

                char first = str[0];

                // skip whitespace
                if (s_isWhitespace(first))
                {
                    str = str.Substring(1);

                    if (s_isNewline(first))
                    {
                        parserState.Line  += 1;
                        parserState.Column = 1;
                    }
                    else
                    {
                        parserState.Column += 1;
                    }
                }

                // comment
                else if (first == ';')
                {
                    bool isTillNewline = true;

                    if (str.Length >= 4)
                    {
                        if (str.Substring(0, 4) == s_StartBlockComment)
                        {
                            isTillNewline = false;
                        }
                    }

                    int endIndex =
                        (isTillNewline
                                                        ? str.IndexOf('\n') // end of line
                                                        : str.IndexOf(s_EndBlockComment)
                        );

                    int lengthToSkip = isTillNewline ? 1 : s_EndBlockComment.Length;

                    // Move forward columns/rows as needed
                    parserState.MoveForwardBasedOnString(
                        str.Substring(0, (endIndex == -1) ? str.Length : (endIndex + lengthToSkip))
                        );

                    if (endIndex == -1 ||
                        endIndex > str.Length - lengthToSkip)
                    {
                        str = "";                                     // dead
                    }
                    else                                              // slice
                    {
                        str = str.Substring(endIndex + lengthToSkip); // skip the comment
                    }
                }

                else
                {
                    break;
                }
            }

            return(str);
        }