summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkira TAGOH <akira@tagoh.org>2006-10-08 19:41:41 +0000
committerAkira TAGOH <akira@tagoh.org>2006-10-08 19:41:41 +0000
commit88ca5b5f6fd94fb08ee0d02e28e5b1e310f244f3 (patch)
treeb1f02f66de3bbfabe60f956af362632b34632d4d
parent9bde539f51912d4bc384a1e30c2a5d4ee6bbd9bf (diff)
2006-10-09 Akira TAGOH <at@gclab.org>
* tests/ps/test-0base.ps: new testcase. * hieroglyph/operator.c (_hg_operator_op_cvi): check the overflow. * hieroglyph/scanner.c (_hg_scanner_get_object): split up the numeral parser. (_hg_scanner_parse_number): new function. * hieroglyph/Makefile.am (libhieroglyph_private_SOURCES): add iarray.[ch]. * hieroglyph/iarray.[ch]: new files.
-rw-r--r--ChangeLog15
-rw-r--r--hieroglyph/Makefile.am2
-rw-r--r--hieroglyph/iarray.c222
-rw-r--r--hieroglyph/iarray.h51
-rw-r--r--hieroglyph/operator.c4
-rw-r--r--hieroglyph/scanner.c394
-rw-r--r--hieroglyph/version.h.in2
-rw-r--r--tests/ps/test-0base.ps13
-rw-r--r--tests/ps/test-cvi.ps19
-rw-r--r--tests/scanner.c115
10 files changed, 746 insertions, 91 deletions
diff --git a/ChangeLog b/ChangeLog
index 198bde9..8e5b7ec 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2006-10-09 Akira TAGOH <at@gclab.org>
+
+ * tests/ps/test-0base.ps: new testcase.
+
+ * hieroglyph/operator.c (_hg_operator_op_cvi): check the overflow.
+
+ * hieroglyph/scanner.c (_hg_scanner_get_object): split up the numeral
+ parser.
+ (_hg_scanner_parse_number): new function.
+
+ * hieroglyph/Makefile.am (libhieroglyph_private_SOURCES):
+ add iarray.[ch].
+
+ * hieroglyph/iarray.[ch]: new files.
+
2006-10-08 Akira TAGOH <at@gclab.org>
* hieroglyph/operator.c (_hg_operator_op_add): correct the overflow
diff --git a/hieroglyph/Makefile.am b/hieroglyph/Makefile.am
index 2b6879f..88433ed 100644
--- a/hieroglyph/Makefile.am
+++ b/hieroglyph/Makefile.am
@@ -74,6 +74,8 @@ lib_LTLIBRARIES = \
$(NULL)
libhieroglyph_private_SOURCES = \
+ iarray.c \
+ iarray.h \
ibtree.c \
ibtree.h \
ilist.c \
diff --git a/hieroglyph/iarray.c b/hieroglyph/iarray.c
new file mode 100644
index 0000000..2391746
--- /dev/null
+++ b/hieroglyph/iarray.c
@@ -0,0 +1,222 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * iarray.c
+ * Copyright (C) 2006 Akira TAGOH
+ *
+ * Authors:
+ * Akira TAGOH <at@gclab.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 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "iarray.h"
+#include "hgmem.h"
+
+#define HG_INT_ARRAY_ALLOC_SIZE 256
+
+struct _HieroGlyphIntArray {
+ HgObject object;
+ gint32 *arrays;
+ guint n_arrays;
+ gint32 allocated_arrays;
+ gboolean is_fixed_size;
+};
+
+
+static void _hg_int_array_real_set_flags(gpointer data,
+ guint flags);
+static void _hg_int_array_real_relocate (gpointer data,
+ HgMemRelocateInfo *info);
+
+
+static HgObjectVTable __hg_int_array_vtable = {
+ .free = NULL,
+ .set_flags = _hg_int_array_real_set_flags,
+ .relocate = _hg_int_array_real_relocate,
+ .dup = NULL,
+ .copy = NULL,
+ .to_string = NULL,
+};
+
+/*
+ * Private Functions
+ */
+static void
+_hg_int_array_real_set_flags(gpointer data,
+ guint flags)
+{
+ HgIntArray *iarray = data;
+ HgMemObject *obj;
+
+ if (iarray->arrays) {
+ hg_mem_get_object__inline(iarray->arrays, obj);
+ if (obj == NULL) {
+ g_warning("[BUG] Invalid object %p to be marked: IntArray", iarray->arrays);
+ } else {
+ if (!hg_mem_is_flags__inline(obj, flags))
+ hg_mem_add_flags__inline(obj, flags, TRUE);
+ }
+ }
+}
+
+static void
+_hg_int_array_real_relocate(gpointer data,
+ HgMemRelocateInfo *info)
+{
+ HgIntArray *iarray = data;
+
+ if ((gsize)iarray->arrays >= info->start &&
+ (gsize)iarray->arrays <= info->end) {
+ iarray->arrays = (gint32 *)((gsize)iarray->arrays + info->diff);
+ }
+}
+
+/*
+ * Public Functions
+ */
+HgIntArray *
+hg_int_array_new(HgMemPool *pool,
+ gint32 num)
+{
+ HgIntArray *retval;
+
+ g_return_val_if_fail (pool != NULL, NULL);
+
+ retval = hg_mem_alloc_with_flags(pool,
+ sizeof (HgIntArray),
+ HG_FL_HGOBJECT | HG_FL_COMPLEX);
+ if (retval == NULL)
+ return NULL;
+
+ HG_OBJECT_INIT_STATE (&retval->object);
+ HG_OBJECT_SET_STATE (&retval->object, hg_mem_pool_get_default_access_mode(pool));
+ hg_object_set_vtable(&retval->object, &__hg_int_array_vtable);
+
+ retval->n_arrays = 0;
+ if (num < 0) {
+ retval->allocated_arrays = HG_INT_ARRAY_ALLOC_SIZE;
+ retval->is_fixed_size = FALSE;
+ } else {
+ retval->allocated_arrays = num;
+ retval->is_fixed_size = TRUE;
+ }
+ /* initialize arrays with NULL first to avoid a crash
+ * when the alloc size is too big and GC is necessary to be ran.
+ */
+ retval->arrays = NULL;
+ retval->arrays = hg_mem_alloc(pool, sizeof (gint32) * retval->allocated_arrays);
+ if (retval->arrays == NULL)
+ return NULL;
+
+ return retval;
+}
+
+gboolean
+hg_int_array_append(HgIntArray *iarray,
+ gint32 i)
+{
+ HgMemObject *obj;
+
+ g_return_val_if_fail (iarray != NULL, FALSE);
+ g_return_val_if_fail (hg_object_is_readable((HgObject *)iarray), FALSE);
+ g_return_val_if_fail (hg_object_is_writable((HgObject *)iarray), FALSE);
+
+ hg_mem_get_object__inline(iarray, obj);
+ g_return_val_if_fail (obj != NULL, FALSE);
+
+ if (!iarray->is_fixed_size &&
+ iarray->n_arrays >= iarray->allocated_arrays) {
+ gpointer p = hg_mem_resize(iarray->arrays,
+ sizeof (gint32) * (iarray->allocated_arrays + HG_INT_ARRAY_ALLOC_SIZE));
+
+ if (p == NULL) {
+ g_warning("Failed to resize an int array.");
+ return FALSE;
+ } else {
+ iarray->arrays = p;
+ iarray->allocated_arrays += HG_INT_ARRAY_ALLOC_SIZE;
+ }
+ }
+ if (iarray->n_arrays < iarray->allocated_arrays) {
+ iarray->arrays[iarray->n_arrays++] = i;
+ } else {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+hg_int_array_replace(HgIntArray *iarray,
+ gint32 i,
+ guint index)
+{
+ HgMemObject *obj;
+
+ g_return_val_if_fail (iarray != NULL, FALSE);
+ g_return_val_if_fail (index < iarray->n_arrays, FALSE);
+ g_return_val_if_fail (hg_object_is_readable((HgObject *)iarray), FALSE);
+ g_return_val_if_fail (hg_object_is_writable((HgObject *)iarray), FALSE);
+
+ hg_mem_get_object__inline(iarray, obj);
+ g_return_val_if_fail (obj != NULL, FALSE);
+
+ iarray->arrays[index] = i;
+
+ return TRUE;
+}
+
+gboolean
+hg_int_array_remove(HgIntArray *iarray,
+ guint index)
+{
+ guint i;
+
+ g_return_val_if_fail (iarray != NULL, FALSE);
+ g_return_val_if_fail (index < iarray->n_arrays, FALSE);
+ g_return_val_if_fail (hg_object_is_readable((HgObject *)iarray), FALSE);
+ g_return_val_if_fail (hg_object_is_writable((HgObject *)iarray), FALSE);
+
+ for (i = index; i <= iarray->n_arrays - 1; i++) {
+ iarray->arrays[i] = iarray->arrays[i + 1];
+ }
+ iarray->n_arrays--;
+
+ return TRUE;
+}
+
+gint32
+hg_int_array_index(const HgIntArray *iarray,
+ guint index)
+{
+ g_return_val_if_fail (iarray != NULL, 0);
+ g_return_val_if_fail (index < iarray->n_arrays, 0);
+ g_return_val_if_fail (hg_object_is_readable((HgObject *)iarray), 0);
+
+ return iarray->arrays[index];
+}
+
+guint
+hg_int_array_length(HgIntArray *iarray)
+{
+ g_return_val_if_fail (iarray != NULL, 0);
+ g_return_val_if_fail (hg_object_is_readable((HgObject *)iarray), 0);
+
+ return iarray->n_arrays;
+}
diff --git a/hieroglyph/iarray.h b/hieroglyph/iarray.h
new file mode 100644
index 0000000..9cea689
--- /dev/null
+++ b/hieroglyph/iarray.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * iarray.h
+ * Copyright (C) 2006 Akira TAGOH
+ *
+ * Authors:
+ * Akira TAGOH <at@gclab.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 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __HG_INT_ARRAY_H__
+#define __HG_INT_ARRAY_H__
+
+#include <hieroglyph/hgtypes.h>
+
+G_BEGIN_DECLS
+
+typedef struct _HieroGlyphIntArray HgIntArray;
+
+#define hg_int_array_free(obj) hg_mem_free(obj)
+
+HgIntArray *hg_int_array_new (HgMemPool *pool,
+ gint32 num);
+gboolean hg_int_array_append (HgIntArray *array,
+ gint32 i);
+gboolean hg_int_array_replace(HgIntArray *array,
+ gint32 i,
+ guint index);
+gboolean hg_int_array_remove (HgIntArray *array,
+ guint index);
+gint32 hg_int_array_index (const HgIntArray *array,
+ guint index);
+guint hg_int_array_length (HgIntArray *array);
+
+
+G_END_DECLS
+
+#endif /* __HG_INT_ARRAY_H__ */
diff --git a/hieroglyph/operator.c b/hieroglyph/operator.c
index 307eab3..d3fb015 100644
--- a/hieroglyph/operator.c
+++ b/hieroglyph/operator.c
@@ -681,7 +681,7 @@ G_STMT_START
break;
}
dr = d1 + d2;
- if (integer && dr <= G_MAXINT32 && dr >= -G_MAXINT32) {
+ if (integer && dr <= G_MAXINT32 && dr >= G_MININT32) {
HG_VALUE_MAKE_INTEGER (pool, n1, (gint32)dr);
} else {
HG_VALUE_MAKE_REAL (pool, n1, dr);
@@ -2016,7 +2016,7 @@ G_STMT_START
} else if (HG_IS_VALUE_REAL (node)) {
gdouble d = HG_VALUE_GET_REAL (node);
- if (d >= G_MAXINT) {
+ if (d > G_MAXINT32 || d < G_MININT32) {
_hg_operator_set_error(vm, op, VM_e_rangecheck);
break;
}
diff --git a/hieroglyph/scanner.c b/hieroglyph/scanner.c
index d5e0021..fe010d8 100644
--- a/hieroglyph/scanner.c
+++ b/hieroglyph/scanner.c
@@ -25,6 +25,7 @@
#include <config.h>
#endif
+#include <ctype.h>
#include "scanner.h"
#include "hgmem.h"
#include "hgarray.h"
@@ -32,10 +33,21 @@
#include "hgfile.h"
#include "hgstring.h"
#include "hgvaluenode.h"
+#include "iarray.h"
#include "operator.h"
#include "vm.h"
+static gboolean _hg_scanner_parse_number(HgVM *vm,
+ HgFileObject *file,
+ gint token_type,
+ gint radix,
+ gint sign,
+ gboolean is_integer,
+ HgString *string,
+ HgValueNode **node,
+ gboolean *error);
+
#define _hg_scanner_is_sign(__hg_scanner_c) \
((__hg_scanner_c) == '+' || \
(__hg_scanner_c) == '-')
@@ -68,7 +80,7 @@ typedef enum {
enum {
HG_SCAN_TOKEN_LITERAL = 1,
HG_SCAN_TOKEN_EVAL_NAME,
- HG_SCAN_TOKEN_REAL,
+ HG_SCAN_TOKEN_NUMERIC,
HG_SCAN_TOKEN_STRING,
HG_SCAN_TOKEN_NAME,
HG_SCAN_TOKEN_MARK,
@@ -221,13 +233,10 @@ _hg_scanner_get_object(HgVM *vm,
HgDict *systemdict;
HgValueNode *node, *retval = NULL;
guchar c;
- gboolean need_loop = TRUE, sign = FALSE, negate = FALSE, numeral = FALSE;
- gboolean power = FALSE, psign = FALSE, pnegate = FALSE;
- gint token_type = 0, string_depth = 0;
+ gboolean need_loop = TRUE, maybe_real = FALSE, error = FALSE;
+ gint token_type = 0, string_depth = 0, sign = 0;
HgString *string = NULL;
HgArray *array = NULL;
- gdouble d = 0.0L, real = 0.0L, de;
- gint32 radix = 10, i = 0, e = 0;
pool = hg_vm_get_current_pool(vm);
ostack = hg_vm_get_ostack(vm);
@@ -444,48 +453,23 @@ _hg_scanner_get_object(HgVM *vm,
return NULL;
}
if (_hg_scanner_is_sign(c)) {
- numeral = TRUE;
- sign = TRUE;
+ sign = 1;
if (c == '-')
- negate = TRUE;
+ sign = -sign;
} else if (c == '.') {
- numeral = TRUE;
- real = 10.0L;
- d = i;
+ maybe_real = TRUE;
}
token_type = HG_SCAN_TOKEN_NAME;
- break;
- case HG_SCAN_TOKEN_NAME:
- if (!power && HG_VALUE_REAL_SIMILAR (real, 0) && c == '.') {
- real = 10.0L;
- d = i;
- } else if (!power && (c == 'e' || c == 'E')) {
- power = TRUE;
- if (HG_VALUE_REAL_SIMILAR (real, 0)) {
- real = 10.0L;
- d = i;
- }
- if (!hg_string_append_c(string, c)) {
- _hg_scanner_set_error(vm,
- __hg_operator_list[HG_op_token],
- VM_e_VMerror);
+ if (_hg_scanner_parse_number(vm, file, token_type,
+ 10, sign, !maybe_real,
+ string, &retval, &error)) {
+ if (error)
return NULL;
- }
- c = hg_file_object_getc(file);
- if (_hg_scanner_is_sign(c)) {
- psign = TRUE;
- if (c == '-') {
- pnegate = TRUE;
- }
- } else {
- if (c < '0' || c > '9')
- numeral = FALSE;
- hg_file_object_ungetc(file, c);
- break;
- }
- } else {
- numeral = FALSE;
+ token_type = HG_SCAN_TOKEN_NUMERIC;
+ need_loop = FALSE;
}
+ break;
+ case HG_SCAN_TOKEN_NAME:
case HG_SCAN_TOKEN_LITERAL:
case HG_SCAN_TOKEN_EVAL_NAME:
case HG_SCAN_TOKEN_STRING:
@@ -497,6 +481,7 @@ _hg_scanner_get_object(HgVM *vm,
}
break;
default:
+ g_warning("[BUG] it may be unlikely to appear HG_SCAN_C_NAME in token type %d\n", token_type);
break;
}
break;
@@ -517,32 +502,21 @@ _hg_scanner_get_object(HgVM *vm,
case 0:
/* it might be a numeral, but possibly name. */
string = hg_string_new(pool, -1);
- if (!hg_string_append_c(string, c)) {
- _hg_scanner_set_error(vm,
- __hg_operator_list[HG_op_token],
- VM_e_VMerror);
- return NULL;
- }
+ hg_file_object_ungetc(file, c);
token_type = HG_SCAN_TOKEN_NAME;
- numeral = TRUE;
- i = c - '0';
+ if (_hg_scanner_parse_number(vm, file, token_type,
+ 10, sign, !maybe_real,
+ string, &retval, &error)) {
+ if (error)
+ return NULL;
+ token_type = HG_SCAN_TOKEN_NUMERIC;
+ need_loop = FALSE;
+ }
break;
case HG_SCAN_TOKEN_LITERAL:
case HG_SCAN_TOKEN_EVAL_NAME:
case HG_SCAN_TOKEN_STRING:
case HG_SCAN_TOKEN_NAME:
- if (numeral) {
- if (power) {
- e *= 10;
- e += c - '0';
- } else if (!HG_VALUE_REAL_SIMILAR (real, 0)) {
- d += (c - '0') / real;
- real *= 10.0L;
- } else {
- i *= radix;
- i += c - '0';
- }
- }
if (!hg_string_append_c(string, c)) {
_hg_scanner_set_error(vm,
__hg_operator_list[HG_op_token],
@@ -567,6 +541,11 @@ _hg_scanner_get_object(HgVM *vm,
hg_object_inexecutable((HgObject *)retval);
hg_mem_free(string);
break;
+ case HG_SCAN_TOKEN_NAME:
+ retval = hg_vm_get_name_node(vm, hg_string_get_string(string));
+ hg_object_executable((HgObject *)retval);
+ hg_mem_free(string);
+ break;
case HG_SCAN_TOKEN_EVAL_NAME:
node = hg_vm_get_name_node(vm, hg_string_get_string(string));
retval = hg_vm_lookup(vm, node);
@@ -577,27 +556,7 @@ _hg_scanner_get_object(HgVM *vm,
}
hg_mem_free(string);
break;
- case HG_SCAN_TOKEN_NAME:
- if (numeral) {
- if (pnegate)
- e = -e;
- if (!HG_VALUE_REAL_SIMILAR (real, 0)) {
- if (power) {
- de = exp10((double)e);
- d *= de;
- }
- if (negate)
- d = -d;
- HG_VALUE_MAKE_REAL (pool, retval, d);
- } else {
- if (negate)
- i = -i;
- HG_VALUE_MAKE_INTEGER (pool, retval, i);
- }
- } else {
- retval = hg_vm_get_name_node(vm, hg_string_get_string(string));
- hg_object_executable((HgObject *)retval);
- }
+ case HG_SCAN_TOKEN_NUMERIC:
hg_mem_free(string);
break;
case HG_SCAN_TOKEN_MARK:
@@ -641,6 +600,275 @@ _hg_scanner_get_object(HgVM *vm,
return retval;
}
+static gboolean
+_hg_scanner_parse_number(HgVM *vm,
+ HgFileObject *file,
+ gint token_type,
+ gint radix,
+ gint sign,
+ gboolean is_integer,
+ HgString *string,
+ HgValueNode **node,
+ gboolean *error)
+{
+ HgMemPool *pool = hg_vm_get_current_pool(vm);
+ guchar c;
+ gboolean need_loop = TRUE, is_valid = FALSE, is_power = FALSE;
+ gboolean has_radix = (radix == 10 ? FALSE : TRUE);
+ HgIntArray *intarray, *floatarray = NULL;
+ gint32 i = 0, power = 0, di = 0;
+ gint power_sign = 0;
+ static const gchar *const radix_index = "0123456789abcdefghijklmnopqrstuvwxyz";
+
+ intarray = hg_int_array_new(pool, -1);
+ if (!is_integer) {
+ /* value may be less than 1 */
+ hg_int_array_append(intarray, 0);
+ floatarray = hg_int_array_new(pool, -1);
+ }
+ while (need_loop) {
+ c = hg_file_object_getc(file);
+ switch (__hg_scanner_token[c]) {
+ case HG_SCAN_C_CONTROL:
+ hg_file_object_ungetc(file, c);
+ case HG_SCAN_C_NULL:
+ case HG_SCAN_C_SPACE:
+ need_loop = FALSE;
+ break;
+ case HG_SCAN_C_NAME:
+ is_valid = TRUE;
+ if (c != '\\') {
+ switch (token_type) {
+ case HG_SCAN_TOKEN_NAME:
+ if (c == '.') {
+ if (!is_integer || is_power || has_radix) {
+ is_valid = FALSE;
+ break;
+ }
+ di = i;
+ floatarray = hg_int_array_new(pool, -1);
+ is_integer = FALSE;
+ i = 0;
+ } else if ((c == 'e' || c == 'E') && !has_radix) {
+ if (is_power) {
+ is_valid = FALSE;
+ break;
+ }
+ is_power = TRUE;
+ if (!hg_string_append_c(string, c)) {
+ _hg_scanner_set_error(vm,
+ __hg_operator_list[HG_op_token],
+ VM_e_VMerror);
+ *error = TRUE;
+ return FALSE;
+ }
+ c = hg_file_object_getc(file);
+ if (_hg_scanner_is_sign(c)) {
+ power_sign = 1;
+ if (c == '-')
+ power_sign = -power_sign;
+ } else if (c < '0' || c > '9') {
+ is_valid = FALSE;
+ break;
+ } else {
+ hg_file_object_ungetc(file, c);
+ }
+ } else if (c == '#') {
+ if (is_power || !is_integer || has_radix ||
+ hg_int_array_length(intarray) > 0 ||
+ i > 36) {
+ is_valid = FALSE;
+ break;
+ }
+ has_radix = TRUE;
+ radix = i;
+ i = 0;
+ } else if ((c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z')) {
+ char *p;
+ gint index;
+
+ if (is_power || !is_integer) {
+ is_valid = FALSE;
+ break;
+ }
+ p = strchr(radix_index, tolower(c));
+ index = p - radix_index;
+ if (index >= radix) {
+ is_valid = FALSE;
+ break;
+ }
+ if ((i > 0 && (i * radix) < 0) ||
+ (i < 0 && (i * radix) > 0)) {
+ /* the overflow may happens but we can't
+ * fallback to real.
+ */
+ _hg_scanner_set_error(vm,
+ __hg_operator_list[HG_op_token],
+ VM_e_limitcheck);
+ *error = TRUE;
+ return FALSE;
+ }
+ i *= radix;
+ i += index;
+ } else {
+ is_valid = FALSE;
+ break;
+ }
+
+ if (!hg_string_append_c(string, c)) {
+ _hg_scanner_set_error(vm,
+ __hg_operator_list[HG_op_token],
+ VM_e_VMerror);
+ *error = TRUE;
+ return FALSE;
+ }
+ break;
+ case HG_SCAN_TOKEN_LITERAL:
+ case HG_SCAN_TOKEN_EVAL_NAME:
+ case HG_SCAN_TOKEN_STRING:
+ /* it may be unlikely */
+ is_valid = FALSE;
+ break;
+ default:
+ g_warning("[BUG] it may be unlikely to appear HG_SCAN_C_NAME in token type %d\n", token_type);
+ is_valid = FALSE;
+ break;
+ }
+ if (is_valid)
+ break;
+ }
+ goto non_numeral_handler;
+ case HG_SCAN_C_NUMERAL:
+ is_valid = TRUE;
+ switch (token_type) {
+ case HG_SCAN_TOKEN_LITERAL:
+ case HG_SCAN_TOKEN_EVAL_NAME:
+ case HG_SCAN_TOKEN_STRING:
+ /* it may be unlikely */
+ goto non_numeral_handler;
+ case HG_SCAN_TOKEN_NAME:
+ if (is_power) {
+ power *= 10;
+ power += c - '0';
+ } else {
+ if (has_radix &&
+ ((i > 0 && (i * radix) < 0) ||
+ (i < 0 && (i * radix) > 0))) {
+ /* the overflow may happens but we can't
+ * fallback to real.
+ */
+ _hg_scanner_set_error(vm,
+ __hg_operator_list[HG_op_token],
+ VM_e_limitcheck);
+ *error = TRUE;
+ return FALSE;
+ } else if (!has_radix &&
+ i > 100000000) {
+ /* it could has 10 digits in 32bit integer though,
+ * it may be complicated to convert it to real,
+ * so that the overflow will happens within 10 digits.
+ */
+ if (floatarray) {
+ hg_int_array_append(floatarray, i);
+ i = 0;
+ } else {
+ hg_int_array_append(intarray, i);
+ i = 0;
+ }
+ }
+ i *= radix;
+ i += c - '0';
+ }
+ if (!hg_string_append_c(string, c)) {
+ _hg_scanner_set_error(vm,
+ __hg_operator_list[HG_op_token],
+ VM_e_VMerror);
+ *error = TRUE;
+ return FALSE;
+ }
+ break;
+ default:
+ g_warning("[BUG] it may be unlikely to appear HG_SCAN_C_NUMERAL in token type %d\n", token_type);
+ goto non_numeral_handler;
+ }
+ break;
+ case HG_SCAN_C_BINARY:
+ default:
+ non_numeral_handler:
+ /* postpone dealing with this */
+ hg_file_object_ungetc(file, c);
+ need_loop = FALSE;
+ is_valid = FALSE;
+ break;
+ }
+ }
+ if (is_valid) {
+ if (hg_int_array_length(intarray) == 0 && floatarray == NULL && !is_power) {
+ /* integer */
+ if (sign < 0)
+ i = -i;
+ HG_VALUE_MAKE_INTEGER (pool, *node, i);
+ } else {
+ guint j, length, digits = (guint)log10(i) + 1, intdigits = 0;
+ gdouble d = 0.0L, dd = 0.0L;
+
+ if (di > 0)
+ intdigits = (guint)log10(di) + 1;
+ if (has_radix) {
+ /* this is unlikely */
+ g_warning("[BUG] numeric with radix is going to be the real.");
+ return FALSE;
+ }
+ if (floatarray) {
+ length = hg_int_array_length(floatarray);
+ for (j = 0; j < length; j++) {
+ dd += ((gdouble)hg_int_array_index(floatarray, j) * exp10((gdouble)-((j + 1) * 9)));
+ }
+ dd += (i * exp10(-(gdouble)digits));
+ digits = 0;
+ i = 0;
+ }
+ length = hg_int_array_length(intarray);
+ for (j = 0; j < length; j++) {
+ d += ((gdouble)hg_int_array_index(intarray, j) * exp10((gdouble)((length - j - 1) * 9 + digits + intdigits)));
+ if (isinf(d) != 0 || isnan(d) != 0) {
+ _hg_scanner_set_error(vm,
+ __hg_operator_list[HG_op_token],
+ VM_e_limitcheck);
+ *error = TRUE;
+ return FALSE;
+ }
+ }
+ if (di != 0) {
+ d += (gdouble)di;
+ } else {
+ d += (gdouble)i;
+ }
+ d += dd;
+ if (is_power) {
+ if (power_sign < 0)
+ power = -power;
+ dd = exp10((gdouble)power);
+ d *= dd;
+ }
+ if (sign < 0)
+ d = -d;
+ if (is_integer && d <= G_MAXINT32 && d >= G_MININT32)
+ HG_VALUE_MAKE_INTEGER (pool, *node, (gint32)d);
+ else
+ HG_VALUE_MAKE_REAL (pool, *node, d);
+ }
+ }
+
+ if (intarray)
+ hg_int_array_free(intarray);
+ if (floatarray)
+ hg_int_array_free(floatarray);
+
+ return is_valid;
+}
+
/*
* Public Functions
*/
diff --git a/hieroglyph/version.h.in b/hieroglyph/version.h.in
index ed4e140..541a4f1 100644
--- a/hieroglyph/version.h.in
+++ b/hieroglyph/version.h.in
@@ -29,7 +29,7 @@
G_BEGIN_DECLS
#define HIEROGLYPH_VERSION "@VERSION@"
-#define HIEROGLYPH_UUID "6dfd2985-0300-4b4c-8bd6-92bbc1de1141"
+#define HIEROGLYPH_UUID "620a4e97-323b-4ee9-9bf5-b683dc4cf41a"
const char *__hg_rcsid G_GNUC_UNUSED = "$Rev$";
diff --git a/tests/ps/test-0base.ps b/tests/ps/test-0base.ps
new file mode 100644
index 0000000..33960c1
--- /dev/null
+++ b/tests/ps/test-0base.ps
@@ -0,0 +1,13 @@
+initunittest
+
+[true] null true initunittestdict {true} unittest
+[false] null true initunittestdict {false} unittest
+[/foo] null true initunittestdict {/foo} unittest
+[0] null true initunittestdict {0} unittest
+[-1] null true initunittestdict {-1} unittest
+[2147483647] null true initunittestdict {2147483647} unittest
+{-2147483648} null true initunittestdict {-2147483648} unittest
+[2147483648.0] null true initunittestdict {2147483648} unittest
+{-2147483649.0} null true initunittestdict {-2147483649} unittest
+
+unittestresult
diff --git a/tests/ps/test-cvi.ps b/tests/ps/test-cvi.ps
new file mode 100644
index 0000000..6e3b5b3
--- /dev/null
+++ b/tests/ps/test-cvi.ps
@@ -0,0 +1,19 @@
+initunittest
+
+true /cvi [[/integertype /realtype]] typecheck
+false /cvi [[/booleantype /nametype /arraytype /dicttype /nulltype /operatortype /marktype /filetype /savetype /proctype]] typecheck
+
+[] /stackunderflow true initunittestdict {cvi} unittest
+[(foo) noaccess] /invalidaccess true initunittestdict {(foo) noaccess cvi} unittest
+[2147483648.0] /rangecheck true initunittestdict {2147483648.0 cvi} unittest
+[-2147483649.0] /rangecheck true initunittestdict {-2147483649.0 cvi} unittest
+% XXX: what causes /undefinedresult?
+[(foo)] /typecheck true initunittestdict {(foo) cvi} unittest
+[()] /syntaxerror true initunittestdict {() cvi} unittest
+[33] null true initunittestdict {(3.3E1) cvi} unittest
+[-47] null true initunittestdict {-47.8 cvi} unittest
+[520] null true initunittestdict {520.9 cvi} unittest
+[2147483647] null true initunittestdict {2147483647.0 cvi} unittest
+[-2147483648] null true initunittestdict {-2147483648.0 cvi} unittest
+
+unittestresult
diff --git a/tests/scanner.c b/tests/scanner.c
index 73596d0..3648911 100644
--- a/tests/scanner.c
+++ b/tests/scanner.c
@@ -1,3 +1,4 @@
+#include <stdlib.h>
#include <hieroglyph/hgmem.h>
#include <hieroglyph/hgfile.h>
#include <hieroglyph/hgstack.h>
@@ -47,17 +48,72 @@ print_stack(HgStack *stack)
}
}
+gboolean
+test(HgVM *vm,
+ HgMemPool *pool,
+ const gchar *expression,
+ HgValueNode *expected_node)
+{
+ HgFileObject *file = hg_file_object_new(pool, HG_FILE_TYPE_BUFFER,
+ HG_FILE_MODE_READ, "*buffer*",
+ expression, -1);
+ HgValueNode *node;
+ HgString *expected_string, *actual_string;
+ gboolean retval = TRUE;
+
+ expected_string = hg_object_to_string((HgObject *)expected_node);
+ node = hg_scanner_get_object(vm, file);
+ if (node != NULL) {
+ if (expected_node != NULL &&
+ !hg_value_node_compare_content(expected_node, node)) {
+ actual_string = hg_object_to_string((HgObject *)node);
+ g_print("Expression: %s, Expected result is %s [%s] but Actual result was %s [%s]\n",
+ expression, hg_string_get_string(expected_string),
+ hg_value_node_get_type_name(HG_VALUE_GET_VALUE_TYPE (expected_node)),
+ hg_string_get_string(actual_string),
+ hg_value_node_get_type_name(HG_VALUE_GET_VALUE_TYPE (node)));
+ retval = FALSE;
+ } else if (expected_node == NULL) {
+ actual_string = hg_object_to_string((HgObject *)node);
+ g_print("Expression: %s, Expected result is NULL but Actual result was %s [%s]\n",
+ expression,
+ hg_string_get_string(actual_string),
+ hg_value_node_get_type_name(HG_VALUE_GET_VALUE_TYPE (node)));
+ retval = FALSE;
+ }
+ } else {
+ if (expected_node != NULL) {
+ g_print("Expression: %s, Expected result is %s [%s] but failed to parse it.\n",
+ expression, hg_string_get_string(expected_string),
+ hg_value_node_get_type_name(HG_VALUE_GET_VALUE_TYPE (expected_node)));
+ retval = FALSE;
+ }
+ }
+ if (hg_object_is_executable((HgObject *)expected_node) &&
+ !hg_object_is_executable((HgObject *)node)) {
+ g_print("Expression: %s, Expected an executable, but it was not.\n",
+ expression);
+ retval = FALSE;
+ } else if (!hg_object_is_executable((HgObject *)expected_node) &&
+ hg_object_is_executable((HgObject *)node)) {
+ g_print("Expression: %s, Expected a non-executable, but it was not.\n",
+ expression);
+ retval = FALSE;
+ }
+
+ return retval;
+}
+
int
main(void)
{
HG_MEM_INIT;
HgVM *vm;
- HgStack *ostack, *estack;
-// gchar *tokens = "true false moveto /foo 10050 10a 10.5 -1 .5 -1e10 10.0E5 1E 5.2e-2 36#Z 1#0 %foobar\nfoo(test)((test test) test)(foo\nbar)";
- HgValueNode *node;
- HgFileObject *file;
HgMemPool *pool;
+ HgFileObject *file;
+ HgValueNode *node;
+ HgStack *ostack;
hg_vm_init();
@@ -65,7 +121,56 @@ main(void)
hg_vm_startjob(vm, NULL, FALSE);
pool = hg_vm_get_current_pool(vm);
ostack = hg_vm_get_ostack(vm);
- estack = hg_vm_get_estack(vm);
+
+#define do_test_null(_vm_, _pool_, _exp_) \
+ G_STMT_START { \
+ if (!test((_vm_), (_pool_), (_exp_), NULL)) { \
+ exit(1); \
+ } \
+ } G_STMT_END
+#define do_test(_vm_, _pool_, _exp_, _type_, _val_) \
+ G_STMT_START { \
+ HgValueNode *__node__; \
+ HG_VALUE_MAKE_ ## _type_ ((_pool_), __node__, (_val_)); \
+ if (!test((_vm_), (_pool_), (_exp_), __node__)) { \
+ exit(1); \
+ } \
+ } G_STMT_END
+#define do_test_name(_vm_, _pool_, _exp_, _val_, _exec_) \
+ G_STMT_START { \
+ HgValueNode *__node__; \
+ HG_VALUE_MAKE_NAME_STATIC ((_pool_), __node__, (_val_)); \
+ if ((_exec_)) \
+ hg_object_executable((HgObject *)__node__); \
+ if (!test((_vm_), (_pool_), (_exp_), __node__)) { \
+ exit(1); \
+ } \
+ } G_STMT_END
+
+ do_test_name(vm, pool, "/foo", "foo", FALSE);
+ do_test_name(vm, pool, "true", "true", TRUE);
+ do_test_name(vm, pool, "false", "false", TRUE);
+ do_test(vm, pool, "//true", BOOLEAN, TRUE);
+ do_test(vm, pool, "//false", BOOLEAN, FALSE);
+ do_test_name(vm, pool, "null", "null", TRUE);
+ do_test(vm, pool, "//null", NULL, NULL);
+ do_test(vm, pool, "10050", INTEGER, 10050);
+ do_test(vm, pool, "2147483647", INTEGER, 2147483647);
+ do_test(vm, pool, "-2147483648", INTEGER, 0x80000000);
+ do_test_name(vm, pool, "10a", "10a", TRUE);
+ do_test(vm, pool, "10.5", REAL, 10.5);
+ do_test(vm, pool, "-1", INTEGER, -1);
+ do_test(vm, pool, ".5", REAL, 0.5);
+ do_test(vm, pool, "-1e10", REAL, -1e+10);
+ do_test(vm, pool, "10.0E5", REAL, 10.0e5);
+ do_test_name(vm, pool, "1E", "1E", TRUE);
+ do_test(vm, pool, "5.2e-2", REAL, 5.2e-2);
+ do_test(vm, pool, "36#Z", INTEGER, 35);
+ do_test(vm, pool, "1#0", INTEGER, 0);
+ do_test_name(vm, pool, "=", "=", TRUE);
+ do_test_null(vm, pool, " ");
+ do_test_null(vm, pool, "\n");
+
file = hg_file_object_new(pool, HG_FILE_TYPE_BUFFER, HG_FILE_MODE_READ, "*buffer*", "/foo true false null [moveto (test(test test) test) 10050 10a 10.5 -1 .5 -1e10 10.0E5 1E 5.2e-2 36#Z 1#0 //true 10e2.5 1.0ee10 1..5", -1);
while (!hg_file_object_is_eof(file)) {
node = hg_scanner_get_object(vm, file);