[Swfdec-commits] 11 commits - vivified/code

Pekka Lampila medar at kemper.freedesktop.org
Thu May 22 02:15:05 PDT 2008


 vivified/code/Makefile.am                         |    2 
 vivified/code/test/compiler/Makefile.am           |    4 
 vivified/code/test/compiler/asm_push.as           |    6 
 vivified/code/test/compiler/asm_push.as.expect    |    4 
 vivified/code/test/compiler/conditional.as        |    1 
 vivified/code/test/compiler/conditional.as.expect |   17 
 vivified/code/vivi_code_asm_push.c                |  460 ++++++++++++----------
 vivified/code/vivi_code_asm_push.h                |   63 ++-
 vivified/code/vivi_code_assembler.c               |   81 ++-
 vivified/code/vivi_code_assembler.h               |    3 
 vivified/code/vivi_code_assignment.c              |    7 
 vivified/code/vivi_code_compiler.c                |    2 
 vivified/code/vivi_code_conditional.c             |  120 +++++
 vivified/code/vivi_code_conditional.h             |   61 ++
 vivified/code/vivi_code_get_url.c                 |    4 
 vivified/code/vivi_code_if.c                      |    3 
 vivified/code/vivi_code_loop.c                    |    3 
 vivified/code/vivi_decompiler_duplicate.c         |    9 
 vivified/code/vivi_decompiler_unknown.c           |   12 
 vivified/code/vivi_parser.c                       |   20 
 20 files changed, 601 insertions(+), 281 deletions(-)

New commits:
commit 5bfe4f57822ae10724b67d09a1a2bd24dc0aae86
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Thu May 22 12:14:43 2008 +0300

    Fix a memory leak in vivi_code_asm_push_remove_value

diff --git a/vivified/code/vivi_code_asm_push.c b/vivified/code/vivi_code_asm_push.c
index fe13b4f..117d9a9 100644
--- a/vivified/code/vivi_code_asm_push.c
+++ b/vivified/code/vivi_code_asm_push.c
@@ -258,9 +258,15 @@ vivi_code_asm_push_get_value_type (const ViviCodeAsmPush *push, guint i)
 void
 vivi_code_asm_push_remove_value (ViviCodeAsmPush *push, guint index_)
 {
+  ViviCodeAsmPushValue *value;
+
   g_return_if_fail (VIVI_IS_CODE_ASM_PUSH (push));
   g_return_if_fail (index_ < push->values->len);
 
+  value = &g_array_index (push->values, ViviCodeAsmPushValue, index_);
+  if (value->type == VIVI_CODE_CONSTANT_STRING)
+    g_free (value->v_string);
+
   g_array_remove_index (push->values, index_);
 }
 
commit 4457619a5ddc24c00d954df37eecb4b73d20e4ed
Merge: d0273c7... cef525e...
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Thu May 22 12:12:54 2008 +0300

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

commit d0273c70245ae28e3ad9da3ec61f71455c41523e
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Thu May 22 12:09:34 2008 +0300

    Add support for merging push over asm statements that take values from stack
    
    This is disabled for now. Also fixed merging so that it won't merge push
    statements on different sides of a label

diff --git a/vivified/code/vivi_code_asm_push.c b/vivified/code/vivi_code_asm_push.c
index 7a56615..fe13b4f 100644
--- a/vivified/code/vivi_code_asm_push.c
+++ b/vivified/code/vivi_code_asm_push.c
@@ -406,11 +406,16 @@ vivi_code_asm_push_insert_pool_big (ViviCodeAsmPush *push, guint index_, guint i
 }
 
 void
-vivi_code_asm_push_copy_value (ViviCodeAsmPush *push,
-    const ViviCodeAsmPush *other, guint index_)
+vivi_code_asm_push_copy_value (ViviCodeAsmPush *push, guint index_to,
+    const ViviCodeAsmPush *other, guint index_from)
 {
-  ViviCodeAsmPushValue *value =
-    &g_array_index (other->values, ViviCodeAsmPushValue, index_);
+  ViviCodeAsmPushValue *value;
+
+  g_return_if_fail (VIVI_IS_CODE_ASM_PUSH (push));
+  g_return_if_fail (VIVI_IS_CODE_ASM_PUSH (other));
+  g_return_if_fail (index_from < other->values->len);
+
+  value = &g_array_index (other->values, ViviCodeAsmPushValue, index_from);
 
   if (value->type == VIVI_CODE_CONSTANT_STRING) {
     ViviCodeAsmPushValue value_new;
@@ -418,9 +423,9 @@ vivi_code_asm_push_copy_value (ViviCodeAsmPush *push,
     value_new.type = VIVI_CODE_CONSTANT_STRING;
     value_new.v_string = g_strdup (value->v_string);
 
-    vivi_code_asm_push_insert_value (push, G_MAXUINT, &value_new);
+    vivi_code_asm_push_insert_value (push, index_to, &value_new);
   } else {
-    vivi_code_asm_push_insert_value (push, G_MAXUINT, value);
+    vivi_code_asm_push_insert_value (push, index_to, value);
   }
 }
 
diff --git a/vivified/code/vivi_code_asm_push.h b/vivified/code/vivi_code_asm_push.h
index ca31aea..a9555f2 100644
--- a/vivified/code/vivi_code_asm_push.h
+++ b/vivified/code/vivi_code_asm_push.h
@@ -125,8 +125,9 @@ void			vivi_code_asm_push_insert_pool_big	(ViviCodeAsmPush *	push,
 void			vivi_code_asm_push_remove_value		(ViviCodeAsmPush *	push,
 								 guint			index_);
 void			vivi_code_asm_push_copy_value		(ViviCodeAsmPush *	push,
+								 guint			index_to,
 								 const ViviCodeAsmPush *other,
-								 guint			index_);
+								 guint			index_from);
 
 
 G_END_DECLS
diff --git a/vivified/code/vivi_code_assembler.c b/vivified/code/vivi_code_assembler.c
index 0a3c854..ded99ca 100644
--- a/vivified/code/vivi_code_assembler.c
+++ b/vivified/code/vivi_code_assembler.c
@@ -293,7 +293,7 @@ vivi_code_assembler_get_stack_change (ViviCodeAsm *code, int *add, int *remove)
 }
 
 void
-vivi_code_assembler_merge_push (ViviCodeAssembler *assembler)
+vivi_code_assembler_merge_push (ViviCodeAssembler *assembler, guint max_depth)
 {
   ViviCodeAsmPush *previous;
   guint i, j, depth;
@@ -302,13 +302,17 @@ vivi_code_assembler_merge_push (ViviCodeAssembler *assembler)
   depth = 0;
   previous = NULL;
   for (i = 0; i < assembler->codes->len; i++) {
-    if (VIVI_IS_CODE_ASM_PUSH (g_ptr_array_index (assembler->codes, i))) {
-      ViviCodeAsmPush *current =
-	VIVI_CODE_ASM_PUSH (g_ptr_array_index (assembler->codes, i));
+    ViviCodeAsm *code =
+      VIVI_CODE_ASM (g_ptr_array_index (assembler->codes, i));
+
+    if (VIVI_IS_CODE_ASM_PUSH (code)) {
+      ViviCodeAsmPush *current = VIVI_CODE_ASM_PUSH (code);
 
-      if (previous != NULL && depth == 0) {
+      if (previous != NULL &&
+	  vivi_code_asm_push_get_n_values (previous) >= depth) {
 	for (j = 0; j < vivi_code_asm_push_get_n_values (current); j++) {
-	  vivi_code_asm_push_copy_value (previous, current, j);
+	  vivi_code_asm_push_copy_value (previous,
+	      vivi_code_asm_push_get_n_values (previous) - depth, current, j);
 	}
 	vivi_code_assembler_remove_code (assembler, VIVI_CODE_ASM (current));
 	i--;
@@ -318,15 +322,24 @@ vivi_code_assembler_merge_push (ViviCodeAssembler *assembler)
       }
     } else {
       if (previous != NULL) {
-	vivi_code_assembler_get_stack_change (VIVI_CODE_ASM (
-		g_ptr_array_index (assembler->codes, i)), &add, &remove);
-	if (add != 0) {
+	if (VIVI_IS_CODE_LABEL (code)) {
 	  previous = NULL;
+	  depth = 0;
 	} else {
-	  if (remove == -1) {
+	  vivi_code_assembler_get_stack_change (code, &add, &remove);
+	  if (add != 0) {
 	    previous = NULL;
+	    depth = 0;
 	  } else {
-	    depth += remove;
+	    if (remove == -1) {
+	      previous = NULL;
+	    } else {
+	      depth += remove;
+	      if (depth > max_depth) {
+		previous = NULL;
+		depth = 0;
+	      }
+	    }
 	  }
 	}
       }
diff --git a/vivified/code/vivi_code_assembler.h b/vivified/code/vivi_code_assembler.h
index 508e861..67b4124 100644
--- a/vivified/code/vivi_code_assembler.h
+++ b/vivified/code/vivi_code_assembler.h
@@ -62,7 +62,8 @@ void			vivi_code_assembler_remove_code		(ViviCodeAssembler *	assembler,
 								 ViviCodeAsm *		code);
 
 gboolean		vivi_code_assembler_pool		(ViviCodeAssembler *	assembler);
-void			vivi_code_assembler_merge_push		(ViviCodeAssembler *	assembler);
+void			vivi_code_assembler_merge_push		(ViviCodeAssembler *	assembler,
+								 guint			max_depth);
 
 SwfdecScript *		vivi_code_assembler_assemble_script	(ViviCodeAssembler *	assembler,
 								 guint			version,
diff --git a/vivified/code/vivi_code_compiler.c b/vivified/code/vivi_code_compiler.c
index 6a54419..a25ded0 100644
--- a/vivified/code/vivi_code_compiler.c
+++ b/vivified/code/vivi_code_compiler.c
@@ -85,7 +85,7 @@ vivi_code_compiler_compile_script (ViviCodeCompiler *compiler,
   vivi_code_compiler_take_code (compiler, vivi_code_asm_end_new ());
 
   vivi_code_assembler_pool (compiler->assembler);
-  vivi_code_assembler_merge_push (compiler->assembler);
+  vivi_code_assembler_merge_push (compiler->assembler, 0);
 }
 
 void
commit 275451d9bf129d11f9296ef8f9455003ea919253
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Thu May 22 11:52:56 2008 +0300

    Simplify vivi_code_assembler_pool implementation

diff --git a/vivified/code/vivi_code_asm_push.c b/vivified/code/vivi_code_asm_push.c
index f306b84..7a56615 100644
--- a/vivified/code/vivi_code_asm_push.c
+++ b/vivified/code/vivi_code_asm_push.c
@@ -255,6 +255,15 @@ vivi_code_asm_push_get_value_type (const ViviCodeAsmPush *push, guint i)
   return g_array_index (push->values, ViviCodeAsmPushValue, i).type;
 }
 
+void
+vivi_code_asm_push_remove_value (ViviCodeAsmPush *push, guint index_)
+{
+  g_return_if_fail (VIVI_IS_CODE_ASM_PUSH (push));
+  g_return_if_fail (index_ < push->values->len);
+
+  g_array_remove_index (push->values, index_);
+}
+
 static void
 vivi_code_asm_push_insert_value (ViviCodeAsmPush *push, guint index_,
     ViviCodeAsmPushValue *value)
diff --git a/vivified/code/vivi_code_asm_push.h b/vivified/code/vivi_code_asm_push.h
index a8308e8..ca31aea 100644
--- a/vivified/code/vivi_code_asm_push.h
+++ b/vivified/code/vivi_code_asm_push.h
@@ -122,6 +122,8 @@ void			vivi_code_asm_push_insert_pool_big	(ViviCodeAsmPush *	push,
 								 guint			index_,
 								 guint			id);
 
+void			vivi_code_asm_push_remove_value		(ViviCodeAsmPush *	push,
+								 guint			index_);
 void			vivi_code_asm_push_copy_value		(ViviCodeAsmPush *	push,
 								 const ViviCodeAsmPush *other,
 								 guint			index_);
diff --git a/vivified/code/vivi_code_assembler.c b/vivified/code/vivi_code_assembler.c
index 86eaffe..0a3c854 100644
--- a/vivified/code/vivi_code_assembler.c
+++ b/vivified/code/vivi_code_assembler.c
@@ -242,34 +242,30 @@ vivi_code_assembler_pool (ViviCodeAssembler *assembler)
   // change the pushes
   for (i = 0; i < assembler->codes->len; i++) {
     if (VIVI_IS_CODE_ASM_PUSH (g_ptr_array_index (assembler->codes, i))) {
-      ViviCodeAsmPush *old =
+      ViviCodeAsmPush *push =
 	VIVI_CODE_ASM_PUSH (g_ptr_array_index (assembler->codes, i));
-      ViviCodeAsmPush *push = VIVI_CODE_ASM_PUSH (vivi_code_asm_push_new ());
-
-      for (j = 0; j < vivi_code_asm_push_get_n_values (old); j++) {
-	if (vivi_code_asm_push_get_value_type (old, j) ==
-	    VIVI_CODE_CONSTANT_STRING) {
-	  const char *str = vivi_code_asm_push_get_string (old, j);
-	  guint k = 0;
-
-	  for (iter = list; iter != NULL; iter = iter->next) {
-	    if (strcmp (iter->data, str) == 0)
-	      break;
-	    k++;
-	  }
-	  if (iter != NULL) {
-	    vivi_code_asm_push_add_pool (push, k);
-	  } else {
-	    vivi_code_asm_push_copy_value (push, old, j);
-	  }
-	} else {
-	  vivi_code_asm_push_copy_value (push, old, j);
+
+      for (j = 0; j < vivi_code_asm_push_get_n_values (push); j++) {
+	const char *string;
+	guint k;
+
+	if (vivi_code_asm_push_get_value_type (push, j) !=
+	    VIVI_CODE_CONSTANT_STRING)
+	  continue;
+
+	string = vivi_code_asm_push_get_string (push, j);
+	k = 0;
+	for (iter = list; iter != NULL; iter = iter->next) {
+	  if (strcmp (iter->data, string) == 0)
+	    break;
+	  k++;
 	}
-      }
 
-      vivi_code_assembler_remove_code (assembler, VIVI_CODE_ASM (old));
-      vivi_code_assembler_insert_code (assembler, i, VIVI_CODE_ASM (push));
-      g_object_unref (push);
+	if (iter != NULL) {
+	  vivi_code_asm_push_remove_value (push, j);
+	  vivi_code_asm_push_insert_pool (push, j, k);
+	}
+      }
     }
   }
 
commit c3900ff6a382599a316f9777f61ae75e99af378b
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Thu May 22 11:44:08 2008 +0300

    Change the implementation of ViviCodeAsmPush to allow inserting values etc.

diff --git a/vivified/code/vivi_code_asm_push.c b/vivified/code/vivi_code_asm_push.c
index f5509fd..f306b84 100644
--- a/vivified/code/vivi_code_asm_push.c
+++ b/vivified/code/vivi_code_asm_push.c
@@ -30,22 +30,81 @@
 #include "vivi_code_error.h"
 #include "vivi_code_printer.h"
 
+typedef struct {
+  ViviCodeConstantType		type;
+  union {
+    char *			v_string;
+    float			v_float;
+    guint			v_register;
+    gboolean			v_boolean;
+    double			v_double;
+    int				v_integer;
+    guint			v_constant_pool;
+  };
+} ViviCodeAsmPushValue;
+
 static gboolean
 vivi_code_asm_push_emit (ViviCodeAsm *code, ViviCodeEmitter *emitter, GError **error)
 {
   ViviCodeAsmPush *push = VIVI_CODE_ASM_PUSH (code);
   SwfdecBots *emit = vivi_code_emitter_get_bots (emitter);
+  SwfdecBots *bots = swfdec_bots_open ();
+  guint i;
   gsize len;
 
-  len = swfdec_bots_get_bytes (push->contents);
+  for (i = 0; i < push->values->len; i++) {
+    ViviCodeAsmPushValue *value =
+      &g_array_index (push->values, ViviCodeAsmPushValue, i);
+
+    swfdec_bots_put_u8 (bots, value->type);
+
+    switch (value->type) {
+      case VIVI_CODE_CONSTANT_STRING:
+	swfdec_bots_put_string (bots, value->v_string);
+	break;
+      case VIVI_CODE_CONSTANT_FLOAT:
+	swfdec_bots_put_float (bots, value->v_float);
+	break;
+      case VIVI_CODE_CONSTANT_NULL:
+	/* nothing */
+	break;
+      case VIVI_CODE_CONSTANT_UNDEFINED:
+	/* nothing */
+	break;
+      case VIVI_CODE_CONSTANT_REGISTER:
+	swfdec_bots_put_u8 (bots, value->v_register);
+	break;
+      case VIVI_CODE_CONSTANT_BOOLEAN:
+	swfdec_bots_put_u8 (bots, value->v_boolean ? 1 : 0);
+	break;
+      case VIVI_CODE_CONSTANT_DOUBLE:
+	swfdec_bots_put_double (bots, value->v_double);
+	break;
+      case VIVI_CODE_CONSTANT_INTEGER:
+	swfdec_bots_put_u32 (bots, value->v_integer);
+	break;
+      case VIVI_CODE_CONSTANT_CONSTANT_POOL:
+	swfdec_bots_put_u8 (bots, value->v_constant_pool);
+	break;
+      case VIVI_CODE_CONSTANT_CONSTANT_POOL_BIG:
+	swfdec_bots_put_u16 (bots, value->v_constant_pool);
+	break;
+      default:
+	g_assert_not_reached ();
+    }
+  }
+
+  len = swfdec_bots_get_bytes (bots);
   if (len > G_MAXUINT16) {
     g_set_error (error, VIVI_CODE_ERROR, VIVI_CODE_ERROR_SIZE,
 	"Push action too big");
+    swfdec_bots_free (bots);
     return FALSE;
   }
   swfdec_bots_put_u8 (emit, SWFDEC_AS_ACTION_PUSH);
   swfdec_bots_put_u16 (emit, len);
-  swfdec_bots_put_bots (emit, push->contents);
+  swfdec_bots_put_bots (emit, bots);
+  swfdec_bots_free (bots);
   return TRUE;
 }
 
@@ -62,38 +121,30 @@ static void
 vivi_code_asm_push_print (ViviCodeToken *token, ViviCodePrinter*printer)
 {
   ViviCodeAsmPush *push = VIVI_CODE_ASM_PUSH (token);
-  SwfdecBits bits;
-  char *s, *s2;
-  gboolean first = TRUE;
-  guint type;
-
-  vivi_code_printer_print (printer, "push");
-  swfdec_bits_init_data (&bits, push->contents->data, swfdec_bots_get_bytes (push->contents));
-  while (swfdec_bits_left (&bits)) {
-    if (first) {
-      vivi_code_printer_print (printer, " ");
-      first = FALSE;
-    } else {
+  char *s;
+  guint i;
+
+  vivi_code_printer_print (printer, "push ");
+
+  for (i = 0; i < push->values->len; i++) {
+    ViviCodeAsmPushValue *value =
+      &g_array_index (push->values, ViviCodeAsmPushValue, i);
+
+    if (i != 0)
       vivi_code_printer_print (printer, ", ");
-    }
-    type = swfdec_bits_get_u8 (&bits);
-    switch (type) {
+
+    switch (value->type) {
       case VIVI_CODE_CONSTANT_STRING:
-	s = swfdec_bits_get_string (&bits, 7);
-	s2 = vivi_code_escape_string (s);
+	s = vivi_code_escape_string (value->v_string);
+	vivi_code_printer_print (printer, s);
 	g_free (s);
-	vivi_code_printer_print (printer, s2);
-	g_free (s2);
 	break;
       case VIVI_CODE_CONSTANT_FLOAT:
-	{
-	  s = g_malloc (G_ASCII_DTOSTR_BUF_SIZE);
-	  g_ascii_dtostr (s, G_ASCII_DTOSTR_BUF_SIZE,
-	      swfdec_bits_get_float (&bits));
-	  vivi_code_printer_print (printer, s);
-	  vivi_code_printer_print (printer, "f");
-	  g_free (s);
-	}
+	s = g_malloc (G_ASCII_DTOSTR_BUF_SIZE);
+	g_ascii_dtostr (s, G_ASCII_DTOSTR_BUF_SIZE, value->v_float);
+	vivi_code_printer_print (printer, s);
+	vivi_code_printer_print (printer, "f");
+	g_free (s);
 	break;
       case VIVI_CODE_CONSTANT_NULL:
 	vivi_code_printer_print (printer, "null");
@@ -102,37 +153,34 @@ vivi_code_asm_push_print (ViviCodeToken *token, ViviCodePrinter*printer)
 	vivi_code_printer_print (printer, "undefined");
 	break;
       case VIVI_CODE_CONSTANT_REGISTER:
-	s = g_strdup_printf ("reg %u", swfdec_bits_get_u8 (&bits));
+	s = g_strdup_printf ("reg %u", value->v_register);
 	vivi_code_printer_print (printer, s);
 	g_free (s);
 	break;
       case VIVI_CODE_CONSTANT_BOOLEAN:
-	vivi_code_printer_print (printer, swfdec_bits_get_u8 (&bits) ? "true" : "false");
+	vivi_code_printer_print (printer, value->v_boolean ? "true" : "false");
 	break;
       case VIVI_CODE_CONSTANT_DOUBLE:
-	{
-	  double number = swfdec_bits_get_double (&bits);
-	  s = g_malloc (G_ASCII_DTOSTR_BUF_SIZE);
-	  g_ascii_dtostr (s, G_ASCII_DTOSTR_BUF_SIZE, number);
-	  vivi_code_printer_print (printer, s);
-	  if (number == swfdec_as_double_to_integer (number))
-	    vivi_code_printer_print (printer, "d");
-	  g_free (s);
-	}
+	s = g_malloc (G_ASCII_DTOSTR_BUF_SIZE);
+	g_ascii_dtostr (s, G_ASCII_DTOSTR_BUF_SIZE, value->v_double);
+	vivi_code_printer_print (printer, s);
+	if (value->v_double == swfdec_as_double_to_integer (value->v_double))
+	  vivi_code_printer_print (printer, "d");
+	g_free (s);
 	break;
       case VIVI_CODE_CONSTANT_INTEGER:
-	s = g_strdup_printf ("%d", swfdec_bits_get_s32 (&bits));
+	s = g_strdup_printf ("%d", value->v_integer);
 	vivi_code_printer_print (printer, s);
 	g_free (s);
 	break;
       case VIVI_CODE_CONSTANT_CONSTANT_POOL:
-	s = g_strdup_printf ("pool %u", swfdec_bits_get_u8 (&bits));
+	s = g_strdup_printf ("pool %u", value->v_constant_pool);
 	vivi_code_printer_print (printer, s);
 	g_free (s);
 	break;
       case VIVI_CODE_CONSTANT_CONSTANT_POOL_BIG:
 	/* FIXME: allow differentiation between pool type for values < 256? */
-	s = g_strdup_printf ("pool %u", swfdec_bits_get_u16 (&bits));
+	s = g_strdup_printf ("pool %u", value->v_constant_pool);
 	vivi_code_printer_print (printer, s);
 	g_free (s);
 	break;
@@ -140,6 +188,7 @@ vivi_code_asm_push_print (ViviCodeToken *token, ViviCodePrinter*printer)
 	g_assert_not_reached ();
     }
   }
+
   vivi_code_printer_new_line (printer, FALSE);
 }
 
@@ -147,9 +196,17 @@ static void
 vivi_code_asm_push_dispose (GObject *object)
 {
   ViviCodeAsmPush *push = VIVI_CODE_ASM_PUSH (object);
+  guint i;
+
+  for (i = 0; i < push->values->len; i++) {
+    ViviCodeAsmPushValue *value =
+      &g_array_index (push->values, ViviCodeAsmPushValue, i);
+    if (value->type == VIVI_CODE_CONSTANT_STRING) {
+      g_free (value->v_string);
+    }
+  }
 
-  swfdec_bots_free (push->contents);
-  g_ptr_array_free (push->offsets, TRUE);
+  g_array_free (push->values, TRUE);
 
   G_OBJECT_CLASS (vivi_code_asm_push_parent_class)->dispose (object);
 }
@@ -165,14 +222,13 @@ vivi_code_asm_push_class_init (ViviCodeAsmPushClass *klass)
 
   token_class->print = vivi_code_asm_push_print;
 
-  code_class->bytecode = SWFDEC_AS_ACTION_STORE_REGISTER;
+  code_class->bytecode = SWFDEC_AS_ACTION_PUSH;
 }
 
 static void
 vivi_code_asm_push_init (ViviCodeAsmPush *push)
 {
-  push->contents = swfdec_bots_open ();
-  push->offsets = g_ptr_array_new ();
+  push->values = g_array_new (FALSE, FALSE, sizeof(ViviCodeAsmPushValue));
 }
 
 ViviCodeAsm *
@@ -185,278 +241,256 @@ guint
 vivi_code_asm_push_get_n_values (const ViviCodeAsmPush *push)
 {
   g_return_val_if_fail (VIVI_IS_CODE_ASM_PUSH (push), 0);
-  
-  return push->offsets->len;
+
+  return push->values->len;
 }
 
 ViviCodeConstantType
 vivi_code_asm_push_get_value_type (const ViviCodeAsmPush *push, guint i)
 {
-  g_return_val_if_fail (VIVI_IS_CODE_ASM_PUSH (push), 0);
-  g_return_val_if_fail (i < push->offsets->len, 0);
+  g_return_val_if_fail (VIVI_IS_CODE_ASM_PUSH (push),
+      VIVI_CODE_CONSTANT_UNDEFINED);
+  g_return_val_if_fail (i < push->values->len, VIVI_CODE_CONSTANT_UNDEFINED);
 
-  return push->contents->data[GPOINTER_TO_SIZE (g_ptr_array_index (push->offsets, i))];
+  return g_array_index (push->values, ViviCodeAsmPushValue, i).type;
+}
+
+static void
+vivi_code_asm_push_insert_value (ViviCodeAsmPush *push, guint index_,
+    ViviCodeAsmPushValue *value)
+{
+  g_return_if_fail (VIVI_IS_CODE_ASM_PUSH (push));
+  g_return_if_fail (value != NULL);
+
+  if (index_ < push->values->len) {
+    g_array_insert_val (push->values, index_, *value);
+  } else {
+    g_array_append_val (push->values, *value);
+  }
 }
 
 void
-vivi_code_asm_push_add_string (ViviCodeAsmPush *push, const char *string)
+vivi_code_asm_push_insert_string (ViviCodeAsmPush *push, guint index_,
+    const char *string)
 {
+  ViviCodeAsmPushValue value;
+
   g_return_if_fail (VIVI_IS_CODE_ASM_PUSH (push));
   g_return_if_fail (string != NULL);
 
-  g_ptr_array_add (push->offsets, GSIZE_TO_POINTER (swfdec_bots_get_bytes (push->contents)));
-  swfdec_bots_put_u8 (push->contents, VIVI_CODE_CONSTANT_STRING);
-  swfdec_bots_put_string (push->contents, string);
+  value.type = VIVI_CODE_CONSTANT_STRING;
+  value.v_string = g_strdup (string);
+  vivi_code_asm_push_insert_value (push, index_, &value);
 }
 
 void
-vivi_code_asm_push_add_float (ViviCodeAsmPush *push, float f)
+vivi_code_asm_push_insert_float (ViviCodeAsmPush *push, guint index_, float f)
 {
+  ViviCodeAsmPushValue value;
+
   g_return_if_fail (VIVI_IS_CODE_ASM_PUSH (push));
 
-  g_ptr_array_add (push->offsets, GSIZE_TO_POINTER (swfdec_bots_get_bytes (push->contents)));
-  swfdec_bots_put_u8 (push->contents, VIVI_CODE_CONSTANT_FLOAT);
-  swfdec_bots_put_float (push->contents, f);
+  value.type = VIVI_CODE_CONSTANT_FLOAT;
+  value.v_float = f;
+  vivi_code_asm_push_insert_value (push, index_, &value);
 }
 
 void
-vivi_code_asm_push_add_null (ViviCodeAsmPush *push)
+vivi_code_asm_push_insert_null (ViviCodeAsmPush *push, guint index_)
 {
+  ViviCodeAsmPushValue value;
+
   g_return_if_fail (VIVI_IS_CODE_ASM_PUSH (push));
 
-  g_ptr_array_add (push->offsets, GSIZE_TO_POINTER (swfdec_bots_get_bytes (push->contents)));
-  swfdec_bots_put_u8 (push->contents, VIVI_CODE_CONSTANT_NULL);
+  value.type = VIVI_CODE_CONSTANT_NULL;
+  vivi_code_asm_push_insert_value (push, index_, &value);
 }
 
 void
-vivi_code_asm_push_add_undefined (ViviCodeAsmPush *push)
+vivi_code_asm_push_insert_undefined (ViviCodeAsmPush *push, guint index_)
 {
+  ViviCodeAsmPushValue value;
+
   g_return_if_fail (VIVI_IS_CODE_ASM_PUSH (push));
 
-  g_ptr_array_add (push->offsets, GSIZE_TO_POINTER (swfdec_bots_get_bytes (push->contents)));
-  swfdec_bots_put_u8 (push->contents, VIVI_CODE_CONSTANT_UNDEFINED);
+  value.type = VIVI_CODE_CONSTANT_UNDEFINED;
+  vivi_code_asm_push_insert_value (push, index_, &value);
 }
 
 void
-vivi_code_asm_push_add_register (ViviCodeAsmPush *push, guint id)
+vivi_code_asm_push_insert_register (ViviCodeAsmPush *push, guint index_,
+    guint id)
 {
+  ViviCodeAsmPushValue value;
+
   g_return_if_fail (VIVI_IS_CODE_ASM_PUSH (push));
   g_return_if_fail (id < 256);
 
-  g_ptr_array_add (push->offsets, GSIZE_TO_POINTER (swfdec_bots_get_bytes (push->contents)));
-  swfdec_bots_put_u8 (push->contents, VIVI_CODE_CONSTANT_REGISTER);
-  swfdec_bots_put_u8 (push->contents, id);
+  value.type = VIVI_CODE_CONSTANT_REGISTER;
+  value.v_register = id;
+  vivi_code_asm_push_insert_value (push, index_, &value);
 }
 
 void
-vivi_code_asm_push_add_boolean (ViviCodeAsmPush *push, gboolean b)
+vivi_code_asm_push_insert_boolean (ViviCodeAsmPush *push, guint index_,
+    gboolean b)
 {
+  ViviCodeAsmPushValue value;
+
   g_return_if_fail (VIVI_IS_CODE_ASM_PUSH (push));
 
-  g_ptr_array_add (push->offsets, GSIZE_TO_POINTER (swfdec_bots_get_bytes (push->contents)));
-  swfdec_bots_put_u8 (push->contents, VIVI_CODE_CONSTANT_BOOLEAN);
-  swfdec_bots_put_u8 (push->contents, b ? 1 : 0);
+  value.type = VIVI_CODE_CONSTANT_BOOLEAN;
+  value.v_boolean = b;
+  vivi_code_asm_push_insert_value (push, index_, &value);
 }
 
 void
-vivi_code_asm_push_add_double (ViviCodeAsmPush *push, double d)
+vivi_code_asm_push_insert_double (ViviCodeAsmPush *push, guint index_,
+    double d)
 {
+  ViviCodeAsmPushValue value;
+
   g_return_if_fail (VIVI_IS_CODE_ASM_PUSH (push));
 
-  g_ptr_array_add (push->offsets, GSIZE_TO_POINTER (swfdec_bots_get_bytes (push->contents)));
-  swfdec_bots_put_u8 (push->contents, VIVI_CODE_CONSTANT_DOUBLE);
-  swfdec_bots_put_double (push->contents, d);
+  value.type = VIVI_CODE_CONSTANT_DOUBLE;
+  value.v_double = d;
+  vivi_code_asm_push_insert_value (push, index_, &value);
 }
 
 void
-vivi_code_asm_push_add_integer (ViviCodeAsmPush *push, int i)
+vivi_code_asm_push_insert_integer (ViviCodeAsmPush *push, guint index_, int i)
 {
+  ViviCodeAsmPushValue value;
+
   g_return_if_fail (VIVI_IS_CODE_ASM_PUSH (push));
   g_return_if_fail (i >= G_MININT32 && i <= G_MAXINT32);
 
-  g_ptr_array_add (push->offsets, GSIZE_TO_POINTER (swfdec_bots_get_bytes (push->contents)));
-  swfdec_bots_put_u8 (push->contents, VIVI_CODE_CONSTANT_INTEGER);
-  swfdec_bots_put_u32 (push->contents, i);
+  value.type = VIVI_CODE_CONSTANT_INTEGER;
+  value.v_integer = i;
+  vivi_code_asm_push_insert_value (push, index_, &value);
 }
 
 void
-vivi_code_asm_push_add_pool (ViviCodeAsmPush *push, guint id)
+vivi_code_asm_push_insert_pool (ViviCodeAsmPush *push, guint index_, guint id)
 {
+  ViviCodeAsmPushValue value;
+
   g_return_if_fail (VIVI_IS_CODE_ASM_PUSH (push));
   g_return_if_fail (id < 256);
 
-  g_ptr_array_add (push->offsets, GSIZE_TO_POINTER (swfdec_bots_get_bytes (push->contents)));
-  swfdec_bots_put_u8 (push->contents, VIVI_CODE_CONSTANT_CONSTANT_POOL);
-  swfdec_bots_put_u8 (push->contents, id);
+  value.type = VIVI_CODE_CONSTANT_CONSTANT_POOL;
+  value.v_constant_pool = id;
+  vivi_code_asm_push_insert_value (push, index_, &value);
 }
 
 void
-vivi_code_asm_push_add_pool_big (ViviCodeAsmPush *push, guint id)
+vivi_code_asm_push_insert_pool_big (ViviCodeAsmPush *push, guint index_, guint id)
 {
+  ViviCodeAsmPushValue value;
+
   g_return_if_fail (VIVI_IS_CODE_ASM_PUSH (push));
   g_return_if_fail (id <= G_MAXUINT16);
 
-  g_ptr_array_add (push->offsets, GSIZE_TO_POINTER (swfdec_bots_get_bytes (push->contents)));
-  swfdec_bots_put_u8 (push->contents, VIVI_CODE_CONSTANT_CONSTANT_POOL_BIG);
-  swfdec_bots_put_u16 (push->contents, id);
+  value.type = VIVI_CODE_CONSTANT_CONSTANT_POOL_BIG;
+  value.v_constant_pool = id;
+  vivi_code_asm_push_insert_value (push, index_, &value);
 }
 
 void
 vivi_code_asm_push_copy_value (ViviCodeAsmPush *push,
-    const ViviCodeAsmPush *other, guint id)
+    const ViviCodeAsmPush *other, guint index_)
 {
-  g_return_if_fail (VIVI_IS_CODE_ASM_PUSH (push));
-  g_return_if_fail (VIVI_IS_CODE_ASM_PUSH (other));
-  g_return_if_fail (id <= G_MAXUINT16);
+  ViviCodeAsmPushValue *value =
+    &g_array_index (other->values, ViviCodeAsmPushValue, index_);
+
+  if (value->type == VIVI_CODE_CONSTANT_STRING) {
+    ViviCodeAsmPushValue value_new;
+
+    value_new.type = VIVI_CODE_CONSTANT_STRING;
+    value_new.v_string = g_strdup (value->v_string);
 
-  switch (vivi_code_asm_push_get_value_type (other, id)) {
-    case VIVI_CODE_CONSTANT_STRING:
-      vivi_code_asm_push_add_string (push,
-	  vivi_code_asm_push_get_string (other, id));
-      break;
-    case VIVI_CODE_CONSTANT_FLOAT:
-      vivi_code_asm_push_add_float (push,
-	  vivi_code_asm_push_get_float (other, id));
-      break;
-    case VIVI_CODE_CONSTANT_NULL:
-      vivi_code_asm_push_add_null (push);
-      break;
-    case VIVI_CODE_CONSTANT_UNDEFINED:
-      vivi_code_asm_push_add_undefined (push);
-      break;
-    case VIVI_CODE_CONSTANT_REGISTER:
-      vivi_code_asm_push_add_register (push,
-	  vivi_code_asm_push_get_register (other, id));
-      break;
-    case VIVI_CODE_CONSTANT_BOOLEAN:
-      vivi_code_asm_push_add_boolean (push,
-	  vivi_code_asm_push_get_boolean (other, id));
-      break;
-    case VIVI_CODE_CONSTANT_DOUBLE:
-      vivi_code_asm_push_add_double (push,
-	  vivi_code_asm_push_get_double (other, id));
-      break;
-    case VIVI_CODE_CONSTANT_INTEGER:
-      vivi_code_asm_push_add_integer (push,
-	  vivi_code_asm_push_get_integer (other, id));
-      break;
-    case VIVI_CODE_CONSTANT_CONSTANT_POOL:
-      vivi_code_asm_push_add_pool (push,
-	  vivi_code_asm_push_get_pool (other, id));
-      break;
-    case VIVI_CODE_CONSTANT_CONSTANT_POOL_BIG:
-      vivi_code_asm_push_add_pool_big (push,
-	  vivi_code_asm_push_get_pool (other, id));
-      break;
-    default:
-      g_assert_not_reached ();
+    vivi_code_asm_push_insert_value (push, G_MAXUINT, &value_new);
+  } else {
+    vivi_code_asm_push_insert_value (push, G_MAXUINT, value);
   }
 }
 
 const char *
-vivi_code_asm_push_get_string (const ViviCodeAsmPush *push, guint id)
+vivi_code_asm_push_get_string (const ViviCodeAsmPush *push, guint index_)
 {
-  SwfdecBits bits;
-
   g_return_val_if_fail (VIVI_IS_CODE_ASM_PUSH (push), NULL);
-  g_return_val_if_fail (id < push->offsets->len, NULL);
-
-  swfdec_bits_init_data (&bits, push->contents->data, swfdec_bots_get_bytes (push->contents));
-  swfdec_bits_skip_bytes (&bits, GPOINTER_TO_SIZE (g_ptr_array_index (push->offsets, id)));
-  g_return_val_if_fail (swfdec_bits_get_u8 (&bits) == VIVI_CODE_CONSTANT_STRING, NULL);
+  g_return_val_if_fail (index_ < push->values->len, NULL);
+  g_return_val_if_fail (vivi_code_asm_push_get_value_type (push, index_)
+      == VIVI_CODE_CONSTANT_STRING, NULL);
 
-  return (char *) bits.ptr;
+  return g_array_index (push->values, ViviCodeAsmPushValue, index_).v_string;
 }
 
 float
-vivi_code_asm_push_get_float (const ViviCodeAsmPush *push, guint id)
+vivi_code_asm_push_get_float (const ViviCodeAsmPush *push, guint index_)
 {
-  SwfdecBits bits;
-
   g_return_val_if_fail (VIVI_IS_CODE_ASM_PUSH (push), 0.0f);
-  g_return_val_if_fail (id < push->offsets->len, 0.0f);
-
-  swfdec_bits_init_data (&bits, push->contents->data, swfdec_bots_get_bytes (push->contents));
-  swfdec_bits_skip_bytes (&bits, GPOINTER_TO_SIZE (g_ptr_array_index (push->offsets, id)));
-  g_return_val_if_fail (swfdec_bits_get_u8 (&bits) == VIVI_CODE_CONSTANT_FLOAT, 0.0f);
+  g_return_val_if_fail (index_ < push->values->len, 0.0f);
+  g_return_val_if_fail (vivi_code_asm_push_get_value_type (push, index_)
+      == VIVI_CODE_CONSTANT_FLOAT, 0.0f);
 
-  return swfdec_bits_get_float (&bits);
+  return g_array_index (push->values, ViviCodeAsmPushValue, index_).v_float;
 }
 
 guint
-vivi_code_asm_push_get_register (const ViviCodeAsmPush *push, guint id)
+vivi_code_asm_push_get_register (const ViviCodeAsmPush *push, guint index_)
 {
-  SwfdecBits bits;
-
   g_return_val_if_fail (VIVI_IS_CODE_ASM_PUSH (push), 0);
-  g_return_val_if_fail (id < push->offsets->len, 0);
+  g_return_val_if_fail (index_ < push->values->len, 0);
+  g_return_val_if_fail (vivi_code_asm_push_get_value_type (push, index_)
+      == VIVI_CODE_CONSTANT_REGISTER, 0);
 
-  swfdec_bits_init_data (&bits, push->contents->data, swfdec_bots_get_bytes (push->contents));
-  swfdec_bits_skip_bytes (&bits, GPOINTER_TO_SIZE (g_ptr_array_index (push->offsets, id)));
-  g_return_val_if_fail (swfdec_bits_get_u8 (&bits) == VIVI_CODE_CONSTANT_REGISTER, 0);
-
-  return swfdec_bits_get_u8 (&bits);
+  return g_array_index (push->values, ViviCodeAsmPushValue, index_).v_register;
 }
 
 double
-vivi_code_asm_push_get_double (const ViviCodeAsmPush *push, guint id)
+vivi_code_asm_push_get_double (const ViviCodeAsmPush *push, guint index_)
 {
-  SwfdecBits bits;
-
   g_return_val_if_fail (VIVI_IS_CODE_ASM_PUSH (push), 0.0);
-  g_return_val_if_fail (id < push->offsets->len, 0.0);
+  g_return_val_if_fail (index_ < push->values->len, 0.0);
+  g_return_val_if_fail (vivi_code_asm_push_get_value_type (push, index_)
+      == VIVI_CODE_CONSTANT_DOUBLE, 0);
 
-  swfdec_bits_init_data (&bits, push->contents->data, swfdec_bots_get_bytes (push->contents));
-  swfdec_bits_skip_bytes (&bits, GPOINTER_TO_SIZE (g_ptr_array_index (push->offsets, id)));
-  g_return_val_if_fail (swfdec_bits_get_u8 (&bits) == VIVI_CODE_CONSTANT_DOUBLE, 0.0);
-
-  return swfdec_bits_get_double (&bits);
+  return g_array_index (push->values, ViviCodeAsmPushValue, index_).v_double;
 }
 
 int
-vivi_code_asm_push_get_integer (const ViviCodeAsmPush *push, guint id)
+vivi_code_asm_push_get_integer (const ViviCodeAsmPush *push, guint index_)
 {
-  SwfdecBits bits;
-
-  g_return_val_if_fail (VIVI_IS_CODE_ASM_PUSH (push), FALSE);
-  g_return_val_if_fail (id < push->offsets->len, FALSE);
-
-  swfdec_bits_init_data (&bits, push->contents->data, swfdec_bots_get_bytes (push->contents));
-  swfdec_bits_skip_bytes (&bits, GPOINTER_TO_SIZE (g_ptr_array_index (push->offsets, id)));
-  g_return_val_if_fail (swfdec_bits_get_u8 (&bits) == VIVI_CODE_CONSTANT_INTEGER, FALSE);
+  g_return_val_if_fail (VIVI_IS_CODE_ASM_PUSH (push), 0);
+  g_return_val_if_fail (index_ < push->values->len, 0);
+  g_return_val_if_fail (vivi_code_asm_push_get_value_type (push, index_)
+      == VIVI_CODE_CONSTANT_INTEGER, 0);
 
-  return swfdec_bits_get_s32 (&bits);
+  return g_array_index (push->values, ViviCodeAsmPushValue, index_).v_integer;
 }
 
 gboolean
-vivi_code_asm_push_get_boolean (const ViviCodeAsmPush *push, guint id)
+vivi_code_asm_push_get_boolean (const ViviCodeAsmPush *push, guint index_)
 {
-  SwfdecBits bits;
-
   g_return_val_if_fail (VIVI_IS_CODE_ASM_PUSH (push), FALSE);
-  g_return_val_if_fail (id < push->offsets->len, FALSE);
-
-  swfdec_bits_init_data (&bits, push->contents->data, swfdec_bots_get_bytes (push->contents));
-  swfdec_bits_skip_bytes (&bits, GPOINTER_TO_SIZE (g_ptr_array_index (push->offsets, id)));
-  g_return_val_if_fail (swfdec_bits_get_u8 (&bits) == VIVI_CODE_CONSTANT_BOOLEAN, FALSE);
+  g_return_val_if_fail (index_ < push->values->len, FALSE);
+  g_return_val_if_fail (vivi_code_asm_push_get_value_type (push, index_)
+      == VIVI_CODE_CONSTANT_BOOLEAN, FALSE);
 
-  return swfdec_bits_get_u8 (&bits) ? TRUE : FALSE;
+  return g_array_index (push->values, ViviCodeAsmPushValue, index_).v_boolean;
 }
 
 guint
-vivi_code_asm_push_get_pool (const ViviCodeAsmPush *push, guint id)
+vivi_code_asm_push_get_pool (const ViviCodeAsmPush *push, guint index_)
 {
-  SwfdecBits bits;
-  guint type;
-
   g_return_val_if_fail (VIVI_IS_CODE_ASM_PUSH (push), 0);
-  g_return_val_if_fail (id < push->offsets->len, 0);
-
-  swfdec_bits_init_data (&bits, push->contents->data, swfdec_bots_get_bytes (push->contents));
-  swfdec_bits_skip_bytes (&bits, GPOINTER_TO_SIZE (g_ptr_array_index (push->offsets, id)));
-  type = swfdec_bits_get_u8 (&bits);
-  g_return_val_if_fail (type == VIVI_CODE_CONSTANT_CONSTANT_POOL ||
-      type == VIVI_CODE_CONSTANT_CONSTANT_POOL_BIG, 0);
-
-  return type == VIVI_CODE_CONSTANT_CONSTANT_POOL ? swfdec_bits_get_u8 (&bits) : swfdec_bits_get_u16 (&bits);
+  g_return_val_if_fail (index_ < push->values->len, 0);
+  g_return_val_if_fail (vivi_code_asm_push_get_value_type (push, index_) ==
+      VIVI_CODE_CONSTANT_CONSTANT_POOL ||
+      vivi_code_asm_push_get_value_type (push, index_) ==
+      VIVI_CODE_CONSTANT_CONSTANT_POOL_BIG, FALSE);
+
+  return
+    g_array_index (push->values, ViviCodeAsmPushValue, index_).v_constant_pool;
 }
diff --git a/vivified/code/vivi_code_asm_push.h b/vivified/code/vivi_code_asm_push.h
index e0f36e3..a8308e8 100644
--- a/vivified/code/vivi_code_asm_push.h
+++ b/vivified/code/vivi_code_asm_push.h
@@ -53,8 +53,7 @@ struct _ViviCodeAsmPush
 {
   ViviCodeAsmCode	code;
 
-  SwfdecBots *		contents;
-  GPtrArray *		offsets;
+  GArray *		values;
 };
 
 struct _ViviCodeAsmPushClass
@@ -70,41 +69,62 @@ guint			vivi_code_asm_push_get_n_values		(const ViviCodeAsmPush *	push);
 ViviCodeConstantType	vivi_code_asm_push_get_value_type	(const ViviCodeAsmPush *	push,
 								 guint			i);
 const char *		vivi_code_asm_push_get_string		(const ViviCodeAsmPush *	push,
-								 guint			id);
+								 guint			index_);
 float			vivi_code_asm_push_get_float		(const ViviCodeAsmPush *	push,
-								 guint			id);
+								 guint			index_);
 guint			vivi_code_asm_push_get_register		(const ViviCodeAsmPush *	push,
-								 guint			id);
+								 guint			index_);
 double			vivi_code_asm_push_get_double		(const ViviCodeAsmPush *	push,
-								 guint			id);
+								 guint			index_);
 int			vivi_code_asm_push_get_integer		(const ViviCodeAsmPush *	push,
-								 guint			id);
+								 guint			index_);
 gboolean		vivi_code_asm_push_get_boolean		(const ViviCodeAsmPush *	push,
-								 guint			id);
+								 guint			index_);
 guint			vivi_code_asm_push_get_pool		(const ViviCodeAsmPush *	push,
-								 guint			id);
+								 guint			index_);
 
-void			vivi_code_asm_push_add_string		(ViviCodeAsmPush *	push,
+#define vivi_code_asm_push_add_string(push, string) vivi_code_asm_push_insert_string(push, G_MAXUINT, string)
+void			vivi_code_asm_push_insert_string	(ViviCodeAsmPush *	push,
+								 guint			index_,
 								 const char *		string);
-void			vivi_code_asm_push_add_float		(ViviCodeAsmPush *	push,
+#define vivi_code_asm_push_add_float(push, f) vivi_code_asm_push_insert_float(push, G_MAXUINT, f)
+void			vivi_code_asm_push_insert_float		(ViviCodeAsmPush *	push,
+								 guint			index_,
 								 float			f);
-void			vivi_code_asm_push_add_null		(ViviCodeAsmPush *	push);
-void			vivi_code_asm_push_add_undefined	(ViviCodeAsmPush *	push);
-void			vivi_code_asm_push_add_register		(ViviCodeAsmPush *	push,
+#define vivi_code_asm_push_add_null(push) vivi_code_asm_push_insert_null(push, G_MAXUINT)
+void			vivi_code_asm_push_insert_null		(ViviCodeAsmPush *	push,
+								 guint			index_);
+#define vivi_code_asm_push_add_undefined(push) vivi_code_asm_push_insert_undefined(push, G_MAXUINT)
+void			vivi_code_asm_push_insert_undefined	(ViviCodeAsmPush *	push,
+								 guint			index_);
+#define vivi_code_asm_push_add_register(push, id) vivi_code_asm_push_insert_register(push, G_MAXUINT, id)
+void			vivi_code_asm_push_insert_register	(ViviCodeAsmPush *	push,
+								 guint			index_,
 								 guint			id);
-void			vivi_code_asm_push_add_boolean		(ViviCodeAsmPush *	push,
+#define vivi_code_asm_push_add_boolean(push, b) vivi_code_asm_push_insert_boolean(push, G_MAXUINT, b)
+void			vivi_code_asm_push_insert_boolean	(ViviCodeAsmPush *	push,
+								 guint			index_,
 								 gboolean		b);
-void			vivi_code_asm_push_add_double		(ViviCodeAsmPush *	push,
+#define vivi_code_asm_push_add_double(push, d) vivi_code_asm_push_insert_double(push, G_MAXUINT, d)
+void			vivi_code_asm_push_insert_double	(ViviCodeAsmPush *	push,
+								 guint			index_,
 								 double			d);
-void			vivi_code_asm_push_add_integer		(ViviCodeAsmPush *	push,
+#define vivi_code_asm_push_add_integer(push, i) vivi_code_asm_push_insert_integer(push, G_MAXUINT, i)
+void			vivi_code_asm_push_insert_integer	(ViviCodeAsmPush *	push,
+								 guint			index_,
 								 int			i);
-void			vivi_code_asm_push_add_pool		(ViviCodeAsmPush *	push,
+#define vivi_code_asm_push_add_pool(push, id) vivi_code_asm_push_insert_pool(push, G_MAXUINT, id)
+void			vivi_code_asm_push_insert_pool		(ViviCodeAsmPush *	push,
+								 guint			index_,
 								 guint			id);
-void			vivi_code_asm_push_add_pool_big		(ViviCodeAsmPush *	push,
+#define vivi_code_asm_push_add_pool_big(push, id) vivi_code_asm_push_insert_pool_big(push, G_MAXUINT, id)
+void			vivi_code_asm_push_insert_pool_big	(ViviCodeAsmPush *	push,
+								 guint			index_,
 								 guint			id);
+
 void			vivi_code_asm_push_copy_value		(ViviCodeAsmPush *	push,
 								 const ViviCodeAsmPush *other,
-								 guint id);
+								 guint			index_);
 
 
 G_END_DECLS
commit 85555a8206380124a23c15e145e4fc91a31e2dfe
Merge: 9d51e1c... 62308fc...
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Wed May 21 15:33:59 2008 +0300

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

commit 9d51e1ca49188c2616adf29f9f600762e390308a
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Mon May 19 16:35:39 2008 +0300

    Add a vivi-compile test for push asm statement

diff --git a/vivified/code/test/compiler/Makefile.am b/vivified/code/test/compiler/Makefile.am
index 4b24789..d979ea0 100644
--- a/vivified/code/test/compiler/Makefile.am
+++ b/vivified/code/test/compiler/Makefile.am
@@ -28,6 +28,8 @@ EXTRA_DIST = \
 	asm_default.as.expect \
 	asm_label.as \
 	asm_label.as.expect \
+	asm_push.as \
+	asm_push.as.expect \
 	assignment.as \
 	assignment.as.expect \
 	assignment_member.as \
diff --git a/vivified/code/test/compiler/asm_push.as b/vivified/code/test/compiler/asm_push.as
new file mode 100644
index 0000000..20cef88
--- /dev/null
+++ b/vivified/code/test/compiler/asm_push.as
@@ -0,0 +1,6 @@
+asm {
+  push true, false, null, undefined
+  push 1, 1.2, 1f, 1d
+  push "stacked", pool 0, pool 1234
+  push reg 0
+}
diff --git a/vivified/code/test/compiler/asm_push.as.expect b/vivified/code/test/compiler/asm_push.as.expect
new file mode 100644
index 0000000..f8cfe54
--- /dev/null
+++ b/vivified/code/test/compiler/asm_push.as.expect
@@ -0,0 +1,4 @@
+asm {
+  push true, false, null, undefined, 1, 1.2, 1f, 1d, "stacked", pool 0, pool 1234, reg 0
+  end
+}
commit 04eb282736856d10b6859f1aeafbd2e91a69968b
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Mon May 19 15:22:26 2008 +0300

    More fixes to printing

diff --git a/vivified/code/vivi_decompiler_duplicate.c b/vivified/code/vivi_decompiler_duplicate.c
index f1fd71d..03dc865 100644
--- a/vivified/code/vivi_decompiler_duplicate.c
+++ b/vivified/code/vivi_decompiler_duplicate.c
@@ -37,9 +37,10 @@ vivi_decompiler_duplicate_dispose (GObject *object)
 }
 
 static void
-vivi_decompiler_duplicate_print (ViviCodeToken *token, ViviCodePrinter*printer)
+vivi_decompiler_duplicate_print_value (ViviCodeValue *value,
+    ViviCodePrinter *printer)
 {
-  ViviDecompilerDuplicate *dupl = VIVI_DECOMPILER_DUPLICATE (token);
+  ViviDecompilerDuplicate *dupl = VIVI_DECOMPILER_DUPLICATE (value);
 
   g_printerr ("FIXME: printing duplicate!\n");
   vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (dupl->value));
@@ -55,13 +56,11 @@ static void
 vivi_decompiler_duplicate_class_init (ViviDecompilerDuplicateClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
-  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
   ViviCodeValueClass *value_class = VIVI_CODE_VALUE_CLASS (klass);
 
   object_class->dispose = vivi_decompiler_duplicate_dispose;
 
-  token_class->print = vivi_decompiler_duplicate_print;
-
+  value_class->print_value = vivi_decompiler_duplicate_print_value;
   value_class->is_constant = vivi_decompiler_duplicate_is_constant;
 }
 
diff --git a/vivified/code/vivi_decompiler_unknown.c b/vivified/code/vivi_decompiler_unknown.c
index 4545069..e36ad3f 100644
--- a/vivified/code/vivi_decompiler_unknown.c
+++ b/vivified/code/vivi_decompiler_unknown.c
@@ -39,12 +39,14 @@ vivi_decompiler_unknown_dispose (GObject *object)
 }
 
 static void
-vivi_decompiler_unknown_print (ViviCodeToken *token, ViviCodePrinter*printer)
+vivi_decompiler_unknown_print_value (ViviCodeValue *value,
+    ViviCodePrinter *printer)
 {
-  ViviDecompilerUnknown *unknown = VIVI_DECOMPILER_UNKNOWN (token);
+  ViviDecompilerUnknown *unknown = VIVI_DECOMPILER_UNKNOWN (value);
 
   if (unknown->value) {
-    vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (unknown->value));
+    vivi_code_printer_print_value (printer, unknown->value,
+	VIVI_PRECEDENCE_MIN);
   } else {
     g_printerr ("FIXME: printing unknown!\n");
     vivi_code_printer_print (printer, unknown->name);
@@ -77,13 +79,11 @@ static void
 vivi_decompiler_unknown_class_init (ViviDecompilerUnknownClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
-  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
   ViviCodeValueClass *value_class = VIVI_CODE_VALUE_CLASS (klass);
 
   object_class->dispose = vivi_decompiler_unknown_dispose;
 
-  token_class->print = vivi_decompiler_unknown_print;
-
+  value_class->print_value = vivi_decompiler_unknown_print_value;
   value_class->is_constant = vivi_decompiler_unknown_is_constant;
   value_class->optimize = vivi_decompiler_unknown_optimize;
 }
commit 3763e331b69b38dcf392afdd0253e10dc74aba0b
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Mon May 19 15:10:25 2008 +0300

    Fix couple of bugs in printing of ViviCode classes

diff --git a/vivified/code/vivi_code_assignment.c b/vivified/code/vivi_code_assignment.c
index ba383b4..26455db 100644
--- a/vivified/code/vivi_code_assignment.c
+++ b/vivified/code/vivi_code_assignment.c
@@ -47,9 +47,10 @@ vivi_code_assignment_dispose (GObject *object)
 }
 
 static void
-vivi_code_assignment_print (ViviCodeToken *token, ViviCodePrinter*printer)
+vivi_code_assignment_print_value (ViviCodeValue *value,
+    ViviCodePrinter *printer)
 {
-  ViviCodeAssignment *assignment = VIVI_CODE_ASSIGNMENT (token);
+  ViviCodeAssignment *assignment = VIVI_CODE_ASSIGNMENT (value);
   char *varname;
 
   if (VIVI_IS_CODE_CONSTANT (assignment->name)) {
@@ -142,9 +143,9 @@ vivi_code_assignment_class_init (ViviCodeAssignmentClass *klass)
 
   object_class->dispose = vivi_code_assignment_dispose;
 
-  token_class->print = vivi_code_assignment_print;
   token_class->compile = vivi_code_assignment_compile;
 
+  value_class->print_value = vivi_code_assignment_print_value;
   value_class->compile_value = vivi_code_assignment_compile_value;
 }
 
diff --git a/vivified/code/vivi_code_get_url.c b/vivified/code/vivi_code_get_url.c
index 724e1c3..ea1bb2a 100644
--- a/vivified/code/vivi_code_get_url.c
+++ b/vivified/code/vivi_code_get_url.c
@@ -50,9 +50,9 @@ vivi_code_get_url_print (ViviCodeToken *token, ViviCodePrinter *printer)
   } else {
     vivi_code_printer_print (printer, "getURL (");
   }
-  vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (url->url));
+  vivi_code_printer_print_value (printer, url->url, VIVI_PRECEDENCE_MIN);
   vivi_code_printer_print (printer, ", ");
-  vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (url->target));
+  vivi_code_printer_print_value (printer, url->target, VIVI_PRECEDENCE_MIN);
   if (url->method != 0) {
     vivi_code_printer_print (printer,
 	url->method == 2 ? ", \"POST\"" : ", \"GET\"");
diff --git a/vivified/code/vivi_code_if.c b/vivified/code/vivi_code_if.c
index 0955937..c0601b7 100644
--- a/vivified/code/vivi_code_if.c
+++ b/vivified/code/vivi_code_if.c
@@ -94,7 +94,8 @@ vivi_code_if_print (ViviCodeToken *token, ViviCodePrinter *printer)
   gboolean needs_braces;
 
   vivi_code_printer_print (printer, "if (");
-  vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (stmt->condition));
+  vivi_code_printer_print_value (printer, stmt->condition,
+      VIVI_PRECEDENCE_MIN);
   vivi_code_printer_print (printer, ")");
   needs_braces = stmt->if_statement && vivi_code_statement_needs_braces (stmt->if_statement);
   needs_braces |= stmt->else_statement && vivi_code_statement_needs_braces (stmt->else_statement);
diff --git a/vivified/code/vivi_code_loop.c b/vivified/code/vivi_code_loop.c
index 61f969a..cf9a375 100644
--- a/vivified/code/vivi_code_loop.c
+++ b/vivified/code/vivi_code_loop.c
@@ -54,7 +54,8 @@ vivi_code_loop_print (ViviCodeToken *token, ViviCodePrinter *printer)
   needs_braces = loop->statement && vivi_code_statement_needs_braces (loop->statement);
   if (loop->condition) {
     vivi_code_printer_print (printer, "while (");
-    vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (loop->condition));
+    vivi_code_printer_print_value (printer, loop->condition,
+	VIVI_PRECEDENCE_MIN);
     vivi_code_printer_print (printer, ")");
   } else {
     vivi_code_printer_print (printer, "for (;;)");
commit 7c3c8ccd5a621b8275c29ec8e1d046f1b079a1a8
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Mon May 19 14:24:54 2008 +0300

    Add a test for compiling conditional expression

diff --git a/vivified/code/test/compiler/Makefile.am b/vivified/code/test/compiler/Makefile.am
index 84445fa..4b24789 100644
--- a/vivified/code/test/compiler/Makefile.am
+++ b/vivified/code/test/compiler/Makefile.am
@@ -44,6 +44,8 @@ EXTRA_DIST = \
 	call_function.as.expect \
 	comment.as \
 	comment.as.expect \
+	conditional.as \
+	conditional.as.expect \
 	decrement.as \
 	decrement.as.expect \
 	do_while.as \
diff --git a/vivified/code/test/compiler/conditional.as b/vivified/code/test/compiler/conditional.as
new file mode 100644
index 0000000..86729fb
--- /dev/null
+++ b/vivified/code/test/compiler/conditional.as
@@ -0,0 +1 @@
+trace (a ? b : c);
diff --git a/vivified/code/test/compiler/conditional.as.expect b/vivified/code/test/compiler/conditional.as.expect
new file mode 100644
index 0000000..234dc7b
--- /dev/null
+++ b/vivified/code/test/compiler/conditional.as.expect
@@ -0,0 +1,17 @@
+asm {
+  pool "a", "c", "b"
+  push pool 0
+  get_variable
+  if conditional_if_0001
+  push pool 1
+  get_variable
+  jump conditional_end_0002
+
+conditional_if_0001:
+  push pool 2
+  get_variable
+
+conditional_end_0002:
+  trace
+  end
+}
commit a616d6fea643bb3cce23c3560a94e3d17656f84a
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Mon May 19 14:23:57 2008 +0300

    Implement parsing and compiling of conditional expressions

diff --git a/vivified/code/Makefile.am b/vivified/code/Makefile.am
index 89e09ec..87409e4 100644
--- a/vivified/code/Makefile.am
+++ b/vivified/code/Makefile.am
@@ -57,6 +57,7 @@ libvivified_compiler_la_SOURCES = \
 	vivi_code_comment.c \
 	vivi_code_compiler.c \
 	vivi_code_concat.c \
+	vivi_code_conditional.c \
 	vivi_code_constant.c \
 	vivi_code_continue.c \
 	vivi_code_emitter.c \
@@ -134,6 +135,7 @@ noinst_HEADERS = \
 	vivi_code_comment.h \
 	vivi_code_compiler.h \
 	vivi_code_concat.h \
+	vivi_code_conditional.h \
 	vivi_code_constant.h \
 	vivi_code_continue.h \
 	vivi_code_defaults.h \
diff --git a/vivified/code/vivi_code_conditional.c b/vivified/code/vivi_code_conditional.c
new file mode 100644
index 0000000..4a3f5f2
--- /dev/null
+++ b/vivified/code/vivi_code_conditional.c
@@ -0,0 +1,120 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_code_conditional.h"
+#include "vivi_code_get.h"
+#include "vivi_code_printer.h"
+#include "vivi_code_string.h"
+#include "vivi_code_undefined.h"
+#include "vivi_code_compiler.h"
+#include "vivi_code_asm_code_default.h"
+#include "vivi_code_asm_if.h"
+#include "vivi_code_asm_jump.h"
+
+G_DEFINE_TYPE (ViviCodeConditional, vivi_code_conditional, VIVI_TYPE_CODE_VALUE)
+
+static void
+vivi_code_conditional_dispose (GObject *object)
+{
+  ViviCodeConditional *conditional = VIVI_CODE_CONDITIONAL (object);
+
+  g_object_unref (conditional->condition);
+  g_object_unref (conditional->if_value);
+  g_object_unref (conditional->else_value);
+
+  G_OBJECT_CLASS (vivi_code_conditional_parent_class)->dispose (object);
+}
+
+static void
+vivi_code_conditional_print_value (ViviCodeValue *value,
+    ViviCodePrinter *printer)
+{
+  ViviCodeConditional *conditional = VIVI_CODE_CONDITIONAL (value);
+
+  vivi_code_printer_print_value (printer, conditional->condition,
+      VIVI_PRECEDENCE_CONDITIONAL);
+  vivi_code_printer_print (printer, " ? ");
+  vivi_code_printer_print_value (printer, conditional->if_value,
+      VIVI_PRECEDENCE_CONDITIONAL);
+  vivi_code_printer_print (printer, " : ");
+  vivi_code_printer_print_value (printer, conditional->else_value,
+      VIVI_PRECEDENCE_CONDITIONAL);
+}
+
+static void
+vivi_code_conditional_compile_value (ViviCodeValue *value,
+    ViviCodeCompiler *compiler)
+{
+  ViviCodeConditional *conditional = VIVI_CODE_CONDITIONAL (value);
+  ViviCodeLabel *label_if, *label_end;
+
+  vivi_code_compiler_compile_value (compiler, conditional->condition);
+
+  label_if = vivi_code_compiler_create_label (compiler, "conditional_if");
+  vivi_code_compiler_take_code (compiler, vivi_code_asm_if_new (label_if));
+
+  vivi_code_compiler_compile_value (compiler, conditional->else_value);
+  label_end = vivi_code_compiler_create_label (compiler, "conditional_end");
+  vivi_code_compiler_take_code (compiler, vivi_code_asm_jump_new (label_end));
+
+  vivi_code_compiler_take_code (compiler, VIVI_CODE_ASM (label_if));
+  vivi_code_compiler_compile_value (compiler, conditional->if_value);
+
+  vivi_code_compiler_take_code (compiler, VIVI_CODE_ASM (label_end));
+}
+
+static void
+vivi_code_conditional_class_init (ViviCodeConditionalClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeValueClass *value_class = VIVI_CODE_VALUE_CLASS (klass);
+
+  object_class->dispose = vivi_code_conditional_dispose;
+
+  value_class->print_value = vivi_code_conditional_print_value;
+  value_class->compile_value = vivi_code_conditional_compile_value;
+}
+
+static void
+vivi_code_conditional_init (ViviCodeConditional *conditional)
+{
+}
+
+ViviCodeValue *
+vivi_code_conditional_new (ViviCodeValue *condition, ViviCodeValue *if_value,
+    ViviCodeValue *else_value)
+{
+  ViviCodeConditional *conditional;
+
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (condition), NULL);
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (if_value), NULL);
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (else_value), NULL);
+
+  conditional = g_object_new (VIVI_TYPE_CODE_CONDITIONAL, NULL);
+  if (conditional)
+    conditional->condition = g_object_ref (condition);
+  conditional->if_value = g_object_ref (if_value);
+  conditional->else_value = g_object_ref (else_value);
+
+  return VIVI_CODE_VALUE (conditional);
+}
diff --git a/vivified/code/vivi_code_conditional.h b/vivified/code/vivi_code_conditional.h
new file mode 100644
index 0000000..7a4fb60
--- /dev/null
+++ b/vivified/code/vivi_code_conditional.h
@@ -0,0 +1,61 @@
+/* Vivified
+ * Copyright (C) 2008 Pekka Lampila <pekka.lampila at iki.fi>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_CONDITIONAL_H_
+#define _VIVI_CODE_CONDITIONAL_H_
+
+#include <vivified/code/vivi_code_value.h>
+#include <vivified/code/vivi_code_value.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeConditional ViviCodeConditional;
+typedef struct _ViviCodeConditionalClass ViviCodeConditionalClass;
+
+#define VIVI_TYPE_CODE_CONDITIONAL                    (vivi_code_conditional_get_type())
+#define VIVI_IS_CODE_CONDITIONAL(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_CONDITIONAL))
+#define VIVI_IS_CODE_CONDITIONAL_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_CONDITIONAL))
+#define VIVI_CODE_CONDITIONAL(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_CONDITIONAL, ViviCodeConditional))
+#define VIVI_CODE_CONDITIONAL_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_CONDITIONAL, ViviCodeConditionalClass))
+#define VIVI_CODE_CONDITIONAL_CONDITIONAL_CLASS(obj)          (G_TYPE_INSTANCE_CONDITIONAL_CLASS ((obj), VIVI_TYPE_CODE_CONDITIONAL, ViviCodeConditionalClass))
+
+struct _ViviCodeConditional
+{
+  ViviCodeValue		token;
+
+  ViviCodeValue *	condition;
+  ViviCodeValue *	if_value;
+  ViviCodeValue	*	else_value;
+};
+
+struct _ViviCodeConditionalClass
+{
+  ViviCodeValueClass	value_class;
+};
+
+GType			vivi_code_conditional_get_type		(void);
+
+ViviCodeValue *		vivi_code_conditional_new		(ViviCodeValue *	condition,
+								 ViviCodeValue *	if_value,
+								 ViviCodeValue *	else_value);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_parser.c b/vivified/code/vivi_parser.c
index 2db3047..a6961df 100644
--- a/vivified/code/vivi_parser.c
+++ b/vivified/code/vivi_parser.c
@@ -40,6 +40,7 @@
 #include "vivi_code_builtin_value_call_default.h"
 #include "vivi_code_builtin_value_statement_default.h"
 #include "vivi_code_concat.h"
+#include "vivi_code_conditional.h"
 #include "vivi_code_constant.h"
 #include "vivi_code_continue.h"
 #include "vivi_code_enumerate.h"
@@ -2168,8 +2169,23 @@ peek_conditional_expression (ParseData *data)
 static ViviCodeValue *
 parse_conditional_expression (ParseData *data)
 {
-  // TODO
-  return parse_logical_or_expression (data);
+  ViviCodeValue *condition, *if_value, *else_value, *conditional;
+
+  condition = parse_logical_or_expression (data);
+
+  if (!try_parse_token (data, TOKEN_QUESTION_MARK))
+    return condition;
+
+  if_value = parse_assignment_expression (data);
+  parse_token (data, TOKEN_COLON);
+  else_value = parse_assignment_expression (data);
+
+  conditional = vivi_code_conditional_new (condition, if_value, else_value);
+  g_object_unref (condition);
+  g_object_unref (if_value);
+  g_object_unref (else_value);
+
+  return conditional;
 }
 
 static gboolean


More information about the Swfdec-commits mailing list