using Island.StandardLib; using Island.StandardLib.Math; using System; namespace EXTS { public abstract class ETypeInstance { public bool AllDefined(EValue[] args) { for (int i = 0; i < args.Length; i++) if (!args[i].Defined) return false; return true; } public bool AllTypeEqual(EValue[] args) where T : ETypeInstance { for (int i = 0; i < args.Length; i++) if (!(args[i]?.Instance is T)) return false; return true; } public void ParameterTypeError(string className, string methodName, string expectClassName) => throw new RuntimeException($"{className}:{methodName} Request {expectClassName} parameters."); public void MethodNotFound(string className, string methodName) => throw new RuntimeException($"class {className} has no public method named {methodName}."); public void UseUndefinedValue() => throw new RuntimeException("Use undefined variable as parameters."); public void UsageError(string className, string methodName) => throw new RuntimeException($"{className}:{methodName} Error method usage (parameters error)."); public abstract EValue PassCall(string callFuncName, EValue[] args); } public class ENumber : ETypeInstance { public float Value; public ENumber(float val) => Value = val; public override EValue PassCall(string callFuncName, EValue[] args) { EValue result = new EValue(); switch (callFuncName) { case "add": { if (!AllDefined(args)) UseUndefinedValue(); if (!AllTypeEqual(args)) ParameterTypeError("Number", callFuncName, "Number"); float val = Value; args.Do((it) => val += ((ENumber)it.Instance).Value); result = new EValue(new ENumber(val)); } break; case "sub": { if (!AllDefined(args)) UseUndefinedValue(); if (!AllTypeEqual(args)) ParameterTypeError("Number", callFuncName, "Number"); float val = Value; args.Do((it) => val -= ((ENumber)it.Instance).Value); result = new EValue(new ENumber(val)); } break; case "mul": { if (!AllDefined(args)) UseUndefinedValue(); if (!AllTypeEqual(args)) ParameterTypeError("Number", callFuncName, "Number"); float val = Value; args.Do((it) => val *= ((ENumber)it.Instance).Value); result = new EValue(new ENumber(val)); } break; case "div": { if (!AllDefined(args)) UseUndefinedValue(); if (!AllTypeEqual(args)) ParameterTypeError("Number", callFuncName, "Number"); float val = Value; args.Do((it) => val /= ((ENumber)it.Instance).Value); result = new EValue(new ENumber(val)); } break; case "pow": { if (!AllDefined(args)) UseUndefinedValue(); if (!AllTypeEqual(args)) ParameterTypeError("Number", callFuncName, "Number"); float val = Value; args.Do((it) => val = (float)Math.Pow(val, ((ENumber)it.Instance).Value)); result = new EValue(new ENumber(val)); } break; case "str": return new EValue(new EString(Value.ToString())); default: MethodNotFound("Number", callFuncName); break; } return result; } } public class EVec3 : ETypeInstance { public Vector3 Value; public EVec3(Vector3 val) => Value = val; public override EValue PassCall(string callFuncName, EValue[] args) { EValue result = new EValue(); switch (callFuncName) { case "add": { if (!AllDefined(args)) UseUndefinedValue(); if (!AllTypeEqual(args)) ParameterTypeError("Vec3", callFuncName, "Vec3"); Vector3 val = Value; args.Do((it) => val += ((EVec3)it.Instance).Value); result = new EValue(new EVec3(val)); } break; case "sub": { if (!AllDefined(args)) UseUndefinedValue(); if (!AllTypeEqual(args)) ParameterTypeError("Vec3", callFuncName, "Vec3"); Vector3 val = Value; args.Do((it) => val -= ((EVec3)it.Instance).Value); result = new EValue(new EVec3(val)); } break; case "x": result = new EValue(new ENumber(Value.x)); break; case "y": result = new EValue(new ENumber(Value.y)); break; case "z": result = new EValue(new ENumber(Value.z)); break; case "dot": { if (!AllDefined(args)) UseUndefinedValue(); if (!AllTypeEqual(args)) ParameterTypeError("Vec3", callFuncName, "Number"); float val = 1; args.Do((it) => val *= it.As().Value); result = new EValue(new EVec3(val * Value)); } break; case "distance": { if (!AllDefined(args)) UseUndefinedValue(); if (!AllTypeEqual(args)) ParameterTypeError("Vec3", callFuncName, "Vec3"); if (args.Length != 1) UsageError("Vec3", callFuncName); result = new EValue(new ENumber(args[0].As().Value.DistanceOf(Value))); } break; case "str": return new EValue(new EString(Value.ToString())); default: MethodNotFound("Vec3", callFuncName); break; } return result; } } public class EString : ETypeInstance { public string Value; public EString(string val) => Value = val; public override EValue PassCall(string callFuncName, EValue[] args) { EValue result = new EValue(); switch (callFuncName) { case "add": { if (!AllDefined(args)) UseUndefinedValue(); if (!AllTypeEqual(args)) ParameterTypeError("String", callFuncName, "String"); string val = Value; args.Do((it) => val += it.As().Value); result = new EValue(new EString(val)); } break; case "log": { Console.WriteLine(Value); } break; case "str": return new EValue(new EString(Value.ToString())); default: MethodNotFound("String", callFuncName); break; } return result; } } }