diff --git a/Peregrine/analyzer/typeChecker.cpp b/Peregrine/analyzer/typeChecker.cpp index ee27c750..0f86dee4 100644 --- a/Peregrine/analyzer/typeChecker.cpp +++ b/Peregrine/analyzer/typeChecker.cpp @@ -143,6 +143,59 @@ bool TypeChecker::visit(const ast::FunctionDefinition& node) { return true; } +bool TypeChecker::visit(const ast::MethodDefinition& node) { + EnvPtr oldEnv = m_env; + m_env = createEnv(oldEnv); + + std::vector parameterTypes; + parameterTypes.reserve(node.parameters().size()+1); + auto reciever = node.reciever(); + if(reciever.p_type->type()!=ast::KAstNoLiteral){ + reciever.p_type->accept(*this); + parameterTypes.push_back(m_result); + m_env->set(identifierName(reciever.p_name), m_result); + } + for (auto& param : node.parameters()) { + 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); + } + + param.p_default->accept(*this); + parameterTypes.push_back(m_result); + m_env->set(identifierName(param.p_name), m_result); + continue; + } + + param.p_type->accept(*this); + parameterTypes.push_back(m_result); + m_env->set(identifierName(param.p_name), m_result); + } + node.returnType()->accept(*this); + auto returnType=m_result; + auto methodType = + std::make_shared(parameterTypes, returnType,true); + + auto oldFunction = m_currentFunction; + auto oldReturnType = m_returnType; + m_returnType = NULL; + m_currentFunction = methodType; + node.body()->accept(*this); + if(m_returnType!=NULL){ + auto& nonconstnode = const_cast(node); + nonconstnode.setType(m_returnType); + methodType =std::make_shared(parameterTypes, m_returnType,true); + } + m_returnType = oldReturnType; + m_currentFunction = oldFunction; + + m_env = oldEnv; + + m_env->set(identifierName(node.name()), methodType); + return true; +} + bool TypeChecker::visit(const ast::VariableStatement& node) { //TODO:check if redefination auto& nonConstNode = const_cast(node); @@ -161,6 +214,13 @@ bool TypeChecker::visit(const ast::VariableStatement& node) { add_error(node.token(), "You cant declare a variable of type void"); return true; } + else if(m_result->category()==Function){ + auto cast=std::dynamic_pointer_cast(m_result); + if(cast->isMethod()){ + add_error(node.token(), "You cant declare a variable of type `method`"); + return true; + } + } nonConstNode.setProcessedType(m_result,defined_before); varType = m_result; } else{ @@ -204,6 +264,13 @@ bool TypeChecker::visit(const ast::ConstDeclaration& node) { add_error(node.token(), "You cant declare a constant of type void"); return true; } + else if(m_result->category()==Function){ + auto cast=std::dynamic_pointer_cast(m_result); + if(cast->isMethod()){ + add_error(node.token(), "You cant declare a variable of type `method`"); + return true; + } + } nonConstNode.setProcessedType(m_result); constType = m_result; } else{ @@ -804,4 +871,28 @@ bool TypeChecker::visit(const ast::LambdaDefinition& node){ m_result=functionType; return true; } +bool TypeChecker::visit(const ast::ExternStatement& node){ + //TODO:prevent extern name with same variabel + extern_libs[node.name()]=node.libs(); + return true; +} +bool TypeChecker::visit(const ast::ExternFuncDef& node) { + //TODO:complete it + if(!extern_libs.contains(node.owner())){ + add_error(node.token(), "Library "+node.owner()+" not found"); + return true; + } + auto name = node.name(); + auto params = node.parameters(); + std::vector param_type; + for (auto& param : params) { + param->accept(*this); + param_type.push_back(m_result); + } + node.returnType()->accept(*this); + auto return_type = m_result; + auto functionType = std::make_shared(param_type, return_type); + // m_env->extern_set(name, functionType); + return true; +} } \ No newline at end of file diff --git a/Peregrine/analyzer/typeChecker.hpp b/Peregrine/analyzer/typeChecker.hpp index ffa53e16..147c50b8 100644 --- a/Peregrine/analyzer/typeChecker.hpp +++ b/Peregrine/analyzer/typeChecker.hpp @@ -32,6 +32,7 @@ class TypeChecker : public ast::AstVisitor { bool visit(const ast::ClassDefinition& node); bool visit(const ast::ImportStatement& node); bool visit(const ast::FunctionDefinition& node); + bool visit(const ast::MethodDefinition& node); bool visit(const ast::VariableStatement& node); bool visit(const ast::ConstDeclaration& node); bool visit(const ast::TypeDefinition& node); @@ -79,6 +80,8 @@ class TypeChecker : public ast::AstVisitor { bool visit(const ast::ExpressionTuple& node); bool visit(const ast::TypeTuple& node); bool visit(const ast::LambdaDefinition& node); + bool visit(const ast::ExternStatement& node); + bool visit(const ast::ExternFuncDef& node); std::string m_filename; TypePtr m_result; @@ -87,6 +90,7 @@ class TypeChecker : public ast::AstVisitor { // the function whose body is being currently checked std::shared_ptr m_currentFunction; TypePtr m_returnType=NULL;//current return type + std::map> extern_libs;//the c libs that are imported }; } #endif \ No newline at end of file diff --git a/Peregrine/ast/ast.cpp b/Peregrine/ast/ast.cpp index 316eb571..c13129fc 100644 --- a/Peregrine/ast/ast.cpp +++ b/Peregrine/ast/ast.cpp @@ -1585,6 +1585,10 @@ Token MethodDefinition::token() const { return m_token; } AstKind MethodDefinition::type() const { return KAstMethodDef; } +void MethodDefinition::setType(types::TypePtr type){ + m_returnType=type->getTypeAst(); +} + std::string MethodDefinition::stringify() const { std::string res = "def ("; if(m_reciever.is_const){ diff --git a/Peregrine/ast/ast.hpp b/Peregrine/ast/ast.hpp index cdce737c..404cf6ec 100644 --- a/Peregrine/ast/ast.hpp +++ b/Peregrine/ast/ast.hpp @@ -1166,6 +1166,7 @@ class MethodDefinition : public AstNode { AstKind type() const; std::string stringify() const; void accept(AstVisitor& visitor) const; + void setType(types::TypePtr type); }; class ExternFuncDef : public AstNode { Token m_token; diff --git a/Peregrine/ast/types.cpp b/Peregrine/ast/types.cpp index 57869b1c..afc54590 100644 --- a/Peregrine/ast/types.cpp +++ b/Peregrine/ast/types.cpp @@ -581,12 +581,19 @@ ast::AstNodePtr UserDefinedType::getTypeAst() const { } FunctionType::FunctionType(std::vector parameterTypes, - TypePtr returnType) { + TypePtr returnType,bool is_user_defined_method) { m_parameterTypes = parameterTypes; m_returnType = returnType; + m_is_user_defined_method=is_user_defined_method; } -TypeCategory FunctionType::category() const { return TypeCategory::Function; } +TypeCategory FunctionType::category() const { + return TypeCategory::Function; +} + +bool FunctionType::isMethod() const{ + return m_is_user_defined_method; +} const std::vector& FunctionType::parameterTypes() const { return m_parameterTypes; diff --git a/Peregrine/ast/types.hpp b/Peregrine/ast/types.hpp index a07fdef4..e1d4143f 100644 --- a/Peregrine/ast/types.hpp +++ b/Peregrine/ast/types.hpp @@ -228,14 +228,16 @@ class UserDefinedType : public Type { }; class FunctionType : public Type { + bool m_is_user_defined_method=false; std::vector m_parameterTypes; TypePtr m_returnType; public: - FunctionType(std::vector parameterTypes, TypePtr returnType); + FunctionType(std::vector parameterTypes, TypePtr returnType,bool is_user_defined_method=false); ast::AstNodePtr getTypeAst() const; TypeCategory category() const; + bool isMethod() const; const std::vector& parameterTypes() const; TypePtr returnType() const; bool isConvertibleTo(const Type& type) const; diff --git a/Peregrine/parser/parser.cpp b/Peregrine/parser/parser.cpp index 6fc85c2d..9e3f97b6 100644 --- a/Peregrine/parser/parser.cpp +++ b/Peregrine/parser/parser.cpp @@ -458,8 +458,8 @@ AstNodePtr Parser::parseExtern(){ auto name=m_currentToken.keyword; std::vector libs; expect(tk_assign,"Expected = but got "+next().keyword+" instead","","",""); - expect(tk_import,"Expected = but got "+next().keyword+" instead","","",""); - expect(tk_l_paren,"Expected = but got "+next().keyword+" instead","","",""); + expect(tk_import,"Expected `import` but got "+next().keyword+" instead","","",""); + expect(tk_l_paren,"Expected `(` but got "+next().keyword+" instead","","",""); while(m_currentToken.tkType!=tk_r_paren){ expect(tk_string,"Expected string but got "+next().keyword+" instead","","",""); libs.push_back(m_currentToken.keyword); diff --git a/Peregrine/test.pe b/Peregrine/test.pe index 34d028ba..b99cc10f 100644 --- a/Peregrine/test.pe +++ b/Peregrine/test.pe @@ -13,6 +13,11 @@ def may(): return c.b.a,test.a,c def june(a:int)->int: return a +def (x:int)f(): + return x +extern x=import("c") def main(): + m=may + #l=f Should be an error j=def (x:int):june(x) - a,b,u=may() + a,b,c=m() \ No newline at end of file