Make TokenKind and ExpressionKind more generic. #10
Labels
No labels
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
mle/selkirk#10
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Currently
TokenKindhard-codes the set of possible token kinds:and similarly,
ExpressionKindhard-codes the set of possible expression types:These should really be made generic.
Some changes that will be necessary to support this:
Parsershould delegate parsing of individual tokens to theParseContext— i.e. if a particular parser has floats, it should provide a float parser. This basically amounts to replacing the match onkindinparse_termandparse_operatorwith matching on the result of [some method onParseContext]; this should flatten with the existing match in theTokenKind::Tagbranch.ParseContextshould add a new associated type:Term, which is a type that can represent a single term in the expression queue.ParseErrorKindshould allow for errors specific to a particularParseContext(maybe it should have a genericOthervariant, andParseContexthas anErrorassociated type?)augh so many generics/associated types
Ok so there are (at least) three stages in this library:
The tokenizer and the parser have one type in common:
TokenKind. The parser and the evaluator have 3 types in common:BinaryOperator,UnaryOperator, andTerm. So the parser has 4 types associated with it just for its connection to the other layers, plus some other types which are internal to the parser:ErrorandDelimiterwith the idea that trait type parameters are for inputs and associated types are for outputs, this would look like
it has previously been noted that apart from the methods to access the input string,
Tokenizeris basically justIterator<Item = (Token, Self::TokenKind)>what if a parser was like an
Iterator<Item = Expression>? On the inside it'd still look basically like the parser trait, but it could be basically presented as an iterator adapter — something likeMyTokenizer::new(input).parse(MyParser::new()).evaluate(MyEvaluator::new()), with theparseandevaluatemethods being part of an extension trait with the appropriate bounds.sourceis necessary for exactly one thing, which is generating an end-of-input span and token, for theNullexpression that gets inserted if the end-of-input is reached inInitialstate (either empty input, or last token has an optional right operand).…if I changed how I handled optional right operands, in such a way as to get rid of
Null, this wouldn't be an issue.This doesn't work, because the parser can also return errors.
The bigger issue is that a single token can parse to multiple expressions (e.g. due to popping things from the stack), so the parser still needs to collect into a queue at least as an intermediate; also, while a tokenizer/parser/evaluator that is totally pipelined as iterators is aesthetically pleasing, it makes logging and error handling far more convoluted (for example, in the fully pipelined setup, a parse error would likely result in a lot of wasted work by the evaluator).