abouttreesummaryrefslogcommitdiff
path: root/src/generic.h
blob: 33323e4eb8e560289faac453b23934b8a5340565 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#pragma once

#include "repr.h"
#include "typeInfo.h"
#include "visit.h"

// add a generic instantiation if its not in the vector already
void addGenericInstantiation(
  std::vector<std::vector<Type>> & insts,
  const std::vector<Type> & newInst)
{
  if (insts.empty())
  {
    insts.push_back(newInst);
    return;
  }
  for (auto inst : insts)
  {
    for (int i = 0; i < inst.size(); i++)
    {
      if (inst[i] != newInst[i])
      {
        insts.push_back(newInst);
        return;
      }
    }
  }
}

Program instantiateGenerics(const Program & p)
{
  Program result = p;

  // Find generic instantiations

  // visit expressions (only function calls are considered) and types,
  // find the function/struct by pointer and add an instantiation
  Visitor findGenericInstantiations;
  findGenericInstantiations.onExpr =
  [&](const Expr & e, const std::shared_ptr<Context> ctx)
  {
    if (e.type == ExprType::Func && !e._func.genericInstantiation.empty())
    {
      auto f = findFunctionPtr(e._func.functionName, e._func.namespacePrefixes, ctx);
      if (f.has_value())
      {
        if (std::get<0>(*f)->genericTypeNames.empty())
          throw "Trying to instantiate non-generic function";
        if (e._func.genericInstantiation.size() != std::get<0>(*f)->genericTypeNames.size())
          throw "Trying to instantiate function with wrong number of types";
        addGenericInstantiation(std::get<0>(*f)->genericInstantiations, e._func.genericInstantiation);
      }
    }
  };
  findGenericInstantiations.onType =
  [&](const Type & t, const std::shared_ptr<Context> ctx)
  {
    if (!t.genericInstantiation.empty())
    {
      auto s = findStructPtr(t.name, t.namespacePrefixes, ctx);
      if (s.has_value())
      {
        if (std::get<0>(*s)->genericTypeNames.empty())
          throw "Trying to instantiate non-generic struct";
        if (t.genericInstantiation.size() != std::get<0>(*s)->genericTypeNames.size())
          throw "Trying to instantiate struct with wrong number of types";
        addGenericInstantiation(std::get<0>(*s)->genericInstantiations, t.genericInstantiation);
      }
    }
  };
  Visit v(findGenericInstantiations);
  v.visit(result);

  return result;
}

// generate the appendix for C struct/function names
// including array/pointer indicators because
// there might be distinct instantiations
// for int and int* for example
std::string genericAppendix(const std::vector<Type> & ts)
{
  std::stringstream sstr;
  for (auto t : ts)
  {
    sstr << "_";
    sstr << t.name;
    for (auto m : t.modifiers)
    {
      if (m.type == TypeModifierType::Array)
      {
        sstr << "_arr";
        if (m._staticArray)
          sstr << m._arraySize;
      }
      else if (m.type == TypeModifierType::Pointer)
      {
        sstr << "_ptr";
      }
    }
    if (!t.genericInstantiation.empty())
    {
      sstr << genericAppendix(t.genericInstantiation);
    }
  }
  return sstr.str();
}