2013-04-11 11:04:16 +00:00
using System.IO ;
2012-07-10 10:20:45 +00:00
using System.Collections.Generic ;
using System.Globalization ;
using CodeImp.DoomBuilder.ZDoom ;
using CodeImp.DoomBuilder.GZBuilder.Data ;
2012-07-12 22:34:12 +00:00
//mxd. ACS parser used to create ScriptItems for use in script editor's navigator
namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
2012-07-10 10:20:45 +00:00
{
2013-09-11 09:47:53 +00:00
internal sealed class AcsParserSE : ZDTextParser
{
internal delegate void IncludeDelegate ( AcsParserSE parser , string includefile ) ;
internal IncludeDelegate OnInclude ;
2014-07-16 09:47:23 +00:00
private readonly List < string > parsedLumps ;
private readonly List < string > includes ;
private readonly List < ScriptItem > namedScripts ;
private readonly List < ScriptItem > numberedScripts ;
private readonly List < ScriptItem > functions ;
2013-09-11 09:47:53 +00:00
internal List < ScriptItem > NamedScripts { get { return namedScripts ; } }
internal List < ScriptItem > NumberedScripts { get { return numberedScripts ; } }
2014-07-16 09:47:23 +00:00
internal List < ScriptItem > Functions { get { return functions ; } }
2013-09-11 09:47:53 +00:00
2014-12-03 23:15:26 +00:00
internal AcsParserSE ( )
{
2013-09-11 09:47:53 +00:00
namedScripts = new List < ScriptItem > ( ) ;
numberedScripts = new List < ScriptItem > ( ) ;
2014-07-16 09:47:23 +00:00
functions = new List < ScriptItem > ( ) ;
2013-09-11 09:47:53 +00:00
parsedLumps = new List < string > ( ) ;
includes = new List < string > ( ) ;
}
2014-12-03 23:15:26 +00:00
internal List < string > Includes
{
2013-09-11 09:47:53 +00:00
get { return includes ; }
}
2014-12-03 23:15:26 +00:00
public override bool Parse ( Stream stream , string sourcefilename )
{
2013-09-11 09:47:53 +00:00
return Parse ( stream , sourcefilename , false , false ) ;
}
2014-12-03 23:15:26 +00:00
public bool Parse ( Stream stream , string sourcefilename , bool processIncludes , bool isinclude )
{
2013-09-11 09:47:53 +00:00
base . Parse ( stream , sourcefilename ) ;
//already parsed this?
if ( parsedLumps . Contains ( sourcefilename ) ) return false ;
parsedLumps . Add ( sourcefilename ) ;
2013-08-05 13:03:08 +00:00
if ( isinclude ) includes . Add ( sourcefilename ) ;
2012-07-23 21:28:23 +00:00
2013-09-11 09:47:53 +00:00
// Keep local data
Stream localstream = datastream ;
string localsourcename = sourcename ;
BinaryReader localreader = datareader ;
2012-07-23 21:28:23 +00:00
2013-09-11 09:47:53 +00:00
// Continue until at the end of the stream
2014-12-03 23:15:26 +00:00
while ( SkipWhitespace ( true ) )
{
2013-09-11 09:47:53 +00:00
string token = ReadToken ( ) ;
2012-07-10 10:20:45 +00:00
2014-12-03 23:15:26 +00:00
if ( ! string . IsNullOrEmpty ( token ) )
{
2013-09-11 09:47:53 +00:00
token = token . ToLowerInvariant ( ) ;
2012-07-10 10:20:45 +00:00
2014-12-03 23:15:26 +00:00
if ( token = = "script" )
{
2013-09-11 09:47:53 +00:00
int startPos = ( int ) stream . Position - 7 ;
SkipWhitespace ( true ) ;
token = ReadToken ( ) ;
2012-07-10 10:20:45 +00:00
2013-09-11 09:47:53 +00:00
//is it named script?
2014-12-03 23:15:26 +00:00
if ( token . IndexOf ( '"' ) ! = - 1 )
{
2013-08-07 09:25:37 +00:00
//check if we have something like '"mycoolscript"(void)' as a token
if ( token . LastIndexOf ( '"' ) ! = token . Length - 1 )
token = token . Substring ( 0 , token . LastIndexOf ( '"' ) ) ;
2013-09-11 09:47:53 +00:00
token = StripTokenQuotes ( token ) ;
ScriptItem i = new ScriptItem ( 0 , token , startPos , ( int ) stream . Position - 1 ) ;
namedScripts . Add ( i ) ;
2014-12-03 23:15:26 +00:00
}
else //should be numbered script
{
2013-08-07 09:25:37 +00:00
//check if we have something like "999(void)" as a token
if ( token . Contains ( "(" ) ) token = token . Substring ( 0 , token . IndexOf ( "(" ) ) ;
2014-02-21 14:42:12 +00:00
int n ;
2014-12-03 23:15:26 +00:00
if ( int . TryParse ( token , NumberStyles . Integer , CultureInfo . InvariantCulture , out n ) )
{
2013-09-11 09:47:53 +00:00
int endPos = ( int ) stream . Position - 1 ;
//now find opening brace
2014-12-03 23:15:26 +00:00
do
{
2013-09-11 09:47:53 +00:00
SkipWhitespace ( true ) ;
token = ReadToken ( ) ;
} while ( token ! = "{" ) ;
token = ReadLine ( ) ;
string name = "" ;
2014-12-03 23:15:26 +00:00
if ( token . Length > 0 )
{
2013-09-11 09:47:53 +00:00
int commentStart = token . IndexOf ( "//" ) ;
2014-12-03 23:15:26 +00:00
if ( commentStart ! = - 1 ) //found comment
{
2013-09-11 09:47:53 +00:00
commentStart + = 2 ;
name = token . Substring ( commentStart , token . Length - commentStart ) . Trim ( ) ;
}
}
name = ( name . Length > 0 ? name + " [" + n + "]" : "Script " + n ) ;
ScriptItem i = new ScriptItem ( n , name , startPos , endPos ) ;
numberedScripts . Add ( i ) ;
}
}
2014-12-03 23:15:26 +00:00
}
else if ( token = = "function" )
{
2014-07-16 09:47:23 +00:00
int startPos = ( int ) stream . Position - 9 ;
SkipWhitespace ( true ) ;
string funcname = ReadToken ( ) ; //read return type
SkipWhitespace ( true ) ;
funcname + = " " + ReadToken ( ) ; //read function name
//look for opening brace
2014-12-03 23:15:26 +00:00
if ( ! funcname . Contains ( "(" ) )
{
2014-07-16 09:47:23 +00:00
SkipWhitespace ( true ) ;
funcname + = " " + ReadToken ( ) ;
2014-12-03 23:15:26 +00:00
}
else
{
2014-07-16 09:47:23 +00:00
funcname = funcname . Replace ( "(" , " (" ) ;
}
//look for closing brace
2014-12-03 23:15:26 +00:00
if ( ! funcname . Contains ( ")" ) )
{
do
{
2014-07-16 09:47:23 +00:00
SkipWhitespace ( true ) ;
token = ReadToken ( ) ;
funcname + = " " + token ;
} while ( ! token . Contains ( ")" ) ) ;
}
ScriptItem i = new ScriptItem ( 0 , funcname , startPos , ( int ) stream . Position - 1 ) ;
functions . Add ( i ) ;
2014-12-03 23:15:26 +00:00
}
else if ( processIncludes & & ( token = = "#include" | | token = = "#import" ) )
{
2013-09-11 09:47:53 +00:00
SkipWhitespace ( true ) ;
string includeLump = StripTokenQuotes ( ReadToken ( ) ) . ToLowerInvariant ( ) ;
2014-12-03 23:15:26 +00:00
if ( ! string . IsNullOrEmpty ( includeLump ) )
{
2013-09-11 09:47:53 +00:00
string includeName = Path . GetFileName ( includeLump ) ;
if ( includeName = = "zcommon.acs" | | includeName = = "common.acs" | | includes . Contains ( includeName ) )
continue ;
// Callback to parse this file
if ( OnInclude ! = null ) OnInclude ( this , includeLump . Replace ( Path . AltDirectorySeparatorChar , Path . DirectorySeparatorChar ) ) ;
// Set our buffers back to continue parsing
datastream = localstream ;
datareader = localreader ;
sourcename = localsourcename ;
2014-12-03 23:15:26 +00:00
}
else
{
2013-09-11 09:47:53 +00:00
General . ErrorLogger . Add ( ErrorType . Error , "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber ( ) + ": got #include directive without include path!" ) ;
}
}
}
}
return true ;
}
}
2012-07-10 14:14:53 +00:00
}