summaryrefslogtreecommitdiff
path: root/Compiler/FunctionReference.cs
blob: cf120adae8d630ca09897eaee02b33988faaca2b (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
127
128
129
namespace Q1.Compiler;

using System.Reflection.Metadata;
using System.Text;

public class FunctionReference
{
    // TODO: Implement return type
    public string                 Name;
    public string                 Type;
    public List<FunctionOverload> Overloads = new();

    public FunctionReference(string name, string type)
    {
        this.Type = type;
        this.Name = name;
    }

    public string GetBranchName(FunctionOverload overload)
    {
        List<(string paramName, string paramType)> parameters = overload
            .ParameterNames
            .Zip(overload.ParameterTypes)
            .ToList();

        StringBuilder branchName = new();
        branchName.Append($"_{this.Name}");

        if (parameters.Count > 0)
        {
            branchName.Append($"_{string.Join("__", parameters
                .Select(x => $"{x.paramType}_{x.paramName}"))}");
        }

        return branchName.ToString();
    }

    public string GetBranchFriendlyName(FunctionOverload overload)
    {
        List<(string paramName, string paramType)> parameters = overload
            .ParameterNames
            .Zip(overload.ParameterTypes)
            .ToList();

        StringBuilder branchName = new();
        branchName.Append($"{this.Type} {this.Name}");
        branchName.Append("(");

        branchName.Append(string.Join(", ", parameters
            .Select(x => $"{x.paramType} {x.paramName}")));

        branchName.Append(")");

        return branchName.ToString();
    }

    public FunctionOverload CreateOverloadWithBody(List<string> parameterNames, List<string> parameterTypes)
    {
        FunctionOverload? existingOverload = this.Overloads
            .FirstOrDefault(x => x.ParamsMatch(parameterNames, parameterTypes));

        if (existingOverload != null)
        {
            if (existingOverload.BodyImplemented)
                throw new CompilerException($"Cannot define another overload for {this.Name},"
                                            + $" as one with an identical signature and body already exists.");

            existingOverload.BodyImplemented = true;
            return existingOverload;
        }
        else
        {
            FunctionOverload newOverload = new(parameterNames, parameterTypes, true);
            this.Overloads.Add(newOverload);
            return newOverload;
        }
    }

    public FunctionOverload CreateOverloadWithoutBody(List<string> parameterNames, List<string> parameterTypes)
    {
        FunctionOverload? existingOverload = this.Overloads
            .FirstOrDefault(x => x.ParamsMatch(parameterNames, parameterTypes));

        if (existingOverload != null)
        {
            if (!existingOverload.BodyImplemented)
                throw new CompilerException($"Cannot prototype another overload for {this.Name},"
                                            + $" as one with an identical signature already exists.");
            return existingOverload;
        }
        else
        {
            FunctionOverload newOverload = new(parameterNames, parameterTypes, false);
            this.Overloads.Add(newOverload);
            return newOverload;
        }
    }
    public FunctionOverload GetOverload(int paramsCount)
    {
        FunctionOverload? overload = this.Overloads
            .FirstOrDefault(x => x.ParameterTypes.Count == paramsCount);

        if (overload != null)
            return overload;

        throw new CompilerException($"Overload for {this.Name} with {paramsCount} arguments could not be found.");
    }
}

public class FunctionOverload
{
    // TODO: Implement return type
    public List<string> ParameterTypes;
    public List<string> ParameterNames;
    public bool         BodyImplemented;

    public FunctionOverload(List<string> parameterNames, List<string> parameterTypes, bool bodyImplemented)
    {
        this.ParameterTypes  = parameterTypes;
        this.ParameterNames  = parameterNames;
        this.BodyImplemented = bodyImplemented;
    }

    public bool ParamsMatch(List<string> parameterNames, List<string> parameterTypes)
    {
        return this.ParameterNames.SequenceEqual(parameterNames)
               && this.ParameterTypes.SequenceEqual(parameterTypes);
    }
}