Exemple #1
0
    public void AddOperator(HotloaderValueOperator op)
    {
        //do not allow if constant
        if ((p_Variable.Accessors & HotloaderAccessor.CONST) == HotloaderAccessor.CONST)
        {
            return;
        }

        lock (p_Mutex) {
            Array.Resize(ref p_Operators, p_Operators.Length + 1);
            p_Operators[p_Operators.Length - 1] = op;
        }
    }
Exemple #2
0
    private object safeEvaluate(out HotloaderValueType type)
    {
        type = HotloaderValueType.NONE;

        //let the evaluation callback deal with it?
        if (p_EvaluationCallback != null)
        {
            object ret = p_EvaluationCallback();
            type = getType(ret);
            return(ret);
        }

        //check for valid evaluation
        if (!Valid)
        {
            throw new Exception("Invalid evaluation");
        }

        #region evaluate each operand
        int                  operandLength = p_Operands.Length;
        object[]             operands      = new object[operandLength];
        HotloaderValueType[] types         = new HotloaderValueType[operandLength];
        for (int c = 0; c < operandLength; c++)
        {
            HotloaderValueOperand opand = p_Operands[c];
            HotloaderValueType    t;
            operands[c] = opand.GetValue(out t);
            types[c]    = t;

            //should this type be the return type?
            if ((int)t > (int)type)
            {
                type = t;
            }

            //boolean? if so, we do not
            //allow operators on bools
            if (t == HotloaderValueType.BOOLEAN &&
                operandLength != 1)
            {
                throw new HotloaderParserException(
                          opand.File,
                          opand.Line,
                          opand.Column,
                          "Booleans cannot be operands");
            }
        }
        #endregion

        //empty?
        if (operandLength == 0)
        {
            return(null);
        }

        //boolean?
        if (type == HotloaderValueType.BOOLEAN)
        {
            //not operator?
            bool not = false;
            if (p_Operators.Length != 0)
            {
                if (p_Operators[0] != HotloaderValueOperator.NOT)
                {
                    throw new HotloaderParserException(
                              p_Operands[0].File,
                              p_Operands[0].Line,
                              p_Operands[0].Column,
                              "Invalid boolean expression");
                }
                not = true;
            }

            //return the boolean
            bool value = (bool)operands[0];
            return
                (not ?
                 !value :
                 value);
        }

        //just 1 operand?
        if (operandLength == 1)
        {
            type = types[0];
            return(operands[0]);
        }

        object buffer = toType(operands[0], types[0], type);

        //perform each operator
        int opLength = p_Operators.Length;
        for (int c = 0; c < opLength; c++)
        {
            HotloaderValueOperator op      = p_Operators[c];
            object             operand     = operands[c + 1];
            HotloaderValueType operandType = types[c + 1];

            operand = toType(
                operand,
                operandType,
                type);

            #region just a string concat?
            if (type == HotloaderValueType.STRING)
            {
                //must be add
                if (op != HotloaderValueOperator.ADD)
                {
                    throw new HotloaderParserException(
                              p_Operands[c + 1].File,
                              p_Operands[c + 1].Line,
                              p_Operands[c + 1].Column,
                              "Cannot perform operation on a string");
                }

                //add
                buffer = (string)buffer + (string)operand;
                continue;
            }
            #endregion

            #region numeric operand

            #region bitwise
            //bitwise?
            bool isBitwise =
                op == HotloaderValueOperator.AND ||
                op == HotloaderValueOperator.OR ||
                op == HotloaderValueOperator.XOR ||
                op == HotloaderValueOperator.SHIFTL ||
                op == HotloaderValueOperator.SHIFTR;

            //if it's bitwise, convert both sides to an int then convert back once
            //the bitwise has been done
            if (isBitwise)
            {
                long a      = (long)toType(buffer, type, HotloaderValueType.NUMERICAL);
                long b      = (long)toType(operand, type, HotloaderValueType.NUMERICAL);
                long result = 0;
                switch (op)
                {
                case HotloaderValueOperator.AND:
                    result = a & b;
                    break;

                case HotloaderValueOperator.OR:
                    result = a | b;
                    break;

                case HotloaderValueOperator.XOR:
                    result = a ^ b;
                    break;

                case HotloaderValueOperator.SHIFTL:
                    result = a << (sbyte)b;
                    break;

                case HotloaderValueOperator.SHIFTR:
                    result = a >> (sbyte)b;
                    break;
                }
                buffer = toType(result, HotloaderValueType.NUMERICAL, type);
                continue;
            }
            #endregion

            //just convert the operands to a double then do the maths on that.
            double d1  = (double)toType(buffer, type, HotloaderValueType.DECIMAL);
            double d2  = (double)toType(operand, type, HotloaderValueType.DECIMAL);
            double res = 0;
            switch (op)
            {
            case HotloaderValueOperator.ADD:
                res = d1 + d2;
                break;

            case HotloaderValueOperator.SUBTRACT:
                res = d1 - d2;
                break;

            case HotloaderValueOperator.MULTIPLY:
                res = d1 * d2;
                break;

            case HotloaderValueOperator.DIVIDE:
                res = d1 / d2;
                break;

            case HotloaderValueOperator.MODULUS:
                res = d1 % d2;
                break;

            case HotloaderValueOperator.POWER:
                res = Math.Pow(d1, d2);
                break;
            }

            buffer = toType(res, HotloaderValueType.DECIMAL, type);
            #endregion
        }

        return(buffer);
    }
Exemple #3
0
    private void load(HotloaderFile file, byte *data, int length)
    {
        byte *ptr    = data;
        byte *ptrEnd = data + length;

        byte *blockStart = ptr;
        byte *blockEnd   = ptr;

        bool negativeFlag = false;

        //keep track of what classes/variables are being added.
        List <HotloaderVariable> fileVariables = new List <HotloaderVariable>();
        List <HotloaderFile>     fileIncludes  = new List <HotloaderFile>();

        //
        HotloaderClass      currentClass      = p_GlobalClass;
        HotloaderVariable   currentVariable   = null;
        HotloaderExpression currentExpression = null;

        //define what mode we are in (what type of block
        //we are reading).
        parserMode mode = parserMode.NONE;

        //
        HotloaderAccessor currentAccessor = HotloaderAccessor.NONE;

        //where we are in a more usable way.
        int currentLine   = 1;
        int currentColumn = 0;

        while (ptr != ptrEnd)
        {
            byte current = *(ptr++);
            currentColumn++;

            //are we at the end of the file?
            bool atEnd = ptr == ptrEnd;

            #region control characters
            //newline?
            bool newLine =
                current == '\n' ||
                current == '\r';
            if (newLine)
            {
                if (current == '\n')
                {
                    currentColumn = 0;
                    currentLine++;
                }
            }

            //whitespace
            bool whitespace =
                newLine ||
                current == ' ' ||
                current == '\t';

            //alpha numeric?
            //(only make the call if
            //we know the character is not a whitespace.
            bool nameChar =
                !whitespace &&
                isNameCharacter(current);
            #endregion

            #region byte block evaluation
            bool evaluateBlock = atEnd || whitespace || !nameChar;

            if (evaluateBlock)
            {
                //if we are at the end, make sure
                //we include the last character
                //in the block.
                if (atEnd && !whitespace && nameChar)
                {
                    blockEnd++;
                }

                //is the block blank?
                bool isBlank     = blockStart == blockEnd;
                int  blockLength = (int)(blockEnd - blockStart);

                //read the block as a string
                if (!isBlank)
                {
                    handleBlock(
                        fileVariables,
                        file,
                        blockStart,
                        blockEnd,
                        currentLine,
                        currentColumn - blockLength + 1,
                        ref negativeFlag,
                        ref mode,
                        ref currentAccessor,
                        ref currentVariable,
                        ref currentExpression,
                        ref currentClass);

                    //block been changed outside pointer?
                    if (blockStart > ptr)
                    {
                        ptr = blockStart;
                    }
                }

                //reset
                blockStart = blockEnd = ptr;

                //do not process anything else if it is a whitespace
                if (whitespace)
                {
                    continue;
                }
            }
            #endregion

            #region comment
            if (current == '#')
            {
                //skip over line
                while (ptr != ptrEnd && *(ptr++) != '\n')
                {
                }

                //we hit newline?
                if (*(ptr - 1) == '\n')
                {
                    ptr--;
                }
                blockStart = blockEnd = ptr;
                continue;
            }
            #endregion

            #region string literal
            if (current == '"')
            {
                //valid?
                if (mode != parserMode.ASSIGNMENT &&
                    mode != parserMode.INCLUDE)
                {
                    throw new HotloaderParserException(
                              file,
                              currentLine,
                              currentColumn,
                              "Unexpected string literal");
                }

                byte *literalStart = ptr;
                if (!readStringLiteral(ref ptr, ptrEnd))
                {
                    throw new HotloaderParserException(
                              file,
                              currentLine,
                              currentColumn,
                              "String literal did not terminate");
                }

                //deturmine where the string ends
                byte *literalEnd = ptr - 1;

                //read the string and remove
                //string terminating characters
                string read = readString(literalStart, literalEnd);
                read = read.Replace("\\", "");

                //include?
                if (mode == parserMode.INCLUDE)
                {
                    mode = parserMode.NONE;
                    if (!File.Exists(read))
                    {
                        throw new HotloaderParserException(
                                  file,
                                  currentLine,
                                  currentColumn,
                                  String.Format(
                                      "Cannot include file \"{0}\". Does not exist.",
                                      read));
                    }

                    //does the file exist?
                    HotloaderFile include = GetFile(read);
                    if (include == null)
                    {
                        include = AddFile(read);
                        fileIncludes.Add(include);
                    }
                    else if (file.Includes.Contains(include))
                    {
                        fileIncludes.Add(include);
                    }
                }
                else
                {
                    //add operand
                    currentExpression.AddOperand(
                        read,
                        HotloaderValueType.STRING,
                        currentLine,
                        currentColumn,
                        file);
                }

                //update line position
                currentColumn += (int)(literalEnd - literalStart) + 1;

                blockStart = blockEnd = ptr;
                continue;
            }
            #endregion

            #region expression scopes

            if (current == '(' || current == ')')
            {
                //valid?
                if (mode != parserMode.ASSIGNMENT)
                {
                    throw new HotloaderParserException(
                              file,
                              currentLine,
                              currentColumn,
                              "Unexpected expression character");
                }

                //close?
                if (current == ')')
                {
                    //can we close?
                    if (currentExpression.Parent == null)
                    {
                        throw new HotloaderParserException(
                                  file,
                                  currentLine,
                                  currentColumn,
                                  "Unexpected end of expression scope");
                    }

                    //add the expression as an operand
                    HotloaderExpression   parent     = currentExpression.Parent;
                    HotloaderExpression   expression = currentExpression;
                    HotloaderValueOperand op         = parent.AddOperand(
                        expression,
                        HotloaderValueType.EVALUATION,
                        currentLine,
                        currentColumn,
                        file);

                    //close
                    currentExpression = currentExpression.Parent;
                }

                //open?
                if (current == '(')
                {
                    HotloaderExpression newExpression = new HotloaderExpression(this, currentVariable);
                    newExpression.Parent = currentExpression;
                    currentExpression    = newExpression;
                }

                //
                blockStart = blockEnd = ptr;
                continue;
            }

            #endregion

            #region operators
            #region class
            if (current == ':')
            {
                //valid?
                if (mode != parserMode.NONE)
                {
                    throw new HotloaderParserException(
                              file,
                              currentLine,
                              currentColumn,
                              "Unexpected class symbol");
                }

                mode       = parserMode.CLASS;
                blockStart = blockEnd = ptr;
                continue;
            }
            #endregion

            #region assignment
            if (current == '=')
            {
                //valid?
                if (mode != parserMode.VARIABLE)
                {
                    throw new HotloaderParserException(
                              file,
                              currentLine,
                              currentColumn,
                              "Unexpected assignment operator");
                }
                mode       = parserMode.ASSIGNMENT;
                blockStart = blockEnd = ptr;
                continue;
            }
            #endregion

            #region end assignment
            if (current == ';')
            {
                //valid?
                if (mode != parserMode.ASSIGNMENT ||
                    !currentExpression.Valid ||
                    currentExpression.Parent != null ||
                    currentExpression.Empty)
                {
                    throw new HotloaderParserException(
                              file,
                              currentLine,
                              currentColumn,
                              "Unexpected end-of-expression character");
                }

                mode       = parserMode.NONE;
                blockStart = blockEnd = ptr;

                //poll the expression to mark the end of
                //an assignment so it can do necassary
                //functions (e.g invoke assignment callback)
                currentExpression.Poll();

                currentExpression = null;
                currentVariable   = null;
                continue;
            }
            #endregion

            #region value operators
            HotloaderValueOperator valueOp = HotloaderValueOperator.NONE;
            switch ((char)current)
            {
            case '+': valueOp = HotloaderValueOperator.ADD; break;

            case '-': valueOp = HotloaderValueOperator.SUBTRACT; break;

            case '*': valueOp = HotloaderValueOperator.MULTIPLY; break;

            case '/': valueOp = HotloaderValueOperator.DIVIDE; break;

            case '^': valueOp = HotloaderValueOperator.POWER; break;

            case '%': valueOp = HotloaderValueOperator.MODULUS; break;

            case '&': valueOp = HotloaderValueOperator.AND; break;

            case '|': valueOp = HotloaderValueOperator.OR; break;

            case '?': valueOp = HotloaderValueOperator.XOR; break;

            case '<': valueOp = HotloaderValueOperator.SHIFTL; break;

            case '>': valueOp = HotloaderValueOperator.SHIFTR; break;

            case '!': valueOp = HotloaderValueOperator.NOT; break;
            }

            //are we expecting a math operation?
            if (valueOp != HotloaderValueOperator.NONE &&
                mode != parserMode.ASSIGNMENT)
            {
                throw new HotloaderParserException(
                          file,
                          currentLine,
                          currentColumn,
                          String.Format(
                              "Unexpected operator {0}",
                              (char)current));
            }

            //wait, was this negative?
            bool addOp = true;
            if (valueOp == HotloaderValueOperator.SUBTRACT)
            {
                //make sure there would be an operand before
                //the subtract. Otherwise we assume it's a
                //negative integer/decimal.
                negativeFlag =
                    currentExpression.Operands ==
                    currentExpression.Operators;
                //addOp = false;
            }

            if (valueOp != HotloaderValueOperator.NONE)
            {
                //if we have discovered a negate operator
                //do not add this as a maths operator!
                if (addOp)
                {
                    currentExpression.AddOperator(valueOp);
                }

                blockStart = blockEnd = ptr;
                continue;
            }
            #endregion
            #endregion

            //invalid character?
            if (!nameChar)
            {
                throw new HotloaderParserException(
                          file,
                          currentLine,
                          currentColumn,
                          String.Format(
                              "Invalid character {0}",
                              (char)current));
            }

            //incriment block end to include this
            //byte so later we can evaluate blocks
            //of the file.
            blockEnd++;
        }

        //not ended correctly?
        if (currentClass.Parent != null)
        {
            throw new HotloaderParserException(
                      file,
                      -1,
                      -1,
                      "Class not terminated");
        }

        //find all includes that have been removed from the file and remove them
        if (file == null)
        {
            return;
        }
        List <HotloaderFile> oldIncludes = file.Includes;
        foreach (HotloaderFile f in oldIncludes)
        {
            if (!fileIncludes.Contains(f))
            {
                RemoveFile(f);
            }
        }

        //find all variables that have been removed from the file and remove them
        List <HotloaderVariable> oldFiles = file.Variables;
        foreach (HotloaderVariable v in oldFiles)
        {
            if (!fileVariables.Contains(v))
            {
                v.Remove();
            }
        }

        file.setVariables(fileVariables);
        file.setIncludes(fileIncludes);
    }