Skip to content

Commit

Permalink
Define $account object for access in scripts. Add object type that ev…
Browse files Browse the repository at this point in the history
…aluates members at runtime when they are called.
  • Loading branch information
ethanmoffat committed Feb 4, 2022
1 parent 5264b3e commit 8c696e4
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 16 deletions.
32 changes: 25 additions & 7 deletions EOBot/Interpreter/BuiltInIdentifierConfigurator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,6 @@ public void SetupBuiltInFunctions()
_state.SymbolTable[PredefinedIdentifiers.DELETE_CHARACTER_FUNC] = Readonly(new AsyncFunction<string, bool, int>(PredefinedIdentifiers.DELETE_CHARACTER_FUNC, DeleteCharacterAsync));
_state.SymbolTable[PredefinedIdentifiers.LOGIN_CHARACTER_FUNC] = Readonly(new AsyncVoidFunction<string>(PredefinedIdentifiers.LOGIN_CHARACTER_FUNC, LoginToCharacterAsync));
}

private static (bool, IIdentifiable) Readonly(IIdentifiable identifiable)
{
return (true, identifiable);
}

public void SetupBuiltInVariables()
{
_state.SymbolTable[PredefinedIdentifiers.HOST] = (true, new StringVariable(_parsedArgs.Host));
Expand All @@ -70,11 +64,16 @@ public void SetupBuiltInVariables()
_state.SymbolTable[PredefinedIdentifiers.VERSION] = (false, new IntVariable(28));

_state.SymbolTable[PredefinedIdentifiers.RESULT] = (false, UndefinedVariable.Instance);
_state.SymbolTable[PredefinedIdentifiers.ACCOUNT] = (true, UndefinedVariable.Instance);
_state.SymbolTable[PredefinedIdentifiers.ACCOUNT] = SetupAccountObject();
_state.SymbolTable[PredefinedIdentifiers.CHARACTER] = (true, UndefinedVariable.Instance);
_state.SymbolTable[PredefinedIdentifiers.MAPSTATE] = (true, UndefinedVariable.Instance);
}

private static (bool, IIdentifiable) Readonly(IIdentifiable identifiable)
{
return (true, identifiable);
}

private void BotDependencySetup()
{
var c = DependencyMaster.TypeRegistry[_botIndex];
Expand Down Expand Up @@ -168,5 +167,24 @@ private Task LoginToCharacterAsync(string charName)
{
return _botHelper.LoginToCharacterAsync(charName);
}

private (bool, IIdentifiable) SetupAccountObject()
{
var playerInfoProv = DependencyMaster.TypeRegistry[_botIndex].Resolve<IPlayerInfoProvider>();
var charSelectProv = DependencyMaster.TypeRegistry[_botIndex].Resolve<ICharacterSelectorProvider>();

var accountObj = new RuntimeEvaluatedMemberObjectVariable();
accountObj.SymbolTable[PredefinedIdentifiers.NAME] = (true, () => new StringVariable(playerInfoProv.LoggedInAccountName));
accountObj.SymbolTable[PredefinedIdentifiers.CHARACTERS] = (true,
() => new ArrayVariable(
charSelectProv.Characters.Select(x =>
{
var retObj = new ObjectVariable();
retObj.SymbolTable[PredefinedIdentifiers.NAME] = Readonly(new StringVariable(x.Name));
return (IVariable)retObj;
}).ToList()));

return Readonly(accountObj);
}
}
}
26 changes: 19 additions & 7 deletions EOBot/Interpreter/States/AssignmentEvaluator.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using EOBot.Interpreter.Extensions;
using EOBot.Interpreter.Variables;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace EOBot.Interpreter.States
Expand Down Expand Up @@ -37,22 +38,33 @@ public override async Task<(EvalResult, string, BotToken)> EvaluateAsync(Program
return StackEmptyError(input.Current());
var assignmentTarget = (IdentifierBotToken)input.OperationStack.Pop();

return Assign2(input.SymbolTable, assignmentTarget, expressionResult);
return Assign(input.SymbolTable, assignmentTarget, expressionResult);
}

private (EvalResult, string, BotToken) Assign2(Dictionary<string, (bool ReadOnly, IIdentifiable Identifiable)> symbols, IdentifierBotToken assignmentTarget, VariableBotToken expressionResult)
private (EvalResult, string, BotToken) Assign(Dictionary<string, (bool ReadOnly, IIdentifiable Identifiable)> symbols, IdentifierBotToken assignmentTarget, VariableBotToken expressionResult)
{
if (assignmentTarget.Member != null)
{
if (!symbols.ContainsKey(assignmentTarget.TokenValue))
return IdentifierNotFoundError(assignmentTarget);

var getVariableResult = symbols.GetVariable<ObjectVariable>(assignmentTarget.TokenValue, assignmentTarget.ArrayIndex);
if (getVariableResult.Result != EvalResult.Ok)
return (getVariableResult.Result, getVariableResult.Reason, assignmentTarget);
var getVariableRes = symbols.GetVariable<ObjectVariable>(assignmentTarget.TokenValue, assignmentTarget.ArrayIndex);
if (getVariableRes.Result != EvalResult.Ok)
{
var getRuntimeEvaluatedVariableRes = symbols.GetVariable<RuntimeEvaluatedMemberObjectVariable>(assignmentTarget.TokenValue, assignmentTarget.ArrayIndex);
if (getRuntimeEvaluatedVariableRes.Result != EvalResult.Ok)
return (EvalResult.Failed, $"Identifier '{assignmentTarget.TokenValue}' is not an object", assignmentTarget);

getVariableRes.Result = getRuntimeEvaluatedVariableRes.Result;
getVariableRes.Reason = getRuntimeEvaluatedVariableRes.Reason;
getVariableRes.Variable = new ObjectVariable(
getRuntimeEvaluatedVariableRes.Variable.SymbolTable
.Select(x => (x.Key, (x.Value.ReadOnly, x.Value.Variable())))
.ToDictionary(x => x.Key, x => x.Item2));
}

var targetObject = getVariableResult.Variable;
return Assign2(targetObject.SymbolTable, assignmentTarget.Member, expressionResult);
var targetObject = getVariableRes.Variable;
return Assign(targetObject.SymbolTable, assignmentTarget.Member, expressionResult);
}

if (assignmentTarget.ArrayIndex != null)
Expand Down
15 changes: 14 additions & 1 deletion EOBot/Interpreter/States/ExpressionEvaluator.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using EOBot.Interpreter.Extensions;
using EOBot.Interpreter.Variables;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace EOBot.Interpreter.States
Expand Down Expand Up @@ -137,6 +138,7 @@ public override async Task<(EvalResult, string, BotToken)> EvaluateAsync(Program
return Success();
}

// todo: a lot of this code is the same as what's in AssignmentEvaluator::Assign, see if it can be split out/shared
private (EvalResult, string, BotToken) GetOperand(Dictionary<string, (bool, IIdentifiable)> symbols, BotToken nextToken)
{
if (nextToken.TokenType == BotTokenType.Literal)
Expand Down Expand Up @@ -168,7 +170,18 @@ public override async Task<(EvalResult, string, BotToken)> EvaluateAsync(Program
{
var getVariableRes = symbols.GetVariable<ObjectVariable>(identifier.TokenValue, identifier.ArrayIndex);
if (getVariableRes.Result != EvalResult.Ok)
return (EvalResult.Failed, $"Identifier '{identifier.TokenValue}' is not an object", identifier);
{
var getRuntimeEvaluatedVariableRes = symbols.GetVariable<RuntimeEvaluatedMemberObjectVariable>(identifier.TokenValue, identifier.ArrayIndex);
if (getRuntimeEvaluatedVariableRes.Result != EvalResult.Ok)
return (EvalResult.Failed, $"Identifier '{identifier.TokenValue}' is not an object", identifier);

getVariableRes.Result = getRuntimeEvaluatedVariableRes.Result;
getVariableRes.Reason = getRuntimeEvaluatedVariableRes.Reason;
getVariableRes.Variable = new ObjectVariable(
getRuntimeEvaluatedVariableRes.Variable.SymbolTable
.Select(x => (x.Key, (x.Value.ReadOnly, x.Value.Variable())))
.ToDictionary(x => x.Key, x => x.Item2));
}

return GetOperand(getVariableRes.Variable.SymbolTable, identifier.Member);
}
Expand Down
24 changes: 23 additions & 1 deletion EOBot/Interpreter/Variables/ObjectVariable.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;

namespace EOBot.Interpreter.Variables
Expand All @@ -11,6 +12,8 @@ public class ObjectVariable : IVariable<object>

public ObjectVariable() => SymbolTable = new Dictionary<string, (bool, IIdentifiable)>();

public ObjectVariable(Dictionary<string, (bool, IIdentifiable)> symbolTable) => SymbolTable = symbolTable;

public string StringValue => $"Object: [{string.Join(", ", SymbolTable.Select(x => $"({x.Key}, {x.Value.Variable})"))}]";

public override bool Equals(object obj) => CompareTo(obj) == 0;
Expand All @@ -21,4 +24,23 @@ public class ObjectVariable : IVariable<object>

public override string ToString() => StringValue;
}

public class RuntimeEvaluatedMemberObjectVariable : IVariable<object>
{
public object Value => SymbolTable;

public Dictionary<string, (bool ReadOnly, Func<IIdentifiable> Variable)> SymbolTable { get; }

public RuntimeEvaluatedMemberObjectVariable() => SymbolTable = new Dictionary<string, (bool, Func<IIdentifiable>)>();

public string StringValue => $"Object: [{string.Join(", ", SymbolTable.Select(x => $"({x.Key}, {x.Value.Variable()})"))}]";

public override bool Equals(object obj) => CompareTo(obj) == 0;

public override int GetHashCode() => Value.GetHashCode();

public int CompareTo(object obj) => obj is ObjectVariable ? SymbolTable.Equals(((ObjectVariable)obj).SymbolTable) ? 0 : -1 : -1;

public override string ToString() => StringValue;
}
}
3 changes: 3 additions & 0 deletions EOBot/Interpreter/Variables/PredefinedIdentifiers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ public static class PredefinedIdentifiers
public const string CHARACTER = "character";
public const string MAPSTATE = "mapstate";

public const string NAME = "name";
public const string CHARACTERS = "characters";

// interpreter functions
public const string PRINT_FUNC = "print";
public const string LEN_FUNC = "len";
Expand Down

0 comments on commit 8c696e4

Please sign in to comment.