Skip to content

Commit

Permalink
Handle parenthesis with nested expression separately from regular exp…
Browse files Browse the repository at this point in the history
…ression handling. Ensure nested parenthesis get evaluated correctly.
  • Loading branch information
ethanmoffat committed Jan 29, 2022
1 parent fb99073 commit 5b495e7
Showing 1 changed file with 50 additions and 30 deletions.
80 changes: 50 additions & 30 deletions EOBot/Interpreter/States/ExpressionEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,50 @@ public ExpressionEvaluator(IEnumerable<IScriptEvaluator> evaluators)

public bool Evaluate(ProgramState input)
{
var rParenExpected = input.Match(BotTokenType.LParen);
if (input.Expect(BotTokenType.LParen))
{
if (!_evaluators.OfType<ExpressionEvaluator>().Single().Evaluate(input))
return false;

if (!_evaluators.OfType<OperandEvaluator>().Single().Evaluate(input))
return false;
// if we get an RParen just be done
if (input.Expect(BotTokenType.RParen))
return true;

// expression_tail is optional
if (!_evaluators.OfType<ExpressionTailEvaluator>().Single().Evaluate(input))
{
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;
}

// 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 (!input.Expect(BotTokenType.RParen))
return false;
}
else
{
if (rParenExpected && !input.Expect(BotTokenType.RParen))
if (!_evaluators.OfType<OperandEvaluator>().Single().Evaluate(input))
return false;

if (input.OperationStack.Count == 0)
return false;
// expression_tail is optional
if (!_evaluators.OfType<ExpressionTailEvaluator>().Single().Evaluate(input))
{
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);
// convert to variable token (resolve identifier) so consumer of expression result can use it
var singleOperand = GetOperand(input);
input.OperationStack.Push(singleOperand);

return true;
return true;
}
}

if (rParenExpected && !input.Expect(BotTokenType.RParen))
return false;

if (input.OperationStack.Count == 0)
return false;
var operand2 = GetOperand(input);
Expand Down Expand Up @@ -67,15 +87,6 @@ public bool Evaluate(ProgramState input)
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;
Expand All @@ -87,20 +98,29 @@ public bool Evaluate(ProgramState input)

private static VariableBotToken GetOperand(ProgramState input)
{
var operand = input.OperationStack.Peek() as VariableBotToken;
var nextToken = input.OperationStack.Pop();
if (nextToken.TokenType == BotTokenType.Literal)
{
if (int.TryParse(nextToken.TokenValue, out var intValue))
return new VariableBotToken(BotTokenType.Literal, nextToken.TokenValue, new IntVariable(intValue));
else if (bool.TryParse(nextToken.TokenValue, out var boolValue))
return new VariableBotToken(BotTokenType.Literal, nextToken.TokenValue, new BoolVariable(boolValue));
else
return new VariableBotToken(BotTokenType.Literal, nextToken.TokenValue, new StringVariable(nextToken.TokenValue));
}

var operand = nextToken as VariableBotToken;
if (operand == null)
{
var identifier = (IdentifierBotToken)input.OperationStack.Pop();
var identifier = (IdentifierBotToken)nextToken;
if (!input.SymbolTable.ContainsKey(identifier.TokenValue))
input.SymbolTable[identifier.TokenValue] = UndefinedVariable.Instance;

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;
}
Expand Down

0 comments on commit 5b495e7

Please sign in to comment.