The SIL parser is one 7000 line file. It attempts to do three things: read SIL text, check and verify the input, and transform the input into SIL instructions/functions/etc. There are, at least, five overarching problems with the current implementation:
- The current implementation is old, complicated, and monolithic.
- The parser is a standalone library (for no good reason) which complicates the build system.
- It is hard to have "drop-in" tooling with this implementation.
- The current implementation has no interoperability with the serializer.
- The current implementation tries to do everything in one place: read, check and parse.
I'd like to propose a solution to incrementally fix all these issues. First, we'll move the parser into lib/Parse
unifying the libraries.
Second I'll update the parser to model a new flow of information. This model has three steps: read, check, parse and allows for drop-in tooling at any point. This will allow us to do large-scale transformations, pretty-printing, and utilize other tools for easier debugging and maintenance. Here's a pseudo-code example of the proposed implementation:
sil @foo {
bb0():
x = copy_value y
store x to [init] z
}
{ OperandIDs, Attrs } readCopyValue() {
return { readOperand() };
}
type: copy_value
operands: { ValID, TypeID }
{ OperandIDs, Attrs } readStore() {
bool isInit = false;
auto src = readOperand();
expectAndConsume("to");
consumeOptionalAttr("init", isInit);
auto dest = readOperand();
return { { src, dest }, isInit };
}
type: store
operands: { ValID, TypeID }, { ValID, TypeID }
attributes: "init"
void checkCopyValue(OperandIDs operands, Attrs attrs) {
require(operands.size() == 0);
// Other checks...
}
// Check store in the same way.
SILInstruction *emitCopyValue(OperandIDs operands, Attrs attrs) {
auto y = getLocalValue(operands.front.val, operands.front.type);
return builder.createCopyValue(y);
}
Splitting the implementation up in this way gives us a few major wins. First and foremost, separation of concerns allows for all three steps to be as simple and straightforward as possible. Second, the verification step allows for much more sensical and intuitive sil parsing errors. Last, this approach models very closely after the serializer's implementation and will allow us to have interoperability between the two in the future.