Skip to content

Commit

Permalink
Add support for ! operator in boolean expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
ethanmoffat committed Feb 5, 2022
1 parent b96007f commit 714dd6a
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 8 deletions.
6 changes: 4 additions & 2 deletions EOBot/Interpreter/BotTokenParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,11 @@ public BotToken GetNextToken()
}
case '!':
{
var nextChar = Read();
var nextChar = Peek();
if (nextChar != '=')
return Token(BotTokenType.NotOperator, inputChar.ToString() + nextChar);
return Token(BotTokenType.NotOperator, inputChar.ToString());

Read();
return Token(BotTokenType.NotEqualOperator, inputChar.ToString() + nextChar);
}
case '>':
Expand Down
41 changes: 35 additions & 6 deletions EOBot/Interpreter/States/ExpressionEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public ExpressionEvaluator(IEnumerable<IScriptEvaluator> evaluators)
// todo: this code is a mess and could use cleaning up (lots of copy/paste...)
public override async Task<(EvalResult, string, BotToken)> EvaluateAsync(ProgramState input)
{
input.Match(BotTokenType.NotOperator);

if (input.Expect(BotTokenType.LParen))
{
var evalRes = await Evaluator<ExpressionEvaluator>().EvaluateAsync(input);
Expand All @@ -22,7 +24,7 @@ public override async Task<(EvalResult, string, BotToken)> EvaluateAsync(Program

// if we get an RParen, the nested expression has been evaluated
if (input.Expect(BotTokenType.RParen))
return evalRes;
return NegateIfNeeded(input);

// expression_tail is optional
evalRes = await Evaluator<ExpressionTailEvaluator>().EvaluateAsync(input);
Expand All @@ -44,7 +46,10 @@ public override async Task<(EvalResult, string, BotToken)> EvaluateAsync(Program
// if there is an expression tail, evaluate the operands below, otherwise return early
evalRes = await Evaluator<ExpressionTailEvaluator>().EvaluateAsync(input);
if (evalRes.Result == EvalResult.NotMatch)
return Success();
{
// function call as single operand expression - negate the result if needed
return NegateIfNeeded(input);
}
else if (evalRes.Result == EvalResult.Failed)
return evalRes;
}
Expand Down Expand Up @@ -110,8 +115,7 @@ public override async Task<(EvalResult, string, BotToken)> EvaluateAsync(Program
return (EvalResult.Failed, $"Error evaluating expression: {res.Reason}", input.Current());

input.OperationStack.Push(new VariableBotToken(BotTokenType.Literal, res.Result.StringValue, res.Result));

return Success();
return NegateIfNeeded(input);
}

private (EvalResult, string, BotToken) EvaluateSingleOperand(ProgramState input)
Expand All @@ -125,8 +129,7 @@ public override async Task<(EvalResult, string, BotToken)> EvaluateAsync(Program
return (localResult, localReason, singleOperand);

input.OperationStack.Push(singleOperand);

return Success();
return NegateIfNeeded(input);
}

// todo: a lot of this code is the same as what's in AssignmentEvaluator::Assign, see if it can be split out/shared
Expand Down Expand Up @@ -181,6 +184,32 @@ public override async Task<(EvalResult, string, BotToken)> EvaluateAsync(Program
return Success(operand);
}

// negate the VariableBotToken on top of the stack if there as a 'not' operator immediately below it
private (EvalResult, string, BotToken) NegateIfNeeded(ProgramState input)
{
if (input.OperationStack.Count == 0)
return StackEmptyError(input.Current());

var varToken = input.OperationStack.Pop();

if (input.OperationStack.Count == 0 || input.OperationStack.Peek().TokenType != BotTokenType.NotOperator)
{
input.OperationStack.Push(varToken);
return Success();
}

var notOperator = input.OperationStack.Pop();

var boolOperand = ((VariableBotToken)varToken).VariableValue as BoolVariable;
if (boolOperand == null)
return UnsupportedOperatorError(notOperator);

var negatedToken = new VariableBotToken(varToken.TokenType, (!boolOperand.Value).ToString(), new BoolVariable(!boolOperand.Value));
input.OperationStack.Push(negatedToken);

return Success();
}

private (IVariable, string) Add(IntVariable a, IntVariable b) => (new IntVariable(a.Value + b.Value), string.Empty);
private (IVariable, string) Add(IntVariable a, StringVariable b) => (new StringVariable(a.Value + b.Value), string.Empty);
private (IVariable, string) Add(StringVariable a, IntVariable b) => (new StringVariable(a.Value + b.Value), string.Empty);
Expand Down
5 changes: 5 additions & 0 deletions EOBot/Interpreter/States/OperandEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ public OperandEvaluator(IEnumerable<IScriptEvaluator> evaluators)

public override async Task<(EvalResult, string, BotToken)> EvaluateAsync(ProgramState input)
{
if (input.Match(BotTokenType.NotOperator))
{

}

var evalRes = await Evaluator<VariableEvaluator>().EvaluateAsync(input);
if (evalRes.Result == EvalResult.Ok)
return evalRes;
Expand Down

0 comments on commit 714dd6a

Please sign in to comment.