Adds Unary length operator
This commit is contained in:
parent
2dc59c5f8b
commit
cd04486d16
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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}
|
||||
|
|
Loading…
Reference in New Issue