/**
* This is an inheritable to handle certain sorts of expressions in stuff.
* These expression can be setup by players (or creators) and then run
* or evaluated. It allows controlling the types usable by the expression
* handlers, strings, arrays, mappings, integers and floats.
* @author Pinkfish
* @started Thu May 4 22:44:34 PDT 2000
*/
#include <money.h>
#include <expressions.h>
#define EXPRESSION_AND -1
#define EXPRESSION_OR -2
#define EXPRESSION_NOT -3
#define EXPRESSION_FALSE -4
#define EXPRESSION_TRUE -5
#define EXPRESSION_GREATOR_THAN -6
#define EXPRESSION_LESS_THAN -7
#define EXPRESSION_EQUAL_TO -8
#define EXPRESSION_GREATOR_OR_EQUAL -9
#define EXPRESSION_LESS_OR_EQUAL -10
#define EXPRESSION_PLUS -11
#define EXPRESSION_MINUS -12
#define EXPRESSION_MULTIPLY -13
#define EXPRESSION_DIVIDE -14
#define EXPRESSION_IF -15
#define EXPRESSION_NOT_EQUAL_TO -16
#define EXPRESSION_ARRAY_DEREFERENCE -17
#define EXPRESSION_ARRAY_AGGREGATE -18
#define EXPRESSION_AND_NEW -19
#define EXPRESSION_OR_NEW -20
#define EXPRESSION_IF_NEW -21
#define EXPRESSION_TREE 0
#define EXPRESSION_PARSE_STRING 1
#define EXPRESSION_TYPE 2
#define EXPRESSION_FUNC_NAME 0
#define EXPRESSION_FUNC_NO_ARGS 1
#define EXPRESSION_FUNC_VAR_NAME 0
#define EXPRESSION_FUNC_VAR_POS 1
class variable_thing {
int type;
function value;
}
class func_variable_thing {
int type;
int arg_no;
}
class function_thing {
int type;
function value;
int* args;
int return_pos; // Only used if the return type is an array.
}
class user_function_thing {
int type;
class parse_node* expr;
int* arg_types;
string* arg_names;
}
private mixed* parse_operator(string str, string token);
string query_expression_string(class parse_node* expr, int brief);
class parse_node evaluate_expression(class parse_node* expr, mixed args ...);
void add_allowed_function(string name, int type, int* args, function value);
mixed query_property(string name);
protected int is_array_type(int type);
int sizeof_function(mixed args ...);
int filter_function(mixed args ...);
private mapping _user_functions;
private nosave mapping _func_variables;
private nosave mapping _variables;
private nosave mapping _functions;
private nosave string _error_string;
private nosave string _warning_string;
void create() {
_variables = ([ ]);
_functions = ([ ]);
if (!_user_functions) {
_user_functions = ([ ]);
}
_func_variables = ([ ]);
_error_string = "no error";
add_allowed_function("sizeof", EXPRESSION_TYPE_INTEGER,
({ EXPRESSION_TYPE_ARRAY }), (: sizeof_function :) );
/* Need to do some other evil things to support this...
add_allowed_function("filter", EXPRESSION_TYPE_OBJECT +
EXPRESSION_TYPE_ARRAY_OFFSET,
({ EXPRESSION_TYPE_ARRAY_OFFSET + EXPRESSION_TYPE_OBJECT,
EXPRESSION_TYPE_BOOLEAN }), (: filter_function :) );
*/
} /* create() */
/**
* This method returns the last error if there was an error in the parsing.
* @return the last error
*/
string query_last_expression_error() {
return _error_string;
} /* query_last_expression_error() */
/**
* This method returns the last warning if there was an warning in the parsing.
* @return the last warning
*/
string query_last_expression_warning() {
return _warning_string;
} /* query_last_expression_warning() */
/**
* This method adds in an allowed variable and specifies it's type.
* @param name the name of the variable
* @param type the type of the variable
* @param value the value of the variable
*/
void add_allowed_variable(string name, int type, function value) {
class variable_thing bing;
bing = new(class variable_thing);
bing->type = type;
bing->value = value;
_variables[name] = bing;
} /* add_allowed_variable() */
/**
* This method adds in an allowed function and specifies the types it
* takes.
* @param name the name of the function
* @param type the return type of the function
* @param args the types of the arguements (an array)
* @param value the function to call to get the value
*/
void add_allowed_function(string name, int type, int* args, function value) {
class function_thing bing;
bing = new(class function_thing);
bing->type = type;
bing->args = args;
bing->value = value;
_functions[name] = bing;
} /* add_allowed_function() */
/**
* This method returns the type of the function variable.
* @param name the name of the function variable to check
* @return the type of the variable, EXPRESSION_TYPE_ERROR if there is no
* variable
*/
int query_function_variable_type(string name) {
if (_func_variables[name]) {
return ((class func_variable_thing)_func_variables[name])->type;
}
return EXPRESSION_TYPE_ERROR;
} /* query_function_variable_type() */
/**
* This method returns the position of the function variable.
* @param name the name of the function variable to check
* @return the type of the variable, EXPRESSION_TYPE_ERROR if there is no
* variable
*/
int query_function_variable_position(string name) {
if (_func_variables[name]) {
return ((class func_variable_thing)_func_variables[name])->arg_no;
}
return EXPRESSION_TYPE_ERROR;
} /* query_function_variable_position() */
/**
* This method returns the names of all the variables.
* @return all the variable names
*/
string *query_variable_names() {
return keys(_variables);
} /* query_variable_type() */
/**
* This method returns the type of the variable.
* @param name the name of the variable to check
* @return the type of the variable, EXPRESSION_TYPE_ERROR if there is no
* variable
*/
int query_variable_type(string name) {
if (_variables[name]) {
return ((class variable_thing)_variables[name])->type;
}
return EXPRESSION_TYPE_ERROR;
} /* query_variable_type() */
/**
* This method returns the value of the variable.
* @param name the name of the variable to find
* @return the value of the variable, 0 if not found
*/
function query_variable_value(string name) {
if (_variables[name]) {
return ((class variable_thing)_variables[name])->value;
}
return 0;
} /* query_variable_value() */
/**
* This method returns all the function names defined in this expression
* inheritable.
* @return the function names
*/
string* query_function_names() {
return keys(_functions);
} /* query_function_names() */
/**
* This method returns the type of the function.
* @param name the name of the function to check
* @return the args of the function, null array is not found
*/
int* query_function_args_types(string name) {
if (_functions[name]) {
return ((class function_thing)_functions[name])->args;
}
return ({ });
} /* query_function_args_types() */
/**
* This method returns the type of the function.
* @param name the name of the function to check
* @return the type of the function, EXPRESSION_TYPE_ERROR if there is no
* function
*/
int query_function_type(string name) {
if (_functions[name]) {
return ((class function_thing)_functions[name])->type;
}
return EXPRESSION_TYPE_ERROR;
} /* query_function_type() */
/**
* This method returns the value of the function.
* @param name the name of the function to find
* @return the value of the function, 0 if not found
*/
function query_function_value(string name) {
if (_functions[name]) {
return ((class function_thing)_functions[name])->value;
}
return 0;
} /* query_function_value() */
/**
* This method returns the list of user defined functions in the
* inheritable.
* @return the list of user defined functions
*/
string* query_user_function_names() {
return keys(_user_functions);
} /* query_user_function_names() */
/**
* This method returns the argument names types of the user defined
* function.
* @param name the name of the function to lookup
* @return information on the arguments, 0 on failure
*/
mixed* query_user_function_arg_types(string name) {
if (_user_functions[name]) {
return _user_functions[name]->arg_types;
}
return 0;
} /* query_user_function_arg_types() */
/**
* This method returns the argument names names of the user defined
* function.
* @param name the name of the function to lookup
* @return information on the arguments, 0 on failure
*/
mixed* query_user_function_arg_names(string name) {
if (_user_functions[name]) {
return _user_functions[name]->arg_names;
}
return 0;
} /* query_user_function_arg_names() */
/**
* This method returns the argument names and types of the user defined
* function. It returns an array of two elements, the first is an
* array of names and the second is an array of types.
* @param args the arguments to return
* @return information on the arguments, 0 on failure
*/
mixed* query_user_function_args(string name) {
if (_user_functions[name]) {
return ({ _user_functions[name]->arg_names,
_user_functions[name]->arg_types });
}
return 0;
} /* query_user_function_args() */
/**
* This method returns the return type of the user defined function.
* @return the return type, EXPRESSION_TYPE_ERROR on error
*/
int query_user_function_return_type(string name) {
if (_user_functions[name]) {
return ((class user_function_thing)_user_functions[name])->type;
}
return EXPRESSION_TYPE_ERROR;
} /* query_user_function_return_type() */
/**
* This method returns the expression of the user defined function.
* @param name the name of the function to look up
* @return the expression of the user defined function
*/
class parse_node* query_user_function_expression(string name) {
if (_user_functions[name]) {
return _user_functions[name]->expr;
}
return 0;
} /* query_user_function_expression() */
/**
* This method removes the currently defined user expression.
* @param name the expression to remove
*/
int remove_user_expression(string name) {
if (_user_functions[name]) {
map_delete(_user_functions, name);
return 1;
}
return 0;
} /* remove_user_expression() */
/**
* This method returns the value of the type.
* @param type the type to get the integer value of
* @return the integer value of the type
*/
int query_type_value(string type) {
switch (lower_case(type)) {
case "integer" :
case "int" :
return EXPRESSION_TYPE_INTEGER;
case "string" :
return EXPRESSION_TYPE_STRING;
case "float" :
return EXPRESSION_TYPE_FLOAT;
case "boolean" :
case "bool" :
return EXPRESSION_TYPE_BOOLEAN;
case "money" :
return EXPRESSION_TYPE_MONEY;
case "object" :
return EXPRESSION_TYPE_OBJECT;
case "array" :
return EXPRESSION_TYPE_ARRAY;
default :
return EXPRESSION_TYPE_ERROR;
}
} /* query_type_value() */
/**
* This method returns the name of the type.
* @param type the type to get the string name of
* @return the string name of the type
*/
string query_type_name(int type) {
if (is_array_type(type)) {
return "array " + query_type_name(type - EXPRESSION_TYPE_ARRAY_OFFSET);
}
switch (type) {
case EXPRESSION_TYPE_INTEGER :
return "integer";
case EXPRESSION_TYPE_STRING :
return "string";
case EXPRESSION_TYPE_ARRAY :
return "array";
case EXPRESSION_TYPE_ARRAY_NULL :
return "array null";
case EXPRESSION_TYPE_MAPPING :
return "mapping";
case EXPRESSION_TYPE_FLOAT :
return "float";
case EXPRESSION_TYPE_BOOLEAN :
return "boolean";
case EXPRESSION_TYPE_MONEY :
return "money";
case EXPRESSION_TYPE_OBJECT :
return "object";
default :
return "error";
}
} /* query_type_name() */
/**
* This method returns the string value of the operator name.
* @param operator the operator name to return
* @return the string name of the operator
*/
string query_operator_name(int operator) {
switch (operator) {
case EXPRESSION_AND_NEW :
case EXPRESSION_AND :
return "and";
case EXPRESSION_OR_NEW :
case EXPRESSION_OR :
return "or";
case EXPRESSION_NOT :
return "not";
case EXPRESSION_FALSE :
return "false";
case EXPRESSION_TRUE :
return "true";
case EXPRESSION_GREATOR_THAN :
return ">";
case EXPRESSION_LESS_THAN :
return "<";
case EXPRESSION_EQUAL_TO :
return "=";
case EXPRESSION_NOT_EQUAL_TO :
return "<>";
case EXPRESSION_GREATOR_OR_EQUAL :
return ">=";
case EXPRESSION_LESS_OR_EQUAL :
return "<=";
case EXPRESSION_PLUS :
return "+";
case EXPRESSION_MINUS :
return "-";
case EXPRESSION_MULTIPLY :
return "*";
case EXPRESSION_DIVIDE :
return "/";
case EXPRESSION_IF :
return "if";
default :
return "unknown";
}
} /* query_operator_name() */
private class parse_node make_node(int type, mixed value, int* tree) {
class parse_node bing;
bing = new(class parse_node);
bing->type = type;
bing->value = value;
bing->tree = tree;
return bing;
} /* make_parse_node() */
/**
* This method returns a null object of the specified type.
* @param type the type to get the null object of
* @return the null object
*/
class parse_node query_null_type(int type) {
if (is_array_type(type)) {
return make_node(type, ({ }), ({ }));
}
switch (type) {
case EXPRESSION_TYPE_INTEGER :
return make_node(type, 0, ({ }));
case EXPRESSION_TYPE_MONEY :
return make_node(type, 0, ({ }));
case EXPRESSION_TYPE_STRING :
return make_node(type, "", ({ }));
case EXPRESSION_TYPE_ARRAY :
case EXPRESSION_TYPE_ARRAY_NULL :
return make_node(type, ({ }), ({ }));
case EXPRESSION_TYPE_MAPPING :
return make_node(type, ([ ]), ({ }));
case EXPRESSION_TYPE_FLOAT :
return make_node(type, 0.0, ({ }));
case EXPRESSION_TYPE_BOOLEAN :
return make_node(EXPRESSION_TYPE_OPERATOR, EXPRESSION_FALSE, ({ }));
case EXPRESSION_TYPE_OBJECT :
return make_node(type, 0, ({ }));
default :
return 0;
}
} /* query_null_type() */
/**
* This method checks to see if the passed in character is an alpha
* or not.
* @param alpha the character to check
* @return 1 if it alpha, 0 if not
*/
protected int is_alpha(int alpha) {
if ((alpha >= 'a' && alpha <= 'z') ||
(alpha >= 'A' && alpha <= 'Z')) {
return 1;
}
return 0;
} /* isalpha() */
/**
* This method checks to see if the passed in character is a number
* or not.
* @param number the character to check
* @return 1 if it is a number, 0 if not
*/
protected int is_number(int number) {
if (number >= '0' && number <= '9') {
return 1;
}
return 0;
} /* is_number() */
/**
* This method checks to see if the passed in character is a space or
* a space equivilant.
* @param space the character to check
* @return 1 if it is a space, 0 if not
*/
protected int is_space(int space) {
if (space == ' ' || space == '\t') {
return 1;
}
return 0;
} /* is_space() */
/**
* This checks to make sure that the type is a number based type.
* This can be controlled to make sure that any added types are also
* allowed to be treated as numbers.
* @param type the type to check
* @return 1 if it is a number, 0 if not
*/
protected int is_number_type(int type) {
return type == EXPRESSION_TYPE_INTEGER ||
type == EXPRESSION_TYPE_FLOAT ||
type == EXPRESSION_TYPE_MONEY;
} /* is_number_type() */
/**
* This checks to make sure that the type is an array.
* @param type the type to check
* @return 1 if it is an array, 0 if not
*/
protected int is_array_type(int type) {
return type == EXPRESSION_TYPE_ARRAY ||
type == EXPRESSION_TYPE_ARRAY_NULL ||
type >= EXPRESSION_TYPE_ARRAY_OFFSET;
} /* is_number_type() */
/**
* This checks to make sure that the type is a null array.
* @param type the type to check
* @return 1 if it is a null array, 0 if not
*/
protected int is_null_array_type(int type) {
return type == EXPRESSION_TYPE_ARRAY_NULL;
} /* is_number_type() */
private int is_valid_variable_name(int type) {
return type == '_' ||
is_alpha(type) ||
is_number(type);
} /* is_valid_variable_name() */
/**
* This method find the next token. It can be overrideen in higher things
* to deal with special token types (ie: money).
* @param str the input string
* @return ({ token, rest })
*/
protected string* query_token(string str) {
int i = 0;
int j;
while (strlen(str) > 1 && is_space(str[0])) {
str = str[1..];
}
if (!strlen(str)) {
return ({ "", str });
}
//
// parse money as money... Make them enclose money inside two $'s.
// ie: $4 dollars$
//
if (str[0] == '$') {
i = 1;
while (strlen(str) > i &&
(str[i] != '$')) {
i++;
}
return ({ str[0..i], str[i+1..] });
}
if (str[0] == '-' || is_number(str[0])) {
i = 0;
while (strlen(str) > i + 1 &&
is_number(str[i + 1])) {
i++;
}
return ({ str[0..i], str[i+1..] });
}
if (is_alpha(str[0]) || str[0] == '_') {
//
// Zip through till we find a non-alpha, non-number.
//
while (strlen(str) > i + 1 &&
is_valid_variable_name(str[i + 1])) {
i++;
}
return ({ str[0..i], str[i+1..] });
}
if (str[0] == '"') {
do {
j = strsrch(str[i + 1..], "\"");
if (j == -1) {
_error_string = "Missing close \"\n";
return 0;
}
i += j + 1;
} while (str[i - 1] == '\\');
return ({ str[0..i], str[i+1..] });
}
if (str[0] == '\'') {
do {
j = strsrch(str[i + 1..], "'");
if (j == -1) {
_error_string = "Missing close '\n";
return 0;
}
i += j + 1;
} while (str[i - 1] == '\\');
return ({ str[0..i], str[i+1..] });
}
if (str[0] == '>' ||
str[0] == '<') {
if (strlen(str) > 1 &&
str[1] == '=') {
return ({ str[0..1], str[2..] });
}
return ({ str[0..0], str[1..] });
}
while (strlen(str) > i + 1 &&
!is_alpha(str[i + 1]) &&
!is_number(str[i + 1]) &&
!is_space(str[i + 1]) &&
member_array(str[i + 1], ({ '>', '<', '=', '!', '-', '$', '\'',
'"', '_', '(', ')', '{', '}', ',' })) == -1)
{
i++;
}
if (i) {
return ({ str[0..i], str[i+1..] });
}
return ({ str[0..0], str[1..] });
} /* query_token() */
private mixed* parse_node(string str, string token) {
class parse_node num;
int type;
int bing;
int pos;
string place;
string fname;
string* token_ret;
mixed *stuff;
mixed *args;
while (strlen(str) &&
str[0] == ' ') {
str = str[1..];
}
if (_functions[token]) {
fname = token;
token_ret = query_token(str);
if (!token_ret) {
return 0;
}
if (token_ret[0] != "(") {
_error_string = "Expected (, got " + token_ret[0] + " rest: " +
token_ret[1];
return 0;
}
str = token_ret[1];
//
// Get all the args...
//
args = ({ });
token_ret = query_token(str);
if (!token_ret) {
return 0;
}
if (token_ret[0] != ")") {
pos = 0;
do {
stuff = parse_operator(token_ret[1], token_ret[0]);
if (!stuff) {
return 0;
}
pos++;
if (sizeof(_functions[fname]->args) < pos) {
_error_string = "To many arguments to " + token + " expected " +
sizeof(_functions[fname]->args) + " got " +
pos;
return 0;
}
//
// We allow array to be a type to an internal function.
// This means it works on all arrays.
//
if (_functions[fname]->args[pos - 1] != stuff[EXPRESSION_TYPE] &&
!(_functions[fname]->args[pos - 1] == EXPRESSION_TYPE_ARRAY &&
is_array_type(stuff[EXPRESSION_TYPE])) &&
!(is_array_type(stuff[EXPRESSION_TYPE]) &&
is_null_array_type(stuff[EXPRESSION_TYPE]))) {
_error_string = "Expected arg " + pos + " to be " +
query_type_name(_functions[fname]->args[pos - 1]) +
" not " + query_type_name(stuff[EXPRESSION_TYPE]);
return 0;
}
str = stuff[EXPRESSION_PARSE_STRING];
args += stuff[EXPRESSION_TREE];
token_ret = query_token(str);
if (!token_ret) {
return 0;
}
if (token_ret[0] == ",") {
token_ret = query_token(token_ret[1]);
}
} while (token_ret[0] != ")");
if (token_ret[0] != ")") {
_error_string = "Expected ')' got " + token_ret[0];
return 0;
}
if (pos != sizeof(_functions[fname]->args)) {
_error_string = "To few arguments to " + token + " expected " +
sizeof(_functions[fname]->args);
return 0;
}
// Jumps are pointless for functions. We cannot skip anything anyway.
return ({ args +
({ make_node(EXPRESSION_TYPE_FUNCTION,
({ fname, pos }), ({ })) }),
token_ret[1],
((class function_thing)_functions[fname])->type });
}
} else if (_user_functions[token]) {
fname = token;
token_ret = query_token(str);
if (!token_ret) {
return 0;
}
if (token_ret[0] != "(") {
_error_string = "Expected (, got " + token_ret[0] + " rest: " +
token_ret[1];
return 0;
}
str = token_ret[1];
//
// Get all the args...
//
args = ({ });
token_ret = query_token(str);
if (!token_ret) {
return 0;
}
if (token_ret[0] != ")") {
do {
stuff = parse_operator(token_ret[1], token_ret[0]);
if (!stuff) {
return 0;
}
pos = sizeof(args);
if (sizeof(_user_functions[fname]->arg_types) <= pos) {
_error_string = "To many arguments to " + token + " expected " +
sizeof(_user_functions[fname]->arg_types);
return 0;
}
// Allow null arrays to pass as any array type.
if (_user_functions[fname]->arg_types[pos] != stuff[EXPRESSION_TYPE] &&
!(is_array_type(stuff[EXPRESSION_TYPE]) &&
is_null_array_type(stuff[EXPRESSION_TYPE]))) {
_error_string = "Expected arg " + (pos + 1) + " to be " +
query_type_name(_user_functions[fname]->arg_types[pos]) +
" not " + query_type_name(stuff[EXPRESSION_TYPE]);
return 0;
}
str = stuff[EXPRESSION_PARSE_STRING];
args += stuff[EXPRESSION_TREE];
token_ret = query_token(str);
if (!token_ret) {
return 0;
}
if (token_ret[0] != "," && token_ret[0] != ")") {
_error_string = "Expected ')' or ',' got " + token_ret[0];
return 0;
}
if (token_ret[0] == ",") {
token_ret = query_token(token_ret[1]);
}
} while (token_ret[0] != ")");
if (token_ret[0] != ")") {
_error_string = "Expected ')' got " + token_ret[0];
return 0;
}
if (sizeof(args) < sizeof(_user_functions[fname]->arg_types)) {
_error_string = "To few arguments to " + token + " expected " +
sizeof(_user_functions[fname]->arg_types);
return 0;
}
return ({ args +
({ make_node(EXPRESSION_TYPE_USER_FUNCTION,
({ fname, sizeof(args) }), ({ })) }),
token_ret[1],
((class user_function_thing)_user_functions[fname])->type });
}
} else switch (token) {
case "true" :
num = make_node(EXPRESSION_TYPE_OPERATOR, EXPRESSION_TRUE, ({ }));
type = EXPRESSION_TYPE_BOOLEAN;
break;
case "false" :
num = make_node(EXPRESSION_TYPE_OPERATOR, EXPRESSION_FALSE, ({ }));
type = EXPRESSION_TYPE_BOOLEAN;
break;
case "{" :
// Array aggregation.
token_ret = query_token(str);
args = ({ });
type = EXPRESSION_TYPE_ARRAY;
pos = 0;
while (token_ret[0] != "}") {
stuff = parse_operator(token_ret[1], token_ret[0]);
if (!stuff) {
return 0;
}
if (sizeof(args)) {
if (type != stuff[EXPRESSION_TYPE]) {
_error_string = "Arrays must be of only one type. " +
query_type_name(type) + " and " +
query_type_name(stuff[EXPRESSION_TYPE]) +
" do not match.";
return 0;
}
} else {
type = stuff[EXPRESSION_TYPE];
if (is_array_type(type)) {
_error_string = "Cannot have nested arrays.";
return 0;
}
}
str = stuff[EXPRESSION_PARSE_STRING];
args += stuff[EXPRESSION_TREE];
token_ret = query_token(str);
if (!token_ret) {
return 0;
}
if (token_ret[0] != "," && token_ret[0] != "}") {
_error_string = "Expected ')' or ',' got " + token_ret[0];
return 0;
}
if (token_ret[0] == ",") {
token_ret = query_token(token_ret[1]);
}
pos++;
}
//token_ret = query_token(token_ret[1]);
if (type != EXPRESSION_TYPE_ARRAY) {
type += EXPRESSION_TYPE_ARRAY_OFFSET;
return ({ args +
({ make_node(EXPRESSION_TYPE_INTEGER, pos, ({ })),
make_node(EXPRESSION_TYPE_OPERATOR,
EXPRESSION_ARRAY_AGGREGATE, ({ })) }),
token_ret[1],
type });
} else {
type = EXPRESSION_TYPE_ARRAY_NULL;
num = make_node(EXPRESSION_TYPE_ARRAY_NULL, 0, ({ }));
str = token_ret[1];
}
break;
case "" :
_error_string = "No token found at: " + token + " " + str;
return 0;
default :
if (token[0] == '-' || is_number(token[0])) {
sscanf(token, "%d", bing);
num = make_node(EXPRESSION_TYPE_INTEGER, bing, ({ }));
type = EXPRESSION_TYPE_INTEGER;
} else if (token == "$0$") {
num = make_node(EXPRESSION_TYPE_MONEY, 0, ({ }));
type = EXPRESSION_TYPE_MONEY;
} else if (token[0] == '$') {
place = query_property("place");
if (!place) {
place = "default";
}
bing = MONEY_HAND->value_from_string(token[1..<2], place);
if (!bing) {
bing = MONEY_HAND->value_from_string(token[0..<2], place);
}
if (bing) {
num = make_node(EXPRESSION_TYPE_MONEY, bing, ({ }));
type = EXPRESSION_TYPE_MONEY;
} else {
_error_string = "Money value is invalid: " + token[1..<2] + " and " +
token[0..<2];
return 0;
}
} else if (token[0] == '\"' || token[0] == '\'') {
num = make_node(EXPRESSION_TYPE_STRING, token[1..<2], ({ }));
type = EXPRESSION_TYPE_STRING;
} else {
type = query_variable_type(token);
if (type == EXPRESSION_TYPE_ERROR) {
type = query_function_variable_type(token);
if (type == EXPRESSION_TYPE_ERROR) {
_error_string = "No variable called '" + token + "' rest: '" +
str;
return 0;
}
pos = query_function_variable_position(token);
num = make_node(EXPRESSION_TYPE_FUNCTION_VARIABLE,
({ token, pos }), ({ }));
} else {
num = make_node(EXPRESSION_TYPE_VARIABLE, token, ({ }));
}
}
break;
}
return ({ ({ num }), str, type });
} /* parse_node() */
private mixed* parse_bracket(string str, string token) {
mixed* stuff;
string* token_ret;
mixed* ret;
switch (token) {
case "(" :
token_ret = query_token(str);
if (!token_ret) {
return 0;
}
stuff = parse_operator(token_ret[1], token_ret[0]);
if (stuff) {
str = stuff[EXPRESSION_PARSE_STRING];
token_ret = query_token(str);
if (!token_ret) {
return 0;
}
if (token_ret[0] != ")") {
_error_string = "Could not find closing bracket at " + str;
return 0;
}
str = token_ret[1];
ret = ({ stuff[EXPRESSION_TREE], str,
stuff[EXPRESSION_TYPE] });
} else {
return 0;
}
break;
default :
stuff = parse_node(str, token);
if (stuff) {
ret = ({ stuff[EXPRESSION_TREE],
stuff[EXPRESSION_PARSE_STRING],
stuff[EXPRESSION_TYPE] });
} else {
return 0;
}
break;
}
//
// Check for a array de-reference.
//
str = ret[EXPRESSION_PARSE_STRING];
token_ret = query_token(str);
if (token_ret && token_ret[0] == "[") {
mixed *stuffy;
if (!is_array_type(ret[EXPRESSION_TYPE])) {
_error_string = "Cannot de-reference " +
query_type_name(stuff[EXPRESSION_TYPE]);
return 0;
}
if (is_null_array_type(ret[EXPRESSION_TYPE])) {
_error_string = "Cannot de-reference a null array, it has no "
"members!";
return 0;
}
//
// Get the index.
//
token_ret = query_token(token_ret[1]);
stuffy = parse_operator(token_ret[1], token_ret[0]);
if (!stuffy) {
return 0;
}
if (stuffy[EXPRESSION_TYPE] != EXPRESSION_TYPE_INTEGER) {
_error_string = "Can only dereference an array with an integer "
"not a " +
query_type_name(stuff[EXPRESSION_TYPE]);
return 0;
}
str = stuffy[EXPRESSION_PARSE_STRING];
token_ret = query_token(str);
if (token_ret[0] != "]") {
_error_string = "Could not find closing square bracket at " + str;
return 0;
}
return ({ ret[EXPRESSION_TREE] + stuffy[EXPRESSION_TREE] +
({ make_node(EXPRESSION_TYPE_OPERATOR, EXPRESSION_ARRAY_DEREFERENCE, ({ })) }),
token_ret[1],
ret[EXPRESSION_TYPE] - EXPRESSION_TYPE_ARRAY_OFFSET });
}
return ret;
} /* parse_bracket() */
private mixed* parse_plus(string str, string token) {
mixed *stuff;
mixed *stuff2;
int type;
string* token_ret;
string blue;
stuff = parse_bracket(str, token);
if (!stuff) {
return 0;
}
str = stuff[EXPRESSION_PARSE_STRING];
token_ret = query_token(str);
if (!token_ret) {
return 0;
}
switch (token_ret[0]) {
case "+" :
type = EXPRESSION_PLUS;
break;
case "-" :
type = EXPRESSION_MINUS;
break;
}
blue = token_ret[0];
if (type) {
token_ret = query_token(token_ret[1]);
if (!token_ret) {
return 0;
}
stuff2 = parse_plus(token_ret[1], token_ret[0]);
if (!stuff2) {
return 0;
}
if ((!is_number_type(stuff[EXPRESSION_TYPE]) ||
!is_number_type(stuff2[EXPRESSION_TYPE])) &&
type != EXPRESSION_PLUS) {
_error_string = "Invalid types to " + blue +
" expected number got: " +
query_type_name(stuff[EXPRESSION_TYPE]) + " and " +
query_type_name(stuff2[EXPRESSION_TYPE]);
return 0;
}
return ({ stuff[EXPRESSION_TREE] + stuff2[EXPRESSION_TREE] +
({ make_node(EXPRESSION_TYPE_OPERATOR, type, ({ })) }),
stuff2[EXPRESSION_PARSE_STRING], stuff[EXPRESSION_TYPE] });
} else {
return stuff;
}
} /* parse_plus() */
private mixed* parse_multiply(string str, string token) {
mixed *stuff;
mixed *stuff2;
string* token_ret;
int type;
string blue;
stuff = parse_plus(str, token);
if (!stuff) {
return 0;
}
str = stuff[EXPRESSION_PARSE_STRING];
token_ret = query_token(str);
if (!token_ret) {
return 0;
}
switch (token_ret[0]) {
case "*" :
type = EXPRESSION_MULTIPLY;
break;
case "/" :
type = EXPRESSION_DIVIDE;
break;
}
blue = token_ret[0];
if (type) {
token_ret = query_token(token_ret[1]);
if (!token_ret) {
return 0;
}
stuff2 = parse_multiply(token_ret[1], token_ret[0]);
if (!stuff2) {
return 0;
}
if (!is_number_type(stuff[EXPRESSION_TYPE]) ||
!is_number_type(stuff2[EXPRESSION_TYPE])) {
_error_string = "Invalid types to " + blue +
" expected number got: " +
query_type_name(stuff[EXPRESSION_TYPE]) + " and " +
query_type_name(stuff2[EXPRESSION_TYPE]);
return 0;
}
return ({ stuff[EXPRESSION_TREE] + stuff2[EXPRESSION_TREE] +
({ make_node(EXPRESSION_TYPE_OPERATOR, type, ({ })) }),
stuff2[EXPRESSION_PARSE_STRING], stuff[EXPRESSION_TYPE] });
} else {
return stuff;
}
} /* parse_multiply() */
private mixed* parse_compare(string str, string token) {
mixed *stuff;
mixed *stuff2;
string* token_ret;
int type;
string blue;
stuff = parse_multiply(str, token);
if (!stuff) {
return 0;
}
str = stuff[EXPRESSION_PARSE_STRING];
token_ret = query_token(str);
if (!token_ret) {
return 0;
}
switch (token_ret[0]) {
case ">=" :
type = EXPRESSION_GREATOR_OR_EQUAL;
break;
case "<=" :
type = EXPRESSION_LESS_OR_EQUAL;
break;
case ">" :
type = EXPRESSION_GREATOR_THAN;
break;
case "<" :
type = EXPRESSION_LESS_THAN;
break;
case "<>" :
case "!=" :
type = EXPRESSION_NOT_EQUAL_TO;
break;
case "==" :
case "=" :
type = EXPRESSION_EQUAL_TO;
break;
}
blue = token_ret[0];
if (type) {
token_ret = query_token(token_ret[1]);
if (!token_ret) {
return 0;
}
stuff2 = parse_compare(token_ret[1], token_ret[0]);
if (!stuff2) {
return 0;
}
if ((!is_number_type(stuff[EXPRESSION_TYPE]) ||
!is_number_type(stuff2[EXPRESSION_TYPE])) &&
type != EXPRESSION_EQUAL_TO &&
type != EXPRESSION_NOT_EQUAL_TO)
{
_error_string = "Invalid types to " + blue +
" expected number got: " +
query_type_name(stuff[EXPRESSION_TYPE]) + " and " +
query_type_name(stuff2[EXPRESSION_TYPE]);
return 0;
}
return ({ stuff[EXPRESSION_TREE] + stuff2[EXPRESSION_TREE] +
({ make_node(EXPRESSION_TYPE_OPERATOR, type, ({ })) }),
stuff2[EXPRESSION_PARSE_STRING],
EXPRESSION_TYPE_BOOLEAN });
} else {
return stuff;
}
} /* parse_compare() */
private mixed* parse_not(string str, string token) {
mixed *stuff;
if (token == "not") {
stuff = query_token(str);
if (!stuff) {
return 0;
}
stuff = parse_not(stuff[1], stuff[0]);
if (!stuff) {
return 0;
}
if (stuff[EXPRESSION_TYPE] != EXPRESSION_TYPE_BOOLEAN) {
_error_string = "Invalid type to not expected boolean got: " +
query_type_name(stuff[EXPRESSION_TYPE]);
return 0;
}
return ({ stuff[EXPRESSION_TREE] +
({ make_node(EXPRESSION_TYPE_OPERATOR, EXPRESSION_NOT, ({ })) }),
stuff[EXPRESSION_PARSE_STRING],
EXPRESSION_TYPE_BOOLEAN });
} else {
return parse_compare(str, token);
}
} /* parse_not() */
private mixed* parse_boolean(string str, string token) {
mixed *stuff;
mixed *stuff2;
string* token_ret;
string blue;
int type;
stuff = parse_not(str, token);
if (!stuff) {
return 0;
}
str = stuff[EXPRESSION_PARSE_STRING];
token_ret = query_token(str);
if (!token_ret) {
return 0;
}
switch (token_ret[0]) {
case "and" :
type = EXPRESSION_AND_NEW;
break;
case "or" :
type = EXPRESSION_OR_NEW;
break;
}
blue = token_ret[0];
if (type) {
token_ret = query_token(token_ret[1]);
if (!token_ret) {
return 0;
}
stuff2 = parse_boolean(token_ret[1], token_ret[0]);
if (!stuff2) {
return 0;
}
if (stuff[EXPRESSION_TYPE] != stuff2[EXPRESSION_TYPE] ||
stuff[EXPRESSION_TYPE] != EXPRESSION_TYPE_BOOLEAN) {
_error_string = "Invalid types to " + blue +
" expected boolean got: " +
query_type_name(stuff[EXPRESSION_TYPE]) + " and " +
query_type_name(stuff2[EXPRESSION_TYPE]);
return 0;
}
return ({ ({ make_node(EXPRESSION_TYPE_OPERATOR, type,
({ stuff[EXPRESSION_TREE], stuff2[EXPRESSION_TREE] }) ) }),
stuff2[EXPRESSION_PARSE_STRING],
stuff2[EXPRESSION_TYPE] });
} else {
return stuff;
}
} /* parse_boolean() */
private mixed* parse_operator(string str, string token) {
mixed *stuff;
mixed *stuff2;
mixed *stuff3;
string* token_ret;
switch (token) {
case "if" :
token_ret = query_token(str);
if (!token_ret) {
return 0;
}
stuff = parse_operator(token_ret[1], token_ret[0]);
if (!stuff) {
return 0;
}
if (stuff[EXPRESSION_TYPE] != EXPRESSION_TYPE_BOOLEAN) {
_error_string = "Invalid type to if expected boolean got: " +
query_type_name(stuff[EXPRESSION_TYPE]);
return 0;
}
token_ret = query_token(stuff[EXPRESSION_PARSE_STRING]);
if (!token_ret) {
return 0;
}
if (token_ret[0] != "then") {
_error_string = "Expected 'then' got " + token_ret[0];
return 0;
}
token_ret = query_token(token_ret[1]);
if (!token_ret) {
return 0;
}
stuff2 = parse_operator(token_ret[1], token_ret[0]);
if (!stuff2) {
return 0;
}
token_ret = query_token(stuff2[EXPRESSION_PARSE_STRING]);
if (!token_ret) {
return 0;
}
if (token_ret[0] == "else") {
token_ret = query_token(token_ret[1]);
if (!token_ret) {
return 0;
}
stuff3 = parse_operator(token_ret[1], token_ret[0]);
if (!stuff3) {
return 0;
}
if (stuff2[EXPRESSION_TYPE] != stuff3[EXPRESSION_TYPE]) {
// The types are equivilant if one of them is null.
if (is_array_type(stuff2[EXPRESSION_TYPE]) &&
is_array_type(stuff3[EXPRESSION_TYPE]) &&
(is_null_array_type(stuff2[EXPRESSION_TYPE]) ||
is_null_array_type(stuff3[EXPRESSION_TYPE]))) {
//
// Move it in here to fix up the type stuff in the
// return information.
//
if (is_null_array_type(stuff2[EXPRESSION_TYPE])) {
stuff2[EXPRESSION_TYPE] = stuff3[EXPRESSION_TYPE];
}
} else {
_error_string = "Types on both sides of an if must match: " +
query_type_name(stuff2[EXPRESSION_TYPE]) + " and " +
query_type_name(stuff3[EXPRESSION_TYPE]);
return 0;
}
}
token_ret = query_token(stuff3[EXPRESSION_PARSE_STRING]);
if (!token_ret) {
return 0;
}
} else {
stuff3 = ({ ({ query_null_type(stuff2[EXPRESSION_TYPE]) }) });
}
if (token_ret[0] != "endif") {
_error_string = "Expected 'endif' got " + token_ret[0] + " (" +
token_ret[1];
return 0;
}
// We always evaluate the expression, so leave that on the stack.
return ({ stuff[EXPRESSION_TREE] +
({ make_node(EXPRESSION_TYPE_OPERATOR, EXPRESSION_IF_NEW,
({
stuff2[EXPRESSION_TREE],
stuff3[EXPRESSION_TREE]
}) ) }),
token_ret[1],
stuff2[EXPRESSION_TYPE] });
break;
default :
stuff = parse_boolean(str, token);
if (!stuff) {
return 0;
}
return stuff;
}
} /* parse_operator() */
/**
* A very small recursive decent parser which must return a boolean
* value.
* @param str the input string
* @return the array control structure
*/
class parse_node* parse_boolean_string(string str) {
mixed* stuff;
string* token_ret;
_warning_string = "";
_func_variables = ([ ]);
token_ret = query_token(lower_case(str));
if (!token_ret) {
return 0;
}
stuff = parse_operator(token_ret[1], token_ret[0]);
if (!stuff) {
return ({ });
}
if (strlen(stuff[EXPRESSION_PARSE_STRING])) {
_error_string = "Unable to parse the rest of: " +
stuff[EXPRESSION_PARSE_STRING];
return ({ });
}
if (stuff[EXPRESSION_TYPE] != EXPRESSION_TYPE_BOOLEAN) {
_error_string = "Invalid return type, expected boolean got " +
query_type_name(stuff[EXPRESSION_TYPE]);
return ({ });
}
return stuff[EXPRESSION_TREE];
} /* parse_boolean_string() */
/**
* A very small recursive decent parser which must return a integer
* value.
* @param str the input string
* @return the array control structure
*/
class parse_node* parse_integer_string(string str) {
mixed* stuff;
string* token_ret;
_warning_string = "";
_func_variables = ([ ]);
token_ret = query_token(lower_case(str));
if (!token_ret) {
return 0;
}
stuff = parse_operator(token_ret[1], token_ret[0]);
if (!stuff) {
//printf("%O", _error_string);
return ({ });
}
if (strlen(stuff[EXPRESSION_PARSE_STRING])) {
_error_string = "Unable to parse the rest of: " +
stuff[EXPRESSION_PARSE_STRING];
//printf("%O", _error_string);
return ({ });
}
if (stuff[EXPRESSION_TYPE] != EXPRESSION_TYPE_INTEGER) {
_error_string = "Invalid return type, expected integer got " +
query_type_name(stuff[EXPRESSION_TYPE]);
//printf("%O", query_expression_string(stuff[EXPRESSION_TREE], 0));
//printf("%O", evaluate_expression(stuff[EXPRESSION_TREE]));
return ({ });
}
//printf("%O", query_expression_string(stuff[EXPRESSION_TREE], 0));
//printf("%O", evaluate_expression(stuff[EXPRESSION_TREE]));
return stuff[EXPRESSION_TREE];
} /* parse_integer_string() */
/**
* A very small recursive decent parser which must return a money
* value.
* @param str the input string
* @return the array control structure
*/
class parse_node* parse_money_string(string str) {
mixed* stuff;
string* token_ret;
_warning_string = "";
_func_variables = ([ ]);
token_ret = query_token(lower_case(str));
if (!token_ret) {
return 0;
}
stuff = parse_operator(token_ret[1], token_ret[0]);
if (!stuff) {
//printf("%O", _error_string);
return ({ });
}
if (strlen(stuff[EXPRESSION_PARSE_STRING])) {
_error_string = "Unable to parse the rest of: " +
stuff[EXPRESSION_PARSE_STRING];
//printf("%O", _error_string);
return ({ });
}
if (stuff[EXPRESSION_TYPE] != EXPRESSION_TYPE_MONEY) {
_error_string = "Invalid return type, expected money got " +
query_type_name(stuff[EXPRESSION_TYPE]);
//printf("%O", query_expression_string(stuff[EXPRESSION_TREE], 0));
//printf("%O", evaluate_expression(stuff[EXPRESSION_TREE]));
return ({ });
}
//printf("%O", stuff[EXPRESSION_TREE]);
//printf("%O", query_expression_string(stuff[EXPRESSION_TREE], 0));
//printf("%O", evaluate_expression(stuff[EXPRESSION_TREE]));
return stuff[EXPRESSION_TREE];
} /* parse_integer_string() */
/**
* This will pass the arguments to a user defined function and return
* an array of three elements. The first is the name of the function,
* the second is the array of arguments types and the third is the array of
* argument names.
*/
mixed* parse_user_expression_definition(string def) {
mixed* token;
string name;
int* arg_types;
int type;
string* arg_names;
token = query_token(def);
name = token[0];
def = token[1];
if (!strlen(def)) {
//
// No arguments.
//
return ({ name, ({ }), ({ }) });
}
token = query_token(def);
if (token[0] == "(") {
//
// Parse some arguments.
//
token = query_token(token[1]);
arg_names = ({ });
arg_types = ({ });
while (token[0] != ")") {
type = query_type_value(token[0]);
if (type == EXPRESSION_TYPE_ARRAY) {
// Try the next token for the type.
token = query_token(token[1]);
type = query_type_value(token[0]);
if (type != EXPRESSION_TYPE_ERROR) {
type += EXPRESSION_TYPE_ARRAY_OFFSET;
}
}
if (type == EXPRESSION_TYPE_ERROR) {
_error_string = "Invalid type " + token[0];
return 0;
} else {
token = query_token(token[1]);
if (member_array(token[0], arg_names) != -1) {
_error_string = "Duplicate argument name " + token[0];
return 0;
}
arg_types += ({ type });
arg_names += ({ token[0] });
token = query_token(token[1]);
if (token[0] != "," && token[0] != ")") {
_error_string = "Expected , or ) after " + arg_names[<1];
return 0;
}
if (token[0] == ",") {
token = query_token(token[1]);
}
}
}
if (strlen(token[1])) {
_error_string = "Unable to parse the rest of " + token[1];
return 0;
}
return ({ name, arg_types, arg_names });
} else {
_error_string = "Unable to parse rest of: " + def;
}
} /* parse_user_expression_definition() */
/**
* This method attempts to parse a user expression.
* @param name the name of the function
* @param args the name and types of the arguments
* @param str the input string
* @return the name of the function, 0 on failure
*/
string parse_user_expression(
string def,
string str)
{
mixed* stuff;
int i;
string* token_ret;
class user_function_thing old_fluff;
class user_function_thing fluff;
class func_variable_thing womble;
int* arg_types;
string* arg_names;
string name;
_warning_string = "";
stuff = parse_user_expression_definition(def);
if (!stuff) {
return 0;
}
//
// Pull the useful bits out of the return value.
//
name = stuff[0];
arg_types = stuff[1];
arg_names = stuff[2];
//
// Setup the function variables.
//
_func_variables = ([ ]);
for (i = 0; i < sizeof(arg_types); i++) {
womble = new(class func_variable_thing);
womble->type = arg_types[i];
womble->arg_no = i;
_func_variables[arg_names[i]] = womble;
}
token_ret = query_token(lower_case(str));
if (!token_ret) {
return 0;
}
stuff = parse_operator(token_ret[1], token_ret[0]);
//
// Zap them back to the default.
//
_func_variables = ([ ]);
if (!stuff) {
//printf("%O", _error_string);
return 0;
}
if (strlen(stuff[EXPRESSION_PARSE_STRING])) {
_error_string = "Unable to parse the rest of: " +
stuff[EXPRESSION_PARSE_STRING];
//printf("%O", _error_string);
return 0;
}
fluff = new(class user_function_thing);
fluff->type = stuff[EXPRESSION_TYPE];
fluff->expr = stuff[EXPRESSION_TREE];
fluff->arg_names = arg_names;
fluff->arg_types = arg_types;
//
// Let us check to see if one exists current and if we have changed
// any types.
//
old_fluff = _user_functions[name];
if (old_fluff) {
if (old_fluff->type != fluff->type) {
_warning_string += "Warning: Return types have changed " +
query_type_name(old_fluff->type) + " to " +
query_type_name(fluff->type) + ".\n";
}
if (sizeof(old_fluff->arg_types) != sizeof(fluff->arg_types)) {
_warning_string += "Warning: Number of arguments has changed.\n";
}
for (i = 0; i < sizeof(old_fluff->arg_types) && i < sizeof(fluff->arg_types); i++) {
if (old_fluff->arg_types[i] != fluff->arg_types[i]) {
_warning_string += "Warning: Argument number " + i +
" differs in type " +
query_type_name(old_fluff->arg_types[i]) +
" to " + query_type_name(fluff->arg_types[i]) +
".\n";
}
}
}
_user_functions[name] = fluff;
return name;
} /* parse_user_expression() */
/**
* Does a sizeof an array. Nifty...
* @param arr the array to get the sizeof
* @param args the rest of the arguments
* @return the sizeof the array
*/
int sizeof_function(mixed* arr, mixed args ...) {
return sizeof(arr);
} /* sizeof_function() */
/**
* This method returns the expresion as a string.
* @param expr the expression
* @param brief don't expand the variable names
* @return the expression as a string
*/
string query_expression_string(class parse_node* expr, int brief) {
string str;
int i;
string* stack;
int* thing;
string tmp;
string place;
int value;
string indent;
if (!sizeof(expr)) {
return "No expression set.";
}
place = query_property("place");
if (!place) {
place = "default";
}
indent = "";
str = "";
stack = ({ });
thing = ({ });
for (i = 0; i < sizeof(expr); i++) {
if (!classp(expr[i])) {
stack += ({ "Broken element" });
thing += ({ 0 });
continue;
}
switch (expr[i]->type) {
case EXPRESSION_TYPE_OPERATOR :
value = expr[i]->value;
switch (expr[i]->value) {
case EXPRESSION_NOT :
str = " " + query_operator_name(expr[i]->value) + " ";
if (thing[<1] && thing[<1] != expr[i]->value) {
str += "(" + stack[<1] + ")";
} else {
str += stack[<1];
}
stack = stack[0..<2];
thing = thing[0..<2];
break;
case EXPRESSION_AND_NEW :
case EXPRESSION_OR_NEW :
str += query_expression_string(expr[i]->tree[0], brief);
str += " " + query_operator_name(expr[i]->value) + " ";
str += query_expression_string(expr[i]->tree[1], brief);
break;
case EXPRESSION_AND :
case EXPRESSION_OR :
case EXPRESSION_PLUS :
case EXPRESSION_MINUS :
case EXPRESSION_DIVIDE :
case EXPRESSION_MULTIPLY :
case EXPRESSION_GREATOR_THAN :
case EXPRESSION_LESS_THAN :
case EXPRESSION_EQUAL_TO :
case EXPRESSION_GREATOR_OR_EQUAL :
case EXPRESSION_LESS_OR_EQUAL :
case EXPRESSION_NOT_EQUAL_TO :
tmp = stack[<2];
if (thing[<2] && thing[<2] != expr[i]->value) {
str = "(" + stack[<2] + ")";
} else {
str = stack[<2];
}
str += " " + query_operator_name(expr[i]->value) + " ";
if (thing[<1] && thing[<1] != expr[i]->value) {
str += "(" + stack[<1] + ")";
} else {
str += stack[<1];
}
stack = stack[0..<3];
thing = thing[0..<3];
break;
case EXPRESSION_TRUE :
str = "true";
value = 0;
break;
case EXPRESSION_FALSE :
str = "false";
value = 0;
break;
case EXPRESSION_IF_NEW :
if (brief) {
str = "if " + stack[<1] + " then " +
query_expression_string(expr[i]->tree[0], brief) +
" else " +
query_expression_string(expr[i]->tree[1], brief) +
" endif";
} else {
str = "if " + stack[<1] + " then\n" +
" " + replace_string(
query_expression_string(expr[i]->tree[0], brief),
"\n", "\n ") +
"\nelse\n" +
" " + replace_string(
query_expression_string(expr[i]->tree[1], brief),
"\n", "\n ") +
"\nendif";
}
stack = stack[0..<2];
thing = thing[0..<2];
value = 0;
break;
case EXPRESSION_IF :
if (brief) {
str = "if " + stack[<3] + " then " + stack[<2] + " else " +
stack[<1] + " endif";
} else {
str = "if " + stack[<3] + " then\n" +
" " + replace_string(stack[<2], "\n", "\n ") +
"\nelse\n" +
" " + replace_string(stack[<1], "\n", "\n ") +
"\nendif";
}
stack = stack[0..<4];
thing = thing[0..<4];
value = 0;
break;
case EXPRESSION_ARRAY_DEREFERENCE :
str = stack[<2] + "[" + stack[<1] + "]";
stack = stack[0..<3];
thing = thing[0..<3];
value = 0;
break;
case EXPRESSION_ARRAY_AGGREGATE :
str = "{ " +
implode(stack[<(expr[i - 1]->value+1)..<2],
", ") + " }";
thing = thing[0..<expr[i - 1]->value + 2];
stack = stack[0..<expr[i - 1]->value + 2];
value = 0;
break;
default :
str = "Error!";
break;
}
stack += ({ str });
thing += ({ value });
break;
case EXPRESSION_TYPE_ARRAY_NULL :
stack += ({ "{}" });
thing += ({ 0 });
break;
case EXPRESSION_TYPE_MONEY :
stack += ({ MONEY_HAND->money_value_string(expr[i]->value, place) });
thing += ({ 0 });
break;
case EXPRESSION_TYPE_INTEGER :
stack += ({ "" + expr[i]->value });
thing += ({ 0 });
break;
case EXPRESSION_TYPE_STRING :
stack += ({ "\"" + expr[i]->value + "\"" });
thing += ({ 0 });
break;
case EXPRESSION_TYPE_VARIABLE :
stack += ({ expr[i]->value });
thing += ({ 0 });
break;
case EXPRESSION_TYPE_FUNCTION_VARIABLE :
stack += ({ expr[i]->value[EXPRESSION_FUNC_VAR_NAME] });
thing += ({ 0 });
break;
case EXPRESSION_TYPE_FUNCTION :
case EXPRESSION_TYPE_USER_FUNCTION :
str = expr[i]->value[EXPRESSION_FUNC_NAME] + "(";
str += implode(stack[<expr[i]->value[EXPRESSION_FUNC_NO_ARGS]..],
", ");
str += ")";
stack = stack[0..<expr[i]->value[EXPRESSION_FUNC_NO_ARGS] + 1];
thing = thing[0..<expr[i]->value[EXPRESSION_FUNC_NO_ARGS] + 1];
stack += ({ str });
thing += ({ 0 });
break;
default :
stack += ({ "Unknown: " + expr[i]->type + " (" + expr[i]->value + ")" });
thing += ({ 0 });
break;
}
}
return stack[<1];
} /* query_expression_string() */
/**
* This method makes a nice string representation of the user function.
* @param func the name of the user function to get a string of
* @return the user function string
*/
string query_user_function_string(string func) {
class user_function_thing thing;
int i;
string ret;
thing = _user_functions[func];
ret = "";
ret += query_type_name(thing->type) + " " + func + "(";
for (i = 0; i < sizeof(thing->arg_types); i++) {
ret += query_type_name(thing->arg_types[i]) + " " + thing->arg_names[i];
if (i < sizeof(thing->arg_types) - 1) {
ret += ", ";
}
}
ret += ") {\n ";
ret += replace_string(query_expression_string(thing->expr, 0),
"\n", "\n ") + "\n}\n";
return ret;
} /* query_user_function_string() */
/**
* This method evaluates the expression and creates a nice end result
* thingy.
* @param expr the exrpession to evaluate
* @param args the optional args parsed into the various function calls
* @return the type and value of the expression, 0 if failed
*/
class parse_node evaluate_expression(class parse_node* expr, mixed args ...) {
class parse_node bing;
class parse_node new_node;
class parse_node* stack;
string fname;
mixed* fargs;
int i;
if (!sizeof(expr)) {
return make_node(EXPRESSION_TYPE_BOOLEAN, 0, ({ }));
}
stack = ({ });
foreach (bing in expr) {
if (!classp(bing)) {
continue;
}
switch (bing->type) {
case EXPRESSION_TYPE_OPERATOR :
switch (bing->value) {
case EXPRESSION_NOT :
stack[<1] = make_node(EXPRESSION_TYPE_BOOLEAN, !stack[<1]->value, 0);
break;
case EXPRESSION_AND_NEW :
// First we evaluate one bit, then the other bit.
new_node = evaluate_expression(bing->tree[0],
args + ({ sizeof(args) }) ...);
if (!new_node->value) {
stack += ({ make_node(EXPRESSION_TYPE_BOOLEAN, 0, 0) });
} else {
new_node = evaluate_expression(bing->tree[1],
args ...);
stack += ({ make_node(EXPRESSION_TYPE_BOOLEAN, new_node->value, 0) });
}
//stack = stack[0..<2];
break;
case EXPRESSION_OR_NEW :
// First we evaluate one bit, then the other bit.
new_node = evaluate_expression(bing->tree[0],
args...);
if (new_node->value) {
stack += ({ make_node(EXPRESSION_TYPE_BOOLEAN, 1, 0) });
} else {
new_node = evaluate_expression(bing->tree[1],
args ...);
stack += ({ make_node(EXPRESSION_TYPE_BOOLEAN, new_node->value, 0) });
}
//stack = stack[0..<2];
break;
case EXPRESSION_AND :
stack[<2] = make_node(EXPRESSION_TYPE_BOOLEAN, stack[<1]->value &&
stack[<2]->value, 0);
stack = stack[0..<2];
break;
case EXPRESSION_OR :
stack[<2] = make_node(EXPRESSION_TYPE_BOOLEAN, stack[<1]->value ||
stack[<2]->value, 0);
stack = stack[0..<2];
break;
case EXPRESSION_PLUS :
stack[<2] = make_node(stack[<1]->type, stack[<2]->value +
stack[<1]->value, 0);
stack = stack[0..<2];
break;
case EXPRESSION_MINUS :
stack[<2] = make_node(stack[<1]->type, stack[<2]->value -
stack[<1]->value, 0);
stack = stack[0..<2];
break;
case EXPRESSION_DIVIDE :
stack[<2] = make_node(stack[<1]->type, stack[<2]->value /
stack[<1]->value, 0);
stack = stack[0..<2];
break;
case EXPRESSION_MULTIPLY :
stack[<2] = make_node(stack[<1]->type, stack[<2]->value *
stack[<1]->value, 0);
stack = stack[0..<2];
break;
case EXPRESSION_GREATOR_THAN :
stack[<2] = make_node(EXPRESSION_TYPE_BOOLEAN, stack[<2]->value >
stack[<1]->value, 0);
stack = stack[0..<2];
break;
case EXPRESSION_LESS_THAN :
stack[<2] = make_node(EXPRESSION_TYPE_BOOLEAN, stack[<2]->value <
stack[<1]->value, 0);
stack = stack[0..<2];
break;
case EXPRESSION_EQUAL_TO :
stack[<2] = make_node(EXPRESSION_TYPE_BOOLEAN, stack[<2]->value ==
stack[<1]->value, 0);
stack = stack[0..<2];
break;
case EXPRESSION_GREATOR_OR_EQUAL :
stack[<2] = make_node(EXPRESSION_TYPE_BOOLEAN, stack[<2]->value >=
stack[<1]->value, 0);
stack = stack[0..<2];
break;
case EXPRESSION_LESS_OR_EQUAL :
stack[<2] = make_node(EXPRESSION_TYPE_BOOLEAN, stack[<2]->value <=
stack[<1]->value, 0);
stack = stack[0..<2];
break;
case EXPRESSION_NOT_EQUAL_TO :
stack[<2] = make_node(EXPRESSION_TYPE_BOOLEAN, stack[<2]->value !=
stack[<1]->value, 0);
stack = stack[0..<2];
break;
case EXPRESSION_IF_NEW :
if (stack[<1]->value) {
new_node = evaluate_expression(bing->tree[0],
args ...);
} else {
new_node = evaluate_expression(bing->tree[1],
args ...);
}
stack = stack[0..<2] + ({ new_node });
break;
case EXPRESSION_IF :
if (stack[<3]->value) {
new_node = stack[<2];
} else {
new_node = stack[<1];
}
stack = stack[0..<4] + ({ new_node });
break;
case EXPRESSION_ARRAY_DEREFERENCE :
if (stack[<1]->value < 0 ||
stack[<1]->value >= sizeof(stack[<2]->value)) {
printf("Warning! Array out of bounds (" +
query_expression_string(expr, 1) + ")\n");
stack = stack[0..<3] + ({ query_null_type(EXPRESSION_TYPE_INTEGER) });
} else {
stack = stack[0..<3] +
({ make_node(stack[<1]->type - EXPRESSION_TYPE_ARRAY_OFFSET,
stack[<2]->value[stack[<1]->value], 0) });
}
break;
case EXPRESSION_ARRAY_AGGREGATE :
fargs = ({ });
for (i = 0; i < stack[<1]->value; i++) {
fargs += ({ stack[<i + 2]->value });
}
new_node = new(class parse_node,
type : stack[<2]->type + EXPRESSION_TYPE_ARRAY_OFFSET,
value : fargs);
stack = stack[0..<stack[<1]->value+2] + ({ new_node });
break;
case EXPRESSION_TRUE :
stack += ({ make_node(EXPRESSION_TYPE_BOOLEAN, 1, 0) });
break;
case EXPRESSION_FALSE :
stack += ({ make_node(EXPRESSION_TYPE_BOOLEAN, 0, 0) });
break;
default :
printf("Unknown operator %O\n", bing);
break;
}
break;
case EXPRESSION_TYPE_ARRAY_NULL :
stack += ({ new(class parse_node, type : EXPRESSION_TYPE_ARRAY_NULL,
value : ({ }) ) });
break;
case EXPRESSION_TYPE_INTEGER :
stack += ({ copy(bing) });
break;
case EXPRESSION_TYPE_STRING :
stack += ({ copy(bing) });
break;
case EXPRESSION_TYPE_MONEY :
stack += ({ copy(bing) });
break;
case EXPRESSION_TYPE_VARIABLE :
stack += ({ make_node(query_variable_type(bing->value),
evaluate(query_variable_value(bing->value),
args ...), 0) });
break;
case EXPRESSION_TYPE_FUNCTION_VARIABLE:
stack += ({ args[bing->value[EXPRESSION_FUNC_VAR_POS] + args[<1]] });
break;
case EXPRESSION_TYPE_USER_FUNCTION:
fname = bing->value[EXPRESSION_FUNC_NAME];
fargs = stack[<bing->value[EXPRESSION_FUNC_NO_ARGS]..];
stack = stack[0..<bing->value[EXPRESSION_FUNC_NO_ARGS] + 1];
if (!_user_functions[fname]) {
printf("Unknown function %O\n", fname);
break;
}
bing = evaluate_expression(_user_functions[fname]->expr,
args + fargs + ({ sizeof(args) }) ...);
if (!bing) {
printf("Broken return stuff.\n");
break;
}
stack += ({ bing });
break;
case EXPRESSION_TYPE_FUNCTION :
fname = bing->value[EXPRESSION_FUNC_NAME];
fargs = stack[<bing->value[EXPRESSION_FUNC_NO_ARGS]..];
stack = stack[0..<bing->value[EXPRESSION_FUNC_NO_ARGS] + 1];
stack += ({ make_node(query_function_type(fname),
evaluate(query_function_value(fname),
map(fargs, (: $1->value :)) +
args ...), 0) });
break;
default :
printf("Unknown type %O\n", bing);
break;
}
//printf("%O: %O\n", bing, stack);
}
return stack[<1];
} /* evaluate_expression() */