/** GSWTemplateParserANTLR.m - GSWeb: Class GSWTemplateParserANTLR Copyright (C) 1999-2004 Free Software Foundation, Inc. Written by: Manuel Guesdon Date: Mar 1999 $Revision$ $Date$ $Id$ This file is part of the GNUstep Web Library. 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. **/ #include "config.h" RCS_ID("$Id$") #include "GSWeb.h" #include "GSWTemplateParserANTLR.h" //==================================================================== @implementation GSWTemplateParserANTLR -(void)dealloc { DESTROY(_tagsNames); DESTROY(_tagsAttrs); [super dealloc]; }; -(NSArray*)templateElements { NSArray* elements=nil; id htmlAST=nil; NSAutoreleasePool* arpParse=nil; ANTLRTextInputStreamString* htmlStream=nil; GSWHTMLLexer* htmlLexer=nil; ANTLRTokenBuffer* htmlTokenBuffer=nil; GSWHTMLParser* htmlParser=nil; LOGObjectFnStart(); NSDebugMLLog(@"low",@"template named:%@ frameworkName:%@ pageDefString=%@", _templateName, _frameworkName, _declarationsString); //TODO remove /* [ANTLRCharBuffer setTraceFlag_LA:YES]; [ANTLRCharScanner setTraceFlag_LA:YES]; [ANTLRLLkParser setTraceFlag_LA:YES]; [ANTLRTokenBuffer setTraceFlag_LA:YES]; */ htmlStream=[[ANTLRTextInputStreamString newWithString:_string] autorelease]; htmlLexer=[[[GSWHTMLLexer alloc]initWithTextStream:htmlStream] autorelease]; htmlTokenBuffer=[ANTLRTokenBuffer tokenBufferWithTokenizer:htmlLexer]; htmlParser=[[[GSWHTMLParser alloc] initWithTokenBuffer:htmlTokenBuffer] autorelease]; NSDebugMLLog(@"low",@"template named:%@ HTMLString=%@", _templateName, _string); arpParse=[NSAutoreleasePool new]; NS_DURING { [htmlParser document]; if ([htmlParser isError]) { LOGError(@"Parser Errors : %@",[htmlParser errors]); ExceptionRaise(@"GSWTemplateParser", @"GSWTemlateParser: Errors in HTML parsing template named %@: %@\nAST:\n%@", _templateName, [htmlParser errors], [htmlParser AST]); }; htmlAST=[htmlParser AST]; NSDebugMLLog0(@"low",@"HTML Parse OK!"); } NS_HANDLER { LOGError(@"template named:%@ HTML Parse failed!",_templateName); localException=ExceptionByAddingUserInfoObjectFrameInfo(localException,@"In [htmlParser document]... template named:%@ HTML Parse failed!",_templateName); RETAIN(localException); DESTROY(arpParse); AUTORELEASE(localException); [localException raise]; } NS_ENDHANDLER; [htmlAST retain]; DESTROY(arpParse); arpParse=[NSAutoreleasePool new]; [htmlAST autorelease]; if (htmlAST) { _tagsNames=[[NSMutableDictionary dictionary] retain]; _tagsAttrs=[[NSMutableDictionary dictionary] retain]; NS_DURING { elements=[self createElementsStartingWithAST:&htmlAST stopOnTagNamed:nil]; NSDebugMLLog(@"low",@"template named:%@ _template=%@", _templateName, elements); } NS_HANDLER { LOGSeriousError(@"template named:%@ createElements failed!", _templateName); localException=ExceptionByAddingUserInfoObjectFrameInfo0(localException, @"In createElementsStartingWithAST..."); RETAIN(localException); DESTROY(arpParse); AUTORELEASE(localException); [localException raise]; } NS_ENDHANDLER; }; [elements retain]; DESTROY(arpParse); [elements autorelease]; NSDebugMLLog0(@"low",@"Display Template\n"); NSDebugMLLog(@"low",@"template named:%@ elements=%@", _templateName, elements); LOGClassFnStop(); return elements; }; //-------------------------------------------------------------------- -(BOOL)parseTag:(ANTLRDefAST)anAST { BOOL htmlAttrParseOK=YES; NSString* tagName=[_tagsNames objectForKey:[NSNumber numberWithUnsignedLong:(unsigned long)anAST]]; //TODO bad hack LOGClassFnStart(); if (!tagName && ([anAST tokenType]==GSWHTMLTokenType_OPENTAG || [anAST tokenType]==GSWHTMLTokenType_CLOSETAG)) { NSAutoreleasePool* arpParse=nil; ANTLRTextInputStreamString* _tagStream=[[[ANTLRTextInputStreamString alloc] initWithString:[anAST text]] autorelease]; GSWHTMLAttrLexer* htmlAttrLexer=[[[GSWHTMLAttrLexer alloc] initWithTextStream:_tagStream] autorelease]; ANTLRTokenBuffer* htmlAttrTokenBuffer=[ANTLRTokenBuffer tokenBufferWithTokenizer:htmlAttrLexer]; GSWHTMLAttrParser* _tagParser=[[[GSWHTMLAttrParser alloc] initWithTokenBuffer:htmlAttrTokenBuffer] autorelease]; NSString* tagName=nil; NSDictionary* tagAttrs=nil; NSDebugMLLog(@"low",@"PARSE:[%@]",[anAST text]); NSDebugMLLog(@"low",@"stream:[%@]",_tagStream); htmlAttrParseOK=NO; arpParse=[NSAutoreleasePool new]; NS_DURING { [_tagParser tag]; if ([_tagParser isError]) { LOGError(@"Parser Errors : %@",[_tagParser errors]); ExceptionRaise(@"GSWTemplateParser", @"GSWTemlateParser: Errors in HTML Tag parsing: %@", [_tagParser errors]); }; tagName=[_tagParser tagName]; tagAttrs=[_tagParser attributes]; NSDebugMLLog(@"low",@"tagName=%@ tagAttrs=%@", tagName, tagAttrs); htmlAttrParseOK=YES; } NS_HANDLER { htmlAttrParseOK=NO; LOGError(@"PARSE PB:[%@]",[anAST text]);//TODO localException=ExceptionByAddingUserInfoObjectFrameInfo0(localException, @"In [_tagParser tag]..."); RETAIN(localException); DESTROY(arpParse); AUTORELEASE(localException); [localException raise]; } NS_ENDHANDLER; DESTROY(arpParse); NSDebugMLLog(@"low",@"END PARSE:[%@]",[anAST text]); if (htmlAttrParseOK && tagName) { NSDebugMLLog(@"low",@"tagName:[%@]",tagName); if ([tagName hasPrefix:@"\""] && [tagName hasSuffix:@"\""]) tagName=[[tagName stringByDeletingPrefix:@"\""]stringByDeletingSuffix:@"\""]; NSDebugMLLog(@"low",@"Add tagName:[%@]", tagName); [_tagsNames setObject:tagName forKey:[NSNumber numberWithUnsignedLong:(unsigned long)anAST]]; //TODO bad hack NSDebugMLLog(@"low",@"Verify tagName=%@", [_tagsNames objectForKey:[NSNumber numberWithUnsignedLong:(unsigned long)anAST]]); //TODO bad hack NSDebugMLLog(@"low",@"Add tagsAttrs:[%@]", tagAttrs); if (tagAttrs) { [_tagsAttrs setObject:tagAttrs forKey:[NSNumber numberWithUnsignedLong:(unsigned long)anAST]]; //TODO bad hack NSDebugMLLog(@"low",@"Verify tagAttrs=%@", [_tagsAttrs objectForKey:[NSNumber numberWithUnsignedLong:(unsigned long)anAST]]); //TODO bad hack }; }; }; LOGClassFnStop(); return htmlAttrParseOK; }; //-------------------------------------------------------------------- -(NSString*)getTagNameFor:(ANTLRDefAST)anAST { NSString* tagName=[_tagsNames objectForKey: [NSNumber numberWithUnsignedLong:(unsigned long)anAST]]; //TODO bad hack LOGClassFnStart(); NSDebugMLLog(@"low",@"[%@]",[anAST text]); if (!tagName) { BOOL htmlAttrParseOK=[self parseTag:anAST]; if (htmlAttrParseOK) tagName=[_tagsNames objectForKey: [NSNumber numberWithUnsignedLong:(unsigned long)anAST]]; //TODO bad hack }; NSDebugMLLog(@"low",@"tagName:[%@]",tagName); LOGClassFnStop(); return tagName; }; //-------------------------------------------------------------------- -(NSDictionary*)getTagAttrsFor:(ANTLRDefAST)anAST { NSDictionary* tagAttrs=[_tagsAttrs objectForKey: [NSNumber numberWithUnsignedLong:(unsigned long)anAST]]; //TODO bad hack LOGClassFnStart(); NSDebugMLLog(@"low",@"[%@]",[anAST text]); if (!tagAttrs) { BOOL htmlAttrParseOK=[self parseTag:anAST]; if (htmlAttrParseOK) tagAttrs=[_tagsAttrs objectForKey: [NSNumber numberWithUnsignedLong:(unsigned long)anAST]]; //TODO bad hack }; NSDebugMLLog(@"low",@"tagAttrs:[%@]",tagAttrs); LOGClassFnStop(); return tagAttrs; }; //-------------------------------------------------------------------- -(NSArray*)createElementsStartingWithAST:(ANTLRDefAST*)anAST stopOnTagNamed:(NSString*)stopTagName { NSMutableArray* elements=[NSMutableArray array]; ANTLRDefAST currentAST=*anAST; BOOL end=NO; BOOL inHTMLBareString=NO; NSMutableString* htmlBareString=nil; LOGClassFnStart(); NSDebugMLLog(@"low",@"stopTagName:[%@]",stopTagName); while(currentAST && !end) { GSWElement* element=nil; NSString* tagName=nil; NSDictionary* tagAttrs=nil; BOOL stopBareString=NO; NSDebugMLLog(@"low",@"[currentAST: text=[%@] Type=%d", [currentAST text], [currentAST tokenType]); NSDebugMLLog(@"low",@"end=%s inHTMLBareString=%s stopBareString=%s", end ? "YES" : "NO", inHTMLBareString ? "YES" : "NO", stopBareString ? "YES" : "NO"); if ([currentAST tokenType]==GSWHTMLTokenType_OPENTAG || [currentAST tokenType]==GSWHTMLTokenType_CLOSETAG) { tagName=[self getTagNameFor:currentAST]; NSDebugMLLog(@"low",@"Result tagName:[%@]",tagName); if (!tagName) { LOGError0(@"");//TODO } else { NSDebugMLLog(@"low",@"[currentAST tokenType]=%d",(int)[currentAST tokenType]); if ([currentAST tokenType]==GSWHTMLTokenType_OPENTAG) { NSDebugMLLog0(@"low",@"Found Open Tag"); tagAttrs=[self getTagAttrsFor:currentAST]; NSDebugMLLog(@"low",@"tagAttrs=%@",tagAttrs); if ([tagName caseInsensitiveCompare:GSWTag_Name[GSWNAMES_INDEX]]==NSOrderedSame || [tagName caseInsensitiveCompare:GSWTag_Name[WONAMES_INDEX]]==NSOrderedSame) { NSDebugMLLog0(@"low",@"Found GSWeb Tag"); NSDebugMLLog(@"low",@"tagAttrs=%@", tagAttrs); if (inHTMLBareString) { NSDebugMLLog0(@"low",@"==>Stop BareString"); stopBareString=YES; } else { ANTLRDefAST nextAST=[currentAST nextSibling]; NSString* name=[tagAttrs objectForKey:@"name"]; NSDebugMLLog0(@"low",@"Process GSWeb Tag"); NSDebugMLLog(@"low",@"GSWeb Tag: name:[%@]", name); if (!name) { LOGError(@"No name for Element:%@", [currentAST text]);//TODO ExceptionRaise(@"GSWTemplateParser", @"GSWTemlateParser: no name for GNUstepWeb tag in template named %@", _templateName); } else { GSWDeclaration* declaration=[_declarations objectForKey:name]; NSDebugMLLog(@"low",@"declaration:[%@]", declaration); NSDebugMLLog(@"low",@"GSWeb Tag declaration:[%@]", declaration); if (declaration) { NSDictionary* _associations=[declaration associations]; NSString* className=nil; className=[declaration type]; NSDebugMLLog(@"low",@"GSWeb Tag className:[%@]", className); if (className) { NSArray* children=nil; children=[self createElementsStartingWithAST:&nextAST stopOnTagNamed:tagName]; NSDebugMLLog(@"low",@"CREATE Element of Class:%@",className); NSDebugMLLog(@"low",@"children:%@",children); NSDebugMLLog(@"low",@"associations:%@",_associations); { NSEnumerator* _tagAttrsEnum = [tagAttrs keyEnumerator]; id _tagAttrKey=nil; id _tagAttrValue=nil; NSMutableDictionary* _addedAssoc=nil; while ((_tagAttrKey = [_tagAttrsEnum nextObject])) { if (![_tagAttrKey isEqualToString:@"name"] && ![_associations objectForKey:_tagAttrKey]) { if (!_addedAssoc) _addedAssoc=(NSMutableDictionary*)[NSMutableDictionary dictionary]; _tagAttrValue=[tagAttrs objectForKey:_tagAttrKey]; [_addedAssoc setObject:[GSWAssociation associationWithValue:_tagAttrValue] forKey:_tagAttrKey]; }; }; if (_addedAssoc) { _associations=[_associations dictionaryByAddingEntriesFromDictionary:_addedAssoc]; }; }; element=[GSWApp dynamicElementWithName:className associations:_associations template:[[[GSWHTMLStaticGroup alloc]initWithContentElements:children]autorelease] languages:_languages]; if (element) [element setDeclarationName:[declaration name]]; else { ExceptionRaise(@"GSWTemplateParser", @"GSWTemplateParser: Creation failed for element named:%@ className:%@ in template named %@", [declaration name], className, _templateName); }; } else { ExceptionRaise(@"GSWTemplateParser", @"GSWTemplateParser: No class name in page definition for tag named:%@ declaration=%@ in template named %@", name, declaration, _templateName); }; } else { ExceptionRaise(@"GSWTemplateParser", @"No element definition for tag named:%@ in template named %@", name, _templateName); }; }; currentAST=nextAST; }; }; } else { if (stopTagName && [tagName caseInsensitiveCompare:stopTagName]==NSOrderedSame) { NSDebugMLLog(@"low",@"stopTagName found: %@",stopTagName); end=YES; stopBareString=YES; currentAST=[currentAST nextSibling]; }; }; }; } else if ([currentAST tokenType]==GSWHTMLTokenType_COMMENT) { stopBareString=YES; element=[GSWHTMLComment elementWithString:[currentAST text]]; currentAST=[currentAST nextSibling]; } NSDebugMLLog(@"low",@"end=%s inHTMLBareString=%s stopBareString=%s", end ? "YES" : "NO", inHTMLBareString ? "YES" : "NO", stopBareString ? "YES" : "NO"); if (!element && !end && !stopBareString) { NSDebugMLLog0(@"low",@"!element && !end && !stopBareString"); if (!inHTMLBareString) { NSDebugMLLog0(@"low",@"!inHTMLBareString ==> inHTMLBareString=YES"); inHTMLBareString=YES; htmlBareString=[[NSMutableString new] autorelease]; }; NSDebugMLLog(@"low",@"inHTMLBareString: adding [%@]",[currentAST text]); if ([currentAST tokenType]==GSWHTMLTokenType_OPENTAG) [htmlBareString appendFormat:@"<%@>",[currentAST text]]; else if ([currentAST tokenType]==GSWHTMLTokenType_CLOSETAG) [htmlBareString appendFormat:@"",[currentAST text]]; else [htmlBareString appendString:[currentAST text]]; NSDebugMLLog(@"low",@"htmlBareString: ==> [%@]",htmlBareString); currentAST=[currentAST nextSibling]; }; if (inHTMLBareString && (stopBareString || !currentAST)) { NSDebugMLLog0(@"low",@"inHTMLBareString && stopBareString"); NSDebugMLLog(@"low",@"CREATE GSWHTMLBareString:\n%@",htmlBareString); element=[GSWHTMLBareString elementWithString:htmlBareString]; NSDebugMLLog(@"low",@"element:%@",element); htmlBareString=nil; inHTMLBareString=NO; }; if (element) { NSDebugMLLog(@"low",@"element to add: element=[%@]",element); [elements addObject:element]; element=nil; }; NSDebugMLLog(@"low",@"element:%@",element); NSDebugMLLog(@"low",@"inHTMLBareString:%d",(int)inHTMLBareString); NSDebugMLLog(@"low",@"htmlBareString:%@",htmlBareString); }; *anAST=currentAST; NSDebugMLLog(@"low",@"elements]:%@",elements); LOGClassFnStop(); return elements; }; @end