mirror of
https://github.com/gnustep/libs-gsweb.git
synced 2025-02-21 19:00:54 +00:00
remove useless comparison * GSWeb/GSWDeclarationParser.m fix some format strings and variables used in there * Add method to interface and remove a cast from bug report 39088 git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gsweb/trunk@36680 72102866-910b-0410-8b05-ffd578937521
1560 lines
50 KiB
Objective-C
1560 lines
50 KiB
Objective-C
/** GSWDeclarationParser.m - <title>GSWeb: Class GSWDeclarationParser</title>
|
|
|
|
Copyright (C) 2004 Free Software Foundation, Inc.
|
|
|
|
Written by: Manuel Guesdon <mguesdon@orange-concept.com>
|
|
Date: Mar 2004
|
|
|
|
$Revision$
|
|
$Date$
|
|
$Id$
|
|
|
|
<abstract></abstract>
|
|
|
|
This file is part of the GNUstep Web Library.
|
|
|
|
<license>
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
License along with this library; if not, write to the Free
|
|
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
</license>
|
|
**/
|
|
|
|
#include "config.h"
|
|
|
|
RCS_ID("$Id$")
|
|
|
|
#include "GSWeb.h"
|
|
|
|
#include "GSWDeclarationParser.h"
|
|
#include <GNUstepBase/Unicode.h>
|
|
#include <GNUstepBase/GSObjCRuntime.h>
|
|
#include <GNUstepBase/NSString+GNUstepBase.h>
|
|
#include <GNUstepBase/NSData+GNUstepBase.h>
|
|
|
|
static inline BOOL _parserIsIdentifierChar(unichar c)
|
|
{
|
|
switch(c)
|
|
{
|
|
case ' ':
|
|
case '\t':
|
|
case '\f':
|
|
case '\r':
|
|
case '\n':
|
|
case '\v':
|
|
case '{': // Dictionary
|
|
case '}': // Dictionary
|
|
case '(': // Array
|
|
case ')': // Array
|
|
case '<': // Data
|
|
case '>': // Data
|
|
case '/': // Comment
|
|
case ':': // Separator
|
|
case ';': // Separator
|
|
case '.': // Separator
|
|
case ',': // Separator
|
|
case '=': // Separator
|
|
return NO;
|
|
default:
|
|
return YES;
|
|
};
|
|
};
|
|
|
|
NSString* const GSWDFEMissingDeclarationForElement = @"GSWDFEMissingDeclarationForElement";
|
|
NSString* const GSWDFEMissingElementName = @"GSWDFEMissingElementName";
|
|
NSString* const GSWDFEMissingClassNameForElement = @"GSWDFEMissingClassNameForElement";
|
|
NSString* const GSWDFEElementCreationFailed = @"GSWDFEElementCreationFailed";
|
|
NSString* const GSWDFEMissingIdentifier = @"GSWDFEMissingIdentifier";
|
|
NSString* const GSWDFEMissingPragmaDelegate = @"GSWDFEMissingPragmaDelegate";
|
|
NSString* const GSWDFEUnknownPragmaDirective = @"GSWDFEUnknownPragmaDirective";
|
|
NSString* const GSWDFEMissingQuotedStringEnd = @"GSWDFEMissingQuotedStringEnd";
|
|
NSString* const GSWDFEMissingHexStringDataEnd = @"GSWDFEMissingHexStringDataEnd";
|
|
NSString* const GSWDFEMissingQuotedKeyPathEnd = @"GSWDFEMissingQuotedKeyPathEnd";
|
|
NSString* const GSWDFEWrongKeyPathFormat = @"GSWDFEWrongKeyPathFormat";
|
|
NSString* const GSWDFEEmptyKeyPath = @"GSWDFEEmptyKeyPath";
|
|
NSString* const GSWDFEWrongNumberFormat = @"GSWDFEWrongNumberFormat";
|
|
NSString* const GSWDFEWrongHexNumberFormat = @"GSWDFEWrongHexNumberFormat";
|
|
NSString* const GSWDFEUnexpectedBufferEnd = @"GSWDFEUnexpectedBufferEnd";
|
|
NSString* const GSWDFEMissingValue = @"GSWDFEMissingValue";
|
|
NSString* const GSWDFEMissingSeparator = @"GSWDFEMissingSeparator";
|
|
NSString* const GSWDFEDictionaryParsingError = @"GSWDFEDictionaryParsingError";
|
|
NSString* const GSWDFEArrayParsingError = @"GSWDFEArrayParsingError";
|
|
NSString* const GSWDFEUnexpectedCharacter = @"GSWDFEUnexpectedCharacter";
|
|
NSString* const GSWDFEMissingAliasedDeclaration = @"GSWDFEMissingAliasedDeclaration";
|
|
|
|
static NSSet* delayedDeclarationFormatExceptionNames = nil;
|
|
static NSMutableDictionary* declarationsCache=nil;
|
|
|
|
static SEL skipBlanksSEL = NULL;
|
|
static SEL skipCommentSEL = NULL;
|
|
static SEL skipBlanksAndCommentsSEL = NULL;
|
|
static SEL parsePragmaSEL = NULL;
|
|
static SEL parseIdentifierSEL = NULL;
|
|
static SEL parseKeySEL = NULL;
|
|
static SEL parseQuotedStringSEL = NULL;
|
|
static SEL parseHexDataSEL = NULL;
|
|
static SEL parseKeyPathSEL = NULL;
|
|
static SEL tryParseBooleanSEL = NULL;
|
|
static SEL parseNumberSEL = NULL;
|
|
static SEL parseHexNumberSEL = NULL;
|
|
static SEL parseValueAsAssociationSEL = NULL;
|
|
static SEL parseDictionaryWithValuesAsAssociationsSEL = NULL;
|
|
static SEL parseArraySEL = NULL;
|
|
static SEL parseDeclarationSEL = NULL;
|
|
|
|
//====================================================================
|
|
@implementation GSWDeclarationFormatException
|
|
|
|
+ (void) initialize
|
|
{
|
|
if (self == [GSWDeclarationFormatException class])
|
|
{
|
|
ASSIGN(delayedDeclarationFormatExceptionNames,
|
|
([NSSet setWithObjects:
|
|
GSWDFEMissingDeclarationForElement,
|
|
GSWDFEMissingElementName,
|
|
GSWDFEMissingClassNameForElement,
|
|
GSWDFEElementCreationFailed,
|
|
GSWDFEMissingIdentifier,
|
|
GSWDFEMissingPragmaDelegate,
|
|
GSWDFEUnknownPragmaDirective,
|
|
GSWDFEMissingQuotedStringEnd,
|
|
GSWDFEMissingHexStringDataEnd,
|
|
GSWDFEMissingQuotedKeyPathEnd,
|
|
GSWDFEWrongKeyPathFormat,
|
|
GSWDFEEmptyKeyPath,
|
|
GSWDFEWrongNumberFormat,
|
|
GSWDFEWrongHexNumberFormat,
|
|
GSWDFEUnexpectedBufferEnd,
|
|
GSWDFEMissingValue,
|
|
GSWDFEMissingSeparator,
|
|
GSWDFEDictionaryParsingError,
|
|
GSWDFEArrayParsingError,
|
|
GSWDFEUnexpectedCharacter,
|
|
nil]));
|
|
};
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
/** Returns YES if we can delay exception reporting (so all errors are
|
|
accumulated instead of blocking on first error) **/
|
|
-(BOOL)canDelay
|
|
{
|
|
return [delayedDeclarationFormatExceptionNames containsObject:[self name]];
|
|
};
|
|
|
|
|
|
@end
|
|
|
|
|
|
// 'Standard' GSWContext class. Used to get IMPs from standardElementIDIMPs
|
|
static Class standardClass=Nil;
|
|
|
|
// List of standardClass IMPs
|
|
static GSWDeclarationParserIMPs standardDeclarationParserIMPs;
|
|
|
|
//====================================================================
|
|
/** Fill impsPtr structure with IMPs for declarationParser **/
|
|
void GetGSWDeclarationParserIMPS(GSWDeclarationParserIMPs* impsPtr,GSWDeclarationParser* declarationParser)
|
|
{
|
|
if ([declarationParser class]==standardClass)
|
|
{
|
|
memcpy(impsPtr,&standardDeclarationParserIMPs,sizeof(GSWDeclarationParserIMPs));
|
|
}
|
|
else
|
|
{
|
|
memset(impsPtr,0,sizeof(GSWDeclarationParserIMPs));
|
|
|
|
impsPtr->_skipBlanksIMP =
|
|
(GSWIMP_BOOL)[declarationParser methodForSelector:skipBlanksSEL];
|
|
|
|
impsPtr->_skipCommentIMP =
|
|
(GSWIMP_BOOL)[declarationParser methodForSelector:skipCommentSEL];
|
|
|
|
impsPtr->_skipBlanksAndCommentsIMP =
|
|
(GSWIMP_BOOL)[declarationParser methodForSelector:skipBlanksAndCommentsSEL];
|
|
|
|
impsPtr->_parsePragmaIMP =
|
|
[declarationParser methodForSelector:parsePragmaSEL];
|
|
|
|
impsPtr->_parseIdentifierIMP =
|
|
[declarationParser methodForSelector:parseIdentifierSEL];
|
|
|
|
impsPtr->_parseKeyIMP =
|
|
[declarationParser methodForSelector:parseKeySEL];
|
|
|
|
impsPtr->_parseQuotedStringIMP =
|
|
[declarationParser methodForSelector:parseQuotedStringSEL];
|
|
|
|
impsPtr->_parseHexDataIMP =
|
|
[declarationParser methodForSelector:parseHexDataSEL];
|
|
|
|
impsPtr->_parseKeyPathIMP =
|
|
[declarationParser methodForSelector:parseKeyPathSEL];
|
|
|
|
impsPtr->_tryParseBooleanIMP =
|
|
[declarationParser methodForSelector:tryParseBooleanSEL];
|
|
|
|
impsPtr->_parseNumberIMP =
|
|
[declarationParser methodForSelector:parseNumberSEL];
|
|
|
|
impsPtr->_parseHexNumberIMP =
|
|
[declarationParser methodForSelector:parseHexNumberSEL];
|
|
|
|
impsPtr->_parseValueAsAssociationIMP =
|
|
[declarationParser methodForSelector:parseValueAsAssociationSEL];
|
|
|
|
impsPtr->_parseDictionaryWithValuesAsAssociationsIMP =
|
|
[declarationParser methodForSelector:parseDictionaryWithValuesAsAssociationsSEL];
|
|
|
|
impsPtr->_parseArrayIMP =
|
|
[declarationParser methodForSelector:parseArraySEL];
|
|
|
|
impsPtr->_parseDeclarationIMP =
|
|
[declarationParser methodForSelector:parseDeclarationSEL];
|
|
};
|
|
};
|
|
|
|
static inline BOOL skipBlanks(GSWDeclarationParser* parser)
|
|
{
|
|
return ((*parser->_selfIMPs._skipBlanksIMP)(parser,skipBlanksSEL));
|
|
};
|
|
|
|
static inline BOOL skipComment(GSWDeclarationParser* parser)
|
|
{
|
|
return ((*parser->_selfIMPs._skipCommentIMP)(parser,skipCommentSEL));
|
|
};
|
|
|
|
static inline BOOL skipBlanksAndComments(GSWDeclarationParser* parser)
|
|
{
|
|
return ((*parser->_selfIMPs._skipBlanksAndCommentsIMP)(parser,skipBlanksAndCommentsSEL));
|
|
};
|
|
|
|
static inline void parsePragma(GSWDeclarationParser* parser)
|
|
{
|
|
((*parser->_selfIMPs._parsePragmaIMP)(parser,parsePragmaSEL));
|
|
};
|
|
|
|
static inline NSString* parseIdentifier(GSWDeclarationParser* parser)
|
|
{
|
|
return ((*parser->_selfIMPs._parseIdentifierIMP)(parser,parseIdentifierSEL));
|
|
};
|
|
|
|
static inline NSString* parseKey(GSWDeclarationParser* parser)
|
|
{
|
|
return ((*parser->_selfIMPs._parseKeyIMP)(parser,parseKeySEL));
|
|
};
|
|
|
|
static inline id parseKeyPath(GSWDeclarationParser* parser)
|
|
{
|
|
return ((*parser->_selfIMPs._parseKeyPathIMP)(parser,parseKeyPathSEL));
|
|
};
|
|
|
|
static inline id parseQuotedString(GSWDeclarationParser* parser)
|
|
{
|
|
return ((*parser->_selfIMPs._parseQuotedStringIMP)(parser,parseQuotedStringSEL));
|
|
};
|
|
|
|
static inline NSData* parseHexData(GSWDeclarationParser* parser)
|
|
{
|
|
return ((*parser->_selfIMPs._parseHexDataIMP)(parser,parseHexDataSEL));
|
|
};
|
|
|
|
static inline NSNumber* tryParseBoolean(GSWDeclarationParser* parser)
|
|
{
|
|
return ((*parser->_selfIMPs._tryParseBooleanIMP)(parser,tryParseBooleanSEL));
|
|
};
|
|
|
|
static inline NSNumber* parseNumber(GSWDeclarationParser* parser)
|
|
{
|
|
return ((*parser->_selfIMPs._parseNumberIMP)(parser,parseNumberSEL));
|
|
};
|
|
|
|
static inline NSNumber* parseHexNumber(GSWDeclarationParser* parser)
|
|
{
|
|
return ((*parser->_selfIMPs._parseHexNumberIMP)(parser,parseHexNumberSEL));
|
|
};
|
|
|
|
static inline id parseValueAsAssociation(GSWDeclarationParser* parser,BOOL asAssociation)
|
|
{
|
|
return ((*parser->_selfIMPs._parseValueAsAssociationIMP)(parser,parseValueAsAssociationSEL,asAssociation));
|
|
};
|
|
|
|
static inline NSDictionary* parseDictionaryWithValuesAsAssociations(GSWDeclarationParser* parser,
|
|
BOOL valuesAsAssociations)
|
|
{
|
|
return ((*parser->_selfIMPs._parseDictionaryWithValuesAsAssociationsIMP)(parser,parseDictionaryWithValuesAsAssociationsSEL,valuesAsAssociations));
|
|
};
|
|
|
|
static inline NSArray* parseArray(GSWDeclarationParser* parser)
|
|
{
|
|
return ((*parser->_selfIMPs._parseArrayIMP)(parser,parseArraySEL));
|
|
};
|
|
|
|
static inline GSWDeclaration* parseDeclaration(GSWDeclarationParser* parser)
|
|
{
|
|
return ((*parser->_selfIMPs._parseDeclarationIMP)(parser,parseDeclarationSEL));
|
|
};
|
|
|
|
|
|
//====================================================================
|
|
@implementation GSWDeclarationParser
|
|
|
|
+ (void) initialize
|
|
{
|
|
if (self == [GSWDeclarationParser class])
|
|
{
|
|
declarationsCache=[NSMutableDictionary new];
|
|
|
|
standardClass=[GSWDeclarationParser class];
|
|
|
|
skipBlanksSEL = @selector(skipBlanks);
|
|
skipCommentSEL = @selector(skipComment);
|
|
skipBlanksAndCommentsSEL = @selector(skipBlanksAndComments);
|
|
parsePragmaSEL = @selector(parsePragma);
|
|
parseIdentifierSEL = @selector(parseIdentifier);
|
|
parseKeySEL = @selector(parseKey);
|
|
parseQuotedStringSEL = @selector(parseQuotedString);
|
|
parseHexDataSEL = @selector(parseHexData);
|
|
parseKeyPathSEL = @selector(parseKeyPath);
|
|
tryParseBooleanSEL = @selector(tryParseBoolean);
|
|
parseNumberSEL = @selector(parseNumber);
|
|
parseHexNumberSEL = @selector(parseHexNumber);
|
|
parseValueAsAssociationSEL = @selector(parseValueAsAssociation:);
|
|
parseDictionaryWithValuesAsAssociationsSEL = @selector(parseDictionaryWithValuesAsAssociations:);
|
|
parseArraySEL = @selector(parseArray);
|
|
parseDeclarationSEL = @selector(parseDeclaration);
|
|
|
|
memset(&standardDeclarationParserIMPs,0,sizeof(GSWDeclarationParserIMPs));
|
|
|
|
standardDeclarationParserIMPs._skipBlanksIMP =
|
|
(GSWIMP_BOOL)[standardClass instanceMethodForSelector:skipBlanksSEL];
|
|
|
|
standardDeclarationParserIMPs._skipCommentIMP =
|
|
(GSWIMP_BOOL)[standardClass instanceMethodForSelector:skipCommentSEL];
|
|
|
|
standardDeclarationParserIMPs._skipBlanksAndCommentsIMP =
|
|
(GSWIMP_BOOL)[standardClass instanceMethodForSelector:skipBlanksAndCommentsSEL];
|
|
|
|
standardDeclarationParserIMPs._parsePragmaIMP =
|
|
[standardClass instanceMethodForSelector:parsePragmaSEL];
|
|
|
|
standardDeclarationParserIMPs._parseIdentifierIMP =
|
|
[standardClass instanceMethodForSelector:parseIdentifierSEL];
|
|
|
|
standardDeclarationParserIMPs._parseKeyIMP =
|
|
[standardClass instanceMethodForSelector:parseKeySEL];
|
|
|
|
standardDeclarationParserIMPs._parseQuotedStringIMP =
|
|
[standardClass instanceMethodForSelector:parseQuotedStringSEL];
|
|
|
|
standardDeclarationParserIMPs._parseHexDataIMP =
|
|
[standardClass instanceMethodForSelector:parseHexDataSEL];
|
|
|
|
standardDeclarationParserIMPs._parseKeyPathIMP =
|
|
[standardClass instanceMethodForSelector:parseKeyPathSEL];
|
|
|
|
standardDeclarationParserIMPs._tryParseBooleanIMP =
|
|
[standardClass instanceMethodForSelector:tryParseBooleanSEL];
|
|
|
|
standardDeclarationParserIMPs._parseNumberIMP =
|
|
[standardClass instanceMethodForSelector:parseNumberSEL];
|
|
|
|
standardDeclarationParserIMPs._parseHexNumberIMP =
|
|
[standardClass instanceMethodForSelector:parseHexNumberSEL];
|
|
|
|
standardDeclarationParserIMPs._parseValueAsAssociationIMP =
|
|
[standardClass instanceMethodForSelector:parseValueAsAssociationSEL];
|
|
|
|
standardDeclarationParserIMPs._parseDictionaryWithValuesAsAssociationsIMP =
|
|
[standardClass instanceMethodForSelector:parseDictionaryWithValuesAsAssociationsSEL];
|
|
|
|
standardDeclarationParserIMPs._parseArrayIMP =
|
|
[standardClass instanceMethodForSelector:parseArraySEL];
|
|
|
|
standardDeclarationParserIMPs._parseDeclarationIMP =
|
|
[standardClass instanceMethodForSelector:parseDeclarationSEL];
|
|
};
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
+(GSWDeclarationParser*)declarationParserWithPragmaDelegate:(id<GSWDeclarationParserPragmaDelegate>)pragmaDelegate
|
|
{
|
|
return [[[self alloc]
|
|
initWithPragmaDelegate:pragmaDelegate]
|
|
autorelease];
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
-(id)initWithPragmaDelegate:(id<GSWDeclarationParserPragmaDelegate>)pragmaDelegate
|
|
{
|
|
if ((self=[self init]))
|
|
{
|
|
ASSIGN(_pragmaDelegate,pragmaDelegate);
|
|
};
|
|
return self;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
-(id)init
|
|
{
|
|
if ((self=[super init]))
|
|
{
|
|
GetGSWDeclarationParserIMPS(&_selfIMPs,self);
|
|
};
|
|
return self;
|
|
};
|
|
//--------------------------------------------------------------------
|
|
-(void)dealloc
|
|
{
|
|
DESTROY(_pragmaDelegate);
|
|
DESTROY(_declarations);
|
|
DESTROY(_fileName);
|
|
DESTROY(_frameworkName);
|
|
|
|
[super dealloc];
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
-(NSDictionary*)parseDeclarationString:(NSString*)declarationString
|
|
named:(NSString*)declarationFileName
|
|
inFrameworkNamed:(NSString*)declarationFrameworkName
|
|
{
|
|
NSData* md5=nil;
|
|
NSDictionary* declarations=nil;
|
|
|
|
if (_declarations)
|
|
[_declarations removeAllObjects];
|
|
|
|
ASSIGN(_string,declarationString);
|
|
ASSIGN(_fileName,declarationFileName);
|
|
ASSIGN(_frameworkName,declarationFrameworkName);
|
|
|
|
NSDebugMLog(@"declarationString=%@",declarationString);
|
|
_length=[_string length];
|
|
|
|
if ([_string rangeOfString:@"#include"].length==0)
|
|
{
|
|
md5=[_string dataUsingEncoding: NSUnicodeStringEncoding];
|
|
md5=[md5 md5Digest];
|
|
declarations=[declarationsCache objectForKey:md5];
|
|
NSDebugMLog(@"declaration (%@) is %scached",declarationFileName,(declarations ? "" : "not "));
|
|
}
|
|
|
|
if (!declarations)
|
|
{
|
|
if (!_declarations)
|
|
_declarations=(NSMutableDictionary*)[NSMutableDictionary new];
|
|
|
|
_uniBuf = (unichar*)NSZoneMalloc(NSDefaultMallocZone(),sizeof(unichar)*(_length+1));
|
|
|
|
NS_DURING
|
|
{
|
|
[_string getCharacters:_uniBuf];
|
|
|
|
NSDebugMLog(@"index=%d length=%d",_index,_length);
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,_length);
|
|
|
|
while(_index<_length)
|
|
{
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
skipBlanksAndComments(self);
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
if (_index<_length)
|
|
{
|
|
if (_uniBuf[_index]=='#')
|
|
{
|
|
parsePragma(self);
|
|
NSDebugMLog(@"index=%d _length=%d",_index,20);
|
|
}
|
|
else if (_parserIsIdentifierChar(_uniBuf[_index]))
|
|
{
|
|
GSWDeclaration* declaration=parseDeclaration(self);
|
|
NSDebugMLog(@"declaration=%@",declaration);
|
|
[_declarations setObject:declaration
|
|
forKey:[declaration name]];
|
|
NSDebugMLog(@"index=%d _length=%d",_index,20);
|
|
}
|
|
else
|
|
{
|
|
[GSWDeclarationFormatException raise:GSWDFEMissingIdentifier
|
|
format:@"In %@ %@: No identifier %@",
|
|
_frameworkName,_fileName,
|
|
[self currentLineAndColumnIndexesString]];
|
|
};
|
|
};
|
|
}
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
}
|
|
NS_HANDLER
|
|
{
|
|
if (_uniBuf)
|
|
{
|
|
NSZoneFree(NSDefaultMallocZone(),_uniBuf);
|
|
_uniBuf=NULL;
|
|
};
|
|
[localException raise];
|
|
};
|
|
NS_ENDHANDLER;
|
|
|
|
NSDebugMLog(@"_declarations=%@",_declarations);
|
|
declarations=[NSDictionary dictionaryWithDictionary:_declarations];
|
|
if (md5)
|
|
[declarationsCache setObject:declarations
|
|
forKey:md5];
|
|
};
|
|
|
|
return declarations;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
-(NSDictionary*)parseDeclarationString:(NSString*)declarationString
|
|
{
|
|
NSDictionary* declarations=nil;
|
|
|
|
declarations=[self parseDeclarationString:declarationString
|
|
named:nil
|
|
inFrameworkNamed:nil];
|
|
|
|
return declarations;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
/** Returns YES if blank skipped **/
|
|
-(BOOL)skipBlanks
|
|
{
|
|
int startIndex=_index;
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
while(_index<_length
|
|
&& (_parserIsBlankChar(_uniBuf[_index])
|
|
|| _parserIsEndOfLineChar(_uniBuf[_index])))
|
|
_index++;
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
return (_index>startIndex ? YES : NO);
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
/** Returns YES if comments skipped **/
|
|
-(BOOL)skipComment
|
|
{
|
|
int startIndex=_index;
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
if (_uniBuf[_index]=='/')
|
|
{
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index+1,10);
|
|
if (_uniBuf[(_index)+1]=='/') // // styles comments
|
|
{
|
|
_index+=2;
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
//TODO Should handle line continuation
|
|
while(_index<_length)
|
|
{
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
if (_parserIsEndOfLineChar(_uniBuf[_index]))
|
|
{
|
|
_index++;
|
|
break;
|
|
}
|
|
else
|
|
_index++;
|
|
};
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,_length);
|
|
}
|
|
else if (_uniBuf[(_index)+1]=='*') // /* styles comments
|
|
{
|
|
_index+=2;
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
//TODO Should handle line continuation
|
|
while(_index<_length-1)
|
|
{
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
if (_uniBuf[_index]=='*'
|
|
&& _uniBuf[(_index)+1]=='/')
|
|
{
|
|
_index+=2;
|
|
break;
|
|
}
|
|
else
|
|
_index++;
|
|
};
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,_length);
|
|
}
|
|
else
|
|
_index++;
|
|
};
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
return (_index>startIndex ? YES : NO);
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
/** Returns YES if blanks or comments skipped **/
|
|
-(BOOL)skipBlanksAndComments
|
|
{
|
|
BOOL skipped=NO;
|
|
BOOL isLastSkipped=YES;
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
while(_index<_length && isLastSkipped)
|
|
{
|
|
isLastSkipped=skipBlanks(self);
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
if (skipComment(self))
|
|
isLastSkipped=YES;
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
if (isLastSkipped)
|
|
skipped=YES;
|
|
};
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
return skipped;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
-(void)parsePragma
|
|
{
|
|
int startIndex=_index;
|
|
NSString* pragmaDirective=nil;
|
|
NSAssert(_index<_length,@"Reached buffer end parsing a prgma");
|
|
NSAssert1(_uniBuf[_index]=='#',@"First character should be '#', not '%c'",(char)_uniBuf[_index]);
|
|
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
|
|
while(_index<_length
|
|
&& !_parserIsEndOfLineChar(_uniBuf[_index]))
|
|
{
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
_index++;
|
|
};
|
|
pragmaDirective=[NSString stringWithCharacters:_uniBuf+startIndex
|
|
length:_index-startIndex];
|
|
NSDebugMLog(@"pragmaDirective=%@",pragmaDirective);
|
|
if ([pragmaDirective hasPrefix:@"#include"])
|
|
{
|
|
if (!_pragmaDelegate)
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEMissingPragmaDelegate
|
|
format:@"In %@ %@: No pragma delegate for pragma directive '%@'",
|
|
_frameworkName,_fileName,pragmaDirective];
|
|
}
|
|
else
|
|
{
|
|
NSDictionary* declarations=nil;
|
|
NSString* file=[pragmaDirective stringByDeletingPrefix:@"#include"];
|
|
file=[file stringByTrimmingSpaces];
|
|
if ([file hasPrefix:@"\""])
|
|
file=[[file stringByDeletingPrefix:@"\""]
|
|
stringByDeletingSuffix:@"\""];
|
|
else if ([file hasPrefix:@"<"])
|
|
file=[[file stringByDeletingPrefix:@"<"]
|
|
stringByDeletingSuffix:@">"];
|
|
NSDebugMLog(@"pragma include file=%@",file);
|
|
NSDebugMLog(@"pragma _frameworkName=%@",_frameworkName);
|
|
declarations=[_pragmaDelegate includedDeclarationsFromFilePath:file
|
|
fromFrameworkNamed:_frameworkName];
|
|
if ([declarations count]>0)
|
|
[_declarations addEntriesFromDictionary:declarations];
|
|
};
|
|
}
|
|
else
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEUnknownPragmaDirective
|
|
format:@"In %@ %@: Unknown pragma directive '%@' at line %d",
|
|
_frameworkName,_fileName,pragmaDirective,
|
|
[self lineIndexFromIndex:startIndex]];
|
|
};
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,_length);
|
|
};
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
/** Parse an indentifier.
|
|
Index should be on the identifier first character
|
|
Returns a NSString
|
|
**/
|
|
-(NSString*)parseIdentifier
|
|
{
|
|
NSString* identifier=nil;
|
|
int startIndex=_index;
|
|
|
|
NSAssert(_index<_length,@"Reached buffer end parsing an identifier");
|
|
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
|
|
while(_index<_length
|
|
&& _parserIsIdentifierChar(_uniBuf[_index]))
|
|
_index++;
|
|
|
|
if (index-startIndex==0)
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEMissingIdentifier
|
|
format:@"IN %@ %@: No identifier %@",
|
|
_frameworkName,_fileName,
|
|
[self currentLineAndColumnIndexesString]];
|
|
}
|
|
else
|
|
{
|
|
identifier=[NSString stringWithCharacters:_uniBuf+startIndex
|
|
length:_index-startIndex];
|
|
NSDebugMLog(@"identifier=%@",identifier);
|
|
};
|
|
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
return identifier;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
/** Parse a key.
|
|
Index should be on the identifier first character
|
|
Returns a NSString
|
|
**/
|
|
-(NSString*)parseKey
|
|
{
|
|
return parseIdentifier(self);
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
/** Parse a quoted string.
|
|
Index should be on the value first character (")
|
|
Returns a NSString without '"' pefix and suffix
|
|
**/
|
|
-(id)parseQuotedString
|
|
{
|
|
NSString *string=nil;
|
|
unsigned startIndex=_index;
|
|
BOOL escaped = NO;
|
|
|
|
NSAssert(_index<_length,@"Reached buffer end parsing an quoted string");
|
|
NSAssert(_uniBuf[_index]=='"',@"First character should be '\"'");
|
|
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
|
|
_index++; // skip '"'
|
|
while(_index<_length
|
|
&& _uniBuf[_index]!='"')
|
|
{
|
|
if (_uniBuf[_index]=='\\' && (_index+1 < _length))
|
|
{
|
|
escaped=YES;
|
|
_index++;
|
|
}
|
|
_index++;
|
|
};
|
|
if (_index<_length && _uniBuf[_index]=='"')
|
|
_index++;
|
|
else
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEMissingQuotedStringEnd
|
|
format:@"In %@ %@: No end '\"' for quoted string starting at line %d",
|
|
_frameworkName,_fileName,
|
|
[self lineIndexFromIndex:startIndex]];
|
|
};
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
if (escaped)
|
|
{
|
|
unsigned i,j,l = _index-startIndex-2; // don't take '"' prefix and suffix
|
|
unichar *buf = GSAutoreleasedBuffer(sizeof(unichar)*l);
|
|
memcpy (buf, &_uniBuf[startIndex+1], sizeof(unichar)*l);
|
|
|
|
for (i=0,j=0;i<l;i++,j++)
|
|
{
|
|
if (buf[i]=='\\' && (i+1 < l)) i++;
|
|
buf[j]=buf[i];
|
|
}
|
|
string=[NSString stringWithCharacters:buf length:j];
|
|
}
|
|
else
|
|
{
|
|
string=[NSString stringWithCharacters:_uniBuf+startIndex+1
|
|
length:_index-startIndex-2]; // don't take '"' prefix and suffix
|
|
}
|
|
return string;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
/** Parse a data <12A1 1213...>
|
|
Index should be on the value first character ('<')
|
|
Returns a NSData
|
|
**/
|
|
-(NSData*)parseHexData
|
|
{
|
|
NSData* data=nil;
|
|
NSString* string=nil;
|
|
int startIndex=_index;
|
|
NSAssert(_index<_length,@"Reached buffer end parsing a data");
|
|
NSAssert(_uniBuf[_index]=='<',@"First character should be '<'");
|
|
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
|
|
_index++; // skip '<'
|
|
while(_index<_length
|
|
&& _uniBuf[_index]!='>')
|
|
{
|
|
_index++;
|
|
};
|
|
if (_index<_length && _uniBuf[_index]=='>')
|
|
_index++;
|
|
else
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEMissingHexStringDataEnd
|
|
format:@"In %@ %@: No end '>' for data starting at line %d",
|
|
_frameworkName,_fileName,
|
|
[self lineIndexFromIndex:startIndex]];
|
|
};
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
string=[NSString stringWithCharacters:_uniBuf+startIndex+1
|
|
length:_index-startIndex-2]; // -2 because we don't take < >
|
|
NSDebugMLog(@"string=%@",string);
|
|
data=[[[NSData alloc]initWithHexadecimalRepresentation:string]autorelease];
|
|
NSDebugMLog(@"data=%@",data);
|
|
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
return data;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
/** Parse a key path
|
|
Index should be on the first character
|
|
Returns a NSString
|
|
**/
|
|
-(id)parseKeyPath
|
|
{
|
|
NSString* keyPath=nil;
|
|
int startIndex=_index;
|
|
BOOL end=NO;
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
while(!end && _index<_length)
|
|
{
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
switch(_uniBuf[_index])
|
|
{
|
|
case '\'':
|
|
_index++;
|
|
while(_index<_length
|
|
&& _uniBuf[_index]!='\'')
|
|
{
|
|
_index++;
|
|
};
|
|
if (_index<_length && _uniBuf[_index]=='\'')
|
|
_index++;
|
|
else
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEMissingQuotedKeyPathEnd
|
|
format:@"In %@ %@: No end '\'' for keyPath starting at line %d",
|
|
_frameworkName,_fileName,
|
|
[self lineIndexFromIndex:startIndex]];
|
|
};
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
break;
|
|
case '\"':
|
|
_index++;
|
|
while(_index<_length
|
|
&& _uniBuf[_index]!='\"')
|
|
{
|
|
_index++;
|
|
};
|
|
if (_index<_length && _uniBuf[_index]=='\"')
|
|
_index++;
|
|
else
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEMissingQuotedKeyPathEnd
|
|
format:@"In %@ %@:No end '\"' for keyPath starting at line %d",
|
|
_frameworkName,_fileName,
|
|
[self lineIndexFromIndex:startIndex]];
|
|
};
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
break;
|
|
case '.':
|
|
if (_index==startIndex)
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEWrongKeyPathFormat
|
|
format:@"In %@ %@: keyPath can't begin with '.' line %d",
|
|
_frameworkName,_fileName,
|
|
[self lineIndexFromIndex:startIndex]];
|
|
}
|
|
else
|
|
_index++;
|
|
break;
|
|
default:
|
|
if (_parserIsIdentifierChar(_uniBuf[_index]))
|
|
_index++;
|
|
else
|
|
end=YES;
|
|
break;
|
|
};
|
|
};
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
if ((index-startIndex)==0)
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEEmptyKeyPath
|
|
format:@"In %@ %@: Empty keyPath at line %d",
|
|
_frameworkName,_fileName,
|
|
[self lineIndexFromIndex:startIndex]];
|
|
}
|
|
else
|
|
{
|
|
keyPath=[NSString stringWithCharacters:_uniBuf+startIndex
|
|
length:_index-startIndex];
|
|
};
|
|
NSDebugMLog(@"keyPath=%@",keyPath);
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
return keyPath;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
/** Try to Parse a boolean (Y/N/YES/NO/T/F/TRUE/FALSE value.
|
|
Index should be on the value first character.
|
|
Returns an NSNumber.
|
|
**/
|
|
- (NSNumber *)tryParseBoolean
|
|
{
|
|
id value = nil;
|
|
NSAssert(_index<_length, @"Reached buffer end parsing boolean");
|
|
|
|
//ParserDebugLogBuffer(_uniBuf, _length, _index, 20);
|
|
|
|
// Test if it is Y/YES or N/NO
|
|
if (uni_toupper(_uniBuf[_index]) == 'Y'
|
|
|| uni_toupper(_uniBuf[_index]) == 'T'
|
|
|| uni_toupper(_uniBuf[_index]) == 'N'
|
|
|| uni_toupper(_uniBuf[_index]) == 'F')
|
|
{
|
|
int i = (_index)+1;
|
|
while(i < _length
|
|
&& _parserIsIdentifierChar(_uniBuf[i]))
|
|
{
|
|
i++;
|
|
}
|
|
|
|
switch(i-_index)
|
|
{
|
|
case 1:
|
|
{
|
|
if (uni_toupper(_uniBuf[(_index)]) == 'Y'
|
|
|| uni_toupper(_uniBuf[(_index)]) == 'T')
|
|
{
|
|
value = GSWNumberYes;
|
|
_index++;
|
|
}
|
|
else if (uni_toupper(_uniBuf[(_index)]) == 'N'
|
|
|| uni_toupper(_uniBuf[(_index)]) == 'F')
|
|
{
|
|
value = GSWNumberNo;
|
|
_index++;
|
|
}
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
if (uni_toupper(_uniBuf[(_index)]) == 'N'
|
|
&& uni_toupper(_uniBuf[(_index)+1]) == 'O')
|
|
{
|
|
value = GSWNumberNo;
|
|
_index += 2;
|
|
}
|
|
break;
|
|
}
|
|
case 3:
|
|
{
|
|
if (uni_toupper(_uniBuf[(_index)]) == 'Y'
|
|
&& uni_toupper(_uniBuf[(_index)+1]) == 'E'
|
|
&& uni_toupper(_uniBuf[(_index)+2]) == 'S')
|
|
{
|
|
value = GSWNumberYes;
|
|
_index += 3;
|
|
}
|
|
break;
|
|
}
|
|
case 4:
|
|
{
|
|
if (uni_toupper(_uniBuf[(_index)]) == 'T'
|
|
&& uni_toupper(_uniBuf[(_index)+1]) == 'R'
|
|
&& uni_toupper(_uniBuf[(_index)+2]) == 'U'
|
|
&& uni_toupper(_uniBuf[(_index)+3]) == 'E')
|
|
{
|
|
value = GSWNumberYes;
|
|
_index += 4;
|
|
}
|
|
break;
|
|
}
|
|
case 5:
|
|
{
|
|
if (uni_toupper(_uniBuf[(_index)]) == 'F'
|
|
&& uni_toupper(_uniBuf[(_index)+1]) == 'A'
|
|
&& uni_toupper(_uniBuf[(_index)+2]) == 'L'
|
|
&& uni_toupper(_uniBuf[(_index)+3]) == 'S'
|
|
&& uni_toupper(_uniBuf[(_index)+4]) == 'E')
|
|
{
|
|
value = GSWNumberNo;
|
|
_index += 5;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
NSDebugMLog(@"value=%@",value);
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
return value;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
/** Parse a number
|
|
Index should be on the value first character
|
|
Returns a NSNumber
|
|
**/
|
|
-(NSNumber*)parseNumber
|
|
{
|
|
NSNumber* value=nil;
|
|
NSString* string=nil;
|
|
int startIndex=_index;
|
|
BOOL seenDot=NO;
|
|
BOOL end=NO;
|
|
NSAssert(_index<_length,@"Reached buffer end parsing number");
|
|
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
|
|
if (_uniBuf[_index]=='-'
|
|
|| _uniBuf[_index]=='+')
|
|
{
|
|
_index++;
|
|
if (_index>=_length)
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEWrongNumberFormat
|
|
format:@"In %@ %@: Bad number line %d",
|
|
_frameworkName,_fileName,
|
|
[self lineIndexFromIndex:startIndex]];
|
|
};
|
|
};
|
|
while(!end && _index<_length)
|
|
{
|
|
if (_parserIsDigit(_uniBuf[_index]))
|
|
_index++;
|
|
else if (_uniBuf[_index]=='.')
|
|
{
|
|
if (seenDot)
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEWrongNumberFormat
|
|
format:@"In %@ %@: 2 dots in a number line %d",
|
|
_frameworkName,_fileName,
|
|
[self lineIndexFromIndex:startIndex]];
|
|
}
|
|
else
|
|
{
|
|
_index++;
|
|
seenDot=YES;
|
|
};
|
|
}
|
|
else
|
|
end=YES;
|
|
};
|
|
string=[NSString stringWithCharacters:_uniBuf+startIndex
|
|
length:_index-startIndex];
|
|
NSDebugMLog(@"string=%@",string);
|
|
if (seenDot)
|
|
value=[NSNumber numberWithDouble:[string floatValue]];
|
|
else
|
|
value=GSWIntNumber([string intValue]);
|
|
NSDebugMLog(@"value=%@",value);
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
return value;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
/** Parse a number
|
|
Index should be on the value first character ('#')
|
|
Returns a NSNumber
|
|
**/
|
|
-(NSNumber*)parseHexNumber
|
|
{
|
|
NSNumber* value=nil;
|
|
int startIndex=_index;
|
|
NSAssert(_index<_length,@"Reached buffer end parsing number");
|
|
NSAssert1(_uniBuf[_index]=='#',@"First character should be '#' not '%c'",(char)_uniBuf[_index]);
|
|
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
|
|
_index++; // skip '#'
|
|
|
|
while(_index<_length
|
|
&& _parserIsHexDigit(_uniBuf[_index]))
|
|
_index++;
|
|
|
|
if (_index>startIndex+1)
|
|
{
|
|
NSString* string=nil;
|
|
const char* cString=NULL;
|
|
char* endPtr=NULL;
|
|
int intValue=0;
|
|
string=[NSString stringWithCharacters:_uniBuf+startIndex+1
|
|
length:_index-startIndex-1];
|
|
NSDebugMLog(@"string=%@",string);
|
|
cString=[string cStringUsingEncoding:NSASCIIStringEncoding];
|
|
intValue=strtol(cString,&endPtr,16);
|
|
NSDebugMLog(@"cString='%s' endPtr='%s'",cString,endPtr);
|
|
if (endPtr && *endPtr)
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEWrongHexNumberFormat
|
|
format:@"In %@ %@: Bad hex number line %d",
|
|
_frameworkName,_fileName,
|
|
[self lineIndexFromIndex:startIndex]];
|
|
};
|
|
value=GSWIntNumber(intValue);
|
|
};
|
|
NSDebugMLog(@"value=%@",value);
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
return value;
|
|
};
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
/** Parse a value.
|
|
Index should be on the value first character
|
|
Returns a NSString
|
|
**/
|
|
-(id)parseValueAsAssociation:(BOOL)asAssociation
|
|
{
|
|
id value=nil;
|
|
NSAssert(_index<_length,@"Reached buffer end parsing an identifier");
|
|
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
|
|
switch(_uniBuf[_index])
|
|
{
|
|
case '"': // a quoted string
|
|
value=parseQuotedString(self);
|
|
if (value && asAssociation)
|
|
value=[GSWAssociation associationWithValue:value];
|
|
break;
|
|
case '<': // a data coded as hex
|
|
value=parseHexData(self);
|
|
if (value && asAssociation)
|
|
value=[GSWAssociation associationWithValue:value];
|
|
break;
|
|
case '{': // a dictionary
|
|
value=parseDictionaryWithValuesAsAssociations(self,NO);
|
|
if (value && asAssociation)
|
|
value=[GSWAssociation associationWithValue:value];
|
|
break;
|
|
case '(': // an array
|
|
value=parseArray(self);
|
|
if (value && asAssociation)
|
|
value=[GSWAssociation associationWithValue:value];
|
|
break;
|
|
case '#':
|
|
value=parseHexNumber(self);
|
|
if (value && asAssociation)
|
|
value=[GSWAssociation associationWithValue:value];
|
|
break;
|
|
default:
|
|
value=tryParseBoolean(self);
|
|
if (value)
|
|
{
|
|
if (asAssociation)
|
|
value=[GSWAssociation associationWithValue:value];
|
|
}
|
|
else
|
|
{
|
|
// Number ?
|
|
if (_parserIsDigit(_uniBuf[_index])
|
|
|| _uniBuf[_index]=='-'
|
|
|| _uniBuf[_index]=='+')
|
|
{
|
|
value=parseNumber(self);
|
|
if (value && asAssociation)
|
|
value=[GSWAssociation associationWithValue:value];
|
|
}
|
|
else
|
|
{
|
|
value=parseKeyPath(self);
|
|
if (value && asAssociation)
|
|
value=[GSWAssociation associationWithKeyPath:value];
|
|
};
|
|
};
|
|
};
|
|
NSDebugMLog(@"value (class=%@)=%@",[value class],value);
|
|
NSDebugMLog(@"value (class=%@)=%@",[value class],value);
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
return value;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
/** Parse a dictionary.
|
|
Index should be on the value first character ('{')
|
|
Returns a NSString
|
|
**/
|
|
-(NSDictionary*)parseDictionaryWithValuesAsAssociations:(BOOL)valuesAsAssociations
|
|
{
|
|
NSMutableDictionary* dictionary=[NSMutableDictionary dictionary];
|
|
BOOL end=NO;
|
|
int startIndex=_index;
|
|
|
|
NSAssert(_index<_length,@"Reached buffer end parsing an dictionary");
|
|
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
|
|
NSAssert1(_uniBuf[_index]=='{',@"Dictionary first character is not a '{' but a %c",(char)_uniBuf[_index]);
|
|
|
|
_index++; // skip '{'
|
|
while(!end && _index<_length)
|
|
{
|
|
int keyStartIndex=_index;
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
|
|
// Parse Key
|
|
skipBlanksAndComments(self);
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
|
|
if (_index<_length)
|
|
{
|
|
if (_uniBuf[_index]=='}')
|
|
{
|
|
_index++;
|
|
end=YES;
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
}
|
|
else
|
|
{
|
|
NSString* key=nil;
|
|
key=parseKeyPath(self);
|
|
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,_length);
|
|
skipBlanksAndComments(self);
|
|
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,_length);
|
|
if (_index>=_length)
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEUnexpectedBufferEnd
|
|
format:@"In %@ %@: Reached buffer end while trying to parse value of a dictionary entry at line %d",
|
|
_frameworkName,_fileName,
|
|
[self lineIndexFromIndex:keyStartIndex]];
|
|
}
|
|
else if (_uniBuf[_index]=='=')
|
|
{
|
|
_index++;
|
|
|
|
skipBlanksAndComments(self);
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,_length);
|
|
|
|
if (_index>=_length)
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEUnexpectedBufferEnd
|
|
format:@"In %@ %@: Reached buffer end while trying to parse value of a dictionary entry at line %d",
|
|
_frameworkName,_fileName,
|
|
[self lineIndexFromIndex:keyStartIndex]];
|
|
}
|
|
else
|
|
{
|
|
id value=nil;
|
|
value=parseValueAsAssociation(self,valuesAsAssociations);
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,_length);
|
|
|
|
if (value)
|
|
[dictionary setObject:value
|
|
forKey:key];
|
|
else
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEMissingValue
|
|
format:@"In %@ %@: No value for key '%@' at line %d",
|
|
_frameworkName,_fileName,
|
|
key,[self lineIndexFromIndex:keyStartIndex]];
|
|
};
|
|
|
|
skipBlanksAndComments(self);
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,_length);
|
|
if (_index>=_length)
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEUnexpectedBufferEnd
|
|
format:@"In %@ %@: Reached buffer end while parse dictionary starting at %d",
|
|
_frameworkName,_fileName,
|
|
[self lineIndexFromIndex:keyStartIndex]];
|
|
}
|
|
else if (_uniBuf[_index]==';')
|
|
{
|
|
_index++;
|
|
};
|
|
};
|
|
}
|
|
else
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEMissingSeparator
|
|
format:@"In %@ %@: No '=' sign when parsing dictionary entry (key = '%@') at line %d but '%c'",
|
|
_frameworkName,_fileName,
|
|
key,[self lineIndexFromIndex:keyStartIndex],(char)_uniBuf[_index]];
|
|
};
|
|
};
|
|
}
|
|
else
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEUnexpectedBufferEnd
|
|
format:@"In %@ %@: Reached buffer end while trying to parse dictionary started at line %d",
|
|
_frameworkName,_fileName,
|
|
[self lineIndexFromIndex:startIndex]];
|
|
};
|
|
if (_index==startIndex)
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEDictionaryParsingError
|
|
format:@"In %@ %@: Found nothing when parsing dictionary at line %d",
|
|
_frameworkName,_fileName,
|
|
[self lineIndexFromIndex:startIndex]];
|
|
};
|
|
}
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
return dictionary;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
/** Parse an array.
|
|
Index should be on the value first character ('(')
|
|
Returns a NSString
|
|
**/
|
|
-(NSArray*)parseArray
|
|
{
|
|
NSMutableArray* array=[NSMutableArray array];
|
|
BOOL end=NO;
|
|
int startIndex=_index;
|
|
|
|
NSAssert(_index<_length,@"Reached buffer end parsing an array");
|
|
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
|
|
NSAssert1(_uniBuf[_index]=='(',@"Array first character is not a '(' but a '%c'",(char)_uniBuf[_index]);
|
|
|
|
_index++; // skip '('
|
|
while(!end && _index<_length)
|
|
{
|
|
int valueStartIndex=_index;
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
|
|
// Parse Value
|
|
skipBlanksAndComments(self);
|
|
if (_index<_length)
|
|
{
|
|
if (_uniBuf[_index]==')')
|
|
{
|
|
_index++;
|
|
end=YES;
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
}
|
|
else
|
|
{
|
|
id value=parseValueAsAssociation(self,NO);
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,_length);
|
|
|
|
if (value)
|
|
[array addObject:value];
|
|
else
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEMissingValue
|
|
format:@"IN %@ %@: No value at line %d",
|
|
_frameworkName,_fileName,
|
|
[self lineIndexFromIndex:valueStartIndex]];
|
|
};
|
|
|
|
skipBlanksAndComments(self);
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,_length);
|
|
if (_index>=_length)
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEUnexpectedBufferEnd
|
|
format:@"In %@ %@: Reached buffer end parsing array line %d",
|
|
_frameworkName,_fileName,
|
|
[self lineIndexFromIndex:startIndex]];
|
|
}
|
|
else if (_uniBuf[_index]==',')
|
|
{
|
|
NSDebugMLog(@"Found ','");
|
|
_index++;
|
|
}
|
|
else
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEUnexpectedCharacter
|
|
format:@"In %@ %@: Bad character '%c' parsing array line %d",
|
|
_frameworkName,_fileName,
|
|
(char)_uniBuf[_index],[self lineIndexFromIndex:startIndex]];
|
|
};
|
|
}
|
|
}
|
|
else
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEUnexpectedBufferEnd
|
|
format:@"In %@ %@: Reached buffer end while trying to parse array started at line %d",
|
|
_frameworkName,_fileName,
|
|
[self lineIndexFromIndex:startIndex]];
|
|
};
|
|
|
|
if (_index==valueStartIndex)
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEArrayParsingError
|
|
format:@"In %@ %@: Found nothing when parsing array at line %d",
|
|
_frameworkName,_fileName,
|
|
[self lineIndexFromIndex:startIndex]];
|
|
};
|
|
}
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
return array;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
/** Parse a declaration.
|
|
Index should be on the identifier first character
|
|
Returns a GSWDeclaration.
|
|
**/
|
|
-(GSWDeclaration*)parseDeclaration
|
|
{
|
|
GSWDeclaration* declaration=nil;
|
|
NSString* identifier=nil;
|
|
|
|
NSAssert(_index<_length,@"Reached buffer end parsing a declaration");
|
|
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
identifier=parseIdentifier(self);
|
|
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
skipBlanksAndComments(self);
|
|
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
if (_index>=_length)
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEUnexpectedBufferEnd
|
|
format:@"In %@ %@: End of buffer before getting declaration type for '%@' line %d",
|
|
_frameworkName,_fileName,
|
|
identifier,[self currentLineIndex]];
|
|
}
|
|
else if (_uniBuf[_index]==':')
|
|
{
|
|
NSString* type=nil;
|
|
NSDictionary* associations=nil;
|
|
_index++;
|
|
skipBlanksAndComments(self);
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
type=parseIdentifier(self);
|
|
skipBlanksAndComments(self);
|
|
if (_index>=_length)
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEUnexpectedBufferEnd
|
|
format:@"In %@ %@: End of buffer before getting declaration bindings for '%@' (type '%@') line %d",
|
|
_frameworkName,_fileName,
|
|
identifier,type,[self currentLineIndex]];
|
|
}
|
|
else if (_uniBuf[_index]=='{')
|
|
{
|
|
associations=parseDictionaryWithValuesAsAssociations(self,YES);
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
skipBlanksAndComments(self);
|
|
if (_index<_length)
|
|
{
|
|
if (_uniBuf[_index]==';')
|
|
{
|
|
_index++;
|
|
};
|
|
};
|
|
//else no bindings dictionary
|
|
declaration=[GSWDeclaration declarationWithName:identifier
|
|
type:type
|
|
associations:associations];
|
|
}
|
|
else
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEUnexpectedCharacter
|
|
format:@"In %@ %@: Don't know what do do with '%c' line %d.",
|
|
_frameworkName,_fileName,
|
|
(char)_uniBuf[_index],[self currentLineIndex]];
|
|
}
|
|
else if (_uniBuf[_index]=='=') // Alias like Identifier1=Identifier2;
|
|
{
|
|
NSString* aliasedIdentifier=nil;
|
|
GSWDeclaration* aliasedDeclaration=nil;
|
|
_index++;
|
|
skipBlanksAndComments(self);
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
aliasedIdentifier=parseIdentifier(self);
|
|
skipBlanksAndComments(self);
|
|
if (_index<_length)
|
|
{
|
|
if (_uniBuf[_index]==';')
|
|
{
|
|
_index++;
|
|
};
|
|
};
|
|
NSDebugMLog(@"aliasedIdentifier=%@",aliasedIdentifier);
|
|
aliasedDeclaration=[_declarations objectForKey:aliasedIdentifier];
|
|
if (aliasedDeclaration)
|
|
{
|
|
declaration=[GSWDeclaration declarationWithName:identifier
|
|
type:[aliasedDeclaration type]
|
|
associations:[aliasedDeclaration associations]];
|
|
}
|
|
else
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEMissingAliasedDeclaration
|
|
format:@"In %@ %@: Can't find declaration named '%@' to be aliased as '%@'. line %d.",
|
|
_frameworkName,_fileName,
|
|
aliasedIdentifier,identifier,
|
|
[self currentLineIndex]];
|
|
};
|
|
}
|
|
else
|
|
{
|
|
[GSWDeclarationFormatException
|
|
raise:GSWDFEMissingSeparator
|
|
format:@"In %@ %@: No ':' delimiter while parsing declaration for '%@' line %d. Found '%c'",
|
|
_frameworkName,_fileName,
|
|
identifier,[self currentLineIndex],(char)_uniBuf[_index]];
|
|
};
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
return declaration;
|
|
};
|
|
|
|
// those are here because a protocol forces us to implement them -- dw
|
|
|
|
- (id) retain
|
|
{
|
|
return [super retain];
|
|
}
|
|
|
|
- (oneway void)release
|
|
{
|
|
return [super release];
|
|
}
|
|
|
|
- (id)autorelease
|
|
{
|
|
return [super autorelease];
|
|
}
|
|
|
|
@end
|
|
|