1 module calcool.parselets;
2 
3 import calcool.expression;
4 import calcool.token;
5 import calcool.parser;
6 import calcool.exceptions;
7 
8 enum Precedence : uint {
9     START = 0,
10     ADD_AND_MINUS = 1,
11     MULT_AND_DIV,
12     POWER,
13     NAME_AND_NEGATE,
14     FUNC,
15     GROUP
16 }
17 
18 interface Parselet {
19     Precedence getPrecedence() immutable;
20 }
21 
22 interface PrefixParselet : Parselet {
23     Expression parse(Parser, Token) immutable;
24 }
25 
26 interface InfixParselet : Parselet {
27     Expression parse(Parser, Expression, Token) immutable;
28 }
29 
30 public:
31 class NumberParselet : PrefixParselet {
32     override Precedence getPrecedence() immutable {
33         return Precedence.NAME_AND_NEGATE;
34     }
35 
36     override Expression parse(Parser, Token token) immutable {
37         if (token.type != TokenType.NUMBER) {
38             throw new ParseException("Unknown token passed to number parselet");
39         }
40 
41         import std.conv : to;
42 
43         return new NumberExpression(token.value.to!real);
44     }
45 }
46 
47 class IdentifierParselet : PrefixParselet {
48     override Precedence getPrecedence() immutable {
49         return Precedence.NAME_AND_NEGATE;
50     }
51 
52     override Expression parse(Parser p, Token token) immutable {
53         if (auto val = token.value in p.getVariables()) {
54             return new NumberExpression(*val);
55         }
56         return new ConstantExpression(token.value);
57     }
58 }
59 
60 class NegateParselet : PrefixParselet {
61     override Precedence getPrecedence() immutable {
62         return Precedence.NAME_AND_NEGATE;
63     }
64 
65     override Expression parse(Parser p, Token token) immutable {
66         return new NegateExpression(p.parseExpression(Precedence.NAME_AND_NEGATE));
67     }
68 }
69 
70 class EolParselet : PrefixParselet {
71     override Precedence getPrecedence() immutable {
72         return Precedence.START;
73     }
74 
75     override Expression parse(Parser p, Token token) immutable {
76         return new EolExpression();
77     }
78 }
79 
80 class FuncParselet : PrefixParselet {
81     override Precedence getPrecedence() immutable {
82         return Precedence.FUNC;
83     }
84 
85     override Expression parse(Parser p, Token token) immutable {
86         p.expect(TokenType.PR_OPEN);
87         auto param = p.parseGroupExpression();
88         return new FuncExpression(token.value, param);
89     }
90 }
91 
92 class GroupParselet : PrefixParselet {
93     override Precedence getPrecedence() immutable {
94         return Precedence.GROUP;
95     }
96 
97     override Expression parse(Parser p, Token token) immutable {
98         return new GroupExpression(p.parseGroupExpression());
99     }
100 }
101 
102 class MultDivParselet : InfixParselet {
103     override Precedence getPrecedence() immutable {
104         return Precedence.MULT_AND_DIV;
105     }
106 
107     override Expression parse(Parser p, Expression left, Token token) immutable {
108         auto right = p.parseExpression(Precedence.MULT_AND_DIV);
109         switch (token.type) {
110         case TokenType.OP_MULT:
111             return new OperatorExpression!"*"(left, right);
112         case TokenType.OP_DIV:
113             return new OperatorExpression!"/"(left, right);
114         default:
115             throw new ParseException("Unknown token for MultDiv parselet");
116         }
117     }
118 }
119 
120 class AddMinusParselet : InfixParselet {
121     override Precedence getPrecedence() immutable {
122         return Precedence.ADD_AND_MINUS;
123     }
124 
125     override Expression parse(Parser p, Expression left, Token token) immutable {
126         auto right = p.parseExpression(Precedence.ADD_AND_MINUS);
127         switch (token.type) {
128         case TokenType.OP_ADD:
129             return new OperatorExpression!"+"(left, right);
130         case TokenType.OP_MINUS:
131             return new OperatorExpression!"-"(left, right);
132         default:
133             throw new ParseException("Unknown token for AddMinus parselet");
134         }
135     }
136 }
137 
138 class PowerParselet : InfixParselet {
139     override Precedence getPrecedence() immutable {
140         return Precedence.POWER;
141     }
142 
143     override Expression parse(Parser p, Expression left, Token token) immutable {
144         return new OperatorExpression!"^^"(left, p.parseExpression(Precedence.POWER));
145     }
146 }