mirror of
https://github.com/gnustep/libs-gsweb.git
synced 2025-02-22 19:21:23 +00:00
o added (New HTML Template Parser) * GSWeb.framework/GSWHTMLRawParser.m/.h: o aded (New HTML Parser) * GSWeb.framework/GSWDeclaration.h/.m: o added (Handle a declaration i.e. an entry from .gswd) * GSWeb.framework/GSWDeclarationParser.h/.m: o added (.gswd parser) * GSWeb.framework/GSWBaseParser.h/.m: o added (base class for parsers) * GSWeb.framework/GSWTemporaryElement.h/.m: o added (Temporary element to handle dynamic tags) git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gsweb/trunk@18891 72102866-910b-0410-8b05-ffd578937521
1048 lines
32 KiB
Objective-C
1048 lines
32 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"
|
|
|
|
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;
|
|
};
|
|
};
|
|
|
|
|
|
//====================================================================
|
|
@implementation GSWDeclarationParser
|
|
|
|
//--------------------------------------------------------------------
|
|
+(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;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
-(void)dealloc
|
|
{
|
|
DESTROY(_pragmaDelegate);
|
|
DESTROY(_declarations);
|
|
DESTROY(_fileName);
|
|
DESTROY(_frameworkName);
|
|
|
|
[super dealloc];
|
|
};
|
|
|
|
-(NSDictionary*)parseDeclarationString:(NSString*)declarationString
|
|
named:(NSString*)declarationFileName
|
|
inFrameworkNamed:(NSString*)declarationFrameworkName
|
|
{
|
|
LOGObjectFnStart();
|
|
|
|
if (_declarations)
|
|
[_declarations removeAllObjects];
|
|
else
|
|
_declarations=(NSMutableDictionary*)[NSMutableDictionary new];
|
|
|
|
ASSIGN(_string,declarationString);
|
|
ASSIGN(_fileName,declarationFileName);
|
|
ASSIGN(_frameworkName,declarationFrameworkName);
|
|
|
|
NSDebugMLog(@"declarationString=%@",declarationString);
|
|
_length=[_string length];
|
|
|
|
_uniBuf = (unichar*)objc_malloc(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);
|
|
[self skipBlanksAndComments];
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
if (_index<_length)
|
|
{
|
|
if (_uniBuf[_index]=='#')
|
|
{
|
|
[self parsePragma];
|
|
NSDebugMLog(@"index=%d _length=%d",_index,20);
|
|
}
|
|
else if (_parserIsIdentifierChar(_uniBuf[_index]))
|
|
{
|
|
GSWDeclaration* declaration=[self parseDeclaration];
|
|
NSDebugMLog(@"declaration=%@",declaration);
|
|
[_declarations setObject:declaration
|
|
forKey:[declaration name]];
|
|
NSDebugMLog(@"index=%d _length=%d",_index,20);
|
|
}
|
|
else
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"No identifier %@",
|
|
[self currentLineAndColumnIndexesString]];
|
|
};
|
|
};
|
|
}
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
}
|
|
NS_HANDLER
|
|
{
|
|
if (_uniBuf)
|
|
{
|
|
objc_free(_uniBuf);
|
|
_uniBuf=NULL;
|
|
};
|
|
[localException raise];
|
|
};
|
|
NS_ENDHANDLER;
|
|
|
|
NSDebugMLog(@"_declarations=%@",_declarations);
|
|
|
|
LOGObjectFnStop();
|
|
|
|
return _declarations;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
-(NSDictionary*)parseDeclarationString:(NSString*)declarationString
|
|
{
|
|
NSDictionary* declarations=nil;
|
|
LOGObjectFnStart();
|
|
|
|
declarations=[self parseDeclarationString:declarationString
|
|
named:nil
|
|
inFrameworkNamed:nil];
|
|
|
|
LOGObjectFnStop();
|
|
|
|
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=[self skipBlanks];
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
if ([self skipComment])
|
|
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)
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"No pragma delegate for pragma directive '%@'"];
|
|
}
|
|
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
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"unknown pragma directive '%@' at line %@",
|
|
[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)
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"No identifier %@",
|
|
[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 [self parseIdentifier];
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
/** Parse a quoted string.
|
|
Index should be on the value first character (")
|
|
Returns a NSString without '"' pefix and suffix
|
|
**/
|
|
-(id)parseQuotedString
|
|
{
|
|
NSString* string=nil;
|
|
int startIndex=_index;
|
|
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]!='"')
|
|
{
|
|
_index++;
|
|
};
|
|
if (_index<_length && _uniBuf[_index]=='"')
|
|
_index++;
|
|
else
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"No end '\"' for quoted string starting at line %d",
|
|
[self lineIndexFromIndex:startIndex]];
|
|
};
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
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
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"No end '>' for data starting at line %d",
|
|
[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
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"No end '\'' for keyPath starting at line %d",
|
|
[self lineIndexFromIndex:startIndex]];
|
|
};
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
break;
|
|
case '\"':
|
|
_index++;
|
|
while(_index<_length
|
|
&& _uniBuf[_index]!='\"')
|
|
{
|
|
_index++;
|
|
};
|
|
if (_index<_length && _uniBuf[_index]=='\"')
|
|
_index++;
|
|
else
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"No end '\"' for keyPath starting at line %d",
|
|
[self lineIndexFromIndex:startIndex]];
|
|
};
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
break;
|
|
case '.':
|
|
if (_index==startIndex)
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"keyPath can't begin with '.' line %d",
|
|
[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)
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"Empty keyPath at line %d",
|
|
[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 value
|
|
Index should be on the value first character
|
|
Returns a NSString
|
|
**/
|
|
-(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 (_uniBuf[_index]=='Y' || _uniBuf[_index]=='N')
|
|
{
|
|
int i=(_index)+1;
|
|
while(i<_length
|
|
&& _parserIsIdentifierChar(_uniBuf[i]))
|
|
i++;
|
|
switch(i-_index)
|
|
{
|
|
case 1:
|
|
if (_uniBuf[(_index)]=='Y')
|
|
{
|
|
value=[NSNumber numberWithBool:YES];
|
|
_index++;
|
|
}
|
|
else if (_uniBuf[(_index)]=='N')
|
|
{
|
|
value=[NSNumber numberWithBool:NO];
|
|
_index++;
|
|
};
|
|
break;
|
|
case 2:
|
|
if (_uniBuf[(_index)+1]=='O')
|
|
{
|
|
value=[NSNumber numberWithBool:NO];
|
|
_index+=2;
|
|
};
|
|
break;
|
|
case 3:
|
|
if (_uniBuf[(_index)+1]=='E'
|
|
&& _uniBuf[(_index)+2]=='S')
|
|
{
|
|
value=[NSNumber numberWithBool:YES];
|
|
_index+=3;
|
|
};
|
|
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)
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"Bad number line %d",
|
|
[self lineIndexFromIndex:startIndex]];
|
|
};
|
|
};
|
|
while(!end && _index<_length)
|
|
{
|
|
if (_parserIsDigit(_uniBuf[_index]))
|
|
_index++;
|
|
else if (_uniBuf[_index]=='.')
|
|
{
|
|
if (seenDot)
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"2 dots in a number line %d",
|
|
[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=[NSNumber numberWithInt:[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 cString];
|
|
intValue=strtol(cString,&endPtr,16);
|
|
NSDebugMLog(@"cString='%s' endPtr='%s'",cString,endPtr);
|
|
if (endPtr && *endPtr)
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"Bad hex number line %d",
|
|
[self lineIndexFromIndex:startIndex]];
|
|
};
|
|
value=[NSNumber numberWithInt: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=[self parseQuotedString];
|
|
if (value && asAssociation)
|
|
value=[GSWAssociation associationWithValue:value];
|
|
break;
|
|
case '<': // a data coded as hex
|
|
value=[self parseHexData];
|
|
if (value && asAssociation)
|
|
value=[GSWAssociation associationWithValue:value];
|
|
break;
|
|
case '{': // a dictionary
|
|
value=[self parseDictionaryWithValuesAsAssociations:NO];
|
|
if (value && asAssociation)
|
|
value=[GSWAssociation associationWithValue:value];
|
|
break;
|
|
case '(': // an array
|
|
value=[self parseArray];
|
|
if (value && asAssociation)
|
|
value=[GSWAssociation associationWithValue:value];
|
|
break;
|
|
case '#':
|
|
value=[self parseHexNumber];
|
|
if (value && asAssociation)
|
|
value=[GSWAssociation associationWithValue:value];
|
|
break;
|
|
default:
|
|
value=[self tryParseBoolean];
|
|
if (value)
|
|
{
|
|
if (asAssociation)
|
|
value=[GSWAssociation associationWithValue:value];
|
|
}
|
|
else
|
|
{
|
|
// Number ?
|
|
if (_parserIsDigit(_uniBuf[_index])
|
|
|| _uniBuf[_index]=='-'
|
|
|| _uniBuf[_index]=='+')
|
|
{
|
|
value=[self parseNumber];
|
|
if (value && asAssociation)
|
|
value=[GSWAssociation associationWithValue:value];
|
|
}
|
|
else
|
|
{
|
|
value=[self parseKeyPath];
|
|
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
|
|
[self skipBlanksAndComments];
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
|
|
if (_index<_length)
|
|
{
|
|
if (_uniBuf[_index]=='}')
|
|
{
|
|
_index++;
|
|
end=YES;
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
}
|
|
else
|
|
{
|
|
NSString* key=nil;
|
|
key=[self parseKey];
|
|
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,_length);
|
|
[self skipBlanksAndComments];
|
|
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,_length);
|
|
if (_index>=_length)
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"Reached buffer end while trying to parse value of a dictionary entry",
|
|
[self lineIndexFromIndex:keyStartIndex]];
|
|
}
|
|
else if (_uniBuf[_index]=='=')
|
|
{
|
|
_index++;
|
|
|
|
[self skipBlanksAndComments];
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,_length);
|
|
|
|
if (_index>=_length)
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"Reached buffer end while trying to parse value of a dictionary entry",
|
|
[self lineIndexFromIndex:keyStartIndex]];
|
|
}
|
|
else
|
|
{
|
|
id value=nil;
|
|
value=[self parseValueAsAssociation:valuesAsAssociations];
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,_length);
|
|
|
|
if (value)
|
|
[dictionary setObject:value
|
|
forKey:key];
|
|
else
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"No value for key '%@' at line %d",
|
|
key,[self lineIndexFromIndex:keyStartIndex]];
|
|
};
|
|
|
|
[self skipBlanksAndComments];
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,_length);
|
|
if (_index>=_length)
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"Reached buffer end while parse dictionary starting at %d",
|
|
[self lineIndexFromIndex:keyStartIndex]];
|
|
}
|
|
else if (_uniBuf[_index]==';')
|
|
{
|
|
_index++;
|
|
};
|
|
};
|
|
}
|
|
else
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"No '=' sign when parsing dictionary entry (key = '%@') at line %d but '%c'",
|
|
key,[self lineIndexFromIndex:keyStartIndex],(char)_uniBuf[_index]];
|
|
};
|
|
};
|
|
}
|
|
else
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"Reached buffer end while trying to parse dictionary started at line %d",
|
|
[self lineIndexFromIndex:startIndex]];
|
|
};
|
|
if (_index==startIndex)
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"Found nothing when parsing dictionary at line %d",
|
|
[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
|
|
[self skipBlanksAndComments];
|
|
if (_index<_length)
|
|
{
|
|
if (_uniBuf[_index]==')')
|
|
{
|
|
_index++;
|
|
end=YES;
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
}
|
|
else
|
|
{
|
|
id value=[self parseValueAsAssociation:NO];
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,_length);
|
|
|
|
if (value)
|
|
[array addObject:value];
|
|
else
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"No value at line %d",
|
|
[self lineIndexFromIndex:valueStartIndex]];
|
|
};
|
|
|
|
[self skipBlanksAndComments];
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,_length);
|
|
if (_index>=_length)
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"Reached buffer end parsing array line %d",
|
|
[self lineIndexFromIndex:startIndex]];
|
|
}
|
|
else if (_uniBuf[_index]==',')
|
|
{
|
|
NSDebugMLog(@"Found ','");
|
|
_index++;
|
|
}
|
|
else
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"Bad character '%c' parsing array line %d",
|
|
(char)_uniBuf[_index],[self lineIndexFromIndex:startIndex]];
|
|
};
|
|
}
|
|
}
|
|
else
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"Reached buffer end while trying to parse array started at line %d",
|
|
[self lineIndexFromIndex:startIndex]];
|
|
};
|
|
|
|
if (_index==valueStartIndex)
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"Found nothing when parsing array at line %d",
|
|
[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=[self parseIdentifier];
|
|
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
[self skipBlanksAndComments];
|
|
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
if (_index>=_length)
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"End of buffer before getting declaration type for '%@' line %d",
|
|
identifier,[self currentLineIndex]];
|
|
}
|
|
else if (_uniBuf[_index]==':')
|
|
{
|
|
NSString* type=nil;
|
|
NSDictionary* associations=nil;
|
|
_index++;
|
|
[self skipBlanksAndComments];
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
type=[self parseIdentifier];
|
|
[self skipBlanksAndComments];
|
|
if (_index>=_length)
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"End of buffer before getting declaration bindings for '%@' (type '%@') line %d",
|
|
identifier,type,[self currentLineIndex]];
|
|
}
|
|
else if (_uniBuf[_index]=='{')
|
|
{
|
|
associations=[self parseDictionaryWithValuesAsAssociations:YES];
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
[self skipBlanksAndComments];
|
|
if (_index<_length)
|
|
{
|
|
if (_uniBuf[_index]==';')
|
|
{
|
|
_index++;
|
|
};
|
|
};
|
|
//else no bindings dictionary
|
|
declaration=[GSWDeclaration declarationWithName:identifier
|
|
type:type
|
|
associations:associations];
|
|
}
|
|
else
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"don't know whet do do with '%c' line %d.",
|
|
(char)_uniBuf[_index],[self currentLineIndex]];
|
|
}
|
|
else
|
|
{
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"No ':' delimiter while parsing declaration for '%@' line %d. Found '%c'",
|
|
identifier,[self currentLineIndex],(char)_uniBuf[_index]];
|
|
};
|
|
//ParserDebugLogBuffer(_uniBuf,_length,_index,20);
|
|
return declaration;
|
|
};
|
|
|
|
@end
|
|
|