135 lines
4.4 KiB
C
135 lines
4.4 KiB
C
|
|
/*************/
|
|
/*GEMWIRE */
|
|
/* ERYTHRO*/
|
|
/*************/
|
|
|
|
#include <Defs.h>
|
|
#include <Data.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <limits.h>
|
|
#include <sys/stat.h>
|
|
|
|
#if defined(__GNUC__) || defined(APPLE)
|
|
#include <errno.h>
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
#define realpath(N,R) _fullpath((R),(N),PATH_MAX)
|
|
#endif
|
|
|
|
/**
|
|
* The function of the importer is to read in definitions from a file, and store
|
|
* them into the symbol tables.
|
|
*
|
|
* The file to be imported is called a "module", which is Erythro terminology for C-like "headers".
|
|
* They contain extra metadata that allows for Erythro's enhanced debugging and error logging.
|
|
*
|
|
* Modules may also contain metadata about the contents within - allowing for multiple compile-time
|
|
* sourcesets with different arguments, all parsed at the same time as the source code.
|
|
*
|
|
* This allows Erythro to have first-class support for multiple-build-single-link situations,
|
|
* that would require the use of a build system like CMake in other languages.
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* Read in the information of a module, check that it is valid, and then read the module itself.
|
|
* Import syntax looks like:
|
|
*
|
|
* > import "file"
|
|
*
|
|
* The string is appended to the current working directory and is checked.
|
|
* If the resulting path exists and resolves to a file, then the file's declarations are added to the symbol tables.
|
|
*
|
|
* Modules may not contain definitions. Only declarations
|
|
* TODO: Module metadata as described above.
|
|
*/
|
|
void ImportModule() {
|
|
// Skip the import keyword
|
|
Tokenise();
|
|
|
|
// Make sure there's a string after the import.
|
|
if (CurrentFile->CurrentSymbol.type != LI_STR)
|
|
Die("Import statement must be followed by a compile-time constant string.");
|
|
|
|
// Read in the string that we know must be there.
|
|
char* Module = strdup(CurrentIdentifier);
|
|
|
|
// Two strategies for finding the module; either it's relative to cwd, or it's relative to source.
|
|
bool FoundImport = false;
|
|
// Check the cwd first.
|
|
|
|
// Figure out the working directory
|
|
char CWD[PATH_MAX];
|
|
|
|
if (getcwd(CWD, sizeof(CWD)) == NULL)
|
|
DieMessage("Unable to find cwd when importing module", Module);
|
|
|
|
// Append the module name to the current working directory
|
|
char* ModulePath = malloc(strlen(CWD) + strlen(Module) + 1);
|
|
strcpy(ModulePath, CWD);
|
|
strcpy(ModulePath + strlen(CWD), "/");
|
|
strcpy(ModulePath + strlen(CWD) + 1, Module);
|
|
|
|
printf("Scanning %s for module definitions.\n", ModulePath);
|
|
|
|
// Stat the file to see if it exists
|
|
struct stat FileInfo;
|
|
if (stat(ModulePath, &FileInfo) != 0) {
|
|
free(ModulePath);
|
|
char SourcePath[PATH_MAX + 1];
|
|
realpath(CurrentFile->SourceName, SourcePath);
|
|
// Deal with windows being windows
|
|
char* SourceFolderLength = strrchr(SourcePath, '/');
|
|
if (SourceFolderLength == NULL) {
|
|
SourceFolderLength = strrchr(SourcePath, '\\');
|
|
}
|
|
|
|
*(SourceFolderLength + 1) = '\0';
|
|
size_t SourcePathLength = strlen(SourcePath);
|
|
|
|
ModulePath = malloc(SourcePathLength + sizeof(Module) + 1);
|
|
strcpy(ModulePath, SourcePath);
|
|
strcpy(ModulePath + SourcePathLength, Module);
|
|
|
|
printf("Scanning %s for module definitions.\n", ModulePath);
|
|
|
|
if (stat(ModulePath, &FileInfo) != 0)
|
|
DieMessage("Unable to access the imported module", ModulePath);
|
|
}
|
|
|
|
// At this point, the file exists and we have the path.
|
|
// Save the current file, so that we can restore it later
|
|
struct FileData* SavedFile = CurrentFile;
|
|
|
|
// Create a new file with the module name
|
|
struct FileData* ModuleData = malloc(sizeof(struct FileData));
|
|
memset(ModuleData, 0, sizeof(struct FileData));
|
|
ModuleData->AllowDefinitions = false;
|
|
ModuleData->SourceName = ModulePath;
|
|
|
|
printf("Swapping to module %s..\n\n", ModulePath);
|
|
|
|
// Parse all relevant data from the module file...
|
|
if ((ModuleData->Stream = fopen(ModuleData->SourceName, "r")) == NULL) {
|
|
fprintf(stderr, "Unable to open %s: %s\n", ModuleData->SourceName, strerror(errno));
|
|
exit(1);
|
|
}
|
|
CurrentFile = ModuleData;
|
|
CurrentFile->CurrentLine = 1;
|
|
Tokenise();
|
|
ParseGlobals();
|
|
fclose(CurrentFile->Stream);
|
|
|
|
printf("\n\nSwapping back to file %s..\n", SavedFile->SourceName);
|
|
|
|
// Reinstate the saved file
|
|
CurrentFile = SavedFile;
|
|
|
|
// Tokenise past the string we just parsed
|
|
Tokenise();
|
|
|
|
} |