// 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;
}
Exemple #2
0
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;
}
Exemple #3
0
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);
    }
  }
}
Exemple #4
0
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;
}
Exemple #5
0
// 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;
            }
          }
        }
      }
    });
  }
Exemple #6
0
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;
}
Exemple #9
0
//-----------------------------------------------------------------
// 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:\\");
}