/** * get symbol's name * * @param[in] sem is the semantic table where symbols and structures are define * @param[in] s the Symbol to return the label of * @returns cstring surface of the first label in the definition * * <b>Examples (from test suite):</b> * @snippet spec/semtable_spec.h testSemTableGetName */ char *_sem_get_name(SemTable *sem,SemanticID s) { if (s.id == 0) { if (s.context == SYS_CONTEXT) { switch (s.semtype) { case SEM_TYPE_STRUCTURE: return "NULL_STRUCTURE"; case SEM_TYPE_SYMBOL: return "NULL_SYMBOL"; case SEM_TYPE_PROCESS: return "NULL_PROCESS"; case SEM_TYPE_RECEPTOR: return "SYS_RECEPTOR"; default: raise_error("bad semtype"); } } else { raise_error("unexpected semantic NULL id!"); } } T *def = _sem_get_def(sem,s); char *n = NULL; if (def) { int path[] ={DefLabelIdx,1,TREE_PATH_TERMINATOR}; T *t = _t_get(def,path); if (!t) raise_error("missing label!"); n = (char *)_t_surface(t); } return n; }
/** * implements the INTERPOLATE_FROM_MATCH process * * replaces the interpolation tree with the matched sub-parts from a semtrex match results tree * * @param[in] t interpolation tree to be scanned for INTERPOLATE_SYMBOL nodes * @param[in] match_results SEMTREX_MATCH_RESULTS tree * @param[in] match_tree original tree that was matched (needed to grab the data to interpolate) * @todo what to do if match has sibs?? */ void _p_interpolate_from_match(T *t,T *match_results,T *match_tree) { if (semeq(_t_symbol(t),INTERPOLATE_SYMBOL)) { Symbol s = *(Symbol *)_t_surface(t); T *m = _t_get_match(match_results,s); if (!m) { raise_error0("expected to have match!"); } int *path = (int *)_t_surface(_t_child(m,2)); int sibs = *(int*)_t_surface(_t_child(m,3)); T *x = _t_get(match_tree,path); if (!x) { raise_error0("expecting to get a value from match!!"); } _t_morph(t,x); } DO_KIDS(t,_p_interpolate_from_match(_t_child(t,i),match_results,match_tree)); }
/** * take one step in the execution state machine given a run-tree context * * a run_tree is expected to have a code tree as the first child, parameters as the second, * and optionally an error handling routine as the third child. * * @param[in] processes context of defined processes * @param[in] pointer to context pointer * @returns the next state that will be called for the context */ Error _p_step(Defs *defs, R **contextP) { R *context = *contextP; switch(context->state) { case noReductionErr: case Block: case Send: raise_error0("whoa, virtual states can't be executed!"); // shouldn't be calling step if Done or noErr or Block or Send break; case Pop: // if this was the successful reduction by an error handler // move the value to the 1st child if (context->err) { T *t = _t_detach_by_idx(context->run_tree,3); if (t) { _t_replace(context->run_tree,1,t); context->err = noReductionErr; } } // if this is top caller on the stack then we are completely done if (!context->caller) { context->state = Done; break; } else { // otherwise pop the context R *ctx = context; context = context->caller; // set the new context if (!ctx->err) { // get results of the run_tree T *np = _t_detach_by_idx(ctx->run_tree,1); _t_replace(context->parent,context->idx,np); // replace the process call node with the result rt_cur_child(np) = RUN_TREE_EVALUATED; context->node_pointer = np; context->state = Eval; // or possible ascend?? } else context->state = ctx->err; // cleanup _t_free(ctx->run_tree); free(ctx); context->callee = 0; *contextP = context; } break; case Eval: { T *np = context->node_pointer; if (!np) { raise_error0("Whoa! Null node pointer"); } Process s = _t_symbol(np); if (semeq(s,PARAM_REF)) { T *param = _t_get(context->run_tree,(int *)_t_surface(np)); if (!param) { raise_error0("request for non-existent param"); } context->node_pointer = np = _t_rclone(param); _t_replace(context->parent, context->idx,np); s = _t_symbol(np); } // @todo what if the replaced parameter is itself a PARAM_REF tree ?? // if this node is not a process, i.e. it's data, then we are done descending // and it will be the result so ascend if (!is_process(s)) { context->state = Ascend; } else { int c = _t_children(np); if (c == rt_cur_child(np) || semeq(s,QUOTE)) { // if the current child == the child count this means // all the children have been processed, so we can evaluate this process // if the process is QUOTE that's a special case and we evaluate it // immediately without descending. if (!is_sys_process(s)) { // if it's user defined process then we check the signature and then make // a new run-tree run that process Error e = __p_check_signature(defs,s,np); if (e) context->state = e; else { T *run_tree = __p_make_run_tree(defs->processes,s,np); context->state = Pushed; *contextP = __p_make_context(run_tree,context); } } else { // if it's a sys process we can just reduce it in and then ascend // or move to the error handling state Error e = __p_reduce_sys_proc(context,s,np); context->state = e ? e : Ascend; } } else if(c) { //descend and increment the current child we're working on! context->state = Descend; } else { raise_error0("whoa! brain fart!"); } } } break; case Ascend: rt_cur_child(context->node_pointer) = RUN_TREE_EVALUATED; context->node_pointer = context->parent; context->parent = _t_parent(context->node_pointer); if (!context->parent || context->parent == context->run_tree) { context->idx = 1; } else context->idx = rt_cur_child(context->parent); if (context->node_pointer == context->run_tree) context->state = Pop; else context->state = Eval; break; case Descend: context->parent = context->node_pointer; context->idx = ++rt_cur_child(context->node_pointer); context->node_pointer = _t_child(context->node_pointer,context->idx); context->state = Eval; break; default: context->err = context->state; if (_t_children(context->run_tree) <= 2) { // no error handler so just return the error context->state = Pop; } else { // the first parameter to the error code is always a reduction error // which gets added on as the 4th child of the run tree when the // error happens. T *ps = _t_newr(context->run_tree,PARAMS); //@todo: fix this so we don't actually use an error value that // then has to be translated into a symbol, but rather so that we // can programatically calculate the symbol. Symbol se; switch(context->state) { case tooFewParamsReductionErr: se=TOO_FEW_PARAMS_ERR;break; case tooManyParamsReductionErr: se=TOO_MANY_PARAMS_ERR;break; case signatureMismatchReductionErr: se=SIGNATURE_MISMATCH_ERR;break; case notProcessReductionError: se=NOT_A_PROCESS_ERR;break; case notInSignalContextReductionError: se=NOT_IN_SIGNAL_CONTEXT_ERR; case divideByZeroReductionErr: se=ZERO_DIVIDE_ERR;break; case incompatibleTypeReductionErr: se=INCOMPATIBLE_TYPE_ERR;break; case raiseReductionErr: se = *(Symbol *)_t_surface(_t_child(context->node_pointer,1)); break; default: raise_error("unknown reduction error: %d",context->state); } T *err = __t_new(ps,se,0,0,sizeof(rT)); int *path = _t_get_path(context->node_pointer); _t_new(err,ERROR_LOCATION,path,sizeof(int)*(_t_path_depth(path)+1)); free(path); // switch the node_pointer to the top of the error handling routine context->node_pointer = _t_child(context->run_tree,3); context->idx = 3; context->parent = context->run_tree; context->state = Eval; } } return context->state; }
/** * bootstrap the ceptr system * * starts up the vmhost and wakes up receptors that should be running in it. * * @TODO check the compository to verify our version of the vmhost * */ void _a_boot(char *dir_path) { // check if the storage directory exists struct stat st = {0}; if (stat(dir_path, &st) == -1) { // if no directory we are firing up an initial instance, so // create directory mkdir(dir_path,0700); // instantiate a VMHost object G_vm = _v_new(); // create the basic receptors that all VMHosts have _v_instantiate_builtins(G_vm); } else { char fn[1000]; void *buffer; // unserialize the semtable base tree SemTable *sem = _sem_new(); T *t = __a_unserializet(dir_path,SEM_FN); sem->stores[0].definitions = t; // restore definitions to the correct store slots T *paths = __a_unserializet(dir_path,PATHS_FN); int i = 0; int c = _t_children(paths); for(i=1;i<=c;i++) { T *p = _t_child(paths,i); if (semeq(RECEPTOR_PATH,_t_symbol(p))) { T *x = _t_get(t,(int *)_t_surface(p)); sem->stores[i-1].definitions = x; } } _t_free(paths); sem->contexts = c+1; // unserialize all of the vmhost's instantiated receptors and other instances __a_vmfn(fn,dir_path); buffer = readFile(fn,0); Receptor *r = _r_unserialize(sem,buffer); G_vm = __v_init(r,sem); free(buffer); // unserialize other vmhost state data S *s; __a_vm_state_fn(fn,dir_path); s = readFile(fn,0); H h = _m_unserialize(s); free(s); H hars; hars.m=h.m; hars.a = _m_child(h,1); // first child is ACTIVE_RECEPTORS H har; har.m=h.m; int j = _m_children(hars); for (i=1;i<=j;i++) { har.a = _m_child(hars,i); if(!semeq(_m_symbol(har),RECEPTOR_XADDR)) raise_error("expecting RECEPTOR_XADDR!"); _v_activate(G_vm,*(Xaddr *)_m_surface(har)); } _m_free(h); } G_vm->dir = dir_path; // _a_check_vm_host_version_on_the_compository(); _v_start_vmhost(G_vm); }