abouttreesummaryrefslogcommitdiff
path: root/src/typeInfo.h
blob: 89fff2a1800d7ceebaed464a9c6c6cebc6314d0d (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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#pragma once

#include "repr.h"

struct TypeInfo
{
  Type type;
  bool isStruct;
};

#include "find.h"

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 == "void")
  {
    result.isStruct = false;
  }
  result.type = t;
  return result;
}

TypeInfo typeExpr(const Program & p, const std::vector<std::string> & globalNamespace, std::shared_ptr<Context> globalCtx, Expr e)
{
  TypeInfo result;

  switch (e.type)
  {
  case ExprType::Func:
  {
    auto namespacePrefixes = globalNamespace;
    namespacePrefixes.insert(namespacePrefixes.end(),
      e._func.namespacePrefixes.begin(),
      e._func.namespacePrefixes.end());
    auto f = findFunction(e._func.functionName, e._func.namespacePrefixes, globalCtx);
    if (!f.has_value())
      throw "Unknown function";
    result = typeType(p, f.value().returnType);
    break;
  }
  case ExprType::Method:
  {
    TypeInfo tiCaller = typeExpr(p, globalNamespace, globalCtx, *e._method.expr);
    if (!tiCaller.isStruct)
      throw "Calling method on non-struct";
    auto s = findStruct(tiCaller.type.name, tiCaller.type.namespacePrefixes, globalCtx);
    if (!s.has_value())
      throw "Calling method on unknown struct";
    auto m = findStructMethod(e._method.methodName, s.value());
    if (!m.has_value())
      throw "Unknown method";
    result = typeType(p, m.value().t.returnType);
    break;
  }
  case ExprType::Lit:
    result.isStruct = false;
    switch (e._lit.type)
    {
    case LitType::Bool:    result.type.name = "bool"; break;
    case LitType::Int:     result.type.name = "int"; break;
    case LitType::Decimal: result.type.name = "double"; break;
    case LitType::String:  result.type.name = "char"; result.type.modifiers.push_back({ TypeModifierType::Pointer, false, -1 }); break;
    }
    break;
  case ExprType::Paren:
    result = typeExpr(p, globalNamespace, globalCtx, *e._paren.expr);
    break;
  case ExprType::Dot:
  {
    auto tiCaller = typeExpr(p, globalNamespace, globalCtx, *e._dot.expr);
    if (!tiCaller.isStruct)
      throw "Accessing member of non-struct";
    auto s = findStruct(tiCaller.type.name, tiCaller.type.namespacePrefixes, globalCtx);
    if (!s.has_value())
      throw "Calling method on unknown struct";
    auto sm = findStructMember(e._dot.identifier, s.value());
    if (!sm.has_value())
      throw "Unknown struct member";
    result = typeType(p, sm.value().t.type);
    break;
  }
  case ExprType::PrefixOp:
    result = typeExpr(p, globalNamespace, globalCtx, *e._prefixOp.expr);
    break;
  case ExprType::PostfixOp:
    result = typeExpr(p, globalNamespace, globalCtx, *e._postfixOp.expr);
    break;
  case ExprType::BinaryOp:
    result = typeExpr(p, globalNamespace, globalCtx, *e._binaryOp.lexpr);
    break;
  case ExprType::TernaryOp:
    result = typeExpr(p, globalNamespace, globalCtx, *e._ternaryOp.rexprTrue);
    break;
  case ExprType::Bracket:
  {
    TypeInfo ti = typeExpr(p, globalNamespace, globalCtx, *e._brackets.lexpr);
    if (!ti.type.modifiers.empty())
    {
      result = ti;
      result.type.modifiers.pop_back();
    }
    else
    {
      throw "Indexing non-array";
    }
  }
  case ExprType::Identifier:
  {
    auto namespacePrefixes = globalNamespace;
    namespacePrefixes.insert(namespacePrefixes.end(),
      e._identifier.namespacePrefixes.begin(),
      e._identifier.namespacePrefixes.end());
    auto v = findVariable(e._identifier.identifier, namespacePrefixes, globalCtx);
    if (!v.has_value())
      throw "Unknown variable";
    result = typeType(p, v.value().type);
    break;
  }
  }

  return result;
}