// only promote numbers u64 ts_promote_typeid(u64 a, u64 b) { ty_t t_a = ts_type_table[a]; ty_t t_b = ts_type_table[b]; fl_assert(t_a.of == TY_NUMBER); fl_assert(t_b.of == TY_NUMBER); // check floating point if (t_a.number.fp && !t_b.number.fp) { return a; } if (t_b.number.fp && !t_a.number.fp) { return b; } // check different sign if (!t_b.number.sign && t_a.number.sign) { return a; } if (t_b.number.sign && !t_a.number.sign) { return b; } // check bits return t_a.number.bits > t_b.number.bits ? a : b; }
ast_t* psr_file_main(const char* filename) { string* code = psr_file_to_string(filename); ast_t* root = __psr_parse(code, filename); fl_assert(root->type == AST_PROGRAM); psr_attach_core(root); ast_parent(root); return root; }
void __foreach_function(char* key, void* ptr) { fl_assert(ptr != 0); array* list = (array*)ptr; for (u64 i = 0; i < list->length; ++i) { ast_t* node = (ast_t*)list->values[0]; if (st_cmp(node->func.id->identifier.string, __target_id) == 0) { log_silly("function found!"); array_push_unique(__target_arr, node); } } }
ast_action_t __trav_load_imports(AST_CB_T_HEADER) { if (mode == AST_TRAV_LEAVE) return 0; if (node->type == AST_IMPORT && !node->import.imported) { fl_assert(parent->type == AST_LIST); char* file = node->import.path->string.value->value; log_verbose("loading module %s", file); char filepath[1024] = ""; if (file[0] == '.' && file[1] == '/') { ast_t* root = ast_get_root(node); strcat(filepath, dirname(root->program.file->value)); strcat(filepath, "/"); strcat(filepath, file + 2); strcat(filepath, ".fl"); } else { strcat(filepath, "./"); strcat(filepath, file); strcat(filepath, ".fl"); } // printf("load module %s\n", filepath); ast_t* module = psr_file(filepath); if (ast_print_error(module)) { fl_fatal_error("parse error, failed to load module: '%s' at '%s'\n", file, filepath); } module->type = AST_MODULE; // ast_mk_insert_before(parent, node, module); ast_t* block_scope = ast_get_scope(node); array_push(&block_scope->block.modules, module); module->parent = block_scope; log_verbose("module loaded %s at %p count=%lu", file, module, block_scope->block.modules.length); // no reimport node->import.imported = true; ((*(u64*)userdata_out))++; } return AST_SEARCH_CONTINUE; }
// TODO this should recieve left/right node because right node may need to be // check for casting ast_t* ast_scope_binop_operator(ast_t* node, int operator, u64 lty_id, u64 rty_id) { u64 can_left_ty_id = ty_get_cannonical(lty_id); // first search array* scopes = ast_get_scopes(node); if (!scopes) return 0; log_silly("searching for '%d' in %lu scopes", operator, scopes->length); for (u64 i = 0; i < scopes->length; ++i) { hash_t* hash = ((ast_t*)scopes->values[i])->block.functions; HASH_EACH(hash, entry, { if (entry->value) { array* functions = (array*)entry->value; for (u64 j = 0; j < functions->length; ++j) { ast_t* fn = functions->values[j]; if (fn->func.type == AST_FUNC_OPERATOR && fn->func.operator== operator) { log_silly("operator found! check params!"); // now check both types ast_t* params = fn->func.params; fl_assert(params->list.length == 2); // jsut to be sure ^^ // TODO REVIEW right now we only check the first parameter // expecting the second to be castable, working but had // edge cases // params->list.values[1]->ty_id == rty_id if (params->list.values[0]->ty_id == lty_id || params->list.values[0]->ty_id == can_left_ty_id) { log_silly("function found[id=%lu]", fn->id); return fn; } } } } }); }
array* ast_get_scopes(ast_t* node) { array* ret = pool_new(sizeof(array)); array_new(ret); do { node = ast_get_scope(node); array_push(ret, node); for (i64 i = 0; i < node->block.modules.length; ++i) { ast_t* module = (ast_t*)node->block.modules.values[i]; fl_assert(module->program.body->type == AST_BLOCK); array_push(ret, module->program.body); } } while (node->block.scope != AST_SCOPE_GLOBAL); if (!ret->length) { array_delete(ret); pool_free(ret); return 0; } return ret; }
u64 __ts_string_to_tyid(ast_t* node) { fl_assert(node != 0); fl_assert(node->type == AST_TYPE); // empty var_decl for example if (!node->ty.id) { return 0; } // once set do not modify, unless you want it // like when implementing a struct templated if (node->ty_id) { return node->ty_id; } string* t_str = node->ty.id->identifier.string; char* tcstr = t_str->value; // built-in if (strcmp(tcstr, "auto") == 0) { return node->ty.id->ty_id = node->ty_id = 0; // inference } if (strcmp(tcstr, "bool") == 0) { return node->ty.id->ty_id = node->ty_id = TS_BOOL; } if (strcmp(tcstr, "void") == 0) { return node->ty.id->ty_id = node->ty_id = TS_VOID; } if (strcmp(tcstr, "i8") == 0) { return node->ty.id->ty_id = node->ty_id = TS_I8; } if (strcmp(tcstr, "u8") == 0) { return node->ty.id->ty_id = node->ty_id = TS_U8; } if (strcmp(tcstr, "i16") == 0) { return node->ty.id->ty_id = node->ty_id = TS_I16; } if (strcmp(tcstr, "u16") == 0) { return node->ty.id->ty_id = node->ty_id = TS_U16; } if (strcmp(tcstr, "i32") == 0) { return node->ty.id->ty_id = node->ty_id = TS_I32; } if (strcmp(tcstr, "u32") == 0) { return node->ty.id->ty_id = node->ty_id = TS_U32; } if (strcmp(tcstr, "i64") == 0) { return node->ty.id->ty_id = node->ty_id = TS_I64; } if (strcmp(tcstr, "u64") == 0) { return node->ty.id->ty_id = node->ty_id = TS_U64; } if (strcmp(tcstr, "f32") == 0) { return node->ty.id->ty_id = node->ty_id = TS_F32; } if (strcmp(tcstr, "f64") == 0) { return node->ty.id->ty_id = node->ty_id = TS_F64; } if (strcmp(tcstr, "string") == 0) { // return node->ty.id->ty_id = node->ty_id = TS_CSTR; // TODO TS_STRING // return node->ty.id->ty_id = node->ty_id = TS_STRING; return node->ty.id->ty_id = node->ty_id = 16; } if (strcmp(tcstr, "ptrdiff") == 0) { return node->ty.id->ty_id = node->ty_id = TS_PTRDIFF; } // type below are wrappers, this means they can appear inside a struct // pointing to themself, so if our parent is a struct, we should use auto // an in the second pass auto will be replaced with the struct type if (strcmp(tcstr, "ptr") == 0) { fl_assert(node->ty.children != 0); fl_assert(node->ty.children->list.length == 1); // TODO raise ts_register_types_pass(node->ty.children); u64 t = __ts_string_to_tyid(node->ty.children->list.values[0]); if (!t && !ast_has_parent(node, AST_DECL_STRUCT)) return 0; return node->ty.id->ty_id = node->ty_id = ty_create_wrapped(TY_POINTER, t); } if (strcmp(tcstr, "vector") == 0) { fl_assert(node->ty.children != 0); fl_assert(node->ty.children->list.length == 1); // TODO raise ts_register_types_pass(node->ty.children); u64 t = __ts_string_to_tyid(node->ty.children->list.values[0]); if (!t && !ast_has_parent(node, AST_DECL_STRUCT)) return 0; return node->ty.id->ty_id = node->ty_id = ty_create_wrapped(TY_VECTOR, t); } if (strcmp(tcstr, "ref") == 0) { fl_assert(node->ty.children != 0); fl_assert(node->ty.children->list.length == 1); // TODO raise ts_register_types_pass(node->ty.children); u64 t = __ts_string_to_tyid(node->ty.children->list.values[0]); if (!t && !ast_has_parent(node, AST_DECL_STRUCT)) return 0; return node->ty.id->ty_id = node->ty_id = ty_create_wrapped(TY_REFERENCE, t); } log_silly("search type for '%s'", tcstr); ast_t* scope = node; ast_t* el = node; array* scopes = ast_get_scopes(node); if (!scopes) { log_warning("delayed type '%s'", tcstr); return 0; } for (u64 i = 0; i < scopes->length; ++i) { scope = ((ast_t*)scopes->values[i]); el = hash_get(scope->block.types, tcstr); if (el != 0) { // check if it's a struct with templates, in wich case, we need to // implement / reuse if (el->type == AST_DECL_STRUCT && el->structure.tpls != 0) { // if it has children defined, then implement // TODO check there is no template type in the list if (node->ty.children) { // register children-types first ts_register_types_pass(node->ty.children); // check that there is no template children bool templated = false; for (int i = 0; i < node->ty.children->list.length; ++i) { if (ty_is_templated(node->ty.children->list.values[i]->ty_id)) { templated = true; } } if (templated) { ast_raise_error(node, "type error, try to implement a template " "using another template"); } // implement el = ast_implement_struct(node->ty.children, el, 0); // enjoy :) } else { // if not it just is just a reference, get the type and wait to // be implemented later } } return node->ty.id->ty_id = node->ty_id = el->ty_id; } } log_warning("delayed type '%s'", tcstr); return 0; }
ast_action_t __trav_register_types(AST_CB_T_HEADER) { if (mode == AST_TRAV_LEAVE) return 0; if (node->ty_id) return AST_SEARCH_CONTINUE; switch (node->type) { case AST_DECL_TEMPLATE: node->tpl.id->ty_id = node->ty.id->ty_id = node->ty_id = ty_create_template(node); break; case AST_DECL_STRUCT: // TODO this need review, we don't want a gap in the type table... // if has templates need to be implemented before has a ty_id // if (node->structure.tpls == 0) { ts_register_types_pass(node->structure.fields); node->ty.id->ty_id = node->ty_id = ty_create_struct(node); //} break; case AST_DECL_FUNCTION: // declare the function ts_register_types_pass(node->func.params); ts_register_types_pass(node->func.ret_type); node->ty.id->ty_id = node->ty_id = ty_create_fn(node); // add the virtual to the list in the type, only once if (node->func.type == AST_FUNC_PROPERTY && node->ts_passes == 0) { node->ts_passes = 1; ty_struct_add_virtual(node); } // add the operator to the list in the type, only once if (node->func.type == AST_FUNC_OPERATOR && node->ts_passes == 0) { node->ts_passes = 1; ty_struct_add_operator(node); } break; case AST_TYPE: { // check wrappers ast_t* p = node->parent; __ts_string_to_tyid(node); // sometimes the types are not fully built so wait for the second pass // if (!node->ty_id) return AST_SEARCH_CONTINUE; switch (p->type) { case AST_DECL_FUNCTION: case AST_TYPE: // just ignore break; case AST_DTOR_VAR: p->ty_id = node->ty_id; p->var.id->ty_id = node->ty_id; ty_create_var(p); break; case AST_PARAMETER: p->ty_id = node->ty_id; p->param.id->ty_id = node->ty_id; break; case AST_DECL_STRUCT_FIELD: p->ty_id = node->ty_id; p->field.id->ty_id = node->ty_id; break; case AST_DECL_STRUCT_ALIAS: // at this point, struct is no created, so we cannot determine // the real type. we will do it @ty_create_struct break; case AST_CAST: p->ty_id = node->ty_id; break; case AST_EXPR_TYPEOF: case AST_EXPR_SIZEOF: p->ty_id = TS_I64; break; case AST_LIST: // TODO this need review break; case AST_DELETE: case AST_NEW: { p->ty_id = node->ty_id; } break; default: { fl_assert(false); } } } default: {} // supress warning } return AST_SEARCH_CONTINUE; }
//----------------------------------------------------------------- // Main: Test bench file to create 5 files with psuedo random // sequences in of varying lengths - read them back and complete // then remove them. //----------------------------------------------------------------- void main() { int i,j,x; FL_FILE * files[5]; FL_FILE *readFile; char filenames[5][260]; BYTE fileData[5][10000]; BYTE readBuffer[10000]; int fileLengths[5]; BYTE *massiveData; time_t timeStart, timeEnd; #define TESTFILES 6 char *testfile[] = { "X:\\1", "X:\\1.bin", "X:\\12345678.321", "X:\\mylongfilename", "X:\\mylongfilename.bin", "X:\\the Quick Brown Fox jumped over the lazy dog.elf.binfile.jar" }; srand(time(NULL)); // Initialise FAT32_InitDrive(); fl_init(); if (fl_attach_media(FAT_ReadSector, FAT_WriteSector) != FAT_INIT_OK) return; // List directory fl_listdirectory("C:\\"); // return ; test_start: // Generate 5 random files memset(filenames, 0x00, 260*5); for (j=0;j<5;j++) { // Length fileLengths[j] = GetRandom(9999); // Data for (x=0;x<fileLengths[j];x++) fileData[j][x] = (BYTE)GetRandom(255); // Names sprintf(filenames[j], "X:\\Auto Generated Filename Number %d", j+1); } // Create some files for (j=0;j<5;j++) { printf("Creating File: %s [%d bytes]\n", filenames[j], fileLengths[j]); // Create File files[j] = fl_fopen(filenames[j], "w"); if (files[j]!=NULL) { if (fl_fwrite(fileData[j], 1, fileLengths[j], files[j])!=fileLengths[j]) { printf("ERROR: File Write Block Failed File %s Length %d\n", filenames[j], fileLengths[j]); fl_assert(0); } } else { printf("ERROR: Error Creating File %s\n", filenames[j]); fl_assert(0); } fl_fclose(files[j]); // Clear buffer for (i=0;i<sizeof(readBuffer);i++) readBuffer[i] = 0; // Verify File readFile = fl_fopen(filenames[j], "r"); if (readFile!=NULL) { int failed = FALSE; printf("File %s Read Check (fread whole file) [%d bytes]\n", filenames[j], fileLengths[j]); if (fl_fread(readBuffer, 1, fileLengths[j], readFile)!=fileLengths[j]) { printf("ERROR: File %s Read Length Error %d\n", filenames[j], fileLengths[j]); fl_assert(0); } for (i=0;i<fileLengths[j];i++) if ( fileData[j][i] != (BYTE)readBuffer[i] ) failed = TRUE; if (failed) { printf("ERROR: File %s Data Verify Failed\n", filenames[j]); fl_assert(0); } } fl_fclose(readFile); // Clear buffer for (i=0;i<sizeof(readBuffer);i++) readBuffer[i] = 0; // Verify File using fgetc readFile = fl_fopen(filenames[j], "r"); if (readFile!=NULL) { int failed = FALSE; printf("File %s Read Check (fgetc) [%d bytes]\n", filenames[j], fileLengths[j]); i = 0; while (i < fileLengths[j]) { int res = fl_fgetc(readFile); if (res == -1) break; readBuffer[i++] = (BYTE)res; } if (i != fileLengths[j]) { printf("ERROR: File %s Read Length Error %d\n", filenames[j], fileLengths[j]); fl_assert(0); } for (i=0;i<fileLengths[j];i++) if ( fileData[j][i] != (BYTE)readBuffer[i] ) failed = TRUE; if (failed) { printf("ERROR: File %s Data Verify Failed\n", filenames[j]); fl_assert(0); } } fl_fclose(readFile); // Clear buffer for (i=0;i<sizeof(readBuffer);i++) readBuffer[i] = 0; // Verify File chunks readFile = fl_fopen(filenames[j], "r"); if (readFile!=NULL) { int failed = FALSE; printf("File %s Read Check (fread chunks) [%d bytes]\n", filenames[j], fileLengths[j]); i = 0; while (i < fileLengths[j]) { int read_length = GetRandom(1025); if (read_length > (fileLengths[j] - i)) read_length = fileLengths[j] - i; if (fl_fread(readBuffer + i, 1, read_length, readFile) != read_length) { printf("ERROR: File %s fread error\n", filenames[j]); fl_assert(0); break; } i += read_length; } if (i != fileLengths[j]) { printf("ERROR: File %s Read Length Error %d\n", filenames[j], fileLengths[j]); fl_assert(0); } for (i=0;i<fileLengths[j];i++) if ( fileData[j][i] != (BYTE)readBuffer[i] ) { failed = TRUE; break; } if (failed) { printf("ERROR: File %s Data Verify Failed at %d\n", filenames[j], i); fl_assert(0); } } fl_fclose(readFile); // Delete File if (fl_remove(filenames[j])<0) printf("ERROR: Delete File %s Failed\n", filenames[j]); // Verify file is no longer present! readFile = fl_fopen(filenames[j], "r"); if (readFile != NULL) { printf("ERROR: File %s still present after delete!\n", filenames[j]); fl_assert(0); fl_fclose(readFile); } } // Create folder fl_createdirectory("C:\\folder1"); #if 0 // Create massive file #define MASSIVE_FILE_LEN (1024 * 1024) printf("Creating Massive File [%d bytes]\n", MASSIVE_FILE_LEN); massiveData = malloc(MASSIVE_FILE_LEN); if (!massiveData) { printf("ERROR: Could not allocate memory for massive array!\n"); fl_assert(0); fl_shutdown(); return ; } // Create random data for file for (x=0;x<MASSIVE_FILE_LEN;x++) massiveData[x] = (BYTE)GetRandom(255); // Remove if it already exists! fl_remove("X:\\folder1\\massive file.bin"); timeStart = time(NULL); // Create Large File readFile = fl_fopen("X:\\folder1\\massive file.bin", "w"); if (readFile != NULL) { if (fl_fwrite(massiveData, 1, MASSIVE_FILE_LEN, readFile) != MASSIVE_FILE_LEN) { printf("ERROR: File Write Block Failed for massive file (Length %d)\n", MASSIVE_FILE_LEN); fl_assert(0); } } else { printf("ERROR: Error Creating massive file\n"); fl_assert(0); } fl_fclose(readFile); // Verify Massive File readFile = fl_fopen("X:\\folder1\\massive file.bin", "r"); if (readFile!=NULL) { int failed = FALSE; printf("File Massive File Read Check (fread whole file) [%d bytes]\n", MASSIVE_FILE_LEN); i = 0; while (i < MASSIVE_FILE_LEN) { int read_length = GetRandom(2048) + 128; if (read_length > (MASSIVE_FILE_LEN - i)) read_length = MASSIVE_FILE_LEN - i; if (fl_fread(readBuffer, 1, read_length, readFile) != read_length) { printf("ERROR: File massive file fread error\n"); fl_assert(0); break; } for (j=0;j<read_length;j++) if ( massiveData[i+j] != (BYTE)readBuffer[j] ) { printf("ERROR: File Massive File Data Verify Failed at %d\n", i+j); fl_assert(0); break; } i += read_length; } if (i != MASSIVE_FILE_LEN) { printf("ERROR: File massive file Read Length Error %d\n", MASSIVE_FILE_LEN); fl_assert(0); } } fl_fclose(readFile); timeEnd = time(NULL); printf("Time taken %d seconds\n", (int)(timeEnd-timeStart)); free(massiveData); #endif // Filename test for (i=0;i<TESTFILES;i++) { // Create File readFile = fl_fopen(testfile[i], "w"); if (readFile != NULL) ; else { printf("ERROR: Error Creating File %s\n", testfile[i]); fl_assert(0); } fl_fputc(0, readFile); fl_fclose(readFile); readFile = fl_fopen(testfile[i], "r"); assert(readFile); fl_fclose(readFile); } // List directory fl_listdirectory("C:\\"); for (i=0;i<TESTFILES;i++) { // Delete File if (fl_remove(testfile[i])<0) { printf("ERROR: Delete File %s Failed\n", testfile[i]); fl_assert(0); } } fl_shutdown(); printf("\r\nCompleted\r\n"); // List directory fl_listdirectory("C:\\"); }