@@ -614,19 +614,16 @@ protected int ReadCallArguments(string expr, int start, string endLexem, List<Ex
614614 return lexem . End ;
615615 } else if ( lexem . GetValue ( ) == "," ) {
616616 if ( args . Count == 0 ) {
617- throw new LambdaParserException ( expr , lexem . Start , "Expected method call parameter " ) ;
617+ throw new LambdaParserException ( expr , lexem . Start , "Value missed " ) ;
618618 }
619619 end = lexem . End ;
620+ } else {
621+ throw new LambdaParserException ( expr , lexem . Start , String . Format ( "Expected '{0}' or ','" , endLexem ) ) ;
620622 }
621623 }
622624 // read parameter
623625 var paramExpr = ParseConditional ( expr , end , vars ) ;
624- var argExpr = paramExpr . Expr ;
625- if ( ! ( argExpr is ConstantExpression constExpr && constExpr . Value is LambdaParameterWrapper ) ) {
626- // result may be a primitive type like bool
627- argExpr = Expression . Convert ( argExpr , typeof ( object ) ) ;
628- }
629- args . Add ( argExpr ) ;
626+ args . Add ( ExprConvertToObjectIfNeeded ( paramExpr . Expr ) ) ;
630627 end = paramExpr . End ;
631628 } while ( true ) ;
632629 }
@@ -644,23 +641,25 @@ protected ParseResult ParseValue(string expr, int start, Variables vars) {
644641 } else if ( lexem . Type == LexemType . NumberConstant ) {
645642 decimal numConst ;
646643 if ( ! Decimal . TryParse ( lexem . GetValue ( ) , NumberStyles . Any , CultureInfo . InvariantCulture , out numConst ) ) {
647- throw new Exception ( String . Format ( "Invalid number: {0}" , lexem . GetValue ( ) ) ) ;
644+ throw new Exception ( String . Format ( "Invalid number: {0}" , lexem . GetValue ( ) ) ) ;
648645 }
649- return new ParseResult ( ) {
650- End = lexem . End ,
651- Expr = Expression . Constant ( new LambdaParameterWrapper ( numConst , LambdaParamCtx ) ) } ;
646+ return new ParseResult ( ) {
647+ End = lexem . End ,
648+ Expr = Expression . Constant ( new LambdaParameterWrapper ( numConst , LambdaParamCtx ) )
649+ } ;
652650 } else if ( lexem . Type == LexemType . StringConstant ) {
653- return new ParseResult ( ) {
654- End = lexem . End ,
655- Expr = Expression . Constant ( new LambdaParameterWrapper ( lexem . GetValue ( ) , LambdaParamCtx ) ) } ;
651+ return new ParseResult ( ) {
652+ End = lexem . End ,
653+ Expr = Expression . Constant ( new LambdaParameterWrapper ( lexem . GetValue ( ) , LambdaParamCtx ) )
654+ } ;
656655 } else if ( lexem . Type == LexemType . Name ) {
657656 // check for predefined constants
658657 var val = lexem . GetValue ( ) ;
659658 switch ( val ) {
660659 case "true" :
661- return new ParseResult ( ) { End = lexem . End , Expr = Expression . Constant ( new LambdaParameterWrapper ( true , LambdaParamCtx ) ) } ;
660+ return new ParseResult ( ) { End = lexem . End , Expr = Expression . Constant ( new LambdaParameterWrapper ( true , LambdaParamCtx ) ) } ;
662661 case "false" :
663- return new ParseResult ( ) { End = lexem . End , Expr = Expression . Constant ( new LambdaParameterWrapper ( false , LambdaParamCtx ) ) } ;
662+ return new ParseResult ( ) { End = lexem . End , Expr = Expression . Constant ( new LambdaParameterWrapper ( false , LambdaParamCtx ) ) } ;
664663 case "null" :
665664 return new ParseResult ( ) { End = lexem . End , Expr = Expression . Constant ( new LambdaParameterWrapper ( null , LambdaParamCtx ) ) } ;
666665 case "new" :
@@ -669,9 +668,13 @@ protected ParseResult ParseValue(string expr, int start, Variables vars) {
669668
670669 // todo
671670 var localVarExpr = vars . Get ( val ) ;
672- return new ParseResult ( ) {
673- End = lexem . End ,
674- Expr = localVarExpr != null ? localVarExpr : Expression . Parameter ( typeof ( LambdaParameterWrapper ) , val ) } ;
671+ return new ParseResult ( ) {
672+ End = lexem . End ,
673+ Expr = localVarExpr != null ? localVarExpr : Expression . Parameter ( typeof ( LambdaParameterWrapper ) , val )
674+ } ;
675+ } else if ( lexem . Type == LexemType . Delimiter && ( lexem . GetValue ( ) == "[" || lexem . GetValue ( ) == "{" ) ) {
676+ // json-like array or object (dictionary) syntax
677+ return ReadNewInstance ( expr , lexem . Start , vars ) ;
675678 }
676679 throw new LambdaParserException ( expr , start , "Expected value" ) ;
677680 }
@@ -680,51 +683,84 @@ protected ParseResult ReadNewInstance(string expr, int start, Variables vars) {
680683 var nextLexem = ReadLexem ( expr , start ) ;
681684 if ( nextLexem . Type == LexemType . Delimiter && nextLexem . GetValue ( ) == "[" ) {
682685 nextLexem = ReadLexem ( expr , nextLexem . End ) ;
683- if ( ! ( nextLexem . Type == LexemType . Delimiter && nextLexem . GetValue ( ) == "]" ) )
684- throw new LambdaParserException ( expr , nextLexem . Start , "Expected ']'" ) ;
685-
686- nextLexem = ReadLexem ( expr , nextLexem . End ) ;
687- if ( ! ( nextLexem . Type == LexemType . Delimiter && nextLexem . GetValue ( ) == "{" ) )
688- throw new LambdaParserException ( expr , nextLexem . Start , "Expected '{'" ) ;
689-
690686 var arrayArgs = new List < Expression > ( ) ;
691- var end = ReadCallArguments ( expr , nextLexem . End , "}" , arrayArgs , vars ) ;
692- var newArrExpr = Expression . NewArrayInit ( typeof ( object ) , arrayArgs ) ;
693- return new ParseResult ( ) {
687+ int end ;
688+ if ( nextLexem . Type == LexemType . Delimiter && nextLexem . GetValue ( ) == "]" ) {
689+ nextLexem = ReadLexem ( expr , nextLexem . End ) ;
690+ if ( nextLexem . Type == LexemType . Delimiter && nextLexem . GetValue ( ) == "{" )
691+ // this is 'new [] { val1, val2 }'
692+ end = ReadCallArguments ( expr , nextLexem . End , "}" , arrayArgs , vars ) ;
693+ else {
694+ // just [] (empty array)
695+ end = nextLexem . Start ;
696+ }
697+ } else {
698+ // this is '[ val1, val2 ]' syntax
699+ end = ReadCallArguments ( expr , nextLexem . Start , "]" , arrayArgs , vars ) ;
700+ }
701+
702+ var newArrExpr = Expression . NewArrayInit ( typeof ( object ) , arrayArgs ) ;
703+ return new ParseResult ( ) {
694704 End = end ,
695- Expr = Expression . New ( LambdaParameterWrapperConstructor ,
705+ Expr = Expression . New ( LambdaParameterWrapperConstructor ,
696706 Expression . Convert ( newArrExpr , typeof ( object ) ) ,
697707 Expression . Constant ( LambdaParamCtx , typeof ( LambdaParameterWrapperContext ) ) )
698708 } ;
699709 }
700710 if ( nextLexem . Type == LexemType . Name && nextLexem . GetValue ( ) . ToLower ( ) == "dictionary" ) {
711+ // just read it, this is old syntax 'new dictionary { }'
701712 nextLexem = ReadLexem ( expr , nextLexem . End ) ;
702- if ( ! ( nextLexem . Type == LexemType . Delimiter && nextLexem . GetValue ( ) == "{" ) )
703- throw new LambdaParserException ( expr , nextLexem . Start , "Expected '{'" ) ;
704-
713+ }
714+ if ( nextLexem . Type == LexemType . Delimiter && nextLexem . GetValue ( ) == "{" ) {
705715 var dictionaryKeys = new List < Expression > ( ) ;
706716 var dictionaryValues = new List < Expression > ( ) ;
707- do {
708- nextLexem = ReadLexem ( expr , nextLexem . End ) ;
709- if ( ! ( nextLexem . Type == LexemType . Delimiter && nextLexem . GetValue ( ) == "{" ) )
710- throw new LambdaParserException ( expr , nextLexem . Start , "Expected '{'" ) ;
711- var entryArgs = new List < Expression > ( ) ;
712- var end = ReadCallArguments ( expr , nextLexem . End , "}" , entryArgs , vars ) ;
713- if ( entryArgs . Count != 2 )
714- throw new LambdaParserException ( expr , nextLexem . Start , "Dictionary entry should have exactly 2 arguments" ) ;
715-
716- dictionaryKeys . Add ( entryArgs [ 0 ] ) ;
717- dictionaryValues . Add ( entryArgs [ 1 ] ) ;
718-
719- nextLexem = ReadLexem ( expr , end ) ;
720- } while ( nextLexem . Type == LexemType . Delimiter && nextLexem . GetValue ( ) == "," ) ;
721-
722- if ( ! ( nextLexem . Type == LexemType . Delimiter && nextLexem . GetValue ( ) == "}" ) )
723- throw new LambdaParserException ( expr , nextLexem . Start , "Expected '}'" ) ;
724-
725- var newKeysArrExpr = Expression . NewArrayInit ( typeof ( object ) , dictionaryKeys ) ;
726- var newValuesArrExpr = Expression . NewArrayInit ( typeof ( object ) , dictionaryValues ) ;
717+ var startLexem = ReadLexem ( expr , nextLexem . End ) ;
718+ if ( startLexem . Type == LexemType . Delimiter && startLexem . GetValue ( ) == "{" ) {
719+ // this is C#-like syntax: '{ {"key1", "val1"}, {"key2", "val2"} }
720+ do {
721+ nextLexem = ReadLexem ( expr , nextLexem . End ) ;
722+ if ( ! ( nextLexem . Type == LexemType . Delimiter && nextLexem . GetValue ( ) == "{" ) )
723+ throw new LambdaParserException ( expr , nextLexem . Start , "Expected '{'" ) ;
724+ var entryArgs = new List < Expression > ( ) ;
725+ var end = ReadCallArguments ( expr , nextLexem . End , "}" , entryArgs , vars ) ;
726+ if ( entryArgs . Count != 2 )
727+ throw new LambdaParserException ( expr , nextLexem . Start , "Dictionary entry should have exactly 2 arguments" ) ;
728+
729+ dictionaryKeys . Add ( entryArgs [ 0 ] ) ;
730+ dictionaryValues . Add ( entryArgs [ 1 ] ) ;
731+
732+ nextLexem = ReadLexem ( expr , end ) ;
733+ } while ( nextLexem . Type == LexemType . Delimiter && nextLexem . GetValue ( ) == "," ) ;
734+
735+ if ( ! ( nextLexem . Type == LexemType . Delimiter && nextLexem . GetValue ( ) == "}" ) )
736+ throw new LambdaParserException ( expr , nextLexem . Start , "Expected '}'" ) ;
737+ } else if ( startLexem . Type == LexemType . Delimiter && startLexem . GetValue ( ) == "}" ) {
738+ // this is '{}' - empty object (dictionary)
739+ nextLexem = startLexem ;
740+ } else {
741+ // this is JSON-like syntax: { 'key1' : 'val1', 'key2': 'val2' }
742+ do {
743+ // read key
744+ var keyExpr = ParseConditional ( expr , nextLexem . End , vars ) ;
745+ dictionaryKeys . Add ( ExprConvertToObjectIfNeeded ( keyExpr . Expr ) ) ;
746+
747+ nextLexem = ReadLexem ( expr , keyExpr . End ) ;
748+ if ( ! ( nextLexem . Type == LexemType . Delimiter && nextLexem . GetValue ( ) == ":" ) )
749+ throw new LambdaParserException ( expr , nextLexem . Start , "Expected ':'" ) ;
750+
751+ // read value
752+ var valExpr = ParseConditional ( expr , nextLexem . End , vars ) ;
753+ dictionaryValues . Add ( ExprConvertToObjectIfNeeded ( valExpr . Expr ) ) ;
754+
755+ nextLexem = ReadLexem ( expr , valExpr . End ) ;
756+ if ( nextLexem . Type == LexemType . Delimiter && ( nextLexem . GetValue ( ) == "}" || nextLexem . GetValue ( ) == "," ) )
757+ continue ;
758+ throw new LambdaParserException ( expr , nextLexem . Start , "Expected ',' or '}'" ) ;
759+ } while ( nextLexem . Type == LexemType . Delimiter && nextLexem . GetValue ( ) == "," ) ;
760+ }
727761
762+ var newKeysArrExpr = Expression . NewArrayInit ( typeof ( object ) , dictionaryKeys ) ;
763+ var newValuesArrExpr = Expression . NewArrayInit ( typeof ( object ) , dictionaryValues ) ;
728764 return new ParseResult ( ) {
729765 End = nextLexem . End ,
730766 Expr = Expression . Call (
@@ -736,6 +772,14 @@ protected ParseResult ReadNewInstance(string expr, int start, Variables vars) {
736772 throw new LambdaParserException ( expr , start , "Unknown new instance initializer" ) ;
737773 }
738774
775+ Expression ExprConvertToObjectIfNeeded ( Expression expr ) {
776+ if ( ! ( expr is ConstantExpression constExpr && constExpr . Value is LambdaParameterWrapper ) ) {
777+ // result may be a primitive type like bool
778+ return Expression . Convert ( expr , typeof ( object ) ) ;
779+ }
780+ return expr ;
781+ }
782+
739783 protected enum LexemType {
740784 Unknown ,
741785 Name ,
0 commit comments