summaryrefslogtreecommitdiff
path: root/tikzit/src/common/TikzGraphAssembler.m
diff options
context:
space:
mode:
Diffstat (limited to 'tikzit/src/common/TikzGraphAssembler.m')
-rw-r--r--tikzit/src/common/TikzGraphAssembler.m233
1 files changed, 129 insertions, 104 deletions
diff --git a/tikzit/src/common/TikzGraphAssembler.m b/tikzit/src/common/TikzGraphAssembler.m
index 5a01036..a6f0e3d 100644
--- a/tikzit/src/common/TikzGraphAssembler.m
+++ b/tikzit/src/common/TikzGraphAssembler.m
@@ -22,15 +22,11 @@
//
#import "TikzGraphAssembler.h"
-#import "TikzGraphAssembler+Parser.h"
#import "tikzparser.h"
+#import "TikzGraphAssembler+Parser.h"
#import "tikzlexer.h"
#import "NSError+Tikzit.h"
-void yyerror(TikzGraphAssembler *assembler, const char *str) {
- [assembler invalidateWithError:str];
-}
-
@implementation TikzGraphAssembler
- (id)init {
@@ -57,6 +53,37 @@ void yyerror(TikzGraphAssembler *assembler, const char *str) {
[super dealloc];
}
+- (BOOL) parseTikz:(NSString*)t error:(NSError**)error {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ tikzStr = [t UTF8String];
+ yy_scan_string(tikzStr, scanner);
+ int result = yyparse(self);
+ tikzStr = NULL;
+
+ [pool drain];
+
+ if (result == 0) {
+ return YES;
+ } else {
+ if (error) {
+ if (lastError) {
+ *error = [[lastError retain] autorelease];
+ } else if (result == 1) {
+ *error = [NSError errorWithMessage:@"Syntax error"
+ code:TZ_ERR_PARSE];
+ } else if (result == 2) {
+ *error = [NSError errorWithMessage:@"Insufficient memory"
+ code:TZ_ERR_PARSE];
+ } else {
+ *error = [NSError errorWithMessage:@"Unknown error"
+ code:TZ_ERR_PARSE];
+ }
+ }
+ return NO;
+ }
+}
+
+ (BOOL) parseTikz:(NSString*)tikz forGraph:(Graph*)gr {
return [self parseTikz:tikz forGraph:gr error:NULL];
}
@@ -74,60 +101,15 @@ void yyerror(TikzGraphAssembler *assembler, const char *str) {
}
+ (BOOL) parseTikz:(NSString*)tikz forGraph:(Graph*)gr error:(NSError**)error {
-
if([tikz length] == 0) {
// empty string -> empty graph
return YES;
}
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
TikzGraphAssembler *assembler = [[self alloc] initWithGraph:gr];
- [assembler autorelease];
-
- /*
- lineno = 1;
- tokenpos = 0;
- NSRange range = [tikz rangeOfString:@"\n"];
- NSString *firstLine;
- if (range.length == 0) {
- firstLine = tikz;
- } else {
- firstLine = [tikz substringToIndex:range.location];
- }
- if (![firstLine getCString:linebuff
- maxLength:500
- encoding:NSUTF8StringEncoding]) {
- // first line too long; just terminate it at the end of the buffer
- linebuff[499] = 0;
- }
- */
-
- yy_scan_string([tikz UTF8String], [assembler scanner]);
- int result = yyparse(assembler);
-
- [pool drain];
- if (result == 0) {
- return YES;
- } else {
- if (error) {
- /*
- if (lastError) {
- *error = [[lastError retain] autorelease];
- } else
- */
- if (result == 1) {
- *error = [NSError errorWithMessage:@"Syntax error"
- code:TZ_ERR_PARSE];
- } else if (result == 2) {
- *error = [NSError errorWithMessage:@"Insufficient memory"
- code:TZ_ERR_PARSE];
- } else {
- *error = [NSError errorWithMessage:@"Unknown error"
- code:TZ_ERR_PARSE];
- }
- }
- return NO;
- }
+ BOOL success = [assembler parseTikz:tikz error:error];
+ [assembler release];
+ return success;
}
+ (BOOL)validateTikzPropertyNameOrValue:(NSString*)tikz {
@@ -140,7 +122,8 @@ void yyerror(TikzGraphAssembler *assembler, const char *str) {
yyset_extra(nil, scanner);
yy_scan_string([testTikz UTF8String], scanner);
YYSTYPE lval;
- yylex(&lval, scanner);
+ YYLTYPE lloc;
+ yylex(&lval, &lloc, scanner);
r = !(yyget_leng(scanner) < [testTikz length]);
yylex_destroy(scanner);
[testTikz autorelease];
@@ -148,70 +131,112 @@ void yyerror(TikzGraphAssembler *assembler, const char *str) {
return r;
}
-- (void)invalidate {
- [graph release];
- graph = nil;
- lastError = nil;
-}
-
@end
@implementation TikzGraphAssembler (Parser)
- (Graph*)graph { return graph; }
+
- (void)addNodeToMap:(Node*)n {
[nodeMap setObject:n forKey:[n name]];
}
+
- (Node*)nodeWithName:(NSString*)name {
return [nodeMap objectForKey:name];
}
-- (void) newLineStarted:(char *)text {
- /*
- strncpy(linebuff, yytext+1, 500);
- linebuff[499] = 0; // ensure null-terminated
- lineno++;
- tokenpos = 0;
- */
-}
-- (void) incrementPosBy:(size_t)amount {
- //tokenpos += amount;
+
+- (void) setLastError:(NSError*)error {
+ [error retain];
+ [lastError release];
+ lastError = error;
}
-- (void) invalidateWithError:(const char *)message {
- /*
- // if the error is on the first line, treat specially
- if([assembler lineNumber] == 1){
- //strcpy(linebuff, yytext+1);
- NSLog(@"Problem ahoy!");
- }
+- (void) reportError:(const char *)message atLocation:(YYLTYPE*)yylloc {
+ NSString *nsmsg = [NSString stringWithUTF8String:message];
- NSString *pointerStrPad = [@"" stringByPaddingToLength:(tokenpos-yyleng)
- withString:@" "
- startingAtIndex:0];
- NSString *pointerStr = [@"" stringByPaddingToLength:yyleng
- withString:@"^"
- startingAtIndex:0];
- NSLog(@"Parse error on line %i: %s\n%s\n%@\n", lineno, str, linebuff,
- [pointerStrPad stringByAppendingString:pointerStr]);
- NSDictionary *userInfo =
- [NSDictionary dictionaryWithObjectsAndKeys:
- [NSString stringWithUTF8String:str],
- NSLocalizedDescriptionKey,
- [NSNumber numberWithInt:lineno],
- @"lineNumber",
- [NSString stringWithUTF8String:linebuff],
- @"syntaxString",
- [NSNumber numberWithInt:tokenpos],
- @"tokenStart",
- [NSNumber numberWithInt:yyleng],
- @"tokenLength"];
- NSError *error =
- [NSError errorWithDomain:@"net.sourceforge.tikzit"
- code:TZ_ERR_PARSE
- userInfo:userInfo];
+ const char *first_line_start = find_start_of_nth_line (
+ tikzStr, yylloc->first_line - 1);
+ const char *last_line_start = find_start_of_nth_line (
+ first_line_start, yylloc->last_line - yylloc->first_line);
+ const char *last_line_end = last_line_start;
+ while (*last_line_end && *last_line_end != '\n') {
+ // points to just after end of last line
+ ++last_line_end;
+ }
+ const char *error_start = first_line_start + (yylloc->first_column - 1);
+ const char *error_end = last_line_start + (yylloc->last_column - 1);
- lastError = [error retain];
- */
- [self invalidate];
+ if (error_start > error_end || error_end > last_line_end) {
+ // error position state is corrupted
+ NSLog(@"Got bad error state for error \"%s\": start(%i,%i), end(%i,%i)",
+ message,
+ yylloc->first_line,
+ yylloc->first_column,
+ yylloc->last_line,
+ yylloc->last_column);
+ [self setLastError:[NSError errorWithMessage:nsmsg
+ code:TZ_ERR_PARSE]];
+ } else {
+ // +1 for null terminator
+ size_t error_text_len = last_line_end - first_line_start;
+ char *error_text = malloc (error_text_len + 1);
+ strncpy (error_text, first_line_start, error_text_len);
+ *(error_text + error_text_len) = '\0';
+
+ int error_start_pos = error_start - first_line_start;
+ int error_end_pos = error_end - first_line_start;
+
+ NSDictionary *userInfo =
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ nsmsg,
+ NSLocalizedDescriptionKey,
+ [NSNumber numberWithInt:yylloc->first_line],
+ @"startLine",
+ [NSNumber numberWithInt:yylloc->first_column],
+ @"startColumn",
+ [NSNumber numberWithInt:yylloc->last_line],
+ @"endLine",
+ [NSNumber numberWithInt:yylloc->last_column],
+ @"endColumn",
+ [NSString stringWithUTF8String:error_text],
+ @"syntaxString",
+ [NSNumber numberWithInt:error_start_pos],
+ @"tokenStart",
+ [NSNumber numberWithInt:error_end_pos],
+ @"tokenLength",
+ nil];
+ [self setLastError:
+ [NSError errorWithDomain:TZErrorDomain
+ code:TZ_ERR_PARSE
+ userInfo:userInfo]];
+
+ // we can now freely edit error_text
+ // we only bother printing out the first line
+ if (yylloc->last_line > yylloc->first_line) {
+ char *nlp = strchr(error_text, '\n');
+ if (nlp) {
+ *nlp = '\0';
+ error_text_len = nlp - error_text;
+ if (error_end_pos > error_text_len)
+ error_end_pos = error_text_len;
+ }
+ }
+ NSString *pointerLinePadding =
+ [@"" stringByPaddingToLength:error_start_pos
+ withString:@" "
+ startingAtIndex:0];
+ NSString *pointerLineCarets =
+ [@"" stringByPaddingToLength:(error_end_pos - error_start_pos)
+ withString:@"^"
+ startingAtIndex:0];
+ NSLog(@"Parse error on line %i, starting at %i: %s\n%s\n%@%@",
+ yylloc->first_line,
+ yylloc->first_column,
+ message,
+ error_text,
+ pointerLinePadding,
+ pointerLineCarets);
+ free (error_text);
+ }
}
- (void*) scanner { return scanner; }
@end