summaryrefslogtreecommitdiff
path: root/src/interpreter/denotable.ts
blob: bb520f8973738a6419c172d88deb5772a9062224 (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
import type { Identifier } from '@/parser';
import { testingLogger } from '@t/logger';

export type UnionDenotableType =
  | Array<DenotableType | DenotableFunctionSignature>
  | DenotableType
  | DenotableFunctionSignature
  | Array<UnionDenotableType>;

export type DenotableFunctionSignature = {
  arguments: Array<UnionDenotableType>;
  return: DenotableType;
};

export type DenotableFunction = {
  signatures: Array<DenotableFunctionSignature>;
  body: Function;
};

export type DenotableType =
  | 'null'
  | 'int'
  | 'real'
  | 'bool'
  | 'string'
  | 'bytearray'
  | 'function'
  | 'reference';

export type DenotableValue =
  | null
  | number
  | string
  | Uint8Array
  | DenotableFunction
  | Identifier;

export type Denotable = {
  type: DenotableType;
  value: DenotableValue;
};

export const denotableTypesEquivalent = (
  a: UnionDenotableType,
  b: UnionDenotableType,
): boolean => {
  if (typeof a !== typeof b) return false;

  if (Array.isArray(a) && Array.isArray(b)) {
    if (a.length !== b.length) return false;
    for (let i = 0; i < a.length; i++) {
      if (!denotableTypesEquivalent(a[i], b[i])) return false;
    }
    return true;
  }

  if (
    typeof a === 'object' &&
    typeof b === 'object' &&
    'arguments' in a &&
    'arguments' in b
  ) {
    if (a.arguments.length !== b.arguments.length) return false;
    if (!denotableTypesEquivalent(a.return, b.return)) return false;
    for (let i = 0; i < a.arguments.length; i++) {
      if (!denotableTypesEquivalent(a.arguments[i], b.arguments[i])) {
        return false;
      }
    }
    return true;
  }

  if (a === b) return true;

  return false;
};

export const matchSignature = (
  args: Array<UnionDenotableType>,
  signatures: Array<DenotableFunctionSignature>,
): DenotableFunctionSignature | undefined => {
  return signatures.find(signature => {
    if (args.length !== signature.arguments.length) return false;

    return args.every((arg, i) => {
      const argSignature = signature.arguments[i];
      if (Array.isArray(argSignature)) {
        return argSignature.some(a => denotableTypesEquivalent(a, arg));
      }

      return denotableTypesEquivalent(arg, signature.arguments[i]);
    });
  });
};