531 lines
12 KiB
C#
531 lines
12 KiB
C#
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<LexerEvent> 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<LexerEvent> 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<List<LexerEvent>> FindSequences( List<LexerEvent> tokens, System.Func<int,bool,Trillean> matcher )
|
|
{
|
|
var sequences = new List<List<LexerEvent>>();
|
|
|
|
List<LexerEvent> 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<LexerEvent>();
|
|
currentSequence.Add( token );
|
|
}
|
|
|
|
if ( Trillean.False == result )
|
|
{
|
|
sequences.Add( new List<LexerEvent>(){ tokens[ i ] } );
|
|
sequences.Add( null );
|
|
return sequences;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sequences;
|
|
}
|
|
|
|
public static FindResult ReverseFind( List<LexerEvent> tokens, int offset, System.Func<LexerEvent,FindResultType> evaluator )
|
|
{
|
|
return Find( tokens, offset, evaluator, false );
|
|
}
|
|
|
|
public static FindResult Find( List<LexerEvent> tokens, int offset, System.Func<LexerEvent,FindResultType> 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<int> GetSeparatorsInBrackets( List<LexerEvent> tokens, int offset, string seperator = "," )
|
|
{
|
|
var openTypes = new List<string>(){ "(","[","{" };
|
|
var closingTypes = new List<string>(){ ")","]","}" };
|
|
|
|
var stack = new List<string>();
|
|
var separators = new List<int>();
|
|
|
|
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<string> openTypes = new List<string>(){ "(","[","{" };
|
|
static List<string> closingTypes = new List<string>(){ ")","]","}" };
|
|
|
|
public static FindResult FindClosingBracket( List<LexerEvent> 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<LexerEvent> tokens, int offset, System.Func<LexerEvent,int> 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<LexerEvent> 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<LexerEvent> 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<RangeI> GetBlocks( List<LexerEvent> tokens )
|
|
{
|
|
var index = 0;
|
|
List<RangeI> blocks = new List<RangeI>();
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
}
|
|
} |