From b9322dfb8efe37f6f88a899269bdf21015f4db9a Mon Sep 17 00:00:00 2001 From: Patrick Schönberger Date: Wed, 4 Aug 2021 21:44:26 +0200 Subject: generic functions and structs --- src/find.h | 111 ++++++++++++++++++++++++++++- src/repr.h | 10 ++- src/repr_get.h | 39 +++++++++++ src/toc.h | 215 +++++++++++++++++++++++++++++++++++++++++++-------------- src/typeInfo.h | 7 +- src/visit.h | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 519 insertions(+), 56 deletions(-) create mode 100644 src/visit.h (limited to 'src') diff --git a/src/find.h b/src/find.h index 1876a1e..fec540f 100644 --- a/src/find.h +++ b/src/find.h @@ -18,6 +18,15 @@ opt find(const std::vector & ts, std::function f) return nullopt; } +template +opt findPtr(const std::vector & ts, std::function f) +{ + for (int i = 0; i < ts.size(); i++) + if (f(ts[i])) + return &((T *)ts.data())[i]; + return nullopt; +} + opt findFunction( const Program & p, const std::string & name, @@ -55,6 +64,43 @@ opt findFunction( return find(p.functions, [&](Function f) { return f.name == name; }); } +opt findFunctionPtr( + const Program & p, + const std::string & name, + const std::vector & namespacePrefixes) +{ + if (namespacePrefixes.empty()) + { + return findPtr(p.functions, [&](Function f) { return f.name == name; }); + } + + auto n = find(p.namespaces, [&](Namespace n) { return n.name == namespacePrefixes[0]; }); + + if (!n.has_value()) + return nullopt; + + std::vector namespaces = { n.value() }; + + for (int i = 1; i < namespacePrefixes.size(); i++) + { + n = find(n.value().namespaces, [&](Namespace n) { return n.name == namespacePrefixes[i]; }); + + if (!n.has_value()) + return nullopt; + + namespaces.push_back(n.value()); + } + + for (int i = namespaces.size()-1; i >= 0; i--) + { + auto f = findPtr(namespaces[i].functions, [&](Function f) { return f.name == name; }); + if (f.has_value()) + return f.value(); + } + + return findPtr(p.functions, [&](Function f) { return f.name == name; }); +} + opt findStruct( const Program & p, const std::string & name, @@ -69,6 +115,8 @@ opt findStruct( if (!n.has_value()) return nullopt; + + std::vector namespaces = { n.value() }; for (int i = 1; i < namespacePrefixes.size(); i++) { @@ -76,10 +124,57 @@ opt findStruct( if (!n.has_value()) return nullopt; + + namespaces.push_back(n.value()); + } + + for (int i = namespaces.size()-1; i >= 0; i--) + { + auto f = find(namespaces[i].structs, [&](Struct f) { return f.name == name; }); + if (f.has_value()) + return f.value(); } + return find(n.value().structs, [&](Struct s) { return s.name == name; }); } +opt findStructPtr( + const Program & p, + const std::string & name, + const std::vector & namespacePrefixes) +{ + if (namespacePrefixes.empty()) + { + return findPtr(p.structs, [&](Struct s) { return s.name == name; }); + } + + auto n = find(p.namespaces, [&](Namespace n) { return n.name == namespacePrefixes[0]; }); + + if (!n.has_value()) + return nullopt; + + std::vector namespaces = { n.value() }; + + for (int i = 1; i < namespacePrefixes.size(); i++) + { + n = find(n.value().namespaces, [&](Namespace n) { return n.name == namespacePrefixes[i]; }); + + if (!n.has_value()) + return nullopt; + + namespaces.push_back(n.value()); + } + + for (int i = namespaces.size()-1; i >= 0; i--) + { + auto f = findPtr(namespaces[i].structs, [&](Struct f) { return f.name == name; }); + if (f.has_value()) + return f.value(); + } + + return findPtr(n.value().structs, [&](Struct s) { return s.name == name; }); +} + opt findVariable( const Program & p, const std::string & name, @@ -96,7 +191,7 @@ opt findVariable( return nullopt; } -opt findStructMethod( +opt> findStructMethod( const Program & p, const std::string & name, TypeInfo ti) @@ -108,8 +203,20 @@ opt findStructMethod( return nullopt; return find>(s.value().methods, [&](Function f) { return f.name == name; }); } +opt *> findStructMethodPtr( + const Program & p, + const std::string & name, + TypeInfo ti) +{ + if (!ti.isStruct) + return nullopt; + auto s = findStruct(p, ti.type.name, ti.type.namespacePrefixes); + if (!s.has_value()) + return nullopt; + return findPtr>(s.value().methods, [&](Function f) { return f.name == name; }); +} -opt findStructMember( +opt> findStructMember( const Program & p, TypeInfo ti, const std::string & name) diff --git a/src/repr.h b/src/repr.h index f12b0da..b30aecd 100644 --- a/src/repr.h +++ b/src/repr.h @@ -61,6 +61,7 @@ struct Type std::vector namespacePrefixes; std::string name; std::vector modifiers; + std::vector genericInstantiation; }; struct Variable @@ -77,8 +78,10 @@ struct Body struct Function { - Type returnType; std::string name; + std::vector genericTypeNames; + std::vector> genericInstantiations; + Type returnType; std::vector parameters; bool defined; Body body; @@ -95,6 +98,8 @@ struct StructMember struct Struct { std::string name; + std::vector genericTypeNames; + std::vector> genericInstantiations; std::vector> members; std::vector> methods; }; @@ -126,6 +131,7 @@ struct FuncExpr std::vector namespacePrefixes; std::string functionName; std::vector arguments; + std::vector genericInstantiation; }; struct MethodExpr @@ -133,6 +139,7 @@ struct MethodExpr std::shared_ptr expr; std::string methodName; std::vector arguments; + std::vector genericInstantiation; }; enum class LitType @@ -157,6 +164,7 @@ struct ParenExpr struct DotExpr { + bool isPointer; std::shared_ptr expr; std::string identifier; }; diff --git a/src/repr_get.h b/src/repr_get.h index 827c02b..2d321b0 100644 --- a/src/repr_get.h +++ b/src/repr_get.h @@ -43,6 +43,13 @@ Type getType(TocParser::TypeContext * ctx) isStaticArray ? atoi(m->INT_LIT()->toString().c_str()) : -1 ); } + if (ctx->genericInstantiation() != nullptr) + { + for (auto g : ctx->genericInstantiation()->type()) + { + result.genericInstantiation.push_back(getType(g)); + } + } return result; } Variable getVariable(TocParser::VarContext * ctx) @@ -77,11 +84,20 @@ Function getFunction(TocParser::FuncContext * ctx, std::shared_ptr pare Function result; result.name = ctx->funcName()->NAME()->toString(); result.returnType = getType(ctx->type()); + if (ctx->genericDecl() != nullptr) + { + for (auto t : ctx->genericDecl()->typeName()) + { + result.genericTypeNames.push_back(t->getText()); + } + } + if (!ctx->parameter()->var().empty()) { for (auto p : ctx->parameter()->var()) result.parameters.push_back(getVariable(p)); } + if (ctx->body() != nullptr) { result.body = getBody(ctx->body(), parent); @@ -97,6 +113,14 @@ Struct getStruct(TocParser::StructDeclContext * ctx, std::shared_ptr pa { Struct result; result.name = ctx->structName()->NAME()->toString(); + if (ctx->genericDecl() != nullptr) + { + for (auto t : ctx->genericDecl()->typeName()) + { + result.genericTypeNames.push_back(t->getText()); + } + } + for (auto m : ctx->structMember()) { if (m->structVar() != nullptr) @@ -199,6 +223,13 @@ Expr getExpr(TocParser::FuncExprContext * ctx) for (auto n : ctx->namespaceSpecifier()) result._func.namespacePrefixes.push_back(n->typeName()->getText()); result._func.functionName = ctx->funcName()->NAME()->toString(); + if (ctx->genericInstantiation() != nullptr) + { + for (auto g : ctx->genericInstantiation()->type()) + { + result._func.genericInstantiation.push_back(getType(g)); + } + } for (auto e : ctx->expr()) result._func.arguments.push_back(getExpr(e)); return result; @@ -209,6 +240,13 @@ Expr getExpr(TocParser::MethodExprContext * ctx) result.type = ExprType::Method; result._method.expr = std::make_unique(getExpr(ctx->expr(0))); result._method.methodName = ctx->funcName()->NAME()->toString(); + if (ctx->genericInstantiation() != nullptr) + { + for (auto g : ctx->genericInstantiation()->type()) + { + result._method.genericInstantiation.push_back(getType(g)); + } + } for (int i = 1; i < ctx->expr().size(); i++) result._method.arguments.push_back(getExpr(ctx->expr(i))); return result; @@ -252,6 +290,7 @@ Expr getExpr(TocParser::DotExprContext * ctx) result.type = ExprType::Dot; result._dot.expr = std::make_unique(getExpr(ctx->expr())); result._dot.identifier = ctx->varName()->getText(); + result._dot.isPointer = ctx->arrow() != nullptr; return result; } Expr getExpr(TocParser::PrefixOpExprContext * ctx) diff --git a/src/toc.h b/src/toc.h index c0c73f1..659c9f3 100644 --- a/src/toc.h +++ b/src/toc.h @@ -4,6 +4,7 @@ #include #include "repr.h" +#include "generic.h" #include "typeInfo.h" template @@ -53,15 +54,27 @@ static std::string namespacePrefix() { return sstr.str(); } +static std::map currentInstantiation; + static Program globalPrg; static std::shared_ptr globalCtx; std::ostream & operator<< (std::ostream & out, const Type & t) { + for (auto kv : currentInstantiation) + { + if (t.name == kv.first) + { + out << kv.second; + return out; + } + } TypeInfo ti = typeType(globalPrg, t); if (ti.isStruct) out << "struct "; out << vectorStr(t.namespacePrefixes, "_", true) << t.name; + if (!t.genericInstantiation.empty()) + out << genericAppendix(t.genericInstantiation); return out; } @@ -135,16 +148,21 @@ std::ostream & operator<< (std::ostream & out, const Expr & e) TypeInfo ti = typeExpr(globalPrg, namespaces, globalCtx, e); } - out << vectorStr(e._func.namespacePrefixes, "_", true) << e._func.functionName << "(" << vectorStr(e._func.arguments, ", ") << ")"; break; + out << vectorStr(e._func.namespacePrefixes, "_", true) << e._func.functionName; + if (!e._func.genericInstantiation.empty()) + out << genericAppendix(e._func.genericInstantiation); + out <<"(" << vectorStr(e._func.arguments, ", ") << ")"; break; } case ExprType::Method: { TypeInfo ti = typeExpr(globalPrg, namespaces, globalCtx, *e._method.expr); out << vectorStr(ti.type.namespacePrefixes, "_", true) << - ti.type.name << "_" << e._method.methodName << - "(&" << *e._method.expr << (e._method.arguments.empty() ? "" : ", ") << - vectorStr(e._method.arguments, ", ") << ")"; break; + ti.type.name << genericAppendix(ti.type.genericInstantiation) << "_" << e._method.methodName; + if (!e._method.genericInstantiation.empty()) + out << genericAppendix(e._method.genericInstantiation); + out << "(&" << *e._method.expr << (e._method.arguments.empty() ? "" : ", ") << + vectorStr(e._method.arguments, ", ") << ")"; break; } case ExprType::Lit: /**/ if (e._lit.type == LitType::Int) out << e._lit._int; @@ -155,7 +173,7 @@ std::ostream & operator<< (std::ostream & out, const Expr & e) case ExprType::Paren: out << "(" << e._paren.expr << ")"; break; case ExprType::Dot: - out << *e._dot.expr << "." << e._dot.identifier; break; + out << *e._dot.expr << (e._dot.isPointer ? "->" : ".") << e._dot.identifier; break; case ExprType::PrefixOp: out << PrefixOperatorTypeStrings[(int)e._prefixOp.type] << *e._prefixOp.expr; break; case ExprType::PostfixOp: @@ -216,75 +234,172 @@ void tocFunction (std::ostream & out, const Function & f, bool stub) { if (!stub && !f.defined) return; - out << f.returnType << " " << namespacePrefix() << f.name << " (" << vectorStr(f.parameters, ", ") << ")"; - - if (stub) + if (f.genericTypeNames.empty()) { - out << ";\n"; + out << f.returnType << " " << namespacePrefix() << f.name << " (" << vectorStr(f.parameters, ", ") << ")"; + + if (stub) + { + out << ";\n"; + } + else + { + out << "\n" << f.body; + } } else { - out << "\n" << f.body; + for (auto instantiation : f.genericInstantiations) + { + for (int i = 0; i < f.genericTypeNames.size(); i++) + { + currentInstantiation[f.genericTypeNames[i]] = instantiation[i]; + } + + out << f.returnType << " " << namespacePrefix() << f.name << genericAppendix(instantiation) << " (" << vectorStr(f.parameters, ", ") << ")"; + + if (stub) + { + out << ";\n"; + } + else + { + out << "\n" << f.body; + } + + currentInstantiation.clear(); + } } } void tocStruct (std::ostream & out, const Struct & s, bool stub) { - out << "struct " << namespacePrefix() << s.name; - if (stub) + if (s.genericTypeNames.empty()) { - out << ";\n"; + out << "struct " << namespacePrefix() << s.name; + if (stub) + { + out << ";\n"; + for (auto m : s.methods) + { + Function f = m; + + f.parameters.insert(f.parameters.begin(), + {"this", + { + namespaces, + s.name, + { + {TypeModifierType::Pointer, false, -1} + } + } + }); + out << f.returnType << " " << + namespacePrefix() << s.name << "_" << f.name << + " (" << vectorStr(f.parameters, ", ") << ");\n"; + } + return; + } + out << "\n{\n"; + indentation += 2; + + for (auto m : s.members) + { + indent(out); + out << m << ";\n"; + } + + indent(out, -2); + out << "};\n"; + for (auto m : s.methods) { Function f = m; - f.parameters.insert(f.parameters.begin(), - {"this", - { - namespaces, - s.name, + {"this", { - {TypeModifierType::Pointer, false, -1} + namespaces, + s.name, + { + {TypeModifierType::Pointer, false, -1} + } } - } - }); + }); out << f.returnType << " " << - namespacePrefix() << s.name << "_" << f.name << - " (" << vectorStr(f.parameters, ", ") << ");\n"; + namespacePrefix() << s.name << "_" << f.name << + " (" << vectorStr(f.parameters, ", ") << ")\n" << f.body; } - return; - } - out << "\n{\n"; - indentation += 2; - - for (auto m : s.members) - { - indent(out); - out << m << ";\n"; } - - indent(out, -2); - out << "};\n"; - - for (auto m : s.methods) + else { - Function f = m; - f.parameters.insert(f.parameters.begin(), - {"this", + for (auto instantiation : s.genericInstantiations) + { + for (int i = 0; i < s.genericTypeNames.size(); i++) + { + currentInstantiation[s.genericTypeNames[i]] = instantiation[i]; + } + + out << "struct " << namespacePrefix() << s.name << genericAppendix(instantiation); + if (stub) + { + out << ";\n"; + for (auto m : s.methods) { - namespaces, - s.name, - { - {TypeModifierType::Pointer, false, -1} - } + Function f = m; + + f.parameters.insert(f.parameters.begin(), + {"this", + { + namespaces, + s.name + genericAppendix(instantiation), + { + {TypeModifierType::Pointer, false, -1} + } + } + }); + out << f.returnType << " " << + namespacePrefix() << s.name << genericAppendix(instantiation) << "_" << f.name << + " (" << vectorStr(f.parameters, ", ") << ");\n"; } - }); - out << f.returnType << " " << - namespacePrefix() << s.name << "_" << f.name << - " (" << vectorStr(f.parameters, ", ") << ")\n" << f.body; + return; + } + out << "\n{\n"; + indentation += 2; + + for (auto m : s.members) + { + indent(out); + out << m << ";\n"; + } + + indent(out, -2); + out << "};\n"; + + for (auto m : s.methods) + { + Function f = m; + f.parameters.insert(f.parameters.begin(), + {"this", + { + namespaces, + s.name + genericAppendix(instantiation), + { + {TypeModifierType::Pointer, false, -1} + } + } + }); + out << f.returnType << " " << + namespacePrefix() << s.name << genericAppendix(instantiation) << "_" << f.name << + " (" << vectorStr(f.parameters, ", ") << ")\n" << f.body; + } + + currentInstantiation.clear(); + } } } -void tocProgram (std::ostream & out, const Program & p) +void tocProgram (std::ostream & out, const Program & _p) { + Program p = instantiateGenerics(_p); + globalCtx = p.ctx; globalPrg = p; diff --git a/src/typeInfo.h b/src/typeInfo.h index 0fd4114..cbe421c 100644 --- a/src/typeInfo.h +++ b/src/typeInfo.h @@ -15,7 +15,8 @@ TypeInfo typeType(const Program & p, Type t) TypeInfo result; result.isStruct = true; if (t.name == "int" || t.name == "float" || t.name == "double" || - t.name == "char" || t.name == "long" || t.name == "short" || t.name == "bool") + t.name == "char" || t.name == "long" || t.name == "short" || t.name == "bool" || + t.name == "void") { result.isStruct = false; } @@ -47,7 +48,7 @@ TypeInfo typeExpr(const Program & p, const std::vector & globalName auto m = findStructMethod(p, e._method.methodName, tiCaller); if (!m.has_value()) throw "Unknown method"; - result = typeType(p, m.value().returnType); + result = typeType(p, m.value().t.returnType); break; } case ExprType::Lit: @@ -69,7 +70,7 @@ TypeInfo typeExpr(const Program & p, const std::vector & globalName typeExpr(p, globalNamespace, globalCtx, *e._dot.expr), e._dot.identifier); if (!sm.has_value()) throw "Unknown struct member"; - result = typeType(p, sm.value().type); + result = typeType(p, sm.value().t.type); break; } case ExprType::PrefixOp: diff --git a/src/visit.h b/src/visit.h new file mode 100644 index 0000000..0cfb9e6 --- /dev/null +++ b/src/visit.h @@ -0,0 +1,193 @@ +#pragma once + +#include "repr.h" + +#include + +struct Visitor { + std::function & namespaces)> onType = [](auto, auto){}; + std::function & namespaces)> onExpr = [](auto, auto){}; + std::function & namespaces)> onStmt = [](auto, auto){}; + std::function & namespaces)> onBody = [](auto, auto){}; + std::function & namespaces)> onFunction = [](auto, auto){}; + std::function & namespaces)> onVariable = [](auto, auto){}; + std::function &, const std::vector & namespaces)> onStructMethod = [](auto, auto){}; + std::function &, const std::vector & namespaces)> onStructMember = [](auto, auto){}; + std::function & namespaces)> onStruct = [](auto, auto){}; + std::function & namespaces)> onNamespace = [](auto, auto){}; + std::function & namespaces)> onProgram = [](auto, auto){}; +}; + +#define VISIT(XS) for (auto x : XS) visit(x); + +struct Visit { +private: + Visitor v; + std::vector namespaces; +public: + Visit(Visitor v) + { + this->v = v; + } + void visit(const Type & x) + { + v.onType(x, namespaces); + } + void visit(const Expr & x) + { + v.onExpr(x, namespaces); + + switch (x.type) + { + case ExprType::Func: + VISIT(x._func.arguments) + break; + case ExprType::Method: + visit(*x._method.expr); + VISIT(x._method.arguments); + break; + case ExprType::Lit: + break; + case ExprType::Paren: + visit(*x._paren.expr); + break; + case ExprType::Dot: + visit(*x._dot.expr); + break; + case ExprType::PrefixOp: + visit(*x._prefixOp.expr); + break; + case ExprType::PostfixOp: + visit(*x._postfixOp.expr); + break; + case ExprType::BinaryOp: + visit(*x._binaryOp.lexpr); + visit(*x._binaryOp.rexpr); + break; + case ExprType::TernaryOp: + visit(*x._ternaryOp.lexpr); + visit(*x._ternaryOp.rexprTrue); + visit(*x._ternaryOp.rexprFalse); + break; + case ExprType::Bracket: + visit(*x._brackets.lexpr); + visit(*x._brackets.rexpr); + break; + case ExprType::Identifier: + break; + } + } + void visit(const Stmt & x) + { + v.onStmt(x, namespaces); + + switch (x.type) + { + case StmtType::Assign: + visit(x._assign.lexpr); + visit(x._assign.rexpr); + break; + case StmtType::Expr: + visit(x._expr); + break; + case StmtType::For: + visit(x._for.init->lexpr); + visit(x._for.init->rexpr); + visit(*x._for.condition); + visit(*x._for.action); + visit(x._for.body); + break; + case StmtType::If: + visit(x._if.condition); + visit(x._if.body); + for (auto e : x._if.elses) + { + if (e._if) + visit(*e.expr); + visit(e.body); + } + break; + case StmtType::Return: + visit(x._return.expr); + break; + case StmtType::Switch: + visit(*x._switch.ident); + for (auto c : x._switch.cases) + { + visit(*c.expr); + visit(c.body); + } + break; + case StmtType::While: + visit(x._while.condition); + visit(x._while.body); + break; + } + } + void visit(const Body & x) + { + v.onBody(x, namespaces); + + VISIT(x.ctx->variables) + VISIT(x.statements) + } + void visit(const Namespace & x) + { + v.onNamespace(x, namespaces); + + namespaces.push_back(x.name); + + VISIT(x.namespaces) + VISIT(x.ctx->variables) + VISIT(x.structs) + VISIT(x.functions) + + namespaces.pop_back(); + } + void visit(const Variable & x) + { + v.onVariable(x, namespaces); + visit(x.type); + } + void visit(const Function & x) + { + v.onFunction(x, namespaces); + + if (x.defined) { + visit(x.body); + for (auto v : x.parameters) + visit(v.type); + } + } + void visit(const StructMember & x) + { + v.onStructMethod(x, namespaces); + + visit(x.t); + } + void visit(const StructMember & x) + { + v.onStructMember(x, namespaces); + + visit(x.t); + } + void visit(const Struct & x) + { + v.onStruct(x, namespaces); + + VISIT(x.members) + VISIT(x.methods) + } + void visit(const Program & x) + { + v.onProgram(x, namespaces); + + VISIT(x.namespaces) + VISIT(x.ctx->variables) + VISIT(x.structs) + VISIT(x.functions) + } +}; + +#undef VISIT + -- cgit v1.2.3