Adds Unary length operator

This commit is contained in:
Deukhoofd 2018-11-24 15:11:33 +01:00
parent 2dc59c5f8b
commit cd04486d16
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
12 changed files with 88 additions and 12 deletions

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -0,0 +1,9 @@
using Upsilon.BaseTypes.Number;
namespace Upsilon.BaseTypes.ScriptTypeInterfaces
{
internal interface ILengthType
{
ScriptNumberLong Length();
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}

View File

@ -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 '=':

View File

@ -27,6 +27,7 @@ namespace Upsilon.Parser
CloseBrace,
OpenBracket,
CloseBracket,
PoundSign,
// key words
TrueKeyword,

View File

@ -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;

View 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);
}
}
}

View File

@ -26,7 +26,7 @@ namespace UpsilonTests.StandardLibraryTests
}
[Fact]
public void IPairsTest()
public void UpTillNilPairsTest()
{
const string input = @"
arr = {100, 56, 28, nil, 100}