Skip to content

Commit

Permalink
prop initializers
Browse files Browse the repository at this point in the history
  • Loading branch information
vajexal committed May 7, 2024
1 parent 3606a96 commit c7ef813
Show file tree
Hide file tree
Showing 12 changed files with 237 additions and 79 deletions.
2 changes: 1 addition & 1 deletion parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ COMMENT { $$ = new CommentNode(std::move($1)); }
;

prop_decl:
access_modifier optional_static type IDENTIFIER { $$ = new PropDeclNode(std::move($3), std::move($4), $1, $2); }
access_modifier optional_static var_decl { $$ = new PropDeclNode($3, $1, $2); }
;

method_def:
Expand Down
10 changes: 4 additions & 6 deletions src/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -614,21 +614,19 @@ namespace X {
};

class PropDeclNode : public Node {
Type type;
std::string name;
DeclNode *decl;
AccessModifier accessModifier;
bool isStatic;

public:
PropDeclNode(Type type, std::string name, AccessModifier accessModifier = AccessModifier::PUBLIC, bool isStatic = false) :
Node(NodeKind::PropDecl), type(std::move(type)), name(std::move(name)), accessModifier(accessModifier), isStatic(isStatic) {}
PropDeclNode(DeclNode *decl, AccessModifier accessModifier = AccessModifier::PUBLIC, bool isStatic = false) :
Node(NodeKind::PropDecl), decl(decl), accessModifier(accessModifier), isStatic(isStatic) {}

void print(Pipes::PrintAst &astPrinter, int level = 0) override;
llvm::Value *gen(Codegen::Codegen &codegen) override;
Type infer(Pipes::TypeInferrer &typeInferrer) override;

const Type &getType() const { return type; }
const std::string &getName() const { return name; }
DeclNode *getDecl() const { return decl; }
AccessModifier getAccessModifier() const { return accessModifier; }
bool getIsStatic() const { return isStatic; }

Expand Down
13 changes: 8 additions & 5 deletions src/codegen/class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ namespace X::Codegen {

auto obj = newObj(classDecl.llvmType);

initVtable(obj, classDecl);

auto initFnName = Mangler::mangleHiddenMethod(Mangler::mangleClass(classDecl.name), INIT_FN_NAME);
if (auto initFn = module.getFunction(initFnName)) {
builder.CreateCall(initFn, {obj});
}

try {
callMethod(obj, classDecl.type, CONSTRUCTOR_FN_NAME, node->getArgs());
} catch (const MethodNotFoundException &e) {
Expand All @@ -96,8 +103,6 @@ namespace X::Codegen {
}
}

initVtable(obj, classDecl);

return obj;
}

Expand Down Expand Up @@ -399,9 +404,7 @@ namespace X::Codegen {
return builder.CreateCall(callee, llvmArgs);
}

std::tuple<llvm::FunctionCallee, FnType *> Codegen::findMethod(
llvm::Value *obj, const Type &objType, const std::string &methodName
) {
std::tuple<llvm::FunctionCallee, FnType *> Codegen::findMethod(llvm::Value *obj, const Type &objType, const std::string &methodName) {
if (objType.isOneOf(Type::TypeID::STRING, Type::TypeID::ARRAY)) {
const auto &name = Mangler::mangleInternalMethod(getClassName(objType), methodName);
auto fn = module.getFunction(name);
Expand Down
5 changes: 5 additions & 0 deletions src/codegen/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ namespace X::Codegen {
bool isAbstract = false;
llvm::StructType *vtableType = nullptr;
GC::Metadata *meta;
bool needInit = false;
};

struct InterfaceDecl {
Expand Down Expand Up @@ -152,6 +153,10 @@ namespace X::Codegen {
void declFuncs(TopStatementListNode *node);
void declGlobals(TopStatementListNode *node);

void genGlobal(DeclNode *node);
void genClassInit(ClassNode *node, const ClassDecl &classDecl);
void genStaticPropInit(PropDeclNode *prop, ClassNode *klass);

llvm::Type *mapType(const Type &type);
llvm::Constant *getDefaultValue(const Type &type);
/// differs from getDefaultValue because getDefaultValue returns constant and createDefaultValue can emit instructions
Expand Down
142 changes: 110 additions & 32 deletions src/codegen/decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ namespace X::Codegen {
propPos++;
classDecl.parent = const_cast<ClassDecl *>(&parentClassDecl);
pointerList = parentClassDecl.meta->pointerList;
classDecl.needInit = parentClassDecl.needInit;
}

auto it = compilerRuntime.virtualMethods.find(name);
Expand All @@ -68,24 +69,29 @@ namespace X::Codegen {
}

for (auto prop: klassNode->getProps()) {
auto &propName = prop->getName();
auto type = mapType(prop->getType());
auto &propName = prop->getDecl()->getName();
auto &type = prop->getDecl()->getType();
auto llvmType = mapType(type);

if (prop->getIsStatic()) {
// check if static prop already declared here, because module.getOrInsertGlobal could return ConstantExpr
// (if prop will be redeclared with different type)
if (classDecl.staticProps.contains(propName)) {
throw PropAlreadyDeclaredException(name, propName);
}
const auto &mangledPropName = Mangler::mangleStaticProp(mangledName, propName);
auto global = llvm::cast<llvm::GlobalVariable>(module.getOrInsertGlobal(mangledPropName, type));
global->setInitializer(getDefaultValue(prop->getType()));
classDecl.staticProps[propName] = {global, prop->getType(), prop->getAccessModifier()};
auto global = llvm::cast<llvm::GlobalVariable>(module.getOrInsertGlobal(mangledPropName, llvmType));
classDecl.staticProps[propName] = {global, type, prop->getAccessModifier()};
} else {
props.push_back(type);
auto [_, inserted] = classDecl.props.try_emplace(propName, prop->getType(), propPos++, prop->getAccessModifier());
props.push_back(llvmType);
auto [_, inserted] = classDecl.props.try_emplace(propName, type, propPos++, prop->getAccessModifier());
if (!inserted) {
throw PropAlreadyDeclaredException(name, propName);
}

if (prop->getDecl()->getExpr()) {
classDecl.needInit = true;
}
}
}

Expand All @@ -102,6 +108,10 @@ namespace X::Codegen {
}

classDecl.meta = gc.addMeta(GC::NodeType::CLASS, std::move(pointerList));

if (classDecl.needInit) {
genClassInit(klassNode, classDecl);
}
}
}

Expand Down Expand Up @@ -149,12 +159,6 @@ namespace X::Codegen {
}

void Codegen::declGlobals(TopStatementListNode *node) {
auto &globals = node->getGlobals();

if (globals.empty()) {
return;
}

// create init function
auto initFn = llvm::Function::Create(
llvm::FunctionType::get(builder.getVoidTy(), {}, false),
Expand All @@ -167,30 +171,104 @@ namespace X::Codegen {
varScopes.emplace_back();
auto &vars = varScopes.back();

for (auto decl: globals) {
auto &name = decl->getName();
if (vars.contains(name)) {
throw VarAlreadyExistsException(name);
// declare global variables
for (auto decl: node->getGlobals()) {
genGlobal(decl);
}

// set initializers for static props
for (auto klass: node->getClasses()) {
for (auto prop: klass->getProps()) {
if (prop->getIsStatic()) {
genStaticPropInit(prop, klass);
}
}
}

auto &type = decl->getType();
auto llvmType = mapType(type);
auto global = llvm::cast<llvm::GlobalVariable>(module.getOrInsertGlobal(name, llvmType));

auto value = decl->getExpr() ?
decl->getExpr()->gen(*this) :
createDefaultValue(type);

if (auto constValue = llvm::dyn_cast<llvm::Constant>(value)) {
global->setInitializer(constValue);
} else {
global->setInitializer(getDefaultValue(type));
builder.CreateStore(value, global);
builder.CreateRetVoid();
}

void Codegen::genGlobal(DeclNode *node) {
auto &vars = varScopes.back();

auto &name = node->getName();
if (vars.contains(name)) {
throw VarAlreadyExistsException(name);
}

auto &type = node->getType();
auto llvmType = mapType(type);
auto global = llvm::cast<llvm::GlobalVariable>(module.getOrInsertGlobal(name, llvmType));

auto value = node->getExpr() ?
castTo(node->getExpr()->gen(*this), node->getExpr()->getType(), type) :
createDefaultValue(type);

if (auto constValue = llvm::dyn_cast<llvm::Constant>(value)) {
global->setInitializer(constValue);
} else {
global->setInitializer(getDefaultValue(type));
builder.CreateStore(value, global);
}

vars[name] = {global, type};

gcAddGlobalRoot(global, type);
}

void Codegen::genStaticPropInit(PropDeclNode *prop, ClassNode *klass) {
auto decl = prop->getDecl();
auto &type = decl->getType();
auto llvmType = mapType(decl->getType());
auto mangledClassName = Mangler::mangleClass(klass->getName());
auto mangledPropName = Mangler::mangleStaticProp(mangledClassName, decl->getName());
auto global = llvm::cast<llvm::GlobalVariable>(module.getOrInsertGlobal(mangledPropName, llvmType));

auto value = decl->getExpr() ?
castTo(decl->getExpr()->gen(*this), decl->getExpr()->getType(), type) :
createDefaultValue(type);

if (auto constValue = llvm::dyn_cast<llvm::Constant>(value)) {
global->setInitializer(constValue);
} else {
global->setInitializer(getDefaultValue(type));
builder.CreateStore(value, global);
}

gcAddGlobalRoot(global, type);
}

void Codegen::genClassInit(ClassNode *node, const ClassDecl &classDecl) {
auto mangledName = Mangler::mangleClass(classDecl.name);

// create init function
auto initFn = llvm::Function::Create(
llvm::FunctionType::get(builder.getVoidTy(), {builder.getPtrTy()}, false),
llvm::Function::ExternalLinkage,
Mangler::mangleHiddenMethod(mangledName, INIT_FN_NAME),
module
);
builder.SetInsertPoint(llvm::BasicBlock::Create(context, "entry", initFn));

auto initFnThis = initFn->getArg(0);

if (classDecl.parent) {
if (auto parentInitFn = module.getFunction(Mangler::mangleHiddenMethod(Mangler::mangleClass(classDecl.parent->name), INIT_FN_NAME))) {
builder.CreateCall(parentInitFn, {initFnThis});
}
}

vars[name] = {global, type};
for (auto prop: node->getProps()) {
if (prop->getIsStatic() || !prop->getDecl()->getExpr()) {
continue;
}

auto decl = prop->getDecl();
auto &type = decl->getType();
auto value = castTo(decl->getExpr()->gen(*this), decl->getExpr()->getType(), type);
auto ptr = builder.CreateStructGEP(classDecl.llvmType, initFnThis, classDecl.props.at(decl->getName()).pos);

gcAddGlobalRoot(global, type);
builder.CreateStore(value, ptr);
}

builder.CreateRetVoid();
Expand Down
2 changes: 1 addition & 1 deletion src/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace X {

(Pipeline{})
.pipe(Pipes::ParseCode(code))
// .pipe(new Pipes::PrintAst())
// .pipe(Pipes::PrintAst())
.pipe(Pipes::CheckInterfaces(compilerRuntime))
.pipe(Pipes::CheckAbstractClasses())
.pipe(Pipes::CheckVirtualMethods(compilerRuntime))
Expand Down
8 changes: 6 additions & 2 deletions src/mangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,19 @@ namespace X {
}

static std::string mangleMethod(const std::string &mangledClassName, const std::string &methodName) {
return mangledClassName + "_" + methodName;
return mangledClassName + '_' + methodName;
}

static std::string mangleHiddenMethod(const std::string &mangledClassName, const std::string &methodName) {
return mangledClassName + '.' + methodName;
}

static std::string mangleInternalMethod(const std::string &mangledClassName, const std::string &methodName) {
return INTERNAL_PREFIX + mangleMethod(mangledClassName, methodName);
}

static std::string mangleStaticProp(const std::string &mangledClassName, const std::string &propName) {
return mangledClassName + "_" + propName;
return mangledClassName + '_' + propName;
}

static std::string mangleInternalFunction(const std::string &fnName) {
Expand Down
2 changes: 1 addition & 1 deletion src/pipes/print_ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ namespace X::Pipes {
std::cout << "static ";
}

std::cout << node->getType() << ' ' << node->getName() << std::endl;
node->getDecl()->print(*this, level);
}

void PrintAst::printNode(MethodDefNode *node, int level) {
Expand Down
Loading

0 comments on commit c7ef813

Please sign in to comment.