What you ideally want is a first step that "validates", i.e. creates a representation from text that is easy to use but also succeeds for any input, and then a further "parsing" step that converts it to another representation such that the parsing only succeeds for valid input and is invertible for any value of the representation type, and then finally code that checks constraints that aren't captured by the type system.
This way you can support IDEs that need to edit partially incorrect code.
Hey, I fail to see how this is suboptimal. Some points I don't understand:
* What's the goal of a validation that always succeed?
* What's the value of checking constraints after you parsed it and not capture this information?
In the end, parsing is just a combination of what you described: ensure something fit a particular shape and constraints :)
What you ideally want is a first step that "validates", i.e. creates a representation from text that is easy to use but also succeeds for any input, and then a further "parsing" step that converts it to another representation such that the parsing only succeeds for valid input and is invertible for any value of the representation type, and then finally code that checks constraints that aren't captured by the type system.
This way you can support IDEs that need to edit partially incorrect code.