mirror of
https://github.com/ldmud/ldmud
synced 2026-08-12 14:26:05 -04:00
Implement LPC Type objects
Add a new type 'lpctype' to contain a type object, describing a compile-time type, together with a decltype() operator and to_lpctype() and check_type() efuns.
This commit is contained in:
parent
73ed64c46b
commit
fb691fa2ea
40 changed files with 1487 additions and 183 deletions
31
doc/LPC/decltype
Normal file
31
doc/LPC/decltype
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
NAME
|
||||
decltype
|
||||
|
||||
SYNTAX
|
||||
decltype(<expr>)
|
||||
|
||||
DESCRIPTION
|
||||
The expression will compiled just to determine the resulting type.
|
||||
The expression itself will not be executed. The result of this
|
||||
operator is the lpctype value representing the expression result.
|
||||
|
||||
NOTE
|
||||
The result of this operator depends on a lot of factors, for example
|
||||
if any type information is preserved for any inherited programs that
|
||||
are referenced in the expression. But it also depends on the type
|
||||
inference capabilities of the LPC compiler. So future versions of
|
||||
LDMud might have different results on the same expression.
|
||||
|
||||
|
||||
EXAMPLES
|
||||
int var;
|
||||
decltype(var) /* result: [int] */
|
||||
|
||||
string fun();
|
||||
decltype(fun()) /* result: [string], fun() will not be called. */
|
||||
|
||||
HISTORY
|
||||
Introduced in LDMud 3.6.7.
|
||||
|
||||
SEE ALSO
|
||||
lpctypes(LPC)
|
||||
48
doc/LPC/lpctypes
Normal file
48
doc/LPC/lpctypes
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
CONCEPT
|
||||
lpctypes
|
||||
|
||||
INTRODUCTION
|
||||
An lpctype variable stores an LPC type like int or string*.
|
||||
They are mainly used in the check_types() efun, but also for
|
||||
introspection with functionlist() and variable_list().
|
||||
|
||||
DEFINITION
|
||||
An lpctype literal can be created either by writing the type
|
||||
in brackets or using the decltype(LPC) operator:
|
||||
|
||||
lpctype t1 = [int];
|
||||
lpctype t2 = decltype(t1); /* t2 will be [lpctype] */
|
||||
|
||||
The type in brackets can be any type declaration, similar to
|
||||
the type declarations of variable or function result.
|
||||
|
||||
OPERATIONS
|
||||
lpctypes support the following operations:
|
||||
|
||||
t1 | t2
|
||||
|
||||
Create a union type of both types.
|
||||
|
||||
t1 & t2
|
||||
|
||||
Create the intersection of both types. If the intersection
|
||||
is empty [void] will be returned.
|
||||
|
||||
t1 in t2
|
||||
|
||||
Yields 1 if t1 is a subset of t2.
|
||||
|
||||
EXAMPLE
|
||||
void process(mixed value)
|
||||
{
|
||||
if (check_type(value, [int|float]))
|
||||
process_number(value);
|
||||
else
|
||||
process_anything(value);
|
||||
}
|
||||
|
||||
HISTORY
|
||||
The type was introduced in LDMud 3.6.7.
|
||||
|
||||
SEE ALSO
|
||||
check_type(E), decltype(LPC)
|
||||
|
|
@ -148,6 +148,8 @@ DESCRIPTION
|
|||
|
||||
o struct A collection of values. See structs(LPC).
|
||||
|
||||
o lpctype A type itself. See lpctypes(LPC).
|
||||
|
||||
o union A range of types, either of which the variable
|
||||
can contain at runtime. See unions(LPC).
|
||||
|
||||
|
|
@ -168,5 +170,6 @@ HISTORY
|
|||
|
||||
SEE ALSO
|
||||
alists(LPC), arrays(LPC), mappings(LPC), closures(LPC), coroutines(LPC),
|
||||
objects(LPC), structs(LPC), unions(LPC), typeof(E), get_type_info(E),
|
||||
inheritance(LPC), pragma(LPC), modifiers(LPC), escape(LPC)
|
||||
objects(LPC), structs(LPC), unions(LPC), lpctypes(E), typeof(E),
|
||||
get_type_info(E), inheritance(LPC), pragma(LPC), modifiers(LPC),
|
||||
escape(LPC)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ BESCHREIBUNG
|
|||
RETURN_FUNCTION_NAME liefert den Funktionsnamen
|
||||
RETURN_FUNCTION_FLAGS liefert die Flags der Funktion
|
||||
RETURN_FUNCTION_TYPE liefert den Rueckgabetyp der Funktion
|
||||
als Zahl.
|
||||
RETURN_FUNCTION_LPCTYPE liefert den Rueckgabetyp der Funktion
|
||||
als lpctype.
|
||||
RETURN_FUNCTION_NUMARG liefert die Anzahl moeglicher
|
||||
Argumente.
|
||||
|
||||
|
|
@ -51,6 +54,9 @@ BESCHREIBUNG
|
|||
TYPE_MOD_NOMASK die Funktion ist nomask deklariert
|
||||
TYPE_MOD_PUBLIC die Funktion ist public deklariert
|
||||
|
||||
GESCHICHTE
|
||||
LDMud 3.6.7 fuehrte RETURN_FUNCTION_LPCTYPE ein.
|
||||
|
||||
SIEHE AUCH
|
||||
inherit_list(E), function_exists(E), variable_list(E),
|
||||
call_resolved(E)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ BESCHREIBUNG
|
|||
Auswahl der gesammelten Information:
|
||||
RETURN_FUNCTION_NAME liefert den Namen der Variablen
|
||||
RETURN_FUNCTION_FLAGS liefert die Flags der Variablen (s. unten)
|
||||
RETURN_FUNCTION_TYPE liefert den Rueckgabetyp
|
||||
RETURN_FUNCTION_TYPE liefert den Variablentyp als Zahl.
|
||||
RETURN_FUNCTION_LPCTYPE liefert den Variablentyp als lpctype.
|
||||
RETURN_VARIABLE_VALUE liefert den Wert der Variablen
|
||||
|
||||
Auswahl der Variablen, die ausgewertet werden:
|
||||
|
|
@ -54,6 +55,7 @@ BESCHREIBUNG
|
|||
|
||||
GESCHICHTE
|
||||
Eingefuehrt in LDMud 3.2.10.
|
||||
LDMud 3.6.7 fuehrte RETURN_FUNCTION_LPCTYPE ein.
|
||||
|
||||
SIEHE AUCH
|
||||
inherit_list(E), functionlist(E), variable_exists(E)
|
||||
|
|
|
|||
16
doc/efun/check_type
Normal file
16
doc/efun/check_type
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
SYNOPSIS
|
||||
int check_type(mixed arg, lpctype type)
|
||||
|
||||
DESCRIPTION
|
||||
Returns 1 if the first argument <arg> fulfills the type <type>,
|
||||
0 otherwise.
|
||||
|
||||
This check is similar to runtime type checks. The target type
|
||||
doesn't need to match exactly, but a variable of that type should
|
||||
be able to hold the argument.
|
||||
|
||||
HISTORY
|
||||
Introduced in LDMud 3.6.7
|
||||
|
||||
SEE ALSO
|
||||
get_type_info(E), lpctypes(LPC)
|
||||
|
|
@ -25,7 +25,8 @@ DESCRIPTION
|
|||
Control of returned information:
|
||||
RETURN_FUNCTION_NAME include the function name
|
||||
RETURN_FUNCTION_FLAGS include the function flags
|
||||
RETURN_FUNCTION_TYPE include the return type
|
||||
RETURN_FUNCTION_TYPE include the return type as an integer
|
||||
RETURN_FUNCTION_LPCTYPE include the return type as lpctype value
|
||||
RETURN_FUNCTION_NUMARG include the number of arguments.
|
||||
|
||||
The name RETURN_FUNCTION_ARGTYPE is defined but not implemented.
|
||||
|
|
@ -46,6 +47,8 @@ DESCRIPTION
|
|||
TYPE_MOD_NO_MASK function is nomask
|
||||
TYPE_MOD_PUBLIC function is public
|
||||
|
||||
HISTORY
|
||||
LDMud 3.6.7 introduced RETURN_FUNCTION_LPCTYPE.
|
||||
|
||||
SEE ALSO
|
||||
inherit_list(E), function_exists(E), variable_list(E),
|
||||
|
|
|
|||
|
|
@ -59,4 +59,4 @@ HISTORY
|
|||
LDMud 3.3.708 added flag setting '4' for lfun/context closures.
|
||||
|
||||
SEE ALSO
|
||||
debug_info(E), typeof(E), to_object(E)
|
||||
debug_info(E), typeof(E), to_object(E), check_type(E)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ SYNOPSIS
|
|||
mixed * to_array(quotedarray)
|
||||
mixed * to_array(mixed *)
|
||||
mixed * to_array(struct)
|
||||
mixed * to_array(lpctype)
|
||||
|
||||
(int*)<value>
|
||||
|
||||
|
|
@ -21,6 +22,9 @@ DESCRIPTION
|
|||
|
||||
Structs are converted into a normal array.
|
||||
|
||||
Union lpc types are split into their union member types
|
||||
(in no particular order).
|
||||
|
||||
BUGS
|
||||
The cast notation only works if the precise type of <value>
|
||||
is known at compile-time. This will not be fixed - use the
|
||||
|
|
|
|||
12
doc/efun/to_lpctype
Normal file
12
doc/efun/to_lpctype
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
SYNOPSIS
|
||||
lpctype to_lpctype(string type)
|
||||
|
||||
DESCRIPTION
|
||||
Interprets the given string as an lpc type. This efun basically
|
||||
returns the same type as the [<type>] literal.
|
||||
|
||||
HISTORY
|
||||
Introduced in LDMud 3.6.7.
|
||||
|
||||
SEE ALSO
|
||||
to_string(E), lpctypes(LPC)
|
||||
|
|
@ -27,7 +27,8 @@ DESCRIPTION
|
|||
Control of returned information:
|
||||
RETURN_FUNCTION_NAME include the variable name
|
||||
RETURN_FUNCTION_FLAGS include the variable flags
|
||||
RETURN_FUNCTION_TYPE include the return type
|
||||
RETURN_FUNCTION_TYPE include the variable type as an integer
|
||||
RETURN_FUNCTION_LPCTYPE include the variable type as an lpctype
|
||||
RETURN_VARIABLE_VALUE include the variable value
|
||||
|
||||
Control of listed variables:
|
||||
|
|
@ -50,6 +51,7 @@ DESCRIPTION
|
|||
|
||||
HISTORY
|
||||
Introduced in LDMud 3.2.10.
|
||||
LDMud 3.6.7 introduced RETURN_FUNCTION_LPCTYPE.
|
||||
|
||||
SEE ALSO
|
||||
inherit_list(E), functionlist(E), variable_exists(E)
|
||||
|
|
|
|||
21
gdb/ldmud.py
21
gdb/ldmud.py
|
|
@ -226,11 +226,12 @@ class SValuePrinter:
|
|||
T_LWOBJECT = 0xd
|
||||
T_COROUTINE = 0xe
|
||||
T_PYTHON = 0xf
|
||||
T_CALLBACK = 0x10
|
||||
T_ERROR_HANDLER = 0x11
|
||||
T_BREAK_ADDR = 0x12
|
||||
T_ARG_FRAME = 0x13
|
||||
T_NULL = 0x14
|
||||
T_LPCTYPE = 0x10
|
||||
T_CALLBACK = 0x11
|
||||
T_ERROR_HANDLER = 0x12
|
||||
T_BREAK_ADDR = 0x13
|
||||
T_ARG_FRAME = 0x14
|
||||
T_NULL = 0x15
|
||||
|
||||
LVALUE_UNPROTECTED = 0x00
|
||||
LVALUE_UNPROTECTED_CHAR = 0x01
|
||||
|
|
@ -260,6 +261,7 @@ class SValuePrinter:
|
|||
T_LWOBJECT: "T_LWOBJECT",
|
||||
T_COROUTINE: "T_COROUTINE",
|
||||
T_PYTHON: "T_PYTHON",
|
||||
T_LPCTYPE: "T_LPCTYPE",
|
||||
T_CALLBACK: "T_CALLBACK",
|
||||
T_ERROR_HANDLER: "T_ERROR_HANDLER",
|
||||
T_BREAK_ADDR: "T_BREAK_ADDR",
|
||||
|
|
@ -358,9 +360,10 @@ class SValuePrinter:
|
|||
return [(".u.strct", val["u"]["strct"])]
|
||||
elif stype == self.T_PYTHON:
|
||||
return [(".u.generic", val["u"]["generic"])]
|
||||
elif stype == self.T_LPCTYPE:
|
||||
return [(".u.lpctype", val["u"]["lpctype"])]
|
||||
elif stype == self.T_CALLBACK:
|
||||
return [(".u.cb", val["u"]["cb"]),
|
||||
(".x.extern_args", val["x"]["extern_args"])]
|
||||
return [(".u.cb", val["u"]["cb"])]
|
||||
elif stype == self.T_ERROR_HANDLER:
|
||||
return [(".u.error_handler", val["u"]["error_handler"])]
|
||||
elif stype == self.T_BREAK_ADDR:
|
||||
|
|
@ -495,6 +498,8 @@ class TypePrinter:
|
|||
TYPE_SYMBOL = 8
|
||||
TYPE_QUOTED_ARRAY = 9
|
||||
TYPE_BYTES = 10
|
||||
TYPE_COROUTINE = 11
|
||||
TYPE_LPCTYPE = 12
|
||||
|
||||
OBJECT_REGULAR = 0
|
||||
OBJECT_LIGHTWEIGHT= 1
|
||||
|
|
@ -511,6 +516,8 @@ class TypePrinter:
|
|||
TYPE_SYMBOL: "symbol",
|
||||
TYPE_QUOTED_ARRAY: "quoted_array",
|
||||
TYPE_BYTES: "bytes",
|
||||
TYPE_COROUTINE: "coroutine",
|
||||
TYPE_LPCTYPE: "lpctype",
|
||||
}
|
||||
|
||||
def __init__(self, val):
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
#define RETURN_FUNCTION_NAME 0x01
|
||||
#define RETURN_FUNCTION_FLAGS 0x02
|
||||
#define RETURN_FUNCTION_TYPE 0x04
|
||||
|
||||
#define RETURN_FUNCTION_LPCTYPE 0x20
|
||||
|
||||
/* Additional return value flag types for functionlist() */
|
||||
|
||||
|
|
@ -45,8 +45,8 @@
|
|||
|
||||
|
||||
/* Masks of the flag unions allowed for various efuns: */
|
||||
#define RETURN_FUNCTION_MASK 0x0f /* functionlist() */
|
||||
#define RETURN_VARIABLE_MASK 0x0f /* variable_list() */
|
||||
#define RETURN_FUNCTION_MASK 0x2f /* functionlist() */
|
||||
#define RETURN_VARIABLE_MASK 0x2f /* variable_list() */
|
||||
|
||||
/* Return value flag types for function_exists() */
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#define TYPE_BYTES 12
|
||||
#define TYPE_LWOBJECT 13
|
||||
#define TYPE_COROUTINE 14
|
||||
#define TYPE_LPCTYPE 15
|
||||
|
||||
#define TYPE_MOD_POINTER 0x0040 /* Pointer to a basic type */
|
||||
|
||||
|
|
@ -39,6 +40,7 @@
|
|||
#define T_LWOBJECT 0xd
|
||||
#define T_COROUTINE 0xe
|
||||
#define T_PYTHON 0xf
|
||||
#define T_LPCTYPE 0x10
|
||||
|
||||
/* Closure types, stored as secondary type info */
|
||||
|
||||
|
|
|
|||
|
|
@ -3215,6 +3215,8 @@ sameval (svalue_t *arg1, svalue_t *arg2)
|
|||
return arg1->u.lwob == arg2->u.lwob;
|
||||
} else if (arg1->type == T_COROUTINE && arg2->type == T_COROUTINE) {
|
||||
return arg1->u.coroutine == arg2->u.coroutine;
|
||||
} else if (arg1->type == T_LPCTYPE && arg2->type == T_LPCTYPE) {
|
||||
return arg1->u.lpctype == arg2->u.lpctype;
|
||||
} else
|
||||
return 0;
|
||||
} /* sameval() */
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ svalue_size (svalue_t *v, mp_int * pTotal)
|
|||
case T_OBJECT:
|
||||
case T_NUMBER:
|
||||
case T_FLOAT:
|
||||
case T_LPCTYPE:
|
||||
return 0;
|
||||
|
||||
case T_STRING:
|
||||
|
|
|
|||
88
src/efuns.c
88
src/efuns.c
|
|
@ -6374,6 +6374,14 @@ f_to_string (svalue_t *sp)
|
|||
break;
|
||||
}
|
||||
|
||||
case T_LPCTYPE:
|
||||
{
|
||||
string_t * rc = new_unicode_mstring(get_lpctype_name(sp->u.lpctype));
|
||||
free_lpctype(sp->u.lpctype);
|
||||
put_string(sp, rc);
|
||||
break;
|
||||
}
|
||||
|
||||
case T_SYMBOL:
|
||||
{
|
||||
/* Easy: the symbol value is a string */
|
||||
|
|
@ -6403,6 +6411,7 @@ f_to_array (svalue_t *sp)
|
|||
* mixed *to_array(quotedarray)
|
||||
* mixed *to_array(mixed *)
|
||||
* mixed *to_array(struct)
|
||||
* lpctype *to_array(lpctype)
|
||||
*
|
||||
* Strings and symbols are converted to an int array that
|
||||
* consists of the args characters.
|
||||
|
|
@ -6499,11 +6508,70 @@ f_to_array (svalue_t *sp)
|
|||
case T_POINTER:
|
||||
/* Good as it is */
|
||||
break;
|
||||
case T_LPCTYPE:
|
||||
{
|
||||
lpctype_t *t = sp->u.lpctype;
|
||||
vector_t *vec;
|
||||
size_t pos = 0;
|
||||
|
||||
len = 1;
|
||||
for (lpctype_t *cur = t; cur->t_class == TCLASS_UNION; cur = cur->t_union.head)
|
||||
len++;
|
||||
|
||||
vec = allocate_array(len);
|
||||
while (true)
|
||||
{
|
||||
if (t->t_class == TCLASS_UNION)
|
||||
{
|
||||
put_ref_lpctype(vec->item + pos, t->t_union.member);
|
||||
t = t->t_union.head;
|
||||
}
|
||||
else
|
||||
{
|
||||
put_ref_lpctype(vec->item + pos, t);
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
free_lpctype(sp->u.lpctype);
|
||||
put_array(sp, vec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return sp;
|
||||
} /* f_to_array() */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
svalue_t *
|
||||
f_to_lpctype (svalue_t *sp)
|
||||
|
||||
/* EFUN to_lpctype()
|
||||
*
|
||||
* lpctype to_lpctype(string type)
|
||||
*
|
||||
* Interpret <type> as an lpctype and return the corresponding type object.
|
||||
*
|
||||
* We could use the LPC parser for this, but it has a high overhead.
|
||||
* So we implement our own type parser here.
|
||||
*/
|
||||
|
||||
{
|
||||
const char *str = get_txt(sp->u.str);
|
||||
const char *end = str + mstrsize(sp->u.str);
|
||||
lpctype_t *result = parse_lpctype(&str, end);
|
||||
if (!result)
|
||||
errorf("Syntax error.\n");
|
||||
if (str < end)
|
||||
{
|
||||
free_lpctype(result);
|
||||
errorf("Extraneous characters at the end.\n");
|
||||
}
|
||||
free_mstring(sp->u.str);
|
||||
put_lpctype(sp, result);
|
||||
return sp;
|
||||
} /* f_to_lpctype() */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* -- struct mtos_member_s --
|
||||
|
|
@ -8230,6 +8298,24 @@ v_get_type_info (svalue_t *sp, int num_arg)
|
|||
return sp;
|
||||
} /* v_get_type_info() */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
svalue_t *
|
||||
f_check_type (svalue_t *sp)
|
||||
|
||||
/* EFUN check_type()
|
||||
*
|
||||
* int check_type(mixed arg, lpctype type)
|
||||
*
|
||||
* Does RTTC of <type> against <arg> and return 1 if correct.
|
||||
*/
|
||||
|
||||
{
|
||||
bool result = check_rtt_compatibility(sp[0].u.lpctype, sp-1);
|
||||
sp = pop_n_elems(2, sp);
|
||||
push_number(sp, result ? 1 : 0);
|
||||
return sp;
|
||||
} /* f_check_type() */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
svalue_t *
|
||||
v_map (svalue_t *sp, int num_arg)
|
||||
|
|
@ -8474,6 +8560,7 @@ v_member (svalue_t *sp, int num_arg)
|
|||
case T_COROUTINE:
|
||||
case T_POINTER:
|
||||
case T_STRUCT:
|
||||
case T_LPCTYPE:
|
||||
#ifdef USE_PYTHON
|
||||
case T_PYTHON:
|
||||
#endif
|
||||
|
|
@ -8787,6 +8874,7 @@ v_rmember (svalue_t *sp, int num_arg)
|
|||
case T_COROUTINE:
|
||||
case T_POINTER:
|
||||
case T_STRUCT:
|
||||
case T_LPCTYPE:
|
||||
#ifdef USE_PYTHON
|
||||
case T_PYTHON:
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -54,10 +54,12 @@ extern svalue_t *f_to_int (svalue_t *sp);
|
|||
extern svalue_t *f_to_float (svalue_t *sp);
|
||||
extern svalue_t *f_to_string (svalue_t *sp);
|
||||
extern svalue_t *f_to_object (svalue_t *sp);
|
||||
extern svalue_t *f_to_lpctype(svalue_t *sp);
|
||||
extern svalue_t *f_copy (svalue_t *sp);
|
||||
extern svalue_t *f_deep_copy (svalue_t *sp);
|
||||
extern svalue_t *v_filter (svalue_t *sp, int num_arg);
|
||||
extern svalue_t *v_get_type_info (svalue_t *sp, int num_arg);
|
||||
extern svalue_t *f_check_type (svalue_t *sp);
|
||||
extern svalue_t *v_map (svalue_t *sp, int num_arg);
|
||||
extern svalue_t *v_member (svalue_t *sp, int num_arg);
|
||||
extern svalue_t *v_rmember (svalue_t *sp, int num_arg);
|
||||
|
|
|
|||
26
src/exec.h
26
src/exec.h
|
|
@ -654,16 +654,24 @@ struct program_s
|
|||
/* Index of the heart beat function. -1 means no heart beat
|
||||
*/
|
||||
|
||||
/* The types of all function arguments are saved in the
|
||||
* .argument_types[]. To look up the arguments types for
|
||||
* function <n>, retrieve the start index from the .type_start[]
|
||||
* as .type_start[n]. If this index is INDEX_START_NONE, the function
|
||||
* has no type information.
|
||||
lpctype_t **types;
|
||||
/* A list of all types used in the program.
|
||||
*/
|
||||
|
||||
/* The types of all function arguments are saved in the .argument_types[].
|
||||
* To look up the arguments types for function <n>:
|
||||
* - Retrieve the start index from the .type_start[] as i=.type_start[n].
|
||||
* If this index is INDEX_START_NONE, the function has no type
|
||||
* information.
|
||||
* - Get the type indices from .argument_types[] for the arguments
|
||||
* starting with i as j=.argument_types[i+x] (x is argument position).
|
||||
* - Get the type from .types as .types[j].
|
||||
*
|
||||
* This is also used for foreach() variables.
|
||||
* Both arrays will only be allocated if '#pragma save_types' has
|
||||
* been specified.
|
||||
*/
|
||||
lpctype_t **argument_types;
|
||||
unsigned short *argument_types;
|
||||
unsigned short *type_start;
|
||||
/* TODO: Some code relies on this being unsigned short */
|
||||
|
||||
|
|
@ -708,8 +716,8 @@ struct program_s
|
|||
/* Number of (directly) inherited programs */
|
||||
unsigned short num_structs;
|
||||
/* Number of listed struct definitions */
|
||||
unsigned int num_argument_types;
|
||||
/* Number of argument types in .argument_types */
|
||||
unsigned int num_types;
|
||||
/* Number of types in .types */
|
||||
};
|
||||
|
||||
/* Constants for flags in program_s. */
|
||||
|
|
@ -810,7 +818,7 @@ struct function_s
|
|||
uint32 fx; /* Function index, this is not an offset. */
|
||||
|
||||
/* These entries are used by simul_efun.c. */
|
||||
lpctype_t **argtypes;
|
||||
unsigned short *argtypes;
|
||||
/* Argument types for this simul_efun. */
|
||||
|
||||
uint32 next_sefun;
|
||||
|
|
|
|||
|
|
@ -267,6 +267,7 @@
|
|||
pop_n
|
||||
put_array_element
|
||||
type_check
|
||||
push_type
|
||||
call_other_cached
|
||||
call_strict_cached
|
||||
#ifdef USE_PYTHON
|
||||
|
|
@ -303,6 +304,7 @@ int stringp(mixed);
|
|||
int bytesp(mixed);
|
||||
int structp(mixed);
|
||||
int symbolp(mixed);
|
||||
int lpctypep(mixed);
|
||||
int typeof(mixed|mixed &);
|
||||
|
||||
mixed negate(int|float);
|
||||
|
|
@ -370,9 +372,10 @@ int sgn(int|float);
|
|||
int to_int(int|string|float|closure);
|
||||
float to_float(float|string|int);
|
||||
string to_string(mixed);
|
||||
mixed *to_array(string|bytes|mixed*|symbol|quoted_array|struct);
|
||||
mixed *to_array(string|bytes|mixed*|symbol|quoted_array|struct|lpctype);
|
||||
mixed to_struct(mapping|mixed*|struct, void|struct);
|
||||
object to_object(null|object|string|closure);
|
||||
lpctype to_lpctype(string);
|
||||
|
||||
bytes to_bytes(string|bytes|int*, void|string);
|
||||
string to_text(string|bytes|int*, void|string);
|
||||
|
|
@ -384,6 +387,7 @@ mixed copy(mixed);
|
|||
mixed deep_copy(mixed);
|
||||
int ed(void|string, void|null|string) no_lightweight;
|
||||
mixed get_type_info(mixed, void|int);
|
||||
int check_type(mixed, lpctype);
|
||||
mixed quote(mixed *|quoted_array|symbol|string);
|
||||
mixed unquote(quoted_array|symbol);
|
||||
|
||||
|
|
|
|||
|
|
@ -1163,11 +1163,11 @@ clear_program_ref (program_t *p, Bool clear_ref)
|
|||
}
|
||||
}
|
||||
|
||||
if (p->argument_types)
|
||||
if (p->types)
|
||||
{
|
||||
lpctype_t** arg_type = p->argument_types;
|
||||
for (i = p->num_argument_types; --i >= 0; arg_type++)
|
||||
clear_lpctype_ref(*arg_type);
|
||||
lpctype_t** t = p->types;
|
||||
for (i = p->num_types; --i >= 0; t++)
|
||||
clear_lpctype_ref(*t);
|
||||
}
|
||||
|
||||
} /* clear_program_ref() */
|
||||
|
|
@ -1299,11 +1299,11 @@ gc_mark_program_ref (program_t *p)
|
|||
str = p->includes[i].filename; MARK_MSTRING_REF(str);
|
||||
}
|
||||
|
||||
if (p->argument_types)
|
||||
if (p->types)
|
||||
{
|
||||
lpctype_t** arg_type = p->argument_types;
|
||||
for (i = p->num_argument_types; --i >= 0; arg_type++)
|
||||
count_lpctype_ref(*arg_type);
|
||||
lpctype_t** t = p->types;
|
||||
for (i = p->num_types; --i >= 0; t++)
|
||||
count_lpctype_ref(*t);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -1516,6 +1516,10 @@ clear_ref_in_vector (svalue_t *svp, size_t num)
|
|||
clear_coroutine_ref(p->u.coroutine);
|
||||
continue;
|
||||
|
||||
case T_LPCTYPE:
|
||||
clear_lpctype_ref(p->u.lpctype);
|
||||
continue;
|
||||
|
||||
case T_LVALUE:
|
||||
switch (p->x.lvalue_type)
|
||||
{
|
||||
|
|
@ -1721,6 +1725,10 @@ gc_count_ref_in_vector (svalue_t *svp, size_t num
|
|||
MARK_MSTRING_REF(p->u.str);
|
||||
continue;
|
||||
|
||||
case T_LPCTYPE:
|
||||
count_lpctype_ref(p->u.lpctype);
|
||||
continue;
|
||||
|
||||
case T_LVALUE:
|
||||
switch (p->x.lvalue_type)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -137,6 +137,10 @@ svalue_hash (svalue_t *svp, int bits)
|
|||
case T_COROUTINE:
|
||||
result = (p_int)svp->u.coroutine;
|
||||
break;
|
||||
|
||||
case T_LPCTYPE:
|
||||
result = (p_int)svp->u.lpctype;
|
||||
break;
|
||||
}
|
||||
|
||||
#if SIZEOF_CHAR_P > 4
|
||||
|
|
|
|||
172
src/interpret.c
172
src/interpret.c
|
|
@ -438,6 +438,7 @@ static const char * svalue_typename[]
|
|||
, /* T_LWOBJECT */ "lwobject"
|
||||
, /* T_COROUTINE */ "coroutine"
|
||||
, /* T_PYTHON */ "python-object"
|
||||
, /* T_LPCTYPE */ "lpctype"
|
||||
, /* T_CALLBACK */ "callback"
|
||||
, /* T_ERROR_HANDLER */ "error-handler"
|
||||
, /* T_BREAK_ADDR */ "break-address"
|
||||
|
|
@ -1237,6 +1238,10 @@ int_free_svalue (svalue_t *v)
|
|||
break;
|
||||
#endif
|
||||
|
||||
case T_LPCTYPE:
|
||||
free_lpctype(v->u.lpctype);
|
||||
break;
|
||||
|
||||
case T_CALLBACK:
|
||||
free_callback(v->u.cb);
|
||||
xfree(v->u.cb);
|
||||
|
|
@ -1713,6 +1718,10 @@ internal_assign_svalue_no_free (svalue_t *to, svalue_t *from)
|
|||
(void)ref_mapping(to->u.map);
|
||||
break;
|
||||
|
||||
case T_LPCTYPE:
|
||||
ref_lpctype(to->u.lpctype);
|
||||
break;
|
||||
|
||||
case T_LVALUE:
|
||||
switch(to->x.lvalue_type)
|
||||
{
|
||||
|
|
@ -8203,6 +8212,10 @@ check_rtt_compatibility_inl(lpctype_t *formaltype, svalue_t *svp, lpctype_t **sv
|
|||
valuetype = get_struct_type(bsvp->u.strct->type);
|
||||
break;
|
||||
|
||||
case T_LPCTYPE:
|
||||
valuetype = lpctype_lpctype;
|
||||
break;
|
||||
|
||||
#ifdef USE_PYTHON
|
||||
case T_PYTHON:
|
||||
valuetype = get_python_type(bsvp->x.python_type);
|
||||
|
|
@ -8298,7 +8311,7 @@ check_function_args(int fx, program_t *progp, bytecode_p funstart)
|
|||
&& progp->type_start && progp->type_start[fx] != INDEX_START_NONE)
|
||||
{
|
||||
// check for the correct argument types
|
||||
lpctype_t **arg_type = progp->argument_types + progp->type_start[fx];
|
||||
unsigned short *arg_type_idx = progp->argument_types + progp->type_start[fx];
|
||||
svalue_t *firstarg = inter_sp - csp->num_local_variables + 1;
|
||||
function_t *header = current_prog->function_headers + FUNCTION_HEADER_INDEX(funstart);
|
||||
|
||||
|
|
@ -8306,16 +8319,17 @@ check_function_args(int fx, program_t *progp, bytecode_p funstart)
|
|||
int i = 0;
|
||||
while (i < formal_args)
|
||||
{
|
||||
lpctype_t *arg_type = progp->types[arg_type_idx[i]];
|
||||
// do the types match (in case of structs also the structure)
|
||||
// or is the formal argument of type TYPE_ANY (mixed)?
|
||||
if (!check_rtt_compatibility(arg_type[i], firstarg+i))
|
||||
if (!check_rtt_compatibility(arg_type, firstarg+i))
|
||||
{
|
||||
// How many control stack frames to remove.
|
||||
int num_csf = 0;
|
||||
|
||||
// Determine the lpctype of arg_type[i] for a better error message.
|
||||
// Determine the lpctype of arg[i] for a better error message.
|
||||
static char buff[512];
|
||||
lpctype_t *realtype = get_rtt_type(arg_type[i], firstarg+i);
|
||||
lpctype_t *realtype = get_rtt_type(arg_type, firstarg+i);
|
||||
get_lpctype_name_buf(realtype, buff, sizeof(buff));
|
||||
free_lpctype(realtype);
|
||||
|
||||
|
|
@ -8371,7 +8385,7 @@ check_function_args(int fx, program_t *progp, bytecode_p funstart)
|
|||
// warnf will return (errors are caught).
|
||||
warnf("Bad arg %d to %s(): got '%s', expected '%s'.\n"
|
||||
, i+1, get_txt(header->name), buff,
|
||||
get_lpctype_name(arg_type[i]));
|
||||
get_lpctype_name(arg_type));
|
||||
|
||||
for (int j = num_csf; j >= 0; j--)
|
||||
*(++csp) = saved_csf[j];
|
||||
|
|
@ -8385,7 +8399,7 @@ check_function_args(int fx, program_t *progp, bytecode_p funstart)
|
|||
|
||||
errorf("Bad arg %d to %s(): got '%s', expected '%s'.\n"
|
||||
, i+1, get_txt(header->name), buff,
|
||||
get_lpctype_name(arg_type[i]));
|
||||
get_lpctype_name(arg_type));
|
||||
}
|
||||
}
|
||||
++i;
|
||||
|
|
@ -13538,6 +13552,10 @@ again:
|
|||
i = (sp-1)->u.map == sp->u.map;
|
||||
break;
|
||||
|
||||
case T_LPCTYPE:
|
||||
i = (sp-1)->u.lpctype == sp->u.lpctype;
|
||||
break;
|
||||
|
||||
#ifdef USE_PYTHON
|
||||
case T_PYTHON:
|
||||
i = (sp-1)->u.generic == sp->u.generic;
|
||||
|
|
@ -13636,6 +13654,10 @@ again:
|
|||
i = (sp-1)->u.map != sp->u.map;
|
||||
break;
|
||||
|
||||
case T_LPCTYPE:
|
||||
i = (sp-1)->u.lpctype != sp->u.lpctype;
|
||||
break;
|
||||
|
||||
#ifdef USE_PYTHON
|
||||
case T_PYTHON:
|
||||
i = (sp-1)->u.generic != sp->u.generic;
|
||||
|
|
@ -13763,8 +13785,20 @@ again:
|
|||
break;
|
||||
}
|
||||
|
||||
case T_LPCTYPE:
|
||||
if (item->type == T_LPCTYPE)
|
||||
{
|
||||
if (item->u.lpctype == lpctype_void)
|
||||
result = 1;
|
||||
else
|
||||
result = lpctype_contains(item->u.lpctype, container->u.lpctype) ? 1 : 0;
|
||||
}
|
||||
else
|
||||
OP_ARG_ERROR(1, TF_LPCTYPE, item);
|
||||
break;
|
||||
|
||||
default:
|
||||
OP_ARG_ERROR(2, TF_POINTER|TF_MAPPING|TF_STRING|TF_BYTES, sp);
|
||||
OP_ARG_ERROR(2, TF_POINTER|TF_MAPPING|TF_STRING|TF_BYTES|TF_LPCTYPE, sp);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
|
@ -13803,6 +13837,7 @@ again:
|
|||
* vector & mapping -> vector
|
||||
* mapping & vector -> mapping
|
||||
* mapping & mapping -> mapping
|
||||
* lpctype & lpctype -> lpctype
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -13862,8 +13897,22 @@ again:
|
|||
break;
|
||||
}
|
||||
|
||||
TYPE_TEST_EXP_LEFT((sp-1), TF_NUMBER|TF_STRING|TF_BYTES|TF_POINTER|TF_MAPPING);
|
||||
TYPE_TEST_EXP_RIGHT(sp, TF_NUMBER|TF_STRING|TF_BYTES|TF_POINTER|TF_MAPPING);
|
||||
if (sp->type == T_LPCTYPE && (sp-1)->type == T_LPCTYPE)
|
||||
{
|
||||
lpctype_t * result = get_common_type(sp[-1].u.lpctype, sp[0].u.lpctype);
|
||||
|
||||
free_lpctype(sp[-1].u.lpctype);
|
||||
free_lpctype(sp[0].u.lpctype);
|
||||
sp--;
|
||||
if (result)
|
||||
sp->u.lpctype = result;
|
||||
else
|
||||
sp->u.lpctype = lpctype_void;
|
||||
break;
|
||||
}
|
||||
|
||||
TYPE_TEST_EXP_LEFT((sp-1), TF_NUMBER|TF_STRING|TF_BYTES|TF_POINTER|TF_MAPPING|TF_LPCTYPE);
|
||||
TYPE_TEST_EXP_RIGHT(sp, TF_NUMBER|TF_STRING|TF_BYTES|TF_POINTER|TF_MAPPING|TF_LPCTYPE);
|
||||
ERRORF(("Arguments to & don't match: %s vs %s\n"
|
||||
, typename(sp[-1].type), typename(sp->type)
|
||||
));
|
||||
|
|
@ -13876,8 +13925,9 @@ again:
|
|||
* the result on the stack.
|
||||
*
|
||||
* Possible type combinations:
|
||||
* int | int -> int
|
||||
* array | array -> array
|
||||
* int | int -> int
|
||||
* array | array -> array
|
||||
* lpctype | lpctype -> lpctype
|
||||
*
|
||||
* TODO: Extend this to mappings.
|
||||
*/
|
||||
|
|
@ -13890,7 +13940,7 @@ again:
|
|||
}
|
||||
#endif
|
||||
|
||||
TYPE_TEST_EXP_LEFT((sp-1), TF_NUMBER|TF_POINTER);
|
||||
TYPE_TEST_EXP_LEFT((sp-1), TF_NUMBER|TF_POINTER|TF_LPCTYPE);
|
||||
if ((sp-1)->type == T_NUMBER)
|
||||
{
|
||||
TYPE_TEST_RIGHT(sp, T_NUMBER);
|
||||
|
|
@ -13906,6 +13956,16 @@ again:
|
|||
sp--;
|
||||
sp->u.vec = join_array(sp->u.vec, (sp+1)->u.vec);
|
||||
}
|
||||
else if (sp->type == T_LPCTYPE && (sp-1)->type == T_LPCTYPE)
|
||||
{
|
||||
TYPE_TEST_RIGHT(sp, T_LPCTYPE);
|
||||
lpctype_t * result = get_union_type(sp[-1].u.lpctype, sp[0].u.lpctype);
|
||||
|
||||
free_lpctype(sp[-1].u.lpctype);
|
||||
free_lpctype(sp[0].u.lpctype);
|
||||
sp--;
|
||||
sp->u.lpctype = result;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
@ -15327,6 +15387,7 @@ again:
|
|||
* array & mapping -> array
|
||||
* mapping & array -> mapping
|
||||
* mapping & mapping -> mapping
|
||||
* lpctype & lpctype -> lpctype
|
||||
*/
|
||||
|
||||
svalue_t *argp;
|
||||
|
|
@ -15487,8 +15548,26 @@ again:
|
|||
/* NOTREACHED */
|
||||
}
|
||||
break;
|
||||
|
||||
case T_LPCTYPE:
|
||||
if (sp[-1].type == T_LPCTYPE)
|
||||
{
|
||||
lpctype_t * result = get_common_type(argp->u.lpctype, sp[-1].u.lpctype);
|
||||
|
||||
free_lpctype(argp->u.lpctype);
|
||||
if (result)
|
||||
argp->u.lpctype = result;
|
||||
else
|
||||
argp->u.lpctype = lpctype_void;
|
||||
}
|
||||
else
|
||||
{
|
||||
OP_ARG_ERROR(2, TF_LPCTYPE, sp-1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
OP_ARG_ERROR(1, TF_NUMBER|TF_STRING|TF_BYTES|TF_POINTER, argp);
|
||||
OP_ARG_ERROR(1, TF_NUMBER|TF_STRING|TF_BYTES|TF_POINTER|TF_LPCTYPE, argp);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
|
@ -15609,8 +15688,22 @@ again:
|
|||
}
|
||||
break;
|
||||
|
||||
case T_LPCTYPE:
|
||||
if (sp[-1].type == T_LPCTYPE)
|
||||
{
|
||||
lpctype_t * result = get_union_type(argp->u.lpctype, sp[-1].u.lpctype);
|
||||
|
||||
free_lpctype(argp->u.lpctype);
|
||||
argp->u.lpctype = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
OP_ARG_ERROR(2, TF_LPCTYPE, sp-1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
OP_ARG_ERROR(1, TF_NUMBER|TF_POINTER, argp);
|
||||
OP_ARG_ERROR(1, TF_NUMBER|TF_POINTER|TF_LPCTYPE, argp);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
|
@ -18541,7 +18634,7 @@ again:
|
|||
/* Do runtime type checks. */
|
||||
for (int i = 0; i <= left; i++)
|
||||
{
|
||||
lpctype_t* exptype = current_prog->argument_types[typeidx + i];
|
||||
lpctype_t* exptype = current_prog->types[current_prog->argument_types[typeidx + i]];
|
||||
svalue_t * val = i ? (values + i - 1) : (indices->item + ix);
|
||||
if (!check_rtt_compatibility(exptype, val))
|
||||
{
|
||||
|
|
@ -18709,7 +18802,7 @@ again:
|
|||
if (typeidx != USHRT_MAX && current_prog->argument_types)
|
||||
{
|
||||
/* Do runtime type checks. */
|
||||
lpctype_t* exptype = current_prog->argument_types[typeidx];
|
||||
lpctype_t* exptype = current_prog->types[current_prog->argument_types[typeidx]];
|
||||
if (!check_rtt_compatibility(exptype, val))
|
||||
{
|
||||
char buf[512];
|
||||
|
|
@ -18998,10 +19091,9 @@ again:
|
|||
CASE(F_TYPE_CHECK); /* --- type_check <op> <ix> --- */
|
||||
{
|
||||
/* Check the top value off the stack against the type
|
||||
* at prog->argument_types[<ix>]. Raise an error if
|
||||
* it doesn't match. Do nothing otherwise.
|
||||
* <op> contains a value of enum type_check_operation to
|
||||
* give a specific error message.
|
||||
* at prog->types[<ix>]. Raise an error if it doesn't match.
|
||||
* Do nothing otherwise. <op> contains a value of
|
||||
* enum type_check_operation to give a specific error message.
|
||||
*/
|
||||
|
||||
unsigned short ix, op = LOAD_UINT8(pc);
|
||||
|
|
@ -19010,10 +19102,10 @@ again:
|
|||
LOAD_SHORT(ix, pc);
|
||||
|
||||
/* Types were saved? */
|
||||
if (!current_prog->argument_types)
|
||||
if (!current_prog->types)
|
||||
break;
|
||||
|
||||
exptype = current_prog->argument_types[ix];
|
||||
exptype = current_prog->types[ix];
|
||||
if (!check_rtt_compatibility(exptype, sp))
|
||||
{
|
||||
static char buff[512];
|
||||
|
|
@ -19056,6 +19148,23 @@ again:
|
|||
break;
|
||||
}
|
||||
|
||||
CASE(F_PUSH_TYPE); /* --- push_type <ix> --- */
|
||||
{
|
||||
/* Push the type at prog->types[<ix>] as an lpctype onto
|
||||
* the stack.
|
||||
*/
|
||||
unsigned short ix;
|
||||
|
||||
LOAD_SHORT(ix, pc);
|
||||
|
||||
/* Types were saved? */
|
||||
if (!current_prog->types)
|
||||
break;
|
||||
|
||||
push_ref_lpctype(sp, current_prog->types[ix]);
|
||||
break;
|
||||
}
|
||||
|
||||
/* --- Efuns: Miscellaneous --- */
|
||||
|
||||
CASE(F_CLONEP); /* --- clonep --- */
|
||||
|
|
@ -19379,6 +19488,25 @@ again:
|
|||
break;
|
||||
}
|
||||
|
||||
CASE(F_LPCTYPEP); /* --- lpctypep --- */
|
||||
{
|
||||
/* EFUN lpctypep()
|
||||
*
|
||||
* int lpctypep(mixed)
|
||||
*
|
||||
* Returns 1 if the argument is an LPC type object.
|
||||
*/
|
||||
|
||||
int i;
|
||||
|
||||
CALL_PYTHON_TYPE_EFUN(F_LPCTYPEP, 1);
|
||||
|
||||
i = sp->type == T_LPCTYPE;
|
||||
free_svalue(sp);
|
||||
put_number(sp, i);
|
||||
break;
|
||||
}
|
||||
|
||||
CASE(F_TYPEOF); /* --- typeof --- */
|
||||
{
|
||||
/* EFUN typeof()
|
||||
|
|
|
|||
|
|
@ -536,6 +536,7 @@ static struct s_reswords reswords[]
|
|||
, { "closure", L_CLOSURE_DECL }
|
||||
, { "continue", L_CONTINUE }
|
||||
, { "coroutine", L_COROUTINE }
|
||||
, { "decltype", L_DECLTYPE }
|
||||
, { "default", L_DEFAULT }
|
||||
, { "do", L_DO }
|
||||
, { "else", L_ELSE }
|
||||
|
|
@ -550,6 +551,7 @@ static struct s_reswords reswords[]
|
|||
, { "inherit", L_INHERIT }
|
||||
, { "int", L_INT }
|
||||
, { "lwobject", L_LWOBJECT }
|
||||
, { "lpctype", L_LPCTYPE }
|
||||
, { "mapping", L_MAPPING }
|
||||
, { "mixed", L_MIXED }
|
||||
, { "nomask", L_NO_MASK }
|
||||
|
|
@ -911,6 +913,7 @@ init_lexer(void)
|
|||
add_permanent_define_str("__LPC_LWOBJECTS__", -1, "1");
|
||||
add_permanent_define_str("__LPC_INLINE_CLOSURES__", -1, "1");
|
||||
add_permanent_define_str("__LPC_COROUTINES__", -1, "1");
|
||||
add_permanent_define_str("__LPC_LPCTYPES__", -1, "1");
|
||||
add_permanent_define_str("__LPC_ARRAY_CALLS__", -1, "1");
|
||||
#ifdef USE_TLS
|
||||
add_permanent_define_str("__TLS__", -1, "1");
|
||||
|
|
@ -1869,7 +1872,7 @@ undefined_function:
|
|||
* Check it with a privilege violation.
|
||||
*/
|
||||
if (!privileged && efun_override == OVERRIDE_EFUN && p->u.global.sim_efun != I_GLOBAL_SEFUN_OTHER
|
||||
&& get_simul_efun_header(p)->flags & TYPE_MOD_NO_MASK)
|
||||
&& get_simul_efun_header(p, NULL)->flags & TYPE_MOD_NO_MASK)
|
||||
{
|
||||
svalue_t *res;
|
||||
|
||||
|
|
@ -5175,7 +5178,7 @@ closure (char *in_yyp)
|
|||
*/
|
||||
if (efun_override == OVERRIDE_EFUN
|
||||
&& p->u.global.sim_efun != I_GLOBAL_SEFUN_OTHER
|
||||
&& (get_simul_efun_header(p)->flags & TYPE_MOD_NO_MASK)
|
||||
&& (get_simul_efun_header(p, NULL)->flags & TYPE_MOD_NO_MASK)
|
||||
&& (p->u.global.efun != I_GLOBAL_EFUN_OTHER
|
||||
#ifdef USE_PYTHON
|
||||
|| is_python_efun(p)
|
||||
|
|
|
|||
|
|
@ -519,6 +519,7 @@ static long lpc_types[MAX_ARGTYPES];
|
|||
# define LPC_T_BYTES (1 << 13)
|
||||
# define LPC_T_LWOBJECT (1 << 14)
|
||||
# define LPC_T_COROUTINE (1 << 15)
|
||||
# define LPC_T_LPCTYPE (1 << 16)
|
||||
|
||||
|
||||
static int last_current_type = 0;
|
||||
|
|
@ -902,8 +903,8 @@ move_to_arg_types ()
|
|||
%token NAME ID
|
||||
|
||||
%token VOID INT STRING BYTES BYTES_OR_STRING OBJECT MAPPING FLOAT CLOSURE SYMBOL QUOTED_ARRAY
|
||||
%token MIXED UNKNOWN NUL STRUCT LWOBJECT OBJECT_OR_LWOBJECT COROUTINE MAPPING_OR_CLOSURE
|
||||
%token INT_OR_STRING STRING_OR_STRING_ARRAY CATCH_MSG_ARG
|
||||
%token MIXED UNKNOWN NUL STRUCT LWOBJECT OBJECT_OR_LWOBJECT COROUTINE LPCTYPE
|
||||
%token MAPPING_OR_CLOSURE INT_OR_STRING STRING_OR_STRING_ARRAY CATCH_MSG_ARG
|
||||
|
||||
%token DEFAULT NO_LIGHTWEIGHT
|
||||
|
||||
|
|
@ -919,7 +920,7 @@ move_to_arg_types ()
|
|||
%token LVALUE
|
||||
|
||||
%type <number> VOID MIXED UNKNOWN NUL STRUCT
|
||||
%type <number> INT STRING BYTES OBJECT MAPPING FLOAT CLOSURE SYMBOL QUOTED_ARRAY LWOBJECT COROUTINE
|
||||
%type <number> INT STRING BYTES OBJECT MAPPING FLOAT CLOSURE SYMBOL QUOTED_ARRAY LWOBJECT COROUTINE LPCTYPE
|
||||
%type <number> basic basic_utype
|
||||
/* Value is the basic type value
|
||||
*/
|
||||
|
|
@ -1239,7 +1240,7 @@ type: basic opt_star opt_ref { $$ = (lpc_type_t){$1, $2 | $3, NULL}; }
|
|||
;
|
||||
|
||||
basic: VOID | INT | STRING | BYTES | MAPPING | FLOAT | MIXED | OBJECT | CLOSURE |
|
||||
UNKNOWN | SYMBOL | QUOTED_ARRAY | STRUCT | LWOBJECT | COROUTINE | NUL ;
|
||||
UNKNOWN | SYMBOL | QUOTED_ARRAY | STRUCT | LWOBJECT | COROUTINE | LPCTYPE | NUL ;
|
||||
|
||||
opt_star : '*' { $$ = MF_TYPE_MOD_POINTER; }
|
||||
| '*' '*' { $$ = MF_TYPE_MOD_POINTER_POINTER; }
|
||||
|
|
@ -1562,6 +1563,7 @@ static struct type types[]
|
|||
, { "struct", STRUCT }
|
||||
, { "lwobject", LWOBJECT }
|
||||
, { "coroutine", COROUTINE }
|
||||
, { "lpctype", LPCTYPE }
|
||||
};
|
||||
|
||||
static struct type visibility[]
|
||||
|
|
@ -2981,6 +2983,7 @@ etype (long n)
|
|||
CONVERT(LPC_T_STRUCT, "TF_STRUCT");
|
||||
CONVERT(LPC_T_LWOBJECT, "TF_LWOBJECT");
|
||||
CONVERT(LPC_T_COROUTINE, "TF_COROUTINE");
|
||||
CONVERT(LPC_T_LPCTYPE, "TF_LPCTYPE");
|
||||
|
||||
# undef CONVERT
|
||||
|
||||
|
|
@ -3028,6 +3031,7 @@ type2flag (lpc_type_t t)
|
|||
case STRUCT: return LPC_T_STRUCT; break;
|
||||
case LWOBJECT:return LPC_T_LWOBJECT; break;
|
||||
case COROUTINE: return LPC_T_COROUTINE; break;
|
||||
case LPCTYPE: return LPC_T_LPCTYPE; break;
|
||||
default: yyerror("(type2flag) Bad type!"); return 0;
|
||||
}
|
||||
} /* type2flag() */
|
||||
|
|
@ -3067,6 +3071,7 @@ lpctypestr (lpc_type_t t)
|
|||
case FLOAT: p = "&_lpctype_float"; break;
|
||||
case CLOSURE: p = "&_lpctype_closure"; break;
|
||||
case COROUTINE: p="&_lpctype_coroutine"; break;
|
||||
case LPCTYPE: p = "&_lpctype_lpctype"; break;
|
||||
case SYMBOL: p = "&_lpctype_symbol"; break;
|
||||
case MIXED: p = "&_lpctype_mixed"; break;
|
||||
case UNKNOWN: p = "&_lpctype_unknown"; break;
|
||||
|
|
|
|||
97
src/object.c
97
src/object.c
|
|
@ -688,8 +688,8 @@ _free_prog (program_t *progp, Bool free_all, const char * file, int line
|
|||
}
|
||||
|
||||
/* Free all argument types. */
|
||||
for (i = progp->num_argument_types; --i >= 0; )
|
||||
free_lpctype(progp->argument_types[i]);
|
||||
for (i = progp->num_types; --i >= 0; )
|
||||
free_lpctype(progp->types[i]);
|
||||
|
||||
/* Free the strings, variable names and include filenames. */
|
||||
do_free_sub_strings( progp->num_strings, progp->strings
|
||||
|
|
@ -1785,7 +1785,8 @@ f_functionlist (svalue_t *sp)
|
|||
* Control of returned information:
|
||||
* RETURN_FUNCTION_NAME include the function name
|
||||
* RETURN_FUNCTION_FLAGS include the function flags
|
||||
* RETURN_FUNCTION_TYPE include the return type
|
||||
* RETURN_FUNCTION_TYPE include the return type as int
|
||||
* RETURN_FUNCTION_LPCTYPE include the return type as lpctype
|
||||
* RETURN_FUNCTION_NUMARG include the number of arguments.
|
||||
*
|
||||
* The name RETURN_FUNCTION_ARGTYPE is defined but not implemented.
|
||||
|
|
@ -2013,6 +2014,11 @@ f_functionlist (svalue_t *sp)
|
|||
svp->u.number = header->num_arg;
|
||||
}
|
||||
|
||||
if (mode_flags & RETURN_FUNCTION_LPCTYPE) {
|
||||
svp--;
|
||||
put_ref_lpctype(svp, header->type);
|
||||
}
|
||||
|
||||
if (mode_flags & RETURN_FUNCTION_TYPE) {
|
||||
svp--;
|
||||
svp->u.number = get_type_compat_int(header->type);
|
||||
|
|
@ -2294,7 +2300,8 @@ f_variable_list (svalue_t *sp)
|
|||
* Control of returned information:
|
||||
* RETURN_FUNCTION_NAME include the variable name
|
||||
* RETURN_FUNCTION_FLAGS include the variable flags
|
||||
* RETURN_FUNCTION_TYPE include the return type
|
||||
* RETURN_FUNCTION_TYPE include the return type as int
|
||||
* RETURN_FUNCTION_LPCTYPE include the return type as lpctype
|
||||
* RETURN_VARIABLE_VALUE include the variable value
|
||||
*
|
||||
* Control of listed variables:
|
||||
|
|
@ -2510,6 +2517,12 @@ f_variable_list (svalue_t *sp)
|
|||
assign_svalue_no_free(svp, variables+i);
|
||||
}
|
||||
|
||||
if (mode_flags & RETURN_FUNCTION_LPCTYPE)
|
||||
{
|
||||
svp--;
|
||||
put_ref_lpctype(svp, var->type.t_type);
|
||||
}
|
||||
|
||||
if (mode_flags & RETURN_FUNCTION_TYPE)
|
||||
{
|
||||
svp--;
|
||||
|
|
@ -4811,6 +4824,7 @@ e_say (svalue_t *v, vector_t *avoid)
|
|||
case T_POINTER:
|
||||
case T_MAPPING:
|
||||
case T_STRUCT:
|
||||
case T_LPCTYPE:
|
||||
#ifdef USE_PYTHON
|
||||
case T_PYTHON:
|
||||
#endif
|
||||
|
|
@ -5018,6 +5032,7 @@ e_tell_room (object_t *room, svalue_t *v, vector_t *avoid)
|
|||
case T_POINTER:
|
||||
case T_MAPPING:
|
||||
case T_STRUCT:
|
||||
case T_LPCTYPE:
|
||||
#ifdef USE_PYTHON
|
||||
case T_PYTHON:
|
||||
#endif
|
||||
|
|
@ -6966,6 +6981,26 @@ save_svalue (svalue_t *v, char delimiter, Bool writable)
|
|||
break;
|
||||
}
|
||||
|
||||
case T_LPCTYPE:
|
||||
if (!recall_pointer(v->u.lpctype))
|
||||
{
|
||||
const char *t = get_lpctype_name(v->u.lpctype);
|
||||
if (t)
|
||||
{
|
||||
L_PUTC_PROLOG
|
||||
L_PUTC('[')
|
||||
while (*t)
|
||||
L_PUTC(*t++);
|
||||
L_PUTC(']')
|
||||
L_PUTC_EPILOG
|
||||
}
|
||||
else if (writable)
|
||||
rc = MY_FALSE;
|
||||
else
|
||||
MY_PUTC('0');
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef USE_PYTHON
|
||||
case T_PYTHON:
|
||||
{
|
||||
|
|
@ -7270,6 +7305,10 @@ register_svalue (svalue_t *svp)
|
|||
register_closure(svp);
|
||||
break;
|
||||
|
||||
case T_LPCTYPE:
|
||||
register_pointer(ptable, svp->u.lpctype);
|
||||
break;
|
||||
|
||||
case T_LVALUE:
|
||||
if (save_version < SAVE_FORMAT_LVALUES)
|
||||
{
|
||||
|
|
@ -8026,6 +8065,28 @@ skip_element (char **str)
|
|||
return true;
|
||||
}
|
||||
|
||||
case '[': /* lpctype */
|
||||
while (true)
|
||||
{
|
||||
/* We look for ']', and skip any strings. */
|
||||
char *end = strchr(pt, ']');
|
||||
char *s = strchr(pt, '"');
|
||||
|
||||
if (!end)
|
||||
return false;
|
||||
|
||||
if (!s || s > end)
|
||||
{
|
||||
*str = end+1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!skip_element(&s))
|
||||
return false;
|
||||
pt = s;
|
||||
}
|
||||
break; /* NOTREACHED */
|
||||
|
||||
case '#': /* A closure: skip the header and restart this check
|
||||
* again from the data part.
|
||||
*/
|
||||
|
|
@ -9817,6 +9878,34 @@ restore_svalue (svalue_t *svp, char **pt, char delimiter)
|
|||
}
|
||||
break;
|
||||
|
||||
case '[': /* lpctype */
|
||||
{
|
||||
lpctype_t *result = NULL;
|
||||
char *end = cp;
|
||||
|
||||
if (skip_element(&end))
|
||||
{
|
||||
const char *s = cp + 1;
|
||||
result = parse_lpctype(&s, end - 1);
|
||||
*pt = end;
|
||||
|
||||
if (s < end - 1)
|
||||
{
|
||||
free_lpctype(result);
|
||||
result = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!result)
|
||||
{
|
||||
*svp = const0;
|
||||
return MY_FALSE;
|
||||
}
|
||||
|
||||
put_lpctype(svp, result);
|
||||
break;
|
||||
}
|
||||
|
||||
case '-': /* A number */
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
|
|
|
|||
|
|
@ -2082,7 +2082,7 @@ ldmud_program_lfun_get_arguments (ldmud_program_and_index_t *lfun, void *closure
|
|||
arg->type = NULL;
|
||||
|
||||
if (progp->argument_types && progp->type_start && progp->type_start[fx] != INDEX_START_NONE)
|
||||
arg->type = lpctype_to_pythontype(progp->argument_types[progp->type_start[fx] + i]);
|
||||
arg->type = lpctype_to_pythontype(progp->types[progp->argument_types[progp->type_start[fx] + i]]);
|
||||
|
||||
PyList_SET_ITEM(result, i, (PyObject*)arg);
|
||||
}
|
||||
|
|
@ -9871,6 +9871,7 @@ lpctype_to_pythontype (lpctype_t *type)
|
|||
Py_INCREF(&PyBytes_Type);
|
||||
return (PyObject *)&PyBytes_Type;
|
||||
|
||||
case TYPE_LPCTYPE: // TODO
|
||||
case TYPE_UNKNOWN:
|
||||
case TYPE_ANY:
|
||||
break;
|
||||
|
|
|
|||
365
src/prolang.y
365
src/prolang.y
|
|
@ -401,12 +401,16 @@ enum e_saved_areas {
|
|||
* variables and functions of an obsolete virtually inherited
|
||||
* program.
|
||||
*/
|
||||
, A_ARGUMENT_TYPES
|
||||
/* (lpctype_t*) Types of the arguments of all functions with
|
||||
* typechecking. The argument types for a specific function
|
||||
* can be found using the ARGUMENT_INDEX. All entries
|
||||
* are counted references.
|
||||
, A_TYPES
|
||||
/* (lpctype_t*) Types used in the program. All entries are
|
||||
* counted references.
|
||||
*/
|
||||
|
||||
, A_ARGUMENT_TYPE_INDEX
|
||||
/* (unsigned short) Index into A_TYPES for every entry in
|
||||
* A_ARGUMENT_TYPES. This is only created during epilog.
|
||||
*/
|
||||
|
||||
, A_ARGUMENT_INDEX
|
||||
/* (unsigned short) Index of the first argument type of function <n>.
|
||||
* INDEX_START_NONE is used for functions with no type information.
|
||||
|
|
@ -431,7 +435,8 @@ typedef variable_t A_VIRTUAL_VAR_t;
|
|||
typedef char A_LINENUMBERS_t;
|
||||
typedef inherit_t A_INHERITS_t;
|
||||
typedef unsigned short A_UPDATE_INDEX_MAP_t;
|
||||
typedef lpctype_t* A_ARGUMENT_TYPES_t;
|
||||
typedef lpctype_t* A_TYPES_t;
|
||||
typedef unsigned short A_ARGUMENT_TYPE_INDEX_t;
|
||||
typedef unsigned short A_ARGUMENT_INDEX_t;
|
||||
typedef include_t A_INCLUDES_t;
|
||||
typedef struct_def_t A_STRUCT_DEFS_t;
|
||||
|
|
@ -459,10 +464,18 @@ enum e_internal_areas {
|
|||
* therefore not virtual) global variables.
|
||||
*/
|
||||
|
||||
, A_ARGUMENT_TYPES
|
||||
/* (lpctype_t*) Types of the arguments of all functions with
|
||||
* typechecking. The argument types for a specific function
|
||||
* can be found using the ARGUMENT_INDEX. All entries
|
||||
* are counted references.
|
||||
*/
|
||||
|
||||
, A_INLINE_PROGRAM
|
||||
/* (bytecode_t, char): Program and linenumbers saved from the compiled
|
||||
* but not yet inserted inline closures.
|
||||
*/
|
||||
|
||||
, A_INLINE_CLOSURE
|
||||
/* (inline_closure_t): The currently pending inline closures. The lexical
|
||||
* nesting is achieved with the .prev/.next pointers in the
|
||||
|
|
@ -553,6 +566,7 @@ typedef function_t A_FUNCTIONS_t;
|
|||
typedef int A_STRING_NEXT_t;
|
||||
typedef local_variable_t A_LOCAL_VARIABLES_t;
|
||||
typedef global_variable_t A_GLOBAL_VARIABLES_t;
|
||||
typedef lpctype_t* A_ARGUMENT_TYPES_t;
|
||||
typedef bytecode_t A_INLINE_PROGRAM_t;
|
||||
typedef inline_closure_t A_INLINE_CLOSURE_t;
|
||||
typedef struct_member_t A_STRUCT_MEMBERS_t;
|
||||
|
|
@ -632,6 +646,17 @@ static mem_block_t mem_block[NUMAREAS];
|
|||
/* Lookup the start index of the types for function number <n>.
|
||||
*/
|
||||
|
||||
#define PROG_TYPE_COUNT GET_BLOCK_COUNT(A_TYPES)
|
||||
/* Number of lpctype_t* stored so far in A_TYPES.
|
||||
*/
|
||||
|
||||
#define PROG_TYPE(n) GET_BLOCK(A_TYPES)[n]
|
||||
/* Get the lpctype_t* with index <n>.
|
||||
*/
|
||||
|
||||
#define ARGUMENT_TYPE_INDEX(n) GET_BLOCK(A_ARGUMENT_TYPE_INDEX)[n]
|
||||
/* Get the index into A_TYPES at position <n>.
|
||||
*/
|
||||
|
||||
#define ARGTYPE_COUNT GET_BLOCK_COUNT(A_ARGUMENT_TYPES)
|
||||
/* Number of lpctype_t* stored so far in A_ARGUMENT_TYPES.
|
||||
|
|
@ -1307,6 +1332,11 @@ static code_context_t* string_context;
|
|||
* NULL when we are compiling a program.
|
||||
*/
|
||||
|
||||
static int compiling_decltype;
|
||||
/* The level of decltype() operations that are currently compilied.
|
||||
* When this is > 0, code generation can be omitted.
|
||||
*/
|
||||
|
||||
/* A few standard types we often need.
|
||||
* We'll initialize them later (using the type functions, so all pointers
|
||||
* are correctly set) and then put them into a static storage (and set
|
||||
|
|
@ -1358,6 +1388,8 @@ static void use_variable (ident_t* name, enum variable_usage usage);
|
|||
static void warn_variable_usage (string_t* name, enum variable_usage usage, const char* prefix);
|
||||
static Bool add_lvalue_code (lvalue_block_t lv, int instruction);
|
||||
static void insert_pop_value(void);
|
||||
static int get_type_index(lpctype_t *t);
|
||||
static int ins_prog_type(lpctype_t *t);
|
||||
static void add_type_check (lpctype_t *expected, enum type_check_operation op);
|
||||
static int insert_inherited(char *super_name, string_t *real_name, program_t **super_p, function_t *fun_p, int num_arg);
|
||||
/* Returnvalues from insert_inherited(): */
|
||||
|
|
@ -1705,6 +1737,7 @@ add_to_mem_block (int n, void *data, size_t size)
|
|||
sizeof(BLOCK_NAME##_t) * count); \
|
||||
}
|
||||
|
||||
DEFINE_ADD_TO_BLOCK_BY_VALUE(ADD_PROG_TYPE, A_TYPES)
|
||||
DEFINE_ADD_TO_BLOCK_BY_VALUE(ADD_ARGUMENT_TYPE, A_ARGUMENT_TYPES)
|
||||
DEFINE_ADD_TO_BLOCK_BY_VALUE(ADD_ARGUMENT_INDEX, A_ARGUMENT_INDEX)
|
||||
DEFINE_ADD_TO_BLOCK_BY_PTR(ADD_FUNCTION, A_FUNCTIONS)
|
||||
|
|
@ -1826,7 +1859,7 @@ get_lpctype_name_buf (lpctype_t *type, char *buf, size_t bufsize)
|
|||
static char *type_name[] = { "unknown", "int", "string", "void",
|
||||
"mapping", "float", "mixed", "closure",
|
||||
"symbol", "quoted_array", "bytes",
|
||||
"coroutine" };
|
||||
"coroutine", "lpctype" };
|
||||
|
||||
if (bufsize <= 0)
|
||||
return 0;
|
||||
|
|
@ -1894,20 +1927,27 @@ get_lpctype_name_buf (lpctype_t *type, char *buf, size_t bufsize)
|
|||
|
||||
if (type->t_object.program_name)
|
||||
{
|
||||
size_t proglen = mstrsize(type->t_object.program_name);
|
||||
size_t len = proglen + obtypenamelen + 4;
|
||||
if (len < bufsize)
|
||||
if (obtypenamelen + 6 < bufsize)
|
||||
{
|
||||
char *bufptr = buf + obtypenamelen;
|
||||
size_t proglen;
|
||||
|
||||
memcpy(buf, obtypename, obtypenamelen);
|
||||
memcpy(bufptr, " \"/", 3);
|
||||
bufptr += 3;
|
||||
|
||||
memcpy(bufptr, get_txt(type->t_object.program_name), proglen);
|
||||
buf[len-1] = '"';
|
||||
buf[len] = 0;
|
||||
return len;
|
||||
proglen = escape_string(get_txt(type->t_object.program_name), mstrsize(type->t_object.program_name),
|
||||
bufptr, bufsize - obtypenamelen - 4, true);
|
||||
if (!proglen || proglen + obtypenamelen + 5 > bufsize)
|
||||
{
|
||||
buf[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
bufptr += proglen;
|
||||
*bufptr++ = '"';
|
||||
*bufptr = 0;
|
||||
return bufptr - buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -2510,21 +2550,41 @@ binary_op_types_t types_binary_and_assignment[] = {
|
|||
{ &_lpctype_int, &_lpctype_int, &_lpctype_int, NULL , NULL , NULL },
|
||||
{ &_lpctype_string, &_lpctype_string, &_lpctype_string, NULL , NULL , NULL },
|
||||
{ &_lpctype_bytes, &_lpctype_bytes, &_lpctype_bytes, NULL , NULL , NULL },
|
||||
{ &_lpctype_lpctype, &_lpctype_lpctype, &_lpctype_lpctype, NULL , NULL , NULL },
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
/* Operator type table for assignment with the binary or and xor.
|
||||
/* Operator type table for assignment with the binary or.
|
||||
*/
|
||||
binary_op_types_t types_binary_or_assignment[] = {
|
||||
{ &_lpctype_int, &_lpctype_int, &_lpctype_int, NULL , NULL , NULL },
|
||||
{ &_lpctype_any_array, &_lpctype_any_array, NULL, &get_sub_array_type , &get_first_type , &get_common_array_type },
|
||||
{ &_lpctype_lpctype, &_lpctype_lpctype, &_lpctype_lpctype, NULL , NULL , NULL },
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
/* Operator type table for assignment with the binary xor.
|
||||
*/
|
||||
binary_op_types_t types_binary_xor_assignment[] = {
|
||||
{ &_lpctype_int, &_lpctype_int, &_lpctype_int, NULL , NULL , NULL },
|
||||
{ &_lpctype_any_array, &_lpctype_any_array, NULL, &get_sub_array_type , &get_first_type , &get_common_array_type },
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
/* Operator type table for the binary or and xor,
|
||||
* allowing <int>|<int> and <mixed*>|<mixed*>.
|
||||
/* Operator type table for the binary or,
|
||||
* allowing <int>|<int>, <mixed*>|<mixed*> and <lpctype>|<lpctype>
|
||||
*/
|
||||
binary_op_types_t types_binary_or[] = {
|
||||
{ &_lpctype_int, &_lpctype_int, &_lpctype_int, NULL , NULL , NULL },
|
||||
{ &_lpctype_any_array, &_lpctype_any_array, NULL, &get_union_array_type , NULL , NULL },
|
||||
{ &_lpctype_lpctype, &_lpctype_lpctype, &_lpctype_lpctype, NULL , NULL , NULL },
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
/* Operator type table for the binary xor,
|
||||
* allowing <int>|<int> and <mixed*>|<mixed*>.
|
||||
*/
|
||||
binary_op_types_t types_binary_xor[] = {
|
||||
{ &_lpctype_int, &_lpctype_int, &_lpctype_int, NULL , NULL , NULL },
|
||||
{ &_lpctype_any_array, &_lpctype_any_array, NULL, &get_union_array_type , NULL , NULL },
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL }
|
||||
|
|
@ -2540,6 +2600,7 @@ binary_op_types_t types_binary_and[] = {
|
|||
{ &_lpctype_int, &_lpctype_int, &_lpctype_int, NULL , NULL , NULL },
|
||||
{ &_lpctype_string, &_lpctype_string, &_lpctype_string, NULL , NULL , NULL },
|
||||
{ &_lpctype_bytes, &_lpctype_bytes, &_lpctype_bytes, NULL , NULL , NULL },
|
||||
{ &_lpctype_lpctype, &_lpctype_lpctype, &_lpctype_lpctype, NULL , NULL , NULL },
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
|
|
@ -2562,6 +2623,7 @@ binary_op_types_t types_in[] = {
|
|||
{ &_lpctype_int, &_lpctype_bytes, &_lpctype_int, NULL , NULL , NULL },
|
||||
{ &_lpctype_string, &_lpctype_string, &_lpctype_int, NULL , NULL , NULL },
|
||||
{ &_lpctype_bytes, &_lpctype_bytes, &_lpctype_int, NULL , NULL , NULL },
|
||||
{ &_lpctype_lpctype, &_lpctype_lpctype, &_lpctype_int, NULL , NULL , NULL },
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
|
|
@ -3326,10 +3388,12 @@ check_assignment_types (fulltype_t src, lpctype_t *dest)
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static void
|
||||
check_function_call_types (fulltype_t *aargs, int num_aarg, function_t *funp, lpctype_t **dargs)
|
||||
check_function_call_types (fulltype_t *aargs, int num_aarg, function_t *funp, unsigned short *dargs, lpctype_t **types)
|
||||
|
||||
/* Checks the actual function arguments (<aargs> with <num_aarg> entries)
|
||||
* against the function definition <funp> with <dargs> argument type list.
|
||||
* against the function definition <funp> with <dargs> argument type index
|
||||
* list into <types>. If <dargs> is NULL, then a direct lookup into <types>
|
||||
* should be done.
|
||||
*/
|
||||
|
||||
{
|
||||
|
|
@ -3347,21 +3411,25 @@ check_function_call_types (fulltype_t *aargs, int num_aarg, function_t *funp, lp
|
|||
|
||||
for (int argno = 1; argno <= num_darg; argno++)
|
||||
{
|
||||
if (!check_assignment_types(*aargs, *dargs))
|
||||
lpctype_t *expected = dargs ? types[*dargs] : *types;
|
||||
if (!check_assignment_types(*aargs, expected))
|
||||
{
|
||||
yyerrorf("Bad type for argument %d of %s %s",
|
||||
argno,
|
||||
get_txt(funp->name),
|
||||
get_two_lpctypes(*dargs, aargs->t_type));
|
||||
get_two_lpctypes(expected, aargs->t_type));
|
||||
}
|
||||
|
||||
aargs++;
|
||||
dargs++;
|
||||
if (dargs)
|
||||
dargs++;
|
||||
else
|
||||
types++;
|
||||
} /* for (all args) */
|
||||
|
||||
if ((funp->flags & TYPE_MOD_XVARARGS) && !missingargs)
|
||||
{
|
||||
lpctype_t *flat_type = get_flattened_type(*dargs);
|
||||
lpctype_t *flat_type = get_flattened_type(dargs ? types[*dargs] : *types);
|
||||
|
||||
for (int argno = num_darg+1; argno <= num_aarg; argno++)
|
||||
{
|
||||
|
|
@ -7648,7 +7716,7 @@ printf("DEBUG: depth %d, locals: %d/%d, break: %d/%d\n",
|
|||
length = current_inline->length;
|
||||
end = current_inline->end;
|
||||
|
||||
if (!bAbort && !string_context)
|
||||
if (!bAbort && !string_context && !compiling_decltype)
|
||||
{
|
||||
backup_start = INLINE_PROGRAM_SIZE;
|
||||
#ifdef DEBUG_INLINES
|
||||
|
|
@ -7692,7 +7760,7 @@ printf("DEBUG: program size: %"PRIuMPINT"\n", CURRENT_PROGRAM_SIZE);
|
|||
/* Move the linenumber data into the backup storage */
|
||||
start = current_inline->li_start;
|
||||
length = current_inline->li_length;
|
||||
if (!bAbort && !string_context)
|
||||
if (!bAbort && !string_context && !compiling_decltype)
|
||||
{
|
||||
backup_start = INLINE_PROGRAM_SIZE;
|
||||
#ifdef DEBUG_INLINES
|
||||
|
|
@ -7847,7 +7915,7 @@ prepare_inline_closure (lpctype_t *returntype, bool coroutine)
|
|||
fulltype_t funtype;
|
||||
ident_t * ident;
|
||||
|
||||
if (!string_context)
|
||||
if (!string_context && !compiling_decltype)
|
||||
{
|
||||
/* Create the name of the new inline function.
|
||||
* We have to make sure the name is really unique.
|
||||
|
|
@ -7920,7 +7988,7 @@ inline_closure_prototype (int num_args)
|
|||
printf("DEBUG: inline_closure_prototype(%d)\n", num_args);
|
||||
#endif /* DEBUG_INLINES */
|
||||
def_function_argument_check(true);
|
||||
if (!string_context)
|
||||
if (!string_context && !compiling_decltype)
|
||||
def_function_prototype(num_args, MY_TRUE);
|
||||
|
||||
#ifdef DEBUG_INLINES
|
||||
|
|
@ -8012,7 +8080,7 @@ printf("DEBUG: current depth: %d: %d\n", block_depth, block_scope[bloc
|
|||
|
||||
/* Generate the function header and update the ident-table entry.
|
||||
*/
|
||||
if (!string_context)
|
||||
if (!string_context && !compiling_decltype)
|
||||
{
|
||||
int fnum = current_inline->ident->u.global.function;
|
||||
FUNCTION(fnum)->num_opt_arg = current_inline->num_opt_args;
|
||||
|
|
@ -8113,7 +8181,7 @@ printf("DEBUG: -> F_CONTEXT_CLOSURE %d %d %d\n", current_inline->function
|
|||
, num_explicit_context, context->num_locals - num_explicit_context);
|
||||
#endif /* DEBUG_INLINES */
|
||||
|
||||
if (string_context)
|
||||
if (string_context && !compiling_decltype)
|
||||
{
|
||||
/* We are compiling a lambda closure. Therefore we cannot insert
|
||||
* the inline closure into a program and need to make that
|
||||
|
|
@ -8406,6 +8474,12 @@ store_lambda_value (svalue_t *svp)
|
|||
|
||||
assert(hash < 0x100);
|
||||
|
||||
if (compiling_decltype > 0)
|
||||
{
|
||||
free_svalue(svp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lambda_values_table_level*0x100 + hash >= LAMBDA_VALUE_TABLE_SIZE)
|
||||
{
|
||||
int needed_entries = (lambda_values_table_level+1)*0x100 - LAMBDA_VALUE_TABLE_SIZE;
|
||||
|
|
@ -8812,6 +8886,7 @@ get_global_variable_lvalue (ident_t *ident)
|
|||
%token L_CONTINUE
|
||||
%token L_COROUTINE
|
||||
%token L_DEC
|
||||
%token L_DECLTYPE
|
||||
%token L_DEFAULT
|
||||
%token L_DO
|
||||
%token L_DUMMY
|
||||
|
|
@ -8835,6 +8910,7 @@ get_global_variable_lvalue (ident_t *ident)
|
|||
%token L_LAND
|
||||
%token L_LE
|
||||
%token L_LOR
|
||||
%token L_LPCTYPE
|
||||
%token L_LSH
|
||||
%token L_LWOBJECT
|
||||
%token L_MAPPING
|
||||
|
|
@ -10569,6 +10645,7 @@ single_basic_non_void_type:
|
|||
| L_STRING_DECL { $$ = pragma_no_bytes_type ? lpctype_string_bytes : lpctype_string; }
|
||||
| L_CLOSURE_DECL { $$ = lpctype_closure; }
|
||||
| L_COROUTINE { $$ = lpctype_coroutine; }
|
||||
| L_LPCTYPE { $$ = lpctype_lpctype; }
|
||||
| L_SYMBOL_DECL { $$ = lpctype_symbol; }
|
||||
| L_FLOAT_DECL { $$ = lpctype_float; }
|
||||
| L_MAPPING { $$ = lpctype_mapping; }
|
||||
|
|
@ -13053,7 +13130,7 @@ expr0:
|
|||
|
||||
case F_XOR_EQ:
|
||||
op_name = "^=";
|
||||
op_table = types_binary_or_assignment;
|
||||
op_table = types_binary_xor_assignment;
|
||||
%ifdef USE_PYTHON
|
||||
python_left_op = PYTHON_OP_XOR;
|
||||
python_right_op = PYTHON_OP_RXOR;
|
||||
|
|
@ -13431,7 +13508,7 @@ expr0:
|
|||
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
|
||||
| expr0 '^' expr0
|
||||
{
|
||||
lpctype_t *result = check_binary_op_types($1.type.t_type, $3.type.t_type, "^", types_binary_or,
|
||||
lpctype_t *result = check_binary_op_types($1.type.t_type, $3.type.t_type, "^", types_binary_xor,
|
||||
%ifdef USE_PYTHON
|
||||
PYTHON_OP_XOR, PYTHON_OP_RXOR, PYTHON_OP_NONE,
|
||||
%endif
|
||||
|
|
@ -14603,7 +14680,7 @@ expr4:
|
|||
| L_SIMUL_EFUN_CLOSURE
|
||||
{
|
||||
int sefun = $1->u.global.sim_efun;
|
||||
function_t *fun = get_simul_efun_header($1);
|
||||
function_t *fun = get_simul_efun_header($1, NULL);
|
||||
|
||||
if (fun->flags & TYPE_MOD_DEPRECATED)
|
||||
{
|
||||
|
|
@ -14705,15 +14782,15 @@ expr4:
|
|||
}
|
||||
|
||||
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
|
||||
| '(' note_start comma_expr ')' %prec '~'
|
||||
| '(' comma_expr ')' %prec '~'
|
||||
{
|
||||
/* A nested expression */
|
||||
|
||||
$$.type = $3.type;
|
||||
$$.start = $2;
|
||||
$$.type = $2.type;
|
||||
$$.start = $2.start;
|
||||
$$.lvalue = (lvalue_block_t) {0, 0};
|
||||
$$.name = $3.name;
|
||||
$$.needs_use = $3.needs_use;
|
||||
$$.name = $2.name;
|
||||
$$.needs_use = $2.needs_use;
|
||||
}
|
||||
|
||||
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
|
||||
|
|
@ -14923,6 +15000,39 @@ expr4:
|
|||
}
|
||||
|
||||
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
|
||||
| '[' basic_type ']'
|
||||
{
|
||||
$$.type = get_fulltype_flags(lpctype_lpctype, TYPE_MOD_LITERAL);
|
||||
$$.start = CURRENT_PROGRAM_SIZE;
|
||||
$$.lvalue = (lvalue_block_t) {0, 0};
|
||||
$$.name = NULL;
|
||||
$$.needs_use = true;
|
||||
|
||||
ins_prog_type($2);
|
||||
free_lpctype($2);
|
||||
}
|
||||
|
||||
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
|
||||
| L_DECLTYPE '('
|
||||
{
|
||||
$<address>$ = CURRENT_PROGRAM_SIZE;
|
||||
compiling_decltype++;
|
||||
}
|
||||
expr0 ')'
|
||||
{
|
||||
compiling_decltype--;
|
||||
|
||||
$$.type = get_fulltype_flags(lpctype_lpctype, TYPE_MOD_LITERAL);
|
||||
$$.start = CURRENT_PROGRAM_SIZE = $<address>3;
|
||||
$$.lvalue = (lvalue_block_t) {0, 0};
|
||||
$$.name = NULL;
|
||||
$$.needs_use = true;
|
||||
|
||||
ins_prog_type($4.type.t_type);
|
||||
free_fulltype($4.type);
|
||||
}
|
||||
|
||||
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
|
||||
%// The following expressions can be patched to lvalues for use in index_lvalue.
|
||||
| L_IDENTIFIER
|
||||
{
|
||||
|
|
@ -17045,8 +17155,6 @@ function_call:
|
|||
%line
|
||||
int f; /* Function index */
|
||||
int simul_efun;
|
||||
lpctype_t **arg_types = NULL; /* Argtypes from the program */
|
||||
int first_arg; /* Startindex in arg_types[] */
|
||||
Bool ap_needed; /* TRUE if arg frame is needed */
|
||||
Bool has_ellipsis; /* TRUE if '...' was used */
|
||||
|
||||
|
|
@ -17085,7 +17193,8 @@ function_call:
|
|||
|
||||
PREPARE_INSERT(6)
|
||||
|
||||
function_t *funp = get_simul_efun_header($1.real);
|
||||
const program_t *progp;
|
||||
function_t *funp = get_simul_efun_header($1.real, &progp);
|
||||
|
||||
if (!(funp->flags & TYPE_MOD_VARARGS))
|
||||
{
|
||||
|
|
@ -17118,7 +17227,7 @@ function_call:
|
|||
ap_needed = MY_TRUE;
|
||||
|
||||
if (funp->offset.argtypes != NULL)
|
||||
check_function_call_types(get_argument_types_start($4), $4, funp, funp->offset.argtypes);
|
||||
check_function_call_types(get_argument_types_start($4), $4, funp, funp->offset.argtypes, progp->types);
|
||||
|
||||
if (simul_efun == I_GLOBAL_SEFUN_BY_NAME)
|
||||
{
|
||||
|
|
@ -17169,6 +17278,9 @@ function_call:
|
|||
|
||||
function_t *funp;
|
||||
function_t inherited_function;
|
||||
unsigned short *arg_types = NULL; /* arg types from the program */
|
||||
lpctype_t **types = NULL; /* actual types for lookup */
|
||||
int first_arg; /* Start index in arg_types[] */
|
||||
|
||||
ap_needed = MY_TRUE;
|
||||
|
||||
|
|
@ -17216,6 +17328,7 @@ function_call:
|
|||
&& NULL != (arg_types = super_prog->argument_types))
|
||||
{
|
||||
first_arg = super_prog->type_start[ix];
|
||||
types = super_prog->types;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -17242,6 +17355,7 @@ function_call:
|
|||
inherited_function.flags = prog->functions[f];
|
||||
get_function_information(&inherited_function, prog, f);
|
||||
arg_types = prog->argument_types;
|
||||
types = prog->types;
|
||||
if (arg_types != NULL)
|
||||
first_arg = prog->type_start[f];
|
||||
else
|
||||
|
|
@ -17251,7 +17365,8 @@ function_call:
|
|||
else
|
||||
{
|
||||
funp = FUNCTION(f);
|
||||
arg_types = GET_BLOCK(A_ARGUMENT_TYPES);
|
||||
arg_types = NULL;
|
||||
types = GET_BLOCK(A_ARGUMENT_TYPES);
|
||||
first_arg = ARGUMENT_INDEX(f);
|
||||
}
|
||||
}
|
||||
|
|
@ -17312,7 +17427,13 @@ function_call:
|
|||
/* Check the argument types.
|
||||
*/
|
||||
if (exact_types && first_arg != INDEX_START_NONE)
|
||||
check_function_call_types(get_argument_types_start($4), $4, funp, arg_types + first_arg);
|
||||
{
|
||||
if (arg_types)
|
||||
arg_types += first_arg;
|
||||
else
|
||||
types += first_arg;
|
||||
check_function_call_types(get_argument_types_start($4), $4, funp, arg_types, types);
|
||||
}
|
||||
|
||||
} /* if (inherited lfun) */
|
||||
|
||||
|
|
@ -17794,7 +17915,7 @@ function_call:
|
|||
, get_txt(funp->name));
|
||||
|
||||
if (funp->offset.argtypes != NULL)
|
||||
check_function_call_types(get_argument_types_start(num_arg), num_arg, funp, funp->offset.argtypes);
|
||||
check_function_call_types(get_argument_types_start(num_arg), num_arg, funp, funp->offset.argtypes, simul_efun_table[sefun].program->types);
|
||||
|
||||
if (!(funp->flags & (TYPE_MOD_VARARGS|TYPE_MOD_XVARARGS))
|
||||
&& !has_ellipsis)
|
||||
|
|
@ -18007,7 +18128,7 @@ function_name:
|
|||
if ( !strcmp($1, "efun")
|
||||
&& fun->type == I_TYPE_GLOBAL
|
||||
&& fun->u.global.sim_efun != I_GLOBAL_SEFUN_OTHER
|
||||
&& (get_simul_efun_header(fun)->flags & TYPE_MOD_NO_MASK)
|
||||
&& (get_simul_efun_header(fun, NULL)->flags & TYPE_MOD_NO_MASK)
|
||||
&& master_ob
|
||||
&& (!EVALUATION_TOO_LONG())
|
||||
)
|
||||
|
|
@ -18707,9 +18828,60 @@ insert_pop_value (void)
|
|||
last_expression = -1;
|
||||
} /* insert_pop_value() */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static int
|
||||
get_type_index (lpctype_t *t)
|
||||
|
||||
/* Add <t> to the programs type list.
|
||||
*/
|
||||
|
||||
{
|
||||
int idx;
|
||||
for (idx = 0; idx < PROG_TYPE_COUNT; idx++)
|
||||
if (PROG_TYPE(idx) == t)
|
||||
break;
|
||||
|
||||
if (idx == PROG_TYPE_COUNT)
|
||||
{
|
||||
if (idx > (long)USHRT_MAX)
|
||||
return -1;
|
||||
|
||||
ADD_PROG_TYPE(ref_lpctype(t));
|
||||
}
|
||||
|
||||
return idx;
|
||||
} /* get_type_index() */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static int
|
||||
ins_prog_type (lpctype_t *t)
|
||||
|
||||
/* Add the type <t> to the program types and insert codes to put it
|
||||
* on the stack into the current bytecode. The references are not adopted.
|
||||
* Returns the number of bytes written to the bytecode.
|
||||
*/
|
||||
{
|
||||
if (string_context)
|
||||
{
|
||||
svalue_t sv = svalue_lpctype(ref_lpctype(t));
|
||||
return ins_lambda_value(&sv);
|
||||
}
|
||||
else
|
||||
{
|
||||
PREPARE_INSERT(3);
|
||||
|
||||
add_f_code(F_PUSH_TYPE);
|
||||
add_short(get_type_index(t));
|
||||
|
||||
CURRENT_PROGRAM_SIZE += 3;
|
||||
return 3;
|
||||
}
|
||||
} /* ins_prog_type() */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static void
|
||||
add_type_check (lpctype_t *expected, enum type_check_operation op)
|
||||
|
||||
/* Adds an instruction for type checking the topmost value
|
||||
* on the stack against <expected>.
|
||||
*/
|
||||
|
|
@ -18730,25 +18902,7 @@ add_type_check (lpctype_t *expected, enum type_check_operation op)
|
|||
return;
|
||||
|
||||
/* Now get an index for the type in our type list. */
|
||||
for (idx = 0; idx < ARGTYPE_COUNT; idx++)
|
||||
if (ARGUMENT_TYPE(idx) == expected)
|
||||
break;
|
||||
|
||||
if (idx == ARGTYPE_COUNT)
|
||||
{
|
||||
/* Check that there is space in the argument type list. */
|
||||
if (arg_types_exhausted)
|
||||
return;
|
||||
|
||||
if (idx > (long)USHRT_MAX)
|
||||
{
|
||||
arg_types_exhausted = true;
|
||||
yywarnf("Type buffer exhausted, cannot store and verify argument types.");
|
||||
return;
|
||||
}
|
||||
|
||||
ADD_ARGUMENT_TYPE(ref_lpctype(expected));
|
||||
}
|
||||
idx = get_type_index(expected);
|
||||
|
||||
ins_f_code(F_TYPE_CHECK);
|
||||
ins_byte(op);
|
||||
|
|
@ -19676,7 +19830,8 @@ inherit_functions (program_t *from, uint32 inheritidx)
|
|||
A_ARGUMENT_INDEX_t argindex = INDEX_START_NONE; /* Presume not available. */
|
||||
if (from->type_start != 0)
|
||||
{
|
||||
if (from->type_start[i] != INDEX_START_NONE)
|
||||
unsigned short arg_type_idx = from->type_start[i];
|
||||
if (arg_type_idx != INDEX_START_NONE)
|
||||
{
|
||||
/* They are available for function number 'i'. Copy types of
|
||||
* all arguments, and remember where they started.
|
||||
|
|
@ -19684,18 +19839,9 @@ inherit_functions (program_t *from, uint32 inheritidx)
|
|||
argindex = ARGTYPE_COUNT;
|
||||
if (fun_p->num_arg)
|
||||
{
|
||||
int ix;
|
||||
|
||||
ix = ARGTYPE_COUNT;
|
||||
|
||||
add_to_mem_block(
|
||||
A_ARGUMENT_TYPES,
|
||||
&from->argument_types[from->type_start[i]],
|
||||
(sizeof (A_ARGUMENT_TYPES_t)) * fun_p->num_arg
|
||||
);
|
||||
|
||||
for ( ; (size_t)ix < ARGTYPE_COUNT; ix++)
|
||||
ref_lpctype(ARGUMENT_TYPE(ix));
|
||||
reserve_mem_block(A_ARGUMENT_TYPES, sizeof(A_ARGUMENT_TYPES_t) * fun_p->num_arg);
|
||||
for (int pos = 0; pos < fun_p->num_arg; pos++)
|
||||
ADD_ARGUMENT_TYPE(ref_lpctype(from->types[from->argument_types[arg_type_idx+pos]]));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -21649,6 +21795,7 @@ prolog (const char * fname, Bool isMasterObj)
|
|||
string_context = NULL;
|
||||
lambda_values_table_level = 0;
|
||||
lambda_values_offset = 0;
|
||||
compiling_decltype = 0;
|
||||
|
||||
free_all_local_names(); /* In case of earlier error */
|
||||
|
||||
|
|
@ -21834,6 +21981,9 @@ epilog_free_all (void)
|
|||
);
|
||||
|
||||
/* Free the type information */
|
||||
for (size_t i = 0; i < PROG_TYPE_COUNT; i++)
|
||||
free_lpctype(PROG_TYPE(i));
|
||||
|
||||
for (size_t i = 0; i < ARGTYPE_COUNT; i++)
|
||||
free_lpctype(ARGUMENT_TYPE(i));
|
||||
|
||||
|
|
@ -22255,6 +22405,22 @@ epilog (void)
|
|||
|
||||
} /* if (parse successful) */
|
||||
|
||||
/* Save argument types into A_TYPES. */
|
||||
if (pragma_save_types)
|
||||
{
|
||||
extend_mem_block(A_ARGUMENT_TYPE_INDEX, ARGTYPE_COUNT * sizeof(A_ARGUMENT_TYPE_INDEX_t));
|
||||
for (i = 0; i < ARGTYPE_COUNT; i++)
|
||||
ARGUMENT_TYPE_INDEX(i) = get_type_index(ARGUMENT_TYPE(i));
|
||||
}
|
||||
else
|
||||
mem_block[A_ARGUMENT_INDEX].current_size = 0;
|
||||
|
||||
if (PROG_TYPE_COUNT > USHRT_MAX)
|
||||
yyerror("Too many types");
|
||||
for (i = 0; (size_t)i < ARGTYPE_COUNT; i++)
|
||||
free_lpctype(ARGUMENT_TYPE(i));
|
||||
mem_block[A_ARGUMENT_TYPES].current_size = 0;
|
||||
|
||||
/* Remove the concrete struct definition from the lpctype object
|
||||
* and free the reference we took.
|
||||
*/
|
||||
|
|
@ -22318,13 +22484,6 @@ epilog (void)
|
|||
|
||||
size = align(sizeof (program_t));
|
||||
|
||||
if (!pragma_save_types)
|
||||
{
|
||||
for (i = 0; (size_t)i < ARGTYPE_COUNT; i++)
|
||||
free_lpctype(ARGUMENT_TYPE(i));
|
||||
mem_block[A_ARGUMENT_TYPES].current_size = 0;
|
||||
mem_block[A_ARGUMENT_INDEX].current_size = 0;
|
||||
}
|
||||
for (i = 0; i< NUMPAREAS; i++)
|
||||
{
|
||||
if (i != A_LINENUMBERS)
|
||||
|
|
@ -22510,20 +22669,34 @@ epilog (void)
|
|||
prog->includes = NULL;
|
||||
p += align(mem_block[A_INCLUDES].current_size);
|
||||
|
||||
/* Add the argument type information
|
||||
/* Add the type information
|
||||
*/
|
||||
if (pragma_save_types)
|
||||
prog->num_types = PROG_TYPE_COUNT;
|
||||
if (prog->num_types)
|
||||
{
|
||||
if (mem_block[A_ARGUMENT_TYPES].current_size)
|
||||
memcpy(p, mem_block[A_ARGUMENT_TYPES].block,
|
||||
mem_block[A_ARGUMENT_TYPES].current_size);
|
||||
prog->argument_types = (A_ARGUMENT_TYPES_t *)p;
|
||||
prog->num_argument_types = ARGTYPE_COUNT;
|
||||
p += align(mem_block[A_ARGUMENT_TYPES].current_size);
|
||||
memcpy(p, mem_block[A_TYPES].block
|
||||
, mem_block[A_TYPES].current_size);
|
||||
prog->types = (A_TYPES_t *)p;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(GET_BLOCK_COUNT(A_ARGUMENT_TYPE_INDEX) == 0);
|
||||
prog->types = NULL;
|
||||
}
|
||||
p += align(mem_block[A_TYPES].current_size);
|
||||
|
||||
/* Add argument type information.
|
||||
*/
|
||||
if (GET_BLOCK_COUNT(A_ARGUMENT_TYPE_INDEX))
|
||||
{
|
||||
memcpy(p, mem_block[A_ARGUMENT_TYPE_INDEX].block
|
||||
, mem_block[A_ARGUMENT_TYPE_INDEX].current_size);
|
||||
prog->argument_types = (A_ARGUMENT_TYPE_INDEX_t *)p;
|
||||
p += align(mem_block[A_ARGUMENT_TYPE_INDEX].current_size);
|
||||
|
||||
if (mem_block[A_ARGUMENT_INDEX].current_size)
|
||||
memcpy(p, mem_block[A_ARGUMENT_INDEX].block,
|
||||
mem_block[A_ARGUMENT_INDEX].current_size);
|
||||
memcpy(p, mem_block[A_ARGUMENT_INDEX].block
|
||||
, mem_block[A_ARGUMENT_INDEX].current_size);
|
||||
prog->type_start = (A_ARGUMENT_INDEX_t *)p;
|
||||
p += align(mem_block[A_ARGUMENT_INDEX].current_size);
|
||||
}
|
||||
|
|
@ -22531,10 +22704,6 @@ epilog (void)
|
|||
{
|
||||
prog->argument_types = NULL;
|
||||
prog->type_start = NULL;
|
||||
prog->num_argument_types = 0;
|
||||
|
||||
for (i = 0; (size_t)i < ARGTYPE_COUNT; i++)
|
||||
free_lpctype(ARGUMENT_TYPE(i));
|
||||
}
|
||||
|
||||
/* Add the lightweight object call cache.
|
||||
|
|
|
|||
|
|
@ -490,13 +490,26 @@ query_simul_efun_file_name(void)
|
|||
return simul_efun_file_name;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
program_t *
|
||||
get_simul_efun_program ()
|
||||
|
||||
/* Return the program of the primary simul_efun object.
|
||||
*/
|
||||
|
||||
{
|
||||
return simul_efun_program;
|
||||
} /* get_simul_efun_program() */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
function_t *
|
||||
get_simul_efun_header (ident_t* name)
|
||||
get_simul_efun_header (ident_t* name, const program_t **progp)
|
||||
|
||||
/* Return the function header for the simul-efun <name>.
|
||||
* <name> must be a valid simul-efun identifier (i.e. there
|
||||
* must be a simul-efun object with such a function).
|
||||
* If <progp> is not NULL, the corresponding program pointer
|
||||
* will be returned there.
|
||||
*/
|
||||
|
||||
{
|
||||
|
|
@ -511,10 +524,12 @@ get_simul_efun_header (ident_t* name)
|
|||
if (fx == -1)
|
||||
fatal("Can't find simul_efun %s", get_txt(name->name));
|
||||
|
||||
return get_function_header(simul_efun_object->prog, fx);
|
||||
return get_function_header_extended(simul_efun_object->prog, fx, progp, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (progp)
|
||||
*progp = simul_efun_table[name->u.global.sim_efun].program;
|
||||
return &simul_efun_table[name->u.global.sim_efun].function;
|
||||
}
|
||||
} /* get_simul_efun_header() */
|
||||
|
|
|
|||
|
|
@ -49,7 +49,8 @@ extern ident_t *all_simul_efuns;
|
|||
extern void invalidate_simul_efuns (void);
|
||||
extern Bool assert_simul_efun_object(void);
|
||||
extern string_t *query_simul_efun_file_name(void);
|
||||
extern function_t *get_simul_efun_header(ident_t* name) __attribute__((nonnull));
|
||||
extern program_t *get_simul_efun_program();
|
||||
extern function_t *get_simul_efun_header(ident_t* name, const program_t **progp) __attribute__((nonnull(1)));
|
||||
extern void sefun_driver_info (svalue_t *svp, int value) __attribute__((nonnull(1)));
|
||||
|
||||
#ifdef GC_SUPPORT
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@
|
|||
#include "mstrings.h"
|
||||
#include "object.h"
|
||||
#include "pkg-python.h"
|
||||
#include "prolang.h"
|
||||
#include "ptrtable.h"
|
||||
#include "random.h"
|
||||
#include "sent.h"
|
||||
|
|
@ -1195,6 +1196,15 @@ svalue_to_string ( fmt_state_t *st
|
|||
break;
|
||||
}
|
||||
|
||||
case T_LPCTYPE:
|
||||
{
|
||||
stradd(st, &str, "[");
|
||||
stradd(st, &str, get_lpctype_name(obj->u.lpctype));
|
||||
stradd(st, &str, "]");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef USE_PYTHON
|
||||
case T_PYTHON:
|
||||
{
|
||||
|
|
|
|||
155
src/strfuns.c
155
src/strfuns.c
|
|
@ -493,6 +493,161 @@ get_escaped_character (p_int c, char* buf, size_t buflen)
|
|||
|
||||
return 0;
|
||||
} /* get_escaped_character() */
|
||||
/*--------------------------------------------------------------------*/
|
||||
bool
|
||||
string_needs_escape (const char * text, size_t len, bool allow_unicode)
|
||||
|
||||
/* Checks whether <text> (of size <len>) contains characters that would
|
||||
* need escaping. If <allow_unicode> is false, all characters > 0x7f
|
||||
* will need escape. Returns the number of additional bytes needed.
|
||||
*/
|
||||
|
||||
{
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
char c = text[i];
|
||||
if (c < 0x20)
|
||||
return true;
|
||||
if (c > 0x7f)
|
||||
{
|
||||
if (allow_unicode)
|
||||
continue;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
if (isescaped(c))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} /* string_needs_escape() */
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
size_t
|
||||
escape_string (const char * text, size_t len, char * buf, size_t buflen, bool allow_unicode)
|
||||
|
||||
/* Escapes all characters of <text> (of size <len>) and puts the result
|
||||
* into <buf> (of size <buflen>)). If the target buffer is not big enough,
|
||||
* this function will return 0, otherwise returns the number of bytes
|
||||
* written. No final zero byte is written.
|
||||
*/
|
||||
|
||||
{
|
||||
if (len > buflen)
|
||||
return 0;
|
||||
|
||||
if (!string_needs_escape(text, len, allow_unicode))
|
||||
{
|
||||
memcpy(buf, text, len);
|
||||
return len;
|
||||
}
|
||||
else
|
||||
{
|
||||
char * dest = buf;
|
||||
for (size_t i = 0; i < len; )
|
||||
{
|
||||
p_int c;
|
||||
size_t clen = utf8_to_unicode(text + i, len - i, &c);
|
||||
if (!clen)
|
||||
{
|
||||
c = *(unsigned char*)text;
|
||||
i++;
|
||||
}
|
||||
else
|
||||
i += clen;
|
||||
|
||||
if (!allow_unicode || c < 0x80)
|
||||
{
|
||||
int s = get_escaped_character(c, dest, buf + buflen - dest);
|
||||
if (!s)
|
||||
return 0;
|
||||
dest += s;
|
||||
}
|
||||
else if (dest + 4 <= buf + buflen)
|
||||
dest += unicode_to_utf8(c, dest);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
return dest - buf;
|
||||
}
|
||||
} /* escape_string() */
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
size_t
|
||||
unescape_string (const char * text, size_t len, char * buf, size_t buflen)
|
||||
|
||||
/* Copies <text> (of size <len>) into <buf> (of size <buflen>) and
|
||||
* thereby unescaping any escaped characters. If the target buffer is
|
||||
* not big enough, this function will return 0, otherwise returns the
|
||||
* number of bytes written (or 0 for any other error).
|
||||
*/
|
||||
|
||||
{
|
||||
char *dest = buf, *end = buf + buflen;
|
||||
for (int i = 0; i < len ; i++)
|
||||
{
|
||||
if (dest == end)
|
||||
return 0;
|
||||
|
||||
if (text[i] == '\\')
|
||||
{
|
||||
switch (text[++i])
|
||||
{
|
||||
case '0': *dest++ = '\0'; break;
|
||||
case 'a': *dest++ = '\007'; break;
|
||||
case 'b': *dest++ = '\b' ; break;
|
||||
case 'e': *dest++= '\033'; break;
|
||||
case 't': *dest++ = '\t' ; break;
|
||||
case 'n': *dest++ = '\n' ; break;
|
||||
case 'r': *dest++ = '\r' ; break;
|
||||
case 'u':
|
||||
case 'U':
|
||||
case 'x':
|
||||
{
|
||||
int num_digits = (text[i] == 'x') ? 2 : (text[i] == 'u') ? 4 : 8;
|
||||
int check_digits = (text[i] != 'x');
|
||||
int value = 0;
|
||||
|
||||
while (num_digits > 0)
|
||||
{
|
||||
int c = text[i+1];
|
||||
if (c >= '0' && c <= '9')
|
||||
value = (value<<4) + (c - '0');
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
value = (value<<4) + (c - 'a');
|
||||
else
|
||||
break;
|
||||
|
||||
i++;
|
||||
num_digits--;
|
||||
}
|
||||
|
||||
/* All digits for u/U, at least one digit for x. */
|
||||
if (check_digits ? (num_digits > 0) : (num_digits == 2))
|
||||
return 0;
|
||||
|
||||
/* Unicode range. */
|
||||
if (value >= 0x110000)
|
||||
return 0;
|
||||
|
||||
if (dest + 4 > end)
|
||||
return 0;
|
||||
|
||||
dest += unicode_to_utf8(value, dest);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
*dest++ = text[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
*dest++ = text[i];
|
||||
}
|
||||
|
||||
return dest - buf;
|
||||
} /* unescape_string() */
|
||||
|
||||
/*====================================================================*/
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ extern void strbuf_copy (strbuf_t *buf, char *cbuf);
|
|||
extern string_t * trim_all_spaces (const string_t * txt);
|
||||
extern char * xstrncpy(char * dest, const char * src, size_t num);
|
||||
extern size_t get_escaped_character(p_int c, char* buf, size_t buflen);
|
||||
extern bool string_needs_escape(const char * text, size_t len, bool allow_unicode);
|
||||
extern size_t escape_string(const char * text, size_t len, char * buf, size_t buflen, bool allow_unicode);
|
||||
extern size_t unescape_string(const char * text, size_t len, char * buf, size_t buflen);
|
||||
|
||||
extern size_t parse_input_encoding(string_t* encoding, bool* ignore, bool* replace);
|
||||
|
||||
|
|
|
|||
36
src/svalue.h
36
src/svalue.h
|
|
@ -70,6 +70,9 @@ union u {
|
|||
coroutine_t *coroutine;
|
||||
/* T_COROUTINE: pointer to the coroutine structure.
|
||||
*/
|
||||
lpctype_t *lpctype;
|
||||
/* T_LPCTYPE: pointer to the type object.
|
||||
*/
|
||||
#ifdef FLOAT_FORMAT_2
|
||||
double float_number;
|
||||
/* T_FLOAT: the double value for this float in FLOAT_FORMAT_2.
|
||||
|
|
@ -223,33 +226,34 @@ struct svalue_s
|
|||
#ifdef USE_PYTHON
|
||||
#define T_PYTHON 0xf /* a Python object */
|
||||
#endif
|
||||
#define T_LPCTYPE 0x10
|
||||
|
||||
#define T_CALLBACK 0x10
|
||||
#define T_CALLBACK 0x11
|
||||
/* A callback structure referenced from the stack to allow
|
||||
* proper cleanup during error recoveries. The interpreter
|
||||
* knows how to free it, but that's all.
|
||||
*/
|
||||
|
||||
#define T_ERROR_HANDLER 0x11
|
||||
#define T_ERROR_HANDLER 0x12
|
||||
/* Not an actual value, this is used internally for cleanup
|
||||
* operations. See the description of the error_handler() member
|
||||
* for details.
|
||||
*/
|
||||
|
||||
#define T_BREAK_ADDR 0x12
|
||||
#define T_BREAK_ADDR 0x13
|
||||
/* Not an actual type, it's used internally for saving
|
||||
* the address where break statements within switch statements
|
||||
* should branch to.
|
||||
*/
|
||||
|
||||
#define T_ARG_FRAME 0x13
|
||||
#define T_ARG_FRAME 0x14
|
||||
/* Not an actual type, it's used internally for saving
|
||||
* the surrounding argument frame pointer, when a new
|
||||
* argument frame is created.
|
||||
*/
|
||||
|
||||
#undef T_NULL /* There is some T_NULL definition in system headers. */
|
||||
#define T_NULL 0x14
|
||||
#define T_NULL 0x15
|
||||
/* Not an actual type, this is used in the efun_lpc_types[] table
|
||||
* to encode the acceptance of '0' instead of the real datatype.
|
||||
*/
|
||||
|
|
@ -434,6 +438,7 @@ struct svalue_s
|
|||
#define TF_BYTES (1 << T_BYTES)
|
||||
#define TF_LWOBJECT (1 << T_LWOBJECT)
|
||||
#define TF_COROUTINE (1 << T_COROUTINE)
|
||||
#define TF_LPCTYPE (1 << T_LPCTYPE)
|
||||
|
||||
#define TF_ANYTYPE (~0)
|
||||
/* This is used in the efun_lpc_types[]
|
||||
|
|
@ -650,6 +655,15 @@ static INLINE svalue_t svalue_coroutine(coroutine_t * const cr)
|
|||
return (svalue_t){ T_COROUTINE, {}, {.coroutine = cr } };
|
||||
}
|
||||
|
||||
static INLINE svalue_t svalue_lpctype(lpctype_t * const t)
|
||||
__attribute__((nonnull(1))) __attribute__((const));
|
||||
static INLINE svalue_t svalue_lpctype(lpctype_t * const t)
|
||||
/* Return an svalue for the lpctype <t>.
|
||||
*/
|
||||
{
|
||||
return (svalue_t){ T_LPCTYPE, {}, {.lpctype = t } };
|
||||
}
|
||||
|
||||
static INLINE svalue_t svalue_callback(callback_t * const cb)
|
||||
__attribute__((nonnull(1))) __attribute__((const));
|
||||
static INLINE svalue_t svalue_callback(callback_t * const cb)
|
||||
|
|
@ -759,6 +773,15 @@ static INLINE void put_coroutine(svalue_t * const dest, coroutine_t * const cr)
|
|||
*dest = svalue_coroutine(cr);
|
||||
}
|
||||
|
||||
static INLINE void put_lpctype(svalue_t * const dest, lpctype_t * const t)
|
||||
__attribute__((nonnull(1,2)));
|
||||
static INLINE void put_lpctype(svalue_t * const dest, lpctype_t * const t)
|
||||
/* Put the lpctype <t> into <dest>, which is considered empty.
|
||||
*/
|
||||
{
|
||||
*dest = svalue_lpctype(t);
|
||||
}
|
||||
|
||||
static INLINE void put_callback(svalue_t * const dest, callback_t * const cb)
|
||||
__attribute__((nonnull(1,2)));
|
||||
static INLINE void put_callback(svalue_t * const dest, callback_t * const cb)
|
||||
|
|
@ -819,6 +842,9 @@ static INLINE void put_callback(svalue_t * const dest, callback_t * const cb)
|
|||
#define push_coroutine(sp,val) \
|
||||
( (sp)++, put_coroutine(sp,val) )
|
||||
|
||||
#define push_lpctype(sp,val) \
|
||||
( (sp)++, put_lpctype(sp,val) )
|
||||
|
||||
#define push_callback(sp,val) \
|
||||
( (sp)++, put_callback(sp,val) )
|
||||
|
||||
|
|
|
|||
11
src/swap.c
11
src/swap.c
|
|
@ -335,9 +335,10 @@ locate_out (program_t *prog)
|
|||
prog->includes = MAKEOFFSET(include_t *, includes);
|
||||
if (prog->lwo_call_cache)
|
||||
prog->lwo_call_cache = MAKEOFFSET(call_cache_t *, lwo_call_cache);
|
||||
prog->types = MAKEOFFSET(lpctype_t **, types);
|
||||
if (prog->type_start)
|
||||
{
|
||||
prog->argument_types = MAKEOFFSET(lpctype_t **, argument_types);
|
||||
prog->argument_types = MAKEOFFSET(unsigned short *, argument_types);
|
||||
prog->type_start = MAKEOFFSET(unsigned short *, type_start);
|
||||
}
|
||||
return MY_TRUE;
|
||||
|
|
@ -383,9 +384,10 @@ locate_in (program_t *prog)
|
|||
prog->includes = MAKEPTR(include_t*, includes);
|
||||
if (prog->lwo_call_cache)
|
||||
prog->lwo_call_cache = MAKEPTR(call_cache_t *, lwo_call_cache);
|
||||
prog->types = MAKEPTR(lpctype_t **, types);
|
||||
if (prog->type_start)
|
||||
{
|
||||
prog->argument_types = MAKEPTR(lpctype_t **, argument_types);
|
||||
prog->argument_types = MAKEPTR(unsigned short *, argument_types);
|
||||
prog->type_start = MAKEPTR(unsigned short *, type_start);
|
||||
}
|
||||
|
||||
|
|
@ -1077,6 +1079,7 @@ swap_svalues (svalue_t *svp, mp_int num, varblock_t *block)
|
|||
case T_LWOBJECT:
|
||||
case T_CLOSURE:
|
||||
case T_COROUTINE:
|
||||
case T_LPCTYPE:
|
||||
case T_LVALUE:
|
||||
#ifdef USE_PYTHON
|
||||
case T_PYTHON:
|
||||
|
|
@ -1240,6 +1243,7 @@ check_swapped_values (mp_int num, unsigned char * p)
|
|||
case T_LWOBJECT:
|
||||
case T_CLOSURE:
|
||||
case T_COROUTINE:
|
||||
case T_LPCTYPE:
|
||||
case T_LVALUE:
|
||||
#ifdef USE_PYTHON
|
||||
case T_PYTHON:
|
||||
|
|
@ -1407,6 +1411,7 @@ dump_swapped_values (mp_int num, unsigned char * p, int indent)
|
|||
case T_LWOBJECT:
|
||||
case T_CLOSURE:
|
||||
case T_COROUTINE:
|
||||
case T_LPCTYPE:
|
||||
case T_LVALUE:
|
||||
#ifdef USE_PYTHON
|
||||
case T_PYTHON:
|
||||
|
|
@ -1599,6 +1604,7 @@ free_swapped_svalues (svalue_t *svp, mp_int num, unsigned char *p)
|
|||
case T_MAPPING:
|
||||
case T_NUMBER:
|
||||
case T_FLOAT:
|
||||
case T_LPCTYPE:
|
||||
case T_LVALUE:
|
||||
#ifdef USE_PYTHON
|
||||
case T_PYTHON:
|
||||
|
|
@ -2116,6 +2122,7 @@ read_unswapped_svalues (svalue_t *svp, mp_int num, unsigned char *p)
|
|||
case T_LWOBJECT:
|
||||
case T_CLOSURE:
|
||||
case T_COROUTINE:
|
||||
case T_LPCTYPE:
|
||||
case T_LVALUE:
|
||||
#ifdef USE_PYTHON
|
||||
case T_PYTHON:
|
||||
|
|
|
|||
299
src/types.c
299
src/types.c
|
|
@ -5,17 +5,22 @@
|
|||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <wctype.h>
|
||||
|
||||
#include "gcollect.h"
|
||||
#include "lex.h"
|
||||
#include "lwobject.h"
|
||||
#include "main.h"
|
||||
#include "object.h"
|
||||
#include "pkg-python.h"
|
||||
#include "types.h"
|
||||
#include "simul_efun.h"
|
||||
#include "simulate.h"
|
||||
#include "structs.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
#include "i-current_object.h"
|
||||
|
||||
#include "../mudlib/sys/driver_info.h"
|
||||
|
||||
/* Base types are statically allocated. */
|
||||
|
|
@ -27,6 +32,7 @@ lpctype_t _lpctype_mixed = { 0, { TCLASS_PRIMARY, true }, {TYPE_ANY},
|
|||
lpctype_t _lpctype_closure = { 0, { TCLASS_PRIMARY, true }, {TYPE_CLOSURE}, NULL, NULL };
|
||||
lpctype_t _lpctype_symbol = { 0, { TCLASS_PRIMARY, true }, {TYPE_SYMBOL}, NULL, NULL };
|
||||
lpctype_t _lpctype_coroutine = { 0, { TCLASS_PRIMARY, true }, {TYPE_COROUTINE}, NULL, NULL };
|
||||
lpctype_t _lpctype_lpctype = { 0, { TCLASS_PRIMARY, true }, {TYPE_LPCTYPE}, NULL, NULL };
|
||||
lpctype_t _lpctype_quoted_array = { 0, { TCLASS_PRIMARY, true }, {TYPE_QUOTED_ARRAY}, NULL, NULL };
|
||||
lpctype_t _lpctype_void = { 0, { TCLASS_PRIMARY, true }, {TYPE_VOID}, NULL, NULL };
|
||||
lpctype_t _lpctype_bytes = { 0, { TCLASS_PRIMARY, true }, {TYPE_BYTES}, NULL, NULL };
|
||||
|
|
@ -44,6 +50,7 @@ lpctype_t *lpctype_mixed = &_lpctype_mixed;
|
|||
lpctype_t *lpctype_closure = &_lpctype_closure;
|
||||
lpctype_t *lpctype_symbol = &_lpctype_symbol;
|
||||
lpctype_t *lpctype_coroutine = &_lpctype_coroutine;
|
||||
lpctype_t *lpctype_lpctype = &_lpctype_lpctype;
|
||||
lpctype_t *lpctype_quoted_array = &_lpctype_quoted_array;
|
||||
lpctype_t *lpctype_any_struct = &_lpctype_any_struct;
|
||||
lpctype_t *lpctype_any_object = &_lpctype_any_object;
|
||||
|
|
@ -514,9 +521,9 @@ get_union_type (lpctype_t *head, lpctype_t* member)
|
|||
lpctype_t *insert = head;
|
||||
lpctype_t *result, *next_member;
|
||||
|
||||
if (member == NULL)
|
||||
if (member == NULL || member == lpctype_void)
|
||||
return ref_lpctype(head);
|
||||
if (head == NULL)
|
||||
if (head == NULL || head == lpctype_void)
|
||||
return ref_lpctype(member);
|
||||
if (head == lpctype_unknown || member == lpctype_unknown)
|
||||
return lpctype_unknown;
|
||||
|
|
@ -1150,6 +1157,292 @@ is_compatible_lwobject (lwobject_t* lwob, lpctype_t *t)
|
|||
return is_compatible_program(lwob->prog, OBJECT_LIGHTWEIGHT, t);
|
||||
} /* is_compatible_lwobject() */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
struct lpctypename_s
|
||||
{
|
||||
const char *name;
|
||||
lpctype_t *type;
|
||||
};
|
||||
|
||||
static struct lpctypename_s lpctypenames[] = {
|
||||
{ "status", &_lpctype_int },
|
||||
{ "int", &_lpctype_int },
|
||||
{ "string", &_lpctype_string },
|
||||
{ "void", &_lpctype_void },
|
||||
{ "mapping", &_lpctype_mapping },
|
||||
{ "float", &_lpctype_float },
|
||||
{ "mixed", &_lpctype_mixed },
|
||||
{ "closure", &_lpctype_closure },
|
||||
{ "symbol", &_lpctype_symbol },
|
||||
{ "quoted_array", &_lpctype_quoted_array },
|
||||
{ "bytes", &_lpctype_bytes },
|
||||
{ "coroutine", &_lpctype_coroutine },
|
||||
{ "lpctype", &_lpctype_lpctype },
|
||||
{ "struct", &_lpctype_any_struct },
|
||||
{ "object", &_lpctype_any_object },
|
||||
{ "lwobject", &_lpctype_any_lwobject },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static const char*
|
||||
skip_whitespace(const char* str, const char* end)
|
||||
|
||||
/* Skip any whitespace characters and return a pointer to the first
|
||||
* non-whitespace character.
|
||||
*/
|
||||
|
||||
{
|
||||
while (str != end)
|
||||
{
|
||||
p_int c;
|
||||
size_t clen = utf8_to_unicode(str, end - str, &c);
|
||||
|
||||
if (!clen || !iswspace(c))
|
||||
return str;
|
||||
str += clen;
|
||||
}
|
||||
return end;
|
||||
} /* skip_whitespace() */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static const char*
|
||||
skip_alunum(const char* str, const char* end)
|
||||
|
||||
/* Skip any alpha-numeric characters (incl. underscore) and return a pointer
|
||||
* to the first non-matching character.
|
||||
*/
|
||||
|
||||
{
|
||||
while (str != end)
|
||||
{
|
||||
p_int c;
|
||||
size_t clen = utf8_to_unicode(str, end - str, &c);
|
||||
|
||||
if (!clen || !(c < 128 ? isalunum(c) : iswalnum((wint_t)c)))
|
||||
return str;
|
||||
str += clen;
|
||||
}
|
||||
return end;
|
||||
} /* skip_alunum() */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
lpctype_t *
|
||||
parse_lpctype (const char** start, const char* end)
|
||||
|
||||
/* Parse the string starting at <*start> as a type, not going beyond <end>.
|
||||
* Return the resulting type (or NULL upon an error). On success <*start>
|
||||
* will then point to the next unprocessed character.
|
||||
*/
|
||||
|
||||
{
|
||||
const char* str = *start;
|
||||
lpctype_t *result = NULL;
|
||||
|
||||
while (true)
|
||||
{
|
||||
lpctype_t *part;
|
||||
p_int c;
|
||||
size_t clen = utf8_to_unicode(str, end - str, &c);
|
||||
if (!clen)
|
||||
break;
|
||||
|
||||
if (c == '<')
|
||||
{
|
||||
str += clen;
|
||||
part = parse_lpctype(&str, end);
|
||||
if (part == NULL)
|
||||
break;
|
||||
|
||||
if (*str != '>')
|
||||
break;
|
||||
str++;
|
||||
}
|
||||
else if (iswspace(c))
|
||||
{
|
||||
str += clen;
|
||||
continue;
|
||||
}
|
||||
else if (c < 128 ? isalunum(c) : iswalnum((wint_t)c))
|
||||
{
|
||||
const char* keyword = str;
|
||||
|
||||
/* Skip to end of alphanumeric characters. */
|
||||
str = skip_alunum(str + clen, end);
|
||||
|
||||
part = NULL;
|
||||
for (struct lpctypename_s *lpctypename = lpctypenames; lpctypename->name != NULL; lpctypename++)
|
||||
{
|
||||
if (!strncmp(lpctypename->name, keyword, str - keyword)
|
||||
&& strlen(lpctypename->name) == str - keyword)
|
||||
{
|
||||
part = lpctypename->type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_PYTHON
|
||||
if (part == NULL)
|
||||
{
|
||||
ident_t *p = find_shared_identifier_n(keyword, str - keyword, I_TYPE_PYTHON_TYPE, 0);
|
||||
while (p && p->type != I_TYPE_PYTHON_TYPE)
|
||||
p = p->inferior;
|
||||
if (p)
|
||||
part = get_python_type(p->u.python_type_id);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (part == NULL)
|
||||
break;
|
||||
|
||||
str = skip_whitespace(str, end);
|
||||
|
||||
if (part == lpctype_any_struct)
|
||||
{
|
||||
/* Struct needs to have specific a name or 'mixed'. */
|
||||
const char* structname = str;
|
||||
str = skip_alunum(str, end);
|
||||
|
||||
if (structname == str)
|
||||
break;
|
||||
|
||||
if (str - structname != 5 || memcmp(structname, "mixed", 5))
|
||||
{
|
||||
/* First look at the current program. */
|
||||
program_t *prog = get_current_object_program();
|
||||
string_t *name;
|
||||
if (!prog)
|
||||
break;
|
||||
|
||||
name = find_tabled_str_n(structname, str - structname, STRING_UTF8);
|
||||
if (!name)
|
||||
break;
|
||||
|
||||
part = NULL;
|
||||
for (int idx = 0; idx < prog->num_structs; idx++)
|
||||
{
|
||||
struct_type_t *st = prog->struct_defs[idx].type;
|
||||
if (st->name->name == name
|
||||
&& !(prog->struct_defs[idx].flags & (TYPE_MOD_PRIVATE|NAME_HIDDEN)))
|
||||
{
|
||||
part = get_struct_type(st);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!part)
|
||||
{
|
||||
/* Look at global struct definitions. */
|
||||
ident_t *p = find_shared_identifier_mstr(name, I_TYPE_GLOBAL, 0);
|
||||
while (p && p->type != I_TYPE_GLOBAL)
|
||||
p = p->inferior;
|
||||
if (p)
|
||||
{
|
||||
struct_type_t *st = NULL;
|
||||
if (p->u.global.sefun_struct_id != I_GLOBAL_SEFUN_STRUCT_NONE)
|
||||
st = get_simul_efun_program()->struct_defs[p->u.global.sefun_struct_id].type;
|
||||
else if (p->u.global.std_struct_id != I_GLOBAL_STD_STRUCT_NONE)
|
||||
st = get_std_struct_type(p->u.global.std_struct_id);
|
||||
|
||||
if (st != NULL)
|
||||
part = get_struct_type(st);
|
||||
}
|
||||
}
|
||||
|
||||
if (!part)
|
||||
break;
|
||||
}
|
||||
|
||||
str = skip_whitespace(str, end);
|
||||
}
|
||||
else if ((part == lpctype_any_object || part == lpctype_any_lwobject)
|
||||
&& str != end && *str == '"')
|
||||
{
|
||||
/* Specific (lw)object type. */
|
||||
char buf[512];
|
||||
const char *obname = ++str;
|
||||
size_t oblen;
|
||||
string_t *obstr;
|
||||
|
||||
while (str != end)
|
||||
{
|
||||
if (*str == '\\')
|
||||
{
|
||||
str++;
|
||||
if (str == end)
|
||||
break;
|
||||
}
|
||||
else if (*str == '"')
|
||||
break;
|
||||
str++;
|
||||
}
|
||||
|
||||
if (str == end)
|
||||
break;
|
||||
|
||||
oblen = unescape_string(obname, str - obname, buf, sizeof(buf));
|
||||
if (!oblen)
|
||||
break;
|
||||
|
||||
obstr = new_n_unicode_mstring(buf, oblen);
|
||||
if (!obstr)
|
||||
break;
|
||||
|
||||
if (part == lpctype_any_object)
|
||||
part = get_object_type(obstr);
|
||||
else
|
||||
part = get_lwobject_type(obstr);
|
||||
free_mstring(obstr);
|
||||
|
||||
str = skip_whitespace(str+1, end);
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
/* At this point we have single type in <part>.
|
||||
* Any whitespaces have been skipped.
|
||||
*/
|
||||
|
||||
if (part != lpctype_void)
|
||||
{
|
||||
while (str != end && *str == '*')
|
||||
{
|
||||
lpctype_t *dummy = part;
|
||||
part = get_array_type(part);
|
||||
free_lpctype(dummy);
|
||||
str = skip_whitespace(str+1, end);
|
||||
}
|
||||
}
|
||||
|
||||
if (result == NULL)
|
||||
result = part;
|
||||
else if (part == lpctype_void)
|
||||
break;
|
||||
else
|
||||
{
|
||||
lpctype_t *u = get_union_type(result, part);
|
||||
free_lpctype(result);
|
||||
free_lpctype(part);
|
||||
result = u;
|
||||
}
|
||||
|
||||
if (str == end || *str == '>')
|
||||
{
|
||||
*start = str;
|
||||
return result;
|
||||
}
|
||||
if (result == lpctype_void || *str != '|')
|
||||
break;
|
||||
str++;
|
||||
}
|
||||
|
||||
/* We get here on errors only. */
|
||||
free_lpctype(result);
|
||||
return NULL;
|
||||
} /* parse_lpctype() */
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* The same definitions are in sys/lpctypes.h for the mudlibs. */
|
||||
|
|
@ -1175,6 +1468,8 @@ get_type_compat_int (lpctype_t *t)
|
|||
val++;
|
||||
if (val >= COMPAT_TYPE_STRUCT)
|
||||
val++;
|
||||
if (val >= COMPAT_TYPE_LWOBJECT)
|
||||
val++;
|
||||
return val;
|
||||
}
|
||||
|
||||
|
|
|
|||
27
src/types.h
27
src/types.h
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include "driver.h"
|
||||
#include "typedefs.h"
|
||||
#include "svalue.h"
|
||||
|
||||
typedef enum type_classes type_classes_t;
|
||||
typedef enum primary_types primary_types_t;
|
||||
|
|
@ -49,11 +50,11 @@ enum type_classes
|
|||
TCLASS_PRIMARY,
|
||||
TCLASS_STRUCT,
|
||||
TCLASS_OBJECT,
|
||||
#ifdef USE_PYTHON
|
||||
TCLASS_PYTHON,
|
||||
#endif
|
||||
TCLASS_ARRAY,
|
||||
TCLASS_UNION
|
||||
TCLASS_UNION,
|
||||
#ifdef USE_PYTHON
|
||||
TCLASS_PYTHON
|
||||
#endif
|
||||
};
|
||||
|
||||
/* --- Primary type values --- */
|
||||
|
|
@ -71,6 +72,7 @@ enum primary_types
|
|||
TYPE_QUOTED_ARRAY = 9,
|
||||
TYPE_BYTES = 10,
|
||||
TYPE_COROUTINE = 11,
|
||||
TYPE_LPCTYPE = 12,
|
||||
};
|
||||
|
||||
/* -- Object types -- */
|
||||
|
|
@ -264,7 +266,7 @@ struct fulltype_s
|
|||
extern lpctype_t *lpctype_int, *lpctype_string, *lpctype_bytes,
|
||||
*lpctype_mapping, *lpctype_float, *lpctype_mixed,
|
||||
*lpctype_closure, *lpctype_symbol, *lpctype_coroutine,
|
||||
*lpctype_quoted_array,
|
||||
*lpctype_lpctype, *lpctype_quoted_array,
|
||||
*lpctype_any_struct, *lpctype_any_object,
|
||||
*lpctype_any_lwobject, *lpctype_void, *lpctype_unknown;
|
||||
|
||||
|
|
@ -272,7 +274,7 @@ extern lpctype_t *lpctype_int, *lpctype_string, *lpctype_bytes,
|
|||
extern lpctype_t _lpctype_int, _lpctype_string, _lpctype_bytes,
|
||||
_lpctype_mapping, _lpctype_float, _lpctype_mixed,
|
||||
_lpctype_closure, _lpctype_symbol, _lpctype_coroutine,
|
||||
_lpctype_quoted_array,
|
||||
_lpctype_lpctype, _lpctype_quoted_array,
|
||||
_lpctype_any_struct, _lpctype_any_object,
|
||||
_lpctype_any_lwobject, _lpctype_void, _lpctype_unknown;
|
||||
|
||||
|
|
@ -296,6 +298,7 @@ extern void _free_lpctype(lpctype_t *t);
|
|||
extern bool lpctype_contains(lpctype_t* src, lpctype_t* dest);
|
||||
extern bool is_compatible_object(object_t *ob, lpctype_t *t);
|
||||
extern bool is_compatible_lwobject(lwobject_t *ob, lpctype_t *t);
|
||||
extern lpctype_t *parse_lpctype(const char** start, const char* end);
|
||||
extern int get_type_compat_int(lpctype_t *t);
|
||||
extern void types_driver_info(svalue_t *svp, int value) __attribute__((nonnull(1)));
|
||||
|
||||
|
|
@ -364,6 +367,18 @@ static INLINE fulltype_t get_fulltype_flags(lpctype_t *t, typeflags_t f)
|
|||
return ((fulltype_t) { .t_type = t, .t_flags = f });
|
||||
}
|
||||
|
||||
static INLINE void put_ref_lpctype(svalue_t * const dest, lpctype_t * const t)
|
||||
__attribute__((nonnull(1,2)));
|
||||
static INLINE void put_ref_lpctype(svalue_t * const dest, lpctype_t * const t)
|
||||
/* Put the type <t> into <dest>, which is considered empty,
|
||||
* and increment the refcount of <t>.
|
||||
*/
|
||||
{
|
||||
*dest = svalue_lpctype(ref_lpctype(t));
|
||||
}
|
||||
|
||||
#define push_ref_lpctype(sp,val) put_ref_lpctype(++(sp),val)
|
||||
|
||||
#ifdef GC_SUPPORT
|
||||
|
||||
extern void clear_lpctype_ref (lpctype_t *t);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ int deep_eq(mixed arg1, mixed arg2)
|
|||
case T_OBJECT:
|
||||
case T_LWOBJECT:
|
||||
case T_COROUTINE:
|
||||
case T_LPCTYPE:
|
||||
return arg1 == arg2;
|
||||
|
||||
case T_POINTER:
|
||||
|
|
|
|||
|
|
@ -253,6 +253,20 @@ mixed *tests =
|
|||
({ "call_direct_resolved array 2", 0, (: int* result; return deep_eq(call_direct_resolved(&result, ({clone,clone,object_name(clone),this_object(),0}), "g", 10, ({ 20 })), ({0, 0, 0, 0, 0})) && deep_eq(result, ({ 0, 0, 0, 0, 0})); :) }),
|
||||
({ "call_direct_resolved array 3", 0, (: int* result; return deep_eq(call_direct_resolved(&result, ({clone,clone,object_name(clone),this_object(),0}), "h", 10, ({ 20 })), ({0, 0, 0, 0, 0})) && deep_eq(result, ({ 0, 0, 0, 0, 0})); :) }),
|
||||
({ "call_out", 0, (: last_rt_warning = 0; call_out("ThisFunctionDoesNotExist", 10); return sizeof(last_rt_warning); :) }),
|
||||
({ "check_type 1", 0, (: check_type(10,[int]) == 1 :) }),
|
||||
({ "check_type 2", 0, (: check_type(10,[int|float]) == 1 :) }),
|
||||
({ "check_type 3", 0, (: check_type(10,[string]) == 0 :) }),
|
||||
({ "check_type 4", 0, (: check_type(10,[mixed]) == 1 :) }),
|
||||
({ "check_type 5", 0, (: check_type(10,[void]) == 0 :) }),
|
||||
({ "check_type 6", 0, (: check_type(({10}),[int*]) == 1 :) }),
|
||||
({ "check_type 7", 0, (: check_type(({10}),[string*]) == 0 :) }),
|
||||
({ "check_type 8", 0, (: check_type(({10}),[<int|string>*]) == 1 :) }),
|
||||
({ "check_type 9", 0, (: check_type(({10}),[int*|string*]) == 1 :) }),
|
||||
({ "check_type 10", 0, (: check_type(({10}),[int*|string*]) == 1 :) }),
|
||||
({ "check_type 11", 0, (: check_type(({10,"X"}),[<int|string>*]) == 1 :) }),
|
||||
({ "check_type 12", 0, (: check_type(({10,"X"}),[int*|string*]) == 0 :) }),
|
||||
({ "check_type 13", 0, (: check_type(({10}),[mixed]) == 1 :) }),
|
||||
({ "check_type 14", 0, (: check_type(({10}),[mixed*]) == 1 :) }),
|
||||
({ "crypt", TF_ERROR, (: crypt("ABC", "$$") :) }),
|
||||
({ "ctime", TF_DONTCHECKERROR, (: ctime(-1) :) }), /* This must be the first ctime call of this test suite. */
|
||||
({ "clone_object 1", 0,
|
||||
|
|
@ -637,6 +651,17 @@ mixed *tests =
|
|||
use_object_structs: 1))));
|
||||
:)
|
||||
}),
|
||||
({ "compile_string with decltype of these tests", 0,
|
||||
(:
|
||||
string file = read_file(__FILE__, 0, 0, "UTF-8");
|
||||
string header = explode(file, "// String compiler header boundary\n")[1];
|
||||
string code = explode(file, "// String compiler test boundary\n")[1];
|
||||
return funcall(compile_string(0, "#define TF_ERROR 1\n#define TF_DONTCHECKERROR 2\n" + header + "decltype(" + code + ")", (<cs_opts>
|
||||
use_object_functions: 1,
|
||||
use_object_variables: 1,
|
||||
use_object_structs: 1))) in [mixed*];
|
||||
:)
|
||||
}),
|
||||
({ "compile_string (simple block)", 0,
|
||||
(:
|
||||
return funcall(compile_string(0, "return 42;", (<cs_opts> compile_block: 1)))==42;
|
||||
|
|
@ -1079,6 +1104,48 @@ mixed *tests =
|
|||
({ "sprintf doc41", 0, (: sprintf("%8.3G",123.5) == " 124" :) }),
|
||||
({ "sprintf doc42", 0, (: sprintf("%8.6g",123.5) == " 123.5" :) }),
|
||||
|
||||
({ "to_array 1", 0, (: deep_eq(to_array([int]), ({ [int] })) :) }),
|
||||
({ "to_array 2", 0, (: deep_eq(to_array([void]), ({ [void] })) :) }),
|
||||
({ "to_array 3", 0, (: deep_eq(to_array([int*]), ({ [int*] })) :) }),
|
||||
({ "to_array 4", 0, (: deep_eq(to_array([<int|string>*]), ({ [<int|string>*] })) :) }),
|
||||
({ "to_array 5", 0, (: deep_eq(mkmapping(to_array([int|string])), ([ [int], [string] ])) :) }),
|
||||
({ "to_array 6", 0, (: deep_eq(mkmapping(to_array([int|float|string])), ([ [int], [float], [string] ])) :) }),
|
||||
({ "to_array 7", 0, (: deep_eq(mkmapping(to_array([int|<int|string>*])), ([ [int], [<int|string>*] ])) :) }),
|
||||
|
||||
({ "to_lpctype 1", 0, (: to_lpctype("int") == [int] :) }),
|
||||
({ "to_lpctype 2", 0, (: to_lpctype("<int>") == [int] :) }),
|
||||
({ "to_lpctype 3", 0, (: to_lpctype("<<int>>") == [int] :) }),
|
||||
({ "to_lpctype 4", 0, (: to_lpctype("int|string") == [int|string] :) }),
|
||||
({ "to_lpctype 5", 0, (: to_lpctype("string|int") == [int|string] :) }),
|
||||
({ "to_lpctype 6", 0, (: to_lpctype("mixed") == [mixed] :) }),
|
||||
({ "to_lpctype 7", 0, (: to_lpctype("void") == [void] :) }),
|
||||
({ "to_lpctype 8", 0, (: to_lpctype("struct mixed") == [struct mixed] :) }),
|
||||
({ "to_lpctype 9", 0, (: to_lpctype("struct test_struct") == [struct test_struct] :) }),
|
||||
({ "to_lpctype 10", 0, (: to_lpctype("struct compile_string_options") == [struct compile_string_options] :) }),
|
||||
({ "to_lpctype 11", 0, (: to_lpctype("int**") == [int**] :) }),
|
||||
({ "to_lpctype 12", 0, (: to_lpctype("<int*|string>*") == [<int*|string>*] :) }),
|
||||
({ "to_lpctype 13", 0, (: to_lpctype("object") == [object] :) }),
|
||||
({ "to_lpctype 14", 0, (: to_lpctype("lwobject") == [lwobject] :) }),
|
||||
({ "to_lpctype 15", 0, (: to_lpctype("lwobject \"/object/\u00c4\"") == [lwobject "/object/\u00c4"] :) }),
|
||||
({ "to_lpctype 16", TF_ERROR, (: to_lpctype("stuff") :) }),
|
||||
({ "to_lpctype 17", TF_ERROR, (: to_lpctype("int what") :) }),
|
||||
({ "to_lpctype 18", TF_ERROR, (: to_lpctype("<int> what") :) }),
|
||||
({ "to_lpctype 17", TF_ERROR, (: to_lpctype("int>") :) }),
|
||||
({ "to_lpctype 18", TF_ERROR, (: to_lpctype("struct whatever") :) }),
|
||||
|
||||
({ "to_string(lpctype) 1", 0, (: to_lpctype(to_string([int])) == [int] :) }),
|
||||
({ "to_string(lpctype) 2", 0, (: to_lpctype(to_string([string|int])) == [int|string] :) }),
|
||||
({ "to_string(lpctype) 3", 0, (: to_lpctype(to_string([mixed])) == [mixed] :) }),
|
||||
({ "to_string(lpctype) 4", 0, (: to_lpctype(to_string([void])) == [void] :) }),
|
||||
({ "to_string(lpctype) 5", 0, (: to_lpctype(to_string([struct mixed])) == [struct mixed] :) }),
|
||||
({ "to_string(lpctype) 6", 0, (: to_lpctype(to_string([struct test_struct])) == [struct test_struct] :) }),
|
||||
({ "to_string(lpctype) 7", 0, (: to_lpctype(to_string([struct compile_string_options])) == [struct compile_string_options] :) }),
|
||||
({ "to_string(lpctype) 8", 0, (: to_lpctype(to_string([int**])) == [int**] :) }),
|
||||
({ "to_string(lpctype) 9", 0, (: to_lpctype(to_string([<int*|string>*])) == [<int*|string>*] :) }),
|
||||
({ "to_string(lpctype) 10", 0, (: to_lpctype(to_string([object])) == [object] :) }),
|
||||
({ "to_string(lpctype) 11", 0, (: to_lpctype(to_string([lwobject])) == [lwobject] :) }),
|
||||
({ "to_string(lpctype) 12", 0, (: to_lpctype(to_string([lwobject "/object/\u00c4"])) == [lwobject "/object/\u00c4"] :) }),
|
||||
|
||||
({ "to_text 1", 0, (: deep_eq(to_array(to_text( ({}) )), ({}) ) :) }),
|
||||
({ "to_text 2", 0, (: deep_eq(to_array(to_text( ({0, 65, 66, 67}) )), ({0, 65, 66, 67}) ) :) }),
|
||||
({ "to_text 3", 0, (: deep_eq(to_array(to_text( copy(({65, 66, 67, "ABC"})) )), ({65, 66, 67}) ) :) }),
|
||||
|
|
@ -1253,6 +1320,17 @@ mixed *tests =
|
|||
([1:"a";"b", 2:"c";"d"]),
|
||||
to_struct((["a":1, "b": 4, "c": 16])),
|
||||
to_struct(({1,2,3})),
|
||||
|
||||
[void],
|
||||
[float],
|
||||
[float|object],
|
||||
[lpctype],
|
||||
[struct mixed],
|
||||
[struct test_struct],
|
||||
[struct compile_string_options],
|
||||
[string**],
|
||||
[<symbol*|string>*],
|
||||
[lwobject "/A/\"\n\""],
|
||||
}))
|
||||
{
|
||||
if(!deep_eq(val, restore_value(save_value(val))))
|
||||
|
|
@ -1328,6 +1406,7 @@ mixed *tests =
|
|||
({ "variable_list 4", 0, (: deep_eq(variable_list(this_object(), RETURN_FUNCTION_NAME | RETURN_FUNCTION_TYPE),
|
||||
({ "last_rt_warning", TYPE_MOD_POINTER|TYPE_STRING, "json_testdata", TYPE_MAPPING, "json_teststring", TYPE_STRING, "b", TYPE_BYTES, "dhe_testdata", TYPE_STRING, "global_var", TYPE_ANY, "clone", TYPE_OBJECT, "last_privi_op", TYPE_STRING, "last_privi_who", TYPE_ANY, "last_privi_args", TYPE_MOD_POINTER|TYPE_ANY, "tests", TYPE_MOD_POINTER|TYPE_ANY, "args", TYPE_NUMBER })) :) }),
|
||||
({ "variable_list 5", 0, (: variable_list(this_object(), RETURN_VARIABLE_VALUE)[3] == b"\x00" :) }),
|
||||
({ "variable_list 6", 0, (: deep_eq(variable_list(this_object(), RETURN_FUNCTION_LPCTYPE), ({ [string*], [mapping], [string], [bytes], [string], [mixed], [object], [string], [mixed], [mixed*], [mixed*], [int] })) :) }),
|
||||
|
||||
#ifdef __JSON__
|
||||
({ "json_parse/_serialize 1", 0,
|
||||
|
|
|
|||
|
|
@ -103,6 +103,55 @@ mixed *tests = ({
|
|||
({ "&(bytes[]) in &(bytes[]) 1", 0, (: bytes str = b"Some String"; return &(str[5..7]) in &(str[5..7]) && &(str[5..5]) in &(str[5..7]) && &(str[0..0]) in &(str[5..7]); :) }),
|
||||
({ "&(bytes[]) in &(bytes[]) 2", 0, (: bytes str = b"Some String"; return !(&(str[0..4]) in &(str[5..7])) && !(&(str[4..5]) in &(str[5..7])) && !(&(str[5..8]) in &(str[5..7])); :) }),
|
||||
|
||||
({ "[int] == [int]", 0, (: [int] == [int] :) }),
|
||||
({ "[int] == [string]", 0, (: !([int] == [string]) :) }),
|
||||
({ "[int|string] == [string|int]", 0, (: [int|string] == [string|int] :) }),
|
||||
({ "[int|string] == [object|int]", 0, (: !([int|string] == [object|int]) :) }),
|
||||
({ "[int] == [mixed]", 0, (: !([int] == [mixed]) :) }),
|
||||
({ "[int] == [void]", 0, (: !([int] == [void]) :) }),
|
||||
|
||||
({ "[int] != [int]", 0, (: !([int] != [int]) :) }),
|
||||
({ "[int] != [string]", 0, (: [int] != [string] :) }),
|
||||
({ "[int|string] != [string|int]", 0, (: !([int|string] != [string|int]) :) }),
|
||||
({ "[int|string] != [object|int]", 0, (: [int|string] != [object|int] :) }),
|
||||
({ "[int] != [mixed]", 0, (: [int] != [mixed] :) }),
|
||||
({ "[int] != [void]", 0, (: [int] != [void] :) }),
|
||||
|
||||
({ "[int] | [float]", 0, (: ([int] | [float]) == [int|float] :) }),
|
||||
({ "[int] | [int|float]", 0, (: ([int] | [int|float]) == [int|float] :) }),
|
||||
({ "[int|string] | [int|float]", 0, (: ([int|string] | [int|float]) == [int|string|float] :) }),
|
||||
({ "[int] | [mixed]", 0, (: ([int] | [mixed]) == [mixed] :) }),
|
||||
({ "[int] | [void]", 0, (: ([int] | [void]) == [int] :) }),
|
||||
|
||||
({ "[int] & [float]", 0, (: ([int] & [float]) == [void] :) }),
|
||||
({ "[int] & [int|float]", 0, (: ([int] & [int|float]) == [int] :) }),
|
||||
({ "[int|string] & [int|float]", 0, (: ([int|string] & [int|float]) == [int] :) }),
|
||||
({ "[int] & [mixed]", 0, (: ([int] & [mixed]) == [int] :) }),
|
||||
({ "[int] & [void]", 0, (: ([int] & [void]) == [void] :) }),
|
||||
|
||||
({ "[int] |= [float]", 0, (: lpctype val = [int]; val |= [float]; return val == [int|float]; :) }),
|
||||
({ "[int] |= [int|float]", 0, (: lpctype val = [int]; val |= [int|float]; return val == [int|float]; :) }),
|
||||
({ "[int|string] |= [int|float]", 0, (: lpctype val = [int|string]; val |= [int|float]; return val == [int|string|float]; :) }),
|
||||
({ "[int] |= [mixed]", 0, (: lpctype val = [int]; val |= [mixed]; return val == [mixed]; :) }),
|
||||
({ "[int] |= [void]", 0, (: lpctype val = [int]; val |= [void]; return val == [int]; :) }),
|
||||
|
||||
({ "[int] &= [float]", 0, (: lpctype val = [int]; val &= [float]; return val == [void]; :) }),
|
||||
({ "[int] &= [int|float]", 0, (: lpctype val = [int]; val &= [int|float]; return val == [int]; :) }),
|
||||
({ "[int|string] &= [int|float]", 0, (: lpctype val = [int|string]; val &= [int|float]; return val == [int]; :) }),
|
||||
({ "[int] &= [mixed]", 0, (: lpctype val = [int]; val &= [mixed]; return val == [int]; :) }),
|
||||
({ "[int] &= [void]", 0, (: lpctype val = [int]; val &= [void]; return val == [void]; :) }),
|
||||
|
||||
({ "[int] in [float]", 0, (: !([int] in [float]) :) }),
|
||||
({ "[int] in [int|float]", 0, (: [int] in [int|float] :) }),
|
||||
({ "[int|string] in [int|float]", 0, (: !([int|string] in [int|float]) :) }),
|
||||
({ "[int] in [mixed]", 0, (: [int] in [mixed] :) }),
|
||||
({ "[int] in [void]", 0, (: !([int] in [void]) :) }),
|
||||
({ "[mixed] in [int]", 0, (: !([mixed] in [int]) :) }),
|
||||
({ "[void] in [int]", 0, (: [void] in [int] :) }),
|
||||
|
||||
({ "decltype(42)", 0, (: decltype(42) == [int] :) }),
|
||||
({ "decltype(int var)", 0, (: int var; return decltype(var) == [int]; :) }),
|
||||
({ "decltype(fun())", 0, (: decltype(deep_eq("A","B")) == [int] :) }),
|
||||
});
|
||||
|
||||
void run_test()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue