diff --git a/src/core/FunctionValue.cs b/src/core/FunctionValue.cs index 418dd29..9e84a9b 100644 --- a/src/core/FunctionValue.cs +++ b/src/core/FunctionValue.cs @@ -12,8 +12,11 @@ namespace csmic public ValueType Type { get; set; } public object? Value { get; set; } - public static readonly FunctionValue TRUE = new FunctionValue(ValueType.Numeric, 1); - public static readonly FunctionValue FALSE = new FunctionValue(ValueType.Numeric, 0); + public static readonly FunctionValue TRUE = new FunctionValue(ValueType.Numeric, 1m); + public static readonly FunctionValue FALSE = new FunctionValue(ValueType.Numeric, 0m); + public static readonly FunctionValue NONE = new FunctionValue(ValueType.None, null); + public static readonly FunctionValue NUMBER = new FunctionValue(ValueType.Numeric, 0m); + public static readonly FunctionValue STRING = new FunctionValue(ValueType.String, string.Empty); public FunctionValue() { diff --git a/src/stdlib/functions/AbsoluteValue.cs b/src/stdlib/functions/AbsoluteValue.cs index 5245182..af1b82b 100644 --- a/src/stdlib/functions/AbsoluteValue.cs +++ b/src/stdlib/functions/AbsoluteValue.cs @@ -5,48 +5,23 @@ namespace stdlib.functions { public class AbsoluteValue : FunctionBase, ICodedFunction { - public IEnumerable ExpectedArguments + public override IEnumerable ExpectedArguments { get { - yield return new FunctionArgument("value", new FunctionValue(ValueType.Numeric, 0m)); + yield return new FunctionArgument("value", FunctionValue.NUMBER); } } - public FunctionValue ReturnValue - { - new FunctionValue(ValueType.Numeric, 0m); - } - => - public FunctionValue Execute(params FunctionArgument[] args) { - base.ArgumentCheck(args); - - try + return base.Execute(args, (_args) => { - var input = args[0].Value; - // Try to interpret both numeric and numeric-like string inputs - decimal number; - if (input.Type == ValueType.Numeric) - { - number = Convert.ToDecimal(input.Value); - } - else if (input.Type == ValueType.String && input.Value is string s) - { - number = Convert.ToDecimal(s); - } - else - { - return new FunctionValue(ValueType.None, null); - } + var input = _args[0].Value; + decimal number = Convert.ToDecimal(input.Value); return new FunctionValue(ValueType.Numeric, Math.Abs(number)); - } - catch - { - return new FunctionValue(ValueType.None, null); - } + }); } } } diff --git a/src/stdlib/functions/FunctionBase.cs b/src/stdlib/functions/FunctionBase.cs index ba8edf2..ee8ec14 100644 --- a/src/stdlib/functions/FunctionBase.cs +++ b/src/stdlib/functions/FunctionBase.cs @@ -7,25 +7,64 @@ namespace stdlib.functions { public virtual IEnumerable ExpectedArguments { get; } - internal bool ArgumentCheck(params FunctionArgument[] args) + public virtual FunctionValue ReturnValue { + get + + { + return FunctionValue.NUMBER; + } + } + + public bool ArgumentCheck(params FunctionArgument[] args) + { + // Top level sanity checks. if (args == null || args.Length != this.ExpectedArguments.Count()) { return false; } + // Check each argument against what is expected. var expectedArgumentsArray = this.ExpectedArguments.ToArray(); for (int i = 0; i < args.Length; i++) { var expectedArgument = expectedArgumentsArray[i]; var argument = args[i]; - if(argument.Value == null || argument.Value.Type != expectedArgument.Value.Type) + if (argument.Value == null || argument.Value.Value == null || argument.Value.Type != expectedArgument.Value.Type) + { + return false; + } + + if (argument.Value.Type == ValueType.Numeric && argument.Value.Value is not decimal) + { + return false; + } + + if (argument.Value.Type == ValueType.String && argument.Value.Value is not string) { return false; } } + // All checks passed. return true; } + + public FunctionValue Execute(FunctionArgument[] args, Func action) + { + if (!ArgumentCheck(args)) + { + return FunctionValue.NONE; + } + + try + { + return action(args); + } + catch + { + return FunctionValue.NONE; + } + } } } diff --git a/src/stdlib/functions/Sign.cs b/src/stdlib/functions/Sign.cs new file mode 100644 index 0000000..1f3bc5c --- /dev/null +++ b/src/stdlib/functions/Sign.cs @@ -0,0 +1,30 @@ +using csmic; +using ValueType = csmic.ValueType; + +namespace stdlib.functions +{ + public class Sign : FunctionBase, ICodedFunction + { + public const decimal POSITIVE = 1; + public const decimal NEGATIVE = -1; + + public override IEnumerable ExpectedArguments + { + get + { + yield return new FunctionArgument("value", FunctionValue.NUMBER); + } + } + + public FunctionValue Execute(params FunctionArgument[] args) + { + return base.Execute(args, (_args) => + { + var input = _args[0].Value; + decimal number = Convert.ToDecimal(input.Value); + + return new FunctionValue(ValueType.Numeric, number >= 0 ? POSITIVE : NEGATIVE); + }); + } + } +}