using System.Collections; using System.Collections.Generic; using System.Text.RegularExpressions; using System.Text; namespace Rokojori { public class LexerEvent { string _type; int _offset; int _length; string _match; public string match => _match; public LexerEvent( string type, int offset, int length ) { Set( type, offset, length ); } public string type { get { return _type; } } public int offset { get { return _offset; } } public int length { get { return _length; } } string _mode = null; public string mode { get { if ( _mode != null ) { return _mode; } var modeDelimiterPosition = type.IndexOf( LexerMatcher.FullTypeDelimiter ); if ( modeDelimiterPosition == -1 ) { _mode = ""; return _mode; } _mode = type.Substring( 0, modeDelimiterPosition ); return _mode; } } public bool isError { get { return this.length == -1; } } public bool isDone { get { return this.length == -2; } } public void Set( string type, int offset, int length ) { this._type = type; this._offset = offset; this._length = length; } public LexerEvent Copy() { return new LexerEvent( _type, _offset, _length ); } public int end { get { return this._offset + _length; } } public override string ToString() { if ( match != null ) { return "Token{ '" + type + "':'" + match + "' (" + offset + "-" + end + ") }"; } return "Token{ '" + type + "' (" + offset + "-" + end + ") }"; } public void GrabMatch( string source ) { if ( _length < 0 ) { return; } _match = source.Substring( offset, length ); } public bool Is( string type, string match = null ) { var typeCorrect = type == null || type == this.type; if ( ! typeCorrect ) { return false; } return match == null || match == this.match; } public bool Is( LexerMatcher matcher, string match = null ) { return Is( matcher == null ? null : matcher.type, match ); } public bool MatchIs( string match ) { return match == this.match; } public bool MatchIsAny( params string[] matches ) { for ( int i = 0; i < matches.Length; i++ ) { if ( MatchIs( matches[ i ] ) ) { return true; } } return false; } public bool IsAnyOf( params LexerMatcher[] matchers ) { for ( int i = 0; i < matchers.Length; i++ ) { if ( Is( matchers[ i ] ) ) { return true; } } return false; } public bool IsAny( LexerMatcher matcher, params string[] matches ) { if ( matches == null || matches.Length == 0 ) { return Is( matcher ); } var correctType = matcher == null || matcher.type == type; if ( ! correctType ) { return false; } return MatchIsAny( matches ); } public enum FindResultType { Found, KeepSearching, NotFound, Error } public class FindResult { public FindResultType type = FindResultType.NotFound; public bool found => FindResultType.Found == type; public int index; public FindResult() { } public FindResult( FindResultType type, int index ) { this.type = type; this.index = index; } } public static FindResult Found( int index) { return new FindResult( FindResultType.Found, index ); } public static FindResult KeepSearch( int index ) { return new FindResult( FindResultType.KeepSearching, index ); } public static FindResult NotFound( int index ) { return new FindResult( FindResultType.NotFound, index ); } public static FindResult Error( int index ) { return new FindResult( FindResultType.NotFound, index ); } public static string GetMatchFromRange( List tokens, int offset, int length = -1 ) { if ( length == -1 ) { length = tokens.Count - offset; } var match = new StringBuilder(); for ( int i = 0; i < length; i++ ) { match.Append( tokens[ offset + i ].match ); } return match.ToString(); } public static int Find( List tokens, int offset, params string[] types ) { for ( int i = offset; i < tokens.Count; i++ ) { if ( Arrays.IndexOf( types, tokens[ i ].type ) != -1 ) { return i; } } return -1; } public static List> FindSequences( List tokens, System.Func matcher ) { var sequences = new List>(); List currentSequence = null; for ( int i = 0; i < tokens.Count; i++ ) { var token = tokens[ i ]; var result = matcher( i, currentSequence != null ); if ( currentSequence != null ) { if ( Trillean.True == result ) { currentSequence.Add( token ); } else if ( Trillean.False == result ) { currentSequence.Add( token ); sequences.Add( currentSequence ); currentSequence = null; } } else { if ( Trillean.True == result ) { currentSequence = new List(); currentSequence.Add( token ); } if ( Trillean.False == result ) { sequences.Add( new List(){ tokens[ i ] } ); sequences.Add( null ); return sequences; } } } return sequences; } public static FindResult ReverseFind( List tokens, int offset, System.Func evaluator ) { return Find( tokens, offset, evaluator, false ); } public static FindResult Find( List tokens, int offset, System.Func evaluator, bool forward = true ) { var result = new FindResult(); var increment = forward ? 1 : -1; var end = forward ? tokens.Count : -1; for ( int i = offset; i != end && i >= 0 && i < tokens.Count; i += increment ) { var tokenResult = evaluator( tokens[ i ] ); if ( tokenResult == FindResultType.Error || tokenResult == FindResultType.Found ) { result.type = tokenResult; result.index = i; return result; } } return result; } public static List GetSeparatorsInBrackets( List tokens, int offset, string seperator = "," ) { var openTypes = new List(){ "(","[","{" }; var closingTypes = new List(){ ")","]","}" }; var stack = new List(); var separators = new List(); for ( int i = offset; i < tokens.Count; i++ ) { if ( stack.Count == 1 && tokens[ i ].MatchIs( seperator ) ) { separators.Add( i ); } var match = tokens[ i ].match; if ( openTypes.Contains( match ) ) { stack.Add( match ); continue; } else if ( closingTypes.Contains( match ) ) { var closingTypeIndex = closingTypes.IndexOf( match ); var expectedOpener = openTypes[ closingTypeIndex ]; if ( stack[ stack.Count - 1 ] != expectedOpener ) { return null; } stack.RemoveAt( stack.Count - 1 ); } } return separators; } static List openTypes = new List(){ "(","[","{" }; static List closingTypes = new List(){ ")","]","}" }; public static FindResult FindClosingBracket( List tokens, int offset ) { var token = tokens[ offset ]; var bracketIndex = openTypes.IndexOf( token.match ); if ( bracketIndex == -1 ) { var result = new FindResult( FindResultType.NotFound, offset ); return result; } var opener = openTypes[ bracketIndex ]; var closer = closingTypes[ bracketIndex ]; var counter = ( LexerEvent le ) => { if ( le.Is( LexerMatcherLibrary.BracketMatcher, closer ) ) { return -1; } if ( le.Is( LexerMatcherLibrary.BracketMatcher, opener ) ) { return 1; } return 0; }; return FindCloser( tokens, offset, counter ); } public static FindResult FindCloser( List tokens, int offset, System.Func counter, bool forward = true ) { var result = new FindResult(); var currentValue = 0; if ( forward ) { for ( int i = offset; i < tokens.Count; i++ ) { var countResult = counter( tokens[ i ] ); currentValue += countResult; if ( currentValue == 0 ) { result.type = FindResultType.Found; result.index = i; return result; } } } else { for ( int i = offset; i >= 0; i-- ) { var countResult = counter( tokens[ i ] ); currentValue += countResult; if ( currentValue == 0 ) { result.type = FindResultType.Found; result.index = i; return result; } } } return result; } public static FindResult FindOpeningBracket( List tokens, int offset, string blockBracket = "{" ) { var result = Find( tokens, offset, ( le ) => { return le.Is( LexerMatcherLibrary.BracketMatcher, blockBracket ) ? FindResultType.Found : FindResultType.KeepSearching; } ); return result; } public static FindResult ReverseFindOpeningBracket( List tokens, int offset ) { var token = tokens[ offset ]; var bracketIndex = closingTypes.IndexOf( token.match ); if ( bracketIndex == -1 ) { var result = new FindResult( FindResultType.NotFound, offset ); return result; } var opener = openTypes[ bracketIndex ]; var closer = closingTypes[ bracketIndex ]; var counter = ( LexerEvent le ) => { if ( le.Is( LexerMatcherLibrary.BracketMatcher, closer ) ) { return 1; } if ( le.Is( LexerMatcherLibrary.BracketMatcher, opener ) ) { return -1; } return 0; }; return FindCloser( tokens, offset, counter, false ); } public static List GetBlocks( List tokens ) { var index = 0; List blocks = new List(); while ( index < tokens.Count ) { var openResult = FindOpeningBracket( tokens, index ); if ( ! openResult.found || openResult.index < index ) { // RJLog.Log( "No OpeningBracket after", index ); if ( index == 0 ) { RJLog.Log( tokens.Map( t => t.type + ": '" + t.match + "'" ).Join( "\n" ) ); } return blocks; } var closeResult = FindClosingBracket( tokens, openResult.index ); if ( ! closeResult.found || closeResult.index <= openResult.index ) { // RJLog.Log( "No ClosingBracket after", index ); return null; } var range = new RangeI( openResult.index, closeResult.index ); blocks.Add( range ); index = closeResult.index + 1; } return blocks; } } }