コード例 #1
0
        /// <summary>
        /// Adds a TFunction to the function dictionary.
        /// </summary>
        /// <param name="interpreter">The interpreter that the method is being called from.</param>
        /// <param name="function">The TFunction to be added to the function dictionary.</param>
        /// <returns>Null if the operation was successful, otherwise a TException.</returns>
        public static TException AddFunction(Interpreter interpreter, TFunction function)
        {
            if (function == null)
            {
                return(new TException(interpreter, "Null TFunction given"));
            }

            // Reject the function if it's already in the standard library
            TFunction existingFunction = StdLibrary.GetFunction(function.Name);

            if (existingFunction != null)
            {
                return(new TException(interpreter,
                                      "Standard library function with name '" + function.Name + "' already exists"));
            }

            // Add it to the function dictionary, overwriting another function with the same name if neccessary
            existingFunction = GetFunction(function.Name, false);
            if (existingFunction == null)
            {
                functions.Add(function.Name, function);
            }
            else
            {
                existingFunction.HardCodedFunction = null;
                existingFunction.CustomFunction    = "";
                existingFunction.Block             = null;
                existingFunction.CopyFrom(function);
            }

            return(null);
        }
コード例 #2
0
 /// <summary>
 /// Copies the data from another TFunction into this TFunction.
 /// </summary>
 /// <param name="function">The existing TFunction whose data is to be copied into the new TFunction.</param>
 public void CopyFrom(TFunction function)
 {
     Name = function.Name;
     HardCodedFunction = function.HardCodedFunction;
     CustomFunction    = function.CustomFunction;
     Block             = function.Block;
     CopyArguments(function.ArgNames, function.DefaultArgs);
 }
コード例 #3
0
 /// <summary>
 /// A copy constructor or TFunction.
 /// </summary>
 /// <param name="function">The existing TFunction whose data is to be copied into the new TFunction.</param>
 public TFunction(TFunction function)
 {
     CopyFrom(function);
 }
コード例 #4
0
        /// <summary>
        /// Attempts to convert an object into a TType.
        /// </summary>
        /// <param name="interpreter">The interpreter that the method is being called from.</param>
        /// <param name="obj">The object that is to be converted into a TType derivative.</param>
        /// <returns>An object of base class TType. If the operation was unsuccessful, null is returned.</returns>
        public static TType Parse(Interpreter interpreter, object obj)
        {
            if (obj is string)
            {
                string str = ((string)obj).Trim();
                if (str == "")
                {
                    return(TNil.Instance);
                }

                // Attempt to convert to a keyword first
                if ((str == "yes") || (str == "no"))
                {
                    return(new TBoolean(str));
                }
                if (str == "nil")
                {
                    return(TNil.Instance);
                }
                if (str == "break")
                {
                    return(TBreak.Instance);
                }

                {
                    long result;
                    if (long.TryParse(str, out result))
                    {
                        return(new TInteger(result));
                    }
                }
                {
                    double result;
                    if (double.TryParse(str, out result))
                    {
                        return(new TReal(result));
                    }
                }
                {   // If first and last characters of string are '"', then return a TString
                    if ((str.First() == STRING_CHARACTER) && (str.Last() == STRING_CHARACTER))
                    {
                        return(new TString(str.Substring(1, str.Length - 2)));
                    }
                }
                {   // Attempt to find a function or variable with the name
                    TType result = TFunction.GetFunction(str);
                    if (result == null)
                    {
                        result = interpreter.Stack.FindVariable(str);
                        if (result == null)
                        {
                            return(new TException(interpreter,
                                                  "Variable or function with identifier '" + str + "' not found"));
                        }
                    }
                    return(result);
                }
            }
            else if (obj is TType)
            {
                return((TType)obj);
            }
            else if (obj is Interpreter.Group)
            {
                return(interpreter.ParseGroup(obj as Interpreter.Group));
            }

            return(null);
        }
コード例 #5
0
        /// <summary>
        /// Parses an assignment operation.
        /// </summary>
        /// <param name="group">The group to parse.</param>
        /// <returns>The assigned variable or function on success, otherwise a TException.</returns>
        TType ParseAssignmentGroup(Group group)
        {
            /* BNF for assignment:
             *      <assignment>       ::= 'let' ( <variable-assignment> | <function-declaration> )
             *      <var-assignment>   ::= <identifier> '=' <expression>
             *      <func-declaration> ::= <identifier> '(' { <parameters> } ')' '=' <statements>
             *      <parameters>       ::= <identifier> { ',' <identifier> }*
             *      <statements>       ::= <block> | <statement>
             *      <block>            ::= <new-line> (<statement> <new-line>)* 'end'
             * You can probably guess what <identifier>, <statement> and <new-line> are
             * The 'let' is assumed to have already been checked for
             */
            int equalsIndex = group.IndexOf("=");
            if (equalsIndex < 0) return new TException(this, "Variable or function could not be assigned a value");

            // Could be assigning a dereferenced variable
            TException exception = ParseReferencesOfGroup(group, equalsIndex);
            if (exception != null) return exception;

            if (group.Count == 1) return new TException(this, "Could not assign variable", "no variable name given");

            string variableName = group[1] as string;
            TVariable existingVariable = null;

            if (variableName == null)
            {
                exception = new TException(this, "Could not assign variable", "invalid variable name given");

                // Check if an existing variable or function is being assigned
                Group groupToParse = group[1] as Group;
                TType value = group[1] as TType;
                if (groupToParse != null) value = ParseGroup(groupToParse);
                if (value == null) return exception;

                TVariable variable = value as TVariable;
                if (variable != null) existingVariable = variable;
                else
                {
                    TFunction function = value as TFunction;
                    if (function != null) variableName = function.Name;
                    else return exception;
                }
            }

            if (group.Count == 2) return new TException(this, "Variable could not be assigned a value");
            string assignmentOperator = group[2] as string;
            if (assignmentOperator == null) // Now we assume that we're dealing with a function declaration
            {
                Group paramGroup = group[2] as Group;
                if (paramGroup == null) // The user probably just wanted to assign a variable but made a typo
                    return new TException(this, "Variable could not be assigned a value",
                        "value to assign to variable must be given");

                // Get the identifiers of all the parameters within the brackets, keeping strict watch on comma usage
                TParameterList paramList = new TParameterList();
                bool commaExpected = false;
                for (int i = 0; i < paramGroup.Count; ++i)
                {
                    if (commaExpected && (i == paramGroup.Count - 1))
                        return new TException(this, "Parameters could not be parsed", "last parameter missing");

                    string paramName = paramGroup[i] as string;

                    if (commaExpected && (paramName != ",")) paramName = null;

                    if (paramName == null) return new TException(this, "Parameters could not be parsed",
                        "invalid parameter name given");

                    if (!commaExpected) paramList.Add(paramName);
                    commaExpected = !commaExpected;
                }

                exception = new TException(this, "Function could not be given a body", "function body must be given");
                if (group.Count == 3) return exception;
                assignmentOperator = group[3] as string;
                if (assignmentOperator == null) return exception;
                else if (assignmentOperator != "=") return exception;

                TFunction function;
                if (group.Count == 4) // statement is just 'let <i><params> =', so get a block
                {
                    TBlock block = new TBlock(this, out exception, false);
                    if (exception != null) return exception;
                    function = new TFunction(variableName ?? existingVariable.Identifier, block,
                        paramList.ParameterNames, null);
                }
                else // Create a single line function
                {
                    Group funcBody = new Group(null);
                    funcBody.AddRange(group.GetRange(4, group.Count - 4));
                    function = new TFunction(variableName ?? existingVariable.Identifier, funcBody.ToString(),
                        paramList.ParameterNames, null);
                }

                exception = TFunction.AddFunction(this, function);
                if (exception != null) return exception;

                return function;
            }
            { // Assume that we're dealing with a variable assigment
                exception = new TException(this, "Variable could not be assigned a value",
                    "value to assign to variable must be given");

                if (assignmentOperator != "=") return exception;
                if (group.Count == 3) return exception;

                // Parse the expression on the right hand side of the assigment operator, and if the result is a
                // TVariable, then get it's value (we don't want to assign the TVariable itself to the new TVariable)
                Group valueGroup = new Group(null);
                valueGroup.AddRange(group.GetRange(3, group.Count - 3));
                TType value = ParseGroup(valueGroup);
                if (value is TException) return value;

                TVariable variable = value as TVariable;
                if (variable != null) value = variable.Value;

                // Make sure we don't get any circular references; they cause stack overflows when outputting them
                variable = existingVariable ?? Stack.FindVariable(variableName);
                if (value == variable) return new TException(this, "Illegal assignment attempted",
                    "variables cannot reference themselves");

                TVariable circularRefCheckVar = value as TVariable;
                while (circularRefCheckVar != null)
                {
                    TVariable variableValue = circularRefCheckVar.Value as TVariable;
                    if (variableValue != null)
                    {
                        if (variableValue == variable)
                            return new TException(this, "Illegal assignment attempted",
                                "circular reference detected");
                        else circularRefCheckVar = variableValue;
                    }
                    else circularRefCheckVar = null;
                }

                if (variable == null) // If the variable doesn't exist already, add it to the stack variable dictionary
                {
                    variable = new TVariable(variableName, value);
                    Stack.AddVariable(variable);
                }
                else variable.Value = value;

                return variable;
            }
        }
コード例 #6
0
 /// <summary>
 /// A copy constructor or TFunction.
 /// </summary>
 /// <param name="function">The existing TFunction whose data is to be copied into the new TFunction.</param>
 public TFunction(TFunction function)
 {
     CopyFrom(function);
 }
コード例 #7
0
 /// <summary>
 /// Copies the data from another TFunction into this TFunction.
 /// </summary>
 /// <param name="function">The existing TFunction whose data is to be copied into the new TFunction.</param>
 public void CopyFrom(TFunction function)
 {
     Name = function.Name;
     HardCodedFunction = function.HardCodedFunction;
     CustomFunction = function.CustomFunction;
     Block = function.Block;
     CopyArguments(function.ArgNames, function.DefaultArgs);
 }
コード例 #8
0
        /// <summary>
        /// Adds a TFunction to the function dictionary.
        /// </summary>
        /// <param name="interpreter">The interpreter that the method is being called from.</param>
        /// <param name="function">The TFunction to be added to the function dictionary.</param>
        /// <returns>Null if the operation was successful, otherwise a TException.</returns>
        public static TException AddFunction(Interpreter interpreter, TFunction function)
        {
            if (function == null) return new TException(interpreter, "Null TFunction given");

            // Reject the function if it's already in the standard library
            TFunction existingFunction = StdLibrary.GetFunction(function.Name);
            if (existingFunction != null)
                return new TException(interpreter,
                    "Standard library function with name '" + function.Name + "' already exists");

            // Add it to the function dictionary, overwriting another function with the same name if neccessary
            existingFunction = GetFunction(function.Name, false);
            if (existingFunction == null) functions.Add(function.Name, function);
            else
            {
                existingFunction.HardCodedFunction = null;
                existingFunction.CustomFunction = "";
                existingFunction.Block = null;
                existingFunction.CopyFrom(function);
            }

            return null;
        }