[Swfdec-commits] 7 commits - vivified/code
Pekka Lampila
medar at kemper.freedesktop.org
Wed Apr 9 08:45:06 PDT 2008
vivified/code/.gitignore | 2
vivified/code/Makefile.am | 26
vivified/code/compiler.c | 4
vivified/code/vivi_compiler.c | 2385 ----------------------
vivified/code/vivi_compiler.h | 36
vivified/code/vivi_compiler_scanner.c | 310 --
vivified/code/vivi_compiler_scanner.h | 216 -
vivified/code/vivi_compiler_scanner_lex.h | 315 --
vivified/code/vivi_compiler_scanner_lex.l | 284 --
vivified/code/vivi_compiler_scanner_lex_include.h | 28
vivified/code/vivi_parser.c | 2233 ++++++++++++++++++++
vivified/code/vivi_parser.h | 36
vivified/code/vivi_parser_scanner.c | 310 ++
vivified/code/vivi_parser_scanner.h | 216 +
vivified/code/vivi_parser_scanner_lex.h | 315 ++
vivified/code/vivi_parser_scanner_lex.l | 284 ++
vivified/code/vivi_parser_scanner_lex_include.h | 28
17 files changed, 3438 insertions(+), 3590 deletions(-)
New commits:
commit 876bc3f7d9534b5069438bb901aacb6292b95810
Merge: c9d36c3... 3bca1a0...
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date: Wed Apr 9 18:44:23 2008 +0300
Merge branch 'master' of ssh://medar@git.freedesktop.org/git/swfdec/swfdec
commit c9d36c38170edafb3b28d70f996d0e0eeff1d5ed
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date: Wed Apr 9 18:30:01 2008 +0300
Fix parsing of >= and unterminated comment
diff --git a/vivified/code/vivi_parser_scanner.c b/vivified/code/vivi_parser_scanner.c
index 97a3a29..092cefa 100644
--- a/vivified/code/vivi_parser_scanner.c
+++ b/vivified/code/vivi_parser_scanner.c
@@ -103,7 +103,7 @@ static const struct {
{ TOKEN_LESS_THAN, "<" },
{ TOKEN_GREATER_THAN, ">" },
{ TOKEN_LESS_THAN_OR_EQUAL, "<=" },
- { TOKEN_EQUAL_OR_GREATER_THAN, "=>" },
+ { TOKEN_EQUAL_OR_GREATER_THAN, ">=" },
// equality
{ TOKEN_EQUAL, "=" },
diff --git a/vivified/code/vivi_parser_scanner_lex.l b/vivified/code/vivi_parser_scanner_lex.l
index 4b96c41..34c4f61 100644
--- a/vivified/code/vivi_parser_scanner_lex.l
+++ b/vivified/code/vivi_parser_scanner_lex.l
@@ -35,23 +35,23 @@ identifier_part [$_a-zA-Z0-9]
GString *string = NULL;
-<<EOF>> { return TOKEN_EOF; }
-
"/*" { BEGIN(comment); }
<comment>{
+ [^*\n]* /* skip */
+ \n { lex_line_number++; }
+ "*/" { BEGIN(INITIAL); }
<<EOF>> {
BEGIN(INITIAL);
return TOKEN_ERROR;
}
- [^*\n]* /* skip */
- \n { lex_line_number++; }
- "*/" { BEGIN(INITIAL); }
}
"//"[^\r\n]* {
lex_line_number++;
return TOKEN_LINE_TERMINATOR;
}
+<<EOF>> { return TOKEN_EOF; }
+
[ \t] /* skip */
\r\n {
@@ -77,7 +77,7 @@ identifier_part [$_a-zA-Z0-9]
"<" { return TOKEN_LESS_THAN; }
">" { return TOKEN_GREATER_THAN; }
"<=" { return TOKEN_LESS_THAN_OR_EQUAL; }
-"=>" { return TOKEN_EQUAL_OR_GREATER_THAN; }
+">=" { return TOKEN_EQUAL_OR_GREATER_THAN; }
"==", { return TOKEN_EQUAL; }
"!=", { return TOKEN_NOT_EQUAL; }
commit 6e3d2c7eb78d758614672686837abe3cd4e5a2b8
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date: Wed Apr 9 16:52:44 2008 +0300
Don't use statement uninitialized
diff --git a/vivified/code/vivi_parser.c b/vivified/code/vivi_parser.c
index c394798..7ec3a0b 100644
--- a/vivified/code/vivi_parser.c
+++ b/vivified/code/vivi_parser.c
@@ -155,7 +155,7 @@ vivi_parser_error (ParseData *data, const char *format, ...)
message = g_strdup_vprintf (format, args);
va_end (args);
- g_printerr (":error: %s\n", message);
+ g_printerr ("%i: error: %s\n", data->scanner->next_line_number, message);
g_free (message);
@@ -701,6 +701,7 @@ parse_array_literal (ParseData *data, ViviCodeValue **value,
ViviCodeStatement *statement_new;
*value = vivi_code_init_array_new ();
+ *statement = NULL;
parse_token (data, TOKEN_BRACKET_LEFT);
@@ -749,6 +750,7 @@ parse_object_literal (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
*value = vivi_code_init_object_new ();
+ *statement = NULL;
parse_token (data, TOKEN_BRACE_LEFT);
@@ -843,6 +845,7 @@ parse_primary_expression (ParseData *data, ViviCodeValue **value,
if (try_parse_token (data, TOKEN_THIS)) {
*value = vivi_code_get_new_name ("this");
+ *statement = NULL;
return;
}
@@ -898,6 +901,7 @@ parse_member_expression (ParseData *data, ViviCodeValue **value,
vivi_parser_error_unexpected_or (data, ERROR_TOKEN_PRIMARY_EXPRESSION,
ERROR_TOKEN_FUNCTION_EXPRESSION, TOKEN_NONE);
*value = vivi_code_constant_new_undefined ();
+ *statement = NULL;
}
while (TRUE) {
commit 3902098fe39ea682abd83c3b8f10b1a9a18319fe
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date: Wed Apr 9 16:40:09 2008 +0300
Continue reworking the error handling in the parser
diff --git a/vivified/code/vivi_parser.c b/vivified/code/vivi_parser.c
index 16bde02..c394798 100644
--- a/vivified/code/vivi_parser.c
+++ b/vivified/code/vivi_parser.c
@@ -58,10 +58,13 @@ enum {
ERROR_TOKEN_IDENTIFIER,
ERROR_TOKEN_PROPERTY_NAME,
ERROR_TOKEN_PRIMARY_EXPRESSION,
+ ERROR_TOKEN_FUNCTION_EXPRESSION,
+ ERROR_TOKEN_ASSIGNMENT_EXPRESSION,
ERROR_TOKEN_EXPRESSION,
ERROR_TOKEN_ITERATION_STATEMENT,
ERROR_TOKEN_EXPRESSION_STATEMENT,
- ERROR_TOKEN_STATEMENT
+ ERROR_TOKEN_STATEMENT,
+ ERROR_TOKEN_FUNCTION_DECLARATION
};
static const struct {
@@ -72,11 +75,14 @@ static const struct {
{ ERROR_TOKEN_IDENTIFIER, "IDENTIFIER" },
{ ERROR_TOKEN_PROPERTY_NAME, "PROPERTY NAME" },
{ ERROR_TOKEN_PRIMARY_EXPRESSION, "PRIMARY EXPRESSION" },
+ { ERROR_TOKEN_FUNCTION_EXPRESSION, "FUNCTION EXPRESSION" },
+ { ERROR_TOKEN_ASSIGNMENT_EXPRESSION, "ASSIGNMENT EXPRESSION" },
{ ERROR_TOKEN_EXPRESSION, "EXPRESSION" },
{ ERROR_TOKEN_ITERATION_STATEMENT, "ITERATION STATEMENT" },
{ ERROR_TOKEN_EXPRESSION_STATEMENT, "EXPRESSION STATEMENT" },
{ ERROR_TOKEN_STATEMENT, "STATEMENT" },
- { TOKEN_LAST, NULL }
+ { ERROR_TOKEN_FUNCTION_DECLARATION, "FUNCTION DECLARATION" },
+ { TOKEN_NONE, NULL }
};
typedef struct {
@@ -87,28 +93,28 @@ typedef struct {
typedef struct {
ViviParserScanner * scanner;
- guint error_count;
-
- char * cancel_error;
-
GSList * levels; // ParseLevel, earlier levels
ParseLevel * level; // current level
+
+ guint error_count;
} ParseData;
-typedef gboolean (*ParseValueFunction) (ParseData *data, ViviCodeValue **value);
-typedef gboolean (*ParseValueStatementFunction) (ParseData *data, ViviCodeValue **value, ViviCodeStatement **statement);
-typedef gboolean (*ParseStatementFunction) (ParseData *data, ViviCodeStatement **statement);
+typedef gboolean (*PeekFunction) (ParseData *data);
+typedef void (*ParseValueFunction) (ParseData *data, ViviCodeValue **value);
+typedef void (*ParseValueStatementFunction) (ParseData *data, ViviCodeValue **value, ViviCodeStatement **statement);
+typedef void (*ParseStatementFunction) (ParseData *data, ViviCodeStatement **statement);
-static gboolean
-parse_statement_list (ParseData *data, ParseStatementFunction function, ViviCodeStatement **statement, guint separator);
+static void
+parse_statement_list (ParseData *data, PeekFunction peek,
+ ParseStatementFunction parse, ViviCodeStatement **block, guint separator);
-static gboolean
-parse_value_statement_list (ParseData *data,
- ParseValueStatementFunction function, ViviCodeValue ***list,
+static void
+parse_value_statement_list (ParseData *data, PeekFunction peek,
+ ParseValueStatementFunction parse, ViviCodeValue ***list,
ViviCodeStatement **statement, guint separator);
-static gboolean
-parse_value_list (ParseData *data, ParseValueFunction function,
+static void
+parse_value_list (ParseData *data, PeekFunction peek, ParseValueFunction parse,
ViviCodeValue ***list, guint separator);
// helpers
@@ -123,7 +129,7 @@ vivi_parser_token_name (guint token)
const char *name;
name = NULL;
- for (i = 0; error_names[i].token != TOKEN_LAST; i++) {
+ for (i = 0; error_names[i].token != TOKEN_NONE; i++) {
if (error_names[i].token == token) {
name = error_names[i].name;
break;
@@ -157,83 +163,114 @@ vivi_parser_error (ParseData *data, const char *format, ...)
}
static void
-vivi_parser_cancel (ParseData *data, const char *format, ...)
+vivi_parser_error_unexpected_or (ParseData *data, ...)
{
va_list args;
- char *message;
+ guint token;
+ GString *message;
g_return_if_fail (data != NULL);
- g_return_if_fail (format != NULL);
- va_start (args, format);
- message = g_strdup_vprintf (format, args);
+ message = g_string_new ("Expected ");
+
+ va_start (args, data);
+
+ token = va_arg (args, guint);
+ g_assert (token != TOKEN_NONE);
+ g_string_append (message, vivi_parser_token_name (token));
+
+ while ((token = va_arg (args, guint)) != TOKEN_NONE) {
+ g_string_append (message, ", ");
+ g_string_append (message, vivi_parser_token_name (token));
+ }
+
va_end (args);
- if (data->cancel_error != NULL)
- g_free (data->cancel_error);
- data->cancel_error = message;
+ g_string_append (message, " before ");
+
+ g_string_append (message,
+ vivi_parser_token_name (data->scanner->next_token));
+
+ vivi_parser_error (data, "%s", g_string_free (message, FALSE));
}
-static char *
-vivi_parser_unexpected_token (ParseData *data, guint expected,
- guint unexpected1, guint unexpected2)
+static void
+vivi_parser_error_unexpected (ParseData *data, guint expected)
{
- return g_strdup_printf ("Expected %s before %s or %s\n",
- vivi_parser_token_name (expected), vivi_parser_token_name (unexpected1),
- vivi_parser_token_name (unexpected2));
+ g_return_if_fail (data != NULL);
+ g_return_if_fail (expected != TOKEN_NONE);
+
+ vivi_parser_error_unexpected_or (data, expected, TOKEN_NONE);
}
static void
-vivi_parser_fail_child (ParseData *data)
+vivi_parser_error_unexpected_line_terminator (ParseData *data, guint expected)
{
- if (data->cancel_error != NULL) {
- vivi_parser_error (data, "%s", data->cancel_error);
- g_free (data->cancel_error);
- data->cancel_error = NULL;
- } else {
- g_assert (data->error_count > 0);
- }
+ g_return_if_fail (data != NULL);
+ g_return_if_fail (expected != TOKEN_NONE);
+
+ vivi_parser_error (data, "Expected %s before %s",
+ vivi_parser_token_name (expected),
+ vivi_parser_token_name (TOKEN_LINE_TERMINATOR));
}
-static gboolean
-check_line_terminator (ParseData *data)
+G_GNUC_WARN_UNUSED_RESULT static gboolean
+peek_line_terminator (ParseData *data)
{
vivi_parser_scanner_peek_next_token (data->scanner);
return data->scanner->next_line_terminator;
}
-static gboolean
-check_token (ParseData *data, ViviParserScannerToken token)
+G_GNUC_WARN_UNUSED_RESULT static gboolean
+peek_token (ParseData *data, ViviParserScannerToken token)
{
vivi_parser_scanner_peek_next_token (data->scanner);
- if (data->scanner->next_token != token)
+ return (data->scanner->next_token == token);
+}
+
+static void
+parse_token (ParseData *data, ViviParserScannerToken token)
+{
+ vivi_parser_scanner_peek_next_token (data->scanner);
+ if (data->scanner->next_token != token) {
+ vivi_parser_error_unexpected (data, token);
+ } else {
+ vivi_parser_scanner_get_next_token (data->scanner);
+ }
+}
+
+G_GNUC_WARN_UNUSED_RESULT static gboolean
+try_parse_token (ParseData *data, ViviParserScannerToken token)
+{
+ if (!peek_token (data, token))
return FALSE;
- vivi_parser_scanner_get_next_token (data->scanner);
+
+ parse_token (data, token);
return TRUE;
}
-static gboolean
-check_automatic_semicolon (ParseData *data)
+static void
+parse_automatic_semicolon (ParseData *data)
{
- if (check_token (data, TOKEN_SEMICOLON))
- return TRUE;
- if (check_line_terminator (data))
- return TRUE;
+ if (try_parse_token (data, TOKEN_SEMICOLON))
+ return;
+ if (peek_line_terminator (data))
+ return;
vivi_parser_scanner_peek_next_token (data->scanner);
if (data->scanner->next_token == TOKEN_BRACE_LEFT ||
data->scanner->next_token == TOKEN_EOF)
- return TRUE;
+ return;
- return FALSE;
+ vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
}
-static gboolean
-check_restricted_semicolon (ParseData *data)
+G_GNUC_WARN_UNUSED_RESULT static gboolean
+try_parse_restricted_semicolon (ParseData *data)
{
- if (check_token (data, TOKEN_SEMICOLON))
+ if (try_parse_token (data, TOKEN_SEMICOLON))
return TRUE;
- if (check_line_terminator (data))
+ if (peek_line_terminator (data))
return TRUE;
return FALSE;
@@ -468,251 +505,290 @@ vivi_parser_add_label (ParseData *data, ViviCodeLabel *label)
/* ActionScript specific */
static gboolean
-parse_undefined_literal (ParseData *data, ViviCodeValue **value)
+peek_undefined_literal (ParseData *data)
{
- *value = NULL;
+ return peek_token (data, TOKEN_UNDEFINED);
+}
- if (!check_token (data, TOKEN_UNDEFINED)) {
- vivi_parser_cancel_unexpected (data, TOKEN_UNDEFINED);
- return FALSE;
- }
+static void
+parse_undefined_literal (ParseData *data, ViviCodeValue **value)
+{
+ parse_token (data, TOKEN_UNDEFINED);
*value = vivi_code_constant_new_undefined ();
- return TRUE;
}
static gboolean
-parse_null_literal (ParseData *data, ViviCodeValue **value)
+peek_null_literal (ParseData *data)
{
- *value = NULL;
+ return peek_token (data, TOKEN_NULL);
+}
- if (!check_token (data, TOKEN_NULL)) {
- vivi_parser_cancel_unexpected (data, TOKEN_NULL);
- return FALSE;
- }
+static void
+parse_null_literal (ParseData *data, ViviCodeValue **value)
+{
+ parse_token (data, TOKEN_NULL);
*value = vivi_code_constant_new_null ();
- return TRUE;
}
static gboolean
-parse_boolean_literal (ParseData *data, ViviCodeValue **value)
+peek_boolean_literal (ParseData *data)
{
- *value = NULL;
+ return peek_token (data, TOKEN_BOOLEAN);
+}
- if (!check_token (data, TOKEN_BOOLEAN)) {
- vivi_parser_cancel_unexpected (data, TOKEN_BOOLEAN);
- return FALSE;
+static void
+parse_boolean_literal (ParseData *data, ViviCodeValue **value)
+{
+ if (!try_parse_token (data, TOKEN_BOOLEAN)) {
+ vivi_parser_error_unexpected (data, TOKEN_BOOLEAN);
+ *value = vivi_code_constant_new_boolean (0);
+ } else {
+ *value = vivi_code_constant_new_boolean (data->scanner->value.v_boolean);
}
-
- *value = vivi_code_constant_new_boolean (data->scanner->value.v_boolean);
- return TRUE;
}
static gboolean
-parse_numeric_literal (ParseData *data, ViviCodeValue **value)
+peek_numeric_literal (ParseData *data)
{
- *value = NULL;
+ return peek_token (data, TOKEN_NUMBER);
+}
- if (!check_token (data, TOKEN_NUMBER)) {
- vivi_parser_cancel_unexpected (data, TOKEN_NUMBER);
- return FALSE;
+static void
+parse_numeric_literal (ParseData *data, ViviCodeValue **value)
+{
+ if (!try_parse_token (data, TOKEN_NUMBER)) {
+ vivi_parser_error_unexpected (data, TOKEN_NUMBER);
+ *value = vivi_code_constant_new_number (0);
+ } else {
+ *value = vivi_code_constant_new_number (data->scanner->value.v_boolean);
}
-
- *value = vivi_code_constant_new_number (data->scanner->value.v_number);
- return TRUE;
}
static gboolean
-parse_string_literal (ParseData *data, ViviCodeValue **value)
+peek_string_literal (ParseData *data)
{
- *value = NULL;
+ return peek_token (data, TOKEN_STRING);
+}
- if (!check_token (data, TOKEN_STRING)) {
- vivi_parser_cancel_unexpected (data, TOKEN_STRING);
- return FALSE;
+static void
+parse_string_literal (ParseData *data, ViviCodeValue **value)
+{
+ if (!try_parse_token (data, TOKEN_STRING)) {
+ vivi_parser_error_unexpected (data, TOKEN_STRING);
+ *value = vivi_code_constant_new_string ("undefined");
+ } else {
+ *value = vivi_code_constant_new_string (data->scanner->value.v_string);
}
-
- *value = vivi_code_constant_new_string (data->scanner->value.v_string);
- return TRUE;
}
+static const struct {
+ PeekFunction peek;
+ ParseValueFunction parse;
+} literal_functions[] = {
+ { peek_undefined_literal, parse_undefined_literal },
+ { peek_null_literal, parse_null_literal },
+ { peek_boolean_literal, parse_boolean_literal },
+ { peek_numeric_literal, parse_numeric_literal },
+ { peek_string_literal, parse_string_literal },
+ { NULL, NULL }
+};
+
static gboolean
-parse_literal (ParseData *data, ViviCodeValue **value)
+peek_literal (ParseData *data)
{
- static const ParseValueFunction functions[] = {
- parse_undefined_literal,
- parse_null_literal,
- parse_boolean_literal,
- parse_numeric_literal,
- parse_string_literal,
- NULL
- };
guint i;
- *value = NULL;
-
- for (i = 0; functions[i] != NULL; i++) {
- if (functions[i] (data, value))
+ for (i = 0; literal_functions[i].peek != NULL; i++) {
+ if (literal_functions[i].peek (data))
return TRUE;
}
- vivi_parser_cancel_unexpected (data, ERROR_TOKEN_LITERAL);
return FALSE;
}
-static gboolean
-parse_identifier (ParseData *data, ViviCodeValue **value)
+static void
+parse_literal (ParseData *data, ViviCodeValue **value)
{
- *value = NULL;
+ guint i;
- if (!check_token (data, TOKEN_IDENTIFIER)) {
- vivi_parser_cancel_unexpected (data, TOKEN_IDENTIFIER);
- return FALSE;
+ for (i = 0; literal_functions[i].peek != NULL; i++) {
+ if (literal_functions[i].peek (data)) {
+ literal_functions[i].parse (data, value);
+ return;
+ }
}
- *value = vivi_code_get_new_name (data->scanner->value.v_identifier);
-
- return TRUE;
+ vivi_parser_error_unexpected (data, ERROR_TOKEN_LITERAL);
+ *value = vivi_code_constant_new_undefined ();
}
static gboolean
-parse_property_name (ParseData *data, ViviCodeValue **value)
+peek_identifier (ParseData *data)
{
- static const ParseValueFunction functions[] = {
- parse_identifier,
- parse_string_literal,
- parse_numeric_literal,
- NULL
- };
- guint i;
+ return peek_token (data, TOKEN_IDENTIFIER);
+}
- *value = NULL;
+static void
+parse_identifier (ParseData *data, ViviCodeValue **value)
+{
+ if (!try_parse_token (data, TOKEN_IDENTIFIER)) {
+ vivi_parser_error_unexpected (data, TOKEN_IDENTIFIER);
+ *value = vivi_code_get_new_name ("undefined");
+ } else {
+ *value = vivi_code_get_new_name (data->scanner->value.v_identifier);
+ }
+}
- for (i = 0; functions[i] != NULL; i++) {
- if (functions[i] (data, value))
+static const struct {
+ PeekFunction peek;
+ ParseValueFunction parse;
+} property_name_functions[] = {
+ { peek_identifier, parse_identifier },
+ { peek_string_literal, parse_string_literal },
+ { peek_numeric_literal, parse_numeric_literal },
+ { NULL, NULL }
+};
+
+G_GNUC_UNUSED static gboolean
+peek_property_name (ParseData *data)
+{
+ guint i;
+
+ for (i = 0; property_name_functions[i].peek != NULL; i++) {
+ if (property_name_functions[i].peek (data))
return TRUE;
}
- vivi_parser_cancel_unexpected (data, ERROR_TOKEN_PROPERTY_NAME);
return FALSE;
}
+static void
+parse_property_name (ParseData *data, ViviCodeValue **value)
+{
+ guint i;
+
+ for (i = 0; property_name_functions[i].peek != NULL; i++) {
+ if (property_name_functions[i].peek (data)) {
+ property_name_functions[i].parse (data, value);
+ return;
+ }
+ }
+
+ vivi_parser_error_unexpected (data, ERROR_TOKEN_PROPERTY_NAME);
+ *value = vivi_code_constant_new_undefined ();
+}
+
+static gboolean
+peek_array_literal (ParseData *data)
+{
+ return peek_token (data, TOKEN_BRACKET_LEFT);
+}
+
static gboolean
+peek_assignment_expression (ParseData *data);
+
+static void
parse_assignment_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement);
-static gboolean
+static void
parse_array_literal (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
ViviCodeValue *member;
ViviCodeStatement *statement_new;
- *value = NULL;
- *statement = NULL;
-
- if (!check_token (data, TOKEN_BRACKET_LEFT)) {
- vivi_parser_cancel_unexpected (data, TOKEN_BRACKET_LEFT);
- return FALSE;
- }
-
*value = vivi_code_init_array_new ();
+ parse_token (data, TOKEN_BRACKET_LEFT);
+
while (TRUE) {
- if (check_token (data, TOKEN_BRACKET_RIGHT)) {
+ if (try_parse_token (data, TOKEN_BRACKET_RIGHT)) {
vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
vivi_code_constant_new_undefined ());
break;
- } else if (check_token (data, TOKEN_COMMA)) {
+ } else if (try_parse_token (data, TOKEN_COMMA)) {
vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
vivi_code_constant_new_undefined ());
- } else if (parse_assignment_expression (data, &member, &statement_new)) {
+ }
+ else if (peek_assignment_expression (data))
+ {
+ parse_assignment_expression (data, &member, &statement_new);
+
*statement = vivi_parser_join_statements (*statement, statement_new);
vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
member);
g_object_unref (member);
- if (!check_token (data, TOKEN_COMMA)) {
- if (!check_token (data, TOKEN_BRACKET_RIGHT)) {
- vivi_parser_error_unexpected (data, TOKEN_BRACKET_RIGHT,
- TOKEN_COMMA);
+ if (!try_parse_token (data, TOKEN_COMMA)) {
+ if (!try_parse_token (data, TOKEN_BRACKET_RIGHT)) {
+ vivi_parser_error_unexpected_or (data, TOKEN_BRACKET_RIGHT,
+ TOKEN_COMMA, TOKEN_NONE);
}
break;
}
} else {
- vivi_parser_error_unexpected (data, TOKEN_BRACKET_RIGHT, TOKEN_COMMA,
- ERROR_TOKEN_ASSIGNMENT_EXPRESSION);
+ vivi_parser_error_unexpected_or (data, TOKEN_BRACKET_RIGHT, TOKEN_COMMA,
+ ERROR_TOKEN_ASSIGNMENT_EXPRESSION, TOKEN_NONE);
break;
}
}
-
- return TRUE;
}
static gboolean
+peek_object_literal (ParseData *data)
+{
+ return peek_token (data, TOKEN_BRACE_LEFT);
+}
+
+static void
parse_object_literal (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
- gboolean status;
-
- *value = NULL;
- *statement = NULL;
-
- if (!check_token (data, TOKEN_BRACE_LEFT)) {
- vivi_parser_cancel_unexpected (data, TOKEN_BRACE_LEFT);
- return FALSE;
- }
-
*value = vivi_code_init_object_new ();
- if (!check_token (data, TOKEN_BRACE_RIGHT)) {
+ parse_token (data, TOKEN_BRACE_LEFT);
+
+ if (!peek_token (data, TOKEN_BRACE_RIGHT)) {
do {
ViviCodeValue *property, *initializer;
ViviCodeStatement *statement_new;
- if (!parse_property_name (data, &property))
- vivi_parser_error_child_value (data, &property);
-
- if (!check_token (data, TOKEN_COLON))
- vivi_parser_error_unexpected (data, TOKEN_COLON);
-
- if (!parse_assignment_expression (data, &initializer, &statement_new))
- vivi_parser_error_child_value (data, &initializer);
+ parse_property_name (data, &property);
+ parse_token (data, TOKEN_COLON);
+ parse_assignment_expression (data, &initializer, &statement_new);
*statement = vivi_parser_join_statements (*statement, statement_new);
vivi_code_init_object_add_variable (VIVI_CODE_INIT_OBJECT (*value),
property, initializer);
- } while (check_token (data, TOKEN_COMMA));
+ } while (try_parse_token (data, TOKEN_COMMA));
}
- if (!check_token (data, TOKEN_BRACE_RIGHT))
- vivi_parser_error_unexpected (data, TOKEN_BRACE_RIGHT);
-
- return TRUE;
+ parse_token (data, TOKEN_BRACE_RIGHT);
}
// misc
static gboolean
+peek_variable_declaration (ParseData *data)
+{
+ return peek_identifier (data);
+}
+
+static void
parse_variable_declaration (ParseData *data, ViviCodeStatement **statement)
{
- gboolean status;
ViviCodeValue *identifier, *value;
ViviCodeStatement *assignment, *statement_right;
- *statement = NULL;
-
- if (!parse_identifier (data, &identifier)) {
- vivi_parser_cancel_unexpected (data, ERROR_TOKEN_IDENTIFIER);
- return FALSE;
- }
+ parse_identifier (data, &identifier);
- if (check_token (data, TOKEN_ASSIGN)) {
- if (!parse_assignment_expression (data, &value, &statement_right))
- vivi_parser_error_child_value (data, value);
+ if (try_parse_token (data, TOKEN_ASSIGN)) {
+ parse_assignment_expression (data, &value, &statement_right);
} else {
value = vivi_code_constant_new_undefined ();
statement_right = NULL;
@@ -722,93 +798,121 @@ parse_variable_declaration (ParseData *data, ViviCodeStatement **statement)
vivi_code_assignment_set_local (VIVI_CODE_ASSIGNMENT (assignment), TRUE);
*statement = vivi_parser_join_statements (statement_right, assignment);
-
- return TRUE;
}
// expression
+static const struct {
+ PeekFunction peek;
+ ParseValueFunction parse_value;
+ ParseValueStatementFunction parse_value_statement;
+} primary_expression_functions[] = {
+ { peek_object_literal, NULL, parse_object_literal },
+ { peek_array_literal, NULL, parse_array_literal },
+ { peek_identifier, parse_identifier, NULL },
+ { peek_literal, parse_literal, NULL },
+ { NULL, NULL, NULL }
+};
+
static gboolean
+peek_primary_expression (ParseData *data)
+{
+ guint i;
+
+ if (peek_token (data, TOKEN_THIS)||
+ peek_token (data, TOKEN_PARENTHESIS_LEFT))
+ return TRUE;
+
+ for (i = 0; primary_expression_functions[i].peek != NULL; i++) {
+ if (primary_expression_functions[i].peek (data))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
parse_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement);
-static gboolean
+static void
parse_primary_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
- *value = NULL;
- *statement = NULL;
+ guint i;
- if (check_token (data, TOKEN_THIS)) {
+ if (try_parse_token (data, TOKEN_THIS)) {
*value = vivi_code_get_new_name ("this");
- return TRUE;
+ return;
}
- if (check_token (data, TOKEN_PARENTHESIS_LEFT)) {
- if (!parse_expression (data, value, statement))
- vivi_parser_error_child_value (data, value);
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
- vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
- return TRUE;
+ if (try_parse_token (data, TOKEN_PARENTHESIS_LEFT)) {
+ parse_expression (data, value, statement);
+ parse_token (data, TOKEN_PARENTHESIS_RIGHT);
+ return;
}
- if (parse_object_literal (data, value, statement))
- return TRUE;
-
- if (parse_array_literal (data, value, statement))
- return TRUE;
-
- if (parse_identifier (data, value))
- return TRUE;
-
- if (parse_literal (data, value))
- return TRUE;
+ for (i = 0; primary_expression_functions[i].peek != NULL; i++) {
+ if (primary_expression_functions[i].peek (data)) {
+ if (primary_expression_functions[i].parse_value != NULL) {
+ primary_expression_functions[i].parse_value (data, value);
+ *statement = NULL;
+ } else {
+ primary_expression_functions[i].parse_value_statement (data, value,
+ statement);
+ }
+ return;
+ }
+ }
- vivi_parser_cancel_unexpected (ERROR_TOKEN_PRIMARY_EXPRESSION);
- return FALSE;
+ vivi_parser_error_unexpected (data, ERROR_TOKEN_PRIMARY_EXPRESSION);
+ *value = vivi_code_constant_new_undefined ();
+ *statement = NULL;
}
static gboolean
+peek_function_expression (ParseData *data);
+
+static void
parse_function_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement);
static gboolean
+peek_member_expression (ParseData *data)
+{
+ return (peek_primary_expression (data) || peek_function_expression (data));
+}
+
+static void
parse_member_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
- gboolean status;
ViviCodeValue *member;
ViviCodeStatement *statement_member;
- *value = NULL;
- *statement = NULL;
-
- // TODO: new MemberExpression Arguments
-
- if (!parse_primary_expression (data, value, statement)) {
- if (!parse_function_expression (data, value, statement)) {
- vivi_parser_cancel_unexpected (data, ERROR_PRIMARY_EXPRESSION,
- ERROR_FUNCTION_EXPRESSION);
- return FALSE;
- }
+ if (peek_primary_expression (data)) {
+ parse_primary_expression (data, value, statement);
+ } else if (peek_function_expression (data)) {
+ parse_function_expression (data, value, statement);
+ } else {
+ vivi_parser_error_unexpected_or (data, ERROR_TOKEN_PRIMARY_EXPRESSION,
+ ERROR_TOKEN_FUNCTION_EXPRESSION, TOKEN_NONE);
+ *value = vivi_code_constant_new_undefined ();
}
- while (TRUE) {
+ while (TRUE) {
ViviCodeValue *tmp;
- if (check_token (data, TOKEN_BRACKET_LEFT)) {
- if (!parse_expression (data, &member, &statement_member))
- vivi_parser_error_child_value (data, &member);
+ if (try_parse_token (data, TOKEN_BRACKET_LEFT)) {
+ parse_expression (data, &member, &statement_member);
*statement = vivi_parser_join_statements (*statement, statement_member);
- if (!check_token (data, TOKEN_BRACKET_RIGHT))
- vivi_parser_error_unexpected (data, TOKEN_BRACKET_RIGHT);
- } else if (check_token (data, TOKEN_DOT)) {
- if (!parse_identifier (data, &member))
- vivi_parser_error_child_value (data, &member);
+ parse_token (data, TOKEN_BRACKET_RIGHT);
+ } else if (try_parse_token (data, TOKEN_DOT)) {
+ parse_identifier (data, &member);
} else {
- return TRUE;
+ return;
}
tmp = *value;
@@ -821,31 +925,13 @@ parse_member_expression (ParseData *data, ViviCodeValue **value,
}
static gboolean
-parse_new_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
+peek_left_hand_side_expression (ParseData *data)
{
- gboolean status;
+ return (peek_token (data, TOKEN_NEW) || peek_member_expression (data));
- *value = NULL;
- *statement = NULL;
-
- if (check_token (data, TOKEN_NEW)) {
- if (!parse_new_expression (data, value, statement))
- vivi_parser_error_child_value (data, value);
- if (!VIVI_IS_CODE_FUNCTION_CALL (*value)) {
- ViviCodeValue *tmp = VIVI_CODE_VALUE (*value);
- *value = vivi_parser_function_call_new (tmp);
- g_object_unref (tmp);
- }
- vivi_code_function_call_set_construct (VIVI_CODE_FUNCTION_CALL (*value),
- TRUE);
- return TRUE;
- } else {
- return parse_member_expression (data, value, statement);
- }
}
-static gboolean
+static void
parse_left_hand_side_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
@@ -854,44 +940,32 @@ parse_left_hand_side_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement *argument_statement;
guint i;
- *value = NULL;
- *statement = NULL;
+ if (try_parse_token (data, TOKEN_NEW)) {
+ parse_left_hand_side_expression (data, value, statement);
- if (check_token (data, TOKEN_NEW)) {
- if (!parse_new_expression (data, value, statement))
- vivi_parser_error_child_value (data, value);
if (!VIVI_IS_CODE_FUNCTION_CALL (*value)) {
ViviCodeValue *tmp = VIVI_CODE_VALUE (*value);
*value = vivi_parser_function_call_new (tmp);
g_object_unref (tmp);
}
+
vivi_code_function_call_set_construct (VIVI_CODE_FUNCTION_CALL (*value),
TRUE);
- return TRUE;
+ return;
}
- if (!parse_member_expression (data, value, statement)) {
- vivi_parser_cancel_unexpected (data, ERROR_TOKEN_MEMBER_EXPRESSION);
- return FALSE;
- }
+ parse_member_expression (data, value, statement);
- while (TRUE) {
- // TODO: member expressions?
- if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
- break;
-
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
- if (!parse_value_statement_list (data, parse_assignment_expression,
- &arguments, &argument_statement, TOKEN_COMMA)) {
- // TODO
- arguments = NULL;
- }
+ while (try_parse_token (data, TOKEN_PARENTHESIS_LEFT)) {
+ if (!try_parse_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+ parse_value_statement_list (data, peek_assignment_expression,
+ parse_assignment_expression, &arguments, &argument_statement,
+ TOKEN_COMMA);
*statement =
vivi_parser_join_statements (*statement, argument_statement);
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
- vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
+ parse_token (data, TOKEN_PARENTHESIS_RIGHT);
} else {
arguments = NULL;
}
@@ -908,39 +982,37 @@ parse_left_hand_side_expression (ParseData *data, ViviCodeValue **value,
free_value_list (arguments);
}
}
-
- return TRUE;
}
static gboolean
+peek_postfix_expression (ParseData *data)
+{
+ return peek_left_hand_side_expression (data);
+}
+
+static void
parse_postfix_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
ViviCodeValue *operation, *one, *temporary;
const char *operator;
- *value = NULL;
- *statement = NULL;
+ parse_left_hand_side_expression (data, value, statement);
- if (!parse_left_hand_side_expression (data, value, statement)) {
- vivi_parser_cancel_unexpected (data, ERROR_TOKEN_POSTFIX_EXPRESSION);
- return FALSE;
- }
-
- if (check_line_terminator (data))
- return TRUE;
+ if (peek_line_terminator (data))
+ return;
- if (check_token (data, TOKEN_INCREASE)) {
+ if (try_parse_token (data, TOKEN_INCREASE)) {
operator = "+";
- } else if (check_token (data, TOKEN_DESCREASE)) {
+ } else if (try_parse_token (data, TOKEN_DESCREASE)) {
operator = "-";
} else {
- return TRUE;
+ return;
}
// FIXME: Correct?
if (!vivi_parser_value_is_left_hand_side (*value)) {
- vivi_parser_error (
+ vivi_parser_error (data,
"Invalid left-hand side expression for INCREASE/DECREASE");
}
@@ -957,20 +1029,37 @@ parse_postfix_expression (ParseData *data, ViviCodeValue **value,
g_object_unref (*value);
*value = temporary;
-
- return TRUE;
}
static gboolean
+peek_unary_expression (ParseData *data)
+{
+ vivi_parser_scanner_peek_next_token (data->scanner);
+ switch ((guint)data->scanner->next_token) {
+ /*case TOKEN_DELETE:
+ case TOKEN_VOID:
+ case TOKEN_TYPEOF:*/
+ case TOKEN_INCREASE:
+ case TOKEN_DESCREASE:
+ /*case TOKEN_PLUS:
+ case TOKEN_MINUS:
+ case TOKEN_BITWISE_NOT:*/
+ case TOKEN_LOGICAL_NOT:
+ return TRUE;
+ default:
+ return peek_postfix_expression (data);
+ }
+
+ g_assert_not_reached ();
+}
+
+static void
parse_unary_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
- gboolean status;
ViviCodeValue *tmp, *one;
const char *operator;
- *value = NULL;
-
operator = NULL;
vivi_parser_scanner_peek_next_token (data->scanner);
@@ -986,12 +1075,11 @@ parse_unary_expression (ParseData *data, ViviCodeValue **value,
vivi_parser_scanner_get_next_token (data->scanner);
- if (!parse_unary_expression (data, value, statement))
- vivi_parser_error_child_value (data, value);
+ parse_unary_expression (data, value, statement);
// FIXME: Correct?
if (!vivi_parser_value_is_left_hand_side (*value)) {
- vivi_parser_error (
+ vivi_parser_error (data,
"Invalid left-hand side expression for INCREASE/DECREASE");
}
@@ -1002,24 +1090,22 @@ parse_unary_expression (ParseData *data, ViviCodeValue **value,
*statement = vivi_parser_join_statements (*statement,
vivi_parser_assignment_new (*value, tmp));
g_object_unref (tmp);
-
- return TRUE;
+ break;
/*case TOKEN_PLUS:
case TOKEN_MINUS:
case TOKEN_BITWISE_NOT:*/
case TOKEN_LOGICAL_NOT:
vivi_parser_scanner_get_next_token (data->scanner);
- if (!parse_unary_expression (data, value, statement))
- vivi_parser_error_child_value (data, value);
+ parse_unary_expression (data, value, statement);
tmp = VIVI_CODE_VALUE (*value);
*value = vivi_code_unary_new (tmp, '!');
g_object_unref (tmp);
-
- return TRUE;
+ break;
default:
- return parse_postfix_expression (data, value, statement);
+ parse_postfix_expression (data, value, statement);
+ break;
}
}
@@ -1029,7 +1115,7 @@ typedef enum {
PASS_LOGICAL_AND
} ParseOperatorPass;
-static gboolean
+static void
parse_operator_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement, const ViviParserScannerToken *tokens,
ParseOperatorPass pass, ParseValueStatementFunction next_parse_function)
@@ -1038,18 +1124,12 @@ parse_operator_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement *statement_right;
guint i;
- *value = NULL;
- *statement = NULL;
-
- if (!next_parse_function (data, value, statement)) {
- // FIXME: token?
- return FALSE;
- }
+ next_parse_function (data, value, statement);
- for (i = 0; tokens[i] != TRUE; i++) {
- while (check_token (data, tokens[i])) {
- if (!next_parse_function (data, &right, &statement_right))
- vivi_parser_error_child_value (data, &right);
+again:
+ for (i = 0; tokens[i] != TOKEN_NONE; i++) {
+ if (try_parse_token (data, tokens[i])) {
+ next_parse_function (data, &right, &statement_right);
if (statement_right != NULL) {
ViviCodeStatement *tmp;
@@ -1082,46 +1162,70 @@ parse_operator_expression (ParseData *data, ViviCodeValue **value,
vivi_parser_scanner_token_name (tokens[i]));
g_object_unref (left);
g_object_unref (right);
- };
- }
- return TRUE;
+ goto again;
+ }
+ }
}
static gboolean
+peek_multiplicative_expression (ParseData *data)
+{
+ return peek_unary_expression (data);
+}
+
+static void
parse_multiplicative_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
static const ViviParserScannerToken tokens[] = { TOKEN_MULTIPLY,
TOKEN_DIVIDE, TOKEN_REMAINDER, TOKEN_NONE };
- return parse_operator_expression (data, value, statement, tokens,
- PASS_ALWAYS, parse_unary_expression);
+ parse_operator_expression (data, value, statement, tokens, PASS_ALWAYS,
+ parse_unary_expression);
}
static gboolean
+peek_additive_expression (ParseData *data)
+{
+ return peek_multiplicative_expression (data);
+}
+
+static void
parse_additive_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
static const ViviParserScannerToken tokens[] = { TOKEN_PLUS, TOKEN_MINUS,
TOKEN_NONE };
- return parse_operator_expression (data, value, statement, tokens,
- PASS_ALWAYS, parse_multiplicative_expression);
+ parse_operator_expression (data, value, statement, tokens, PASS_ALWAYS,
+ parse_multiplicative_expression);
}
static gboolean
+peek_shift_expression (ParseData *data)
+{
+ return peek_additive_expression (data);
+}
+
+static void
parse_shift_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
static const ViviParserScannerToken tokens[] = { TOKEN_SHIFT_LEFT,
TOKEN_SHIFT_RIGHT, TOKEN_SHIFT_RIGHT_UNSIGNED, TOKEN_NONE };
- return parse_operator_expression (data, value, statement, tokens,
- PASS_ALWAYS, parse_additive_expression);
+ parse_operator_expression (data, value, statement, tokens, PASS_ALWAYS,
+ parse_additive_expression);
}
static gboolean
+peek_relational_expression (ParseData *data)
+{
+ return peek_shift_expression (data);
+}
+
+static void
parse_relational_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
@@ -1129,11 +1233,17 @@ parse_relational_expression (ParseData *data, ViviCodeValue **value,
TOKEN_GREATER_THAN, /*TOKEN_LESS_THAN_OR_EQUAL,
TOKEN_EQUAL_OR_GREATER_THAN, TOKEN_INSTANCEOF, TOKEN_IN,*/ TOKEN_NONE };
- return parse_operator_expression (data, value, statement, tokens,
- PASS_ALWAYS, parse_shift_expression);
+ parse_operator_expression (data, value, statement, tokens, PASS_ALWAYS,
+ parse_shift_expression);
}
static gboolean
+peek_equality_expression (ParseData *data)
+{
+ return peek_relational_expression (data);
+}
+
+static void
parse_equality_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
@@ -1141,78 +1251,111 @@ parse_equality_expression (ParseData *data, ViviCodeValue **value,
/*TOKEN_NOT_EQUAL,*/ TOKEN_STRICT_EQUAL, /*TOKEN_NOT_STRICT_EQUAL,*/
TOKEN_NONE };
- return parse_operator_expression (data, value, statement, tokens,
- PASS_ALWAYS, parse_relational_expression);
+ parse_operator_expression (data, value, statement, tokens, PASS_ALWAYS,
+ parse_relational_expression);
}
static gboolean
+peek_bitwise_and_expression (ParseData *data)
+{
+ return peek_equality_expression (data);
+}
+
+static void
parse_bitwise_and_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
static const ViviParserScannerToken tokens[] = { TOKEN_BITWISE_AND,
TOKEN_NONE };
- return parse_operator_expression (data, value, statement, tokens,
- PASS_ALWAYS, parse_equality_expression);
+ parse_operator_expression (data, value, statement, tokens, PASS_ALWAYS,
+ parse_equality_expression);
}
static gboolean
+peek_bitwise_xor_expression (ParseData *data)
+{
+ return peek_bitwise_and_expression (data);
+}
+
+static void
parse_bitwise_xor_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
static const ViviParserScannerToken tokens[] = { TOKEN_BITWISE_XOR,
TOKEN_NONE };
- return parse_operator_expression (data, value, statement, tokens,
- PASS_ALWAYS, parse_bitwise_and_expression);
+ parse_operator_expression (data, value, statement, tokens, PASS_ALWAYS,
+ parse_bitwise_and_expression);
}
static gboolean
+peek_bitwise_or_expression (ParseData *data)
+{
+ return peek_bitwise_xor_expression (data);
+}
+
+static void
parse_bitwise_or_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
static const ViviParserScannerToken tokens[] = { TOKEN_BITWISE_OR,
TOKEN_NONE };
- return parse_operator_expression (data, value, statement, tokens,
- PASS_ALWAYS, parse_bitwise_xor_expression);
+ parse_operator_expression (data, value, statement, tokens, PASS_ALWAYS,
+ parse_bitwise_xor_expression);
}
static gboolean
+peek_logical_and_expression (ParseData *data)
+{
+ return peek_bitwise_or_expression (data);
+}
+
+static void
parse_logical_and_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
static const ViviParserScannerToken tokens[] = { TOKEN_LOGICAL_AND,
TOKEN_NONE };
- return parse_operator_expression (data, value, statement, tokens,
- PASS_LOGICAL_AND, parse_bitwise_or_expression);
+ parse_operator_expression (data, value, statement, tokens, PASS_LOGICAL_AND,
+ parse_bitwise_or_expression);
}
static gboolean
+peek_logical_or_expression (ParseData *data)
+{
+ return peek_logical_and_expression (data);
+}
+
+static void
parse_logical_or_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
static const ViviParserScannerToken tokens[] = { TOKEN_LOGICAL_OR,
TOKEN_NONE };
- return parse_operator_expression (data, value, statement, tokens,
- PASS_LOGICAL_OR, parse_logical_and_expression);
+ parse_operator_expression (data, value, statement, tokens, PASS_LOGICAL_OR,
+ parse_logical_and_expression);
}
static gboolean
+peek_conditional_expression (ParseData *data)
+{
+ return peek_logical_or_expression (data);
+}
+
+static void
parse_conditional_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
//ViviCodeStatement *if_statement, *else_statement;
- *value = NULL;
-
- if (!parse_logical_or_expression (data, value, statement))
- return FALSE;
+ parse_logical_or_expression (data, value, statement);
#if 0
- if (!check_token (data, TOKEN_QUESTION_MARK)) {
+ if (!parse_token (data, TOKEN_QUESTION_MARK)) {
*statement = vivi_code_value_statement_new (VIVI_CODE_VALUE (value));
g_object_unref (value);
return TRUE;
@@ -1224,7 +1367,7 @@ parse_conditional_expression (ParseData *data, ViviCodeValue **value,
return FAIL_CHILD (status);
}
- if (!check_token (data, TOKEN_COLON)) {
+ if (!parse_token (data, TOKEN_COLON)) {
g_object_unref (value);
g_object_unref (if_statement);
return TOKEN_COLON;
@@ -1245,11 +1388,15 @@ parse_conditional_expression (ParseData *data, ViviCodeValue **value,
g_object_unref (if_statement);
g_object_unref (else_statement);
#endif
-
- return TRUE;
}
static gboolean
+peek_assignment_expression (ParseData *data)
+{
+ return peek_conditional_expression (data);
+}
+
+static void
parse_assignment_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
@@ -1257,16 +1404,11 @@ parse_assignment_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement *assignment, *statement_right;
const char *operator;
- *value = NULL;
- *statement = NULL;
-
- if (!parse_conditional_expression (data, value, statement)) {
- vivi_parser_cancel_unexpected (data, ERROR_TOKEN_CONDITIONAL_EXPRESSION);
- return FALSE;
- }
+ parse_conditional_expression (data, value, statement);
+ // FIXME: Correct?
if (!vivi_parser_value_is_left_hand_side (*value))
- return TRUE;
+ return;
operator = NULL;
@@ -1297,8 +1439,7 @@ parse_assignment_expression (ParseData *data, ViviCodeValue **value,
case TOKEN_ASSIGN:
vivi_parser_scanner_get_next_token (data->scanner);
- if (parse_assignment_expression (data, &right, &statement_right))
- vivi_parser_error_child_value (data, &right);
+ parse_assignment_expression (data, &right, &statement_right);
if (operator != NULL) {
assignment = vivi_parser_assignment_new (*value,
@@ -1310,98 +1451,71 @@ parse_assignment_expression (ParseData *data, ViviCodeValue **value,
*statement = vivi_parser_join_statements (*statement,
vivi_parser_join_statements (statement_right, assignment));
-
- return TRUE;
+ break;
default:
- return TRUE;
+ break;
}
-
- g_assert_not_reached ();
}
static gboolean
+peek_expression (ParseData *data)
+{
+ return peek_assignment_expression (data);
+}
+
+static void
parse_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
ViviCodeStatement *statement_one;
+ *value = NULL;
*statement = NULL;
- if (parse_assignment_expression (data, value, &statement_one)) {
- vivi_parser_cancel_unexpected (data, ERROR_TOKEN_ASSIGNMENT_EXPRESSION);
- return FALSE;
- }
-
- while (TRUE) {
+ do {
+ if (*value != NULL)
+ g_object_unref (*value);
+ parse_assignment_expression (data, value, &statement_one);
*statement = vivi_parser_join_statements (*statement, statement_one);
-
- if (!check_token (data, TOKEN_COMMA))
- break;
-
- g_object_unref (*value);
-
- if (!parse_assignment_expression (data, value, &statement_one))
- vivi_parser_error_child_value (data, value);
- }
-
- return TRUE;
+ } while (try_parse_token (data, TOKEN_COMMA));
}
// statement
static gboolean
-parse_statement (ParseData *data, ViviCodeStatement **statement);
+peek_trace_statement (ParseData *data)
+{
+ return peek_token (data, TOKEN_TRACE);
+}
-static gboolean
+static void
parse_trace_statement (ParseData *data, ViviCodeStatement **statement)
{
ViviCodeValue *value;
ViviCodeStatement *expression_statement;
- *statement = NULL;
-
- if (!check_token (data, TOKEN_TRACE)) {
- vivi_parser_cancel_unexpected (data, TOKEN_TRACE);
- return FALSE;
- }
-
- if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
- vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
-
- if (parse_expression (data, &value, &expression_statement))
- vivi_parser_error_child_value (data, &value);
-
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
- vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
-
- if (!check_automatic_semicolon (data))
- vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
+ parse_token (data, TOKEN_TRACE);
+ parse_token (data, TOKEN_PARENTHESIS_LEFT);
+ parse_expression (data, &value, &expression_statement);
+ parse_token (data, TOKEN_PARENTHESIS_RIGHT);
+ parse_automatic_semicolon (data);
*statement = vivi_code_trace_new (value);
g_object_unref (value);
*statement = vivi_parser_join_statements (expression_statement, *statement);
-
- return TRUE;
}
-static gboolean
+static void
parse_continue_or_break_statement (ParseData *data,
ViviCodeStatement **statement, ViviParserScannerToken token)
{
- *statement = NULL;
+ parse_token (data, token);
- if (!check_token (data, token)) {
- vivi_parser_cancel_unexpected (data, token);
- return FALSE;
- }
-
- if (!check_restricted_semicolon (data)) {
- gboolean status;
+ if (!try_parse_restricted_semicolon (data)) {
ViviCodeValue *identifier;
- if (!parse_identifier (data, &identifier))
- vivi_parser_error_child_value (data, &identifier);
+ parse_identifier (data, &identifier);
// FIXME
*statement = vivi_compiler_goto_name_new (
@@ -1411,81 +1525,84 @@ parse_continue_or_break_statement (ParseData *data,
vivi_parser_add_goto (data, VIVI_COMPILER_GOTO_NAME (*statement));
- if (!check_automatic_semicolon (data))
- vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
+ parse_automatic_semicolon (data);
} else {
+ // FIXME
*statement = vivi_code_break_new ();
}
-
- return TRUE;
}
static gboolean
+peek_continue_statement (ParseData *data)
+{
+ return peek_token (data, TOKEN_CONTINUE);
+}
+
+static void
parse_continue_statement (ParseData *data, ViviCodeStatement **statement)
{
return parse_continue_or_break_statement (data, statement, TOKEN_CONTINUE);
}
static gboolean
+peek_break_statement (ParseData *data)
+{
+ return peek_token (data, TOKEN_BREAK);
+}
+
+static void
parse_break_statement (ParseData *data, ViviCodeStatement **statement)
{
- return parse_continue_or_break_statement (data, statement, TOKEN_BREAK);
+ parse_continue_or_break_statement (data, statement, TOKEN_BREAK);
}
static gboolean
+peek_throw_statement (ParseData *data)
+{
+ return peek_token (data, TOKEN_THROW);
+}
+
+static void
parse_throw_statement (ParseData *data, ViviCodeStatement **statement)
{
- gboolean status;
ViviCodeValue *value;
ViviCodeStatement *expression_statement;
- *statement = NULL;
-
- if (!check_token (data, TOKEN_THROW)) {
- vivi_parser_cancel_unexpected (data, TOKEN_THROW);
- return FALSE;
- }
+ parse_token (data, TOKEN_THROW);
- if (check_line_terminator (data))
+ if (peek_line_terminator (data)) {
vivi_parser_error_unexpected_line_terminator (data,
ERROR_TOKEN_EXPRESSION);
+ }
- if (parse_expression (data, &value, &expression_statement))
- vivi_parser_error_child_value (data, &value);
+ parse_expression (data, &value, &expression_statement);
*statement = vivi_code_throw_new (value);
g_object_unref (value);
*statement = vivi_parser_join_statements (expression_statement, *statement);
- if (!check_automatic_semicolon (data))
- vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
-
- return TRUE;
+ parse_automatic_semicolon (data);
}
static gboolean
-parse_return_statement (ParseData *data, ViviCodeStatement **statement)
+peek_return_statement (ParseData *data)
{
- *statement = NULL;
-
- if (!check_token (data, TOKEN_RETURN)) {
- vivi_parser_cancel_unexpected (data, TOKEN_RETURN);
- return FALSE;
- }
+ return peek_token (data, TOKEN_RETURN);
+}
+static void
+parse_return_statement (ParseData *data, ViviCodeStatement **statement)
+{
*statement = vivi_code_return_new ();
- if (!check_restricted_semicolon (data)) {
- gboolean status;
+ parse_token (data, TOKEN_RETURN);
+
+ if (!try_parse_restricted_semicolon (data)) {
ViviCodeValue *value;
ViviCodeStatement *expression_statement;
- if (!parse_expression (data, &value, &expression_statement)) {
- vivi_parser_error_unexpected (data, TOKEN_SEMICOLON,
- ERROR_TOKEN_EXPRESSION);
- return TRUE;
- }
+ parse_expression (data, &value, &expression_statement);
vivi_code_return_set_value (VIVI_CODE_RETURN (*statement), value);
g_object_unref (value);
@@ -1493,69 +1610,60 @@ parse_return_statement (ParseData *data, ViviCodeStatement **statement)
*statement =
vivi_parser_join_statements (expression_statement, *statement);
- if (!check_automatic_semicolon (data))
- vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
+ parse_automatic_semicolon (data);
}
-
- return TRUE;
}
static gboolean
+peek_statement (ParseData *data);
+
+static void
+parse_statement (ParseData *data, ViviCodeStatement **statement);
+
+static gboolean
+peek_iteration_statement (ParseData *data)
+{
+ return (peek_token (data, TOKEN_DO) || peek_token (data, TOKEN_WHILE) ||
+ peek_token (data, TOKEN_FOR));
+}
+
+static void
parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
{
ViviCodeValue *condition;
ViviCodeStatement *pre_statement, *condition_statement, *loop_statement;
- *statement = NULL;
-
- pre_statement = NULL;
- condition_statement = NULL;
-
- if (check_token (data, TOKEN_DO)) {
- if (!parse_statement (data, &loop_statement))
- vivi_parser_error_child_statement (data, &loop_statement);
-
- if (!check_token (data, TOKEN_WHILE))
- vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
-
- if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
- vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
-
- if (parse_expression (data, &condition, &condition_statement))
- vivi_parser_error_child_value (data, &condition);
-
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
- vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
-
- if (!check_automatic_semicolon (data))
- vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
+ if (try_parse_token (data, TOKEN_DO))
+ {
+ parse_statement (data, &loop_statement);
+ parse_token (data, TOKEN_WHILE);
+ parse_token (data, TOKEN_PARENTHESIS_LEFT);
+ parse_expression (data, &condition, &condition_statement);
+ parse_token (data, TOKEN_PARENTHESIS_RIGHT);
+ parse_automatic_semicolon (data);
pre_statement = g_object_ref (loop_statement);
- } else if (check_token (data, TOKEN_WHILE)) {
- if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
- vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
-
- if (parse_expression (data, &condition, &condition_statement))
- vivi_parser_error_child_value (data, &condition);
-
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
- vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
+ }
+ else if (try_parse_token (data, TOKEN_WHILE))
+ {
+ parse_token (data, TOKEN_PARENTHESIS_LEFT);
+ parse_expression (data, &condition, &condition_statement);
+ parse_token (data, TOKEN_PARENTHESIS_RIGHT);
+ parse_statement (data, &loop_statement);
- if (!parse_statement (data, &loop_statement))
- vivi_parser_error_child_statement (data, &loop_statement);
- } else if (check_token (data, TOKEN_FOR)) {
+ pre_statement = NULL;
+ }
+ else if (try_parse_token (data, TOKEN_FOR))
+ {
ViviCodeValue *pre_value;
ViviCodeStatement *post_statement;
- if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
- vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
+ parse_token (data, TOKEN_PARENTHESIS_LEFT);
- if (check_token (data, TOKEN_VAR)) {
+ if (try_parse_token (data, TOKEN_VAR)) {
// FIXME: no in
- if (parse_statement_list (data, parse_variable_declaration,
- &pre_statement, TOKEN_COMMA)) {
- // FIXME
- }
+ parse_statement_list (data, peek_variable_declaration,
+ parse_variable_declaration, &pre_statement, TOKEN_COMMA);
// FIXME: ugly
// If there was only one VariableDeclaration, get the name for pre_value
g_assert (VIVI_IS_CODE_BLOCK (pre_statement));
@@ -1569,49 +1677,60 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
pre_value = NULL;
}
} else {
- if (!check_token (data, TOKEN_SEMICOLON)) {
- // FIXME: no in
- if (parse_expression (data, &pre_value, &pre_statement))
- vivi_parser_error_child_value (data, &pre_value);
- } else {
+ if (try_parse_token (data, TOKEN_SEMICOLON)) {
pre_value = NULL;
pre_statement = NULL;
+ } else {
+ // FIXME: no in
+ parse_expression (data, &pre_value, &pre_statement);
}
}
- if (check_token (data, TOKEN_SEMICOLON)) {
+ if (try_parse_token (data, TOKEN_SEMICOLON)) {
if (pre_value != NULL)
g_object_unref (pre_value);
- if (!check_token (data, TOKEN_SEMICOLON)) {
- if (parse_expression (data, &condition, &condition_statement))
- vivi_parser_error_child_value (data, &condition);
- if (!check_token (data, TOKEN_SEMICOLON))
- vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
+ if (try_parse_token (data, TOKEN_SEMICOLON)) {
+ condition = vivi_code_constant_new_boolean (TRUE);
+ condition_statement = NULL;
+ } else {
+ parse_expression (data, &condition, &condition_statement);
+ parse_token (data, TOKEN_SEMICOLON);
}
- if (!parse_expression (data, &pre_value, &post_statement))
- vivi_parser_error_child_value (data, &pre_value);
- g_object_unref (pre_value);
- } else if (pre_value != NULL && check_token (data, TOKEN_IN)) {
+ if (peek_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+ post_statement = NULL;
+ } else {
+ parse_expression (data, &pre_value, &post_statement);
+ g_object_unref (pre_value);
+ }
+ } else if (pre_value != NULL && try_parse_token (data, TOKEN_IN)) {
post_statement = NULL;
// FIXME: correct?
if (!vivi_parser_value_is_left_hand_side (pre_value))
- vivi_parser_error ("Invalid left-hand side expression for in");
+ vivi_parser_error (data, "Invalid left-hand side expression for in");
g_object_unref (pre_value);
if (pre_statement != NULL)
g_object_unref (pre_statement);
- vivi_parser_error ("for (... in ...) has not been implemented yet");
+
+ vivi_parser_error (data, "for (... in ...) has not been implemented yet");
+
+ condition = vivi_code_constant_new_undefined ();
+ condition_statement = NULL;
+ post_statement = NULL;
} else {
if (pre_value != NULL) {
- vivi_parser_error_unexpected (data, TOKEN_SEMICOLON, TOKEN_IN);
+ vivi_parser_error_unexpected_or (data, TOKEN_SEMICOLON, TOKEN_IN,
+ TOKEN_NONE);
} else {
vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
}
condition = vivi_code_constant_new_undefined ();
+ condition_statement = NULL;
+ post_statement = NULL;
if (pre_value != NULL)
g_object_unref (pre_value);
@@ -1619,17 +1738,20 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
g_object_unref (pre_statement);
}
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
- vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
-
- if (!parse_statement (data, &loop_statement))
- vivi_parser_error_child_statement (data, &loop_statement);
+ parse_token (data, TOKEN_PARENTHESIS_RIGHT);
+ parse_statement (data, &loop_statement);
loop_statement =
vivi_parser_join_statements (loop_statement, post_statement);
- } else {
- vivi_parser_cancel_unexpected (data, ERROR_TOKEN_ITERATION_STATEMENT);
- return FALSE;
+ }
+ else
+ {
+ vivi_parser_error_unexpected (data, ERROR_TOKEN_ITERATION_STATEMENT);
+
+ condition = vivi_code_constant_new_undefined ();
+ pre_statement = NULL;
+ condition_statement = NULL;
+ loop_statement = vivi_compiler_empty_statement_new ();
}
if (condition_statement != NULL) {
@@ -1647,38 +1769,28 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
g_object_unref (loop_statement);
*statement = vivi_parser_join_statements (pre_statement, *statement);
-
- return TRUE;
}
static gboolean
+peek_if_statement (ParseData *data)
+{
+ return peek_token (data, TOKEN_IF);
+}
+
+static void
parse_if_statement (ParseData *data, ViviCodeStatement **statement)
{
ViviCodeValue *condition;
ViviCodeStatement *pre_statement, *if_statement, *else_statement;
- *statement = NULL;
-
- if (!check_token (data, TOKEN_IF)) {
- vivi_parser_cancel_unexpected (data, TOKEN_IF);
- return FALSE;
- }
-
- if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
- vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
-
- if (!parse_expression (data, &condition, &pre_statement))
- vivi_parser_error_child_value (data, &condition);
-
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
- vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
+ parse_token (data, TOKEN_IF);
+ parse_token (data, TOKEN_PARENTHESIS_LEFT);
+ parse_expression (data, &condition, &pre_statement);
+ parse_token (data, TOKEN_PARENTHESIS_RIGHT);
+ parse_statement (data, &if_statement);
- if (!parse_statement (data, &if_statement))
- vivi_parser_error_child_statement (data, &if_statement);
-
- if (check_token (data, TOKEN_ELSE)) {
- if (!parse_statement (data, &else_statement))
- vivi_parser_error_child_statement (data, &else_statement);
+ if (try_parse_token (data, TOKEN_ELSE)) {
+ parse_statement (data, &else_statement);
} else {
else_statement = NULL;
}
@@ -1695,43 +1807,40 @@ parse_if_statement (ParseData *data, ViviCodeStatement **statement)
}
*statement = vivi_parser_join_statements (pre_statement, *statement);
+}
- g_assert (*statement != NULL);
+static gboolean
+peek_expression_statement (ParseData *data)
+{
+ if (peek_token (data, TOKEN_BRACE_LEFT) || peek_token (data, TOKEN_FUNCTION))
+ return FALSE;
- return TRUE;
+ return peek_expression (data);
}
-static gboolean
+static void
parse_expression_statement (ParseData *data, ViviCodeStatement **statement)
{
ViviCodeValue *value;
ViviCodeStatement *last;
- *statement = NULL;
+ if (peek_token (data, TOKEN_BRACE_LEFT) || peek_token (data, TOKEN_FUNCTION))
+ vivi_parser_error_unexpected (data, ERROR_TOKEN_EXPRESSION_STATEMENT);
- vivi_parser_scanner_peek_next_token (data->scanner);
- if (data->scanner->next_token == TOKEN_BRACE_LEFT ||
- data->scanner->next_token == TOKEN_FUNCTION) {
- vivi_parser_cancel_unexpected (data, ERROR_TOKEN_EXPRESSION_STATEMENT);
- return FALSE;
- }
-
- if (!parse_expression (data, &value, statement))
- return FALSE;
+ parse_expression (data, &value, statement);
// check for label
- if (*statement == NULL && vivi_parser_value_is_identifier (value)) {
- if (check_token (data, TOKEN_COLON)) {
- *statement = vivi_code_label_new (vivi_code_constant_get_variable_name (
- VIVI_CODE_CONSTANT (VIVI_CODE_GET (value)->name)));
- if (!vivi_parser_add_label (data, VIVI_CODE_LABEL (*statement)))
- vivi_parser_error ("Same label name used twice");
- return TRUE;
- }
+ if (*statement == NULL && vivi_parser_value_is_identifier (value) &&
+ try_parse_token (data, TOKEN_COLON))
+ {
+ *statement = vivi_code_label_new (vivi_code_constant_get_variable_name (
+ VIVI_CODE_CONSTANT (VIVI_CODE_GET (value)->name)));
+ if (!vivi_parser_add_label (data, VIVI_CODE_LABEL (*statement)))
+ vivi_parser_error (data, "Same label name used twice");
+ return;
}
- if (!check_automatic_semicolon (data))
- vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
+ parse_automatic_semicolon (data);
// add a value statement, if the last statement is not an assignment with the
// same value
@@ -1749,124 +1858,129 @@ parse_expression_statement (ParseData *data, ViviCodeStatement **statement)
if (assignment->from == NULL && assignment->name == VIVI_CODE_GET (value)->name) {
g_object_unref (value);
- return TRUE;
+ return;
}
}
*statement = vivi_parser_join_statements (*statement,
vivi_code_value_statement_new (value));
g_object_unref (value);
-
- return TRUE;
}
static gboolean
-parse_empty_statement (ParseData *data, ViviCodeStatement **statement)
+peek_empty_statement (ParseData *data)
{
- *statement = NULL;
+ return peek_token (data, TOKEN_SEMICOLON);
+}
- if (!check_token (data, TOKEN_SEMICOLON)) {
- vivi_parser_cancel_unexpected (data, TOKEN_SEMICOLON);
- return FALSE;
- }
+static void
+parse_empty_statement (ParseData *data, ViviCodeStatement **statement)
+{
+ parse_token (data, TOKEN_SEMICOLON);
*statement = vivi_compiler_empty_statement_new ();
-
- return TRUE;
}
static gboolean
-parse_block (ParseData *data, ViviCodeStatement **statement)
+peek_block (ParseData *data)
{
- gboolean status;
-
- *statement = NULL;
-
- if (!check_token (data, TOKEN_BRACE_LEFT)) {
- vivi_parser_cancel_unexpected (data, TOKEN_BRACE_LEFT);
- return FALSE;
- }
+ return peek_token (data, TOKEN_BRACE_LEFT);
+}
- vivi_parser_scanner_peek_next_token (data->scanner);
- if (!check_token (data, TOKEN_BRACE_RIGHT)) {
- if (!parse_statement_list (data, parse_statement, statement, TRUE)) {
- // FIXME: child token
- vivi_parser_error_unexpected (data, TOKEN_BRACE_RIGHT,
- ERROR_TOKEN_STATEMENT);
- *statement = vivi_code_block_new ();
- }
+static void
+parse_block (ParseData *data, ViviCodeStatement **statement)
+{
+ parse_token (data, TOKEN_BRACE_LEFT);
- if (!check_token (data, TOKEN_BRACE_RIGHT))
- vivi_parser_error_unexpected (data, TOKEN_BRACE_RIGHT);
+ if (!try_parse_token (data, TOKEN_BRACE_RIGHT)) {
+ parse_statement_list (data, peek_statement, parse_statement, statement,
+ TOKEN_NONE);
+ parse_token (data, TOKEN_BRACE_RIGHT);
} else {
- *statement = vivi_code_block_new ();
+ *statement = vivi_code_block_new ();;
}
-
- return TRUE;
}
static gboolean
+peek_variable_statement (ParseData *data)
+{
+ return peek_token (data, TOKEN_VAR);
+}
+
+static void
parse_variable_statement (ParseData *data, ViviCodeStatement **statement)
{
- gboolean status;
+ parse_token (data, TOKEN_VAR);
+ parse_statement_list (data, peek_variable_declaration,
+ parse_variable_declaration, statement, TOKEN_COMMA);
+ parse_automatic_semicolon (data);
+}
- *statement = NULL;
+static const struct {
+ PeekFunction peek;
+ ParseStatementFunction parse;
+} statement_functions[] = {
+ { peek_block, parse_block },
+ { peek_variable_statement, parse_variable_statement },
+ { peek_empty_statement, parse_empty_statement },
+ { peek_expression_statement, parse_expression_statement },
+ { peek_if_statement, parse_if_statement },
+ { peek_iteration_statement, parse_iteration_statement },
+ { peek_continue_statement, parse_continue_statement },
+ { peek_break_statement, parse_break_statement },
+ { peek_return_statement, parse_return_statement },
+ //{ peek_with_statement, parse_with_statement },
+ //{ peek_switch_statement, parse_switch_statement },
+ { peek_throw_statement, parse_throw_statement },
+ //{ peek_try_statement, parse_try_statement },
+ { peek_trace_statement, parse_trace_statement },
+ { NULL, NULL }
+};
- if (!check_token (data, TOKEN_VAR)) {
- vivi_parser_cancel_unexpected (data, TOKEN_VAR);
- return FALSE;
- }
+static gboolean
+peek_statement (ParseData *data)
+{
+ guint i;
- if (!parse_statement_list (data, parse_variable_declaration, statement,
- TOKEN_COMMA)) {
- // FIXME
+ for (i = 0; statement_functions[i].peek != NULL; i++) {
+ if (statement_functions[i].peek (data))
+ return TRUE;
}
- if (!check_automatic_semicolon (data))
- vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
-
- return TRUE;
+ return FALSE;
}
-static gboolean
+static void
parse_statement (ParseData *data, ViviCodeStatement **statement)
{
- static const ParseStatementFunction functions[] = {
- parse_block,
- parse_variable_statement,
- parse_empty_statement,
- parse_expression_statement,
- parse_if_statement,
- parse_iteration_statement,
- parse_continue_statement,
- parse_break_statement,
- parse_return_statement,
- //parse_with_statement,
- //parse_switch_statement,
- parse_throw_statement,
- //parse_try_statement,
- parse_trace_statement,
- NULL
- };
guint i;
- *statement = NULL;
-
- for (i = 0; functions[i] != NULL; i++) {
- if (functions[i] (data, statement))
- return TRUE;
+ for (i = 0; statement_functions[i].peek != NULL; i++) {
+ if (statement_functions[i].peek (data)) {
+ statement_functions[i].parse (data, statement);
+ return;
+ }
}
- vivi_parser_cancel_unexpected (data, ERROR_TOKEN_STATEMENT);
- return FALSE;
+ vivi_parser_error_unexpected (data, ERROR_TOKEN_STATEMENT);
+ *statement = vivi_compiler_empty_statement_new ();
}
// function
static gboolean
-parse_source_element (ParseData *data, ViviCodeStatement **statement);
+peek_function_definition (ParseData *data)
+{
+ return peek_token (data, TOKEN_FUNCTION);
+}
static gboolean
+peek_source_element (ParseData *data);
+
+static void
+parse_source_element (ParseData *data, ViviCodeStatement **statement);
+
+static void
parse_function_definition (ParseData *data, ViviCodeValue **function,
ViviCodeValue **identifier, gboolean identifier_required)
{
@@ -1874,56 +1988,43 @@ parse_function_definition (ParseData *data, ViviCodeValue **function,
ViviCodeStatement *body;
guint i;
- *function = NULL;
- *identifier = NULL;
-
arguments = NULL;
body = NULL;
- if (!check_token (data, TOKEN_FUNCTION)) {
- vivi_parser_cancel_unexpected (data, TOKEN_FUNCTION);
- return FALSE;
- }
+ parse_token (data, TOKEN_FUNCTION);
if (identifier_required) {
- if (!parse_identifier (data, identifier))
- vivi_parser_error_child_value (data, identifier);
-
- if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
- vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
+ parse_identifier (data, identifier);
+ parse_token (data, TOKEN_PARENTHESIS_LEFT);
} else {
- if (!check_token (data, TOKEN_PARENTHESIS_LEFT)) {
- if (!parse_identifier (data, identifier)) {
- // FIXME: child token
- vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT,
- ERROR_TOKEN_IDENTIFIER);
+ if (!try_parse_token (data, TOKEN_PARENTHESIS_LEFT)) {
+ if (peek_identifier (data)) {
+ parse_identifier (data, identifier);
+ parse_token (data, TOKEN_PARENTHESIS_LEFT);
+ } else {
+ vivi_parser_error_unexpected_or (data, TOKEN_PARENTHESIS_LEFT,
+ ERROR_TOKEN_IDENTIFIER, TOKEN_NONE);
+ *identifier = NULL;
}
-
- if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
- vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
+ } else {
+ *identifier = NULL;
}
}
- if (!parse_value_list (data, parse_identifier, &arguments, TOKEN_COMMA)) {
- // FIXME
+ if (!try_parse_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+ parse_value_list (data, peek_identifier, parse_identifier, &arguments,
+ TOKEN_COMMA);
+ parse_token (data, TOKEN_PARENTHESIS_RIGHT);
}
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
- vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
-
- if (!check_token (data, TOKEN_BRACE_LEFT))
- vivi_parser_error_unexpected (data, TOKEN_BRACE_LEFT);
+ parse_token (data, TOKEN_BRACE_LEFT);
vivi_parser_start_level (data);
-
- if (parse_statement_list (data, parse_source_element, &body, TRUE)) {
- // FIXME
- }
-
+ parse_statement_list (data, peek_source_element, parse_source_element,
+ &body, TOKEN_NONE);
vivi_parser_end_level (data);
- if (!check_token (data, TOKEN_BRACE_RIGHT))
- vivi_parser_error_unexpected (data, TOKEN_BRACE_RIGHT);
+ parse_token (data, TOKEN_BRACE_RIGHT);
*function = vivi_code_function_new ();
if (body != NULL) {
@@ -1938,65 +2039,74 @@ parse_function_definition (ParseData *data, ViviCodeValue **function,
}
free_value_list (arguments);
}
-
- return TRUE;
}
static gboolean
+peek_function_declaration (ParseData *data)
+{
+ return peek_function_definition (data);
+}
+
+static void
parse_function_declaration (ParseData *data, ViviCodeStatement **statement)
{
- gboolean status;
ViviCodeValue *function, *identifier;
- *statement = NULL;
-
- if (!parse_function_definition (data, &function, &identifier, TRUE))
- return FALSE;
+ parse_function_definition (data, &function, &identifier, TRUE);
+ // FIXME
*statement = vivi_parser_assignment_new (identifier, function);
g_object_unref (identifier);
g_object_unref (function);
-
- return TRUE;
}
static gboolean
+peek_function_expression (ParseData *data)
+{
+ return peek_function_definition (data);
+}
+
+static void
parse_function_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
- gboolean status;
- ViviCodeValue *identifier;
-
- *statement = NULL;
+ ViviCodeValue *function, *identifier;
- if (!parse_function_definition (data, &function, &identifier, FALSE))
- return FALSE;
+ parse_function_definition (data, &function, &identifier, FALSE);
+ // FIXME
if (identifier != NULL) {
*statement = vivi_parser_assignment_new (identifier, *value);
g_object_unref (identifier);
}
-
- return TRUE;
}
// top
static gboolean
-parse_source_element (ParseData *data, ViviCodeStatement **statement)
+peek_source_element (ParseData *data)
{
- *statement = NULL;
+ return (peek_function_declaration (data) || peek_statement (data));
+}
- if (!parse_function_declaration (data, statement)) {
- if (!parse_statement (data, statement)) {
- // FIXME
- vivi_parser_cancel_unexpected (data, ERROR_TOKEN_FUNCTION_DECLARATION,
- ERROR_TOKEN_STATEMENT);
- return FALSE;
- }
+static void
+parse_source_element (ParseData *data, ViviCodeStatement **statement)
+{
+ if (peek_function_declaration (data)) {
+ parse_function_declaration (data, statement);
+ } else if (peek_statement (data)) {
+ parse_statement (data, statement);
+ } else {
+ vivi_parser_error_unexpected_or (data, ERROR_TOKEN_FUNCTION_DECLARATION,
+ ERROR_TOKEN_STATEMENT, TOKEN_NONE);
+ *statement = vivi_compiler_empty_statement_new ();
}
+}
- return TRUE;
+G_GNUC_UNUSED static gboolean
+peek_program (ParseData *data)
+{
+ return peek_source_element (data);
}
static void
@@ -2005,138 +2115,91 @@ parse_program (ParseData *data, ViviCodeStatement **statement)
g_assert (data->level == NULL);
vivi_parser_start_level (data);
- *statement = NULL;
-
- if (!parse_statement_list (data, parse_source_element, statement, TRUE))
- // FIXME
-
- if (!check_token (data, TOKEN_EOF))
- vivi_parser_error_unexpected (data, TOKEN_EOF);
+ parse_statement_list (data, peek_source_element, parse_source_element,
+ statement, TOKEN_NONE);
+ parse_token (data, TOKEN_EOF);
vivi_parser_end_level (data);
-
g_assert (data->level == NULL);
}
// parsing
-static gboolean
-parse_statement_list (ParseData *data, ParseStatementFunction function,
- ViviCodeStatement **block, guint separator)
+static void
+parse_statement_list (ParseData *data, PeekFunction peek,
+ ParseStatementFunction parse, ViviCodeStatement **block, guint separator)
{
ViviCodeStatement *statement;
- gboolean status;
g_assert (data != NULL);
- g_assert (function != NULL);
+ g_assert (peek != NULL);
+ g_assert (parse != NULL);
g_assert (block != NULL);
- *block = NULL;
-
- status = function (data, &statement);
- if (status != TRUE)
- return status;
-
*block = vivi_code_block_new ();
do {
+ parse (data, &statement);
vivi_code_block_add_statement (VIVI_CODE_BLOCK (*block), statement);
g_object_unref (statement);
-
- if (separator != TRUE && !check_token (data, separator))
- break;
-
- status = function (data, &statement);
- if (status == STATUS_FAIL) {
- g_object_unref (*block);
- *block = NULL;
- return STATUS_FAIL;
- }
- } while (status == TRUE);
-
- return TRUE;
+ } while ((separator == TOKEN_NONE || try_parse_token (data, separator)) &&
+ peek (data));
}
-static gboolean
-parse_value_statement_list (ParseData *data,
- ParseValueStatementFunction function, ViviCodeValue ***list,
+static void
+parse_value_statement_list (ParseData *data, PeekFunction peek,
+ ParseValueStatementFunction parse, ViviCodeValue ***list,
ViviCodeStatement **statement, guint separator)
{
GPtrArray *array;
ViviCodeValue *value;
ViviCodeStatement *statement_one;
- gboolean status;
g_assert (data != NULL);
- g_assert (function != NULL);
+ g_assert (peek != NULL);
+ g_assert (parse != NULL);
g_assert (list != NULL);
g_assert (statement != NULL);
- *list = NULL;
*statement = NULL;
- status = function (data, &value, statement);
- if (status != TRUE)
- return status;
-
array = g_ptr_array_new ();
do {
+ parse (data, &value, &statement_one);
g_ptr_array_add (array, value);
+ *statement = vivi_parser_join_statements (*statement, statement_one);
+ } while ((separator == TOKEN_NONE || try_parse_token (data, separator)) &&
+ peek (data));
- if (separator != TOKEN_NONE && !check_token (data, separator))
- break;
-
- status = function (data, &value, &statement_one);
- if (status != TRUE) {
- if (status == STATUS_FAIL || separator != TOKEN_NONE)
- return FAIL_CHILD (status);
- } else {
- *statement = vivi_parser_join_statements (*statement, statement_one);
- }
- } while (status == TRUE);
g_ptr_array_add (array, NULL);
*list = (ViviCodeValue **)g_ptr_array_free (array, FALSE);
-
- return TRUE;
}
-static gboolean
-parse_value_list (ParseData *data, ParseValueFunction function,
+static void
+parse_value_list (ParseData *data, PeekFunction peek, ParseValueFunction parse,
ViviCodeValue ***list, guint separator)
{
GPtrArray *array;
ViviCodeValue *value;
- gboolean status;
g_assert (data != NULL);
- g_assert (function != NULL);
+ g_assert (peek != NULL);
+ g_assert (parse != NULL);
g_assert (list != NULL);
- *list = NULL;
-
- status = function (data, &value);
- if (status != TRUE)
- return status;
-
array = g_ptr_array_new ();
do {
+ parse (data, &value);
g_ptr_array_add (array, value);
+ } while ((separator == TOKEN_NONE || try_parse_token (data, separator)) &&
+ peek (data));
- if (separator != TRUE && !check_token (data, separator))
- break;
-
- status = function (data, &value);
- if (status == STATUS_FAIL)
- return STATUS_FAIL;
- } while (status == TRUE);
g_ptr_array_add (array, NULL);
*list = (ViviCodeValue **)g_ptr_array_free (array, FALSE);
-
- return TRUE;
}
// public
@@ -2146,46 +2209,18 @@ vivi_parse_file (FILE *file, const char *input_name)
{
ParseData data;
ViviCodeStatement *statement;
- gboolean status;
g_return_val_if_fail (file != NULL, NULL);
data.scanner = vivi_parser_scanner_new (file);
- data.unexpected_line_terminator = FALSE;
- data.expected[0] = TOKEN_NONE;
- data.expected[1] = TOKEN_NONE;
- data.custom_error = NULL;
data.levels = NULL;
data.level = NULL;
+ data.error_count = 0;
- status = parse_program (&data, &statement);
- g_assert ((status == TRUE && VIVI_IS_CODE_STATEMENT (statement)) ||
- (status != TRUE && statement == NULL));
- g_assert (status >= 0);
-
- if (status != TRUE) {
- g_printerr ("%s:%i:%i: error: ", input_name,
- vivi_parser_scanner_cur_line (data.scanner),
- vivi_parser_scanner_cur_column (data.scanner));
-
- if (data.custom_error != NULL) {
- g_printerr ("%s\n", data.custom_error);
- g_free (data.custom_error);
- } else {
- vivi_parser_scanner_get_next_token (data.scanner);
-
- g_printerr ("Expected %s ", vivi_parser_token_name (data.expected[0]));
- if (data.expected[1] != TOKEN_NONE)
- g_printerr ("or %s ", vivi_parser_token_name (data.expected[1]));
-
- if (data.unexpected_line_terminator) {
- g_printerr ("before %s token\n",
- vivi_parser_token_name (TOKEN_LINE_TERMINATOR));
- } else {
- g_printerr ("before %s token\n",
- vivi_parser_token_name (data.scanner->token));
- }
- }
+ parse_program (&data, &statement);
+ if (data.error_count != 0) {
+ g_object_unref (statement);
+ statement = NULL;
}
g_object_unref (data.scanner);
commit d3161936eb3dd66558100cb73dcc870fc5b06108
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date: Wed Apr 9 11:25:45 2008 +0300
Change vivi_compiler_scanner_lex.c to vivi_parser_scanner_lex.c in ignore list
diff --git a/vivified/code/.gitignore b/vivified/code/.gitignore
index 1cc3a3f..83ce7a9 100644
--- a/vivified/code/.gitignore
+++ b/vivified/code/.gitignore
@@ -11,7 +11,7 @@ Makefile.in
*.lo
*.loT
-vivi_compiler_scanner_lex.c
+vivi_parser_scanner_lex.c
vivi-decompile
vivi-compile
commit c9aeaef7f136e618bf2286375c9914e46b1b1f83
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date: Wed Apr 9 11:24:06 2008 +0300
Start converting vivi_parser.c to better error handling
It will just set an error state and continue parsing when errors occur
diff --git a/vivified/code/vivi_parser.c b/vivified/code/vivi_parser.c
index 2969593..16bde02 100644
--- a/vivified/code/vivi_parser.c
+++ b/vivified/code/vivi_parser.c
@@ -79,12 +79,6 @@ static const struct {
{ TOKEN_LAST, NULL }
};
-typedef enum {
- STATUS_CANCEL = -1,
- STATUS_OK = 0,
- STATUS_FAIL = 1
-} ParseStatus;
-
typedef struct {
GSList *labels;
GSList *gotos;
@@ -92,37 +86,28 @@ typedef struct {
typedef struct {
ViviParserScanner * scanner;
- gboolean unexpected_line_terminator;
- guint expected[2];
- char * custom_error;
+
+ guint error_count;
+
+ char * cancel_error;
GSList * levels; // ParseLevel, earlier levels
ParseLevel * level; // current level
} ParseData;
-#define FAIL_OR(x, y) (data->expected[0] = (x), data->expected[1] = (y), STATUS_FAIL)
-#define FAIL_LINE_TERMINATOR_OR(x, y) (data->unexpected_line_terminator = TRUE, FAIL_OR(x,y))
-#define FAIL_LINE_TERMINATOR(x) FAIL_LINE_TERMINATOR_OR(x,TOKEN_NONE)
-#define FAIL(x) FAIL_OR(x,TOKEN_NONE)
-#define FAIL_CHILD(x) STATUS_FAIL
-#define FAIL_CUSTOM(x) (data->custom_error = (x), STATUS_FAIL)
-#define CANCEL_OR(x, y) (data->expected[0] = (x), data->expected[1] = (y), STATUS_CANCEL)
-#define CANCEL(x) CANCEL_OR(x, TOKEN_NONE)
-#define CANCEL_CUSTOM(x) (data->custom_error = (x), STATUS_CANCEL)
-
-typedef ParseStatus (*ParseValueFunction) (ParseData *data, ViviCodeValue **value);
-typedef ParseStatus (*ParseValueStatementFunction) (ParseData *data, ViviCodeValue **value, ViviCodeStatement **statement);
-typedef ParseStatus (*ParseStatementFunction) (ParseData *data, ViviCodeStatement **statement);
-
-static ParseStatus
+typedef gboolean (*ParseValueFunction) (ParseData *data, ViviCodeValue **value);
+typedef gboolean (*ParseValueStatementFunction) (ParseData *data, ViviCodeValue **value, ViviCodeStatement **statement);
+typedef gboolean (*ParseStatementFunction) (ParseData *data, ViviCodeStatement **statement);
+
+static gboolean
parse_statement_list (ParseData *data, ParseStatementFunction function, ViviCodeStatement **statement, guint separator);
-static ParseStatus
+static gboolean
parse_value_statement_list (ParseData *data,
ParseValueStatementFunction function, ViviCodeValue ***list,
ViviCodeStatement **statement, guint separator);
-static ParseStatus
+static gboolean
parse_value_list (ParseData *data, ParseValueFunction function,
ViviCodeValue ***list, guint separator);
@@ -151,6 +136,65 @@ vivi_parser_token_name (guint token)
}
}
+static void
+vivi_parser_error (ParseData *data, const char *format, ...)
+{
+ va_list args;
+ char *message;
+
+ g_return_if_fail (data != NULL);
+ g_return_if_fail (format != NULL);
+
+ va_start (args, format);
+ message = g_strdup_vprintf (format, args);
+ va_end (args);
+
+ g_printerr (":error: %s\n", message);
+
+ g_free (message);
+
+ data->error_count++;
+}
+
+static void
+vivi_parser_cancel (ParseData *data, const char *format, ...)
+{
+ va_list args;
+ char *message;
+
+ g_return_if_fail (data != NULL);
+ g_return_if_fail (format != NULL);
+
+ va_start (args, format);
+ message = g_strdup_vprintf (format, args);
+ va_end (args);
+
+ if (data->cancel_error != NULL)
+ g_free (data->cancel_error);
+ data->cancel_error = message;
+}
+
+static char *
+vivi_parser_unexpected_token (ParseData *data, guint expected,
+ guint unexpected1, guint unexpected2)
+{
+ return g_strdup_printf ("Expected %s before %s or %s\n",
+ vivi_parser_token_name (expected), vivi_parser_token_name (unexpected1),
+ vivi_parser_token_name (unexpected2));
+}
+
+static void
+vivi_parser_fail_child (ParseData *data)
+{
+ if (data->cancel_error != NULL) {
+ vivi_parser_error (data, "%s", data->cancel_error);
+ g_free (data->cancel_error);
+ data->cancel_error = NULL;
+ } else {
+ g_assert (data->error_count > 0);
+ }
+}
+
static gboolean
check_line_terminator (ParseData *data)
{
@@ -346,14 +390,13 @@ vivi_parser_find_label (ParseData *data, const char *name)
return NULL;
}
-static ParseStatus
-vivi_parser_end_level (ParseData *data, gboolean fail)
+static void
+vivi_parser_end_level (ParseData *data)
{
GSList *iter;
- char *custom_error = NULL;
- g_return_val_if_fail (data != NULL, STATUS_FAIL);
- g_return_val_if_fail (data->level != NULL, STATUS_FAIL);
+ g_return_if_fail (data != NULL);
+ g_return_if_fail (data->level != NULL);
for (iter = data->level->gotos; iter != NULL; iter = iter->next) {
ViviCompilerGotoName *goto_;
@@ -366,11 +409,8 @@ vivi_parser_end_level (ParseData *data, gboolean fail)
if (label != NULL) {
vivi_compiler_goto_name_set_label (goto_, label);
} else {
- if (custom_error == NULL) {
- custom_error =
- g_strdup_printf ("Label named '%s' doesn't exist in this block",
- vivi_compiler_goto_name_get_name (goto_));
- }
+ vivi_parser_error (data, "Label named '%s' doesn't exist in this block",
+ vivi_compiler_goto_name_get_name (goto_));
}
g_object_unref (goto_);
@@ -390,16 +430,6 @@ vivi_parser_end_level (ParseData *data, gboolean fail)
} else {
data->level = NULL;
}
-
- if (custom_error != NULL) {
- if (fail) {
- return FAIL_CUSTOM (custom_error);
- } else {
- return STATUS_FAIL;
- }
- } else {
- return STATUS_OK;
- }
}
static void
@@ -437,72 +467,80 @@ vivi_parser_add_label (ParseData *data, ViviCodeLabel *label)
// values
/* ActionScript specific */
-static ParseStatus
+static gboolean
parse_undefined_literal (ParseData *data, ViviCodeValue **value)
{
*value = NULL;
- if (!check_token (data, TOKEN_UNDEFINED))
- return CANCEL (TOKEN_UNDEFINED);
+ if (!check_token (data, TOKEN_UNDEFINED)) {
+ vivi_parser_cancel_unexpected (data, TOKEN_UNDEFINED);
+ return FALSE;
+ }
*value = vivi_code_constant_new_undefined ();
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_null_literal (ParseData *data, ViviCodeValue **value)
{
*value = NULL;
- if (!check_token (data, TOKEN_NULL))
- return CANCEL (TOKEN_NULL);
+ if (!check_token (data, TOKEN_NULL)) {
+ vivi_parser_cancel_unexpected (data, TOKEN_NULL);
+ return FALSE;
+ }
*value = vivi_code_constant_new_null ();
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_boolean_literal (ParseData *data, ViviCodeValue **value)
{
*value = NULL;
- if (!check_token (data, TOKEN_BOOLEAN))
- return CANCEL (TOKEN_BOOLEAN);
+ if (!check_token (data, TOKEN_BOOLEAN)) {
+ vivi_parser_cancel_unexpected (data, TOKEN_BOOLEAN);
+ return FALSE;
+ }
*value = vivi_code_constant_new_boolean (data->scanner->value.v_boolean);
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_numeric_literal (ParseData *data, ViviCodeValue **value)
{
*value = NULL;
- if (!check_token (data, TOKEN_NUMBER))
- return CANCEL (TOKEN_NUMBER);
+ if (!check_token (data, TOKEN_NUMBER)) {
+ vivi_parser_cancel_unexpected (data, TOKEN_NUMBER);
+ return FALSE;
+ }
*value = vivi_code_constant_new_number (data->scanner->value.v_number);
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_string_literal (ParseData *data, ViviCodeValue **value)
{
*value = NULL;
- if (!check_token (data, TOKEN_STRING))
- return CANCEL (TOKEN_STRING);
+ if (!check_token (data, TOKEN_STRING)) {
+ vivi_parser_cancel_unexpected (data, TOKEN_STRING);
+ return FALSE;
+ }
*value = vivi_code_constant_new_string (data->scanner->value.v_string);
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_literal (ParseData *data, ViviCodeValue **value)
{
- ParseStatus status;
- int i;
- ParseValueFunction functions[] = {
+ static const ParseValueFunction functions[] = {
parse_undefined_literal,
parse_null_literal,
parse_boolean_literal,
@@ -510,71 +548,74 @@ parse_literal (ParseData *data, ViviCodeValue **value)
parse_string_literal,
NULL
};
+ guint i;
*value = NULL;
for (i = 0; functions[i] != NULL; i++) {
- status = functions[i] (data, value);
- if (status != STATUS_CANCEL)
- return status;
+ if (functions[i] (data, value))
+ return TRUE;
}
- return CANCEL (ERROR_TOKEN_LITERAL);
+ vivi_parser_cancel_unexpected (data, ERROR_TOKEN_LITERAL);
+ return FALSE;
}
-static ParseStatus
+static gboolean
parse_identifier (ParseData *data, ViviCodeValue **value)
{
*value = NULL;
- if (!check_token (data, TOKEN_IDENTIFIER))
- return CANCEL (TOKEN_IDENTIFIER);
+ if (!check_token (data, TOKEN_IDENTIFIER)) {
+ vivi_parser_cancel_unexpected (data, TOKEN_IDENTIFIER);
+ return FALSE;
+ }
*value = vivi_code_get_new_name (data->scanner->value.v_identifier);
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_property_name (ParseData *data, ViviCodeValue **value)
{
- ParseStatus status;
- int i;
- ParseValueFunction functions[] = {
+ static const ParseValueFunction functions[] = {
parse_identifier,
parse_string_literal,
parse_numeric_literal,
NULL
};
+ guint i;
*value = NULL;
for (i = 0; functions[i] != NULL; i++) {
- status = functions[i] (data, value);
- if (status != STATUS_CANCEL)
- return status;
+ if (functions[i] (data, value))
+ return TRUE;
}
- return CANCEL (ERROR_TOKEN_PROPERTY_NAME);
+ vivi_parser_cancel_unexpected (data, ERROR_TOKEN_PROPERTY_NAME);
+ return FALSE;
}
-static ParseStatus
+static gboolean
parse_assignment_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement);
-static ParseStatus
+static gboolean
parse_array_literal (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
ViviCodeValue *member;
ViviCodeStatement *statement_new;
- ParseStatus status;
*value = NULL;
*statement = NULL;
- if (!check_token (data, TOKEN_BRACKET_LEFT))
- return CANCEL (TOKEN_BRACKET_LEFT);
+ if (!check_token (data, TOKEN_BRACKET_LEFT)) {
+ vivi_parser_cancel_unexpected (data, TOKEN_BRACKET_LEFT);
+ return FALSE;
+ }
*value = vivi_code_init_array_new ();
@@ -586,16 +627,7 @@ parse_array_literal (ParseData *data, ViviCodeValue **value,
} else if (check_token (data, TOKEN_COMMA)) {
vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
vivi_code_constant_new_undefined ());
- } else {
- status = parse_assignment_expression (data, &member, &statement_new);
- if (status != STATUS_OK) {
- if (*statement != NULL) {
- g_object_unref (*statement);
- *statement = NULL;
- }
- return FAIL_CHILD (status);
- }
-
+ } else if (parse_assignment_expression (data, &member, &statement_new)) {
*statement = vivi_parser_join_statements (*statement, statement_new);
vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
@@ -604,27 +636,34 @@ parse_array_literal (ParseData *data, ViviCodeValue **value,
if (!check_token (data, TOKEN_COMMA)) {
if (!check_token (data, TOKEN_BRACKET_RIGHT)) {
- return FAIL_OR (TOKEN_BRACKET_RIGHT, TOKEN_COMMA);
+ vivi_parser_error_unexpected (data, TOKEN_BRACKET_RIGHT,
+ TOKEN_COMMA);
}
break;
}
+ } else {
+ vivi_parser_error_unexpected (data, TOKEN_BRACKET_RIGHT, TOKEN_COMMA,
+ ERROR_TOKEN_ASSIGNMENT_EXPRESSION);
+ break;
}
}
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_object_literal (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
- ParseStatus status;
+ gboolean status;
*value = NULL;
*statement = NULL;
- if (!check_token (data, TOKEN_BRACE_LEFT))
- return CANCEL (TOKEN_BRACE_LEFT);
+ if (!check_token (data, TOKEN_BRACE_LEFT)) {
+ vivi_parser_cancel_unexpected (data, TOKEN_BRACE_LEFT);
+ return FALSE;
+ }
*value = vivi_code_init_object_new ();
@@ -633,38 +672,14 @@ parse_object_literal (ParseData *data, ViviCodeValue **value,
ViviCodeValue *property, *initializer;
ViviCodeStatement *statement_new;
- status = parse_property_name (data, &property);
- if (status != STATUS_OK) {
- g_object_unref (*value);
- *value = NULL;
- if (*statement != NULL) {
- g_object_unref (*statement);
- *statement = NULL;
- }
- return FAIL_CHILD (status);
- }
+ if (!parse_property_name (data, &property))
+ vivi_parser_error_child_value (data, &property);
- if (!check_token (data, TOKEN_COLON)) {
- g_object_unref (*value);
- *value = NULL;
- if (*statement != NULL) {
- g_object_unref (*statement);
- *statement = NULL;
- }
- return FAIL (TOKEN_COLON);
- }
+ if (!check_token (data, TOKEN_COLON))
+ vivi_parser_error_unexpected (data, TOKEN_COLON);
- status = parse_assignment_expression (data, &initializer,
- &statement_new);
- if (status != STATUS_OK) {
- g_object_unref (*value);
- *value = NULL;
- if (*statement != NULL) {
- g_object_unref (*statement);
- *statement = NULL;
- }
- return FAIL_CHILD (status);
- }
+ if (!parse_assignment_expression (data, &initializer, &statement_new))
+ vivi_parser_error_child_value (data, &initializer);
*statement = vivi_parser_join_statements (*statement, statement_new);
@@ -673,40 +688,31 @@ parse_object_literal (ParseData *data, ViviCodeValue **value,
} while (check_token (data, TOKEN_COMMA));
}
- if (!check_token (data, TOKEN_BRACE_RIGHT)) {
- g_object_unref (*value);
- *value = NULL;
- if (*statement != NULL) {
- g_object_unref (*statement);
- *statement = NULL;
- }
- return FAIL (TOKEN_BRACE_RIGHT);
- }
+ if (!check_token (data, TOKEN_BRACE_RIGHT))
+ vivi_parser_error_unexpected (data, TOKEN_BRACE_RIGHT);
- return STATUS_OK;
+ return TRUE;
}
// misc
-static ParseStatus
+static gboolean
parse_variable_declaration (ParseData *data, ViviCodeStatement **statement)
{
- ParseStatus status;
+ gboolean status;
ViviCodeValue *identifier, *value;
ViviCodeStatement *assignment, *statement_right;
*statement = NULL;
- status = parse_identifier (data, &identifier);
- if (status != STATUS_OK)
- return status;
+ if (!parse_identifier (data, &identifier)) {
+ vivi_parser_cancel_unexpected (data, ERROR_TOKEN_IDENTIFIER);
+ return FALSE;
+ }
if (check_token (data, TOKEN_ASSIGN)) {
- status = parse_assignment_expression (data, &value, &statement_right);
- if (status != STATUS_OK) {
- g_object_unref (identifier);
- return FAIL_CHILD (status);
- }
+ if (!parse_assignment_expression (data, &value, &statement_right))
+ vivi_parser_error_child_value (data, value);
} else {
value = vivi_code_constant_new_undefined ();
statement_right = NULL;
@@ -717,74 +723,60 @@ parse_variable_declaration (ParseData *data, ViviCodeStatement **statement)
*statement = vivi_parser_join_statements (statement_right, assignment);
- return STATUS_OK;
+ return TRUE;
}
// expression
-static ParseStatus
+static gboolean
parse_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement);
-static ParseStatus
+static gboolean
parse_primary_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
- ParseStatus status;
- int i;
- ParseValueFunction functions[] = {
- parse_identifier,
- parse_literal,
- NULL
- };
-
*value = NULL;
*statement = NULL;
if (check_token (data, TOKEN_THIS)) {
*value = vivi_code_get_new_name ("this");
- return STATUS_OK;
+ return TRUE;
}
if (check_token (data, TOKEN_PARENTHESIS_LEFT)) {
- status = parse_expression (data, value, statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
- g_object_unref (*value);
- *value = NULL;
- return FAIL (TOKEN_PARENTHESIS_RIGHT);
- }
- return STATUS_OK;
+ if (!parse_expression (data, value, statement))
+ vivi_parser_error_child_value (data, value);
+ if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
+ vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
+ return TRUE;
}
+ if (parse_object_literal (data, value, statement))
+ return TRUE;
- status = parse_object_literal (data, value, statement);
- if (status != STATUS_CANCEL)
- return status;
+ if (parse_array_literal (data, value, statement))
+ return TRUE;
- status = parse_array_literal (data, value, statement);
- if (status != STATUS_CANCEL)
- return status;
+ if (parse_identifier (data, value))
+ return TRUE;
- for (i = 0; functions[i] != NULL; i++) {
- status = functions[i] (data, value);
- if (status != STATUS_CANCEL)
- return status;
- }
+ if (parse_literal (data, value))
+ return TRUE;
- return CANCEL (ERROR_TOKEN_PRIMARY_EXPRESSION);
+ vivi_parser_cancel_unexpected (ERROR_TOKEN_PRIMARY_EXPRESSION);
+ return FALSE;
}
-static ParseStatus
+static gboolean
parse_function_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement);
-static ParseStatus
+static gboolean
parse_member_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
- ParseStatus status;
+ gboolean status;
ViviCodeValue *member;
ViviCodeStatement *statement_member;
@@ -793,70 +785,53 @@ parse_member_expression (ParseData *data, ViviCodeValue **value,
// TODO: new MemberExpression Arguments
- status = parse_primary_expression (data, value, statement);
- if (status == STATUS_CANCEL)
- status = parse_function_expression (data, value, statement);
-
- if (status != STATUS_OK)
- return status;
+ if (!parse_primary_expression (data, value, statement)) {
+ if (!parse_function_expression (data, value, statement)) {
+ vivi_parser_cancel_unexpected (data, ERROR_PRIMARY_EXPRESSION,
+ ERROR_FUNCTION_EXPRESSION);
+ return FALSE;
+ }
+ }
- do {
+ while (TRUE) {
ViviCodeValue *tmp;
if (check_token (data, TOKEN_BRACKET_LEFT)) {
- status = parse_expression (data, &member, &statement_member);
- if (status != STATUS_OK) {
- g_object_unref (*value);
- *value = NULL;
- if (*statement != NULL) {
- g_object_unref (*statement);
- *statement = NULL;
- }
- return FAIL_CHILD (status);
- }
+ if (!parse_expression (data, &member, &statement_member))
+ vivi_parser_error_child_value (data, &member);
- *statement =
- vivi_parser_join_statements (*statement, statement_member);
-
- if (!check_token (data, TOKEN_BRACKET_RIGHT)) {
- g_object_unref (*value);
- *value = NULL;
- if (*statement != NULL) {
- g_object_unref (*statement);
- *statement = NULL;
- }
- return FAIL (TOKEN_BRACKET_RIGHT);
- }
+ *statement = vivi_parser_join_statements (*statement, statement_member);
+
+ if (!check_token (data, TOKEN_BRACKET_RIGHT))
+ vivi_parser_error_unexpected (data, TOKEN_BRACKET_RIGHT);
} else if (check_token (data, TOKEN_DOT)) {
- status = parse_identifier (data, &member);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
+ if (!parse_identifier (data, &member))
+ vivi_parser_error_child_value (data, &member);
} else {
- return STATUS_OK;
+ return TRUE;
}
tmp = *value;
*value = vivi_parser_get_new (tmp, member);
g_object_unref (tmp);
g_object_unref (member);
- } while (TRUE);
+ }
g_assert_not_reached ();
}
-static ParseStatus
+static gboolean
parse_new_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
- ParseStatus status;
+ gboolean status;
*value = NULL;
*statement = NULL;
if (check_token (data, TOKEN_NEW)) {
- status = parse_new_expression (data, value, statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
+ if (!parse_new_expression (data, value, statement))
+ vivi_parser_error_child_value (data, value);
if (!VIVI_IS_CODE_FUNCTION_CALL (*value)) {
ViviCodeValue *tmp = VIVI_CODE_VALUE (*value);
*value = vivi_parser_function_call_new (tmp);
@@ -864,29 +839,27 @@ parse_new_expression (ParseData *data, ViviCodeValue **value,
}
vivi_code_function_call_set_construct (VIVI_CODE_FUNCTION_CALL (*value),
TRUE);
- return STATUS_OK;
+ return TRUE;
} else {
return parse_member_expression (data, value, statement);
}
}
-static ParseStatus
+static gboolean
parse_left_hand_side_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
- ParseStatus status;
- int i;
ViviCodeValue *name;
ViviCodeValue **arguments;
ViviCodeStatement *argument_statement;
+ guint i;
*value = NULL;
*statement = NULL;
if (check_token (data, TOKEN_NEW)) {
- status = parse_new_expression (data, value, statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
+ if (!parse_new_expression (data, value, statement))
+ vivi_parser_error_child_value (data, value);
if (!VIVI_IS_CODE_FUNCTION_CALL (*value)) {
ViviCodeValue *tmp = VIVI_CODE_VALUE (*value);
*value = vivi_parser_function_call_new (tmp);
@@ -894,12 +867,13 @@ parse_left_hand_side_expression (ParseData *data, ViviCodeValue **value,
}
vivi_code_function_call_set_construct (VIVI_CODE_FUNCTION_CALL (*value),
TRUE);
- return STATUS_OK;
+ return TRUE;
}
- status = parse_member_expression (data, value, statement);
- if (status != STATUS_OK)
- return status;
+ if (!parse_member_expression (data, value, statement)) {
+ vivi_parser_cancel_unexpected (data, ERROR_TOKEN_MEMBER_EXPRESSION);
+ return FALSE;
+ }
while (TRUE) {
// TODO: member expressions?
@@ -907,30 +881,17 @@ parse_left_hand_side_expression (ParseData *data, ViviCodeValue **value,
break;
if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
- status = parse_value_statement_list (data, parse_assignment_expression,
- &arguments, &argument_statement, TOKEN_COMMA);
- if (status != STATUS_OK) {
- g_object_unref (*value);
- *value = NULL;
- if (*statement != NULL) {
- g_object_unref (*statement);
- *statement = NULL;
- }
- return FAIL_CHILD (status);
+ if (!parse_value_statement_list (data, parse_assignment_expression,
+ &arguments, &argument_statement, TOKEN_COMMA)) {
+ // TODO
+ arguments = NULL;
}
*statement =
vivi_parser_join_statements (*statement, argument_statement);
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
- g_object_unref (*value);
- *value = NULL;
- if (*statement != NULL) {
- g_object_unref (*statement);
- *statement = NULL;
- }
- return FAIL (TOKEN_PARENTHESIS_RIGHT);
- }
+ if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
+ vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
} else {
arguments = NULL;
}
@@ -948,43 +909,39 @@ parse_left_hand_side_expression (ParseData *data, ViviCodeValue **value,
}
}
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_postfix_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
- ParseStatus status;
ViviCodeValue *operation, *one, *temporary;
const char *operator;
*value = NULL;
*statement = NULL;
- status = parse_left_hand_side_expression (data, value, statement);
- if (status != STATUS_OK)
- return status;
+ if (!parse_left_hand_side_expression (data, value, statement)) {
+ vivi_parser_cancel_unexpected (data, ERROR_TOKEN_POSTFIX_EXPRESSION);
+ return FALSE;
+ }
if (check_line_terminator (data))
- return status;
+ return TRUE;
if (check_token (data, TOKEN_INCREASE)) {
operator = "+";
} else if (check_token (data, TOKEN_DESCREASE)) {
operator = "-";
} else {
- return STATUS_OK;
+ return TRUE;
}
+ // FIXME: Correct?
if (!vivi_parser_value_is_left_hand_side (*value)) {
- g_object_unref (*value);
- *value = NULL;
- if (*statement != NULL) {
- g_object_unref (*statement);
- *statement = NULL;
- }
- return CANCEL_CUSTOM (g_strdup ("INCREASE/DECREASE not allowed here"));
+ vivi_parser_error (
+ "Invalid left-hand side expression for INCREASE/DECREASE");
}
one = vivi_code_constant_new_number (1);
@@ -1001,14 +958,14 @@ parse_postfix_expression (ParseData *data, ViviCodeValue **value,
g_object_unref (*value);
*value = temporary;
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_unary_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
- ParseStatus status;
+ gboolean status;
ViviCodeValue *tmp, *one;
const char *operator;
@@ -1028,12 +985,15 @@ parse_unary_expression (ParseData *data, ViviCodeValue **value,
if (!operator) operator = "-";
vivi_parser_scanner_get_next_token (data->scanner);
- status = parse_unary_expression (data, value, statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
- if (!vivi_parser_value_is_left_hand_side (*value))
- return CANCEL_CUSTOM (g_strdup ("INCREASE/DECREASE not allowed here"));
+ if (!parse_unary_expression (data, value, statement))
+ vivi_parser_error_child_value (data, value);
+
+ // FIXME: Correct?
+ if (!vivi_parser_value_is_left_hand_side (*value)) {
+ vivi_parser_error (
+ "Invalid left-hand side expression for INCREASE/DECREASE");
+ }
one = vivi_code_constant_new_number (1);
tmp = vivi_code_binary_new_name (*value, one, operator);
@@ -1043,19 +1003,21 @@ parse_unary_expression (ParseData *data, ViviCodeValue **value,
vivi_parser_assignment_new (*value, tmp));
g_object_unref (tmp);
- return STATUS_OK;
+ return TRUE;
/*case TOKEN_PLUS:
case TOKEN_MINUS:
case TOKEN_BITWISE_NOT:*/
case TOKEN_LOGICAL_NOT:
vivi_parser_scanner_get_next_token (data->scanner);
- status = parse_unary_expression (data, value, statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
+
+ if (!parse_unary_expression (data, value, statement))
+ vivi_parser_error_child_value (data, value);
+
tmp = VIVI_CODE_VALUE (*value);
*value = vivi_code_unary_new (tmp, '!');
g_object_unref (tmp);
- return STATUS_OK;
+
+ return TRUE;
default:
return parse_postfix_expression (data, value, statement);
}
@@ -1067,31 +1029,27 @@ typedef enum {
PASS_LOGICAL_AND
} ParseOperatorPass;
-static ParseStatus
+static gboolean
parse_operator_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement, const ViviParserScannerToken *tokens,
ParseOperatorPass pass, ParseValueStatementFunction next_parse_function)
{
- ParseStatus status;
- int i;
ViviCodeValue *left, *right;
ViviCodeStatement *statement_right;
+ guint i;
*value = NULL;
*statement = NULL;
- status = next_parse_function (data, value, statement);
- if (status != STATUS_OK)
- return status;
+ if (!next_parse_function (data, value, statement)) {
+ // FIXME: token?
+ return FALSE;
+ }
- for (i = 0; tokens[i] != STATUS_OK; i++) {
+ for (i = 0; tokens[i] != TRUE; i++) {
while (check_token (data, tokens[i])) {
- status = next_parse_function (data, &right, &statement_right);
- if (status != STATUS_OK) {
- g_object_unref (*value);
- *value = NULL;
- return FAIL_CHILD (status);
- }
+ if (!next_parse_function (data, &right, &statement_right))
+ vivi_parser_error_child_value (data, &right);
if (statement_right != NULL) {
ViviCodeStatement *tmp;
@@ -1116,8 +1074,7 @@ parse_operator_expression (ParseData *data, ViviCodeValue **value,
g_assert_not_reached ();
}
- *statement =
- vivi_parser_join_statements (*statement, statement_right);
+ *statement = vivi_parser_join_statements (*statement, statement_right);
}
left = VIVI_CODE_VALUE (*value);
@@ -1128,10 +1085,10 @@ parse_operator_expression (ParseData *data, ViviCodeValue **value,
};
}
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_multiplicative_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
@@ -1142,7 +1099,7 @@ parse_multiplicative_expression (ParseData *data, ViviCodeValue **value,
PASS_ALWAYS, parse_unary_expression);
}
-static ParseStatus
+static gboolean
parse_additive_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
@@ -1153,7 +1110,7 @@ parse_additive_expression (ParseData *data, ViviCodeValue **value,
PASS_ALWAYS, parse_multiplicative_expression);
}
-static ParseStatus
+static gboolean
parse_shift_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
@@ -1164,7 +1121,7 @@ parse_shift_expression (ParseData *data, ViviCodeValue **value,
PASS_ALWAYS, parse_additive_expression);
}
-static ParseStatus
+static gboolean
parse_relational_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
@@ -1176,7 +1133,7 @@ parse_relational_expression (ParseData *data, ViviCodeValue **value,
PASS_ALWAYS, parse_shift_expression);
}
-static ParseStatus
+static gboolean
parse_equality_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
@@ -1188,7 +1145,7 @@ parse_equality_expression (ParseData *data, ViviCodeValue **value,
PASS_ALWAYS, parse_relational_expression);
}
-static ParseStatus
+static gboolean
parse_bitwise_and_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
@@ -1199,7 +1156,7 @@ parse_bitwise_and_expression (ParseData *data, ViviCodeValue **value,
PASS_ALWAYS, parse_equality_expression);
}
-static ParseStatus
+static gboolean
parse_bitwise_xor_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
@@ -1210,7 +1167,7 @@ parse_bitwise_xor_expression (ParseData *data, ViviCodeValue **value,
PASS_ALWAYS, parse_bitwise_and_expression);
}
-static ParseStatus
+static gboolean
parse_bitwise_or_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
@@ -1221,7 +1178,7 @@ parse_bitwise_or_expression (ParseData *data, ViviCodeValue **value,
PASS_ALWAYS, parse_bitwise_xor_expression);
}
-static ParseStatus
+static gboolean
parse_logical_and_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
@@ -1232,7 +1189,7 @@ parse_logical_and_expression (ParseData *data, ViviCodeValue **value,
PASS_LOGICAL_AND, parse_bitwise_or_expression);
}
-static ParseStatus
+static gboolean
parse_logical_or_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
@@ -1243,28 +1200,26 @@ parse_logical_or_expression (ParseData *data, ViviCodeValue **value,
PASS_LOGICAL_OR, parse_logical_and_expression);
}
-static ParseStatus
+static gboolean
parse_conditional_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
- ParseStatus status;
//ViviCodeStatement *if_statement, *else_statement;
*value = NULL;
- status = parse_logical_or_expression (data, value, statement);
- if (status != STATUS_OK)
- return status;
+ if (!parse_logical_or_expression (data, value, statement))
+ return FALSE;
#if 0
if (!check_token (data, TOKEN_QUESTION_MARK)) {
*statement = vivi_code_value_statement_new (VIVI_CODE_VALUE (value));
g_object_unref (value);
- return STATUS_OK;
+ return TRUE;
}
status = parse_assignment_expression (data, &if_statement);
- if (status != STATUS_OK) {
+ if (status != TRUE) {
g_object_unref (value);
return FAIL_CHILD (status);
}
@@ -1276,7 +1231,7 @@ parse_conditional_expression (ParseData *data, ViviCodeValue **value,
}
status = parse_assignment_expression (data, &else_statement);
- if (status != STATUS_OK) {
+ if (status != TRUE) {
g_object_unref (value);
g_object_unref (if_statement);
return FAIL_CHILD (status);
@@ -1291,14 +1246,13 @@ parse_conditional_expression (ParseData *data, ViviCodeValue **value,
g_object_unref (else_statement);
#endif
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_assignment_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
- ParseStatus status;
ViviCodeValue *right;
ViviCodeStatement *assignment, *statement_right;
const char *operator;
@@ -1306,17 +1260,18 @@ parse_assignment_expression (ParseData *data, ViviCodeValue **value,
*value = NULL;
*statement = NULL;
- status = parse_conditional_expression (data, value, statement);
- if (status != STATUS_OK)
- return status;
+ if (!parse_conditional_expression (data, value, statement)) {
+ vivi_parser_cancel_unexpected (data, ERROR_TOKEN_CONDITIONAL_EXPRESSION);
+ return FALSE;
+ }
if (!vivi_parser_value_is_left_hand_side (*value))
- return STATUS_OK;
+ return TRUE;
operator = NULL;
vivi_parser_scanner_peek_next_token (data->scanner);
- switch ((int)data->scanner->next_token) {
+ switch ((guint)data->scanner->next_token) {
case TOKEN_ASSIGN_MULTIPLY:
if (operator == NULL) operator = "*";
case TOKEN_ASSIGN_DIVIDE:
@@ -1341,13 +1296,9 @@ parse_assignment_expression (ParseData *data, ViviCodeValue **value,
if (operator == NULL) operator = "^";
case TOKEN_ASSIGN:
vivi_parser_scanner_get_next_token (data->scanner);
- status = parse_assignment_expression (data, &right,
- &statement_right);
- if (status != STATUS_OK) {
- g_object_unref (*value);
- *value = NULL;
- return FAIL_CHILD (status);
- }
+
+ if (parse_assignment_expression (data, &right, &statement_right))
+ vivi_parser_error_child_value (data, &right);
if (operator != NULL) {
assignment = vivi_parser_assignment_new (*value,
@@ -1360,27 +1311,26 @@ parse_assignment_expression (ParseData *data, ViviCodeValue **value,
*statement = vivi_parser_join_statements (*statement,
vivi_parser_join_statements (statement_right, assignment));
- break;
+ return TRUE;
default:
- return STATUS_OK;
+ return TRUE;
}
-
- return STATUS_OK;
+ g_assert_not_reached ();
}
-static ParseStatus
+static gboolean
parse_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
ViviCodeStatement *statement_one;
- ParseStatus status;
*statement = NULL;
- status = parse_assignment_expression (data, value, &statement_one);
- if (status != STATUS_OK)
- return status;
+ if (parse_assignment_expression (data, value, &statement_one)) {
+ vivi_parser_cancel_unexpected (data, ERROR_TOKEN_ASSIGNMENT_EXPRESSION);
+ return FALSE;
+ }
while (TRUE) {
*statement = vivi_parser_join_statements (*statement, statement_one);
@@ -1390,80 +1340,70 @@ parse_expression (ParseData *data, ViviCodeValue **value,
g_object_unref (*value);
- status = parse_assignment_expression (data, value, &statement_one);
- if (status != STATUS_OK) {
- g_object_unref (*value);
- *value = NULL;
- g_object_unref (*statement);
- *statement = NULL;
- return FAIL_CHILD (status);
- }
+ if (!parse_assignment_expression (data, value, &statement_one))
+ vivi_parser_error_child_value (data, value);
}
- return STATUS_OK;
+ return TRUE;
}
// statement
-static ParseStatus
+static gboolean
parse_statement (ParseData *data, ViviCodeStatement **statement);
-static ParseStatus
+static gboolean
parse_trace_statement (ParseData *data, ViviCodeStatement **statement)
{
ViviCodeValue *value;
ViviCodeStatement *expression_statement;
- ParseStatus status;
*statement = NULL;
- if (!check_token (data, TOKEN_TRACE))
- return CANCEL (TOKEN_TRACE);
+ if (!check_token (data, TOKEN_TRACE)) {
+ vivi_parser_cancel_unexpected (data, TOKEN_TRACE);
+ return FALSE;
+ }
if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
- return FAIL (TOKEN_PARENTHESIS_LEFT);
+ vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
- status = parse_expression (data, &value, &expression_statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
+ if (parse_expression (data, &value, &expression_statement))
+ vivi_parser_error_child_value (data, &value);
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
- g_object_unref (value);
- if (expression_statement != NULL)
- g_object_unref (expression_statement);
- return FAIL (TOKEN_PARENTHESIS_RIGHT);
- }
+ if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
+ vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
- if (!check_automatic_semicolon (data)) {
- g_object_unref (value);
- if (expression_statement != NULL)
- g_object_unref (expression_statement);
- return FAIL (TOKEN_SEMICOLON);
- }
+ if (!check_automatic_semicolon (data))
+ vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
*statement = vivi_code_trace_new (value);
g_object_unref (value);
- *statement =
- vivi_parser_join_statements (expression_statement, *statement);
+ *statement = vivi_parser_join_statements (expression_statement, *statement);
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_continue_or_break_statement (ParseData *data,
ViviCodeStatement **statement, ViviParserScannerToken token)
{
*statement = NULL;
- if (!check_token (data, token))
- return CANCEL (token);
+ if (!check_token (data, token)) {
+ vivi_parser_cancel_unexpected (data, token);
+ return FALSE;
+ }
if (!check_restricted_semicolon (data)) {
- ParseStatus status;
+ gboolean status;
ViviCodeValue *identifier;
- status = parse_identifier (data, &identifier);
+ if (!parse_identifier (data, &identifier))
+ vivi_parser_error_child_value (data, &identifier);
+
+ // FIXME
*statement = vivi_compiler_goto_name_new (
vivi_code_constant_get_variable_name (
VIVI_CODE_CONSTANT (VIVI_CODE_GET (identifier)->name)));
@@ -1471,84 +1411,80 @@ parse_continue_or_break_statement (ParseData *data,
vivi_parser_add_goto (data, VIVI_COMPILER_GOTO_NAME (*statement));
- if (!check_automatic_semicolon (data)) {
- g_object_unref (*statement);
- *statement = NULL;
- return FAIL (TOKEN_SEMICOLON);
- }
+ if (!check_automatic_semicolon (data))
+ vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
} else {
*statement = vivi_code_break_new ();
}
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_continue_statement (ParseData *data, ViviCodeStatement **statement)
{
return parse_continue_or_break_statement (data, statement, TOKEN_CONTINUE);
}
-static ParseStatus
+static gboolean
parse_break_statement (ParseData *data, ViviCodeStatement **statement)
{
return parse_continue_or_break_statement (data, statement, TOKEN_BREAK);
}
-static ParseStatus
+static gboolean
parse_throw_statement (ParseData *data, ViviCodeStatement **statement)
{
- ParseStatus status;
+ gboolean status;
ViviCodeValue *value;
ViviCodeStatement *expression_statement;
*statement = NULL;
- if (!check_token (data, TOKEN_THROW))
- return CANCEL (TOKEN_THROW);
+ if (!check_token (data, TOKEN_THROW)) {
+ vivi_parser_cancel_unexpected (data, TOKEN_THROW);
+ return FALSE;
+ }
if (check_line_terminator (data))
- return FAIL_LINE_TERMINATOR (ERROR_TOKEN_EXPRESSION);
+ vivi_parser_error_unexpected_line_terminator (data,
+ ERROR_TOKEN_EXPRESSION);
- status = parse_expression (data, &value, &expression_statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
+ if (parse_expression (data, &value, &expression_statement))
+ vivi_parser_error_child_value (data, &value);
*statement = vivi_code_throw_new (value);
g_object_unref (value);
- *statement =
- vivi_parser_join_statements (expression_statement, *statement);
+ *statement = vivi_parser_join_statements (expression_statement, *statement);
- if (!check_automatic_semicolon (data)) {
- g_object_unref (*statement);
- *statement = NULL;
- return FAIL (TOKEN_SEMICOLON);
- }
+ if (!check_automatic_semicolon (data))
+ vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_return_statement (ParseData *data, ViviCodeStatement **statement)
{
*statement = NULL;
- if (!check_token (data, TOKEN_RETURN))
- return CANCEL (TOKEN_RETURN);
+ if (!check_token (data, TOKEN_RETURN)) {
+ vivi_parser_cancel_unexpected (data, TOKEN_RETURN);
+ return FALSE;
+ }
*statement = vivi_code_return_new ();
if (!check_restricted_semicolon (data)) {
- ParseStatus status;
+ gboolean status;
ViviCodeValue *value;
ViviCodeStatement *expression_statement;
- status = parse_expression (data, &value, &expression_statement);
- if (status != STATUS_OK) {
- g_object_unref (*statement);
- *statement = NULL;
- return FAIL_CHILD (status);
+ if (!parse_expression (data, &value, &expression_statement)) {
+ vivi_parser_error_unexpected (data, TOKEN_SEMICOLON,
+ ERROR_TOKEN_EXPRESSION);
+ return TRUE;
}
vivi_code_return_set_value (VIVI_CODE_RETURN (*statement), value);
@@ -1557,20 +1493,16 @@ parse_return_statement (ParseData *data, ViviCodeStatement **statement)
*statement =
vivi_parser_join_statements (expression_statement, *statement);
- if (!check_automatic_semicolon (data)) {
- g_object_unref (*statement);
- *statement = NULL;
- return FAIL (TOKEN_SEMICOLON);
- }
+ if (!check_automatic_semicolon (data))
+ vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
}
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
{
- ParseStatus status;
ViviCodeValue *condition;
ViviCodeStatement *pre_statement, *condition_statement, *loop_statement;
@@ -1580,78 +1512,50 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
condition_statement = NULL;
if (check_token (data, TOKEN_DO)) {
- status = parse_statement (data, &loop_statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
+ if (!parse_statement (data, &loop_statement))
+ vivi_parser_error_child_statement (data, &loop_statement);
- if (!check_token (data, TOKEN_WHILE)) {
- g_object_unref (loop_statement);
- return FAIL (TOKEN_WHILE);
- }
+ if (!check_token (data, TOKEN_WHILE))
+ vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
- if (!check_token (data, TOKEN_PARENTHESIS_LEFT)) {
- g_object_unref (loop_statement);
- return FAIL (TOKEN_PARENTHESIS_LEFT);
- }
+ if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
+ vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
- status = parse_expression (data, &condition, &condition_statement);
- if (status != STATUS_OK) {
- g_object_unref (loop_statement);
- return FAIL_CHILD (status);
- }
+ if (parse_expression (data, &condition, &condition_statement))
+ vivi_parser_error_child_value (data, &condition);
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
- g_object_unref (loop_statement);
- g_object_unref (condition);
- if (condition_statement != NULL)
- g_object_unref (condition_statement);
- return FAIL (TOKEN_PARENTHESIS_LEFT);
- }
+ if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
+ vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
- if (!check_automatic_semicolon (data)) {
- g_object_unref (loop_statement);
- g_object_unref (condition);
- if (condition_statement != NULL)
- g_object_unref (condition_statement);
- return FAIL (TOKEN_PARENTHESIS_LEFT);
- }
+ if (!check_automatic_semicolon (data))
+ vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
pre_statement = g_object_ref (loop_statement);
} else if (check_token (data, TOKEN_WHILE)) {
if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
- return FAIL (TOKEN_PARENTHESIS_LEFT);
+ vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
- status = parse_expression (data, &condition, &condition_statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
+ if (parse_expression (data, &condition, &condition_statement))
+ vivi_parser_error_child_value (data, &condition);
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
- g_object_unref (condition);
- if (condition_statement != NULL)
- g_object_unref (condition_statement);
- return FAIL (TOKEN_PARENTHESIS_RIGHT);
- }
+ if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
+ vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
- status = parse_statement (data, &loop_statement);
- if (status != STATUS_OK) {
- g_object_unref (condition);
- if (condition_statement != NULL)
- g_object_unref (condition_statement);
- return FAIL_CHILD (status);
- }
+ if (!parse_statement (data, &loop_statement))
+ vivi_parser_error_child_statement (data, &loop_statement);
} else if (check_token (data, TOKEN_FOR)) {
ViviCodeValue *pre_value;
ViviCodeStatement *post_statement;
if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
- return FAIL (TOKEN_PARENTHESIS_LEFT);
+ vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
if (check_token (data, TOKEN_VAR)) {
// FIXME: no in
- status = parse_statement_list (data, parse_variable_declaration,
- &pre_statement, TOKEN_COMMA);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
+ if (parse_statement_list (data, parse_variable_declaration,
+ &pre_statement, TOKEN_COMMA)) {
+ // FIXME
+ }
// FIXME: ugly
// If there was only one VariableDeclaration, get the name for pre_value
g_assert (VIVI_IS_CODE_BLOCK (pre_statement));
@@ -1667,9 +1571,8 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
} else {
if (!check_token (data, TOKEN_SEMICOLON)) {
// FIXME: no in
- status = parse_expression (data, &pre_value, &pre_statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
+ if (parse_expression (data, &pre_value, &pre_statement))
+ vivi_parser_error_child_value (data, &pre_value);
} else {
pre_value = NULL;
pre_statement = NULL;
@@ -1680,87 +1583,53 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
if (pre_value != NULL)
g_object_unref (pre_value);
if (!check_token (data, TOKEN_SEMICOLON)) {
- status = parse_expression (data, &condition, &condition_statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
-
- if (!check_token (data, TOKEN_SEMICOLON)) {
- if (pre_statement != NULL)
- g_object_unref (pre_statement);
- g_object_unref (condition);
- if (condition_statement != NULL)
- g_object_unref (condition_statement);
- return FAIL (TOKEN_SEMICOLON);
- }
- }
+ if (parse_expression (data, &condition, &condition_statement))
+ vivi_parser_error_child_value (data, &condition);
- status = parse_expression (data, &pre_value, &post_statement);
- if (status != STATUS_OK) {
- if (pre_statement != NULL)
- g_object_unref (pre_statement);
- g_object_unref (condition);
- if (condition_statement != NULL)
- g_object_unref (condition_statement);
- return FAIL_CHILD (status);
+ if (!check_token (data, TOKEN_SEMICOLON))
+ vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
}
+
+ if (!parse_expression (data, &pre_value, &post_statement))
+ vivi_parser_error_child_value (data, &pre_value);
g_object_unref (pre_value);
} else if (pre_value != NULL && check_token (data, TOKEN_IN)) {
post_statement = NULL;
- if (!vivi_parser_value_is_left_hand_side (pre_value)) {
- g_object_unref (pre_value);
- if (pre_statement != NULL)
- g_object_unref (pre_statement);
- return FAIL_CUSTOM (g_strdup (
- "Invalid left hand side expression for in"));
- }
+ // FIXME: correct?
+ if (!vivi_parser_value_is_left_hand_side (pre_value))
+ vivi_parser_error ("Invalid left-hand side expression for in");
g_object_unref (pre_value);
if (pre_statement != NULL)
g_object_unref (pre_statement);
- return FAIL_CUSTOM (g_strdup (
- "for (... in ...) has not been implemented yet"));
+ vivi_parser_error ("for (... in ...) has not been implemented yet");
} else {
- ViviParserScannerToken fail_token;
-
if (pre_value != NULL) {
- fail_token = TOKEN_IN;
- g_object_unref (pre_value);
+ vivi_parser_error_unexpected (data, TOKEN_SEMICOLON, TOKEN_IN);
} else {
- fail_token = TOKEN_NONE;
+ vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
}
- if (pre_statement != NULL)
- g_object_unref (pre_statement);
-
- return FAIL_OR (TOKEN_SEMICOLON, fail_token);
- }
+ condition = vivi_code_constant_new_undefined ();
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+ if (pre_value != NULL)
+ g_object_unref (pre_value);
if (pre_statement != NULL)
g_object_unref (pre_statement);
- g_object_unref (condition);
- if (condition_statement != NULL)
- g_object_unref (condition_statement);
- g_object_unref (post_statement);
- return FAIL (TOKEN_PARENTHESIS_RIGHT);
}
- status = parse_statement (data, &loop_statement);
- if (status != STATUS_OK) {
- if (pre_statement != NULL)
- g_object_unref (pre_statement);
- g_object_unref (condition);
- if (condition_statement != NULL)
- g_object_unref (condition_statement);
- g_object_unref (post_statement);
- return FAIL_CHILD (status);
- }
+ if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
+ vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
+
+ if (!parse_statement (data, &loop_statement))
+ vivi_parser_error_child_statement (data, &loop_statement);
loop_statement =
vivi_parser_join_statements (loop_statement, post_statement);
} else {
- return CANCEL (ERROR_TOKEN_ITERATION_STATEMENT);
+ vivi_parser_cancel_unexpected (data, ERROR_TOKEN_ITERATION_STATEMENT);
+ return FALSE;
}
if (condition_statement != NULL) {
@@ -1779,58 +1648,37 @@ parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
*statement = vivi_parser_join_statements (pre_statement, *statement);
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_if_statement (ParseData *data, ViviCodeStatement **statement)
{
- ParseStatus status;
ViviCodeValue *condition;
ViviCodeStatement *pre_statement, *if_statement, *else_statement;
*statement = NULL;
- if (!check_token (data, TOKEN_IF))
- return CANCEL (TOKEN_IF);
+ if (!check_token (data, TOKEN_IF)) {
+ vivi_parser_cancel_unexpected (data, TOKEN_IF);
+ return FALSE;
+ }
if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
- return FAIL (TOKEN_PARENTHESIS_LEFT);
+ vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
- status = parse_expression (data, &condition, &pre_statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
+ if (!parse_expression (data, &condition, &pre_statement))
+ vivi_parser_error_child_value (data, &condition);
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
- g_object_unref (condition);
- if (pre_statement != NULL) {
- g_object_unref (pre_statement);
- pre_statement = NULL;
- }
- return FAIL (TOKEN_PARENTHESIS_RIGHT);
- }
+ if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
+ vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
- status = parse_statement (data, &if_statement);
- if (status != STATUS_OK) {
- g_object_unref (condition);
- if (pre_statement != NULL) {
- g_object_unref (pre_statement);
- pre_statement = NULL;
- }
- return FAIL_CHILD (status);
- }
+ if (!parse_statement (data, &if_statement))
+ vivi_parser_error_child_statement (data, &if_statement);
if (check_token (data, TOKEN_ELSE)) {
- status = parse_statement (data, &else_statement);
- if (status != STATUS_OK) {
- g_object_unref (condition);
- if (pre_statement != NULL) {
- g_object_unref (pre_statement);
- pre_statement = NULL;
- }
- g_object_unref (if_statement);
- return FAIL_CHILD (status);
- }
+ if (!parse_statement (data, &else_statement))
+ vivi_parser_error_child_statement (data, &else_statement);
} else {
else_statement = NULL;
}
@@ -1850,13 +1698,12 @@ parse_if_statement (ParseData *data, ViviCodeStatement **statement)
g_assert (*statement != NULL);
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_expression_statement (ParseData *data, ViviCodeStatement **statement)
{
- ParseStatus status;
ViviCodeValue *value;
ViviCodeStatement *last;
@@ -1864,12 +1711,13 @@ parse_expression_statement (ParseData *data, ViviCodeStatement **statement)
vivi_parser_scanner_peek_next_token (data->scanner);
if (data->scanner->next_token == TOKEN_BRACE_LEFT ||
- data->scanner->next_token == TOKEN_FUNCTION)
- return CANCEL (ERROR_TOKEN_EXPRESSION_STATEMENT);
+ data->scanner->next_token == TOKEN_FUNCTION) {
+ vivi_parser_cancel_unexpected (data, ERROR_TOKEN_EXPRESSION_STATEMENT);
+ return FALSE;
+ }
- status = parse_expression (data, &value, statement);
- if (status != STATUS_OK)
- return status;
+ if (!parse_expression (data, &value, statement))
+ return FALSE;
// check for label
if (*statement == NULL && vivi_parser_value_is_identifier (value)) {
@@ -1877,19 +1725,13 @@ parse_expression_statement (ParseData *data, ViviCodeStatement **statement)
*statement = vivi_code_label_new (vivi_code_constant_get_variable_name (
VIVI_CODE_CONSTANT (VIVI_CODE_GET (value)->name)));
if (!vivi_parser_add_label (data, VIVI_CODE_LABEL (*statement)))
- return FAIL_CUSTOM (g_strdup ("Same label name used twice"));
- return STATUS_OK;
+ vivi_parser_error ("Same label name used twice");
+ return TRUE;
}
}
- if (!check_automatic_semicolon (data)) {
- g_object_unref (value);
- if (*statement != NULL) {
- g_object_unref (*statement);
- *statement = NULL;
- }
- return FAIL (TOKEN_SEMICOLON);
- }
+ if (!check_automatic_semicolon (data))
+ vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
// add a value statement, if the last statement is not an assignment with the
// same value
@@ -1907,7 +1749,7 @@ parse_expression_statement (ParseData *data, ViviCodeStatement **statement)
if (assignment->from == NULL && assignment->name == VIVI_CODE_GET (value)->name) {
g_object_unref (value);
- return STATUS_OK;
+ return TRUE;
}
}
@@ -1915,81 +1757,81 @@ parse_expression_statement (ParseData *data, ViviCodeStatement **statement)
vivi_code_value_statement_new (value));
g_object_unref (value);
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_empty_statement (ParseData *data, ViviCodeStatement **statement)
{
*statement = NULL;
- if (!check_token (data, TOKEN_SEMICOLON))
- return CANCEL (TOKEN_SEMICOLON);
+ if (!check_token (data, TOKEN_SEMICOLON)) {
+ vivi_parser_cancel_unexpected (data, TOKEN_SEMICOLON);
+ return FALSE;
+ }
*statement = vivi_compiler_empty_statement_new ();
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_block (ParseData *data, ViviCodeStatement **statement)
{
- ParseStatus status;
+ gboolean status;
*statement = NULL;
- if (!check_token (data, TOKEN_BRACE_LEFT))
- return CANCEL (TOKEN_BRACE_LEFT);
+ if (!check_token (data, TOKEN_BRACE_LEFT)) {
+ vivi_parser_cancel_unexpected (data, TOKEN_BRACE_LEFT);
+ return FALSE;
+ }
vivi_parser_scanner_peek_next_token (data->scanner);
- if (data->scanner->next_token != TOKEN_BRACE_RIGHT) {
- status =
- parse_statement_list (data, parse_statement, statement, STATUS_OK);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
+ if (!check_token (data, TOKEN_BRACE_RIGHT)) {
+ if (!parse_statement_list (data, parse_statement, statement, TRUE)) {
+ // FIXME: child token
+ vivi_parser_error_unexpected (data, TOKEN_BRACE_RIGHT,
+ ERROR_TOKEN_STATEMENT);
+ *statement = vivi_code_block_new ();
+ }
+
+ if (!check_token (data, TOKEN_BRACE_RIGHT))
+ vivi_parser_error_unexpected (data, TOKEN_BRACE_RIGHT);
} else {
*statement = vivi_code_block_new ();
}
- if (!check_token (data, TOKEN_BRACE_RIGHT)) {
- g_object_unref (*statement);
- *statement = NULL;
- return FAIL (TOKEN_BRACE_RIGHT);
- }
-
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_variable_statement (ParseData *data, ViviCodeStatement **statement)
{
- ParseStatus status;
+ gboolean status;
*statement = NULL;
- if (!check_token (data, TOKEN_VAR))
- return CANCEL (TOKEN_VAR);
-
- status = parse_statement_list (data, parse_variable_declaration, statement,
- TOKEN_COMMA);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
+ if (!check_token (data, TOKEN_VAR)) {
+ vivi_parser_cancel_unexpected (data, TOKEN_VAR);
+ return FALSE;
+ }
- if (!check_automatic_semicolon (data)) {
- g_object_unref (*statement);
- *statement = NULL;
- return FAIL (TOKEN_SEMICOLON);
+ if (!parse_statement_list (data, parse_variable_declaration, statement,
+ TOKEN_COMMA)) {
+ // FIXME
}
- return STATUS_OK;
+ if (!check_automatic_semicolon (data))
+ vivi_parser_error_unexpected (data, TOKEN_SEMICOLON);
+
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_statement (ParseData *data, ViviCodeStatement **statement)
{
- ParseStatus status;
- int i;
- ParseStatementFunction functions[] = {
+ static const ParseStatementFunction functions[] = {
parse_block,
parse_variable_statement,
parse_empty_statement,
@@ -2006,28 +1848,28 @@ parse_statement (ParseData *data, ViviCodeStatement **statement)
parse_trace_statement,
NULL
};
+ guint i;
*statement = NULL;
for (i = 0; functions[i] != NULL; i++) {
- status = functions[i] (data, statement);
- if (status != STATUS_CANCEL)
- return status;
+ if (functions[i] (data, statement))
+ return TRUE;
}
- return CANCEL (ERROR_TOKEN_STATEMENT);
+ vivi_parser_cancel_unexpected (data, ERROR_TOKEN_STATEMENT);
+ return FALSE;
}
// function
-static ParseStatus
+static gboolean
parse_source_element (ParseData *data, ViviCodeStatement **statement);
-static ParseStatus
+static gboolean
parse_function_definition (ParseData *data, ViviCodeValue **function,
ViviCodeValue **identifier, gboolean identifier_required)
{
- ParseStatus status;
ViviCodeValue **arguments;
ViviCodeStatement *body;
guint i;
@@ -2038,65 +1880,50 @@ parse_function_definition (ParseData *data, ViviCodeValue **function,
arguments = NULL;
body = NULL;
- if (!check_token (data, TOKEN_FUNCTION))
- return CANCEL (TOKEN_FUNCTION);
+ if (!check_token (data, TOKEN_FUNCTION)) {
+ vivi_parser_cancel_unexpected (data, TOKEN_FUNCTION);
+ return FALSE;
+ }
- status = parse_identifier (data, identifier);
- if (status == STATUS_FAIL ||
- (identifier_required && status == STATUS_CANCEL))
- return FAIL_CHILD (status);
+ if (identifier_required) {
+ if (!parse_identifier (data, identifier))
+ vivi_parser_error_child_value (data, identifier);
- if (!check_token (data, TOKEN_PARENTHESIS_LEFT)) {
- g_object_unref (*identifier);
- return FAIL (TOKEN_PARENTHESIS_LEFT);
- }
+ if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
+ vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
+ } else {
+ if (!check_token (data, TOKEN_PARENTHESIS_LEFT)) {
+ if (!parse_identifier (data, identifier)) {
+ // FIXME: child token
+ vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT,
+ ERROR_TOKEN_IDENTIFIER);
+ }
- status = parse_value_list (data, parse_identifier, &arguments, TOKEN_COMMA);
- if (status == STATUS_FAIL) {
- g_object_unref (*identifier);
- return STATUS_FAIL;
+ if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
+ vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_LEFT);
+ }
}
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
- g_object_unref (*identifier);
- if (arguments != NULL)
- free_value_list (arguments);
- return FAIL (TOKEN_PARENTHESIS_RIGHT);
+ if (!parse_value_list (data, parse_identifier, &arguments, TOKEN_COMMA)) {
+ // FIXME
}
- if (!check_token (data, TOKEN_BRACE_LEFT)) {
- g_object_unref (*identifier);
- if (arguments != NULL)
- free_value_list (arguments);
- return FAIL (TOKEN_BRACE_LEFT);
- }
+ if (!check_token (data, TOKEN_PARENTHESIS_RIGHT))
+ vivi_parser_error_unexpected (data, TOKEN_PARENTHESIS_RIGHT);
+
+ if (!check_token (data, TOKEN_BRACE_LEFT))
+ vivi_parser_error_unexpected (data, TOKEN_BRACE_LEFT);
vivi_parser_start_level (data);
- status = parse_statement_list (data, parse_source_element, &body, STATUS_OK);
- if (status == STATUS_FAIL) {
- vivi_parser_end_level (data, FALSE);
- g_object_unref (*identifier);
- if (arguments != NULL)
- free_value_list (arguments);
- return STATUS_FAIL;
+ if (parse_statement_list (data, parse_source_element, &body, TRUE)) {
+ // FIXME
}
- status = vivi_parser_end_level (data, TRUE);
- if (status != STATUS_OK) {
- g_object_unref (*identifier);
- if (arguments != NULL)
- free_value_list (arguments);
- return FAIL_CHILD (status);
- }
+ vivi_parser_end_level (data);
- if (!check_token (data, TOKEN_BRACE_RIGHT)) {
- g_object_unref (*identifier);
- if (arguments != NULL)
- free_value_list (arguments);
- g_object_unref (body);
- return FAIL (TOKEN_BRACE_RIGHT);
- }
+ if (!check_token (data, TOKEN_BRACE_RIGHT))
+ vivi_parser_error_unexpected (data, TOKEN_BRACE_RIGHT);
*function = vivi_code_function_new ();
if (body != NULL) {
@@ -2112,111 +1939,93 @@ parse_function_definition (ParseData *data, ViviCodeValue **function,
free_value_list (arguments);
}
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_function_declaration (ParseData *data, ViviCodeStatement **statement)
{
- ParseStatus status;
+ gboolean status;
ViviCodeValue *function, *identifier;
*statement = NULL;
- status = parse_function_definition (data, &function, &identifier, TRUE);
- if (status != STATUS_OK)
- return status;
+ if (!parse_function_definition (data, &function, &identifier, TRUE))
+ return FALSE;
*statement = vivi_parser_assignment_new (identifier, function);
g_object_unref (identifier);
g_object_unref (function);
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_function_expression (ParseData *data, ViviCodeValue **value,
ViviCodeStatement **statement)
{
- ParseStatus status;
+ gboolean status;
ViviCodeValue *identifier;
*statement = NULL;
- status = parse_function_definition (data, value, &identifier, FALSE);
- if (status != STATUS_OK)
- return status;
+ if (!parse_function_definition (data, &function, &identifier, FALSE))
+ return FALSE;
if (identifier != NULL) {
*statement = vivi_parser_assignment_new (identifier, *value);
g_object_unref (identifier);
}
- return STATUS_OK;
+ return TRUE;
}
// top
-static ParseStatus
+static gboolean
parse_source_element (ParseData *data, ViviCodeStatement **statement)
{
- ParseStatus status;
-
*statement = NULL;
- status = parse_function_declaration (data, statement);
- if (status == STATUS_CANCEL)
- status = parse_statement (data, statement);
+ if (!parse_function_declaration (data, statement)) {
+ if (!parse_statement (data, statement)) {
+ // FIXME
+ vivi_parser_cancel_unexpected (data, ERROR_TOKEN_FUNCTION_DECLARATION,
+ ERROR_TOKEN_STATEMENT);
+ return FALSE;
+ }
+ }
- return status;
+ return TRUE;
}
-static ParseStatus
+static void
parse_program (ParseData *data, ViviCodeStatement **statement)
{
- ParseStatus status;
-
g_assert (data->level == NULL);
vivi_parser_start_level (data);
*statement = NULL;
- status =
- parse_statement_list (data, parse_source_element, statement, STATUS_OK);
- if (status != STATUS_OK) {
- vivi_parser_end_level (data, FALSE);
- return FAIL_CHILD (status);
- }
-
- if (!check_token (data, TOKEN_EOF)) {
- vivi_parser_end_level (data, FALSE);
- g_object_unref (*statement);
- *statement = NULL;
- status = parse_statement (data, statement);
- return FAIL_CHILD (status);
- }
+ if (!parse_statement_list (data, parse_source_element, statement, TRUE))
+ // FIXME
+ if (!check_token (data, TOKEN_EOF))
+ vivi_parser_error_unexpected (data, TOKEN_EOF);
- status = vivi_parser_end_level (data, TRUE);
- if (status != STATUS_OK) {
- g_object_unref (*statement);
- *statement = NULL;
- return FAIL_CHILD (status);
- }
+ vivi_parser_end_level (data);
g_assert (data->level == NULL);
-
- return STATUS_OK;
}
// parsing
-static ParseStatus
+static gboolean
parse_statement_list (ParseData *data, ParseStatementFunction function,
ViviCodeStatement **block, guint separator)
{
ViviCodeStatement *statement;
- ParseStatus status;
+ gboolean status;
g_assert (data != NULL);
g_assert (function != NULL);
@@ -2225,7 +2034,7 @@ parse_statement_list (ParseData *data, ParseStatementFunction function,
*block = NULL;
status = function (data, &statement);
- if (status != STATUS_OK)
+ if (status != TRUE)
return status;
*block = vivi_code_block_new ();
@@ -2234,7 +2043,7 @@ parse_statement_list (ParseData *data, ParseStatementFunction function,
vivi_code_block_add_statement (VIVI_CODE_BLOCK (*block), statement);
g_object_unref (statement);
- if (separator != STATUS_OK && !check_token (data, separator))
+ if (separator != TRUE && !check_token (data, separator))
break;
status = function (data, &statement);
@@ -2243,12 +2052,12 @@ parse_statement_list (ParseData *data, ParseStatementFunction function,
*block = NULL;
return STATUS_FAIL;
}
- } while (status == STATUS_OK);
+ } while (status == TRUE);
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_value_statement_list (ParseData *data,
ParseValueStatementFunction function, ViviCodeValue ***list,
ViviCodeStatement **statement, guint separator)
@@ -2256,7 +2065,7 @@ parse_value_statement_list (ParseData *data,
GPtrArray *array;
ViviCodeValue *value;
ViviCodeStatement *statement_one;
- ParseStatus status;
+ gboolean status;
g_assert (data != NULL);
g_assert (function != NULL);
@@ -2267,7 +2076,7 @@ parse_value_statement_list (ParseData *data,
*statement = NULL;
status = function (data, &value, statement);
- if (status != STATUS_OK)
+ if (status != TRUE)
return status;
array = g_ptr_array_new ();
@@ -2279,27 +2088,27 @@ parse_value_statement_list (ParseData *data,
break;
status = function (data, &value, &statement_one);
- if (status != STATUS_OK) {
+ if (status != TRUE) {
if (status == STATUS_FAIL || separator != TOKEN_NONE)
return FAIL_CHILD (status);
} else {
*statement = vivi_parser_join_statements (*statement, statement_one);
}
- } while (status == STATUS_OK);
+ } while (status == TRUE);
g_ptr_array_add (array, NULL);
*list = (ViviCodeValue **)g_ptr_array_free (array, FALSE);
- return STATUS_OK;
+ return TRUE;
}
-static ParseStatus
+static gboolean
parse_value_list (ParseData *data, ParseValueFunction function,
ViviCodeValue ***list, guint separator)
{
GPtrArray *array;
ViviCodeValue *value;
- ParseStatus status;
+ gboolean status;
g_assert (data != NULL);
g_assert (function != NULL);
@@ -2308,7 +2117,7 @@ parse_value_list (ParseData *data, ParseValueFunction function,
*list = NULL;
status = function (data, &value);
- if (status != STATUS_OK)
+ if (status != TRUE)
return status;
array = g_ptr_array_new ();
@@ -2316,18 +2125,18 @@ parse_value_list (ParseData *data, ParseValueFunction function,
do {
g_ptr_array_add (array, value);
- if (separator != STATUS_OK && !check_token (data, separator))
+ if (separator != TRUE && !check_token (data, separator))
break;
status = function (data, &value);
if (status == STATUS_FAIL)
return STATUS_FAIL;
- } while (status == STATUS_OK);
+ } while (status == TRUE);
g_ptr_array_add (array, NULL);
*list = (ViviCodeValue **)g_ptr_array_free (array, FALSE);
- return STATUS_OK;
+ return TRUE;
}
// public
@@ -2337,7 +2146,7 @@ vivi_parse_file (FILE *file, const char *input_name)
{
ParseData data;
ViviCodeStatement *statement;
- ParseStatus status;
+ gboolean status;
g_return_val_if_fail (file != NULL, NULL);
@@ -2350,11 +2159,11 @@ vivi_parse_file (FILE *file, const char *input_name)
data.level = NULL;
status = parse_program (&data, &statement);
- g_assert ((status == STATUS_OK && VIVI_IS_CODE_STATEMENT (statement)) ||
- (status != STATUS_OK && statement == NULL));
+ g_assert ((status == TRUE && VIVI_IS_CODE_STATEMENT (statement)) ||
+ (status != TRUE && statement == NULL));
g_assert (status >= 0);
- if (status != STATUS_OK) {
+ if (status != TRUE) {
g_printerr ("%s:%i:%i: error: ", input_name,
vivi_parser_scanner_cur_line (data.scanner),
vivi_parser_scanner_cur_column (data.scanner));
commit b7d5363c6ad7f7e9b10cede8c1b18c200a302bb6
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date: Tue Apr 8 23:29:39 2008 +0300
Rename vivi_compiler.[ch] and vivi_compiler_scanner* to vivi_parser*
diff --git a/vivified/code/Makefile.am b/vivified/code/Makefile.am
index a38f95a..1ce87dd 100644
--- a/vivified/code/Makefile.am
+++ b/vivified/code/Makefile.am
@@ -1,19 +1,19 @@
SUBDIRS = test
-noinst_LTLIBRARIES = libvivified-compiler-lex.la libvivified-compiler.la
+noinst_LTLIBRARIES = libvivified-parser-lex.la libvivified-compiler.la
# we create own .la for lex generated code, so we can disable some warnings
-libvivified_compiler_lex_la_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS) -Wno-switch-default -Wno-missing-declarations -Wno-missing-prototypes -Wno-sign-compare -Wno-unused-function -Wno-missing-noreturn
-libvivified_compiler_lex_la_LDFLAGS = $(SWFDEC_LIBS)
+libvivified_parser_lex_la_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS) -Wno-switch-default -Wno-missing-declarations -Wno-missing-prototypes -Wno-sign-compare -Wno-unused-function -Wno-missing-noreturn
+libvivified_parser_lex_la_LDFLAGS = $(SWFDEC_LIBS)
-libvivified_compiler_lex_la_SOURCES = \
- vivi_compiler_scanner_lex.l
+libvivified_parser_lex_la_SOURCES = \
+ vivi_parser_scanner_lex.l
libvivified_compiler_la_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS)
libvivified_compiler_la_LDFLAGS = $(SWFDEC_LIBS)
libvivified_compiler_la_LIBADD = \
- libvivified-compiler-lex.la
+ libvivified-parser-lex.la
libvivified_compiler_la_SOURCES = \
vivi_code_assignment.c \
@@ -44,16 +44,16 @@ libvivified_compiler_la_SOURCES = \
vivi_code_unary.c \
vivi_code_value.c \
vivi_code_value_statement.c \
- vivi_compiler.c \
vivi_compiler_empty_statement.c \
vivi_compiler_get_temporary.c \
vivi_compiler_goto_name.c \
- vivi_compiler_scanner.c \
vivi_decompiler_block.c \
vivi_decompiler_duplicate.c \
vivi_decompiler_state.c \
vivi_decompiler_unknown.c \
- vivi_decompiler.c
+ vivi_decompiler.c \
+ vivi_parser.c \
+ vivi_parser_scanner.c
noinst_HEADERS = \
vivi_code_assignment.h \
@@ -84,18 +84,18 @@ noinst_HEADERS = \
vivi_code_unary.h \
vivi_code_value.h \
vivi_code_value_statement.h \
- vivi_compiler.h \
vivi_compiler_empty_statement.h \
vivi_compiler_get_temporary.h \
vivi_compiler_goto_name.h \
- vivi_compiler_scanner.h \
- vivi_compiler_scanner_lex.h \
- vivi_compiler_scanner_lex_include.h \
vivi_decompiler.h \
vivi_decompiler_block.h \
vivi_decompiler_duplicate.h \
vivi_decompiler_state.h
vivi_decompiler_unknown.h \
+ vivi_parser.h \
+ vivi_parser_scanner.h \
+ vivi_parser_scanner_lex.h \
+ vivi_parser_scanner_lex_include.h \
vivified-compiler.h
noinst_PROGRAMS = vivi-decompile vivi-compile
diff --git a/vivified/code/compiler.c b/vivified/code/compiler.c
index 0b984f5..e3a32a9 100644
--- a/vivified/code/compiler.c
+++ b/vivified/code/compiler.c
@@ -23,7 +23,7 @@
#include <swfdec/swfdec.h>
-#include "vivi_compiler.h"
+#include "vivi_parser.h"
#include "vivi_code_text_printer.h"
#include "vivi_code_compiler.h"
@@ -54,7 +54,7 @@ main (int argc, char *argv[])
return -1;
}
- statement = vivi_compile_file (source, argv[1]);
+ statement = vivi_parse_file (source, argv[1]);
fclose (source);
diff --git a/vivified/code/vivi_compiler.c b/vivified/code/vivi_compiler.c
deleted file mode 100644
index 10b3e61..0000000
--- a/vivified/code/vivi_compiler.c
+++ /dev/null
@@ -1,2385 +0,0 @@
-/* Vivified
- * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <string.h>
-
-#include "vivi_compiler.h"
-
-#include "vivi_compiler_scanner.h"
-
-#include "vivi_code_assignment.h"
-#include "vivi_code_binary.h"
-#include "vivi_code_block.h"
-#include "vivi_code_break.h"
-#include "vivi_code_constant.h"
-#include "vivi_code_continue.h"
-#include "vivi_code_function.h"
-#include "vivi_code_function_call.h"
-#include "vivi_code_get.h"
-#include "vivi_code_get_url.h"
-#include "vivi_code_goto.h"
-#include "vivi_code_if.h"
-#include "vivi_code_init_array.h"
-#include "vivi_code_init_object.h"
-#include "vivi_code_loop.h"
-#include "vivi_code_return.h"
-#include "vivi_code_throw.h"
-#include "vivi_code_trace.h"
-#include "vivi_code_unary.h"
-#include "vivi_code_value_statement.h"
-#include "vivi_compiler_empty_statement.h"
-#include "vivi_compiler_get_temporary.h"
-#include "vivi_compiler_goto_name.h"
-
-#include "vivi_code_text_printer.h"
-
-enum {
- ERROR_TOKEN_LITERAL = TOKEN_LAST + 1,
- ERROR_TOKEN_IDENTIFIER,
- ERROR_TOKEN_PROPERTY_NAME,
- ERROR_TOKEN_PRIMARY_EXPRESSION,
- ERROR_TOKEN_EXPRESSION,
- ERROR_TOKEN_ITERATION_STATEMENT,
- ERROR_TOKEN_EXPRESSION_STATEMENT,
- ERROR_TOKEN_STATEMENT
-};
-
-static const struct {
- guint token;
- const char * name;
-} error_names[] = {
- { ERROR_TOKEN_LITERAL, "LITERAL" },
- { ERROR_TOKEN_IDENTIFIER, "IDENTIFIER" },
- { ERROR_TOKEN_PROPERTY_NAME, "PROPERTY NAME" },
- { ERROR_TOKEN_PRIMARY_EXPRESSION, "PRIMARY EXPRESSION" },
- { ERROR_TOKEN_EXPRESSION, "EXPRESSION" },
- { ERROR_TOKEN_ITERATION_STATEMENT, "ITERATION STATEMENT" },
- { ERROR_TOKEN_EXPRESSION_STATEMENT, "EXPRESSION STATEMENT" },
- { ERROR_TOKEN_STATEMENT, "STATEMENT" },
- { TOKEN_LAST, NULL }
-};
-
-typedef enum {
- STATUS_CANCEL = -1,
- STATUS_OK = 0,
- STATUS_FAIL = 1
-} ParseStatus;
-
-typedef struct {
- GSList *labels;
- GSList *gotos;
-} ParseLevel;
-
-typedef struct {
- ViviCompilerScanner * scanner;
- gboolean unexpected_line_terminator;
- guint expected[2];
- char * custom_error;
-
- GSList * levels; // ParseLevel, earlier levels
- ParseLevel * level; // current level
-} ParseData;
-
-#define FAIL_OR(x, y) (data->expected[0] = (x), data->expected[1] = (y), STATUS_FAIL)
-#define FAIL_LINE_TERMINATOR_OR(x, y) (data->unexpected_line_terminator = TRUE, FAIL_OR(x,y))
-#define FAIL_LINE_TERMINATOR(x) FAIL_LINE_TERMINATOR_OR(x,TOKEN_NONE)
-#define FAIL(x) FAIL_OR(x,TOKEN_NONE)
-#define FAIL_CHILD(x) STATUS_FAIL
-#define FAIL_CUSTOM(x) (data->custom_error = (x), STATUS_FAIL)
-#define CANCEL_OR(x, y) (data->expected[0] = (x), data->expected[1] = (y), STATUS_CANCEL)
-#define CANCEL(x) CANCEL_OR(x, TOKEN_NONE)
-#define CANCEL_CUSTOM(x) (data->custom_error = (x), STATUS_CANCEL)
-
-typedef ParseStatus (*ParseValueFunction) (ParseData *data, ViviCodeValue **value);
-typedef ParseStatus (*ParseValueStatementFunction) (ParseData *data, ViviCodeValue **value, ViviCodeStatement **statement);
-typedef ParseStatus (*ParseStatementFunction) (ParseData *data, ViviCodeStatement **statement);
-
-static ParseStatus
-parse_statement_list (ParseData *data, ParseStatementFunction function, ViviCodeStatement **statement, guint separator);
-
-static ParseStatus
-parse_value_statement_list (ParseData *data,
- ParseValueStatementFunction function, ViviCodeValue ***list,
- ViviCodeStatement **statement, guint separator);
-
-static ParseStatus
-parse_value_list (ParseData *data, ParseValueFunction function,
- ViviCodeValue ***list, guint separator);
-
-// helpers
-
-static const char *
-vivi_compiler_token_name (guint token)
-{
- if (token < TOKEN_LAST) {
- return vivi_compiler_scanner_token_name (token);
- } else {
- guint i;
- const char *name;
-
- name = NULL;
- for (i = 0; error_names[i].token != TOKEN_LAST; i++) {
- if (error_names[i].token == token) {
- name = error_names[i].name;
- break;
- }
- }
-
- g_assert (name != NULL);
-
- return name;
- }
-}
-
-static gboolean
-check_line_terminator (ParseData *data)
-{
- vivi_compiler_scanner_peek_next_token (data->scanner);
- return data->scanner->next_line_terminator;
-}
-
-static gboolean
-check_token (ParseData *data, ViviCompilerScannerToken token)
-{
- vivi_compiler_scanner_peek_next_token (data->scanner);
- if (data->scanner->next_token != token)
- return FALSE;
- vivi_compiler_scanner_get_next_token (data->scanner);
- return TRUE;
-}
-
-static gboolean
-check_automatic_semicolon (ParseData *data)
-{
- if (check_token (data, TOKEN_SEMICOLON))
- return TRUE;
- if (check_line_terminator (data))
- return TRUE;
-
- vivi_compiler_scanner_peek_next_token (data->scanner);
- if (data->scanner->next_token == TOKEN_BRACE_LEFT ||
- data->scanner->next_token == TOKEN_EOF)
- return TRUE;
-
- return FALSE;
-}
-
-static gboolean
-check_restricted_semicolon (ParseData *data)
-{
- if (check_token (data, TOKEN_SEMICOLON))
- return TRUE;
- if (check_line_terminator (data))
- return TRUE;
-
- return FALSE;
-}
-
-static void
-free_value_list (ViviCodeValue **list)
-{
- int i;
-
- for (i = 0; list[i] != NULL; i++) {
- g_object_unref (list[i]);
- }
- g_free (list);
-}
-
-G_GNUC_WARN_UNUSED_RESULT static ViviCodeStatement *
-vivi_compiler_join_statements (ViviCodeStatement *one, ViviCodeStatement *two)
-{
-
- if (one == NULL) {
- return two;
- } else if (two == NULL) {
- return one;
- }
-
- if (VIVI_IS_CODE_BLOCK (one)) {
- vivi_code_block_add_statement (VIVI_CODE_BLOCK (one), two);
- g_object_unref (two);
- return one;
- } else if (VIVI_IS_CODE_BLOCK (two)) {
- vivi_code_block_insert_statement (VIVI_CODE_BLOCK (two), 0, one);
- g_object_unref (one);
- return two;
- } else {
- ViviCodeStatement *block = vivi_code_block_new ();
- vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), one);
- g_object_unref (one);
- vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), two);
- g_object_unref (two);
- return block;
- }
-}
-
-static ViviCodeValue *
-vivi_compiler_function_call_new (ViviCodeValue *name)
-{
- ViviCodeValue *value;
-
- g_return_val_if_fail (VIVI_IS_CODE_VALUE (name), NULL);
-
- value = NULL;
-
- if (VIVI_IS_CODE_GET (name)) {
- ViviCodeGet *get = VIVI_CODE_GET (name);
-
- if (get->from != NULL) {
- value = g_object_ref (get->from);
- name = g_object_ref (get->name);
- }
- }
-
- if (VIVI_IS_CODE_GET (name)) {
- ViviCodeGet *get = VIVI_CODE_GET (name);
-
- if (get->from == NULL)
- name = g_object_ref (get->name);
- }
-
- return vivi_code_function_call_new (value, name);
-}
-
-static ViviCodeStatement *
-vivi_compiler_assignment_new (ViviCodeValue *left, ViviCodeValue *right)
-{
- ViviCodeValue *from;
-
- g_return_val_if_fail (VIVI_IS_CODE_VALUE (left), NULL);
- g_return_val_if_fail (VIVI_IS_CODE_VALUE (right), NULL);
-
- from = NULL;
-
- if (VIVI_IS_CODE_GET (left)) {
- ViviCodeGet *get = VIVI_CODE_GET (left);
-
- if (get->from != NULL) {
- from = g_object_ref (get->from);
- left = g_object_ref (get->name);
- }
- }
-
- if (VIVI_IS_CODE_GET (left)) {
- ViviCodeGet *get = VIVI_CODE_GET (left);
-
- if (get->from == NULL)
- left = g_object_ref (get->name);
- }
-
- return vivi_code_assignment_new (from, left, right);
-}
-
-static ViviCodeValue *
-vivi_compiler_get_new (ViviCodeValue *from, ViviCodeValue *name)
-{
- g_return_val_if_fail (VIVI_IS_CODE_VALUE (from), NULL);
- g_return_val_if_fail (VIVI_IS_CODE_VALUE (name), NULL);
-
- if (VIVI_IS_CODE_GET (name)) {
- ViviCodeGet *get = VIVI_CODE_GET (name);
-
- if (get->from == NULL)
- name = g_object_ref (get->name);
- }
-
- return vivi_code_get_new (from, name);
-}
-
-static gboolean
-vivi_compiler_value_is_left_hand_side (ViviCodeValue *value)
-{
- // FIXME: Correct?
- return VIVI_IS_CODE_GET (value);
-}
-
-static gboolean
-vivi_compiler_value_is_identifier (ViviCodeValue *value)
-{
- if (!VIVI_IS_CODE_GET (value))
- return FALSE;
- return VIVI_IS_CODE_CONSTANT (VIVI_CODE_GET (value)->name);
-}
-
-static void
-vivi_compiler_start_level (ParseData *data)
-{
- g_return_if_fail (data != NULL);
-
- if (data->level != NULL)
- data->levels = g_slist_prepend (data->levels, data->level);
- data->level = g_new0 (ParseLevel, 1);
-}
-
-static ViviCodeLabel *
-vivi_compiler_find_label (ParseData *data, const char *name)
-{
- GSList *iter;
-
- for (iter = data->level->labels; iter != NULL; iter = iter->next) {
- if (g_str_equal (vivi_code_label_get_name (VIVI_CODE_LABEL (iter->data)),
- name))
- return VIVI_CODE_LABEL (iter->data);
- }
-
- return NULL;
-}
-
-static ParseStatus
-vivi_compiler_end_level (ParseData *data, gboolean fail)
-{
- GSList *iter;
- char *custom_error = NULL;
-
- g_return_val_if_fail (data != NULL, STATUS_FAIL);
- g_return_val_if_fail (data->level != NULL, STATUS_FAIL);
-
- for (iter = data->level->gotos; iter != NULL; iter = iter->next) {
- ViviCompilerGotoName *goto_;
- ViviCodeLabel *label;
-
- goto_ = VIVI_COMPILER_GOTO_NAME (iter->data);
- label = vivi_compiler_find_label (data,
- vivi_compiler_goto_name_get_name (goto_));
-
- if (label != NULL) {
- vivi_compiler_goto_name_set_label (goto_, label);
- } else {
- if (custom_error == NULL) {
- custom_error =
- g_strdup_printf ("Label named '%s' doesn't exist in this block",
- vivi_compiler_goto_name_get_name (goto_));
- }
- }
-
- g_object_unref (goto_);
- }
- g_slist_free (data->level->gotos);
-
- for (iter = data->level->labels; iter != NULL; iter = iter->next) {
- g_object_unref (VIVI_CODE_LABEL (iter->data));
- }
- g_slist_free (data->level->labels);
-
- g_free (data->level);
-
- if (data->levels != NULL) {
- data->level = data->levels->data;
- data->levels = g_slist_delete_link (data->levels, data->levels);
- } else {
- data->level = NULL;
- }
-
- if (custom_error != NULL) {
- if (fail) {
- return FAIL_CUSTOM (custom_error);
- } else {
- return STATUS_FAIL;
- }
- } else {
- return STATUS_OK;
- }
-}
-
-static void
-vivi_compiler_add_goto (ParseData *data, ViviCompilerGotoName *goto_)
-{
- g_return_if_fail (data != NULL);
- g_return_if_fail (data->level != NULL);
- g_return_if_fail (VIVI_IS_COMPILER_GOTO_NAME (goto_));
-
- data->level->gotos =
- g_slist_prepend (data->level->gotos, g_object_ref (goto_));
-}
-
-static gboolean
-vivi_compiler_add_label (ParseData *data, ViviCodeLabel *label)
-{
- GSList *iter;
-
- g_return_val_if_fail (data != NULL, FALSE);
- g_return_val_if_fail (data->level != NULL, FALSE);
- g_return_val_if_fail (VIVI_IS_CODE_LABEL (label), FALSE);
-
- for (iter = data->level->labels; iter != NULL; iter = iter->next) {
- if (g_str_equal (vivi_code_label_get_name (VIVI_CODE_LABEL (iter->data)),
- vivi_code_label_get_name (label)))
- return FALSE;
- }
-
- data->level->labels =
- g_slist_prepend (data->level->labels, g_object_ref (label));
-
- return TRUE;
-}
-
-// values
-
-/* ActionScript specific */
-static ParseStatus
-parse_undefined_literal (ParseData *data, ViviCodeValue **value)
-{
- *value = NULL;
-
- if (!check_token (data, TOKEN_UNDEFINED))
- return CANCEL (TOKEN_UNDEFINED);
-
- *value = vivi_code_constant_new_undefined ();
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_null_literal (ParseData *data, ViviCodeValue **value)
-{
- *value = NULL;
-
- if (!check_token (data, TOKEN_NULL))
- return CANCEL (TOKEN_NULL);
-
- *value = vivi_code_constant_new_null ();
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_boolean_literal (ParseData *data, ViviCodeValue **value)
-{
- *value = NULL;
-
- if (!check_token (data, TOKEN_BOOLEAN))
- return CANCEL (TOKEN_BOOLEAN);
-
- *value = vivi_code_constant_new_boolean (data->scanner->value.v_boolean);
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_numeric_literal (ParseData *data, ViviCodeValue **value)
-{
- *value = NULL;
-
- if (!check_token (data, TOKEN_NUMBER))
- return CANCEL (TOKEN_NUMBER);
-
- *value = vivi_code_constant_new_number (data->scanner->value.v_number);
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_string_literal (ParseData *data, ViviCodeValue **value)
-{
- *value = NULL;
-
- if (!check_token (data, TOKEN_STRING))
- return CANCEL (TOKEN_STRING);
-
- *value = vivi_code_constant_new_string (data->scanner->value.v_string);
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_literal (ParseData *data, ViviCodeValue **value)
-{
- ParseStatus status;
- int i;
- ParseValueFunction functions[] = {
- parse_undefined_literal,
- parse_null_literal,
- parse_boolean_literal,
- parse_numeric_literal,
- parse_string_literal,
- NULL
- };
-
- *value = NULL;
-
- for (i = 0; functions[i] != NULL; i++) {
- status = functions[i] (data, value);
- if (status != STATUS_CANCEL)
- return status;
- }
-
- return CANCEL (ERROR_TOKEN_LITERAL);
-}
-
-static ParseStatus
-parse_identifier (ParseData *data, ViviCodeValue **value)
-{
- *value = NULL;
-
- if (!check_token (data, TOKEN_IDENTIFIER))
- return CANCEL (TOKEN_IDENTIFIER);
-
- *value = vivi_code_get_new_name (data->scanner->value.v_identifier);
-
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_property_name (ParseData *data, ViviCodeValue **value)
-{
- ParseStatus status;
- int i;
- ParseValueFunction functions[] = {
- parse_identifier,
- parse_string_literal,
- parse_numeric_literal,
- NULL
- };
-
- *value = NULL;
-
- for (i = 0; functions[i] != NULL; i++) {
- status = functions[i] (data, value);
- if (status != STATUS_CANCEL)
- return status;
- }
-
- return CANCEL (ERROR_TOKEN_PROPERTY_NAME);
-}
-
-static ParseStatus
-parse_assignment_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement);
-
-static ParseStatus
-parse_array_literal (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
-{
- ViviCodeValue *member;
- ViviCodeStatement *statement_new;
- ParseStatus status;
-
- *value = NULL;
- *statement = NULL;
-
- if (!check_token (data, TOKEN_BRACKET_LEFT))
- return CANCEL (TOKEN_BRACKET_LEFT);
-
- *value = vivi_code_init_array_new ();
-
- while (TRUE) {
- if (check_token (data, TOKEN_BRACKET_RIGHT)) {
- vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
- vivi_code_constant_new_undefined ());
- break;
- } else if (check_token (data, TOKEN_COMMA)) {
- vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
- vivi_code_constant_new_undefined ());
- } else {
- status = parse_assignment_expression (data, &member, &statement_new);
- if (status != STATUS_OK) {
- if (*statement != NULL) {
- g_object_unref (*statement);
- *statement = NULL;
- }
- return FAIL_CHILD (status);
- }
-
- *statement = vivi_compiler_join_statements (*statement, statement_new);
-
- vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
- member);
- g_object_unref (member);
-
- if (!check_token (data, TOKEN_COMMA)) {
- if (!check_token (data, TOKEN_BRACKET_RIGHT)) {
- return FAIL_OR (TOKEN_BRACKET_RIGHT, TOKEN_COMMA);
- }
- break;
- }
- }
- }
-
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_object_literal (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
-{
- ParseStatus status;
-
- *value = NULL;
- *statement = NULL;
-
- if (!check_token (data, TOKEN_BRACE_LEFT))
- return CANCEL (TOKEN_BRACE_LEFT);
-
- *value = vivi_code_init_object_new ();
-
- if (!check_token (data, TOKEN_BRACE_RIGHT)) {
- do {
- ViviCodeValue *property, *initializer;
- ViviCodeStatement *statement_new;
-
- status = parse_property_name (data, &property);
- if (status != STATUS_OK) {
- g_object_unref (*value);
- *value = NULL;
- if (*statement != NULL) {
- g_object_unref (*statement);
- *statement = NULL;
- }
- return FAIL_CHILD (status);
- }
-
- if (!check_token (data, TOKEN_COLON)) {
- g_object_unref (*value);
- *value = NULL;
- if (*statement != NULL) {
- g_object_unref (*statement);
- *statement = NULL;
- }
- return FAIL (TOKEN_COLON);
- }
-
- status = parse_assignment_expression (data, &initializer,
- &statement_new);
- if (status != STATUS_OK) {
- g_object_unref (*value);
- *value = NULL;
- if (*statement != NULL) {
- g_object_unref (*statement);
- *statement = NULL;
- }
- return FAIL_CHILD (status);
- }
-
- *statement = vivi_compiler_join_statements (*statement, statement_new);
-
- vivi_code_init_object_add_variable (VIVI_CODE_INIT_OBJECT (*value),
- property, initializer);
- } while (check_token (data, TOKEN_COMMA));
- }
-
- if (!check_token (data, TOKEN_BRACE_RIGHT)) {
- g_object_unref (*value);
- *value = NULL;
- if (*statement != NULL) {
- g_object_unref (*statement);
- *statement = NULL;
- }
- return FAIL (TOKEN_BRACE_RIGHT);
- }
-
- return STATUS_OK;
-}
-
-// misc
-
-static ParseStatus
-parse_variable_declaration (ParseData *data, ViviCodeStatement **statement)
-{
- ParseStatus status;
- ViviCodeValue *identifier, *value;
- ViviCodeStatement *assignment, *statement_right;
-
- *statement = NULL;
-
- status = parse_identifier (data, &identifier);
- if (status != STATUS_OK)
- return status;
-
- if (check_token (data, TOKEN_ASSIGN)) {
- status = parse_assignment_expression (data, &value, &statement_right);
- if (status != STATUS_OK) {
- g_object_unref (identifier);
- return FAIL_CHILD (status);
- }
- } else {
- value = vivi_code_constant_new_undefined ();
- statement_right = NULL;
- }
-
- assignment = vivi_compiler_assignment_new (identifier, value);
- vivi_code_assignment_set_local (VIVI_CODE_ASSIGNMENT (assignment), TRUE);
-
- *statement = vivi_compiler_join_statements (statement_right, assignment);
-
- return STATUS_OK;
-}
-
-// expression
-
-static ParseStatus
-parse_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement);
-
-static ParseStatus
-parse_primary_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
-{
- ParseStatus status;
- int i;
- ParseValueFunction functions[] = {
- parse_identifier,
- parse_literal,
- NULL
- };
-
- *value = NULL;
- *statement = NULL;
-
- if (check_token (data, TOKEN_THIS)) {
- *value = vivi_code_get_new_name ("this");
- return STATUS_OK;
- }
-
- if (check_token (data, TOKEN_PARENTHESIS_LEFT)) {
- status = parse_expression (data, value, statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
- g_object_unref (*value);
- *value = NULL;
- return FAIL (TOKEN_PARENTHESIS_RIGHT);
- }
- return STATUS_OK;
- }
-
-
- status = parse_object_literal (data, value, statement);
- if (status != STATUS_CANCEL)
- return status;
-
- status = parse_array_literal (data, value, statement);
- if (status != STATUS_CANCEL)
- return status;
-
- for (i = 0; functions[i] != NULL; i++) {
- status = functions[i] (data, value);
- if (status != STATUS_CANCEL)
- return status;
- }
-
- return CANCEL (ERROR_TOKEN_PRIMARY_EXPRESSION);
-}
-
-static ParseStatus
-parse_function_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement);
-
-static ParseStatus
-parse_member_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
-{
- ParseStatus status;
- ViviCodeValue *member;
- ViviCodeStatement *statement_member;
-
- *value = NULL;
- *statement = NULL;
-
- // TODO: new MemberExpression Arguments
-
- status = parse_primary_expression (data, value, statement);
- if (status == STATUS_CANCEL)
- status = parse_function_expression (data, value, statement);
-
- if (status != STATUS_OK)
- return status;
-
- do {
- ViviCodeValue *tmp;
-
- if (check_token (data, TOKEN_BRACKET_LEFT)) {
- status = parse_expression (data, &member, &statement_member);
- if (status != STATUS_OK) {
- g_object_unref (*value);
- *value = NULL;
- if (*statement != NULL) {
- g_object_unref (*statement);
- *statement = NULL;
- }
- return FAIL_CHILD (status);
- }
-
- *statement =
- vivi_compiler_join_statements (*statement, statement_member);
-
- if (!check_token (data, TOKEN_BRACKET_RIGHT)) {
- g_object_unref (*value);
- *value = NULL;
- if (*statement != NULL) {
- g_object_unref (*statement);
- *statement = NULL;
- }
- return FAIL (TOKEN_BRACKET_RIGHT);
- }
- } else if (check_token (data, TOKEN_DOT)) {
- status = parse_identifier (data, &member);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
- } else {
- return STATUS_OK;
- }
-
- tmp = *value;
- *value = vivi_compiler_get_new (tmp, member);
- g_object_unref (tmp);
- g_object_unref (member);
- } while (TRUE);
-
- g_assert_not_reached ();
-}
-
-static ParseStatus
-parse_new_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
-{
- ParseStatus status;
-
- *value = NULL;
- *statement = NULL;
-
- if (check_token (data, TOKEN_NEW)) {
- status = parse_new_expression (data, value, statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
- if (!VIVI_IS_CODE_FUNCTION_CALL (*value)) {
- ViviCodeValue *tmp = VIVI_CODE_VALUE (*value);
- *value = vivi_compiler_function_call_new (tmp);
- g_object_unref (tmp);
- }
- vivi_code_function_call_set_construct (VIVI_CODE_FUNCTION_CALL (*value),
- TRUE);
- return STATUS_OK;
- } else {
- return parse_member_expression (data, value, statement);
- }
-}
-
-static ParseStatus
-parse_left_hand_side_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
-{
- ParseStatus status;
- int i;
- ViviCodeValue *name;
- ViviCodeValue **arguments;
- ViviCodeStatement *argument_statement;
-
- *value = NULL;
- *statement = NULL;
-
- if (check_token (data, TOKEN_NEW)) {
- status = parse_new_expression (data, value, statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
- if (!VIVI_IS_CODE_FUNCTION_CALL (*value)) {
- ViviCodeValue *tmp = VIVI_CODE_VALUE (*value);
- *value = vivi_compiler_function_call_new (tmp);
- g_object_unref (tmp);
- }
- vivi_code_function_call_set_construct (VIVI_CODE_FUNCTION_CALL (*value),
- TRUE);
- return STATUS_OK;
- }
-
- status = parse_member_expression (data, value, statement);
- if (status != STATUS_OK)
- return status;
-
- while (TRUE) {
- // TODO: member expressions?
- if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
- break;
-
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
- status = parse_value_statement_list (data, parse_assignment_expression,
- &arguments, &argument_statement, TOKEN_COMMA);
- if (status != STATUS_OK) {
- g_object_unref (*value);
- *value = NULL;
- if (*statement != NULL) {
- g_object_unref (*statement);
- *statement = NULL;
- }
- return FAIL_CHILD (status);
- }
-
- *statement =
- vivi_compiler_join_statements (*statement, argument_statement);
-
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
- g_object_unref (*value);
- *value = NULL;
- if (*statement != NULL) {
- g_object_unref (*statement);
- *statement = NULL;
- }
- return FAIL (TOKEN_PARENTHESIS_RIGHT);
- }
- } else {
- arguments = NULL;
- }
-
- name = *value;
- *value = vivi_compiler_function_call_new (name);
- g_object_unref (name);
-
- if (arguments != NULL) {
- for (i = 0; arguments[i] != NULL; i++) {
- vivi_code_function_call_add_argument (VIVI_CODE_FUNCTION_CALL (*value),
- arguments[i]);
- }
- free_value_list (arguments);
- }
- }
-
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_postfix_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
-{
- ParseStatus status;
- ViviCodeValue *operation, *one, *temporary;
- const char *operator;
-
- *value = NULL;
- *statement = NULL;
-
- status = parse_left_hand_side_expression (data, value, statement);
- if (status != STATUS_OK)
- return status;
-
- if (check_line_terminator (data))
- return status;
-
- if (check_token (data, TOKEN_INCREASE)) {
- operator = "+";
- } else if (check_token (data, TOKEN_DESCREASE)) {
- operator = "-";
- } else {
- return STATUS_OK;
- }
-
- if (!vivi_compiler_value_is_left_hand_side (*value)) {
- g_object_unref (*value);
- *value = NULL;
- if (*statement != NULL) {
- g_object_unref (*statement);
- *statement = NULL;
- }
- return CANCEL_CUSTOM (g_strdup ("INCREASE/DECREASE not allowed here"));
- }
-
- one = vivi_code_constant_new_number (1);
- operation = vivi_code_binary_new_name (*value, one, operator);
- g_object_unref (one);
-
- temporary = vivi_compiler_get_temporary_new ();
- *statement = vivi_compiler_join_statements (*statement,
- vivi_compiler_join_statements (
- vivi_compiler_assignment_new (temporary, *value),
- vivi_compiler_assignment_new (*value, operation)));
- g_object_unref (operation);
-
- g_object_unref (*value);
- *value = temporary;
-
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_unary_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
-{
- ParseStatus status;
- ViviCodeValue *tmp, *one;
- const char *operator;
-
- *value = NULL;
-
- operator = NULL;
-
- vivi_compiler_scanner_peek_next_token (data->scanner);
- switch ((guint)data->scanner->next_token) {
- /*case TOKEN_DELETE:
- case TOKEN_VOID:
- case TOKEN_TYPEOF:*/
- case TOKEN_INCREASE:
- operator = "+";
- // fall through
- case TOKEN_DESCREASE:
- if (!operator) operator = "-";
-
- vivi_compiler_scanner_get_next_token (data->scanner);
- status = parse_unary_expression (data, value, statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
-
- if (!vivi_compiler_value_is_left_hand_side (*value))
- return CANCEL_CUSTOM (g_strdup ("INCREASE/DECREASE not allowed here"));
-
- one = vivi_code_constant_new_number (1);
- tmp = vivi_code_binary_new_name (*value, one, operator);
- g_object_unref (one);
-
- *statement = vivi_compiler_join_statements (*statement,
- vivi_compiler_assignment_new (*value, tmp));
- g_object_unref (tmp);
-
- return STATUS_OK;
- /*case TOKEN_PLUS:
- case TOKEN_MINUS:
- case TOKEN_BITWISE_NOT:*/
- case TOKEN_LOGICAL_NOT:
- vivi_compiler_scanner_get_next_token (data->scanner);
- status = parse_unary_expression (data, value, statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
- tmp = VIVI_CODE_VALUE (*value);
- *value = vivi_code_unary_new (tmp, '!');
- g_object_unref (tmp);
- return STATUS_OK;
- default:
- return parse_postfix_expression (data, value, statement);
- }
-}
-
-typedef enum {
- PASS_ALWAYS,
- PASS_LOGICAL_OR,
- PASS_LOGICAL_AND
-} ParseOperatorPass;
-
-static ParseStatus
-parse_operator_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement, const ViviCompilerScannerToken *tokens,
- ParseOperatorPass pass, ParseValueStatementFunction next_parse_function)
-{
- ParseStatus status;
- int i;
- ViviCodeValue *left, *right;
- ViviCodeStatement *statement_right;
-
- *value = NULL;
- *statement = NULL;
-
- status = next_parse_function (data, value, statement);
- if (status != STATUS_OK)
- return status;
-
- for (i = 0; tokens[i] != STATUS_OK; i++) {
- while (check_token (data, tokens[i])) {
- status = next_parse_function (data, &right, &statement_right);
- if (status != STATUS_OK) {
- g_object_unref (*value);
- *value = NULL;
- return FAIL_CHILD (status);
- }
-
- if (statement_right != NULL) {
- ViviCodeStatement *tmp;
-
- switch (pass) {
- case PASS_LOGICAL_OR:
- tmp = vivi_code_if_new (vivi_code_unary_new (*value, '!'));
- vivi_code_if_set_if (VIVI_CODE_IF (tmp), statement_right);
- g_object_unref (statement_right);
- statement_right = tmp;
- break;
- case PASS_LOGICAL_AND:
- tmp = vivi_code_if_new (*value);
- vivi_code_if_set_if (VIVI_CODE_IF (tmp), statement_right);
- g_object_unref (statement_right);
- statement_right = tmp;
- break;
- case PASS_ALWAYS:
- // nothing
- break;
- default:
- g_assert_not_reached ();
- }
-
- *statement =
- vivi_compiler_join_statements (*statement, statement_right);
- }
-
- left = VIVI_CODE_VALUE (*value);
- *value = vivi_code_binary_new_name (left, VIVI_CODE_VALUE (right),
- vivi_compiler_scanner_token_name (tokens[i]));
- g_object_unref (left);
- g_object_unref (right);
- };
- }
-
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_multiplicative_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
-{
- static const ViviCompilerScannerToken tokens[] = { TOKEN_MULTIPLY,
- TOKEN_DIVIDE, TOKEN_REMAINDER, TOKEN_NONE };
-
- return parse_operator_expression (data, value, statement, tokens,
- PASS_ALWAYS, parse_unary_expression);
-}
-
-static ParseStatus
-parse_additive_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
-{
- static const ViviCompilerScannerToken tokens[] = { TOKEN_PLUS, TOKEN_MINUS,
- TOKEN_NONE };
-
- return parse_operator_expression (data, value, statement, tokens,
- PASS_ALWAYS, parse_multiplicative_expression);
-}
-
-static ParseStatus
-parse_shift_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
-{
- static const ViviCompilerScannerToken tokens[] = { TOKEN_SHIFT_LEFT,
- TOKEN_SHIFT_RIGHT, TOKEN_SHIFT_RIGHT_UNSIGNED, TOKEN_NONE };
-
- return parse_operator_expression (data, value, statement, tokens,
- PASS_ALWAYS, parse_additive_expression);
-}
-
-static ParseStatus
-parse_relational_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
-{
- static const ViviCompilerScannerToken tokens[] = { TOKEN_LESS_THAN,
- TOKEN_GREATER_THAN, /*TOKEN_LESS_THAN_OR_EQUAL,
- TOKEN_EQUAL_OR_GREATER_THAN, TOKEN_INSTANCEOF, TOKEN_IN,*/ TOKEN_NONE };
-
- return parse_operator_expression (data, value, statement, tokens,
- PASS_ALWAYS, parse_shift_expression);
-}
-
-static ParseStatus
-parse_equality_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
-{
- static const ViviCompilerScannerToken tokens[] = { TOKEN_EQUAL,
- /*TOKEN_NOT_EQUAL,*/ TOKEN_STRICT_EQUAL, /*TOKEN_NOT_STRICT_EQUAL,*/
- TOKEN_NONE };
-
- return parse_operator_expression (data, value, statement, tokens,
- PASS_ALWAYS, parse_relational_expression);
-}
-
-static ParseStatus
-parse_bitwise_and_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
-{
- static const ViviCompilerScannerToken tokens[] = { TOKEN_BITWISE_AND,
- TOKEN_NONE };
-
- return parse_operator_expression (data, value, statement, tokens,
- PASS_ALWAYS, parse_equality_expression);
-}
-
-static ParseStatus
-parse_bitwise_xor_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
-{
- static const ViviCompilerScannerToken tokens[] = { TOKEN_BITWISE_XOR,
- TOKEN_NONE };
-
- return parse_operator_expression (data, value, statement, tokens,
- PASS_ALWAYS, parse_bitwise_and_expression);
-}
-
-static ParseStatus
-parse_bitwise_or_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
-{
- static const ViviCompilerScannerToken tokens[] = { TOKEN_BITWISE_OR,
- TOKEN_NONE };
-
- return parse_operator_expression (data, value, statement, tokens,
- PASS_ALWAYS, parse_bitwise_xor_expression);
-}
-
-static ParseStatus
-parse_logical_and_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
-{
- static const ViviCompilerScannerToken tokens[] = { TOKEN_LOGICAL_AND,
- TOKEN_NONE };
-
- return parse_operator_expression (data, value, statement, tokens,
- PASS_LOGICAL_AND, parse_bitwise_or_expression);
-}
-
-static ParseStatus
-parse_logical_or_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
-{
- static const ViviCompilerScannerToken tokens[] = { TOKEN_LOGICAL_OR,
- TOKEN_NONE };
-
- return parse_operator_expression (data, value, statement, tokens,
- PASS_LOGICAL_OR, parse_logical_and_expression);
-}
-
-static ParseStatus
-parse_conditional_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
-{
- ParseStatus status;
- //ViviCodeStatement *if_statement, *else_statement;
-
- *value = NULL;
-
- status = parse_logical_or_expression (data, value, statement);
- if (status != STATUS_OK)
- return status;
-
-#if 0
- if (!check_token (data, TOKEN_QUESTION_MARK)) {
- *statement = vivi_code_value_statement_new (VIVI_CODE_VALUE (value));
- g_object_unref (value);
- return STATUS_OK;
- }
-
- status = parse_assignment_expression (data, &if_statement);
- if (status != STATUS_OK) {
- g_object_unref (value);
- return FAIL_CHILD (status);
- }
-
- if (!check_token (data, TOKEN_COLON)) {
- g_object_unref (value);
- g_object_unref (if_statement);
- return TOKEN_COLON;
- }
-
- status = parse_assignment_expression (data, &else_statement);
- if (status != STATUS_OK) {
- g_object_unref (value);
- g_object_unref (if_statement);
- return FAIL_CHILD (status);
- }
-
- *statement = vivi_code_if_new (value);
- vivi_code_if_set_if (VIVI_CODE_IF (*statement), if_statement);
- vivi_code_if_set_else (VIVI_CODE_IF (*statement), else_statement);
-
- g_object_unref (value);
- g_object_unref (if_statement);
- g_object_unref (else_statement);
-#endif
-
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_assignment_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
-{
- ParseStatus status;
- ViviCodeValue *right;
- ViviCodeStatement *assignment, *statement_right;
- const char *operator;
-
- *value = NULL;
- *statement = NULL;
-
- status = parse_conditional_expression (data, value, statement);
- if (status != STATUS_OK)
- return status;
-
- if (!vivi_compiler_value_is_left_hand_side (*value))
- return STATUS_OK;
-
- operator = NULL;
-
- vivi_compiler_scanner_peek_next_token (data->scanner);
- switch ((int)data->scanner->next_token) {
- case TOKEN_ASSIGN_MULTIPLY:
- if (operator == NULL) operator = "*";
- case TOKEN_ASSIGN_DIVIDE:
- if (operator == NULL) operator = "/";
- case TOKEN_ASSIGN_REMAINDER:
- if (operator == NULL) operator = "%";
- case TOKEN_ASSIGN_ADD:
- if (operator == NULL) operator = "+";
- case TOKEN_ASSIGN_MINUS:
- if (operator == NULL) operator = "-";
- case TOKEN_ASSIGN_SHIFT_LEFT:
- if (operator == NULL) operator = "<<";
- case TOKEN_ASSIGN_SHIFT_RIGHT:
- if (operator == NULL) operator = ">>";
- case TOKEN_ASSIGN_SHIFT_RIGHT_ZERO:
- if (operator == NULL) operator = ">>>";
- case TOKEN_ASSIGN_BITWISE_AND:
- if (operator == NULL) operator = "&";
- case TOKEN_ASSIGN_BITWISE_OR:
- if (operator == NULL) operator = "|";
- case TOKEN_ASSIGN_BITWISE_XOR:
- if (operator == NULL) operator = "^";
- case TOKEN_ASSIGN:
- vivi_compiler_scanner_get_next_token (data->scanner);
- status = parse_assignment_expression (data, &right,
- &statement_right);
- if (status != STATUS_OK) {
- g_object_unref (*value);
- *value = NULL;
- return FAIL_CHILD (status);
- }
-
- if (operator != NULL) {
- assignment = vivi_compiler_assignment_new (*value,
- vivi_code_binary_new_name (*value, right, operator));
- } else {
- assignment = vivi_compiler_assignment_new (*value, right);
- }
- g_object_unref (right);
-
- *statement = vivi_compiler_join_statements (*statement,
- vivi_compiler_join_statements (statement_right, assignment));
-
- break;
- default:
- return STATUS_OK;
- }
-
-
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
-{
- ViviCodeStatement *statement_one;
- ParseStatus status;
-
- *statement = NULL;
-
- status = parse_assignment_expression (data, value, &statement_one);
- if (status != STATUS_OK)
- return status;
-
- while (TRUE) {
- *statement = vivi_compiler_join_statements (*statement, statement_one);
-
- if (!check_token (data, TOKEN_COMMA))
- break;
-
- g_object_unref (*value);
-
- status = parse_assignment_expression (data, value, &statement_one);
- if (status != STATUS_OK) {
- g_object_unref (*value);
- *value = NULL;
- g_object_unref (*statement);
- *statement = NULL;
- return FAIL_CHILD (status);
- }
- }
-
- return STATUS_OK;
-}
-
-// statement
-
-static ParseStatus
-parse_statement (ParseData *data, ViviCodeStatement **statement);
-
-static ParseStatus
-parse_trace_statement (ParseData *data, ViviCodeStatement **statement)
-{
- ViviCodeValue *value;
- ViviCodeStatement *expression_statement;
- ParseStatus status;
-
- *statement = NULL;
-
- if (!check_token (data, TOKEN_TRACE))
- return CANCEL (TOKEN_TRACE);
-
- if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
- return FAIL (TOKEN_PARENTHESIS_LEFT);
-
- status = parse_expression (data, &value, &expression_statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
-
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
- g_object_unref (value);
- if (expression_statement != NULL)
- g_object_unref (expression_statement);
- return FAIL (TOKEN_PARENTHESIS_RIGHT);
- }
-
- if (!check_automatic_semicolon (data)) {
- g_object_unref (value);
- if (expression_statement != NULL)
- g_object_unref (expression_statement);
- return FAIL (TOKEN_SEMICOLON);
- }
-
- *statement = vivi_code_trace_new (value);
- g_object_unref (value);
-
- *statement =
- vivi_compiler_join_statements (expression_statement, *statement);
-
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_continue_or_break_statement (ParseData *data,
- ViviCodeStatement **statement, ViviCompilerScannerToken token)
-{
- *statement = NULL;
-
- if (!check_token (data, token))
- return CANCEL (token);
-
- if (!check_restricted_semicolon (data)) {
- ParseStatus status;
- ViviCodeValue *identifier;
-
- status = parse_identifier (data, &identifier);
- *statement = vivi_compiler_goto_name_new (
- vivi_code_constant_get_variable_name (
- VIVI_CODE_CONSTANT (VIVI_CODE_GET (identifier)->name)));
- g_object_unref (identifier);
-
- vivi_compiler_add_goto (data, VIVI_COMPILER_GOTO_NAME (*statement));
-
- if (!check_automatic_semicolon (data)) {
- g_object_unref (*statement);
- *statement = NULL;
- return FAIL (TOKEN_SEMICOLON);
- }
- } else {
- *statement = vivi_code_break_new ();
- }
-
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_continue_statement (ParseData *data, ViviCodeStatement **statement)
-{
- return parse_continue_or_break_statement (data, statement, TOKEN_CONTINUE);
-}
-
-static ParseStatus
-parse_break_statement (ParseData *data, ViviCodeStatement **statement)
-{
- return parse_continue_or_break_statement (data, statement, TOKEN_BREAK);
-}
-
-static ParseStatus
-parse_throw_statement (ParseData *data, ViviCodeStatement **statement)
-{
- ParseStatus status;
- ViviCodeValue *value;
- ViviCodeStatement *expression_statement;
-
- *statement = NULL;
-
- if (!check_token (data, TOKEN_THROW))
- return CANCEL (TOKEN_THROW);
-
- if (check_line_terminator (data))
- return FAIL_LINE_TERMINATOR (ERROR_TOKEN_EXPRESSION);
-
- status = parse_expression (data, &value, &expression_statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
-
- *statement = vivi_code_throw_new (value);
- g_object_unref (value);
-
- *statement =
- vivi_compiler_join_statements (expression_statement, *statement);
-
- if (!check_automatic_semicolon (data)) {
- g_object_unref (*statement);
- *statement = NULL;
- return FAIL (TOKEN_SEMICOLON);
- }
-
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_return_statement (ParseData *data, ViviCodeStatement **statement)
-{
- *statement = NULL;
-
- if (!check_token (data, TOKEN_RETURN))
- return CANCEL (TOKEN_RETURN);
-
- *statement = vivi_code_return_new ();
-
- if (!check_restricted_semicolon (data)) {
- ParseStatus status;
- ViviCodeValue *value;
- ViviCodeStatement *expression_statement;
-
- status = parse_expression (data, &value, &expression_statement);
- if (status != STATUS_OK) {
- g_object_unref (*statement);
- *statement = NULL;
- return FAIL_CHILD (status);
- }
-
- vivi_code_return_set_value (VIVI_CODE_RETURN (*statement), value);
- g_object_unref (value);
-
- *statement =
- vivi_compiler_join_statements (expression_statement, *statement);
-
- if (!check_automatic_semicolon (data)) {
- g_object_unref (*statement);
- *statement = NULL;
- return FAIL (TOKEN_SEMICOLON);
- }
- }
-
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
-{
- ParseStatus status;
- ViviCodeValue *condition;
- ViviCodeStatement *pre_statement, *condition_statement, *loop_statement;
-
- *statement = NULL;
-
- pre_statement = NULL;
- condition_statement = NULL;
-
- if (check_token (data, TOKEN_DO)) {
- status = parse_statement (data, &loop_statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
-
- if (!check_token (data, TOKEN_WHILE)) {
- g_object_unref (loop_statement);
- return FAIL (TOKEN_WHILE);
- }
-
- if (!check_token (data, TOKEN_PARENTHESIS_LEFT)) {
- g_object_unref (loop_statement);
- return FAIL (TOKEN_PARENTHESIS_LEFT);
- }
-
- status = parse_expression (data, &condition, &condition_statement);
- if (status != STATUS_OK) {
- g_object_unref (loop_statement);
- return FAIL_CHILD (status);
- }
-
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
- g_object_unref (loop_statement);
- g_object_unref (condition);
- if (condition_statement != NULL)
- g_object_unref (condition_statement);
- return FAIL (TOKEN_PARENTHESIS_LEFT);
- }
-
- if (!check_automatic_semicolon (data)) {
- g_object_unref (loop_statement);
- g_object_unref (condition);
- if (condition_statement != NULL)
- g_object_unref (condition_statement);
- return FAIL (TOKEN_PARENTHESIS_LEFT);
- }
-
- pre_statement = g_object_ref (loop_statement);
- } else if (check_token (data, TOKEN_WHILE)) {
- if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
- return FAIL (TOKEN_PARENTHESIS_LEFT);
-
- status = parse_expression (data, &condition, &condition_statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
-
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
- g_object_unref (condition);
- if (condition_statement != NULL)
- g_object_unref (condition_statement);
- return FAIL (TOKEN_PARENTHESIS_RIGHT);
- }
-
- status = parse_statement (data, &loop_statement);
- if (status != STATUS_OK) {
- g_object_unref (condition);
- if (condition_statement != NULL)
- g_object_unref (condition_statement);
- return FAIL_CHILD (status);
- }
- } else if (check_token (data, TOKEN_FOR)) {
- ViviCodeValue *pre_value;
- ViviCodeStatement *post_statement;
-
- if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
- return FAIL (TOKEN_PARENTHESIS_LEFT);
-
- if (check_token (data, TOKEN_VAR)) {
- // FIXME: no in
- status = parse_statement_list (data, parse_variable_declaration,
- &pre_statement, TOKEN_COMMA);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
- // FIXME: ugly
- // If there was only one VariableDeclaration, get the name for pre_value
- g_assert (VIVI_IS_CODE_BLOCK (pre_statement));
- if (vivi_code_block_get_n_statements (VIVI_CODE_BLOCK (pre_statement))
- == 1) {
- ViviCodeAssignment *assignment = VIVI_CODE_ASSIGNMENT (
- vivi_code_block_get_statement (VIVI_CODE_BLOCK (pre_statement), 0));
- g_assert (assignment->from == NULL);
- pre_value = vivi_code_get_new (NULL, assignment->name);
- } else {
- pre_value = NULL;
- }
- } else {
- if (!check_token (data, TOKEN_SEMICOLON)) {
- // FIXME: no in
- status = parse_expression (data, &pre_value, &pre_statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
- } else {
- pre_value = NULL;
- pre_statement = NULL;
- }
- }
-
- if (check_token (data, TOKEN_SEMICOLON)) {
- if (pre_value != NULL)
- g_object_unref (pre_value);
- if (!check_token (data, TOKEN_SEMICOLON)) {
- status = parse_expression (data, &condition, &condition_statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
-
- if (!check_token (data, TOKEN_SEMICOLON)) {
- if (pre_statement != NULL)
- g_object_unref (pre_statement);
- g_object_unref (condition);
- if (condition_statement != NULL)
- g_object_unref (condition_statement);
- return FAIL (TOKEN_SEMICOLON);
- }
- }
-
- status = parse_expression (data, &pre_value, &post_statement);
- if (status != STATUS_OK) {
- if (pre_statement != NULL)
- g_object_unref (pre_statement);
- g_object_unref (condition);
- if (condition_statement != NULL)
- g_object_unref (condition_statement);
- return FAIL_CHILD (status);
- }
- g_object_unref (pre_value);
- } else if (pre_value != NULL && check_token (data, TOKEN_IN)) {
- post_statement = NULL;
-
- if (!vivi_compiler_value_is_left_hand_side (pre_value)) {
- g_object_unref (pre_value);
- if (pre_statement != NULL)
- g_object_unref (pre_statement);
- return FAIL_CUSTOM (g_strdup (
- "Invalid left hand side expression for in"));
- }
-
- g_object_unref (pre_value);
- if (pre_statement != NULL)
- g_object_unref (pre_statement);
- return FAIL_CUSTOM (g_strdup (
- "for (... in ...) has not been implemented yet"));
- } else {
- ViviCompilerScannerToken fail_token;
-
- if (pre_value != NULL) {
- fail_token = TOKEN_IN;
- g_object_unref (pre_value);
- } else {
- fail_token = TOKEN_NONE;
- }
-
- if (pre_statement != NULL)
- g_object_unref (pre_statement);
-
- return FAIL_OR (TOKEN_SEMICOLON, fail_token);
- }
-
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
- if (pre_statement != NULL)
- g_object_unref (pre_statement);
- g_object_unref (condition);
- if (condition_statement != NULL)
- g_object_unref (condition_statement);
- g_object_unref (post_statement);
- return FAIL (TOKEN_PARENTHESIS_RIGHT);
- }
-
- status = parse_statement (data, &loop_statement);
- if (status != STATUS_OK) {
- if (pre_statement != NULL)
- g_object_unref (pre_statement);
- g_object_unref (condition);
- if (condition_statement != NULL)
- g_object_unref (condition_statement);
- g_object_unref (post_statement);
- return FAIL_CHILD (status);
- }
-
- loop_statement =
- vivi_compiler_join_statements (loop_statement, post_statement);
- } else {
- return CANCEL (ERROR_TOKEN_ITERATION_STATEMENT);
- }
-
- if (condition_statement != NULL) {
- pre_statement = vivi_compiler_join_statements (pre_statement,
- g_object_ref (condition_statement));
- loop_statement = vivi_compiler_join_statements (loop_statement,
- g_object_ref (condition_statement));
- g_object_unref (condition_statement);
- }
-
- *statement = vivi_code_loop_new ();
- vivi_code_loop_set_condition (VIVI_CODE_LOOP (*statement), condition);
- g_object_unref (condition);
- vivi_code_loop_set_statement (VIVI_CODE_LOOP (*statement), loop_statement);
- g_object_unref (loop_statement);
-
- *statement = vivi_compiler_join_statements (pre_statement, *statement);
-
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_if_statement (ParseData *data, ViviCodeStatement **statement)
-{
- ParseStatus status;
- ViviCodeValue *condition;
- ViviCodeStatement *pre_statement, *if_statement, *else_statement;
-
- *statement = NULL;
-
- if (!check_token (data, TOKEN_IF))
- return CANCEL (TOKEN_IF);
-
- if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
- return FAIL (TOKEN_PARENTHESIS_LEFT);
-
- status = parse_expression (data, &condition, &pre_statement);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
-
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
- g_object_unref (condition);
- if (pre_statement != NULL) {
- g_object_unref (pre_statement);
- pre_statement = NULL;
- }
- return FAIL (TOKEN_PARENTHESIS_RIGHT);
- }
-
- status = parse_statement (data, &if_statement);
- if (status != STATUS_OK) {
- g_object_unref (condition);
- if (pre_statement != NULL) {
- g_object_unref (pre_statement);
- pre_statement = NULL;
- }
- return FAIL_CHILD (status);
- }
-
- if (check_token (data, TOKEN_ELSE)) {
- status = parse_statement (data, &else_statement);
- if (status != STATUS_OK) {
- g_object_unref (condition);
- if (pre_statement != NULL) {
- g_object_unref (pre_statement);
- pre_statement = NULL;
- }
- g_object_unref (if_statement);
- return FAIL_CHILD (status);
- }
- } else {
- else_statement = NULL;
- }
-
- *statement = vivi_code_if_new (condition);
- g_object_unref (condition);
-
- vivi_code_if_set_if (VIVI_CODE_IF (*statement), if_statement);
- g_object_unref (if_statement);
-
- if (else_statement != NULL) {
- vivi_code_if_set_else (VIVI_CODE_IF (*statement), else_statement);
- g_object_unref (else_statement);
- }
-
- *statement = vivi_compiler_join_statements (pre_statement, *statement);
-
- g_assert (*statement != NULL);
-
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_expression_statement (ParseData *data, ViviCodeStatement **statement)
-{
- ParseStatus status;
- ViviCodeValue *value;
- ViviCodeStatement *last;
-
- *statement = NULL;
-
- vivi_compiler_scanner_peek_next_token (data->scanner);
- if (data->scanner->next_token == TOKEN_BRACE_LEFT ||
- data->scanner->next_token == TOKEN_FUNCTION)
- return CANCEL (ERROR_TOKEN_EXPRESSION_STATEMENT);
-
- status = parse_expression (data, &value, statement);
- if (status != STATUS_OK)
- return status;
-
- // check for label
- if (*statement == NULL && vivi_compiler_value_is_identifier (value)) {
- if (check_token (data, TOKEN_COLON)) {
- *statement = vivi_code_label_new (vivi_code_constant_get_variable_name (
- VIVI_CODE_CONSTANT (VIVI_CODE_GET (value)->name)));
- if (!vivi_compiler_add_label (data, VIVI_CODE_LABEL (*statement)))
- return FAIL_CUSTOM (g_strdup ("Same label name used twice"));
- return STATUS_OK;
- }
- }
-
- if (!check_automatic_semicolon (data)) {
- g_object_unref (value);
- if (*statement != NULL) {
- g_object_unref (*statement);
- *statement = NULL;
- }
- return FAIL (TOKEN_SEMICOLON);
- }
-
- // add a value statement, if the last statement is not an assignment with the
- // same value
- if (VIVI_IS_CODE_BLOCK (*statement)) {
- ViviCodeBlock *block = VIVI_CODE_BLOCK (*statement);
-
- last = vivi_code_block_get_statement (block,
- vivi_code_block_get_n_statements (block) - 1);
- } else {
- last = *statement;
- }
-
- if (VIVI_IS_CODE_ASSIGNMENT (last) && VIVI_IS_CODE_GET (value)) {
- ViviCodeAssignment *assignment = VIVI_CODE_ASSIGNMENT (last);
-
- if (assignment->from == NULL && assignment->name == VIVI_CODE_GET (value)->name) {
- g_object_unref (value);
- return STATUS_OK;
- }
- }
-
- *statement = vivi_compiler_join_statements (*statement,
- vivi_code_value_statement_new (value));
- g_object_unref (value);
-
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_empty_statement (ParseData *data, ViviCodeStatement **statement)
-{
- *statement = NULL;
-
- if (!check_token (data, TOKEN_SEMICOLON))
- return CANCEL (TOKEN_SEMICOLON);
-
- *statement = vivi_compiler_empty_statement_new ();
-
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_block (ParseData *data, ViviCodeStatement **statement)
-{
- ParseStatus status;
-
- *statement = NULL;
-
- if (!check_token (data, TOKEN_BRACE_LEFT))
- return CANCEL (TOKEN_BRACE_LEFT);
-
- vivi_compiler_scanner_peek_next_token (data->scanner);
- if (data->scanner->next_token != TOKEN_BRACE_RIGHT) {
- status =
- parse_statement_list (data, parse_statement, statement, STATUS_OK);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
- } else {
- *statement = vivi_code_block_new ();
- }
-
- if (!check_token (data, TOKEN_BRACE_RIGHT)) {
- g_object_unref (*statement);
- *statement = NULL;
- return FAIL (TOKEN_BRACE_RIGHT);
- }
-
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_variable_statement (ParseData *data, ViviCodeStatement **statement)
-{
- ParseStatus status;
-
- *statement = NULL;
-
- if (!check_token (data, TOKEN_VAR))
- return CANCEL (TOKEN_VAR);
-
- status = parse_statement_list (data, parse_variable_declaration, statement,
- TOKEN_COMMA);
- if (status != STATUS_OK)
- return FAIL_CHILD (status);
-
- if (!check_automatic_semicolon (data)) {
- g_object_unref (*statement);
- *statement = NULL;
- return FAIL (TOKEN_SEMICOLON);
- }
-
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_statement (ParseData *data, ViviCodeStatement **statement)
-{
- ParseStatus status;
- int i;
- ParseStatementFunction functions[] = {
- parse_block,
- parse_variable_statement,
- parse_empty_statement,
- parse_expression_statement,
- parse_if_statement,
- parse_iteration_statement,
- parse_continue_statement,
- parse_break_statement,
- parse_return_statement,
- //parse_with_statement,
- //parse_switch_statement,
- parse_throw_statement,
- //parse_try_statement,
- parse_trace_statement,
- NULL
- };
-
- *statement = NULL;
-
- for (i = 0; functions[i] != NULL; i++) {
- status = functions[i] (data, statement);
- if (status != STATUS_CANCEL)
- return status;
- }
-
- return CANCEL (ERROR_TOKEN_STATEMENT);
-}
-
-// function
-
-static ParseStatus
-parse_source_element (ParseData *data, ViviCodeStatement **statement);
-
-static ParseStatus
-parse_function_definition (ParseData *data, ViviCodeValue **function,
- ViviCodeValue **identifier, gboolean identifier_required)
-{
- ParseStatus status;
- ViviCodeValue **arguments;
- ViviCodeStatement *body;
- guint i;
-
- *function = NULL;
- *identifier = NULL;
-
- arguments = NULL;
- body = NULL;
-
- if (!check_token (data, TOKEN_FUNCTION))
- return CANCEL (TOKEN_FUNCTION);
-
- status = parse_identifier (data, identifier);
- if (status == STATUS_FAIL ||
- (identifier_required && status == STATUS_CANCEL))
- return FAIL_CHILD (status);
-
- if (!check_token (data, TOKEN_PARENTHESIS_LEFT)) {
- g_object_unref (*identifier);
- return FAIL (TOKEN_PARENTHESIS_LEFT);
- }
-
- status = parse_value_list (data, parse_identifier, &arguments, TOKEN_COMMA);
- if (status == STATUS_FAIL) {
- g_object_unref (*identifier);
- return STATUS_FAIL;
- }
-
- if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
- g_object_unref (*identifier);
- if (arguments != NULL)
- free_value_list (arguments);
- return FAIL (TOKEN_PARENTHESIS_RIGHT);
- }
-
- if (!check_token (data, TOKEN_BRACE_LEFT)) {
- g_object_unref (*identifier);
- if (arguments != NULL)
- free_value_list (arguments);
- return FAIL (TOKEN_BRACE_LEFT);
- }
-
- vivi_compiler_start_level (data);
-
- status = parse_statement_list (data, parse_source_element, &body, STATUS_OK);
- if (status == STATUS_FAIL) {
- vivi_compiler_end_level (data, FALSE);
- g_object_unref (*identifier);
- if (arguments != NULL)
- free_value_list (arguments);
- return STATUS_FAIL;
- }
-
- status = vivi_compiler_end_level (data, TRUE);
- if (status != STATUS_OK) {
- g_object_unref (*identifier);
- if (arguments != NULL)
- free_value_list (arguments);
- return FAIL_CHILD (status);
- }
-
- if (!check_token (data, TOKEN_BRACE_RIGHT)) {
- g_object_unref (*identifier);
- if (arguments != NULL)
- free_value_list (arguments);
- g_object_unref (body);
- return FAIL (TOKEN_BRACE_RIGHT);
- }
-
- *function = vivi_code_function_new ();
- if (body != NULL) {
- vivi_code_function_set_body (VIVI_CODE_FUNCTION (*function), body);
- g_object_unref (body);
- }
- if (arguments != NULL) {
- for (i = 0; arguments[i] != NULL; i++) {
- vivi_code_function_add_argument (VIVI_CODE_FUNCTION (*function),
- vivi_code_constant_get_variable_name (VIVI_CODE_CONSTANT (
- VIVI_CODE_GET (arguments[i])->name)));
- }
- free_value_list (arguments);
- }
-
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_function_declaration (ParseData *data, ViviCodeStatement **statement)
-{
- ParseStatus status;
- ViviCodeValue *function, *identifier;
-
- *statement = NULL;
-
- status = parse_function_definition (data, &function, &identifier, TRUE);
- if (status != STATUS_OK)
- return status;
-
- *statement = vivi_compiler_assignment_new (identifier, function);
- g_object_unref (identifier);
- g_object_unref (function);
-
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_function_expression (ParseData *data, ViviCodeValue **value,
- ViviCodeStatement **statement)
-{
- ParseStatus status;
- ViviCodeValue *identifier;
-
- *statement = NULL;
-
- status = parse_function_definition (data, value, &identifier, FALSE);
- if (status != STATUS_OK)
- return status;
-
- if (identifier != NULL) {
- *statement = vivi_compiler_assignment_new (identifier, *value);
- g_object_unref (identifier);
- }
-
- return STATUS_OK;
-}
-
-// top
-
-static ParseStatus
-parse_source_element (ParseData *data, ViviCodeStatement **statement)
-{
- ParseStatus status;
-
- *statement = NULL;
-
- status = parse_function_declaration (data, statement);
- if (status == STATUS_CANCEL)
- status = parse_statement (data, statement);
-
- return status;
-}
-
-static ParseStatus
-parse_program (ParseData *data, ViviCodeStatement **statement)
-{
- ParseStatus status;
-
- g_assert (data->level == NULL);
- vivi_compiler_start_level (data);
-
- *statement = NULL;
-
- status =
- parse_statement_list (data, parse_source_element, statement, STATUS_OK);
- if (status != STATUS_OK) {
- vivi_compiler_end_level (data, FALSE);
- return FAIL_CHILD (status);
- }
-
- if (!check_token (data, TOKEN_EOF)) {
- vivi_compiler_end_level (data, FALSE);
- g_object_unref (*statement);
- *statement = NULL;
- status = parse_statement (data, statement);
- return FAIL_CHILD (status);
- }
-
-
- status = vivi_compiler_end_level (data, TRUE);
- if (status != STATUS_OK) {
- g_object_unref (*statement);
- *statement = NULL;
- return FAIL_CHILD (status);
- }
-
- g_assert (data->level == NULL);
-
- return STATUS_OK;
-}
-
-// parsing
-
-static ParseStatus
-parse_statement_list (ParseData *data, ParseStatementFunction function,
- ViviCodeStatement **block, guint separator)
-{
- ViviCodeStatement *statement;
- ParseStatus status;
-
- g_assert (data != NULL);
- g_assert (function != NULL);
- g_assert (block != NULL);
-
- *block = NULL;
-
- status = function (data, &statement);
- if (status != STATUS_OK)
- return status;
-
- *block = vivi_code_block_new ();
-
- do {
- vivi_code_block_add_statement (VIVI_CODE_BLOCK (*block), statement);
- g_object_unref (statement);
-
- if (separator != STATUS_OK && !check_token (data, separator))
- break;
-
- status = function (data, &statement);
- if (status == STATUS_FAIL) {
- g_object_unref (*block);
- *block = NULL;
- return STATUS_FAIL;
- }
- } while (status == STATUS_OK);
-
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_value_statement_list (ParseData *data,
- ParseValueStatementFunction function, ViviCodeValue ***list,
- ViviCodeStatement **statement, guint separator)
-{
- GPtrArray *array;
- ViviCodeValue *value;
- ViviCodeStatement *statement_one;
- ParseStatus status;
-
- g_assert (data != NULL);
- g_assert (function != NULL);
- g_assert (list != NULL);
- g_assert (statement != NULL);
-
- *list = NULL;
- *statement = NULL;
-
- status = function (data, &value, statement);
- if (status != STATUS_OK)
- return status;
-
- array = g_ptr_array_new ();
-
- do {
- g_ptr_array_add (array, value);
-
- if (separator != TOKEN_NONE && !check_token (data, separator))
- break;
-
- status = function (data, &value, &statement_one);
- if (status != STATUS_OK) {
- if (status == STATUS_FAIL || separator != TOKEN_NONE)
- return FAIL_CHILD (status);
- } else {
- *statement = vivi_compiler_join_statements (*statement, statement_one);
- }
- } while (status == STATUS_OK);
- g_ptr_array_add (array, NULL);
-
- *list = (ViviCodeValue **)g_ptr_array_free (array, FALSE);
-
- return STATUS_OK;
-}
-
-static ParseStatus
-parse_value_list (ParseData *data, ParseValueFunction function,
- ViviCodeValue ***list, guint separator)
-{
- GPtrArray *array;
- ViviCodeValue *value;
- ParseStatus status;
-
- g_assert (data != NULL);
- g_assert (function != NULL);
- g_assert (list != NULL);
-
- *list = NULL;
-
- status = function (data, &value);
- if (status != STATUS_OK)
- return status;
-
- array = g_ptr_array_new ();
-
- do {
- g_ptr_array_add (array, value);
-
- if (separator != STATUS_OK && !check_token (data, separator))
- break;
-
- status = function (data, &value);
- if (status == STATUS_FAIL)
- return STATUS_FAIL;
- } while (status == STATUS_OK);
- g_ptr_array_add (array, NULL);
-
- *list = (ViviCodeValue **)g_ptr_array_free (array, FALSE);
-
- return STATUS_OK;
-}
-
-// public
-
-ViviCodeStatement *
-vivi_compile_file (FILE *file, const char *input_name)
-{
- ParseData data;
- ViviCodeStatement *statement;
- ParseStatus status;
-
- g_return_val_if_fail (file != NULL, NULL);
-
- data.scanner = vivi_compiler_scanner_new (file);
- data.unexpected_line_terminator = FALSE;
- data.expected[0] = TOKEN_NONE;
- data.expected[1] = TOKEN_NONE;
- data.custom_error = NULL;
- data.levels = NULL;
- data.level = NULL;
-
- status = parse_program (&data, &statement);
- g_assert ((status == STATUS_OK && VIVI_IS_CODE_STATEMENT (statement)) ||
- (status != STATUS_OK && statement == NULL));
- g_assert (status >= 0);
-
- if (status != STATUS_OK) {
- g_printerr ("%s:%i:%i: error: ", input_name,
- vivi_compiler_scanner_cur_line (data.scanner),
- vivi_compiler_scanner_cur_column (data.scanner));
-
- if (data.custom_error != NULL) {
- g_printerr ("%s\n", data.custom_error);
- g_free (data.custom_error);
- } else {
- vivi_compiler_scanner_get_next_token (data.scanner);
-
- g_printerr ("Expected %s ", vivi_compiler_token_name (data.expected[0]));
- if (data.expected[1] != TOKEN_NONE)
- g_printerr ("or %s ", vivi_compiler_token_name (data.expected[1]));
-
- if (data.unexpected_line_terminator) {
- g_printerr ("before %s token\n",
- vivi_compiler_token_name (TOKEN_LINE_TERMINATOR));
- } else {
- g_printerr ("before %s token\n",
- vivi_compiler_token_name (data.scanner->token));
- }
- }
- }
-
- g_object_unref (data.scanner);
-
- return statement;
-}
diff --git a/vivified/code/vivi_compiler.h b/vivified/code/vivi_compiler.h
deleted file mode 100644
index 4a8529b..0000000
--- a/vivified/code/vivi_compiler.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* Vivified
- * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifndef _VIVI_DECOMPILER_H_
-#define _VIVI_DECOMPILER_H_
-
-#include <stdio.h>
-
-#include <swfdec/swfdec.h>
-#include <vivified/code/vivi_code_statement.h>
-
-G_BEGIN_DECLS
-
-
-ViviCodeStatement * vivi_compile_file (FILE * file,
- const char * input_name);
-
-
-G_END_DECLS
-#endif
diff --git a/vivified/code/vivi_compiler_scanner.c b/vivified/code/vivi_compiler_scanner.c
deleted file mode 100644
index fd5c378..0000000
--- a/vivified/code/vivi_compiler_scanner.c
+++ /dev/null
@@ -1,310 +0,0 @@
-/* Vivified
- * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "vivi_compiler_scanner.h"
-
-#include "vivi_compiler_scanner_lex.h"
-#include "vivi_compiler_scanner_lex_include.h"
-
-G_DEFINE_TYPE (ViviCompilerScanner, vivi_compiler_scanner, G_TYPE_OBJECT)
-
-static void
-vivi_compiler_scanner_free_type_value (ViviCompilerScannerValue *value)
-{
- switch (value->type) {
- case VALUE_TYPE_STRING:
- g_free (value->v_string);
- break;
- case VALUE_TYPE_IDENTIFIER:
- g_free (value->v_identifier);
- break;
- case VALUE_TYPE_NONE:
- case VALUE_TYPE_BOOLEAN:
- case VALUE_TYPE_NUMBER:
- /* nothing */
- break;
- default:
- g_assert_not_reached ();
- break;
- }
-
- value->type = VALUE_TYPE_NONE;
-}
-
-static void
-vivi_compiler_scanner_dispose (GObject *object)
-{
- ViviCompilerScanner *scanner = VIVI_COMPILER_SCANNER (object);
-
- vivi_compiler_scanner_free_type_value (&scanner->value);
- vivi_compiler_scanner_free_type_value (&scanner->next_value);
-
- G_OBJECT_CLASS (vivi_compiler_scanner_parent_class)->dispose (object);
-}
-
-static void
-vivi_compiler_scanner_class_init (ViviCompilerScannerClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->dispose = vivi_compiler_scanner_dispose;
-}
-
-static void
-vivi_compiler_scanner_init (ViviCompilerScanner *token)
-{
-}
-
-static const struct {
- ViviCompilerScannerToken token;
- const char * name;
-} token_names[] = {
- // special
- { TOKEN_NONE, "NONE" },
- { TOKEN_EOF, "EOF" },
- { TOKEN_ERROR, "ERROR" },
- { TOKEN_UNKNOWN, "UNKNOWN" },
- { TOKEN_LINE_TERMINATOR, "NEW LINE" },
-
- // comparision
- { TOKEN_BRACE_LEFT, "{", },
- { TOKEN_BRACE_RIGHT, "}", },
- { TOKEN_BRACKET_LEFT, "[", },
- { TOKEN_BRACKET_RIGHT, "]", },
- { TOKEN_PARENTHESIS_LEFT, "(", },
- { TOKEN_PARENTHESIS_RIGHT, ")", },
-
- // punctuation
- { TOKEN_DOT, ".", },
- { TOKEN_SEMICOLON, ";" },
- { TOKEN_COMMA, "," },
-
- // comparision
- { TOKEN_LESS_THAN, "<" },
- { TOKEN_GREATER_THAN, ">" },
- { TOKEN_LESS_THAN_OR_EQUAL, "<=" },
- { TOKEN_EQUAL_OR_GREATER_THAN, "=>" },
-
- // equality
- { TOKEN_EQUAL, "=" },
- { TOKEN_NOT_EQUAL, "!=" },
- { TOKEN_STRICT_EQUAL, "===" },
- { TOKEN_NOT_STRICT_EQUAL, "!==" },
-
- // operator
- { TOKEN_PLUS, "+" },
- { TOKEN_MINUS, "-" },
- { TOKEN_MULTIPLY, "*" },
- { TOKEN_DIVIDE, "/" },
- { TOKEN_REMAINDER, "%" },
-
- // shift
- { TOKEN_SHIFT_LEFT, "<<" },
- { TOKEN_SHIFT_RIGHT, ">>" },
- { TOKEN_SHIFT_RIGHT_UNSIGNED, ">>>" },
-
- // bitwise
- { TOKEN_BITWISE_AND, "&" },
- { TOKEN_BITWISE_OR, "|" },
- { TOKEN_BITWISE_XOR, "^" },
-
- // unary/postfix
- { TOKEN_LOGICAL_NOT, "!" },
- { TOKEN_BITWISE_NOT, "~" },
- { TOKEN_INCREASE, "++" },
- { TOKEN_DESCREASE, "--" },
-
- // conditional
- { TOKEN_QUESTION_MARK, "?" },
- { TOKEN_COLON, ":" },
-
- // logical
- { TOKEN_LOGICAL_AND, "&&" },
- { TOKEN_LOGICAL_OR, "||" },
-
- // assign
- { TOKEN_ASSIGN, "=" },
- { TOKEN_ASSIGN_MULTIPLY, "*=" },
- { TOKEN_ASSIGN_DIVIDE, "/=" },
- { TOKEN_ASSIGN_REMAINDER, "%=" },
- { TOKEN_ASSIGN_ADD, "+=" },
- { TOKEN_ASSIGN_MINUS, "-=" },
- { TOKEN_ASSIGN_SHIFT_LEFT, "<<=" },
- { TOKEN_ASSIGN_SHIFT_RIGHT, ">>=" },
- { TOKEN_ASSIGN_SHIFT_RIGHT_ZERO, ">>>=" },
- { TOKEN_ASSIGN_BITWISE_AND, "&=" },
- { TOKEN_ASSIGN_BITWISE_XOR, "^=" },
- { TOKEN_ASSIGN_BITWISE_OR, "|=" },
-
- // values
- { TOKEN_NULL, "NULL" },
- { TOKEN_BOOLEAN, "BOOLEAN" },
- { TOKEN_NUMBER, "NUMBER" },
- { TOKEN_STRING, "STRING" },
- { TOKEN_IDENTIFIER, "IDENTIFIER" },
-
- // keywords
- { TOKEN_BREAK, "break" },
- { TOKEN_CASE, "case" },
- { TOKEN_CATCH, "catch" },
- { TOKEN_CONTINUE, "continue" },
- { TOKEN_DEFAULT, "default" },
- { TOKEN_DELETE, "delete" },
- { TOKEN_DO, "do" },
- { TOKEN_ELSE, "else" },
- { TOKEN_FINALLY, "finally" },
- { TOKEN_FOR, "for" },
- { TOKEN_FUNCTION, "function" },
- { TOKEN_IF, "if" },
- { TOKEN_IN, "in" },
- { TOKEN_INSTANCEOF, "instanceof" },
- { TOKEN_NEW, "new" },
- { TOKEN_RETURN, "return" },
- { TOKEN_SWITCH, "switch" },
- { TOKEN_THIS, "this" },
- { TOKEN_THROW, "throw" },
- { TOKEN_TRY, "try" },
- { TOKEN_TYPEOF, "typeof" },
- { TOKEN_VAR, "var" },
- { TOKEN_VOID, "void" },
- { TOKEN_WHILE, "while" },
- { TOKEN_WITH, "with" },
-
- // reserved keywords
- { TOKEN_RESERVED_KEYWORD, "RESERVED KEYWORD" },
-
- // ActionScript specific
- { TOKEN_UNDEFINED, "undefined" },
- { TOKEN_TRACE, "trace" },
-
- { TOKEN_LAST, NULL }
-};
-
-const char *vivi_compiler_scanner_token_name (ViviCompilerScannerToken token)
-{
- int i;
-
- for (i = 0; token_names[i].token != TOKEN_LAST; i++) {
- if (token_names[i].token == token)
- return token_names[i].name;
- }
-
- g_assert_not_reached ();
-
- return "INVALID TOKEN";
-}
-
-static void
-vivi_compiler_scanner_advance (ViviCompilerScanner *scanner)
-{
- g_return_if_fail (VIVI_IS_COMPILER_SCANNER (scanner));
-
- vivi_compiler_scanner_free_type_value (&scanner->value);
-
- scanner->token = scanner->next_token;
- scanner->value = scanner->next_value;
- scanner->line_number = scanner->next_line_number;
- scanner->line_terminator = scanner->next_line_terminator;
-
- if (scanner->file == NULL) {
- scanner->next_token = TOKEN_EOF;
- scanner->next_value.v_string = NULL;
- } else {
- scanner->next_token = yylex ();
- if (scanner->next_token == TOKEN_LINE_TERMINATOR) {
- scanner->next_line_terminator = TRUE;
- } else {
- scanner->next_line_terminator = FALSE;
- }
- while (scanner->next_token == TOKEN_LINE_TERMINATOR) {
- scanner->next_token = yylex ();
- }
- scanner->next_value = lex_value;
- scanner->next_line_number = lex_line_number;
- lex_value.type = VALUE_TYPE_NONE;
- }
-}
-
-ViviCompilerScanner *
-vivi_compiler_scanner_new (FILE *file)
-{
- ViviCompilerScanner *scanner;
-
- g_return_val_if_fail (file != NULL, NULL);
-
- scanner = g_object_new (VIVI_TYPE_COMPILER_SCANNER, NULL);
- scanner->file = file;
- scanner->line_number = scanner->next_line_number = lex_line_number = 1;
-
- yyrestart (file);
-
- vivi_compiler_scanner_advance (scanner);
-
- return scanner;
-}
-
-ViviCompilerScannerToken
-vivi_compiler_scanner_get_next_token (ViviCompilerScanner *scanner)
-{
- g_return_val_if_fail (VIVI_IS_COMPILER_SCANNER (scanner), TOKEN_EOF);
-
- vivi_compiler_scanner_advance (scanner);
-
- return scanner->token;
-}
-
-ViviCompilerScannerToken
-vivi_compiler_scanner_peek_next_token (ViviCompilerScanner *scanner)
-{
- g_return_val_if_fail (VIVI_IS_COMPILER_SCANNER (scanner), TOKEN_EOF);
-
- return scanner->next_token;
-}
-
-guint
-vivi_compiler_scanner_cur_line (ViviCompilerScanner *scanner)
-{
- g_return_val_if_fail (VIVI_IS_COMPILER_SCANNER (scanner), 0);
-
- return scanner->line_number;
-}
-
-guint
-vivi_compiler_scanner_cur_column (ViviCompilerScanner *scanner)
-{
- g_return_val_if_fail (VIVI_IS_COMPILER_SCANNER (scanner), 0);
-
- // TODO
-
- return 0;
-}
-
-char *
-vivi_compiler_scanner_get_line (ViviCompilerScanner *scanner)
-{
- g_return_val_if_fail (VIVI_IS_COMPILER_SCANNER (scanner), 0);
-
- // TODO
-
- return g_strdup ("");
-}
diff --git a/vivified/code/vivi_compiler_scanner.h b/vivified/code/vivi_compiler_scanner.h
deleted file mode 100644
index bcccd2d..0000000
--- a/vivified/code/vivi_compiler_scanner.h
+++ /dev/null
@@ -1,216 +0,0 @@
-/* Vivified
- * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifndef _VIVI_COMPILER_SCANNER_H_
-#define _VIVI_COMPILER_SCANNER_H_
-
-#include <stdio.h>
-#include <swfdec/swfdec.h>
-
-G_BEGIN_DECLS
-
-
-typedef enum {
- // special
- TOKEN_NONE = 0,
- TOKEN_EOF,
- TOKEN_ERROR,
- TOKEN_UNKNOWN,
- TOKEN_LINE_TERMINATOR,
-
- // comparision
- TOKEN_BRACE_LEFT,
- TOKEN_BRACE_RIGHT,
- TOKEN_BRACKET_LEFT,
- TOKEN_BRACKET_RIGHT,
- TOKEN_PARENTHESIS_LEFT,
- TOKEN_PARENTHESIS_RIGHT,
-
- // punctuation
- TOKEN_DOT,
- TOKEN_SEMICOLON,
- TOKEN_COMMA,
-
- // comparision
- TOKEN_LESS_THAN,
- TOKEN_GREATER_THAN,
- TOKEN_LESS_THAN_OR_EQUAL,
- TOKEN_EQUAL_OR_GREATER_THAN,
-
- // equality
- TOKEN_EQUAL,
- TOKEN_NOT_EQUAL,
- TOKEN_STRICT_EQUAL,
- TOKEN_NOT_STRICT_EQUAL,
-
- // operator
- TOKEN_PLUS,
- TOKEN_MINUS,
- TOKEN_MULTIPLY,
- TOKEN_DIVIDE,
- TOKEN_REMAINDER,
-
- // shift
- TOKEN_SHIFT_LEFT,
- TOKEN_SHIFT_RIGHT,
- TOKEN_SHIFT_RIGHT_UNSIGNED,
-
- // bitwise
- TOKEN_BITWISE_AND,
- TOKEN_BITWISE_OR,
- TOKEN_BITWISE_XOR,
-
- // unary/postfix
- TOKEN_LOGICAL_NOT,
- TOKEN_BITWISE_NOT,
- TOKEN_INCREASE,
- TOKEN_DESCREASE,
-
- // conditional
- TOKEN_QUESTION_MARK,
- TOKEN_COLON,
-
- // logical
- TOKEN_LOGICAL_AND,
- TOKEN_LOGICAL_OR,
-
- // assign
- TOKEN_ASSIGN,
- TOKEN_ASSIGN_MULTIPLY,
- TOKEN_ASSIGN_DIVIDE,
- TOKEN_ASSIGN_REMAINDER,
- TOKEN_ASSIGN_ADD,
- TOKEN_ASSIGN_MINUS,
- TOKEN_ASSIGN_SHIFT_LEFT,
- TOKEN_ASSIGN_SHIFT_RIGHT,
- TOKEN_ASSIGN_SHIFT_RIGHT_ZERO,
- TOKEN_ASSIGN_BITWISE_AND,
- TOKEN_ASSIGN_BITWISE_XOR,
- TOKEN_ASSIGN_BITWISE_OR,
-
- // values
- TOKEN_NULL,
- TOKEN_BOOLEAN,
- TOKEN_NUMBER,
- TOKEN_STRING,
- TOKEN_IDENTIFIER,
-
- // keywords
- TOKEN_BREAK,
- TOKEN_CASE,
- TOKEN_CATCH,
- TOKEN_CONTINUE,
- TOKEN_DEFAULT,
- TOKEN_DELETE,
- TOKEN_DO,
- TOKEN_ELSE,
- TOKEN_FINALLY,
- TOKEN_FOR,
- TOKEN_FUNCTION,
- TOKEN_IF,
- TOKEN_IN,
- TOKEN_INSTANCEOF,
- TOKEN_NEW,
- TOKEN_RETURN,
- TOKEN_SWITCH,
- TOKEN_THIS,
- TOKEN_THROW,
- TOKEN_TRY,
- TOKEN_TYPEOF,
- TOKEN_VAR,
- TOKEN_VOID,
- TOKEN_WHILE,
- TOKEN_WITH,
-
- // reserved keywords
- TOKEN_RESERVED_KEYWORD,
-
- // ActionScript specific
- TOKEN_UNDEFINED,
- TOKEN_TRACE,
-
- TOKEN_LAST
-} ViviCompilerScannerToken;
-
-typedef enum {
- VALUE_TYPE_NONE,
- VALUE_TYPE_BOOLEAN,
- VALUE_TYPE_NUMBER,
- VALUE_TYPE_STRING,
- VALUE_TYPE_IDENTIFIER
-} ViviCompilerScannerValueType;
-
-typedef struct {
- ViviCompilerScannerValueType type;
- union {
- gboolean v_boolean;
- double v_number;
- char * v_string;
- char * v_identifier;
- };
-} ViviCompilerScannerValue;
-
-typedef struct _ViviCompilerScanner ViviCompilerScanner;
-typedef struct _ViviCompilerScannerClass ViviCompilerScannerClass;
-
-#define VIVI_TYPE_COMPILER_SCANNER (vivi_compiler_scanner_get_type())
-#define VIVI_IS_COMPILER_SCANNER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_COMPILER_SCANNER))
-#define VIVI_IS_COMPILER_SCANNER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_COMPILER_SCANNER))
-#define VIVI_COMPILER_SCANNER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_COMPILER_SCANNER, ViviCompilerScanner))
-#define VIVI_COMPILER_SCANNER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_COMPILER_SCANNER, ViviCompilerScannerClass))
-#define VIVI_COMPILER_SCANNER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_COMPILER_SCANNER, ViviCompilerScannerClass))
-
-struct _ViviCompilerScanner
-{
- GObject object;
-
- FILE * file;
-
- ViviCompilerScannerToken token;
- ViviCompilerScannerToken next_token;
- guint line_number;
- gboolean line_terminator;
-
- ViviCompilerScannerValue value;
- ViviCompilerScannerValue next_value;
- guint next_line_number;
- gboolean next_line_terminator;
-
- ViviCompilerScannerToken expected;
-};
-
-struct _ViviCompilerScannerClass
-{
- GObjectClass object_class;
-};
-
-GType vivi_compiler_scanner_get_type (void);
-
-ViviCompilerScanner * vivi_compiler_scanner_new (FILE * file);
-ViviCompilerScannerToken vivi_compiler_scanner_get_next_token (ViviCompilerScanner * scanner);
-ViviCompilerScannerToken vivi_compiler_scanner_peek_next_token (ViviCompilerScanner * scanner);
-
-const char * vivi_compiler_scanner_token_name (ViviCompilerScannerToken token);
-guint vivi_compiler_scanner_cur_line (ViviCompilerScanner *scanner);
-guint vivi_compiler_scanner_cur_column (ViviCompilerScanner *scanner);
-char * vivi_compiler_scanner_get_line (ViviCompilerScanner *scanner);
-
-
-G_END_DECLS
-#endif
diff --git a/vivified/code/vivi_compiler_scanner_lex.h b/vivified/code/vivi_compiler_scanner_lex.h
deleted file mode 100644
index 14d2a0f..0000000
--- a/vivified/code/vivi_compiler_scanner_lex.h
+++ /dev/null
@@ -1,315 +0,0 @@
-/* Vivified
- * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifndef yyHEADER_H
-#define yyHEADER_H 1
-#define yyIN_HEADER 1
-
-#line 6 "vivi_compiler_scanner_lex.h"
-
-#line 8 "vivi_compiler_scanner_lex.h"
-
-#define YY_INT_ALIGNED short int
-
-/* A lexical scanner generated by flex */
-
-#define FLEX_SCANNER
-#define YY_FLEX_MAJOR_VERSION 2
-#define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 34
-#if YY_FLEX_SUBMINOR_VERSION > 0
-#define FLEX_BETA
-#endif
-
-/* First, we deal with platform-specific or compiler-specific issues. */
-
-/* begin standard C headers. */
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-
-/* end standard C headers. */
-
-/* flex integer type definitions */
-
-#ifndef FLEXINT_H
-#define FLEXINT_H
-
-/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
-
-#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-
-/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
- * if you want the limit (max/min) macros for int types.
- */
-#ifndef __STDC_LIMIT_MACROS
-#define __STDC_LIMIT_MACROS 1
-#endif
-
-#include <inttypes.h>
-typedef int8_t flex_int8_t;
-typedef uint8_t flex_uint8_t;
-typedef int16_t flex_int16_t;
-typedef uint16_t flex_uint16_t;
-typedef int32_t flex_int32_t;
-typedef uint32_t flex_uint32_t;
-#else
-typedef signed char flex_int8_t;
-typedef short int flex_int16_t;
-typedef int flex_int32_t;
-typedef unsigned char flex_uint8_t;
-typedef unsigned short int flex_uint16_t;
-typedef unsigned int flex_uint32_t;
-#endif /* ! C99 */
-
-/* Limits of integral types. */
-#ifndef INT8_MIN
-#define INT8_MIN (-128)
-#endif
-#ifndef INT16_MIN
-#define INT16_MIN (-32767-1)
-#endif
-#ifndef INT32_MIN
-#define INT32_MIN (-2147483647-1)
-#endif
-#ifndef INT8_MAX
-#define INT8_MAX (127)
-#endif
-#ifndef INT16_MAX
-#define INT16_MAX (32767)
-#endif
-#ifndef INT32_MAX
-#define INT32_MAX (2147483647)
-#endif
-#ifndef UINT8_MAX
-#define UINT8_MAX (255U)
-#endif
-#ifndef UINT16_MAX
-#define UINT16_MAX (65535U)
-#endif
-#ifndef UINT32_MAX
-#define UINT32_MAX (4294967295U)
-#endif
-
-#endif /* ! FLEXINT_H */
-
-#ifdef __cplusplus
-
-/* The "const" storage-class-modifier is valid. */
-#define YY_USE_CONST
-
-#else /* ! __cplusplus */
-
-/* C99 requires __STDC__ to be defined as 1. */
-#if defined (__STDC__)
-
-#define YY_USE_CONST
-
-#endif /* defined (__STDC__) */
-#endif /* ! __cplusplus */
-
-#ifdef YY_USE_CONST
-#define yyconst const
-#else
-#define yyconst
-#endif
-
-/* Size of default input buffer. */
-#ifndef YY_BUF_SIZE
-#define YY_BUF_SIZE 16384
-#endif
-
-#ifndef YY_TYPEDEF_YY_BUFFER_STATE
-#define YY_TYPEDEF_YY_BUFFER_STATE
-typedef struct yy_buffer_state *YY_BUFFER_STATE;
-#endif
-
-extern int yyleng;
-
-extern FILE *yyin, *yyout;
-
-/* The following is because we cannot portably get our hands on size_t
- * (without autoconf's help, which isn't available because we want
- * flex-generated scanners to compile on their own).
- * Given that the standard has decreed that size_t exists since 1989,
- * I guess we can afford to depend on it. Manoj.
- */
-
-#ifndef YY_TYPEDEF_YY_SIZE_T
-#define YY_TYPEDEF_YY_SIZE_T
-typedef size_t yy_size_t;
-#endif
-
-#ifndef YY_STRUCT_YY_BUFFER_STATE
-#define YY_STRUCT_YY_BUFFER_STATE
-struct yy_buffer_state
- {
- FILE *yy_input_file;
-
- char *yy_ch_buf; /* input buffer */
- char *yy_buf_pos; /* current position in input buffer */
-
- /* Size of input buffer in bytes, not including room for EOB
- * characters.
- */
- yy_size_t yy_buf_size;
-
- /* Number of characters read into yy_ch_buf, not including EOB
- * characters.
- */
- int yy_n_chars;
-
- /* Whether we "own" the buffer - i.e., we know we created it,
- * and can realloc() it to grow it, and should free() it to
- * delete it.
- */
- int yy_is_our_buffer;
-
- /* Whether this is an "interactive" input source; if so, and
- * if we're using stdio for input, then we want to use getc()
- * instead of fread(), to make sure we stop fetching input after
- * each newline.
- */
- int yy_is_interactive;
-
- /* Whether we're considered to be at the beginning of a line.
- * If so, '^' rules will be active on the next match, otherwise
- * not.
- */
- int yy_at_bol;
-
- int yy_bs_lineno; /**< The line count. */
- int yy_bs_column; /**< The column count. */
-
- /* Whether to try to fill the input buffer when we reach the
- * end of it.
- */
- int yy_fill_buffer;
-
- int yy_buffer_status;
-
- };
-#endif /* !YY_STRUCT_YY_BUFFER_STATE */
-
-void yyrestart (FILE *input_file );
-void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer );
-YY_BUFFER_STATE yy_create_buffer (FILE *file,int size );
-void yy_delete_buffer (YY_BUFFER_STATE b );
-void yy_flush_buffer (YY_BUFFER_STATE b );
-void yypush_buffer_state (YY_BUFFER_STATE new_buffer );
-void yypop_buffer_state (void );
-
-YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
-YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
-YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len );
-
-void *yyalloc (yy_size_t );
-void *yyrealloc (void *,yy_size_t );
-void yyfree (void * );
-
-/* Begin user sect3 */
-
-extern int yylineno;
-
-extern char *yytext;
-#define yytext_ptr yytext
-
-#ifdef YY_HEADER_EXPORT_START_CONDITIONS
-#define INITIAL 0
-
-#endif
-
-#ifndef YY_NO_UNISTD_H
-/* Special case for "unistd.h", since it is non-ANSI. We include it way
- * down here because we want the user's section 1 to have been scanned first.
- * The user has a chance to override it with an option.
- */
-#include <unistd.h>
-#endif
-
-#ifndef YY_EXTRA_TYPE
-#define YY_EXTRA_TYPE void *
-#endif
-
-/* Macros after this point can all be overridden by user definitions in
- * section 1.
- */
-
-#ifndef YY_SKIP_YYWRAP
-#ifdef __cplusplus
-extern "C" int yywrap (void );
-#else
-extern int yywrap (void );
-#endif
-#endif
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy (char *,yyconst char *,int );
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * );
-#endif
-
-#ifndef YY_NO_INPUT
-
-#endif
-
-/* Amount of stuff to slurp up with each read. */
-#ifndef YY_READ_BUF_SIZE
-#define YY_READ_BUF_SIZE 8192
-#endif
-
-/* Number of entries by which start-condition stack grows. */
-#ifndef YY_START_STACK_INCR
-#define YY_START_STACK_INCR 25
-#endif
-
-/* Default declaration of generated scanner - a define so the user can
- * easily add parameters.
- */
-#ifndef YY_DECL
-#define YY_DECL_IS_OURS 1
-
-extern int yylex (void);
-
-#define YY_DECL int yylex (void)
-#endif /* !YY_DECL */
-
-/* yy_get_previous_state - get the state just before the EOB char was reached */
-
-#undef YY_NEW_FILE
-#undef YY_FLUSH_BUFFER
-#undef yy_set_bol
-#undef yy_new_buffer
-#undef yy_set_interactive
-#undef YY_DO_BEFORE_ACTION
-
-#ifdef YY_DECL_IS_OURS
-#undef YY_DECL_IS_OURS
-#undef YY_DECL
-#endif
-
-#line 148 "vivi_compiler_scanner_lex.l"
-
-
-#line 295 "vivi_compiler_scanner_lex.h"
-#undef yyIN_HEADER
-#endif /* yyHEADER_H */
diff --git a/vivified/code/vivi_compiler_scanner_lex.l b/vivified/code/vivi_compiler_scanner_lex.l
deleted file mode 100644
index 7d2cc9b..0000000
--- a/vivified/code/vivi_compiler_scanner_lex.l
+++ /dev/null
@@ -1,284 +0,0 @@
-%{
-/* Vivified
- * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#include "vivi_compiler_scanner_lex_include.h"
-%}
-
-%option noyywrap
-%option nostdinit
-%option never-interactive
-
-identifier_start [$_a-zA-Z]
-identifier_part [$_a-zA-Z0-9]
-
-%x str
-%x comment
-
-%%
-
- GString *string = NULL;
-
-<<EOF>> { return TOKEN_EOF; }
-
-"/*" { BEGIN(comment); }
-<comment>{
- [^*\n]* /* skip */
- \n { lex_line_number++; }
- "*/" { BEGIN(INITIAL); }
- <<EOF>> {
- BEGIN(INITIAL);
- return TOKEN_ERROR;
- }
-}
-"//"[^\r\n]* {
- lex_line_number++;
- return TOKEN_LINE_TERMINATOR;
- }
-
-[ \t] /* skip */
-
-\r\n {
- lex_line_number++;
- return TOKEN_LINE_TERMINATOR;
- }
-[\r\n] {
- lex_line_number++;
- return TOKEN_LINE_TERMINATOR;
- }
-
-"{" { return TOKEN_BRACE_LEFT; }
-"}" { return TOKEN_BRACE_RIGHT; }
-"[" { return TOKEN_BRACKET_LEFT; }
-"]" { return TOKEN_BRACKET_RIGHT; }
-"(" { return TOKEN_PARENTHESIS_LEFT; }
-")" { return TOKEN_PARENTHESIS_RIGHT; }
-
-"." { return TOKEN_DOT; }
-";" { return TOKEN_SEMICOLON; }
-"," { return TOKEN_COMMA; }
-
-"<" { return TOKEN_LESS_THAN; }
-">" { return TOKEN_GREATER_THAN; }
-"<=" { return TOKEN_LESS_THAN_OR_EQUAL; }
-"=>" { return TOKEN_EQUAL_OR_GREATER_THAN; }
-
-"==", { return TOKEN_EQUAL; }
-"!=", { return TOKEN_NOT_EQUAL; }
-"===", { return TOKEN_STRICT_EQUAL; }
-"!==", { return TOKEN_NOT_STRICT_EQUAL; }
-
-"+" { return TOKEN_PLUS; }
-"-" { return TOKEN_MINUS; }
-"*" { return TOKEN_MULTIPLY; }
-"/" { return TOKEN_DIVIDE; }
-"%" { return TOKEN_REMAINDER; }
-
-"<<" { return TOKEN_SHIFT_LEFT; }
-">>" { return TOKEN_SHIFT_RIGHT; }
-">>>" { return TOKEN_SHIFT_RIGHT_UNSIGNED; }
-
-"&" { return TOKEN_BITWISE_AND; }
-"|" { return TOKEN_BITWISE_OR; }
-"^" { return TOKEN_BITWISE_XOR; }
-
-"!" { return TOKEN_LOGICAL_NOT; }
-"~" { return TOKEN_BITWISE_NOT; }
-"++" { return TOKEN_INCREASE; }
-"--" { return TOKEN_DESCREASE; }
-
-"?" { return TOKEN_QUESTION_MARK; }
-":" { return TOKEN_COLON; }
-
-"&&" { return TOKEN_LOGICAL_AND; }
-"||" { return TOKEN_LOGICAL_OR; }
-
-"=" { return TOKEN_ASSIGN; }
-"*=" { return TOKEN_ASSIGN_MULTIPLY; }
-"/=" { return TOKEN_ASSIGN_DIVIDE; }
-"%=" { return TOKEN_ASSIGN_REMAINDER; }
-"+=" { return TOKEN_ASSIGN_ADD; }
-"-=" { return TOKEN_ASSIGN_MINUS; }
-"<<=" { return TOKEN_ASSIGN_SHIFT_LEFT; }
-">>=" { return TOKEN_ASSIGN_SHIFT_RIGHT; }
-">>>=" { return TOKEN_ASSIGN_SHIFT_RIGHT_ZERO; }
-"&=" { return TOKEN_ASSIGN_BITWISE_AND; }
-"^=" { return TOKEN_ASSIGN_BITWISE_XOR; }
-"|=" { return TOKEN_ASSIGN_BITWISE_OR; }
-
-"break" { return TOKEN_BREAK; }
-"case" { return TOKEN_CASE; }
-"catch" { return TOKEN_CATCH; }
-"continue" { return TOKEN_CONTINUE; }
-"default" { return TOKEN_DEFAULT; }
-"delete" { return TOKEN_DELETE; }
-"do" { return TOKEN_DO; }
-"else" { return TOKEN_ELSE; }
-"finally" { return TOKEN_FINALLY; }
-"for" { return TOKEN_FOR; }
-"function" { return TOKEN_FUNCTION; }
-"if" { return TOKEN_IF; }
-"in" { return TOKEN_IN; }
-"instanceof" { return TOKEN_INSTANCEOF; }
-"new" { return TOKEN_NEW; }
-"return" { return TOKEN_RETURN; }
-"switch" { return TOKEN_SWITCH; }
-"this" { return TOKEN_THIS; }
-"throw" { return TOKEN_THROW; }
-"try" { return TOKEN_TRY; }
-"typeof" { return TOKEN_TYPEOF; }
-"var" { return TOKEN_VAR; }
-"void" { return TOKEN_VOID; }
-"while" { return TOKEN_WHILE; }
-"with" { return TOKEN_WITH; }
-
-"abstract" { return TOKEN_RESERVED_KEYWORD; }
-"boolean" { return TOKEN_RESERVED_KEYWORD; }
-"byte" { return TOKEN_RESERVED_KEYWORD; }
-"char" { return TOKEN_RESERVED_KEYWORD; }
-"class" { return TOKEN_RESERVED_KEYWORD; }
-"const" { return TOKEN_RESERVED_KEYWORD; }
-"debugger" { return TOKEN_RESERVED_KEYWORD; }
-"double" { return TOKEN_RESERVED_KEYWORD; }
-"enum" { return TOKEN_RESERVED_KEYWORD; }
-"export" { return TOKEN_RESERVED_KEYWORD; }
-"extends" { return TOKEN_RESERVED_KEYWORD; }
-"final" { return TOKEN_RESERVED_KEYWORD; }
-"float" { return TOKEN_RESERVED_KEYWORD; }
-"goto" { return TOKEN_RESERVED_KEYWORD; }
-"implements" { return TOKEN_RESERVED_KEYWORD; }
-"import" { return TOKEN_RESERVED_KEYWORD; }
-"int" { return TOKEN_RESERVED_KEYWORD; }
-"interface" { return TOKEN_RESERVED_KEYWORD; }
-"long" { return TOKEN_RESERVED_KEYWORD; }
-"native" { return TOKEN_RESERVED_KEYWORD; }
-"package" { return TOKEN_RESERVED_KEYWORD; }
-"private" { return TOKEN_RESERVED_KEYWORD; }
-"protected" { return TOKEN_RESERVED_KEYWORD; }
-"public" { return TOKEN_RESERVED_KEYWORD; }
-"short" { return TOKEN_RESERVED_KEYWORD; }
-"static" { return TOKEN_RESERVED_KEYWORD; }
-"super" { return TOKEN_RESERVED_KEYWORD; }
-"synchronized" { return TOKEN_RESERVED_KEYWORD; }
-"throws" { return TOKEN_RESERVED_KEYWORD; }
-"transient" { return TOKEN_RESERVED_KEYWORD; }
-"volatile" { return TOKEN_RESERVED_KEYWORD; }
-
-"undefined" { return TOKEN_UNDEFINED; }
-"trace" { return TOKEN_TRACE; }
-
-"null" { return TOKEN_NULL; }
-"true" {
- lex_value.type = VALUE_TYPE_BOOLEAN;
- lex_value.v_boolean = 1;
- return TOKEN_BOOLEAN;
- }
-"false" {
- lex_value.type = VALUE_TYPE_BOOLEAN;
- lex_value.v_boolean = 0;
- return TOKEN_BOOLEAN;
- }
-
-0[xX][0-9a-fA-F]+ {
- lex_value.type = VALUE_TYPE_NUMBER;
- lex_value.v_number =
- g_ascii_strtoull (yytext, NULL, 16);
- return TOKEN_NUMBER;
- }
-
-([1-9][0-9]*|0)(\.[0-9]*)?([eE][+-]?[0-9]+)? {
- lex_value.type = VALUE_TYPE_NUMBER;
- lex_value.v_number = g_ascii_strtod (yytext, NULL);
- return TOKEN_NUMBER;
- }
-
-\.[0-9]+([eE][+-]?[0-9]+)? {
- lex_value.type = VALUE_TYPE_NUMBER;
- lex_value.v_number = g_ascii_strtod (yytext, NULL);
- return TOKEN_NUMBER;
- }
-
-\" {
- string = g_string_new ("");
- BEGIN(str);
- }
-
-<str>{
- \" {
- BEGIN(INITIAL);
- lex_value.type = VALUE_TYPE_STRING;
- lex_value.v_string = g_string_free (string, FALSE);
- return TOKEN_STRING;
- }
- \n {
- BEGIN(INITIAL);
- g_string_free (string, TRUE);
- return TOKEN_ERROR;
- }
- \\0 { g_string_append_c (string, '0'); }
- \\[0-7]{1,3} {
- guint64 result;
- result = g_ascii_strtoull (yytext + 1, NULL, 8);
- if (result > 0xff || result == 0) {
- BEGIN(INITIAL);
- g_string_free (string, TRUE);
- return TOKEN_ERROR;
- } else {
- g_string_append_c (string, result);
- }
- }
- \\[0-9]+ {
- g_string_free (string, TRUE);
- return TOKEN_ERROR;
- }
- \\x[0-9a-fA-F]{2} {
- guint64 result;
- result = g_ascii_strtoull (yytext + 2, NULL, 16);
- if (result == 0) {
- BEGIN(INITIAL);
- g_string_free (string, TRUE);
- return TOKEN_ERROR;
- } else {
- g_string_append_c (string, result);
- }
- }
- \\b { g_string_append_c (string, '\b'); }
- \\f { g_string_append_c (string, '\f'); }
- \\n { g_string_append_c (string, '\n'); }
- \\r { g_string_append_c (string, '\r'); }
- \\t { g_string_append_c (string, '\t'); }
- \\v { g_string_append_c (string, '\v'); }
- \\. { g_string_append_c (string, yytext[1]); }
- [^\\\n\"]+ {
- char *p;
- for (p = yytext; *p != '\0'; p++) {
- g_string_append_c (string, *p);
- }
- }
-}
-
-{identifier_start}({identifier_part})* {
- lex_value.type = VALUE_TYPE_IDENTIFIER;
- lex_value.v_identifier = g_strdup (yytext);
- return TOKEN_IDENTIFIER;
- }
-
-. { return TOKEN_ERROR; }
-
-%%
diff --git a/vivified/code/vivi_compiler_scanner_lex_include.h b/vivified/code/vivi_compiler_scanner_lex_include.h
deleted file mode 100644
index f85f00e..0000000
--- a/vivified/code/vivi_compiler_scanner_lex_include.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* Vivified
- * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifndef _VIVI_COMPILER_SCANNER_LEX_INCLUDE_H_
-#define _VIVI_COMPILER_SCANNER_LEX_INCLUDE_H_
-
-#include "vivi_compiler_scanner.h"
-
-ViviCompilerScannerValue lex_value;
-guint lex_line_number;
-
-#endif // _VIVI_COMPILER_SCANNER_LEX_INCLUDE_H_
diff --git a/vivified/code/vivi_parser.c b/vivified/code/vivi_parser.c
new file mode 100644
index 0000000..2969593
--- /dev/null
+++ b/vivified/code/vivi_parser.c
@@ -0,0 +1,2385 @@
+/* Vivified
+ * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "vivi_parser.h"
+
+#include "vivi_parser_scanner.h"
+
+#include "vivi_code_assignment.h"
+#include "vivi_code_binary.h"
+#include "vivi_code_block.h"
+#include "vivi_code_break.h"
+#include "vivi_code_constant.h"
+#include "vivi_code_continue.h"
+#include "vivi_code_function.h"
+#include "vivi_code_function_call.h"
+#include "vivi_code_get.h"
+#include "vivi_code_get_url.h"
+#include "vivi_code_goto.h"
+#include "vivi_code_if.h"
+#include "vivi_code_init_array.h"
+#include "vivi_code_init_object.h"
+#include "vivi_code_loop.h"
+#include "vivi_code_return.h"
+#include "vivi_code_throw.h"
+#include "vivi_code_trace.h"
+#include "vivi_code_unary.h"
+#include "vivi_code_value_statement.h"
+#include "vivi_compiler_empty_statement.h"
+#include "vivi_compiler_get_temporary.h"
+#include "vivi_compiler_goto_name.h"
+
+#include "vivi_code_text_printer.h"
+
+enum {
+ ERROR_TOKEN_LITERAL = TOKEN_LAST + 1,
+ ERROR_TOKEN_IDENTIFIER,
+ ERROR_TOKEN_PROPERTY_NAME,
+ ERROR_TOKEN_PRIMARY_EXPRESSION,
+ ERROR_TOKEN_EXPRESSION,
+ ERROR_TOKEN_ITERATION_STATEMENT,
+ ERROR_TOKEN_EXPRESSION_STATEMENT,
+ ERROR_TOKEN_STATEMENT
+};
+
+static const struct {
+ guint token;
+ const char * name;
+} error_names[] = {
+ { ERROR_TOKEN_LITERAL, "LITERAL" },
+ { ERROR_TOKEN_IDENTIFIER, "IDENTIFIER" },
+ { ERROR_TOKEN_PROPERTY_NAME, "PROPERTY NAME" },
+ { ERROR_TOKEN_PRIMARY_EXPRESSION, "PRIMARY EXPRESSION" },
+ { ERROR_TOKEN_EXPRESSION, "EXPRESSION" },
+ { ERROR_TOKEN_ITERATION_STATEMENT, "ITERATION STATEMENT" },
+ { ERROR_TOKEN_EXPRESSION_STATEMENT, "EXPRESSION STATEMENT" },
+ { ERROR_TOKEN_STATEMENT, "STATEMENT" },
+ { TOKEN_LAST, NULL }
+};
+
+typedef enum {
+ STATUS_CANCEL = -1,
+ STATUS_OK = 0,
+ STATUS_FAIL = 1
+} ParseStatus;
+
+typedef struct {
+ GSList *labels;
+ GSList *gotos;
+} ParseLevel;
+
+typedef struct {
+ ViviParserScanner * scanner;
+ gboolean unexpected_line_terminator;
+ guint expected[2];
+ char * custom_error;
+
+ GSList * levels; // ParseLevel, earlier levels
+ ParseLevel * level; // current level
+} ParseData;
+
+#define FAIL_OR(x, y) (data->expected[0] = (x), data->expected[1] = (y), STATUS_FAIL)
+#define FAIL_LINE_TERMINATOR_OR(x, y) (data->unexpected_line_terminator = TRUE, FAIL_OR(x,y))
+#define FAIL_LINE_TERMINATOR(x) FAIL_LINE_TERMINATOR_OR(x,TOKEN_NONE)
+#define FAIL(x) FAIL_OR(x,TOKEN_NONE)
+#define FAIL_CHILD(x) STATUS_FAIL
+#define FAIL_CUSTOM(x) (data->custom_error = (x), STATUS_FAIL)
+#define CANCEL_OR(x, y) (data->expected[0] = (x), data->expected[1] = (y), STATUS_CANCEL)
+#define CANCEL(x) CANCEL_OR(x, TOKEN_NONE)
+#define CANCEL_CUSTOM(x) (data->custom_error = (x), STATUS_CANCEL)
+
+typedef ParseStatus (*ParseValueFunction) (ParseData *data, ViviCodeValue **value);
+typedef ParseStatus (*ParseValueStatementFunction) (ParseData *data, ViviCodeValue **value, ViviCodeStatement **statement);
+typedef ParseStatus (*ParseStatementFunction) (ParseData *data, ViviCodeStatement **statement);
+
+static ParseStatus
+parse_statement_list (ParseData *data, ParseStatementFunction function, ViviCodeStatement **statement, guint separator);
+
+static ParseStatus
+parse_value_statement_list (ParseData *data,
+ ParseValueStatementFunction function, ViviCodeValue ***list,
+ ViviCodeStatement **statement, guint separator);
+
+static ParseStatus
+parse_value_list (ParseData *data, ParseValueFunction function,
+ ViviCodeValue ***list, guint separator);
+
+// helpers
+
+static const char *
+vivi_parser_token_name (guint token)
+{
+ if (token < TOKEN_LAST) {
+ return vivi_parser_scanner_token_name (token);
+ } else {
+ guint i;
+ const char *name;
+
+ name = NULL;
+ for (i = 0; error_names[i].token != TOKEN_LAST; i++) {
+ if (error_names[i].token == token) {
+ name = error_names[i].name;
+ break;
+ }
+ }
+
+ g_assert (name != NULL);
+
+ return name;
+ }
+}
+
+static gboolean
+check_line_terminator (ParseData *data)
+{
+ vivi_parser_scanner_peek_next_token (data->scanner);
+ return data->scanner->next_line_terminator;
+}
+
+static gboolean
+check_token (ParseData *data, ViviParserScannerToken token)
+{
+ vivi_parser_scanner_peek_next_token (data->scanner);
+ if (data->scanner->next_token != token)
+ return FALSE;
+ vivi_parser_scanner_get_next_token (data->scanner);
+ return TRUE;
+}
+
+static gboolean
+check_automatic_semicolon (ParseData *data)
+{
+ if (check_token (data, TOKEN_SEMICOLON))
+ return TRUE;
+ if (check_line_terminator (data))
+ return TRUE;
+
+ vivi_parser_scanner_peek_next_token (data->scanner);
+ if (data->scanner->next_token == TOKEN_BRACE_LEFT ||
+ data->scanner->next_token == TOKEN_EOF)
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+check_restricted_semicolon (ParseData *data)
+{
+ if (check_token (data, TOKEN_SEMICOLON))
+ return TRUE;
+ if (check_line_terminator (data))
+ return TRUE;
+
+ return FALSE;
+}
+
+static void
+free_value_list (ViviCodeValue **list)
+{
+ int i;
+
+ for (i = 0; list[i] != NULL; i++) {
+ g_object_unref (list[i]);
+ }
+ g_free (list);
+}
+
+G_GNUC_WARN_UNUSED_RESULT static ViviCodeStatement *
+vivi_parser_join_statements (ViviCodeStatement *one, ViviCodeStatement *two)
+{
+
+ if (one == NULL) {
+ return two;
+ } else if (two == NULL) {
+ return one;
+ }
+
+ if (VIVI_IS_CODE_BLOCK (one)) {
+ vivi_code_block_add_statement (VIVI_CODE_BLOCK (one), two);
+ g_object_unref (two);
+ return one;
+ } else if (VIVI_IS_CODE_BLOCK (two)) {
+ vivi_code_block_insert_statement (VIVI_CODE_BLOCK (two), 0, one);
+ g_object_unref (one);
+ return two;
+ } else {
+ ViviCodeStatement *block = vivi_code_block_new ();
+ vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), one);
+ g_object_unref (one);
+ vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), two);
+ g_object_unref (two);
+ return block;
+ }
+}
+
+static ViviCodeValue *
+vivi_parser_function_call_new (ViviCodeValue *name)
+{
+ ViviCodeValue *value;
+
+ g_return_val_if_fail (VIVI_IS_CODE_VALUE (name), NULL);
+
+ value = NULL;
+
+ if (VIVI_IS_CODE_GET (name)) {
+ ViviCodeGet *get = VIVI_CODE_GET (name);
+
+ if (get->from != NULL) {
+ value = g_object_ref (get->from);
+ name = g_object_ref (get->name);
+ }
+ }
+
+ if (VIVI_IS_CODE_GET (name)) {
+ ViviCodeGet *get = VIVI_CODE_GET (name);
+
+ if (get->from == NULL)
+ name = g_object_ref (get->name);
+ }
+
+ return vivi_code_function_call_new (value, name);
+}
+
+static ViviCodeStatement *
+vivi_parser_assignment_new (ViviCodeValue *left, ViviCodeValue *right)
+{
+ ViviCodeValue *from;
+
+ g_return_val_if_fail (VIVI_IS_CODE_VALUE (left), NULL);
+ g_return_val_if_fail (VIVI_IS_CODE_VALUE (right), NULL);
+
+ from = NULL;
+
+ if (VIVI_IS_CODE_GET (left)) {
+ ViviCodeGet *get = VIVI_CODE_GET (left);
+
+ if (get->from != NULL) {
+ from = g_object_ref (get->from);
+ left = g_object_ref (get->name);
+ }
+ }
+
+ if (VIVI_IS_CODE_GET (left)) {
+ ViviCodeGet *get = VIVI_CODE_GET (left);
+
+ if (get->from == NULL)
+ left = g_object_ref (get->name);
+ }
+
+ return vivi_code_assignment_new (from, left, right);
+}
+
+static ViviCodeValue *
+vivi_parser_get_new (ViviCodeValue *from, ViviCodeValue *name)
+{
+ g_return_val_if_fail (VIVI_IS_CODE_VALUE (from), NULL);
+ g_return_val_if_fail (VIVI_IS_CODE_VALUE (name), NULL);
+
+ if (VIVI_IS_CODE_GET (name)) {
+ ViviCodeGet *get = VIVI_CODE_GET (name);
+
+ if (get->from == NULL)
+ name = g_object_ref (get->name);
+ }
+
+ return vivi_code_get_new (from, name);
+}
+
+static gboolean
+vivi_parser_value_is_left_hand_side (ViviCodeValue *value)
+{
+ // FIXME: Correct?
+ return VIVI_IS_CODE_GET (value);
+}
+
+static gboolean
+vivi_parser_value_is_identifier (ViviCodeValue *value)
+{
+ if (!VIVI_IS_CODE_GET (value))
+ return FALSE;
+ return VIVI_IS_CODE_CONSTANT (VIVI_CODE_GET (value)->name);
+}
+
+static void
+vivi_parser_start_level (ParseData *data)
+{
+ g_return_if_fail (data != NULL);
+
+ if (data->level != NULL)
+ data->levels = g_slist_prepend (data->levels, data->level);
+ data->level = g_new0 (ParseLevel, 1);
+}
+
+static ViviCodeLabel *
+vivi_parser_find_label (ParseData *data, const char *name)
+{
+ GSList *iter;
+
+ for (iter = data->level->labels; iter != NULL; iter = iter->next) {
+ if (g_str_equal (vivi_code_label_get_name (VIVI_CODE_LABEL (iter->data)),
+ name))
+ return VIVI_CODE_LABEL (iter->data);
+ }
+
+ return NULL;
+}
+
+static ParseStatus
+vivi_parser_end_level (ParseData *data, gboolean fail)
+{
+ GSList *iter;
+ char *custom_error = NULL;
+
+ g_return_val_if_fail (data != NULL, STATUS_FAIL);
+ g_return_val_if_fail (data->level != NULL, STATUS_FAIL);
+
+ for (iter = data->level->gotos; iter != NULL; iter = iter->next) {
+ ViviCompilerGotoName *goto_;
+ ViviCodeLabel *label;
+
+ goto_ = VIVI_COMPILER_GOTO_NAME (iter->data);
+ label = vivi_parser_find_label (data,
+ vivi_compiler_goto_name_get_name (goto_));
+
+ if (label != NULL) {
+ vivi_compiler_goto_name_set_label (goto_, label);
+ } else {
+ if (custom_error == NULL) {
+ custom_error =
+ g_strdup_printf ("Label named '%s' doesn't exist in this block",
+ vivi_compiler_goto_name_get_name (goto_));
+ }
+ }
+
+ g_object_unref (goto_);
+ }
+ g_slist_free (data->level->gotos);
+
+ for (iter = data->level->labels; iter != NULL; iter = iter->next) {
+ g_object_unref (VIVI_CODE_LABEL (iter->data));
+ }
+ g_slist_free (data->level->labels);
+
+ g_free (data->level);
+
+ if (data->levels != NULL) {
+ data->level = data->levels->data;
+ data->levels = g_slist_delete_link (data->levels, data->levels);
+ } else {
+ data->level = NULL;
+ }
+
+ if (custom_error != NULL) {
+ if (fail) {
+ return FAIL_CUSTOM (custom_error);
+ } else {
+ return STATUS_FAIL;
+ }
+ } else {
+ return STATUS_OK;
+ }
+}
+
+static void
+vivi_parser_add_goto (ParseData *data, ViviCompilerGotoName *goto_)
+{
+ g_return_if_fail (data != NULL);
+ g_return_if_fail (data->level != NULL);
+ g_return_if_fail (VIVI_IS_COMPILER_GOTO_NAME (goto_));
+
+ data->level->gotos =
+ g_slist_prepend (data->level->gotos, g_object_ref (goto_));
+}
+
+static gboolean
+vivi_parser_add_label (ParseData *data, ViviCodeLabel *label)
+{
+ GSList *iter;
+
+ g_return_val_if_fail (data != NULL, FALSE);
+ g_return_val_if_fail (data->level != NULL, FALSE);
+ g_return_val_if_fail (VIVI_IS_CODE_LABEL (label), FALSE);
+
+ for (iter = data->level->labels; iter != NULL; iter = iter->next) {
+ if (g_str_equal (vivi_code_label_get_name (VIVI_CODE_LABEL (iter->data)),
+ vivi_code_label_get_name (label)))
+ return FALSE;
+ }
+
+ data->level->labels =
+ g_slist_prepend (data->level->labels, g_object_ref (label));
+
+ return TRUE;
+}
+
+// values
+
+/* ActionScript specific */
+static ParseStatus
+parse_undefined_literal (ParseData *data, ViviCodeValue **value)
+{
+ *value = NULL;
+
+ if (!check_token (data, TOKEN_UNDEFINED))
+ return CANCEL (TOKEN_UNDEFINED);
+
+ *value = vivi_code_constant_new_undefined ();
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_null_literal (ParseData *data, ViviCodeValue **value)
+{
+ *value = NULL;
+
+ if (!check_token (data, TOKEN_NULL))
+ return CANCEL (TOKEN_NULL);
+
+ *value = vivi_code_constant_new_null ();
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_boolean_literal (ParseData *data, ViviCodeValue **value)
+{
+ *value = NULL;
+
+ if (!check_token (data, TOKEN_BOOLEAN))
+ return CANCEL (TOKEN_BOOLEAN);
+
+ *value = vivi_code_constant_new_boolean (data->scanner->value.v_boolean);
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_numeric_literal (ParseData *data, ViviCodeValue **value)
+{
+ *value = NULL;
+
+ if (!check_token (data, TOKEN_NUMBER))
+ return CANCEL (TOKEN_NUMBER);
+
+ *value = vivi_code_constant_new_number (data->scanner->value.v_number);
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_string_literal (ParseData *data, ViviCodeValue **value)
+{
+ *value = NULL;
+
+ if (!check_token (data, TOKEN_STRING))
+ return CANCEL (TOKEN_STRING);
+
+ *value = vivi_code_constant_new_string (data->scanner->value.v_string);
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_literal (ParseData *data, ViviCodeValue **value)
+{
+ ParseStatus status;
+ int i;
+ ParseValueFunction functions[] = {
+ parse_undefined_literal,
+ parse_null_literal,
+ parse_boolean_literal,
+ parse_numeric_literal,
+ parse_string_literal,
+ NULL
+ };
+
+ *value = NULL;
+
+ for (i = 0; functions[i] != NULL; i++) {
+ status = functions[i] (data, value);
+ if (status != STATUS_CANCEL)
+ return status;
+ }
+
+ return CANCEL (ERROR_TOKEN_LITERAL);
+}
+
+static ParseStatus
+parse_identifier (ParseData *data, ViviCodeValue **value)
+{
+ *value = NULL;
+
+ if (!check_token (data, TOKEN_IDENTIFIER))
+ return CANCEL (TOKEN_IDENTIFIER);
+
+ *value = vivi_code_get_new_name (data->scanner->value.v_identifier);
+
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_property_name (ParseData *data, ViviCodeValue **value)
+{
+ ParseStatus status;
+ int i;
+ ParseValueFunction functions[] = {
+ parse_identifier,
+ parse_string_literal,
+ parse_numeric_literal,
+ NULL
+ };
+
+ *value = NULL;
+
+ for (i = 0; functions[i] != NULL; i++) {
+ status = functions[i] (data, value);
+ if (status != STATUS_CANCEL)
+ return status;
+ }
+
+ return CANCEL (ERROR_TOKEN_PROPERTY_NAME);
+}
+
+static ParseStatus
+parse_assignment_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement);
+
+static ParseStatus
+parse_array_literal (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement)
+{
+ ViviCodeValue *member;
+ ViviCodeStatement *statement_new;
+ ParseStatus status;
+
+ *value = NULL;
+ *statement = NULL;
+
+ if (!check_token (data, TOKEN_BRACKET_LEFT))
+ return CANCEL (TOKEN_BRACKET_LEFT);
+
+ *value = vivi_code_init_array_new ();
+
+ while (TRUE) {
+ if (check_token (data, TOKEN_BRACKET_RIGHT)) {
+ vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
+ vivi_code_constant_new_undefined ());
+ break;
+ } else if (check_token (data, TOKEN_COMMA)) {
+ vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
+ vivi_code_constant_new_undefined ());
+ } else {
+ status = parse_assignment_expression (data, &member, &statement_new);
+ if (status != STATUS_OK) {
+ if (*statement != NULL) {
+ g_object_unref (*statement);
+ *statement = NULL;
+ }
+ return FAIL_CHILD (status);
+ }
+
+ *statement = vivi_parser_join_statements (*statement, statement_new);
+
+ vivi_code_init_array_add_variable (VIVI_CODE_INIT_ARRAY (*value),
+ member);
+ g_object_unref (member);
+
+ if (!check_token (data, TOKEN_COMMA)) {
+ if (!check_token (data, TOKEN_BRACKET_RIGHT)) {
+ return FAIL_OR (TOKEN_BRACKET_RIGHT, TOKEN_COMMA);
+ }
+ break;
+ }
+ }
+ }
+
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_object_literal (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement)
+{
+ ParseStatus status;
+
+ *value = NULL;
+ *statement = NULL;
+
+ if (!check_token (data, TOKEN_BRACE_LEFT))
+ return CANCEL (TOKEN_BRACE_LEFT);
+
+ *value = vivi_code_init_object_new ();
+
+ if (!check_token (data, TOKEN_BRACE_RIGHT)) {
+ do {
+ ViviCodeValue *property, *initializer;
+ ViviCodeStatement *statement_new;
+
+ status = parse_property_name (data, &property);
+ if (status != STATUS_OK) {
+ g_object_unref (*value);
+ *value = NULL;
+ if (*statement != NULL) {
+ g_object_unref (*statement);
+ *statement = NULL;
+ }
+ return FAIL_CHILD (status);
+ }
+
+ if (!check_token (data, TOKEN_COLON)) {
+ g_object_unref (*value);
+ *value = NULL;
+ if (*statement != NULL) {
+ g_object_unref (*statement);
+ *statement = NULL;
+ }
+ return FAIL (TOKEN_COLON);
+ }
+
+ status = parse_assignment_expression (data, &initializer,
+ &statement_new);
+ if (status != STATUS_OK) {
+ g_object_unref (*value);
+ *value = NULL;
+ if (*statement != NULL) {
+ g_object_unref (*statement);
+ *statement = NULL;
+ }
+ return FAIL_CHILD (status);
+ }
+
+ *statement = vivi_parser_join_statements (*statement, statement_new);
+
+ vivi_code_init_object_add_variable (VIVI_CODE_INIT_OBJECT (*value),
+ property, initializer);
+ } while (check_token (data, TOKEN_COMMA));
+ }
+
+ if (!check_token (data, TOKEN_BRACE_RIGHT)) {
+ g_object_unref (*value);
+ *value = NULL;
+ if (*statement != NULL) {
+ g_object_unref (*statement);
+ *statement = NULL;
+ }
+ return FAIL (TOKEN_BRACE_RIGHT);
+ }
+
+ return STATUS_OK;
+}
+
+// misc
+
+static ParseStatus
+parse_variable_declaration (ParseData *data, ViviCodeStatement **statement)
+{
+ ParseStatus status;
+ ViviCodeValue *identifier, *value;
+ ViviCodeStatement *assignment, *statement_right;
+
+ *statement = NULL;
+
+ status = parse_identifier (data, &identifier);
+ if (status != STATUS_OK)
+ return status;
+
+ if (check_token (data, TOKEN_ASSIGN)) {
+ status = parse_assignment_expression (data, &value, &statement_right);
+ if (status != STATUS_OK) {
+ g_object_unref (identifier);
+ return FAIL_CHILD (status);
+ }
+ } else {
+ value = vivi_code_constant_new_undefined ();
+ statement_right = NULL;
+ }
+
+ assignment = vivi_parser_assignment_new (identifier, value);
+ vivi_code_assignment_set_local (VIVI_CODE_ASSIGNMENT (assignment), TRUE);
+
+ *statement = vivi_parser_join_statements (statement_right, assignment);
+
+ return STATUS_OK;
+}
+
+// expression
+
+static ParseStatus
+parse_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement);
+
+static ParseStatus
+parse_primary_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement)
+{
+ ParseStatus status;
+ int i;
+ ParseValueFunction functions[] = {
+ parse_identifier,
+ parse_literal,
+ NULL
+ };
+
+ *value = NULL;
+ *statement = NULL;
+
+ if (check_token (data, TOKEN_THIS)) {
+ *value = vivi_code_get_new_name ("this");
+ return STATUS_OK;
+ }
+
+ if (check_token (data, TOKEN_PARENTHESIS_LEFT)) {
+ status = parse_expression (data, value, statement);
+ if (status != STATUS_OK)
+ return FAIL_CHILD (status);
+ if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+ g_object_unref (*value);
+ *value = NULL;
+ return FAIL (TOKEN_PARENTHESIS_RIGHT);
+ }
+ return STATUS_OK;
+ }
+
+
+ status = parse_object_literal (data, value, statement);
+ if (status != STATUS_CANCEL)
+ return status;
+
+ status = parse_array_literal (data, value, statement);
+ if (status != STATUS_CANCEL)
+ return status;
+
+ for (i = 0; functions[i] != NULL; i++) {
+ status = functions[i] (data, value);
+ if (status != STATUS_CANCEL)
+ return status;
+ }
+
+ return CANCEL (ERROR_TOKEN_PRIMARY_EXPRESSION);
+}
+
+static ParseStatus
+parse_function_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement);
+
+static ParseStatus
+parse_member_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement)
+{
+ ParseStatus status;
+ ViviCodeValue *member;
+ ViviCodeStatement *statement_member;
+
+ *value = NULL;
+ *statement = NULL;
+
+ // TODO: new MemberExpression Arguments
+
+ status = parse_primary_expression (data, value, statement);
+ if (status == STATUS_CANCEL)
+ status = parse_function_expression (data, value, statement);
+
+ if (status != STATUS_OK)
+ return status;
+
+ do {
+ ViviCodeValue *tmp;
+
+ if (check_token (data, TOKEN_BRACKET_LEFT)) {
+ status = parse_expression (data, &member, &statement_member);
+ if (status != STATUS_OK) {
+ g_object_unref (*value);
+ *value = NULL;
+ if (*statement != NULL) {
+ g_object_unref (*statement);
+ *statement = NULL;
+ }
+ return FAIL_CHILD (status);
+ }
+
+ *statement =
+ vivi_parser_join_statements (*statement, statement_member);
+
+ if (!check_token (data, TOKEN_BRACKET_RIGHT)) {
+ g_object_unref (*value);
+ *value = NULL;
+ if (*statement != NULL) {
+ g_object_unref (*statement);
+ *statement = NULL;
+ }
+ return FAIL (TOKEN_BRACKET_RIGHT);
+ }
+ } else if (check_token (data, TOKEN_DOT)) {
+ status = parse_identifier (data, &member);
+ if (status != STATUS_OK)
+ return FAIL_CHILD (status);
+ } else {
+ return STATUS_OK;
+ }
+
+ tmp = *value;
+ *value = vivi_parser_get_new (tmp, member);
+ g_object_unref (tmp);
+ g_object_unref (member);
+ } while (TRUE);
+
+ g_assert_not_reached ();
+}
+
+static ParseStatus
+parse_new_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement)
+{
+ ParseStatus status;
+
+ *value = NULL;
+ *statement = NULL;
+
+ if (check_token (data, TOKEN_NEW)) {
+ status = parse_new_expression (data, value, statement);
+ if (status != STATUS_OK)
+ return FAIL_CHILD (status);
+ if (!VIVI_IS_CODE_FUNCTION_CALL (*value)) {
+ ViviCodeValue *tmp = VIVI_CODE_VALUE (*value);
+ *value = vivi_parser_function_call_new (tmp);
+ g_object_unref (tmp);
+ }
+ vivi_code_function_call_set_construct (VIVI_CODE_FUNCTION_CALL (*value),
+ TRUE);
+ return STATUS_OK;
+ } else {
+ return parse_member_expression (data, value, statement);
+ }
+}
+
+static ParseStatus
+parse_left_hand_side_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement)
+{
+ ParseStatus status;
+ int i;
+ ViviCodeValue *name;
+ ViviCodeValue **arguments;
+ ViviCodeStatement *argument_statement;
+
+ *value = NULL;
+ *statement = NULL;
+
+ if (check_token (data, TOKEN_NEW)) {
+ status = parse_new_expression (data, value, statement);
+ if (status != STATUS_OK)
+ return FAIL_CHILD (status);
+ if (!VIVI_IS_CODE_FUNCTION_CALL (*value)) {
+ ViviCodeValue *tmp = VIVI_CODE_VALUE (*value);
+ *value = vivi_parser_function_call_new (tmp);
+ g_object_unref (tmp);
+ }
+ vivi_code_function_call_set_construct (VIVI_CODE_FUNCTION_CALL (*value),
+ TRUE);
+ return STATUS_OK;
+ }
+
+ status = parse_member_expression (data, value, statement);
+ if (status != STATUS_OK)
+ return status;
+
+ while (TRUE) {
+ // TODO: member expressions?
+ if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
+ break;
+
+ if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+ status = parse_value_statement_list (data, parse_assignment_expression,
+ &arguments, &argument_statement, TOKEN_COMMA);
+ if (status != STATUS_OK) {
+ g_object_unref (*value);
+ *value = NULL;
+ if (*statement != NULL) {
+ g_object_unref (*statement);
+ *statement = NULL;
+ }
+ return FAIL_CHILD (status);
+ }
+
+ *statement =
+ vivi_parser_join_statements (*statement, argument_statement);
+
+ if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+ g_object_unref (*value);
+ *value = NULL;
+ if (*statement != NULL) {
+ g_object_unref (*statement);
+ *statement = NULL;
+ }
+ return FAIL (TOKEN_PARENTHESIS_RIGHT);
+ }
+ } else {
+ arguments = NULL;
+ }
+
+ name = *value;
+ *value = vivi_parser_function_call_new (name);
+ g_object_unref (name);
+
+ if (arguments != NULL) {
+ for (i = 0; arguments[i] != NULL; i++) {
+ vivi_code_function_call_add_argument (VIVI_CODE_FUNCTION_CALL (*value),
+ arguments[i]);
+ }
+ free_value_list (arguments);
+ }
+ }
+
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_postfix_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement)
+{
+ ParseStatus status;
+ ViviCodeValue *operation, *one, *temporary;
+ const char *operator;
+
+ *value = NULL;
+ *statement = NULL;
+
+ status = parse_left_hand_side_expression (data, value, statement);
+ if (status != STATUS_OK)
+ return status;
+
+ if (check_line_terminator (data))
+ return status;
+
+ if (check_token (data, TOKEN_INCREASE)) {
+ operator = "+";
+ } else if (check_token (data, TOKEN_DESCREASE)) {
+ operator = "-";
+ } else {
+ return STATUS_OK;
+ }
+
+ if (!vivi_parser_value_is_left_hand_side (*value)) {
+ g_object_unref (*value);
+ *value = NULL;
+ if (*statement != NULL) {
+ g_object_unref (*statement);
+ *statement = NULL;
+ }
+ return CANCEL_CUSTOM (g_strdup ("INCREASE/DECREASE not allowed here"));
+ }
+
+ one = vivi_code_constant_new_number (1);
+ operation = vivi_code_binary_new_name (*value, one, operator);
+ g_object_unref (one);
+
+ temporary = vivi_compiler_get_temporary_new ();
+ *statement = vivi_parser_join_statements (*statement,
+ vivi_parser_join_statements (
+ vivi_parser_assignment_new (temporary, *value),
+ vivi_parser_assignment_new (*value, operation)));
+ g_object_unref (operation);
+
+ g_object_unref (*value);
+ *value = temporary;
+
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_unary_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement)
+{
+ ParseStatus status;
+ ViviCodeValue *tmp, *one;
+ const char *operator;
+
+ *value = NULL;
+
+ operator = NULL;
+
+ vivi_parser_scanner_peek_next_token (data->scanner);
+ switch ((guint)data->scanner->next_token) {
+ /*case TOKEN_DELETE:
+ case TOKEN_VOID:
+ case TOKEN_TYPEOF:*/
+ case TOKEN_INCREASE:
+ operator = "+";
+ // fall through
+ case TOKEN_DESCREASE:
+ if (!operator) operator = "-";
+
+ vivi_parser_scanner_get_next_token (data->scanner);
+ status = parse_unary_expression (data, value, statement);
+ if (status != STATUS_OK)
+ return FAIL_CHILD (status);
+
+ if (!vivi_parser_value_is_left_hand_side (*value))
+ return CANCEL_CUSTOM (g_strdup ("INCREASE/DECREASE not allowed here"));
+
+ one = vivi_code_constant_new_number (1);
+ tmp = vivi_code_binary_new_name (*value, one, operator);
+ g_object_unref (one);
+
+ *statement = vivi_parser_join_statements (*statement,
+ vivi_parser_assignment_new (*value, tmp));
+ g_object_unref (tmp);
+
+ return STATUS_OK;
+ /*case TOKEN_PLUS:
+ case TOKEN_MINUS:
+ case TOKEN_BITWISE_NOT:*/
+ case TOKEN_LOGICAL_NOT:
+ vivi_parser_scanner_get_next_token (data->scanner);
+ status = parse_unary_expression (data, value, statement);
+ if (status != STATUS_OK)
+ return FAIL_CHILD (status);
+ tmp = VIVI_CODE_VALUE (*value);
+ *value = vivi_code_unary_new (tmp, '!');
+ g_object_unref (tmp);
+ return STATUS_OK;
+ default:
+ return parse_postfix_expression (data, value, statement);
+ }
+}
+
+typedef enum {
+ PASS_ALWAYS,
+ PASS_LOGICAL_OR,
+ PASS_LOGICAL_AND
+} ParseOperatorPass;
+
+static ParseStatus
+parse_operator_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement, const ViviParserScannerToken *tokens,
+ ParseOperatorPass pass, ParseValueStatementFunction next_parse_function)
+{
+ ParseStatus status;
+ int i;
+ ViviCodeValue *left, *right;
+ ViviCodeStatement *statement_right;
+
+ *value = NULL;
+ *statement = NULL;
+
+ status = next_parse_function (data, value, statement);
+ if (status != STATUS_OK)
+ return status;
+
+ for (i = 0; tokens[i] != STATUS_OK; i++) {
+ while (check_token (data, tokens[i])) {
+ status = next_parse_function (data, &right, &statement_right);
+ if (status != STATUS_OK) {
+ g_object_unref (*value);
+ *value = NULL;
+ return FAIL_CHILD (status);
+ }
+
+ if (statement_right != NULL) {
+ ViviCodeStatement *tmp;
+
+ switch (pass) {
+ case PASS_LOGICAL_OR:
+ tmp = vivi_code_if_new (vivi_code_unary_new (*value, '!'));
+ vivi_code_if_set_if (VIVI_CODE_IF (tmp), statement_right);
+ g_object_unref (statement_right);
+ statement_right = tmp;
+ break;
+ case PASS_LOGICAL_AND:
+ tmp = vivi_code_if_new (*value);
+ vivi_code_if_set_if (VIVI_CODE_IF (tmp), statement_right);
+ g_object_unref (statement_right);
+ statement_right = tmp;
+ break;
+ case PASS_ALWAYS:
+ // nothing
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ *statement =
+ vivi_parser_join_statements (*statement, statement_right);
+ }
+
+ left = VIVI_CODE_VALUE (*value);
+ *value = vivi_code_binary_new_name (left, VIVI_CODE_VALUE (right),
+ vivi_parser_scanner_token_name (tokens[i]));
+ g_object_unref (left);
+ g_object_unref (right);
+ };
+ }
+
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_multiplicative_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement)
+{
+ static const ViviParserScannerToken tokens[] = { TOKEN_MULTIPLY,
+ TOKEN_DIVIDE, TOKEN_REMAINDER, TOKEN_NONE };
+
+ return parse_operator_expression (data, value, statement, tokens,
+ PASS_ALWAYS, parse_unary_expression);
+}
+
+static ParseStatus
+parse_additive_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement)
+{
+ static const ViviParserScannerToken tokens[] = { TOKEN_PLUS, TOKEN_MINUS,
+ TOKEN_NONE };
+
+ return parse_operator_expression (data, value, statement, tokens,
+ PASS_ALWAYS, parse_multiplicative_expression);
+}
+
+static ParseStatus
+parse_shift_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement)
+{
+ static const ViviParserScannerToken tokens[] = { TOKEN_SHIFT_LEFT,
+ TOKEN_SHIFT_RIGHT, TOKEN_SHIFT_RIGHT_UNSIGNED, TOKEN_NONE };
+
+ return parse_operator_expression (data, value, statement, tokens,
+ PASS_ALWAYS, parse_additive_expression);
+}
+
+static ParseStatus
+parse_relational_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement)
+{
+ static const ViviParserScannerToken tokens[] = { TOKEN_LESS_THAN,
+ TOKEN_GREATER_THAN, /*TOKEN_LESS_THAN_OR_EQUAL,
+ TOKEN_EQUAL_OR_GREATER_THAN, TOKEN_INSTANCEOF, TOKEN_IN,*/ TOKEN_NONE };
+
+ return parse_operator_expression (data, value, statement, tokens,
+ PASS_ALWAYS, parse_shift_expression);
+}
+
+static ParseStatus
+parse_equality_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement)
+{
+ static const ViviParserScannerToken tokens[] = { TOKEN_EQUAL,
+ /*TOKEN_NOT_EQUAL,*/ TOKEN_STRICT_EQUAL, /*TOKEN_NOT_STRICT_EQUAL,*/
+ TOKEN_NONE };
+
+ return parse_operator_expression (data, value, statement, tokens,
+ PASS_ALWAYS, parse_relational_expression);
+}
+
+static ParseStatus
+parse_bitwise_and_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement)
+{
+ static const ViviParserScannerToken tokens[] = { TOKEN_BITWISE_AND,
+ TOKEN_NONE };
+
+ return parse_operator_expression (data, value, statement, tokens,
+ PASS_ALWAYS, parse_equality_expression);
+}
+
+static ParseStatus
+parse_bitwise_xor_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement)
+{
+ static const ViviParserScannerToken tokens[] = { TOKEN_BITWISE_XOR,
+ TOKEN_NONE };
+
+ return parse_operator_expression (data, value, statement, tokens,
+ PASS_ALWAYS, parse_bitwise_and_expression);
+}
+
+static ParseStatus
+parse_bitwise_or_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement)
+{
+ static const ViviParserScannerToken tokens[] = { TOKEN_BITWISE_OR,
+ TOKEN_NONE };
+
+ return parse_operator_expression (data, value, statement, tokens,
+ PASS_ALWAYS, parse_bitwise_xor_expression);
+}
+
+static ParseStatus
+parse_logical_and_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement)
+{
+ static const ViviParserScannerToken tokens[] = { TOKEN_LOGICAL_AND,
+ TOKEN_NONE };
+
+ return parse_operator_expression (data, value, statement, tokens,
+ PASS_LOGICAL_AND, parse_bitwise_or_expression);
+}
+
+static ParseStatus
+parse_logical_or_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement)
+{
+ static const ViviParserScannerToken tokens[] = { TOKEN_LOGICAL_OR,
+ TOKEN_NONE };
+
+ return parse_operator_expression (data, value, statement, tokens,
+ PASS_LOGICAL_OR, parse_logical_and_expression);
+}
+
+static ParseStatus
+parse_conditional_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement)
+{
+ ParseStatus status;
+ //ViviCodeStatement *if_statement, *else_statement;
+
+ *value = NULL;
+
+ status = parse_logical_or_expression (data, value, statement);
+ if (status != STATUS_OK)
+ return status;
+
+#if 0
+ if (!check_token (data, TOKEN_QUESTION_MARK)) {
+ *statement = vivi_code_value_statement_new (VIVI_CODE_VALUE (value));
+ g_object_unref (value);
+ return STATUS_OK;
+ }
+
+ status = parse_assignment_expression (data, &if_statement);
+ if (status != STATUS_OK) {
+ g_object_unref (value);
+ return FAIL_CHILD (status);
+ }
+
+ if (!check_token (data, TOKEN_COLON)) {
+ g_object_unref (value);
+ g_object_unref (if_statement);
+ return TOKEN_COLON;
+ }
+
+ status = parse_assignment_expression (data, &else_statement);
+ if (status != STATUS_OK) {
+ g_object_unref (value);
+ g_object_unref (if_statement);
+ return FAIL_CHILD (status);
+ }
+
+ *statement = vivi_code_if_new (value);
+ vivi_code_if_set_if (VIVI_CODE_IF (*statement), if_statement);
+ vivi_code_if_set_else (VIVI_CODE_IF (*statement), else_statement);
+
+ g_object_unref (value);
+ g_object_unref (if_statement);
+ g_object_unref (else_statement);
+#endif
+
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_assignment_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement)
+{
+ ParseStatus status;
+ ViviCodeValue *right;
+ ViviCodeStatement *assignment, *statement_right;
+ const char *operator;
+
+ *value = NULL;
+ *statement = NULL;
+
+ status = parse_conditional_expression (data, value, statement);
+ if (status != STATUS_OK)
+ return status;
+
+ if (!vivi_parser_value_is_left_hand_side (*value))
+ return STATUS_OK;
+
+ operator = NULL;
+
+ vivi_parser_scanner_peek_next_token (data->scanner);
+ switch ((int)data->scanner->next_token) {
+ case TOKEN_ASSIGN_MULTIPLY:
+ if (operator == NULL) operator = "*";
+ case TOKEN_ASSIGN_DIVIDE:
+ if (operator == NULL) operator = "/";
+ case TOKEN_ASSIGN_REMAINDER:
+ if (operator == NULL) operator = "%";
+ case TOKEN_ASSIGN_ADD:
+ if (operator == NULL) operator = "+";
+ case TOKEN_ASSIGN_MINUS:
+ if (operator == NULL) operator = "-";
+ case TOKEN_ASSIGN_SHIFT_LEFT:
+ if (operator == NULL) operator = "<<";
+ case TOKEN_ASSIGN_SHIFT_RIGHT:
+ if (operator == NULL) operator = ">>";
+ case TOKEN_ASSIGN_SHIFT_RIGHT_ZERO:
+ if (operator == NULL) operator = ">>>";
+ case TOKEN_ASSIGN_BITWISE_AND:
+ if (operator == NULL) operator = "&";
+ case TOKEN_ASSIGN_BITWISE_OR:
+ if (operator == NULL) operator = "|";
+ case TOKEN_ASSIGN_BITWISE_XOR:
+ if (operator == NULL) operator = "^";
+ case TOKEN_ASSIGN:
+ vivi_parser_scanner_get_next_token (data->scanner);
+ status = parse_assignment_expression (data, &right,
+ &statement_right);
+ if (status != STATUS_OK) {
+ g_object_unref (*value);
+ *value = NULL;
+ return FAIL_CHILD (status);
+ }
+
+ if (operator != NULL) {
+ assignment = vivi_parser_assignment_new (*value,
+ vivi_code_binary_new_name (*value, right, operator));
+ } else {
+ assignment = vivi_parser_assignment_new (*value, right);
+ }
+ g_object_unref (right);
+
+ *statement = vivi_parser_join_statements (*statement,
+ vivi_parser_join_statements (statement_right, assignment));
+
+ break;
+ default:
+ return STATUS_OK;
+ }
+
+
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement)
+{
+ ViviCodeStatement *statement_one;
+ ParseStatus status;
+
+ *statement = NULL;
+
+ status = parse_assignment_expression (data, value, &statement_one);
+ if (status != STATUS_OK)
+ return status;
+
+ while (TRUE) {
+ *statement = vivi_parser_join_statements (*statement, statement_one);
+
+ if (!check_token (data, TOKEN_COMMA))
+ break;
+
+ g_object_unref (*value);
+
+ status = parse_assignment_expression (data, value, &statement_one);
+ if (status != STATUS_OK) {
+ g_object_unref (*value);
+ *value = NULL;
+ g_object_unref (*statement);
+ *statement = NULL;
+ return FAIL_CHILD (status);
+ }
+ }
+
+ return STATUS_OK;
+}
+
+// statement
+
+static ParseStatus
+parse_statement (ParseData *data, ViviCodeStatement **statement);
+
+static ParseStatus
+parse_trace_statement (ParseData *data, ViviCodeStatement **statement)
+{
+ ViviCodeValue *value;
+ ViviCodeStatement *expression_statement;
+ ParseStatus status;
+
+ *statement = NULL;
+
+ if (!check_token (data, TOKEN_TRACE))
+ return CANCEL (TOKEN_TRACE);
+
+ if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
+ return FAIL (TOKEN_PARENTHESIS_LEFT);
+
+ status = parse_expression (data, &value, &expression_statement);
+ if (status != STATUS_OK)
+ return FAIL_CHILD (status);
+
+ if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+ g_object_unref (value);
+ if (expression_statement != NULL)
+ g_object_unref (expression_statement);
+ return FAIL (TOKEN_PARENTHESIS_RIGHT);
+ }
+
+ if (!check_automatic_semicolon (data)) {
+ g_object_unref (value);
+ if (expression_statement != NULL)
+ g_object_unref (expression_statement);
+ return FAIL (TOKEN_SEMICOLON);
+ }
+
+ *statement = vivi_code_trace_new (value);
+ g_object_unref (value);
+
+ *statement =
+ vivi_parser_join_statements (expression_statement, *statement);
+
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_continue_or_break_statement (ParseData *data,
+ ViviCodeStatement **statement, ViviParserScannerToken token)
+{
+ *statement = NULL;
+
+ if (!check_token (data, token))
+ return CANCEL (token);
+
+ if (!check_restricted_semicolon (data)) {
+ ParseStatus status;
+ ViviCodeValue *identifier;
+
+ status = parse_identifier (data, &identifier);
+ *statement = vivi_compiler_goto_name_new (
+ vivi_code_constant_get_variable_name (
+ VIVI_CODE_CONSTANT (VIVI_CODE_GET (identifier)->name)));
+ g_object_unref (identifier);
+
+ vivi_parser_add_goto (data, VIVI_COMPILER_GOTO_NAME (*statement));
+
+ if (!check_automatic_semicolon (data)) {
+ g_object_unref (*statement);
+ *statement = NULL;
+ return FAIL (TOKEN_SEMICOLON);
+ }
+ } else {
+ *statement = vivi_code_break_new ();
+ }
+
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_continue_statement (ParseData *data, ViviCodeStatement **statement)
+{
+ return parse_continue_or_break_statement (data, statement, TOKEN_CONTINUE);
+}
+
+static ParseStatus
+parse_break_statement (ParseData *data, ViviCodeStatement **statement)
+{
+ return parse_continue_or_break_statement (data, statement, TOKEN_BREAK);
+}
+
+static ParseStatus
+parse_throw_statement (ParseData *data, ViviCodeStatement **statement)
+{
+ ParseStatus status;
+ ViviCodeValue *value;
+ ViviCodeStatement *expression_statement;
+
+ *statement = NULL;
+
+ if (!check_token (data, TOKEN_THROW))
+ return CANCEL (TOKEN_THROW);
+
+ if (check_line_terminator (data))
+ return FAIL_LINE_TERMINATOR (ERROR_TOKEN_EXPRESSION);
+
+ status = parse_expression (data, &value, &expression_statement);
+ if (status != STATUS_OK)
+ return FAIL_CHILD (status);
+
+ *statement = vivi_code_throw_new (value);
+ g_object_unref (value);
+
+ *statement =
+ vivi_parser_join_statements (expression_statement, *statement);
+
+ if (!check_automatic_semicolon (data)) {
+ g_object_unref (*statement);
+ *statement = NULL;
+ return FAIL (TOKEN_SEMICOLON);
+ }
+
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_return_statement (ParseData *data, ViviCodeStatement **statement)
+{
+ *statement = NULL;
+
+ if (!check_token (data, TOKEN_RETURN))
+ return CANCEL (TOKEN_RETURN);
+
+ *statement = vivi_code_return_new ();
+
+ if (!check_restricted_semicolon (data)) {
+ ParseStatus status;
+ ViviCodeValue *value;
+ ViviCodeStatement *expression_statement;
+
+ status = parse_expression (data, &value, &expression_statement);
+ if (status != STATUS_OK) {
+ g_object_unref (*statement);
+ *statement = NULL;
+ return FAIL_CHILD (status);
+ }
+
+ vivi_code_return_set_value (VIVI_CODE_RETURN (*statement), value);
+ g_object_unref (value);
+
+ *statement =
+ vivi_parser_join_statements (expression_statement, *statement);
+
+ if (!check_automatic_semicolon (data)) {
+ g_object_unref (*statement);
+ *statement = NULL;
+ return FAIL (TOKEN_SEMICOLON);
+ }
+ }
+
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_iteration_statement (ParseData *data, ViviCodeStatement **statement)
+{
+ ParseStatus status;
+ ViviCodeValue *condition;
+ ViviCodeStatement *pre_statement, *condition_statement, *loop_statement;
+
+ *statement = NULL;
+
+ pre_statement = NULL;
+ condition_statement = NULL;
+
+ if (check_token (data, TOKEN_DO)) {
+ status = parse_statement (data, &loop_statement);
+ if (status != STATUS_OK)
+ return FAIL_CHILD (status);
+
+ if (!check_token (data, TOKEN_WHILE)) {
+ g_object_unref (loop_statement);
+ return FAIL (TOKEN_WHILE);
+ }
+
+ if (!check_token (data, TOKEN_PARENTHESIS_LEFT)) {
+ g_object_unref (loop_statement);
+ return FAIL (TOKEN_PARENTHESIS_LEFT);
+ }
+
+ status = parse_expression (data, &condition, &condition_statement);
+ if (status != STATUS_OK) {
+ g_object_unref (loop_statement);
+ return FAIL_CHILD (status);
+ }
+
+ if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+ g_object_unref (loop_statement);
+ g_object_unref (condition);
+ if (condition_statement != NULL)
+ g_object_unref (condition_statement);
+ return FAIL (TOKEN_PARENTHESIS_LEFT);
+ }
+
+ if (!check_automatic_semicolon (data)) {
+ g_object_unref (loop_statement);
+ g_object_unref (condition);
+ if (condition_statement != NULL)
+ g_object_unref (condition_statement);
+ return FAIL (TOKEN_PARENTHESIS_LEFT);
+ }
+
+ pre_statement = g_object_ref (loop_statement);
+ } else if (check_token (data, TOKEN_WHILE)) {
+ if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
+ return FAIL (TOKEN_PARENTHESIS_LEFT);
+
+ status = parse_expression (data, &condition, &condition_statement);
+ if (status != STATUS_OK)
+ return FAIL_CHILD (status);
+
+ if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+ g_object_unref (condition);
+ if (condition_statement != NULL)
+ g_object_unref (condition_statement);
+ return FAIL (TOKEN_PARENTHESIS_RIGHT);
+ }
+
+ status = parse_statement (data, &loop_statement);
+ if (status != STATUS_OK) {
+ g_object_unref (condition);
+ if (condition_statement != NULL)
+ g_object_unref (condition_statement);
+ return FAIL_CHILD (status);
+ }
+ } else if (check_token (data, TOKEN_FOR)) {
+ ViviCodeValue *pre_value;
+ ViviCodeStatement *post_statement;
+
+ if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
+ return FAIL (TOKEN_PARENTHESIS_LEFT);
+
+ if (check_token (data, TOKEN_VAR)) {
+ // FIXME: no in
+ status = parse_statement_list (data, parse_variable_declaration,
+ &pre_statement, TOKEN_COMMA);
+ if (status != STATUS_OK)
+ return FAIL_CHILD (status);
+ // FIXME: ugly
+ // If there was only one VariableDeclaration, get the name for pre_value
+ g_assert (VIVI_IS_CODE_BLOCK (pre_statement));
+ if (vivi_code_block_get_n_statements (VIVI_CODE_BLOCK (pre_statement))
+ == 1) {
+ ViviCodeAssignment *assignment = VIVI_CODE_ASSIGNMENT (
+ vivi_code_block_get_statement (VIVI_CODE_BLOCK (pre_statement), 0));
+ g_assert (assignment->from == NULL);
+ pre_value = vivi_code_get_new (NULL, assignment->name);
+ } else {
+ pre_value = NULL;
+ }
+ } else {
+ if (!check_token (data, TOKEN_SEMICOLON)) {
+ // FIXME: no in
+ status = parse_expression (data, &pre_value, &pre_statement);
+ if (status != STATUS_OK)
+ return FAIL_CHILD (status);
+ } else {
+ pre_value = NULL;
+ pre_statement = NULL;
+ }
+ }
+
+ if (check_token (data, TOKEN_SEMICOLON)) {
+ if (pre_value != NULL)
+ g_object_unref (pre_value);
+ if (!check_token (data, TOKEN_SEMICOLON)) {
+ status = parse_expression (data, &condition, &condition_statement);
+ if (status != STATUS_OK)
+ return FAIL_CHILD (status);
+
+ if (!check_token (data, TOKEN_SEMICOLON)) {
+ if (pre_statement != NULL)
+ g_object_unref (pre_statement);
+ g_object_unref (condition);
+ if (condition_statement != NULL)
+ g_object_unref (condition_statement);
+ return FAIL (TOKEN_SEMICOLON);
+ }
+ }
+
+ status = parse_expression (data, &pre_value, &post_statement);
+ if (status != STATUS_OK) {
+ if (pre_statement != NULL)
+ g_object_unref (pre_statement);
+ g_object_unref (condition);
+ if (condition_statement != NULL)
+ g_object_unref (condition_statement);
+ return FAIL_CHILD (status);
+ }
+ g_object_unref (pre_value);
+ } else if (pre_value != NULL && check_token (data, TOKEN_IN)) {
+ post_statement = NULL;
+
+ if (!vivi_parser_value_is_left_hand_side (pre_value)) {
+ g_object_unref (pre_value);
+ if (pre_statement != NULL)
+ g_object_unref (pre_statement);
+ return FAIL_CUSTOM (g_strdup (
+ "Invalid left hand side expression for in"));
+ }
+
+ g_object_unref (pre_value);
+ if (pre_statement != NULL)
+ g_object_unref (pre_statement);
+ return FAIL_CUSTOM (g_strdup (
+ "for (... in ...) has not been implemented yet"));
+ } else {
+ ViviParserScannerToken fail_token;
+
+ if (pre_value != NULL) {
+ fail_token = TOKEN_IN;
+ g_object_unref (pre_value);
+ } else {
+ fail_token = TOKEN_NONE;
+ }
+
+ if (pre_statement != NULL)
+ g_object_unref (pre_statement);
+
+ return FAIL_OR (TOKEN_SEMICOLON, fail_token);
+ }
+
+ if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+ if (pre_statement != NULL)
+ g_object_unref (pre_statement);
+ g_object_unref (condition);
+ if (condition_statement != NULL)
+ g_object_unref (condition_statement);
+ g_object_unref (post_statement);
+ return FAIL (TOKEN_PARENTHESIS_RIGHT);
+ }
+
+ status = parse_statement (data, &loop_statement);
+ if (status != STATUS_OK) {
+ if (pre_statement != NULL)
+ g_object_unref (pre_statement);
+ g_object_unref (condition);
+ if (condition_statement != NULL)
+ g_object_unref (condition_statement);
+ g_object_unref (post_statement);
+ return FAIL_CHILD (status);
+ }
+
+ loop_statement =
+ vivi_parser_join_statements (loop_statement, post_statement);
+ } else {
+ return CANCEL (ERROR_TOKEN_ITERATION_STATEMENT);
+ }
+
+ if (condition_statement != NULL) {
+ pre_statement = vivi_parser_join_statements (pre_statement,
+ g_object_ref (condition_statement));
+ loop_statement = vivi_parser_join_statements (loop_statement,
+ g_object_ref (condition_statement));
+ g_object_unref (condition_statement);
+ }
+
+ *statement = vivi_code_loop_new ();
+ vivi_code_loop_set_condition (VIVI_CODE_LOOP (*statement), condition);
+ g_object_unref (condition);
+ vivi_code_loop_set_statement (VIVI_CODE_LOOP (*statement), loop_statement);
+ g_object_unref (loop_statement);
+
+ *statement = vivi_parser_join_statements (pre_statement, *statement);
+
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_if_statement (ParseData *data, ViviCodeStatement **statement)
+{
+ ParseStatus status;
+ ViviCodeValue *condition;
+ ViviCodeStatement *pre_statement, *if_statement, *else_statement;
+
+ *statement = NULL;
+
+ if (!check_token (data, TOKEN_IF))
+ return CANCEL (TOKEN_IF);
+
+ if (!check_token (data, TOKEN_PARENTHESIS_LEFT))
+ return FAIL (TOKEN_PARENTHESIS_LEFT);
+
+ status = parse_expression (data, &condition, &pre_statement);
+ if (status != STATUS_OK)
+ return FAIL_CHILD (status);
+
+ if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+ g_object_unref (condition);
+ if (pre_statement != NULL) {
+ g_object_unref (pre_statement);
+ pre_statement = NULL;
+ }
+ return FAIL (TOKEN_PARENTHESIS_RIGHT);
+ }
+
+ status = parse_statement (data, &if_statement);
+ if (status != STATUS_OK) {
+ g_object_unref (condition);
+ if (pre_statement != NULL) {
+ g_object_unref (pre_statement);
+ pre_statement = NULL;
+ }
+ return FAIL_CHILD (status);
+ }
+
+ if (check_token (data, TOKEN_ELSE)) {
+ status = parse_statement (data, &else_statement);
+ if (status != STATUS_OK) {
+ g_object_unref (condition);
+ if (pre_statement != NULL) {
+ g_object_unref (pre_statement);
+ pre_statement = NULL;
+ }
+ g_object_unref (if_statement);
+ return FAIL_CHILD (status);
+ }
+ } else {
+ else_statement = NULL;
+ }
+
+ *statement = vivi_code_if_new (condition);
+ g_object_unref (condition);
+
+ vivi_code_if_set_if (VIVI_CODE_IF (*statement), if_statement);
+ g_object_unref (if_statement);
+
+ if (else_statement != NULL) {
+ vivi_code_if_set_else (VIVI_CODE_IF (*statement), else_statement);
+ g_object_unref (else_statement);
+ }
+
+ *statement = vivi_parser_join_statements (pre_statement, *statement);
+
+ g_assert (*statement != NULL);
+
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_expression_statement (ParseData *data, ViviCodeStatement **statement)
+{
+ ParseStatus status;
+ ViviCodeValue *value;
+ ViviCodeStatement *last;
+
+ *statement = NULL;
+
+ vivi_parser_scanner_peek_next_token (data->scanner);
+ if (data->scanner->next_token == TOKEN_BRACE_LEFT ||
+ data->scanner->next_token == TOKEN_FUNCTION)
+ return CANCEL (ERROR_TOKEN_EXPRESSION_STATEMENT);
+
+ status = parse_expression (data, &value, statement);
+ if (status != STATUS_OK)
+ return status;
+
+ // check for label
+ if (*statement == NULL && vivi_parser_value_is_identifier (value)) {
+ if (check_token (data, TOKEN_COLON)) {
+ *statement = vivi_code_label_new (vivi_code_constant_get_variable_name (
+ VIVI_CODE_CONSTANT (VIVI_CODE_GET (value)->name)));
+ if (!vivi_parser_add_label (data, VIVI_CODE_LABEL (*statement)))
+ return FAIL_CUSTOM (g_strdup ("Same label name used twice"));
+ return STATUS_OK;
+ }
+ }
+
+ if (!check_automatic_semicolon (data)) {
+ g_object_unref (value);
+ if (*statement != NULL) {
+ g_object_unref (*statement);
+ *statement = NULL;
+ }
+ return FAIL (TOKEN_SEMICOLON);
+ }
+
+ // add a value statement, if the last statement is not an assignment with the
+ // same value
+ if (VIVI_IS_CODE_BLOCK (*statement)) {
+ ViviCodeBlock *block = VIVI_CODE_BLOCK (*statement);
+
+ last = vivi_code_block_get_statement (block,
+ vivi_code_block_get_n_statements (block) - 1);
+ } else {
+ last = *statement;
+ }
+
+ if (VIVI_IS_CODE_ASSIGNMENT (last) && VIVI_IS_CODE_GET (value)) {
+ ViviCodeAssignment *assignment = VIVI_CODE_ASSIGNMENT (last);
+
+ if (assignment->from == NULL && assignment->name == VIVI_CODE_GET (value)->name) {
+ g_object_unref (value);
+ return STATUS_OK;
+ }
+ }
+
+ *statement = vivi_parser_join_statements (*statement,
+ vivi_code_value_statement_new (value));
+ g_object_unref (value);
+
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_empty_statement (ParseData *data, ViviCodeStatement **statement)
+{
+ *statement = NULL;
+
+ if (!check_token (data, TOKEN_SEMICOLON))
+ return CANCEL (TOKEN_SEMICOLON);
+
+ *statement = vivi_compiler_empty_statement_new ();
+
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_block (ParseData *data, ViviCodeStatement **statement)
+{
+ ParseStatus status;
+
+ *statement = NULL;
+
+ if (!check_token (data, TOKEN_BRACE_LEFT))
+ return CANCEL (TOKEN_BRACE_LEFT);
+
+ vivi_parser_scanner_peek_next_token (data->scanner);
+ if (data->scanner->next_token != TOKEN_BRACE_RIGHT) {
+ status =
+ parse_statement_list (data, parse_statement, statement, STATUS_OK);
+ if (status != STATUS_OK)
+ return FAIL_CHILD (status);
+ } else {
+ *statement = vivi_code_block_new ();
+ }
+
+ if (!check_token (data, TOKEN_BRACE_RIGHT)) {
+ g_object_unref (*statement);
+ *statement = NULL;
+ return FAIL (TOKEN_BRACE_RIGHT);
+ }
+
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_variable_statement (ParseData *data, ViviCodeStatement **statement)
+{
+ ParseStatus status;
+
+ *statement = NULL;
+
+ if (!check_token (data, TOKEN_VAR))
+ return CANCEL (TOKEN_VAR);
+
+ status = parse_statement_list (data, parse_variable_declaration, statement,
+ TOKEN_COMMA);
+ if (status != STATUS_OK)
+ return FAIL_CHILD (status);
+
+ if (!check_automatic_semicolon (data)) {
+ g_object_unref (*statement);
+ *statement = NULL;
+ return FAIL (TOKEN_SEMICOLON);
+ }
+
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_statement (ParseData *data, ViviCodeStatement **statement)
+{
+ ParseStatus status;
+ int i;
+ ParseStatementFunction functions[] = {
+ parse_block,
+ parse_variable_statement,
+ parse_empty_statement,
+ parse_expression_statement,
+ parse_if_statement,
+ parse_iteration_statement,
+ parse_continue_statement,
+ parse_break_statement,
+ parse_return_statement,
+ //parse_with_statement,
+ //parse_switch_statement,
+ parse_throw_statement,
+ //parse_try_statement,
+ parse_trace_statement,
+ NULL
+ };
+
+ *statement = NULL;
+
+ for (i = 0; functions[i] != NULL; i++) {
+ status = functions[i] (data, statement);
+ if (status != STATUS_CANCEL)
+ return status;
+ }
+
+ return CANCEL (ERROR_TOKEN_STATEMENT);
+}
+
+// function
+
+static ParseStatus
+parse_source_element (ParseData *data, ViviCodeStatement **statement);
+
+static ParseStatus
+parse_function_definition (ParseData *data, ViviCodeValue **function,
+ ViviCodeValue **identifier, gboolean identifier_required)
+{
+ ParseStatus status;
+ ViviCodeValue **arguments;
+ ViviCodeStatement *body;
+ guint i;
+
+ *function = NULL;
+ *identifier = NULL;
+
+ arguments = NULL;
+ body = NULL;
+
+ if (!check_token (data, TOKEN_FUNCTION))
+ return CANCEL (TOKEN_FUNCTION);
+
+ status = parse_identifier (data, identifier);
+ if (status == STATUS_FAIL ||
+ (identifier_required && status == STATUS_CANCEL))
+ return FAIL_CHILD (status);
+
+ if (!check_token (data, TOKEN_PARENTHESIS_LEFT)) {
+ g_object_unref (*identifier);
+ return FAIL (TOKEN_PARENTHESIS_LEFT);
+ }
+
+ status = parse_value_list (data, parse_identifier, &arguments, TOKEN_COMMA);
+ if (status == STATUS_FAIL) {
+ g_object_unref (*identifier);
+ return STATUS_FAIL;
+ }
+
+ if (!check_token (data, TOKEN_PARENTHESIS_RIGHT)) {
+ g_object_unref (*identifier);
+ if (arguments != NULL)
+ free_value_list (arguments);
+ return FAIL (TOKEN_PARENTHESIS_RIGHT);
+ }
+
+ if (!check_token (data, TOKEN_BRACE_LEFT)) {
+ g_object_unref (*identifier);
+ if (arguments != NULL)
+ free_value_list (arguments);
+ return FAIL (TOKEN_BRACE_LEFT);
+ }
+
+ vivi_parser_start_level (data);
+
+ status = parse_statement_list (data, parse_source_element, &body, STATUS_OK);
+ if (status == STATUS_FAIL) {
+ vivi_parser_end_level (data, FALSE);
+ g_object_unref (*identifier);
+ if (arguments != NULL)
+ free_value_list (arguments);
+ return STATUS_FAIL;
+ }
+
+ status = vivi_parser_end_level (data, TRUE);
+ if (status != STATUS_OK) {
+ g_object_unref (*identifier);
+ if (arguments != NULL)
+ free_value_list (arguments);
+ return FAIL_CHILD (status);
+ }
+
+ if (!check_token (data, TOKEN_BRACE_RIGHT)) {
+ g_object_unref (*identifier);
+ if (arguments != NULL)
+ free_value_list (arguments);
+ g_object_unref (body);
+ return FAIL (TOKEN_BRACE_RIGHT);
+ }
+
+ *function = vivi_code_function_new ();
+ if (body != NULL) {
+ vivi_code_function_set_body (VIVI_CODE_FUNCTION (*function), body);
+ g_object_unref (body);
+ }
+ if (arguments != NULL) {
+ for (i = 0; arguments[i] != NULL; i++) {
+ vivi_code_function_add_argument (VIVI_CODE_FUNCTION (*function),
+ vivi_code_constant_get_variable_name (VIVI_CODE_CONSTANT (
+ VIVI_CODE_GET (arguments[i])->name)));
+ }
+ free_value_list (arguments);
+ }
+
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_function_declaration (ParseData *data, ViviCodeStatement **statement)
+{
+ ParseStatus status;
+ ViviCodeValue *function, *identifier;
+
+ *statement = NULL;
+
+ status = parse_function_definition (data, &function, &identifier, TRUE);
+ if (status != STATUS_OK)
+ return status;
+
+ *statement = vivi_parser_assignment_new (identifier, function);
+ g_object_unref (identifier);
+ g_object_unref (function);
+
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_function_expression (ParseData *data, ViviCodeValue **value,
+ ViviCodeStatement **statement)
+{
+ ParseStatus status;
+ ViviCodeValue *identifier;
+
+ *statement = NULL;
+
+ status = parse_function_definition (data, value, &identifier, FALSE);
+ if (status != STATUS_OK)
+ return status;
+
+ if (identifier != NULL) {
+ *statement = vivi_parser_assignment_new (identifier, *value);
+ g_object_unref (identifier);
+ }
+
+ return STATUS_OK;
+}
+
+// top
+
+static ParseStatus
+parse_source_element (ParseData *data, ViviCodeStatement **statement)
+{
+ ParseStatus status;
+
+ *statement = NULL;
+
+ status = parse_function_declaration (data, statement);
+ if (status == STATUS_CANCEL)
+ status = parse_statement (data, statement);
+
+ return status;
+}
+
+static ParseStatus
+parse_program (ParseData *data, ViviCodeStatement **statement)
+{
+ ParseStatus status;
+
+ g_assert (data->level == NULL);
+ vivi_parser_start_level (data);
+
+ *statement = NULL;
+
+ status =
+ parse_statement_list (data, parse_source_element, statement, STATUS_OK);
+ if (status != STATUS_OK) {
+ vivi_parser_end_level (data, FALSE);
+ return FAIL_CHILD (status);
+ }
+
+ if (!check_token (data, TOKEN_EOF)) {
+ vivi_parser_end_level (data, FALSE);
+ g_object_unref (*statement);
+ *statement = NULL;
+ status = parse_statement (data, statement);
+ return FAIL_CHILD (status);
+ }
+
+
+ status = vivi_parser_end_level (data, TRUE);
+ if (status != STATUS_OK) {
+ g_object_unref (*statement);
+ *statement = NULL;
+ return FAIL_CHILD (status);
+ }
+
+ g_assert (data->level == NULL);
+
+ return STATUS_OK;
+}
+
+// parsing
+
+static ParseStatus
+parse_statement_list (ParseData *data, ParseStatementFunction function,
+ ViviCodeStatement **block, guint separator)
+{
+ ViviCodeStatement *statement;
+ ParseStatus status;
+
+ g_assert (data != NULL);
+ g_assert (function != NULL);
+ g_assert (block != NULL);
+
+ *block = NULL;
+
+ status = function (data, &statement);
+ if (status != STATUS_OK)
+ return status;
+
+ *block = vivi_code_block_new ();
+
+ do {
+ vivi_code_block_add_statement (VIVI_CODE_BLOCK (*block), statement);
+ g_object_unref (statement);
+
+ if (separator != STATUS_OK && !check_token (data, separator))
+ break;
+
+ status = function (data, &statement);
+ if (status == STATUS_FAIL) {
+ g_object_unref (*block);
+ *block = NULL;
+ return STATUS_FAIL;
+ }
+ } while (status == STATUS_OK);
+
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_value_statement_list (ParseData *data,
+ ParseValueStatementFunction function, ViviCodeValue ***list,
+ ViviCodeStatement **statement, guint separator)
+{
+ GPtrArray *array;
+ ViviCodeValue *value;
+ ViviCodeStatement *statement_one;
+ ParseStatus status;
+
+ g_assert (data != NULL);
+ g_assert (function != NULL);
+ g_assert (list != NULL);
+ g_assert (statement != NULL);
+
+ *list = NULL;
+ *statement = NULL;
+
+ status = function (data, &value, statement);
+ if (status != STATUS_OK)
+ return status;
+
+ array = g_ptr_array_new ();
+
+ do {
+ g_ptr_array_add (array, value);
+
+ if (separator != TOKEN_NONE && !check_token (data, separator))
+ break;
+
+ status = function (data, &value, &statement_one);
+ if (status != STATUS_OK) {
+ if (status == STATUS_FAIL || separator != TOKEN_NONE)
+ return FAIL_CHILD (status);
+ } else {
+ *statement = vivi_parser_join_statements (*statement, statement_one);
+ }
+ } while (status == STATUS_OK);
+ g_ptr_array_add (array, NULL);
+
+ *list = (ViviCodeValue **)g_ptr_array_free (array, FALSE);
+
+ return STATUS_OK;
+}
+
+static ParseStatus
+parse_value_list (ParseData *data, ParseValueFunction function,
+ ViviCodeValue ***list, guint separator)
+{
+ GPtrArray *array;
+ ViviCodeValue *value;
+ ParseStatus status;
+
+ g_assert (data != NULL);
+ g_assert (function != NULL);
+ g_assert (list != NULL);
+
+ *list = NULL;
+
+ status = function (data, &value);
+ if (status != STATUS_OK)
+ return status;
+
+ array = g_ptr_array_new ();
+
+ do {
+ g_ptr_array_add (array, value);
+
+ if (separator != STATUS_OK && !check_token (data, separator))
+ break;
+
+ status = function (data, &value);
+ if (status == STATUS_FAIL)
+ return STATUS_FAIL;
+ } while (status == STATUS_OK);
+ g_ptr_array_add (array, NULL);
+
+ *list = (ViviCodeValue **)g_ptr_array_free (array, FALSE);
+
+ return STATUS_OK;
+}
+
+// public
+
+ViviCodeStatement *
+vivi_parse_file (FILE *file, const char *input_name)
+{
+ ParseData data;
+ ViviCodeStatement *statement;
+ ParseStatus status;
+
+ g_return_val_if_fail (file != NULL, NULL);
+
+ data.scanner = vivi_parser_scanner_new (file);
+ data.unexpected_line_terminator = FALSE;
+ data.expected[0] = TOKEN_NONE;
+ data.expected[1] = TOKEN_NONE;
+ data.custom_error = NULL;
+ data.levels = NULL;
+ data.level = NULL;
+
+ status = parse_program (&data, &statement);
+ g_assert ((status == STATUS_OK && VIVI_IS_CODE_STATEMENT (statement)) ||
+ (status != STATUS_OK && statement == NULL));
+ g_assert (status >= 0);
+
+ if (status != STATUS_OK) {
+ g_printerr ("%s:%i:%i: error: ", input_name,
+ vivi_parser_scanner_cur_line (data.scanner),
+ vivi_parser_scanner_cur_column (data.scanner));
+
+ if (data.custom_error != NULL) {
+ g_printerr ("%s\n", data.custom_error);
+ g_free (data.custom_error);
+ } else {
+ vivi_parser_scanner_get_next_token (data.scanner);
+
+ g_printerr ("Expected %s ", vivi_parser_token_name (data.expected[0]));
+ if (data.expected[1] != TOKEN_NONE)
+ g_printerr ("or %s ", vivi_parser_token_name (data.expected[1]));
+
+ if (data.unexpected_line_terminator) {
+ g_printerr ("before %s token\n",
+ vivi_parser_token_name (TOKEN_LINE_TERMINATOR));
+ } else {
+ g_printerr ("before %s token\n",
+ vivi_parser_token_name (data.scanner->token));
+ }
+ }
+ }
+
+ g_object_unref (data.scanner);
+
+ return statement;
+}
diff --git a/vivified/code/vivi_parser.h b/vivified/code/vivi_parser.h
new file mode 100644
index 0000000..82cbe89
--- /dev/null
+++ b/vivified/code/vivi_parser.h
@@ -0,0 +1,36 @@
+/* Vivified
+ * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef _VIVI_DECOMPILER_H_
+#define _VIVI_DECOMPILER_H_
+
+#include <stdio.h>
+
+#include <swfdec/swfdec.h>
+#include <vivified/code/vivi_code_statement.h>
+
+G_BEGIN_DECLS
+
+
+ViviCodeStatement * vivi_parse_file (FILE * file,
+ const char * input_name);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_parser_scanner.c b/vivified/code/vivi_parser_scanner.c
new file mode 100644
index 0000000..97a3a29
--- /dev/null
+++ b/vivified/code/vivi_parser_scanner.c
@@ -0,0 +1,310 @@
+/* Vivified
+ * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_parser_scanner.h"
+
+#include "vivi_parser_scanner_lex.h"
+#include "vivi_parser_scanner_lex_include.h"
+
+G_DEFINE_TYPE (ViviParserScanner, vivi_parser_scanner, G_TYPE_OBJECT)
+
+static void
+vivi_parser_scanner_free_type_value (ViviParserScannerValue *value)
+{
+ switch (value->type) {
+ case VALUE_TYPE_STRING:
+ g_free (value->v_string);
+ break;
+ case VALUE_TYPE_IDENTIFIER:
+ g_free (value->v_identifier);
+ break;
+ case VALUE_TYPE_NONE:
+ case VALUE_TYPE_BOOLEAN:
+ case VALUE_TYPE_NUMBER:
+ /* nothing */
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ value->type = VALUE_TYPE_NONE;
+}
+
+static void
+vivi_parser_scanner_dispose (GObject *object)
+{
+ ViviParserScanner *scanner = VIVI_PARSER_SCANNER (object);
+
+ vivi_parser_scanner_free_type_value (&scanner->value);
+ vivi_parser_scanner_free_type_value (&scanner->next_value);
+
+ G_OBJECT_CLASS (vivi_parser_scanner_parent_class)->dispose (object);
+}
+
+static void
+vivi_parser_scanner_class_init (ViviParserScannerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = vivi_parser_scanner_dispose;
+}
+
+static void
+vivi_parser_scanner_init (ViviParserScanner *token)
+{
+}
+
+static const struct {
+ ViviParserScannerToken token;
+ const char * name;
+} token_names[] = {
+ // special
+ { TOKEN_NONE, "NONE" },
+ { TOKEN_EOF, "EOF" },
+ { TOKEN_ERROR, "ERROR" },
+ { TOKEN_UNKNOWN, "UNKNOWN" },
+ { TOKEN_LINE_TERMINATOR, "NEW LINE" },
+
+ // comparision
+ { TOKEN_BRACE_LEFT, "{", },
+ { TOKEN_BRACE_RIGHT, "}", },
+ { TOKEN_BRACKET_LEFT, "[", },
+ { TOKEN_BRACKET_RIGHT, "]", },
+ { TOKEN_PARENTHESIS_LEFT, "(", },
+ { TOKEN_PARENTHESIS_RIGHT, ")", },
+
+ // punctuation
+ { TOKEN_DOT, ".", },
+ { TOKEN_SEMICOLON, ";" },
+ { TOKEN_COMMA, "," },
+
+ // comparision
+ { TOKEN_LESS_THAN, "<" },
+ { TOKEN_GREATER_THAN, ">" },
+ { TOKEN_LESS_THAN_OR_EQUAL, "<=" },
+ { TOKEN_EQUAL_OR_GREATER_THAN, "=>" },
+
+ // equality
+ { TOKEN_EQUAL, "=" },
+ { TOKEN_NOT_EQUAL, "!=" },
+ { TOKEN_STRICT_EQUAL, "===" },
+ { TOKEN_NOT_STRICT_EQUAL, "!==" },
+
+ // operator
+ { TOKEN_PLUS, "+" },
+ { TOKEN_MINUS, "-" },
+ { TOKEN_MULTIPLY, "*" },
+ { TOKEN_DIVIDE, "/" },
+ { TOKEN_REMAINDER, "%" },
+
+ // shift
+ { TOKEN_SHIFT_LEFT, "<<" },
+ { TOKEN_SHIFT_RIGHT, ">>" },
+ { TOKEN_SHIFT_RIGHT_UNSIGNED, ">>>" },
+
+ // bitwise
+ { TOKEN_BITWISE_AND, "&" },
+ { TOKEN_BITWISE_OR, "|" },
+ { TOKEN_BITWISE_XOR, "^" },
+
+ // unary/postfix
+ { TOKEN_LOGICAL_NOT, "!" },
+ { TOKEN_BITWISE_NOT, "~" },
+ { TOKEN_INCREASE, "++" },
+ { TOKEN_DESCREASE, "--" },
+
+ // conditional
+ { TOKEN_QUESTION_MARK, "?" },
+ { TOKEN_COLON, ":" },
+
+ // logical
+ { TOKEN_LOGICAL_AND, "&&" },
+ { TOKEN_LOGICAL_OR, "||" },
+
+ // assign
+ { TOKEN_ASSIGN, "=" },
+ { TOKEN_ASSIGN_MULTIPLY, "*=" },
+ { TOKEN_ASSIGN_DIVIDE, "/=" },
+ { TOKEN_ASSIGN_REMAINDER, "%=" },
+ { TOKEN_ASSIGN_ADD, "+=" },
+ { TOKEN_ASSIGN_MINUS, "-=" },
+ { TOKEN_ASSIGN_SHIFT_LEFT, "<<=" },
+ { TOKEN_ASSIGN_SHIFT_RIGHT, ">>=" },
+ { TOKEN_ASSIGN_SHIFT_RIGHT_ZERO, ">>>=" },
+ { TOKEN_ASSIGN_BITWISE_AND, "&=" },
+ { TOKEN_ASSIGN_BITWISE_XOR, "^=" },
+ { TOKEN_ASSIGN_BITWISE_OR, "|=" },
+
+ // values
+ { TOKEN_NULL, "NULL" },
+ { TOKEN_BOOLEAN, "BOOLEAN" },
+ { TOKEN_NUMBER, "NUMBER" },
+ { TOKEN_STRING, "STRING" },
+ { TOKEN_IDENTIFIER, "IDENTIFIER" },
+
+ // keywords
+ { TOKEN_BREAK, "break" },
+ { TOKEN_CASE, "case" },
+ { TOKEN_CATCH, "catch" },
+ { TOKEN_CONTINUE, "continue" },
+ { TOKEN_DEFAULT, "default" },
+ { TOKEN_DELETE, "delete" },
+ { TOKEN_DO, "do" },
+ { TOKEN_ELSE, "else" },
+ { TOKEN_FINALLY, "finally" },
+ { TOKEN_FOR, "for" },
+ { TOKEN_FUNCTION, "function" },
+ { TOKEN_IF, "if" },
+ { TOKEN_IN, "in" },
+ { TOKEN_INSTANCEOF, "instanceof" },
+ { TOKEN_NEW, "new" },
+ { TOKEN_RETURN, "return" },
+ { TOKEN_SWITCH, "switch" },
+ { TOKEN_THIS, "this" },
+ { TOKEN_THROW, "throw" },
+ { TOKEN_TRY, "try" },
+ { TOKEN_TYPEOF, "typeof" },
+ { TOKEN_VAR, "var" },
+ { TOKEN_VOID, "void" },
+ { TOKEN_WHILE, "while" },
+ { TOKEN_WITH, "with" },
+
+ // reserved keywords
+ { TOKEN_RESERVED_KEYWORD, "RESERVED KEYWORD" },
+
+ // ActionScript specific
+ { TOKEN_UNDEFINED, "undefined" },
+ { TOKEN_TRACE, "trace" },
+
+ { TOKEN_LAST, NULL }
+};
+
+const char *vivi_parser_scanner_token_name (ViviParserScannerToken token)
+{
+ int i;
+
+ for (i = 0; token_names[i].token != TOKEN_LAST; i++) {
+ if (token_names[i].token == token)
+ return token_names[i].name;
+ }
+
+ g_assert_not_reached ();
+
+ return "INVALID TOKEN";
+}
+
+static void
+vivi_parser_scanner_advance (ViviParserScanner *scanner)
+{
+ g_return_if_fail (VIVI_IS_PARSER_SCANNER (scanner));
+
+ vivi_parser_scanner_free_type_value (&scanner->value);
+
+ scanner->token = scanner->next_token;
+ scanner->value = scanner->next_value;
+ scanner->line_number = scanner->next_line_number;
+ scanner->line_terminator = scanner->next_line_terminator;
+
+ if (scanner->file == NULL) {
+ scanner->next_token = TOKEN_EOF;
+ scanner->next_value.v_string = NULL;
+ } else {
+ scanner->next_token = yylex ();
+ if (scanner->next_token == TOKEN_LINE_TERMINATOR) {
+ scanner->next_line_terminator = TRUE;
+ } else {
+ scanner->next_line_terminator = FALSE;
+ }
+ while (scanner->next_token == TOKEN_LINE_TERMINATOR) {
+ scanner->next_token = yylex ();
+ }
+ scanner->next_value = lex_value;
+ scanner->next_line_number = lex_line_number;
+ lex_value.type = VALUE_TYPE_NONE;
+ }
+}
+
+ViviParserScanner *
+vivi_parser_scanner_new (FILE *file)
+{
+ ViviParserScanner *scanner;
+
+ g_return_val_if_fail (file != NULL, NULL);
+
+ scanner = g_object_new (VIVI_TYPE_PARSER_SCANNER, NULL);
+ scanner->file = file;
+ scanner->line_number = scanner->next_line_number = lex_line_number = 1;
+
+ yyrestart (file);
+
+ vivi_parser_scanner_advance (scanner);
+
+ return scanner;
+}
+
+ViviParserScannerToken
+vivi_parser_scanner_get_next_token (ViviParserScanner *scanner)
+{
+ g_return_val_if_fail (VIVI_IS_PARSER_SCANNER (scanner), TOKEN_EOF);
+
+ vivi_parser_scanner_advance (scanner);
+
+ return scanner->token;
+}
+
+ViviParserScannerToken
+vivi_parser_scanner_peek_next_token (ViviParserScanner *scanner)
+{
+ g_return_val_if_fail (VIVI_IS_PARSER_SCANNER (scanner), TOKEN_EOF);
+
+ return scanner->next_token;
+}
+
+guint
+vivi_parser_scanner_cur_line (ViviParserScanner *scanner)
+{
+ g_return_val_if_fail (VIVI_IS_PARSER_SCANNER (scanner), 0);
+
+ return scanner->line_number;
+}
+
+guint
+vivi_parser_scanner_cur_column (ViviParserScanner *scanner)
+{
+ g_return_val_if_fail (VIVI_IS_PARSER_SCANNER (scanner), 0);
+
+ // TODO
+
+ return 0;
+}
+
+char *
+vivi_parser_scanner_get_line (ViviParserScanner *scanner)
+{
+ g_return_val_if_fail (VIVI_IS_PARSER_SCANNER (scanner), 0);
+
+ // TODO
+
+ return g_strdup ("");
+}
diff --git a/vivified/code/vivi_parser_scanner.h b/vivified/code/vivi_parser_scanner.h
new file mode 100644
index 0000000..4e7bd30
--- /dev/null
+++ b/vivified/code/vivi_parser_scanner.h
@@ -0,0 +1,216 @@
+/* Vivified
+ * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef _VIVI_PARSER_SCANNER_H_
+#define _VIVI_PARSER_SCANNER_H_
+
+#include <stdio.h>
+#include <swfdec/swfdec.h>
+
+G_BEGIN_DECLS
+
+
+typedef enum {
+ // special
+ TOKEN_NONE = 0,
+ TOKEN_EOF,
+ TOKEN_ERROR,
+ TOKEN_UNKNOWN,
+ TOKEN_LINE_TERMINATOR,
+
+ // comparision
+ TOKEN_BRACE_LEFT,
+ TOKEN_BRACE_RIGHT,
+ TOKEN_BRACKET_LEFT,
+ TOKEN_BRACKET_RIGHT,
+ TOKEN_PARENTHESIS_LEFT,
+ TOKEN_PARENTHESIS_RIGHT,
+
+ // punctuation
+ TOKEN_DOT,
+ TOKEN_SEMICOLON,
+ TOKEN_COMMA,
+
+ // comparision
+ TOKEN_LESS_THAN,
+ TOKEN_GREATER_THAN,
+ TOKEN_LESS_THAN_OR_EQUAL,
+ TOKEN_EQUAL_OR_GREATER_THAN,
+
+ // equality
+ TOKEN_EQUAL,
+ TOKEN_NOT_EQUAL,
+ TOKEN_STRICT_EQUAL,
+ TOKEN_NOT_STRICT_EQUAL,
+
+ // operator
+ TOKEN_PLUS,
+ TOKEN_MINUS,
+ TOKEN_MULTIPLY,
+ TOKEN_DIVIDE,
+ TOKEN_REMAINDER,
+
+ // shift
+ TOKEN_SHIFT_LEFT,
+ TOKEN_SHIFT_RIGHT,
+ TOKEN_SHIFT_RIGHT_UNSIGNED,
+
+ // bitwise
+ TOKEN_BITWISE_AND,
+ TOKEN_BITWISE_OR,
+ TOKEN_BITWISE_XOR,
+
+ // unary/postfix
+ TOKEN_LOGICAL_NOT,
+ TOKEN_BITWISE_NOT,
+ TOKEN_INCREASE,
+ TOKEN_DESCREASE,
+
+ // conditional
+ TOKEN_QUESTION_MARK,
+ TOKEN_COLON,
+
+ // logical
+ TOKEN_LOGICAL_AND,
+ TOKEN_LOGICAL_OR,
+
+ // assign
+ TOKEN_ASSIGN,
+ TOKEN_ASSIGN_MULTIPLY,
+ TOKEN_ASSIGN_DIVIDE,
+ TOKEN_ASSIGN_REMAINDER,
+ TOKEN_ASSIGN_ADD,
+ TOKEN_ASSIGN_MINUS,
+ TOKEN_ASSIGN_SHIFT_LEFT,
+ TOKEN_ASSIGN_SHIFT_RIGHT,
+ TOKEN_ASSIGN_SHIFT_RIGHT_ZERO,
+ TOKEN_ASSIGN_BITWISE_AND,
+ TOKEN_ASSIGN_BITWISE_XOR,
+ TOKEN_ASSIGN_BITWISE_OR,
+
+ // values
+ TOKEN_NULL,
+ TOKEN_BOOLEAN,
+ TOKEN_NUMBER,
+ TOKEN_STRING,
+ TOKEN_IDENTIFIER,
+
+ // keywords
+ TOKEN_BREAK,
+ TOKEN_CASE,
+ TOKEN_CATCH,
+ TOKEN_CONTINUE,
+ TOKEN_DEFAULT,
+ TOKEN_DELETE,
+ TOKEN_DO,
+ TOKEN_ELSE,
+ TOKEN_FINALLY,
+ TOKEN_FOR,
+ TOKEN_FUNCTION,
+ TOKEN_IF,
+ TOKEN_IN,
+ TOKEN_INSTANCEOF,
+ TOKEN_NEW,
+ TOKEN_RETURN,
+ TOKEN_SWITCH,
+ TOKEN_THIS,
+ TOKEN_THROW,
+ TOKEN_TRY,
+ TOKEN_TYPEOF,
+ TOKEN_VAR,
+ TOKEN_VOID,
+ TOKEN_WHILE,
+ TOKEN_WITH,
+
+ // reserved keywords
+ TOKEN_RESERVED_KEYWORD,
+
+ // ActionScript specific
+ TOKEN_UNDEFINED,
+ TOKEN_TRACE,
+
+ TOKEN_LAST
+} ViviParserScannerToken;
+
+typedef enum {
+ VALUE_TYPE_NONE,
+ VALUE_TYPE_BOOLEAN,
+ VALUE_TYPE_NUMBER,
+ VALUE_TYPE_STRING,
+ VALUE_TYPE_IDENTIFIER
+} ViviParserScannerValueType;
+
+typedef struct {
+ ViviParserScannerValueType type;
+ union {
+ gboolean v_boolean;
+ double v_number;
+ char * v_string;
+ char * v_identifier;
+ };
+} ViviParserScannerValue;
+
+typedef struct _ViviParserScanner ViviParserScanner;
+typedef struct _ViviParserScannerClass ViviParserScannerClass;
+
+#define VIVI_TYPE_PARSER_SCANNER (vivi_parser_scanner_get_type())
+#define VIVI_IS_PARSER_SCANNER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_PARSER_SCANNER))
+#define VIVI_IS_PARSER_SCANNER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_PARSER_SCANNER))
+#define VIVI_PARSER_SCANNER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_PARSER_SCANNER, ViviParserScanner))
+#define VIVI_PARSER_SCANNER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_PARSER_SCANNER, ViviParserScannerClass))
+#define VIVI_PARSER_SCANNER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_PARSER_SCANNER, ViviParserScannerClass))
+
+struct _ViviParserScanner
+{
+ GObject object;
+
+ FILE * file;
+
+ ViviParserScannerToken token;
+ ViviParserScannerToken next_token;
+ guint line_number;
+ gboolean line_terminator;
+
+ ViviParserScannerValue value;
+ ViviParserScannerValue next_value;
+ guint next_line_number;
+ gboolean next_line_terminator;
+
+ ViviParserScannerToken expected;
+};
+
+struct _ViviParserScannerClass
+{
+ GObjectClass object_class;
+};
+
+GType vivi_parser_scanner_get_type (void);
+
+ViviParserScanner * vivi_parser_scanner_new (FILE * file);
+ViviParserScannerToken vivi_parser_scanner_get_next_token (ViviParserScanner * scanner);
+ViviParserScannerToken vivi_parser_scanner_peek_next_token (ViviParserScanner * scanner);
+
+const char * vivi_parser_scanner_token_name (ViviParserScannerToken token);
+guint vivi_parser_scanner_cur_line (ViviParserScanner *scanner);
+guint vivi_parser_scanner_cur_column (ViviParserScanner *scanner);
+char * vivi_parser_scanner_get_line (ViviParserScanner *scanner);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_parser_scanner_lex.h b/vivified/code/vivi_parser_scanner_lex.h
new file mode 100644
index 0000000..ff2a155
--- /dev/null
+++ b/vivified/code/vivi_parser_scanner_lex.h
@@ -0,0 +1,315 @@
+/* Vivified
+ * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef yyHEADER_H
+#define yyHEADER_H 1
+#define yyIN_HEADER 1
+
+#line 6 "vivi_parser_scanner_lex.h"
+
+#line 8 "vivi_parser_scanner_lex.h"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 34
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int yyleng;
+
+extern FILE *yyin, *yyout;
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ * Given that the standard has decreed that size_t exists since 1989,
+ * I guess we can afford to depend on it. Manoj.
+ */
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+void yyrestart (FILE *input_file );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size );
+void yy_delete_buffer (YY_BUFFER_STATE b );
+void yy_flush_buffer (YY_BUFFER_STATE b );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer );
+void yypop_buffer_state (void );
+
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len );
+
+void *yyalloc (yy_size_t );
+void *yyrealloc (void *,yy_size_t );
+void yyfree (void * );
+
+/* Begin user sect3 */
+
+extern int yylineno;
+
+extern char *yytext;
+#define yytext_ptr yytext
+
+#ifdef YY_HEADER_EXPORT_START_CONDITIONS
+#define INITIAL 0
+
+#endif
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap (void );
+#else
+extern int yywrap (void );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (void);
+
+#define YY_DECL int yylex (void)
+#endif /* !YY_DECL */
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+#line 148 "vivi_parser_scanner_lex.l"
+
+
+#line 295 "vivi_parser_scanner_lex.h"
+#undef yyIN_HEADER
+#endif /* yyHEADER_H */
diff --git a/vivified/code/vivi_parser_scanner_lex.l b/vivified/code/vivi_parser_scanner_lex.l
new file mode 100644
index 0000000..4b96c41
--- /dev/null
+++ b/vivified/code/vivi_parser_scanner_lex.l
@@ -0,0 +1,284 @@
+%{
+/* Vivified
+ * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "vivi_parser_scanner_lex_include.h"
+%}
+
+%option noyywrap
+%option nostdinit
+%option never-interactive
+
+identifier_start [$_a-zA-Z]
+identifier_part [$_a-zA-Z0-9]
+
+%x str
+%x comment
+
+%%
+
+ GString *string = NULL;
+
+<<EOF>> { return TOKEN_EOF; }
+
+"/*" { BEGIN(comment); }
+<comment>{
+ <<EOF>> {
+ BEGIN(INITIAL);
+ return TOKEN_ERROR;
+ }
+ [^*\n]* /* skip */
+ \n { lex_line_number++; }
+ "*/" { BEGIN(INITIAL); }
+}
+"//"[^\r\n]* {
+ lex_line_number++;
+ return TOKEN_LINE_TERMINATOR;
+ }
+
+[ \t] /* skip */
+
+\r\n {
+ lex_line_number++;
+ return TOKEN_LINE_TERMINATOR;
+ }
+[\r\n] {
+ lex_line_number++;
+ return TOKEN_LINE_TERMINATOR;
+ }
+
+"{" { return TOKEN_BRACE_LEFT; }
+"}" { return TOKEN_BRACE_RIGHT; }
+"[" { return TOKEN_BRACKET_LEFT; }
+"]" { return TOKEN_BRACKET_RIGHT; }
+"(" { return TOKEN_PARENTHESIS_LEFT; }
+")" { return TOKEN_PARENTHESIS_RIGHT; }
+
+"." { return TOKEN_DOT; }
+";" { return TOKEN_SEMICOLON; }
+"," { return TOKEN_COMMA; }
+
+"<" { return TOKEN_LESS_THAN; }
+">" { return TOKEN_GREATER_THAN; }
+"<=" { return TOKEN_LESS_THAN_OR_EQUAL; }
+"=>" { return TOKEN_EQUAL_OR_GREATER_THAN; }
+
+"==", { return TOKEN_EQUAL; }
+"!=", { return TOKEN_NOT_EQUAL; }
+"===", { return TOKEN_STRICT_EQUAL; }
+"!==", { return TOKEN_NOT_STRICT_EQUAL; }
+
+"+" { return TOKEN_PLUS; }
+"-" { return TOKEN_MINUS; }
+"*" { return TOKEN_MULTIPLY; }
+"/" { return TOKEN_DIVIDE; }
+"%" { return TOKEN_REMAINDER; }
+
+"<<" { return TOKEN_SHIFT_LEFT; }
+">>" { return TOKEN_SHIFT_RIGHT; }
+">>>" { return TOKEN_SHIFT_RIGHT_UNSIGNED; }
+
+"&" { return TOKEN_BITWISE_AND; }
+"|" { return TOKEN_BITWISE_OR; }
+"^" { return TOKEN_BITWISE_XOR; }
+
+"!" { return TOKEN_LOGICAL_NOT; }
+"~" { return TOKEN_BITWISE_NOT; }
+"++" { return TOKEN_INCREASE; }
+"--" { return TOKEN_DESCREASE; }
+
+"?" { return TOKEN_QUESTION_MARK; }
+":" { return TOKEN_COLON; }
+
+"&&" { return TOKEN_LOGICAL_AND; }
+"||" { return TOKEN_LOGICAL_OR; }
+
+"=" { return TOKEN_ASSIGN; }
+"*=" { return TOKEN_ASSIGN_MULTIPLY; }
+"/=" { return TOKEN_ASSIGN_DIVIDE; }
+"%=" { return TOKEN_ASSIGN_REMAINDER; }
+"+=" { return TOKEN_ASSIGN_ADD; }
+"-=" { return TOKEN_ASSIGN_MINUS; }
+"<<=" { return TOKEN_ASSIGN_SHIFT_LEFT; }
+">>=" { return TOKEN_ASSIGN_SHIFT_RIGHT; }
+">>>=" { return TOKEN_ASSIGN_SHIFT_RIGHT_ZERO; }
+"&=" { return TOKEN_ASSIGN_BITWISE_AND; }
+"^=" { return TOKEN_ASSIGN_BITWISE_XOR; }
+"|=" { return TOKEN_ASSIGN_BITWISE_OR; }
+
+"break" { return TOKEN_BREAK; }
+"case" { return TOKEN_CASE; }
+"catch" { return TOKEN_CATCH; }
+"continue" { return TOKEN_CONTINUE; }
+"default" { return TOKEN_DEFAULT; }
+"delete" { return TOKEN_DELETE; }
+"do" { return TOKEN_DO; }
+"else" { return TOKEN_ELSE; }
+"finally" { return TOKEN_FINALLY; }
+"for" { return TOKEN_FOR; }
+"function" { return TOKEN_FUNCTION; }
+"if" { return TOKEN_IF; }
+"in" { return TOKEN_IN; }
+"instanceof" { return TOKEN_INSTANCEOF; }
+"new" { return TOKEN_NEW; }
+"return" { return TOKEN_RETURN; }
+"switch" { return TOKEN_SWITCH; }
+"this" { return TOKEN_THIS; }
+"throw" { return TOKEN_THROW; }
+"try" { return TOKEN_TRY; }
+"typeof" { return TOKEN_TYPEOF; }
+"var" { return TOKEN_VAR; }
+"void" { return TOKEN_VOID; }
+"while" { return TOKEN_WHILE; }
+"with" { return TOKEN_WITH; }
+
+"abstract" { return TOKEN_RESERVED_KEYWORD; }
+"boolean" { return TOKEN_RESERVED_KEYWORD; }
+"byte" { return TOKEN_RESERVED_KEYWORD; }
+"char" { return TOKEN_RESERVED_KEYWORD; }
+"class" { return TOKEN_RESERVED_KEYWORD; }
+"const" { return TOKEN_RESERVED_KEYWORD; }
+"debugger" { return TOKEN_RESERVED_KEYWORD; }
+"double" { return TOKEN_RESERVED_KEYWORD; }
+"enum" { return TOKEN_RESERVED_KEYWORD; }
+"export" { return TOKEN_RESERVED_KEYWORD; }
+"extends" { return TOKEN_RESERVED_KEYWORD; }
+"final" { return TOKEN_RESERVED_KEYWORD; }
+"float" { return TOKEN_RESERVED_KEYWORD; }
+"goto" { return TOKEN_RESERVED_KEYWORD; }
+"implements" { return TOKEN_RESERVED_KEYWORD; }
+"import" { return TOKEN_RESERVED_KEYWORD; }
+"int" { return TOKEN_RESERVED_KEYWORD; }
+"interface" { return TOKEN_RESERVED_KEYWORD; }
+"long" { return TOKEN_RESERVED_KEYWORD; }
+"native" { return TOKEN_RESERVED_KEYWORD; }
+"package" { return TOKEN_RESERVED_KEYWORD; }
+"private" { return TOKEN_RESERVED_KEYWORD; }
+"protected" { return TOKEN_RESERVED_KEYWORD; }
+"public" { return TOKEN_RESERVED_KEYWORD; }
+"short" { return TOKEN_RESERVED_KEYWORD; }
+"static" { return TOKEN_RESERVED_KEYWORD; }
+"super" { return TOKEN_RESERVED_KEYWORD; }
+"synchronized" { return TOKEN_RESERVED_KEYWORD; }
+"throws" { return TOKEN_RESERVED_KEYWORD; }
+"transient" { return TOKEN_RESERVED_KEYWORD; }
+"volatile" { return TOKEN_RESERVED_KEYWORD; }
+
+"undefined" { return TOKEN_UNDEFINED; }
+"trace" { return TOKEN_TRACE; }
+
+"null" { return TOKEN_NULL; }
+"true" {
+ lex_value.type = VALUE_TYPE_BOOLEAN;
+ lex_value.v_boolean = 1;
+ return TOKEN_BOOLEAN;
+ }
+"false" {
+ lex_value.type = VALUE_TYPE_BOOLEAN;
+ lex_value.v_boolean = 0;
+ return TOKEN_BOOLEAN;
+ }
+
+0[xX][0-9a-fA-F]+ {
+ lex_value.type = VALUE_TYPE_NUMBER;
+ lex_value.v_number =
+ g_ascii_strtoull (yytext, NULL, 16);
+ return TOKEN_NUMBER;
+ }
+
+([1-9][0-9]*|0)(\.[0-9]*)?([eE][+-]?[0-9]+)? {
+ lex_value.type = VALUE_TYPE_NUMBER;
+ lex_value.v_number = g_ascii_strtod (yytext, NULL);
+ return TOKEN_NUMBER;
+ }
+
+\.[0-9]+([eE][+-]?[0-9]+)? {
+ lex_value.type = VALUE_TYPE_NUMBER;
+ lex_value.v_number = g_ascii_strtod (yytext, NULL);
+ return TOKEN_NUMBER;
+ }
+
+\" {
+ string = g_string_new ("");
+ BEGIN(str);
+ }
+
+<str>{
+ \" {
+ BEGIN(INITIAL);
+ lex_value.type = VALUE_TYPE_STRING;
+ lex_value.v_string = g_string_free (string, FALSE);
+ return TOKEN_STRING;
+ }
+ \n {
+ BEGIN(INITIAL);
+ g_string_free (string, TRUE);
+ return TOKEN_ERROR;
+ }
+ \\0 { g_string_append_c (string, '0'); }
+ \\[0-7]{1,3} {
+ guint64 result;
+ result = g_ascii_strtoull (yytext + 1, NULL, 8);
+ if (result > 0xff || result == 0) {
+ BEGIN(INITIAL);
+ g_string_free (string, TRUE);
+ return TOKEN_ERROR;
+ } else {
+ g_string_append_c (string, result);
+ }
+ }
+ \\[0-9]+ {
+ g_string_free (string, TRUE);
+ return TOKEN_ERROR;
+ }
+ \\x[0-9a-fA-F]{2} {
+ guint64 result;
+ result = g_ascii_strtoull (yytext + 2, NULL, 16);
+ if (result == 0) {
+ BEGIN(INITIAL);
+ g_string_free (string, TRUE);
+ return TOKEN_ERROR;
+ } else {
+ g_string_append_c (string, result);
+ }
+ }
+ \\b { g_string_append_c (string, '\b'); }
+ \\f { g_string_append_c (string, '\f'); }
+ \\n { g_string_append_c (string, '\n'); }
+ \\r { g_string_append_c (string, '\r'); }
+ \\t { g_string_append_c (string, '\t'); }
+ \\v { g_string_append_c (string, '\v'); }
+ \\. { g_string_append_c (string, yytext[1]); }
+ [^\\\n\"]+ {
+ char *p;
+ for (p = yytext; *p != '\0'; p++) {
+ g_string_append_c (string, *p);
+ }
+ }
+}
+
+{identifier_start}({identifier_part})* {
+ lex_value.type = VALUE_TYPE_IDENTIFIER;
+ lex_value.v_identifier = g_strdup (yytext);
+ return TOKEN_IDENTIFIER;
+ }
+
+. { return TOKEN_ERROR; }
+
+%%
diff --git a/vivified/code/vivi_parser_scanner_lex_include.h b/vivified/code/vivi_parser_scanner_lex_include.h
new file mode 100644
index 0000000..1c2dabc
--- /dev/null
+++ b/vivified/code/vivi_parser_scanner_lex_include.h
@@ -0,0 +1,28 @@
+/* Vivified
+ * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef _VIVI_PARSER_SCANNER_LEX_INCLUDE_H_
+#define _VIVI_PARSER_SCANNER_LEX_INCLUDE_H_
+
+#include "vivi_parser_scanner.h"
+
+ViviParserScannerValue lex_value;
+guint lex_line_number;
+
+#endif // _VIVI_PARSER_SCANNER_LEX_INCLUDE_H_
More information about the Swfdec-commits
mailing list