diff options
author | Akira TAGOH <akira@tagoh.org> | 2006-10-08 19:41:41 +0000 |
---|---|---|
committer | Akira TAGOH <akira@tagoh.org> | 2006-10-08 19:41:41 +0000 |
commit | 88ca5b5f6fd94fb08ee0d02e28e5b1e310f244f3 (patch) | |
tree | b1f02f66de3bbfabe60f956af362632b34632d4d | |
parent | 9bde539f51912d4bc384a1e30c2a5d4ee6bbd9bf (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-- | ChangeLog | 15 | ||||
-rw-r--r-- | hieroglyph/Makefile.am | 2 | ||||
-rw-r--r-- | hieroglyph/iarray.c | 222 | ||||
-rw-r--r-- | hieroglyph/iarray.h | 51 | ||||
-rw-r--r-- | hieroglyph/operator.c | 4 | ||||
-rw-r--r-- | hieroglyph/scanner.c | 394 | ||||
-rw-r--r-- | hieroglyph/version.h.in | 2 | ||||
-rw-r--r-- | tests/ps/test-0base.ps | 13 | ||||
-rw-r--r-- | tests/ps/test-cvi.ps | 19 | ||||
-rw-r--r-- | tests/scanner.c | 115 |
10 files changed, 746 insertions, 91 deletions
@@ -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); |