summaryrefslogtreecommitdiff
path: root/src/ast/nodes/AtomNode.java
blob: ea998088bbcc1a7dbc9f60c18ca1e72fefd8a92a (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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package ast.nodes;

import ast.types.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import semanticanalysis.SemanticError;
import semanticanalysis.SymbolTable;

/**
 * Node for the `atom` statement of the grammar.
 */
public class AtomNode implements Node {

    protected String val;
    protected TestlistCompNode exprlist;

    // very scatchy
    protected int ns;
    protected int offset;

    public AtomNode(String val, Node exprlist) {
        this.val = val;
        this.exprlist = (TestlistCompNode) exprlist;
    }

    /**
     * Returns the identifier of the `AtomNode` if it's not `null`, otherwise
     * returns `null`.
     */
    public String getId() {
        return val;
    }

    @Override
    public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting, FunctionType ft) {
        ArrayList<SemanticError> errors = new ArrayList<>();

        if (val != null) {
            if (!Arrays.asList(bif).contains(getId())) {
                if ((typeCheck() instanceof AtomType) && ST.nslookup(getId()) < 0) {
                    errors.add(new SemanticError("name '" + getId() + "' is not defined."));
                } else {
                    if ((typeCheck() instanceof AtomType)) {
                        int varNs = ST.lookup(getId()).getNesting();
                        this.ns = _nesting - varNs;
                        offset = ST.lookup(getId()).getOffset();
                    }
                }
            }
        }

        if (exprlist != null) {
            errors.addAll(exprlist.checkSemantics(ST, _nesting, ft));
        }

        return errors;
    }

    // ENHANCE: return more specific types
    @Override
    public Type typeCheck() {
        if (val == null) {
            return new VoidType();
        }

        Pattern noneVariable = Pattern.compile("^(None)$");
        Pattern booleanVariable = Pattern.compile("^(True|False)$");
        Pattern integerVariable = Pattern.compile("^[0-9]+$");
        Pattern reservedWords = Pattern.compile("^(continue|break|int|float)$");
        // this regex should match every possible atom name written in this format: CHAR
        // (CHAR | DIGIT)*
        Pattern simpleVariable = Pattern.compile("^[a-zA-Z][a-zA-Z0-9]*$", Pattern.CASE_INSENSITIVE);

        Matcher noneVariableMatcher = noneVariable.matcher(val);
        Matcher booleanVariableMatcher = booleanVariable.matcher(val);
        Matcher integerVariableMatcher = integerVariable.matcher(val);
        Matcher reservedWordsMatcher = reservedWords.matcher(val);
        Matcher simpleVariableMatcher = simpleVariable.matcher(val);

        boolean matchFoundNone = noneVariableMatcher.find();
        boolean matchFoundBoolean = booleanVariableMatcher.find();
        boolean matchFoundInteger = integerVariableMatcher.find();
        boolean matchFoundContinueBreak = reservedWordsMatcher.find();
        boolean matchFoundSimpleVariable = simpleVariableMatcher.find();

        if (matchFoundBoolean) {
            return new BoolType();
        } else if (matchFoundInteger) {
            return new IntType();
        } else if (matchFoundContinueBreak) {
            return new ReservedWordsType();
        } else if (matchFoundNone) {
            return new NoneType();
        } else if (matchFoundSimpleVariable) {
            return new AtomType(); // could be a variable or a fuction
        } else {
            return new VoidType(); // could be any type of data
        }
    }

    @Override
    public String codeGeneration() {
        if (exprlist != null) {
            return exprlist.codeGeneration();
        }

        if (typeCheck() instanceof IntType) {
            return "storei A0 " + getId() + "\n";
        }

        if (typeCheck() instanceof BoolType) {
            return "storei A0 " + boolValue(getId()) + "\n";
        }

        if (typeCheck() instanceof AtomType) {
            // We need to ascend the access-link chain to the top (or bottom,
            // who knows).
            String str = "move AL T1\n";
            for (int i = 0; i < this.ns; i++) {
                str += "store T1 0(T1)\n";
            }

            str += "subi T1 " + offset + "\nstore A0 0(T1)\n";
            return str;
        }

        return "Error: could not parse an atom\n";
    }

    public static String boolValue(String id) {
        return id.equals("True") ? "1" : "0";
    }

    @Override
    public String toPrint(String prefix) {
        // FIXME: can be a testlist_comp with two expr and two atoms
        if (val != null) {
            return prefix + "Atom(" + val + ")\n";
        }

        return prefix + "Atom(null)\n";

    }
}