Adds Unary length operator
This commit is contained in:
@@ -6,7 +6,7 @@ using Upsilon.Text;
|
||||
|
||||
namespace Upsilon.BaseTypes
|
||||
{
|
||||
internal class ScriptString : ScriptType, IIndexable
|
||||
internal class ScriptString : ScriptType, IIndexable, ILengthType
|
||||
{
|
||||
public ScriptString(string value)
|
||||
{
|
||||
@@ -85,6 +85,11 @@ namespace Upsilon.BaseTypes
|
||||
return Value;
|
||||
}
|
||||
|
||||
public ScriptNumberLong Length()
|
||||
{
|
||||
return new ScriptNumberLong(Value.Length);
|
||||
}
|
||||
|
||||
public ScriptType Get(Diagnostics diagnostics, TextSpan span, ScriptType index, EvaluationScope scope)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Upsilon.BaseTypes.Number;
|
||||
using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
||||
using Upsilon.Binder;
|
||||
using Upsilon.Evaluator;
|
||||
@@ -8,7 +9,7 @@ using Upsilon.Text;
|
||||
|
||||
namespace Upsilon.BaseTypes
|
||||
{
|
||||
internal class ScriptTable : ScriptType, IIndexable, IScopeOwner, IIterable
|
||||
internal class ScriptTable : ScriptType, IIndexable, IScopeOwner, IIterable, ILengthType
|
||||
{
|
||||
public EvaluationScope EvaluationScope { get; }
|
||||
|
||||
@@ -66,5 +67,10 @@ namespace Upsilon.BaseTypes
|
||||
yield return variable.Key.ToScriptType();
|
||||
}
|
||||
}
|
||||
|
||||
public ScriptNumberLong Length()
|
||||
{
|
||||
return new ScriptNumberLong(EvaluationScope.Variables.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Upsilon/BaseTypes/ScriptTypeInterfaces/ILengthType.cs
Normal file
9
Upsilon/BaseTypes/ScriptTypeInterfaces/ILengthType.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Upsilon.BaseTypes.Number;
|
||||
|
||||
namespace Upsilon.BaseTypes.ScriptTypeInterfaces
|
||||
{
|
||||
internal interface ILengthType
|
||||
{
|
||||
ScriptNumberLong Length();
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Upsilon.BaseTypes.Number;
|
||||
using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
||||
using Upsilon.Evaluator;
|
||||
using Upsilon.Text;
|
||||
|
||||
namespace Upsilon.BaseTypes.UserData
|
||||
{
|
||||
internal class DictionaryUserData : ScriptType, IUserData
|
||||
internal class DictionaryUserData : ScriptType, IUserData, ILengthType
|
||||
{
|
||||
public IDictionary Dictionary { get; }
|
||||
|
||||
@@ -47,5 +50,10 @@ namespace Upsilon.BaseTypes.UserData
|
||||
{
|
||||
return Dictionary.GetType();
|
||||
}
|
||||
|
||||
public ScriptNumberLong Length()
|
||||
{
|
||||
return new ScriptNumberLong(Dictionary.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ using Upsilon.Text;
|
||||
|
||||
namespace Upsilon.BaseTypes.UserData
|
||||
{
|
||||
internal class ListUserData : ScriptType, IUserData, IIterable
|
||||
internal class ListUserData : ScriptType, IUserData, IIterable, ILengthType
|
||||
{
|
||||
private IList List { get; }
|
||||
|
||||
@@ -66,5 +66,10 @@ namespace Upsilon.BaseTypes.UserData
|
||||
yield return new ScriptNumberLong(i);
|
||||
}
|
||||
}
|
||||
|
||||
public ScriptNumberLong Length()
|
||||
{
|
||||
return new ScriptNumberLong(List.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,11 @@ namespace Upsilon.Binder
|
||||
{
|
||||
Identity,
|
||||
Negation,
|
||||
LogicalNegation
|
||||
LogicalNegation,
|
||||
Length
|
||||
}
|
||||
|
||||
public Type InType { get; }
|
||||
private Type InType { get; }
|
||||
public Type OutType { get; }
|
||||
public OperatorKind Kind { get; }
|
||||
|
||||
@@ -25,11 +26,13 @@ namespace Upsilon.Binder
|
||||
OutType = outType;
|
||||
}
|
||||
|
||||
private static BoundUnaryOperator[] _operators= new BoundUnaryOperator[]
|
||||
{
|
||||
private static readonly BoundUnaryOperator[] Operators= {
|
||||
new BoundUnaryOperator(OperatorKind.Identity, Type.Number, Type.Number),
|
||||
new BoundUnaryOperator(OperatorKind.Negation, Type.Number, Type.Number),
|
||||
new BoundUnaryOperator(OperatorKind.LogicalNegation, Type.Boolean, Type.Boolean),
|
||||
new BoundUnaryOperator(OperatorKind.Length, Type.String, Type.Number),
|
||||
new BoundUnaryOperator(OperatorKind.Length, Type.Table, Type.Number),
|
||||
new BoundUnaryOperator(OperatorKind.Length, Type.UserData, Type.Number),
|
||||
};
|
||||
|
||||
public static BoundUnaryOperator Bind(SyntaxKind operatorToken, Type inType)
|
||||
@@ -46,13 +49,16 @@ namespace Upsilon.Binder
|
||||
case SyntaxKind.NotKeyword:
|
||||
kind = OperatorKind.LogicalNegation;
|
||||
break;
|
||||
case SyntaxKind.PoundSign:
|
||||
kind = OperatorKind.Length;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Unknown unary operator token: " + operatorToken);
|
||||
}
|
||||
|
||||
if (inType == Type.Unknown)
|
||||
return _operators.FirstOrDefault(op => op.Kind == kind);
|
||||
return _operators.FirstOrDefault(op => op.Kind == kind && op.InType == inType);
|
||||
return Operators.FirstOrDefault(op => op.Kind == kind);
|
||||
return Operators.FirstOrDefault(op => op.Kind == kind && op.InType == inType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -211,7 +211,12 @@ namespace Upsilon.Evaluator
|
||||
return type;
|
||||
}
|
||||
goto default;
|
||||
|
||||
case BoundUnaryOperator.OperatorKind.Length:
|
||||
if (operand is ILengthType length)
|
||||
{
|
||||
return length.Length();
|
||||
}
|
||||
goto default;
|
||||
default:
|
||||
throw new Exception("Invalid Unary Operator: " + e.Operator.Kind);
|
||||
}
|
||||
|
||||
@@ -78,6 +78,8 @@ namespace Upsilon.Parser
|
||||
return new SyntaxToken(SyntaxKind.FullStop, _position, ".", null);
|
||||
case ',':
|
||||
return new SyntaxToken(SyntaxKind.Comma, _position, ",", null);
|
||||
case '#':
|
||||
return new SyntaxToken(SyntaxKind.PoundSign, _position, "#", null);
|
||||
case '"':
|
||||
return LexString();
|
||||
case '=':
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace Upsilon.Parser
|
||||
CloseBrace,
|
||||
OpenBracket,
|
||||
CloseBracket,
|
||||
PoundSign,
|
||||
|
||||
// key words
|
||||
TrueKeyword,
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace Upsilon.Parser
|
||||
PlusMinus,
|
||||
StarSlash,
|
||||
Unary,
|
||||
Exponentiation
|
||||
}
|
||||
|
||||
public static Precedence UnaryOperatorPrecedence(this SyntaxKind kind)
|
||||
@@ -20,6 +21,7 @@ namespace Upsilon.Parser
|
||||
case SyntaxKind.Plus:
|
||||
case SyntaxKind.Minus:
|
||||
case SyntaxKind.NotKeyword:
|
||||
case SyntaxKind.PoundSign:
|
||||
return Precedence.Unary;
|
||||
default:
|
||||
return Precedence.None;
|
||||
|
||||
27
UpsilonTests/GeneralTests/LengthOperatorTests.cs
Normal file
27
UpsilonTests/GeneralTests/LengthOperatorTests.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using Upsilon.Binder;
|
||||
using Upsilon.Evaluator;
|
||||
using Upsilon.StandardLibraries;
|
||||
using Xunit;
|
||||
|
||||
namespace UpsilonTests.GeneralTests
|
||||
{
|
||||
public class LengthOperatorTests : TestClass
|
||||
{
|
||||
public LengthOperatorTests(StaticScriptFixture fix) : base(fix)
|
||||
{
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(@"#""test""", 4)]
|
||||
[InlineData(@"#{100,50,60,7863,1564,12354,10354}", 7)]
|
||||
public void Test(string input, long expectedOutput)
|
||||
{
|
||||
var script = new Script(input, BoundScope, StaticScope);
|
||||
Assert.Empty(script.Diagnostics.Messages);
|
||||
var actual = script.Evaluate<long>();
|
||||
Assert.Empty(script.Diagnostics.Messages);
|
||||
Assert.Equal(expectedOutput, actual);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ namespace UpsilonTests.StandardLibraryTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IPairsTest()
|
||||
public void UpTillNilPairsTest()
|
||||
{
|
||||
const string input = @"
|
||||
arr = {100, 56, 28, nil, 100}
|
||||
|
||||
Reference in New Issue
Block a user