/* compute an expression or action given by an AST node */ Res* computeNode( Node *node, Node *reco, Env *env, ruleExecInfo_t *rei, int reiSaveFlag, rError_t* errmsg, Region *r ) { Hashtable *varTypes = newHashTable2( 10, r ); Region *rNew = make_region( 0, NULL ); Node *en; Node **errnode = &en; Res* res; int errorcode; if ( ( errorcode = typeNode( node, varTypes, errmsg, errnode, r ) ) != 0 ) { res = newErrorRes( r, errorcode ); RETURN; } if ( reco != NULL && ( errorcode = typeNode( reco, varTypes, errmsg, errnode, r ) ) != 0 ) { res = newErrorRes( r, errorcode ); RETURN; } if ( getNodeType( node ) == N_ACTIONS ) { res = evaluateActions( node, NULL, GlobalAllRuleExecFlag, rei, reiSaveFlag, env, errmsg, rNew ); } else { res = evaluateExpression3( node, GlobalAllRuleExecFlag, 0, rei, reiSaveFlag, env, errmsg, rNew ); } /* switch (TYPE(res)) { case T_ERROR: addRErrorMsg(errmsg, -1, "error: in rule"); break; default: break; }*/ ret: res = cpRes( res, r ); cpEnv( env, r ); region_free( rNew ); return res; }
/* make a new type by substituting tvars with fresh tvars */ ExprType *dupType(ExprType *ty, Region *r) { Hashtable *varTable = newHashTable2(100, r); /* todo add oom handler here */ ExprType *dup = dupTypeAux(ty, r, varTable); return dup; }
int checkPointExtRuleSet( Region *r ) { ruleEngineConfig.extFuncDescIndex = newEnv( newHashTable2( 100, r ), ruleEngineConfig.extFuncDescIndex, NULL, r ); return ruleEngineConfig.extRuleSet->len; }
Env *defaultEnv( Region *r ) { Env *global = newEnv( newHashTable2( 10, r ), NULL, NULL, r ); Env *env = newEnv( newHashTable2( 10, r ), global, NULL, r ); return env; }
ExprType *typeRuleSet( RuleSet *ruleset, rError_t *errmsg, Node **errnode, Region *r ) { Env *funcDesc = ruleEngineConfig.extFuncDescIndex; Hashtable *ruleType = newHashTable2( MAX_NUM_RULES * 2, r ); ExprType *res; int i; for ( i = 0; i < ruleset->len; i++ ) { RuleDesc *rule = ruleset->rules[i]; if ( rule->ruleType == RK_REL || rule->ruleType == RK_FUNC ) { List *typingConstraints = newList( r ); Hashtable *varTypes = newHashTable2( 100, r ); ExprType *restype = typeRule( rule, funcDesc, varTypes, typingConstraints, errmsg, errnode, r ); /*char buf[1024]; */ /*typingConstraintsToString(typingConstraints, buf, 1024); */ /*printf("rule %s, typing constraints: %s\n", ruleset->rules[i]->subtrees[0]->text, buf); */ if ( getNodeType( restype ) == T_ERROR ) { res = restype; char *errbuf = ( char * ) malloc( ERR_MSG_LEN * 1024 * sizeof( char ) ); errMsgToString( errmsg, errbuf, ERR_MSG_LEN * 1024 ); #ifdef DEBUG writeToTmp( "ruleerr.log", errbuf ); writeToTmp( "ruleerr.log", "\n" ); #endif rodsLog( LOG_ERROR, "%s", errbuf ); free( errbuf ); freeRErrorContent( errmsg ); RETURN; } /* check that function names are unique and do not conflict with system msis */ char errbuf[ERR_MSG_LEN]; char *ruleName = rule->node->subtrees[0]->text; FunctionDesc *fd; if ( ( fd = ( FunctionDesc * )lookupFromEnv( funcDesc, ruleName ) ) != NULL ) { if ( getNodeType( fd ) != N_FD_EXTERNAL && getNodeType( fd ) != N_FD_RULE_INDEX_LIST ) { char *err; switch ( getNodeType( fd ) ) { case N_FD_CONSTRUCTOR: err = "redefinition of constructor"; break; case N_FD_DECONSTRUCTOR: err = "redefinition of deconstructor"; break; case N_FD_FUNCTION: err = "redefinition of system microservice"; break; default: err = "redefinition of system symbol"; break; } generateErrMsg( err, NODE_EXPR_POS( rule->node ), rule->node->base, errbuf ); addRErrorMsg( errmsg, RE_FUNCTION_REDEFINITION, errbuf ); res = newErrorType( RE_FUNCTION_REDEFINITION, r ); *errnode = rule->node; RETURN; } } RuleDesc *rd = ( RuleDesc * )lookupFromHashTable( ruleType, ruleName ); if ( rd != NULL ) { if ( rule->ruleType == RK_FUNC || rd ->ruleType == RK_FUNC ) { generateErrMsg( "redefinition of function", NODE_EXPR_POS( rule->node ), rule->node->base, errbuf ); addRErrorMsg( errmsg, RE_FUNCTION_REDEFINITION, errbuf ); generateErrMsg( "previous definition", NODE_EXPR_POS( rd->node ), rd->node->base, errbuf ); addRErrorMsg( errmsg, RE_FUNCTION_REDEFINITION, errbuf ); res = newErrorType( RE_FUNCTION_REDEFINITION, r ); *errnode = rule->node; RETURN; } } else { insertIntoHashTable( ruleType, ruleName, rule ); } } } res = newSimpType( T_INT, r ); /* Although a rule set does not have type T_INT, return T_INT to indicate success. */ ret: return res; }
/* call an action with actionName and string parameters */ Res *computeExpressionWithParams( const char *actionName, const char **params, int paramsCount, ruleExecInfo_t *rei, int reiSaveFlag, msParamArray_t *msParamArray, rError_t *errmsg, Region *r ) { #ifdef DEBUG char buf[ERR_MSG_LEN > 1024 ? ERR_MSG_LEN : 1024]; snprintf( buf, 1024, "computExpressionWithParams: %s\n", actionName ); writeToTmp( "entry.log", buf ); #endif /* set clearDelayed to 0 so that nested calls to this function do not call clearDelay() */ int recclearDelayed = ruleEngineConfig.clearDelayed; ruleEngineConfig.clearDelayed = 0; if ( overflow( actionName, MAX_NAME_LEN ) ) { addRErrorMsg( errmsg, RE_BUFFER_OVERFLOW, "error: potential buffer overflow" ); return newErrorRes( r, RE_BUFFER_OVERFLOW ); } int k; for ( k = 0; k < paramsCount; k++ ) { if ( overflow( params[k], MAX_RULE_LEN ) ) { addRErrorMsg( errmsg, RE_BUFFER_OVERFLOW, "error: potential buffer overflow" ); return newErrorRes( r, RE_BUFFER_OVERFLOW ); } } Node** paramNodes = ( Node ** )region_alloc( r, sizeof( Node * ) * paramsCount ); int i; for ( i = 0; i < paramsCount; i++ ) { Node *node; /*Pointer *e = newPointer2(params[i]); if(e == NULL) { addRErrorMsg(errmsg, -1, "error: can not create Pointer."); return newErrorRes(r, -1); } node = parseTermRuleGen(e, 1, errmsg, r);*/ node = newNode( TK_STRING, params[i], 0, r ); /*if(node==NULL) { addRErrorMsg(errmsg, OUT_OF_MEMORY, "error: out of memory."); return newErrorRes(r, OUT_OF_MEMORY); } else if (getNodeType(node) == N_ERROR) { return newErrorRes(r, RES_ERR_CODE(node)); }*/ paramNodes[i] = node; } Node *node = createFunctionNode( actionName, paramNodes, paramsCount, NULL, r ); Env *global = newEnv( newHashTable2( 10, r ), NULL, NULL, r ); Env *env = newEnv( newHashTable2( 10, r ), global, NULL, r ); if ( msParamArray != NULL ) { convertMsParamArrayToEnv( msParamArray, global, r ); deleteFromHashTable(global->current, "ruleExecOut"); } Res *res = computeNode( node, NULL, env, rei, reiSaveFlag, errmsg, r ); /* deleteEnv(env, 3); */ if ( recclearDelayed ) { clearDelayed(); } ruleEngineConfig.clearDelayed = recclearDelayed; return res; }
/* parse and compute a rule */ int parseAndComputeRule( char *rule, Env *env, ruleExecInfo_t *rei, int reiSaveFlag, rError_t *errmsg, Region *r ) { if ( overflow( rule, MAX_RULE_LEN ) ) { addRErrorMsg( errmsg, RE_BUFFER_OVERFLOW, "error: potential buffer overflow" ); return RE_BUFFER_OVERFLOW; } Node *node; Pointer *e = newPointer2( rule ); if ( e == NULL ) { addRErrorMsg( errmsg, RE_POINTER_ERROR, "error: can not create a Pointer." ); return RE_POINTER_ERROR; } int tempLen = ruleEngineConfig.extRuleSet->len; int checkPoint = checkPointExtRuleSet( r ); int rescode; int errloc; /* add rules into ext rule set */ rescode = parseRuleSet( e, ruleEngineConfig.extRuleSet, ruleEngineConfig.extFuncDescIndex, &errloc, errmsg, r ); deletePointer( e ); if ( rescode != 0 ) { return RE_PARSER_ERROR; } RuleDesc *rd = NULL; Res *res = NULL; /* add rules into rule index */ int i; for ( i = tempLen; i < ruleEngineConfig.extRuleSet->len; i++ ) { if ( ruleEngineConfig.extRuleSet->rules[i]->ruleType == RK_FUNC || ruleEngineConfig.extRuleSet->rules[i]->ruleType == RK_REL ) { appendRuleIntoExtIndex( ruleEngineConfig.extRuleSet->rules[i], i, r ); } } for ( i = tempLen; i < ruleEngineConfig.extRuleSet->len; i++ ) { if ( ruleEngineConfig.extRuleSet->rules[i]->ruleType == RK_FUNC || ruleEngineConfig.extRuleSet->rules[i]->ruleType == RK_REL ) { Hashtable *varTypes = newHashTable2( 10, r ); List *typingConstraints = newList( r ); Node *errnode; ExprType *type = typeRule( ruleEngineConfig.extRuleSet->rules[i], ruleEngineConfig.extFuncDescIndex, varTypes, typingConstraints, errmsg, &errnode, r ); if ( getNodeType( type ) == T_ERROR ) { /* rescode = TYPE_ERROR; # TGR, since renamed to RE_TYPE_ERROR */ rescode = RE_TYPE_ERROR; RETURN; } } } /* exec the first rule */ rd = ruleEngineConfig.extRuleSet->rules[tempLen]; node = rd->node; res = execRuleNodeRes( node, NULL, 0, GlobalAllRuleExecFlag, env, rei, reiSaveFlag, errmsg, r ); rescode = getNodeType( res ) == N_ERROR ? RES_ERR_CODE( res ) : 0; ret: /* remove rules from ext rule set */ popExtRuleSet( checkPoint ); return rescode; }