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 namespace Upsilon.BaseTypes
{ {
internal class ScriptString : ScriptType, IIndexable internal class ScriptString : ScriptType, IIndexable, ILengthType
{ {
public ScriptString(string value) public ScriptString(string value)
{ {
@ -85,6 +85,11 @@ namespace Upsilon.BaseTypes
return Value; return Value;
} }
public ScriptNumberLong Length()
{
return new ScriptNumberLong(Value.Length);
}
public ScriptType Get(Diagnostics diagnostics, TextSpan span, ScriptType index, EvaluationScope scope) public ScriptType Get(Diagnostics diagnostics, TextSpan span, ScriptType index, EvaluationScope scope)
{ {
int i; int i;

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Upsilon.BaseTypes.Number;
using Upsilon.BaseTypes.ScriptTypeInterfaces; using Upsilon.BaseTypes.ScriptTypeInterfaces;
using Upsilon.Binder; using Upsilon.Binder;
using Upsilon.Evaluator; using Upsilon.Evaluator;
@ -8,7 +9,7 @@ using Upsilon.Text;
namespace Upsilon.BaseTypes namespace Upsilon.BaseTypes
{ {
internal class ScriptTable : ScriptType, IIndexable, IScopeOwner, IIterable internal class ScriptTable : ScriptType, IIndexable, IScopeOwner, IIterable, ILengthType
{ {
public EvaluationScope EvaluationScope { get; } public EvaluationScope EvaluationScope { get; }
@ -66,5 +67,10 @@ namespace Upsilon.BaseTypes
yield return variable.Key.ToScriptType(); 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;
using System.Collections.Generic;
using Upsilon.BaseTypes.Number;
using Upsilon.BaseTypes.ScriptTypeInterfaces;
using Upsilon.Evaluator; using Upsilon.Evaluator;
using Upsilon.Text; using Upsilon.Text;
namespace Upsilon.BaseTypes.UserData namespace Upsilon.BaseTypes.UserData
{ {
internal class DictionaryUserData : ScriptType, IUserData internal class DictionaryUserData : ScriptType, IUserData, ILengthType
{ {
public IDictionary Dictionary { get; } public IDictionary Dictionary { get; }
@ -47,5 +50,10 @@ namespace Upsilon.BaseTypes.UserData
{ {
return Dictionary.GetType(); return Dictionary.GetType();
} }
public ScriptNumberLong Length()
{
return new ScriptNumberLong(Dictionary.Count);
}
} }
} }

View File

@ -8,7 +8,7 @@ using Upsilon.Text;
namespace Upsilon.BaseTypes.UserData namespace Upsilon.BaseTypes.UserData
{ {
internal class ListUserData : ScriptType, IUserData, IIterable internal class ListUserData : ScriptType, IUserData, IIterable, ILengthType
{ {
private IList List { get; } private IList List { get; }
@ -66,5 +66,10 @@ namespace Upsilon.BaseTypes.UserData
yield return new ScriptNumberLong(i); yield return new ScriptNumberLong(i);
} }
} }
public ScriptNumberLong Length()
{
return new ScriptNumberLong(List.Count);
}
} }
} }

View File

@ -11,10 +11,11 @@ namespace Upsilon.Binder
{ {
Identity, Identity,
Negation, Negation,
LogicalNegation LogicalNegation,
Length
} }
public Type InType { get; } private Type InType { get; }
public Type OutType { get; } public Type OutType { get; }
public OperatorKind Kind { get; } public OperatorKind Kind { get; }
@ -25,11 +26,13 @@ namespace Upsilon.Binder
OutType = outType; OutType = outType;
} }
private static BoundUnaryOperator[] _operators= new BoundUnaryOperator[] private static readonly BoundUnaryOperator[] Operators= {
{
new BoundUnaryOperator(OperatorKind.Identity, Type.Number, Type.Number), new BoundUnaryOperator(OperatorKind.Identity, Type.Number, Type.Number),
new BoundUnaryOperator(OperatorKind.Negation, Type.Number, Type.Number), new BoundUnaryOperator(OperatorKind.Negation, Type.Number, Type.Number),
new BoundUnaryOperator(OperatorKind.LogicalNegation, Type.Boolean, Type.Boolean), 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) public static BoundUnaryOperator Bind(SyntaxKind operatorToken, Type inType)
@ -46,13 +49,16 @@ namespace Upsilon.Binder
case SyntaxKind.NotKeyword: case SyntaxKind.NotKeyword:
kind = OperatorKind.LogicalNegation; kind = OperatorKind.LogicalNegation;
break; break;
case SyntaxKind.PoundSign:
kind = OperatorKind.Length;
break;
default: default:
throw new Exception("Unknown unary operator token: " + operatorToken); throw new Exception("Unknown unary operator token: " + operatorToken);
} }
if (inType == Type.Unknown) if (inType == Type.Unknown)
return _operators.FirstOrDefault(op => op.Kind == kind); return Operators.FirstOrDefault(op => op.Kind == kind);
return _operators.FirstOrDefault(op => op.Kind == kind && op.InType == inType); return Operators.FirstOrDefault(op => op.Kind == kind && op.InType == inType);
} }
} }
} }

View File

@ -211,7 +211,12 @@ namespace Upsilon.Evaluator
return type; return type;
} }
goto default; goto default;
case BoundUnaryOperator.OperatorKind.Length:
if (operand is ILengthType length)
{
return length.Length();
}
goto default;
default: default:
throw new Exception("Invalid Unary Operator: " + e.Operator.Kind); 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); return new SyntaxToken(SyntaxKind.FullStop, _position, ".", null);
case ',': case ',':
return new SyntaxToken(SyntaxKind.Comma, _position, ",", null); return new SyntaxToken(SyntaxKind.Comma, _position, ",", null);
case '#':
return new SyntaxToken(SyntaxKind.PoundSign, _position, "#", null);
case '"': case '"':
return LexString(); return LexString();
case '=': case '=':

View File

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

View File

@ -11,6 +11,7 @@ namespace Upsilon.Parser
PlusMinus, PlusMinus,
StarSlash, StarSlash,
Unary, Unary,
Exponentiation
} }
public static Precedence UnaryOperatorPrecedence(this SyntaxKind kind) public static Precedence UnaryOperatorPrecedence(this SyntaxKind kind)
@ -20,6 +21,7 @@ namespace Upsilon.Parser
case SyntaxKind.Plus: case SyntaxKind.Plus:
case SyntaxKind.Minus: case SyntaxKind.Minus:
case SyntaxKind.NotKeyword: case SyntaxKind.NotKeyword:
case SyntaxKind.PoundSign:
return Precedence.Unary; return Precedence.Unary;
default: default:
return Precedence.None; 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] [Fact]
public void IPairsTest() public void UpTillNilPairsTest()
{ {
const string input = @" const string input = @"
arr = {100, 56, 28, nil, 100} arr = {100, 56, 28, nil, 100}