On Wednesday, 17 June 2020 at 11:50:27 UTC, Per Nordlöw wrote:
Should a range-compliant aggregate type realizing a parser be encoded as a struct or class? In dmd `Lexer` and `Parser` are both classes.

In general how should I reason about whether an aggregate type should be encoded as a struct or class?

What's a range-compliant aggregate type? Ranges are typically views of someone else's data; an owner of the data woulnd't store mutable iterators, and won't be a range. For that reason also, ranges are structs, as most of them are thin wrappers over a set of iterators with an interface to mutate them.

If you *really* need runtime polymorphism as provided by the language - use a class. Otherwise - use a struct. It's pretty straightforward. Even then, in some cases one can realize their own runtime polymorphism without classes (look at e.g. Atila Neves' 'tardy' library).

It's very easy to implement a lexer as an input range: it'd just be a pointer into a buffer plus some additional iteration data (like line/column position, for example). I.e. a struct. Making it a struct also allows to make it into a forward range, instead of input range, which is useful if you need lookahead:

struct TokenStream
{
    this(SourceBuffer source)
    {
        this.cursor = source.text.ptr;
        advance(this);
    }

    bool empty() const
    {
        return token.type == TokenType.eof;
    }

    ref front() return scope const
    {
        return token;
    }

    void popFront()
    {
        switch (token.type)
        {
            default:
                advance(this);
                break;
            case TokenType.eof:
                break;
            case TokenType.error:
                token.type = TokenType.eof;
token.lexSpan = LexicalSpan(token.lexSpan.end, token.lexSpan.end);
                break;
        }
    }

    TokenStream save() const
    {
        return this;
    }

private:

    const(char)* cursor;
    Location location;
    Token token;
}

, where `advance` is implemented as a module private function that actually parses source into next token.

DMD's Lexer/Parser aren't ranges. They're ourobori.

Reply via email to