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

Commit

Permalink
typechecker...
Browse files Browse the repository at this point in the history
  • Loading branch information
SaptakBhoumik committed Jun 14, 2022
1 parent ba331bb commit a3a12c1
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 46 deletions.
8 changes: 8 additions & 0 deletions Peregrine/analyzer/ast_validate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,14 @@ bool Validator::visit(const MultipleAssign& node){
for(auto& x:node.names()){
x->accept(*this);
}
if(node.values().size()!=1&&node.values().size()!=node.names().size()){
if(node.values().size()>node.names().size()){
add_error(node.token(), "SyntaxError: Too many values in multiple assignment");
}
else{
add_error(node.token(), "SyntaxError: Too few values in multiple assignment");
}
}
return true;
}
bool Validator::visit(const AugAssign& node){
Expand Down
129 changes: 94 additions & 35 deletions Peregrine/analyzer/typeChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,19 @@ TypeChecker::TypeChecker(ast::AstNodePtr ast) {
exit(1);
}
}

bool TypeChecker::defined(ast::AstNodePtr name){
bool defined_before=true;

{
if(name->type()==ast::KAstIdentifier){
auto identifierType = m_env->get(identifierName(name));
if (identifierType==std::nullopt) {
defined_before=false;
}
}
}
return defined_before;
}
void TypeChecker::add_error(Token tok, std::string_view msg) {
PEError err = {
{tok.line, tok.start, tok.location, m_filename, tok.statement},
Expand Down Expand Up @@ -47,17 +59,20 @@ void TypeChecker::checkBody(ast::AstNodePtr body,
m_env = previousEnv;
}

void TypeChecker::check(ast::AstNodePtr expr, const Type& expectedType) {
void TypeChecker::check(ast::AstNodePtr expr, const TypePtr expTypePtr) {
if(expTypePtr==NULL){
return;
}
expr->accept(*this);
if(m_result==NULL){
return;
}
const Type& exprType = *m_result;

if (exprType != expectedType) {
if (!exprType.isConvertibleTo(expectedType) &&
!expectedType.isConvertibleTo(exprType)) {
add_error(expr->token(), "expected type " + expectedType.stringify() +
if (exprType != *expTypePtr) {
if (!exprType.isConvertibleTo(*expTypePtr) &&
!expTypePtr->isConvertibleTo(exprType)) {
add_error(expr->token(), "expected type " + expTypePtr->stringify() +
", got " + exprType.stringify() +
" instead");
}
Expand Down Expand Up @@ -89,7 +104,7 @@ bool TypeChecker::visit(const ast::FunctionDefinition& node) {
if (param.p_default->type() != ast::KAstNoLiteral) {
if (param.p_type->type() != ast::KAstNoLiteral) {
param.p_type->accept(*this);
check(param.p_default, *m_result);
check(param.p_default, m_result);
}

param.p_default->accept(*this);
Expand Down Expand Up @@ -118,20 +133,12 @@ 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=true;

{
if(node.name()->type()==ast::KAstIdentifier){
auto identifierType = m_env->get(identifierName(node.name()));
if (identifierType==std::nullopt) {
defined_before=false;
}
}
}
bool defined_before=defined(node.name());

if (varType->category() == TypeCategory::Void) {
// inferring the type of the variable
Expand All @@ -140,17 +147,21 @@ bool TypeChecker::visit(const ast::VariableStatement& node) {
varType = m_result;
} else{
if(node.value()->type()!=ast::KAstNoLiteral){
check(node.value(), *varType);
check(node.value(), varType);
}
nonConstNode.setProcessedType(varType,true);
}

//TODO:Check if it is an identifier
m_env->set(identifierName(node.name()), varType);
if(node.name()->type()==ast::KAstIdentifier){
m_env->set(identifierName(node.name()), varType);
}
else{
//TODO:implement it
}
return true;
}

bool TypeChecker::visit(const ast::ConstDeclaration& node) {
//TODO:check if redefination
auto& nonConstNode = const_cast<ast::ConstDeclaration&>(node);

node.constType()->accept(*this);
Expand All @@ -162,11 +173,10 @@ bool TypeChecker::visit(const ast::ConstDeclaration& node) {
nonConstNode.setProcessedType(m_result);
constType = m_result;
} else{
check(node.value(), *constType);
check(node.value(), constType);
nonConstNode.setProcessedType(NULL);
}

//TODO:Check if it is an identifier
m_env->set(identifierName(node.name()), constType);
return true;
}
Expand All @@ -180,11 +190,11 @@ bool TypeChecker::visit(const ast::TypeDefinition& node) {
}

bool TypeChecker::visit(const ast::IfStatement& node) {
check(node.condition(), *TypeProducer::boolean());
check(node.condition(), TypeProducer::boolean());
checkBody(node.ifBody());

for (auto& elif : node.elifs()) {
check(elif.first, *TypeProducer::boolean());
check(elif.first, TypeProducer::boolean());
checkBody(elif.second);
}

Expand All @@ -195,7 +205,7 @@ bool TypeChecker::visit(const ast::IfStatement& node) {
}

bool TypeChecker::visit(const ast::AssertStatement& node) {
check(node.condition(), *TypeProducer::boolean());
check(node.condition(), TypeProducer::boolean());
return true;
}

Expand All @@ -218,7 +228,7 @@ bool TypeChecker::visit(const ast::RaiseStatement& node) {
}

bool TypeChecker::visit(const ast::WhileStatement& node) {
check(node.condition(), *TypeProducer::boolean());
check(node.condition(), TypeProducer::boolean());
checkBody(node.body());
return true;
}
Expand Down Expand Up @@ -251,7 +261,7 @@ bool TypeChecker::visit(const ast::MatchStatement& node) {
break;
}
else if(case_exp[i]->type()!=ast::KAstNoLiteral){
check(case_exp[i],*types[i]);
check(case_exp[i],types[i]);
}
}
}
Expand All @@ -270,7 +280,7 @@ bool TypeChecker::visit(const ast::ReturnStatement& node) {

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

check(node.returnValue(), *m_currentFunction->returnType());
check(node.returnValue(), m_currentFunction->returnType());
return true;
}

Expand All @@ -288,7 +298,7 @@ bool TypeChecker::visit(const ast::ListLiteral& node) {
TypePtr listType = m_result;

for (auto& elem : node.elements()) {
check(elem, *listType);
check(elem, listType);
}
m_result = TypeProducer::list(listType, std::to_string(node.elements().size()));
return true;
Expand Down Expand Up @@ -359,7 +369,7 @@ bool TypeChecker::visit(const ast::FunctionCall& node) {
identifierName(node.name()));

for (size_t i = 0; i < node.arguments().size(); i++) {
check(node.arguments()[i], *functionType->parameterTypes()[i]);
check(node.arguments()[i], functionType->parameterTypes()[i]);
}

m_result = functionType->returnType();
Expand Down Expand Up @@ -405,7 +415,7 @@ bool TypeChecker::visit(const ast::ListTypeExpr& node) {
node.elemType()->accept(*this);
auto listType = m_result;
if(node.size()->type()!=ast::KAstNoLiteral){
check(node.size(), *TypeProducer::integer());
check(node.size(), TypeProducer::integer());
}
std::string size="";
if(node.size()->type()==ast::KAstNoLiteral){
Expand Down Expand Up @@ -498,8 +508,8 @@ bool TypeChecker::visit(const ast::DefaultArg& node) { return true; }
bool TypeChecker::visit(const ast::TernaryIf& node) {
node.if_value()->accept(*this);
TypePtr ifType = m_result;
check(node.if_condition(), *TypeProducer::boolean());
check(node.else_value(), *ifType);
check(node.if_condition(), TypeProducer::boolean());
check(node.else_value(), ifType);
m_result=ifType;
return true;
}
Expand All @@ -518,7 +528,7 @@ bool TypeChecker::visit(const ast::TryExcept& node) {
exception[0]->accept(*this);
auto type=m_result;
for(size_t i=1;i<exception.size();i++){
check(exception[i],*type);
check(exception[i],type);
}
if(except_clause.first.second->type()!=ast::KAstNoLiteral){
std::pair<TypePtr,ast::AstNodePtr> var=std::make_pair(type,except_clause.first.second);
Expand All @@ -529,4 +539,53 @@ bool TypeChecker::visit(const ast::TryExcept& node) {
}
return true;
}
bool TypeChecker::visit(const ast::MultipleAssign& node){
auto name=node.names();
auto value=node.values();
//type and if it is defined before
std::vector<std::pair<TypePtr,bool>> value_type;
for(auto& val : value){
val->accept(*this);
value_type.push_back(std::make_pair(m_result,true));
}
if(value_type.size()>1){
//this is not a list or function returning multiple stuff
for(size_t i=0;i<name.size();i++){
if(name[i]->type()==ast::KAstIdentifier){
if(defined(name[i])){
check(name[i],value_type[i].first);
}
else{
value_type[i].second=false;
m_env->set(identifierName(name[i]), value_type[i].first);
}
}
}
}
else{
auto type=value_type[0].first;
value_type.clear();
if(type->category()==List){
//TODO:add dictionary here
auto elem_type=std::dynamic_pointer_cast<ListType>(type)->elemType();
for(size_t i=0;i<name.size();i++){
value_type.push_back(std::make_pair(elem_type,true));
if(name[i]->type()==ast::KAstIdentifier){
if(defined(name[i])){
check(name[i],elem_type);
}
else{
value_type[i].second=false;
m_env->set(identifierName(name[i]), elem_type);
}
}
}
}
//TODO: add function returning multiple stuff
}
auto& nonConstNode = const_cast<ast::MultipleAssign&>(node);
nonConstNode.setProcessedType(value_type);

return true;
}
}
4 changes: 3 additions & 1 deletion Peregrine/analyzer/typeChecker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@ class TypeChecker : public ast::AstVisitor {
private:
std::vector<PEError> m_errors;
void add_error(Token tok, std::string_view msg);
bool defined(ast::AstNodePtr name);
EnvPtr createEnv(EnvPtr parent = nullptr);
std::string identifierName(ast::AstNodePtr identifier);
void checkBody(ast::AstNodePtr body,
std::vector<std::pair<TypePtr,ast::AstNodePtr>> add_var={});

void check(ast::AstNodePtr expr, const Type& expectedType);
void check(ast::AstNodePtr expr, const TypePtr expectedType);

bool visit(const ast::ClassDefinition& node);
bool visit(const ast::ImportStatement& node);
Expand Down Expand Up @@ -75,6 +76,7 @@ class TypeChecker : public ast::AstVisitor {
bool visit(const ast::DefaultArg& node);
bool visit(const ast::TernaryIf& node);
bool visit(const ast::TryExcept& node);
bool visit(const ast::MultipleAssign& node);

std::string m_filename;
TypePtr m_result;
Expand Down
25 changes: 21 additions & 4 deletions Peregrine/ast/ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1487,12 +1487,29 @@ MultipleAssign::MultipleAssign(std::vector<AstNodePtr> names,std::vector<AstNode
std::vector<AstNodePtr> MultipleAssign::names() const{return m_names;}
std::vector<AstNodePtr> MultipleAssign::values() const{return m_values;}
AstKind MultipleAssign::type() const{return KAstMultipleAssign;}
std::vector<std::pair<types::TypePtr,bool>> MultipleAssign::processed_types() const{return m_processed_types;}
void MultipleAssign::setProcessedType(std::vector<std::pair<types::TypePtr,bool>> processed_types){
m_processed_types=processed_types;
}
std::string MultipleAssign::stringify() const{
std::string res="((";
for (size_t i=0;i<m_names.size();++i){
res+=m_names[i]->stringify();
if(i<m_names.size()-1){
res+=",";
if(m_processed_types.size()>0){
for (size_t i=0;i<m_names.size();++i){
res+=m_names[i]->stringify();
if(!m_processed_types[i].second){
res+=":"+m_processed_types[i].first->getTypeAst()->stringify();
}
if(i<m_names.size()-1){
res+=",";
}
}
}
else{
for (size_t i=0;i<m_names.size();++i){
res+=m_names[i]->stringify();
if(i<m_names.size()-1){
res+=",";
}
}
}
res+=")=(";
Expand Down
3 changes: 3 additions & 0 deletions Peregrine/ast/ast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1099,8 +1099,11 @@ class SumType : public AstNode {
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:
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;
std::vector<AstNodePtr> names() const;
std::vector<AstNodePtr> values() const;
Token token() const;
Expand Down
2 changes: 1 addition & 1 deletion Peregrine/lexer/lexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ void LEXER::add_unknown(){
type = key_map[m_keyword];
}
else if(m_keyword!=""){
if(is_int(m_keyword)){
if(is_int(m_keyword)||is_hex(m_keyword)){
type=tk_integer;
}
else if(std::regex_match(m_keyword,std::regex(R"(^^\s*[-+]?((\d+(\.\d+)?)|(\d+\.)|(\.\d+))(e[-+]?\d+)?\s*$)"))){
Expand Down
1 change: 1 addition & 0 deletions Peregrine/lexer/lexer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class LEXER{
bool advance();
std::vector<std::string> split_ln(std::string code);
bool is_int(const std::string s);
bool is_hex(const std::string s);


void lex_string();
Expand Down
7 changes: 7 additions & 0 deletions Peregrine/lexer/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ bool LEXER::is_int(const std::string s)
s.end(), [](unsigned char c) { return !std::isdigit(c); }) == s.end();
}

bool LEXER::is_hex(const std::string s)
{
return !s.empty()&&(s.compare(0, 2, "0x") == 0||s.compare(0, 2, "0X") == 0)
&& s.size() > 2
&& s.find_first_not_of("0123456789abcdefABCDEF", 2) == std::string::npos;
}

char LEXER::next(){
if((m_curr_index+1)<m_input.size()){
return m_input[m_curr_index+1];
Expand Down
Loading

0 comments on commit a3a12c1

Please sign in to comment.