<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -55,6 +55,9 @@ PkString *kPkBuiltinErrorDomain;
  * Error Codes
  * ---------------------------------------------------------------- */
 
+enum {
+  kPkParserSyntaxError
+};
 
 
 /* ----------------------------------------------------------------
@@ -64,6 +67,17 @@ PkString *kPkBuiltinErrorDomain;
 PK_EXPORT
 PkError *PkErrorCreateWithFormat(PkString *domain, int code, const char *format, ...);
 
+PK_EXPORT
+PkError *PkErrorCreateParseError(
+    int           code,
+    PkString     *sourceName,
+    unsigned int  lineno,
+    unsigned int  columnno,
+    PkString     *reason);
+
+PK_EXPORT
+PkString *PkErrorGetReason(PkError *error);
+
 
 PK_DECL_END
 </diff>
      <filename>include/pekoe/error.h</filename>
    </modified>
    <modified>
      <diff>@@ -76,7 +76,7 @@ typedef enum {
   kPkNodeTrue,
   kPkNodeFalse,
 
-  kPkNodeUnrecognized
+  kPkNodeEOS
 } PkNodeType;
 
 PK_EXPORT</diff>
      <filename>include/pekoe/node.h</filename>
    </modified>
    <modified>
      <diff>@@ -71,10 +71,10 @@ PkParser *PkParserCreateWithTokenizer(
     const PkParserCallbackFunctions *callbacks);
 
 PK_EXPORT
-PkNode *PkParserParse(PkParser *parser);
+PkNode *PkParserParse(PkParser *parser, PkError **errorPtr);
 
 PK_EXPORT
-PkNode *PkParserParseStatement(PkParser *parser);
+PkNode *PkParserParseStatement(PkParser *parser, PkError **errorPtr);
 
 PK_EXPORT
 int PkParserLookahead(PkParser *parser);</diff>
      <filename>include/pekoe/parser.h</filename>
    </modified>
    <modified>
      <diff>@@ -35,6 +35,7 @@
 #include &lt;pekoe/private/error.h&gt;
 #include &lt;pekoe/private/string.h&gt;
 #include &lt;pekoe/utils.h&gt;
+#include &lt;pekoe/autorelease.h&gt;
 #include &lt;pekoe/object.h&gt;
 #include &lt;stdarg.h&gt;
 #include &lt;assert.h&gt;
@@ -109,24 +110,52 @@ void PkRuntimeErrorInitialize(void) {
 /* ----------------------------------------------------------------
  * PkError
  * ---------------------------------------------------------------- */
+static PkError *PkErrorCreate(PkString *domain, int code, PkString *reason) {
+  PK_DEFINE_INSTANCE(struct _PkError, &amp;kPkErrorClass, error);
+
+  ERROR_CODE(error)   = code;
+  ERROR_DOMAIN(error) = domain;
+  ERROR_REASON(error) = reason;
+
+  PkRetain(ERROR_DOMAIN(error));
+  PkRetain(ERROR_REASON(error));
+  return error;
+}
 
 PkError *PkErrorCreateWithFormat(PkString *domain, int code, const char *format, ...) {
-  PK_DEFINE_INSTANCE(struct _PkError, &amp;kPkErrorClass, error);
   PkString *reason;
-  va_list args;
+  PkError  *error;
+  va_list   args;
 
   va_start(args, format);
   reason = PkStringCreateWithFormatAndArguments(format, args);
   va_end(args);
 
-  ERROR_DOMAIN(error) = domain;
-  ERROR_CODE(error)   = code;
-  ERROR_REASON(error) = reason;
+  error = PkErrorCreate(domain, code, reason);
+  PkRelease(ERROR_REASON(error));
+  return error;
+}
 
-  PkRetain(ERROR_DOMAIN(error));
+PkError *PkErrorCreateParseError(
+    int           code,
+    PkString     *sourceName,
+    unsigned int  lineno,
+    unsigned int  columnno,
+    PkString     *reason)
+{
+  PkError *error = PkErrorCreate(kPkBuiltinErrorDomain, code, reason);
   return error;
 }
 
+PkString *PkErrorGetReason(PkError *error) {
+  PkString *reason = ERROR_REASON(error);
+
+  PkRetain(reason);
+  PkAutorelease(reason);
+
+  return ERROR_REASON(error);
+}
+
 
 /* ----------------------------------------------------------------
  * Polymorphic Functions</diff>
      <filename>src/error.c</filename>
    </modified>
    <modified>
      <diff>@@ -34,6 +34,8 @@
 
 #include &lt;pekoe/parser.h&gt;
 #include &lt;pekoe/utils.h&gt;
+#include &lt;pekoe/autorelease.h&gt;
+#include &lt;pekoe/error.h&gt;
 #include &lt;pekoe/hashtable.h&gt;
 #include &lt;pekoe/object.h&gt;
 #include &lt;pekoe/private/node.h&gt;
@@ -41,6 +43,7 @@
 #include &lt;stdlib.h&gt;
 #include &lt;stdarg.h&gt;
 #include &lt;string.h&gt;
+#include &lt;setjmp.h&gt;
 #include &lt;assert.h&gt;
 
 /* Logging */
@@ -121,6 +124,11 @@ PkNode *PkNodeCreateEmptyStatement(void) {
 }
 
 PK_INLINE
+PkNode *PkNodeCreateEOS(void) {
+  return createNodeWithName(kPkNodeEOS, &quot;EOS&quot;);
+}
+
+PK_INLINE
 PkNode *PkNodeCreateNull(void) {
   return createNodeWithName(kPkNodeNull, &quot;Null&quot;);
 }
@@ -330,16 +338,22 @@ void PkRuntimeParserInitialize(void) {
  * PkParser
  * ---------------------------------------------------------------- */
 struct _PkParser {
-  PkInstanceRec               base;
-  PkTokenizer              *tokenizer;
-  int                       lookahead;
-  int                       tokenRead;
+  PkInstanceRec  base;
+  PkTokenizer   *tokenizer;
+  int            lookahead;
+  int            tokenRead;
+
   PkParserCallbackFunctions callbacks;
+
+  PkError *error;
+  jmp_buf  env;    
 };
 
-#define PARSER_TOKENIZER(parser)  ((parser)-&gt;tokenizer)
-#define PARSER_LOOKAHEAD(parser)  ((parser)-&gt;lookahead)
-#define PARSER_TOKEN_READ(parser) ((parser)-&gt;tokenRead)
+#define PARSER_TOKENIZER(parser)    ((parser)-&gt;tokenizer)
+#define PARSER_LOOKAHEAD(parser)    ((parser)-&gt;lookahead)
+#define PARSER_TOKEN_READ(parser)   ((parser)-&gt;tokenRead)
+#define PARSER_LAST_ERROR(parser)   ((parser)-&gt;error)
+#define PARSER_ENV_CONTEXT(parser)  ((parser)-&gt;env)
 
 
 static const PkParserCallbackFunctions kEmptyCallbackFunctions = {
@@ -531,23 +545,29 @@ static void installOperators(void) {
  * Parsing utilities
  * ---------------------------------------------------------------- */
 static void PkParserParseError(PkParser *parser, const char *format, ...) {
-  va_list args;
+  PkString         *description;
+  PkString         *sourceName = PkTokenizerCopySourceName(PARSER_TOKENIZER(parser));
+  PkSourcePosition  position;
+  va_list           args;
 
   va_start(args, format);
-  vfprintf(stderr, format, args);
+  description = PkStringCreateWithFormatAndArguments(format, args);
   va_end(args);
 
-  {
-    PkSourcePosition position;
-    COPY_POSITION(parser, &amp;position);
+  COPY_POSITION(parser, &amp;position);
+  PK_RELEASE(PARSER_LAST_ERROR(parser));
 
-    fprintf(stderr, &quot; in %s at line:%u:%u\n&quot;,
-        PkTokenizerGetSourceNameCString(PARSER_TOKENIZER(parser)),
-        PkSourcePositionGetLine(&amp;position) + 1,
-        PkSourcePositionGetColumn(&amp;position) + 1);
-  }
+  PARSER_LAST_ERROR(parser) = PkErrorCreateParseError(
+      kPkParserSyntaxError,
+      sourceName,
+      PkSourcePositionGetLine(&amp;position),
+      PkSourcePositionGetColumn(&amp;position),
+      description);
 
-  abort();
+  PkRelease(sourceName);
+  PkRelease(description);
+
+  longjmp(PARSER_ENV_CONTEXT(parser), 1);
 }
 
 /**
@@ -577,6 +597,7 @@ PkString *interpret_string(PkParser *parser, const char *src) {
       case 't':  c = '\t'; break;    /* horizontal tab */
       case '0':  c = '\0'; break;    /* NUL character */
       default:
+        PkFree(copy);
         PkParserParseError(parser, &quot;SyntaxError: invalid escape character: \\%c&quot;, c);
         break;
       }
@@ -694,7 +715,7 @@ static PkNode *parse_expression(PkParser *parser, PkNode *lhs, int min_precedenc
   PkRetain(lhs);
 
   for (;;) {
-    int t  = lookahead(parser);
+    int t = lookahead(parser);
     PkSourcePosition pos;
     const struct operator_t *op = getBinaryOperator(t);
 
@@ -712,7 +733,10 @@ static PkNode *parse_expression(PkParser *parser, PkNode *lhs, int min_precedenc
         NODE_TYPE(lhs) != kPkNodeIdentifier &amp;&amp;
         NODE_TYPE(lhs) != kPkNodeAccessProperty)
     {
-      PkParserParseError(parser, &quot;Syntax error: can't assign to node:%d&quot;, NODE_TYPE(lhs));
+      const PkNodeType type = NODE_TYPE(lhs);
+
+      PkRelease(lhs);
+      PkParserParseError(parser, &quot;Syntax error: can't assign to node:%d&quot;, type);
     }
 
     {
@@ -908,9 +932,9 @@ static PkNode *stmt(PkParser *parser) {
   switch(lookahead(parser)) {
   case ';':
     nextToken_(parser);
-    /* fall through */
-  case kPkTokenEOS:
     return PkNodeCreateEmptyStatement();
+  case kPkTokenEOS:
+    return PkNodeCreateEOS();
   case '{':
     return block(parser);
   case kPkTokenVar:
@@ -924,6 +948,7 @@ static PkNode *stmt(PkParser *parser) {
   default:
     {
       PkNode *node = expr(parser);
+
       matchAtEndOfStatement(parser);
       return node;
     }
@@ -1033,6 +1058,8 @@ static PkNode *object(PkParser *parser) {
         t != kPkTokenString &amp;&amp;
         t != kPkTokenNumber)
     {
+      nextToken(parser);
+      PkRelease(node);
       PkParserParseError(parser,
           &quot;Syntax error: property name must be &quot;
           &quot;identifier, string or number, but was %s&quot;,
@@ -1095,17 +1122,18 @@ static PkNode *atom(PkParser *parser) {
     matchToken1(parser, ')');
     break;
   default:
+    nextToken(parser);
     PkParserParseError(parser, &quot;Unrecognized *atom* token: '%s'&quot;, PkTokenGetName(t));
     break;
   }
 
-  assert( node != NULL );
   return node;
 }
 
 static PkNode *callargs(PkParser *parser) {
   PkNode *args = PkNodeCreateList();
 
+  PkAutorelease(args);
   if (lookahead(parser) != ')') {
     PkNode *node = expr(parser);
 
@@ -1120,12 +1148,14 @@ static PkNode *callargs(PkParser *parser) {
     }
   }
 
+  PkRetain(args);
   return args;
 }
 
 static PkNode *funcargs(PkParser *parser) {
   PkNode *args = PkNodeCreateList();
 
+  PkAutorelease(args);
   if (lookahead(parser) != ')') {
     PkNode *node = identifier(parser);
 
@@ -1140,6 +1170,7 @@ static PkNode *funcargs(PkParser *parser) {
     }
   }
 
+  PkRetain(args);
   return args;
 }
 
@@ -1148,21 +1179,49 @@ static PkNode *function(PkParser *parser) {
 
   matchToken1(parser, kPkTokenFunction);
   matchToken1(parser, '(');
+
   args = funcargs(parser);
+  PkAutorelease(args);
   matchToken1(parser, ')');
-  body = block(parser);
 
+  body = block(parser);
+  PkAutorelease(body);
   return PkNodeCreateFunction(args, body);
 }
 
-PkNode *PkParserParse(PkParser *parser) {
-  return stmts(parser);
+static PkNode *parse(PkParser *parser, parser_proc proc, PkError **errorPtr) {
+  PkAutoreleasePool *const volatile arp_ = PkAutoreleasePoolCreate();
+  PkParser *const volatile parser_       = parser;
+  PkError **const volatile errorPtr_     = errorPtr;
+
+  if (setjmp(PARSER_ENV_CONTEXT(parser)) == 0) {
+    PkNode *node = proc(parser);
+
+    PkRelease(arp_);
+    return node;
+  } else { /* when longjmp jumps back, setjmp returns nonzero value */
+    PkError *err = PARSER_LAST_ERROR(parser_);
+
+    PkAssert0( err != NULL, &quot;parser-&gt;error must be set before longjmp jumps back&quot; );
+    if (errorPtr_ != NULL) {
+      *errorPtr_ = err;
+    }
+
+    /* carefully rc management */
+    PkRelease(arp_);
+    return NULL;
+  }
+}
+
+PkNode *PkParserParse(PkParser *parser, PkError **errorPtr) {
+  return parse(parser, stmts, errorPtr);
 }
 
-PkNode *PkParserParseStatement(PkParser *parser) {
-  return lookahead(parser) == kPkTokenEOS ? NULL : stmt(parser);
+PkNode *PkParserParseStatement(PkParser *parser, PkError **errorPtr) {
+  return parse(parser, stmt, errorPtr);
 }
 
+
 /* ----------------------------------------------------------------
  * Object
  * ---------------------------------------------------------------- */
@@ -1172,6 +1231,7 @@ static PkRef parser_init(PkRef object) {
   PkParserInitialize();
 
   PARSER_TOKENIZER(parser)  = NULL;
+  PARSER_LAST_ERROR(parser) = NULL;
   PARSER_LOOKAHEAD(parser)  = kPkTokenReserved;
   PARSER_TOKEN_READ(parser) = kPkTokenReserved;
 
@@ -1180,6 +1240,8 @@ static PkRef parser_init(PkRef object) {
 
 static void parser_finalize(PkRef object) {
   PkParser *parser = (PkParser *) object;
+
+  PK_RELEASE(PARSER_LAST_ERROR(parser));
   PK_RELEASE(PARSER_TOKENIZER(parser));
 }
 </diff>
      <filename>src/parser.c</filename>
    </modified>
    <modified>
      <diff>@@ -103,7 +103,12 @@ static void installSystemLibrary(PkMemoryPool *pool, const char *include_path) {
     PkContinuation *context   = PkContinuationCreate(module);
     PkExecutor     *executor  = PkExecutorCreate(pool);
     PkParser       *parser    = PkParserCreateWithTokenizer(tokenizer, NULL);
-    PkNode         *node      = PkParserParse(parser);
+    PkError        *error;
+    PkNode         *node;
+
+    if (!(node = PkParserParse(parser, &amp;error))) {
+      PkAbort1(&quot;%s&quot;, PKCSTR(PkErrorGetReason(error)));
+    }
 
     PkModuleCompileNode(module, node);
     PkContinuationModuleUpdated(context);
@@ -132,7 +137,6 @@ static void run(FILE *in, FILE *out, const char *sourceName, const char *include
   PkContinuation *context   = PkContinuationCreate(module);
   PkExecutor     *executor  = PkExecutorCreate(pool);
   PkParser       *parser;
-  PkNode         *node;
 
   if (include_path != NULL) {
     installSystemLibrary(pool, include_path);
@@ -148,8 +152,19 @@ static void run(FILE *in, FILE *out, const char *sourceName, const char *include
     parser = PkParserCreateWithTokenizer(tokenizer, NULL);
   }
 
-  while ((node = PkParserParseStatement(parser)) != NULL) {
-    PkRef v = kPkNull;
+  for (;;) {
+    PkRef    v = kPkNull;
+    PkNode  *node;
+    PkError *error;
+
+    if (!(node = PkParserParseStatement(parser, &amp;error))) {
+      fprintf(stderr, &quot;%s\n&quot;, PKCSTR(PkErrorGetReason(error)));
+      continue;
+    }
+
+    if (PkNodeGetType(node) == kPkNodeEOS) {
+      break;
+    }
 
     PkModuleCompileNode(module, node);
     PkContinuationModuleUpdated(context);</diff>
      <filename>src/repl.c</filename>
    </modified>
    <modified>
      <diff>@@ -4,10 +4,9 @@
 
 
 static void test_current(void) {
-  PkAutoreleasePool *p1, *p2;
-  
-  assert( PkAutoreleasePoolGetCurret() == NULL );
-
+  PkAutoreleasePool *p1, *p2,
+                    *current = PkAutoreleasePoolGetCurret();
+    
   p1 = PkAutoreleasePoolCreate();
   assert( p1 != NULL );
   assert( p1 == PkAutoreleasePoolGetCurret() );
@@ -20,7 +19,7 @@ static void test_current(void) {
   assert( PkAutoreleasePoolGetCurret() == p1 );
 
   PkRelease(p1);
-  assert( PkAutoreleasePoolGetCurret() == NULL );
+  assert( PkAutoreleasePoolGetCurret() == current );
 }
 
 static void test_autorelease(void) {</diff>
      <filename>test/autorelease.c</filename>
    </modified>
    <modified>
      <diff>@@ -22,7 +22,10 @@ extern void PkContinuationUnitTest(void);
 extern void PkExecutorUnitTest(void);
 
 int main(void) {
+  PkAutoreleasePool *arp;
+
   PkRuntimeInitialize();
+  arp = PkAutoreleasePoolCreate();
 
   PkConfigUnitTest();
   PkUtilsUnitTest();
@@ -45,6 +48,7 @@ int main(void) {
   PkContinuationUnitTest();
   PkExecutorUnitTest();
 
+  PkRelease(arp);
   return 0;
 }
 </diff>
      <filename>test/runtests.c</filename>
    </modified>
    <modified>
      <diff>@@ -18,8 +18,13 @@ PkParser *PkUTCreateParserWithCString(const char *src) {
 }
 
 PkNode *PkUTCompileCString(const char *src) {
-  PkParser *const parser = PkUTCreateParserWithCString(src);
-  PkNode   *const node   = PkParserParse(parser);
+  PkParser *parser = PkUTCreateParserWithCString(src);
+  PkError  *error;
+  PkNode   *node;
+
+  if (!(node = PkParserParse(parser, &amp;error))) {
+    PkAbort1(&quot;%s&quot;, PKCSTR(PkErrorGetReason(error)));
+  }
 
   PkRelease(parser);
   return node;</diff>
      <filename>test/unittest.c</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>c7eefacbb31b1fb7ea572b0cb97a524431192c7d</id>
    </parent>
  </parents>
  <author>
    <name>Takanori Ishikawa</name>
    <email>takanori.ishikawa@gmail.com</email>
  </author>
  <url>http://github.com/ishikawa/pekoe/commit/6645cea117cd47eb3a52f15c2160ea2c148249ad</url>
  <id>6645cea117cd47eb3a52f15c2160ea2c148249ad</id>
  <committed-date>2009-06-30T09:22:34-07:00</committed-date>
  <authored-date>2009-06-30T09:22:34-07:00</authored-date>
  <message>Added setjmp/longjmp error handling</message>
  <tree>de82906c6ccce71d1b075bece591065a874b599d</tree>
  <committer>
    <name>Takanori Ishikawa</name>
    <email>takanori.ishikawa@gmail.com</email>
  </committer>
</commit>
