@@ -407,7 +407,7 @@ private enum IfBlockEvaluatedState
407407
408408 #endregion
409409
410- #region Evaluation case sensitivity and options
410+ #region Options
411411
412412 private bool optionCaseSensitiveEvaluationActive = true ;
413413
@@ -542,6 +542,14 @@ public bool OptionNewFunctionEvaluationActive
542542 /// </summary>
543543 public bool OptionScriptEvaluateFunctionActive { get ; set ; } = false ;
544544
545+ /// <summary>
546+ /// If <c>ReturnAutomaticallyLastEvaluatedExpression</c> ScriptEvaluate return automatically the last evaluated expression if no return keyword is met.
547+ /// If <c>ReturnNull</c> return null if no return keyword is met.
548+ /// If <c>ThrowSyntaxException</c> a exception is throw if no return keyword is met.
549+ /// By default : ReturnAutomaticallyLastEvaluatedExpression;
550+ /// </summary>
551+ public OptionOnNoReturnKeywordFoundInScriptAction OptionOnNoReturnKeywordFoundInScriptAction { get ; set ; } = OptionOnNoReturnKeywordFoundInScriptAction . ReturnAutomaticallyLastEvaluatedExpression ;
552+
545553 #endregion
546554
547555 #region Reflection flags
@@ -624,6 +632,19 @@ public ExpressionEvaluator(Dictionary<string, object> variables) : this()
624632
625633 #region Main evaluate methods (Expressions and scripts ==> public)
626634
635+ /// <summary>
636+ /// Evaluate a script (multiple expressions separated by semicolon)
637+ /// Support Assignation with [=] (for simple variable write in the Variables dictionary)
638+ /// support also if, else if, else while and for keywords
639+ /// </summary>
640+ /// <typeparam name="T">The type in which to cast the result of the expression</typeparam>
641+ /// <param name="script">the script to evaluate</param>
642+ /// <returns>The result of the last evaluated expression</returns>
643+ public T ScriptEvaluate < T > ( string script )
644+ {
645+ return ( T ) ScriptEvaluate ( script ) ;
646+ }
647+
627648 /// <summary>
628649 /// Evaluate a script (multiple expressions separated by semicolon)
629650 /// Support Assignation with [=] (for simple variable write in the Variables dictionary)
@@ -634,14 +655,25 @@ public ExpressionEvaluator(Dictionary<string, object> variables) : this()
634655 public object ScriptEvaluate ( string script )
635656 {
636657 bool isReturn = false ;
658+ bool isBreak = false ;
659+ bool isContinue = false ;
660+
661+ object result = ScriptEvaluate ( script , ref isReturn , ref isBreak , ref isContinue ) ;
637662
638- return ScriptEvaluate ( script , ref isReturn ) ;
663+ if ( isBreak )
664+ throw new ExpressionEvaluatorSyntaxErrorException ( "[break] keyword executed outside a loop" ) ;
665+ else if ( isContinue )
666+ throw new ExpressionEvaluatorSyntaxErrorException ( "[continue] keyword executed outside a loop" ) ;
667+ else
668+ return result ;
639669 }
640670
641- private object ScriptEvaluate ( string script , ref bool valueReturned )
671+ private object ScriptEvaluate ( string script , ref bool valueReturned , ref bool breakCalled , ref bool continueCalled )
642672 {
643673 object lastResult = null ;
644674 bool isReturn = valueReturned ;
675+ bool isBreak = breakCalled ;
676+ bool isContinue = continueCalled ;
645677 int startOfExpression = 0 ;
646678 IfBlockEvaluatedState ifBlockEvaluatedState = IfBlockEvaluatedState . NoBlockEvaluated ;
647679 List < List < string > > ifElseStatementsList = new List < List < string > > ( ) ;
@@ -655,8 +687,25 @@ object AssignationOrExpressionEval(string expression)
655687
656688 expression = expression . Trim ( ) ;
657689
690+ string expressionToTest = OptionCaseSensitiveEvaluationActive ? expression : expression . ToLower ( ) ;
691+
692+ if ( expressionToTest . Equals ( "break" ) )
693+ {
694+ isBreak = true ;
695+ return lastResult ;
696+ }
697+
698+ if ( expressionToTest . Equals ( "continue" ) )
699+ {
700+ isContinue = true ;
701+ return lastResult ;
702+ }
703+
658704 expression = returnKeywordRegex . Replace ( expression , match =>
659705 {
706+ if ( OptionCaseSensitiveEvaluationActive && ! match . Value . StartsWith ( "return" ) )
707+ return match . Value ;
708+
660709 isReturn = true ;
661710 return match . Value . Contains ( "(" ) ? "(" : string . Empty ;
662711 } ) ;
@@ -730,15 +779,15 @@ void ExecuteIfList()
730779 string ifScript = ifElseStatementsList . Find ( statement => ( bool ) AssignationOrExpressionEval ( statement [ 0 ] ) ) ? [ 1 ] ;
731780
732781 if ( ! string . IsNullOrEmpty ( ifScript ) )
733- lastResult = ScriptEvaluate ( ifScript , ref isReturn ) ;
782+ lastResult = ScriptEvaluate ( ifScript , ref isReturn , ref isBreak , ref isContinue ) ;
734783
735784 ifElseStatementsList . Clear ( ) ;
736785 }
737786 }
738787
739788 int i = 0 ;
740789
741- while ( ! isReturn && i < script . Length )
790+ while ( ! isReturn && ! isBreak && ! isContinue && i < script . Length )
742791 {
743792 Match blockKeywordsBeginingMatch ;
744793 Match elseBlockKeywordsBeginingMatch = null ;
@@ -830,15 +879,41 @@ void ExecuteIfList()
830879 else if ( keyword . Equals ( "while" ) )
831880 {
832881 while ( ! isReturn && ( bool ) AssignationOrExpressionEval ( keywordAttributes [ 0 ] ) )
833- lastResult = ScriptEvaluate ( subScript , ref isReturn ) ;
882+ {
883+ lastResult = ScriptEvaluate ( subScript , ref isReturn , ref isBreak , ref isContinue ) ;
884+
885+ if ( isBreak )
886+ {
887+ isBreak = false ;
888+ break ;
889+ }
890+ if ( isContinue )
891+ {
892+ isContinue = false ;
893+ continue ;
894+ }
895+ }
834896 }
835897 else if ( keyword . Equals ( "for" ) )
836898 {
837899 void forAction ( int index )
838900 { if ( keywordAttributes . Count > index && ! keywordAttributes [ index ] . Trim ( ) . Equals ( string . Empty ) ) AssignationOrExpressionEval ( keywordAttributes [ index ] ) ; }
839901
840902 for ( forAction ( 0 ) ; ! isReturn && ( bool ) AssignationOrExpressionEval ( keywordAttributes [ 1 ] ) ; forAction ( 2 ) )
841- lastResult = ScriptEvaluate ( subScript , ref isReturn ) ;
903+ {
904+ lastResult = ScriptEvaluate ( subScript , ref isReturn , ref isBreak , ref isContinue ) ;
905+
906+ if ( isBreak )
907+ {
908+ isBreak = false ;
909+ break ;
910+ }
911+ if ( isContinue )
912+ {
913+ isContinue = false ;
914+ continue ;
915+ }
916+ }
842917 }
843918 }
844919
@@ -864,14 +939,21 @@ void forAction(int index)
864939 }
865940 }
866941
867- if ( ! script . Substring ( startOfExpression ) . Trim ( ) . Equals ( string . Empty ) && ! isReturn )
942+ if ( ! script . Substring ( startOfExpression ) . Trim ( ) . Equals ( string . Empty ) && ! isReturn && ! isBreak && ! isContinue )
868943 throw new ExpressionEvaluatorSyntaxErrorException ( "A [;] character is missing." ) ;
869944
870945 ExecuteIfList ( ) ;
871946
872947 valueReturned = isReturn ;
948+ breakCalled = isBreak ;
949+ continueCalled = isContinue ;
873950
874- return lastResult ;
951+ if ( isReturn || OptionOnNoReturnKeywordFoundInScriptAction == OptionOnNoReturnKeywordFoundInScriptAction . ReturnAutomaticallyLastEvaluatedExpression )
952+ return lastResult ;
953+ else if ( OptionOnNoReturnKeywordFoundInScriptAction == OptionOnNoReturnKeywordFoundInScriptAction . ReturnNull )
954+ return null ;
955+ else
956+ throw new ExpressionEvaluatorSyntaxErrorException ( "No [return] keyword found" ) ;
875957 }
876958
877959 /// <summary>
@@ -2250,6 +2332,17 @@ public static string ManageCasing(this string text, bool isCaseSensitive)
22502332
22512333 #endregion
22522334
2335+ #region linked enums
2336+
2337+ public enum OptionOnNoReturnKeywordFoundInScriptAction
2338+ {
2339+ ReturnAutomaticallyLastEvaluatedExpression ,
2340+ ReturnNull ,
2341+ ThrowSyntaxException
2342+ }
2343+
2344+ #endregion
2345+
22532346 #region ExpressionEvaluator linked public classes (specific Exceptions and EventArgs)
22542347
22552348 public class ExpressionEvaluatorSyntaxErrorException : Exception
@@ -2277,7 +2370,7 @@ public ExpressionEvaluatorSecurityException(string message, Exception innerExcep
22772370 public class VariableEvaluationEventArg : EventArgs
22782371 {
22792372 /// <summary>
2280- ///
2373+ /// Constructor of the VariableEvaluationEventArg
22812374 /// </summary>
22822375 /// <param name="name">The name of the variable to Evaluate</param>
22832376 public VariableEvaluationEventArg ( string name , object onInstance = null )
0 commit comments