[Swfdec-commits] 19 commits - vivified/code

Pekka Lampila medar at kemper.freedesktop.org
Sat Apr 5 03:04:41 PDT 2008


 vivified/code/Makefile.am                         |    6 
 vivified/code/vivi_code_constant.c                |    2 
 vivified/code/vivi_code_goto.c                    |    3 
 vivified/code/vivi_code_init_array.c              |  127 +++
 vivified/code/vivi_code_init_array.h              |   59 +
 vivified/code/vivi_code_throw.c                   |   88 ++
 vivified/code/vivi_code_throw.h                   |   59 +
 vivified/code/vivi_compiler.c                     |  830 +++++++++++++++++++---
 vivified/code/vivi_compiler_get_temporary.h       |    3 
 vivified/code/vivi_compiler_goto_name.c           |  102 ++
 vivified/code/vivi_compiler_goto_name.h           |   60 +
 vivified/code/vivi_compiler_scanner.c             |   50 -
 vivified/code/vivi_compiler_scanner.h             |   17 
 vivified/code/vivi_compiler_scanner_lex.h         |   19 
 vivified/code/vivi_compiler_scanner_lex.l         |   41 -
 vivified/code/vivi_compiler_scanner_lex_include.h |   19 
 16 files changed, 1332 insertions(+), 153 deletions(-)

New commits:
commit 4dea51f6bf9ba5519924ab801ae5654e6823d1c7
Merge: b55243c... d4b651f...
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Sat Apr 5 13:01:00 2008 +0300

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

commit b55243c31d0654ddb9392819718ab471a238d6b9
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Sat Apr 5 12:42:40 2008 +0300

    Fix some copyright headers

diff --git a/vivified/code/vivi_code_init_array.c b/vivified/code/vivi_code_init_array.c
index 7d5e9e3..d5ac090 100644
--- a/vivified/code/vivi_code_init_array.c
+++ b/vivified/code/vivi_code_init_array.c
@@ -1,5 +1,6 @@
 /* Vivified
- * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *               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
diff --git a/vivified/code/vivi_code_init_array.h b/vivified/code/vivi_code_init_array.h
index 86f8756..a7843bc 100644
--- a/vivified/code/vivi_code_init_array.h
+++ b/vivified/code/vivi_code_init_array.h
@@ -1,5 +1,6 @@
 /* Vivified
- * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *               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
diff --git a/vivified/code/vivi_compiler_get_temporary.h b/vivified/code/vivi_compiler_get_temporary.h
index 43b0baf..5a748f2 100644
--- a/vivified/code/vivi_compiler_get_temporary.h
+++ b/vivified/code/vivi_compiler_get_temporary.h
@@ -1,5 +1,6 @@
 /* Vivified
- * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *               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
diff --git a/vivified/code/vivi_compiler_goto_name.c b/vivified/code/vivi_compiler_goto_name.c
index 7926d81..e8f5df9 100644
--- a/vivified/code/vivi_compiler_goto_name.c
+++ b/vivified/code/vivi_compiler_goto_name.c
@@ -1,5 +1,6 @@
 /* Vivified
  * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *               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
diff --git a/vivified/code/vivi_compiler_goto_name.h b/vivified/code/vivi_compiler_goto_name.h
index a348eaf..7c92983 100644
--- a/vivified/code/vivi_compiler_goto_name.h
+++ b/vivified/code/vivi_compiler_goto_name.h
@@ -1,5 +1,6 @@
 /* Vivified
  * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *               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
diff --git a/vivified/code/vivi_compiler_scanner.c b/vivified/code/vivi_compiler_scanner.c
index ddbd738..2f36db0 100644
--- a/vivified/code/vivi_compiler_scanner.c
+++ b/vivified/code/vivi_compiler_scanner.c
@@ -1,5 +1,5 @@
 /* Vivified
- * Copyright (C) Pekka Lampila <pekka.lampila at iki.fi>
+ * 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
diff --git a/vivified/code/vivi_compiler_scanner_lex.h b/vivified/code/vivi_compiler_scanner_lex.h
index fe5fbe7..14d2a0f 100644
--- a/vivified/code/vivi_compiler_scanner_lex.h
+++ b/vivified/code/vivi_compiler_scanner_lex.h
@@ -1,3 +1,22 @@
+/* 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
diff --git a/vivified/code/vivi_compiler_scanner_lex.l b/vivified/code/vivi_compiler_scanner_lex.l
index 7773ffb..55f9e44 100644
--- a/vivified/code/vivi_compiler_scanner_lex.l
+++ b/vivified/code/vivi_compiler_scanner_lex.l
@@ -1,4 +1,23 @@
 %{
+/* 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"
 %}
 
diff --git a/vivified/code/vivi_compiler_scanner_lex_include.h b/vivified/code/vivi_compiler_scanner_lex_include.h
index 2224b2f..5527862 100644
--- a/vivified/code/vivi_compiler_scanner_lex_include.h
+++ b/vivified/code/vivi_compiler_scanner_lex_include.h
@@ -1,3 +1,22 @@
+/* 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_
 
commit 52ca6a40bced4c7703f8560eab2234ce6fffec8f
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Sat Apr 5 11:27:51 2008 +0300

    Make vivi_compiler_combine_statements only take 2 statements, rename to join

diff --git a/vivified/code/vivi_compiler.c b/vivified/code/vivi_compiler.c
index 7ec0357..acdbdf1 100644
--- a/vivified/code/vivi_compiler.c
+++ b/vivified/code/vivi_compiler.c
@@ -180,43 +180,31 @@ free_value_list (ViviCodeValue **list)
 }
 
 G_GNUC_WARN_UNUSED_RESULT static ViviCodeStatement *
-vivi_compiler_combine_statements (guint count, ...)
+vivi_compiler_join_statements (ViviCodeStatement *one, ViviCodeStatement *two)
 {
-  va_list args;
-  ViviCodeBlock *block;
-  guint i;
 
-  if (count == 0)
-    return NULL;
-
-  va_start (args, count);
-  block = VIVI_CODE_BLOCK (vivi_code_block_new ());
-  for (i = 0; i < count; i++) {
-    ViviCodeStatement *statement = va_arg (args, ViviCodeStatement *);
-
-    if (statement == NULL)
-      continue;
-
-    g_assert (VIVI_IS_CODE_STATEMENT (statement));
-
-    vivi_code_block_add_statement (block, statement);
-    g_object_unref (statement);
-  }
-  va_end (args);
-
-  if (vivi_code_block_get_n_statements (block) == 0) {
-    g_object_unref (block);
-    return NULL;
+  if (one == NULL) {
+    return two;
+  } else if (two == NULL) {
+    return one;
   }
 
-  if (vivi_code_block_get_n_statements (block) == 1) {
-    ViviCodeStatement *statement =
-      g_object_ref (vivi_code_block_get_statement (block, 0));
-    g_object_unref (block);
-    return statement;
+  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;
   }
-
-  return VIVI_CODE_STATEMENT (block);
 }
 
 static ViviCodeValue *
@@ -581,8 +569,7 @@ parse_array_literal (ParseData *data, ViviCodeValue **value,
 	return FAIL_CHILD (status);
       }
 
-      *statement = vivi_compiler_combine_statements (2, *statement,
-	  statement_new);
+      *statement = vivi_compiler_join_statements (*statement, statement_new);
 
       vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
 	  member);
@@ -652,8 +639,7 @@ parse_object_literal (ParseData *data, ViviCodeValue **value,
 	return FAIL_CHILD (status);
       }
 
-      *statement =
-	vivi_compiler_combine_statements (2, *statement, statement_new);
+      *statement = vivi_compiler_join_statements (*statement, statement_new);
 
       vivi_code_init_object_add_variable (VIVI_CODE_INIT_OBJECT (*value),
 	  property, initializer);
@@ -702,8 +688,7 @@ parse_variable_declaration (ParseData *data, ViviCodeStatement **statement)
   assignment = vivi_compiler_assignment_new (identifier, value);
   vivi_code_assignment_set_local (VIVI_CODE_ASSIGNMENT (assignment), TRUE);
 
-  *statement =
-    vivi_compiler_combine_statements (2, statement_right, assignment);
+  *statement = vivi_compiler_join_statements (statement_right, assignment);
 
   return STATUS_OK;
 }
@@ -803,8 +788,8 @@ parse_member_expression (ParseData *data, ViviCodeValue **value,
 	return FAIL_CHILD (status);
       }
 
-      *statement = vivi_compiler_combine_statements (2, *statement,
-	  statement_member);
+      *statement =
+	vivi_compiler_join_statements (*statement, statement_member);
 
       if (!check_token (data, TOKEN_BRACKET_RIGHT)) {
 	g_object_unref (*value);
@@ -908,7 +893,7 @@ parse_left_hand_side_expression (ParseData *data, ViviCodeValue **value,
       }
 
       *statement =
-	vivi_compiler_combine_statements (2, *statement, argument_statement);
+	vivi_compiler_join_statements (*statement, argument_statement);
 
       if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
 	g_object_unref (*value);
@@ -987,9 +972,10 @@ parse_postfix_expression (ParseData *data, ViviCodeValue **value,
   g_object_unref (one);
 
   temporary = vivi_compiler_get_temporary_new ();
-  *statement = vivi_compiler_combine_statements (3, *statement,
-      vivi_compiler_assignment_new (temporary, *value),
-      vivi_compiler_assignment_new (*value, operation));
+  *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);
@@ -1033,7 +1019,7 @@ parse_unary_expression (ParseData *data, ViviCodeValue **value,
       tmp = vivi_code_binary_new_name (*value, one, operator);
       g_object_unref (one);
 
-      *statement = vivi_compiler_combine_statements (2, *statement,
+      *statement = vivi_compiler_join_statements (*statement,
 	  vivi_compiler_assignment_new (*value, tmp));
       g_object_unref (tmp);
 
@@ -1110,8 +1096,8 @@ parse_operator_expression (ParseData *data, ViviCodeValue **value,
 	    g_assert_not_reached ();
 	}
 
-	*statement = vivi_compiler_combine_statements (2, *statement,
-	    *statement_right);
+	*statement =
+	  vivi_compiler_join_statements (*statement, statement_right);
       }
 
       left = VIVI_CODE_VALUE (*value);
@@ -1351,8 +1337,8 @@ parse_assignment_expression (ParseData *data, ViviCodeValue **value,
       }
       g_object_unref (right);
 
-      *statement = vivi_compiler_combine_statements (3, *statement,
-	  statement_right, assignment);
+      *statement = vivi_compiler_join_statements (*statement,
+	  vivi_compiler_join_statements (statement_right, assignment));
 
       break;
     default:
@@ -1377,8 +1363,7 @@ parse_expression (ParseData *data, ViviCodeValue **value,
     return status;
 
   while (TRUE) {
-    *statement =
-      vivi_compiler_combine_statements (2, *statement, statement_one);
+    *statement = vivi_compiler_join_statements (*statement, statement_one);
 
     if (!check_token (data, TOKEN_COMMA))
       break;
@@ -1472,7 +1457,7 @@ parse_throw_statement (ParseData *data, ViviCodeStatement **statement)
   g_object_unref (value);
 
   *statement =
-    vivi_compiler_combine_statements (2, expression_statement, *statement);
+    vivi_compiler_join_statements (expression_statement, *statement);
 
   if (!check_token (data, TOKEN_SEMICOLON)) {
     g_object_unref (*statement);
@@ -1512,7 +1497,7 @@ parse_return_statement (ParseData *data, ViviCodeStatement **statement)
     g_object_unref (value);
 
     *statement =
-      vivi_compiler_combine_statements (2, expression_statement, *statement);
+      vivi_compiler_join_statements (expression_statement, *statement);
 
     if (!check_token (data, TOKEN_SEMICOLON)) {
       g_object_unref (*statement);
@@ -1714,17 +1699,17 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
       return FAIL_CHILD (status);
     }
 
-    loop_statement = vivi_compiler_combine_statements (2,
-	loop_statement, post_statement);
+    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_combine_statements (2,
-	pre_statement, g_object_ref (condition_statement));
-    loop_statement = vivi_compiler_combine_statements (2,
-	loop_statement, g_object_ref (condition_statement));
+    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);
   }
 
@@ -1734,7 +1719,7 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
   vivi_code_loop_set_statement (VIVI_CODE_LOOP (*statement), loop_statement);
   g_object_unref (loop_statement);
 
-  *statement = vivi_compiler_combine_statements (2, pre_statement, *statement);
+  *statement = vivi_compiler_join_statements (pre_statement, *statement);
 
   return STATUS_OK;
 }
@@ -1803,7 +1788,7 @@ parse_if_statement (ParseData *data, ViviCodeStatement **statement)
     g_object_unref (else_statement);
   }
 
-  *statement = vivi_compiler_combine_statements (2, pre_statement, *statement);
+  *statement = vivi_compiler_join_statements (pre_statement, *statement);
 
   g_assert (*statement != NULL);
 
@@ -1868,7 +1853,7 @@ parse_expression_statement (ParseData *data, ViviCodeStatement **statement)
     }
   }
 
-  *statement = vivi_compiler_combine_statements (2, *statement,
+  *statement = vivi_compiler_join_statements (*statement,
       vivi_code_value_statement_new (value));
   g_object_unref (value);
 
@@ -2230,8 +2215,7 @@ parse_value_statement_list (ParseData *data,
       if (status == STATUS_FAIL || separator != TOKEN_NONE)
 	return FAIL_CHILD (status);
     } else {
-      *statement =
-	vivi_compiler_combine_statements (2, *statement, statement_one);
+      *statement = vivi_compiler_join_statements (*statement, statement_one);
     }
   } while (status == STATUS_OK);
   g_ptr_array_add (array, NULL);
commit 29c3602874cf82f421be93fae2fac708f915f228
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Sat Apr 5 11:17:29 2008 +0300

    Fixes to line number counting, operator statements, plus one assert

diff --git a/vivified/code/vivi_compiler.c b/vivified/code/vivi_compiler.c
index aa4df26..7ec0357 100644
--- a/vivified/code/vivi_compiler.c
+++ b/vivified/code/vivi_compiler.c
@@ -1645,7 +1645,8 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
 	  if (pre_statement != NULL)
 	    g_object_unref (pre_statement);
 	  g_object_unref (condition);
-	  g_object_unref (condition_statement);
+	  if (condition_statement != NULL)
+	    g_object_unref (condition_statement);
 	  return FAIL (TOKEN_SEMICOLON);
 	}
       }
@@ -1655,7 +1656,8 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
 	if (pre_statement != NULL)
 	  g_object_unref (pre_statement);
 	g_object_unref (condition);
-	g_object_unref (condition_statement);
+	if (condition_statement != NULL)
+	  g_object_unref (condition_statement);
 	return FAIL_CHILD (status);
       }
       g_object_unref (pre_value);
@@ -1695,7 +1697,8 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
       if (pre_statement != NULL)
 	g_object_unref (pre_statement);
       g_object_unref (condition);
-      g_object_unref (condition_statement);
+      if (condition_statement != NULL)
+	g_object_unref (condition_statement);
       g_object_unref (post_statement);
       return FAIL (TOKEN_PARENTHESIS_RIGHT);
     }
@@ -1705,7 +1708,8 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
       if (pre_statement != NULL)
 	g_object_unref (pre_statement);
       g_object_unref (condition);
-      g_object_unref (condition_statement);
+      if (condition_statement != NULL)
+	g_object_unref (condition_statement);
       g_object_unref (post_statement);
       return FAIL_CHILD (status);
     }
diff --git a/vivified/code/vivi_compiler_scanner.c b/vivified/code/vivi_compiler_scanner.c
index d59fb34..ddbd738 100644
--- a/vivified/code/vivi_compiler_scanner.c
+++ b/vivified/code/vivi_compiler_scanner.c
@@ -60,74 +60,74 @@ static const struct {
   { TOKEN_LINE_TERMINATOR, "NEW LINE" },
 
   // comparision
-  { TOKEN_BRACE_LEFT, "'{'", },
-  { TOKEN_BRACE_RIGHT, "'}'", },
-  { TOKEN_BRACKET_LEFT, "'['", },
-  { TOKEN_BRACKET_RIGHT, "']'", },
-  { TOKEN_PARENTHESIS_LEFT, "'('", },
-  { TOKEN_PARENTHESIS_RIGHT, "')'", },
+  { 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, "','" },
+  { TOKEN_DOT, ".", },
+  { TOKEN_SEMICOLON, ";" },
+  { TOKEN_COMMA, "," },
 
   // comparision
-  { TOKEN_LESS_THAN, "'<'" },
-  { TOKEN_GREATER_THAN, "'>'" },
-  { TOKEN_LESS_THAN_OR_EQUAL, "'<='" },
-  { TOKEN_EQUAL_OR_GREATER_THAN, "'=>'" },
+  { 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, "'!=='" },
+  { TOKEN_EQUAL, "=" },
+  { TOKEN_NOT_EQUAL, "!=" },
+  { TOKEN_STRICT_EQUAL, "===" },
+  { TOKEN_NOT_STRICT_EQUAL, "!==" },
 
   // operator
-  { TOKEN_PLUS, "'+'" },
-  { TOKEN_MINUS, "'-'" },
-  { TOKEN_MULTIPLY, "'*'" },
-  { TOKEN_DIVIDE, "'/'" },
-  { TOKEN_REMAINDER, "'%'" },
+  { TOKEN_PLUS, "+" },
+  { TOKEN_MINUS, "-" },
+  { TOKEN_MULTIPLY, "*" },
+  { TOKEN_DIVIDE, "/" },
+  { TOKEN_REMAINDER, "%" },
 
   // shift
-  { TOKEN_SHIFT_LEFT, "'<<'" },
-  { TOKEN_SHIFT_RIGHT, "'>>'" },
-  { TOKEN_SHIFT_RIGHT_UNSIGNED, "'>>>'" },
+  { TOKEN_SHIFT_LEFT, "<<" },
+  { TOKEN_SHIFT_RIGHT, ">>" },
+  { TOKEN_SHIFT_RIGHT_UNSIGNED, ">>>" },
 
   // bitwise
-  { TOKEN_BITWISE_AND, "'&'" },
-  { TOKEN_BITWISE_OR, "'|'" },
-  { TOKEN_BITWISE_XOR, "'^'" },
+  { TOKEN_BITWISE_AND, "&" },
+  { TOKEN_BITWISE_OR, "|" },
+  { TOKEN_BITWISE_XOR, "^" },
   
   // unary/postfix
-  { TOKEN_LOGICAL_NOT, "'!'" },
-  { TOKEN_BITWISE_NOT, "'~'" },
-  { TOKEN_INCREASE, "'++'" },
-  { TOKEN_DESCREASE, "'--'" },
+  { TOKEN_LOGICAL_NOT, "!" },
+  { TOKEN_BITWISE_NOT, "~" },
+  { TOKEN_INCREASE, "++" },
+  { TOKEN_DESCREASE, "--" },
 
   // conditional
-  { TOKEN_QUESTION_MARK, "'?'" },
-  { TOKEN_COLON, "':'" },
+  { TOKEN_QUESTION_MARK, "?" },
+  { TOKEN_COLON, ":" },
 
   // logical
-  { TOKEN_LOGICAL_AND, "'&&'" },
-  { TOKEN_LOGICAL_OR, "'||'" },
+  { 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, "'|='" },
+  { 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" },
@@ -137,31 +137,31 @@ static const struct {
   { 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'" },
+  { 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" },
@@ -190,6 +190,7 @@ vivi_compiler_scanner_advance (ViviCompilerScanner *scanner)
 
   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) {
@@ -199,10 +200,13 @@ vivi_compiler_scanner_advance (ViviCompilerScanner *scanner)
     scanner->next_token = yylex ();
     if (scanner->next_token == TOKEN_LINE_TERMINATOR) {
       scanner->next_line_terminator = TRUE;
-      scanner->next_token = yylex ();
     } else {
       scanner->next_line_terminator = FALSE;
     }
+    while (scanner->next_token == TOKEN_LINE_TERMINATOR) {
+      scanner->next_line_number++;
+      scanner->next_token = yylex ();
+    }
     scanner->next_value = yylval;
   }
 }
@@ -216,9 +220,10 @@ vivi_compiler_scanner_new (FILE *file)
 
   scanner = g_object_new (VIVI_TYPE_COMPILER_SCANNER, NULL);
   scanner->file = file;
+  scanner->line_number = 1;
+  scanner->next_line_number = 1;
 
   yyrestart (file);
-  yyout = stdout;
 
   vivi_compiler_scanner_advance (scanner);
 
@@ -248,7 +253,7 @@ vivi_compiler_scanner_cur_line (ViviCompilerScanner *scanner)
 {
   g_return_val_if_fail (VIVI_IS_COMPILER_SCANNER (scanner), 0);
 
-  return yylineno;
+  return scanner->line_number;
 }
 
 guint
diff --git a/vivified/code/vivi_compiler_scanner.h b/vivified/code/vivi_compiler_scanner.h
index 15fe50b..e5d349f 100644
--- a/vivified/code/vivi_compiler_scanner.h
+++ b/vivified/code/vivi_compiler_scanner.h
@@ -171,9 +171,12 @@ struct _ViviCompilerScanner
 
   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;
diff --git a/vivified/code/vivi_compiler_scanner_lex.l b/vivified/code/vivi_compiler_scanner_lex.l
index 161764d..7773ffb 100644
--- a/vivified/code/vivi_compiler_scanner_lex.l
+++ b/vivified/code/vivi_compiler_scanner_lex.l
@@ -7,17 +7,16 @@
 digit			[0-9]
 identifier_start	[$_a-zA-Z]
 identifier_part		[$_a-zA-Z0-9]
-line_terminator		[\n\r]
 
 /* r'([1-9][0-9]*|0)(\.[0-9]*)?([eE][+-][0-9]+)? */
 /* '\.[0-9]+([eE][+-][0-9]+)?' */
 
 %%
 
-"//".*{line_terminator}	/* skip single line comments */
+"//"[^\r\n]*		{ return TOKEN_LINE_TERMINATOR; }
 [ \t]			/* skip whitespace */
 <<EOF>>			{ return TOKEN_EOF; }
-[\n\r]			{ return TOKEN_LINE_TERMINATOR; }
+[\n\r]*			{ return TOKEN_LINE_TERMINATOR; }
 
 "{"			{ return TOKEN_BRACE_LEFT; }
 "}"			{ return TOKEN_BRACE_RIGHT; }
commit 4bbf9735931566f32e2c1c629bbe19f676ef3c44
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Sat Apr 5 02:03:59 2008 +0300

    Don't add extra value statement for assignments

diff --git a/vivified/code/vivi_compiler.c b/vivified/code/vivi_compiler.c
index bcf9da3..aa4df26 100644
--- a/vivified/code/vivi_compiler.c
+++ b/vivified/code/vivi_compiler.c
@@ -847,7 +847,7 @@ parse_new_expression (ParseData *data, ViviCodeValue **value,
       return FAIL_CHILD (status);
     if (!VIVI_IS_CODE_FUNCTION_CALL (*value)) {
       ViviCodeValue *tmp = VIVI_CODE_VALUE (*value);
-      *value = vivi_code_function_call_new (NULL, tmp);
+      *value = vivi_compiler_function_call_new (tmp);
       g_object_unref (tmp);
     }
     vivi_code_function_call_set_construct (VIVI_CODE_FUNCTION_CALL (*value),
@@ -877,7 +877,7 @@ parse_left_hand_side_expression (ParseData *data, ViviCodeValue **value,
       return FAIL_CHILD (status);
     if (!VIVI_IS_CODE_FUNCTION_CALL (*value)) {
       ViviCodeValue *tmp = VIVI_CODE_VALUE (*value);
-      *value = vivi_code_function_call_new (NULL, tmp);
+      *value = vivi_compiler_function_call_new (tmp);
       g_object_unref (tmp);
     }
     vivi_code_function_call_set_construct (VIVI_CODE_FUNCTION_CALL (*value),
@@ -1811,6 +1811,7 @@ parse_expression_statement (ParseData *data, ViviCodeStatement **statement)
 {
   ParseStatus status;
   ViviCodeValue *value;
+  ViviCodeStatement *last;
 
   *statement = NULL;
 
@@ -1843,6 +1844,26 @@ parse_expression_statement (ParseData *data, ViviCodeStatement **statement)
     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)) {
+    ViviCodeAssignment *assignment = VIVI_CODE_ASSIGNMENT (last);
+
+    if (assignment->from == NULL && assignment->name == value) {
+      g_object_unref (value);
+      return STATUS_OK;
+    }
+  }
+
   *statement = vivi_compiler_combine_statements (2, *statement,
       vivi_code_value_statement_new (value));
   g_object_unref (value);
commit 702eb520772544e358498d260883007f5b598322
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Sat Apr 5 01:49:48 2008 +0300

    Parse throw statement

diff --git a/vivified/code/Makefile.am b/vivified/code/Makefile.am
index c12a0bd..0adf79f 100644
--- a/vivified/code/Makefile.am
+++ b/vivified/code/Makefile.am
@@ -37,6 +37,7 @@ libvivified_compiler_la_SOURCES = \
 	vivi_code_return.c \
 	vivi_code_statement.c \
 	vivi_code_text_printer.c \
+	vivi_code_throw.c \
 	vivi_code_token.c \
 	vivi_code_trace.c \
 	vivi_code_unary.c \
@@ -75,6 +76,7 @@ noinst_HEADERS = \
 	vivi_code_return.h \
 	vivi_code_statement.h \
 	vivi_code_text_printer.h \
+	vivi_code_throw.h \
 	vivi_code_token.h \
 	vivi_code_trace.h \
 	vivi_code_unary.h \
diff --git a/vivified/code/vivi_code_throw.c b/vivified/code/vivi_code_throw.c
new file mode 100644
index 0000000..ba97115
--- /dev/null
+++ b/vivified/code/vivi_code_throw.c
@@ -0,0 +1,88 @@
+/* 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_code_throw.h"
+#include "vivi_code_printer.h"
+
+G_DEFINE_TYPE (ViviCodeThrow, vivi_code_throw, VIVI_TYPE_CODE_STATEMENT)
+
+static void
+vivi_code_throw_dispose (GObject *object)
+{
+  ViviCodeThrow *throw_ = VIVI_CODE_THROW (object);
+
+  if (throw_->value) {
+    g_object_unref (throw_->value);
+    throw_->value = NULL;
+  }
+
+  G_OBJECT_CLASS (vivi_code_throw_parent_class)->dispose (object);
+}
+
+static void
+vivi_code_throw_print (ViviCodeToken *token, ViviCodePrinter *printer)
+{
+  ViviCodeThrow *throw_ = VIVI_CODE_THROW (token);
+
+  vivi_code_printer_print (printer, "return");
+  if (throw_->value) {
+    vivi_code_printer_print (printer, " ");
+    vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (throw_->value));
+  }
+  vivi_code_printer_print (printer, ";");
+  vivi_code_printer_new_line (printer, FALSE);
+}
+
+static void
+vivi_code_throw_class_init (ViviCodeThrowClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+
+  object_class->dispose = vivi_code_throw_dispose;
+
+  token_class->print = vivi_code_throw_print;
+}
+
+static void
+vivi_code_throw_init (ViviCodeThrow *token)
+{
+}
+
+ViviCodeStatement *
+vivi_code_throw_new (ViviCodeValue *value)
+{
+  ViviCodeThrow *throw_ = g_object_new (VIVI_TYPE_CODE_THROW, NULL);
+
+  throw_->value = g_object_ref (value);
+
+  return VIVI_CODE_STATEMENT (throw_);
+}
+
+ViviCodeValue *
+vivi_code_throw_get_value (ViviCodeThrow *throw_)
+{
+  g_return_val_if_fail (VIVI_IS_CODE_THROW (throw_), NULL);
+
+  return throw_->value;
+}
diff --git a/vivified/code/vivi_code_throw.h b/vivified/code/vivi_code_throw.h
new file mode 100644
index 0000000..d0c8990
--- /dev/null
+++ b/vivified/code/vivi_code_throw.h
@@ -0,0 +1,59 @@
+/* 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_CODE_THROW_H_
+#define _VIVI_CODE_THROW_H_
+
+#include <vivified/code/vivi_code_statement.h>
+#include <vivified/code/vivi_code_value.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeThrow ViviCodeThrow;
+typedef struct _ViviCodeThrowClass ViviCodeThrowClass;
+
+#define VIVI_TYPE_CODE_THROW                    (vivi_code_throw_get_type())
+#define VIVI_IS_CODE_THROW(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_THROW))
+#define VIVI_IS_CODE_THROW_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_THROW))
+#define VIVI_CODE_THROW(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_THROW, ViviCodeThrow))
+#define VIVI_CODE_THROW_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_THROW, ViviCodeThrowClass))
+#define VIVI_CODE_THROW_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_THROW, ViviCodeThrowClass))
+
+struct _ViviCodeThrow
+{
+  ViviCodeStatement	statement;
+
+  ViviCodeValue *	value;
+};
+
+struct _ViviCodeThrowClass
+{
+  ViviCodeStatementClass	statement_class;
+};
+
+GType			vivi_code_throw_get_type   	(void);
+
+ViviCodeStatement *   	vivi_code_throw_new		(ViviCodeValue *	value);
+
+ViviCodeValue *		vivi_code_throw_get_value	(ViviCodeThrow *	throw_);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_compiler.c b/vivified/code/vivi_compiler.c
index 1d5e6c6..bcf9da3 100644
--- a/vivified/code/vivi_compiler.c
+++ b/vivified/code/vivi_compiler.c
@@ -43,6 +43,7 @@
 #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"
@@ -57,6 +58,7 @@ enum {
   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
@@ -70,6 +72,7 @@ static const struct {
   { 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" },
@@ -99,6 +102,7 @@ typedef struct {
 
 #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)
@@ -1446,6 +1450,40 @@ parse_break_statement (ParseData *data, ViviCodeStatement **statement)
 }
 
 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_combine_statements (2, expression_statement, *statement);
+
+  if (!check_token (data, TOKEN_SEMICOLON)) {
+    g_object_unref (*statement);
+    *statement = NULL;
+    return FAIL (TOKEN_SEMICOLON);
+  }
+
+  return STATUS_OK;
+}
+
+static ParseStatus
 parse_return_statement (ParseData *data, ViviCodeStatement **statement)
 {
   *statement = NULL;
@@ -1495,8 +1533,6 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
 
   *statement = NULL;
 
-  // TODO: for, do while
-
   pre_statement = NULL;
   condition_statement = NULL;
 
@@ -1897,7 +1933,7 @@ parse_statement (ParseData *data, ViviCodeStatement **statement)
     parse_return_statement,
     //parse_with_statement,
     //parse_switch_statement,
-    //parse_throw_statement,
+    parse_throw_statement,
     //parse_try_statement,
     NULL
   };
commit 9903e6c9cdb4f27f23548cb6837e73966c805c81
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Sat Apr 5 01:35:28 2008 +0300

    Implement the parsing of init arrays

diff --git a/vivified/code/vivi_code_init_array.c b/vivified/code/vivi_code_init_array.c
index b8fbf89..7d5e9e3 100644
--- a/vivified/code/vivi_code_init_array.c
+++ b/vivified/code/vivi_code_init_array.c
@@ -22,6 +22,7 @@
 #endif
 
 #include "vivi_code_init_array.h"
+#include "vivi_code_constant.h"
 #include "vivi_code_printer.h"
 
 G_DEFINE_TYPE (ViviCodeInitArray, vivi_code_init_array, VIVI_TYPE_CODE_VALUE)
@@ -60,16 +61,20 @@ vivi_code_init_array_print (ViviCodeToken *token, ViviCodePrinter *printer)
   ViviCodeInitArray *array = VIVI_CODE_INIT_ARRAY (token);
   guint i;
 
-  vivi_code_printer_print (printer, "{");
+  vivi_code_printer_print (printer, "[");
   for (i = 0; i < array->variables->len; i++) {
     ViviCodeValue *value =
       VIVI_CODE_VALUE (g_ptr_array_index (array->variables, i));
     if (i > 0)
       vivi_code_printer_print (printer, ", ");
     /* FIXME: precedences? */
-    vivi_code_printer_print_value (printer, value, VIVI_PRECEDENCE_COMMA);
+    // don't write undefined values
+    if (!VIVI_IS_CODE_CONSTANT (value) ||
+	vivi_code_constant_get_value_type (VIVI_CODE_CONSTANT (value))
+	!= SWFDEC_AS_TYPE_UNDEFINED)
+      vivi_code_printer_print_value (printer, value, VIVI_PRECEDENCE_COMMA);
   }
-  vivi_code_printer_print (printer, "}");
+  vivi_code_printer_print (printer, "]");
 }
 
 static gboolean
diff --git a/vivified/code/vivi_compiler.c b/vivified/code/vivi_compiler.c
index 95e07d0..1d5e6c6 100644
--- a/vivified/code/vivi_compiler.c
+++ b/vivified/code/vivi_compiler.c
@@ -39,6 +39,7 @@
 #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"
@@ -543,6 +544,59 @@ 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_combine_statements (2, *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)
 {
@@ -665,7 +719,6 @@ parse_primary_expression (ParseData *data, ViviCodeValue **value,
   ParseValueFunction functions[] = {
     parse_identifier,
     parse_literal,
-    //parse_array_literal,
     NULL
   };
 
@@ -694,6 +747,10 @@ parse_primary_expression (ParseData *data, ViviCodeValue **value,
   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)
commit 43a4aa3c7aab8d595856cc048373d0f0e2d2b636
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Sat Apr 5 01:01:16 2008 +0300

    Create ViviCodeInitArray class

diff --git a/vivified/code/Makefile.am b/vivified/code/Makefile.am
index 471c59f..c12a0bd 100644
--- a/vivified/code/Makefile.am
+++ b/vivified/code/Makefile.am
@@ -29,6 +29,7 @@ libvivified_compiler_la_SOURCES = \
 	vivi_code_get_url.c \
 	vivi_code_goto.c \
 	vivi_code_if.c \
+	vivi_code_init_array.c \
 	vivi_code_init_object.c \
 	vivi_code_label.c \
 	vivi_code_loop.c \
@@ -66,6 +67,7 @@ noinst_HEADERS = \
 	vivi_code_get_url.h \
 	vivi_code_goto.h \
 	vivi_code_if.h \
+	vivi_code_init_array.h \
 	vivi_code_init_object.h \
 	vivi_code_label.h \
 	vivi_code_loop.h \
diff --git a/vivified/code/vivi_code_init_array.c b/vivified/code/vivi_code_init_array.c
new file mode 100644
index 0000000..b8fbf89
--- /dev/null
+++ b/vivified/code/vivi_code_init_array.c
@@ -0,0 +1,121 @@
+/* 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_code_init_array.h"
+#include "vivi_code_printer.h"
+
+G_DEFINE_TYPE (ViviCodeInitArray, vivi_code_init_array, VIVI_TYPE_CODE_VALUE)
+
+typedef struct _VariableEntry VariableEntry;
+struct _VariableEntry {
+  ViviCodeValue *	name;
+  ViviCodeValue *	value;
+};
+
+static void
+vivi_code_init_array_dispose (GObject *object)
+{
+  ViviCodeInitArray *array = VIVI_CODE_INIT_ARRAY (object);
+  guint i;
+
+  for (i = 0; i < array->variables->len; i++) {
+    g_object_unref (g_ptr_array_index (array->variables, i));
+  }
+  g_ptr_array_free (array->variables, TRUE);
+
+  G_OBJECT_CLASS (vivi_code_init_array_parent_class)->dispose (object);
+}
+
+static ViviCodeValue * 
+vivi_code_init_array_optimize (ViviCodeValue *value, SwfdecAsValueType hint)
+{
+  /* FIXME: write */
+
+  return g_object_ref (value);
+}
+
+static void
+vivi_code_init_array_print (ViviCodeToken *token, ViviCodePrinter *printer)
+{
+  ViviCodeInitArray *array = VIVI_CODE_INIT_ARRAY (token);
+  guint i;
+
+  vivi_code_printer_print (printer, "{");
+  for (i = 0; i < array->variables->len; i++) {
+    ViviCodeValue *value =
+      VIVI_CODE_VALUE (g_ptr_array_index (array->variables, i));
+    if (i > 0)
+      vivi_code_printer_print (printer, ", ");
+    /* FIXME: precedences? */
+    vivi_code_printer_print_value (printer, value, VIVI_PRECEDENCE_COMMA);
+  }
+  vivi_code_printer_print (printer, "}");
+}
+
+static gboolean
+vivi_code_init_array_is_constant (ViviCodeValue *value)
+{
+  /* not constant, because we return a new array every time */
+  return FALSE;
+}
+
+static void
+vivi_code_init_array_class_init (ViviCodeInitArrayClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+  ViviCodeValueClass *value_class = VIVI_CODE_VALUE_CLASS (klass);
+
+  object_class->dispose = vivi_code_init_array_dispose;
+
+  token_class->print = vivi_code_init_array_print;
+
+  value_class->is_constant = vivi_code_init_array_is_constant;
+  value_class->optimize = vivi_code_init_array_optimize;
+}
+
+static void
+vivi_code_init_array_init (ViviCodeInitArray *array)
+{
+  ViviCodeValue *value = VIVI_CODE_VALUE (array);
+
+  array->variables = g_ptr_array_new ();
+
+  vivi_code_value_set_precedence (value, VIVI_PRECEDENCE_PARENTHESIS);
+}
+
+ViviCodeValue *
+vivi_code_init_array_new (void)
+{
+  return g_object_new (VIVI_TYPE_CODE_INIT_ARRAY, NULL);
+}
+
+void
+vivi_code_init_array_add_variable (ViviCodeInitArray *array,
+    ViviCodeValue *value)
+{
+  g_return_if_fail (VIVI_IS_CODE_INIT_ARRAY (array));
+  g_return_if_fail (VIVI_IS_CODE_VALUE (value));
+
+  g_ptr_array_add (array->variables, g_object_ref (value));
+}
diff --git a/vivified/code/vivi_code_init_array.h b/vivified/code/vivi_code_init_array.h
new file mode 100644
index 0000000..86f8756
--- /dev/null
+++ b/vivified/code/vivi_code_init_array.h
@@ -0,0 +1,58 @@
+/* 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_CODE_INIT_ARRAY_H_
+#define _VIVI_CODE_INIT_ARRAY_H_
+
+#include <vivified/code/vivi_code_value.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeInitArray ViviCodeInitArray;
+typedef struct _ViviCodeInitArrayClass ViviCodeInitArrayClass;
+
+#define VIVI_TYPE_CODE_INIT_ARRAY                    (vivi_code_init_array_get_type())
+#define VIVI_IS_CODE_INIT_ARRAY(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_INIT_ARRAY))
+#define VIVI_IS_CODE_INIT_ARRAY_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_INIT_ARRAY))
+#define VIVI_CODE_INIT_ARRAY(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_INIT_ARRAY, ViviCodeInitArray))
+#define VIVI_CODE_INIT_ARRAY_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_INIT_ARRAY, ViviCodeInitArrayClass))
+#define VIVI_CODE_INIT_ARRAY_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_INIT_ARRAY, ViviCodeInitArrayClass))
+
+struct _ViviCodeInitArray
+{
+  ViviCodeValue		value;
+
+  GPtrArray *		variables;
+};
+
+struct _ViviCodeInitArrayClass
+{
+  ViviCodeValueClass	value_class;
+};
+
+GType			vivi_code_init_array_get_type   	(void);
+
+ViviCodeValue *		vivi_code_init_array_new		(void);
+
+void			vivi_code_init_array_add_variable	(ViviCodeInitArray *	array,
+								 ViviCodeValue *	value);
+
+G_END_DECLS
+#endif
commit d4c35fe615718bcc2c134d9a8d6d00466f0af8d7
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Sat Apr 5 00:34:00 2008 +0300

    Add parsing for undefined

diff --git a/vivified/code/vivi_compiler.c b/vivified/code/vivi_compiler.c
index b9e9a55..95e07d0 100644
--- a/vivified/code/vivi_compiler.c
+++ b/vivified/code/vivi_compiler.c
@@ -416,6 +416,19 @@ vivi_compiler_add_label (ParseData *data, ViviCodeLabel *label)
 
 // 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)
 {
@@ -470,6 +483,7 @@ parse_literal (ParseData *data, ViviCodeValue **value)
   ParseStatus status;
   int i;
   ParseValueFunction functions[] = {
+    parse_undefined_literal,
     parse_null_literal,
     parse_boolean_literal,
     parse_numeric_literal,
diff --git a/vivified/code/vivi_compiler_scanner.h b/vivified/code/vivi_compiler_scanner.h
index 3ebafb1..15fe50b 100644
--- a/vivified/code/vivi_compiler_scanner.h
+++ b/vivified/code/vivi_compiler_scanner.h
@@ -140,6 +140,9 @@ typedef enum {
   // reserved keywords
   TOKEN_RESERVED_KEYWORD,
 
+  // ActionScript specific
+  TOKEN_UNDEFINED,
+
   TOKEN_LAST
 } ViviCompilerScannerToken;
 
diff --git a/vivified/code/vivi_compiler_scanner_lex.l b/vivified/code/vivi_compiler_scanner_lex.l
index 99f8d3e..161764d 100644
--- a/vivified/code/vivi_compiler_scanner_lex.l
+++ b/vivified/code/vivi_compiler_scanner_lex.l
@@ -78,12 +78,6 @@ line_terminator		[\n\r]
 "^="			{ return TOKEN_ASSIGN_BITWISE_XOR; }
 "|="			{ return TOKEN_ASSIGN_BITWISE_OR; }
 
-"null"			{ return TOKEN_NULL; }
-"true"			{ yylval.v_boolean = 1;
-			  return TOKEN_BOOLEAN; }
-"false"			{ yylval.v_boolean = 0;
-			  return TOKEN_BOOLEAN; }
-
 "break"			{ return TOKEN_BREAK; }
 "case"			{ return TOKEN_CASE; }
 "catch"			{ return TOKEN_CATCH; }
@@ -142,6 +136,11 @@ line_terminator		[\n\r]
 "transient"		{ return TOKEN_RESERVED_KEYWORD; }
 "volatile"		{ return TOKEN_RESERVED_KEYWORD; }
 
+"null"			{ return TOKEN_NULL; }
+"true"			{ yylval.v_boolean = 1;
+			  return TOKEN_BOOLEAN; }
+"false"			{ yylval.v_boolean = 0;
+			  return TOKEN_BOOLEAN; }
 [-+]*{digit}+		{ yylval.v_number = atoi(yytext);
 			  return TOKEN_NUMBER; }
 ("\""[^\"]*"\""|"'"[^']*"'") {
@@ -152,6 +151,8 @@ line_terminator		[\n\r]
 			  yylval.v_identifier = g_strdup (yytext);
 			  return TOKEN_IDENTIFIER; }
 
+"undefined"		{ return TOKEN_UNDEFINED; }
+
 .			{ printf("Unknown character [%c]\n",yytext[0]);
 			  return TOKEN_UNKNOWN; }
 %%
commit 0a5ebe8edb97de39d519a33159205f0789247a90
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Sat Apr 5 00:26:33 2008 +0300

    Fixes to compiler's string handling

diff --git a/vivified/code/vivi_code_constant.c b/vivified/code/vivi_code_constant.c
index 51c680f..10ab8c9 100644
--- a/vivified/code/vivi_code_constant.c
+++ b/vivified/code/vivi_code_constant.c
@@ -52,7 +52,7 @@ escape_string (const char *s)
     g_string_append_len (str, s, next - s);
     switch (*next) {
       case '"':
-	g_string_append (str, "\"");
+	g_string_append (str, "\\\"");
 	break;
       case '\n':
 	g_string_append (str, "\n");
diff --git a/vivified/code/vivi_compiler_scanner_lex.l b/vivified/code/vivi_compiler_scanner_lex.l
index 5f75cce..99f8d3e 100644
--- a/vivified/code/vivi_compiler_scanner_lex.l
+++ b/vivified/code/vivi_compiler_scanner_lex.l
@@ -144,7 +144,8 @@ line_terminator		[\n\r]
 
 [-+]*{digit}+		{ yylval.v_number = atoi(yytext);
 			  return TOKEN_NUMBER; }
-"\"".*"\""		{ yylval.v_string = g_strndup (yytext + 1, yyleng - 2);
+("\""[^\"]*"\""|"'"[^']*"'") {
+			  yylval.v_string = g_strndup (yytext + 1, yyleng - 2);
 			  return TOKEN_STRING; }
 
 {identifier_start}({identifier_part})* {
commit b3b48fe2c9850016363d46e5fa36c843d013ec0d
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Fri Apr 4 23:45:13 2008 +0300

    Don't allow line terminator between return and ;

diff --git a/vivified/code/vivi_compiler.c b/vivified/code/vivi_compiler.c
index 6728e41..b9e9a55 100644
--- a/vivified/code/vivi_compiler.c
+++ b/vivified/code/vivi_compiler.c
@@ -1382,7 +1382,8 @@ parse_return_statement (ParseData *data, ViviCodeStatement **statement)
   if (!check_token (data, TOKEN_RETURN))
     return CANCEL (TOKEN_RETURN);
 
-  // FIXME: no LineTerminator here
+  if (check_line_terminator (data))
+    return FAIL_LINE_TERMINATOR_OR (TOKEN_SEMICOLON, TOKEN_IDENTIFIER);
 
   *statement = vivi_code_return_new ();
 
commit d2c0f209bfa9099cfd0a95b9ea4b1cb196993288
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Fri Apr 4 23:29:51 2008 +0300

    Set labels for gotos when block ends and give error if label is not found

diff --git a/vivified/code/vivi_code_goto.c b/vivified/code/vivi_code_goto.c
index 60301f8..2d3ab2b 100644
--- a/vivified/code/vivi_code_goto.c
+++ b/vivified/code/vivi_code_goto.c
@@ -31,7 +31,8 @@ vivi_code_goto_dispose (GObject *object)
 {
   ViviCodeGoto *gotoo = VIVI_CODE_GOTO (object);
 
-  g_object_unref (gotoo->label);
+  if (gotoo->label)
+    g_object_unref (gotoo->label);
 
   G_OBJECT_CLASS (vivi_code_goto_parent_class)->dispose (object);
 }
diff --git a/vivified/code/vivi_compiler.c b/vivified/code/vivi_compiler.c
index e842ab8..6728e41 100644
--- a/vivified/code/vivi_compiler.c
+++ b/vivified/code/vivi_compiler.c
@@ -83,13 +83,14 @@ typedef enum {
 
 typedef struct {
   GSList			*labels;
+  GSList			*gotos;
 } ParseLevel;
 
 typedef struct {
   ViviCompilerScanner *		scanner;
   gboolean			unexpected_line_terminator;
   guint				expected[2];
-  const char *			custom_error;
+  char *			custom_error;
 
   GSList *			levels; // ParseLevel, earlier levels
   ParseLevel *			level;  // current level
@@ -311,13 +312,50 @@ vivi_compiler_start_level (ParseData *data)
   data->level = g_new0 (ParseLevel, 1);
 }
 
-static void
-vivi_compiler_end_level (ParseData *data)
+static ViviCodeLabel *
+vivi_compiler_find_label (ParseData *data, const char *name)
 {
   GSList *iter;
 
-  g_return_if_fail (data != NULL);
-  g_return_if_fail (data->level != NULL);
+  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));
@@ -332,6 +370,27 @@ vivi_compiler_end_level (ParseData *data)
   } 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
@@ -339,7 +398,9 @@ 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)),
@@ -843,7 +904,7 @@ parse_postfix_expression (ParseData *data, ViviCodeValue **value,
       g_object_unref (*statement);
       *statement = NULL;
     }
-    return CANCEL_CUSTOM ("INCREASE/DECREASE not allowed here");
+    return CANCEL_CUSTOM (g_strdup ("INCREASE/DECREASE not allowed here"));
   }
 
   one = vivi_code_constant_new_number (1);
@@ -891,7 +952,7 @@ parse_unary_expression (ParseData *data, ViviCodeValue **value,
 	return FAIL_CHILD (status);
 
       if (!vivi_compiler_value_is_left_hand_side (*value))
-	return CANCEL_CUSTOM ("INCREASE/DECREASE not allowed here");
+	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);
@@ -1287,6 +1348,8 @@ parse_continue_or_break_statement (ParseData *data,
 	  VIVI_CODE_CONSTANT (VIVI_CODE_GET (identifier)->name)));
     g_object_unref (identifier);
 
+    vivi_compiler_add_goto (data, VIVI_COMPILER_GOTO_NAME (*statement));
+
     if (!check_token (data, TOKEN_SEMICOLON)) {
       g_object_unref (*statement);
       *statement = NULL;
@@ -1495,13 +1558,15 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
 	g_object_unref (pre_value);
 	if (pre_statement != NULL)
 	  g_object_unref (pre_statement);
-	return FAIL_CUSTOM ("Invalid left hand side expression for in");
+	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 ("for (... in ...) has not been implemented yet");
+      return FAIL_CUSTOM (g_strdup (
+	    "for (... in ...) has not been implemented yet"));
     } else {
       ViviCompilerScannerToken fail_token;
 
@@ -1656,7 +1721,7 @@ 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_compiler_add_label (data, VIVI_CODE_LABEL (*statement)))
-	return FAIL_CUSTOM ("Same label name used twice");
+	return FAIL_CUSTOM (g_strdup ("Same label name used twice"));
       return STATUS_OK;
     }
   }
@@ -1831,16 +1896,22 @@ parse_function_definition (ParseData *data, ViviCodeValue **function,
   vivi_compiler_start_level (data);
 
   status = parse_statement_list (data, parse_source_element, &body, STATUS_OK);
-
-  vivi_compiler_end_level (data);
-
   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)
@@ -1926,10 +1997,13 @@ parse_program (ParseData *data, ViviCodeStatement **statement)
 
   status =
     parse_statement_list (data, parse_source_element, statement, STATUS_OK);
-  if (status != 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);
@@ -1937,7 +2011,13 @@ parse_program (ParseData *data, ViviCodeStatement **statement)
   }
 
 
-  vivi_compiler_end_level (data);
+  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;
@@ -2096,6 +2176,7 @@ vivi_compile_file (FILE *file, const char *input_name)
 
     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);
 
diff --git a/vivified/code/vivi_compiler_goto_name.c b/vivified/code/vivi_compiler_goto_name.c
index 6c24d5b..7926d81 100644
--- a/vivified/code/vivi_compiler_goto_name.c
+++ b/vivified/code/vivi_compiler_goto_name.c
@@ -24,7 +24,7 @@
 #include "vivi_compiler_goto_name.h"
 #include "vivi_code_printer.h"
 
-G_DEFINE_TYPE (ViviCompilerGotoName, vivi_compiler_goto_name, VIVI_TYPE_CODE_STATEMENT)
+G_DEFINE_TYPE (ViviCompilerGotoName, vivi_compiler_goto_name, VIVI_TYPE_CODE_GOTO)
 
 static void
 vivi_compiler_goto_name_dispose (GObject *object)
@@ -41,6 +41,12 @@ vivi_compiler_goto_name_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
   ViviCompilerGotoName *goto_ = VIVI_COMPILER_GOTO_NAME (token);
 
+  if (VIVI_CODE_GOTO (goto_)->label != NULL) {
+    VIVI_CODE_TOKEN_CLASS (vivi_compiler_goto_name_parent_class)->print (token,
+	printer);
+    return;
+  }
+
   vivi_code_printer_print (printer, "goto ");
   vivi_code_printer_print (printer, goto_->name);
   vivi_code_printer_print (printer, ";");
@@ -63,6 +69,24 @@ vivi_compiler_goto_name_init (ViviCompilerGotoName *token)
 {
 }
 
+const char *
+vivi_compiler_goto_name_get_name (ViviCompilerGotoName *goto_)
+{
+  g_return_val_if_fail (VIVI_IS_COMPILER_GOTO_NAME (goto_), NULL);
+
+  return goto_->name;
+}
+
+void
+vivi_compiler_goto_name_set_label (ViviCompilerGotoName *goto_,
+    ViviCodeLabel *label)
+{
+  g_return_if_fail (VIVI_IS_COMPILER_GOTO_NAME (goto_));
+  g_return_if_fail (VIVI_IS_CODE_LABEL (label));
+
+  VIVI_CODE_GOTO (goto_)->label = g_object_ref (label);
+}
+
 ViviCodeStatement *
 vivi_compiler_goto_name_new (const char *name)
 {
diff --git a/vivified/code/vivi_compiler_goto_name.h b/vivified/code/vivi_compiler_goto_name.h
index 219a4bc..a348eaf 100644
--- a/vivified/code/vivi_compiler_goto_name.h
+++ b/vivified/code/vivi_compiler_goto_name.h
@@ -20,8 +20,7 @@
 #ifndef _VIVI_COMPILER_GOTO_NAME_H_
 #define _VIVI_COMPILER_GOTO_NAME_H_
 
-#include <vivified/code/vivi_code_label.h>
-#include <vivified/code/vivi_code_statement.h>
+#include <vivified/code/vivi_code_goto.h>
 
 G_BEGIN_DECLS
 
@@ -38,19 +37,22 @@ typedef struct _ViviCompilerGotoNameClass ViviCompilerGotoNameClass;
 
 struct _ViviCompilerGotoName
 {
-  ViviCodeStatement	statement;
+  ViviCodeGoto		statement;
 
   char *		name;
 };
 
 struct _ViviCompilerGotoNameClass
 {
-  ViviCodeStatementClass	statement_class;
+  ViviCodeGotoClass	statement_class;
 };
 
 GType			vivi_compiler_goto_name_get_type	(void);
 
-ViviCodeStatement *	vivi_compiler_goto_name_new		(const char *	name);
+ViviCodeStatement *	vivi_compiler_goto_name_new		(const char *		name);
+const char *		vivi_compiler_goto_name_get_name	(ViviCompilerGotoName *	goto_);
+void			vivi_compiler_goto_name_set_label	(ViviCompilerGotoName *	goto_,
+								 ViviCodeLabel *	label);
 
 
 G_END_DECLS
commit 26ade3e670156252336d4ce967fd4da055826e9f
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Fri Apr 4 22:00:12 2008 +0300

    Redo error message generation for the compiler

diff --git a/vivified/code/vivi_compiler.c b/vivified/code/vivi_compiler.c
index 2f40088..e842ab8 100644
--- a/vivified/code/vivi_compiler.c
+++ b/vivified/code/vivi_compiler.c
@@ -122,6 +122,29 @@ parse_value_list (ParseData *data, ParseValueFunction function,
 
 // 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)
 {
@@ -2067,27 +2090,26 @@ vivi_compile_file (FILE *file, const char *input_name)
   g_assert (status >= 0);
 
   if (status != STATUS_OK) {
-    // FIXME: multiple expected tokens
-    vivi_compiler_scanner_get_next_token (data.scanner);
+    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);
-    } else if (data.expected[0] < TOKEN_LAST) {
-      vivi_compiler_scanner_unexp_token (data.scanner, data.expected[0]);
     } else {
-      guint i;
-      const char *name;
-
-      name = NULL;
-      for (i = 0; error_names[i].token != TOKEN_LAST; i++) {
-	if (error_names[i].token == data.expected[0]) {
-	  name = error_names[i].name;
-	  break;
-	}
-      }
+      vivi_compiler_scanner_get_next_token (data.scanner);
 
-      g_assert (name != NULL);
+      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]));
 
-      vivi_compiler_scanner_unexp_token_custom (data.scanner, name);
+      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));
+      }
     }
   }
 
diff --git a/vivified/code/vivi_compiler_scanner.c b/vivified/code/vivi_compiler_scanner.c
index 4eda684..d59fb34 100644
--- a/vivified/code/vivi_compiler_scanner.c
+++ b/vivified/code/vivi_compiler_scanner.c
@@ -60,74 +60,74 @@ static const struct {
   { TOKEN_LINE_TERMINATOR, "NEW LINE" },
 
   // comparision
-  { TOKEN_BRACE_LEFT, "{", },
-  { TOKEN_BRACE_RIGHT, "}", },
-  { TOKEN_BRACKET_LEFT, "[", },
-  { TOKEN_BRACKET_RIGHT, "]", },
-  { TOKEN_PARENTHESIS_LEFT, "(", },
-  { TOKEN_PARENTHESIS_RIGHT, ")", },
+  { 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, "," },
+  { TOKEN_DOT, "'.'", },
+  { TOKEN_SEMICOLON, "';'" },
+  { TOKEN_COMMA, "','" },
 
   // comparision
-  { TOKEN_LESS_THAN, "<" },
-  { TOKEN_GREATER_THAN, ">" },
-  { TOKEN_LESS_THAN_OR_EQUAL, "<=" },
-  { TOKEN_EQUAL_OR_GREATER_THAN, "=>" },
+  { 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, "!==" },
+  { TOKEN_EQUAL, "'='" },
+  { TOKEN_NOT_EQUAL, "'!='" },
+  { TOKEN_STRICT_EQUAL, "'==='" },
+  { TOKEN_NOT_STRICT_EQUAL, "'!=='" },
 
   // operator
-  { TOKEN_PLUS, "+" },
-  { TOKEN_MINUS, "-" },
-  { TOKEN_MULTIPLY, "*" },
-  { TOKEN_DIVIDE, "/" },
-  { TOKEN_REMAINDER, "%" },
+  { TOKEN_PLUS, "'+'" },
+  { TOKEN_MINUS, "'-'" },
+  { TOKEN_MULTIPLY, "'*'" },
+  { TOKEN_DIVIDE, "'/'" },
+  { TOKEN_REMAINDER, "'%'" },
 
   // shift
-  { TOKEN_SHIFT_LEFT, "<<" },
-  { TOKEN_SHIFT_RIGHT, ">>" },
-  { TOKEN_SHIFT_RIGHT_UNSIGNED, ">>>" },
+  { TOKEN_SHIFT_LEFT, "'<<'" },
+  { TOKEN_SHIFT_RIGHT, "'>>'" },
+  { TOKEN_SHIFT_RIGHT_UNSIGNED, "'>>>'" },
 
   // bitwise
-  { TOKEN_BITWISE_AND, "&" },
-  { TOKEN_BITWISE_OR, "|" },
-  { TOKEN_BITWISE_XOR, "^" },
+  { TOKEN_BITWISE_AND, "'&'" },
+  { TOKEN_BITWISE_OR, "'|'" },
+  { TOKEN_BITWISE_XOR, "'^'" },
   
   // unary/postfix
-  { TOKEN_LOGICAL_NOT, "!" },
-  { TOKEN_BITWISE_NOT, "~" },
-  { TOKEN_INCREASE, "++" },
-  { TOKEN_DESCREASE, "--" },
+  { TOKEN_LOGICAL_NOT, "'!'" },
+  { TOKEN_BITWISE_NOT, "'~'" },
+  { TOKEN_INCREASE, "'++'" },
+  { TOKEN_DESCREASE, "'--'" },
 
   // conditional
-  { TOKEN_QUESTION_MARK, "?" },
-  { TOKEN_COLON, ":" },
+  { TOKEN_QUESTION_MARK, "'?'" },
+  { TOKEN_COLON, "':'" },
 
   // logical
-  { TOKEN_LOGICAL_AND, "&&" },
-  { TOKEN_LOGICAL_OR, "||" },
+  { 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, "|=" },
+  { 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" },
@@ -137,31 +137,31 @@ static const struct {
   { 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" },
+  { 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" },
@@ -251,27 +251,22 @@ vivi_compiler_scanner_cur_line (ViviCompilerScanner *scanner)
   return yylineno;
 }
 
-static void
-vivi_compiler_scanner_print_unexp_token_message (ViviCompilerScanner *scanner,
-    const char *unexpected, const char *expected)
+guint
+vivi_compiler_scanner_cur_column (ViviCompilerScanner *scanner)
 {
-  g_printerr ("%i: Unexpected token %s expected %s\n",
-      vivi_compiler_scanner_cur_line (scanner), unexpected, expected);
-}
+  g_return_val_if_fail (VIVI_IS_COMPILER_SCANNER (scanner), 0);
 
-void
-vivi_compiler_scanner_unexp_token (ViviCompilerScanner *scanner,
-    ViviCompilerScannerToken expected)
-{
-  vivi_compiler_scanner_print_unexp_token_message (scanner,
-      vivi_compiler_scanner_token_name (scanner->token),
-      vivi_compiler_scanner_token_name (expected));
+  // TODO
+
+  return 0;
 }
 
-void
-vivi_compiler_scanner_unexp_token_custom (ViviCompilerScanner *scanner,
-    const char *expected)
+char *
+vivi_compiler_scanner_get_line (ViviCompilerScanner *scanner)
 {
-  vivi_compiler_scanner_print_unexp_token_message (scanner,
-      vivi_compiler_scanner_token_name (scanner->token), expected);
+  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
index 756b6bf..3ebafb1 100644
--- a/vivified/code/vivi_compiler_scanner.h
+++ b/vivified/code/vivi_compiler_scanner.h
@@ -188,13 +188,9 @@ ViviCompilerScannerToken	vivi_compiler_scanner_get_next_token	(ViviCompilerScann
 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);
-
-void				vivi_compiler_scanner_unexp_token	(ViviCompilerScanner *	scanner,
-									 ViviCompilerScannerToken expected);
-void				vivi_compiler_scanner_unexp_token_custom (ViviCompilerScanner *	scanner,
-									 const char *		expected);
+guint				vivi_compiler_scanner_cur_column	(ViviCompilerScanner *scanner);
+char *				vivi_compiler_scanner_get_line		(ViviCompilerScanner *scanner);
 
 
 G_END_DECLS
commit acd0b6a756f45cf499e07f268a5712fe515e1056
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Fri Apr 4 20:00:24 2008 +0300

    Parse break and continue statements with labels to temporary goto statements
    
    Those statements will be replaced by the final goto statements when the block
    (function) finishes and the labels are available

diff --git a/vivified/code/Makefile.am b/vivified/code/Makefile.am
index 409d224..471c59f 100644
--- a/vivified/code/Makefile.am
+++ b/vivified/code/Makefile.am
@@ -44,6 +44,7 @@ libvivified_compiler_la_SOURCES = \
 	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 \
@@ -80,6 +81,7 @@ noinst_HEADERS = \
 	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 \
diff --git a/vivified/code/vivi_compiler.c b/vivified/code/vivi_compiler.c
index a5b3cc2..2f40088 100644
--- a/vivified/code/vivi_compiler.c
+++ b/vivified/code/vivi_compiler.c
@@ -47,6 +47,7 @@
 #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"
 
@@ -1242,57 +1243,49 @@ static ParseStatus
 parse_statement (ParseData *data, ViviCodeStatement **statement);
 
 static ParseStatus
-parse_continue_statement (ParseData *data, ViviCodeStatement **statement)
+parse_continue_or_break_statement (ParseData *data,
+    ViviCodeStatement **statement, ViviCompilerScannerToken token)
 {
   *statement = NULL;
 
-  if (!check_token (data, TOKEN_CONTINUE))
-    return CANCEL (TOKEN_CONTINUE);
+  if (!check_token (data, token))
+    return CANCEL (token);
 
   if (check_line_terminator (data))
     return FAIL_LINE_TERMINATOR_OR (TOKEN_SEMICOLON, ERROR_TOKEN_IDENTIFIER);
 
-  *statement = vivi_code_continue_new ();
-
   if (!check_token (data, TOKEN_SEMICOLON)) {
-    g_object_unref (*statement);
-    *statement = NULL;
-    return FAIL_CUSTOM ("Handling of label in continue has not been implemented yet");
+    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);
 
-    /* if (!check_token (data, TOKEN_SEMICOLON)) {
+    if (!check_token (data, TOKEN_SEMICOLON)) {
       g_object_unref (*statement);
       *statement = NULL;
       return FAIL (TOKEN_SEMICOLON);
-    } */
+    }
+  } else {
+    *statement = vivi_code_break_new ();
   }
 
   return STATUS_OK;
 }
 
 static ParseStatus
-parse_break_statement (ParseData *data, ViviCodeStatement **statement)
+parse_continue_statement (ParseData *data, ViviCodeStatement **statement)
 {
-  *statement = NULL;
-
-  if (!check_token (data, TOKEN_BREAK))
-    return CANCEL (TOKEN_BREAK);
-
-  if (check_line_terminator (data))
-    return FAIL_LINE_TERMINATOR_OR (TOKEN_SEMICOLON, ERROR_TOKEN_IDENTIFIER);
-
-  if (!check_token (data, TOKEN_SEMICOLON)) {
-    return FAIL_CUSTOM ("Handling of label in break has not been implemented yet");
-
-    /* if (!check_token (data, TOKEN_SEMICOLON)) {
-      g_object_unref (*statement);
-      *statement = NULL;
-      return FAIL (TOKEN_SEMICOLON);
-    } */
-  } else {
-    *statement = vivi_code_break_new ();
-  }
+  return parse_continue_or_break_statement (data, statement, TOKEN_CONTINUE);
+}
 
-  return STATUS_OK;
+static ParseStatus
+parse_break_statement (ParseData *data, ViviCodeStatement **statement)
+{
+  return parse_continue_or_break_statement (data, statement, TOKEN_BREAK);
 }
 
 static ParseStatus
@@ -1472,7 +1465,6 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
 	return FAIL_CHILD (status);
       }
       g_object_unref (pre_value);
-    // FIXME: or one in declaration
     } else if (pre_value != NULL && check_token (data, TOKEN_IN)) {
       post_statement = NULL;
 
diff --git a/vivified/code/vivi_compiler_goto_name.c b/vivified/code/vivi_compiler_goto_name.c
new file mode 100644
index 0000000..6c24d5b
--- /dev/null
+++ b/vivified/code/vivi_compiler_goto_name.c
@@ -0,0 +1,77 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * 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_goto_name.h"
+#include "vivi_code_printer.h"
+
+G_DEFINE_TYPE (ViviCompilerGotoName, vivi_compiler_goto_name, VIVI_TYPE_CODE_STATEMENT)
+
+static void
+vivi_compiler_goto_name_dispose (GObject *object)
+{
+  ViviCompilerGotoName *goto_ = VIVI_COMPILER_GOTO_NAME (object);
+
+  g_free (goto_->name);
+
+  G_OBJECT_CLASS (vivi_compiler_goto_name_parent_class)->dispose (object);
+}
+
+static void
+vivi_compiler_goto_name_print (ViviCodeToken *token, ViviCodePrinter *printer)
+{
+  ViviCompilerGotoName *goto_ = VIVI_COMPILER_GOTO_NAME (token);
+
+  vivi_code_printer_print (printer, "goto ");
+  vivi_code_printer_print (printer, goto_->name);
+  vivi_code_printer_print (printer, ";");
+  vivi_code_printer_new_line (printer, FALSE);
+}
+
+static void
+vivi_compiler_goto_name_class_init (ViviCompilerGotoNameClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+
+  object_class->dispose = vivi_compiler_goto_name_dispose;
+
+  token_class->print = vivi_compiler_goto_name_print;
+}
+
+static void
+vivi_compiler_goto_name_init (ViviCompilerGotoName *token)
+{
+}
+
+ViviCodeStatement *
+vivi_compiler_goto_name_new (const char *name)
+{
+  ViviCompilerGotoName *goto_;
+
+  g_return_val_if_fail (name != NULL, NULL);
+
+  goto_ = g_object_new (VIVI_TYPE_COMPILER_GOTO_NAME, NULL);
+  goto_->name = g_strdup (name);
+
+  return VIVI_CODE_STATEMENT (goto_);
+}
diff --git a/vivified/code/vivi_compiler_goto_name.h b/vivified/code/vivi_compiler_goto_name.h
new file mode 100644
index 0000000..219a4bc
--- /dev/null
+++ b/vivified/code/vivi_compiler_goto_name.h
@@ -0,0 +1,57 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * 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_GOTO_NAME_H_
+#define _VIVI_COMPILER_GOTO_NAME_H_
+
+#include <vivified/code/vivi_code_label.h>
+#include <vivified/code/vivi_code_statement.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCompilerGotoName ViviCompilerGotoName;
+typedef struct _ViviCompilerGotoNameClass ViviCompilerGotoNameClass;
+
+#define VIVI_TYPE_COMPILER_GOTO_NAME                    (vivi_compiler_goto_name_get_type())
+#define VIVI_IS_COMPILER_GOTO_NAME(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_COMPILER_GOTO_NAME))
+#define VIVI_IS_COMPILER_GOTO_NAME_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_COMPILER_GOTO_NAME))
+#define VIVI_COMPILER_GOTO_NAME(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_COMPILER_GOTO_NAME, ViviCompilerGotoName))
+#define VIVI_COMPILER_GOTO_NAME_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_COMPILER_GOTO_NAME, ViviCompilerGotoNameClass))
+#define VIVI_COMPILER_GOTO_NAME_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_COMPILER_GOTO_NAME, ViviCompilerGotoNameClass))
+
+struct _ViviCompilerGotoName
+{
+  ViviCodeStatement	statement;
+
+  char *		name;
+};
+
+struct _ViviCompilerGotoNameClass
+{
+  ViviCodeStatementClass	statement_class;
+};
+
+GType			vivi_compiler_goto_name_get_type	(void);
+
+ViviCodeStatement *	vivi_compiler_goto_name_new		(const char *	name);
+
+
+G_END_DECLS
+#endif
commit bd8f639e8e2fca2fc823c6501595509c006d0919
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Fri Apr 4 19:56:11 2008 +0300

    Add support for detecting line terminators in spots that don't allow them

diff --git a/vivified/code/vivi_compiler.c b/vivified/code/vivi_compiler.c
index 09be5a5..a5b3cc2 100644
--- a/vivified/code/vivi_compiler.c
+++ b/vivified/code/vivi_compiler.c
@@ -52,6 +52,7 @@
 
 enum {
   ERROR_TOKEN_LITERAL = TOKEN_LAST + 1,
+  ERROR_TOKEN_IDENTIFIER,
   ERROR_TOKEN_PROPERTY_NAME,
   ERROR_TOKEN_PRIMARY_EXPRESSION,
   ERROR_TOKEN_ITERATION_STATEMENT,
@@ -64,6 +65,7 @@ static const struct {
   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_ITERATION_STATEMENT, "ITERATION STATEMENT" },
@@ -84,6 +86,7 @@ typedef struct {
 
 typedef struct {
   ViviCompilerScanner *		scanner;
+  gboolean			unexpected_line_terminator;
   guint				expected[2];
   const char *			custom_error;
 
@@ -92,6 +95,7 @@ typedef struct {
 } 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(x) FAIL_OR(x,TOKEN_NONE)
 #define FAIL_CHILD(x) STATUS_FAIL
 #define FAIL_CUSTOM(x) (data->custom_error = (x), STATUS_FAIL)
@@ -118,6 +122,13 @@ parse_value_list (ParseData *data, ParseValueFunction function,
 // helpers
 
 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);
@@ -724,7 +735,6 @@ parse_left_hand_side_expression (ParseData *data, ViviCodeValue **value,
       break;
 
     if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
-      // FIXME: assignment expression
       status = parse_value_statement_list (data, parse_assignment_expression,
 	  &arguments, &argument_statement, TOKEN_COMMA);
       if (status != STATUS_OK) {
@@ -784,7 +794,15 @@ parse_postfix_expression (ParseData *data, ViviCodeValue **value,
   if (status != STATUS_OK)
     return status;
 
-  // FIXME: Don't allow new line here
+  if (check_line_terminator (data)) {
+    g_object_unref (*value);
+    *value = NULL;
+    if (*statement != NULL) {
+      g_object_unref (*statement);
+      *statement = NULL;
+    }
+    return FAIL_LINE_TERMINATOR_OR (TOKEN_INCREASE, TOKEN_DESCREASE);
+  }
 
   if (check_token (data, TOKEN_INCREASE)) {
     operator = "+";
@@ -1231,7 +1249,8 @@ parse_continue_statement (ParseData *data, ViviCodeStatement **statement)
   if (!check_token (data, TOKEN_CONTINUE))
     return CANCEL (TOKEN_CONTINUE);
 
-  // FIXME: no LineTerminator here
+  if (check_line_terminator (data))
+    return FAIL_LINE_TERMINATOR_OR (TOKEN_SEMICOLON, ERROR_TOKEN_IDENTIFIER);
 
   *statement = vivi_code_continue_new ();
 
@@ -1258,7 +1277,8 @@ parse_break_statement (ParseData *data, ViviCodeStatement **statement)
   if (!check_token (data, TOKEN_BREAK))
     return CANCEL (TOKEN_BREAK);
 
-  // FIXME: no LineTerminator here
+  if (check_line_terminator (data))
+    return FAIL_LINE_TERMINATOR_OR (TOKEN_SEMICOLON, ERROR_TOKEN_IDENTIFIER);
 
   if (!check_token (data, TOKEN_SEMICOLON)) {
     return FAIL_CUSTOM ("Handling of label in break has not been implemented yet");
@@ -2042,6 +2062,7 @@ vivi_compile_file (FILE *file, const char *input_name)
   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;
diff --git a/vivified/code/vivi_compiler_scanner.c b/vivified/code/vivi_compiler_scanner.c
index e9c576b..4eda684 100644
--- a/vivified/code/vivi_compiler_scanner.c
+++ b/vivified/code/vivi_compiler_scanner.c
@@ -57,6 +57,7 @@ static const struct {
   { TOKEN_NONE, "NONE" },
   { TOKEN_EOF, "EOF" },
   { TOKEN_UNKNOWN, "UNKNOWN" },
+  { TOKEN_LINE_TERMINATOR, "NEW LINE" },
 
   // comparision
   { TOKEN_BRACE_LEFT, "{", },
@@ -189,12 +190,19 @@ vivi_compiler_scanner_advance (ViviCompilerScanner *scanner)
 
   scanner->token = scanner->next_token;
   scanner->value = scanner->next_value;
+  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;
+      scanner->next_token = yylex ();
+    } else {
+      scanner->next_line_terminator = FALSE;
+    }
     scanner->next_value = yylval;
   }
 }
diff --git a/vivified/code/vivi_compiler_scanner.h b/vivified/code/vivi_compiler_scanner.h
index 64067bd..756b6bf 100644
--- a/vivified/code/vivi_compiler_scanner.h
+++ b/vivified/code/vivi_compiler_scanner.h
@@ -31,6 +31,7 @@ typedef enum {
   TOKEN_NONE = 0,
   TOKEN_EOF,
   TOKEN_UNKNOWN,
+  TOKEN_LINE_TERMINATOR,
 
   // comparision
   TOKEN_BRACE_LEFT,
@@ -167,8 +168,10 @@ struct _ViviCompilerScanner
 
   ViviCompilerScannerToken	token;
   ViviCompilerScannerToken	next_token;
+  gboolean			line_terminator;
   ViviCompilerScannerValue	value;
   ViviCompilerScannerValue	next_value;
+  gboolean			next_line_terminator;
 
   ViviCompilerScannerToken	expected;
 };
diff --git a/vivified/code/vivi_compiler_scanner_lex.l b/vivified/code/vivi_compiler_scanner_lex.l
index 2a2c433..5f75cce 100644
--- a/vivified/code/vivi_compiler_scanner_lex.l
+++ b/vivified/code/vivi_compiler_scanner_lex.l
@@ -15,8 +15,9 @@ line_terminator		[\n\r]
 %%
 
 "//".*{line_terminator}	/* skip single line comments */
-[ \t\n\r]		/* skip whitespace */
+[ \t]			/* skip whitespace */
 <<EOF>>			{ return TOKEN_EOF; }
+[\n\r]			{ return TOKEN_LINE_TERMINATOR; }
 
 "{"			{ return TOKEN_BRACE_LEFT; }
 "}"			{ return TOKEN_BRACE_RIGHT; }
commit a79f30b849ed77417a78138d12f98b737fda0813
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Fri Apr 4 18:08:04 2008 +0300

    Add support for parsing labels

diff --git a/vivified/code/vivi_compiler.c b/vivified/code/vivi_compiler.c
index d03735d..09be5a5 100644
--- a/vivified/code/vivi_compiler.c
+++ b/vivified/code/vivi_compiler.c
@@ -79,9 +79,16 @@ typedef enum {
 } ParseStatus;
 
 typedef struct {
+  GSList			*labels;
+} ParseLevel;
+
+typedef struct {
   ViviCompilerScanner *		scanner;
   guint				expected[2];
   const 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)
@@ -251,6 +258,66 @@ vivi_compiler_value_is_left_hand_side (ViviCodeValue *value)
   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 void
+vivi_compiler_end_level (ParseData *data)
+{
+  GSList *iter;
+
+  g_return_if_fail (data != NULL);
+  g_return_if_fail (data->level != NULL);
+
+  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;
+  }
+}
+
+static gboolean
+vivi_compiler_add_label (ParseData *data, ViviCodeLabel *label)
+{
+  GSList *iter;
+
+  g_return_val_if_fail (data->level != NULL, 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
 
 static ParseStatus
@@ -1193,11 +1260,7 @@ parse_break_statement (ParseData *data, ViviCodeStatement **statement)
 
   // FIXME: no LineTerminator here
 
-  *statement = vivi_code_break_new ();
-
   if (!check_token (data, TOKEN_SEMICOLON)) {
-    g_object_unref (*statement);
-    *statement = NULL;
     return FAIL_CUSTOM ("Handling of label in break has not been implemented yet");
 
     /* if (!check_token (data, TOKEN_SEMICOLON)) {
@@ -1205,6 +1268,8 @@ parse_break_statement (ParseData *data, ViviCodeStatement **statement)
       *statement = NULL;
       return FAIL (TOKEN_SEMICOLON);
     } */
+  } else {
+    *statement = vivi_code_break_new ();
   }
 
   return STATUS_OK;
@@ -1550,6 +1615,17 @@ parse_expression_statement (ParseData *data, ViviCodeStatement **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 ("Same label name used twice");
+      return STATUS_OK;
+    }
+  }
+
   if (!check_token (data, TOKEN_SEMICOLON)) {
     g_object_unref (value);
     if (*statement != NULL) {
@@ -1648,7 +1724,6 @@ parse_statement (ParseData *data, ViviCodeStatement **statement)
     parse_break_statement,
     parse_return_statement,
     //parse_with_statement,
-    //parse_labelled_statement,
     //parse_switch_statement,
     //parse_throw_statement,
     //parse_try_statement,
@@ -1706,33 +1781,43 @@ parse_function_definition (ParseData *data, ViviCodeValue **function,
 
   if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
     g_object_unref (*identifier);
-    free_value_list (arguments);
+    if (arguments != NULL)
+      free_value_list (arguments);
     return FAIL (TOKEN_PARENTHESIS_RIGHT);
   }
 
   if (!check_token (data, TOKEN_BRACE_LEFT)) {
     g_object_unref (*identifier);
-    free_value_list (arguments);
+    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);
+
+  vivi_compiler_end_level (data);
+
   if (status == STATUS_FAIL) {
     g_object_unref (*identifier);
-    free_value_list (arguments);
+    if (arguments != NULL)
+      free_value_list (arguments);
     return STATUS_FAIL;
   }
 
   if (!check_token (data, TOKEN_BRACE_RIGHT)) {
     g_object_unref (*identifier);
-    free_value_list (arguments);
+    if (arguments != NULL)
+      free_value_list (arguments);
     g_object_unref (body);
     return FAIL (TOKEN_BRACE_RIGHT);
   }
 
   *function = vivi_code_function_new ();
   vivi_code_function_set_body (VIVI_CODE_FUNCTION (*function), body);
-  free_value_list (arguments);
+  if (arguments != NULL)
+    free_value_list (arguments);
   g_object_unref (body);
 
   return STATUS_OK;
@@ -1799,6 +1884,9 @@ parse_program (ParseData *data, ViviCodeStatement **statement)
 {
   ParseStatus status;
 
+  g_assert (data->level == NULL);
+  vivi_compiler_start_level (data);
+
   *statement = NULL;
 
   status =
@@ -1813,6 +1901,10 @@ parse_program (ParseData *data, ViviCodeStatement **statement)
     return FAIL_CHILD (status);
   }
 
+
+  vivi_compiler_end_level (data);
+  g_assert (data->level == NULL);
+
   return STATUS_OK;
 }
 
@@ -1953,6 +2045,8 @@ vivi_compile_file (FILE *file, const char *input_name)
   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)) ||
commit d5ef1164946eeb4852476daa39f8d3af89691eb0
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Fri Apr 4 16:38:23 2008 +0300

    Implement parsing of continue, break and return statements. No labels for now

diff --git a/vivified/code/vivi_compiler.c b/vivified/code/vivi_compiler.c
index c8c1efc..d03735d 100644
--- a/vivified/code/vivi_compiler.c
+++ b/vivified/code/vivi_compiler.c
@@ -1157,6 +1157,100 @@ static ParseStatus
 parse_statement (ParseData *data, ViviCodeStatement **statement);
 
 static ParseStatus
+parse_continue_statement (ParseData *data, ViviCodeStatement **statement)
+{
+  *statement = NULL;
+
+  if (!check_token (data, TOKEN_CONTINUE))
+    return CANCEL (TOKEN_CONTINUE);
+
+  // FIXME: no LineTerminator here
+
+  *statement = vivi_code_continue_new ();
+
+  if (!check_token (data, TOKEN_SEMICOLON)) {
+    g_object_unref (*statement);
+    *statement = NULL;
+    return FAIL_CUSTOM ("Handling of label in continue has not been implemented yet");
+
+    /* if (!check_token (data, TOKEN_SEMICOLON)) {
+      g_object_unref (*statement);
+      *statement = NULL;
+      return FAIL (TOKEN_SEMICOLON);
+    } */
+  }
+
+  return STATUS_OK;
+}
+
+static ParseStatus
+parse_break_statement (ParseData *data, ViviCodeStatement **statement)
+{
+  *statement = NULL;
+
+  if (!check_token (data, TOKEN_BREAK))
+    return CANCEL (TOKEN_BREAK);
+
+  // FIXME: no LineTerminator here
+
+  *statement = vivi_code_break_new ();
+
+  if (!check_token (data, TOKEN_SEMICOLON)) {
+    g_object_unref (*statement);
+    *statement = NULL;
+    return FAIL_CUSTOM ("Handling of label in break has not been implemented yet");
+
+    /* if (!check_token (data, TOKEN_SEMICOLON)) {
+      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);
+
+  // FIXME: no LineTerminator here
+
+  *statement = vivi_code_return_new ();
+
+  if (!check_token (data, TOKEN_SEMICOLON)) {
+    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_combine_statements (2, expression_statement, *statement);
+
+    if (!check_token (data, TOKEN_SEMICOLON)) {
+      g_object_unref (*statement);
+      *statement = NULL;
+      return FAIL (TOKEN_SEMICOLON);
+    }
+  }
+
+  return STATUS_OK;
+}
+
+static ParseStatus
 parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
 {
   ParseStatus status;
@@ -1550,9 +1644,9 @@ parse_statement (ParseData *data, ViviCodeStatement **statement)
     parse_expression_statement,
     parse_if_statement,
     parse_iteration_statement,
-    //parse_continue_statement,
-    //parse_break_statement,
-    //parse_return_statement,
+    parse_continue_statement,
+    parse_break_statement,
+    parse_return_statement,
     //parse_with_statement,
     //parse_labelled_statement,
     //parse_switch_statement,
commit aee2ac306c07a2fa944db9fec9203b2e1660655d
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Fri Apr 4 16:20:00 2008 +0300

    More fixes to iteration statement handling

diff --git a/vivified/code/vivi_compiler.c b/vivified/code/vivi_compiler.c
index 244e27f..c8c1efc 100644
--- a/vivified/code/vivi_compiler.c
+++ b/vivified/code/vivi_compiler.c
@@ -80,14 +80,16 @@ typedef enum {
 
 typedef struct {
   ViviCompilerScanner *		scanner;
-  guint				expected;
+  guint				expected[2];
   const char *			custom_error;
 } ParseData;
 
-#define FAIL(x) (data->expected = (x), STATUS_FAIL)
+#define FAIL_OR(x, y) (data->expected[0] = (x), data->expected[1] = (y), STATUS_FAIL)
+#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(x) (data->expected = (x), STATUS_CANCEL)
+#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);
@@ -1013,7 +1015,7 @@ parse_conditional_expression (ParseData *data, ViviCodeValue **value,
   status = parse_assignment_expression (data, &if_statement);
   if (status != STATUS_OK) {
     g_object_unref (value);
-    return FAIL (status);
+    return FAIL_CHILD (status);
   }
 
   if (!check_token (data, TOKEN_COLON)) {
@@ -1026,7 +1028,7 @@ parse_conditional_expression (ParseData *data, ViviCodeValue **value,
   if (status != STATUS_OK) {
     g_object_unref (value);
     g_object_unref (if_statement);
-    return FAIL (status);
+    return FAIL_CHILD (status);
   }
 
   *statement = vivi_code_if_new (value);
@@ -1229,76 +1231,120 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **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)) {
-      return FAIL (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 {
-      ViviCodeValue *pre_value;
-
       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)) {
-	ViviCodeStatement *post_statement;
-
+    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)) {
+	status = parse_expression (data, &condition, &condition_statement);
+	if (status != STATUS_OK)
+	  return FAIL_CHILD (status);
 
-	  if (!check_token (data, TOKEN_SEMICOLON)) {
+	if (!check_token (data, TOKEN_SEMICOLON)) {
+	  if (pre_statement != NULL)
 	    g_object_unref (pre_statement);
-	    g_object_unref (condition);
-	    g_object_unref (condition_statement);
-	    return FAIL (TOKEN_SEMICOLON);
-	  }
-	}
-
-	status = parse_expression (data, &pre_value, &post_statement);
-	if (status != STATUS_OK) {
-	  g_object_unref (pre_statement);
 	  g_object_unref (condition);
 	  g_object_unref (condition_statement);
+	  return FAIL (TOKEN_SEMICOLON);
 	}
-	g_object_unref (pre_value);
+      }
 
-	if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+      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);
-	  g_object_unref (condition_statement);
-	  g_object_unref (post_statement);
-	  return FAIL (TOKEN_PARENTHESIS_RIGHT);
-	}
+	g_object_unref (condition);
+	g_object_unref (condition_statement);
+	return FAIL_CHILD (status);
+      }
+      g_object_unref (pre_value);
+    // FIXME: or one in declaration
+    } else if (pre_value != NULL && check_token (data, TOKEN_IN)) {
+      post_statement = NULL;
 
-	status = parse_statement (data, &loop_statement);
-	if (status != STATUS_OK) {
+      if (!vivi_compiler_value_is_left_hand_side (pre_value)) {
+	g_object_unref (pre_value);
+	if (pre_statement != NULL)
 	  g_object_unref (pre_statement);
-	  g_object_unref (condition);
-	  g_object_unref (condition_statement);
-	  g_object_unref (post_statement);
-	  return FAIL_CHILD (status);
-	}
+	return FAIL_CUSTOM ("Invalid left hand side expression for in");
+      }
 
-	loop_statement = vivi_compiler_combine_statements (2,
-	    loop_statement, post_statement);
-      } else if (check_token (data, TOKEN_IN)) {
-	if (!vivi_compiler_value_is_left_hand_side (pre_value)) {
-	  g_object_unref (pre_value);
-	  g_object_unref (pre_statement);
-	  return FAIL_CUSTOM ("Invalid left hand side expression for in");
-	}
-	FAIL (TOKEN_IN);
+      g_object_unref (pre_value);
+      if (pre_statement != NULL)
+	g_object_unref (pre_statement);
+      return FAIL_CUSTOM ("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 {
-	// TODO: or TOKEN_IN
-	return FAIL (TOKEN_SEMICOLON);
+	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);
+      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);
+      g_object_unref (condition_statement);
+      g_object_unref (post_statement);
+      return FAIL_CHILD (status);
+    }
+
+    loop_statement = vivi_compiler_combine_statements (2,
+	loop_statement, post_statement);
   } else {
     return CANCEL (ERROR_TOKEN_ITERATION_STATEMENT);
   }
@@ -1481,7 +1527,7 @@ parse_variable_statement (ParseData *data, ViviCodeStatement **statement)
   status = parse_statement_list (data, parse_variable_declaration, statement,
       TOKEN_COMMA);
   if (status != STATUS_OK)
-    return FAIL (status);
+    return FAIL_CHILD (status);
 
   if (!check_token (data, TOKEN_SEMICOLON)) {
     g_object_unref (*statement);
@@ -1810,7 +1856,8 @@ vivi_compile_file (FILE *file, const char *input_name)
   g_return_val_if_fail (file != NULL, NULL);
 
   data.scanner = vivi_compiler_scanner_new (file);
-  data.expected = TOKEN_NONE;
+  data.expected[0] = TOKEN_NONE;
+  data.expected[1] = TOKEN_NONE;
   data.custom_error = NULL;
 
   status = parse_program (&data, &statement);
@@ -1819,18 +1866,19 @@ vivi_compile_file (FILE *file, const char *input_name)
   g_assert (status >= 0);
 
   if (status != STATUS_OK) {
+    // FIXME: multiple expected tokens
     vivi_compiler_scanner_get_next_token (data.scanner);
     if (data.custom_error != NULL) {
       g_printerr ("%s\n", data.custom_error);
-    } else if (data.expected < TOKEN_LAST) {
-      vivi_compiler_scanner_unexp_token (data.scanner, data.expected);
+    } else if (data.expected[0] < TOKEN_LAST) {
+      vivi_compiler_scanner_unexp_token (data.scanner, data.expected[0]);
     } else {
       guint i;
       const char *name;
 
       name = NULL;
       for (i = 0; error_names[i].token != TOKEN_LAST; i++) {
-	if (error_names[i].token == data.expected) {
+	if (error_names[i].token == data.expected[0]) {
 	  name = error_names[i].name;
 	  break;
 	}
commit f238d9acadf6947b4cedc64d9755c8c761ba788e
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Fri Apr 4 15:39:05 2008 +0300

    Implement do while loop and one type of for loop parsing. Fix few issues

diff --git a/vivified/code/vivi_compiler.c b/vivified/code/vivi_compiler.c
index c5db218..244e27f 100644
--- a/vivified/code/vivi_compiler.c
+++ b/vivified/code/vivi_compiler.c
@@ -86,6 +86,7 @@ typedef struct {
 
 #define FAIL(x) (data->expected = (x), STATUS_FAIL)
 #define FAIL_CHILD(x) STATUS_FAIL
+#define FAIL_CUSTOM(x) (data->custom_error = (x), STATUS_FAIL)
 #define CANCEL(x) (data->expected = (x), STATUS_CANCEL)
 #define CANCEL_CUSTOM(x) (data->custom_error = (x), STATUS_CANCEL)
 
@@ -139,7 +140,7 @@ vivi_compiler_combine_statements (guint count, ...)
     return NULL;
 
   va_start (args, count);
-  block = NULL;
+  block = VIVI_CODE_BLOCK (vivi_code_block_new ());
   for (i = 0; i < count; i++) {
     ViviCodeStatement *statement = va_arg (args, ViviCodeStatement *);
 
@@ -148,20 +149,23 @@ vivi_compiler_combine_statements (guint count, ...)
 
     g_assert (VIVI_IS_CODE_STATEMENT (statement));
 
-    if (block == NULL) {
-      if (VIVI_IS_CODE_BLOCK (statement)) {
-	block = VIVI_CODE_BLOCK (statement);
-	continue;
-      } else {
-	block = VIVI_CODE_BLOCK (vivi_code_block_new ());
-      }
-    }
-
     vivi_code_block_add_statement (block, statement);
     g_object_unref (statement);
   }
   va_end (args);
 
+  if (vivi_code_block_get_n_statements (block) == 0) {
+    g_object_unref (block);
+    return NULL;
+  }
+
+  if (vivi_code_block_get_n_statements (block) == 1) {
+    ViviCodeStatement *statement =
+      g_object_ref (vivi_code_block_get_statement (block, 0));
+    g_object_unref (block);
+    return statement;
+  }
+
   return VIVI_CODE_STATEMENT (block);
 }
 
@@ -238,6 +242,13 @@ vivi_compiler_get_new (ViviCodeValue *from, ViviCodeValue *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);
+}
+
 // values
 
 static ParseStatus
@@ -714,8 +725,15 @@ parse_postfix_expression (ParseData *data, ViviCodeValue **value,
     return STATUS_OK;
   }
 
-  if (!VIVI_IS_CODE_GET (*value))
+  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 ("INCREASE/DECREASE not allowed here");
+  }
 
   one = vivi_code_constant_new_number (1);
   operation = vivi_code_binary_new_name (*value, one, operator);
@@ -761,7 +779,7 @@ parse_unary_expression (ParseData *data, ViviCodeValue **value,
       if (status != STATUS_OK)
 	return FAIL_CHILD (status);
 
-      if (!VIVI_IS_CODE_GET (*value))
+      if (!vivi_compiler_value_is_left_hand_side (*value))
 	return CANCEL_CUSTOM ("INCREASE/DECREASE not allowed here");
 
       one = vivi_code_constant_new_number (1);
@@ -1039,7 +1057,7 @@ parse_assignment_expression (ParseData *data, ViviCodeValue **value,
   if (status != STATUS_OK)
     return status;
 
-  if (!VIVI_IS_CODE_GET (*value))
+  if (!vivi_compiler_value_is_left_hand_side (*value))
     return STATUS_OK;
 
   operator = NULL;
@@ -1106,7 +1124,6 @@ parse_expression (ParseData *data, ViviCodeValue **value,
   ParseStatus status;
 
   *statement = NULL;
-  statement_one = NULL;
 
   status = parse_assignment_expression (data, value, &statement_one);
   if (status != STATUS_OK)
@@ -1119,7 +1136,6 @@ parse_expression (ParseData *data, ViviCodeValue **value,
     if (!check_token (data, TOKEN_COMMA))
       break;
 
-    statement_one = NULL;
     status = parse_assignment_expression (data, value, &statement_one);
     if (status != STATUS_OK) {
       g_object_unref (*value);
@@ -1143,48 +1159,167 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
 {
   ParseStatus status;
   ViviCodeValue *condition;
-  ViviCodeStatement *pre_statement, *loop_statement;
+  ViviCodeStatement *pre_statement, *condition_statement, *loop_statement;
 
   *statement = NULL;
 
   // TODO: for, do while
 
-  if (check_token (data, TOKEN_WHILE)) {
+  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_token (data, TOKEN_SEMICOLON)) {
+      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, &pre_statement);
+    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 (pre_statement != NULL)
-	g_object_unref (pre_statement);
+      if (condition_statement != NULL)
+	g_object_unref (condition_statement);
       return FAIL (TOKEN_PARENTHESIS_RIGHT);
     }
 
-    status = parse_statement (data, &loop_statement); 
+    status = parse_statement (data, &loop_statement);
     if (status != STATUS_OK) {
       g_object_unref (condition);
-      if (pre_statement != NULL)
-	g_object_unref (pre_statement);
+      if (condition_statement != NULL)
+	g_object_unref (condition_statement);
       return FAIL_CHILD (status);
     }
+  } else if (check_token (data, TOKEN_FOR)) {
+    if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
+      return FAIL (TOKEN_PARENTHESIS_LEFT);
 
-    *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);
+    if (check_token (data, TOKEN_VAR)) {
+      return FAIL (TOKEN_VAR);
+    } else {
+      ViviCodeValue *pre_value;
 
-    *statement =
-      vivi_compiler_combine_statements (2, pre_statement, *statement);
+      if (!check_token (data, TOKEN_SEMICOLON)) {
+	status = parse_expression (data, &pre_value, &pre_statement);
+	if (status != STATUS_OK)
+	  return FAIL_CHILD (status);
+      }
 
-    return STATUS_OK;
+      if (check_token (data, TOKEN_SEMICOLON)) {
+	ViviCodeStatement *post_statement;
+
+	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)) {
+	    g_object_unref (pre_statement);
+	    g_object_unref (condition);
+	    g_object_unref (condition_statement);
+	    return FAIL (TOKEN_SEMICOLON);
+	  }
+	}
+
+	status = parse_expression (data, &pre_value, &post_statement);
+	if (status != STATUS_OK) {
+	  g_object_unref (pre_statement);
+	  g_object_unref (condition);
+	  g_object_unref (condition_statement);
+	}
+	g_object_unref (pre_value);
+
+	if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+	  g_object_unref (pre_statement);
+	  g_object_unref (condition);
+	  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) {
+	  g_object_unref (pre_statement);
+	  g_object_unref (condition);
+	  g_object_unref (condition_statement);
+	  g_object_unref (post_statement);
+	  return FAIL_CHILD (status);
+	}
+
+	loop_statement = vivi_compiler_combine_statements (2,
+	    loop_statement, post_statement);
+      } else if (check_token (data, TOKEN_IN)) {
+	if (!vivi_compiler_value_is_left_hand_side (pre_value)) {
+	  g_object_unref (pre_value);
+	  g_object_unref (pre_statement);
+	  return FAIL_CUSTOM ("Invalid left hand side expression for in");
+	}
+	FAIL (TOKEN_IN);
+      } else {
+	// TODO: or TOKEN_IN
+	return FAIL (TOKEN_SEMICOLON);
+      }
+    }
   } else {
     return CANCEL (ERROR_TOKEN_ITERATION_STATEMENT);
   }
+
+  if (condition_statement != NULL) {
+    pre_statement = vivi_compiler_combine_statements (2,
+	pre_statement, g_object_ref (condition_statement));
+    loop_statement = vivi_compiler_combine_statements (2,
+	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_combine_statements (2, pre_statement, *statement);
+
+  return STATUS_OK;
 }
 
 static ParseStatus


More information about the Swfdec-commits mailing list