Skip to content
This repository has been archived by the owner on Nov 24, 2024. It is now read-only.

Commit

Permalink
typecheck:-rough type inference of function return and enum done
Browse files Browse the repository at this point in the history
  • Loading branch information
SaptakBhoumik committed Jun 18, 2022
1 parent a3a12c1 commit 82df231
Show file tree
Hide file tree
Showing 9 changed files with 355 additions and 264 deletions.
157 changes: 145 additions & 12 deletions Peregrine/analyzer/typeChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace TypeCheck{

TypeChecker::TypeChecker(ast::AstNodePtr ast) {
m_env = createEnv();
m_env = createEnv(nullptr);
m_currentFunction = nullptr;
ast->accept(*this);
if(m_errors.size()!=0) {
Expand Down Expand Up @@ -49,7 +49,7 @@ EnvPtr TypeChecker::createEnv(EnvPtr parent) {
void TypeChecker::checkBody(ast::AstNodePtr body,
std::vector<std::pair<TypePtr,ast::AstNodePtr>> add_var) {
EnvPtr previousEnv = m_env;
m_env = createEnv();
m_env = createEnv(previousEnv);
if(add_var.size()!=0) {
for(auto& var : add_var) {
m_env->set(var.second,var.first);
Expand Down Expand Up @@ -95,7 +95,7 @@ bool TypeChecker::visit(const ast::ImportStatement& node) { return true; }
// TODO: default args
bool TypeChecker::visit(const ast::FunctionDefinition& node) {
EnvPtr oldEnv = m_env;
m_env = createEnv();
m_env = createEnv(oldEnv);

std::vector<TypePtr> parameterTypes;
parameterTypes.reserve(node.parameters().size());
Expand All @@ -118,16 +118,25 @@ bool TypeChecker::visit(const ast::FunctionDefinition& node) {
m_env->set(identifierName(param.p_name), m_result);
}
node.returnType()->accept(*this);

auto returnType=m_result;
auto functionType =
std::make_shared<FunctionType>(parameterTypes, m_result);
std::make_shared<FunctionType>(parameterTypes, returnType);

auto oldFunction = m_currentFunction;
auto oldReturnType = m_returnType;
m_returnType = NULL;
m_currentFunction = functionType;
node.body()->accept(*this);
if(m_returnType!=NULL){
auto& nonconstnode = const_cast<ast::FunctionDefinition&>(node);
nonconstnode.setType(m_returnType);
functionType =std::make_shared<FunctionType>(parameterTypes, m_returnType);
}
m_returnType = oldReturnType;
m_currentFunction = oldFunction;

m_env = oldEnv;

m_env->set(identifierName(node.name()), functionType);
return true;
}
Expand All @@ -143,12 +152,28 @@ bool TypeChecker::visit(const ast::VariableStatement& node) {
if (varType->category() == TypeCategory::Void) {
// inferring the type of the variable
node.value()->accept(*this);
if(m_result->category()==MultipleReturn){
add_error(node.token(), "Too few variables on the left hand side");
return true;
}
else if(m_result->category()==Void){
add_error(node.token(), "You cant declare a variable of type void");
return true;
}
nonConstNode.setProcessedType(m_result,defined_before);
varType = m_result;
} else{
if(node.value()->type()!=ast::KAstNoLiteral){
check(node.value(), varType);
}
if(m_result->category()==MultipleReturn){
add_error(node.token(), "Too few variables on the left hand side");
return true;
}
else if(m_result->category()==Void){
add_error(node.token(), "You cant declare a variable of type void");
return true;
}
nonConstNode.setProcessedType(varType,true);
}
if(node.name()->type()==ast::KAstIdentifier){
Expand All @@ -170,10 +195,26 @@ bool TypeChecker::visit(const ast::ConstDeclaration& node) {
if (constType->category() == TypeCategory::Void) {
// inferring the type of the constant
node.value()->accept(*this);
if(m_result->category()==MultipleReturn){
add_error(node.token(), "Too few variables on the left hand side");
return true;
}
else if(m_result->category()==Void){
add_error(node.token(), "You cant declare a constant of type void");
return true;
}
nonConstNode.setProcessedType(m_result);
constType = m_result;
} else{
check(node.value(), constType);
if(m_result->category()==MultipleReturn){
add_error(node.token(), "Too few variables on the left hand side");
return true;
}
else if(m_result->category()==Void){
add_error(node.token(), "You cant declare a variable of type void");
return true;
}
nonConstNode.setProcessedType(NULL);
}

Expand Down Expand Up @@ -236,7 +277,7 @@ bool TypeChecker::visit(const ast::WhileStatement& node) {
bool TypeChecker::visit(const ast::ForStatement& node) {
// check(node.sequence(), *TypeProducer::list());
EnvPtr oldEnv = m_env;
m_env = createEnv();
m_env = createEnv(oldEnv);
// m_env->set(identifierName(node.variable()), m_result); // result may not
// be correct here

Expand Down Expand Up @@ -279,8 +320,12 @@ bool TypeChecker::visit(const ast::ReturnStatement& node) {
}

node.returnValue()->accept(*this);

check(node.returnValue(), m_currentFunction->returnType());
if(m_currentFunction->returnType()->category()==TypeCategory::Void){
m_returnType=m_result;
}
else{
check(node.returnValue(), m_currentFunction->returnType());
}
return true;
}

Expand Down Expand Up @@ -376,7 +421,25 @@ bool TypeChecker::visit(const ast::FunctionCall& node) {
return true;
}

bool TypeChecker::visit(const ast::DotExpression& node) { return true; }
bool TypeChecker::visit(const ast::DotExpression& node) {
if(node.owner()->type()==ast::KAstIdentifier&&node.referenced()->type()==ast::KAstIdentifier){
auto name=identifierName(node.owner());
auto ref=identifierName(node.referenced());
if(m_enumMap.contains(name)){
auto type=m_enumMap[name];
auto _enum=std::dynamic_pointer_cast<types::EnumType>(type);
auto items=_enum->getItem();
if(std::count(items.begin(),items.end(),ref)){
m_result=type;
}
else{
add_error(node.token(),ref+" is not a member of "+name);
m_result=NULL;
}
}
}
return true;
}

bool TypeChecker::visit(const ast::ArrowExpression& node) { return true; }

Expand All @@ -395,7 +458,10 @@ bool TypeChecker::visit(const ast::IdentifierExpression& node) {
}

bool TypeChecker::visit(const ast::TypeExpression& node) {
if (!identifierToTypeMap.count(node.value())) {
if(m_enumMap.contains(node.value())){
m_result=m_enumMap[node.value()];
}
else if (!identifierToTypeMap.count(node.value())) {
auto type = m_env->get(node.value());

if (!type || type.value()->category() != TypeCategory::UserDefined) {
Expand All @@ -411,6 +477,28 @@ bool TypeChecker::visit(const ast::TypeExpression& node) {
return true;
}

bool TypeChecker::visit(const ast::ExpressionTuple& node){
auto items=node.items();
std::vector<TypePtr> types;
for(auto& elem:items){
elem->accept(*this);
types.push_back(m_result);
}
m_result=TypeProducer::multipleReturn(types);
return true;
}

bool TypeChecker::visit(const ast::TypeTuple& node){
auto items=node.items();
std::vector<TypePtr> types;
for(auto& elem:items){
elem->accept(*this);
types.push_back(m_result);
}
m_result=TypeProducer::multipleReturn(types);
return true;
}

bool TypeChecker::visit(const ast::ListTypeExpr& node) {
node.elemType()->accept(*this);
auto listType = m_result;
Expand Down Expand Up @@ -480,7 +568,26 @@ bool TypeChecker::visit(const ast::NoneLiteral& node) {

bool TypeChecker::visit(const ast::UnionLiteral& node) { return true; }

bool TypeChecker::visit(const ast::EnumLiteral& node) { return true; }
bool TypeChecker::visit(const ast::EnumLiteral& node) {
auto name=identifierName(node.name());
std::vector<std::string> values;
for(auto& elem:node.fields()){
auto itemName=identifierName(elem.first);
if(std::count(values.begin(), values.end(), itemName)){
add_error(elem.first->token(), "Duplicate enum item: " + itemName);
}
else{
values.push_back(itemName);
}
}
if(m_enumMap.contains(name)){
add_error(node.token(), "Redefination of enum: " + name);
}
else{
m_enumMap[name] = types::TypeProducer::enumT(name, values);
}
return true;
}

bool TypeChecker::visit(const ast::WithStatement& node) {
//TODO: check if the variables are capable of context creation and add them to the environment
Expand Down Expand Up @@ -581,7 +688,33 @@ bool TypeChecker::visit(const ast::MultipleAssign& node){
}
}
}
//TODO: add function returning multiple stuff
else if(type->category()==MultipleReturn){
auto ret_type=std::dynamic_pointer_cast<MultipleReturnType>(type);
auto ret_types=ret_type->returnTypes();
if(ret_types.size()>name.size()){
add_error(node.token(), "To few variables on the left hand side");
}
else if(ret_types.size()<name.size()){
add_error(node.token(), "To many variables on the left hand side");
}
else{
for(size_t i=0;i<name.size();i++){
value_type.push_back(std::make_pair(ret_types[i],true));
if(name[i]->type()==ast::KAstIdentifier){
if(defined(name[i])){
check(name[i],ret_types[i]);
}
else{
value_type[i].second=false;
m_env->set(identifierName(name[i]), value_type[i].first);
}
}
}
}
}
else{
add_error(node.token(), "To many variables on the left hand side");
}
}
auto& nonConstNode = const_cast<ast::MultipleAssign&>(node);
nonConstNode.setProcessedType(value_type);
Expand Down
6 changes: 5 additions & 1 deletion Peregrine/analyzer/typeChecker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class TypeChecker : public ast::AstVisitor {
std::vector<PEError> m_errors;
void add_error(Token tok, std::string_view msg);
bool defined(ast::AstNodePtr name);
EnvPtr createEnv(EnvPtr parent = nullptr);
EnvPtr createEnv(EnvPtr parent);
std::string identifierName(ast::AstNodePtr identifier);
void checkBody(ast::AstNodePtr body,
std::vector<std::pair<TypePtr,ast::AstNodePtr>> add_var={});
Expand Down Expand Up @@ -77,13 +77,17 @@ class TypeChecker : public ast::AstVisitor {
bool visit(const ast::TernaryIf& node);
bool visit(const ast::TryExcept& node);
bool visit(const ast::MultipleAssign& node);
bool visit(const ast::ExpressionTuple& node);
bool visit(const ast::TypeTuple& node);

std::string m_filename;
TypePtr m_result;
EnvPtr m_env;

// the function whose body is being currently checked
std::shared_ptr<FunctionType> m_currentFunction;
std::map<std::string, TypePtr> m_enumMap;//TODO:Nested enum
TypePtr m_returnType=NULL;//current return type
};
}
#endif
4 changes: 4 additions & 0 deletions Peregrine/ast/ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,10 @@ std::vector<parameter> FunctionDefinition::parameters() const {
}
std::string FunctionDefinition::comment() const { return m_comment; }

void FunctionDefinition::setType(types::TypePtr type){
m_returnType=type->getTypeAst();
}

AstNodePtr FunctionDefinition::body() const { return m_body; }

Token FunctionDefinition::token() const { return m_token; }
Expand Down
1 change: 1 addition & 0 deletions Peregrine/ast/ast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,7 @@ class FunctionDefinition : public AstNode {
AstKind type() const;
std::string stringify() const;
void accept(AstVisitor& visitor) const;
void setType(types::TypePtr type);
};

class ReturnStatement : public AstNode {
Expand Down
Loading

0 comments on commit 82df231

Please sign in to comment.