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

Commit

Permalink
add union
Browse files Browse the repository at this point in the history
  • Loading branch information
SaptakBhoumik committed Jun 25, 2022
1 parent 98a8b68 commit aae43f7
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 44 deletions.
134 changes: 96 additions & 38 deletions Peregrine/analyzer/typeChecker.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//TODO: Add support for variable shadowing of the same name/type in different scopes

#include "typeChecker.hpp"
#include "ast/ast.hpp"
#include "ast/types.hpp"
Expand Down Expand Up @@ -144,43 +146,42 @@ bool TypeChecker::visit(const ast::FunctionDefinition& node) {
bool TypeChecker::visit(const ast::VariableStatement& node) {
//TODO:check if redefination
auto& nonConstNode = const_cast<ast::VariableStatement&>(node);

node.varType()->accept(*this);
TypePtr varType = m_result;
bool defined_before=defined(node.name());

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){
node.varType()->accept(*this);
TypePtr varType = m_result;
bool defined_before=defined(node.name());
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);
}
m_env->set(identifierName(node.name()), varType);
}
else{
//TODO:implement it
node.name()->accept(*this);
check(node.value(), m_result);
}
return true;
}
Expand Down Expand Up @@ -437,6 +438,34 @@ bool TypeChecker::visit(const ast::DotExpression& node) {
add_error(node.token(),ref+" is not a member of "+name);
m_result=NULL;
}
return true;
}
}
node.owner()->accept(*this);
auto type=m_result;
if(type==NULL){
return true;
}
switch(type->category()){
case TypeCategory::Union:{
auto union_type=std::dynamic_pointer_cast<types::UnionTypeDef>(type);
auto items=union_type->getItem();
m_result=NULL;
if(node.referenced()->type()!=ast::KAstIdentifier){
add_error(node.token(),"Union member must be an identifier");
}
else if(items.contains(identifierName(node.referenced()))){
m_result=items[identifierName(node.referenced())];
}
else{
add_error(node.token(),identifierName(node.referenced())+" is not a member of "+type->stringify());
}
break;
}
default:{
add_error(node.token(),"can not access member of "+type->stringify());
m_result=NULL;
return true;
}
}
return true;
Expand All @@ -460,9 +489,13 @@ bool TypeChecker::visit(const ast::IdentifierExpression& node) {

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

Expand All @@ -474,8 +507,9 @@ bool TypeChecker::visit(const ast::TypeExpression& node) {
m_result = type.value();
return true;
}

m_result = identifierToTypeMap[node.value()];
else{
m_result = identifierToTypeMap[node.value()];
}
return true;
}

Expand Down Expand Up @@ -568,7 +602,28 @@ bool TypeChecker::visit(const ast::NoneLiteral& node) {
return true;
}

bool TypeChecker::visit(const ast::UnionLiteral& node) { return true; }
bool TypeChecker::visit(const ast::UnionLiteral& node) {
auto name =identifierName(node.name());
std::map<std::string, TypePtr> item_map;
for (auto item : node.elements()) {
item.first->accept(*this);
auto item_name=identifierName(item.second);
if(item_map.contains(item_name)){
add_error(item.second->token(),item_name+" is already defined as an union member");
}
else{
item_map[item_name]=m_result;
}
}
auto union_map= m_env->getUnionMap();
if(union_map.contains(name)){
add_error(node.token(), "Redefination of union: " + name);
}
else{
m_env->add_union(name,types::TypeProducer::unionT(name, item_map));
}
return true;
}

bool TypeChecker::visit(const ast::EnumLiteral& node) {
auto name=identifierName(node.name());
Expand Down Expand Up @@ -651,7 +706,8 @@ bool TypeChecker::visit(const ast::TryExcept& node) {
}
bool TypeChecker::visit(const ast::MultipleAssign& node){
auto name=node.names();
auto value=node.values();
auto value=node.values();
auto assign_type=ast::MultipleAssign::MultiAssignType::Normal;
//type and if it is defined before
std::vector<std::pair<TypePtr,bool>> value_type;
for(auto& val : value){
Expand Down Expand Up @@ -690,6 +746,7 @@ bool TypeChecker::visit(const ast::MultipleAssign& node){
}
}
}
assign_type=ast::MultipleAssign::MultiAssignType::ListType;
}
else if(type->category()==MultipleReturn){
auto ret_type=std::dynamic_pointer_cast<MultipleReturnType>(type);
Expand All @@ -714,14 +771,15 @@ bool TypeChecker::visit(const ast::MultipleAssign& node){
}
}
}
assign_type=ast::MultipleAssign::MultiAssignType::MultipleReturn;
}
else{
add_error(node.token(), "To many variables on the left hand side");
}
}
auto& nonConstNode = const_cast<ast::MultipleAssign&>(node);
nonConstNode.setProcessedType(value_type);

nonConstNode.set_assign_type(assign_type);
return true;
}
}
6 changes: 6 additions & 0 deletions Peregrine/ast/ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1527,6 +1527,12 @@ std::string MultipleAssign::stringify() const{
return res;
}
Token MultipleAssign::token() const{return m_names[0]->token();}
MultipleAssign::MultiAssignType MultipleAssign::get_assign_type() const{
return m_assign_type;
}
void MultipleAssign::set_assign_type(MultipleAssign::MultiAssignType type){
m_assign_type = type;
}
AugAssign::AugAssign(Token tok, AstNodePtr name, AstNodePtr value){
m_token=tok;
m_name=name;
Expand Down
16 changes: 13 additions & 3 deletions Peregrine/ast/ast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1098,10 +1098,13 @@ class SumType : public AstNode {
};
//multiple assign
class MultipleAssign : public AstNode {
std::vector<AstNodePtr> m_names;
std::vector<AstNodePtr> m_values;
std::vector<std::pair<types::TypePtr,bool>> m_processed_types;

public:
enum MultiAssignType{
Normal,
MultipleReturn,
ListType
};
MultipleAssign(std::vector<AstNodePtr> names,std::vector<AstNodePtr> values);
void setProcessedType(std::vector<std::pair<types::TypePtr,bool>> types);
std::vector<std::pair<types::TypePtr,bool>> processed_types() const;
Expand All @@ -1111,6 +1114,13 @@ class MultipleAssign : public AstNode {
AstKind type() const;
std::string stringify() const;
void accept(AstVisitor& visitor) const;
MultiAssignType get_assign_type() const;
void set_assign_type(MultiAssignType type);
private:
std::vector<AstNodePtr> m_names;
std::vector<AstNodePtr> m_values;
std::vector<std::pair<types::TypePtr,bool>> m_processed_types;
MultiAssignType m_assign_type=Normal;
};
class AugAssign : public AstNode {
Token m_token;
Expand Down
7 changes: 7 additions & 0 deletions Peregrine/ast/types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,10 @@ bool UnionTypeDef::operator==(const Type& type) const{
return false;
}

ast::AstNodePtr UnionTypeDef::defaultValue() const{
return std::make_shared<ast::NoLiteral>();
}

std::array<TypePtr, 8> TypeProducer::m_integer = {
std::make_shared<IntType>(IntType::IntSizes::Int8),
std::make_shared<IntType>(IntType::IntSizes::Int16),
Expand Down Expand Up @@ -909,6 +913,9 @@ TypePtr TypeProducer::multipleReturn(std::vector<TypePtr> returnTypes){
TypePtr TypeProducer::enumT(std::string name,std::vector<std::string> items,std::string curr_value){
return std::make_shared<EnumType>(name,items,curr_value);
}
TypePtr TypeProducer::unionT(std::string name,std::map<std::string,TypePtr> items){
return std::make_shared<UnionTypeDef>(name,items);
}
std::map<std::string, TypePtr> identifierToTypeMap = {
{"i8", TypeProducer::integer(IntType::IntSizes::Int8)},
{"i16", TypeProducer::integer(IntType::IntSizes::Int16)},
Expand Down
2 changes: 2 additions & 0 deletions Peregrine/ast/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ class UnionTypeDef : public Type {
std::string stringify() const;
std::map<std::string,TypePtr> getItem() const;
std::string getName() const;
ast::AstNodePtr defaultValue() const;

bool operator==(const Type& type) const;
private:
Expand Down Expand Up @@ -324,6 +325,7 @@ class TypeProducer {
static TypePtr list(TypePtr elemType, std::string size);
static TypePtr pointer(TypePtr baseType);
static TypePtr enumT(std::string name,std::vector<std::string> items,std::string curr_value="");
static TypePtr unionT(std::string name,std::map<std::string,TypePtr> items);
};

extern std::map<std::string, TypePtr> identifierToTypeMap;
Expand Down
14 changes: 11 additions & 3 deletions Peregrine/test.pe
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
enum test:
a,b,c
union union_test1:
a:int
b:int
union union_test:
a:int
b:union_test1
def may():
return 1,test.a
c:union_test
c1:union_test1
c.b.a=4
return c.b.a,test.a,c
def main():
a=5
a,b=may()
a,b,u=may()
10 changes: 10 additions & 0 deletions Peregrine/utils/symbolTable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ class SymbolTable {
std::map<std::string, T> m_symbols;
std::shared_ptr<SymbolTable<T>> m_parent;
std::map<std::string, T> m_enumMap;
std::map<std::string, T> m_unionMap;

public:
SymbolTable(std::shared_ptr<SymbolTable> parent) {
m_parent = parent;
if(m_parent!=nullptr){
m_enumMap = parent->getEnumMap();
m_unionMap = parent->getUnionMap();
}
}

Expand All @@ -45,6 +47,14 @@ class SymbolTable {
m_enumMap[key]=value;
}

std::map<std::string, T> getUnionMap(){
return m_unionMap;
}

void add_union(std::string key,T value){
m_unionMap[key]=value;
}

bool set(std::string name, T value) {
if (get(name)) {
return false; // the symbol has been defined already
Expand Down

0 comments on commit aae43f7

Please sign in to comment.