using System.Collections; using System.Collections.Generic; using System.Text; using Godot; namespace Rokojori { using LexerType = JSONLexerEventType; public class JSONParser { List stack = new List(); 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(); 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; } } }