Reworked script function attribute, added initial math library

This commit is contained in:
Deukhoofd 2018-12-07 16:11:52 +01:00
parent 9bd82174f2
commit ac05647d71
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
15 changed files with 95 additions and 29 deletions

View File

@ -2,9 +2,9 @@ using System;
namespace Upsilon.BaseTypes.Number namespace Upsilon.BaseTypes.Number
{ {
internal abstract class ScriptNumber : ScriptType public abstract class ScriptNumber : ScriptType
{ {
protected abstract bool IsFloat { get; } protected internal abstract bool IsFloat { get; }
public override Type Type => Type.Number; public override Type Type => Type.Number;

View File

@ -5,7 +5,7 @@ namespace Upsilon.BaseTypes.Number
internal class ScriptNumberDouble : ScriptNumber internal class ScriptNumberDouble : ScriptNumber
{ {
public double Value { get; } public double Value { get; }
protected override bool IsFloat { get; } = true; protected internal override bool IsFloat { get; } = true;
public ScriptNumberDouble(double value) public ScriptNumberDouble(double value)
{ {

View File

@ -6,7 +6,7 @@ namespace Upsilon.BaseTypes.Number
internal class ScriptNumberLong : ScriptNumber internal class ScriptNumberLong : ScriptNumber
{ {
public long Value { get; set; } public long Value { get; set; }
protected override bool IsFloat { get; } = false; protected internal override bool IsFloat { get; } = false;
public ScriptNumberLong(long val) public ScriptNumberLong(long val)
{ {

View File

@ -1,6 +1,6 @@
namespace Upsilon.BaseTypes namespace Upsilon.BaseTypes
{ {
internal class ScriptBoolean : ScriptType public class ScriptBoolean : ScriptType
{ {
public ScriptBoolean(bool value) public ScriptBoolean(bool value)
{ {

View File

@ -19,6 +19,15 @@ namespace Upsilon.BaseTypes.ScriptFunction
_passScopeReference = passScopeReference; _passScopeReference = passScopeReference;
ReturnType = _method.ReturnType; ReturnType = _method.ReturnType;
if (method.GetMethods().First().Attribute != null)
{
var attr = method.GetMethods().First().Attribute;
_directTypeManipulation = attr.DirectScriptManipulation;
_passScriptReference = attr.PassScriptReference;
_passScopeReference = attr.PassScopeReference;
}
} }
private readonly UserDataMethod _method; private readonly UserDataMethod _method;

View File

@ -3,7 +3,7 @@ using Upsilon.Text;
namespace Upsilon.BaseTypes.UserData namespace Upsilon.BaseTypes.UserData
{ {
internal class GenericUserData : ScriptType, IUserData internal sealed class GenericUserData : ScriptType, IUserData
{ {
public GenericUserData(object dictionary) public GenericUserData(object dictionary)
{ {
@ -12,7 +12,7 @@ namespace Upsilon.BaseTypes.UserData
} }
public override Type Type => Type.UserData; public override Type Type => Type.UserData;
protected virtual object Value { get; } private object Value { get; }
private readonly UserDataType _typeInfo; private readonly UserDataType _typeInfo;
public override object ToCSharpObject() public override object ToCSharpObject()
@ -25,7 +25,7 @@ namespace Upsilon.BaseTypes.UserData
return Value.GetType(); return Value.GetType();
} }
public virtual ScriptType Get(Diagnostics diagnostics, TextSpan span, ScriptType index, EvaluationScope scope) public ScriptType Get(Diagnostics diagnostics, TextSpan span, ScriptType index, EvaluationScope scope)
{ {
var s = index.ToCSharpObject().ToString(); var s = index.ToCSharpObject().ToString();
var (type, failed, error) = _typeInfo.Get(Value, s); var (type, failed, error) = _typeInfo.Get(Value, s);
@ -36,7 +36,7 @@ namespace Upsilon.BaseTypes.UserData
return type; return type;
} }
public virtual void Set(Diagnostics diagnostics, TextSpan span, ScriptType index, ScriptType value) public void Set(Diagnostics diagnostics, TextSpan span, ScriptType index, ScriptType value)
{ {
var s = index.ToCSharpObject().ToString(); var s = index.ToCSharpObject().ToString();
var (failed, error) = _typeInfo.Set(Value, s, value); var (failed, error) = _typeInfo.Set(Value, s, value);

View File

@ -2,6 +2,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using Upsilon.Evaluator; using Upsilon.Evaluator;
using Upsilon.StandardLibraries;
namespace Upsilon.BaseTypes.UserData namespace Upsilon.BaseTypes.UserData
{ {
@ -13,6 +14,8 @@ namespace Upsilon.BaseTypes.UserData
{ {
Method = method; Method = method;
var pars = method.GetParameters(); var pars = method.GetParameters();
Attribute = (ScriptFunctionAttribute) method.GetCustomAttribute(typeof(ScriptFunctionAttribute));
var ls = new List<UserDataMethodParameter>(); var ls = new List<UserDataMethodParameter>();
foreach (var parameter in pars) foreach (var parameter in pars)
{ {
@ -26,6 +29,7 @@ namespace Upsilon.BaseTypes.UserData
} }
public MethodInfo Method { get; } public MethodInfo Method { get; }
public ScriptFunctionAttribute Attribute { get; }
public UserDataMethodParameter[] Parameters { get; } public UserDataMethodParameter[] Parameters { get; }
} }

View File

@ -2,6 +2,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using Upsilon.BaseTypes.ScriptFunction; using Upsilon.BaseTypes.ScriptFunction;
using Upsilon.StandardLibraries;
namespace Upsilon.BaseTypes.UserData namespace Upsilon.BaseTypes.UserData
{ {
@ -16,6 +17,12 @@ namespace Upsilon.BaseTypes.UserData
foreach (var methodInfo in type.GetMethods()) foreach (var methodInfo in type.GetMethods())
{ {
var commonName = methodInfo.Name.ToLowerInvariant(); var commonName = methodInfo.Name.ToLowerInvariant();
var attribute = methodInfo.GetCustomAttribute(typeof(ScriptFunctionAttribute));
if (attribute is ScriptFunctionAttribute sfa )
{
commonName = sfa.Name.ToLowerInvariant();
}
if (Methods.TryGetValue(commonName, out var methodData)) if (Methods.TryGetValue(commonName, out var methodData))
{ {
methodData.LoadMethodPart(methodInfo); methodData.LoadMethodPart(methodInfo);

View File

@ -1,7 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection;
using Upsilon.BaseTypes; using Upsilon.BaseTypes;
using Upsilon.StandardLibraries;
using Type = Upsilon.BaseTypes.Type; using Type = Upsilon.BaseTypes.Type;
namespace Upsilon.BoundTypes namespace Upsilon.BoundTypes
@ -52,12 +54,25 @@ namespace Upsilon.BoundTypes
{ {
obj.Properties.Add(f.Name.ToLowerInvariant(), f); obj.Properties.Add(f.Name.ToLowerInvariant(), f);
} }
var methods = backingType.GetMethods().Select(x => new UserDataBoundMethod() var methods = new List<UserDataBoundMethod>();
var backingMethods = backingType.GetMethods();
foreach (var backingMethod in backingMethods)
{ {
Name = x.Name, if (backingMethod.IsSpecialName)
Type = Type.Function, continue;
ResultType = x.ReturnType.GetScriptType() var name = backingMethod.Name;
}); var attribute = backingMethod.GetCustomAttribute(typeof(ScriptFunctionAttribute));
if (attribute is ScriptFunctionAttribute sfa )
{
name = sfa.Name;
}
methods.Add(new UserDataBoundMethod()
{
Name = name,
Type = Type.Function,
ResultType = backingMethod.ReturnType.GetScriptType()
});
}
foreach (var f in methods) foreach (var f in methods)
{ {
obj.Properties.Add(f.Name.ToLowerInvariant(), f); obj.Properties.Add(f.Name.ToLowerInvariant(), f);

View File

@ -13,8 +13,9 @@ namespace Upsilon.StandardLibraries
{ {
internal class BasicFunctions : ScriptLibrary internal class BasicFunctions : ScriptLibrary
{ {
[StandardLibraryScriptFunction("assert", "Asserts that the parameter passed is true. Throws an exception if it is not true. " + [ScriptFunction("assert", "Asserts that the parameter passed is true. Throws an exception if it is not true. " +
"Can take a message to show in the exception, otherwise throws with message \"assertion failed!\"")] "Can take a message to show in the exception, otherwise throws with message \"assertion failed!\"",
directScriptManipulation: true)]
public void Assert(ScriptBoolean boolean, ScriptString message = null) public void Assert(ScriptBoolean boolean, ScriptString message = null)
{ {
if (!boolean) if (!boolean)
@ -23,26 +24,29 @@ namespace Upsilon.StandardLibraries
} }
} }
[StandardLibraryScriptFunction("error", "Throw an exception with given error message")] [ScriptFunction("error", "Throw an exception with given error message",
directScriptManipulation: true)]
public void Error(ScriptString message) public void Error(ScriptString message)
{ {
throw new Exception(message.Value); throw new Exception(message.Value);
} }
[StandardLibraryScriptFunction("ipairs", "Iterates over an iterable variable, like a table, until it encounters a nil value.")] [ScriptFunction("ipairs", "Iterates over an iterable variable, like a table, until it encounters a nil value.",
directScriptManipulation: true)]
public IIterable UpTillNullPairs(IIterable table) public IIterable UpTillNullPairs(IIterable table)
{ {
return new UpTillNullPairsScriptIterator(table); return new UpTillNullPairsScriptIterator(table);
} }
[StandardLibraryScriptFunction("pairs", "Iterates over an iterable variable, like a table, skipping all nil values.")] [ScriptFunction("pairs", "Iterates over an iterable variable, like a table, skipping all nil values.",
directScriptManipulation: true)]
public IIterable Pairs(IIterable table) public IIterable Pairs(IIterable table)
{ {
return new PairsScriptIterator(table); return new PairsScriptIterator(table);
} }
[StandardLibraryScriptFunction("require", "Loads a module from the module path, using the given script loader.", [ScriptFunction("require", "Loads a module from the module path, using the given script loader.",
true)] true, true)]
public ScriptType Require(Script script, ScriptString fileName) public ScriptType Require(Script script, ScriptString fileName)
{ {
var file = fileName.Value; var file = fileName.Value;
@ -57,7 +61,7 @@ namespace Upsilon.StandardLibraries
} }
[StandardLibraryScriptFunction("tonumber", "Parses a string to a number.")] [ScriptFunction("tonumber", "Parses a string to a number.", directScriptManipulation: true)]
public ScriptNumber ToNumber(ScriptString obj) public ScriptNumber ToNumber(ScriptString obj)
{ {
var str = obj.Value; var str = obj.Value;
@ -71,13 +75,13 @@ namespace Upsilon.StandardLibraries
} }
} }
[StandardLibraryScriptFunction("tostring", "Returns the string value of the given object.")] [ScriptFunction("tostring", "Returns the string value of the given object.", directScriptManipulation: true)]
public ScriptString ToString(ScriptType obj) public ScriptString ToString(ScriptType obj)
{ {
return new ScriptString(obj.ToString()); return new ScriptString(obj.ToString());
} }
[StandardLibraryScriptFunction("type", "Returns the type of the given object as a string.")] [ScriptFunction("type", "Returns the type of the given object as a string.", directScriptManipulation: true)]
public ScriptString Type(ScriptType obj) public ScriptString Type(ScriptType obj)
{ {
return new ScriptString(obj.Type.ToString()); return new ScriptString(obj.Type.ToString());

View File

@ -0,0 +1,18 @@
using System;
using Upsilon.BaseTypes.Number;
namespace Upsilon.StandardLibraries
{
internal class MathLibrary
{
[ScriptFunction("abs", "Returns the absolute value of x. (integer/float)", directScriptManipulation: true)]
public ScriptNumber Absolute(ScriptNumber a)
{
if (a.IsFloat)
{
return new ScriptNumberDouble(Math.Abs(((ScriptNumberDouble) a).Value));
}
return new ScriptNumberLong(Math.Abs(((ScriptNumberLong) a).Value));
}
}
}

View File

@ -3,19 +3,21 @@ using System;
namespace Upsilon.StandardLibraries namespace Upsilon.StandardLibraries
{ {
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class StandardLibraryScriptFunctionAttribute : Attribute public class ScriptFunctionAttribute : Attribute
{ {
public StandardLibraryScriptFunctionAttribute(string name, string comment = null, public ScriptFunctionAttribute(string name, string comment = null,
bool passScriptReference = false, bool passScopeReference = false) bool directScriptManipulation = false, bool passScriptReference = false, bool passScopeReference = false)
{ {
Name = name; Name = name;
Comment = comment; Comment = comment;
DirectScriptManipulation = directScriptManipulation;
PassScriptReference = passScriptReference; PassScriptReference = passScriptReference;
PassScopeReference = passScopeReference; PassScopeReference = passScopeReference;
} }
public string Name { get; } public string Name { get; }
public string Comment { get; } public string Comment { get; }
public bool DirectScriptManipulation { get; }
public bool PassScriptReference { get; } public bool PassScriptReference { get; }
public bool PassScopeReference { get; } public bool PassScopeReference { get; }
} }

View File

@ -14,7 +14,7 @@ namespace Upsilon.StandardLibraries
var methods = GetType().GetMethods(); var methods = GetType().GetMethods();
foreach (var methodInfo in methods) foreach (var methodInfo in methods)
{ {
var attr = methodInfo.GetCustomAttribute<StandardLibraryScriptFunctionAttribute>(); var attr = methodInfo.GetCustomAttribute<ScriptFunctionAttribute>();
if (attr != null) if (attr != null)
{ {
dictionary.Add(attr.Name, new LoadedStandardFunction() dictionary.Add(attr.Name, new LoadedStandardFunction()

View File

@ -6,6 +6,7 @@ using System.Linq;
using Upsilon.BaseTypes; using Upsilon.BaseTypes;
using Upsilon.BaseTypes.Number; using Upsilon.BaseTypes.Number;
using Upsilon.BaseTypes.ScriptTypeInterfaces; using Upsilon.BaseTypes.ScriptTypeInterfaces;
using Upsilon.BaseTypes.UserData;
using Upsilon.Binder; using Upsilon.Binder;
using Upsilon.Binder.VariableSymbols; using Upsilon.Binder.VariableSymbols;
using Upsilon.BoundTypes; using Upsilon.BoundTypes;
@ -68,6 +69,12 @@ namespace Upsilon.StandardLibraries
}; };
boundFuncs.Add(func.Key, functionSymbol); boundFuncs.Add(func.Key, functionSymbol);
} }
UserDataTypeHandler.LoadType<MathLibrary>();
funcs.Add("math", new MathLibrary().ToScriptType());
boundFuncs.Add("math",
new FunctionParameterSymbol("math", BoundTypeHandler.GetTypeDefinition(typeof(MathLibrary))));
var scope = new EvaluationScope(funcs); var scope = new EvaluationScope(funcs);
var boundScope = new BoundScope(boundFuncs, null); var boundScope = new BoundScope(boundFuncs, null);
return (scope, boundScope); return (scope, boundScope);

View File

@ -50,7 +50,7 @@ namespace UpsilonTests.GeneralTests
[Theory] [Theory]
[InlineData("1/1", 1)] [InlineData("1/1", 1)]
[InlineData("1000 / 10", 100)] [InlineData("1000 / 10", 100)]
[InlineData("656486 / 5146", 127)] [InlineData("656486 / 5146", 127.57209483)]
[InlineData("656486 / 5146.0", 127.57209483)] [InlineData("656486 / 5146.0", 127.57209483)]
public void Divison(string input, double expectedOutput) public void Divison(string input, double expectedOutput)
{ {