Skip to content

Commit

Permalink
Added structs to typechecker
Browse files Browse the repository at this point in the history
  • Loading branch information
tlaceby committed May 23, 2024
1 parent 545db23 commit ed42a1f
Show file tree
Hide file tree
Showing 11 changed files with 254 additions and 72 deletions.
6 changes: 6 additions & 0 deletions examples/test.br
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
struct Rect {
static count: Number;
width: Number;
height: Number;
}

fn main () {
let x = 0;
let y: &Number;
Expand Down
3 changes: 3 additions & 0 deletions src/analysis/analsyis.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ shared_ptr<analysis::Type> tc_var_decl_stmt(ast::VarDeclStmt*,
shared_ptr<analysis::Type> tc_fn_decl_stmt(ast::FnDeclStmt*,
shared_ptr<analysis::Scope>);

shared_ptr<analysis::Type> tc_struct_stmt(ast::StructStmt*,
shared_ptr<analysis::Scope>);

shared_ptr<analysis::Type> tc_block_stmt(ast::BlockStmt*);
shared_ptr<analysis::Type> tc_expr_stmt(ast::ExprStmt*,
shared_ptr<analysis::Scope>);
Expand Down
52 changes: 43 additions & 9 deletions src/analysis/analysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,60 @@ void analysis::Scope::debugScope() {
if (!DISPLAY_TYPEINFO) return;
using std::cout;
using utils::space;
int structCount = 0;

if (is_global) {
cout << "\n---- " << bold_magenta("Globals") << " ----\n";
} else
cout << "\n---- " << bold_magenta(name) << " ----\n";

cout << yellow("types") << ":\n";
for (const auto& [name, type] : types) {
cout << " " << white(name) << ":" << space((uint)(PADDING - name.size()));
cout << type->str() << "\n";
if (types.size() > 0) {
// Count struct occurences
for (const auto& [name, type] : types) {
if (type->kind == STRUCT) {
structCount += 1;
}
}

// Display Non Struct Properties
if (types.size() != structCount) {
cout << yellow("types") << ":\n";
for (const auto& [name, type] : types) {
if (type->kind == STRUCT) {
continue;
}

cout << " " << white(name) << ":"
<< space((uint)(PADDING - name.size()));
cout << type->str() << "\n";
}

std::cout << "\n";
}
}

cout << yellow("\nsymbols") << ":\n";
for (const auto& [name, type] : symbols) {
cout << " " << white(name) << ":" << space((uint)(PADDING - name.size()));
cout << type->str() << "\n";
if (structCount > 0) {
for (const auto& [_, type] : types) {
if (type->kind == STRUCT) {
cout << AS_STRUCT(type)->debugScopeStr();
}
}

std::cout << "\n";
}

if (symbols.size() > 0) {
cout << yellow("symbols") << ":\n";
for (const auto& [name, type] : symbols) {
cout << " " << white(name) << ":"
<< space((uint)(PADDING - name.size()));
cout << type->str() << "\n";
}

std::cout << "\n";
}

cout << "\n\n"; // end
return;
}

// Scope Functions
Expand Down
61 changes: 60 additions & 1 deletion src/analysis/tc_stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ shared_ptr<Scope> createGlobalScope() {
env->defineType("Void", MK_VOID());
env->defineType("String", MK_STR());

// Define program object
auto p = MK_STRUCT("BedrockProgram");
p->properties["argc"] = MK_NUM();
p->properties["cwd"] = MK_STR();

env->defineType("BedrockProgram", p);
env->defineSymbol("program", p, true);

// Define Global Variables
env->defineSymbol("true", MK_BOOL(), true);
env->defineSymbol("false", MK_BOOL(), true);
Expand Down Expand Up @@ -44,15 +52,17 @@ shared_ptr<analysis::Type> analysis::tc_program(
shared_ptr<analysis::Type> analysis::tc_module(
shared_ptr<ast::ModuleStmt> stmt) {
auto env = make_shared<Scope>();
stmt->scope = env;

env->is_module = true;
env->name = stmt->name;

stmt->scope = env;

for (const auto& s : stmt->body) {
tc_stmt(s, stmt->scope);
}

stmt->scope->debugScope();
return MK_VOID();
}

Expand Down Expand Up @@ -147,6 +157,53 @@ shared_ptr<analysis::Type> analysis::tc_expr_stmt(ExprStmt* stmt,
return tc_expr(stmt->expr, env);
}

shared_ptr<analysis::Type> analysis::tc_struct_stmt(StructStmt* stmt,
shared_ptr<Scope> env) {
auto name = stmt->name;
auto s = MK_STRUCT(name);

// Verify name does not already exist
if (env->typeExists(name)) {
std::cout << "Cannot define struct " << name;
std::cout << " as a type with this name already exists\n";
exit(1);
}

// Install & Validate Properties
for (const auto& prop : stmt->properties) {
auto propName = prop.name;
auto propType = tc_type(prop.type, env);

// Name is already in use
if (s->hasField(propName)) {
std::cout << "Struct " << name << " ";
std::cout << "already has a property with ";
std::cout << "the name " << propName << "\n";
exit(1);
}

if (prop.is_static) {
s->staticProperties[propName] = propType;
} else {
s->properties[propName] = propType;
}

if (prop.is_pub) {
s->publicMembers.insert(propName);
}
}

// Add struct to current scope if inside module or global
if (env->is_module || env->is_global) {
env->defineType(name, s);
return s;
}

std::cout << "Struct " << name << " ";
std::cout << "cannot be declared in current scope\n";
exit(1);
}

shared_ptr<analysis::Type> analysis::tc_stmt(shared_ptr<ast::Stmt> stmt,
shared_ptr<Scope> env) {
switch (stmt->kind) {
Expand All @@ -156,6 +213,8 @@ shared_ptr<analysis::Type> analysis::tc_stmt(shared_ptr<ast::Stmt> stmt,
return tc_fn_decl_stmt(static_cast<FnDeclStmt*>(stmt.get()), env);
case EXPR_STMT:
return tc_expr_stmt(static_cast<ExprStmt*>(stmt.get()), env);
case STRUCT_STMT:
return tc_struct_stmt(static_cast<StructStmt*>(stmt.get()), env);
default:
stmt->debug(0);
std::cout << "^^^^^ typechecking for node Unimplimented ^^^^^^\n";
Expand Down
34 changes: 33 additions & 1 deletion src/analysis/types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ shared_ptr<analysis::NumberType> analysis::MK_NUM() {
return make_shared<NumberType>();
}

shared_ptr<analysis::StructType> analysis::MK_STRUCT(string name) {
return make_shared<StructType>(name);
}

shared_ptr<analysis::FnType> analysis::MK_FN(vector<FnParam> params,
shared_ptr<Type> returns,
bool variadic) {
Expand All @@ -35,4 +39,32 @@ bool analysis::types_match(shared_ptr<Type> expected,
}

return expected->str() == recieved->str(); // TODO: Make lose comparison
}
}

analysis::VoidType* analysis::AS_VOID(shared_ptr<Type> t) {
return static_cast<VoidType*>(t.get());
}

analysis::BoolType* analysis::AS_BOOL(shared_ptr<Type> t) {
return static_cast<BoolType*>(t.get());
}

analysis::StringType* analysis::AS_STR(shared_ptr<Type> t) {
return static_cast<StringType*>(t.get());
}

analysis::PointerType* analysis::AS_PTR(shared_ptr<Type> t) {
return static_cast<PointerType*>(t.get());
}

analysis::NumberType* analysis::AS_NUM(shared_ptr<Type> t) {
return static_cast<NumberType*>(t.get());
}

analysis::StructType* analysis::AS_STRUCT(shared_ptr<Type> t) {
return static_cast<StructType*>(t.get());
}

analysis::FnType* analysis::AS_FN(shared_ptr<Type> t) {
return static_cast<FnType*>(t.get());
}
102 changes: 102 additions & 0 deletions src/analysis/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,116 @@ struct FnType : public Type {
}
};

struct StructType : public Type {
string name;
set<string> publicMembers; // whether a member is public or private
unordered_map<string, shared_ptr<Type>> staticProperties;
unordered_map<string, shared_ptr<FnType>> staticMethods;
unordered_map<string, shared_ptr<Type>> properties;
unordered_map<string, shared_ptr<FnType>> methods;

virtual ~StructType() {}
StructType(string name) : name(name) { kind = STRUCT; }

bool hasField(string propName) {
return hasProperty(propName, false) || hasProperty(propName, true) ||
hasMethod(propName, false) || hasMethod(propName, true);
}

bool hasProperty(string propName, bool isStatic) {
if (isStatic) {
return staticProperties.find(propName) != staticProperties.end();
}

return properties.find(propName) != properties.end();
}

bool hasMethod(string propName, bool isStatic) {
if (isStatic) {
return staticMethods.find(propName) != staticMethods.end();
}

return methods.find(propName) != methods.end();
}

shared_ptr<Type> getProperty(string propName, bool isStatic) {
if (isStatic) {
return staticProperties[propName];
}

return properties[propName];
}

shared_ptr<FnType> getMethod(string propName, bool isStatic) {
if (isStatic) {
return staticMethods[propName];
}

return methods[propName];
}

string str() override { return yellow("Struct") + "." + name + "\n"; }

// Output when printing the debug for a scope
string debugScopeStr() {
using utils::space;
size_t PADDING = 10;
string out;

out += magenta("Struct") + "." + blue(name) + ":\n";

// Properties
if (this->staticProperties.size() > 0 || this->properties.size() > 0) {
out += yellow(" properties") + ":\n";
for (const auto& [name, type] : this->staticProperties) {
out += " " + red(name) + ":";
out += space((uint)(PADDING - name.size()));
out += type->str() += "\n";
}

for (const auto& [name, type] : this->properties) {
out +=
" " + white(name) + ":" + space((uint)(PADDING - name.size()));
out += type->str() += "\n";
}
}

// Methods
if (this->staticMethods.size() > 0 || this->methods.size() > 0) {
out += yellow(" methods") + ":\n";
for (const auto& [name, type] : this->staticMethods) {
out += " " + red(name) + ":";
out += space((uint)(PADDING - name.size()));
out += type->str() += "\n";
}

for (const auto& [name, type] : this->methods) {
out +=
" " + white(name) + ":" + space((uint)(PADDING - name.size()));
out += type->str() += "\n";
}
}

return out;
}
};
// Type Creation

shared_ptr<analysis::VoidType> MK_VOID();
shared_ptr<analysis::BoolType> MK_BOOL();
shared_ptr<analysis::StringType> MK_STR();
shared_ptr<analysis::PointerType> MK_PTR(shared_ptr<Type>);
shared_ptr<analysis::NumberType> MK_NUM();
shared_ptr<analysis::StructType> MK_STRUCT(string);
shared_ptr<analysis::FnType> MK_FN(vector<FnParam>, shared_ptr<Type>, bool);

analysis::VoidType* AS_VOID(shared_ptr<Type>);
analysis::BoolType* AS_BOOL(shared_ptr<Type>);
analysis::StringType* AS_STR(shared_ptr<Type>);
analysis::PointerType* AS_PTR(shared_ptr<Type>);
analysis::NumberType* AS_NUM(shared_ptr<Type>);
analysis::StructType* AS_STRUCT(shared_ptr<Type>);
analysis::FnType* AS_FN(shared_ptr<Type>);

bool types_match(shared_ptr<Type> expected, shared_ptr<Type> recieved);
}; // namespace analysis
27 changes: 0 additions & 27 deletions src/ast/ast_stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,33 +84,6 @@ string StructStmt::debug(size_t depth) {
out += "\n";
}

if (this->instance_methods.size() > 0) {
out += space(depth + 1) + blue("Methods") + ": \n";

for (const auto& [propertyName, fn] : instance_methods) {
bool is_pub = public_status[propertyName];

out += space(depth + 2) + bold_magenta(propertyName) + ": \n";
out += space(depth + 3) + blue("Public") + ": ";
out += string((is_pub) ? "true" : "false") + "\n";

out += fn->debug(depth + 3);
}

out += "\n";
}

if (this->static_methods.size() > 0) {
out += space(depth + 1) + blue("StaticMethods") + ": \n";

for (const auto& [properyName, fn] : static_methods) {
out += space(depth + 2) + bold_magenta(properyName) + ": \n";
out += fn->debug(depth + 3);
}

out += "\n";
}

return out;
}

Expand Down
2 changes: 0 additions & 2 deletions src/ast/ast_stmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,6 @@ struct StructStmt : public Stmt {
vector<string> generics;
vector<PropertyKey> properties;
bool pub;
unordered_map<string, shared_ptr<FnType>> instance_methods;
unordered_map<string, shared_ptr<FnType>> static_methods;
unordered_map<string, bool>
public_status; // map of all keys and whether it's public.

Expand Down
Loading

0 comments on commit ed42a1f

Please sign in to comment.