rj-action-library/Runtime/Text/JSON/JSONParser.cs

227 lines
5.2 KiB
C#

using System.Collections;
using System.Collections.Generic;
using System.Text;
using Godot;
namespace Rokojori
{
using LexerType = JSONLexerEventType;
public class JSONParser
{
List<JSONData> stack = new List<JSONData>();
JSONArray currentArray = null;
JSONObject currentObject = null;
JSONData current = null;
bool currentIsArray = false;
JSONData root = null;
string identifier = null;
string source = null;
bool hasError = false;
JSONObject errorReport = null;
void Reset()
{
stack = new List<JSONData>();
currentArray = null;
currentObject = null;
current = null;
currentIsArray = false;
root = null;
identifier = null;
source = null;
}
void ProcessJSONData( JSONData jsonData )
{
if ( current == null )
{
root = jsonData;
}
else if ( currentIsArray )
{
currentArray.Push( jsonData );
}
else
{
currentObject.Set( identifier, jsonData );
}
}
public static bool SHOW_DEBUG_INFO = false;
void OnParse( LexerType type, int offset, int length )
{
if ( hasError ) { return; }
if ( SHOW_DEBUG_INFO )
{
RJLog.Log(type, offset, length );
if ( offset < source.Length && length > 0 && ( offset + length ) < source.Length )
{
RJLog.Log("'" + source.Substring( offset, length ) + "'" );
}
}
switch ( type )
{
case LexerType.NUMBER:
{
var stringValue = source.Substring( offset, length );
//double numberValue = 0;
double numberValue = RegexUtility.ParseDouble( stringValue );
//System.Double.TryParse( stringValue, out numberValue );
ProcessJSONData( new JSONValue( numberValue ) );
}
break;
case LexerType.STRING:
{
var stringValue = new StringBuilder();
JSONStringConverter.Read( stringValue, source, offset, length );
ProcessJSONData( new JSONValue( stringValue.ToString() ) );
}
break;
case LexerType.IDENTIFIER:
{
var stringValue = new StringBuilder();
JSONStringConverter.Read( stringValue, source, offset, length );
identifier = stringValue.ToString();
}
break;
case LexerType.NULL:
case LexerType.TRUE:
case LexerType.FALSE:
{
JSONData jsonData = new JSONValue();
if ( LexerType.NULL != type )
{ jsonData = new JSONValue( LexerType.TRUE == type ); }
ProcessJSONData( jsonData );
}
break;
case LexerType.ARRAY_START:
case LexerType.OBJECT_START:
{
var isArrayStart = LexerType.ARRAY_START == type;
JSONData jsonData = null;
if ( isArrayStart ){ jsonData = new JSONArray(); }
else { jsonData = new JSONObject(); }
ProcessJSONData( jsonData );
current = jsonData;
if ( isArrayStart )
{
currentArray = (JSONArray) jsonData;
currentObject = null;
}
else
{
currentObject = (JSONObject) jsonData;
currentArray = null;
}
stack.Add( current );
currentIsArray = isArrayStart;
}
break;
case LexerType.ARRAY_END:
case LexerType.OBJECT_END:
{
Lists.Pop( stack );
current = Lists.Last( stack );
if ( current is JSONArray )
{
currentArray = (JSONArray) current;
currentObject = null;
currentIsArray = true;
}
else if ( current is JSONObject )
{
currentArray = null;
currentObject = (JSONObject) current;
currentIsArray = false;
}
}
break;
case LexerType.ARRAY_SEPERATOR:
case LexerType.IDENTIFIER_SEPERATOR:
{
}
break;
case LexerType.DONE_SUCCESS:
{
}
break;
// ERRORS:
default:
{
hasError = true;
CreateErrorReport( type, offset, length );
}
break;
}
}
void CreateErrorReport( LexerType type, int offset, int length )
{
var linesMapper = new TextLinesMapper();
linesMapper.Map( source );
errorReport = new JSONObject();
var end = offset + Mathf.Max( length, 0 );
var linesInfo = linesMapper.GetTextEditorInfo( offset, end );
var snippet = linesMapper.GetTextEditorSnippet( source, offset, end );
errorReport.Set( "errorType", type + "" );
errorReport.Set( "linesInfo", linesInfo );
errorReport.Set( "snippet", snippet );
}
public JSONData Parse( string source )
{
Reset();
this.source = source;
var lexer = new JSONLexer();
lexer.Lex( source, this.OnParse );
if ( hasError )
{
RJLog.Log( errorReport.Stringify() );
return null;
}
return root;
}
}
}