Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implicit this reference #232. #233

Merged
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,25 @@ Assert.AreEqual(30, myFunc.Invoke(23, 7));
Assert.AreEqual(30, myFunc.Invoke(32, -2));
```

### Special identifiers

Either a variable or a parameter with name `this` can be referenced implicitly.

```csharp
class Customer { public string Name { get; set; } }

var target = new Interpreter();

// 'this' is treated as a special identifier and could by accessed implicitly
ealeykin marked this conversation as resolved.
Show resolved Hide resolved
target.SetVariable("this", new Customer { Name = "John" });

// explicit context reference via 'this' variable
Assert.AreEqual("John", target.Eval("this.Name"));

// 'this' variable is referenced implicitly
Assert.AreEqual("John", target.Eval("Name"));
```

### Built-in types and custom types
Currently predefined types available are:

Expand Down Expand Up @@ -305,12 +324,21 @@ The following character escape sequences are supported inside string or char lit
### Type's members invocation
Any standard .NET method, field, property or constructor can be invoked.
```csharp
var x = new MyTestService();
var target = new Interpreter().SetVariable("x", x);
var service = new MyTestService();
var context = new MyTestContext();

var target = new Interpreter()
.SetVariable("x", service)
.SetVariable("this", context);

Assert.AreEqual(x.HelloWorld(), target.Eval("x.HelloWorld()"));
Assert.AreEqual(x.AProperty, target.Eval("x.AProperty"));
Assert.AreEqual(x.AField, target.Eval("x.AField"));

// implicit context reference
Assert.AreEqual(x.HelloWorld(), target.Eval("GetContextId()"));
Assert.AreEqual(x.AProperty, target.Eval("ContextName"));
Assert.AreEqual(x.AField, target.Eval("ContextField"));
ealeykin marked this conversation as resolved.
Show resolved Hide resolved
```
```csharp
var target = new Interpreter();
Expand Down
2 changes: 2 additions & 0 deletions src/DynamicExpresso.Core/LanguageConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ namespace DynamicExpresso
{
public static class LanguageConstants
{
public const string This = "this";

public static readonly ReferenceType[] PrimitiveTypes = {
new ReferenceType(typeof(object)),
new ReferenceType(typeof(bool)),
Expand Down
23 changes: 21 additions & 2 deletions src/DynamicExpresso.Core/Parsing/Parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1019,12 +1019,31 @@ private Expression ParseIdentifier()
{
return ParseTypeKeyword(knownType);
}


var token = _token;

try
{
if (_arguments.TryGetIdentifier(LanguageConstants.This, out var thisKeywordExpression))
{
return ParseMemberAccess(thisKeywordExpression);
}

if (_arguments.TryGetParameters(LanguageConstants.This, out var thisParameterExpression))
{
return ParseMemberAccess(thisParameterExpression);
}
}
catch(ParseException)
{
// ignore
}

// Working context implementation
//if (it != null)
// return ParseMemberAccess(null, it);

throw new UnknownIdentifierException(_token.text, _token.pos);
throw new UnknownIdentifierException(token.text, token.pos);
}

// Working context implementation
Expand Down
42 changes: 42 additions & 0 deletions test/DynamicExpresso.UnitTest/IdentifiersTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ namespace DynamicExpresso.UnitTest
[TestFixture]
public class IdentifiersTest
{
class Customer
{
public string Name { get; set; }

public string GetName()
{
return Name;
}
}

[Test]
public void Default_identifiers_are_saved_inside_the_interpreter()
{
Expand Down Expand Up @@ -38,5 +48,37 @@ public void Getting_the_list_of_used_identifiers()
Assert.AreEqual("x", lambda.Identifiers.ElementAt(0).Name);
Assert.AreEqual("true", lambda.Identifiers.ElementAt(1).Name);
}

[Test]
public void This_identifier_variable()
{
const string Name = "John";

var interpreter = new Interpreter();

interpreter.SetVariable("this", new Customer {Name = Name});

Assert.AreEqual(Name, interpreter.Eval("this.Name"));
Assert.AreEqual(Name, interpreter.Eval("this.GetName()"));

Assert.AreEqual(Name, interpreter.Eval("Name"));
Assert.AreEqual(Name, interpreter.Eval("GetName()"));
}

[Test]
public void This_identifier_parameter()
{
const string Name = "John";

var context = new Customer {Name = Name};
var parameter = new Parameter("this", context.GetType());
var interpreter = new Interpreter();

Assert.AreEqual(Name, interpreter.Parse("this.Name", parameter).Invoke(context));
Assert.AreEqual(Name, interpreter.Parse("this.GetName()", parameter).Invoke(context));

Assert.AreEqual(Name, interpreter.Parse("Name", parameter).Invoke(context));
Assert.AreEqual(Name, interpreter.Parse("GetName()", parameter).Invoke(context));
}
}
}