[Swfdec-commits] 7 commits - vivified/code

Pekka Lampila medar at kemper.freedesktop.org
Wed Apr 9 08:45:06 PDT 2008


 vivified/code/.gitignore                          |    2 
 vivified/code/Makefile.am                         |   26 
 vivified/code/compiler.c                          |    4 
 vivified/code/vivi_compiler.c                     | 2385 ----------------------
 vivified/code/vivi_compiler.h                     |   36 
 vivified/code/vivi_compiler_scanner.c             |  310 --
 vivified/code/vivi_compiler_scanner.h             |  216 -
 vivified/code/vivi_compiler_scanner_lex.h         |  315 --
 vivified/code/vivi_compiler_scanner_lex.l         |  284 --
 vivified/code/vivi_compiler_scanner_lex_include.h |   28 
 vivified/code/vivi_parser.c                       | 2233 ++++++++++++++++++++
 vivified/code/vivi_parser.h                       |   36 
 vivified/code/vivi_parser_scanner.c               |  310 ++
 vivified/code/vivi_parser_scanner.h               |  216 +
 vivified/code/vivi_parser_scanner_lex.h           |  315 ++
 vivified/code/vivi_parser_scanner_lex.l           |  284 ++
 vivified/code/vivi_parser_scanner_lex_include.h   |   28 
 17 files changed, 3438 insertions(+), 3590 deletions(-)

New commits:
commit 876bc3f7d9534b5069438bb901aacb6292b95810
Merge: c9d36c3... 3bca1a0...
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Wed Apr 9 18:44:23 2008 +0300

    Merge branch 'master' of ssh://medar@git.freedesktop.org/git/swfdec/swfdec

commit c9d36c38170edafb3b28d70f996d0e0eeff1d5ed
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Wed Apr 9 18:30:01 2008 +0300

    Fix parsing of >= and unterminated comment

diff --git a/vivified/code/vivi_parser_scanner.c b/vivified/code/vivi_parser_scanner.c
index 97a3a29..092cefa 100644
--- a/vivified/code/vivi_parser_scanner.c
+++ b/vivified/code/vivi_parser_scanner.c
@@ -103,7 +103,7 @@ static const struct {
   { TOKEN_LESS_THAN, "<" },
   { TOKEN_GREATER_THAN, ">" },
   { TOKEN_LESS_THAN_OR_EQUAL, "<=" },
-  { TOKEN_EQUAL_OR_GREATER_THAN, "=>" },
+  { TOKEN_EQUAL_OR_GREATER_THAN, ">=" },
 
   // equality
   { TOKEN_EQUAL, "=" },
diff --git a/vivified/code/vivi_parser_scanner_lex.l b/vivified/code/vivi_parser_scanner_lex.l
index 4b96c41..34c4f61 100644
--- a/vivified/code/vivi_parser_scanner_lex.l
+++ b/vivified/code/vivi_parser_scanner_lex.l
@@ -35,23 +35,23 @@ identifier_part		[$_a-zA-Z0-9]
 
 			GString *string = NULL;
 
-<<EOF>>			{ return TOKEN_EOF; }
-
 "/*"			{ BEGIN(comment); }
 <comment>{
+  [^*\n]*		/* skip */
+  \n			{ lex_line_number++; }
+  "*/"			{ BEGIN(INITIAL); }
   <<EOF>>		{
 			  BEGIN(INITIAL);
 			  return TOKEN_ERROR;
 			}
-  [^*\n]*		/* skip */
-  \n			{ lex_line_number++; }
-  "*/"			{ BEGIN(INITIAL); }
 }
 "//"[^\r\n]*		{
 			  lex_line_number++;
 			  return TOKEN_LINE_TERMINATOR;
 			}
 
+<<EOF>>			{ return TOKEN_EOF; }
+
 [ \t]			/* skip */
 
 \r\n			{
@@ -77,7 +77,7 @@ identifier_part		[$_a-zA-Z0-9]
 "<"			{ return TOKEN_LESS_THAN; }
 ">"			{ return TOKEN_GREATER_THAN; }
 "<="			{ return TOKEN_LESS_THAN_OR_EQUAL; }
-"=>"			{ return TOKEN_EQUAL_OR_GREATER_THAN; }
+">="			{ return TOKEN_EQUAL_OR_GREATER_THAN; }
 
 "==",			{ return TOKEN_EQUAL; }
 "!=",			{ return TOKEN_NOT_EQUAL; }
commit 6e3d2c7eb78d758614672686837abe3cd4e5a2b8
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Wed Apr 9 16:52:44 2008 +0300

    Don't use statement uninitialized

diff --git a/vivified/code/vivi_parser.c b/vivified/code/vivi_parser.c
index c394798..7ec3a0b 100644
--- a/vivified/code/vivi_parser.c
+++ b/vivified/code/vivi_parser.c
@@ -155,7 +155,7 @@ vivi_parser_error (ParseData *data, const char *format, ...)
   message = g_strdup_vprintf (format, args);
   va_end (args);
 
-  g_printerr (":error: %s\n", message);
+  g_printerr ("%i: error: %s\n", data->scanner->next_line_number, message);
 
   g_free (message);
 
@@ -701,6 +701,7 @@ parse_array_literal (ParseData *data, ViviCodeValue **value,
   ViviCodeStatement *statement_new;
 
   *value = vivi_code_init_array_new ();
+  *statement = NULL;
 
   parse_token (data, TOKEN_BRACKET_LEFT);
 
@@ -749,6 +750,7 @@ parse_object_literal (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
   *value = vivi_code_init_object_new ();
+  *statement = NULL;
 
   parse_token (data, TOKEN_BRACE_LEFT);
 
@@ -843,6 +845,7 @@ parse_primary_expression (ParseData *data, ViviCodeValue **value,
 
   if (try_parse_token (data, TOKEN_THIS)) {
     *value = vivi_code_get_new_name ("this");
+    *statement = NULL;
     return;
   }
 
@@ -898,6 +901,7 @@ parse_member_expression (ParseData *data, ViviCodeValue **value,
     vivi_parser_error_unexpected_or (data, ERROR_TOKEN_PRIMARY_EXPRESSION,
 	ERROR_TOKEN_FUNCTION_EXPRESSION, TOKEN_NONE);
     *value = vivi_code_constant_new_undefined ();
+    *statement = NULL;
   }
 
   while (TRUE) {
commit 3902098fe39ea682abd83c3b8f10b1a9a18319fe
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Wed Apr 9 16:40:09 2008 +0300

    Continue reworking the error handling in the parser

diff --git a/vivified/code/vivi_parser.c b/vivified/code/vivi_parser.c
index 16bde02..c394798 100644
--- a/vivified/code/vivi_parser.c
+++ b/vivified/code/vivi_parser.c
@@ -58,10 +58,13 @@ enum {
   ERROR_TOKEN_IDENTIFIER,
   ERROR_TOKEN_PROPERTY_NAME,
   ERROR_TOKEN_PRIMARY_EXPRESSION,
+  ERROR_TOKEN_FUNCTION_EXPRESSION,
+  ERROR_TOKEN_ASSIGNMENT_EXPRESSION,
   ERROR_TOKEN_EXPRESSION,
   ERROR_TOKEN_ITERATION_STATEMENT,
   ERROR_TOKEN_EXPRESSION_STATEMENT,
-  ERROR_TOKEN_STATEMENT
+  ERROR_TOKEN_STATEMENT,
+  ERROR_TOKEN_FUNCTION_DECLARATION
 };
 
 static const struct {
@@ -72,11 +75,14 @@ static const struct {
   { ERROR_TOKEN_IDENTIFIER, "IDENTIFIER" },
   { ERROR_TOKEN_PROPERTY_NAME, "PROPERTY NAME" },
   { ERROR_TOKEN_PRIMARY_EXPRESSION, "PRIMARY EXPRESSION" },
+  { ERROR_TOKEN_FUNCTION_EXPRESSION, "FUNCTION EXPRESSION" },
+  { ERROR_TOKEN_ASSIGNMENT_EXPRESSION, "ASSIGNMENT EXPRESSION" },
   { ERROR_TOKEN_EXPRESSION, "EXPRESSION" },
   { ERROR_TOKEN_ITERATION_STATEMENT, "ITERATION STATEMENT" },
   { ERROR_TOKEN_EXPRESSION_STATEMENT, "EXPRESSION STATEMENT" },
   { ERROR_TOKEN_STATEMENT, "STATEMENT" },
-  { TOKEN_LAST, NULL }
+  { ERROR_TOKEN_FUNCTION_DECLARATION, "FUNCTION DECLARATION" },
+  { TOKEN_NONE, NULL }
 };
 
 typedef struct {
@@ -87,28 +93,28 @@ typedef struct {
 typedef struct {
   ViviParserScanner *		scanner;
 
-  guint				error_count;
-
-  char *			cancel_error;
-
   GSList *			levels; // ParseLevel, earlier levels
   ParseLevel *			level;  // current level
+
+  guint				error_count;
 } ParseData;
 
-typedef gboolean (*ParseValueFunction) (ParseData *data, ViviCodeValue **value);
-typedef gboolean (*ParseValueStatementFunction) (ParseData *data, ViviCodeValue **value, ViviCodeStatement **statement);
-typedef gboolean (*ParseStatementFunction) (ParseData *data, ViviCodeStatement **statement);
+typedef gboolean (*PeekFunction) (ParseData *data);
+typedef void (*ParseValueFunction) (ParseData *data, ViviCodeValue **value);
+typedef void (*ParseValueStatementFunction) (ParseData *data, ViviCodeValue **value, ViviCodeStatement **statement);
+typedef void (*ParseStatementFunction) (ParseData *data, ViviCodeStatement **statement);
 
-static gboolean
-parse_statement_list (ParseData *data, ParseStatementFunction function, ViviCodeStatement **statement, guint separator);
+static void
+parse_statement_list (ParseData *data, PeekFunction peek,
+    ParseStatementFunction parse, ViviCodeStatement **block, guint separator);
 
-static gboolean
-parse_value_statement_list (ParseData *data,
-    ParseValueStatementFunction function, ViviCodeValue ***list,
+static void
+parse_value_statement_list (ParseData *data, PeekFunction peek,
+    ParseValueStatementFunction parse, ViviCodeValue ***list,
     ViviCodeStatement **statement, guint separator);
 
-static gboolean
-parse_value_list (ParseData *data, ParseValueFunction function,
+static void
+parse_value_list (ParseData *data, PeekFunction peek, ParseValueFunction parse,
     ViviCodeValue ***list, guint separator);
 
 // helpers
@@ -123,7 +129,7 @@ vivi_parser_token_name (guint token)
     const char *name;
 
     name = NULL;
-    for (i = 0; error_names[i].token != TOKEN_LAST; i++) {
+    for (i = 0; error_names[i].token != TOKEN_NONE; i++) {
       if (error_names[i].token == token) {
 	name = error_names[i].name;
 	break;
@@ -157,83 +163,114 @@ vivi_parser_error (ParseData *data, const char *format, ...)
 }
 
 static void
-vivi_parser_cancel (ParseData *data, const char *format, ...)
+vivi_parser_error_unexpected_or (ParseData *data, ...)
 {
   va_list args;
-  char *message;
+  guint token;
+  GString *message;
 
   g_return_if_fail (data != NULL);
-  g_return_if_fail (format != NULL);
 
-  va_start (args, format);
-  message = g_strdup_vprintf (format, args);
+  message = g_string_new ("Expected ");
+
+  va_start (args, data);
+
+  token = va_arg (args, guint);
+  g_assert (token != TOKEN_NONE);
+  g_string_append (message, vivi_parser_token_name (token));
+
+  while ((token = va_arg (args, guint)) != TOKEN_NONE) {
+    g_string_append (message, ", ");
+    g_string_append (message, vivi_parser_token_name (token));
+  }
+
   va_end (args);
 
-  if (data->cancel_error != NULL)
-    g_free (data->cancel_error);
-  data->cancel_error = message;
+  g_string_append (message, " before ");
+
+  g_string_append (message,
+      vivi_parser_token_name (data->scanner->next_token));
+
+  vivi_parser_error (data, "%s", g_string_free (message, FALSE));
 }
 
-static char *
-vivi_parser_unexpected_token (ParseData *data, guint expected,
-    guint unexpected1, guint unexpected2)
+static void
+vivi_parser_error_unexpected (ParseData *data, guint expected)
 {
-  return g_strdup_printf ("Expected %s before %s or %s\n",
-      vivi_parser_token_name (expected), vivi_parser_token_name (unexpected1),
-      vivi_parser_token_name (unexpected2));
+  g_return_if_fail (data != NULL);
+  g_return_if_fail (expected != TOKEN_NONE);
+
+  vivi_parser_error_unexpected_or (data, expected, TOKEN_NONE);
 }
 
 static void
-vivi_parser_fail_child (ParseData *data)
+vivi_parser_error_unexpected_line_terminator (ParseData *data, guint expected)
 {
-  if (data->cancel_error != NULL) {
-    vivi_parser_error (data, "%s", data->cancel_error);
-    g_free (data->cancel_error);
-    data->cancel_error = NULL;
-  } else {
-    g_assert (data->error_count > 0);
-  }
+  g_return_if_fail (data != NULL);
+  g_return_if_fail (expected != TOKEN_NONE);
+
+  vivi_parser_error (data, "Expected %s before %s",
+      vivi_parser_token_name (expected),
+      vivi_parser_token_name (TOKEN_LINE_TERMINATOR));
 }
 
-static gboolean
-check_line_terminator (ParseData *data)
+G_GNUC_WARN_UNUSED_RESULT static gboolean
+peek_line_terminator (ParseData *data)
 {
   vivi_parser_scanner_peek_next_token (data->scanner);
   return data->scanner->next_line_terminator;
 }
 
-static gboolean
-check_token (ParseData *data, ViviParserScannerToken token)
+G_GNUC_WARN_UNUSED_RESULT static gboolean
+peek_token (ParseData *data, ViviParserScannerToken token)
 {
   vivi_parser_scanner_peek_next_token (data->scanner);
-  if (data->scanner->next_token != token)
+  return (data->scanner->next_token == token);
+}
+
+static void
+parse_token (ParseData *data, ViviParserScannerToken token)
+{
+  vivi_parser_scanner_peek_next_token (data->scanner);
+  if (data->scanner->next_token != token) {
+    vivi_parser_error_unexpected (data, token);
+  } else {
+    vivi_parser_scanner_get_next_token (data->scanner);
+  }
+}
+
+G_GNUC_WARN_UNUSED_RESULT static gboolean
+try_parse_token (ParseData *data, ViviParserScannerToken token)
+{
+  if (!peek_token (data, token))
     return FALSE;
-  vivi_parser_scanner_get_next_token (data->scanner);
+
+  parse_token (data, token);
   return TRUE;
 }
 
-static gboolean
-check_automatic_semicolon (ParseData *data)
+static void
+parse_automatic_semicolon (ParseData *data)
 {
-  if (check_token (data, TOKEN_SEMICOLON))
-    return TRUE;
-  if (check_line_terminator (data))
-    return TRUE;
+  if (try_parse_token (data, TOKEN_SEMICOLON))
+    return;
+  if (peek_line_terminator (data))
+    return;
 
   vivi_parser_scanner_peek_next_token (data->scanner);
   if (data->scanner->next_token == TOKEN_BRACE_LEFT ||
       data->scanner->next_token == TOKEN_EOF)
-    return TRUE;
+    return;
 
-  return FALSE;
+  vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
 }
 
-static gboolean
-check_restricted_semicolon (ParseData *data)
+G_GNUC_WARN_UNUSED_RESULT static gboolean
+try_parse_restricted_semicolon (ParseData *data)
 {
-  if (check_token (data, TOKEN_SEMICOLON))
+  if (try_parse_token (data, TOKEN_SEMICOLON))
     return TRUE;
-  if (check_line_terminator (data))
+  if (peek_line_terminator (data))
     return TRUE;
 
   return FALSE;
@@ -468,251 +505,290 @@ vivi_parser_add_label (ParseData *data, ViviCodeLabel *label)
 
 /* ActionScript specific */
 static gboolean
-parse_undefined_literal (ParseData *data, ViviCodeValue **value)
+peek_undefined_literal (ParseData *data)
 {
-  *value = NULL;
+  return peek_token (data, TOKEN_UNDEFINED);
+}
 
-  if (!check_token (data, TOKEN_UNDEFINED)) {
-    vivi_parser_cancel_unexpected (data, TOKEN_UNDEFINED);
-    return FALSE;
-  }
+static void
+parse_undefined_literal (ParseData *data, ViviCodeValue **value)
+{
+  parse_token (data, TOKEN_UNDEFINED);
 
   *value = vivi_code_constant_new_undefined ();
-  return TRUE;
 }
 
 static gboolean
-parse_null_literal (ParseData *data, ViviCodeValue **value)
+peek_null_literal (ParseData *data)
 {
-  *value = NULL;
+  return peek_token (data, TOKEN_NULL);
+}
 
-  if (!check_token (data, TOKEN_NULL)) {
-    vivi_parser_cancel_unexpected (data, TOKEN_NULL);
-    return FALSE;
-  }
+static void
+parse_null_literal (ParseData *data, ViviCodeValue **value)
+{
+  parse_token (data, TOKEN_NULL);
 
   *value = vivi_code_constant_new_null ();
-  return TRUE;
 }
 
 static gboolean
-parse_boolean_literal (ParseData *data, ViviCodeValue **value)
+peek_boolean_literal (ParseData *data)
 {
-  *value = NULL;
+  return peek_token (data, TOKEN_BOOLEAN);
+}
 
-  if (!check_token (data, TOKEN_BOOLEAN)) {
-    vivi_parser_cancel_unexpected (data, TOKEN_BOOLEAN);
-    return FALSE;
+static void
+parse_boolean_literal (ParseData *data, ViviCodeValue **value)
+{
+  if (!try_parse_token (data, TOKEN_BOOLEAN)) {
+    vivi_parser_error_unexpected (data, TOKEN_BOOLEAN);
+    *value = vivi_code_constant_new_boolean (0);
+  } else {
+    *value = vivi_code_constant_new_boolean (data->scanner->value.v_boolean);
   }
-
-  *value = vivi_code_constant_new_boolean (data->scanner->value.v_boolean);
-  return TRUE;
 }
 
 static gboolean
-parse_numeric_literal (ParseData *data, ViviCodeValue **value)
+peek_numeric_literal (ParseData *data)
 {
-  *value = NULL;
+  return peek_token (data, TOKEN_NUMBER);
+}
 
-  if (!check_token (data, TOKEN_NUMBER)) {
-    vivi_parser_cancel_unexpected (data, TOKEN_NUMBER);
-    return FALSE;
+static void
+parse_numeric_literal (ParseData *data, ViviCodeValue **value)
+{
+  if (!try_parse_token (data, TOKEN_NUMBER)) {
+    vivi_parser_error_unexpected (data, TOKEN_NUMBER);
+    *value = vivi_code_constant_new_number (0);
+  } else {
+    *value = vivi_code_constant_new_number (data->scanner->value.v_boolean);
   }
-
-  *value = vivi_code_constant_new_number (data->scanner->value.v_number);
-  return TRUE;
 }
 
 static gboolean
-parse_string_literal (ParseData *data, ViviCodeValue **value)
+peek_string_literal (ParseData *data)
 {
-  *value = NULL;
+  return peek_token (data, TOKEN_STRING);
+}
 
-  if (!check_token (data, TOKEN_STRING)) {
-    vivi_parser_cancel_unexpected (data, TOKEN_STRING);
-    return FALSE;
+static void
+parse_string_literal (ParseData *data, ViviCodeValue **value)
+{
+  if (!try_parse_token (data, TOKEN_STRING)) {
+    vivi_parser_error_unexpected (data, TOKEN_STRING);
+    *value = vivi_code_constant_new_string ("undefined");
+  } else {
+    *value = vivi_code_constant_new_string (data->scanner->value.v_string);
   }
-
-  *value = vivi_code_constant_new_string (data->scanner->value.v_string);
-  return TRUE;
 }
 
+static const struct {
+  PeekFunction peek;
+  ParseValueFunction parse;
+} literal_functions[] = {
+  { peek_undefined_literal, parse_undefined_literal },
+  { peek_null_literal, parse_null_literal },
+  { peek_boolean_literal, parse_boolean_literal },
+  { peek_numeric_literal, parse_numeric_literal },
+  { peek_string_literal, parse_string_literal },
+  { NULL, NULL }
+};
+
 static gboolean
-parse_literal (ParseData *data, ViviCodeValue **value)
+peek_literal (ParseData *data)
 {
-  static const ParseValueFunction functions[] = {
-    parse_undefined_literal,
-    parse_null_literal,
-    parse_boolean_literal,
-    parse_numeric_literal,
-    parse_string_literal,
-    NULL
-  };
   guint i;
 
-  *value = NULL;
-
-  for (i = 0; functions[i] != NULL; i++) {
-    if (functions[i] (data, value))
+  for (i = 0; literal_functions[i].peek != NULL; i++) {
+    if (literal_functions[i].peek (data))
       return TRUE;
   }
 
-  vivi_parser_cancel_unexpected (data, ERROR_TOKEN_LITERAL);
   return FALSE;
 }
 
-static gboolean
-parse_identifier (ParseData *data, ViviCodeValue **value)
+static void
+parse_literal (ParseData *data, ViviCodeValue **value)
 {
-  *value = NULL;
+  guint i;
 
-  if (!check_token (data, TOKEN_IDENTIFIER)) {
-    vivi_parser_cancel_unexpected (data, TOKEN_IDENTIFIER);
-    return FALSE;
+  for (i = 0; literal_functions[i].peek != NULL; i++) {
+    if (literal_functions[i].peek (data)) {
+      literal_functions[i].parse (data, value);
+      return;
+    }
   }
 
-  *value = vivi_code_get_new_name (data->scanner->value.v_identifier);
-
-  return TRUE;
+  vivi_parser_error_unexpected (data, ERROR_TOKEN_LITERAL);
+  *value = vivi_code_constant_new_undefined ();
 }
 
 static gboolean
-parse_property_name (ParseData *data, ViviCodeValue **value)
+peek_identifier (ParseData *data)
 {
-  static const ParseValueFunction functions[] = {
-    parse_identifier,
-    parse_string_literal,
-    parse_numeric_literal,
-    NULL
-  };
-  guint i;
+  return peek_token (data, TOKEN_IDENTIFIER);
+}
 
-  *value = NULL;
+static void
+parse_identifier (ParseData *data, ViviCodeValue **value)
+{
+  if (!try_parse_token (data, TOKEN_IDENTIFIER)) {
+    vivi_parser_error_unexpected (data, TOKEN_IDENTIFIER);
+    *value = vivi_code_get_new_name ("undefined");
+  } else {
+    *value = vivi_code_get_new_name (data->scanner->value.v_identifier);
+  }
+}
 
-  for (i = 0; functions[i] != NULL; i++) {
-    if (functions[i] (data, value))
+static const struct {
+  PeekFunction peek;
+  ParseValueFunction parse;
+} property_name_functions[] = {
+  { peek_identifier, parse_identifier },
+  { peek_string_literal, parse_string_literal },
+  { peek_numeric_literal, parse_numeric_literal },
+  { NULL, NULL }
+};
+
+G_GNUC_UNUSED static gboolean
+peek_property_name (ParseData *data)
+{
+  guint i;
+
+  for (i = 0; property_name_functions[i].peek != NULL; i++) {
+    if (property_name_functions[i].peek (data))
       return TRUE;
   }
 
-  vivi_parser_cancel_unexpected (data, ERROR_TOKEN_PROPERTY_NAME);
   return FALSE;
 }
 
+static void
+parse_property_name (ParseData *data, ViviCodeValue **value)
+{
+  guint i;
+
+  for (i = 0; property_name_functions[i].peek != NULL; i++) {
+    if (property_name_functions[i].peek (data)) {
+      property_name_functions[i].parse (data, value);
+      return;
+    }
+  }
+
+  vivi_parser_error_unexpected (data, ERROR_TOKEN_PROPERTY_NAME);
+  *value = vivi_code_constant_new_undefined ();
+}
+
+static gboolean
+peek_array_literal (ParseData *data)
+{
+  return peek_token (data, TOKEN_BRACKET_LEFT);
+}
+
 static gboolean
+peek_assignment_expression (ParseData *data);
+
+static void
 parse_assignment_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement);
 
-static gboolean
+static void
 parse_array_literal (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
   ViviCodeValue *member;
   ViviCodeStatement *statement_new;
 
-  *value = NULL;
-  *statement = NULL;
-
-  if (!check_token (data, TOKEN_BRACKET_LEFT)) {
-    vivi_parser_cancel_unexpected (data, TOKEN_BRACKET_LEFT);
-    return FALSE;
-  }
-
   *value = vivi_code_init_array_new ();
 
+  parse_token (data, TOKEN_BRACKET_LEFT);
+
   while (TRUE) {
-    if (check_token (data, TOKEN_BRACKET_RIGHT)) {
+    if (try_parse_token (data, TOKEN_BRACKET_RIGHT)) {
       vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
 	 vivi_code_constant_new_undefined ());
       break;
-    } else if (check_token (data, TOKEN_COMMA)) {
+    } else if (try_parse_token (data, TOKEN_COMMA)) {
       vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
 	 vivi_code_constant_new_undefined ());
-    } else if (parse_assignment_expression (data, &member, &statement_new)) {
+    }
+    else if (peek_assignment_expression (data))
+    {
+      parse_assignment_expression (data, &member, &statement_new);
+
       *statement = vivi_parser_join_statements (*statement, statement_new);
 
       vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
 	  member);
       g_object_unref (member);
 
-      if (!check_token (data, TOKEN_COMMA)) {
-	if (!check_token (data, TOKEN_BRACKET_RIGHT)) {
-	  vivi_parser_error_unexpected (data, TOKEN_BRACKET_RIGHT,
-	      TOKEN_COMMA);
+      if (!try_parse_token (data, TOKEN_COMMA)) {
+	if (!try_parse_token (data, TOKEN_BRACKET_RIGHT)) {
+	  vivi_parser_error_unexpected_or (data, TOKEN_BRACKET_RIGHT,
+	      TOKEN_COMMA, TOKEN_NONE);
 	}
 	break;
       }
     } else {
-      vivi_parser_error_unexpected (data, TOKEN_BRACKET_RIGHT, TOKEN_COMMA,
-	  ERROR_TOKEN_ASSIGNMENT_EXPRESSION);
+      vivi_parser_error_unexpected_or (data, TOKEN_BRACKET_RIGHT, TOKEN_COMMA,
+	  ERROR_TOKEN_ASSIGNMENT_EXPRESSION, TOKEN_NONE);
       break;
     }
   }
-
-  return TRUE;
 }
 
 static gboolean
+peek_object_literal (ParseData *data)
+{
+  return peek_token (data, TOKEN_BRACE_LEFT);
+}
+
+static void
 parse_object_literal (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
-  gboolean status;
-
-  *value = NULL;
-  *statement = NULL;
-
-  if (!check_token (data, TOKEN_BRACE_LEFT)) {
-    vivi_parser_cancel_unexpected (data, TOKEN_BRACE_LEFT);
-    return FALSE;
-  }
-
   *value = vivi_code_init_object_new ();
 
-  if (!check_token (data, TOKEN_BRACE_RIGHT)) {
+  parse_token (data, TOKEN_BRACE_LEFT);
+
+  if (!peek_token (data, TOKEN_BRACE_RIGHT)) {
     do {
       ViviCodeValue *property, *initializer;
       ViviCodeStatement *statement_new;
 
-      if (!parse_property_name (data, &property))
-	vivi_parser_error_child_value (data, &property);
-
-      if (!check_token (data, TOKEN_COLON))
-	vivi_parser_error_unexpected (data, TOKEN_COLON);
-
-      if (!parse_assignment_expression (data, &initializer, &statement_new))
-	vivi_parser_error_child_value (data, &initializer);
+      parse_property_name (data, &property);
+      parse_token (data, TOKEN_COLON);
+      parse_assignment_expression (data, &initializer, &statement_new);
 
       *statement = vivi_parser_join_statements (*statement, statement_new);
 
       vivi_code_init_object_add_variable (VIVI_CODE_INIT_OBJECT (*value),
 	  property, initializer);
-    } while (check_token (data, TOKEN_COMMA));
+    } while (try_parse_token (data, TOKEN_COMMA));
   }
 
-  if (!check_token (data, TOKEN_BRACE_RIGHT))
-    vivi_parser_error_unexpected (data, TOKEN_BRACE_RIGHT);
-
-  return TRUE;
+  parse_token (data, TOKEN_BRACE_RIGHT);
 }
 
 // misc
 
 static gboolean
+peek_variable_declaration (ParseData *data)
+{
+  return peek_identifier (data);
+}
+
+static void
 parse_variable_declaration (ParseData *data, ViviCodeStatement **statement)
 {
-  gboolean status;
   ViviCodeValue *identifier, *value;
   ViviCodeStatement *assignment, *statement_right;
 
-  *statement = NULL;
-
-  if (!parse_identifier (data, &identifier)) {
-    vivi_parser_cancel_unexpected (data, ERROR_TOKEN_IDENTIFIER);
-    return FALSE;
-  }
+  parse_identifier (data, &identifier);
 
-  if (check_token (data, TOKEN_ASSIGN)) {
-    if (!parse_assignment_expression (data, &value, &statement_right))
-      vivi_parser_error_child_value (data, value);
+  if (try_parse_token (data, TOKEN_ASSIGN)) {
+    parse_assignment_expression (data, &value, &statement_right);
   } else {
     value = vivi_code_constant_new_undefined ();
     statement_right = NULL;
@@ -722,93 +798,121 @@ parse_variable_declaration (ParseData *data, ViviCodeStatement **statement)
   vivi_code_assignment_set_local (VIVI_CODE_ASSIGNMENT (assignment), TRUE);
 
   *statement = vivi_parser_join_statements (statement_right, assignment);
-
-  return TRUE;
 }
 
 // expression
 
+static const struct {
+  PeekFunction peek;
+  ParseValueFunction parse_value;
+  ParseValueStatementFunction parse_value_statement;
+} primary_expression_functions[] = {
+  { peek_object_literal, NULL, parse_object_literal },
+  { peek_array_literal, NULL, parse_array_literal },
+  { peek_identifier, parse_identifier, NULL },
+  { peek_literal, parse_literal, NULL },
+  { NULL, NULL, NULL }
+};
+
 static gboolean
+peek_primary_expression (ParseData *data)
+{
+  guint i;
+
+  if (peek_token (data, TOKEN_THIS)||
+      peek_token (data, TOKEN_PARENTHESIS_LEFT))
+    return TRUE;
+
+  for (i = 0; primary_expression_functions[i].peek != NULL; i++) {
+    if (primary_expression_functions[i].peek (data))
+      return TRUE;
+  }
+
+  return FALSE;
+}
+
+static void
 parse_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement);
 
-static gboolean
+static void
 parse_primary_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
-  *value = NULL;
-  *statement = NULL;
+  guint i;
 
-  if (check_token (data, TOKEN_THIS)) {
+  if (try_parse_token (data, TOKEN_THIS)) {
     *value = vivi_code_get_new_name ("this");
-    return TRUE;
+    return;
   }
 
-  if (check_token (data, TOKEN_PARENTHESIS_LEFT)) {
-    if (!parse_expression (data, value, statement))
-      vivi_parser_error_child_value (data, value);
-    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
-      vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
-    return TRUE;
+  if (try_parse_token (data, TOKEN_PARENTHESIS_LEFT)) {
+    parse_expression (data, value, statement);
+    parse_token (data, TOKEN_PARENTHESIS_RIGHT);
+    return;
   }
 
-  if (parse_object_literal (data, value, statement))
-    return TRUE;
-
-  if (parse_array_literal (data, value, statement))
-    return TRUE;
-
-  if (parse_identifier (data, value))
-    return TRUE;
-
-  if (parse_literal (data, value))
-    return TRUE;
+  for (i = 0; primary_expression_functions[i].peek != NULL; i++) {
+    if (primary_expression_functions[i].peek (data)) {
+      if (primary_expression_functions[i].parse_value != NULL) {
+	primary_expression_functions[i].parse_value (data, value);
+	*statement = NULL;
+      } else {
+	primary_expression_functions[i].parse_value_statement (data, value,
+	    statement);
+      }
+      return;
+    }
+  }
 
-  vivi_parser_cancel_unexpected (ERROR_TOKEN_PRIMARY_EXPRESSION);
-  return FALSE;
+  vivi_parser_error_unexpected (data, ERROR_TOKEN_PRIMARY_EXPRESSION);
+  *value = vivi_code_constant_new_undefined ();
+  *statement = NULL;
 }
 
 static gboolean
+peek_function_expression (ParseData *data);
+
+static void
 parse_function_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement);
 
 static gboolean
+peek_member_expression (ParseData *data)
+{
+  return (peek_primary_expression (data) || peek_function_expression (data));
+}
+
+static void
 parse_member_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
-  gboolean status;
   ViviCodeValue *member;
   ViviCodeStatement *statement_member;
 
-  *value = NULL;
-  *statement = NULL;
-
-  // TODO: new MemberExpression Arguments
-
-  if (!parse_primary_expression (data, value, statement)) {
-    if (!parse_function_expression (data, value, statement)) {
-      vivi_parser_cancel_unexpected (data, ERROR_PRIMARY_EXPRESSION,
-	  ERROR_FUNCTION_EXPRESSION);
-      return FALSE;
-    }
+  if (peek_primary_expression (data)) {
+    parse_primary_expression (data, value, statement);
+  } else if (peek_function_expression (data)) {
+    parse_function_expression (data, value, statement);
+  } else {
+    vivi_parser_error_unexpected_or (data, ERROR_TOKEN_PRIMARY_EXPRESSION,
+	ERROR_TOKEN_FUNCTION_EXPRESSION, TOKEN_NONE);
+    *value = vivi_code_constant_new_undefined ();
   }
 
-   while (TRUE) {
+  while (TRUE) {
     ViviCodeValue *tmp;
 
-    if (check_token (data, TOKEN_BRACKET_LEFT)) {
-      if (!parse_expression (data, &member, &statement_member))
-	vivi_parser_error_child_value (data, &member);
+    if (try_parse_token (data, TOKEN_BRACKET_LEFT)) {
+      parse_expression (data, &member, &statement_member);
 
       *statement = vivi_parser_join_statements (*statement, statement_member);
 
-      if (!check_token (data, TOKEN_BRACKET_RIGHT))
-	vivi_parser_error_unexpected (data, TOKEN_BRACKET_RIGHT);
-    } else if (check_token (data, TOKEN_DOT)) {
-      if (!parse_identifier (data, &member))
-	vivi_parser_error_child_value (data, &member);
+      parse_token (data, TOKEN_BRACKET_RIGHT);
+    } else if (try_parse_token (data, TOKEN_DOT)) {
+      parse_identifier (data, &member);
     } else {
-      return TRUE;
+      return;
     }
 
     tmp = *value;
@@ -821,31 +925,13 @@ parse_member_expression (ParseData *data, ViviCodeValue **value,
 }
 
 static gboolean
-parse_new_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
+peek_left_hand_side_expression (ParseData *data)
 {
-  gboolean status;
+  return (peek_token (data, TOKEN_NEW) || peek_member_expression (data));
 
-  *value = NULL;
-  *statement = NULL;
-
-  if (check_token (data, TOKEN_NEW)) {
-    if (!parse_new_expression (data, value, statement))
-      vivi_parser_error_child_value (data, value);
-    if (!VIVI_IS_CODE_FUNCTION_CALL (*value)) {
-      ViviCodeValue *tmp = VIVI_CODE_VALUE (*value);
-      *value = vivi_parser_function_call_new (tmp);
-      g_object_unref (tmp);
-    }
-    vivi_code_function_call_set_construct (VIVI_CODE_FUNCTION_CALL (*value),
-	TRUE);
-    return TRUE;
-  } else {
-    return parse_member_expression (data, value, statement);
-  }
 }
 
-static gboolean
+static void
 parse_left_hand_side_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
@@ -854,44 +940,32 @@ parse_left_hand_side_expression (ParseData *data, ViviCodeValue **value,
   ViviCodeStatement *argument_statement;
   guint i;
 
-  *value = NULL;
-  *statement = NULL;
+  if (try_parse_token (data, TOKEN_NEW)) {
+    parse_left_hand_side_expression (data, value, statement);
 
-  if (check_token (data, TOKEN_NEW)) {
-    if (!parse_new_expression (data, value, statement))
-      vivi_parser_error_child_value (data, value);
     if (!VIVI_IS_CODE_FUNCTION_CALL (*value)) {
       ViviCodeValue *tmp = VIVI_CODE_VALUE (*value);
       *value = vivi_parser_function_call_new (tmp);
       g_object_unref (tmp);
     }
+
     vivi_code_function_call_set_construct (VIVI_CODE_FUNCTION_CALL (*value),
 	TRUE);
-    return TRUE;
+    return;
   }
 
-  if (!parse_member_expression (data, value, statement)) {
-    vivi_parser_cancel_unexpected (data, ERROR_TOKEN_MEMBER_EXPRESSION);
-    return FALSE;
-  }
+  parse_member_expression (data, value, statement);
 
-  while (TRUE) {
-    // TODO: member expressions?
-    if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
-      break;
-
-    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
-      if (!parse_value_statement_list (data, parse_assignment_expression,
-	    &arguments, &argument_statement, TOKEN_COMMA)) {
-	// TODO
-	arguments = NULL;
-      }
+  while (try_parse_token (data, TOKEN_PARENTHESIS_LEFT)) {
+    if (!try_parse_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+      parse_value_statement_list (data, peek_assignment_expression,
+	  parse_assignment_expression, &arguments, &argument_statement,
+	  TOKEN_COMMA);
 
       *statement =
 	vivi_parser_join_statements (*statement, argument_statement);
 
-      if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
-	vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
+      parse_token (data, TOKEN_PARENTHESIS_RIGHT);
     } else {
       arguments = NULL;
     }
@@ -908,39 +982,37 @@ parse_left_hand_side_expression (ParseData *data, ViviCodeValue **value,
       free_value_list (arguments);
     }
   }
-
-  return TRUE;
 }
 
 static gboolean
+peek_postfix_expression (ParseData *data)
+{
+  return peek_left_hand_side_expression (data);
+}
+
+static void
 parse_postfix_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
   ViviCodeValue *operation, *one, *temporary;
   const char *operator;
 
-  *value = NULL;
-  *statement = NULL;
+  parse_left_hand_side_expression (data, value, statement);
 
-  if (!parse_left_hand_side_expression (data, value, statement)) {
-    vivi_parser_cancel_unexpected (data, ERROR_TOKEN_POSTFIX_EXPRESSION);
-    return FALSE;
-  }
-
-  if (check_line_terminator (data))
-    return TRUE;
+  if (peek_line_terminator (data))
+    return;
 
-  if (check_token (data, TOKEN_INCREASE)) {
+  if (try_parse_token (data, TOKEN_INCREASE)) {
     operator = "+";
-  } else if (check_token (data, TOKEN_DESCREASE)) {
+  } else if (try_parse_token (data, TOKEN_DESCREASE)) {
     operator = "-";
   } else {
-    return TRUE;
+    return;
   }
 
   // FIXME: Correct?
   if (!vivi_parser_value_is_left_hand_side (*value)) {
-    vivi_parser_error (
+    vivi_parser_error (data,
 	"Invalid left-hand side expression for INCREASE/DECREASE");
   }
 
@@ -957,20 +1029,37 @@ parse_postfix_expression (ParseData *data, ViviCodeValue **value,
 
   g_object_unref (*value);
   *value = temporary;
-
-  return TRUE;
 }
 
 static gboolean
+peek_unary_expression (ParseData *data)
+{
+  vivi_parser_scanner_peek_next_token (data->scanner);
+  switch ((guint)data->scanner->next_token) {
+    /*case TOKEN_DELETE:
+    case TOKEN_VOID:
+    case TOKEN_TYPEOF:*/
+    case TOKEN_INCREASE:
+    case TOKEN_DESCREASE:
+    /*case TOKEN_PLUS:
+    case TOKEN_MINUS:
+    case TOKEN_BITWISE_NOT:*/
+    case TOKEN_LOGICAL_NOT:
+      return TRUE;
+    default:
+      return peek_postfix_expression (data);
+  }
+
+  g_assert_not_reached ();
+}
+
+static void
 parse_unary_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
-  gboolean status;
   ViviCodeValue *tmp, *one;
   const char *operator;
 
-  *value = NULL;
-
   operator = NULL;
 
   vivi_parser_scanner_peek_next_token (data->scanner);
@@ -986,12 +1075,11 @@ parse_unary_expression (ParseData *data, ViviCodeValue **value,
 
       vivi_parser_scanner_get_next_token (data->scanner);
 
-      if (!parse_unary_expression (data, value, statement))
-	vivi_parser_error_child_value (data, value);
+      parse_unary_expression (data, value, statement);
 
       // FIXME: Correct?
       if (!vivi_parser_value_is_left_hand_side (*value)) {
-	vivi_parser_error (
+	vivi_parser_error (data,
 	    "Invalid left-hand side expression for INCREASE/DECREASE");
       }
 
@@ -1002,24 +1090,22 @@ parse_unary_expression (ParseData *data, ViviCodeValue **value,
       *statement = vivi_parser_join_statements (*statement,
 	  vivi_parser_assignment_new (*value, tmp));
       g_object_unref (tmp);
-
-      return TRUE;
+      break;
     /*case TOKEN_PLUS:
     case TOKEN_MINUS:
     case TOKEN_BITWISE_NOT:*/
     case TOKEN_LOGICAL_NOT:
       vivi_parser_scanner_get_next_token (data->scanner);
 
-      if (!parse_unary_expression (data, value, statement))
-	vivi_parser_error_child_value (data, value);
+      parse_unary_expression (data, value, statement);
 
       tmp = VIVI_CODE_VALUE (*value);
       *value = vivi_code_unary_new (tmp, '!');
       g_object_unref (tmp);
-
-      return TRUE;
+      break;
     default:
-      return parse_postfix_expression (data, value, statement);
+      parse_postfix_expression (data, value, statement);
+      break;
   }
 }
 
@@ -1029,7 +1115,7 @@ typedef enum {
   PASS_LOGICAL_AND
 } ParseOperatorPass;
 
-static gboolean
+static void
 parse_operator_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement, const ViviParserScannerToken *tokens,
     ParseOperatorPass pass, ParseValueStatementFunction next_parse_function)
@@ -1038,18 +1124,12 @@ parse_operator_expression (ParseData *data, ViviCodeValue **value,
   ViviCodeStatement *statement_right;
   guint i;
 
-  *value = NULL;
-  *statement = NULL;
-
-  if (!next_parse_function (data, value, statement)) {
-    // FIXME: token?
-    return FALSE;
-  }
+  next_parse_function (data, value, statement);
 
-  for (i = 0; tokens[i] != TRUE; i++) {
-    while (check_token (data, tokens[i])) {
-      if (!next_parse_function (data, &right, &statement_right))
-	vivi_parser_error_child_value (data, &right);
+again:
+  for (i = 0; tokens[i] != TOKEN_NONE; i++) {
+    if (try_parse_token (data, tokens[i])) {
+      next_parse_function (data, &right, &statement_right);
 
       if (statement_right != NULL) {
 	ViviCodeStatement *tmp;
@@ -1082,46 +1162,70 @@ parse_operator_expression (ParseData *data, ViviCodeValue **value,
 	  vivi_parser_scanner_token_name (tokens[i]));
       g_object_unref (left);
       g_object_unref (right);
-    };
-  }
 
-  return TRUE;
+      goto again;
+    }
+  }
 }
 
 static gboolean
+peek_multiplicative_expression (ParseData *data)
+{
+  return peek_unary_expression (data);
+}
+
+static void
 parse_multiplicative_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
   static const ViviParserScannerToken tokens[] = { TOKEN_MULTIPLY,
     TOKEN_DIVIDE, TOKEN_REMAINDER, TOKEN_NONE };
 
-  return parse_operator_expression (data, value, statement, tokens,
-      PASS_ALWAYS, parse_unary_expression);
+  parse_operator_expression (data, value, statement, tokens, PASS_ALWAYS,
+      parse_unary_expression);
 }
 
 static gboolean
+peek_additive_expression (ParseData *data)
+{
+  return peek_multiplicative_expression (data);
+}
+
+static void
 parse_additive_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
   static const ViviParserScannerToken tokens[] = { TOKEN_PLUS, TOKEN_MINUS,
     TOKEN_NONE };
 
-  return parse_operator_expression (data, value, statement, tokens,
-      PASS_ALWAYS, parse_multiplicative_expression);
+  parse_operator_expression (data, value, statement, tokens, PASS_ALWAYS,
+      parse_multiplicative_expression);
 }
 
 static gboolean
+peek_shift_expression (ParseData *data)
+{
+  return peek_additive_expression (data);
+}
+
+static void
 parse_shift_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
   static const ViviParserScannerToken tokens[] = { TOKEN_SHIFT_LEFT,
     TOKEN_SHIFT_RIGHT, TOKEN_SHIFT_RIGHT_UNSIGNED, TOKEN_NONE };
 
-  return parse_operator_expression (data, value, statement, tokens,
-      PASS_ALWAYS, parse_additive_expression);
+  parse_operator_expression (data, value, statement, tokens, PASS_ALWAYS,
+      parse_additive_expression);
 }
 
 static gboolean
+peek_relational_expression (ParseData *data)
+{
+  return peek_shift_expression (data);
+}
+
+static void
 parse_relational_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
@@ -1129,11 +1233,17 @@ parse_relational_expression (ParseData *data, ViviCodeValue **value,
     TOKEN_GREATER_THAN, /*TOKEN_LESS_THAN_OR_EQUAL,
     TOKEN_EQUAL_OR_GREATER_THAN, TOKEN_INSTANCEOF, TOKEN_IN,*/ TOKEN_NONE };
 
-  return parse_operator_expression (data, value, statement, tokens,
-      PASS_ALWAYS, parse_shift_expression);
+  parse_operator_expression (data, value, statement, tokens, PASS_ALWAYS,
+      parse_shift_expression);
 }
 
 static gboolean
+peek_equality_expression (ParseData *data)
+{
+  return peek_relational_expression (data);
+}
+
+static void
 parse_equality_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
@@ -1141,78 +1251,111 @@ parse_equality_expression (ParseData *data, ViviCodeValue **value,
     /*TOKEN_NOT_EQUAL,*/ TOKEN_STRICT_EQUAL, /*TOKEN_NOT_STRICT_EQUAL,*/
     TOKEN_NONE };
 
-  return parse_operator_expression (data, value, statement, tokens,
-      PASS_ALWAYS, parse_relational_expression);
+  parse_operator_expression (data, value, statement, tokens, PASS_ALWAYS,
+      parse_relational_expression);
 }
 
 static gboolean
+peek_bitwise_and_expression (ParseData *data)
+{
+  return peek_equality_expression (data);
+}
+
+static void
 parse_bitwise_and_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
   static const ViviParserScannerToken tokens[] = { TOKEN_BITWISE_AND,
     TOKEN_NONE };
 
-  return parse_operator_expression (data, value, statement, tokens,
-      PASS_ALWAYS, parse_equality_expression);
+  parse_operator_expression (data, value, statement, tokens, PASS_ALWAYS,
+      parse_equality_expression);
 }
 
 static gboolean
+peek_bitwise_xor_expression (ParseData *data)
+{
+  return peek_bitwise_and_expression (data);
+}
+
+static void
 parse_bitwise_xor_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
   static const ViviParserScannerToken tokens[] = { TOKEN_BITWISE_XOR,
     TOKEN_NONE };
 
-  return parse_operator_expression (data, value, statement, tokens,
-      PASS_ALWAYS, parse_bitwise_and_expression);
+  parse_operator_expression (data, value, statement, tokens, PASS_ALWAYS,
+      parse_bitwise_and_expression);
 }
 
 static gboolean
+peek_bitwise_or_expression (ParseData *data)
+{
+  return peek_bitwise_xor_expression (data);
+}
+
+static void
 parse_bitwise_or_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
   static const ViviParserScannerToken tokens[] = { TOKEN_BITWISE_OR,
     TOKEN_NONE };
 
-  return parse_operator_expression (data, value, statement, tokens,
-      PASS_ALWAYS, parse_bitwise_xor_expression);
+  parse_operator_expression (data, value, statement, tokens, PASS_ALWAYS,
+      parse_bitwise_xor_expression);
 }
 
 static gboolean
+peek_logical_and_expression (ParseData *data)
+{
+  return peek_bitwise_or_expression (data);
+}
+
+static void
 parse_logical_and_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
   static const ViviParserScannerToken tokens[] = { TOKEN_LOGICAL_AND,
     TOKEN_NONE };
 
-  return parse_operator_expression (data, value, statement, tokens,
-      PASS_LOGICAL_AND, parse_bitwise_or_expression);
+  parse_operator_expression (data, value, statement, tokens, PASS_LOGICAL_AND,
+      parse_bitwise_or_expression);
 }
 
 static gboolean
+peek_logical_or_expression (ParseData *data)
+{
+  return peek_logical_and_expression (data);
+}
+
+static void
 parse_logical_or_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
   static const ViviParserScannerToken tokens[] = { TOKEN_LOGICAL_OR,
     TOKEN_NONE };
 
-  return parse_operator_expression (data, value, statement, tokens,
-      PASS_LOGICAL_OR, parse_logical_and_expression);
+  parse_operator_expression (data, value, statement, tokens, PASS_LOGICAL_OR,
+      parse_logical_and_expression);
 }
 
 static gboolean
+peek_conditional_expression (ParseData *data)
+{
+  return peek_logical_or_expression (data);
+}
+
+static void
 parse_conditional_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
   //ViviCodeStatement *if_statement, *else_statement;
 
-  *value = NULL;
-
-  if (!parse_logical_or_expression (data, value, statement))
-    return FALSE;
+  parse_logical_or_expression (data, value, statement);
 
 #if 0
-  if (!check_token (data, TOKEN_QUESTION_MARK)) {
+  if (!parse_token (data, TOKEN_QUESTION_MARK)) {
     *statement = vivi_code_value_statement_new (VIVI_CODE_VALUE (value));
     g_object_unref (value);
     return TRUE;
@@ -1224,7 +1367,7 @@ parse_conditional_expression (ParseData *data, ViviCodeValue **value,
     return FAIL_CHILD (status);
   }
 
-  if (!check_token (data, TOKEN_COLON)) {
+  if (!parse_token (data, TOKEN_COLON)) {
     g_object_unref (value);
     g_object_unref (if_statement);
     return TOKEN_COLON;
@@ -1245,11 +1388,15 @@ parse_conditional_expression (ParseData *data, ViviCodeValue **value,
   g_object_unref (if_statement);
   g_object_unref (else_statement);
 #endif
-
-  return TRUE;
 }
 
 static gboolean
+peek_assignment_expression (ParseData *data)
+{
+  return peek_conditional_expression (data);
+}
+
+static void
 parse_assignment_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
@@ -1257,16 +1404,11 @@ parse_assignment_expression (ParseData *data, ViviCodeValue **value,
   ViviCodeStatement *assignment, *statement_right;
   const char *operator;
 
-  *value = NULL;
-  *statement = NULL;
-
-  if (!parse_conditional_expression (data, value, statement)) {
-    vivi_parser_cancel_unexpected (data, ERROR_TOKEN_CONDITIONAL_EXPRESSION);
-    return FALSE;
-  }
+  parse_conditional_expression (data, value, statement);
 
+  // FIXME: Correct?
   if (!vivi_parser_value_is_left_hand_side (*value))
-    return TRUE;
+    return;
 
   operator = NULL;
 
@@ -1297,8 +1439,7 @@ parse_assignment_expression (ParseData *data, ViviCodeValue **value,
     case TOKEN_ASSIGN:
       vivi_parser_scanner_get_next_token (data->scanner);
 
-      if (parse_assignment_expression (data, &right, &statement_right))
-	vivi_parser_error_child_value (data, &right);
+      parse_assignment_expression (data, &right, &statement_right);
 
       if (operator != NULL) {
 	assignment = vivi_parser_assignment_new (*value,
@@ -1310,98 +1451,71 @@ parse_assignment_expression (ParseData *data, ViviCodeValue **value,
 
       *statement = vivi_parser_join_statements (*statement,
 	  vivi_parser_join_statements (statement_right, assignment));
-
-      return TRUE;
+      break;
     default:
-      return TRUE;
+      break;
   }
-
-  g_assert_not_reached ();
 }
 
 static gboolean
+peek_expression (ParseData *data)
+{
+  return peek_assignment_expression (data);
+}
+
+static void
 parse_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
   ViviCodeStatement *statement_one;
 
+  *value = NULL;
   *statement = NULL;
 
-  if (parse_assignment_expression (data, value, &statement_one)) {
-    vivi_parser_cancel_unexpected (data, ERROR_TOKEN_ASSIGNMENT_EXPRESSION);
-    return FALSE;
-  }
-
-  while (TRUE) {
+  do {
+    if (*value != NULL)
+      g_object_unref (*value);
+    parse_assignment_expression (data, value, &statement_one);
     *statement = vivi_parser_join_statements (*statement, statement_one);
-
-    if (!check_token (data, TOKEN_COMMA))
-      break;
-
-    g_object_unref (*value);
-
-    if (!parse_assignment_expression (data, value, &statement_one))
-	vivi_parser_error_child_value (data, value);
-  }
-
-  return TRUE;
+  } while (try_parse_token (data, TOKEN_COMMA));
 }
 
 // statement
 
 static gboolean
-parse_statement (ParseData *data, ViviCodeStatement **statement);
+peek_trace_statement (ParseData *data)
+{
+  return peek_token (data, TOKEN_TRACE);
+}
 
-static gboolean
+static void
 parse_trace_statement (ParseData *data, ViviCodeStatement **statement)
 {
   ViviCodeValue *value;
   ViviCodeStatement *expression_statement;
 
-  *statement = NULL;
-
-  if (!check_token (data, TOKEN_TRACE)) {
-    vivi_parser_cancel_unexpected (data, TOKEN_TRACE);
-    return FALSE;
-  }
-
-  if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
-    vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
-
-  if (parse_expression (data, &value, &expression_statement))
-    vivi_parser_error_child_value (data, &value);
-
-  if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
-    vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
-
-  if (!check_automatic_semicolon (data))
-    vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
+  parse_token (data, TOKEN_TRACE);
+  parse_token (data, TOKEN_PARENTHESIS_LEFT);
+  parse_expression (data, &value, &expression_statement);
+  parse_token (data, TOKEN_PARENTHESIS_RIGHT);
+  parse_automatic_semicolon (data);
 
   *statement = vivi_code_trace_new (value);
   g_object_unref (value);
 
   *statement = vivi_parser_join_statements (expression_statement, *statement);
-
-  return TRUE;
 }
 
-static gboolean
+static void
 parse_continue_or_break_statement (ParseData *data,
     ViviCodeStatement **statement, ViviParserScannerToken token)
 {
-  *statement = NULL;
+  parse_token (data, token);
 
-  if (!check_token (data, token)) {
-    vivi_parser_cancel_unexpected (data, token);
-    return FALSE;
-  }
-
-  if (!check_restricted_semicolon (data)) {
-    gboolean status;
+  if (!try_parse_restricted_semicolon (data)) {
     ViviCodeValue *identifier;
 
-    if (!parse_identifier (data, &identifier))
-      vivi_parser_error_child_value (data, &identifier);
+    parse_identifier (data, &identifier);
 
     // FIXME
     *statement = vivi_compiler_goto_name_new (
@@ -1411,81 +1525,84 @@ parse_continue_or_break_statement (ParseData *data,
 
     vivi_parser_add_goto (data, VIVI_COMPILER_GOTO_NAME (*statement));
 
-    if (!check_automatic_semicolon (data))
-      vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
+    parse_automatic_semicolon (data);
   } else {
+    // FIXME
     *statement = vivi_code_break_new ();
   }
-
-  return TRUE;
 }
 
 static gboolean
+peek_continue_statement (ParseData *data)
+{
+  return peek_token (data, TOKEN_CONTINUE);
+}
+
+static void
 parse_continue_statement (ParseData *data, ViviCodeStatement **statement)
 {
   return parse_continue_or_break_statement (data, statement, TOKEN_CONTINUE);
 }
 
 static gboolean
+peek_break_statement (ParseData *data)
+{
+  return peek_token (data, TOKEN_BREAK);
+}
+
+static void
 parse_break_statement (ParseData *data, ViviCodeStatement **statement)
 {
-  return parse_continue_or_break_statement (data, statement, TOKEN_BREAK);
+  parse_continue_or_break_statement (data, statement, TOKEN_BREAK);
 }
 
 static gboolean
+peek_throw_statement (ParseData *data)
+{
+  return peek_token (data, TOKEN_THROW);
+}
+
+static void
 parse_throw_statement (ParseData *data, ViviCodeStatement **statement)
 {
-  gboolean status;
   ViviCodeValue *value;
   ViviCodeStatement *expression_statement;
 
-  *statement = NULL;
-
-  if (!check_token (data, TOKEN_THROW)) {
-    vivi_parser_cancel_unexpected (data, TOKEN_THROW);
-    return FALSE;
-  }
+  parse_token (data, TOKEN_THROW);
 
-  if (check_line_terminator (data))
+  if (peek_line_terminator (data)) {
     vivi_parser_error_unexpected_line_terminator (data,
 	ERROR_TOKEN_EXPRESSION);
+  }
 
-  if (parse_expression (data, &value, &expression_statement))
-    vivi_parser_error_child_value (data, &value);
+  parse_expression (data, &value, &expression_statement);
 
   *statement = vivi_code_throw_new (value);
   g_object_unref (value);
 
   *statement = vivi_parser_join_statements (expression_statement, *statement);
 
-  if (!check_automatic_semicolon (data))
-    vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
-
-  return TRUE;
+  parse_automatic_semicolon (data);
 }
 
 static gboolean
-parse_return_statement (ParseData *data, ViviCodeStatement **statement)
+peek_return_statement (ParseData *data)
 {
-  *statement = NULL;
-
-  if (!check_token (data, TOKEN_RETURN)) {
-    vivi_parser_cancel_unexpected (data, TOKEN_RETURN);
-    return FALSE;
-  }
+  return peek_token (data, TOKEN_RETURN);
+}
 
+static void
+parse_return_statement (ParseData *data, ViviCodeStatement **statement)
+{
   *statement = vivi_code_return_new ();
 
-  if (!check_restricted_semicolon (data)) {
-    gboolean status;
+  parse_token (data, TOKEN_RETURN);
+
+  if (!try_parse_restricted_semicolon (data)) {
     ViviCodeValue *value;
     ViviCodeStatement *expression_statement;
 
-    if (!parse_expression (data, &value, &expression_statement)) {
-      vivi_parser_error_unexpected (data, TOKEN_SEMICOLON,
-	  ERROR_TOKEN_EXPRESSION);
-      return TRUE;
-    }
+    parse_expression (data, &value, &expression_statement);
 
     vivi_code_return_set_value (VIVI_CODE_RETURN (*statement), value);
     g_object_unref (value);
@@ -1493,69 +1610,60 @@ parse_return_statement (ParseData *data, ViviCodeStatement **statement)
     *statement =
       vivi_parser_join_statements (expression_statement, *statement);
 
-    if (!check_automatic_semicolon (data))
-      vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
+    parse_automatic_semicolon (data);
   }
-
-  return TRUE;
 }
 
 static gboolean
+peek_statement (ParseData *data);
+
+static void
+parse_statement (ParseData *data, ViviCodeStatement **statement);
+
+static gboolean
+peek_iteration_statement (ParseData *data)
+{
+  return (peek_token (data, TOKEN_DO) || peek_token (data, TOKEN_WHILE) ||
+      peek_token (data, TOKEN_FOR));
+}
+
+static void
 parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
 {
   ViviCodeValue *condition;
   ViviCodeStatement *pre_statement, *condition_statement, *loop_statement;
 
-  *statement = NULL;
-
-  pre_statement = NULL;
-  condition_statement = NULL;
-
-  if (check_token (data, TOKEN_DO)) {
-    if (!parse_statement (data, &loop_statement))
-      vivi_parser_error_child_statement (data, &loop_statement);
-
-    if (!check_token (data, TOKEN_WHILE))
-      vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
-
-    if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
-      vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
-
-    if (parse_expression (data, &condition, &condition_statement))
-      vivi_parser_error_child_value (data, &condition);
-
-    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
-      vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
-
-    if (!check_automatic_semicolon (data))
-      vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
+  if (try_parse_token (data, TOKEN_DO))
+  {
+    parse_statement (data, &loop_statement);
+    parse_token (data, TOKEN_WHILE);
+    parse_token (data, TOKEN_PARENTHESIS_LEFT);
+    parse_expression (data, &condition, &condition_statement);
+    parse_token (data, TOKEN_PARENTHESIS_RIGHT);
+    parse_automatic_semicolon (data);
 
     pre_statement = g_object_ref (loop_statement);
-  } else if (check_token (data, TOKEN_WHILE)) {
-    if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
-      vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
-
-    if (parse_expression (data, &condition, &condition_statement))
-      vivi_parser_error_child_value (data, &condition);
-
-    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
-      vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
+  }
+  else if (try_parse_token (data, TOKEN_WHILE))
+  {
+    parse_token (data, TOKEN_PARENTHESIS_LEFT);
+    parse_expression (data, &condition, &condition_statement);
+    parse_token (data, TOKEN_PARENTHESIS_RIGHT);
+    parse_statement (data, &loop_statement);
 
-    if (!parse_statement (data, &loop_statement))
-      vivi_parser_error_child_statement (data, &loop_statement);
-  } else if (check_token (data, TOKEN_FOR)) {
+    pre_statement = NULL;
+  }
+  else if (try_parse_token (data, TOKEN_FOR))
+  {
     ViviCodeValue *pre_value;
     ViviCodeStatement *post_statement;
 
-    if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
-      vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
+    parse_token (data, TOKEN_PARENTHESIS_LEFT);
 
-    if (check_token (data, TOKEN_VAR)) {
+    if (try_parse_token (data, TOKEN_VAR)) {
       // FIXME: no in
-      if (parse_statement_list (data, parse_variable_declaration,
-	    &pre_statement, TOKEN_COMMA)) {
-	// FIXME
-      }
+      parse_statement_list (data, peek_variable_declaration,
+	  parse_variable_declaration, &pre_statement, TOKEN_COMMA);
       // FIXME: ugly
       // If there was only one VariableDeclaration, get the name for pre_value
       g_assert (VIVI_IS_CODE_BLOCK (pre_statement));
@@ -1569,49 +1677,60 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
 	pre_value = NULL;
       }
     } else {
-      if (!check_token (data, TOKEN_SEMICOLON)) {
-	// FIXME: no in
-	if (parse_expression (data, &pre_value, &pre_statement))
-	  vivi_parser_error_child_value (data, &pre_value);
-      } else {
+      if (try_parse_token (data, TOKEN_SEMICOLON)) {
 	pre_value = NULL;
 	pre_statement = NULL;
+      } else {
+	// FIXME: no in
+	parse_expression (data, &pre_value, &pre_statement);
       }
     }
 
-    if (check_token (data, TOKEN_SEMICOLON)) {
+    if (try_parse_token (data, TOKEN_SEMICOLON)) {
       if (pre_value != NULL)
 	g_object_unref (pre_value);
-      if (!check_token (data, TOKEN_SEMICOLON)) {
-	if (parse_expression (data, &condition, &condition_statement))
-	  vivi_parser_error_child_value (data, &condition);
 
-	if (!check_token (data, TOKEN_SEMICOLON))
-	  vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
+      if (try_parse_token (data, TOKEN_SEMICOLON)) {
+	condition = vivi_code_constant_new_boolean (TRUE);
+	condition_statement = NULL;
+      } else {
+	parse_expression (data, &condition, &condition_statement);
+	parse_token (data, TOKEN_SEMICOLON);
       }
 
-      if (!parse_expression (data, &pre_value, &post_statement))
-	vivi_parser_error_child_value (data, &pre_value);
-      g_object_unref (pre_value);
-    } else if (pre_value != NULL && check_token (data, TOKEN_IN)) {
+      if (peek_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+	post_statement = NULL;
+      } else {
+	parse_expression (data, &pre_value, &post_statement);
+	g_object_unref (pre_value);
+      }
+    } else if (pre_value != NULL && try_parse_token (data, TOKEN_IN)) {
       post_statement = NULL;
 
       // FIXME: correct?
       if (!vivi_parser_value_is_left_hand_side (pre_value))
-	vivi_parser_error ("Invalid left-hand side expression for in");
+	vivi_parser_error (data, "Invalid left-hand side expression for in");
 
       g_object_unref (pre_value);
       if (pre_statement != NULL)
 	g_object_unref (pre_statement);
-      vivi_parser_error ("for (... in ...) has not been implemented yet");
+
+      vivi_parser_error (data, "for (... in ...) has not been implemented yet");
+
+      condition = vivi_code_constant_new_undefined ();
+      condition_statement = NULL;
+      post_statement = NULL;
     } else {
       if (pre_value != NULL) {
-	vivi_parser_error_unexpected (data, TOKEN_SEMICOLON, TOKEN_IN);
+	vivi_parser_error_unexpected_or (data, TOKEN_SEMICOLON, TOKEN_IN,
+	    TOKEN_NONE);
       } else {
 	vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
       }
 
       condition = vivi_code_constant_new_undefined ();
+      condition_statement = NULL;
+      post_statement = NULL;
 
       if (pre_value != NULL)
 	g_object_unref (pre_value);
@@ -1619,17 +1738,20 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
 	g_object_unref (pre_statement);
     }
 
-    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
-      vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
-
-    if (!parse_statement (data, &loop_statement))
-      vivi_parser_error_child_statement (data, &loop_statement);
+    parse_token (data, TOKEN_PARENTHESIS_RIGHT);
+    parse_statement (data, &loop_statement);
 
     loop_statement =
       vivi_parser_join_statements (loop_statement, post_statement);
-  } else {
-    vivi_parser_cancel_unexpected (data, ERROR_TOKEN_ITERATION_STATEMENT);
-    return FALSE;
+  }
+  else
+  {
+    vivi_parser_error_unexpected (data, ERROR_TOKEN_ITERATION_STATEMENT);
+
+    condition = vivi_code_constant_new_undefined ();
+    pre_statement = NULL;
+    condition_statement = NULL;
+    loop_statement = vivi_compiler_empty_statement_new ();
   }
 
   if (condition_statement != NULL) {
@@ -1647,38 +1769,28 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
   g_object_unref (loop_statement);
 
   *statement = vivi_parser_join_statements (pre_statement, *statement);
-
-  return TRUE;
 }
 
 static gboolean
+peek_if_statement (ParseData *data)
+{
+  return peek_token (data, TOKEN_IF);
+}
+
+static void
 parse_if_statement (ParseData *data, ViviCodeStatement **statement)
 {
   ViviCodeValue *condition;
   ViviCodeStatement *pre_statement, *if_statement, *else_statement;
 
-  *statement = NULL;
-
-  if (!check_token (data, TOKEN_IF)) {
-    vivi_parser_cancel_unexpected (data, TOKEN_IF);
-    return FALSE;
-  }
-
-  if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
-    vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
-
-  if (!parse_expression (data, &condition, &pre_statement))
-    vivi_parser_error_child_value (data, &condition);
-
-  if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
-    vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
+  parse_token (data, TOKEN_IF);
+  parse_token (data, TOKEN_PARENTHESIS_LEFT);
+  parse_expression (data, &condition, &pre_statement);
+  parse_token (data, TOKEN_PARENTHESIS_RIGHT);
+  parse_statement (data, &if_statement);
 
-  if (!parse_statement (data, &if_statement))
-    vivi_parser_error_child_statement (data, &if_statement);
-
-  if (check_token (data, TOKEN_ELSE)) {
-    if (!parse_statement (data, &else_statement))
-      vivi_parser_error_child_statement (data, &else_statement);
+  if (try_parse_token (data, TOKEN_ELSE)) {
+    parse_statement (data, &else_statement);
   } else {
     else_statement = NULL;
   }
@@ -1695,43 +1807,40 @@ parse_if_statement (ParseData *data, ViviCodeStatement **statement)
   }
 
   *statement = vivi_parser_join_statements (pre_statement, *statement);
+}
 
-  g_assert (*statement != NULL);
+static gboolean
+peek_expression_statement (ParseData *data)
+{
+  if (peek_token (data, TOKEN_BRACE_LEFT) || peek_token (data, TOKEN_FUNCTION))
+    return FALSE;
 
-  return TRUE;
+  return peek_expression (data);
 }
 
-static gboolean
+static void
 parse_expression_statement (ParseData *data, ViviCodeStatement **statement)
 {
   ViviCodeValue *value;
   ViviCodeStatement *last;
 
-  *statement = NULL;
+  if (peek_token (data, TOKEN_BRACE_LEFT) || peek_token (data, TOKEN_FUNCTION))
+    vivi_parser_error_unexpected (data, ERROR_TOKEN_EXPRESSION_STATEMENT);
 
-  vivi_parser_scanner_peek_next_token (data->scanner);
-  if (data->scanner->next_token == TOKEN_BRACE_LEFT ||
-      data->scanner->next_token == TOKEN_FUNCTION) {
-    vivi_parser_cancel_unexpected (data, ERROR_TOKEN_EXPRESSION_STATEMENT);
-    return FALSE;
-  }
-
-  if (!parse_expression (data, &value, statement))
-    return FALSE;
+  parse_expression (data, &value, statement);
 
   // check for label
-  if (*statement == NULL && vivi_parser_value_is_identifier (value)) {
-    if (check_token (data, TOKEN_COLON)) {
-      *statement = vivi_code_label_new (vivi_code_constant_get_variable_name (
-	    VIVI_CODE_CONSTANT (VIVI_CODE_GET (value)->name)));
-      if (!vivi_parser_add_label (data, VIVI_CODE_LABEL (*statement)))
-	vivi_parser_error ("Same label name used twice");
-      return TRUE;
-    }
+  if (*statement == NULL && vivi_parser_value_is_identifier (value) &&
+      try_parse_token (data, TOKEN_COLON))
+  {
+    *statement = vivi_code_label_new (vivi_code_constant_get_variable_name (
+	  VIVI_CODE_CONSTANT (VIVI_CODE_GET (value)->name)));
+    if (!vivi_parser_add_label (data, VIVI_CODE_LABEL (*statement)))
+      vivi_parser_error (data, "Same label name used twice");
+    return;
   }
 
-  if (!check_automatic_semicolon (data))
-    vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
+  parse_automatic_semicolon (data);
 
   // add a value statement, if the last statement is not an assignment with the
   // same value
@@ -1749,124 +1858,129 @@ parse_expression_statement (ParseData *data, ViviCodeStatement **statement)
 
     if (assignment->from == NULL && assignment->name == VIVI_CODE_GET (value)->name) {
       g_object_unref (value);
-      return TRUE;
+      return;
     }
   }
 
   *statement = vivi_parser_join_statements (*statement,
       vivi_code_value_statement_new (value));
   g_object_unref (value);
-
-  return TRUE;
 }
 
 static gboolean
-parse_empty_statement (ParseData *data, ViviCodeStatement **statement)
+peek_empty_statement (ParseData *data)
 {
-  *statement = NULL;
+  return peek_token (data, TOKEN_SEMICOLON);
+}
 
-  if (!check_token (data, TOKEN_SEMICOLON)) {
-    vivi_parser_cancel_unexpected (data, TOKEN_SEMICOLON);
-    return FALSE;
-  }
+static void
+parse_empty_statement (ParseData *data, ViviCodeStatement **statement)
+{
+  parse_token (data, TOKEN_SEMICOLON);
 
   *statement = vivi_compiler_empty_statement_new ();
-
-  return TRUE;
 }
 
 static gboolean
-parse_block (ParseData *data, ViviCodeStatement **statement)
+peek_block (ParseData *data)
 {
-  gboolean status;
-
-  *statement = NULL;
-
-  if (!check_token (data, TOKEN_BRACE_LEFT)) {
-    vivi_parser_cancel_unexpected (data, TOKEN_BRACE_LEFT);
-    return FALSE;
-  }
+  return peek_token (data, TOKEN_BRACE_LEFT);
+}
 
-  vivi_parser_scanner_peek_next_token (data->scanner);
-  if (!check_token (data, TOKEN_BRACE_RIGHT)) {
-    if (!parse_statement_list (data, parse_statement, statement, TRUE)) {
-      // FIXME: child token
-      vivi_parser_error_unexpected (data, TOKEN_BRACE_RIGHT,
-	  ERROR_TOKEN_STATEMENT);
-      *statement = vivi_code_block_new ();
-    }
+static void
+parse_block (ParseData *data, ViviCodeStatement **statement)
+{
+  parse_token (data, TOKEN_BRACE_LEFT);
 
-    if (!check_token (data, TOKEN_BRACE_RIGHT))
-      vivi_parser_error_unexpected (data, TOKEN_BRACE_RIGHT);
+  if (!try_parse_token (data, TOKEN_BRACE_RIGHT)) {
+    parse_statement_list (data, peek_statement, parse_statement, statement,
+	TOKEN_NONE);
+    parse_token (data, TOKEN_BRACE_RIGHT);
   } else {
-    *statement = vivi_code_block_new ();
+    *statement = vivi_code_block_new ();;
   }
-
-  return TRUE;
 }
 
 static gboolean
+peek_variable_statement (ParseData *data)
+{
+  return peek_token (data, TOKEN_VAR);
+}
+
+static void
 parse_variable_statement (ParseData *data, ViviCodeStatement **statement)
 {
-  gboolean status;
+  parse_token (data, TOKEN_VAR);
+  parse_statement_list (data, peek_variable_declaration,
+      parse_variable_declaration, statement, TOKEN_COMMA);
+  parse_automatic_semicolon (data);
+}
 
-  *statement = NULL;
+static const struct {
+  PeekFunction peek;
+  ParseStatementFunction parse;
+} statement_functions[] = {
+  { peek_block, parse_block },
+  { peek_variable_statement, parse_variable_statement },
+  { peek_empty_statement, parse_empty_statement },
+  { peek_expression_statement, parse_expression_statement },
+  { peek_if_statement, parse_if_statement },
+  { peek_iteration_statement, parse_iteration_statement },
+  { peek_continue_statement, parse_continue_statement },
+  { peek_break_statement, parse_break_statement },
+  { peek_return_statement, parse_return_statement },
+  //{ peek_with_statement, parse_with_statement },
+  //{ peek_switch_statement, parse_switch_statement },
+  { peek_throw_statement, parse_throw_statement },
+  //{ peek_try_statement, parse_try_statement },
+  { peek_trace_statement, parse_trace_statement },
+  { NULL, NULL }
+};
 
-  if (!check_token (data, TOKEN_VAR)) {
-    vivi_parser_cancel_unexpected (data, TOKEN_VAR);
-    return FALSE;
-  }
+static gboolean
+peek_statement (ParseData *data)
+{
+  guint i;
 
-  if (!parse_statement_list (data, parse_variable_declaration, statement,
-	TOKEN_COMMA)) {
-    // FIXME
+  for (i = 0; statement_functions[i].peek != NULL; i++) {
+    if (statement_functions[i].peek (data))
+      return TRUE;
   }
 
-  if (!check_automatic_semicolon (data))
-    vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
-
-  return TRUE;
+  return FALSE;
 }
 
-static gboolean
+static void
 parse_statement (ParseData *data, ViviCodeStatement **statement)
 {
-  static const ParseStatementFunction functions[] = {
-    parse_block,
-    parse_variable_statement,
-    parse_empty_statement,
-    parse_expression_statement,
-    parse_if_statement,
-    parse_iteration_statement,
-    parse_continue_statement,
-    parse_break_statement,
-    parse_return_statement,
-    //parse_with_statement,
-    //parse_switch_statement,
-    parse_throw_statement,
-    //parse_try_statement,
-    parse_trace_statement,
-    NULL
-  };
   guint i;
 
-  *statement = NULL;
-
-  for (i = 0; functions[i] != NULL; i++) {
-    if (functions[i] (data, statement))
-      return TRUE;
+  for (i = 0; statement_functions[i].peek != NULL; i++) {
+    if (statement_functions[i].peek (data)) {
+      statement_functions[i].parse (data, statement);
+      return;
+    }
   }
 
-  vivi_parser_cancel_unexpected (data, ERROR_TOKEN_STATEMENT);
-  return FALSE;
+  vivi_parser_error_unexpected (data, ERROR_TOKEN_STATEMENT);
+  *statement = vivi_compiler_empty_statement_new ();
 }
 
 // function
 
 static gboolean
-parse_source_element (ParseData *data, ViviCodeStatement **statement);
+peek_function_definition (ParseData *data)
+{
+  return peek_token (data, TOKEN_FUNCTION);
+}
 
 static gboolean
+peek_source_element (ParseData *data);
+
+static void
+parse_source_element (ParseData *data, ViviCodeStatement **statement);
+
+static void
 parse_function_definition (ParseData *data, ViviCodeValue **function,
     ViviCodeValue **identifier, gboolean identifier_required)
 {
@@ -1874,56 +1988,43 @@ parse_function_definition (ParseData *data, ViviCodeValue **function,
   ViviCodeStatement *body;
   guint i;
 
-  *function = NULL;
-  *identifier = NULL;
-
   arguments = NULL;
   body = NULL;
 
-  if (!check_token (data, TOKEN_FUNCTION)) {
-    vivi_parser_cancel_unexpected (data, TOKEN_FUNCTION);
-    return FALSE;
-  }
+  parse_token (data, TOKEN_FUNCTION);
 
   if (identifier_required) {
-    if (!parse_identifier (data, identifier))
-      vivi_parser_error_child_value (data, identifier);
-
-    if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
-      vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
+    parse_identifier (data, identifier);
+    parse_token (data, TOKEN_PARENTHESIS_LEFT);
   } else {
-    if (!check_token (data, TOKEN_PARENTHESIS_LEFT)) {
-      if (!parse_identifier (data, identifier)) {
-	// FIXME: child token
-	vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT,
-	    ERROR_TOKEN_IDENTIFIER);
+    if (!try_parse_token (data, TOKEN_PARENTHESIS_LEFT)) {
+      if (peek_identifier (data)) {
+	parse_identifier (data, identifier);
+	parse_token (data, TOKEN_PARENTHESIS_LEFT);
+      } else {
+	vivi_parser_error_unexpected_or (data, TOKEN_PARENTHESIS_LEFT,
+	    ERROR_TOKEN_IDENTIFIER, TOKEN_NONE);
+	*identifier = NULL;
       }
-
-      if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
-	vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
+    } else {
+      *identifier = NULL;
     }
   }
 
-  if (!parse_value_list (data, parse_identifier, &arguments, TOKEN_COMMA)) {
-    // FIXME
+  if (!try_parse_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+    parse_value_list (data, peek_identifier, parse_identifier, &arguments,
+	TOKEN_COMMA);
+    parse_token (data, TOKEN_PARENTHESIS_RIGHT);
   }
 
-  if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
-    vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
-
-  if (!check_token (data, TOKEN_BRACE_LEFT))
-    vivi_parser_error_unexpected (data, TOKEN_BRACE_LEFT);
+  parse_token (data, TOKEN_BRACE_LEFT);
 
   vivi_parser_start_level (data);
-
-  if (parse_statement_list (data, parse_source_element, &body, TRUE)) {
-    // FIXME
-  }
-
+  parse_statement_list (data, peek_source_element, parse_source_element,
+      &body, TOKEN_NONE);
   vivi_parser_end_level (data);
 
-  if (!check_token (data, TOKEN_BRACE_RIGHT))
-    vivi_parser_error_unexpected (data, TOKEN_BRACE_RIGHT);
+  parse_token (data, TOKEN_BRACE_RIGHT);
 
   *function = vivi_code_function_new ();
   if (body != NULL) {
@@ -1938,65 +2039,74 @@ parse_function_definition (ParseData *data, ViviCodeValue **function,
     }
     free_value_list (arguments);
   }
-
-  return TRUE;
 }
 
 static gboolean
+peek_function_declaration (ParseData *data)
+{
+  return peek_function_definition (data);
+}
+
+static void
 parse_function_declaration (ParseData *data, ViviCodeStatement **statement)
 {
-  gboolean status;
   ViviCodeValue *function, *identifier;
 
-  *statement = NULL;
-
-  if (!parse_function_definition (data, &function, &identifier, TRUE))
-    return FALSE;
+  parse_function_definition (data, &function, &identifier, TRUE);
 
+  // FIXME
   *statement = vivi_parser_assignment_new (identifier, function);
   g_object_unref (identifier);
   g_object_unref (function);
-
-  return TRUE;
 }
 
 static gboolean
+peek_function_expression (ParseData *data)
+{
+  return peek_function_definition (data);
+}
+
+static void
 parse_function_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
-  gboolean status;
-  ViviCodeValue *identifier;
-
-  *statement = NULL;
+  ViviCodeValue *function, *identifier;
 
-  if (!parse_function_definition (data, &function, &identifier, FALSE))
-    return FALSE;
+  parse_function_definition (data, &function, &identifier, FALSE);
 
+  // FIXME
   if (identifier != NULL) {
     *statement = vivi_parser_assignment_new (identifier, *value);
     g_object_unref (identifier);
   }
-
-  return TRUE;
 }
 
 // top
 
 static gboolean
-parse_source_element (ParseData *data, ViviCodeStatement **statement)
+peek_source_element (ParseData *data)
 {
-  *statement = NULL;
+  return (peek_function_declaration (data) || peek_statement (data));
+}
 
-  if (!parse_function_declaration (data, statement)) {
-    if (!parse_statement (data, statement)) {
-      // FIXME
-      vivi_parser_cancel_unexpected (data, ERROR_TOKEN_FUNCTION_DECLARATION,
-	  ERROR_TOKEN_STATEMENT);
-      return FALSE;
-    }
+static void
+parse_source_element (ParseData *data, ViviCodeStatement **statement)
+{
+  if (peek_function_declaration (data)) {
+    parse_function_declaration (data, statement);
+  } else if (peek_statement (data)) {
+    parse_statement (data, statement);
+  } else {
+    vivi_parser_error_unexpected_or (data, ERROR_TOKEN_FUNCTION_DECLARATION,
+	ERROR_TOKEN_STATEMENT, TOKEN_NONE);
+    *statement = vivi_compiler_empty_statement_new ();
   }
+}
 
-  return TRUE;
+G_GNUC_UNUSED static gboolean
+peek_program (ParseData *data)
+{
+  return peek_source_element (data);
 }
 
 static void
@@ -2005,138 +2115,91 @@ parse_program (ParseData *data, ViviCodeStatement **statement)
   g_assert (data->level == NULL);
   vivi_parser_start_level (data);
 
-  *statement = NULL;
-
-  if (!parse_statement_list (data, parse_source_element, statement, TRUE))
-    // FIXME
-
-  if (!check_token (data, TOKEN_EOF))
-    vivi_parser_error_unexpected (data, TOKEN_EOF);
+  parse_statement_list (data, peek_source_element, parse_source_element,
+      statement, TOKEN_NONE);
+  parse_token (data, TOKEN_EOF);
 
   vivi_parser_end_level (data);
-
   g_assert (data->level == NULL);
 }
 
 // parsing
 
-static gboolean
-parse_statement_list (ParseData *data, ParseStatementFunction function,
-    ViviCodeStatement **block, guint separator)
+static void
+parse_statement_list (ParseData *data, PeekFunction peek,
+    ParseStatementFunction parse, ViviCodeStatement **block, guint separator)
 {
   ViviCodeStatement *statement;
-  gboolean status;
 
   g_assert (data != NULL);
-  g_assert (function != NULL);
+  g_assert (peek != NULL);
+  g_assert (parse != NULL);
   g_assert (block != NULL);
 
-  *block = NULL;
-
-  status = function (data, &statement);
-  if (status != TRUE)
-    return status;
-
   *block = vivi_code_block_new ();
 
   do {
+    parse (data, &statement);
     vivi_code_block_add_statement (VIVI_CODE_BLOCK (*block), statement);
     g_object_unref (statement);
-
-    if (separator != TRUE && !check_token (data, separator))
-      break;
-
-    status = function (data, &statement);
-    if (status == STATUS_FAIL) {
-      g_object_unref (*block);
-      *block = NULL;
-      return STATUS_FAIL;
-    }
-  } while (status == TRUE);
-
-  return TRUE;
+  } while ((separator == TOKEN_NONE || try_parse_token (data, separator)) &&
+      peek (data));
 }
 
-static gboolean
-parse_value_statement_list (ParseData *data,
-    ParseValueStatementFunction function, ViviCodeValue ***list,
+static void
+parse_value_statement_list (ParseData *data, PeekFunction peek,
+    ParseValueStatementFunction parse, ViviCodeValue ***list,
     ViviCodeStatement **statement, guint separator)
 {
   GPtrArray *array;
   ViviCodeValue *value;
   ViviCodeStatement *statement_one;
-  gboolean status;
 
   g_assert (data != NULL);
-  g_assert (function != NULL);
+  g_assert (peek != NULL);
+  g_assert (parse != NULL);
   g_assert (list != NULL);
   g_assert (statement != NULL);
 
-  *list = NULL;
   *statement = NULL;
 
-  status = function (data, &value, statement);
-  if (status != TRUE)
-    return status;
-
   array = g_ptr_array_new ();
 
   do {
+    parse (data, &value, &statement_one);
     g_ptr_array_add (array, value);
+    *statement = vivi_parser_join_statements (*statement, statement_one);
+  } while ((separator == TOKEN_NONE || try_parse_token (data, separator)) &&
+      peek (data));
 
-    if (separator != TOKEN_NONE && !check_token (data, separator))
-      break;
-
-    status = function (data, &value, &statement_one);
-    if (status != TRUE) {
-      if (status == STATUS_FAIL || separator != TOKEN_NONE)
-	return FAIL_CHILD (status);
-    } else {
-      *statement = vivi_parser_join_statements (*statement, statement_one);
-    }
-  } while (status == TRUE);
   g_ptr_array_add (array, NULL);
 
   *list = (ViviCodeValue **)g_ptr_array_free (array, FALSE);
-
-  return TRUE;
 }
 
-static gboolean
-parse_value_list (ParseData *data, ParseValueFunction function,
+static void
+parse_value_list (ParseData *data, PeekFunction peek, ParseValueFunction parse,
     ViviCodeValue ***list, guint separator)
 {
   GPtrArray *array;
   ViviCodeValue *value;
-  gboolean status;
 
   g_assert (data != NULL);
-  g_assert (function != NULL);
+  g_assert (peek != NULL);
+  g_assert (parse != NULL);
   g_assert (list != NULL);
 
-  *list = NULL;
-
-  status = function (data, &value);
-  if (status != TRUE)
-    return status;
-
   array = g_ptr_array_new ();
 
   do {
+    parse (data, &value);
     g_ptr_array_add (array, value);
+  } while ((separator == TOKEN_NONE || try_parse_token (data, separator)) &&
+      peek (data));
 
-    if (separator != TRUE && !check_token (data, separator))
-      break;
-
-    status = function (data, &value);
-    if (status == STATUS_FAIL)
-      return STATUS_FAIL;
-  } while (status == TRUE);
   g_ptr_array_add (array, NULL);
 
   *list = (ViviCodeValue **)g_ptr_array_free (array, FALSE);
-
-  return TRUE;
 }
 
 // public
@@ -2146,46 +2209,18 @@ vivi_parse_file (FILE *file, const char *input_name)
 {
   ParseData data;
   ViviCodeStatement *statement;
-  gboolean status;
 
   g_return_val_if_fail (file != NULL, NULL);
 
   data.scanner = vivi_parser_scanner_new (file);
-  data.unexpected_line_terminator = FALSE;
-  data.expected[0] = TOKEN_NONE;
-  data.expected[1] = TOKEN_NONE;
-  data.custom_error = NULL;
   data.levels = NULL;
   data.level = NULL;
+  data.error_count = 0;
 
-  status = parse_program (&data, &statement);
-  g_assert ((status == TRUE && VIVI_IS_CODE_STATEMENT (statement)) ||
-	(status != TRUE && statement == NULL));
-  g_assert (status >= 0);
-
-  if (status != TRUE) {
-    g_printerr ("%s:%i:%i: error: ", input_name,
-	vivi_parser_scanner_cur_line (data.scanner),
-	vivi_parser_scanner_cur_column (data.scanner));
-
-    if (data.custom_error != NULL) {
-      g_printerr ("%s\n", data.custom_error);
-      g_free (data.custom_error);
-    } else {
-      vivi_parser_scanner_get_next_token (data.scanner);
-
-      g_printerr ("Expected %s ", vivi_parser_token_name (data.expected[0]));
-      if (data.expected[1] != TOKEN_NONE)
-	g_printerr ("or %s ", vivi_parser_token_name (data.expected[1]));
-
-      if (data.unexpected_line_terminator) {
-	g_printerr ("before %s token\n",
-	    vivi_parser_token_name (TOKEN_LINE_TERMINATOR));
-      } else {
-	g_printerr ("before %s token\n",
-	    vivi_parser_token_name (data.scanner->token));
-      }
-    }
+  parse_program (&data, &statement);
+  if (data.error_count != 0) {
+    g_object_unref (statement);
+    statement = NULL;
   }
 
   g_object_unref (data.scanner);
commit d3161936eb3dd66558100cb73dcc870fc5b06108
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Wed Apr 9 11:25:45 2008 +0300

    Change vivi_compiler_scanner_lex.c to vivi_parser_scanner_lex.c in ignore list

diff --git a/vivified/code/.gitignore b/vivified/code/.gitignore
index 1cc3a3f..83ce7a9 100644
--- a/vivified/code/.gitignore
+++ b/vivified/code/.gitignore
@@ -11,7 +11,7 @@ Makefile.in
 *.lo
 *.loT
 
-vivi_compiler_scanner_lex.c
+vivi_parser_scanner_lex.c
 
 vivi-decompile
 vivi-compile
commit c9aeaef7f136e618bf2286375c9914e46b1b1f83
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Wed Apr 9 11:24:06 2008 +0300

    Start converting vivi_parser.c to better error handling
    
    It will just set an error state and continue parsing when errors occur

diff --git a/vivified/code/vivi_parser.c b/vivified/code/vivi_parser.c
index 2969593..16bde02 100644
--- a/vivified/code/vivi_parser.c
+++ b/vivified/code/vivi_parser.c
@@ -79,12 +79,6 @@ static const struct {
   { TOKEN_LAST, NULL }
 };
 
-typedef enum {
-  STATUS_CANCEL = -1,
-  STATUS_OK = 0,
-  STATUS_FAIL = 1
-} ParseStatus;
-
 typedef struct {
   GSList			*labels;
   GSList			*gotos;
@@ -92,37 +86,28 @@ typedef struct {
 
 typedef struct {
   ViviParserScanner *		scanner;
-  gboolean			unexpected_line_terminator;
-  guint				expected[2];
-  char *			custom_error;
+
+  guint				error_count;
+
+  char *			cancel_error;
 
   GSList *			levels; // ParseLevel, earlier levels
   ParseLevel *			level;  // current level
 } ParseData;
 
-#define FAIL_OR(x, y) (data->expected[0] = (x), data->expected[1] = (y), STATUS_FAIL)
-#define FAIL_LINE_TERMINATOR_OR(x, y) (data->unexpected_line_terminator = TRUE, FAIL_OR(x,y))
-#define FAIL_LINE_TERMINATOR(x) FAIL_LINE_TERMINATOR_OR(x,TOKEN_NONE)
-#define FAIL(x) FAIL_OR(x,TOKEN_NONE)
-#define FAIL_CHILD(x) STATUS_FAIL
-#define FAIL_CUSTOM(x) (data->custom_error = (x), STATUS_FAIL)
-#define CANCEL_OR(x, y) (data->expected[0] = (x), data->expected[1] = (y), STATUS_CANCEL)
-#define CANCEL(x) CANCEL_OR(x, TOKEN_NONE)
-#define CANCEL_CUSTOM(x) (data->custom_error = (x), STATUS_CANCEL)
-
-typedef ParseStatus (*ParseValueFunction) (ParseData *data, ViviCodeValue **value);
-typedef ParseStatus (*ParseValueStatementFunction) (ParseData *data, ViviCodeValue **value, ViviCodeStatement **statement);
-typedef ParseStatus (*ParseStatementFunction) (ParseData *data, ViviCodeStatement **statement);
-
-static ParseStatus
+typedef gboolean (*ParseValueFunction) (ParseData *data, ViviCodeValue **value);
+typedef gboolean (*ParseValueStatementFunction) (ParseData *data, ViviCodeValue **value, ViviCodeStatement **statement);
+typedef gboolean (*ParseStatementFunction) (ParseData *data, ViviCodeStatement **statement);
+
+static gboolean
 parse_statement_list (ParseData *data, ParseStatementFunction function, ViviCodeStatement **statement, guint separator);
 
-static ParseStatus
+static gboolean
 parse_value_statement_list (ParseData *data,
     ParseValueStatementFunction function, ViviCodeValue ***list,
     ViviCodeStatement **statement, guint separator);
 
-static ParseStatus
+static gboolean
 parse_value_list (ParseData *data, ParseValueFunction function,
     ViviCodeValue ***list, guint separator);
 
@@ -151,6 +136,65 @@ vivi_parser_token_name (guint token)
   }
 }
 
+static void
+vivi_parser_error (ParseData *data, const char *format, ...)
+{
+  va_list args;
+  char *message;
+
+  g_return_if_fail (data != NULL);
+  g_return_if_fail (format != NULL);
+
+  va_start (args, format);
+  message = g_strdup_vprintf (format, args);
+  va_end (args);
+
+  g_printerr (":error: %s\n", message);
+
+  g_free (message);
+
+  data->error_count++;
+}
+
+static void
+vivi_parser_cancel (ParseData *data, const char *format, ...)
+{
+  va_list args;
+  char *message;
+
+  g_return_if_fail (data != NULL);
+  g_return_if_fail (format != NULL);
+
+  va_start (args, format);
+  message = g_strdup_vprintf (format, args);
+  va_end (args);
+
+  if (data->cancel_error != NULL)
+    g_free (data->cancel_error);
+  data->cancel_error = message;
+}
+
+static char *
+vivi_parser_unexpected_token (ParseData *data, guint expected,
+    guint unexpected1, guint unexpected2)
+{
+  return g_strdup_printf ("Expected %s before %s or %s\n",
+      vivi_parser_token_name (expected), vivi_parser_token_name (unexpected1),
+      vivi_parser_token_name (unexpected2));
+}
+
+static void
+vivi_parser_fail_child (ParseData *data)
+{
+  if (data->cancel_error != NULL) {
+    vivi_parser_error (data, "%s", data->cancel_error);
+    g_free (data->cancel_error);
+    data->cancel_error = NULL;
+  } else {
+    g_assert (data->error_count > 0);
+  }
+}
+
 static gboolean
 check_line_terminator (ParseData *data)
 {
@@ -346,14 +390,13 @@ vivi_parser_find_label (ParseData *data, const char *name)
   return NULL;
 }
 
-static ParseStatus
-vivi_parser_end_level (ParseData *data, gboolean fail)
+static void
+vivi_parser_end_level (ParseData *data)
 {
   GSList *iter;
-  char *custom_error = NULL;
 
-  g_return_val_if_fail (data != NULL, STATUS_FAIL);
-  g_return_val_if_fail (data->level != NULL, STATUS_FAIL);
+  g_return_if_fail (data != NULL);
+  g_return_if_fail (data->level != NULL);
 
   for (iter = data->level->gotos; iter != NULL; iter = iter->next) {
     ViviCompilerGotoName *goto_;
@@ -366,11 +409,8 @@ vivi_parser_end_level (ParseData *data, gboolean fail)
     if (label != NULL) {
       vivi_compiler_goto_name_set_label (goto_, label);
     } else {
-      if (custom_error == NULL) {
-	custom_error =
-	  g_strdup_printf ("Label named '%s' doesn't exist in this block",
-	      vivi_compiler_goto_name_get_name (goto_));
-      }
+      vivi_parser_error (data, "Label named '%s' doesn't exist in this block",
+	  vivi_compiler_goto_name_get_name (goto_));
     }
 
     g_object_unref (goto_);
@@ -390,16 +430,6 @@ vivi_parser_end_level (ParseData *data, gboolean fail)
   } else {
     data->level = NULL;
   }
-
-  if (custom_error != NULL) {
-    if (fail) {
-      return FAIL_CUSTOM (custom_error);
-    } else {
-      return STATUS_FAIL;
-    }
-  } else {
-    return STATUS_OK;
-  }
 }
 
 static void
@@ -437,72 +467,80 @@ vivi_parser_add_label (ParseData *data, ViviCodeLabel *label)
 // values
 
 /* ActionScript specific */
-static ParseStatus
+static gboolean
 parse_undefined_literal (ParseData *data, ViviCodeValue **value)
 {
   *value = NULL;
 
-  if (!check_token (data, TOKEN_UNDEFINED))
-    return CANCEL (TOKEN_UNDEFINED);
+  if (!check_token (data, TOKEN_UNDEFINED)) {
+    vivi_parser_cancel_unexpected (data, TOKEN_UNDEFINED);
+    return FALSE;
+  }
 
   *value = vivi_code_constant_new_undefined ();
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_null_literal (ParseData *data, ViviCodeValue **value)
 {
   *value = NULL;
 
-  if (!check_token (data, TOKEN_NULL))
-    return CANCEL (TOKEN_NULL);
+  if (!check_token (data, TOKEN_NULL)) {
+    vivi_parser_cancel_unexpected (data, TOKEN_NULL);
+    return FALSE;
+  }
 
   *value = vivi_code_constant_new_null ();
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_boolean_literal (ParseData *data, ViviCodeValue **value)
 {
   *value = NULL;
 
-  if (!check_token (data, TOKEN_BOOLEAN))
-    return CANCEL (TOKEN_BOOLEAN);
+  if (!check_token (data, TOKEN_BOOLEAN)) {
+    vivi_parser_cancel_unexpected (data, TOKEN_BOOLEAN);
+    return FALSE;
+  }
 
   *value = vivi_code_constant_new_boolean (data->scanner->value.v_boolean);
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_numeric_literal (ParseData *data, ViviCodeValue **value)
 {
   *value = NULL;
 
-  if (!check_token (data, TOKEN_NUMBER))
-    return CANCEL (TOKEN_NUMBER);
+  if (!check_token (data, TOKEN_NUMBER)) {
+    vivi_parser_cancel_unexpected (data, TOKEN_NUMBER);
+    return FALSE;
+  }
 
   *value = vivi_code_constant_new_number (data->scanner->value.v_number);
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_string_literal (ParseData *data, ViviCodeValue **value)
 {
   *value = NULL;
 
-  if (!check_token (data, TOKEN_STRING))
-    return CANCEL (TOKEN_STRING);
+  if (!check_token (data, TOKEN_STRING)) {
+    vivi_parser_cancel_unexpected (data, TOKEN_STRING);
+    return FALSE;
+  }
 
   *value = vivi_code_constant_new_string (data->scanner->value.v_string);
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_literal (ParseData *data, ViviCodeValue **value)
 {
-  ParseStatus status;
-  int i;
-  ParseValueFunction functions[] = {
+  static const ParseValueFunction functions[] = {
     parse_undefined_literal,
     parse_null_literal,
     parse_boolean_literal,
@@ -510,71 +548,74 @@ parse_literal (ParseData *data, ViviCodeValue **value)
     parse_string_literal,
     NULL
   };
+  guint i;
 
   *value = NULL;
 
   for (i = 0; functions[i] != NULL; i++) {
-    status = functions[i] (data, value);
-    if (status != STATUS_CANCEL)
-      return status;
+    if (functions[i] (data, value))
+      return TRUE;
   }
 
-  return CANCEL (ERROR_TOKEN_LITERAL);
+  vivi_parser_cancel_unexpected (data, ERROR_TOKEN_LITERAL);
+  return FALSE;
 }
 
-static ParseStatus
+static gboolean
 parse_identifier (ParseData *data, ViviCodeValue **value)
 {
   *value = NULL;
 
-  if (!check_token (data, TOKEN_IDENTIFIER))
-    return CANCEL (TOKEN_IDENTIFIER);
+  if (!check_token (data, TOKEN_IDENTIFIER)) {
+    vivi_parser_cancel_unexpected (data, TOKEN_IDENTIFIER);
+    return FALSE;
+  }
 
   *value = vivi_code_get_new_name (data->scanner->value.v_identifier);
 
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_property_name (ParseData *data, ViviCodeValue **value)
 {
-  ParseStatus status;
-  int i;
-  ParseValueFunction functions[] = {
+  static const ParseValueFunction functions[] = {
     parse_identifier,
     parse_string_literal,
     parse_numeric_literal,
     NULL
   };
+  guint i;
 
   *value = NULL;
 
   for (i = 0; functions[i] != NULL; i++) {
-    status = functions[i] (data, value);
-    if (status != STATUS_CANCEL)
-      return status;
+    if (functions[i] (data, value))
+      return TRUE;
   }
 
-  return CANCEL (ERROR_TOKEN_PROPERTY_NAME);
+  vivi_parser_cancel_unexpected (data, ERROR_TOKEN_PROPERTY_NAME);
+  return FALSE;
 }
 
-static ParseStatus
+static gboolean
 parse_assignment_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement);
 
-static ParseStatus
+static gboolean
 parse_array_literal (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
   ViviCodeValue *member;
   ViviCodeStatement *statement_new;
-  ParseStatus status;
 
   *value = NULL;
   *statement = NULL;
 
-  if (!check_token (data, TOKEN_BRACKET_LEFT))
-    return CANCEL (TOKEN_BRACKET_LEFT);
+  if (!check_token (data, TOKEN_BRACKET_LEFT)) {
+    vivi_parser_cancel_unexpected (data, TOKEN_BRACKET_LEFT);
+    return FALSE;
+  }
 
   *value = vivi_code_init_array_new ();
 
@@ -586,16 +627,7 @@ parse_array_literal (ParseData *data, ViviCodeValue **value,
     } else if (check_token (data, TOKEN_COMMA)) {
       vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
 	 vivi_code_constant_new_undefined ());
-    } else {
-      status = parse_assignment_expression (data, &member, &statement_new);
-      if (status != STATUS_OK) {
-	if (*statement != NULL) {
-	  g_object_unref (*statement);
-	  *statement = NULL;
-	}
-	return FAIL_CHILD (status);
-      }
-
+    } else if (parse_assignment_expression (data, &member, &statement_new)) {
       *statement = vivi_parser_join_statements (*statement, statement_new);
 
       vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
@@ -604,27 +636,34 @@ parse_array_literal (ParseData *data, ViviCodeValue **value,
 
       if (!check_token (data, TOKEN_COMMA)) {
 	if (!check_token (data, TOKEN_BRACKET_RIGHT)) {
-	  return FAIL_OR (TOKEN_BRACKET_RIGHT, TOKEN_COMMA);
+	  vivi_parser_error_unexpected (data, TOKEN_BRACKET_RIGHT,
+	      TOKEN_COMMA);
 	}
 	break;
       }
+    } else {
+      vivi_parser_error_unexpected (data, TOKEN_BRACKET_RIGHT, TOKEN_COMMA,
+	  ERROR_TOKEN_ASSIGNMENT_EXPRESSION);
+      break;
     }
   }
 
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_object_literal (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
-  ParseStatus status;
+  gboolean status;
 
   *value = NULL;
   *statement = NULL;
 
-  if (!check_token (data, TOKEN_BRACE_LEFT))
-    return CANCEL (TOKEN_BRACE_LEFT);
+  if (!check_token (data, TOKEN_BRACE_LEFT)) {
+    vivi_parser_cancel_unexpected (data, TOKEN_BRACE_LEFT);
+    return FALSE;
+  }
 
   *value = vivi_code_init_object_new ();
 
@@ -633,38 +672,14 @@ parse_object_literal (ParseData *data, ViviCodeValue **value,
       ViviCodeValue *property, *initializer;
       ViviCodeStatement *statement_new;
 
-      status = parse_property_name (data, &property);
-      if (status != STATUS_OK) {
-	g_object_unref (*value);
-	*value = NULL;
-	if (*statement != NULL) {
-	  g_object_unref (*statement);
-	  *statement = NULL;
-	}
-	return FAIL_CHILD (status);
-      }
+      if (!parse_property_name (data, &property))
+	vivi_parser_error_child_value (data, &property);
 
-      if (!check_token (data, TOKEN_COLON)) {
-	g_object_unref (*value);
-	*value = NULL;
-	if (*statement != NULL) {
-	  g_object_unref (*statement);
-	  *statement = NULL;
-	}
-	return FAIL (TOKEN_COLON);
-      }
+      if (!check_token (data, TOKEN_COLON))
+	vivi_parser_error_unexpected (data, TOKEN_COLON);
 
-      status = parse_assignment_expression (data, &initializer,
-	  &statement_new);
-      if (status != STATUS_OK) {
-	g_object_unref (*value);
-	*value = NULL;
-	if (*statement != NULL) {
-	  g_object_unref (*statement);
-	  *statement = NULL;
-	}
-	return FAIL_CHILD (status);
-      }
+      if (!parse_assignment_expression (data, &initializer, &statement_new))
+	vivi_parser_error_child_value (data, &initializer);
 
       *statement = vivi_parser_join_statements (*statement, statement_new);
 
@@ -673,40 +688,31 @@ parse_object_literal (ParseData *data, ViviCodeValue **value,
     } while (check_token (data, TOKEN_COMMA));
   }
 
-  if (!check_token (data, TOKEN_BRACE_RIGHT)) {
-    g_object_unref (*value);
-    *value = NULL;
-    if (*statement != NULL) {
-      g_object_unref (*statement);
-      *statement = NULL;
-    }
-    return FAIL (TOKEN_BRACE_RIGHT);
-  }
+  if (!check_token (data, TOKEN_BRACE_RIGHT))
+    vivi_parser_error_unexpected (data, TOKEN_BRACE_RIGHT);
 
-  return STATUS_OK;
+  return TRUE;
 }
 
 // misc
 
-static ParseStatus
+static gboolean
 parse_variable_declaration (ParseData *data, ViviCodeStatement **statement)
 {
-  ParseStatus status;
+  gboolean status;
   ViviCodeValue *identifier, *value;
   ViviCodeStatement *assignment, *statement_right;
 
   *statement = NULL;
 
-  status = parse_identifier (data, &identifier);
-  if (status != STATUS_OK)
-    return status;
+  if (!parse_identifier (data, &identifier)) {
+    vivi_parser_cancel_unexpected (data, ERROR_TOKEN_IDENTIFIER);
+    return FALSE;
+  }
 
   if (check_token (data, TOKEN_ASSIGN)) {
-    status = parse_assignment_expression (data, &value, &statement_right);
-    if (status != STATUS_OK) {
-      g_object_unref (identifier);
-      return FAIL_CHILD (status);
-    }
+    if (!parse_assignment_expression (data, &value, &statement_right))
+      vivi_parser_error_child_value (data, value);
   } else {
     value = vivi_code_constant_new_undefined ();
     statement_right = NULL;
@@ -717,74 +723,60 @@ parse_variable_declaration (ParseData *data, ViviCodeStatement **statement)
 
   *statement = vivi_parser_join_statements (statement_right, assignment);
 
-  return STATUS_OK;
+  return TRUE;
 }
 
 // expression
 
-static ParseStatus
+static gboolean
 parse_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement);
 
-static ParseStatus
+static gboolean
 parse_primary_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
-  ParseStatus status;
-  int i;
-  ParseValueFunction functions[] = {
-    parse_identifier,
-    parse_literal,
-    NULL
-  };
-
   *value = NULL;
   *statement = NULL;
 
   if (check_token (data, TOKEN_THIS)) {
     *value = vivi_code_get_new_name ("this");
-    return STATUS_OK;
+    return TRUE;
   }
 
   if (check_token (data, TOKEN_PARENTHESIS_LEFT)) {
-    status = parse_expression (data, value, statement);
-    if (status != STATUS_OK)
-      return FAIL_CHILD (status);
-    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
-      g_object_unref (*value);
-      *value = NULL;
-      return FAIL (TOKEN_PARENTHESIS_RIGHT);
-    }
-    return STATUS_OK;
+    if (!parse_expression (data, value, statement))
+      vivi_parser_error_child_value (data, value);
+    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
+      vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
+    return TRUE;
   }
 
+  if (parse_object_literal (data, value, statement))
+    return TRUE;
 
-  status = parse_object_literal (data, value, statement);
-  if (status != STATUS_CANCEL)
-    return status;
+  if (parse_array_literal (data, value, statement))
+    return TRUE;
 
-  status = parse_array_literal (data, value, statement);
-  if (status != STATUS_CANCEL)
-    return status;
+  if (parse_identifier (data, value))
+    return TRUE;
 
-  for (i = 0; functions[i] != NULL; i++) {
-    status = functions[i] (data, value);
-    if (status != STATUS_CANCEL)
-      return status;
-  }
+  if (parse_literal (data, value))
+    return TRUE;
 
-  return CANCEL (ERROR_TOKEN_PRIMARY_EXPRESSION);
+  vivi_parser_cancel_unexpected (ERROR_TOKEN_PRIMARY_EXPRESSION);
+  return FALSE;
 }
 
-static ParseStatus
+static gboolean
 parse_function_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement);
 
-static ParseStatus
+static gboolean
 parse_member_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
-  ParseStatus status;
+  gboolean status;
   ViviCodeValue *member;
   ViviCodeStatement *statement_member;
 
@@ -793,70 +785,53 @@ parse_member_expression (ParseData *data, ViviCodeValue **value,
 
   // TODO: new MemberExpression Arguments
 
-  status = parse_primary_expression (data, value, statement);
-  if (status == STATUS_CANCEL)
-    status = parse_function_expression (data, value, statement);
-
-  if (status != STATUS_OK)
-    return status;
+  if (!parse_primary_expression (data, value, statement)) {
+    if (!parse_function_expression (data, value, statement)) {
+      vivi_parser_cancel_unexpected (data, ERROR_PRIMARY_EXPRESSION,
+	  ERROR_FUNCTION_EXPRESSION);
+      return FALSE;
+    }
+  }
 
-  do {
+   while (TRUE) {
     ViviCodeValue *tmp;
 
     if (check_token (data, TOKEN_BRACKET_LEFT)) {
-      status = parse_expression (data, &member, &statement_member);
-      if (status != STATUS_OK) {
-	g_object_unref (*value);
-	*value = NULL;
-	if (*statement != NULL) {
-	  g_object_unref (*statement);
-	  *statement = NULL;
-	}
-	return FAIL_CHILD (status);
-      }
+      if (!parse_expression (data, &member, &statement_member))
+	vivi_parser_error_child_value (data, &member);
 
-      *statement =
-	vivi_parser_join_statements (*statement, statement_member);
-
-      if (!check_token (data, TOKEN_BRACKET_RIGHT)) {
-	g_object_unref (*value);
-	*value = NULL;
-	if (*statement != NULL) {
-	  g_object_unref (*statement);
-	  *statement = NULL;
-	}
-	return FAIL (TOKEN_BRACKET_RIGHT);
-      }
+      *statement = vivi_parser_join_statements (*statement, statement_member);
+
+      if (!check_token (data, TOKEN_BRACKET_RIGHT))
+	vivi_parser_error_unexpected (data, TOKEN_BRACKET_RIGHT);
     } else if (check_token (data, TOKEN_DOT)) {
-      status = parse_identifier (data, &member);
-      if (status != STATUS_OK)
-	return FAIL_CHILD (status);
+      if (!parse_identifier (data, &member))
+	vivi_parser_error_child_value (data, &member);
     } else {
-      return STATUS_OK;
+      return TRUE;
     }
 
     tmp = *value;
     *value = vivi_parser_get_new (tmp, member);
     g_object_unref (tmp);
     g_object_unref (member);
-  } while (TRUE);
+  }
 
   g_assert_not_reached ();
 }
 
-static ParseStatus
+static gboolean
 parse_new_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
-  ParseStatus status;
+  gboolean status;
 
   *value = NULL;
   *statement = NULL;
 
   if (check_token (data, TOKEN_NEW)) {
-    status = parse_new_expression (data, value, statement);
-    if (status != STATUS_OK)
-      return FAIL_CHILD (status);
+    if (!parse_new_expression (data, value, statement))
+      vivi_parser_error_child_value (data, value);
     if (!VIVI_IS_CODE_FUNCTION_CALL (*value)) {
       ViviCodeValue *tmp = VIVI_CODE_VALUE (*value);
       *value = vivi_parser_function_call_new (tmp);
@@ -864,29 +839,27 @@ parse_new_expression (ParseData *data, ViviCodeValue **value,
     }
     vivi_code_function_call_set_construct (VIVI_CODE_FUNCTION_CALL (*value),
 	TRUE);
-    return STATUS_OK;
+    return TRUE;
   } else {
     return parse_member_expression (data, value, statement);
   }
 }
 
-static ParseStatus
+static gboolean
 parse_left_hand_side_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
-  ParseStatus status;
-  int i;
   ViviCodeValue *name;
   ViviCodeValue **arguments;
   ViviCodeStatement *argument_statement;
+  guint i;
 
   *value = NULL;
   *statement = NULL;
 
   if (check_token (data, TOKEN_NEW)) {
-    status = parse_new_expression (data, value, statement);
-    if (status != STATUS_OK)
-      return FAIL_CHILD (status);
+    if (!parse_new_expression (data, value, statement))
+      vivi_parser_error_child_value (data, value);
     if (!VIVI_IS_CODE_FUNCTION_CALL (*value)) {
       ViviCodeValue *tmp = VIVI_CODE_VALUE (*value);
       *value = vivi_parser_function_call_new (tmp);
@@ -894,12 +867,13 @@ parse_left_hand_side_expression (ParseData *data, ViviCodeValue **value,
     }
     vivi_code_function_call_set_construct (VIVI_CODE_FUNCTION_CALL (*value),
 	TRUE);
-    return STATUS_OK;
+    return TRUE;
   }
 
-  status = parse_member_expression (data, value, statement);
-  if (status != STATUS_OK)
-    return status;
+  if (!parse_member_expression (data, value, statement)) {
+    vivi_parser_cancel_unexpected (data, ERROR_TOKEN_MEMBER_EXPRESSION);
+    return FALSE;
+  }
 
   while (TRUE) {
     // TODO: member expressions?
@@ -907,30 +881,17 @@ parse_left_hand_side_expression (ParseData *data, ViviCodeValue **value,
       break;
 
     if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
-      status = parse_value_statement_list (data, parse_assignment_expression,
-	  &arguments, &argument_statement, TOKEN_COMMA);
-      if (status != STATUS_OK) {
-	g_object_unref (*value);
-	*value = NULL;
-	if (*statement != NULL) {
-	  g_object_unref (*statement);
-	  *statement = NULL;
-	}
-	return FAIL_CHILD (status);
+      if (!parse_value_statement_list (data, parse_assignment_expression,
+	    &arguments, &argument_statement, TOKEN_COMMA)) {
+	// TODO
+	arguments = NULL;
       }
 
       *statement =
 	vivi_parser_join_statements (*statement, argument_statement);
 
-      if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
-	g_object_unref (*value);
-	*value = NULL;
-	if (*statement != NULL) {
-	  g_object_unref (*statement);
-	  *statement = NULL;
-	}
-	return FAIL (TOKEN_PARENTHESIS_RIGHT);
-      }
+      if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
+	vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
     } else {
       arguments = NULL;
     }
@@ -948,43 +909,39 @@ parse_left_hand_side_expression (ParseData *data, ViviCodeValue **value,
     }
   }
 
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_postfix_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
-  ParseStatus status;
   ViviCodeValue *operation, *one, *temporary;
   const char *operator;
 
   *value = NULL;
   *statement = NULL;
 
-  status = parse_left_hand_side_expression (data, value, statement);
-  if (status != STATUS_OK)
-    return status;
+  if (!parse_left_hand_side_expression (data, value, statement)) {
+    vivi_parser_cancel_unexpected (data, ERROR_TOKEN_POSTFIX_EXPRESSION);
+    return FALSE;
+  }
 
   if (check_line_terminator (data))
-    return status;
+    return TRUE;
 
   if (check_token (data, TOKEN_INCREASE)) {
     operator = "+";
   } else if (check_token (data, TOKEN_DESCREASE)) {
     operator = "-";
   } else {
-    return STATUS_OK;
+    return TRUE;
   }
 
+  // FIXME: Correct?
   if (!vivi_parser_value_is_left_hand_side (*value)) {
-    g_object_unref (*value);
-    *value = NULL;
-    if (*statement != NULL) {
-      g_object_unref (*statement);
-      *statement = NULL;
-    }
-    return CANCEL_CUSTOM (g_strdup ("INCREASE/DECREASE not allowed here"));
+    vivi_parser_error (
+	"Invalid left-hand side expression for INCREASE/DECREASE");
   }
 
   one = vivi_code_constant_new_number (1);
@@ -1001,14 +958,14 @@ parse_postfix_expression (ParseData *data, ViviCodeValue **value,
   g_object_unref (*value);
   *value = temporary;
 
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_unary_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
-  ParseStatus status;
+  gboolean status;
   ViviCodeValue *tmp, *one;
   const char *operator;
 
@@ -1028,12 +985,15 @@ parse_unary_expression (ParseData *data, ViviCodeValue **value,
       if (!operator) operator = "-";
 
       vivi_parser_scanner_get_next_token (data->scanner);
-      status = parse_unary_expression (data, value, statement);
-      if (status != STATUS_OK)
-	return FAIL_CHILD (status);
 
-      if (!vivi_parser_value_is_left_hand_side (*value))
-	return CANCEL_CUSTOM (g_strdup ("INCREASE/DECREASE not allowed here"));
+      if (!parse_unary_expression (data, value, statement))
+	vivi_parser_error_child_value (data, value);
+
+      // FIXME: Correct?
+      if (!vivi_parser_value_is_left_hand_side (*value)) {
+	vivi_parser_error (
+	    "Invalid left-hand side expression for INCREASE/DECREASE");
+      }
 
       one = vivi_code_constant_new_number (1);
       tmp = vivi_code_binary_new_name (*value, one, operator);
@@ -1043,19 +1003,21 @@ parse_unary_expression (ParseData *data, ViviCodeValue **value,
 	  vivi_parser_assignment_new (*value, tmp));
       g_object_unref (tmp);
 
-      return STATUS_OK;
+      return TRUE;
     /*case TOKEN_PLUS:
     case TOKEN_MINUS:
     case TOKEN_BITWISE_NOT:*/
     case TOKEN_LOGICAL_NOT:
       vivi_parser_scanner_get_next_token (data->scanner);
-      status = parse_unary_expression (data, value, statement);
-      if (status != STATUS_OK)
-	return FAIL_CHILD (status);
+
+      if (!parse_unary_expression (data, value, statement))
+	vivi_parser_error_child_value (data, value);
+
       tmp = VIVI_CODE_VALUE (*value);
       *value = vivi_code_unary_new (tmp, '!');
       g_object_unref (tmp);
-      return STATUS_OK;
+
+      return TRUE;
     default:
       return parse_postfix_expression (data, value, statement);
   }
@@ -1067,31 +1029,27 @@ typedef enum {
   PASS_LOGICAL_AND
 } ParseOperatorPass;
 
-static ParseStatus
+static gboolean
 parse_operator_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement, const ViviParserScannerToken *tokens,
     ParseOperatorPass pass, ParseValueStatementFunction next_parse_function)
 {
-  ParseStatus status;
-  int i;
   ViviCodeValue *left, *right;
   ViviCodeStatement *statement_right;
+  guint i;
 
   *value = NULL;
   *statement = NULL;
 
-  status = next_parse_function (data, value, statement);
-  if (status != STATUS_OK)
-    return status;
+  if (!next_parse_function (data, value, statement)) {
+    // FIXME: token?
+    return FALSE;
+  }
 
-  for (i = 0; tokens[i] != STATUS_OK; i++) {
+  for (i = 0; tokens[i] != TRUE; i++) {
     while (check_token (data, tokens[i])) {
-      status = next_parse_function (data, &right, &statement_right);
-      if (status != STATUS_OK) {
-	g_object_unref (*value);
-	*value = NULL;
-	return FAIL_CHILD (status);
-      }
+      if (!next_parse_function (data, &right, &statement_right))
+	vivi_parser_error_child_value (data, &right);
 
       if (statement_right != NULL) {
 	ViviCodeStatement *tmp;
@@ -1116,8 +1074,7 @@ parse_operator_expression (ParseData *data, ViviCodeValue **value,
 	    g_assert_not_reached ();
 	}
 
-	*statement =
-	  vivi_parser_join_statements (*statement, statement_right);
+	*statement = vivi_parser_join_statements (*statement, statement_right);
       }
 
       left = VIVI_CODE_VALUE (*value);
@@ -1128,10 +1085,10 @@ parse_operator_expression (ParseData *data, ViviCodeValue **value,
     };
   }
 
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_multiplicative_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
@@ -1142,7 +1099,7 @@ parse_multiplicative_expression (ParseData *data, ViviCodeValue **value,
       PASS_ALWAYS, parse_unary_expression);
 }
 
-static ParseStatus
+static gboolean
 parse_additive_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
@@ -1153,7 +1110,7 @@ parse_additive_expression (ParseData *data, ViviCodeValue **value,
       PASS_ALWAYS, parse_multiplicative_expression);
 }
 
-static ParseStatus
+static gboolean
 parse_shift_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
@@ -1164,7 +1121,7 @@ parse_shift_expression (ParseData *data, ViviCodeValue **value,
       PASS_ALWAYS, parse_additive_expression);
 }
 
-static ParseStatus
+static gboolean
 parse_relational_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
@@ -1176,7 +1133,7 @@ parse_relational_expression (ParseData *data, ViviCodeValue **value,
       PASS_ALWAYS, parse_shift_expression);
 }
 
-static ParseStatus
+static gboolean
 parse_equality_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
@@ -1188,7 +1145,7 @@ parse_equality_expression (ParseData *data, ViviCodeValue **value,
       PASS_ALWAYS, parse_relational_expression);
 }
 
-static ParseStatus
+static gboolean
 parse_bitwise_and_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
@@ -1199,7 +1156,7 @@ parse_bitwise_and_expression (ParseData *data, ViviCodeValue **value,
       PASS_ALWAYS, parse_equality_expression);
 }
 
-static ParseStatus
+static gboolean
 parse_bitwise_xor_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
@@ -1210,7 +1167,7 @@ parse_bitwise_xor_expression (ParseData *data, ViviCodeValue **value,
       PASS_ALWAYS, parse_bitwise_and_expression);
 }
 
-static ParseStatus
+static gboolean
 parse_bitwise_or_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
@@ -1221,7 +1178,7 @@ parse_bitwise_or_expression (ParseData *data, ViviCodeValue **value,
       PASS_ALWAYS, parse_bitwise_xor_expression);
 }
 
-static ParseStatus
+static gboolean
 parse_logical_and_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
@@ -1232,7 +1189,7 @@ parse_logical_and_expression (ParseData *data, ViviCodeValue **value,
       PASS_LOGICAL_AND, parse_bitwise_or_expression);
 }
 
-static ParseStatus
+static gboolean
 parse_logical_or_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
@@ -1243,28 +1200,26 @@ parse_logical_or_expression (ParseData *data, ViviCodeValue **value,
       PASS_LOGICAL_OR, parse_logical_and_expression);
 }
 
-static ParseStatus
+static gboolean
 parse_conditional_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
-  ParseStatus status;
   //ViviCodeStatement *if_statement, *else_statement;
 
   *value = NULL;
 
-  status = parse_logical_or_expression (data, value, statement);
-  if (status != STATUS_OK)
-    return status;
+  if (!parse_logical_or_expression (data, value, statement))
+    return FALSE;
 
 #if 0
   if (!check_token (data, TOKEN_QUESTION_MARK)) {
     *statement = vivi_code_value_statement_new (VIVI_CODE_VALUE (value));
     g_object_unref (value);
-    return STATUS_OK;
+    return TRUE;
   }
 
   status = parse_assignment_expression (data, &if_statement);
-  if (status != STATUS_OK) {
+  if (status != TRUE) {
     g_object_unref (value);
     return FAIL_CHILD (status);
   }
@@ -1276,7 +1231,7 @@ parse_conditional_expression (ParseData *data, ViviCodeValue **value,
   }
 
   status = parse_assignment_expression (data, &else_statement);
-  if (status != STATUS_OK) {
+  if (status != TRUE) {
     g_object_unref (value);
     g_object_unref (if_statement);
     return FAIL_CHILD (status);
@@ -1291,14 +1246,13 @@ parse_conditional_expression (ParseData *data, ViviCodeValue **value,
   g_object_unref (else_statement);
 #endif
 
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_assignment_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
-  ParseStatus status;
   ViviCodeValue *right;
   ViviCodeStatement *assignment, *statement_right;
   const char *operator;
@@ -1306,17 +1260,18 @@ parse_assignment_expression (ParseData *data, ViviCodeValue **value,
   *value = NULL;
   *statement = NULL;
 
-  status = parse_conditional_expression (data, value, statement);
-  if (status != STATUS_OK)
-    return status;
+  if (!parse_conditional_expression (data, value, statement)) {
+    vivi_parser_cancel_unexpected (data, ERROR_TOKEN_CONDITIONAL_EXPRESSION);
+    return FALSE;
+  }
 
   if (!vivi_parser_value_is_left_hand_side (*value))
-    return STATUS_OK;
+    return TRUE;
 
   operator = NULL;
 
   vivi_parser_scanner_peek_next_token (data->scanner);
-  switch ((int)data->scanner->next_token) {
+  switch ((guint)data->scanner->next_token) {
     case TOKEN_ASSIGN_MULTIPLY:
       if (operator == NULL) operator = "*";
     case TOKEN_ASSIGN_DIVIDE:
@@ -1341,13 +1296,9 @@ parse_assignment_expression (ParseData *data, ViviCodeValue **value,
       if (operator == NULL) operator = "^";
     case TOKEN_ASSIGN:
       vivi_parser_scanner_get_next_token (data->scanner);
-      status = parse_assignment_expression (data, &right,
-	  &statement_right);
-      if (status != STATUS_OK) {
-	g_object_unref (*value);
-	*value = NULL;
-	return FAIL_CHILD (status);
-      }
+
+      if (parse_assignment_expression (data, &right, &statement_right))
+	vivi_parser_error_child_value (data, &right);
 
       if (operator != NULL) {
 	assignment = vivi_parser_assignment_new (*value,
@@ -1360,27 +1311,26 @@ parse_assignment_expression (ParseData *data, ViviCodeValue **value,
       *statement = vivi_parser_join_statements (*statement,
 	  vivi_parser_join_statements (statement_right, assignment));
 
-      break;
+      return TRUE;
     default:
-      return STATUS_OK;
+      return TRUE;
   }
 
-
-  return STATUS_OK;
+  g_assert_not_reached ();
 }
 
-static ParseStatus
+static gboolean
 parse_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
   ViviCodeStatement *statement_one;
-  ParseStatus status;
 
   *statement = NULL;
 
-  status = parse_assignment_expression (data, value, &statement_one);
-  if (status != STATUS_OK)
-    return status;
+  if (parse_assignment_expression (data, value, &statement_one)) {
+    vivi_parser_cancel_unexpected (data, ERROR_TOKEN_ASSIGNMENT_EXPRESSION);
+    return FALSE;
+  }
 
   while (TRUE) {
     *statement = vivi_parser_join_statements (*statement, statement_one);
@@ -1390,80 +1340,70 @@ parse_expression (ParseData *data, ViviCodeValue **value,
 
     g_object_unref (*value);
 
-    status = parse_assignment_expression (data, value, &statement_one);
-    if (status != STATUS_OK) {
-      g_object_unref (*value);
-      *value = NULL;
-      g_object_unref (*statement);
-      *statement = NULL;
-      return FAIL_CHILD (status);
-    }
+    if (!parse_assignment_expression (data, value, &statement_one))
+	vivi_parser_error_child_value (data, value);
   }
 
-  return STATUS_OK;
+  return TRUE;
 }
 
 // statement
 
-static ParseStatus
+static gboolean
 parse_statement (ParseData *data, ViviCodeStatement **statement);
 
-static ParseStatus
+static gboolean
 parse_trace_statement (ParseData *data, ViviCodeStatement **statement)
 {
   ViviCodeValue *value;
   ViviCodeStatement *expression_statement;
-  ParseStatus status;
 
   *statement = NULL;
 
-  if (!check_token (data, TOKEN_TRACE))
-    return CANCEL (TOKEN_TRACE);
+  if (!check_token (data, TOKEN_TRACE)) {
+    vivi_parser_cancel_unexpected (data, TOKEN_TRACE);
+    return FALSE;
+  }
 
   if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
-    return FAIL (TOKEN_PARENTHESIS_LEFT);
+    vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
 
-  status = parse_expression (data, &value, &expression_statement);
-  if (status != STATUS_OK)
-    return FAIL_CHILD (status);
+  if (parse_expression (data, &value, &expression_statement))
+    vivi_parser_error_child_value (data, &value);
 
-  if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
-    g_object_unref (value);
-    if (expression_statement != NULL)
-      g_object_unref (expression_statement);
-    return FAIL (TOKEN_PARENTHESIS_RIGHT);
-  }
+  if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
+    vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
 
-  if (!check_automatic_semicolon (data)) {
-    g_object_unref (value);
-    if (expression_statement != NULL)
-      g_object_unref (expression_statement);
-    return FAIL (TOKEN_SEMICOLON);
-  }
+  if (!check_automatic_semicolon (data))
+    vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
 
   *statement = vivi_code_trace_new (value);
   g_object_unref (value);
 
-  *statement =
-    vivi_parser_join_statements (expression_statement, *statement);
+  *statement = vivi_parser_join_statements (expression_statement, *statement);
 
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_continue_or_break_statement (ParseData *data,
     ViviCodeStatement **statement, ViviParserScannerToken token)
 {
   *statement = NULL;
 
-  if (!check_token (data, token))
-    return CANCEL (token);
+  if (!check_token (data, token)) {
+    vivi_parser_cancel_unexpected (data, token);
+    return FALSE;
+  }
 
   if (!check_restricted_semicolon (data)) {
-    ParseStatus status;
+    gboolean status;
     ViviCodeValue *identifier;
 
-    status = parse_identifier (data, &identifier);
+    if (!parse_identifier (data, &identifier))
+      vivi_parser_error_child_value (data, &identifier);
+
+    // FIXME
     *statement = vivi_compiler_goto_name_new (
 	vivi_code_constant_get_variable_name (
 	  VIVI_CODE_CONSTANT (VIVI_CODE_GET (identifier)->name)));
@@ -1471,84 +1411,80 @@ parse_continue_or_break_statement (ParseData *data,
 
     vivi_parser_add_goto (data, VIVI_COMPILER_GOTO_NAME (*statement));
 
-    if (!check_automatic_semicolon (data)) {
-      g_object_unref (*statement);
-      *statement = NULL;
-      return FAIL (TOKEN_SEMICOLON);
-    }
+    if (!check_automatic_semicolon (data))
+      vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
   } else {
     *statement = vivi_code_break_new ();
   }
 
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_continue_statement (ParseData *data, ViviCodeStatement **statement)
 {
   return parse_continue_or_break_statement (data, statement, TOKEN_CONTINUE);
 }
 
-static ParseStatus
+static gboolean
 parse_break_statement (ParseData *data, ViviCodeStatement **statement)
 {
   return parse_continue_or_break_statement (data, statement, TOKEN_BREAK);
 }
 
-static ParseStatus
+static gboolean
 parse_throw_statement (ParseData *data, ViviCodeStatement **statement)
 {
-  ParseStatus status;
+  gboolean status;
   ViviCodeValue *value;
   ViviCodeStatement *expression_statement;
 
   *statement = NULL;
 
-  if (!check_token (data, TOKEN_THROW))
-    return CANCEL (TOKEN_THROW);
+  if (!check_token (data, TOKEN_THROW)) {
+    vivi_parser_cancel_unexpected (data, TOKEN_THROW);
+    return FALSE;
+  }
 
   if (check_line_terminator (data))
-    return FAIL_LINE_TERMINATOR (ERROR_TOKEN_EXPRESSION);
+    vivi_parser_error_unexpected_line_terminator (data,
+	ERROR_TOKEN_EXPRESSION);
 
-  status = parse_expression (data, &value, &expression_statement);
-  if (status != STATUS_OK)
-    return FAIL_CHILD (status);
+  if (parse_expression (data, &value, &expression_statement))
+    vivi_parser_error_child_value (data, &value);
 
   *statement = vivi_code_throw_new (value);
   g_object_unref (value);
 
-  *statement =
-    vivi_parser_join_statements (expression_statement, *statement);
+  *statement = vivi_parser_join_statements (expression_statement, *statement);
 
-  if (!check_automatic_semicolon (data)) {
-    g_object_unref (*statement);
-    *statement = NULL;
-    return FAIL (TOKEN_SEMICOLON);
-  }
+  if (!check_automatic_semicolon (data))
+    vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
 
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_return_statement (ParseData *data, ViviCodeStatement **statement)
 {
   *statement = NULL;
 
-  if (!check_token (data, TOKEN_RETURN))
-    return CANCEL (TOKEN_RETURN);
+  if (!check_token (data, TOKEN_RETURN)) {
+    vivi_parser_cancel_unexpected (data, TOKEN_RETURN);
+    return FALSE;
+  }
 
   *statement = vivi_code_return_new ();
 
   if (!check_restricted_semicolon (data)) {
-    ParseStatus status;
+    gboolean status;
     ViviCodeValue *value;
     ViviCodeStatement *expression_statement;
 
-    status = parse_expression (data, &value, &expression_statement);
-    if (status != STATUS_OK) {
-      g_object_unref (*statement);
-      *statement = NULL;
-      return FAIL_CHILD (status);
+    if (!parse_expression (data, &value, &expression_statement)) {
+      vivi_parser_error_unexpected (data, TOKEN_SEMICOLON,
+	  ERROR_TOKEN_EXPRESSION);
+      return TRUE;
     }
 
     vivi_code_return_set_value (VIVI_CODE_RETURN (*statement), value);
@@ -1557,20 +1493,16 @@ parse_return_statement (ParseData *data, ViviCodeStatement **statement)
     *statement =
       vivi_parser_join_statements (expression_statement, *statement);
 
-    if (!check_automatic_semicolon (data)) {
-      g_object_unref (*statement);
-      *statement = NULL;
-      return FAIL (TOKEN_SEMICOLON);
-    }
+    if (!check_automatic_semicolon (data))
+      vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
   }
 
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
 {
-  ParseStatus status;
   ViviCodeValue *condition;
   ViviCodeStatement *pre_statement, *condition_statement, *loop_statement;
 
@@ -1580,78 +1512,50 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
   condition_statement = NULL;
 
   if (check_token (data, TOKEN_DO)) {
-    status = parse_statement (data, &loop_statement);
-    if (status != STATUS_OK)
-      return FAIL_CHILD (status);
+    if (!parse_statement (data, &loop_statement))
+      vivi_parser_error_child_statement (data, &loop_statement);
 
-    if (!check_token (data, TOKEN_WHILE)) {
-      g_object_unref (loop_statement);
-      return FAIL (TOKEN_WHILE);
-    }
+    if (!check_token (data, TOKEN_WHILE))
+      vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
 
-    if (!check_token (data, TOKEN_PARENTHESIS_LEFT)) {
-      g_object_unref (loop_statement);
-      return FAIL (TOKEN_PARENTHESIS_LEFT);
-    }
+    if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
+      vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
 
-    status = parse_expression (data, &condition, &condition_statement);
-    if (status != STATUS_OK) {
-      g_object_unref (loop_statement);
-      return FAIL_CHILD (status);
-    }
+    if (parse_expression (data, &condition, &condition_statement))
+      vivi_parser_error_child_value (data, &condition);
 
-    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
-      g_object_unref (loop_statement);
-      g_object_unref (condition);
-      if (condition_statement != NULL)
-	g_object_unref (condition_statement);
-      return FAIL (TOKEN_PARENTHESIS_LEFT);
-    }
+    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
+      vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
 
-    if (!check_automatic_semicolon (data)) {
-      g_object_unref (loop_statement);
-      g_object_unref (condition);
-      if (condition_statement != NULL)
-	g_object_unref (condition_statement);
-      return FAIL (TOKEN_PARENTHESIS_LEFT);
-    }
+    if (!check_automatic_semicolon (data))
+      vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
 
     pre_statement = g_object_ref (loop_statement);
   } else if (check_token (data, TOKEN_WHILE)) {
     if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
-      return FAIL (TOKEN_PARENTHESIS_LEFT);
+      vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
 
-    status = parse_expression (data, &condition, &condition_statement);
-    if (status != STATUS_OK)
-      return FAIL_CHILD (status);
+    if (parse_expression (data, &condition, &condition_statement))
+      vivi_parser_error_child_value (data, &condition);
 
-    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
-      g_object_unref (condition);
-      if (condition_statement != NULL)
-	g_object_unref (condition_statement);
-      return FAIL (TOKEN_PARENTHESIS_RIGHT);
-    }
+    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
+      vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
 
-    status = parse_statement (data, &loop_statement);
-    if (status != STATUS_OK) {
-      g_object_unref (condition);
-      if (condition_statement != NULL)
-	g_object_unref (condition_statement);
-      return FAIL_CHILD (status);
-    }
+    if (!parse_statement (data, &loop_statement))
+      vivi_parser_error_child_statement (data, &loop_statement);
   } else if (check_token (data, TOKEN_FOR)) {
     ViviCodeValue *pre_value;
     ViviCodeStatement *post_statement;
 
     if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
-      return FAIL (TOKEN_PARENTHESIS_LEFT);
+      vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
 
     if (check_token (data, TOKEN_VAR)) {
       // FIXME: no in
-      status = parse_statement_list (data, parse_variable_declaration,
-	  &pre_statement, TOKEN_COMMA);
-      if (status != STATUS_OK)
-	return FAIL_CHILD (status);
+      if (parse_statement_list (data, parse_variable_declaration,
+	    &pre_statement, TOKEN_COMMA)) {
+	// FIXME
+      }
       // FIXME: ugly
       // If there was only one VariableDeclaration, get the name for pre_value
       g_assert (VIVI_IS_CODE_BLOCK (pre_statement));
@@ -1667,9 +1571,8 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
     } else {
       if (!check_token (data, TOKEN_SEMICOLON)) {
 	// FIXME: no in
-	status = parse_expression (data, &pre_value, &pre_statement);
-	if (status != STATUS_OK)
-	  return FAIL_CHILD (status);
+	if (parse_expression (data, &pre_value, &pre_statement))
+	  vivi_parser_error_child_value (data, &pre_value);
       } else {
 	pre_value = NULL;
 	pre_statement = NULL;
@@ -1680,87 +1583,53 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
       if (pre_value != NULL)
 	g_object_unref (pre_value);
       if (!check_token (data, TOKEN_SEMICOLON)) {
-	status = parse_expression (data, &condition, &condition_statement);
-	if (status != STATUS_OK)
-	  return FAIL_CHILD (status);
-
-	if (!check_token (data, TOKEN_SEMICOLON)) {
-	  if (pre_statement != NULL)
-	    g_object_unref (pre_statement);
-	  g_object_unref (condition);
-	  if (condition_statement != NULL)
-	    g_object_unref (condition_statement);
-	  return FAIL (TOKEN_SEMICOLON);
-	}
-      }
+	if (parse_expression (data, &condition, &condition_statement))
+	  vivi_parser_error_child_value (data, &condition);
 
-      status = parse_expression (data, &pre_value, &post_statement);
-      if (status != STATUS_OK) {
-	if (pre_statement != NULL)
-	  g_object_unref (pre_statement);
-	g_object_unref (condition);
-	if (condition_statement != NULL)
-	  g_object_unref (condition_statement);
-	return FAIL_CHILD (status);
+	if (!check_token (data, TOKEN_SEMICOLON))
+	  vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
       }
+
+      if (!parse_expression (data, &pre_value, &post_statement))
+	vivi_parser_error_child_value (data, &pre_value);
       g_object_unref (pre_value);
     } else if (pre_value != NULL && check_token (data, TOKEN_IN)) {
       post_statement = NULL;
 
-      if (!vivi_parser_value_is_left_hand_side (pre_value)) {
-	g_object_unref (pre_value);
-	if (pre_statement != NULL)
-	  g_object_unref (pre_statement);
-	return FAIL_CUSTOM (g_strdup (
-	      "Invalid left hand side expression for in"));
-      }
+      // FIXME: correct?
+      if (!vivi_parser_value_is_left_hand_side (pre_value))
+	vivi_parser_error ("Invalid left-hand side expression for in");
 
       g_object_unref (pre_value);
       if (pre_statement != NULL)
 	g_object_unref (pre_statement);
-      return FAIL_CUSTOM (g_strdup (
-	    "for (... in ...) has not been implemented yet"));
+      vivi_parser_error ("for (... in ...) has not been implemented yet");
     } else {
-      ViviParserScannerToken fail_token;
-
       if (pre_value != NULL) {
-	fail_token = TOKEN_IN;
-	g_object_unref (pre_value);
+	vivi_parser_error_unexpected (data, TOKEN_SEMICOLON, TOKEN_IN);
       } else {
-	fail_token = TOKEN_NONE;
+	vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
       }
 
-      if (pre_statement != NULL)
-	g_object_unref (pre_statement);
-
-      return FAIL_OR (TOKEN_SEMICOLON, fail_token);
-    }
+      condition = vivi_code_constant_new_undefined ();
 
-    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+      if (pre_value != NULL)
+	g_object_unref (pre_value);
       if (pre_statement != NULL)
 	g_object_unref (pre_statement);
-      g_object_unref (condition);
-      if (condition_statement != NULL)
-	g_object_unref (condition_statement);
-      g_object_unref (post_statement);
-      return FAIL (TOKEN_PARENTHESIS_RIGHT);
     }
 
-    status = parse_statement (data, &loop_statement);
-    if (status != STATUS_OK) {
-      if (pre_statement != NULL)
-	g_object_unref (pre_statement);
-      g_object_unref (condition);
-      if (condition_statement != NULL)
-	g_object_unref (condition_statement);
-      g_object_unref (post_statement);
-      return FAIL_CHILD (status);
-    }
+    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
+      vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
+
+    if (!parse_statement (data, &loop_statement))
+      vivi_parser_error_child_statement (data, &loop_statement);
 
     loop_statement =
       vivi_parser_join_statements (loop_statement, post_statement);
   } else {
-    return CANCEL (ERROR_TOKEN_ITERATION_STATEMENT);
+    vivi_parser_cancel_unexpected (data, ERROR_TOKEN_ITERATION_STATEMENT);
+    return FALSE;
   }
 
   if (condition_statement != NULL) {
@@ -1779,58 +1648,37 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
 
   *statement = vivi_parser_join_statements (pre_statement, *statement);
 
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_if_statement (ParseData *data, ViviCodeStatement **statement)
 {
-  ParseStatus status;
   ViviCodeValue *condition;
   ViviCodeStatement *pre_statement, *if_statement, *else_statement;
 
   *statement = NULL;
 
-  if (!check_token (data, TOKEN_IF))
-    return CANCEL (TOKEN_IF);
+  if (!check_token (data, TOKEN_IF)) {
+    vivi_parser_cancel_unexpected (data, TOKEN_IF);
+    return FALSE;
+  }
 
   if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
-    return FAIL (TOKEN_PARENTHESIS_LEFT);
+    vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
 
-  status = parse_expression (data, &condition, &pre_statement);
-  if (status != STATUS_OK)
-    return FAIL_CHILD (status);
+  if (!parse_expression (data, &condition, &pre_statement))
+    vivi_parser_error_child_value (data, &condition);
 
-  if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
-    g_object_unref (condition);
-    if (pre_statement != NULL) {
-      g_object_unref (pre_statement);
-      pre_statement = NULL;
-    }
-    return FAIL (TOKEN_PARENTHESIS_RIGHT);
-  }
+  if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
+    vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
 
-  status = parse_statement (data, &if_statement);
-  if (status != STATUS_OK) {
-    g_object_unref (condition);
-    if (pre_statement != NULL) {
-      g_object_unref (pre_statement);
-      pre_statement = NULL;
-    }
-    return FAIL_CHILD (status);
-  }
+  if (!parse_statement (data, &if_statement))
+    vivi_parser_error_child_statement (data, &if_statement);
 
   if (check_token (data, TOKEN_ELSE)) {
-    status = parse_statement (data, &else_statement);
-    if (status != STATUS_OK) {
-      g_object_unref (condition);
-      if (pre_statement != NULL) {
-	g_object_unref (pre_statement);
-	pre_statement = NULL;
-      }
-      g_object_unref (if_statement);
-      return FAIL_CHILD (status);
-    }
+    if (!parse_statement (data, &else_statement))
+      vivi_parser_error_child_statement (data, &else_statement);
   } else {
     else_statement = NULL;
   }
@@ -1850,13 +1698,12 @@ parse_if_statement (ParseData *data, ViviCodeStatement **statement)
 
   g_assert (*statement != NULL);
 
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_expression_statement (ParseData *data, ViviCodeStatement **statement)
 {
-  ParseStatus status;
   ViviCodeValue *value;
   ViviCodeStatement *last;
 
@@ -1864,12 +1711,13 @@ parse_expression_statement (ParseData *data, ViviCodeStatement **statement)
 
   vivi_parser_scanner_peek_next_token (data->scanner);
   if (data->scanner->next_token == TOKEN_BRACE_LEFT ||
-      data->scanner->next_token == TOKEN_FUNCTION)
-    return CANCEL (ERROR_TOKEN_EXPRESSION_STATEMENT);
+      data->scanner->next_token == TOKEN_FUNCTION) {
+    vivi_parser_cancel_unexpected (data, ERROR_TOKEN_EXPRESSION_STATEMENT);
+    return FALSE;
+  }
 
-  status = parse_expression (data, &value, statement);
-  if (status != STATUS_OK)
-    return status;
+  if (!parse_expression (data, &value, statement))
+    return FALSE;
 
   // check for label
   if (*statement == NULL && vivi_parser_value_is_identifier (value)) {
@@ -1877,19 +1725,13 @@ parse_expression_statement (ParseData *data, ViviCodeStatement **statement)
       *statement = vivi_code_label_new (vivi_code_constant_get_variable_name (
 	    VIVI_CODE_CONSTANT (VIVI_CODE_GET (value)->name)));
       if (!vivi_parser_add_label (data, VIVI_CODE_LABEL (*statement)))
-	return FAIL_CUSTOM (g_strdup ("Same label name used twice"));
-      return STATUS_OK;
+	vivi_parser_error ("Same label name used twice");
+      return TRUE;
     }
   }
 
-  if (!check_automatic_semicolon (data)) {
-    g_object_unref (value);
-    if (*statement != NULL) {
-      g_object_unref (*statement);
-      *statement = NULL;
-    }
-    return FAIL (TOKEN_SEMICOLON);
-  }
+  if (!check_automatic_semicolon (data))
+    vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
 
   // add a value statement, if the last statement is not an assignment with the
   // same value
@@ -1907,7 +1749,7 @@ parse_expression_statement (ParseData *data, ViviCodeStatement **statement)
 
     if (assignment->from == NULL && assignment->name == VIVI_CODE_GET (value)->name) {
       g_object_unref (value);
-      return STATUS_OK;
+      return TRUE;
     }
   }
 
@@ -1915,81 +1757,81 @@ parse_expression_statement (ParseData *data, ViviCodeStatement **statement)
       vivi_code_value_statement_new (value));
   g_object_unref (value);
 
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_empty_statement (ParseData *data, ViviCodeStatement **statement)
 {
   *statement = NULL;
 
-  if (!check_token (data, TOKEN_SEMICOLON))
-    return CANCEL (TOKEN_SEMICOLON);
+  if (!check_token (data, TOKEN_SEMICOLON)) {
+    vivi_parser_cancel_unexpected (data, TOKEN_SEMICOLON);
+    return FALSE;
+  }
 
   *statement = vivi_compiler_empty_statement_new ();
 
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_block (ParseData *data, ViviCodeStatement **statement)
 {
-  ParseStatus status;
+  gboolean status;
 
   *statement = NULL;
 
-  if (!check_token (data, TOKEN_BRACE_LEFT))
-    return CANCEL (TOKEN_BRACE_LEFT);
+  if (!check_token (data, TOKEN_BRACE_LEFT)) {
+    vivi_parser_cancel_unexpected (data, TOKEN_BRACE_LEFT);
+    return FALSE;
+  }
 
   vivi_parser_scanner_peek_next_token (data->scanner);
-  if (data->scanner->next_token != TOKEN_BRACE_RIGHT) {
-    status =
-      parse_statement_list (data, parse_statement, statement, STATUS_OK);
-    if (status != STATUS_OK)
-      return FAIL_CHILD (status);
+  if (!check_token (data, TOKEN_BRACE_RIGHT)) {
+    if (!parse_statement_list (data, parse_statement, statement, TRUE)) {
+      // FIXME: child token
+      vivi_parser_error_unexpected (data, TOKEN_BRACE_RIGHT,
+	  ERROR_TOKEN_STATEMENT);
+      *statement = vivi_code_block_new ();
+    }
+
+    if (!check_token (data, TOKEN_BRACE_RIGHT))
+      vivi_parser_error_unexpected (data, TOKEN_BRACE_RIGHT);
   } else {
     *statement = vivi_code_block_new ();
   }
 
-  if (!check_token (data, TOKEN_BRACE_RIGHT)) {
-    g_object_unref (*statement);
-    *statement = NULL;
-    return FAIL (TOKEN_BRACE_RIGHT);
-  }
-
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_variable_statement (ParseData *data, ViviCodeStatement **statement)
 {
-  ParseStatus status;
+  gboolean status;
 
   *statement = NULL;
 
-  if (!check_token (data, TOKEN_VAR))
-    return CANCEL (TOKEN_VAR);
-
-  status = parse_statement_list (data, parse_variable_declaration, statement,
-      TOKEN_COMMA);
-  if (status != STATUS_OK)
-    return FAIL_CHILD (status);
+  if (!check_token (data, TOKEN_VAR)) {
+    vivi_parser_cancel_unexpected (data, TOKEN_VAR);
+    return FALSE;
+  }
 
-  if (!check_automatic_semicolon (data)) {
-    g_object_unref (*statement);
-    *statement = NULL;
-    return FAIL (TOKEN_SEMICOLON);
+  if (!parse_statement_list (data, parse_variable_declaration, statement,
+	TOKEN_COMMA)) {
+    // FIXME
   }
 
-  return STATUS_OK;
+  if (!check_automatic_semicolon (data))
+    vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
+
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_statement (ParseData *data, ViviCodeStatement **statement)
 {
-  ParseStatus status;
-  int i;
-  ParseStatementFunction functions[] = {
+  static const ParseStatementFunction functions[] = {
     parse_block,
     parse_variable_statement,
     parse_empty_statement,
@@ -2006,28 +1848,28 @@ parse_statement (ParseData *data, ViviCodeStatement **statement)
     parse_trace_statement,
     NULL
   };
+  guint i;
 
   *statement = NULL;
 
   for (i = 0; functions[i] != NULL; i++) {
-    status = functions[i] (data, statement);
-    if (status != STATUS_CANCEL)
-      return status;
+    if (functions[i] (data, statement))
+      return TRUE;
   }
 
-  return CANCEL (ERROR_TOKEN_STATEMENT);
+  vivi_parser_cancel_unexpected (data, ERROR_TOKEN_STATEMENT);
+  return FALSE;
 }
 
 // function
 
-static ParseStatus
+static gboolean
 parse_source_element (ParseData *data, ViviCodeStatement **statement);
 
-static ParseStatus
+static gboolean
 parse_function_definition (ParseData *data, ViviCodeValue **function,
     ViviCodeValue **identifier, gboolean identifier_required)
 {
-  ParseStatus status;
   ViviCodeValue **arguments;
   ViviCodeStatement *body;
   guint i;
@@ -2038,65 +1880,50 @@ parse_function_definition (ParseData *data, ViviCodeValue **function,
   arguments = NULL;
   body = NULL;
 
-  if (!check_token (data, TOKEN_FUNCTION))
-    return CANCEL (TOKEN_FUNCTION);
+  if (!check_token (data, TOKEN_FUNCTION)) {
+    vivi_parser_cancel_unexpected (data, TOKEN_FUNCTION);
+    return FALSE;
+  }
 
-  status = parse_identifier (data, identifier);
-  if (status == STATUS_FAIL ||
-      (identifier_required && status == STATUS_CANCEL))
-    return FAIL_CHILD (status);
+  if (identifier_required) {
+    if (!parse_identifier (data, identifier))
+      vivi_parser_error_child_value (data, identifier);
 
-  if (!check_token (data, TOKEN_PARENTHESIS_LEFT)) {
-    g_object_unref (*identifier);
-    return FAIL (TOKEN_PARENTHESIS_LEFT);
-  }
+    if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
+      vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
+  } else {
+    if (!check_token (data, TOKEN_PARENTHESIS_LEFT)) {
+      if (!parse_identifier (data, identifier)) {
+	// FIXME: child token
+	vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT,
+	    ERROR_TOKEN_IDENTIFIER);
+      }
 
-  status = parse_value_list (data, parse_identifier, &arguments, TOKEN_COMMA);
-  if (status == STATUS_FAIL) {
-    g_object_unref (*identifier);
-    return STATUS_FAIL;
+      if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
+	vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
+    }
   }
 
-  if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
-    g_object_unref (*identifier);
-    if (arguments != NULL)
-      free_value_list (arguments);
-    return FAIL (TOKEN_PARENTHESIS_RIGHT);
+  if (!parse_value_list (data, parse_identifier, &arguments, TOKEN_COMMA)) {
+    // FIXME
   }
 
-  if (!check_token (data, TOKEN_BRACE_LEFT)) {
-    g_object_unref (*identifier);
-    if (arguments != NULL)
-      free_value_list (arguments);
-    return FAIL (TOKEN_BRACE_LEFT);
-  }
+  if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
+    vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
+
+  if (!check_token (data, TOKEN_BRACE_LEFT))
+    vivi_parser_error_unexpected (data, TOKEN_BRACE_LEFT);
 
   vivi_parser_start_level (data);
 
-  status = parse_statement_list (data, parse_source_element, &body, STATUS_OK);
-  if (status == STATUS_FAIL) {
-    vivi_parser_end_level (data, FALSE);
-    g_object_unref (*identifier);
-    if (arguments != NULL)
-      free_value_list (arguments);
-    return STATUS_FAIL;
+  if (parse_statement_list (data, parse_source_element, &body, TRUE)) {
+    // FIXME
   }
 
-  status = vivi_parser_end_level (data, TRUE);
-  if (status != STATUS_OK) {
-    g_object_unref (*identifier);
-    if (arguments != NULL)
-      free_value_list (arguments);
-    return FAIL_CHILD (status);
-  }
+  vivi_parser_end_level (data);
 
-  if (!check_token (data, TOKEN_BRACE_RIGHT)) {
-    g_object_unref (*identifier);
-    if (arguments != NULL)
-      free_value_list (arguments);
-    g_object_unref (body);
-    return FAIL (TOKEN_BRACE_RIGHT);
-  }
+  if (!check_token (data, TOKEN_BRACE_RIGHT))
+    vivi_parser_error_unexpected (data, TOKEN_BRACE_RIGHT);
 
   *function = vivi_code_function_new ();
   if (body != NULL) {
@@ -2112,111 +1939,93 @@ parse_function_definition (ParseData *data, ViviCodeValue **function,
     free_value_list (arguments);
   }
 
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_function_declaration (ParseData *data, ViviCodeStatement **statement)
 {
-  ParseStatus status;
+  gboolean status;
   ViviCodeValue *function, *identifier;
 
   *statement = NULL;
 
-  status = parse_function_definition (data, &function, &identifier, TRUE);
-  if (status != STATUS_OK)
-    return status;
+  if (!parse_function_definition (data, &function, &identifier, TRUE))
+    return FALSE;
 
   *statement = vivi_parser_assignment_new (identifier, function);
   g_object_unref (identifier);
   g_object_unref (function);
 
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_function_expression (ParseData *data, ViviCodeValue **value,
     ViviCodeStatement **statement)
 {
-  ParseStatus status;
+  gboolean status;
   ViviCodeValue *identifier;
 
   *statement = NULL;
 
-  status = parse_function_definition (data, value, &identifier, FALSE);
-  if (status != STATUS_OK)
-    return status;
+  if (!parse_function_definition (data, &function, &identifier, FALSE))
+    return FALSE;
 
   if (identifier != NULL) {
     *statement = vivi_parser_assignment_new (identifier, *value);
     g_object_unref (identifier);
   }
 
-  return STATUS_OK;
+  return TRUE;
 }
 
 // top
 
-static ParseStatus
+static gboolean
 parse_source_element (ParseData *data, ViviCodeStatement **statement)
 {
-  ParseStatus status;
-
   *statement = NULL;
 
-  status = parse_function_declaration (data, statement);
-  if (status == STATUS_CANCEL)
-    status = parse_statement (data, statement);
+  if (!parse_function_declaration (data, statement)) {
+    if (!parse_statement (data, statement)) {
+      // FIXME
+      vivi_parser_cancel_unexpected (data, ERROR_TOKEN_FUNCTION_DECLARATION,
+	  ERROR_TOKEN_STATEMENT);
+      return FALSE;
+    }
+  }
 
-  return status;
+  return TRUE;
 }
 
-static ParseStatus
+static void
 parse_program (ParseData *data, ViviCodeStatement **statement)
 {
-  ParseStatus status;
-
   g_assert (data->level == NULL);
   vivi_parser_start_level (data);
 
   *statement = NULL;
 
-  status =
-    parse_statement_list (data, parse_source_element, statement, STATUS_OK);
-  if (status != STATUS_OK) {
-    vivi_parser_end_level (data, FALSE);
-    return FAIL_CHILD (status);
-  }
-
-  if (!check_token (data, TOKEN_EOF)) {
-    vivi_parser_end_level (data, FALSE);
-    g_object_unref (*statement);
-    *statement = NULL;
-    status = parse_statement (data, statement);
-    return FAIL_CHILD (status);
-  }
+  if (!parse_statement_list (data, parse_source_element, statement, TRUE))
+    // FIXME
 
+  if (!check_token (data, TOKEN_EOF))
+    vivi_parser_error_unexpected (data, TOKEN_EOF);
 
-  status = vivi_parser_end_level (data, TRUE);
-  if (status != STATUS_OK) {
-    g_object_unref (*statement);
-    *statement = NULL;
-    return FAIL_CHILD (status);
-  }
+  vivi_parser_end_level (data);
 
   g_assert (data->level == NULL);
-
-  return STATUS_OK;
 }
 
 // parsing
 
-static ParseStatus
+static gboolean
 parse_statement_list (ParseData *data, ParseStatementFunction function,
     ViviCodeStatement **block, guint separator)
 {
   ViviCodeStatement *statement;
-  ParseStatus status;
+  gboolean status;
 
   g_assert (data != NULL);
   g_assert (function != NULL);
@@ -2225,7 +2034,7 @@ parse_statement_list (ParseData *data, ParseStatementFunction function,
   *block = NULL;
 
   status = function (data, &statement);
-  if (status != STATUS_OK)
+  if (status != TRUE)
     return status;
 
   *block = vivi_code_block_new ();
@@ -2234,7 +2043,7 @@ parse_statement_list (ParseData *data, ParseStatementFunction function,
     vivi_code_block_add_statement (VIVI_CODE_BLOCK (*block), statement);
     g_object_unref (statement);
 
-    if (separator != STATUS_OK && !check_token (data, separator))
+    if (separator != TRUE && !check_token (data, separator))
       break;
 
     status = function (data, &statement);
@@ -2243,12 +2052,12 @@ parse_statement_list (ParseData *data, ParseStatementFunction function,
       *block = NULL;
       return STATUS_FAIL;
     }
-  } while (status == STATUS_OK);
+  } while (status == TRUE);
 
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_value_statement_list (ParseData *data,
     ParseValueStatementFunction function, ViviCodeValue ***list,
     ViviCodeStatement **statement, guint separator)
@@ -2256,7 +2065,7 @@ parse_value_statement_list (ParseData *data,
   GPtrArray *array;
   ViviCodeValue *value;
   ViviCodeStatement *statement_one;
-  ParseStatus status;
+  gboolean status;
 
   g_assert (data != NULL);
   g_assert (function != NULL);
@@ -2267,7 +2076,7 @@ parse_value_statement_list (ParseData *data,
   *statement = NULL;
 
   status = function (data, &value, statement);
-  if (status != STATUS_OK)
+  if (status != TRUE)
     return status;
 
   array = g_ptr_array_new ();
@@ -2279,27 +2088,27 @@ parse_value_statement_list (ParseData *data,
       break;
 
     status = function (data, &value, &statement_one);
-    if (status != STATUS_OK) {
+    if (status != TRUE) {
       if (status == STATUS_FAIL || separator != TOKEN_NONE)
 	return FAIL_CHILD (status);
     } else {
       *statement = vivi_parser_join_statements (*statement, statement_one);
     }
-  } while (status == STATUS_OK);
+  } while (status == TRUE);
   g_ptr_array_add (array, NULL);
 
   *list = (ViviCodeValue **)g_ptr_array_free (array, FALSE);
 
-  return STATUS_OK;
+  return TRUE;
 }
 
-static ParseStatus
+static gboolean
 parse_value_list (ParseData *data, ParseValueFunction function,
     ViviCodeValue ***list, guint separator)
 {
   GPtrArray *array;
   ViviCodeValue *value;
-  ParseStatus status;
+  gboolean status;
 
   g_assert (data != NULL);
   g_assert (function != NULL);
@@ -2308,7 +2117,7 @@ parse_value_list (ParseData *data, ParseValueFunction function,
   *list = NULL;
 
   status = function (data, &value);
-  if (status != STATUS_OK)
+  if (status != TRUE)
     return status;
 
   array = g_ptr_array_new ();
@@ -2316,18 +2125,18 @@ parse_value_list (ParseData *data, ParseValueFunction function,
   do {
     g_ptr_array_add (array, value);
 
-    if (separator != STATUS_OK && !check_token (data, separator))
+    if (separator != TRUE && !check_token (data, separator))
       break;
 
     status = function (data, &value);
     if (status == STATUS_FAIL)
       return STATUS_FAIL;
-  } while (status == STATUS_OK);
+  } while (status == TRUE);
   g_ptr_array_add (array, NULL);
 
   *list = (ViviCodeValue **)g_ptr_array_free (array, FALSE);
 
-  return STATUS_OK;
+  return TRUE;
 }
 
 // public
@@ -2337,7 +2146,7 @@ vivi_parse_file (FILE *file, const char *input_name)
 {
   ParseData data;
   ViviCodeStatement *statement;
-  ParseStatus status;
+  gboolean status;
 
   g_return_val_if_fail (file != NULL, NULL);
 
@@ -2350,11 +2159,11 @@ vivi_parse_file (FILE *file, const char *input_name)
   data.level = NULL;
 
   status = parse_program (&data, &statement);
-  g_assert ((status == STATUS_OK && VIVI_IS_CODE_STATEMENT (statement)) ||
-	(status != STATUS_OK && statement == NULL));
+  g_assert ((status == TRUE && VIVI_IS_CODE_STATEMENT (statement)) ||
+	(status != TRUE && statement == NULL));
   g_assert (status >= 0);
 
-  if (status != STATUS_OK) {
+  if (status != TRUE) {
     g_printerr ("%s:%i:%i: error: ", input_name,
 	vivi_parser_scanner_cur_line (data.scanner),
 	vivi_parser_scanner_cur_column (data.scanner));
commit b7d5363c6ad7f7e9b10cede8c1b18c200a302bb6
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Tue Apr 8 23:29:39 2008 +0300

    Rename vivi_compiler.[ch] and vivi_compiler_scanner* to vivi_parser*

diff --git a/vivified/code/Makefile.am b/vivified/code/Makefile.am
index a38f95a..1ce87dd 100644
--- a/vivified/code/Makefile.am
+++ b/vivified/code/Makefile.am
@@ -1,19 +1,19 @@
 SUBDIRS = test
 
-noinst_LTLIBRARIES = libvivified-compiler-lex.la libvivified-compiler.la
+noinst_LTLIBRARIES = libvivified-parser-lex.la libvivified-compiler.la
 
 # we create own .la for lex generated code, so we can disable some warnings
-libvivified_compiler_lex_la_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS) -Wno-switch-default -Wno-missing-declarations -Wno-missing-prototypes -Wno-sign-compare -Wno-unused-function -Wno-missing-noreturn
-libvivified_compiler_lex_la_LDFLAGS = $(SWFDEC_LIBS)
+libvivified_parser_lex_la_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS) -Wno-switch-default -Wno-missing-declarations -Wno-missing-prototypes -Wno-sign-compare -Wno-unused-function -Wno-missing-noreturn
+libvivified_parser_lex_la_LDFLAGS = $(SWFDEC_LIBS)
 
-libvivified_compiler_lex_la_SOURCES = \
-	vivi_compiler_scanner_lex.l
+libvivified_parser_lex_la_SOURCES = \
+	vivi_parser_scanner_lex.l
 
 libvivified_compiler_la_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS)
 libvivified_compiler_la_LDFLAGS = $(SWFDEC_LIBS)
 
 libvivified_compiler_la_LIBADD = \
-	libvivified-compiler-lex.la
+	libvivified-parser-lex.la
 
 libvivified_compiler_la_SOURCES = \
 	vivi_code_assignment.c \
@@ -44,16 +44,16 @@ libvivified_compiler_la_SOURCES = \
 	vivi_code_unary.c \
 	vivi_code_value.c \
 	vivi_code_value_statement.c \
-	vivi_compiler.c \
 	vivi_compiler_empty_statement.c \
 	vivi_compiler_get_temporary.c \
 	vivi_compiler_goto_name.c \
-	vivi_compiler_scanner.c \
 	vivi_decompiler_block.c \
 	vivi_decompiler_duplicate.c \
 	vivi_decompiler_state.c \
 	vivi_decompiler_unknown.c \
-	vivi_decompiler.c
+	vivi_decompiler.c \
+	vivi_parser.c \
+	vivi_parser_scanner.c
 
 noinst_HEADERS = \
 	vivi_code_assignment.h \
@@ -84,18 +84,18 @@ noinst_HEADERS = \
 	vivi_code_unary.h \
 	vivi_code_value.h \
 	vivi_code_value_statement.h \
-	vivi_compiler.h \
 	vivi_compiler_empty_statement.h \
 	vivi_compiler_get_temporary.h \
 	vivi_compiler_goto_name.h \
-	vivi_compiler_scanner.h \
-	vivi_compiler_scanner_lex.h \
-	vivi_compiler_scanner_lex_include.h \
 	vivi_decompiler.h \
 	vivi_decompiler_block.h \
 	vivi_decompiler_duplicate.h \
 	vivi_decompiler_state.h
 	vivi_decompiler_unknown.h \
+	vivi_parser.h \
+	vivi_parser_scanner.h \
+	vivi_parser_scanner_lex.h \
+	vivi_parser_scanner_lex_include.h \
 	vivified-compiler.h
 
 noinst_PROGRAMS = vivi-decompile vivi-compile
diff --git a/vivified/code/compiler.c b/vivified/code/compiler.c
index 0b984f5..e3a32a9 100644
--- a/vivified/code/compiler.c
+++ b/vivified/code/compiler.c
@@ -23,7 +23,7 @@
 
 #include <swfdec/swfdec.h>
 
-#include "vivi_compiler.h"
+#include "vivi_parser.h"
 #include "vivi_code_text_printer.h"
 #include "vivi_code_compiler.h"
 
@@ -54,7 +54,7 @@ main (int argc, char *argv[])
     return -1;
   }
 
-  statement = vivi_compile_file (source, argv[1]);
+  statement = vivi_parse_file (source, argv[1]);
 
   fclose (source);
 
diff --git a/vivified/code/vivi_compiler.c b/vivified/code/vivi_compiler.c
deleted file mode 100644
index 10b3e61..0000000
--- a/vivified/code/vivi_compiler.c
+++ /dev/null
@@ -1,2385 +0,0 @@
-/* Vivified
- * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 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
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <string.h>
-
-#include "vivi_compiler.h"
-
-#include "vivi_compiler_scanner.h"
-
-#include "vivi_code_assignment.h"
-#include "vivi_code_binary.h"
-#include "vivi_code_block.h"
-#include "vivi_code_break.h"
-#include "vivi_code_constant.h"
-#include "vivi_code_continue.h"
-#include "vivi_code_function.h"
-#include "vivi_code_function_call.h"
-#include "vivi_code_get.h"
-#include "vivi_code_get_url.h"
-#include "vivi_code_goto.h"
-#include "vivi_code_if.h"
-#include "vivi_code_init_array.h"
-#include "vivi_code_init_object.h"
-#include "vivi_code_loop.h"
-#include "vivi_code_return.h"
-#include "vivi_code_throw.h"
-#include "vivi_code_trace.h"
-#include "vivi_code_unary.h"
-#include "vivi_code_value_statement.h"
-#include "vivi_compiler_empty_statement.h"
-#include "vivi_compiler_get_temporary.h"
-#include "vivi_compiler_goto_name.h"
-
-#include "vivi_code_text_printer.h"
-
-enum {
-  ERROR_TOKEN_LITERAL = TOKEN_LAST + 1,
-  ERROR_TOKEN_IDENTIFIER,
-  ERROR_TOKEN_PROPERTY_NAME,
-  ERROR_TOKEN_PRIMARY_EXPRESSION,
-  ERROR_TOKEN_EXPRESSION,
-  ERROR_TOKEN_ITERATION_STATEMENT,
-  ERROR_TOKEN_EXPRESSION_STATEMENT,
-  ERROR_TOKEN_STATEMENT
-};
-
-static const struct {
-  guint				token;
-  const char *			name;
-} error_names[] = {
-  { ERROR_TOKEN_LITERAL, "LITERAL" },
-  { ERROR_TOKEN_IDENTIFIER, "IDENTIFIER" },
-  { ERROR_TOKEN_PROPERTY_NAME, "PROPERTY NAME" },
-  { ERROR_TOKEN_PRIMARY_EXPRESSION, "PRIMARY EXPRESSION" },
-  { ERROR_TOKEN_EXPRESSION, "EXPRESSION" },
-  { ERROR_TOKEN_ITERATION_STATEMENT, "ITERATION STATEMENT" },
-  { ERROR_TOKEN_EXPRESSION_STATEMENT, "EXPRESSION STATEMENT" },
-  { ERROR_TOKEN_STATEMENT, "STATEMENT" },
-  { TOKEN_LAST, NULL }
-};
-
-typedef enum {
-  STATUS_CANCEL = -1,
-  STATUS_OK = 0,
-  STATUS_FAIL = 1
-} ParseStatus;
-
-typedef struct {
-  GSList			*labels;
-  GSList			*gotos;
-} ParseLevel;
-
-typedef struct {
-  ViviCompilerScanner *		scanner;
-  gboolean			unexpected_line_terminator;
-  guint				expected[2];
-  char *			custom_error;
-
-  GSList *			levels; // ParseLevel, earlier levels
-  ParseLevel *			level;  // current level
-} ParseData;
-
-#define FAIL_OR(x, y) (data->expected[0] = (x), data->expected[1] = (y), STATUS_FAIL)
-#define FAIL_LINE_TERMINATOR_OR(x, y) (data->unexpected_line_terminator = TRUE, FAIL_OR(x,y))
-#define FAIL_LINE_TERMINATOR(x) FAIL_LINE_TERMINATOR_OR(x,TOKEN_NONE)
-#define FAIL(x) FAIL_OR(x,TOKEN_NONE)
-#define FAIL_CHILD(x) STATUS_FAIL
-#define FAIL_CUSTOM(x) (data->custom_error = (x), STATUS_FAIL)
-#define CANCEL_OR(x, y) (data->expected[0] = (x), data->expected[1] = (y), STATUS_CANCEL)
-#define CANCEL(x) CANCEL_OR(x, TOKEN_NONE)
-#define CANCEL_CUSTOM(x) (data->custom_error = (x), STATUS_CANCEL)
-
-typedef ParseStatus (*ParseValueFunction) (ParseData *data, ViviCodeValue **value);
-typedef ParseStatus (*ParseValueStatementFunction) (ParseData *data, ViviCodeValue **value, ViviCodeStatement **statement);
-typedef ParseStatus (*ParseStatementFunction) (ParseData *data, ViviCodeStatement **statement);
-
-static ParseStatus
-parse_statement_list (ParseData *data, ParseStatementFunction function, ViviCodeStatement **statement, guint separator);
-
-static ParseStatus
-parse_value_statement_list (ParseData *data,
-    ParseValueStatementFunction function, ViviCodeValue ***list,
-    ViviCodeStatement **statement, guint separator);
-
-static ParseStatus
-parse_value_list (ParseData *data, ParseValueFunction function,
-    ViviCodeValue ***list, guint separator);
-
-// helpers
-
-static const char *
-vivi_compiler_token_name (guint token)
-{
-  if (token < TOKEN_LAST) {
-    return vivi_compiler_scanner_token_name (token);
-  } else {
-    guint i;
-    const char *name;
-
-    name = NULL;
-    for (i = 0; error_names[i].token != TOKEN_LAST; i++) {
-      if (error_names[i].token == token) {
-	name = error_names[i].name;
-	break;
-      }
-    }
-
-    g_assert (name != NULL);
-
-    return name;
-  }
-}
-
-static gboolean
-check_line_terminator (ParseData *data)
-{
-  vivi_compiler_scanner_peek_next_token (data->scanner);
-  return data->scanner->next_line_terminator;
-}
-
-static gboolean
-check_token (ParseData *data, ViviCompilerScannerToken token)
-{
-  vivi_compiler_scanner_peek_next_token (data->scanner);
-  if (data->scanner->next_token != token)
-    return FALSE;
-  vivi_compiler_scanner_get_next_token (data->scanner);
-  return TRUE;
-}
-
-static gboolean
-check_automatic_semicolon (ParseData *data)
-{
-  if (check_token (data, TOKEN_SEMICOLON))
-    return TRUE;
-  if (check_line_terminator (data))
-    return TRUE;
-
-  vivi_compiler_scanner_peek_next_token (data->scanner);
-  if (data->scanner->next_token == TOKEN_BRACE_LEFT ||
-      data->scanner->next_token == TOKEN_EOF)
-    return TRUE;
-
-  return FALSE;
-}
-
-static gboolean
-check_restricted_semicolon (ParseData *data)
-{
-  if (check_token (data, TOKEN_SEMICOLON))
-    return TRUE;
-  if (check_line_terminator (data))
-    return TRUE;
-
-  return FALSE;
-}
-
-static void
-free_value_list (ViviCodeValue **list)
-{
-  int i;
-
-  for (i = 0; list[i] != NULL; i++) {
-    g_object_unref (list[i]);
-  }
-  g_free (list);
-}
-
-G_GNUC_WARN_UNUSED_RESULT static ViviCodeStatement *
-vivi_compiler_join_statements (ViviCodeStatement *one, ViviCodeStatement *two)
-{
-
-  if (one == NULL) {
-    return two;
-  } else if (two == NULL) {
-    return one;
-  }
-
-  if (VIVI_IS_CODE_BLOCK (one)) {
-    vivi_code_block_add_statement (VIVI_CODE_BLOCK (one), two);
-    g_object_unref (two);
-    return one;
-  } else if (VIVI_IS_CODE_BLOCK (two)) {
-    vivi_code_block_insert_statement (VIVI_CODE_BLOCK (two), 0, one);
-    g_object_unref (one);
-    return two;
-  } else {
-    ViviCodeStatement *block = vivi_code_block_new ();
-    vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), one);
-    g_object_unref (one);
-    vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), two);
-    g_object_unref (two);
-    return block;
-  }
-}
-
-static ViviCodeValue *
-vivi_compiler_function_call_new (ViviCodeValue *name)
-{
-  ViviCodeValue *value;
-
-  g_return_val_if_fail (VIVI_IS_CODE_VALUE (name), NULL);
-
-  value = NULL;
-
-  if (VIVI_IS_CODE_GET (name)) {
-    ViviCodeGet *get = VIVI_CODE_GET (name);
-
-    if (get->from != NULL) {
-      value = g_object_ref (get->from);
-      name = g_object_ref (get->name);
-    }
-  }
-
-  if (VIVI_IS_CODE_GET (name)) {
-    ViviCodeGet *get = VIVI_CODE_GET (name);
-
-    if (get->from == NULL)
-      name = g_object_ref (get->name);
-  }
-
-  return vivi_code_function_call_new (value, name);
-}
-
-static ViviCodeStatement *
-vivi_compiler_assignment_new (ViviCodeValue *left, ViviCodeValue *right)
-{
-  ViviCodeValue *from;
-
-  g_return_val_if_fail (VIVI_IS_CODE_VALUE (left), NULL);
-  g_return_val_if_fail (VIVI_IS_CODE_VALUE (right), NULL);
-
-  from = NULL;
-
-  if (VIVI_IS_CODE_GET (left)) {
-    ViviCodeGet *get = VIVI_CODE_GET (left);
-
-    if (get->from != NULL) {
-      from = g_object_ref (get->from);
-      left = g_object_ref (get->name);
-    }
-  }
-
-  if (VIVI_IS_CODE_GET (left)) {
-    ViviCodeGet *get = VIVI_CODE_GET (left);
-
-    if (get->from == NULL)
-      left = g_object_ref (get->name);
-  }
-
-  return vivi_code_assignment_new (from, left, right);
-}
-
-static ViviCodeValue *
-vivi_compiler_get_new (ViviCodeValue *from, ViviCodeValue *name)
-{
-  g_return_val_if_fail (VIVI_IS_CODE_VALUE (from), NULL);
-  g_return_val_if_fail (VIVI_IS_CODE_VALUE (name), NULL);
-
-  if (VIVI_IS_CODE_GET (name)) {
-    ViviCodeGet *get = VIVI_CODE_GET (name);
-
-    if (get->from == NULL)
-      name = g_object_ref (get->name);
-  }
-
-  return vivi_code_get_new (from, name);
-}
-
-static gboolean
-vivi_compiler_value_is_left_hand_side (ViviCodeValue *value)
-{
-  // FIXME: Correct?
-  return VIVI_IS_CODE_GET (value);
-}
-
-static gboolean
-vivi_compiler_value_is_identifier (ViviCodeValue *value)
-{
-  if (!VIVI_IS_CODE_GET (value))
-    return FALSE;
-  return VIVI_IS_CODE_CONSTANT (VIVI_CODE_GET (value)->name);
-}
-
-static void
-vivi_compiler_start_level (ParseData *data)
-{
-  g_return_if_fail (data != NULL);
-
-  if (data->level != NULL)
-    data->levels = g_slist_prepend (data->levels, data->level);
-  data->level = g_new0 (ParseLevel, 1);
-}
-
-static ViviCodeLabel *
-vivi_compiler_find_label (ParseData *data, const char *name)
-{
-  GSList *iter;
-
-  for (iter = data->level->labels; iter != NULL; iter = iter->next) {
-    if (g_str_equal (vivi_code_label_get_name (VIVI_CODE_LABEL (iter->data)),
-	  name))
-      return VIVI_CODE_LABEL (iter->data);
-  }
-
-  return NULL;
-}
-
-static ParseStatus
-vivi_compiler_end_level (ParseData *data, gboolean fail)
-{
-  GSList *iter;
-  char *custom_error = NULL;
-
-  g_return_val_if_fail (data != NULL, STATUS_FAIL);
-  g_return_val_if_fail (data->level != NULL, STATUS_FAIL);
-
-  for (iter = data->level->gotos; iter != NULL; iter = iter->next) {
-    ViviCompilerGotoName *goto_;
-    ViviCodeLabel *label;
-
-    goto_ = VIVI_COMPILER_GOTO_NAME (iter->data);
-    label = vivi_compiler_find_label (data,
-	vivi_compiler_goto_name_get_name (goto_));
-
-    if (label != NULL) {
-      vivi_compiler_goto_name_set_label (goto_, label);
-    } else {
-      if (custom_error == NULL) {
-	custom_error =
-	  g_strdup_printf ("Label named '%s' doesn't exist in this block",
-	      vivi_compiler_goto_name_get_name (goto_));
-      }
-    }
-
-    g_object_unref (goto_);
-  }
-  g_slist_free (data->level->gotos);
-
-  for (iter = data->level->labels; iter != NULL; iter = iter->next) {
-    g_object_unref (VIVI_CODE_LABEL (iter->data));
-  }
-  g_slist_free (data->level->labels);
-
-  g_free (data->level);
-
-  if (data->levels != NULL) {
-    data->level = data->levels->data;
-    data->levels = g_slist_delete_link (data->levels, data->levels);
-  } else {
-    data->level = NULL;
-  }
-
-  if (custom_error != NULL) {
-    if (fail) {
-      return FAIL_CUSTOM (custom_error);
-    } else {
-      return STATUS_FAIL;
-    }
-  } else {
-    return STATUS_OK;
-  }
-}
-
-static void
-vivi_compiler_add_goto (ParseData *data, ViviCompilerGotoName *goto_)
-{
-  g_return_if_fail (data != NULL);
-  g_return_if_fail (data->level != NULL);
-  g_return_if_fail (VIVI_IS_COMPILER_GOTO_NAME (goto_));
-
-  data->level->gotos =
-    g_slist_prepend (data->level->gotos, g_object_ref (goto_));
-}
-
-static gboolean
-vivi_compiler_add_label (ParseData *data, ViviCodeLabel *label)
-{
-  GSList *iter;
-
-  g_return_val_if_fail (data != NULL, FALSE);
-  g_return_val_if_fail (data->level != NULL, FALSE);
-  g_return_val_if_fail (VIVI_IS_CODE_LABEL (label), FALSE);
-
-  for (iter = data->level->labels; iter != NULL; iter = iter->next) {
-    if (g_str_equal (vivi_code_label_get_name (VIVI_CODE_LABEL (iter->data)),
-	  vivi_code_label_get_name (label)))
-      return FALSE;
-  }
-
-  data->level->labels =
-    g_slist_prepend (data->level->labels, g_object_ref (label));
-
-  return TRUE;
-}
-
-// values
-
-/* ActionScript specific */
-static ParseStatus
-parse_undefined_literal (ParseData *data, ViviCodeValue **value)
-{
-  *value = NULL;
-
-  if (!check_token (data, TOKEN_UNDEFINED))
-    return CANCEL (TOKEN_UNDEFINED);
-
-  *value = vivi_code_constant_new_undefined ();
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_null_literal (ParseData *data, ViviCodeValue **value)
-{
-  *value = NULL;
-
-  if (!check_token (data, TOKEN_NULL))
-    return CANCEL (TOKEN_NULL);
-
-  *value = vivi_code_constant_new_null ();
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_boolean_literal (ParseData *data, ViviCodeValue **value)
-{
-  *value = NULL;
-
-  if (!check_token (data, TOKEN_BOOLEAN))
-    return CANCEL (TOKEN_BOOLEAN);
-
-  *value = vivi_code_constant_new_boolean (data->scanner->value.v_boolean);
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_numeric_literal (ParseData *data, ViviCodeValue **value)
-{
-  *value = NULL;
-
-  if (!check_token (data, TOKEN_NUMBER))
-    return CANCEL (TOKEN_NUMBER);
-
-  *value = vivi_code_constant_new_number (data->scanner->value.v_number);
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_string_literal (ParseData *data, ViviCodeValue **value)
-{
-  *value = NULL;
-
-  if (!check_token (data, TOKEN_STRING))
-    return CANCEL (TOKEN_STRING);
-
-  *value = vivi_code_constant_new_string (data->scanner->value.v_string);
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_literal (ParseData *data, ViviCodeValue **value)
-{
-  ParseStatus status;
-  int i;
-  ParseValueFunction functions[] = {
-    parse_undefined_literal,
-    parse_null_literal,
-    parse_boolean_literal,
-    parse_numeric_literal,
-    parse_string_literal,
-    NULL
-  };
-
-  *value = NULL;
-
-  for (i = 0; functions[i] != NULL; i++) {
-    status = functions[i] (data, value);
-    if (status != STATUS_CANCEL)
-      return status;
-  }
-
-  return CANCEL (ERROR_TOKEN_LITERAL);
-}
-
-static ParseStatus
-parse_identifier (ParseData *data, ViviCodeValue **value)
-{
-  *value = NULL;
-
-  if (!check_token (data, TOKEN_IDENTIFIER))
-    return CANCEL (TOKEN_IDENTIFIER);
-
-  *value = vivi_code_get_new_name (data->scanner->value.v_identifier);
-
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_property_name (ParseData *data, ViviCodeValue **value)
-{
-  ParseStatus status;
-  int i;
-  ParseValueFunction functions[] = {
-    parse_identifier,
-    parse_string_literal,
-    parse_numeric_literal,
-    NULL
-  };
-
-  *value = NULL;
-
-  for (i = 0; functions[i] != NULL; i++) {
-    status = functions[i] (data, value);
-    if (status != STATUS_CANCEL)
-      return status;
-  }
-
-  return CANCEL (ERROR_TOKEN_PROPERTY_NAME);
-}
-
-static ParseStatus
-parse_assignment_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement);
-
-static ParseStatus
-parse_array_literal (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
-{
-  ViviCodeValue *member;
-  ViviCodeStatement *statement_new;
-  ParseStatus status;
-
-  *value = NULL;
-  *statement = NULL;
-
-  if (!check_token (data, TOKEN_BRACKET_LEFT))
-    return CANCEL (TOKEN_BRACKET_LEFT);
-
-  *value = vivi_code_init_array_new ();
-
-  while (TRUE) {
-    if (check_token (data, TOKEN_BRACKET_RIGHT)) {
-      vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
-	 vivi_code_constant_new_undefined ());
-      break;
-    } else if (check_token (data, TOKEN_COMMA)) {
-      vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
-	 vivi_code_constant_new_undefined ());
-    } else {
-      status = parse_assignment_expression (data, &member, &statement_new);
-      if (status != STATUS_OK) {
-	if (*statement != NULL) {
-	  g_object_unref (*statement);
-	  *statement = NULL;
-	}
-	return FAIL_CHILD (status);
-      }
-
-      *statement = vivi_compiler_join_statements (*statement, statement_new);
-
-      vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
-	  member);
-      g_object_unref (member);
-
-      if (!check_token (data, TOKEN_COMMA)) {
-	if (!check_token (data, TOKEN_BRACKET_RIGHT)) {
-	  return FAIL_OR (TOKEN_BRACKET_RIGHT, TOKEN_COMMA);
-	}
-	break;
-      }
-    }
-  }
-
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_object_literal (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
-{
-  ParseStatus status;
-
-  *value = NULL;
-  *statement = NULL;
-
-  if (!check_token (data, TOKEN_BRACE_LEFT))
-    return CANCEL (TOKEN_BRACE_LEFT);
-
-  *value = vivi_code_init_object_new ();
-
-  if (!check_token (data, TOKEN_BRACE_RIGHT)) {
-    do {
-      ViviCodeValue *property, *initializer;
-      ViviCodeStatement *statement_new;
-
-      status = parse_property_name (data, &property);
-      if (status != STATUS_OK) {
-	g_object_unref (*value);
-	*value = NULL;
-	if (*statement != NULL) {
-	  g_object_unref (*statement);
-	  *statement = NULL;
-	}
-	return FAIL_CHILD (status);
-      }
-
-      if (!check_token (data, TOKEN_COLON)) {
-	g_object_unref (*value);
-	*value = NULL;
-	if (*statement != NULL) {
-	  g_object_unref (*statement);
-	  *statement = NULL;
-	}
-	return FAIL (TOKEN_COLON);
-      }
-
-      status = parse_assignment_expression (data, &initializer,
-	  &statement_new);
-      if (status != STATUS_OK) {
-	g_object_unref (*value);
-	*value = NULL;
-	if (*statement != NULL) {
-	  g_object_unref (*statement);
-	  *statement = NULL;
-	}
-	return FAIL_CHILD (status);
-      }
-
-      *statement = vivi_compiler_join_statements (*statement, statement_new);
-
-      vivi_code_init_object_add_variable (VIVI_CODE_INIT_OBJECT (*value),
-	  property, initializer);
-    } while (check_token (data, TOKEN_COMMA));
-  }
-
-  if (!check_token (data, TOKEN_BRACE_RIGHT)) {
-    g_object_unref (*value);
-    *value = NULL;
-    if (*statement != NULL) {
-      g_object_unref (*statement);
-      *statement = NULL;
-    }
-    return FAIL (TOKEN_BRACE_RIGHT);
-  }
-
-  return STATUS_OK;
-}
-
-// misc
-
-static ParseStatus
-parse_variable_declaration (ParseData *data, ViviCodeStatement **statement)
-{
-  ParseStatus status;
-  ViviCodeValue *identifier, *value;
-  ViviCodeStatement *assignment, *statement_right;
-
-  *statement = NULL;
-
-  status = parse_identifier (data, &identifier);
-  if (status != STATUS_OK)
-    return status;
-
-  if (check_token (data, TOKEN_ASSIGN)) {
-    status = parse_assignment_expression (data, &value, &statement_right);
-    if (status != STATUS_OK) {
-      g_object_unref (identifier);
-      return FAIL_CHILD (status);
-    }
-  } else {
-    value = vivi_code_constant_new_undefined ();
-    statement_right = NULL;
-  }
-
-  assignment = vivi_compiler_assignment_new (identifier, value);
-  vivi_code_assignment_set_local (VIVI_CODE_ASSIGNMENT (assignment), TRUE);
-
-  *statement = vivi_compiler_join_statements (statement_right, assignment);
-
-  return STATUS_OK;
-}
-
-// expression
-
-static ParseStatus
-parse_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement);
-
-static ParseStatus
-parse_primary_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
-{
-  ParseStatus status;
-  int i;
-  ParseValueFunction functions[] = {
-    parse_identifier,
-    parse_literal,
-    NULL
-  };
-
-  *value = NULL;
-  *statement = NULL;
-
-  if (check_token (data, TOKEN_THIS)) {
-    *value = vivi_code_get_new_name ("this");
-    return STATUS_OK;
-  }
-
-  if (check_token (data, TOKEN_PARENTHESIS_LEFT)) {
-    status = parse_expression (data, value, statement);
-    if (status != STATUS_OK)
-      return FAIL_CHILD (status);
-    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
-      g_object_unref (*value);
-      *value = NULL;
-      return FAIL (TOKEN_PARENTHESIS_RIGHT);
-    }
-    return STATUS_OK;
-  }
-
-
-  status = parse_object_literal (data, value, statement);
-  if (status != STATUS_CANCEL)
-    return status;
-
-  status = parse_array_literal (data, value, statement);
-  if (status != STATUS_CANCEL)
-    return status;
-
-  for (i = 0; functions[i] != NULL; i++) {
-    status = functions[i] (data, value);
-    if (status != STATUS_CANCEL)
-      return status;
-  }
-
-  return CANCEL (ERROR_TOKEN_PRIMARY_EXPRESSION);
-}
-
-static ParseStatus
-parse_function_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement);
-
-static ParseStatus
-parse_member_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
-{
-  ParseStatus status;
-  ViviCodeValue *member;
-  ViviCodeStatement *statement_member;
-
-  *value = NULL;
-  *statement = NULL;
-
-  // TODO: new MemberExpression Arguments
-
-  status = parse_primary_expression (data, value, statement);
-  if (status == STATUS_CANCEL)
-    status = parse_function_expression (data, value, statement);
-
-  if (status != STATUS_OK)
-    return status;
-
-  do {
-    ViviCodeValue *tmp;
-
-    if (check_token (data, TOKEN_BRACKET_LEFT)) {
-      status = parse_expression (data, &member, &statement_member);
-      if (status != STATUS_OK) {
-	g_object_unref (*value);
-	*value = NULL;
-	if (*statement != NULL) {
-	  g_object_unref (*statement);
-	  *statement = NULL;
-	}
-	return FAIL_CHILD (status);
-      }
-
-      *statement =
-	vivi_compiler_join_statements (*statement, statement_member);
-
-      if (!check_token (data, TOKEN_BRACKET_RIGHT)) {
-	g_object_unref (*value);
-	*value = NULL;
-	if (*statement != NULL) {
-	  g_object_unref (*statement);
-	  *statement = NULL;
-	}
-	return FAIL (TOKEN_BRACKET_RIGHT);
-      }
-    } else if (check_token (data, TOKEN_DOT)) {
-      status = parse_identifier (data, &member);
-      if (status != STATUS_OK)
-	return FAIL_CHILD (status);
-    } else {
-      return STATUS_OK;
-    }
-
-    tmp = *value;
-    *value = vivi_compiler_get_new (tmp, member);
-    g_object_unref (tmp);
-    g_object_unref (member);
-  } while (TRUE);
-
-  g_assert_not_reached ();
-}
-
-static ParseStatus
-parse_new_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
-{
-  ParseStatus status;
-
-  *value = NULL;
-  *statement = NULL;
-
-  if (check_token (data, TOKEN_NEW)) {
-    status = parse_new_expression (data, value, statement);
-    if (status != STATUS_OK)
-      return FAIL_CHILD (status);
-    if (!VIVI_IS_CODE_FUNCTION_CALL (*value)) {
-      ViviCodeValue *tmp = VIVI_CODE_VALUE (*value);
-      *value = vivi_compiler_function_call_new (tmp);
-      g_object_unref (tmp);
-    }
-    vivi_code_function_call_set_construct (VIVI_CODE_FUNCTION_CALL (*value),
-	TRUE);
-    return STATUS_OK;
-  } else {
-    return parse_member_expression (data, value, statement);
-  }
-}
-
-static ParseStatus
-parse_left_hand_side_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
-{
-  ParseStatus status;
-  int i;
-  ViviCodeValue *name;
-  ViviCodeValue **arguments;
-  ViviCodeStatement *argument_statement;
-
-  *value = NULL;
-  *statement = NULL;
-
-  if (check_token (data, TOKEN_NEW)) {
-    status = parse_new_expression (data, value, statement);
-    if (status != STATUS_OK)
-      return FAIL_CHILD (status);
-    if (!VIVI_IS_CODE_FUNCTION_CALL (*value)) {
-      ViviCodeValue *tmp = VIVI_CODE_VALUE (*value);
-      *value = vivi_compiler_function_call_new (tmp);
-      g_object_unref (tmp);
-    }
-    vivi_code_function_call_set_construct (VIVI_CODE_FUNCTION_CALL (*value),
-	TRUE);
-    return STATUS_OK;
-  }
-
-  status = parse_member_expression (data, value, statement);
-  if (status != STATUS_OK)
-    return status;
-
-  while (TRUE) {
-    // TODO: member expressions?
-    if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
-      break;
-
-    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
-      status = parse_value_statement_list (data, parse_assignment_expression,
-	  &arguments, &argument_statement, TOKEN_COMMA);
-      if (status != STATUS_OK) {
-	g_object_unref (*value);
-	*value = NULL;
-	if (*statement != NULL) {
-	  g_object_unref (*statement);
-	  *statement = NULL;
-	}
-	return FAIL_CHILD (status);
-      }
-
-      *statement =
-	vivi_compiler_join_statements (*statement, argument_statement);
-
-      if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
-	g_object_unref (*value);
-	*value = NULL;
-	if (*statement != NULL) {
-	  g_object_unref (*statement);
-	  *statement = NULL;
-	}
-	return FAIL (TOKEN_PARENTHESIS_RIGHT);
-      }
-    } else {
-      arguments = NULL;
-    }
-
-    name = *value;
-    *value = vivi_compiler_function_call_new (name);
-    g_object_unref (name);
-
-    if (arguments != NULL) {
-      for (i = 0; arguments[i] != NULL; i++) {
-	vivi_code_function_call_add_argument (VIVI_CODE_FUNCTION_CALL (*value),
-	    arguments[i]);
-      }
-      free_value_list (arguments);
-    }
-  }
-
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_postfix_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
-{
-  ParseStatus status;
-  ViviCodeValue *operation, *one, *temporary;
-  const char *operator;
-
-  *value = NULL;
-  *statement = NULL;
-
-  status = parse_left_hand_side_expression (data, value, statement);
-  if (status != STATUS_OK)
-    return status;
-
-  if (check_line_terminator (data))
-    return status;
-
-  if (check_token (data, TOKEN_INCREASE)) {
-    operator = "+";
-  } else if (check_token (data, TOKEN_DESCREASE)) {
-    operator = "-";
-  } else {
-    return STATUS_OK;
-  }
-
-  if (!vivi_compiler_value_is_left_hand_side (*value)) {
-    g_object_unref (*value);
-    *value = NULL;
-    if (*statement != NULL) {
-      g_object_unref (*statement);
-      *statement = NULL;
-    }
-    return CANCEL_CUSTOM (g_strdup ("INCREASE/DECREASE not allowed here"));
-  }
-
-  one = vivi_code_constant_new_number (1);
-  operation = vivi_code_binary_new_name (*value, one, operator);
-  g_object_unref (one);
-
-  temporary = vivi_compiler_get_temporary_new ();
-  *statement = vivi_compiler_join_statements (*statement,
-      vivi_compiler_join_statements (
-	vivi_compiler_assignment_new (temporary, *value),
-	vivi_compiler_assignment_new (*value, operation)));
-  g_object_unref (operation);
-
-  g_object_unref (*value);
-  *value = temporary;
-
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_unary_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
-{
-  ParseStatus status;
-  ViviCodeValue *tmp, *one;
-  const char *operator;
-
-  *value = NULL;
-
-  operator = NULL;
-
-  vivi_compiler_scanner_peek_next_token (data->scanner);
-  switch ((guint)data->scanner->next_token) {
-    /*case TOKEN_DELETE:
-    case TOKEN_VOID:
-    case TOKEN_TYPEOF:*/
-    case TOKEN_INCREASE:
-      operator = "+";
-      // fall through
-    case TOKEN_DESCREASE:
-      if (!operator) operator = "-";
-
-      vivi_compiler_scanner_get_next_token (data->scanner);
-      status = parse_unary_expression (data, value, statement);
-      if (status != STATUS_OK)
-	return FAIL_CHILD (status);
-
-      if (!vivi_compiler_value_is_left_hand_side (*value))
-	return CANCEL_CUSTOM (g_strdup ("INCREASE/DECREASE not allowed here"));
-
-      one = vivi_code_constant_new_number (1);
-      tmp = vivi_code_binary_new_name (*value, one, operator);
-      g_object_unref (one);
-
-      *statement = vivi_compiler_join_statements (*statement,
-	  vivi_compiler_assignment_new (*value, tmp));
-      g_object_unref (tmp);
-
-      return STATUS_OK;
-    /*case TOKEN_PLUS:
-    case TOKEN_MINUS:
-    case TOKEN_BITWISE_NOT:*/
-    case TOKEN_LOGICAL_NOT:
-      vivi_compiler_scanner_get_next_token (data->scanner);
-      status = parse_unary_expression (data, value, statement);
-      if (status != STATUS_OK)
-	return FAIL_CHILD (status);
-      tmp = VIVI_CODE_VALUE (*value);
-      *value = vivi_code_unary_new (tmp, '!');
-      g_object_unref (tmp);
-      return STATUS_OK;
-    default:
-      return parse_postfix_expression (data, value, statement);
-  }
-}
-
-typedef enum {
-  PASS_ALWAYS,
-  PASS_LOGICAL_OR,
-  PASS_LOGICAL_AND
-} ParseOperatorPass;
-
-static ParseStatus
-parse_operator_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement, const ViviCompilerScannerToken *tokens,
-    ParseOperatorPass pass, ParseValueStatementFunction next_parse_function)
-{
-  ParseStatus status;
-  int i;
-  ViviCodeValue *left, *right;
-  ViviCodeStatement *statement_right;
-
-  *value = NULL;
-  *statement = NULL;
-
-  status = next_parse_function (data, value, statement);
-  if (status != STATUS_OK)
-    return status;
-
-  for (i = 0; tokens[i] != STATUS_OK; i++) {
-    while (check_token (data, tokens[i])) {
-      status = next_parse_function (data, &right, &statement_right);
-      if (status != STATUS_OK) {
-	g_object_unref (*value);
-	*value = NULL;
-	return FAIL_CHILD (status);
-      }
-
-      if (statement_right != NULL) {
-	ViviCodeStatement *tmp;
-
-	switch (pass) {
-	  case PASS_LOGICAL_OR:
-	    tmp = vivi_code_if_new (vivi_code_unary_new (*value, '!'));
-	    vivi_code_if_set_if (VIVI_CODE_IF (tmp), statement_right);
-	    g_object_unref (statement_right);
-	    statement_right = tmp;
-	    break;
-	  case PASS_LOGICAL_AND:
-	    tmp = vivi_code_if_new (*value);
-	    vivi_code_if_set_if (VIVI_CODE_IF (tmp), statement_right);
-	    g_object_unref (statement_right);
-	    statement_right = tmp;
-	    break;
-	  case PASS_ALWAYS:
-	    // nothing
-	    break;
-	  default:
-	    g_assert_not_reached ();
-	}
-
-	*statement =
-	  vivi_compiler_join_statements (*statement, statement_right);
-      }
-
-      left = VIVI_CODE_VALUE (*value);
-      *value = vivi_code_binary_new_name (left, VIVI_CODE_VALUE (right),
-	  vivi_compiler_scanner_token_name (tokens[i]));
-      g_object_unref (left);
-      g_object_unref (right);
-    };
-  }
-
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_multiplicative_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
-{
-  static const ViviCompilerScannerToken tokens[] = { TOKEN_MULTIPLY,
-    TOKEN_DIVIDE, TOKEN_REMAINDER, TOKEN_NONE };
-
-  return parse_operator_expression (data, value, statement, tokens,
-      PASS_ALWAYS, parse_unary_expression);
-}
-
-static ParseStatus
-parse_additive_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
-{
-  static const ViviCompilerScannerToken tokens[] = { TOKEN_PLUS, TOKEN_MINUS,
-    TOKEN_NONE };
-
-  return parse_operator_expression (data, value, statement, tokens,
-      PASS_ALWAYS, parse_multiplicative_expression);
-}
-
-static ParseStatus
-parse_shift_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
-{
-  static const ViviCompilerScannerToken tokens[] = { TOKEN_SHIFT_LEFT,
-    TOKEN_SHIFT_RIGHT, TOKEN_SHIFT_RIGHT_UNSIGNED, TOKEN_NONE };
-
-  return parse_operator_expression (data, value, statement, tokens,
-      PASS_ALWAYS, parse_additive_expression);
-}
-
-static ParseStatus
-parse_relational_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
-{
-  static const ViviCompilerScannerToken tokens[] = { TOKEN_LESS_THAN,
-    TOKEN_GREATER_THAN, /*TOKEN_LESS_THAN_OR_EQUAL,
-    TOKEN_EQUAL_OR_GREATER_THAN, TOKEN_INSTANCEOF, TOKEN_IN,*/ TOKEN_NONE };
-
-  return parse_operator_expression (data, value, statement, tokens,
-      PASS_ALWAYS, parse_shift_expression);
-}
-
-static ParseStatus
-parse_equality_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
-{
-  static const ViviCompilerScannerToken tokens[] = { TOKEN_EQUAL,
-    /*TOKEN_NOT_EQUAL,*/ TOKEN_STRICT_EQUAL, /*TOKEN_NOT_STRICT_EQUAL,*/
-    TOKEN_NONE };
-
-  return parse_operator_expression (data, value, statement, tokens,
-      PASS_ALWAYS, parse_relational_expression);
-}
-
-static ParseStatus
-parse_bitwise_and_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
-{
-  static const ViviCompilerScannerToken tokens[] = { TOKEN_BITWISE_AND,
-    TOKEN_NONE };
-
-  return parse_operator_expression (data, value, statement, tokens,
-      PASS_ALWAYS, parse_equality_expression);
-}
-
-static ParseStatus
-parse_bitwise_xor_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
-{
-  static const ViviCompilerScannerToken tokens[] = { TOKEN_BITWISE_XOR,
-    TOKEN_NONE };
-
-  return parse_operator_expression (data, value, statement, tokens,
-      PASS_ALWAYS, parse_bitwise_and_expression);
-}
-
-static ParseStatus
-parse_bitwise_or_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
-{
-  static const ViviCompilerScannerToken tokens[] = { TOKEN_BITWISE_OR,
-    TOKEN_NONE };
-
-  return parse_operator_expression (data, value, statement, tokens,
-      PASS_ALWAYS, parse_bitwise_xor_expression);
-}
-
-static ParseStatus
-parse_logical_and_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
-{
-  static const ViviCompilerScannerToken tokens[] = { TOKEN_LOGICAL_AND,
-    TOKEN_NONE };
-
-  return parse_operator_expression (data, value, statement, tokens,
-      PASS_LOGICAL_AND, parse_bitwise_or_expression);
-}
-
-static ParseStatus
-parse_logical_or_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
-{
-  static const ViviCompilerScannerToken tokens[] = { TOKEN_LOGICAL_OR,
-    TOKEN_NONE };
-
-  return parse_operator_expression (data, value, statement, tokens,
-      PASS_LOGICAL_OR, parse_logical_and_expression);
-}
-
-static ParseStatus
-parse_conditional_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
-{
-  ParseStatus status;
-  //ViviCodeStatement *if_statement, *else_statement;
-
-  *value = NULL;
-
-  status = parse_logical_or_expression (data, value, statement);
-  if (status != STATUS_OK)
-    return status;
-
-#if 0
-  if (!check_token (data, TOKEN_QUESTION_MARK)) {
-    *statement = vivi_code_value_statement_new (VIVI_CODE_VALUE (value));
-    g_object_unref (value);
-    return STATUS_OK;
-  }
-
-  status = parse_assignment_expression (data, &if_statement);
-  if (status != STATUS_OK) {
-    g_object_unref (value);
-    return FAIL_CHILD (status);
-  }
-
-  if (!check_token (data, TOKEN_COLON)) {
-    g_object_unref (value);
-    g_object_unref (if_statement);
-    return TOKEN_COLON;
-  }
-
-  status = parse_assignment_expression (data, &else_statement);
-  if (status != STATUS_OK) {
-    g_object_unref (value);
-    g_object_unref (if_statement);
-    return FAIL_CHILD (status);
-  }
-
-  *statement = vivi_code_if_new (value);
-  vivi_code_if_set_if (VIVI_CODE_IF (*statement), if_statement);
-  vivi_code_if_set_else (VIVI_CODE_IF (*statement), else_statement);
-
-  g_object_unref (value);
-  g_object_unref (if_statement);
-  g_object_unref (else_statement);
-#endif
-
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_assignment_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
-{
-  ParseStatus status;
-  ViviCodeValue *right;
-  ViviCodeStatement *assignment, *statement_right;
-  const char *operator;
-
-  *value = NULL;
-  *statement = NULL;
-
-  status = parse_conditional_expression (data, value, statement);
-  if (status != STATUS_OK)
-    return status;
-
-  if (!vivi_compiler_value_is_left_hand_side (*value))
-    return STATUS_OK;
-
-  operator = NULL;
-
-  vivi_compiler_scanner_peek_next_token (data->scanner);
-  switch ((int)data->scanner->next_token) {
-    case TOKEN_ASSIGN_MULTIPLY:
-      if (operator == NULL) operator = "*";
-    case TOKEN_ASSIGN_DIVIDE:
-      if (operator == NULL) operator = "/";
-    case TOKEN_ASSIGN_REMAINDER:
-      if (operator == NULL) operator = "%";
-    case TOKEN_ASSIGN_ADD:
-      if (operator == NULL) operator = "+";
-    case TOKEN_ASSIGN_MINUS:
-      if (operator == NULL) operator = "-";
-    case TOKEN_ASSIGN_SHIFT_LEFT:
-      if (operator == NULL) operator = "<<";
-    case TOKEN_ASSIGN_SHIFT_RIGHT:
-      if (operator == NULL) operator = ">>";
-    case TOKEN_ASSIGN_SHIFT_RIGHT_ZERO:
-      if (operator == NULL) operator = ">>>";
-    case TOKEN_ASSIGN_BITWISE_AND:
-      if (operator == NULL) operator = "&";
-    case TOKEN_ASSIGN_BITWISE_OR:
-      if (operator == NULL) operator = "|";
-    case TOKEN_ASSIGN_BITWISE_XOR:
-      if (operator == NULL) operator = "^";
-    case TOKEN_ASSIGN:
-      vivi_compiler_scanner_get_next_token (data->scanner);
-      status = parse_assignment_expression (data, &right,
-	  &statement_right);
-      if (status != STATUS_OK) {
-	g_object_unref (*value);
-	*value = NULL;
-	return FAIL_CHILD (status);
-      }
-
-      if (operator != NULL) {
-	assignment = vivi_compiler_assignment_new (*value,
-	    vivi_code_binary_new_name (*value, right, operator));
-      } else {
-	assignment = vivi_compiler_assignment_new (*value, right);
-      }
-      g_object_unref (right);
-
-      *statement = vivi_compiler_join_statements (*statement,
-	  vivi_compiler_join_statements (statement_right, assignment));
-
-      break;
-    default:
-      return STATUS_OK;
-  }
-
-
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
-{
-  ViviCodeStatement *statement_one;
-  ParseStatus status;
-
-  *statement = NULL;
-
-  status = parse_assignment_expression (data, value, &statement_one);
-  if (status != STATUS_OK)
-    return status;
-
-  while (TRUE) {
-    *statement = vivi_compiler_join_statements (*statement, statement_one);
-
-    if (!check_token (data, TOKEN_COMMA))
-      break;
-
-    g_object_unref (*value);
-
-    status = parse_assignment_expression (data, value, &statement_one);
-    if (status != STATUS_OK) {
-      g_object_unref (*value);
-      *value = NULL;
-      g_object_unref (*statement);
-      *statement = NULL;
-      return FAIL_CHILD (status);
-    }
-  }
-
-  return STATUS_OK;
-}
-
-// statement
-
-static ParseStatus
-parse_statement (ParseData *data, ViviCodeStatement **statement);
-
-static ParseStatus
-parse_trace_statement (ParseData *data, ViviCodeStatement **statement)
-{
-  ViviCodeValue *value;
-  ViviCodeStatement *expression_statement;
-  ParseStatus status;
-
-  *statement = NULL;
-
-  if (!check_token (data, TOKEN_TRACE))
-    return CANCEL (TOKEN_TRACE);
-
-  if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
-    return FAIL (TOKEN_PARENTHESIS_LEFT);
-
-  status = parse_expression (data, &value, &expression_statement);
-  if (status != STATUS_OK)
-    return FAIL_CHILD (status);
-
-  if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
-    g_object_unref (value);
-    if (expression_statement != NULL)
-      g_object_unref (expression_statement);
-    return FAIL (TOKEN_PARENTHESIS_RIGHT);
-  }
-
-  if (!check_automatic_semicolon (data)) {
-    g_object_unref (value);
-    if (expression_statement != NULL)
-      g_object_unref (expression_statement);
-    return FAIL (TOKEN_SEMICOLON);
-  }
-
-  *statement = vivi_code_trace_new (value);
-  g_object_unref (value);
-
-  *statement =
-    vivi_compiler_join_statements (expression_statement, *statement);
-
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_continue_or_break_statement (ParseData *data,
-    ViviCodeStatement **statement, ViviCompilerScannerToken token)
-{
-  *statement = NULL;
-
-  if (!check_token (data, token))
-    return CANCEL (token);
-
-  if (!check_restricted_semicolon (data)) {
-    ParseStatus status;
-    ViviCodeValue *identifier;
-
-    status = parse_identifier (data, &identifier);
-    *statement = vivi_compiler_goto_name_new (
-	vivi_code_constant_get_variable_name (
-	  VIVI_CODE_CONSTANT (VIVI_CODE_GET (identifier)->name)));
-    g_object_unref (identifier);
-
-    vivi_compiler_add_goto (data, VIVI_COMPILER_GOTO_NAME (*statement));
-
-    if (!check_automatic_semicolon (data)) {
-      g_object_unref (*statement);
-      *statement = NULL;
-      return FAIL (TOKEN_SEMICOLON);
-    }
-  } else {
-    *statement = vivi_code_break_new ();
-  }
-
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_continue_statement (ParseData *data, ViviCodeStatement **statement)
-{
-  return parse_continue_or_break_statement (data, statement, TOKEN_CONTINUE);
-}
-
-static ParseStatus
-parse_break_statement (ParseData *data, ViviCodeStatement **statement)
-{
-  return parse_continue_or_break_statement (data, statement, TOKEN_BREAK);
-}
-
-static ParseStatus
-parse_throw_statement (ParseData *data, ViviCodeStatement **statement)
-{
-  ParseStatus status;
-  ViviCodeValue *value;
-  ViviCodeStatement *expression_statement;
-
-  *statement = NULL;
-
-  if (!check_token (data, TOKEN_THROW))
-    return CANCEL (TOKEN_THROW);
-
-  if (check_line_terminator (data))
-    return FAIL_LINE_TERMINATOR (ERROR_TOKEN_EXPRESSION);
-
-  status = parse_expression (data, &value, &expression_statement);
-  if (status != STATUS_OK)
-    return FAIL_CHILD (status);
-
-  *statement = vivi_code_throw_new (value);
-  g_object_unref (value);
-
-  *statement =
-    vivi_compiler_join_statements (expression_statement, *statement);
-
-  if (!check_automatic_semicolon (data)) {
-    g_object_unref (*statement);
-    *statement = NULL;
-    return FAIL (TOKEN_SEMICOLON);
-  }
-
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_return_statement (ParseData *data, ViviCodeStatement **statement)
-{
-  *statement = NULL;
-
-  if (!check_token (data, TOKEN_RETURN))
-    return CANCEL (TOKEN_RETURN);
-
-  *statement = vivi_code_return_new ();
-
-  if (!check_restricted_semicolon (data)) {
-    ParseStatus status;
-    ViviCodeValue *value;
-    ViviCodeStatement *expression_statement;
-
-    status = parse_expression (data, &value, &expression_statement);
-    if (status != STATUS_OK) {
-      g_object_unref (*statement);
-      *statement = NULL;
-      return FAIL_CHILD (status);
-    }
-
-    vivi_code_return_set_value (VIVI_CODE_RETURN (*statement), value);
-    g_object_unref (value);
-
-    *statement =
-      vivi_compiler_join_statements (expression_statement, *statement);
-
-    if (!check_automatic_semicolon (data)) {
-      g_object_unref (*statement);
-      *statement = NULL;
-      return FAIL (TOKEN_SEMICOLON);
-    }
-  }
-
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
-{
-  ParseStatus status;
-  ViviCodeValue *condition;
-  ViviCodeStatement *pre_statement, *condition_statement, *loop_statement;
-
-  *statement = NULL;
-
-  pre_statement = NULL;
-  condition_statement = NULL;
-
-  if (check_token (data, TOKEN_DO)) {
-    status = parse_statement (data, &loop_statement);
-    if (status != STATUS_OK)
-      return FAIL_CHILD (status);
-
-    if (!check_token (data, TOKEN_WHILE)) {
-      g_object_unref (loop_statement);
-      return FAIL (TOKEN_WHILE);
-    }
-
-    if (!check_token (data, TOKEN_PARENTHESIS_LEFT)) {
-      g_object_unref (loop_statement);
-      return FAIL (TOKEN_PARENTHESIS_LEFT);
-    }
-
-    status = parse_expression (data, &condition, &condition_statement);
-    if (status != STATUS_OK) {
-      g_object_unref (loop_statement);
-      return FAIL_CHILD (status);
-    }
-
-    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
-      g_object_unref (loop_statement);
-      g_object_unref (condition);
-      if (condition_statement != NULL)
-	g_object_unref (condition_statement);
-      return FAIL (TOKEN_PARENTHESIS_LEFT);
-    }
-
-    if (!check_automatic_semicolon (data)) {
-      g_object_unref (loop_statement);
-      g_object_unref (condition);
-      if (condition_statement != NULL)
-	g_object_unref (condition_statement);
-      return FAIL (TOKEN_PARENTHESIS_LEFT);
-    }
-
-    pre_statement = g_object_ref (loop_statement);
-  } else if (check_token (data, TOKEN_WHILE)) {
-    if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
-      return FAIL (TOKEN_PARENTHESIS_LEFT);
-
-    status = parse_expression (data, &condition, &condition_statement);
-    if (status != STATUS_OK)
-      return FAIL_CHILD (status);
-
-    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
-      g_object_unref (condition);
-      if (condition_statement != NULL)
-	g_object_unref (condition_statement);
-      return FAIL (TOKEN_PARENTHESIS_RIGHT);
-    }
-
-    status = parse_statement (data, &loop_statement);
-    if (status != STATUS_OK) {
-      g_object_unref (condition);
-      if (condition_statement != NULL)
-	g_object_unref (condition_statement);
-      return FAIL_CHILD (status);
-    }
-  } else if (check_token (data, TOKEN_FOR)) {
-    ViviCodeValue *pre_value;
-    ViviCodeStatement *post_statement;
-
-    if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
-      return FAIL (TOKEN_PARENTHESIS_LEFT);
-
-    if (check_token (data, TOKEN_VAR)) {
-      // FIXME: no in
-      status = parse_statement_list (data, parse_variable_declaration,
-	  &pre_statement, TOKEN_COMMA);
-      if (status != STATUS_OK)
-	return FAIL_CHILD (status);
-      // FIXME: ugly
-      // If there was only one VariableDeclaration, get the name for pre_value
-      g_assert (VIVI_IS_CODE_BLOCK (pre_statement));
-      if (vivi_code_block_get_n_statements (VIVI_CODE_BLOCK (pre_statement))
-	  == 1) {
-	ViviCodeAssignment *assignment = VIVI_CODE_ASSIGNMENT (
-	    vivi_code_block_get_statement (VIVI_CODE_BLOCK (pre_statement), 0));
-	g_assert (assignment->from == NULL);
-	pre_value = vivi_code_get_new (NULL, assignment->name);
-      } else {
-	pre_value = NULL;
-      }
-    } else {
-      if (!check_token (data, TOKEN_SEMICOLON)) {
-	// FIXME: no in
-	status = parse_expression (data, &pre_value, &pre_statement);
-	if (status != STATUS_OK)
-	  return FAIL_CHILD (status);
-      } else {
-	pre_value = NULL;
-	pre_statement = NULL;
-      }
-    }
-
-    if (check_token (data, TOKEN_SEMICOLON)) {
-      if (pre_value != NULL)
-	g_object_unref (pre_value);
-      if (!check_token (data, TOKEN_SEMICOLON)) {
-	status = parse_expression (data, &condition, &condition_statement);
-	if (status != STATUS_OK)
-	  return FAIL_CHILD (status);
-
-	if (!check_token (data, TOKEN_SEMICOLON)) {
-	  if (pre_statement != NULL)
-	    g_object_unref (pre_statement);
-	  g_object_unref (condition);
-	  if (condition_statement != NULL)
-	    g_object_unref (condition_statement);
-	  return FAIL (TOKEN_SEMICOLON);
-	}
-      }
-
-      status = parse_expression (data, &pre_value, &post_statement);
-      if (status != STATUS_OK) {
-	if (pre_statement != NULL)
-	  g_object_unref (pre_statement);
-	g_object_unref (condition);
-	if (condition_statement != NULL)
-	  g_object_unref (condition_statement);
-	return FAIL_CHILD (status);
-      }
-      g_object_unref (pre_value);
-    } else if (pre_value != NULL && check_token (data, TOKEN_IN)) {
-      post_statement = NULL;
-
-      if (!vivi_compiler_value_is_left_hand_side (pre_value)) {
-	g_object_unref (pre_value);
-	if (pre_statement != NULL)
-	  g_object_unref (pre_statement);
-	return FAIL_CUSTOM (g_strdup (
-	      "Invalid left hand side expression for in"));
-      }
-
-      g_object_unref (pre_value);
-      if (pre_statement != NULL)
-	g_object_unref (pre_statement);
-      return FAIL_CUSTOM (g_strdup (
-	    "for (... in ...) has not been implemented yet"));
-    } else {
-      ViviCompilerScannerToken fail_token;
-
-      if (pre_value != NULL) {
-	fail_token = TOKEN_IN;
-	g_object_unref (pre_value);
-      } else {
-	fail_token = TOKEN_NONE;
-      }
-
-      if (pre_statement != NULL)
-	g_object_unref (pre_statement);
-
-      return FAIL_OR (TOKEN_SEMICOLON, fail_token);
-    }
-
-    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
-      if (pre_statement != NULL)
-	g_object_unref (pre_statement);
-      g_object_unref (condition);
-      if (condition_statement != NULL)
-	g_object_unref (condition_statement);
-      g_object_unref (post_statement);
-      return FAIL (TOKEN_PARENTHESIS_RIGHT);
-    }
-
-    status = parse_statement (data, &loop_statement);
-    if (status != STATUS_OK) {
-      if (pre_statement != NULL)
-	g_object_unref (pre_statement);
-      g_object_unref (condition);
-      if (condition_statement != NULL)
-	g_object_unref (condition_statement);
-      g_object_unref (post_statement);
-      return FAIL_CHILD (status);
-    }
-
-    loop_statement =
-      vivi_compiler_join_statements (loop_statement, post_statement);
-  } else {
-    return CANCEL (ERROR_TOKEN_ITERATION_STATEMENT);
-  }
-
-  if (condition_statement != NULL) {
-    pre_statement = vivi_compiler_join_statements (pre_statement,
-	g_object_ref (condition_statement));
-    loop_statement = vivi_compiler_join_statements (loop_statement,
-	g_object_ref (condition_statement));
-    g_object_unref (condition_statement);
-  }
-
-  *statement = vivi_code_loop_new ();
-  vivi_code_loop_set_condition (VIVI_CODE_LOOP (*statement), condition);
-  g_object_unref (condition);
-  vivi_code_loop_set_statement (VIVI_CODE_LOOP (*statement), loop_statement);
-  g_object_unref (loop_statement);
-
-  *statement = vivi_compiler_join_statements (pre_statement, *statement);
-
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_if_statement (ParseData *data, ViviCodeStatement **statement)
-{
-  ParseStatus status;
-  ViviCodeValue *condition;
-  ViviCodeStatement *pre_statement, *if_statement, *else_statement;
-
-  *statement = NULL;
-
-  if (!check_token (data, TOKEN_IF))
-    return CANCEL (TOKEN_IF);
-
-  if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
-    return FAIL (TOKEN_PARENTHESIS_LEFT);
-
-  status = parse_expression (data, &condition, &pre_statement);
-  if (status != STATUS_OK)
-    return FAIL_CHILD (status);
-
-  if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
-    g_object_unref (condition);
-    if (pre_statement != NULL) {
-      g_object_unref (pre_statement);
-      pre_statement = NULL;
-    }
-    return FAIL (TOKEN_PARENTHESIS_RIGHT);
-  }
-
-  status = parse_statement (data, &if_statement);
-  if (status != STATUS_OK) {
-    g_object_unref (condition);
-    if (pre_statement != NULL) {
-      g_object_unref (pre_statement);
-      pre_statement = NULL;
-    }
-    return FAIL_CHILD (status);
-  }
-
-  if (check_token (data, TOKEN_ELSE)) {
-    status = parse_statement (data, &else_statement);
-    if (status != STATUS_OK) {
-      g_object_unref (condition);
-      if (pre_statement != NULL) {
-	g_object_unref (pre_statement);
-	pre_statement = NULL;
-      }
-      g_object_unref (if_statement);
-      return FAIL_CHILD (status);
-    }
-  } else {
-    else_statement = NULL;
-  }
-
-  *statement = vivi_code_if_new (condition);
-  g_object_unref (condition);
-
-  vivi_code_if_set_if (VIVI_CODE_IF (*statement), if_statement);
-  g_object_unref (if_statement);
-
-  if (else_statement != NULL) {
-    vivi_code_if_set_else (VIVI_CODE_IF (*statement), else_statement);
-    g_object_unref (else_statement);
-  }
-
-  *statement = vivi_compiler_join_statements (pre_statement, *statement);
-
-  g_assert (*statement != NULL);
-
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_expression_statement (ParseData *data, ViviCodeStatement **statement)
-{
-  ParseStatus status;
-  ViviCodeValue *value;
-  ViviCodeStatement *last;
-
-  *statement = NULL;
-
-  vivi_compiler_scanner_peek_next_token (data->scanner);
-  if (data->scanner->next_token == TOKEN_BRACE_LEFT ||
-      data->scanner->next_token == TOKEN_FUNCTION)
-    return CANCEL (ERROR_TOKEN_EXPRESSION_STATEMENT);
-
-  status = parse_expression (data, &value, statement);
-  if (status != STATUS_OK)
-    return status;
-
-  // check for label
-  if (*statement == NULL && vivi_compiler_value_is_identifier (value)) {
-    if (check_token (data, TOKEN_COLON)) {
-      *statement = vivi_code_label_new (vivi_code_constant_get_variable_name (
-	    VIVI_CODE_CONSTANT (VIVI_CODE_GET (value)->name)));
-      if (!vivi_compiler_add_label (data, VIVI_CODE_LABEL (*statement)))
-	return FAIL_CUSTOM (g_strdup ("Same label name used twice"));
-      return STATUS_OK;
-    }
-  }
-
-  if (!check_automatic_semicolon (data)) {
-    g_object_unref (value);
-    if (*statement != NULL) {
-      g_object_unref (*statement);
-      *statement = NULL;
-    }
-    return FAIL (TOKEN_SEMICOLON);
-  }
-
-  // add a value statement, if the last statement is not an assignment with the
-  // same value
-  if (VIVI_IS_CODE_BLOCK (*statement)) {
-    ViviCodeBlock *block = VIVI_CODE_BLOCK (*statement);
-
-    last = vivi_code_block_get_statement (block,
-	vivi_code_block_get_n_statements (block) - 1);
-  } else {
-    last = *statement;
-  }
-
-  if (VIVI_IS_CODE_ASSIGNMENT (last) && VIVI_IS_CODE_GET (value)) {
-    ViviCodeAssignment *assignment = VIVI_CODE_ASSIGNMENT (last);
-
-    if (assignment->from == NULL && assignment->name == VIVI_CODE_GET (value)->name) {
-      g_object_unref (value);
-      return STATUS_OK;
-    }
-  }
-
-  *statement = vivi_compiler_join_statements (*statement,
-      vivi_code_value_statement_new (value));
-  g_object_unref (value);
-
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_empty_statement (ParseData *data, ViviCodeStatement **statement)
-{
-  *statement = NULL;
-
-  if (!check_token (data, TOKEN_SEMICOLON))
-    return CANCEL (TOKEN_SEMICOLON);
-
-  *statement = vivi_compiler_empty_statement_new ();
-
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_block (ParseData *data, ViviCodeStatement **statement)
-{
-  ParseStatus status;
-
-  *statement = NULL;
-
-  if (!check_token (data, TOKEN_BRACE_LEFT))
-    return CANCEL (TOKEN_BRACE_LEFT);
-
-  vivi_compiler_scanner_peek_next_token (data->scanner);
-  if (data->scanner->next_token != TOKEN_BRACE_RIGHT) {
-    status =
-      parse_statement_list (data, parse_statement, statement, STATUS_OK);
-    if (status != STATUS_OK)
-      return FAIL_CHILD (status);
-  } else {
-    *statement = vivi_code_block_new ();
-  }
-
-  if (!check_token (data, TOKEN_BRACE_RIGHT)) {
-    g_object_unref (*statement);
-    *statement = NULL;
-    return FAIL (TOKEN_BRACE_RIGHT);
-  }
-
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_variable_statement (ParseData *data, ViviCodeStatement **statement)
-{
-  ParseStatus status;
-
-  *statement = NULL;
-
-  if (!check_token (data, TOKEN_VAR))
-    return CANCEL (TOKEN_VAR);
-
-  status = parse_statement_list (data, parse_variable_declaration, statement,
-      TOKEN_COMMA);
-  if (status != STATUS_OK)
-    return FAIL_CHILD (status);
-
-  if (!check_automatic_semicolon (data)) {
-    g_object_unref (*statement);
-    *statement = NULL;
-    return FAIL (TOKEN_SEMICOLON);
-  }
-
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_statement (ParseData *data, ViviCodeStatement **statement)
-{
-  ParseStatus status;
-  int i;
-  ParseStatementFunction functions[] = {
-    parse_block,
-    parse_variable_statement,
-    parse_empty_statement,
-    parse_expression_statement,
-    parse_if_statement,
-    parse_iteration_statement,
-    parse_continue_statement,
-    parse_break_statement,
-    parse_return_statement,
-    //parse_with_statement,
-    //parse_switch_statement,
-    parse_throw_statement,
-    //parse_try_statement,
-    parse_trace_statement,
-    NULL
-  };
-
-  *statement = NULL;
-
-  for (i = 0; functions[i] != NULL; i++) {
-    status = functions[i] (data, statement);
-    if (status != STATUS_CANCEL)
-      return status;
-  }
-
-  return CANCEL (ERROR_TOKEN_STATEMENT);
-}
-
-// function
-
-static ParseStatus
-parse_source_element (ParseData *data, ViviCodeStatement **statement);
-
-static ParseStatus
-parse_function_definition (ParseData *data, ViviCodeValue **function,
-    ViviCodeValue **identifier, gboolean identifier_required)
-{
-  ParseStatus status;
-  ViviCodeValue **arguments;
-  ViviCodeStatement *body;
-  guint i;
-
-  *function = NULL;
-  *identifier = NULL;
-
-  arguments = NULL;
-  body = NULL;
-
-  if (!check_token (data, TOKEN_FUNCTION))
-    return CANCEL (TOKEN_FUNCTION);
-
-  status = parse_identifier (data, identifier);
-  if (status == STATUS_FAIL ||
-      (identifier_required && status == STATUS_CANCEL))
-    return FAIL_CHILD (status);
-
-  if (!check_token (data, TOKEN_PARENTHESIS_LEFT)) {
-    g_object_unref (*identifier);
-    return FAIL (TOKEN_PARENTHESIS_LEFT);
-  }
-
-  status = parse_value_list (data, parse_identifier, &arguments, TOKEN_COMMA);
-  if (status == STATUS_FAIL) {
-    g_object_unref (*identifier);
-    return STATUS_FAIL;
-  }
-
-  if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
-    g_object_unref (*identifier);
-    if (arguments != NULL)
-      free_value_list (arguments);
-    return FAIL (TOKEN_PARENTHESIS_RIGHT);
-  }
-
-  if (!check_token (data, TOKEN_BRACE_LEFT)) {
-    g_object_unref (*identifier);
-    if (arguments != NULL)
-      free_value_list (arguments);
-    return FAIL (TOKEN_BRACE_LEFT);
-  }
-
-  vivi_compiler_start_level (data);
-
-  status = parse_statement_list (data, parse_source_element, &body, STATUS_OK);
-  if (status == STATUS_FAIL) {
-    vivi_compiler_end_level (data, FALSE);
-    g_object_unref (*identifier);
-    if (arguments != NULL)
-      free_value_list (arguments);
-    return STATUS_FAIL;
-  }
-
-  status = vivi_compiler_end_level (data, TRUE);
-  if (status != STATUS_OK) {
-    g_object_unref (*identifier);
-    if (arguments != NULL)
-      free_value_list (arguments);
-    return FAIL_CHILD (status);
-  }
-
-  if (!check_token (data, TOKEN_BRACE_RIGHT)) {
-    g_object_unref (*identifier);
-    if (arguments != NULL)
-      free_value_list (arguments);
-    g_object_unref (body);
-    return FAIL (TOKEN_BRACE_RIGHT);
-  }
-
-  *function = vivi_code_function_new ();
-  if (body != NULL) {
-    vivi_code_function_set_body (VIVI_CODE_FUNCTION (*function), body);
-    g_object_unref (body);
-  }
-  if (arguments != NULL) {
-    for (i = 0; arguments[i] != NULL; i++) {
-      vivi_code_function_add_argument (VIVI_CODE_FUNCTION (*function),
-	  vivi_code_constant_get_variable_name (VIVI_CODE_CONSTANT (
-	      VIVI_CODE_GET (arguments[i])->name)));
-    }
-    free_value_list (arguments);
-  }
-
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_function_declaration (ParseData *data, ViviCodeStatement **statement)
-{
-  ParseStatus status;
-  ViviCodeValue *function, *identifier;
-
-  *statement = NULL;
-
-  status = parse_function_definition (data, &function, &identifier, TRUE);
-  if (status != STATUS_OK)
-    return status;
-
-  *statement = vivi_compiler_assignment_new (identifier, function);
-  g_object_unref (identifier);
-  g_object_unref (function);
-
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_function_expression (ParseData *data, ViviCodeValue **value,
-    ViviCodeStatement **statement)
-{
-  ParseStatus status;
-  ViviCodeValue *identifier;
-
-  *statement = NULL;
-
-  status = parse_function_definition (data, value, &identifier, FALSE);
-  if (status != STATUS_OK)
-    return status;
-
-  if (identifier != NULL) {
-    *statement = vivi_compiler_assignment_new (identifier, *value);
-    g_object_unref (identifier);
-  }
-
-  return STATUS_OK;
-}
-
-// top
-
-static ParseStatus
-parse_source_element (ParseData *data, ViviCodeStatement **statement)
-{
-  ParseStatus status;
-
-  *statement = NULL;
-
-  status = parse_function_declaration (data, statement);
-  if (status == STATUS_CANCEL)
-    status = parse_statement (data, statement);
-
-  return status;
-}
-
-static ParseStatus
-parse_program (ParseData *data, ViviCodeStatement **statement)
-{
-  ParseStatus status;
-
-  g_assert (data->level == NULL);
-  vivi_compiler_start_level (data);
-
-  *statement = NULL;
-
-  status =
-    parse_statement_list (data, parse_source_element, statement, STATUS_OK);
-  if (status != STATUS_OK) {
-    vivi_compiler_end_level (data, FALSE);
-    return FAIL_CHILD (status);
-  }
-
-  if (!check_token (data, TOKEN_EOF)) {
-    vivi_compiler_end_level (data, FALSE);
-    g_object_unref (*statement);
-    *statement = NULL;
-    status = parse_statement (data, statement);
-    return FAIL_CHILD (status);
-  }
-
-
-  status = vivi_compiler_end_level (data, TRUE);
-  if (status != STATUS_OK) {
-    g_object_unref (*statement);
-    *statement = NULL;
-    return FAIL_CHILD (status);
-  }
-
-  g_assert (data->level == NULL);
-
-  return STATUS_OK;
-}
-
-// parsing
-
-static ParseStatus
-parse_statement_list (ParseData *data, ParseStatementFunction function,
-    ViviCodeStatement **block, guint separator)
-{
-  ViviCodeStatement *statement;
-  ParseStatus status;
-
-  g_assert (data != NULL);
-  g_assert (function != NULL);
-  g_assert (block != NULL);
-
-  *block = NULL;
-
-  status = function (data, &statement);
-  if (status != STATUS_OK)
-    return status;
-
-  *block = vivi_code_block_new ();
-
-  do {
-    vivi_code_block_add_statement (VIVI_CODE_BLOCK (*block), statement);
-    g_object_unref (statement);
-
-    if (separator != STATUS_OK && !check_token (data, separator))
-      break;
-
-    status = function (data, &statement);
-    if (status == STATUS_FAIL) {
-      g_object_unref (*block);
-      *block = NULL;
-      return STATUS_FAIL;
-    }
-  } while (status == STATUS_OK);
-
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_value_statement_list (ParseData *data,
-    ParseValueStatementFunction function, ViviCodeValue ***list,
-    ViviCodeStatement **statement, guint separator)
-{
-  GPtrArray *array;
-  ViviCodeValue *value;
-  ViviCodeStatement *statement_one;
-  ParseStatus status;
-
-  g_assert (data != NULL);
-  g_assert (function != NULL);
-  g_assert (list != NULL);
-  g_assert (statement != NULL);
-
-  *list = NULL;
-  *statement = NULL;
-
-  status = function (data, &value, statement);
-  if (status != STATUS_OK)
-    return status;
-
-  array = g_ptr_array_new ();
-
-  do {
-    g_ptr_array_add (array, value);
-
-    if (separator != TOKEN_NONE && !check_token (data, separator))
-      break;
-
-    status = function (data, &value, &statement_one);
-    if (status != STATUS_OK) {
-      if (status == STATUS_FAIL || separator != TOKEN_NONE)
-	return FAIL_CHILD (status);
-    } else {
-      *statement = vivi_compiler_join_statements (*statement, statement_one);
-    }
-  } while (status == STATUS_OK);
-  g_ptr_array_add (array, NULL);
-
-  *list = (ViviCodeValue **)g_ptr_array_free (array, FALSE);
-
-  return STATUS_OK;
-}
-
-static ParseStatus
-parse_value_list (ParseData *data, ParseValueFunction function,
-    ViviCodeValue ***list, guint separator)
-{
-  GPtrArray *array;
-  ViviCodeValue *value;
-  ParseStatus status;
-
-  g_assert (data != NULL);
-  g_assert (function != NULL);
-  g_assert (list != NULL);
-
-  *list = NULL;
-
-  status = function (data, &value);
-  if (status != STATUS_OK)
-    return status;
-
-  array = g_ptr_array_new ();
-
-  do {
-    g_ptr_array_add (array, value);
-
-    if (separator != STATUS_OK && !check_token (data, separator))
-      break;
-
-    status = function (data, &value);
-    if (status == STATUS_FAIL)
-      return STATUS_FAIL;
-  } while (status == STATUS_OK);
-  g_ptr_array_add (array, NULL);
-
-  *list = (ViviCodeValue **)g_ptr_array_free (array, FALSE);
-
-  return STATUS_OK;
-}
-
-// public
-
-ViviCodeStatement *
-vivi_compile_file (FILE *file, const char *input_name)
-{
-  ParseData data;
-  ViviCodeStatement *statement;
-  ParseStatus status;
-
-  g_return_val_if_fail (file != NULL, NULL);
-
-  data.scanner = vivi_compiler_scanner_new (file);
-  data.unexpected_line_terminator = FALSE;
-  data.expected[0] = TOKEN_NONE;
-  data.expected[1] = TOKEN_NONE;
-  data.custom_error = NULL;
-  data.levels = NULL;
-  data.level = NULL;
-
-  status = parse_program (&data, &statement);
-  g_assert ((status == STATUS_OK && VIVI_IS_CODE_STATEMENT (statement)) ||
-	(status != STATUS_OK && statement == NULL));
-  g_assert (status >= 0);
-
-  if (status != STATUS_OK) {
-    g_printerr ("%s:%i:%i: error: ", input_name,
-	vivi_compiler_scanner_cur_line (data.scanner),
-	vivi_compiler_scanner_cur_column (data.scanner));
-
-    if (data.custom_error != NULL) {
-      g_printerr ("%s\n", data.custom_error);
-      g_free (data.custom_error);
-    } else {
-      vivi_compiler_scanner_get_next_token (data.scanner);
-
-      g_printerr ("Expected %s ", vivi_compiler_token_name (data.expected[0]));
-      if (data.expected[1] != TOKEN_NONE)
-	g_printerr ("or %s ", vivi_compiler_token_name (data.expected[1]));
-
-      if (data.unexpected_line_terminator) {
-	g_printerr ("before %s token\n",
-	    vivi_compiler_token_name (TOKEN_LINE_TERMINATOR));
-      } else {
-	g_printerr ("before %s token\n",
-	    vivi_compiler_token_name (data.scanner->token));
-      }
-    }
-  }
-
-  g_object_unref (data.scanner);
-
-  return statement;
-}
diff --git a/vivified/code/vivi_compiler.h b/vivified/code/vivi_compiler.h
deleted file mode 100644
index 4a8529b..0000000
--- a/vivified/code/vivi_compiler.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* Vivified
- * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 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
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifndef _VIVI_DECOMPILER_H_
-#define _VIVI_DECOMPILER_H_
-
-#include <stdio.h>
-
-#include <swfdec/swfdec.h>
-#include <vivified/code/vivi_code_statement.h>
-
-G_BEGIN_DECLS
-
-
-ViviCodeStatement *	vivi_compile_file		(FILE *		file,
-							 const char *	input_name);
-
-
-G_END_DECLS
-#endif
diff --git a/vivified/code/vivi_compiler_scanner.c b/vivified/code/vivi_compiler_scanner.c
deleted file mode 100644
index fd5c378..0000000
--- a/vivified/code/vivi_compiler_scanner.c
+++ /dev/null
@@ -1,310 +0,0 @@
-/* Vivified
- * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 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
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "vivi_compiler_scanner.h"
-
-#include "vivi_compiler_scanner_lex.h"
-#include "vivi_compiler_scanner_lex_include.h"
-
-G_DEFINE_TYPE (ViviCompilerScanner, vivi_compiler_scanner, G_TYPE_OBJECT)
-
-static void
-vivi_compiler_scanner_free_type_value (ViviCompilerScannerValue *value)
-{
-  switch (value->type) {
-    case VALUE_TYPE_STRING:
-      g_free (value->v_string);
-      break;
-    case VALUE_TYPE_IDENTIFIER:
-      g_free (value->v_identifier);
-      break;
-    case VALUE_TYPE_NONE:
-    case VALUE_TYPE_BOOLEAN:
-    case VALUE_TYPE_NUMBER:
-      /* nothing */
-      break;
-    default:
-      g_assert_not_reached ();
-      break;
-  }
-
-  value->type = VALUE_TYPE_NONE;
-}
-
-static void
-vivi_compiler_scanner_dispose (GObject *object)
-{
-  ViviCompilerScanner *scanner = VIVI_COMPILER_SCANNER (object);
-
-  vivi_compiler_scanner_free_type_value (&scanner->value);
-  vivi_compiler_scanner_free_type_value (&scanner->next_value);
-
-  G_OBJECT_CLASS (vivi_compiler_scanner_parent_class)->dispose (object);
-}
-
-static void
-vivi_compiler_scanner_class_init (ViviCompilerScannerClass *klass)
-{
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-  object_class->dispose = vivi_compiler_scanner_dispose;
-}
-
-static void
-vivi_compiler_scanner_init (ViviCompilerScanner *token)
-{
-}
-
-static const struct {
-  ViviCompilerScannerToken	token;
-  const char *			name;
-} token_names[] = {
-  // special
-  { TOKEN_NONE, "NONE" },
-  { TOKEN_EOF, "EOF" },
-  { TOKEN_ERROR, "ERROR" },
-  { TOKEN_UNKNOWN, "UNKNOWN" },
-  { TOKEN_LINE_TERMINATOR, "NEW LINE" },
-
-  // comparision
-  { TOKEN_BRACE_LEFT, "{", },
-  { TOKEN_BRACE_RIGHT, "}", },
-  { TOKEN_BRACKET_LEFT, "[", },
-  { TOKEN_BRACKET_RIGHT, "]", },
-  { TOKEN_PARENTHESIS_LEFT, "(", },
-  { TOKEN_PARENTHESIS_RIGHT, ")", },
-
-  // punctuation
-  { TOKEN_DOT, ".", },
-  { TOKEN_SEMICOLON, ";" },
-  { TOKEN_COMMA, "," },
-
-  // comparision
-  { TOKEN_LESS_THAN, "<" },
-  { TOKEN_GREATER_THAN, ">" },
-  { TOKEN_LESS_THAN_OR_EQUAL, "<=" },
-  { TOKEN_EQUAL_OR_GREATER_THAN, "=>" },
-
-  // equality
-  { TOKEN_EQUAL, "=" },
-  { TOKEN_NOT_EQUAL, "!=" },
-  { TOKEN_STRICT_EQUAL, "===" },
-  { TOKEN_NOT_STRICT_EQUAL, "!==" },
-
-  // operator
-  { TOKEN_PLUS, "+" },
-  { TOKEN_MINUS, "-" },
-  { TOKEN_MULTIPLY, "*" },
-  { TOKEN_DIVIDE, "/" },
-  { TOKEN_REMAINDER, "%" },
-
-  // shift
-  { TOKEN_SHIFT_LEFT, "<<" },
-  { TOKEN_SHIFT_RIGHT, ">>" },
-  { TOKEN_SHIFT_RIGHT_UNSIGNED, ">>>" },
-
-  // bitwise
-  { TOKEN_BITWISE_AND, "&" },
-  { TOKEN_BITWISE_OR, "|" },
-  { TOKEN_BITWISE_XOR, "^" },
-  
-  // unary/postfix
-  { TOKEN_LOGICAL_NOT, "!" },
-  { TOKEN_BITWISE_NOT, "~" },
-  { TOKEN_INCREASE, "++" },
-  { TOKEN_DESCREASE, "--" },
-
-  // conditional
-  { TOKEN_QUESTION_MARK, "?" },
-  { TOKEN_COLON, ":" },
-
-  // logical
-  { TOKEN_LOGICAL_AND, "&&" },
-  { TOKEN_LOGICAL_OR, "||" },
-
-  // assign
-  { TOKEN_ASSIGN, "=" },
-  { TOKEN_ASSIGN_MULTIPLY, "*=" },
-  { TOKEN_ASSIGN_DIVIDE, "/=" },
-  { TOKEN_ASSIGN_REMAINDER, "%=" },
-  { TOKEN_ASSIGN_ADD, "+=" },
-  { TOKEN_ASSIGN_MINUS, "-=" },
-  { TOKEN_ASSIGN_SHIFT_LEFT, "<<=" },
-  { TOKEN_ASSIGN_SHIFT_RIGHT, ">>=" },
-  { TOKEN_ASSIGN_SHIFT_RIGHT_ZERO, ">>>=" },
-  { TOKEN_ASSIGN_BITWISE_AND, "&=" },
-  { TOKEN_ASSIGN_BITWISE_XOR, "^=" },
-  { TOKEN_ASSIGN_BITWISE_OR, "|=" },
-
-  // values
-  { TOKEN_NULL, "NULL" },
-  { TOKEN_BOOLEAN, "BOOLEAN" },
-  { TOKEN_NUMBER, "NUMBER" },
-  { TOKEN_STRING, "STRING" },
-  { TOKEN_IDENTIFIER, "IDENTIFIER" },
-
-  // keywords
-  { TOKEN_BREAK, "break" },
-  { TOKEN_CASE, "case" },
-  { TOKEN_CATCH, "catch" },
-  { TOKEN_CONTINUE, "continue" },
-  { TOKEN_DEFAULT, "default" },
-  { TOKEN_DELETE, "delete" },
-  { TOKEN_DO, "do" },
-  { TOKEN_ELSE, "else" },
-  { TOKEN_FINALLY, "finally" },
-  { TOKEN_FOR, "for" },
-  { TOKEN_FUNCTION, "function" },
-  { TOKEN_IF, "if" },
-  { TOKEN_IN, "in" },
-  { TOKEN_INSTANCEOF, "instanceof" },
-  { TOKEN_NEW, "new" },
-  { TOKEN_RETURN, "return" },
-  { TOKEN_SWITCH, "switch" },
-  { TOKEN_THIS, "this" },
-  { TOKEN_THROW, "throw" },
-  { TOKEN_TRY, "try" },
-  { TOKEN_TYPEOF, "typeof" },
-  { TOKEN_VAR, "var" },
-  { TOKEN_VOID, "void" },
-  { TOKEN_WHILE, "while" },
-  { TOKEN_WITH, "with" },
-
-  // reserved keywords
-  { TOKEN_RESERVED_KEYWORD, "RESERVED KEYWORD" },
-
-  // ActionScript specific
-  { TOKEN_UNDEFINED, "undefined" },
-  { TOKEN_TRACE, "trace" },
-
-  { TOKEN_LAST, NULL }
-};
-
-const char *vivi_compiler_scanner_token_name (ViviCompilerScannerToken token)
-{
-  int i;
-
-  for (i = 0; token_names[i].token != TOKEN_LAST; i++) {
-    if (token_names[i].token == token)
-      return token_names[i].name;
-  }
-
-  g_assert_not_reached ();
-
-  return "INVALID TOKEN";
-}
-
-static void
-vivi_compiler_scanner_advance (ViviCompilerScanner *scanner)
-{
-  g_return_if_fail (VIVI_IS_COMPILER_SCANNER (scanner));
-
-  vivi_compiler_scanner_free_type_value (&scanner->value);
-
-  scanner->token = scanner->next_token;
-  scanner->value = scanner->next_value;
-  scanner->line_number = scanner->next_line_number;
-  scanner->line_terminator = scanner->next_line_terminator;
-
-  if (scanner->file == NULL) {
-    scanner->next_token = TOKEN_EOF;
-    scanner->next_value.v_string = NULL;
-  } else {
-    scanner->next_token = yylex ();
-    if (scanner->next_token == TOKEN_LINE_TERMINATOR) {
-      scanner->next_line_terminator = TRUE;
-    } else {
-      scanner->next_line_terminator = FALSE;
-    }
-    while (scanner->next_token == TOKEN_LINE_TERMINATOR) {
-      scanner->next_token = yylex ();
-    }
-    scanner->next_value = lex_value;
-    scanner->next_line_number = lex_line_number;
-    lex_value.type = VALUE_TYPE_NONE;
-  }
-}
-
-ViviCompilerScanner *
-vivi_compiler_scanner_new (FILE *file)
-{
-  ViviCompilerScanner *scanner;
-
-  g_return_val_if_fail (file != NULL, NULL);
-
-  scanner = g_object_new (VIVI_TYPE_COMPILER_SCANNER, NULL);
-  scanner->file = file;
-  scanner->line_number = scanner->next_line_number = lex_line_number = 1;
-
-  yyrestart (file);
-
-  vivi_compiler_scanner_advance (scanner);
-
-  return scanner;
-}
-
-ViviCompilerScannerToken
-vivi_compiler_scanner_get_next_token (ViviCompilerScanner *scanner)
-{
-  g_return_val_if_fail (VIVI_IS_COMPILER_SCANNER (scanner), TOKEN_EOF);
-
-  vivi_compiler_scanner_advance (scanner);
-
-  return scanner->token;
-}
-
-ViviCompilerScannerToken
-vivi_compiler_scanner_peek_next_token (ViviCompilerScanner *scanner)
-{
-  g_return_val_if_fail (VIVI_IS_COMPILER_SCANNER (scanner), TOKEN_EOF);
-
-  return scanner->next_token;
-}
-
-guint
-vivi_compiler_scanner_cur_line (ViviCompilerScanner *scanner)
-{
-  g_return_val_if_fail (VIVI_IS_COMPILER_SCANNER (scanner), 0);
-
-  return scanner->line_number;
-}
-
-guint
-vivi_compiler_scanner_cur_column (ViviCompilerScanner *scanner)
-{
-  g_return_val_if_fail (VIVI_IS_COMPILER_SCANNER (scanner), 0);
-
-  // TODO
-
-  return 0;
-}
-
-char *
-vivi_compiler_scanner_get_line (ViviCompilerScanner *scanner)
-{
-  g_return_val_if_fail (VIVI_IS_COMPILER_SCANNER (scanner), 0);
-
-  // TODO
-
-  return g_strdup ("");
-}
diff --git a/vivified/code/vivi_compiler_scanner.h b/vivified/code/vivi_compiler_scanner.h
deleted file mode 100644
index bcccd2d..0000000
--- a/vivified/code/vivi_compiler_scanner.h
+++ /dev/null
@@ -1,216 +0,0 @@
-/* Vivified
- * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 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
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifndef _VIVI_COMPILER_SCANNER_H_
-#define _VIVI_COMPILER_SCANNER_H_
-
-#include <stdio.h>
-#include <swfdec/swfdec.h>
-
-G_BEGIN_DECLS
-
-
-typedef enum {
-  // special
-  TOKEN_NONE = 0,
-  TOKEN_EOF,
-  TOKEN_ERROR,
-  TOKEN_UNKNOWN,
-  TOKEN_LINE_TERMINATOR,
-
-  // comparision
-  TOKEN_BRACE_LEFT,
-  TOKEN_BRACE_RIGHT,
-  TOKEN_BRACKET_LEFT,
-  TOKEN_BRACKET_RIGHT,
-  TOKEN_PARENTHESIS_LEFT,
-  TOKEN_PARENTHESIS_RIGHT,
-
-  // punctuation
-  TOKEN_DOT,
-  TOKEN_SEMICOLON,
-  TOKEN_COMMA,
-
-  // comparision
-  TOKEN_LESS_THAN,
-  TOKEN_GREATER_THAN,
-  TOKEN_LESS_THAN_OR_EQUAL,
-  TOKEN_EQUAL_OR_GREATER_THAN,
-
-  // equality
-  TOKEN_EQUAL,
-  TOKEN_NOT_EQUAL,
-  TOKEN_STRICT_EQUAL,
-  TOKEN_NOT_STRICT_EQUAL,
-
-  // operator
-  TOKEN_PLUS,
-  TOKEN_MINUS,
-  TOKEN_MULTIPLY,
-  TOKEN_DIVIDE,
-  TOKEN_REMAINDER,
-
-  // shift
-  TOKEN_SHIFT_LEFT,
-  TOKEN_SHIFT_RIGHT,
-  TOKEN_SHIFT_RIGHT_UNSIGNED,
-
-  // bitwise
-  TOKEN_BITWISE_AND,
-  TOKEN_BITWISE_OR,
-  TOKEN_BITWISE_XOR,
-  
-  // unary/postfix
-  TOKEN_LOGICAL_NOT,
-  TOKEN_BITWISE_NOT,
-  TOKEN_INCREASE,
-  TOKEN_DESCREASE,
-
-  // conditional
-  TOKEN_QUESTION_MARK,
-  TOKEN_COLON,
-
-  // logical
-  TOKEN_LOGICAL_AND,
-  TOKEN_LOGICAL_OR,
-
-  // assign
-  TOKEN_ASSIGN,
-  TOKEN_ASSIGN_MULTIPLY,
-  TOKEN_ASSIGN_DIVIDE,
-  TOKEN_ASSIGN_REMAINDER,
-  TOKEN_ASSIGN_ADD,
-  TOKEN_ASSIGN_MINUS,
-  TOKEN_ASSIGN_SHIFT_LEFT,
-  TOKEN_ASSIGN_SHIFT_RIGHT,
-  TOKEN_ASSIGN_SHIFT_RIGHT_ZERO,
-  TOKEN_ASSIGN_BITWISE_AND,
-  TOKEN_ASSIGN_BITWISE_XOR,
-  TOKEN_ASSIGN_BITWISE_OR,
-
-  // values
-  TOKEN_NULL,
-  TOKEN_BOOLEAN,
-  TOKEN_NUMBER,
-  TOKEN_STRING,
-  TOKEN_IDENTIFIER,
-
-  // keywords
-  TOKEN_BREAK,
-  TOKEN_CASE,
-  TOKEN_CATCH,
-  TOKEN_CONTINUE,
-  TOKEN_DEFAULT,
-  TOKEN_DELETE,
-  TOKEN_DO,
-  TOKEN_ELSE,
-  TOKEN_FINALLY,
-  TOKEN_FOR,
-  TOKEN_FUNCTION,
-  TOKEN_IF,
-  TOKEN_IN,
-  TOKEN_INSTANCEOF,
-  TOKEN_NEW,
-  TOKEN_RETURN,
-  TOKEN_SWITCH,
-  TOKEN_THIS,
-  TOKEN_THROW,
-  TOKEN_TRY,
-  TOKEN_TYPEOF,
-  TOKEN_VAR,
-  TOKEN_VOID,
-  TOKEN_WHILE,
-  TOKEN_WITH,
-
-  // reserved keywords
-  TOKEN_RESERVED_KEYWORD,
-
-  // ActionScript specific
-  TOKEN_UNDEFINED,
-  TOKEN_TRACE,
-
-  TOKEN_LAST
-} ViviCompilerScannerToken;
-
-typedef enum {
-  VALUE_TYPE_NONE,
-  VALUE_TYPE_BOOLEAN,
-  VALUE_TYPE_NUMBER,
-  VALUE_TYPE_STRING,
-  VALUE_TYPE_IDENTIFIER
-} ViviCompilerScannerValueType;
-
-typedef struct {
-  ViviCompilerScannerValueType	type;
-  union {
-    gboolean	v_boolean;
-    double	v_number;
-    char *	v_string;
-    char *	v_identifier;
-  };
-} ViviCompilerScannerValue;
-
-typedef struct _ViviCompilerScanner ViviCompilerScanner;
-typedef struct _ViviCompilerScannerClass ViviCompilerScannerClass;
-
-#define VIVI_TYPE_COMPILER_SCANNER                    (vivi_compiler_scanner_get_type())
-#define VIVI_IS_COMPILER_SCANNER(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_COMPILER_SCANNER))
-#define VIVI_IS_COMPILER_SCANNER_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_COMPILER_SCANNER))
-#define VIVI_COMPILER_SCANNER(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_COMPILER_SCANNER, ViviCompilerScanner))
-#define VIVI_COMPILER_SCANNER_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_COMPILER_SCANNER, ViviCompilerScannerClass))
-#define VIVI_COMPILER_SCANNER_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_COMPILER_SCANNER, ViviCompilerScannerClass))
-
-struct _ViviCompilerScanner
-{
-  GObject			object;
-
-  FILE *			file;
-
-  ViviCompilerScannerToken	token;
-  ViviCompilerScannerToken	next_token;
-  guint				line_number;
-  gboolean			line_terminator;
-
-  ViviCompilerScannerValue	value;
-  ViviCompilerScannerValue	next_value;
-  guint				next_line_number;
-  gboolean			next_line_terminator;
-
-  ViviCompilerScannerToken	expected;
-};
-
-struct _ViviCompilerScannerClass
-{
-  GObjectClass		object_class;
-};
-
-GType				vivi_compiler_scanner_get_type   	(void);
-
-ViviCompilerScanner *		vivi_compiler_scanner_new		(FILE *		file);
-ViviCompilerScannerToken	vivi_compiler_scanner_get_next_token	(ViviCompilerScanner *	scanner);
-ViviCompilerScannerToken	vivi_compiler_scanner_peek_next_token	(ViviCompilerScanner *	scanner);
-
-const char *			vivi_compiler_scanner_token_name	(ViviCompilerScannerToken token);
-guint				vivi_compiler_scanner_cur_line		(ViviCompilerScanner *scanner);
-guint				vivi_compiler_scanner_cur_column	(ViviCompilerScanner *scanner);
-char *				vivi_compiler_scanner_get_line		(ViviCompilerScanner *scanner);
-
-
-G_END_DECLS
-#endif
diff --git a/vivified/code/vivi_compiler_scanner_lex.h b/vivified/code/vivi_compiler_scanner_lex.h
deleted file mode 100644
index 14d2a0f..0000000
--- a/vivified/code/vivi_compiler_scanner_lex.h
+++ /dev/null
@@ -1,315 +0,0 @@
-/* Vivified
- * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 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
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifndef yyHEADER_H
-#define yyHEADER_H 1
-#define yyIN_HEADER 1
-
-#line 6 "vivi_compiler_scanner_lex.h"
-
-#line 8 "vivi_compiler_scanner_lex.h"
-
-#define  YY_INT_ALIGNED short int
-
-/* A lexical scanner generated by flex */
-
-#define FLEX_SCANNER
-#define YY_FLEX_MAJOR_VERSION 2
-#define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 34
-#if YY_FLEX_SUBMINOR_VERSION > 0
-#define FLEX_BETA
-#endif
-
-/* First, we deal with  platform-specific or compiler-specific issues. */
-
-/* begin standard C headers. */
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-
-/* end standard C headers. */
-
-/* flex integer type definitions */
-
-#ifndef FLEXINT_H
-#define FLEXINT_H
-
-/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
-
-#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-
-/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
- * if you want the limit (max/min) macros for int types. 
- */
-#ifndef __STDC_LIMIT_MACROS
-#define __STDC_LIMIT_MACROS 1
-#endif
-
-#include <inttypes.h>
-typedef int8_t flex_int8_t;
-typedef uint8_t flex_uint8_t;
-typedef int16_t flex_int16_t;
-typedef uint16_t flex_uint16_t;
-typedef int32_t flex_int32_t;
-typedef uint32_t flex_uint32_t;
-#else
-typedef signed char flex_int8_t;
-typedef short int flex_int16_t;
-typedef int flex_int32_t;
-typedef unsigned char flex_uint8_t; 
-typedef unsigned short int flex_uint16_t;
-typedef unsigned int flex_uint32_t;
-#endif /* ! C99 */
-
-/* Limits of integral types. */
-#ifndef INT8_MIN
-#define INT8_MIN               (-128)
-#endif
-#ifndef INT16_MIN
-#define INT16_MIN              (-32767-1)
-#endif
-#ifndef INT32_MIN
-#define INT32_MIN              (-2147483647-1)
-#endif
-#ifndef INT8_MAX
-#define INT8_MAX               (127)
-#endif
-#ifndef INT16_MAX
-#define INT16_MAX              (32767)
-#endif
-#ifndef INT32_MAX
-#define INT32_MAX              (2147483647)
-#endif
-#ifndef UINT8_MAX
-#define UINT8_MAX              (255U)
-#endif
-#ifndef UINT16_MAX
-#define UINT16_MAX             (65535U)
-#endif
-#ifndef UINT32_MAX
-#define UINT32_MAX             (4294967295U)
-#endif
-
-#endif /* ! FLEXINT_H */
-
-#ifdef __cplusplus
-
-/* The "const" storage-class-modifier is valid. */
-#define YY_USE_CONST
-
-#else	/* ! __cplusplus */
-
-/* C99 requires __STDC__ to be defined as 1. */
-#if defined (__STDC__)
-
-#define YY_USE_CONST
-
-#endif	/* defined (__STDC__) */
-#endif	/* ! __cplusplus */
-
-#ifdef YY_USE_CONST
-#define yyconst const
-#else
-#define yyconst
-#endif
-
-/* Size of default input buffer. */
-#ifndef YY_BUF_SIZE
-#define YY_BUF_SIZE 16384
-#endif
-
-#ifndef YY_TYPEDEF_YY_BUFFER_STATE
-#define YY_TYPEDEF_YY_BUFFER_STATE
-typedef struct yy_buffer_state *YY_BUFFER_STATE;
-#endif
-
-extern int yyleng;
-
-extern FILE *yyin, *yyout;
-
-/* The following is because we cannot portably get our hands on size_t
- * (without autoconf's help, which isn't available because we want
- * flex-generated scanners to compile on their own).
- * Given that the standard has decreed that size_t exists since 1989,
- * I guess we can afford to depend on it. Manoj.
- */
-
-#ifndef YY_TYPEDEF_YY_SIZE_T
-#define YY_TYPEDEF_YY_SIZE_T
-typedef size_t yy_size_t;
-#endif
-
-#ifndef YY_STRUCT_YY_BUFFER_STATE
-#define YY_STRUCT_YY_BUFFER_STATE
-struct yy_buffer_state
-	{
-	FILE *yy_input_file;
-
-	char *yy_ch_buf;		/* input buffer */
-	char *yy_buf_pos;		/* current position in input buffer */
-
-	/* Size of input buffer in bytes, not including room for EOB
-	 * characters.
-	 */
-	yy_size_t yy_buf_size;
-
-	/* Number of characters read into yy_ch_buf, not including EOB
-	 * characters.
-	 */
-	int yy_n_chars;
-
-	/* Whether we "own" the buffer - i.e., we know we created it,
-	 * and can realloc() it to grow it, and should free() it to
-	 * delete it.
-	 */
-	int yy_is_our_buffer;
-
-	/* Whether this is an "interactive" input source; if so, and
-	 * if we're using stdio for input, then we want to use getc()
-	 * instead of fread(), to make sure we stop fetching input after
-	 * each newline.
-	 */
-	int yy_is_interactive;
-
-	/* Whether we're considered to be at the beginning of a line.
-	 * If so, '^' rules will be active on the next match, otherwise
-	 * not.
-	 */
-	int yy_at_bol;
-
-    int yy_bs_lineno; /**< The line count. */
-    int yy_bs_column; /**< The column count. */
-    
-	/* Whether to try to fill the input buffer when we reach the
-	 * end of it.
-	 */
-	int yy_fill_buffer;
-
-	int yy_buffer_status;
-
-	};
-#endif /* !YY_STRUCT_YY_BUFFER_STATE */
-
-void yyrestart (FILE *input_file  );
-void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer  );
-YY_BUFFER_STATE yy_create_buffer (FILE *file,int size  );
-void yy_delete_buffer (YY_BUFFER_STATE b  );
-void yy_flush_buffer (YY_BUFFER_STATE b  );
-void yypush_buffer_state (YY_BUFFER_STATE new_buffer  );
-void yypop_buffer_state (void );
-
-YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size  );
-YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str  );
-YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len  );
-
-void *yyalloc (yy_size_t  );
-void *yyrealloc (void *,yy_size_t  );
-void yyfree (void *  );
-
-/* Begin user sect3 */
-
-extern int yylineno;
-
-extern char *yytext;
-#define yytext_ptr yytext
-
-#ifdef YY_HEADER_EXPORT_START_CONDITIONS
-#define INITIAL 0
-
-#endif
-
-#ifndef YY_NO_UNISTD_H
-/* Special case for "unistd.h", since it is non-ANSI. We include it way
- * down here because we want the user's section 1 to have been scanned first.
- * The user has a chance to override it with an option.
- */
-#include <unistd.h>
-#endif
-
-#ifndef YY_EXTRA_TYPE
-#define YY_EXTRA_TYPE void *
-#endif
-
-/* Macros after this point can all be overridden by user definitions in
- * section 1.
- */
-
-#ifndef YY_SKIP_YYWRAP
-#ifdef __cplusplus
-extern "C" int yywrap (void );
-#else
-extern int yywrap (void );
-#endif
-#endif
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy (char *,yyconst char *,int );
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * );
-#endif
-
-#ifndef YY_NO_INPUT
-
-#endif
-
-/* Amount of stuff to slurp up with each read. */
-#ifndef YY_READ_BUF_SIZE
-#define YY_READ_BUF_SIZE 8192
-#endif
-
-/* Number of entries by which start-condition stack grows. */
-#ifndef YY_START_STACK_INCR
-#define YY_START_STACK_INCR 25
-#endif
-
-/* Default declaration of generated scanner - a define so the user can
- * easily add parameters.
- */
-#ifndef YY_DECL
-#define YY_DECL_IS_OURS 1
-
-extern int yylex (void);
-
-#define YY_DECL int yylex (void)
-#endif /* !YY_DECL */
-
-/* yy_get_previous_state - get the state just before the EOB char was reached */
-
-#undef YY_NEW_FILE
-#undef YY_FLUSH_BUFFER
-#undef yy_set_bol
-#undef yy_new_buffer
-#undef yy_set_interactive
-#undef YY_DO_BEFORE_ACTION
-
-#ifdef YY_DECL_IS_OURS
-#undef YY_DECL_IS_OURS
-#undef YY_DECL
-#endif
-
-#line 148 "vivi_compiler_scanner_lex.l"
-
-
-#line 295 "vivi_compiler_scanner_lex.h"
-#undef yyIN_HEADER
-#endif /* yyHEADER_H */
diff --git a/vivified/code/vivi_compiler_scanner_lex.l b/vivified/code/vivi_compiler_scanner_lex.l
deleted file mode 100644
index 7d2cc9b..0000000
--- a/vivified/code/vivi_compiler_scanner_lex.l
+++ /dev/null
@@ -1,284 +0,0 @@
-%{
-/* Vivified
- * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 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
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#include "vivi_compiler_scanner_lex_include.h"
-%}
-
-%option			noyywrap
-%option			nostdinit
-%option			never-interactive
-
-identifier_start	[$_a-zA-Z]
-identifier_part		[$_a-zA-Z0-9]
-
-%x			str
-%x			comment
-
-%%
-
-			GString *string = NULL;
-
-<<EOF>>			{ return TOKEN_EOF; }
-
-"/*"			{ BEGIN(comment); }
-<comment>{
-  [^*\n]*		/* skip */
-  \n			{ lex_line_number++; }
-  "*/"			{ BEGIN(INITIAL); }
-  <<EOF>>		{
-			  BEGIN(INITIAL);
-			  return TOKEN_ERROR;
-			}
-}
-"//"[^\r\n]*		{
-			  lex_line_number++;
-			  return TOKEN_LINE_TERMINATOR;
-			}
-
-[ \t]			/* skip */
-
-\r\n			{
-			  lex_line_number++;
-			  return TOKEN_LINE_TERMINATOR;
-			}
-[\r\n]			{
-			  lex_line_number++;
-			  return TOKEN_LINE_TERMINATOR;
-			}
-
-"{"			{ return TOKEN_BRACE_LEFT; }
-"}"			{ return TOKEN_BRACE_RIGHT; }
-"["			{ return TOKEN_BRACKET_LEFT; }
-"]"			{ return TOKEN_BRACKET_RIGHT; }
-"("			{ return TOKEN_PARENTHESIS_LEFT; }
-")"			{ return TOKEN_PARENTHESIS_RIGHT; }
-
-"."			{ return TOKEN_DOT; }
-";"			{ return TOKEN_SEMICOLON; }
-","			{ return TOKEN_COMMA; }
-
-"<"			{ return TOKEN_LESS_THAN; }
-">"			{ return TOKEN_GREATER_THAN; }
-"<="			{ return TOKEN_LESS_THAN_OR_EQUAL; }
-"=>"			{ return TOKEN_EQUAL_OR_GREATER_THAN; }
-
-"==",			{ return TOKEN_EQUAL; }
-"!=",			{ return TOKEN_NOT_EQUAL; }
-"===",			{ return TOKEN_STRICT_EQUAL; }
-"!==",			{ return TOKEN_NOT_STRICT_EQUAL; }
-
-"+"			{ return TOKEN_PLUS; }
-"-"			{ return TOKEN_MINUS; }
-"*"			{ return TOKEN_MULTIPLY; }
-"/"			{ return TOKEN_DIVIDE; }
-"%"			{ return TOKEN_REMAINDER; }
-
-"<<"			{ return TOKEN_SHIFT_LEFT; }
-">>"			{ return TOKEN_SHIFT_RIGHT; }
-">>>"			{ return TOKEN_SHIFT_RIGHT_UNSIGNED; }
-
-"&"			{ return TOKEN_BITWISE_AND; }
-"|"			{ return TOKEN_BITWISE_OR; }
-"^"			{ return TOKEN_BITWISE_XOR; }
-
-"!"			{ return TOKEN_LOGICAL_NOT; }
-"~"			{ return TOKEN_BITWISE_NOT; }
-"++"			{ return TOKEN_INCREASE; }
-"--"			{ return TOKEN_DESCREASE; }
-
-"?"			{ return TOKEN_QUESTION_MARK; }
-":"			{ return TOKEN_COLON; }
-
-"&&"			{ return TOKEN_LOGICAL_AND; }
-"||"			{ return TOKEN_LOGICAL_OR; }
-
-"="			{ return TOKEN_ASSIGN; }
-"*="			{ return TOKEN_ASSIGN_MULTIPLY; }
-"/="			{ return TOKEN_ASSIGN_DIVIDE; }
-"%="			{ return TOKEN_ASSIGN_REMAINDER; }
-"+="			{ return TOKEN_ASSIGN_ADD; }
-"-="			{ return TOKEN_ASSIGN_MINUS; }
-"<<="			{ return TOKEN_ASSIGN_SHIFT_LEFT; }
-">>="			{ return TOKEN_ASSIGN_SHIFT_RIGHT; }
-">>>="			{ return TOKEN_ASSIGN_SHIFT_RIGHT_ZERO; }
-"&="			{ return TOKEN_ASSIGN_BITWISE_AND; }
-"^="			{ return TOKEN_ASSIGN_BITWISE_XOR; }
-"|="			{ return TOKEN_ASSIGN_BITWISE_OR; }
-
-"break"			{ return TOKEN_BREAK; }
-"case"			{ return TOKEN_CASE; }
-"catch"			{ return TOKEN_CATCH; }
-"continue"		{ return TOKEN_CONTINUE; }
-"default"		{ return TOKEN_DEFAULT; }
-"delete"		{ return TOKEN_DELETE; }
-"do"			{ return TOKEN_DO; }
-"else"			{ return TOKEN_ELSE; }
-"finally"		{ return TOKEN_FINALLY; }
-"for"			{ return TOKEN_FOR; }
-"function"		{ return TOKEN_FUNCTION; }
-"if"			{ return TOKEN_IF; }
-"in"			{ return TOKEN_IN; }
-"instanceof"		{ return TOKEN_INSTANCEOF; }
-"new"			{ return TOKEN_NEW; }
-"return"		{ return TOKEN_RETURN; }
-"switch"		{ return TOKEN_SWITCH; }
-"this"			{ return TOKEN_THIS; }
-"throw"			{ return TOKEN_THROW; }
-"try"			{ return TOKEN_TRY; }
-"typeof"		{ return TOKEN_TYPEOF; }
-"var"			{ return TOKEN_VAR; }
-"void"			{ return TOKEN_VOID; }
-"while"			{ return TOKEN_WHILE; }
-"with"			{ return TOKEN_WITH; }
-
-"abstract"		{ return TOKEN_RESERVED_KEYWORD; }
-"boolean"		{ return TOKEN_RESERVED_KEYWORD; }
-"byte"			{ return TOKEN_RESERVED_KEYWORD; }
-"char"			{ return TOKEN_RESERVED_KEYWORD; }
-"class"			{ return TOKEN_RESERVED_KEYWORD; }
-"const"			{ return TOKEN_RESERVED_KEYWORD; }
-"debugger"		{ return TOKEN_RESERVED_KEYWORD; }
-"double"		{ return TOKEN_RESERVED_KEYWORD; }
-"enum"			{ return TOKEN_RESERVED_KEYWORD; }
-"export"		{ return TOKEN_RESERVED_KEYWORD; }
-"extends"		{ return TOKEN_RESERVED_KEYWORD; }
-"final"			{ return TOKEN_RESERVED_KEYWORD; }
-"float"			{ return TOKEN_RESERVED_KEYWORD; }
-"goto"			{ return TOKEN_RESERVED_KEYWORD; }
-"implements"		{ return TOKEN_RESERVED_KEYWORD; }
-"import"		{ return TOKEN_RESERVED_KEYWORD; }
-"int"			{ return TOKEN_RESERVED_KEYWORD; }
-"interface"		{ return TOKEN_RESERVED_KEYWORD; }
-"long"			{ return TOKEN_RESERVED_KEYWORD; }
-"native"		{ return TOKEN_RESERVED_KEYWORD; }
-"package"		{ return TOKEN_RESERVED_KEYWORD; }
-"private"		{ return TOKEN_RESERVED_KEYWORD; }
-"protected"		{ return TOKEN_RESERVED_KEYWORD; }
-"public"		{ return TOKEN_RESERVED_KEYWORD; }
-"short"			{ return TOKEN_RESERVED_KEYWORD; }
-"static"		{ return TOKEN_RESERVED_KEYWORD; }
-"super"			{ return TOKEN_RESERVED_KEYWORD; }
-"synchronized"		{ return TOKEN_RESERVED_KEYWORD; }
-"throws"		{ return TOKEN_RESERVED_KEYWORD; }
-"transient"		{ return TOKEN_RESERVED_KEYWORD; }
-"volatile"		{ return TOKEN_RESERVED_KEYWORD; }
-
-"undefined"		{ return TOKEN_UNDEFINED; }
-"trace"			{ return TOKEN_TRACE; }
-
-"null"			{ return TOKEN_NULL; }
-"true"			{
-			  lex_value.type = VALUE_TYPE_BOOLEAN;
-			  lex_value.v_boolean = 1;
-			  return TOKEN_BOOLEAN;
-			}
-"false"			{
-			  lex_value.type = VALUE_TYPE_BOOLEAN;
-			  lex_value.v_boolean = 0;
-			  return TOKEN_BOOLEAN;
-			}
-
-0[xX][0-9a-fA-F]+	{
-			  lex_value.type = VALUE_TYPE_NUMBER;
-			  lex_value.v_number =
-			    g_ascii_strtoull (yytext, NULL, 16);
-			  return TOKEN_NUMBER;
-			}
-
-([1-9][0-9]*|0)(\.[0-9]*)?([eE][+-]?[0-9]+)? {
-			  lex_value.type = VALUE_TYPE_NUMBER;
-			  lex_value.v_number = g_ascii_strtod (yytext, NULL);
-			  return TOKEN_NUMBER;
-			}
-
-\.[0-9]+([eE][+-]?[0-9]+)? {
-			  lex_value.type = VALUE_TYPE_NUMBER;
-			  lex_value.v_number = g_ascii_strtod (yytext, NULL);
-			  return TOKEN_NUMBER;
-			}
-
-\"			{
-			  string = g_string_new ("");
-			  BEGIN(str);
-			}
-
-<str>{
-  \"			{
-			  BEGIN(INITIAL);
-			  lex_value.type = VALUE_TYPE_STRING;
-			  lex_value.v_string = g_string_free (string, FALSE);
-			  return TOKEN_STRING;
-			}
-  \n			{
-			  BEGIN(INITIAL);
-			  g_string_free (string, TRUE);
-			  return TOKEN_ERROR;
-			}
-  \\0			{ g_string_append_c (string, '0'); }
-  \\[0-7]{1,3}		{
-			  guint64 result;
-			  result = g_ascii_strtoull (yytext + 1, NULL, 8);
-			  if (result > 0xff || result == 0) {
-			    BEGIN(INITIAL);
-			    g_string_free (string, TRUE);
-			    return TOKEN_ERROR;
-			  } else {
-			    g_string_append_c (string, result);
-			  }
-			}
-  \\[0-9]+		{
-			  g_string_free (string, TRUE);
-			  return TOKEN_ERROR;
-			}
-  \\x[0-9a-fA-F]{2}	{
-			  guint64 result;
-			  result = g_ascii_strtoull (yytext + 2, NULL, 16);
-			  if (result == 0) {
-			    BEGIN(INITIAL);
-			    g_string_free (string, TRUE);
-			    return TOKEN_ERROR;
-			  } else {
-			    g_string_append_c (string, result);
-			  }
-			}
-  \\b			{ g_string_append_c (string, '\b'); }
-  \\f			{ g_string_append_c (string, '\f'); }
-  \\n			{ g_string_append_c (string, '\n'); }
-  \\r			{ g_string_append_c (string, '\r'); }
-  \\t			{ g_string_append_c (string, '\t'); }
-  \\v			{ g_string_append_c (string, '\v'); }
-  \\.			{ g_string_append_c (string, yytext[1]); }
-  [^\\\n\"]+		{
-			  char *p;
-			  for (p = yytext; *p != '\0'; p++) {
-			    g_string_append_c (string, *p);
-			  }
-			}
-}
-
-{identifier_start}({identifier_part})* {
-  			  lex_value.type = VALUE_TYPE_IDENTIFIER;
-			  lex_value.v_identifier = g_strdup (yytext);
-			  return TOKEN_IDENTIFIER;
-			}
-
-.			{ return TOKEN_ERROR; }
-
-%%
diff --git a/vivified/code/vivi_compiler_scanner_lex_include.h b/vivified/code/vivi_compiler_scanner_lex_include.h
deleted file mode 100644
index f85f00e..0000000
--- a/vivified/code/vivi_compiler_scanner_lex_include.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* Vivified
- * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 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
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifndef _VIVI_COMPILER_SCANNER_LEX_INCLUDE_H_
-#define _VIVI_COMPILER_SCANNER_LEX_INCLUDE_H_
-
-#include "vivi_compiler_scanner.h"
-
-ViviCompilerScannerValue lex_value;
-guint lex_line_number;
-
-#endif // _VIVI_COMPILER_SCANNER_LEX_INCLUDE_H_
diff --git a/vivified/code/vivi_parser.c b/vivified/code/vivi_parser.c
new file mode 100644
index 0000000..2969593
--- /dev/null
+++ b/vivified/code/vivi_parser.c
@@ -0,0 +1,2385 @@
+/* Vivified
+ * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "vivi_parser.h"
+
+#include "vivi_parser_scanner.h"
+
+#include "vivi_code_assignment.h"
+#include "vivi_code_binary.h"
+#include "vivi_code_block.h"
+#include "vivi_code_break.h"
+#include "vivi_code_constant.h"
+#include "vivi_code_continue.h"
+#include "vivi_code_function.h"
+#include "vivi_code_function_call.h"
+#include "vivi_code_get.h"
+#include "vivi_code_get_url.h"
+#include "vivi_code_goto.h"
+#include "vivi_code_if.h"
+#include "vivi_code_init_array.h"
+#include "vivi_code_init_object.h"
+#include "vivi_code_loop.h"
+#include "vivi_code_return.h"
+#include "vivi_code_throw.h"
+#include "vivi_code_trace.h"
+#include "vivi_code_unary.h"
+#include "vivi_code_value_statement.h"
+#include "vivi_compiler_empty_statement.h"
+#include "vivi_compiler_get_temporary.h"
+#include "vivi_compiler_goto_name.h"
+
+#include "vivi_code_text_printer.h"
+
+enum {
+  ERROR_TOKEN_LITERAL = TOKEN_LAST + 1,
+  ERROR_TOKEN_IDENTIFIER,
+  ERROR_TOKEN_PROPERTY_NAME,
+  ERROR_TOKEN_PRIMARY_EXPRESSION,
+  ERROR_TOKEN_EXPRESSION,
+  ERROR_TOKEN_ITERATION_STATEMENT,
+  ERROR_TOKEN_EXPRESSION_STATEMENT,
+  ERROR_TOKEN_STATEMENT
+};
+
+static const struct {
+  guint				token;
+  const char *			name;
+} error_names[] = {
+  { ERROR_TOKEN_LITERAL, "LITERAL" },
+  { ERROR_TOKEN_IDENTIFIER, "IDENTIFIER" },
+  { ERROR_TOKEN_PROPERTY_NAME, "PROPERTY NAME" },
+  { ERROR_TOKEN_PRIMARY_EXPRESSION, "PRIMARY EXPRESSION" },
+  { ERROR_TOKEN_EXPRESSION, "EXPRESSION" },
+  { ERROR_TOKEN_ITERATION_STATEMENT, "ITERATION STATEMENT" },
+  { ERROR_TOKEN_EXPRESSION_STATEMENT, "EXPRESSION STATEMENT" },
+  { ERROR_TOKEN_STATEMENT, "STATEMENT" },
+  { TOKEN_LAST, NULL }
+};
+
+typedef enum {
+  STATUS_CANCEL = -1,
+  STATUS_OK = 0,
+  STATUS_FAIL = 1
+} ParseStatus;
+
+typedef struct {
+  GSList			*labels;
+  GSList			*gotos;
+} ParseLevel;
+
+typedef struct {
+  ViviParserScanner *		scanner;
+  gboolean			unexpected_line_terminator;
+  guint				expected[2];
+  char *			custom_error;
+
+  GSList *			levels; // ParseLevel, earlier levels
+  ParseLevel *			level;  // current level
+} ParseData;
+
+#define FAIL_OR(x, y) (data->expected[0] = (x), data->expected[1] = (y), STATUS_FAIL)
+#define FAIL_LINE_TERMINATOR_OR(x, y) (data->unexpected_line_terminator = TRUE, FAIL_OR(x,y))
+#define FAIL_LINE_TERMINATOR(x) FAIL_LINE_TERMINATOR_OR(x,TOKEN_NONE)
+#define FAIL(x) FAIL_OR(x,TOKEN_NONE)
+#define FAIL_CHILD(x) STATUS_FAIL
+#define FAIL_CUSTOM(x) (data->custom_error = (x), STATUS_FAIL)
+#define CANCEL_OR(x, y) (data->expected[0] = (x), data->expected[1] = (y), STATUS_CANCEL)
+#define CANCEL(x) CANCEL_OR(x, TOKEN_NONE)
+#define CANCEL_CUSTOM(x) (data->custom_error = (x), STATUS_CANCEL)
+
+typedef ParseStatus (*ParseValueFunction) (ParseData *data, ViviCodeValue **value);
+typedef ParseStatus (*ParseValueStatementFunction) (ParseData *data, ViviCodeValue **value, ViviCodeStatement **statement);
+typedef ParseStatus (*ParseStatementFunction) (ParseData *data, ViviCodeStatement **statement);
+
+static ParseStatus
+parse_statement_list (ParseData *data, ParseStatementFunction function, ViviCodeStatement **statement, guint separator);
+
+static ParseStatus
+parse_value_statement_list (ParseData *data,
+    ParseValueStatementFunction function, ViviCodeValue ***list,
+    ViviCodeStatement **statement, guint separator);
+
+static ParseStatus
+parse_value_list (ParseData *data, ParseValueFunction function,
+    ViviCodeValue ***list, guint separator);
+
+// helpers
+
+static const char *
+vivi_parser_token_name (guint token)
+{
+  if (token < TOKEN_LAST) {
+    return vivi_parser_scanner_token_name (token);
+  } else {
+    guint i;
+    const char *name;
+
+    name = NULL;
+    for (i = 0; error_names[i].token != TOKEN_LAST; i++) {
+      if (error_names[i].token == token) {
+	name = error_names[i].name;
+	break;
+      }
+    }
+
+    g_assert (name != NULL);
+
+    return name;
+  }
+}
+
+static gboolean
+check_line_terminator (ParseData *data)
+{
+  vivi_parser_scanner_peek_next_token (data->scanner);
+  return data->scanner->next_line_terminator;
+}
+
+static gboolean
+check_token (ParseData *data, ViviParserScannerToken token)
+{
+  vivi_parser_scanner_peek_next_token (data->scanner);
+  if (data->scanner->next_token != token)
+    return FALSE;
+  vivi_parser_scanner_get_next_token (data->scanner);
+  return TRUE;
+}
+
+static gboolean
+check_automatic_semicolon (ParseData *data)
+{
+  if (check_token (data, TOKEN_SEMICOLON))
+    return TRUE;
+  if (check_line_terminator (data))
+    return TRUE;
+
+  vivi_parser_scanner_peek_next_token (data->scanner);
+  if (data->scanner->next_token == TOKEN_BRACE_LEFT ||
+      data->scanner->next_token == TOKEN_EOF)
+    return TRUE;
+
+  return FALSE;
+}
+
+static gboolean
+check_restricted_semicolon (ParseData *data)
+{
+  if (check_token (data, TOKEN_SEMICOLON))
+    return TRUE;
+  if (check_line_terminator (data))
+    return TRUE;
+
+  return FALSE;
+}
+
+static void
+free_value_list (ViviCodeValue **list)
+{
+  int i;
+
+  for (i = 0; list[i] != NULL; i++) {
+    g_object_unref (list[i]);
+  }
+  g_free (list);
+}
+
+G_GNUC_WARN_UNUSED_RESULT static ViviCodeStatement *
+vivi_parser_join_statements (ViviCodeStatement *one, ViviCodeStatement *two)
+{
+
+  if (one == NULL) {
+    return two;
+  } else if (two == NULL) {
+    return one;
+  }
+
+  if (VIVI_IS_CODE_BLOCK (one)) {
+    vivi_code_block_add_statement (VIVI_CODE_BLOCK (one), two);
+    g_object_unref (two);
+    return one;
+  } else if (VIVI_IS_CODE_BLOCK (two)) {
+    vivi_code_block_insert_statement (VIVI_CODE_BLOCK (two), 0, one);
+    g_object_unref (one);
+    return two;
+  } else {
+    ViviCodeStatement *block = vivi_code_block_new ();
+    vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), one);
+    g_object_unref (one);
+    vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), two);
+    g_object_unref (two);
+    return block;
+  }
+}
+
+static ViviCodeValue *
+vivi_parser_function_call_new (ViviCodeValue *name)
+{
+  ViviCodeValue *value;
+
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (name), NULL);
+
+  value = NULL;
+
+  if (VIVI_IS_CODE_GET (name)) {
+    ViviCodeGet *get = VIVI_CODE_GET (name);
+
+    if (get->from != NULL) {
+      value = g_object_ref (get->from);
+      name = g_object_ref (get->name);
+    }
+  }
+
+  if (VIVI_IS_CODE_GET (name)) {
+    ViviCodeGet *get = VIVI_CODE_GET (name);
+
+    if (get->from == NULL)
+      name = g_object_ref (get->name);
+  }
+
+  return vivi_code_function_call_new (value, name);
+}
+
+static ViviCodeStatement *
+vivi_parser_assignment_new (ViviCodeValue *left, ViviCodeValue *right)
+{
+  ViviCodeValue *from;
+
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (left), NULL);
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (right), NULL);
+
+  from = NULL;
+
+  if (VIVI_IS_CODE_GET (left)) {
+    ViviCodeGet *get = VIVI_CODE_GET (left);
+
+    if (get->from != NULL) {
+      from = g_object_ref (get->from);
+      left = g_object_ref (get->name);
+    }
+  }
+
+  if (VIVI_IS_CODE_GET (left)) {
+    ViviCodeGet *get = VIVI_CODE_GET (left);
+
+    if (get->from == NULL)
+      left = g_object_ref (get->name);
+  }
+
+  return vivi_code_assignment_new (from, left, right);
+}
+
+static ViviCodeValue *
+vivi_parser_get_new (ViviCodeValue *from, ViviCodeValue *name)
+{
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (from), NULL);
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (name), NULL);
+
+  if (VIVI_IS_CODE_GET (name)) {
+    ViviCodeGet *get = VIVI_CODE_GET (name);
+
+    if (get->from == NULL)
+      name = g_object_ref (get->name);
+  }
+
+  return vivi_code_get_new (from, name);
+}
+
+static gboolean
+vivi_parser_value_is_left_hand_side (ViviCodeValue *value)
+{
+  // FIXME: Correct?
+  return VIVI_IS_CODE_GET (value);
+}
+
+static gboolean
+vivi_parser_value_is_identifier (ViviCodeValue *value)
+{
+  if (!VIVI_IS_CODE_GET (value))
+    return FALSE;
+  return VIVI_IS_CODE_CONSTANT (VIVI_CODE_GET (value)->name);
+}
+
+static void
+vivi_parser_start_level (ParseData *data)
+{
+  g_return_if_fail (data != NULL);
+
+  if (data->level != NULL)
+    data->levels = g_slist_prepend (data->levels, data->level);
+  data->level = g_new0 (ParseLevel, 1);
+}
+
+static ViviCodeLabel *
+vivi_parser_find_label (ParseData *data, const char *name)
+{
+  GSList *iter;
+
+  for (iter = data->level->labels; iter != NULL; iter = iter->next) {
+    if (g_str_equal (vivi_code_label_get_name (VIVI_CODE_LABEL (iter->data)),
+	  name))
+      return VIVI_CODE_LABEL (iter->data);
+  }
+
+  return NULL;
+}
+
+static ParseStatus
+vivi_parser_end_level (ParseData *data, gboolean fail)
+{
+  GSList *iter;
+  char *custom_error = NULL;
+
+  g_return_val_if_fail (data != NULL, STATUS_FAIL);
+  g_return_val_if_fail (data->level != NULL, STATUS_FAIL);
+
+  for (iter = data->level->gotos; iter != NULL; iter = iter->next) {
+    ViviCompilerGotoName *goto_;
+    ViviCodeLabel *label;
+
+    goto_ = VIVI_COMPILER_GOTO_NAME (iter->data);
+    label = vivi_parser_find_label (data,
+	vivi_compiler_goto_name_get_name (goto_));
+
+    if (label != NULL) {
+      vivi_compiler_goto_name_set_label (goto_, label);
+    } else {
+      if (custom_error == NULL) {
+	custom_error =
+	  g_strdup_printf ("Label named '%s' doesn't exist in this block",
+	      vivi_compiler_goto_name_get_name (goto_));
+      }
+    }
+
+    g_object_unref (goto_);
+  }
+  g_slist_free (data->level->gotos);
+
+  for (iter = data->level->labels; iter != NULL; iter = iter->next) {
+    g_object_unref (VIVI_CODE_LABEL (iter->data));
+  }
+  g_slist_free (data->level->labels);
+
+  g_free (data->level);
+
+  if (data->levels != NULL) {
+    data->level = data->levels->data;
+    data->levels = g_slist_delete_link (data->levels, data->levels);
+  } else {
+    data->level = NULL;
+  }
+
+  if (custom_error != NULL) {
+    if (fail) {
+      return FAIL_CUSTOM (custom_error);
+    } else {
+      return STATUS_FAIL;
+    }
+  } else {
+    return STATUS_OK;
+  }
+}
+
+static void
+vivi_parser_add_goto (ParseData *data, ViviCompilerGotoName *goto_)
+{
+  g_return_if_fail (data != NULL);
+  g_return_if_fail (data->level != NULL);
+  g_return_if_fail (VIVI_IS_COMPILER_GOTO_NAME (goto_));
+
+  data->level->gotos =
+    g_slist_prepend (data->level->gotos, g_object_ref (goto_));
+}
+
+static gboolean
+vivi_parser_add_label (ParseData *data, ViviCodeLabel *label)
+{
+  GSList *iter;
+
+  g_return_val_if_fail (data != NULL, FALSE);
+  g_return_val_if_fail (data->level != NULL, FALSE);
+  g_return_val_if_fail (VIVI_IS_CODE_LABEL (label), FALSE);
+
+  for (iter = data->level->labels; iter != NULL; iter = iter->next) {
+    if (g_str_equal (vivi_code_label_get_name (VIVI_CODE_LABEL (iter->data)),
+	  vivi_code_label_get_name (label)))
+      return FALSE;
+  }
+
+  data->level->labels =
+    g_slist_prepend (data->level->labels, g_object_ref (label));
+
+  return TRUE;
+}
+
+// values
+
+/* ActionScript specific */
+static ParseStatus
+parse_undefined_literal (ParseData *data, ViviCodeValue **value)
+{
+  *value = NULL;
+
+  if (!check_token (data, TOKEN_UNDEFINED))
+    return CANCEL (TOKEN_UNDEFINED);
+
+  *value = vivi_code_constant_new_undefined ();
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_null_literal (ParseData *data, ViviCodeValue **value)
+{
+  *value = NULL;
+
+  if (!check_token (data, TOKEN_NULL))
+    return CANCEL (TOKEN_NULL);
+
+  *value = vivi_code_constant_new_null ();
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_boolean_literal (ParseData *data, ViviCodeValue **value)
+{
+  *value = NULL;
+
+  if (!check_token (data, TOKEN_BOOLEAN))
+    return CANCEL (TOKEN_BOOLEAN);
+
+  *value = vivi_code_constant_new_boolean (data->scanner->value.v_boolean);
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_numeric_literal (ParseData *data, ViviCodeValue **value)
+{
+  *value = NULL;
+
+  if (!check_token (data, TOKEN_NUMBER))
+    return CANCEL (TOKEN_NUMBER);
+
+  *value = vivi_code_constant_new_number (data->scanner->value.v_number);
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_string_literal (ParseData *data, ViviCodeValue **value)
+{
+  *value = NULL;
+
+  if (!check_token (data, TOKEN_STRING))
+    return CANCEL (TOKEN_STRING);
+
+  *value = vivi_code_constant_new_string (data->scanner->value.v_string);
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_literal (ParseData *data, ViviCodeValue **value)
+{
+  ParseStatus status;
+  int i;
+  ParseValueFunction functions[] = {
+    parse_undefined_literal,
+    parse_null_literal,
+    parse_boolean_literal,
+    parse_numeric_literal,
+    parse_string_literal,
+    NULL
+  };
+
+  *value = NULL;
+
+  for (i = 0; functions[i] != NULL; i++) {
+    status = functions[i] (data, value);
+    if (status != STATUS_CANCEL)
+      return status;
+  }
+
+  return CANCEL (ERROR_TOKEN_LITERAL);
+}
+
+static ParseStatus
+parse_identifier (ParseData *data, ViviCodeValue **value)
+{
+  *value = NULL;
+
+  if (!check_token (data, TOKEN_IDENTIFIER))
+    return CANCEL (TOKEN_IDENTIFIER);
+
+  *value = vivi_code_get_new_name (data->scanner->value.v_identifier);
+
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_property_name (ParseData *data, ViviCodeValue **value)
+{
+  ParseStatus status;
+  int i;
+  ParseValueFunction functions[] = {
+    parse_identifier,
+    parse_string_literal,
+    parse_numeric_literal,
+    NULL
+  };
+
+  *value = NULL;
+
+  for (i = 0; functions[i] != NULL; i++) {
+    status = functions[i] (data, value);
+    if (status != STATUS_CANCEL)
+      return status;
+  }
+
+  return CANCEL (ERROR_TOKEN_PROPERTY_NAME);
+}
+
+static ParseStatus
+parse_assignment_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement);
+
+static ParseStatus
+parse_array_literal (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement)
+{
+  ViviCodeValue *member;
+  ViviCodeStatement *statement_new;
+  ParseStatus status;
+
+  *value = NULL;
+  *statement = NULL;
+
+  if (!check_token (data, TOKEN_BRACKET_LEFT))
+    return CANCEL (TOKEN_BRACKET_LEFT);
+
+  *value = vivi_code_init_array_new ();
+
+  while (TRUE) {
+    if (check_token (data, TOKEN_BRACKET_RIGHT)) {
+      vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
+	 vivi_code_constant_new_undefined ());
+      break;
+    } else if (check_token (data, TOKEN_COMMA)) {
+      vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
+	 vivi_code_constant_new_undefined ());
+    } else {
+      status = parse_assignment_expression (data, &member, &statement_new);
+      if (status != STATUS_OK) {
+	if (*statement != NULL) {
+	  g_object_unref (*statement);
+	  *statement = NULL;
+	}
+	return FAIL_CHILD (status);
+      }
+
+      *statement = vivi_parser_join_statements (*statement, statement_new);
+
+      vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
+	  member);
+      g_object_unref (member);
+
+      if (!check_token (data, TOKEN_COMMA)) {
+	if (!check_token (data, TOKEN_BRACKET_RIGHT)) {
+	  return FAIL_OR (TOKEN_BRACKET_RIGHT, TOKEN_COMMA);
+	}
+	break;
+      }
+    }
+  }
+
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_object_literal (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement)
+{
+  ParseStatus status;
+
+  *value = NULL;
+  *statement = NULL;
+
+  if (!check_token (data, TOKEN_BRACE_LEFT))
+    return CANCEL (TOKEN_BRACE_LEFT);
+
+  *value = vivi_code_init_object_new ();
+
+  if (!check_token (data, TOKEN_BRACE_RIGHT)) {
+    do {
+      ViviCodeValue *property, *initializer;
+      ViviCodeStatement *statement_new;
+
+      status = parse_property_name (data, &property);
+      if (status != STATUS_OK) {
+	g_object_unref (*value);
+	*value = NULL;
+	if (*statement != NULL) {
+	  g_object_unref (*statement);
+	  *statement = NULL;
+	}
+	return FAIL_CHILD (status);
+      }
+
+      if (!check_token (data, TOKEN_COLON)) {
+	g_object_unref (*value);
+	*value = NULL;
+	if (*statement != NULL) {
+	  g_object_unref (*statement);
+	  *statement = NULL;
+	}
+	return FAIL (TOKEN_COLON);
+      }
+
+      status = parse_assignment_expression (data, &initializer,
+	  &statement_new);
+      if (status != STATUS_OK) {
+	g_object_unref (*value);
+	*value = NULL;
+	if (*statement != NULL) {
+	  g_object_unref (*statement);
+	  *statement = NULL;
+	}
+	return FAIL_CHILD (status);
+      }
+
+      *statement = vivi_parser_join_statements (*statement, statement_new);
+
+      vivi_code_init_object_add_variable (VIVI_CODE_INIT_OBJECT (*value),
+	  property, initializer);
+    } while (check_token (data, TOKEN_COMMA));
+  }
+
+  if (!check_token (data, TOKEN_BRACE_RIGHT)) {
+    g_object_unref (*value);
+    *value = NULL;
+    if (*statement != NULL) {
+      g_object_unref (*statement);
+      *statement = NULL;
+    }
+    return FAIL (TOKEN_BRACE_RIGHT);
+  }
+
+  return STATUS_OK;
+}
+
+// misc
+
+static ParseStatus
+parse_variable_declaration (ParseData *data, ViviCodeStatement **statement)
+{
+  ParseStatus status;
+  ViviCodeValue *identifier, *value;
+  ViviCodeStatement *assignment, *statement_right;
+
+  *statement = NULL;
+
+  status = parse_identifier (data, &identifier);
+  if (status != STATUS_OK)
+    return status;
+
+  if (check_token (data, TOKEN_ASSIGN)) {
+    status = parse_assignment_expression (data, &value, &statement_right);
+    if (status != STATUS_OK) {
+      g_object_unref (identifier);
+      return FAIL_CHILD (status);
+    }
+  } else {
+    value = vivi_code_constant_new_undefined ();
+    statement_right = NULL;
+  }
+
+  assignment = vivi_parser_assignment_new (identifier, value);
+  vivi_code_assignment_set_local (VIVI_CODE_ASSIGNMENT (assignment), TRUE);
+
+  *statement = vivi_parser_join_statements (statement_right, assignment);
+
+  return STATUS_OK;
+}
+
+// expression
+
+static ParseStatus
+parse_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement);
+
+static ParseStatus
+parse_primary_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement)
+{
+  ParseStatus status;
+  int i;
+  ParseValueFunction functions[] = {
+    parse_identifier,
+    parse_literal,
+    NULL
+  };
+
+  *value = NULL;
+  *statement = NULL;
+
+  if (check_token (data, TOKEN_THIS)) {
+    *value = vivi_code_get_new_name ("this");
+    return STATUS_OK;
+  }
+
+  if (check_token (data, TOKEN_PARENTHESIS_LEFT)) {
+    status = parse_expression (data, value, statement);
+    if (status != STATUS_OK)
+      return FAIL_CHILD (status);
+    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+      g_object_unref (*value);
+      *value = NULL;
+      return FAIL (TOKEN_PARENTHESIS_RIGHT);
+    }
+    return STATUS_OK;
+  }
+
+
+  status = parse_object_literal (data, value, statement);
+  if (status != STATUS_CANCEL)
+    return status;
+
+  status = parse_array_literal (data, value, statement);
+  if (status != STATUS_CANCEL)
+    return status;
+
+  for (i = 0; functions[i] != NULL; i++) {
+    status = functions[i] (data, value);
+    if (status != STATUS_CANCEL)
+      return status;
+  }
+
+  return CANCEL (ERROR_TOKEN_PRIMARY_EXPRESSION);
+}
+
+static ParseStatus
+parse_function_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement);
+
+static ParseStatus
+parse_member_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement)
+{
+  ParseStatus status;
+  ViviCodeValue *member;
+  ViviCodeStatement *statement_member;
+
+  *value = NULL;
+  *statement = NULL;
+
+  // TODO: new MemberExpression Arguments
+
+  status = parse_primary_expression (data, value, statement);
+  if (status == STATUS_CANCEL)
+    status = parse_function_expression (data, value, statement);
+
+  if (status != STATUS_OK)
+    return status;
+
+  do {
+    ViviCodeValue *tmp;
+
+    if (check_token (data, TOKEN_BRACKET_LEFT)) {
+      status = parse_expression (data, &member, &statement_member);
+      if (status != STATUS_OK) {
+	g_object_unref (*value);
+	*value = NULL;
+	if (*statement != NULL) {
+	  g_object_unref (*statement);
+	  *statement = NULL;
+	}
+	return FAIL_CHILD (status);
+      }
+
+      *statement =
+	vivi_parser_join_statements (*statement, statement_member);
+
+      if (!check_token (data, TOKEN_BRACKET_RIGHT)) {
+	g_object_unref (*value);
+	*value = NULL;
+	if (*statement != NULL) {
+	  g_object_unref (*statement);
+	  *statement = NULL;
+	}
+	return FAIL (TOKEN_BRACKET_RIGHT);
+      }
+    } else if (check_token (data, TOKEN_DOT)) {
+      status = parse_identifier (data, &member);
+      if (status != STATUS_OK)
+	return FAIL_CHILD (status);
+    } else {
+      return STATUS_OK;
+    }
+
+    tmp = *value;
+    *value = vivi_parser_get_new (tmp, member);
+    g_object_unref (tmp);
+    g_object_unref (member);
+  } while (TRUE);
+
+  g_assert_not_reached ();
+}
+
+static ParseStatus
+parse_new_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement)
+{
+  ParseStatus status;
+
+  *value = NULL;
+  *statement = NULL;
+
+  if (check_token (data, TOKEN_NEW)) {
+    status = parse_new_expression (data, value, statement);
+    if (status != STATUS_OK)
+      return FAIL_CHILD (status);
+    if (!VIVI_IS_CODE_FUNCTION_CALL (*value)) {
+      ViviCodeValue *tmp = VIVI_CODE_VALUE (*value);
+      *value = vivi_parser_function_call_new (tmp);
+      g_object_unref (tmp);
+    }
+    vivi_code_function_call_set_construct (VIVI_CODE_FUNCTION_CALL (*value),
+	TRUE);
+    return STATUS_OK;
+  } else {
+    return parse_member_expression (data, value, statement);
+  }
+}
+
+static ParseStatus
+parse_left_hand_side_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement)
+{
+  ParseStatus status;
+  int i;
+  ViviCodeValue *name;
+  ViviCodeValue **arguments;
+  ViviCodeStatement *argument_statement;
+
+  *value = NULL;
+  *statement = NULL;
+
+  if (check_token (data, TOKEN_NEW)) {
+    status = parse_new_expression (data, value, statement);
+    if (status != STATUS_OK)
+      return FAIL_CHILD (status);
+    if (!VIVI_IS_CODE_FUNCTION_CALL (*value)) {
+      ViviCodeValue *tmp = VIVI_CODE_VALUE (*value);
+      *value = vivi_parser_function_call_new (tmp);
+      g_object_unref (tmp);
+    }
+    vivi_code_function_call_set_construct (VIVI_CODE_FUNCTION_CALL (*value),
+	TRUE);
+    return STATUS_OK;
+  }
+
+  status = parse_member_expression (data, value, statement);
+  if (status != STATUS_OK)
+    return status;
+
+  while (TRUE) {
+    // TODO: member expressions?
+    if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
+      break;
+
+    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+      status = parse_value_statement_list (data, parse_assignment_expression,
+	  &arguments, &argument_statement, TOKEN_COMMA);
+      if (status != STATUS_OK) {
+	g_object_unref (*value);
+	*value = NULL;
+	if (*statement != NULL) {
+	  g_object_unref (*statement);
+	  *statement = NULL;
+	}
+	return FAIL_CHILD (status);
+      }
+
+      *statement =
+	vivi_parser_join_statements (*statement, argument_statement);
+
+      if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+	g_object_unref (*value);
+	*value = NULL;
+	if (*statement != NULL) {
+	  g_object_unref (*statement);
+	  *statement = NULL;
+	}
+	return FAIL (TOKEN_PARENTHESIS_RIGHT);
+      }
+    } else {
+      arguments = NULL;
+    }
+
+    name = *value;
+    *value = vivi_parser_function_call_new (name);
+    g_object_unref (name);
+
+    if (arguments != NULL) {
+      for (i = 0; arguments[i] != NULL; i++) {
+	vivi_code_function_call_add_argument (VIVI_CODE_FUNCTION_CALL (*value),
+	    arguments[i]);
+      }
+      free_value_list (arguments);
+    }
+  }
+
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_postfix_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement)
+{
+  ParseStatus status;
+  ViviCodeValue *operation, *one, *temporary;
+  const char *operator;
+
+  *value = NULL;
+  *statement = NULL;
+
+  status = parse_left_hand_side_expression (data, value, statement);
+  if (status != STATUS_OK)
+    return status;
+
+  if (check_line_terminator (data))
+    return status;
+
+  if (check_token (data, TOKEN_INCREASE)) {
+    operator = "+";
+  } else if (check_token (data, TOKEN_DESCREASE)) {
+    operator = "-";
+  } else {
+    return STATUS_OK;
+  }
+
+  if (!vivi_parser_value_is_left_hand_side (*value)) {
+    g_object_unref (*value);
+    *value = NULL;
+    if (*statement != NULL) {
+      g_object_unref (*statement);
+      *statement = NULL;
+    }
+    return CANCEL_CUSTOM (g_strdup ("INCREASE/DECREASE not allowed here"));
+  }
+
+  one = vivi_code_constant_new_number (1);
+  operation = vivi_code_binary_new_name (*value, one, operator);
+  g_object_unref (one);
+
+  temporary = vivi_compiler_get_temporary_new ();
+  *statement = vivi_parser_join_statements (*statement,
+      vivi_parser_join_statements (
+	vivi_parser_assignment_new (temporary, *value),
+	vivi_parser_assignment_new (*value, operation)));
+  g_object_unref (operation);
+
+  g_object_unref (*value);
+  *value = temporary;
+
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_unary_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement)
+{
+  ParseStatus status;
+  ViviCodeValue *tmp, *one;
+  const char *operator;
+
+  *value = NULL;
+
+  operator = NULL;
+
+  vivi_parser_scanner_peek_next_token (data->scanner);
+  switch ((guint)data->scanner->next_token) {
+    /*case TOKEN_DELETE:
+    case TOKEN_VOID:
+    case TOKEN_TYPEOF:*/
+    case TOKEN_INCREASE:
+      operator = "+";
+      // fall through
+    case TOKEN_DESCREASE:
+      if (!operator) operator = "-";
+
+      vivi_parser_scanner_get_next_token (data->scanner);
+      status = parse_unary_expression (data, value, statement);
+      if (status != STATUS_OK)
+	return FAIL_CHILD (status);
+
+      if (!vivi_parser_value_is_left_hand_side (*value))
+	return CANCEL_CUSTOM (g_strdup ("INCREASE/DECREASE not allowed here"));
+
+      one = vivi_code_constant_new_number (1);
+      tmp = vivi_code_binary_new_name (*value, one, operator);
+      g_object_unref (one);
+
+      *statement = vivi_parser_join_statements (*statement,
+	  vivi_parser_assignment_new (*value, tmp));
+      g_object_unref (tmp);
+
+      return STATUS_OK;
+    /*case TOKEN_PLUS:
+    case TOKEN_MINUS:
+    case TOKEN_BITWISE_NOT:*/
+    case TOKEN_LOGICAL_NOT:
+      vivi_parser_scanner_get_next_token (data->scanner);
+      status = parse_unary_expression (data, value, statement);
+      if (status != STATUS_OK)
+	return FAIL_CHILD (status);
+      tmp = VIVI_CODE_VALUE (*value);
+      *value = vivi_code_unary_new (tmp, '!');
+      g_object_unref (tmp);
+      return STATUS_OK;
+    default:
+      return parse_postfix_expression (data, value, statement);
+  }
+}
+
+typedef enum {
+  PASS_ALWAYS,
+  PASS_LOGICAL_OR,
+  PASS_LOGICAL_AND
+} ParseOperatorPass;
+
+static ParseStatus
+parse_operator_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement, const ViviParserScannerToken *tokens,
+    ParseOperatorPass pass, ParseValueStatementFunction next_parse_function)
+{
+  ParseStatus status;
+  int i;
+  ViviCodeValue *left, *right;
+  ViviCodeStatement *statement_right;
+
+  *value = NULL;
+  *statement = NULL;
+
+  status = next_parse_function (data, value, statement);
+  if (status != STATUS_OK)
+    return status;
+
+  for (i = 0; tokens[i] != STATUS_OK; i++) {
+    while (check_token (data, tokens[i])) {
+      status = next_parse_function (data, &right, &statement_right);
+      if (status != STATUS_OK) {
+	g_object_unref (*value);
+	*value = NULL;
+	return FAIL_CHILD (status);
+      }
+
+      if (statement_right != NULL) {
+	ViviCodeStatement *tmp;
+
+	switch (pass) {
+	  case PASS_LOGICAL_OR:
+	    tmp = vivi_code_if_new (vivi_code_unary_new (*value, '!'));
+	    vivi_code_if_set_if (VIVI_CODE_IF (tmp), statement_right);
+	    g_object_unref (statement_right);
+	    statement_right = tmp;
+	    break;
+	  case PASS_LOGICAL_AND:
+	    tmp = vivi_code_if_new (*value);
+	    vivi_code_if_set_if (VIVI_CODE_IF (tmp), statement_right);
+	    g_object_unref (statement_right);
+	    statement_right = tmp;
+	    break;
+	  case PASS_ALWAYS:
+	    // nothing
+	    break;
+	  default:
+	    g_assert_not_reached ();
+	}
+
+	*statement =
+	  vivi_parser_join_statements (*statement, statement_right);
+      }
+
+      left = VIVI_CODE_VALUE (*value);
+      *value = vivi_code_binary_new_name (left, VIVI_CODE_VALUE (right),
+	  vivi_parser_scanner_token_name (tokens[i]));
+      g_object_unref (left);
+      g_object_unref (right);
+    };
+  }
+
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_multiplicative_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement)
+{
+  static const ViviParserScannerToken tokens[] = { TOKEN_MULTIPLY,
+    TOKEN_DIVIDE, TOKEN_REMAINDER, TOKEN_NONE };
+
+  return parse_operator_expression (data, value, statement, tokens,
+      PASS_ALWAYS, parse_unary_expression);
+}
+
+static ParseStatus
+parse_additive_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement)
+{
+  static const ViviParserScannerToken tokens[] = { TOKEN_PLUS, TOKEN_MINUS,
+    TOKEN_NONE };
+
+  return parse_operator_expression (data, value, statement, tokens,
+      PASS_ALWAYS, parse_multiplicative_expression);
+}
+
+static ParseStatus
+parse_shift_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement)
+{
+  static const ViviParserScannerToken tokens[] = { TOKEN_SHIFT_LEFT,
+    TOKEN_SHIFT_RIGHT, TOKEN_SHIFT_RIGHT_UNSIGNED, TOKEN_NONE };
+
+  return parse_operator_expression (data, value, statement, tokens,
+      PASS_ALWAYS, parse_additive_expression);
+}
+
+static ParseStatus
+parse_relational_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement)
+{
+  static const ViviParserScannerToken tokens[] = { TOKEN_LESS_THAN,
+    TOKEN_GREATER_THAN, /*TOKEN_LESS_THAN_OR_EQUAL,
+    TOKEN_EQUAL_OR_GREATER_THAN, TOKEN_INSTANCEOF, TOKEN_IN,*/ TOKEN_NONE };
+
+  return parse_operator_expression (data, value, statement, tokens,
+      PASS_ALWAYS, parse_shift_expression);
+}
+
+static ParseStatus
+parse_equality_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement)
+{
+  static const ViviParserScannerToken tokens[] = { TOKEN_EQUAL,
+    /*TOKEN_NOT_EQUAL,*/ TOKEN_STRICT_EQUAL, /*TOKEN_NOT_STRICT_EQUAL,*/
+    TOKEN_NONE };
+
+  return parse_operator_expression (data, value, statement, tokens,
+      PASS_ALWAYS, parse_relational_expression);
+}
+
+static ParseStatus
+parse_bitwise_and_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement)
+{
+  static const ViviParserScannerToken tokens[] = { TOKEN_BITWISE_AND,
+    TOKEN_NONE };
+
+  return parse_operator_expression (data, value, statement, tokens,
+      PASS_ALWAYS, parse_equality_expression);
+}
+
+static ParseStatus
+parse_bitwise_xor_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement)
+{
+  static const ViviParserScannerToken tokens[] = { TOKEN_BITWISE_XOR,
+    TOKEN_NONE };
+
+  return parse_operator_expression (data, value, statement, tokens,
+      PASS_ALWAYS, parse_bitwise_and_expression);
+}
+
+static ParseStatus
+parse_bitwise_or_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement)
+{
+  static const ViviParserScannerToken tokens[] = { TOKEN_BITWISE_OR,
+    TOKEN_NONE };
+
+  return parse_operator_expression (data, value, statement, tokens,
+      PASS_ALWAYS, parse_bitwise_xor_expression);
+}
+
+static ParseStatus
+parse_logical_and_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement)
+{
+  static const ViviParserScannerToken tokens[] = { TOKEN_LOGICAL_AND,
+    TOKEN_NONE };
+
+  return parse_operator_expression (data, value, statement, tokens,
+      PASS_LOGICAL_AND, parse_bitwise_or_expression);
+}
+
+static ParseStatus
+parse_logical_or_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement)
+{
+  static const ViviParserScannerToken tokens[] = { TOKEN_LOGICAL_OR,
+    TOKEN_NONE };
+
+  return parse_operator_expression (data, value, statement, tokens,
+      PASS_LOGICAL_OR, parse_logical_and_expression);
+}
+
+static ParseStatus
+parse_conditional_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement)
+{
+  ParseStatus status;
+  //ViviCodeStatement *if_statement, *else_statement;
+
+  *value = NULL;
+
+  status = parse_logical_or_expression (data, value, statement);
+  if (status != STATUS_OK)
+    return status;
+
+#if 0
+  if (!check_token (data, TOKEN_QUESTION_MARK)) {
+    *statement = vivi_code_value_statement_new (VIVI_CODE_VALUE (value));
+    g_object_unref (value);
+    return STATUS_OK;
+  }
+
+  status = parse_assignment_expression (data, &if_statement);
+  if (status != STATUS_OK) {
+    g_object_unref (value);
+    return FAIL_CHILD (status);
+  }
+
+  if (!check_token (data, TOKEN_COLON)) {
+    g_object_unref (value);
+    g_object_unref (if_statement);
+    return TOKEN_COLON;
+  }
+
+  status = parse_assignment_expression (data, &else_statement);
+  if (status != STATUS_OK) {
+    g_object_unref (value);
+    g_object_unref (if_statement);
+    return FAIL_CHILD (status);
+  }
+
+  *statement = vivi_code_if_new (value);
+  vivi_code_if_set_if (VIVI_CODE_IF (*statement), if_statement);
+  vivi_code_if_set_else (VIVI_CODE_IF (*statement), else_statement);
+
+  g_object_unref (value);
+  g_object_unref (if_statement);
+  g_object_unref (else_statement);
+#endif
+
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_assignment_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement)
+{
+  ParseStatus status;
+  ViviCodeValue *right;
+  ViviCodeStatement *assignment, *statement_right;
+  const char *operator;
+
+  *value = NULL;
+  *statement = NULL;
+
+  status = parse_conditional_expression (data, value, statement);
+  if (status != STATUS_OK)
+    return status;
+
+  if (!vivi_parser_value_is_left_hand_side (*value))
+    return STATUS_OK;
+
+  operator = NULL;
+
+  vivi_parser_scanner_peek_next_token (data->scanner);
+  switch ((int)data->scanner->next_token) {
+    case TOKEN_ASSIGN_MULTIPLY:
+      if (operator == NULL) operator = "*";
+    case TOKEN_ASSIGN_DIVIDE:
+      if (operator == NULL) operator = "/";
+    case TOKEN_ASSIGN_REMAINDER:
+      if (operator == NULL) operator = "%";
+    case TOKEN_ASSIGN_ADD:
+      if (operator == NULL) operator = "+";
+    case TOKEN_ASSIGN_MINUS:
+      if (operator == NULL) operator = "-";
+    case TOKEN_ASSIGN_SHIFT_LEFT:
+      if (operator == NULL) operator = "<<";
+    case TOKEN_ASSIGN_SHIFT_RIGHT:
+      if (operator == NULL) operator = ">>";
+    case TOKEN_ASSIGN_SHIFT_RIGHT_ZERO:
+      if (operator == NULL) operator = ">>>";
+    case TOKEN_ASSIGN_BITWISE_AND:
+      if (operator == NULL) operator = "&";
+    case TOKEN_ASSIGN_BITWISE_OR:
+      if (operator == NULL) operator = "|";
+    case TOKEN_ASSIGN_BITWISE_XOR:
+      if (operator == NULL) operator = "^";
+    case TOKEN_ASSIGN:
+      vivi_parser_scanner_get_next_token (data->scanner);
+      status = parse_assignment_expression (data, &right,
+	  &statement_right);
+      if (status != STATUS_OK) {
+	g_object_unref (*value);
+	*value = NULL;
+	return FAIL_CHILD (status);
+      }
+
+      if (operator != NULL) {
+	assignment = vivi_parser_assignment_new (*value,
+	    vivi_code_binary_new_name (*value, right, operator));
+      } else {
+	assignment = vivi_parser_assignment_new (*value, right);
+      }
+      g_object_unref (right);
+
+      *statement = vivi_parser_join_statements (*statement,
+	  vivi_parser_join_statements (statement_right, assignment));
+
+      break;
+    default:
+      return STATUS_OK;
+  }
+
+
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement)
+{
+  ViviCodeStatement *statement_one;
+  ParseStatus status;
+
+  *statement = NULL;
+
+  status = parse_assignment_expression (data, value, &statement_one);
+  if (status != STATUS_OK)
+    return status;
+
+  while (TRUE) {
+    *statement = vivi_parser_join_statements (*statement, statement_one);
+
+    if (!check_token (data, TOKEN_COMMA))
+      break;
+
+    g_object_unref (*value);
+
+    status = parse_assignment_expression (data, value, &statement_one);
+    if (status != STATUS_OK) {
+      g_object_unref (*value);
+      *value = NULL;
+      g_object_unref (*statement);
+      *statement = NULL;
+      return FAIL_CHILD (status);
+    }
+  }
+
+  return STATUS_OK;
+}
+
+// statement
+
+static ParseStatus
+parse_statement (ParseData *data, ViviCodeStatement **statement);
+
+static ParseStatus
+parse_trace_statement (ParseData *data, ViviCodeStatement **statement)
+{
+  ViviCodeValue *value;
+  ViviCodeStatement *expression_statement;
+  ParseStatus status;
+
+  *statement = NULL;
+
+  if (!check_token (data, TOKEN_TRACE))
+    return CANCEL (TOKEN_TRACE);
+
+  if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
+    return FAIL (TOKEN_PARENTHESIS_LEFT);
+
+  status = parse_expression (data, &value, &expression_statement);
+  if (status != STATUS_OK)
+    return FAIL_CHILD (status);
+
+  if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+    g_object_unref (value);
+    if (expression_statement != NULL)
+      g_object_unref (expression_statement);
+    return FAIL (TOKEN_PARENTHESIS_RIGHT);
+  }
+
+  if (!check_automatic_semicolon (data)) {
+    g_object_unref (value);
+    if (expression_statement != NULL)
+      g_object_unref (expression_statement);
+    return FAIL (TOKEN_SEMICOLON);
+  }
+
+  *statement = vivi_code_trace_new (value);
+  g_object_unref (value);
+
+  *statement =
+    vivi_parser_join_statements (expression_statement, *statement);
+
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_continue_or_break_statement (ParseData *data,
+    ViviCodeStatement **statement, ViviParserScannerToken token)
+{
+  *statement = NULL;
+
+  if (!check_token (data, token))
+    return CANCEL (token);
+
+  if (!check_restricted_semicolon (data)) {
+    ParseStatus status;
+    ViviCodeValue *identifier;
+
+    status = parse_identifier (data, &identifier);
+    *statement = vivi_compiler_goto_name_new (
+	vivi_code_constant_get_variable_name (
+	  VIVI_CODE_CONSTANT (VIVI_CODE_GET (identifier)->name)));
+    g_object_unref (identifier);
+
+    vivi_parser_add_goto (data, VIVI_COMPILER_GOTO_NAME (*statement));
+
+    if (!check_automatic_semicolon (data)) {
+      g_object_unref (*statement);
+      *statement = NULL;
+      return FAIL (TOKEN_SEMICOLON);
+    }
+  } else {
+    *statement = vivi_code_break_new ();
+  }
+
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_continue_statement (ParseData *data, ViviCodeStatement **statement)
+{
+  return parse_continue_or_break_statement (data, statement, TOKEN_CONTINUE);
+}
+
+static ParseStatus
+parse_break_statement (ParseData *data, ViviCodeStatement **statement)
+{
+  return parse_continue_or_break_statement (data, statement, TOKEN_BREAK);
+}
+
+static ParseStatus
+parse_throw_statement (ParseData *data, ViviCodeStatement **statement)
+{
+  ParseStatus status;
+  ViviCodeValue *value;
+  ViviCodeStatement *expression_statement;
+
+  *statement = NULL;
+
+  if (!check_token (data, TOKEN_THROW))
+    return CANCEL (TOKEN_THROW);
+
+  if (check_line_terminator (data))
+    return FAIL_LINE_TERMINATOR (ERROR_TOKEN_EXPRESSION);
+
+  status = parse_expression (data, &value, &expression_statement);
+  if (status != STATUS_OK)
+    return FAIL_CHILD (status);
+
+  *statement = vivi_code_throw_new (value);
+  g_object_unref (value);
+
+  *statement =
+    vivi_parser_join_statements (expression_statement, *statement);
+
+  if (!check_automatic_semicolon (data)) {
+    g_object_unref (*statement);
+    *statement = NULL;
+    return FAIL (TOKEN_SEMICOLON);
+  }
+
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_return_statement (ParseData *data, ViviCodeStatement **statement)
+{
+  *statement = NULL;
+
+  if (!check_token (data, TOKEN_RETURN))
+    return CANCEL (TOKEN_RETURN);
+
+  *statement = vivi_code_return_new ();
+
+  if (!check_restricted_semicolon (data)) {
+    ParseStatus status;
+    ViviCodeValue *value;
+    ViviCodeStatement *expression_statement;
+
+    status = parse_expression (data, &value, &expression_statement);
+    if (status != STATUS_OK) {
+      g_object_unref (*statement);
+      *statement = NULL;
+      return FAIL_CHILD (status);
+    }
+
+    vivi_code_return_set_value (VIVI_CODE_RETURN (*statement), value);
+    g_object_unref (value);
+
+    *statement =
+      vivi_parser_join_statements (expression_statement, *statement);
+
+    if (!check_automatic_semicolon (data)) {
+      g_object_unref (*statement);
+      *statement = NULL;
+      return FAIL (TOKEN_SEMICOLON);
+    }
+  }
+
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
+{
+  ParseStatus status;
+  ViviCodeValue *condition;
+  ViviCodeStatement *pre_statement, *condition_statement, *loop_statement;
+
+  *statement = NULL;
+
+  pre_statement = NULL;
+  condition_statement = NULL;
+
+  if (check_token (data, TOKEN_DO)) {
+    status = parse_statement (data, &loop_statement);
+    if (status != STATUS_OK)
+      return FAIL_CHILD (status);
+
+    if (!check_token (data, TOKEN_WHILE)) {
+      g_object_unref (loop_statement);
+      return FAIL (TOKEN_WHILE);
+    }
+
+    if (!check_token (data, TOKEN_PARENTHESIS_LEFT)) {
+      g_object_unref (loop_statement);
+      return FAIL (TOKEN_PARENTHESIS_LEFT);
+    }
+
+    status = parse_expression (data, &condition, &condition_statement);
+    if (status != STATUS_OK) {
+      g_object_unref (loop_statement);
+      return FAIL_CHILD (status);
+    }
+
+    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+      g_object_unref (loop_statement);
+      g_object_unref (condition);
+      if (condition_statement != NULL)
+	g_object_unref (condition_statement);
+      return FAIL (TOKEN_PARENTHESIS_LEFT);
+    }
+
+    if (!check_automatic_semicolon (data)) {
+      g_object_unref (loop_statement);
+      g_object_unref (condition);
+      if (condition_statement != NULL)
+	g_object_unref (condition_statement);
+      return FAIL (TOKEN_PARENTHESIS_LEFT);
+    }
+
+    pre_statement = g_object_ref (loop_statement);
+  } else if (check_token (data, TOKEN_WHILE)) {
+    if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
+      return FAIL (TOKEN_PARENTHESIS_LEFT);
+
+    status = parse_expression (data, &condition, &condition_statement);
+    if (status != STATUS_OK)
+      return FAIL_CHILD (status);
+
+    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+      g_object_unref (condition);
+      if (condition_statement != NULL)
+	g_object_unref (condition_statement);
+      return FAIL (TOKEN_PARENTHESIS_RIGHT);
+    }
+
+    status = parse_statement (data, &loop_statement);
+    if (status != STATUS_OK) {
+      g_object_unref (condition);
+      if (condition_statement != NULL)
+	g_object_unref (condition_statement);
+      return FAIL_CHILD (status);
+    }
+  } else if (check_token (data, TOKEN_FOR)) {
+    ViviCodeValue *pre_value;
+    ViviCodeStatement *post_statement;
+
+    if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
+      return FAIL (TOKEN_PARENTHESIS_LEFT);
+
+    if (check_token (data, TOKEN_VAR)) {
+      // FIXME: no in
+      status = parse_statement_list (data, parse_variable_declaration,
+	  &pre_statement, TOKEN_COMMA);
+      if (status != STATUS_OK)
+	return FAIL_CHILD (status);
+      // FIXME: ugly
+      // If there was only one VariableDeclaration, get the name for pre_value
+      g_assert (VIVI_IS_CODE_BLOCK (pre_statement));
+      if (vivi_code_block_get_n_statements (VIVI_CODE_BLOCK (pre_statement))
+	  == 1) {
+	ViviCodeAssignment *assignment = VIVI_CODE_ASSIGNMENT (
+	    vivi_code_block_get_statement (VIVI_CODE_BLOCK (pre_statement), 0));
+	g_assert (assignment->from == NULL);
+	pre_value = vivi_code_get_new (NULL, assignment->name);
+      } else {
+	pre_value = NULL;
+      }
+    } else {
+      if (!check_token (data, TOKEN_SEMICOLON)) {
+	// FIXME: no in
+	status = parse_expression (data, &pre_value, &pre_statement);
+	if (status != STATUS_OK)
+	  return FAIL_CHILD (status);
+      } else {
+	pre_value = NULL;
+	pre_statement = NULL;
+      }
+    }
+
+    if (check_token (data, TOKEN_SEMICOLON)) {
+      if (pre_value != NULL)
+	g_object_unref (pre_value);
+      if (!check_token (data, TOKEN_SEMICOLON)) {
+	status = parse_expression (data, &condition, &condition_statement);
+	if (status != STATUS_OK)
+	  return FAIL_CHILD (status);
+
+	if (!check_token (data, TOKEN_SEMICOLON)) {
+	  if (pre_statement != NULL)
+	    g_object_unref (pre_statement);
+	  g_object_unref (condition);
+	  if (condition_statement != NULL)
+	    g_object_unref (condition_statement);
+	  return FAIL (TOKEN_SEMICOLON);
+	}
+      }
+
+      status = parse_expression (data, &pre_value, &post_statement);
+      if (status != STATUS_OK) {
+	if (pre_statement != NULL)
+	  g_object_unref (pre_statement);
+	g_object_unref (condition);
+	if (condition_statement != NULL)
+	  g_object_unref (condition_statement);
+	return FAIL_CHILD (status);
+      }
+      g_object_unref (pre_value);
+    } else if (pre_value != NULL && check_token (data, TOKEN_IN)) {
+      post_statement = NULL;
+
+      if (!vivi_parser_value_is_left_hand_side (pre_value)) {
+	g_object_unref (pre_value);
+	if (pre_statement != NULL)
+	  g_object_unref (pre_statement);
+	return FAIL_CUSTOM (g_strdup (
+	      "Invalid left hand side expression for in"));
+      }
+
+      g_object_unref (pre_value);
+      if (pre_statement != NULL)
+	g_object_unref (pre_statement);
+      return FAIL_CUSTOM (g_strdup (
+	    "for (... in ...) has not been implemented yet"));
+    } else {
+      ViviParserScannerToken fail_token;
+
+      if (pre_value != NULL) {
+	fail_token = TOKEN_IN;
+	g_object_unref (pre_value);
+      } else {
+	fail_token = TOKEN_NONE;
+      }
+
+      if (pre_statement != NULL)
+	g_object_unref (pre_statement);
+
+      return FAIL_OR (TOKEN_SEMICOLON, fail_token);
+    }
+
+    if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+      if (pre_statement != NULL)
+	g_object_unref (pre_statement);
+      g_object_unref (condition);
+      if (condition_statement != NULL)
+	g_object_unref (condition_statement);
+      g_object_unref (post_statement);
+      return FAIL (TOKEN_PARENTHESIS_RIGHT);
+    }
+
+    status = parse_statement (data, &loop_statement);
+    if (status != STATUS_OK) {
+      if (pre_statement != NULL)
+	g_object_unref (pre_statement);
+      g_object_unref (condition);
+      if (condition_statement != NULL)
+	g_object_unref (condition_statement);
+      g_object_unref (post_statement);
+      return FAIL_CHILD (status);
+    }
+
+    loop_statement =
+      vivi_parser_join_statements (loop_statement, post_statement);
+  } else {
+    return CANCEL (ERROR_TOKEN_ITERATION_STATEMENT);
+  }
+
+  if (condition_statement != NULL) {
+    pre_statement = vivi_parser_join_statements (pre_statement,
+	g_object_ref (condition_statement));
+    loop_statement = vivi_parser_join_statements (loop_statement,
+	g_object_ref (condition_statement));
+    g_object_unref (condition_statement);
+  }
+
+  *statement = vivi_code_loop_new ();
+  vivi_code_loop_set_condition (VIVI_CODE_LOOP (*statement), condition);
+  g_object_unref (condition);
+  vivi_code_loop_set_statement (VIVI_CODE_LOOP (*statement), loop_statement);
+  g_object_unref (loop_statement);
+
+  *statement = vivi_parser_join_statements (pre_statement, *statement);
+
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_if_statement (ParseData *data, ViviCodeStatement **statement)
+{
+  ParseStatus status;
+  ViviCodeValue *condition;
+  ViviCodeStatement *pre_statement, *if_statement, *else_statement;
+
+  *statement = NULL;
+
+  if (!check_token (data, TOKEN_IF))
+    return CANCEL (TOKEN_IF);
+
+  if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
+    return FAIL (TOKEN_PARENTHESIS_LEFT);
+
+  status = parse_expression (data, &condition, &pre_statement);
+  if (status != STATUS_OK)
+    return FAIL_CHILD (status);
+
+  if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+    g_object_unref (condition);
+    if (pre_statement != NULL) {
+      g_object_unref (pre_statement);
+      pre_statement = NULL;
+    }
+    return FAIL (TOKEN_PARENTHESIS_RIGHT);
+  }
+
+  status = parse_statement (data, &if_statement);
+  if (status != STATUS_OK) {
+    g_object_unref (condition);
+    if (pre_statement != NULL) {
+      g_object_unref (pre_statement);
+      pre_statement = NULL;
+    }
+    return FAIL_CHILD (status);
+  }
+
+  if (check_token (data, TOKEN_ELSE)) {
+    status = parse_statement (data, &else_statement);
+    if (status != STATUS_OK) {
+      g_object_unref (condition);
+      if (pre_statement != NULL) {
+	g_object_unref (pre_statement);
+	pre_statement = NULL;
+      }
+      g_object_unref (if_statement);
+      return FAIL_CHILD (status);
+    }
+  } else {
+    else_statement = NULL;
+  }
+
+  *statement = vivi_code_if_new (condition);
+  g_object_unref (condition);
+
+  vivi_code_if_set_if (VIVI_CODE_IF (*statement), if_statement);
+  g_object_unref (if_statement);
+
+  if (else_statement != NULL) {
+    vivi_code_if_set_else (VIVI_CODE_IF (*statement), else_statement);
+    g_object_unref (else_statement);
+  }
+
+  *statement = vivi_parser_join_statements (pre_statement, *statement);
+
+  g_assert (*statement != NULL);
+
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_expression_statement (ParseData *data, ViviCodeStatement **statement)
+{
+  ParseStatus status;
+  ViviCodeValue *value;
+  ViviCodeStatement *last;
+
+  *statement = NULL;
+
+  vivi_parser_scanner_peek_next_token (data->scanner);
+  if (data->scanner->next_token == TOKEN_BRACE_LEFT ||
+      data->scanner->next_token == TOKEN_FUNCTION)
+    return CANCEL (ERROR_TOKEN_EXPRESSION_STATEMENT);
+
+  status = parse_expression (data, &value, statement);
+  if (status != STATUS_OK)
+    return status;
+
+  // check for label
+  if (*statement == NULL && vivi_parser_value_is_identifier (value)) {
+    if (check_token (data, TOKEN_COLON)) {
+      *statement = vivi_code_label_new (vivi_code_constant_get_variable_name (
+	    VIVI_CODE_CONSTANT (VIVI_CODE_GET (value)->name)));
+      if (!vivi_parser_add_label (data, VIVI_CODE_LABEL (*statement)))
+	return FAIL_CUSTOM (g_strdup ("Same label name used twice"));
+      return STATUS_OK;
+    }
+  }
+
+  if (!check_automatic_semicolon (data)) {
+    g_object_unref (value);
+    if (*statement != NULL) {
+      g_object_unref (*statement);
+      *statement = NULL;
+    }
+    return FAIL (TOKEN_SEMICOLON);
+  }
+
+  // add a value statement, if the last statement is not an assignment with the
+  // same value
+  if (VIVI_IS_CODE_BLOCK (*statement)) {
+    ViviCodeBlock *block = VIVI_CODE_BLOCK (*statement);
+
+    last = vivi_code_block_get_statement (block,
+	vivi_code_block_get_n_statements (block) - 1);
+  } else {
+    last = *statement;
+  }
+
+  if (VIVI_IS_CODE_ASSIGNMENT (last) && VIVI_IS_CODE_GET (value)) {
+    ViviCodeAssignment *assignment = VIVI_CODE_ASSIGNMENT (last);
+
+    if (assignment->from == NULL && assignment->name == VIVI_CODE_GET (value)->name) {
+      g_object_unref (value);
+      return STATUS_OK;
+    }
+  }
+
+  *statement = vivi_parser_join_statements (*statement,
+      vivi_code_value_statement_new (value));
+  g_object_unref (value);
+
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_empty_statement (ParseData *data, ViviCodeStatement **statement)
+{
+  *statement = NULL;
+
+  if (!check_token (data, TOKEN_SEMICOLON))
+    return CANCEL (TOKEN_SEMICOLON);
+
+  *statement = vivi_compiler_empty_statement_new ();
+
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_block (ParseData *data, ViviCodeStatement **statement)
+{
+  ParseStatus status;
+
+  *statement = NULL;
+
+  if (!check_token (data, TOKEN_BRACE_LEFT))
+    return CANCEL (TOKEN_BRACE_LEFT);
+
+  vivi_parser_scanner_peek_next_token (data->scanner);
+  if (data->scanner->next_token != TOKEN_BRACE_RIGHT) {
+    status =
+      parse_statement_list (data, parse_statement, statement, STATUS_OK);
+    if (status != STATUS_OK)
+      return FAIL_CHILD (status);
+  } else {
+    *statement = vivi_code_block_new ();
+  }
+
+  if (!check_token (data, TOKEN_BRACE_RIGHT)) {
+    g_object_unref (*statement);
+    *statement = NULL;
+    return FAIL (TOKEN_BRACE_RIGHT);
+  }
+
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_variable_statement (ParseData *data, ViviCodeStatement **statement)
+{
+  ParseStatus status;
+
+  *statement = NULL;
+
+  if (!check_token (data, TOKEN_VAR))
+    return CANCEL (TOKEN_VAR);
+
+  status = parse_statement_list (data, parse_variable_declaration, statement,
+      TOKEN_COMMA);
+  if (status != STATUS_OK)
+    return FAIL_CHILD (status);
+
+  if (!check_automatic_semicolon (data)) {
+    g_object_unref (*statement);
+    *statement = NULL;
+    return FAIL (TOKEN_SEMICOLON);
+  }
+
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_statement (ParseData *data, ViviCodeStatement **statement)
+{
+  ParseStatus status;
+  int i;
+  ParseStatementFunction functions[] = {
+    parse_block,
+    parse_variable_statement,
+    parse_empty_statement,
+    parse_expression_statement,
+    parse_if_statement,
+    parse_iteration_statement,
+    parse_continue_statement,
+    parse_break_statement,
+    parse_return_statement,
+    //parse_with_statement,
+    //parse_switch_statement,
+    parse_throw_statement,
+    //parse_try_statement,
+    parse_trace_statement,
+    NULL
+  };
+
+  *statement = NULL;
+
+  for (i = 0; functions[i] != NULL; i++) {
+    status = functions[i] (data, statement);
+    if (status != STATUS_CANCEL)
+      return status;
+  }
+
+  return CANCEL (ERROR_TOKEN_STATEMENT);
+}
+
+// function
+
+static ParseStatus
+parse_source_element (ParseData *data, ViviCodeStatement **statement);
+
+static ParseStatus
+parse_function_definition (ParseData *data, ViviCodeValue **function,
+    ViviCodeValue **identifier, gboolean identifier_required)
+{
+  ParseStatus status;
+  ViviCodeValue **arguments;
+  ViviCodeStatement *body;
+  guint i;
+
+  *function = NULL;
+  *identifier = NULL;
+
+  arguments = NULL;
+  body = NULL;
+
+  if (!check_token (data, TOKEN_FUNCTION))
+    return CANCEL (TOKEN_FUNCTION);
+
+  status = parse_identifier (data, identifier);
+  if (status == STATUS_FAIL ||
+      (identifier_required && status == STATUS_CANCEL))
+    return FAIL_CHILD (status);
+
+  if (!check_token (data, TOKEN_PARENTHESIS_LEFT)) {
+    g_object_unref (*identifier);
+    return FAIL (TOKEN_PARENTHESIS_LEFT);
+  }
+
+  status = parse_value_list (data, parse_identifier, &arguments, TOKEN_COMMA);
+  if (status == STATUS_FAIL) {
+    g_object_unref (*identifier);
+    return STATUS_FAIL;
+  }
+
+  if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+    g_object_unref (*identifier);
+    if (arguments != NULL)
+      free_value_list (arguments);
+    return FAIL (TOKEN_PARENTHESIS_RIGHT);
+  }
+
+  if (!check_token (data, TOKEN_BRACE_LEFT)) {
+    g_object_unref (*identifier);
+    if (arguments != NULL)
+      free_value_list (arguments);
+    return FAIL (TOKEN_BRACE_LEFT);
+  }
+
+  vivi_parser_start_level (data);
+
+  status = parse_statement_list (data, parse_source_element, &body, STATUS_OK);
+  if (status == STATUS_FAIL) {
+    vivi_parser_end_level (data, FALSE);
+    g_object_unref (*identifier);
+    if (arguments != NULL)
+      free_value_list (arguments);
+    return STATUS_FAIL;
+  }
+
+  status = vivi_parser_end_level (data, TRUE);
+  if (status != STATUS_OK) {
+    g_object_unref (*identifier);
+    if (arguments != NULL)
+      free_value_list (arguments);
+    return FAIL_CHILD (status);
+  }
+
+  if (!check_token (data, TOKEN_BRACE_RIGHT)) {
+    g_object_unref (*identifier);
+    if (arguments != NULL)
+      free_value_list (arguments);
+    g_object_unref (body);
+    return FAIL (TOKEN_BRACE_RIGHT);
+  }
+
+  *function = vivi_code_function_new ();
+  if (body != NULL) {
+    vivi_code_function_set_body (VIVI_CODE_FUNCTION (*function), body);
+    g_object_unref (body);
+  }
+  if (arguments != NULL) {
+    for (i = 0; arguments[i] != NULL; i++) {
+      vivi_code_function_add_argument (VIVI_CODE_FUNCTION (*function),
+	  vivi_code_constant_get_variable_name (VIVI_CODE_CONSTANT (
+	      VIVI_CODE_GET (arguments[i])->name)));
+    }
+    free_value_list (arguments);
+  }
+
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_function_declaration (ParseData *data, ViviCodeStatement **statement)
+{
+  ParseStatus status;
+  ViviCodeValue *function, *identifier;
+
+  *statement = NULL;
+
+  status = parse_function_definition (data, &function, &identifier, TRUE);
+  if (status != STATUS_OK)
+    return status;
+
+  *statement = vivi_parser_assignment_new (identifier, function);
+  g_object_unref (identifier);
+  g_object_unref (function);
+
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_function_expression (ParseData *data, ViviCodeValue **value,
+    ViviCodeStatement **statement)
+{
+  ParseStatus status;
+  ViviCodeValue *identifier;
+
+  *statement = NULL;
+
+  status = parse_function_definition (data, value, &identifier, FALSE);
+  if (status != STATUS_OK)
+    return status;
+
+  if (identifier != NULL) {
+    *statement = vivi_parser_assignment_new (identifier, *value);
+    g_object_unref (identifier);
+  }
+
+  return STATUS_OK;
+}
+
+// top
+
+static ParseStatus
+parse_source_element (ParseData *data, ViviCodeStatement **statement)
+{
+  ParseStatus status;
+
+  *statement = NULL;
+
+  status = parse_function_declaration (data, statement);
+  if (status == STATUS_CANCEL)
+    status = parse_statement (data, statement);
+
+  return status;
+}
+
+static ParseStatus
+parse_program (ParseData *data, ViviCodeStatement **statement)
+{
+  ParseStatus status;
+
+  g_assert (data->level == NULL);
+  vivi_parser_start_level (data);
+
+  *statement = NULL;
+
+  status =
+    parse_statement_list (data, parse_source_element, statement, STATUS_OK);
+  if (status != STATUS_OK) {
+    vivi_parser_end_level (data, FALSE);
+    return FAIL_CHILD (status);
+  }
+
+  if (!check_token (data, TOKEN_EOF)) {
+    vivi_parser_end_level (data, FALSE);
+    g_object_unref (*statement);
+    *statement = NULL;
+    status = parse_statement (data, statement);
+    return FAIL_CHILD (status);
+  }
+
+
+  status = vivi_parser_end_level (data, TRUE);
+  if (status != STATUS_OK) {
+    g_object_unref (*statement);
+    *statement = NULL;
+    return FAIL_CHILD (status);
+  }
+
+  g_assert (data->level == NULL);
+
+  return STATUS_OK;
+}
+
+// parsing
+
+static ParseStatus
+parse_statement_list (ParseData *data, ParseStatementFunction function,
+    ViviCodeStatement **block, guint separator)
+{
+  ViviCodeStatement *statement;
+  ParseStatus status;
+
+  g_assert (data != NULL);
+  g_assert (function != NULL);
+  g_assert (block != NULL);
+
+  *block = NULL;
+
+  status = function (data, &statement);
+  if (status != STATUS_OK)
+    return status;
+
+  *block = vivi_code_block_new ();
+
+  do {
+    vivi_code_block_add_statement (VIVI_CODE_BLOCK (*block), statement);
+    g_object_unref (statement);
+
+    if (separator != STATUS_OK && !check_token (data, separator))
+      break;
+
+    status = function (data, &statement);
+    if (status == STATUS_FAIL) {
+      g_object_unref (*block);
+      *block = NULL;
+      return STATUS_FAIL;
+    }
+  } while (status == STATUS_OK);
+
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_value_statement_list (ParseData *data,
+    ParseValueStatementFunction function, ViviCodeValue ***list,
+    ViviCodeStatement **statement, guint separator)
+{
+  GPtrArray *array;
+  ViviCodeValue *value;
+  ViviCodeStatement *statement_one;
+  ParseStatus status;
+
+  g_assert (data != NULL);
+  g_assert (function != NULL);
+  g_assert (list != NULL);
+  g_assert (statement != NULL);
+
+  *list = NULL;
+  *statement = NULL;
+
+  status = function (data, &value, statement);
+  if (status != STATUS_OK)
+    return status;
+
+  array = g_ptr_array_new ();
+
+  do {
+    g_ptr_array_add (array, value);
+
+    if (separator != TOKEN_NONE && !check_token (data, separator))
+      break;
+
+    status = function (data, &value, &statement_one);
+    if (status != STATUS_OK) {
+      if (status == STATUS_FAIL || separator != TOKEN_NONE)
+	return FAIL_CHILD (status);
+    } else {
+      *statement = vivi_parser_join_statements (*statement, statement_one);
+    }
+  } while (status == STATUS_OK);
+  g_ptr_array_add (array, NULL);
+
+  *list = (ViviCodeValue **)g_ptr_array_free (array, FALSE);
+
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_value_list (ParseData *data, ParseValueFunction function,
+    ViviCodeValue ***list, guint separator)
+{
+  GPtrArray *array;
+  ViviCodeValue *value;
+  ParseStatus status;
+
+  g_assert (data != NULL);
+  g_assert (function != NULL);
+  g_assert (list != NULL);
+
+  *list = NULL;
+
+  status = function (data, &value);
+  if (status != STATUS_OK)
+    return status;
+
+  array = g_ptr_array_new ();
+
+  do {
+    g_ptr_array_add (array, value);
+
+    if (separator != STATUS_OK && !check_token (data, separator))
+      break;
+
+    status = function (data, &value);
+    if (status == STATUS_FAIL)
+      return STATUS_FAIL;
+  } while (status == STATUS_OK);
+  g_ptr_array_add (array, NULL);
+
+  *list = (ViviCodeValue **)g_ptr_array_free (array, FALSE);
+
+  return STATUS_OK;
+}
+
+// public
+
+ViviCodeStatement *
+vivi_parse_file (FILE *file, const char *input_name)
+{
+  ParseData data;
+  ViviCodeStatement *statement;
+  ParseStatus status;
+
+  g_return_val_if_fail (file != NULL, NULL);
+
+  data.scanner = vivi_parser_scanner_new (file);
+  data.unexpected_line_terminator = FALSE;
+  data.expected[0] = TOKEN_NONE;
+  data.expected[1] = TOKEN_NONE;
+  data.custom_error = NULL;
+  data.levels = NULL;
+  data.level = NULL;
+
+  status = parse_program (&data, &statement);
+  g_assert ((status == STATUS_OK && VIVI_IS_CODE_STATEMENT (statement)) ||
+	(status != STATUS_OK && statement == NULL));
+  g_assert (status >= 0);
+
+  if (status != STATUS_OK) {
+    g_printerr ("%s:%i:%i: error: ", input_name,
+	vivi_parser_scanner_cur_line (data.scanner),
+	vivi_parser_scanner_cur_column (data.scanner));
+
+    if (data.custom_error != NULL) {
+      g_printerr ("%s\n", data.custom_error);
+      g_free (data.custom_error);
+    } else {
+      vivi_parser_scanner_get_next_token (data.scanner);
+
+      g_printerr ("Expected %s ", vivi_parser_token_name (data.expected[0]));
+      if (data.expected[1] != TOKEN_NONE)
+	g_printerr ("or %s ", vivi_parser_token_name (data.expected[1]));
+
+      if (data.unexpected_line_terminator) {
+	g_printerr ("before %s token\n",
+	    vivi_parser_token_name (TOKEN_LINE_TERMINATOR));
+      } else {
+	g_printerr ("before %s token\n",
+	    vivi_parser_token_name (data.scanner->token));
+      }
+    }
+  }
+
+  g_object_unref (data.scanner);
+
+  return statement;
+}
diff --git a/vivified/code/vivi_parser.h b/vivified/code/vivi_parser.h
new file mode 100644
index 0000000..82cbe89
--- /dev/null
+++ b/vivified/code/vivi_parser.h
@@ -0,0 +1,36 @@
+/* Vivified
+ * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_DECOMPILER_H_
+#define _VIVI_DECOMPILER_H_
+
+#include <stdio.h>
+
+#include <swfdec/swfdec.h>
+#include <vivified/code/vivi_code_statement.h>
+
+G_BEGIN_DECLS
+
+
+ViviCodeStatement *	vivi_parse_file			(FILE *		file,
+							 const char *	input_name);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_parser_scanner.c b/vivified/code/vivi_parser_scanner.c
new file mode 100644
index 0000000..97a3a29
--- /dev/null
+++ b/vivified/code/vivi_parser_scanner.c
@@ -0,0 +1,310 @@
+/* Vivified
+ * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_parser_scanner.h"
+
+#include "vivi_parser_scanner_lex.h"
+#include "vivi_parser_scanner_lex_include.h"
+
+G_DEFINE_TYPE (ViviParserScanner, vivi_parser_scanner, G_TYPE_OBJECT)
+
+static void
+vivi_parser_scanner_free_type_value (ViviParserScannerValue *value)
+{
+  switch (value->type) {
+    case VALUE_TYPE_STRING:
+      g_free (value->v_string);
+      break;
+    case VALUE_TYPE_IDENTIFIER:
+      g_free (value->v_identifier);
+      break;
+    case VALUE_TYPE_NONE:
+    case VALUE_TYPE_BOOLEAN:
+    case VALUE_TYPE_NUMBER:
+      /* nothing */
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+
+  value->type = VALUE_TYPE_NONE;
+}
+
+static void
+vivi_parser_scanner_dispose (GObject *object)
+{
+  ViviParserScanner *scanner = VIVI_PARSER_SCANNER (object);
+
+  vivi_parser_scanner_free_type_value (&scanner->value);
+  vivi_parser_scanner_free_type_value (&scanner->next_value);
+
+  G_OBJECT_CLASS (vivi_parser_scanner_parent_class)->dispose (object);
+}
+
+static void
+vivi_parser_scanner_class_init (ViviParserScannerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = vivi_parser_scanner_dispose;
+}
+
+static void
+vivi_parser_scanner_init (ViviParserScanner *token)
+{
+}
+
+static const struct {
+  ViviParserScannerToken	token;
+  const char *			name;
+} token_names[] = {
+  // special
+  { TOKEN_NONE, "NONE" },
+  { TOKEN_EOF, "EOF" },
+  { TOKEN_ERROR, "ERROR" },
+  { TOKEN_UNKNOWN, "UNKNOWN" },
+  { TOKEN_LINE_TERMINATOR, "NEW LINE" },
+
+  // comparision
+  { TOKEN_BRACE_LEFT, "{", },
+  { TOKEN_BRACE_RIGHT, "}", },
+  { TOKEN_BRACKET_LEFT, "[", },
+  { TOKEN_BRACKET_RIGHT, "]", },
+  { TOKEN_PARENTHESIS_LEFT, "(", },
+  { TOKEN_PARENTHESIS_RIGHT, ")", },
+
+  // punctuation
+  { TOKEN_DOT, ".", },
+  { TOKEN_SEMICOLON, ";" },
+  { TOKEN_COMMA, "," },
+
+  // comparision
+  { TOKEN_LESS_THAN, "<" },
+  { TOKEN_GREATER_THAN, ">" },
+  { TOKEN_LESS_THAN_OR_EQUAL, "<=" },
+  { TOKEN_EQUAL_OR_GREATER_THAN, "=>" },
+
+  // equality
+  { TOKEN_EQUAL, "=" },
+  { TOKEN_NOT_EQUAL, "!=" },
+  { TOKEN_STRICT_EQUAL, "===" },
+  { TOKEN_NOT_STRICT_EQUAL, "!==" },
+
+  // operator
+  { TOKEN_PLUS, "+" },
+  { TOKEN_MINUS, "-" },
+  { TOKEN_MULTIPLY, "*" },
+  { TOKEN_DIVIDE, "/" },
+  { TOKEN_REMAINDER, "%" },
+
+  // shift
+  { TOKEN_SHIFT_LEFT, "<<" },
+  { TOKEN_SHIFT_RIGHT, ">>" },
+  { TOKEN_SHIFT_RIGHT_UNSIGNED, ">>>" },
+
+  // bitwise
+  { TOKEN_BITWISE_AND, "&" },
+  { TOKEN_BITWISE_OR, "|" },
+  { TOKEN_BITWISE_XOR, "^" },
+  
+  // unary/postfix
+  { TOKEN_LOGICAL_NOT, "!" },
+  { TOKEN_BITWISE_NOT, "~" },
+  { TOKEN_INCREASE, "++" },
+  { TOKEN_DESCREASE, "--" },
+
+  // conditional
+  { TOKEN_QUESTION_MARK, "?" },
+  { TOKEN_COLON, ":" },
+
+  // logical
+  { TOKEN_LOGICAL_AND, "&&" },
+  { TOKEN_LOGICAL_OR, "||" },
+
+  // assign
+  { TOKEN_ASSIGN, "=" },
+  { TOKEN_ASSIGN_MULTIPLY, "*=" },
+  { TOKEN_ASSIGN_DIVIDE, "/=" },
+  { TOKEN_ASSIGN_REMAINDER, "%=" },
+  { TOKEN_ASSIGN_ADD, "+=" },
+  { TOKEN_ASSIGN_MINUS, "-=" },
+  { TOKEN_ASSIGN_SHIFT_LEFT, "<<=" },
+  { TOKEN_ASSIGN_SHIFT_RIGHT, ">>=" },
+  { TOKEN_ASSIGN_SHIFT_RIGHT_ZERO, ">>>=" },
+  { TOKEN_ASSIGN_BITWISE_AND, "&=" },
+  { TOKEN_ASSIGN_BITWISE_XOR, "^=" },
+  { TOKEN_ASSIGN_BITWISE_OR, "|=" },
+
+  // values
+  { TOKEN_NULL, "NULL" },
+  { TOKEN_BOOLEAN, "BOOLEAN" },
+  { TOKEN_NUMBER, "NUMBER" },
+  { TOKEN_STRING, "STRING" },
+  { TOKEN_IDENTIFIER, "IDENTIFIER" },
+
+  // keywords
+  { TOKEN_BREAK, "break" },
+  { TOKEN_CASE, "case" },
+  { TOKEN_CATCH, "catch" },
+  { TOKEN_CONTINUE, "continue" },
+  { TOKEN_DEFAULT, "default" },
+  { TOKEN_DELETE, "delete" },
+  { TOKEN_DO, "do" },
+  { TOKEN_ELSE, "else" },
+  { TOKEN_FINALLY, "finally" },
+  { TOKEN_FOR, "for" },
+  { TOKEN_FUNCTION, "function" },
+  { TOKEN_IF, "if" },
+  { TOKEN_IN, "in" },
+  { TOKEN_INSTANCEOF, "instanceof" },
+  { TOKEN_NEW, "new" },
+  { TOKEN_RETURN, "return" },
+  { TOKEN_SWITCH, "switch" },
+  { TOKEN_THIS, "this" },
+  { TOKEN_THROW, "throw" },
+  { TOKEN_TRY, "try" },
+  { TOKEN_TYPEOF, "typeof" },
+  { TOKEN_VAR, "var" },
+  { TOKEN_VOID, "void" },
+  { TOKEN_WHILE, "while" },
+  { TOKEN_WITH, "with" },
+
+  // reserved keywords
+  { TOKEN_RESERVED_KEYWORD, "RESERVED KEYWORD" },
+
+  // ActionScript specific
+  { TOKEN_UNDEFINED, "undefined" },
+  { TOKEN_TRACE, "trace" },
+
+  { TOKEN_LAST, NULL }
+};
+
+const char *vivi_parser_scanner_token_name (ViviParserScannerToken token)
+{
+  int i;
+
+  for (i = 0; token_names[i].token != TOKEN_LAST; i++) {
+    if (token_names[i].token == token)
+      return token_names[i].name;
+  }
+
+  g_assert_not_reached ();
+
+  return "INVALID TOKEN";
+}
+
+static void
+vivi_parser_scanner_advance (ViviParserScanner *scanner)
+{
+  g_return_if_fail (VIVI_IS_PARSER_SCANNER (scanner));
+
+  vivi_parser_scanner_free_type_value (&scanner->value);
+
+  scanner->token = scanner->next_token;
+  scanner->value = scanner->next_value;
+  scanner->line_number = scanner->next_line_number;
+  scanner->line_terminator = scanner->next_line_terminator;
+
+  if (scanner->file == NULL) {
+    scanner->next_token = TOKEN_EOF;
+    scanner->next_value.v_string = NULL;
+  } else {
+    scanner->next_token = yylex ();
+    if (scanner->next_token == TOKEN_LINE_TERMINATOR) {
+      scanner->next_line_terminator = TRUE;
+    } else {
+      scanner->next_line_terminator = FALSE;
+    }
+    while (scanner->next_token == TOKEN_LINE_TERMINATOR) {
+      scanner->next_token = yylex ();
+    }
+    scanner->next_value = lex_value;
+    scanner->next_line_number = lex_line_number;
+    lex_value.type = VALUE_TYPE_NONE;
+  }
+}
+
+ViviParserScanner *
+vivi_parser_scanner_new (FILE *file)
+{
+  ViviParserScanner *scanner;
+
+  g_return_val_if_fail (file != NULL, NULL);
+
+  scanner = g_object_new (VIVI_TYPE_PARSER_SCANNER, NULL);
+  scanner->file = file;
+  scanner->line_number = scanner->next_line_number = lex_line_number = 1;
+
+  yyrestart (file);
+
+  vivi_parser_scanner_advance (scanner);
+
+  return scanner;
+}
+
+ViviParserScannerToken
+vivi_parser_scanner_get_next_token (ViviParserScanner *scanner)
+{
+  g_return_val_if_fail (VIVI_IS_PARSER_SCANNER (scanner), TOKEN_EOF);
+
+  vivi_parser_scanner_advance (scanner);
+
+  return scanner->token;
+}
+
+ViviParserScannerToken
+vivi_parser_scanner_peek_next_token (ViviParserScanner *scanner)
+{
+  g_return_val_if_fail (VIVI_IS_PARSER_SCANNER (scanner), TOKEN_EOF);
+
+  return scanner->next_token;
+}
+
+guint
+vivi_parser_scanner_cur_line (ViviParserScanner *scanner)
+{
+  g_return_val_if_fail (VIVI_IS_PARSER_SCANNER (scanner), 0);
+
+  return scanner->line_number;
+}
+
+guint
+vivi_parser_scanner_cur_column (ViviParserScanner *scanner)
+{
+  g_return_val_if_fail (VIVI_IS_PARSER_SCANNER (scanner), 0);
+
+  // TODO
+
+  return 0;
+}
+
+char *
+vivi_parser_scanner_get_line (ViviParserScanner *scanner)
+{
+  g_return_val_if_fail (VIVI_IS_PARSER_SCANNER (scanner), 0);
+
+  // TODO
+
+  return g_strdup ("");
+}
diff --git a/vivified/code/vivi_parser_scanner.h b/vivified/code/vivi_parser_scanner.h
new file mode 100644
index 0000000..4e7bd30
--- /dev/null
+++ b/vivified/code/vivi_parser_scanner.h
@@ -0,0 +1,216 @@
+/* Vivified
+ * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_PARSER_SCANNER_H_
+#define _VIVI_PARSER_SCANNER_H_
+
+#include <stdio.h>
+#include <swfdec/swfdec.h>
+
+G_BEGIN_DECLS
+
+
+typedef enum {
+  // special
+  TOKEN_NONE = 0,
+  TOKEN_EOF,
+  TOKEN_ERROR,
+  TOKEN_UNKNOWN,
+  TOKEN_LINE_TERMINATOR,
+
+  // comparision
+  TOKEN_BRACE_LEFT,
+  TOKEN_BRACE_RIGHT,
+  TOKEN_BRACKET_LEFT,
+  TOKEN_BRACKET_RIGHT,
+  TOKEN_PARENTHESIS_LEFT,
+  TOKEN_PARENTHESIS_RIGHT,
+
+  // punctuation
+  TOKEN_DOT,
+  TOKEN_SEMICOLON,
+  TOKEN_COMMA,
+
+  // comparision
+  TOKEN_LESS_THAN,
+  TOKEN_GREATER_THAN,
+  TOKEN_LESS_THAN_OR_EQUAL,
+  TOKEN_EQUAL_OR_GREATER_THAN,
+
+  // equality
+  TOKEN_EQUAL,
+  TOKEN_NOT_EQUAL,
+  TOKEN_STRICT_EQUAL,
+  TOKEN_NOT_STRICT_EQUAL,
+
+  // operator
+  TOKEN_PLUS,
+  TOKEN_MINUS,
+  TOKEN_MULTIPLY,
+  TOKEN_DIVIDE,
+  TOKEN_REMAINDER,
+
+  // shift
+  TOKEN_SHIFT_LEFT,
+  TOKEN_SHIFT_RIGHT,
+  TOKEN_SHIFT_RIGHT_UNSIGNED,
+
+  // bitwise
+  TOKEN_BITWISE_AND,
+  TOKEN_BITWISE_OR,
+  TOKEN_BITWISE_XOR,
+  
+  // unary/postfix
+  TOKEN_LOGICAL_NOT,
+  TOKEN_BITWISE_NOT,
+  TOKEN_INCREASE,
+  TOKEN_DESCREASE,
+
+  // conditional
+  TOKEN_QUESTION_MARK,
+  TOKEN_COLON,
+
+  // logical
+  TOKEN_LOGICAL_AND,
+  TOKEN_LOGICAL_OR,
+
+  // assign
+  TOKEN_ASSIGN,
+  TOKEN_ASSIGN_MULTIPLY,
+  TOKEN_ASSIGN_DIVIDE,
+  TOKEN_ASSIGN_REMAINDER,
+  TOKEN_ASSIGN_ADD,
+  TOKEN_ASSIGN_MINUS,
+  TOKEN_ASSIGN_SHIFT_LEFT,
+  TOKEN_ASSIGN_SHIFT_RIGHT,
+  TOKEN_ASSIGN_SHIFT_RIGHT_ZERO,
+  TOKEN_ASSIGN_BITWISE_AND,
+  TOKEN_ASSIGN_BITWISE_XOR,
+  TOKEN_ASSIGN_BITWISE_OR,
+
+  // values
+  TOKEN_NULL,
+  TOKEN_BOOLEAN,
+  TOKEN_NUMBER,
+  TOKEN_STRING,
+  TOKEN_IDENTIFIER,
+
+  // keywords
+  TOKEN_BREAK,
+  TOKEN_CASE,
+  TOKEN_CATCH,
+  TOKEN_CONTINUE,
+  TOKEN_DEFAULT,
+  TOKEN_DELETE,
+  TOKEN_DO,
+  TOKEN_ELSE,
+  TOKEN_FINALLY,
+  TOKEN_FOR,
+  TOKEN_FUNCTION,
+  TOKEN_IF,
+  TOKEN_IN,
+  TOKEN_INSTANCEOF,
+  TOKEN_NEW,
+  TOKEN_RETURN,
+  TOKEN_SWITCH,
+  TOKEN_THIS,
+  TOKEN_THROW,
+  TOKEN_TRY,
+  TOKEN_TYPEOF,
+  TOKEN_VAR,
+  TOKEN_VOID,
+  TOKEN_WHILE,
+  TOKEN_WITH,
+
+  // reserved keywords
+  TOKEN_RESERVED_KEYWORD,
+
+  // ActionScript specific
+  TOKEN_UNDEFINED,
+  TOKEN_TRACE,
+
+  TOKEN_LAST
+} ViviParserScannerToken;
+
+typedef enum {
+  VALUE_TYPE_NONE,
+  VALUE_TYPE_BOOLEAN,
+  VALUE_TYPE_NUMBER,
+  VALUE_TYPE_STRING,
+  VALUE_TYPE_IDENTIFIER
+} ViviParserScannerValueType;
+
+typedef struct {
+  ViviParserScannerValueType	type;
+  union {
+    gboolean	v_boolean;
+    double	v_number;
+    char *	v_string;
+    char *	v_identifier;
+  };
+} ViviParserScannerValue;
+
+typedef struct _ViviParserScanner ViviParserScanner;
+typedef struct _ViviParserScannerClass ViviParserScannerClass;
+
+#define VIVI_TYPE_PARSER_SCANNER                    (vivi_parser_scanner_get_type())
+#define VIVI_IS_PARSER_SCANNER(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_PARSER_SCANNER))
+#define VIVI_IS_PARSER_SCANNER_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_PARSER_SCANNER))
+#define VIVI_PARSER_SCANNER(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_PARSER_SCANNER, ViviParserScanner))
+#define VIVI_PARSER_SCANNER_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_PARSER_SCANNER, ViviParserScannerClass))
+#define VIVI_PARSER_SCANNER_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_PARSER_SCANNER, ViviParserScannerClass))
+
+struct _ViviParserScanner
+{
+  GObject			object;
+
+  FILE *			file;
+
+  ViviParserScannerToken	token;
+  ViviParserScannerToken	next_token;
+  guint				line_number;
+  gboolean			line_terminator;
+
+  ViviParserScannerValue	value;
+  ViviParserScannerValue	next_value;
+  guint				next_line_number;
+  gboolean			next_line_terminator;
+
+  ViviParserScannerToken	expected;
+};
+
+struct _ViviParserScannerClass
+{
+  GObjectClass		object_class;
+};
+
+GType				vivi_parser_scanner_get_type   	(void);
+
+ViviParserScanner *		vivi_parser_scanner_new		(FILE *		file);
+ViviParserScannerToken	vivi_parser_scanner_get_next_token	(ViviParserScanner *	scanner);
+ViviParserScannerToken	vivi_parser_scanner_peek_next_token	(ViviParserScanner *	scanner);
+
+const char *			vivi_parser_scanner_token_name	(ViviParserScannerToken token);
+guint				vivi_parser_scanner_cur_line	(ViviParserScanner *scanner);
+guint				vivi_parser_scanner_cur_column	(ViviParserScanner *scanner);
+char *				vivi_parser_scanner_get_line	(ViviParserScanner *scanner);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_parser_scanner_lex.h b/vivified/code/vivi_parser_scanner_lex.h
new file mode 100644
index 0000000..ff2a155
--- /dev/null
+++ b/vivified/code/vivi_parser_scanner_lex.h
@@ -0,0 +1,315 @@
+/* Vivified
+ * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef yyHEADER_H
+#define yyHEADER_H 1
+#define yyIN_HEADER 1
+
+#line 6 "vivi_parser_scanner_lex.h"
+
+#line 8 "vivi_parser_scanner_lex.h"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 34
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int yyleng;
+
+extern FILE *yyin, *yyout;
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ * Given that the standard has decreed that size_t exists since 1989,
+ * I guess we can afford to depend on it. Manoj.
+ */
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+void yyrestart (FILE *input_file  );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size  );
+void yy_delete_buffer (YY_BUFFER_STATE b  );
+void yy_flush_buffer (YY_BUFFER_STATE b  );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer  );
+void yypop_buffer_state (void );
+
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len  );
+
+void *yyalloc (yy_size_t  );
+void *yyrealloc (void *,yy_size_t  );
+void yyfree (void *  );
+
+/* Begin user sect3 */
+
+extern int yylineno;
+
+extern char *yytext;
+#define yytext_ptr yytext
+
+#ifdef YY_HEADER_EXPORT_START_CONDITIONS
+#define INITIAL 0
+
+#endif
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap (void );
+#else
+extern int yywrap (void );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (void);
+
+#define YY_DECL int yylex (void)
+#endif /* !YY_DECL */
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+#line 148 "vivi_parser_scanner_lex.l"
+
+
+#line 295 "vivi_parser_scanner_lex.h"
+#undef yyIN_HEADER
+#endif /* yyHEADER_H */
diff --git a/vivified/code/vivi_parser_scanner_lex.l b/vivified/code/vivi_parser_scanner_lex.l
new file mode 100644
index 0000000..4b96c41
--- /dev/null
+++ b/vivified/code/vivi_parser_scanner_lex.l
@@ -0,0 +1,284 @@
+%{
+/* Vivified
+ * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#include "vivi_parser_scanner_lex_include.h"
+%}
+
+%option			noyywrap
+%option			nostdinit
+%option			never-interactive
+
+identifier_start	[$_a-zA-Z]
+identifier_part		[$_a-zA-Z0-9]
+
+%x			str
+%x			comment
+
+%%
+
+			GString *string = NULL;
+
+<<EOF>>			{ return TOKEN_EOF; }
+
+"/*"			{ BEGIN(comment); }
+<comment>{
+  <<EOF>>		{
+			  BEGIN(INITIAL);
+			  return TOKEN_ERROR;
+			}
+  [^*\n]*		/* skip */
+  \n			{ lex_line_number++; }
+  "*/"			{ BEGIN(INITIAL); }
+}
+"//"[^\r\n]*		{
+			  lex_line_number++;
+			  return TOKEN_LINE_TERMINATOR;
+			}
+
+[ \t]			/* skip */
+
+\r\n			{
+			  lex_line_number++;
+			  return TOKEN_LINE_TERMINATOR;
+			}
+[\r\n]			{
+			  lex_line_number++;
+			  return TOKEN_LINE_TERMINATOR;
+			}
+
+"{"			{ return TOKEN_BRACE_LEFT; }
+"}"			{ return TOKEN_BRACE_RIGHT; }
+"["			{ return TOKEN_BRACKET_LEFT; }
+"]"			{ return TOKEN_BRACKET_RIGHT; }
+"("			{ return TOKEN_PARENTHESIS_LEFT; }
+")"			{ return TOKEN_PARENTHESIS_RIGHT; }
+
+"."			{ return TOKEN_DOT; }
+";"			{ return TOKEN_SEMICOLON; }
+","			{ return TOKEN_COMMA; }
+
+"<"			{ return TOKEN_LESS_THAN; }
+">"			{ return TOKEN_GREATER_THAN; }
+"<="			{ return TOKEN_LESS_THAN_OR_EQUAL; }
+"=>"			{ return TOKEN_EQUAL_OR_GREATER_THAN; }
+
+"==",			{ return TOKEN_EQUAL; }
+"!=",			{ return TOKEN_NOT_EQUAL; }
+"===",			{ return TOKEN_STRICT_EQUAL; }
+"!==",			{ return TOKEN_NOT_STRICT_EQUAL; }
+
+"+"			{ return TOKEN_PLUS; }
+"-"			{ return TOKEN_MINUS; }
+"*"			{ return TOKEN_MULTIPLY; }
+"/"			{ return TOKEN_DIVIDE; }
+"%"			{ return TOKEN_REMAINDER; }
+
+"<<"			{ return TOKEN_SHIFT_LEFT; }
+">>"			{ return TOKEN_SHIFT_RIGHT; }
+">>>"			{ return TOKEN_SHIFT_RIGHT_UNSIGNED; }
+
+"&"			{ return TOKEN_BITWISE_AND; }
+"|"			{ return TOKEN_BITWISE_OR; }
+"^"			{ return TOKEN_BITWISE_XOR; }
+
+"!"			{ return TOKEN_LOGICAL_NOT; }
+"~"			{ return TOKEN_BITWISE_NOT; }
+"++"			{ return TOKEN_INCREASE; }
+"--"			{ return TOKEN_DESCREASE; }
+
+"?"			{ return TOKEN_QUESTION_MARK; }
+":"			{ return TOKEN_COLON; }
+
+"&&"			{ return TOKEN_LOGICAL_AND; }
+"||"			{ return TOKEN_LOGICAL_OR; }
+
+"="			{ return TOKEN_ASSIGN; }
+"*="			{ return TOKEN_ASSIGN_MULTIPLY; }
+"/="			{ return TOKEN_ASSIGN_DIVIDE; }
+"%="			{ return TOKEN_ASSIGN_REMAINDER; }
+"+="			{ return TOKEN_ASSIGN_ADD; }
+"-="			{ return TOKEN_ASSIGN_MINUS; }
+"<<="			{ return TOKEN_ASSIGN_SHIFT_LEFT; }
+">>="			{ return TOKEN_ASSIGN_SHIFT_RIGHT; }
+">>>="			{ return TOKEN_ASSIGN_SHIFT_RIGHT_ZERO; }
+"&="			{ return TOKEN_ASSIGN_BITWISE_AND; }
+"^="			{ return TOKEN_ASSIGN_BITWISE_XOR; }
+"|="			{ return TOKEN_ASSIGN_BITWISE_OR; }
+
+"break"			{ return TOKEN_BREAK; }
+"case"			{ return TOKEN_CASE; }
+"catch"			{ return TOKEN_CATCH; }
+"continue"		{ return TOKEN_CONTINUE; }
+"default"		{ return TOKEN_DEFAULT; }
+"delete"		{ return TOKEN_DELETE; }
+"do"			{ return TOKEN_DO; }
+"else"			{ return TOKEN_ELSE; }
+"finally"		{ return TOKEN_FINALLY; }
+"for"			{ return TOKEN_FOR; }
+"function"		{ return TOKEN_FUNCTION; }
+"if"			{ return TOKEN_IF; }
+"in"			{ return TOKEN_IN; }
+"instanceof"		{ return TOKEN_INSTANCEOF; }
+"new"			{ return TOKEN_NEW; }
+"return"		{ return TOKEN_RETURN; }
+"switch"		{ return TOKEN_SWITCH; }
+"this"			{ return TOKEN_THIS; }
+"throw"			{ return TOKEN_THROW; }
+"try"			{ return TOKEN_TRY; }
+"typeof"		{ return TOKEN_TYPEOF; }
+"var"			{ return TOKEN_VAR; }
+"void"			{ return TOKEN_VOID; }
+"while"			{ return TOKEN_WHILE; }
+"with"			{ return TOKEN_WITH; }
+
+"abstract"		{ return TOKEN_RESERVED_KEYWORD; }
+"boolean"		{ return TOKEN_RESERVED_KEYWORD; }
+"byte"			{ return TOKEN_RESERVED_KEYWORD; }
+"char"			{ return TOKEN_RESERVED_KEYWORD; }
+"class"			{ return TOKEN_RESERVED_KEYWORD; }
+"const"			{ return TOKEN_RESERVED_KEYWORD; }
+"debugger"		{ return TOKEN_RESERVED_KEYWORD; }
+"double"		{ return TOKEN_RESERVED_KEYWORD; }
+"enum"			{ return TOKEN_RESERVED_KEYWORD; }
+"export"		{ return TOKEN_RESERVED_KEYWORD; }
+"extends"		{ return TOKEN_RESERVED_KEYWORD; }
+"final"			{ return TOKEN_RESERVED_KEYWORD; }
+"float"			{ return TOKEN_RESERVED_KEYWORD; }
+"goto"			{ return TOKEN_RESERVED_KEYWORD; }
+"implements"		{ return TOKEN_RESERVED_KEYWORD; }
+"import"		{ return TOKEN_RESERVED_KEYWORD; }
+"int"			{ return TOKEN_RESERVED_KEYWORD; }
+"interface"		{ return TOKEN_RESERVED_KEYWORD; }
+"long"			{ return TOKEN_RESERVED_KEYWORD; }
+"native"		{ return TOKEN_RESERVED_KEYWORD; }
+"package"		{ return TOKEN_RESERVED_KEYWORD; }
+"private"		{ return TOKEN_RESERVED_KEYWORD; }
+"protected"		{ return TOKEN_RESERVED_KEYWORD; }
+"public"		{ return TOKEN_RESERVED_KEYWORD; }
+"short"			{ return TOKEN_RESERVED_KEYWORD; }
+"static"		{ return TOKEN_RESERVED_KEYWORD; }
+"super"			{ return TOKEN_RESERVED_KEYWORD; }
+"synchronized"		{ return TOKEN_RESERVED_KEYWORD; }
+"throws"		{ return TOKEN_RESERVED_KEYWORD; }
+"transient"		{ return TOKEN_RESERVED_KEYWORD; }
+"volatile"		{ return TOKEN_RESERVED_KEYWORD; }
+
+"undefined"		{ return TOKEN_UNDEFINED; }
+"trace"			{ return TOKEN_TRACE; }
+
+"null"			{ return TOKEN_NULL; }
+"true"			{
+			  lex_value.type = VALUE_TYPE_BOOLEAN;
+			  lex_value.v_boolean = 1;
+			  return TOKEN_BOOLEAN;
+			}
+"false"			{
+			  lex_value.type = VALUE_TYPE_BOOLEAN;
+			  lex_value.v_boolean = 0;
+			  return TOKEN_BOOLEAN;
+			}
+
+0[xX][0-9a-fA-F]+	{
+			  lex_value.type = VALUE_TYPE_NUMBER;
+			  lex_value.v_number =
+			    g_ascii_strtoull (yytext, NULL, 16);
+			  return TOKEN_NUMBER;
+			}
+
+([1-9][0-9]*|0)(\.[0-9]*)?([eE][+-]?[0-9]+)? {
+			  lex_value.type = VALUE_TYPE_NUMBER;
+			  lex_value.v_number = g_ascii_strtod (yytext, NULL);
+			  return TOKEN_NUMBER;
+			}
+
+\.[0-9]+([eE][+-]?[0-9]+)? {
+			  lex_value.type = VALUE_TYPE_NUMBER;
+			  lex_value.v_number = g_ascii_strtod (yytext, NULL);
+			  return TOKEN_NUMBER;
+			}
+
+\"			{
+			  string = g_string_new ("");
+			  BEGIN(str);
+			}
+
+<str>{
+  \"			{
+			  BEGIN(INITIAL);
+			  lex_value.type = VALUE_TYPE_STRING;
+			  lex_value.v_string = g_string_free (string, FALSE);
+			  return TOKEN_STRING;
+			}
+  \n			{
+			  BEGIN(INITIAL);
+			  g_string_free (string, TRUE);
+			  return TOKEN_ERROR;
+			}
+  \\0			{ g_string_append_c (string, '0'); }
+  \\[0-7]{1,3}		{
+			  guint64 result;
+			  result = g_ascii_strtoull (yytext + 1, NULL, 8);
+			  if (result > 0xff || result == 0) {
+			    BEGIN(INITIAL);
+			    g_string_free (string, TRUE);
+			    return TOKEN_ERROR;
+			  } else {
+			    g_string_append_c (string, result);
+			  }
+			}
+  \\[0-9]+		{
+			  g_string_free (string, TRUE);
+			  return TOKEN_ERROR;
+			}
+  \\x[0-9a-fA-F]{2}	{
+			  guint64 result;
+			  result = g_ascii_strtoull (yytext + 2, NULL, 16);
+			  if (result == 0) {
+			    BEGIN(INITIAL);
+			    g_string_free (string, TRUE);
+			    return TOKEN_ERROR;
+			  } else {
+			    g_string_append_c (string, result);
+			  }
+			}
+  \\b			{ g_string_append_c (string, '\b'); }
+  \\f			{ g_string_append_c (string, '\f'); }
+  \\n			{ g_string_append_c (string, '\n'); }
+  \\r			{ g_string_append_c (string, '\r'); }
+  \\t			{ g_string_append_c (string, '\t'); }
+  \\v			{ g_string_append_c (string, '\v'); }
+  \\.			{ g_string_append_c (string, yytext[1]); }
+  [^\\\n\"]+		{
+			  char *p;
+			  for (p = yytext; *p != '\0'; p++) {
+			    g_string_append_c (string, *p);
+			  }
+			}
+}
+
+{identifier_start}({identifier_part})* {
+  			  lex_value.type = VALUE_TYPE_IDENTIFIER;
+			  lex_value.v_identifier = g_strdup (yytext);
+			  return TOKEN_IDENTIFIER;
+			}
+
+.			{ return TOKEN_ERROR; }
+
+%%
diff --git a/vivified/code/vivi_parser_scanner_lex_include.h b/vivified/code/vivi_parser_scanner_lex_include.h
new file mode 100644
index 0000000..1c2dabc
--- /dev/null
+++ b/vivified/code/vivi_parser_scanner_lex_include.h
@@ -0,0 +1,28 @@
+/* Vivified
+ * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_PARSER_SCANNER_LEX_INCLUDE_H_
+#define _VIVI_PARSER_SCANNER_LEX_INCLUDE_H_
+
+#include "vivi_parser_scanner.h"
+
+ViviParserScannerValue lex_value;
+guint lex_line_number;
+
+#endif // _VIVI_PARSER_SCANNER_LEX_INCLUDE_H_


More information about the Swfdec-commits mailing list