Skip to content

Commit

Permalink
feat: Added export keyword, fixed classes and enums not being importe…
Browse files Browse the repository at this point in the history
…d in compilation
  • Loading branch information
alinalihassan committed Jun 3, 2022
1 parent da65190 commit e83055b
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 62 deletions.
18 changes: 13 additions & 5 deletions src/liblesma/AST/AST.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,15 @@ namespace lesma {
class Enum : public Statement {
std::string identifier;
std::vector<std::string> values;
bool exported;

public:
Enum(llvm::SMRange Loc, std::string identifier, std::vector<std::string> values) : Statement(Loc), identifier(std::move(identifier)), values(std::move(values)){};
Enum(llvm::SMRange Loc, std::string identifier, std::vector<std::string> values, bool exported) : Statement(Loc), identifier(std::move(identifier)), values(std::move(values)), exported(exported){};
~Enum() override = default;

[[nodiscard]] [[maybe_unused]] std::string getIdentifier() const { return identifier; }
[[nodiscard]] [[maybe_unused]] std::vector<std::string> getValues() const { return values; }
[[nodiscard]] [[maybe_unused]] bool isExported() const { return exported; }

std::string toString(llvm::SourceMgr *srcMgr, const std::string &prefix, bool isTail) override {
std::ostringstream imploded;
Expand Down Expand Up @@ -268,11 +270,12 @@ namespace lesma {
std::vector<std::pair<std::string, Type *>> parameters;
Compound *body;
bool varargs;
bool exported;

public:
FuncDecl(llvm::SMRange Loc, std::string name, Type *return_type,
std::vector<std::pair<std::string, Type *>> parameters, Compound *body, bool varargs) : Statement(Loc), name(std::move(name)), return_type(return_type), parameters(std::move(parameters)),
body(body), varargs(varargs) {}
std::vector<std::pair<std::string, Type *>> parameters, Compound *body, bool varargs, bool exported) : Statement(Loc), name(std::move(name)), return_type(return_type), parameters(std::move(parameters)),
body(body), varargs(varargs), exported(exported) {}

~FuncDecl() override = default;

Expand All @@ -281,6 +284,7 @@ namespace lesma {
[[nodiscard]] [[maybe_unused]] std::vector<std::pair<std::string, Type *>> getParameters() const { return parameters; }
[[nodiscard]] [[maybe_unused]] Compound *getBody() const { return body; }
[[nodiscard]] [[maybe_unused]] bool getVarArgs() const { return varargs; }
[[nodiscard]] [[maybe_unused]] bool isExported() { return exported; }

std::string toString(llvm::SourceMgr *srcMgr, const std::string &prefix, bool isTail) override {
auto ret = fmt::format("{}{}FuncDecl[Line({}-{}):Col({}-{})]: {}(",
Expand All @@ -307,17 +311,19 @@ namespace lesma {
Type *return_type;
std::vector<std::pair<std::string, Type *>> parameters;
bool varargs;
bool exported;

public:
ExternFuncDecl(llvm::SMRange Loc, std::string name, Type *return_type,
std::vector<std::pair<std::string, Type *>> parameters, bool varargs) : Statement(Loc), name(std::move(name)), return_type(return_type), parameters(std::move(parameters)), varargs(varargs) {}
std::vector<std::pair<std::string, Type *>> parameters, bool varargs, bool exported) : Statement(Loc), name(std::move(name)), return_type(return_type), parameters(std::move(parameters)), varargs(varargs), exported(exported) {}

~ExternFuncDecl() override = default;

[[nodiscard]] [[maybe_unused]] std::string getName() const { return name; }
[[nodiscard]] [[maybe_unused]] Type *getReturnType() const { return return_type; }
[[nodiscard]] [[maybe_unused]] std::vector<std::pair<std::string, Type *>> getParameters() const { return parameters; }
[[nodiscard]] [[maybe_unused]] bool getVarArgs() const { return varargs; }
[[nodiscard]] [[maybe_unused]] bool isExported() { return exported; }

std::string toString(llvm::SourceMgr *srcMgr, const std::string &prefix, bool isTail) override {
auto ret = fmt::format("{}{}ExternFuncDecl[Line({}-{}):Col({}-{})]: {}(",
Expand Down Expand Up @@ -585,14 +591,16 @@ namespace lesma {
std::string identifier;
std::vector<VarDecl *> fields;
std::vector<FuncDecl *> methods;
bool exported;

public:
Class(llvm::SMRange Loc, std::string identifier, std::vector<VarDecl *> fields, std::vector<FuncDecl *> methods) : Statement(Loc), identifier(std::move(identifier)), fields(std::move(fields)), methods(std::move(methods)){};
Class(llvm::SMRange Loc, std::string identifier, std::vector<VarDecl *> fields, std::vector<FuncDecl *> methods, bool exported) : Statement(Loc), identifier(std::move(identifier)), fields(std::move(fields)), methods(std::move(methods)), exported(exported){};
~Class() override = default;

[[nodiscard]] [[maybe_unused]] std::string getIdentifier() const { return identifier; }
[[nodiscard]] [[maybe_unused]] std::vector<VarDecl *> getFields() const { return fields; }
[[nodiscard]] [[maybe_unused]] std::vector<FuncDecl *> getMethods() const { return methods; }
[[nodiscard]] [[maybe_unused]] bool isExported() const { return exported; }

std::string toString(llvm::SourceMgr *srcMgr, const std::string &prefix, bool isTail) override {
std::string fields_str;
Expand Down
92 changes: 56 additions & 36 deletions src/liblesma/Backend/Codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,58 +161,74 @@ void Codegen::CompileModule(llvm::SMRange span, const std::string &filepath, boo

ImportedModules = std::move(codegen->ImportedModules);

if (isJIT) {
// Add classes and enums
for (auto sym: codegen->Scope->getSymbols()) {
if (sym.second->getType()->isOneOf({TY_ENUM, TY_CLASS})) {
// TODO: We have to reconstruct classes and enums, fix me
auto struct_ty = cast<llvm::StructType>(sym.second->getLLVMType());
llvm::StructType *structType = llvm::StructType::create(*TheContext, struct_ty->elements(), sym.first);

auto *structSymbol = new SymbolTableEntry(sym.first, sym.second->getType());
structSymbol->setLLVMType(structType);
Scope->insertType(sym.first, sym.second->getType());
Scope->insertSymbol(structSymbol);
}
// Add classes and enums
for (auto sym: codegen->Scope->getSymbols()) {
if (sym.second->getType()->isOneOf({TY_ENUM, TY_CLASS})) {
// TODO: We have to reconstruct classes and enums, fix me
auto struct_ty = cast<llvm::StructType>(sym.second->getLLVMType());
llvm::StructType *structType = llvm::StructType::create(*TheContext, struct_ty->elements(), sym.first);

auto *structSymbol = new SymbolTableEntry(sym.first, sym.second->getType());
structSymbol->setLLVMType(structType);
Scope->insertType(sym.first, sym.second->getType());
Scope->insertSymbol(structSymbol);
}
}

if (isJIT) {
// Link modules together
if (Linker::linkModules(*TheModule, std::move(codegen->TheModule), (1 << 0)))
throw CodegenError({}, "Error linking modules together");

// Add function to main module
Module::iterator it;
Module::iterator end = TheModule->end();
for (it = TheModule->begin(); it != end; ++it) {
// If it's external function (only functions without body) don't import
if ((*it).getBasicBlockList().empty())
continue;

for (Module::iterator it = TheModule->begin(); it != TheModule->end(); ++it) {
auto name = std::string{(*it).getName()};
auto symbol = new SymbolTableEntry(name, new SymbolType(SymbolSuperType::TY_FUNCTION));
symbol->setLLVMType((*it).getFunctionType());
symbol->setLLVMValue((Value *) &(*it).getFunction());
Scope->insertSymbol(symbol);
std::vector<llvm::Type *> paramTypes;
for (unsigned param_i = 0; param_i < (*it).getFunctionType()->getNumParams(); param_i++)
paramTypes.push_back((*it).getFunctionType()->getParamType(param_i));

auto mangled_name = getMangledName(span, name, paramTypes, (*it).isVarArg());
auto func_symbol = codegen->Scope->lookup(mangled_name);
// Get function without name mangling in case of extern C functions
func_symbol = func_symbol == nullptr ? codegen->Scope->lookup(name) : func_symbol;

// If it's external function (only functions without body) don't import
if (func_symbol != nullptr && func_symbol->isExported()) {
auto symbol = new SymbolTableEntry(name, new SymbolType(SymbolSuperType::TY_FUNCTION));
symbol->setLLVMType((*it).getFunctionType());
symbol->setLLVMValue((Value *) &(*it).getFunction());
Scope->insertSymbol(symbol);
}
}
} else {
// Create object file to be linked
std::string obj_file = fmt::format("tmp{}", ObjectFiles.size());
codegen->WriteToObjectFile(obj_file);
ObjectFiles.push_back(fmt::format("{}.o", obj_file));

// Add function definitions
Module::iterator it;
Module::iterator end = codegen->TheModule->end();
for (it = codegen->TheModule->begin(); it != end; ++it) {
for (Module::iterator it = codegen->TheModule->begin(); it != codegen->TheModule->end(); ++it) {
auto name = std::string{(*it).getName()};
auto new_func = Function::Create((*it).getFunctionType(),
Function::ExternalLinkage,
name,
*TheModule);

auto symbol = new SymbolTableEntry(name, new SymbolType(SymbolSuperType::TY_FUNCTION));
symbol->setLLVMType(new_func->getFunctionType());
symbol->setLLVMValue(new_func);
Scope->insertSymbol(symbol);
std::vector<llvm::Type *> paramTypes;
for (unsigned param_i = 0; param_i < (*it).getFunctionType()->getNumParams(); param_i++)
paramTypes.push_back((*it).getFunctionType()->getParamType(param_i));

auto mangled_name = getMangledName(span, name, paramTypes, (*it).isVarArg());
auto func_symbol = codegen->Scope->lookup(mangled_name);
// Get function without name mangling in case of extern C functions
func_symbol = func_symbol == nullptr ? codegen->Scope->lookup(name) : func_symbol;

if (func_symbol != nullptr && func_symbol->isExported()) {
auto new_func = Function::Create((*it).getFunctionType(),
Function::ExternalLinkage,
name,
*TheModule);

auto symbol = new SymbolTableEntry(name, new SymbolType(SymbolSuperType::TY_FUNCTION));
symbol->setLLVMType(new_func->getFunctionType());
symbol->setLLVMValue(new_func);
Scope->insertSymbol(symbol);
}
}
}
} catch (const LesmaError &err) {
Expand Down Expand Up @@ -565,6 +581,7 @@ void Codegen::visit(FuncDecl *node) {
auto func_symbol = new SymbolTableEntry(name, new SymbolType(SymbolSuperType::TY_FUNCTION));
func_symbol->setLLVMType(F->getFunctionType());
func_symbol->setLLVMValue(F);
func_symbol->setExported(node->isExported());
Scope->insertSymbol(func_symbol);

Prototypes.emplace_back(F, node, selfSymbol);
Expand All @@ -589,6 +606,7 @@ void Codegen::visit(ExternFuncDecl *node) {
auto symbol = new SymbolTableEntry(node->getName(), new SymbolType(SymbolSuperType::TY_FUNCTION));
symbol->setLLVMType(F.getFunctionType());
symbol->setLLVMValue(F.getCallee());
symbol->setExported(node->isExported());
Scope->insertSymbol(symbol);
}

Expand Down Expand Up @@ -760,6 +778,7 @@ void Codegen::visit(Class *node) {
auto *type = new SymbolType(TY_CLASS, fields, nullptr);
auto *structSymbol = new SymbolTableEntry(node->getIdentifier(), type);
structSymbol->setLLVMType(structType);
structSymbol->setExported(node->isExported());
Scope->insertType(node->getIdentifier(), type);
Scope->insertSymbol(structSymbol);

Expand Down Expand Up @@ -788,6 +807,7 @@ void Codegen::visit(Enum *node) {
auto *type = new SymbolType(TY_ENUM, fields, nullptr);
auto *structSymbol = new SymbolTableEntry(node->getIdentifier(), type);
structSymbol->setLLVMType(structType);
structSymbol->setExported(node->isExported());
Scope->insertType(node->getIdentifier(), type);
Scope->insertSymbol(structSymbol);
}
Expand Down
42 changes: 35 additions & 7 deletions src/liblesma/Frontend/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ Statement *Parser::ParseDefer() {
}

Statement *Parser::ParseStatement(bool isTopLevel) {
if (CheckAny<TokenType::DEF, TokenType::IMPORT>() && !isTopLevel)
if (CheckAny<TokenType::DEF, TokenType::IMPORT, TokenType::CLASS, TokenType::ENUM, TokenType::EXPORT>() && !isTopLevel)
Error(Peek(), "Statement not allowed inside a block");

if (Check(TokenType::DEF))
Expand All @@ -402,6 +402,8 @@ Statement *Parser::ParseStatement(bool isTopLevel) {
return ParseClass();
else if (Check(TokenType::ENUM))
return ParseEnum();
else if (Check(TokenType::EXPORT))
return ParseExport();
else if (Check(TokenType::LET) || Check(TokenType::VAR))
return ParseVarDecl();
else if (Check(TokenType::IF))
Expand Down Expand Up @@ -448,11 +450,11 @@ Compound *Parser::ParseBlock() {
}

Statement *Parser::ParseFunctionDeclaration() {
auto loc = Peek()->span;
auto loc = isExported ? Previous()->span : Peek()->span;
Consume(TokenType::DEF);
bool extern_func = false;

if (AdvanceIfMatchAny<TokenType::EXTERN_FUNC>())
if (AdvanceIfMatchAny<TokenType::EXTERN>())
extern_func = true;

if (extern_func && inClass) {
Expand Down Expand Up @@ -495,12 +497,38 @@ Statement *Parser::ParseFunctionDeclaration() {

if (extern_func) {
ConsumeNewline();
return new ExternFuncDecl({loc.Start, return_type->getEnd()}, identifier->lexeme, return_type, parameters, varargs);
return new ExternFuncDecl({loc.Start, return_type->getEnd()}, identifier->lexeme, return_type, parameters, varargs, isExported);
}

auto body = ParseBlock();

return new FuncDecl({loc.Start, return_type->getEnd()}, identifier->lexeme, return_type, parameters, body, false);
return new FuncDecl({loc.Start, return_type->getEnd()}, identifier->lexeme, return_type, parameters, body, false, isExported);
}

Statement *Parser::ParseExport() {
Consume(TokenType::EXPORT);

if (inClass)
Error(Peek(), "Cannot export class members");

if (!CheckAny<TokenType::DEF, TokenType::CLASS, TokenType::ENUM>())
Error(Peek(), "Can only export functions, classes and enums");

isExported = true;
Statement *statement = nullptr;
if (Check(TokenType::DEF))
statement = ParseFunctionDeclaration();
else if (Check(TokenType::IMPORT))
statement = ParseImport();
else if (Check(TokenType::CLASS))
statement = ParseClass();
else if (Check(TokenType::ENUM))
statement = ParseEnum();
else
Error(Peek(), "Unexpected statement after export");

isExported = false;
return statement;
}

Statement *Parser::ParseImport() {
Expand Down Expand Up @@ -555,7 +583,7 @@ Statement *Parser::ParseClass() {

AdvanceIfMatchAny<TokenType::DEDENT>();

return new Class(loc, token->lexeme, fields, methods);
return new Class(loc, token->lexeme, fields, methods, isExported);
}

Statement *Parser::ParseEnum() {
Expand All @@ -575,7 +603,7 @@ Statement *Parser::ParseEnum() {

AdvanceIfMatchAny<TokenType::DEDENT>();

return new Enum(loc, token->lexeme, values);
return new Enum(loc, token->lexeme, values, isExported);
}

Compound *Parser::ParseCompound() {
Expand Down
2 changes: 2 additions & 0 deletions src/liblesma/Frontend/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,15 @@ namespace lesma {
const std::vector<Token *> tokens;
unsigned long index;
bool inClass = false;
bool isExported = false;
Compound *tree;

static void Error(Token *token, const std::string &basicString);

Compound *ParseCompound();
Compound *ParseBlock();
Statement *ParseFunctionDeclaration();
Statement *ParseExport();
Statement *ParseImport();
Statement *ParseClass();
Statement *ParseEnum();
Expand Down
3 changes: 3 additions & 0 deletions src/liblesma/Symbol/SymbolTableEntry.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,15 @@ namespace lesma {
[[nodiscard]] bool getSigned() const { return signed_; }
[[nodiscard]] SymbolState getState() { return state; }
[[nodiscard]] SymbolType *getType() { return type; }
[[nodiscard]] bool isExported() { return exported; }
[[nodiscard]] bool isUsed() { return used; }

void setLLVMValue(llvm::Value *value) { llvmValue = value; }
void setLLVMType(llvm::Type *type_) { llvmType = type_; }
void setUsed(bool used_) { used = used_; }
void setSigned(bool signed__) { signed_ = signed__; }
void setMutable(bool mutable__) { mutable_ = mutable__; }
void setExported(bool exported_) { exported = exported_; }

std::string toString() {
std::string type_str, value_str;
Expand All @@ -61,5 +63,6 @@ namespace lesma {
bool mutable_;
bool signed_;
bool used = false;
bool exported = false;
};
}//namespace lesma
4 changes: 3 additions & 1 deletion src/liblesma/Token/Token.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ TokenType Token::GetIdentifierType(const std::string &identifier, Token *lastTok
else if (identifier == "super")
return TokenType::SUPER;
else if (identifier == "extern")
return TokenType::EXTERN_FUNC;
return TokenType::EXTERN;
else if (identifier == "export")
return TokenType::EXPORT;
else if (identifier == "as")
return TokenType::AS;
else if (identifier == "is")
Expand Down
3 changes: 2 additions & 1 deletion src/liblesma/Token/TokenType.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ namespace lesma {
NIL,
OR,
NOT,
EXTERN_FUNC,
EXTERN,
EXPORT,
RETURN,
SUPER,
THIS,
Expand Down
Loading

0 comments on commit e83055b

Please sign in to comment.