Skip to content

Commit cd10881

Browse files
committed
first return keyword implementation
1 parent f3c4721 commit cd10881

File tree

1 file changed

+31
-13
lines changed

1 file changed

+31
-13
lines changed

CodingSeb.ExpressionEvaluator/ExpressionEvaluator.cs

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,11 @@ public class ExpressionEvaluator
4242
private static readonly Regex newLineCharsRegex = new Regex(@"\r\n|\r|\n");
4343

4444
// For script only
45-
private static Regex variableAssignationRegex = new Regex(@"^(?<name>[a-zA-Z_][a-zA-Z0-9_]*)\s*(?<assignmentPrefix>[+\-*/%&|^]|<<|>>)?=(?![=>])");
46-
private static Regex blockKeywordsBeginningRegex = new Regex(@"^\s*(?<keyword>while|for|if|else\s+if)\s*[(]", RegexOptions.IgnoreCase);
47-
private static Regex elseblockKeywordsBeginningRegex = new Regex(@"^\s*(?<keyword>else)(?![a-zA-Z0-9_])", RegexOptions.IgnoreCase);
48-
private static Regex blockBeginningRegex = new Regex(@"^\s*[{]");
45+
private static readonly Regex variableAssignationRegex = new Regex(@"^(?<name>[a-zA-Z_][a-zA-Z0-9_]*)\s*(?<assignmentPrefix>[+\-*/%&|^]|<<|>>)?=(?![=>])");
46+
private static readonly Regex blockKeywordsBeginningRegex = new Regex(@"^\s*(?<keyword>while|for|if|else\s+if)\s*[(]", RegexOptions.IgnoreCase);
47+
private static readonly Regex elseblockKeywordsBeginningRegex = new Regex(@"^\s*(?<keyword>else)(?![a-zA-Z0-9_])", RegexOptions.IgnoreCase);
48+
private static readonly Regex blockBeginningRegex = new Regex(@"^\s*[{]");
49+
private static readonly Regex returnKeywordRegex = new Regex(@"^return(\s+|\()", RegexOptions.IgnoreCase | RegexOptions.Singleline);
4950

5051
#endregion
5152

@@ -626,12 +627,21 @@ public ExpressionEvaluator(Dictionary<string, object> variables) : this()
626627
/// <summary>
627628
/// Evaluate a script (multiple expressions separated by semicolon)
628629
/// Support Assignation with [=] (for simple variable write in the Variables dictionary)
630+
/// support also if, else if, else while and for keywords
629631
/// </summary>
630632
/// <param name="script">the script to evaluate</param>
631633
/// <returns>The result of the last evaluated expression</returns>
632634
public object ScriptEvaluate(string script)
635+
{
636+
bool isReturn = false;
637+
638+
return ScriptEvaluate(script, ref isReturn);
639+
}
640+
641+
private object ScriptEvaluate(string script, ref bool valueReturned)
633642
{
634643
object lastResult = null;
644+
bool isReturn = valueReturned;
635645
int startOfExpression = 0;
636646
IfBlockEvaluatedState ifBlockEvaluatedState = IfBlockEvaluatedState.NoBlockEvaluated;
637647
List<List<string>> ifElseStatementsList = new List<List<string>>();
@@ -645,6 +655,12 @@ object AssignationOrExpressionEval(string expression)
645655

646656
expression = expression.Trim();
647657

658+
expression = returnKeywordRegex.Replace(expression, match =>
659+
{
660+
isReturn = true;
661+
return match.Value.Contains("(") ? "(" : string.Empty;
662+
});
663+
648664
Match variableAssignationMatch = variableAssignationRegex.Match(expression);
649665

650666
if (variableAssignationMatch.Success)
@@ -714,15 +730,15 @@ void ExecuteIfList()
714730
string ifScript = ifElseStatementsList.Find(statement => (bool)AssignationOrExpressionEval(statement[0]))?[1];
715731

716732
if (!string.IsNullOrEmpty(ifScript))
717-
lastResult = ScriptEvaluate(ifScript);
733+
lastResult = ScriptEvaluate(ifScript, ref isReturn);
718734

719735
ifElseStatementsList.Clear();
720736
}
721737
}
722738

723739
int i = 0;
724740

725-
while(i < script.Length)
741+
while(!isReturn && i < script.Length)
726742
{
727743
Match blockKeywordsBeginingMatch;
728744
Match elseBlockKeywordsBeginingMatch = null;
@@ -813,16 +829,16 @@ void ExecuteIfList()
813829
}
814830
else if (keyword.Equals("while"))
815831
{
816-
while ((bool)AssignationOrExpressionEval(keywordAttributes[0]))
817-
lastResult = ScriptEvaluate(subScript);
832+
while (!isReturn && (bool)AssignationOrExpressionEval(keywordAttributes[0]))
833+
lastResult = ScriptEvaluate(subScript, ref isReturn);
818834
}
819835
else if (keyword.Equals("for"))
820836
{
821837
void forAction(int index)
822838
{ if (keywordAttributes.Count > index && !keywordAttributes[index].Trim().Equals(string.Empty)) AssignationOrExpressionEval(keywordAttributes[index]); }
823839

824-
for (forAction(0); (bool)AssignationOrExpressionEval(keywordAttributes[1]); forAction(2))
825-
lastResult = ScriptEvaluate(subScript);
840+
for (forAction(0); !isReturn && (bool)AssignationOrExpressionEval(keywordAttributes[1]); forAction(2))
841+
lastResult = ScriptEvaluate(subScript, ref isReturn);
826842
}
827843
}
828844

@@ -848,10 +864,12 @@ void forAction(int index)
848864
}
849865
}
850866

867+
if (!script.Substring(startOfExpression).Trim().Equals(string.Empty) && !isReturn)
868+
throw new ExpressionEvaluatorSyntaxErrorException("A [;] character is missing.");
869+
851870
ExecuteIfList();
852871

853-
if (!script.Substring(startOfExpression).Trim().Equals(string.Empty))
854-
lastResult = ScriptExpressionEvaluate(ref i);
872+
valueReturned = isReturn;
855873

856874
return lastResult;
857875
}
@@ -1700,7 +1718,7 @@ private bool GetLambdaExpression(string expr, Stack<object> stack)
17001718
.Cast<Match>().ToList()
17011719
.ConvertAll(argMatch => argMatch.Value);
17021720

1703-
stack.Push(new lambdaExpressionDelegate(delegate (object[] args)
1721+
stack.Push(new lambdaExpressionDelegate((object[] args) =>
17041722
{
17051723
Dictionary<string, object> vars = new Dictionary<string, object>(Variables);
17061724

0 commit comments

Comments
 (0)