Skip to content

Commit

Permalink
Allow immediate access to struct return values (#210)
Browse files Browse the repository at this point in the history
* Rebase

* Fix bug & extend string runtime

* Fix bug in test runner

* Tweak build configuration

* Add stub for fastbuild

* Allow direct member access on return values of method calls

* Allow direct method calls on return values of method calls

* Add run configurations
  • Loading branch information
marcauberer committed Oct 9, 2022
1 parent 20be089 commit a3760b8
Show file tree
Hide file tree
Showing 26 changed files with 338 additions and 107 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/ci-cpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,14 @@ jobs:
mkdir ./bin
cd ./bin
cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DSPICE_IS_GH_ACTIONS=ON -DSPICE_BUILT_BY="ghactions" -DSPICE_LINK_STATIC=OFF -DSPICE_DEV_COMPILE=ON -DSPICE_RUN_COVERAGE=ON -GNinja -Wattributes ..
cmake --build . --target Spice_test -j$(nproc)
cmake --build . --target spicetest -j$(nproc)
- name: Run Test target
env:
SPICE_STD_DIR: /home/runner/work/spice/spice/std
run: |
cd ./bin/test
./Spice_test false
./spicetest false
- name: Generate coverage report
run: |
Expand Down Expand Up @@ -109,6 +109,6 @@ jobs:
# SPICE_STD_DIR: /home/runner/work/spice/spice/std
# run: |
# cd ./bin/test
# ./Spice_test true
# ./spicetest true
# git status --porcelain
# git diff --exit-code
2 changes: 1 addition & 1 deletion .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ jobs:
mkdir ./bin
cd ./bin
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DSPICE_BUILT_BY="ghactions" -DSPICE_LINK_STATIC=OFF -DSPICE_DEV_COMPILE=ON -GNinja -Wattributes ..
cmake --build . --target Spice_test -j$(nproc)
cmake --build . --target spicetest -j$(nproc)
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
8 changes: 4 additions & 4 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ jobs:
mkdir ./bin
cd ./bin
cmake -GNinja -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DSPICE_LINK_STATIC=OFF -DSPICE_VERSION="${{ steps.get_version.outputs.version }}" -DSPICE_BUILT_BY="ghactions" -DCMAKE_CXX_FLAGS_RELEASE="-O2" ..
cmake --build . --target Spice_run -j$(nproc)
cmake --build . --target spice -j$(nproc)
- name: Process build output
working-directory: bin
run: |
mv ./src/Spice_run spice
mv ./src/spice spice
chmod +x spice
- name: Upload artifact
Expand Down Expand Up @@ -146,11 +146,11 @@ jobs:
mkdir ./bin
cd ./bin
cmake -GNinja -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DSPICE_LINK_STATIC=ON -DSPICE_VERSION="${{ steps.get_version.outputs.version }}" -DSPICE_BUILT_BY="ghactions" -DCMAKE_CXX_FLAGS_RELEASE="-O2" ..
cmake --build . --target Spice_run -j$(nproc)
cmake --build . --target spice -j$(nproc)
- name: Process build output
working-directory: bin
run: mv ./src/Spice_run.exe spice.exe
run: mv ./src/spice.exe spice.exe

- name: Upload artifact
uses: actions/upload-artifact@v3
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ media/test-project/*.exe

# LLVM
/llvm

# FASTBuild
*.fdb
11 changes: 0 additions & 11 deletions .run/Spice_run.run.xml

This file was deleted.

11 changes: 0 additions & 11 deletions .run/Spice_test.run.xml

This file was deleted.

11 changes: 11 additions & 0 deletions .run/spice.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="spice" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="run -O2 -ir ../../media/test-project/os-test.spice" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="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="RUN_TESTS" value="OFF" />
<env name="SPICE_STD_DIR" value="$PROJECT_DIR$/std" />
</envs>
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>
</configuration>
</component>
12 changes: 12 additions & 0 deletions .run/spicetest.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="spicetest" type="CMakeGoogleTestRunConfigurationType" factoryName="Google Test" PROGRAM_PARAMS="true" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="spicetest" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="spicetest" TEST_MODE="SUITE_TEST">
<envs>
<env name="RUN_TESTS" value="ON" />
<env name="SPICE_STD_DIR" value="$PROJECT_DIR$/std" />
</envs>
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
<option name="BeforeTestRunTask" enabled="true" />
</method>
</configuration>
</component>
4 changes: 2 additions & 2 deletions build.bat
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ REM - Build
mkdir bin 2> NUL
pushd bin
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -GNinja -DCMAKE_CXX_FLAGS_RELEASE="-O2" ..
cmake --build . --target Spice_run
move src\Spice_run.exe spice.exe
cmake --build . --target spice
move src\spice.exe spice.exe
popd
4 changes: 2 additions & 2 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ export LLVM_DIR=./llvm/build-release/lib/cmake/llvm
(
cd ./bin || exit
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -GNinja -DCMAKE_CXX_FLAGS_RELEASE="-O2" ..
cmake --build . --target Spice_run
mv ./src/Spice_run spice
cmake --build . --target spice
mv ./src/spice spice
)
71 changes: 38 additions & 33 deletions media/test-project/os-test.spice
Original file line number Diff line number Diff line change
@@ -1,40 +1,45 @@
import "std/runtime/string_rt" as _rt_str;
type Stamp struct {
double value
bool glued
}

p Stamp.print() {
printf("Value: %f, glued: %d", this.value, this.glued);
}

type Letter struct {
string content
Stamp stamp
}

f<string> Letter.getContent() {
return this.content;
}

p Letter.setContent(string text) {
this.content = text;
}

f<Stamp> Letter.getStamp() {
return this.stamp;
}

p Letter.setStamp(Stamp stamp) {
this.stamp = stamp;
}

f<int> main() {
_rt_str::String s = _rt_str::String("Hello ");
printf("Content: %s\n", s.getRaw());
printf("Length: %d\n", s.getLength());
printf("Capacity: %d\n\n", s.getCapacity());
s.append("World!");
printf("Content: %s\n", s.getRaw());
printf("Length: %d\n", s.getLength());
printf("Capacity: %d\n\n", s.getCapacity());
s.append('?');
printf("Content: %s\n", s.getRaw());
printf("Length: %d\n", s.getLength());
printf("Capacity: %d\n\n", s.getCapacity());
s.append('!');
printf("Content: %s\n", s.getRaw());
printf("Length: %d\n", s.getLength());
printf("Capacity: %d\n\n", s.getCapacity());
printf("Equals: %d\n", s.opEquals("Hello World!?!"));
printf("Equals: %d\n", s.opEquals("Hello World!!"));
printf("Not Equals: %d\n", s.opNotEquals("Hello World!?!"));
printf("Not Equals: %d\n", s.opNotEquals("Hello World!!"));
s.clear();
printf("Content: %s\n", s.getRaw());
printf("Length: %d\n", s.getLength());
printf("Capacity: %d\n\n", s.getCapacity());
s.reserve(100l);
printf("Content: %s\n", s.getRaw());
printf("Length: %d\n", s.getLength());
printf("Capacity: %d\n\n", s.getCapacity());
s = _rt_str::String("");
printf("Empty: %d\n", s.isEmpty());
s.append('a');
printf("Empty: %d", s.isEmpty());
dyn letter = Letter{ "", Stamp{ 3.4, false } };
printf("Stamp glued: %f\n", letter.getStamp().value);
letter.getStamp().print();
}

/*import "std/runtime/string_rt" as _rt_str;

f<int> main() {
printf("%d", _rt_str::String("Test").isEmpty());
}*/

/*import "std/net/http" as http;

f<int> main() {
Expand Down
6 changes: 3 additions & 3 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,11 @@ set(SOURCES
util/CompilerWarning.cpp
util/CompilerWarning.h)

add_executable(${CMAKE_PROJECT_NAME}_run ${SOURCES} ${ANTLR_Spice_CXX_OUTPUTS})
add_executable(spice ${SOURCES} ${ANTLR_Spice_CXX_OUTPUTS})

# Include Antlr components
include_directories(${ANTLR_Spice_OUTPUT_DIR})
include_directories(../lib/antlr4/runtime/Cpp/runtime/src)

target_link_libraries(${CMAKE_PROJECT_NAME}_run antlr4_static ${LLVM_LIBS})
add_library(${CMAKE_PROJECT_NAME}_lib STATIC ${SOURCES} ${ANTLR_Spice_CXX_OUTPUTS})
target_link_libraries(spice antlr4_static ${LLVM_LIBS})
add_library(spicelib STATIC ${SOURCES} ${ANTLR_Spice_CXX_OUTPUTS})
27 changes: 17 additions & 10 deletions src/analyzer/AnalyzerVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1685,7 +1685,7 @@ std::any AnalyzerVisitor::visitPostfixUnaryExpr(PostfixUnaryExprNode *node) {
}
case PostfixUnaryExprNode::OP_MEMBER_ACCESS: {
// Check if lhs is struct
if (!lhs.isBaseType(TY_STRUCT) && !lhs.isBaseType(TY_ENUM))
if (!lhs.isBaseType(TY_STRUCT) && !lhs.isOneOf({TY_ENUM, TY_STRING}))
throw SemanticError(node->codeLoc, MEMBER_ACCESS_ONLY_STRUCTS, "Cannot apply member access operator on " + lhs.getName());

PostfixUnaryExprNode *rhs = node->postfixUnaryExpr()[memberAccessCounter++];
Expand Down Expand Up @@ -1900,7 +1900,7 @@ std::any AnalyzerVisitor::visitFunctionCall(FunctionCallNode *node) {
SymbolTable *accessScope = scopePath.getCurrentScope() ? scopePath.getCurrentScope() : currentScope;

std::string functionName;
SymbolType thisType = SymbolType(TY_DYN);
SymbolType thisType = currentThisType;
bool constructorCall = false;
for (unsigned int i = 0; i < node->functionNameFragments.size(); i++) {
std::string identifier = node->functionNameFragments[i];
Expand Down Expand Up @@ -2008,7 +2008,7 @@ std::any AnalyzerVisitor::visitFunctionCall(FunctionCallNode *node) {
// Add anonymous symbol to keep track of de-allocation
currentScope->insertAnonymous(thisType, node);
// Return struct type on constructor call
return node->setEvaluatedSymbolType(thisType);
return currentThisType = node->setEvaluatedSymbolType(thisType);
}

// If the callee is a procedure, return type bool
Expand All @@ -2018,15 +2018,22 @@ std::any AnalyzerVisitor::visitFunctionCall(FunctionCallNode *node) {
// Retrieve the return type of the function
SymbolType returnType = spiceFunc->getReturnType();

// If the return type is an external struct, initialize it
if (!scopePathBackup.isEmpty() && returnType.is(TY_STRUCT) && scopePathBackup.getCurrentScope()->isImported(currentScope)) {
std::string scopePrefix = scopePathBackup.getScopePrefix(!spiceFunc->isGenericSubstantiation);
SymbolType symbolType =
initExtStruct(currentScope, scopePrefix, returnType.getSubType(), returnType.getTemplateTypes(), node->codeLoc);
return node->setEvaluatedSymbolType(symbolType);
if (returnType.is(TY_STRUCT)) {
// Add struct scope to scope path
std::string structSignature = Struct::getSignature(returnType.getSubType(), returnType.getTemplateTypes());
SymbolTable *newAccessScope = accessScope->lookupTable(STRUCT_SCOPE_PREFIX + structSignature);
scopePath.pushFragment(returnType.getSubType(), newAccessScope);

// If the return type is an external struct, initialize it
if (!scopePathBackup.isEmpty() && scopePathBackup.getCurrentScope()->isImported(currentScope)) {
std::string scopePrefix = scopePathBackup.getScopePrefix(!spiceFunc->isGenericSubstantiation);
SymbolType symbolType =
initExtStruct(currentScope, scopePrefix, returnType.getSubType(), returnType.getTemplateTypes(), node->codeLoc);
return currentThisType = node->setEvaluatedSymbolType(symbolType);
}
}

return node->setEvaluatedSymbolType(returnType);
return currentThisType = node->setEvaluatedSymbolType(returnType);
}

std::any AnalyzerVisitor::visitArrayInitialization(ArrayInitializationNode *node) {
Expand Down
8 changes: 8 additions & 0 deletions src/config.bff
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#once

.Compiler = 'D:\mingw64\bin\g++.exe'
.CompilerOptions = '%1 -c -o %2'
.Linker = 'D:\mingw64\bin\ld.exe'
.LinkerOptions = '-o %2 %1'
.Librarian = 'D:\mingw64\bin\ld.exe'
.LibrarianOptions = '-o %2 %1'
26 changes: 26 additions & 0 deletions src/fbuild.bff
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
; Compiler configuration
#include "config.bff"

; Compile all .cpp files in the src dir
ObjectList('Spice')
{
.CompilerInputPath = '/'
.CompilerOutputPath = '../build/'
}

Library('antlr')
{
.CompilerInputPath = '../lib/antlr4/runtime/Cpp/runtime/src'
.CompilerOutputPath = '../build/antlr/'
.LibrarianOutput = '../build/antlr.lib'
}

; Link the executable
Executable('spice-run')
{
.Libraries = { 'Spice' }
.LinkerOutput = '../bin/spice.exe'
}

; Create a default target
Alias('all') { .Targets = { 'spice-run' } }
18 changes: 14 additions & 4 deletions src/generator/GeneratorVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2573,8 +2573,8 @@ std::any GeneratorVisitor::visitFunctionCall(FunctionCallNode *node) {
bool constructorCall = false;

// Load the 'this' value if it is a pointer
llvm::Value *thisValuePtr = nullptr;
SymbolType thisSymbolType;
llvm::Value *thisValuePtr = currentThisValuePtr;
SymbolType thisSymbolType = currentSymbolType;
for (unsigned int i = 0; i < node->functionNameFragments.size(); i++) {
std::string identifier = node->functionNameFragments[i];
SymbolTableEntry *symbolEntry = accessScope->lookup(identifier);
Expand Down Expand Up @@ -2695,6 +2695,14 @@ std::any GeneratorVisitor::visitFunctionCall(FunctionCallNode *node) {
// Create the function call
llvm::Value *resultValue = builder->CreateCall(fct, argValues);

SymbolType returnSymbolType = spiceFunc->getReturnType();
if (returnSymbolType.isBaseType(TY_STRUCT)) {
// Add struct scope to scope path
std::string structSignature = Struct::getSignature(returnSymbolType.getSubType(), returnSymbolType.getTemplateTypes());
SymbolTable *newAccessScope = accessScope->lookupTable(STRUCT_SCOPE_PREFIX + structSignature);
scopePath.pushFragment(returnSymbolType.getSubType(), newAccessScope);
}

// Consider constructor calls
if (constructorCall) {
// Update mem-address of anonymous symbol
Expand All @@ -2703,15 +2711,17 @@ std::any GeneratorVisitor::visitFunctionCall(FunctionCallNode *node) {
anonEntry->updateAddress(thisValuePtr);

// Return pointer to this value
return thisValuePtr;
currentSymbolType = anonEntry->type;
structAccessType = currentSymbolType.toLLVMType(*context, accessScope);
return currentThisValuePtr = structAccessAddress = thisValuePtr;
} else if (!resultValue->getType()->isSized()) {
// Set return type bool for procedures
resultValue = builder->getTrue();
}

llvm::Value *resultPtr = insertAlloca(resultValue->getType());
builder->CreateStore(resultValue, resultPtr);
return resultPtr;
return currentThisValuePtr = structAccessAddress = resultPtr;
}

std::any GeneratorVisitor::visitArrayInitialization(ArrayInitializationNode *node) {
Expand Down
3 changes: 2 additions & 1 deletion src/generator/GeneratorVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ class GeneratorVisitor : public AstVisitor {
std::unique_ptr<StdFunctionManager> stdFunctionManager;
std::unique_ptr<OpRuleConversionsManager> conversionsManager;
const std::string &objectFile;
llvm::TargetMachine *targetMachine{};
llvm::TargetMachine *targetMachine;
const CliOptions &cliOptions;
const LinkerInterface &linker;
bool requiresMainFct = true;
Expand All @@ -119,6 +119,7 @@ class GeneratorVisitor : public AstVisitor {
SymbolTable *currentScope;
SymbolTable *rootScope;
SymbolType currentSymbolType = SymbolType(TY_INVALID);
llvm::Value *currentThisValuePtr = nullptr;
ScopePath scopePath;
ThreadFactory &threadFactory;
bool blockAlreadyTerminated = false;
Expand Down

0 comments on commit a3760b8

Please sign in to comment.