Esempio n. 1
0
        /// <summary>
        /// Try to parse arguments for the expected function. Returns null if not a match. Throws if it's
        /// a match, but invalid.
        /// </summary>
        /// <param name="module"></param>
        /// <param name="parsedParams"></param>
        /// <param name="identifier"></param>
        /// <param name="numArguments">Required number of arguments.</param>
        /// <param name="exactNumberOfArguments">If true, numArguments must be exact value. If false, numArguments is a minimum.</param>
        /// <returns></returns>
        private static double[] TryParseArguments(
            PartModule module,
            ParsedParameters parsedParams,
            int numArguments,
            bool exactNumberOfArguments,
            params string[] identifiers)
        {
            if (identifiers.IndexOf(parsedParams.Identifier) < 0)
            {
                // not a match!
                return(null);
            }

            if (exactNumberOfArguments)
            {
                if (parsedParams.Count != numArguments)
                {
                    throw new ArgumentException("Wrong number of arguments for '" + parsedParams.Identifier
                                                + "' (was " + parsedParams.Count + ", must be " + numArguments + ")");
                }
            }
            else
            {
                if (parsedParams.Count < numArguments)
                {
                    throw new ArgumentException("Wrong number of arguments for '" + parsedParams.Identifier
                                                + "' (was " + parsedParams.Count + ", must be at least " + numArguments + ")");
                }
            }

            double[] args = new double[parsedParams.Count];
            for (int i = 0; i < parsedParams.Count; ++i)
            {
                args[i] = Parse(module, parsedParams[i]);
            }
            return(args);
        }
Esempio n. 2
0
            public static IScalar TryParse(PartModule module, ParsedParameters parsedParams)
            {
                if (parsedParams == null)
                {
                    return(null);
                }
                switch (parsedParams.Identifier)
                {
                case RANGE:
                {
                    parsedParams.RequireCount(module, 3);
                    IScalar input   = Scalars.Require(module, parsedParams[0]);
                    double  minimum = Statics.Parse(module, parsedParams[1]);
                    double  maximum = Statics.Parse(module, parsedParams[2]);
                    return(Between(input, minimum, maximum));
                }

                case GREATER_THAN:
                {
                    parsedParams.RequireCount(module, 2);
                    IScalar input   = Scalars.Require(module, parsedParams[0]);
                    double  minimum = Statics.Parse(module, parsedParams[1]);
                    return(AtLeast(input, minimum));
                }

                case LESS_THAN:
                {
                    parsedParams.RequireCount(module, 2);
                    IScalar input   = Scalars.Require(module, parsedParams[0]);
                    double  maximum = Statics.Parse(module, parsedParams[1]);
                    return(AtMost(input, maximum));
                }

                default:
                    return(null);
                }
            }
Esempio n. 3
0
            /// <summary>
            /// Try to get a "vessel control level" matcher from a ParsedParameters. The expected format is:
            ///
            /// controlLevel(level1, level2, ...)
            ///
            /// Must have at least one level. The allowed control level values are the enum constants
            /// in Vessel.ControlLevel.
            /// </summary>
            /// <param name="module"></param>
            /// <param name="parsedParams"></param>
            /// <returns></returns>
            public static IToggle TryParse(PartModule module, ParsedParameters parsedParams)
            {
                if (parsedParams == null)
                {
                    return(null);
                }
                if (!TYPE_NAME.Equals(parsedParams.Identifier))
                {
                    return(null);
                }
                parsedParams.RequireCount(module, 1, -1);
                HashSet <Vessel.ControlLevel> requiredLevels = new HashSet <Vessel.ControlLevel>();

                for (int i = 0; i < parsedParams.Count; ++i)
                {
                    Vessel.ControlLevel additionalControlLevel = ParseLevel(module, parsedParams[i]);
                    if (!requiredLevels.Add(additionalControlLevel))
                    {
                        throw new ArgumentException("Duplicate specification of '" + parsedParams[i] + "' for " + TYPE_NAME
                                                    + "() on " + module.ClassName + " of " + module.part.GetTitle());
                    }
                }
                return(new VesselControlLevelMatch(module, requiredLevels));
            }
Esempio n. 4
0
        /// <summary>
        /// Parse an IToggle from the specified text. Throws ArgumentException if there's a problem.
        /// </summary>
        /// <param name="module"></param>
        /// <param name="text"></param>
        /// <returns></returns>
        public static IToggle Require(PartModule module, string text)
        {
            if (string.IsNullOrEmpty(text))
            {
                throw new ArgumentException("must supply a value");
            }
            text = text.Trim();

            // Check for constants.
            if (text == "true")
            {
                return(Constant.TRUE);
            }
            if (text == "false")
            {
                return(Constant.FALSE);
            }

            // Perhaps it's an inverted toggle?
            if (text.StartsWith(NOT_OPERATOR))
            {
                return(Inverter.of(Require(module, text.Substring(NOT_OPERATOR.Length))));
            }

            // Maybe it's an identifier for a toggle.
            IToggle found = Identifiers.FindFirst <IToggle>(module.part, text);

            if (found != null)
            {
                return(found);
            }

            // Could it be a named-field reference?
            Identifiers.IFieldEvaluator field = Identifiers.FindKSPField(module.part, text);
            if (field != null)
            {
                if (!typeof(bool).IsAssignableFrom(field.FieldType))
                {
                    throw new ArgumentException("Can't use " + text + " as a boolean field (it's of type " + field.FieldType.Name + ")");
                }
                return(new NamedField(field));
            }

            // Perhaps it's a parameterized expression?
            ParsedParameters parsedParams = ParsedParameters.TryParse(text);

            if (parsedParams != null)
            {
                for (int i = 0; i < PARSEABLE_TOGGLES.Length; ++i)
                {
                    IToggle parsed = PARSEABLE_TOGGLES[i](module, parsedParams);
                    if (parsed != null)
                    {
                        return(parsed);
                    }
                }
            }

            // Nope, not parseable.
            throw new ArgumentException("Invalid toggle syntax \"" + text + "\"");
        }
Esempio n. 5
0
 /// <summary>
 /// Parse a static expression thus:
 ///
 /// sqrt(arg)
 /// </summary>
 /// <param name="module"></param>
 /// <param name="parameters"></param>
 /// <returns></returns>
 private static double TryParseSquareRoot(PartModule module, ParsedParameters parameters)
 {
     double[] args = TryParseArguments(module, parameters, 1, true, "sqrt");
     return((args == null) ? double.NaN : Math.Sqrt(args[0]));
 }
Esempio n. 6
0
            /// <summary>
            /// Try to get a random color source from a ParsedParameters. The expected format is:
            ///
            /// random(onSource, offSource, periodMillis, bias, seed)
            /// random(onSource, offSource, periodMillis, bias)
            /// random(onSource, offSource, periodMillis)
            /// </summary>
            public static IColorSource TryParse(PartModule module, ParsedParameters parsedParams)
            {
                if (parsedParams == null)
                {
                    return(null);
                }
                if (!TYPE_NAME.Equals(parsedParams.Identifier))
                {
                    return(null);
                }
                parsedParams.RequireCount(module, 3, 5);

                IColorSource onSource;

                try
                {
                    onSource = FindPrivate(module, parsedParams[0]);
                }
                catch (ColorSourceException e)
                {
                    throw new ColorSourceException(module, TYPE_NAME + "() source has invalid 'on' parameter", e);
                }


                IColorSource offSource;

                try
                {
                    offSource = FindPrivate(module, parsedParams[1]);
                }
                catch (ColorSourceException e)
                {
                    throw new ColorSourceException(module, TYPE_NAME + "() source has invalid 'off' parameter", e);
                }

                long periodMillis;

                try
                {
                    periodMillis = (long)Statics.Parse(module, parsedParams[2]);
                }
                catch (ArgumentException e)
                {
                    throw new ColorSourceException(module, TYPE_NAME + "(): Invalid 'period' milliseconds value '" + parsedParams[2] + "': " + e.Message, e);
                }
                if (periodMillis < 1)
                {
                    throw new ColorSourceException(module, TYPE_NAME + "(): 'period' milliseconds must be positive");
                }

                double bias = 0;

                if (parsedParams.Count > 3)
                {
                    try
                    {
                        bias = Statics.Parse(module, parsedParams[3]);
                    }
                    catch (ArgumentException e)
                    {
                        throw new ColorSourceException(module, TYPE_NAME + "(): Invalid bias value '" + parsedParams[3] + "': " + e.Message, e);
                    }
                    if ((bias < -1) || (bias > 1))
                    {
                        throw new ColorSourceException(module, TYPE_NAME + "(): Invalid bias value '" + parsedParams[3] + "' (must be between -1 and 1)");
                    }
                }

                int seed = 0;

                if (parsedParams.Count > 4)
                {
                    try
                    {
                        seed = (int)Statics.Parse(module, parsedParams[4]);
                    }
                    catch (ArgumentException e)
                    {
                        throw new ColorSourceException(module, TYPE_NAME + "(): Invalid seed value '" + parsedParams[4] + "': " + e.Message, e);
                    }
                }
                if (module.vessel != null)
                {
                    seed ^= module.vessel.id.GetHashCode();
                }
                if (module.part != null)
                {
                    seed ^= module.part.flightID.GetHashCode();
                    seed ^= IndexOf(module).GetHashCode();
                }

                return(new RandomColorSource(onSource, offSource, periodMillis, bias, seed));
            }
Esempio n. 7
0
            /// <summary>
            /// Try to get a pulsate color source from a ParsedParameters. The expected format is:
            ///
            /// pulsate(origin, cycleMillis, multiplier)
            /// pulsate(origin, cycleMillis, multiplier1, multiplier2)
            /// pulsate(origin, cycleMillis, multiplier1, multiplier2, phase)
            ///
            /// ...where multiplier is a float in the range 0 - 1.
            /// </summary>
            public static IColorSource TryParse(PartModule module, ParsedParameters parsedParams)
            {
                if (parsedParams == null)
                {
                    return(null);
                }
                if (!TYPE_NAME.Equals(parsedParams.Identifier))
                {
                    return(null);
                }
                parsedParams.RequireCount(module, 3, 5);

                IColorSource origin;

                try
                {
                    origin = FindPrivate(module, parsedParams[0]);
                }
                catch (ColorSourceException e)
                {
                    throw new ColorSourceException(module, TYPE_NAME + "() source has invalid origin", e);
                }

                long cycleMillis;

                try
                {
                    cycleMillis = (long)Statics.Parse(module, parsedParams[1]);
                }
                catch (ArgumentException e)
                {
                    throw new ColorSourceException(module, TYPE_NAME + "(): Invalid cycle milliseconds value '" + parsedParams[1] + "': " + e.Message, e);
                }
                if (cycleMillis < 1)
                {
                    throw new ColorSourceException(module, TYPE_NAME + "(): cycle milliseconds must be positive");
                }

                float multiplier1;

                try
                {
                    multiplier1 = (float)Statics.Parse(module, parsedParams[2]);
                }
                catch (ArgumentException e)
                {
                    throw new ColorSourceException(module, TYPE_NAME + "(): Invalid multiplier value '" + parsedParams[2] + "': " + e.Message, e);
                }
                if ((multiplier1 < 0) || (multiplier1 > 1))
                {
                    throw new ColorSourceException(module, TYPE_NAME + "(): Invalid multiplier value '" + parsedParams[2] + "' (must be in range 0 - 1)");
                }

                float multiplier2 = 1f;

                if (parsedParams.Count > 3)
                {
                    try
                    {
                        multiplier2 = (float)Statics.Parse(module, parsedParams[3]);
                    }
                    catch (ArgumentException e)
                    {
                        throw new ColorSourceException(module, TYPE_NAME + "(): Invalid multiplier value '" + parsedParams[3] + "': " + e.Message, e);
                    }
                    if ((multiplier2 < 0) || (multiplier2 > 1))
                    {
                        throw new ColorSourceException(module, TYPE_NAME + "(): Invalid multiplier value '" + parsedParams[3] + "' (must be in range 0 - 1)");
                    }
                }

                float phase = 0;

                if (parsedParams.Count > 4)
                {
                    try
                    {
                        phase = (float)Statics.Parse(module, parsedParams[4]);
                    }
                    catch (ArgumentException e)
                    {
                        throw new ColorSourceException(module, TYPE_NAME + "(): Invalid phase value '" + parsedParams[4] + "': " + e.Message, e);
                    }
                }

                if ((multiplier1 >= 1) && (multiplier2 >= 1))
                {
                    return(origin);
                }
                if ((multiplier1 <= 0) && (multiplier2 <= 0))
                {
                    return(BLACK);
                }

                return(new PulsateColorSource(origin, cycleMillis, multiplier1, multiplier2, phase));
            }
Esempio n. 8
0
            /// <summary>
            /// Try to get a blink color source from a ParsedParameters. The expected format is:
            ///
            /// blink(onSource, onMillis, offSource, offMillis)
            /// blink(onSource, onMillis, offSource, offMillis, phase)
            /// </summary>
            public static IColorSource TryParse(PartModule module, ParsedParameters parsedParams)
            {
                if (parsedParams == null)
                {
                    return(null);
                }
                if (!TYPE_NAME.Equals(parsedParams.Identifier))
                {
                    return(null);
                }
                parsedParams.RequireCount(module, 4, 5);

                IColorSource onSource;

                try
                {
                    onSource = FindPrivate(module, parsedParams[0]);
                }
                catch (ColorSourceException e)
                {
                    throw new ColorSourceException(module, TYPE_NAME + "() source has invalid 'on' parameter", e);
                }


                long onMillis;

                try
                {
                    onMillis = (long)Statics.Parse(module, parsedParams[1]);
                }
                catch (ArgumentException e)
                {
                    throw new ColorSourceException(module, TYPE_NAME + "(): Invalid 'on' milliseconds value '" + parsedParams[1] + "': " + e.Message, e);
                }
                if (onMillis < 1)
                {
                    throw new ColorSourceException(module, TYPE_NAME + "(): 'on' milliseconds must be positive");
                }

                IColorSource offSource;

                try
                {
                    offSource = FindPrivate(module, parsedParams[2]);
                }
                catch (ColorSourceException e)
                {
                    throw new ColorSourceException(module, TYPE_NAME + "() source has invalid 'off' parameter", e);
                }

                long offMillis;

                try
                {
                    offMillis = (long)Statics.Parse(module, parsedParams[3]);
                }
                catch (ArgumentException e)
                {
                    throw new ColorSourceException(module, TYPE_NAME + "(): Invalid 'off' milliseconds value '" + parsedParams[3] + "': " + e.Message, e);
                }
                if (offMillis < 1)
                {
                    throw new ColorSourceException(module, TYPE_NAME + "(): 'off' milliseconds must be positive");
                }

                float phase = 0F;

                if (parsedParams.Count > 4)
                {
                    try
                    {
                        phase = (float)Statics.Parse(module, parsedParams[4]);
                    }
                    catch (ArgumentException e)
                    {
                        throw new ColorSourceException(module, TYPE_NAME + "(): Invalid phase value '" + parsedParams[4] + "': " + e.Message, e);
                    }
                }

                return(new BlinkColorSource(onSource, onMillis, offSource, offMillis, phase));
            }
Esempio n. 9
0
        /// <summary>
        /// Given a color source ID (which might be a literal color, the ID of a controller,
        /// or a parameterized source), try to find the appropriate source. If it can't
        /// be parsed or found, throws a ColorSourceException.
        private static IColorSource FindPrivate(PartModule module, string sourceID)
        {
            if (string.IsNullOrEmpty(sourceID))
            {
                throw new ColorSourceException(module, "Null or empty color source");
            }

            // Maybe it's a color string.
            if (Colors.IsColorString(sourceID))
            {
                return(Constant(Colors.Parse(sourceID, Color.black)));
            }

            // Is it a parameterized source?
            ParsedParameters parsedParams = ParsedParameters.TryParse(sourceID);

            if (parsedParams != null)
            {
                // It has the right syntax for a parameterizeed source. Do we recognize it?
                for (int i = 0; i < PARSEABLE_SOURCES.Length; ++i)
                {
                    IColorSource candidate = PARSEABLE_SOURCES[i](module, parsedParams);
                    if (candidate != null)
                    {
                        return(candidate);
                    }
                }
                throw new ColorSourceException(module, "Unknown function type '" + parsedParams.Identifier + "'");
            }

            // Maybe it's another field on the module?
            for (int i = 0; i < module.Fields.Count; ++i)
            {
                BaseField field = module.Fields[i];
                if (!sourceID.Equals(field.name))
                {
                    continue;
                }
                if (!ColorSourceIDField.Is(field))
                {
                    throw new ColorSourceException(
                              module, sourceID + " field on " + module.ClassName + " of "
                              + module.part.GetTitle() + " is not a color source ID field");
                }
                return(Find(module, field.GetValue <string>(module)));
            }

            // Maybe it's a module on the part?
            for (int i = 0; i < module.part.Modules.Count; ++i)
            {
                IColorSource candidate = module.part.Modules[i] as IColorSource;
                if (candidate == null)
                {
                    continue;
                }
                if (sourceID.Equals(candidate.ColorSourceID))
                {
                    return(candidate);
                }
            }

            // not found
            throw new ColorSourceException(module, "Can't find a color source named '" + sourceID + "'");
        }
Esempio n. 10
0
        /// <summary>
        /// Parse an IScalar from the specified text. Throws ArgumentException if there's a problem.
        /// </summary>
        /// <param name="module"></param>
        /// <param name="text"></param>
        /// <returns></returns>
        public static IScalar Require(PartModule module, string text)
        {
            if (string.IsNullOrEmpty(text))
            {
                throw new ArgumentException("must supply a value");
            }
            text = text.Trim();

            // Perhaps it's an inverted scalar?
            if (text.StartsWith(INVERT_OPERATOR))
            {
                return(LinearTransform.Invert(Require(module, text.Substring(INVERT_OPERATOR.Length))));
            }

            // Maybe it's an identifier for a scalar.
            IScalar found = Identifiers.FindFirst <IScalar>(module.part, text);

            if (found != null)
            {
                return(found);
            }

            // Could it be a named-field reference?
            Identifiers.IFieldEvaluator field = Identifiers.FindKSPField(module.part, text);
            if (field != null)
            {
                if (NamedSingleField.Is(field))
                {
                    return(new NamedSingleField(field));
                }
                if (NamedDoubleField.Is(field))
                {
                    return(new NamedDoubleField(field));
                }
                if (NamedIntegerField.Is(field))
                {
                    return(new NamedIntegerField(field));
                }
                if (NamedShortField.Is(field))
                {
                    return(new NamedShortField(field));
                }
                if (NamedLongField.Is(field))
                {
                    return(new NamedLongField(field));
                }

                throw new ArgumentException("Can't use " + text + " as a scalar field (it's of type " + field.FieldType.Name + ")");
            }

            // Perhaps it's a parameterized expression?
            ParsedParameters parsedParams = ParsedParameters.TryParse(text);

            if (parsedParams != null)
            {
                for (int i = 0; i < PARSEABLE_SCALARS.Length; ++i)
                {
                    IScalar parsed = PARSEABLE_SCALARS[i](module, parsedParams);
                    if (parsed != null)
                    {
                        return(parsed);
                    }
                }
            }

            // Last chance:  it could be a static value.
            return(Constant.Of(Statics.Parse(module, text)));
        }