📄 builtins.c
字号:
*result = list_new( *result, copystr( *(char**)np ) );}static struct hash *get_running_module_vars(){ struct hash *dummy, *vars = NULL; /* Get the global variables pointer (that of the currently running module) */ var_hash_swap(&vars); dummy = vars; /* Put the global variables pointer in its right place */ var_hash_swap(&dummy); return vars;}LIST *builtin_varnames( PARSE *parse, FRAME *frame ){ LIST *arg0 = lol_get( frame->args, 0 ); LIST *result = L0; module_t* source_module = bindmodule( arg0 ? arg0->string : 0 ); /* The running module _always_ has its 'variables' member set to NULL * due to the way enter_module and var_hash_swap work */ struct hash *vars = source_module == frame->module ? get_running_module_vars() : source_module->variables; if ( vars ) hashenumerate( vars, add_hash_key, &result ); return result;}/* * builtin_delete_module() - MODULE ? * * Clears all rules and variables from the given module. */LIST *builtin_delete_module( PARSE *parse, FRAME *frame ){ LIST *arg0 = lol_get( frame->args, 0 ); LIST *result = L0; module_t* source_module = bindmodule( arg0 ? arg0->string : 0 ); delete_module( source_module ); return result;}static void unknown_rule( FRAME *frame, char* key, char *module_name, char *rule_name ){ backtrace_line( frame->prev ); printf( "%s error: rule \"%s\" unknown in module \"%s\"\n", key, rule_name, module_name ); backtrace( frame->prev ); exit(1); }/* * builtin_import() - IMPORT ( SOURCE_MODULE ? : SOURCE_RULES * : TARGET_MODULE ? : TARGET_RULES * : LOCALIZE ? ) * * The IMPORT rule imports rules from the SOURCE_MODULE into the * TARGET_MODULE as local rules. If either SOURCE_MODULE or * TARGET_MODULE is not supplied, it refers to the global * module. SOURCE_RULES specifies which rules from the SOURCE_MODULE * to import; TARGET_RULES specifies the names to give those rules in * TARGET_MODULE. If SOURCE_RULES contains a name which doesn't * correspond to a rule in SOURCE_MODULE, or if it contains a * different number of items than TARGET_RULES, an error is issued. * if LOCALIZE is specified, the rules will be executed in * TARGET_MODULE, with corresponding access to its module local * variables. */LIST *builtin_import( PARSE *parse, FRAME *frame ){ LIST *source_module_list = lol_get( frame->args, 0 ); LIST *source_rules = lol_get( frame->args, 1 ); LIST *target_module_list = lol_get( frame->args, 2 ); LIST *target_rules = lol_get( frame->args, 3 ); LIST *localize = lol_get( frame->args, 4 ); module_t* target_module = bindmodule( target_module_list ? target_module_list->string : 0 ); module_t* source_module = bindmodule( source_module_list ? source_module_list->string : 0 ); LIST *source_name, *target_name; for ( source_name = source_rules, target_name = target_rules; source_name && target_name; source_name = list_next( source_name ) , target_name = list_next( target_name ) ) { RULE r_, *r = &r_, *imported; r_.name = source_name->string; if ( !source_module->rules || !hashcheck( source_module->rules, (HASHDATA**)&r ) ) { unknown_rule( frame, "IMPORT", source_module->name, r_.name ); } imported = import_rule( r, target_module, target_name->string ); if ( localize ) imported->module = target_module; imported->exported = 0; /* this rule is really part of some other module; just refer to it here, but don't let it out */ } if ( source_name || target_name ) { backtrace_line( frame->prev ); printf( "import error: length of source and target rule name lists don't match!\n" ); printf( " source: " ); list_print( source_rules ); printf( "\n target: " ); list_print( target_rules ); printf( "\n" ); backtrace( frame->prev ); exit(1); } return L0;}/* * builtin_export() - EXPORT ( MODULE ? : RULES * ) * * The EXPORT rule marks RULES from the SOURCE_MODULE as non-local * (and thus exportable). If an element of RULES does not name a rule * in MODULE, an error is issued. */LIST *builtin_export( PARSE *parse, FRAME *frame ){ LIST *module_list = lol_get( frame->args, 0 ); LIST *rules = lol_get( frame->args, 1 ); module_t* m = bindmodule( module_list ? module_list->string : 0 ); for ( ; rules; rules = list_next( rules ) ) { RULE r_, *r = &r_; r_.name = rules->string; if ( !m->rules || !hashcheck( m->rules, (HASHDATA**)&r ) ) unknown_rule( frame, "EXPORT", m->name, r_.name ); r->exported = 1; } return L0;}/* Retrieve the file and line number that should be indicated for a * given procedure in debug output or an error backtrace */static void get_source_line( PARSE* procedure, char** file, int* line ){ if ( procedure ) { char* f = procedure->file; int l = procedure->line; if ( !strcmp( f, "+" ) ) { f = "jambase.c"; l += 3; } *file = f; *line = l; } else { *file = "(builtin)"; *line = -1; }}void print_source_line( PARSE* p ){ char* file; int line; get_source_line( p, &file, &line ); if ( line < 0 ) printf( "(builtin):" ); else printf( "%s:%d:", file, line);}/* Print a single line of error backtrace for the given frame */void backtrace_line( FRAME *frame ){ if ( frame == 0 ) { printf( "(no frame):" ); } else { print_source_line( frame->procedure ); printf( " in %s\n", frame->rulename ); }}/* Print the entire backtrace from the given frame to the Jambase * which invoked it. */void backtrace( FRAME *frame ){ if ( !frame ) return; while ( frame = frame->prev ) { backtrace_line( frame ); }}/* A Jam version of the backtrace function, taking no arguments and * returning a list of quadruples: FILENAME LINE MODULE. RULENAME * describing each frame. Note that the module-name is always * followed by a period. */LIST *builtin_backtrace( PARSE *parse, FRAME *frame ){ LIST* levels_arg = lol_get( frame->args, 0 ); int levels = levels_arg ? atoi( levels_arg->string ) : ((unsigned int)(-1) >> 1) ; LIST* result = L0; for(; (frame = frame->prev) && levels ; --levels ) { char* file; int line; char buf[32]; get_source_line( frame->procedure, &file, &line ); sprintf( buf, "%d", line ); result = list_new( result, newstr( file ) ); result = list_new( result, newstr( buf ) ); result = list_new( result, newstr( frame->module->name ) ); result = list_new( result, newstr( frame->rulename ) ); } return result;}/* * builtin_caller_module() - CALLER_MODULE ( levels ? ) * * If levels is not supplied, returns the name of the module of the rule which * called the one calling this one. If levels is supplied, it is interpreted as * an integer specifying a number of additional levels of call stack to traverse * in order to locate the module in question. If no such module exists, * returns the empty list. Also returns the empty list when the module in * question is the global module. This rule is needed for implementing module * import behavior. */LIST *builtin_caller_module( PARSE *parse, FRAME *frame ){ LIST* levels_arg = lol_get( frame->args, 0 ); int levels = levels_arg ? atoi( levels_arg->string ) : 0 ; int i; for (i = 0; i < levels + 2 && frame->prev; ++i) frame = frame->prev; if ( frame->module == root_module() ) { return L0; } else { LIST* result; string name; string_copy( &name, frame->module->name ); string_pop_back( &name ); result = list_new( L0, newstr(name.value) ); string_free( &name ); return result; }}/* * Return the current working directory. * * Usage: pwd = [ PWD ] ; */LIST*builtin_pwd( PARSE *parse, FRAME *frame ){ return pwd();}/* * Adds targets to the list of target that jam will attempt to update. */LIST* builtin_update( PARSE *parse, FRAME *frame){ LIST* result = list_copy( L0, targets_to_update() ); LIST* arg1 = lol_get( frame->args, 0 ); clear_targets_to_update(); for ( ; arg1; arg1 = list_next( arg1 ) ) mark_target_for_updating( newstr(arg1->string) ); return result;}LIST*builtin_search_for_target( PARSE *parse, FRAME *frame ){ LIST* arg1 = lol_get( frame->args, 0 ); LIST* arg2 = lol_get( frame->args, 1 ); TARGET* t = search_for_target( arg1->string, arg2 ); return list_new( L0, t->name );}LIST *builtin_import_module( PARSE *parse, FRAME *frame ){ LIST* arg1 = lol_get( frame->args, 0 ); LIST* arg2 = lol_get( frame->args, 1 ); module_t* m = arg2 ? bindmodule(arg2->string) : root_module(); import_module(arg1, m); return L0;}LIST *builtin_imported_modules( PARSE *parse, FRAME *frame ){ LIST *arg0 = lol_get( frame->args, 0 ); module_t* source_module = bindmodule( arg0 ? arg0->string : 0 ); return imported_modules(source_module);}LIST *builtin_instance( PARSE *parse, FRAME *frame ){ LIST* arg1 = lol_get( frame->args, 0 ); LIST* arg2 = lol_get( frame->args, 1 ); module_t* instance = bindmodule( arg1->string ); module_t* class_module = bindmodule( arg2->string ); instance->class_module = class_module; return L0;}LIST*builtin_sort( PARSE *parse, FRAME *frame ){ LIST* arg1 = lol_get( frame->args, 0 ); return list_sort(arg1);}LIST *builtin_normalize_path( PARSE *parse, FRAME *frame ){ LIST* arg = lol_get( frame->args, 0 ); /* First, we iterate over all '/'-separated elements, starting from the end of string. If we see '..', we remove previous path elements. If we see '.', we remove it. The removal is done by putting '\1' in the string. After all the string is processed, we do a second pass, removing '\1' characters. */ string in[1], out[1], tmp[1]; char* end; /* Last character of the part of string still to be processed. */ char* current; /* Working pointer. */ int dotdots = 0; /* Number of '..' elements seen and not processed yet. */ int rooted = arg->string[0] == '/'; char* result; /* Make a copy of input: we should not change it. */ string_new(in); if (!rooted) string_push_back(in, '/'); while (arg) { string_append(in, arg->string); arg = list_next(arg); if (arg) string_append(in, "/"); } /* Convert \ into /. On windows, paths using / and \ are equivalent, and we want this function to obtain canonic representation. */ for (current = in->value, end = in->value + in->size; current < end; ++current) if (*current == '\\') *current = '/'; end = in->value + in->size - 1; current = end; for(;end >= in->value;) { /* Set 'current' to the next occurence of '/', which always exists. */ for(current = end; *current != '/'; --current) ; if (current == end && current != in->value) { /* Found a trailing slash. Remove it. */ *current = '\1'; } else if (current == end && *(current+1) == '/') { /* Found duplicated slash. Remove it. */ *current = '\1'; } else if (end - current == 1 && strncmp(current, "/.", 2) == 0) { /* Found '/.'. Drop them all. */ *current = '\1'; *(current+1) = '\1'; } else if (end - current == 2 && strncmp(current, "/..", 3) == 0) { /* Found '/..' */ *current = '\1'; *(current+1) = '\1'; *(current+2) = '\1'; ++dotdots; } else if (dotdots) { char* p = current; memset(current, '\1', end-current+1); --dotdots; } end = current-1; } string_new(tmp); while(dotdots--) string_append(tmp, "/.."); string_append(tmp, in->value); string_copy(in, tmp->value); string_free(tmp); string_new(out); /* The resulting path is either empty or has '/' as the first significant element. If the original path was not rooted, we need to drop first '/'. If the original path was rooted, and we've got empty path, need to add '/' */ if (!rooted) { current = strchr(in->value, '/'); if (current) *current = '\1'; } for (current = in->value; *current; ++current) if (*current != '\1') string_push_back(out, *current); result = newstr(out->size ? out->value : (rooted ? "/" : ".")); string_free(in); string_free(out); return list_new(0, result);}LIST *builtin_native_rule( PARSE *parse, FRAME *frame ){ LIST* module_name = lol_get( frame->args, 0 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -