示例#1
0
        //
        /// <summary>
        /// Creates an expression from a string.
        /// </summary>
        /// <param name="str">The string.</param>
        /// <param name="flags">Flags about parsin.</param>
        /// <param name="referenceTable">The table to use for pulling references in, after ones in the file.</param>
        /// <returns>The created expression, or null if none.</returns>
        //
        public static Expression CreateFromStringWithExternalReferenceTable(string str, ParseFlags flags, ReferenceTable referenceTable)
        {
            var expr = CreateInvalid();

            var parserState = new Internal.ParserState();

            parserState.ExternalReferenceMap = referenceTable;

            // we assume its UTF8 safe since csharp should take care of this

            // now start parsing
            var rest = expr.p_parseFromString(
                str, flags, parserState
                );

            var postRest = s_trimFrontOfString(rest, parserState);

            if (postRest.Length != 0)
            {
                throw new ExtraDataAfterParsingRootException(parserState.Line, parserState.Column, "Extra data after parsing the root expression");
            }

            if (expr.ExpressionType == ExpressionType.Invalid)
            {
                throw new EmptyStringException(parserState.Line, parserState.Column, "No expression found [remained invalid]");
            }

            return(expr);
        }
示例#2
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("");
        }
示例#3
0
        private static PrivateWexprStringValue s_createValueOfString(string str, Internal.ParserState parserState)
        {
            // two pass:
            // first pass, get the length of the size
            // second pass, store the buffer

            int  bufferLength   = 0;
            bool isQuotedString = false;
            bool isEscaped      = false;
            int  pos            = 0; // position we're parsing at

            if (str[0] == '"')
            {
                isQuotedString = true;
                ++pos;
            }

            while (pos < str.Length)
            {
                char c = str[pos];

                if (isQuotedString)
                {
                    if (isEscaped)
                    {
                        // we're in an escape. Is it valid?
                        if (s_isEscapeValid(c))
                        {
                            ++bufferLength;                             // counts
                            isEscaped = false;                          // escape ended
                        }
                        else
                        {
                            throw new InvalidStringEscapeException(parserState.Line, parserState.Column, "Invalid escape found in teh string");
                        }
                    }
                    else
                    {
                        if (c == '"')
                        {
                            // end quote - part of us
                            ++pos;
                            break;
                        }
                        else if (c == '\\')
                        {
                            // we're escaping
                            isEscaped = true;
                        }
                        else
                        {
                            // otherwise it's a character
                            ++bufferLength;
                        }
                    }
                }
                else
                {
                    // have we neded the word?
                    if (s_isNotBarewordSafe(c))
                    {
                        // ended - not part of us
                        break;
                    }

                    // otherwise, it's a character
                    ++bufferLength;
                }

                ++pos;
            }

            if (bufferLength == 0 && !isQuotedString)             // cannot have an empty barewords string
            {
                throw new EmptyStringException(parserState.Line, parserState.Column, "Was told to parse an empty string");
            }

            int end = pos;

            // we now know our buffer size and the string has been checked
            string buffer   = "";
            int    writePos = 0;

            pos = 0;
            if (isQuotedString)
            {
                pos = 1;
            }

            while (writePos < bufferLength)
            {
                char c = str[pos];

                if (isQuotedString)
                {
                    if (isEscaped)
                    {
                        char escapedValue = s_valueForEscape(c);
                        buffer += escapedValue;
                        ++writePos;
                        isEscaped = false;
                    }
                    else
                    {
                        if (c == '\\')
                        {
                            // we're escaping
                            isEscaped = true;
                        }
                        else
                        {
                            // otherwise it's a character
                            buffer += c;
                            ++writePos;
                        }
                    }
                }
                else
                {
                    // its a character
                    buffer += c;
                    ++writePos;
                }

                // next character
                ++pos;
            }

            var ret = new PrivateWexprStringValue();

            ret.value    = buffer;
            ret.endIndex = end;

            return(ret);
        }
示例#4
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);
        }