public override void GenerateCode(CodeGeneration.CodeGenerator cg) { var arrayinfo = TypeInfo.ArrayFromTypeInfo(Scope.ResolveType(TypeNode.TypeName)); //to get the length LocalBuilder length = cg.IlGenerator.DeclareLocal(typeof(int)); LocalBuilder count = cg.IlGenerator.DeclareLocal(typeof(int)); LocalBuilder arr = cg.IlGenerator.DeclareLocal(arrayinfo.GetILType()); Label initloopbegin = cg.IlGenerator.DefineLabel(); Label initloopend = cg.IlGenerator.DefineLabel(); //set the count to zero cg.IlGenerator.Emit(OpCodes.Ldc_I4_0); cg.IlGenerator.Emit(OpCodes.Stloc, count); LengthExpression.GenerateCode(cg); cg.IlGenerator.Emit(OpCodes.Dup); //get the length cg.IlGenerator.Emit(OpCodes.Stloc, length); cg.IlGenerator.Emit(OpCodes.Newarr, arrayinfo.TargetType.GetILType()); cg.IlGenerator.Emit(OpCodes.Stloc, arr); //make the initialization loop cg.IlGenerator.MarkLabel(initloopbegin); //make the comparison and jmp to end if does not hold cg.IlGenerator.Emit(OpCodes.Ldloc, count); cg.IlGenerator.Emit(OpCodes.Ldloc, length); cg.IlGenerator.Emit(OpCodes.Bge, initloopend); //Evaluate the expr and store it cg.IlGenerator.Emit(OpCodes.Ldloc, arr); cg.IlGenerator.Emit(OpCodes.Ldloc, count); InitExpression.GenerateCode(cg); cg.IlGenerator.Emit(OpCodes.Stelem, arrayinfo.TargetType.GetILType()); //increase count and jmp to begin cg.IlGenerator.Emit(OpCodes.Ldloc, count); cg.IlGenerator.Emit(OpCodes.Ldc_I4_1); cg.IlGenerator.Emit(OpCodes.Add); cg.IlGenerator.Emit(OpCodes.Stloc, count); cg.IlGenerator.Emit(OpCodes.Br, initloopbegin); cg.IlGenerator.MarkLabel(initloopend); //leave the arr reference in the top of the stack cg.IlGenerator.Emit(OpCodes.Ldloc, arr); }
public bool TryParse <T>(string source, ref int index, [NotNullWhen(true)] out JsonPathExpression?expression, [NotNullWhen(false)] out string?errorMessage) { PathExpression <T> node; var isLocal = source[index] == '@'; if (!JsonPathParser.TryParse(source, ref index, out var path, out errorMessage) && // Swallow this error from the path parser and assume the path just ended. // If it's really a syntax error, the expression parser should catch it. errorMessage != "Unrecognized JSON Path element.") { expression = null !; return(false); } var lastOp = path !.Operators.Last(); if (lastOp is NameOperator name) { path.Operators.Remove(name); if (name.Name == "indexOf") { if (source[index] != '(') { errorMessage = "Expected '('. 'indexOf' operator requires a parameter."; expression = null !; return(false); } index++; if (!JsonParser.TryParse(source, ref index, out var parameter, out errorMessage, true) && // Swallow this error from the JSON parser and assume the value just ended. // If it's really a syntax error, the expression parser should catch it. errorMessage != "Expected \',\', \']\', or \'}\'.") { errorMessage = $"Error parsing parameter for 'indexOf' expression: {errorMessage}."; expression = null !; return(false); } if (source[index] != ')') { errorMessage = "Expected ')'."; expression = null !; return(false); } index++; node = new IndexOfExpression <T>(path, isLocal, parameter !); } else { node = new NameExpression <T>(path, isLocal, name.Name); } } else if (lastOp is LengthOperator length) { path.Operators.Remove(length); node = new LengthExpression <T>(path, isLocal); } else if (lastOp is ArrayOperator array) { path.Operators.Remove(array); var query = array.Query as SliceQuery; var constant = query?.Slices.FirstOrDefault <Slice?>()?.Index; if (query == null || query.Slices.Count() != 1 || !constant.HasValue) { errorMessage = "JSON Path expression indexers only support single constant values."; expression = null !; return(false); } node = new ArrayIndexExpression <T>(path, isLocal, constant.Value); } else { throw new NotImplementedException(); } expression = new PathValueExpression <T>(node); return(true); }
public string TryParse <T>(string source, ref int index, out JsonPathExpression expression) { expression = null; PathExpression <T> node; var isLocal = source[index] == '@'; var error = JsonPathParser.Parse(source, ref index, out JsonPath path); // Swallow this error from the path parser and assume the path just ended. // If it's really a syntax error, the expression parser should catch it. if (error != null && error != "Unrecognized JSON Path element.") { return(error); } var lastOp = path.Operators.Last(); if (lastOp is NameOperator name) { path.Operators.Remove(name); if (name.Name == "indexOf") { if (source[index] != '(') { return("Expected '('. 'indexOf' operator requires a parameter."); } index++; error = JsonParser.Parse(source, ref index, out JsonValue parameter, true); // Swallow this error from the JSON parser and assume the value just ended. // If it's really a syntax error, the expression parser should catch it. if (error != null && error != "Expected \',\', \']\', or \'}\'.") { return($"Error parsing parameter for 'indexOf' expression: {error}."); } if (source[index] != ')') { return("Expected ')'."); } index++; node = new IndexOfExpression <T> { Path = path, IsLocal = isLocal, Parameter = parameter }; } else { node = new NameExpression <T> { Path = path, IsLocal = isLocal, Name = name.Name } }; } else if (lastOp is LengthOperator length) { path.Operators.Remove(length); node = new LengthExpression <T> { Path = path, IsLocal = isLocal }; } else if (lastOp is ArrayOperator array) { path.Operators.Remove(array); var query = array.Query as SliceQuery; var constant = query?.Slices.FirstOrDefault()?.Index; if (query == null || query.Slices.Count() != 1 || !constant.HasValue) { return("JSON Path expression indexers only support single constant values."); } node = new ArrayIndexExpression <T> { Path = path, IsLocal = isLocal, Index = constant.Value }; } else { throw new NotImplementedException(); } expression = new PathValueExpression <T> { Path = node }; return(null); }