Skip to content

Commit

Permalink
Extend file util of boostrap compiler (#487)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcauberer committed Feb 29, 2024
1 parent f935920 commit c3d782d
Show file tree
Hide file tree
Showing 13 changed files with 369 additions and 60 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/ci-cpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ jobs:
- name: Setup Ninja
run: sudo apt-get install ninja-build

- name: Setup Graphviz
run: sudo apt-get install graphviz

- name: Setup Valgrind
if: github.event_name == 'pull_request'
run: sudo apt-get install valgrind
Expand Down
2 changes: 1 addition & 1 deletion .run/spice.run.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="spice" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="run -O0 -d -ir ../../media/test-project/test.spice" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="spice" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="spice">
<configuration default="false" name="spice" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="run -O2 -d ../../media/test-project/test.spice" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="spice" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="spice">
<envs>
<env name="LLVM_BUILD_INCLUDE_DIR" value="D:/LLVM/build-release/include" />
<env name="LLVM_INCLUDE_DIR" value="D:/LLVM/llvm/include" />
Expand Down
44 changes: 17 additions & 27 deletions media/test-project/test.spice
Original file line number Diff line number Diff line change
@@ -1,31 +1,21 @@
import "std/io/cli-parser";
import "std/io/filepath";
import "std/os/os";

type CliOptions struct {
bool sayHi = false
}

p callback(bool& value) {
printf("Callback called with value %d\n", value);
}

f<int> main(int argc, string[] argv) {
CliParser parser = CliParser("Test Program", "This is a simple test program");
parser.setVersion("v0.1.0");
parser.setFooter("Copyright (c) Marc Auberer 2021-2024");

CliOptions options;
parser.addFlag("--hi", options.sayHi, "Say hi to the user");
parser.addFlag("--callback", callback, "Call a callback function");
parser.addFlag("-cb", p(bool& value) {
printf("CB called with value %d\n", value);
}, "Call a callback function");

parser.parse(argc, argv);

// Print hi if requested
if options.sayHi {
printf("Hi!\n");
}
f<int> main() {
FilePath path = FilePath("C:\Users\Public\Documents");
path /= "test.txt";
assert len(path.toString()) == 34;
string expectedString = isWindows() ? "C:\\Users\\Public\\Documents\\test.txt" : "C:\\Users\\Public\\Documents/test.txt";
assert path.toString() == expectedString;
expectedString = isWindows() ? "C:\\Users\\Public\\Documents\\test.txt" : "C:/Users/Public/Documents/test.txt";
assert path.toNativeString() == expectedString;
assert path.toGenericString() == "C:/Users/Public/Documents/test.txt";

assert path.getFileName() == "test.txt";
assert path.getExtension() == "txt";
assert path.getBaseName() == "test";

printf("All assertions passed!");
}

/*import "bootstrap/util/block-allocator";
Expand Down
151 changes: 139 additions & 12 deletions src-bootstrap/util/file-util.spice
Original file line number Diff line number Diff line change
@@ -1,27 +1,154 @@
// Std imports
import "std/io/file" as file;
import "std/os/os";
import "std/os/cmd";
import "std/os/env";
import "std/io/file";
import "std/io/filepath";
import "std/type/error";
import "std/iterator/array-iterator";

public type ExecResult struct {
string output
String output
int exitCode
}

/**
* Util class for file-related work
* Execute external command. Used to execute compiled binaries
*
* @param cmd Command to execute
* @return Result struct
*/
public type FileUtil struct {}

public f<ExecResult> FileUtil.exec(const string cmd) {
public f<ExecResult> exec(const string cmd) {
// ToDo
return ExecResult{};
}

public f<string> FileUtil.getStdDir() {
// ToDo
return "";
/**
* Checks if a certain command is available on the computer
*
* @param cmd Command to search for
* @return Present or not
*/
public f<bool> isCommandAvailable(const string cmd) {
String checkCmd;
if isWindows() {
checkCmd = "where " + cmd + " > nul 2>&1";
} else if isLinux() {
checkCmd = "which " + cmd + " > /dev/null 2>&1";
} else {
panic(Error("Unsupported platform"));
}
return execCmd(checkCmd.getRaw()) == 0;
}

public f<string> FileUtil.getSpiceBinDir() {
// ToDo
return "";
/**
* Checks if Graphviz is installed on the system
*
* @return Present or not
*/
public f<bool> isGraphvizInstalled() {
return isCommandAvailable("dot");
}

/**
* Search for a supported linker invoker on the system and return the executable name or path.
* This function may throw a LinkerError if no linker invoker is found.
*
* @return Name of path to the linker invoker executable
*/
public f<String> findLinkerInvoker() {
foreach const string linkerInvoker : ["clang", "gcc"] {
if isLinux() {
foreach const string path : ["/usr/bin/", "/usr/local/bin/", "/bin/"] {
const String linkerInvokerPath = path + linkerInvoker;
if fileExists(linkerInvokerPath.getRaw()) {
return linkerInvokerPath;
}
}
} else if isWindows() {
String linkerInvokerLookupCommand = linkerInvoker + " -v";
if isCommandAvailable(linkerInvokerLookupCommand.getRaw()) {
return String(linkerInvoker);
}
}
}
panic(Error("No supported linker invoker found on the system. Supported are: clang and gcc"));
}

/**
* Search for a supported linker on the system and return the executable name or path.
* This function may throw a LinkerError if no linker is found.
*
* @return Name of path to the linker executable
*/
public f<String> findLinker() {
if isLinux() {
foreach const string linkerName : ["mold", "lld", "gold", "ld"] {
foreach const string path : ["/usr/bin/", "/usr/local/bin/", "/bin/"] {
String linker = path + linkerName;
if fileExists(linker.getRaw()) {
return linker;
}
}
}
} else if isWindows() {
foreach const string linkerName : ["lld", "ld"] {
String checkCmd = linkerName + " -v";
if isCommandAvailable(checkCmd.getRaw()) {
return String(linkerName);
}
}
}
panic(Error("No supported linker found on the system. Supported are: mold, lld, gold and ld"));
}

/**
* Retrieve the dir, where the standard library lives.
* Returns an empty string if the std was not found.
*
* @return Std directory
*/
public f<FilePath> getStdDir() {
if isLinux() {
result = FilePath("/usr/lib/spice/std/");
if result.exists() { return; }
}
string value = getEnv("SPICE_STD_DIR");
if value != "" {
result = FilePath(value);
if result.exists() { return; }
}
return FilePath();
}

/**
* Retrieve the dir, where the bootstrap compiler lives.
* Returns an empty string if the bootstrap compiler was not found.
*
* @return
*/
public f<FilePath> getBootstrapCompilerDir() {
string value = getEnv("SPICE_BOOTSTRAP_DIR");
if value != "" {
result = FilePath(value);
if result.exists() { return; }
}
return FilePath();
}

/**
* Retrieve the dir, where output binaries should go when installing them
*
* @return Installation directory
*/
public f<FilePath> getSpiceBinDir() {
if isWindows() {
string userprofile = getEnv("USERPROFILE");
assert userprofile != "";
return FilePath(userprofile) / "spice" / "bin";
} else if isLinux() {
return FilePath("/usr/local/bin");
} else {
panic(Error("Unsupported platform"));
}
}
39 changes: 28 additions & 11 deletions src/ast/ASTBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1468,17 +1468,34 @@ template <typename T> T ASTBuilder::parseNumeric(TerminalNode *terminal, const N
}
}

void ASTBuilder::replaceEscapeChars(std::string &string) {
CommonUtil::replaceAll(string, "\\a", "\a");
CommonUtil::replaceAll(string, "\\b", "\b");
CommonUtil::replaceAll(string, "\\f", "\f");
CommonUtil::replaceAll(string, "\\n", "\n");
CommonUtil::replaceAll(string, "\\r", "\r");
CommonUtil::replaceAll(string, "\\t", "\t");
CommonUtil::replaceAll(string, "\\v", "\v");
CommonUtil::replaceAll(string, "\\'", "\'");
CommonUtil::replaceAll(string, "\\\"", "\"");
CommonUtil::replaceAll(string, "\\?", "\?");
void ASTBuilder::replaceEscapeChars(std::string &input) {
std::unordered_map<char, char> escapeMap = {
{'a', '\a'}, {'b', '\b'}, {'f', '\f'}, {'n', '\n'}, {'r', '\r'}, {'t', '\t'},
{'v', '\v'}, {'\\', '\\'}, {'?', '\?'}, {'\'', '\''}, {'"', '\"'},
};

size_t writeIndex = 0; // Index where the next character should be written
for (size_t readIndex = 0; readIndex < input.length(); ++readIndex, ++writeIndex) {
if (input[readIndex] == '\\' && readIndex + 1 < input.length()) {
char nextChar = input[readIndex + 1];
if (escapeMap.find(nextChar) != escapeMap.end()) {
// If the next character forms a valid escape sequence, replace it
input[writeIndex] = escapeMap[nextChar];
readIndex++; // Skip the next character as it's part of the escape sequence
} else {
// If it's not a valid escape sequence, just copy the backslash
input[writeIndex] = input[readIndex];
}
} else {
if (writeIndex != readIndex) {
// If we've made replacements, shift the current character to the write position
input[writeIndex] = input[readIndex];
}
// If no replacements were needed, writeIndex and readIndex are the same, and this does nothing
}
}
// Resize the string to remove the unused portion
input.resize(writeIndex);
}

std::string ASTBuilder::getIdentifier(TerminalNode *terminal) {
Expand Down
2 changes: 1 addition & 1 deletion src/ast/ASTBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class ASTBuilder : private CompilerPass, public SpiceVisitor {
int8_t parseChar(TerminalNode *terminal);
static std::string parseString(std::string input);
template <typename T> T parseNumeric(TerminalNode *terminal, const NumericParserCallback<T> &cb);
static void replaceEscapeChars(std::string &string);
static void replaceEscapeChars(std::string &input);
std::string getIdentifier(TerminalNode *terminal);
};

Expand Down

0 comments on commit c3d782d

Please sign in to comment.