Skip to content

Commit

Permalink
fix EvilBeaver#1373, EvilBeaver#1404 для v2: чтение JSON
Browse files Browse the repository at this point in the history
  • Loading branch information
Mr-Rm committed May 23, 2024
1 parent a47b0ab commit c6c3205
Show file tree
Hide file tree
Showing 5 changed files with 692 additions and 216 deletions.
227 changes: 125 additions & 102 deletions src/OneScript.StandardLibrary/Json/GlobalJsonFunctions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This Source Code Form is subject to the terms of the
----------------------------------------------------------*/

using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using OneScript.Commons;
using OneScript.Contexts;
Expand Down Expand Up @@ -59,130 +60,143 @@ public static IAttachableContext CreateInstance()
[ContextMethod("ПрочитатьJSON", "ReadJSON")]
public IValue ReadJSON(JSONReader Reader, bool ReadToMap = false, IValue PropertiesWithDateValuesNames = null, IValue ExpectedDateFormat = null, string ReviverFunctionName = null, IValue ReviverFunctionModule = null, IValue ReviverFunctionAdditionalParameters = null, IValue RetriverPropertiesNames = null, int MaximumNesting = 500)
{
if (ReadToMap)
return ReadJSONInMap(Reader);
else
return ReadJSONInStruct(Reader);
var jsonReader = new JsonReaderInternal(Reader);
return ReadToMap ? jsonReader.Read<MapImpl>() : jsonReader.Read<StructureImpl>();
}

public IValue ReadJSONInStruct(JSONReader Reader, bool nestedArray = false)
internal class JsonReaderInternal
{
if (nestedArray)
{
ArrayImpl NestedArray = new ArrayImpl();
private readonly JSONReader _reader;
private Func<IValue> _builder;
private Action<IValue, string, IValue> _inserter;

while (Reader.Read())
private void Init<TStructure>()
{
if (typeof(TStructure) == typeof(StructureImpl))
{
if (Reader.CurrentJsonTokenType == JsonToken.EndArray)
{
break;
}
else if (Reader.CurrentJsonTokenType == JsonToken.StartObject)
{
NestedArray.Add(ReadJSONInStruct(Reader));
}
else if (Reader.CurrentJsonTokenType == JsonToken.StartArray)
{
NestedArray.Add(ReadJSONInStruct(Reader, true));
}
else
NestedArray.Add(Reader.CurrentValue);
_builder = () => new StructureImpl();
_inserter = (o, s, v) => ((StructureImpl)o).Insert(s, v);
}
else if (typeof(TStructure) == typeof(MapImpl))
{
_builder = () => new MapImpl();
_inserter = (o, s, v) =>((MapImpl)o).Insert(ValueFactory.Create(s), v);
}
return NestedArray;
else
{
throw new InvalidOperationException();
}
}

public JsonReaderInternal(JSONReader reader)
{
_reader = reader;
}

StructureImpl ResStruct = new StructureImpl();
private IValue Create() => _builder();

while ((Reader).Read())
private void AddProperty(IValue obj, string str, IValue val) => _inserter(obj, str, val);

public IValue Read<T>() where T: IEnumerable<KeyAndValueImpl>
{
if (Reader.CurrentJsonTokenType == JsonToken.PropertyName)
System.Diagnostics.Debug.Assert(typeof(T)==typeof(StructureImpl)||typeof(T)==typeof(MapImpl));
Init<T>();

try
{
string PropertyName = Reader.CurrentValue.AsString();
Reader.Read();

if (Reader.CurrentJsonTokenType == JsonToken.StartObject)
{
ResStruct.Insert(PropertyName, ReadJSONInStruct(Reader));
}
else if (Reader.CurrentJsonTokenType == JsonToken.StartArray)
{
ResStruct.Insert(PropertyName, ReadJSONInStruct(Reader, true));
}
else
{
ResStruct.Insert(PropertyName, Reader.CurrentValue);
}
if (ReadJsonValue(out var value))
return value;
}
else if (Reader.CurrentJsonTokenType == JsonToken.EndObject)
catch (JSONReaderException)
{
break;
throw;
}
else if (Reader.CurrentJsonTokenType == JsonToken.StartArray)
catch (Exception exc)
{
return ReadJSONInStruct(Reader, true);
throw InvalidJsonException(exc.Message);
}
}
return ResStruct;
}

public IValue ReadJSONInMap(JSONReader Reader, bool nestedArray = false)
{
throw InvalidJsonException();
}

if (nestedArray)
private JsonToken ReadJsonToken()
{
ArrayImpl NestedArray = new ArrayImpl();
while (_reader.Read())
{
var tok = _reader.CurrentJsonTokenType;
if (tok != JsonToken.Comment)
return tok;
}

while (Reader.Read())
return JsonToken.None;
}

private bool ReadJsonValue(out IValue value)
{
switch (ReadJsonToken())
{
if (Reader.CurrentJsonTokenType == JsonToken.EndArray)
{
case JsonToken.StartObject:
var jsonObject = Create();

while (ReadJsonToken() == JsonToken.PropertyName)
{
var propertyName = _reader.CurrentValue.AsString();
if (!ReadJsonValue(out value))
return false;

AddProperty(jsonObject, propertyName, value);
}

if (_reader.CurrentJsonTokenType == JsonToken.EndObject)
{
value = jsonObject;
return true;
}
break;
}
else if (Reader.CurrentJsonTokenType == JsonToken.StartObject)
{
NestedArray.Add(ReadJSONInMap(Reader));
}
else if (Reader.CurrentJsonTokenType == JsonToken.StartArray)
{
NestedArray.Add(ReadJSONInMap(Reader, true));
}
else
NestedArray.Add(Reader.CurrentValue);

case JsonToken.StartArray:
var resArray = new ArrayImpl();

while (ReadJsonValue(out value))
{
resArray.Add(value);
}

if (_reader.CurrentJsonTokenType == JsonToken.EndArray)
{
value = resArray;
return true;
}
break;

case JsonToken.EndArray:
case JsonToken.EndObject:
case JsonToken.None:
break;

default:
value = _reader.CurrentValue;
return true;
}
return NestedArray;

value = null;
return false;
}

MapImpl ResStruct = new MapImpl();
while ((Reader).Read())
private RuntimeException InvalidJsonException(string message=null)
{
if (Reader.CurrentJsonTokenType == JsonToken.PropertyName)
{
string PropertyName = Reader.CurrentValue.AsString();
Reader.Read();

if (Reader.CurrentJsonTokenType == JsonToken.StartObject)
{
ResStruct.Insert(ValueFactory.Create(PropertyName), ReadJSONInMap(Reader));
}
else if (Reader.CurrentJsonTokenType == JsonToken.StartArray)
{
ResStruct.Insert(ValueFactory.Create(PropertyName), ReadJSONInMap(Reader, true));
}
else
{
ResStruct.Insert(ValueFactory.Create(PropertyName), Reader.CurrentValue);
}
}
else if (Reader.CurrentJsonTokenType == JsonToken.EndObject)
{
break;
}
else if (Reader.CurrentJsonTokenType == JsonToken.StartArray)
{
return ReadJSONInMap(Reader, true);
}
var addition = string.IsNullOrWhiteSpace(message) ? string.Empty : $"\n({message})";
return new RuntimeException(string.Format(Locale.NStr
("ru='Недопустимое состояние потока чтения JSON в строке {0} позиции {1}{2}'"
+ "en='Invalid JSON reader state at line {0} position {1}{2}'"),
_reader.CurrentLine, _reader.CurrentPosition, addition));
}
return ResStruct;
}

public IValue ReadJSONInMap(JSONReader reader)
{
var jsonReader = new JsonReaderInternal(reader);
return jsonReader.Read<MapImpl>();
}

/// <summary>
Expand Down Expand Up @@ -214,17 +228,26 @@ public IValue ReadJSONDate(string String, JSONDateFormatEnum? format)
break;
case JSONDateFormatEnum.JavaScript:
default:
throw new RuntimeException(Locale.NStr("ru='Формат даты JavaScript не поддерживается.'; en='JavaScript date format is not supported'"));
throw new RuntimeException(Locale.NStr(
"ru='Формат даты JavaScript не поддерживается.'; en='JavaScript date format is not supported'"));
}

string json = @"{""Date"":""" + String + @"""}";
string json = @"{""Date"":""" + String + @"""}";

var settings = new JsonSerializerSettings
{
DateFormatHandling = dateFormatHandling
};
var result = JsonConvert.DeserializeObject<ConvertedDate>(json, settings);
return ValueFactory.Create((DateTime)result.Date);
};

try
{
var result = JsonConvert.DeserializeObject<ConvertedDate>(json, settings);
return ValueFactory.Create((DateTime)result.Date);
}
catch (JsonException)
{
throw new RuntimeException(Locale.NStr("ru='Представление даты имеет неверный формат.'; en='Invalid date presentation format'"));
}
}

/// <summary>
Expand Down
Loading

0 comments on commit c6c3205

Please sign in to comment.