-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement evaluation of assignments/expressions
- Loading branch information
1 parent
9f25a89
commit 8d7f154
Showing
17 changed files
with
396 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
using EOBot.Interpreter.States; | ||
|
||
namespace EOBot.Interpreter.Extensions | ||
{ | ||
public static class ProgramStateExtensions | ||
{ | ||
public static bool MatchOneOf(this ProgramState input, params BotTokenType[] tokenTypes) | ||
{ | ||
// todo: there's probably LINQ for this but I'm tired and my brain isn't quite working | ||
// needs to stop trying to match after first match, can't use FirstOrDefault unless default(BotTokenType) can be used as an "empty" value | ||
foreach (var type in tokenTypes) | ||
{ | ||
if (input.Match(type)) | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
namespace EOBot.Interpreter | ||
{ | ||
public class IdentifierBotToken : BotToken | ||
{ | ||
public int? ArrayIndex { get; } | ||
|
||
public IdentifierBotToken(BotTokenType tokenType, string tokenValue, int? arrayIndex = null) | ||
: base(tokenType, tokenValue) | ||
{ | ||
ArrayIndex = arrayIndex; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
using EOBot.Interpreter.Variables; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace EOBot.Interpreter.States | ||
{ | ||
public class ExpressionEvaluator : IScriptEvaluator | ||
{ | ||
private readonly IEnumerable<IScriptEvaluator> _evaluators; | ||
|
||
public ExpressionEvaluator(IEnumerable<IScriptEvaluator> evaluators) | ||
{ | ||
_evaluators = evaluators; | ||
} | ||
|
||
public bool Evaluate(ProgramState input) | ||
{ | ||
var rParenExpected = input.Match(BotTokenType.LParen); | ||
|
||
if (!_evaluators.OfType<OperandEvaluator>().Single().Evaluate(input)) | ||
return false; | ||
|
||
// expression may just be a single result (since expressions are recursive - doesn't have to be 'A op B') | ||
if (!_evaluators.OfType<ExpressionTailEvaluator>().Single().Evaluate(input)) | ||
{ | ||
if (rParenExpected && !input.Expect(BotTokenType.RParen)) | ||
return false; | ||
|
||
if (input.OperationStack.Count == 0) | ||
return false; | ||
|
||
// convert to variable token (resolve identifier) so consumer of expression result can use it | ||
var singleOperand = GetOperand(input); | ||
input.OperationStack.Push(singleOperand); | ||
|
||
return true; | ||
} | ||
|
||
if (rParenExpected && !input.Expect(BotTokenType.RParen)) | ||
return false; | ||
|
||
if (input.OperationStack.Count == 0) | ||
return false; | ||
var operand2 = GetOperand(input); | ||
|
||
if (input.OperationStack.Count == 0) | ||
return false; | ||
var @operator = input.OperationStack.Pop(); | ||
|
||
if (input.OperationStack.Count == 0) | ||
return false; | ||
var operand1 = GetOperand(input); | ||
|
||
IVariable expressionResult; | ||
switch (@operator.TokenType) | ||
{ | ||
case BotTokenType.EqualOperator: expressionResult = new BoolVariable(operand1.VariableValue.Equals(operand2.VariableValue)); break; | ||
case BotTokenType.NotEqualOperator: expressionResult = new BoolVariable(!operand1.VariableValue.Equals(operand2.VariableValue)); break; | ||
case BotTokenType.LessThanOperator: expressionResult = new BoolVariable(operand1.VariableValue.CompareTo(operand2.VariableValue) < 0); break; | ||
case BotTokenType.GreaterThanOperator: expressionResult = new BoolVariable(operand1.VariableValue.CompareTo(operand2.VariableValue) > 0); break; | ||
case BotTokenType.LessThanEqOperator: expressionResult = new BoolVariable(operand1.VariableValue.CompareTo(operand2.VariableValue) <= 0); break; | ||
case BotTokenType.GreaterThanEqOperator: expressionResult = new BoolVariable(operand1.VariableValue.CompareTo(operand2.VariableValue) >= 0); break; | ||
case BotTokenType.PlusOperator: expressionResult = Add((dynamic)operand1.VariableValue, (dynamic)operand2.VariableValue); break; | ||
case BotTokenType.MinusOperator: expressionResult = Subtract((dynamic)operand1.VariableValue, (dynamic)operand2.VariableValue); break; | ||
case BotTokenType.MultiplyOperator: expressionResult = Multiply((dynamic)operand1.VariableValue, (dynamic)operand2.VariableValue); break; | ||
case BotTokenType.DivideOperator: expressionResult = Divide((dynamic)operand1.VariableValue, (dynamic)operand2.VariableValue); break; | ||
default: return false; | ||
} | ||
|
||
if (rParenExpected) | ||
{ | ||
if (input.OperationStack.Count == 0) | ||
return false; | ||
|
||
// todo: check that this is the LPAREN | ||
input.OperationStack.Pop(); | ||
} | ||
|
||
// todo: indicate errors in the operation | ||
if (expressionResult == null) | ||
return false; | ||
|
||
input.OperationStack.Push(new VariableBotToken(BotTokenType.Literal, expressionResult.StringValue, expressionResult)); | ||
|
||
return true; | ||
} | ||
|
||
private static VariableBotToken GetOperand(ProgramState input) | ||
{ | ||
var operand = input.OperationStack.Peek() as VariableBotToken; | ||
|
||
if (operand == null) | ||
{ | ||
var identifier = (IdentifierBotToken)input.OperationStack.Pop(); | ||
var variableValue = (IVariable)input.SymbolTable[identifier.TokenValue]; | ||
if (identifier.ArrayIndex != null) | ||
variableValue = ((ArrayVariable)variableValue).Value[identifier.ArrayIndex.Value]; | ||
operand = new VariableBotToken(BotTokenType.Literal, variableValue.ToString(), variableValue); | ||
} | ||
else | ||
{ | ||
input.OperationStack.Pop(); | ||
} | ||
|
||
return operand; | ||
} | ||
|
||
private IIdentifiable Add(IntVariable a, IntVariable b) => new IntVariable(a.Value + b.Value); | ||
private IIdentifiable Add(IntVariable a, StringVariable b) => new StringVariable(a.Value + b.Value); | ||
private IIdentifiable Add(StringVariable a, IntVariable b) => new StringVariable(a.Value + b.Value); | ||
private IIdentifiable Add(StringVariable a, StringVariable b) => new StringVariable(a.Value + b.Value); | ||
private IIdentifiable Add(object a, object b) => null; | ||
|
||
private IIdentifiable Subtract(IntVariable a, IntVariable b) => new IntVariable(a.Value - b.Value); | ||
private IIdentifiable Subtract(object a, object b) => null; | ||
|
||
private IIdentifiable Multiply(IntVariable a, IntVariable b) => new IntVariable(a.Value * b.Value); | ||
private IIdentifiable Multiply(object a, object b) => null; | ||
|
||
private IIdentifiable Divide(IntVariable a, IntVariable b) => new IntVariable(a.Value / b.Value); | ||
private IIdentifiable Divide(object a, object b) => null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
using EOBot.Interpreter.Extensions; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace EOBot.Interpreter.States | ||
{ | ||
public class ExpressionTailEvaluator : IScriptEvaluator | ||
{ | ||
private readonly IEnumerable<IScriptEvaluator> _evaluators; | ||
|
||
public ExpressionTailEvaluator(IEnumerable<IScriptEvaluator> evaluators) | ||
{ | ||
_evaluators = evaluators; | ||
} | ||
|
||
public bool Evaluate(ProgramState input) | ||
{ | ||
return input.MatchOneOf( | ||
BotTokenType.EqualOperator, | ||
BotTokenType.NotEqualOperator, | ||
BotTokenType.GreaterThanOperator, | ||
BotTokenType.LessThanOperator, | ||
BotTokenType.GreaterThanEqOperator, | ||
BotTokenType.LessThanEqOperator, | ||
BotTokenType.PlusOperator, | ||
BotTokenType.MinusOperator, | ||
BotTokenType.MultiplyOperator, | ||
BotTokenType.DivideOperator) | ||
&& _evaluators.OfType<ExpressionEvaluator>().Single().Evaluate(input); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace EOBot.Interpreter.States | ||
{ | ||
public class OperandEvaluator : IScriptEvaluator | ||
{ | ||
private readonly IEnumerable<IScriptEvaluator> _evaluators; | ||
|
||
public OperandEvaluator(IEnumerable<IScriptEvaluator> evaluators) | ||
{ | ||
_evaluators = evaluators; | ||
} | ||
|
||
public bool Evaluate(ProgramState input) | ||
{ | ||
return _evaluators.OfType<VariableEvaluator>().Single().Evaluate(input) || | ||
input.Match(BotTokenType.Literal); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
using EOBot.Interpreter.Variables; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace EOBot.Interpreter.States | ||
{ | ||
public class VariableEvaluator : IScriptEvaluator | ||
{ | ||
private readonly IEnumerable<IScriptEvaluator> _evaluators; | ||
|
||
public VariableEvaluator(IEnumerable<IScriptEvaluator> evaluators) | ||
{ | ||
_evaluators = evaluators; | ||
} | ||
|
||
public bool Evaluate(ProgramState input) | ||
{ | ||
if (!input.Match(BotTokenType.Identifier)) | ||
return false; | ||
|
||
int? arrayIndex = null; | ||
|
||
if (input.Expect(BotTokenType.LBracket)) | ||
{ | ||
if (!_evaluators.OfType<ExpressionEvaluator>().Single().Evaluate(input)) | ||
return false; | ||
input.Expect(BotTokenType.RBracket); | ||
|
||
if (input.OperationStack.Count == 0) | ||
return false; | ||
var expressionResult = (VariableBotToken)input.OperationStack.Pop(); | ||
|
||
// todo: error checking if expression doesn't evaluate down to int | ||
arrayIndex = ((IntVariable)expressionResult.VariableValue).Value; | ||
} | ||
|
||
if (input.OperationStack.Count == 0) | ||
return false; | ||
var identifier = input.OperationStack.Pop(); | ||
|
||
input.OperationStack.Push(new IdentifierBotToken(BotTokenType.Identifier, identifier.TokenValue, arrayIndex)); | ||
|
||
return true; | ||
} | ||
} | ||
} |
Oops, something went wrong.