LParser Class

#include <Layers/lparser.h>

Public Functions

LParser(const std::vector<LToken> & tokens)
const std::vector<LError> & errors()
LLayerNode parse_file()

Detailed Description

Build a Layers abstract syntax tree (AST) from a token stream.

Consider the following Layers text:

Host: "huntrsoftware.com"

Providing the lexer's tokens for the above as input, the parser produces a root layer node representing the whole file, holding one attribute node:

attributes = {
    { declaration = {
          item = {{"Host"}} }
      expression -> value -> string = "huntrsoftware.com" } }

It is not the job of the parser to resolve references or create live data; the tree only describes the file. Converting it into live LLayer and LAttribute objects is called lowering, and that's handled by the loader.

Converting tokens into a tree

The parser provides parse_file() which returns the root LLayerNode built from the tokens provided when constructing the parser. The tokens must end with an ENDFILE token (tokens from LLexer always do).

LLexer lexer("Host: \"huntrsoftware.com\"");
LParser parser(lexer.build_tokens());
LLayerNode root = parser.parse_file();
    // `root.attributes` contains the `Host` attribute node

After parsing, acquire and log errors

Call errors() to acquire the errors that were found while parsing the tokens. The parser doesn't stop at an error; it reports it, skips ahead to the next line or past the current block, and carries on, so a single pass finds as many errors as it can. A tree with errors is therefore only a best effort: it can be missing statements or hold incomplete nodes, and shouldn't be lowered.

Parser errors that follow lexer errors are often caused by them, so consider logging the parser's errors only when the lexer found none, like LEngine does.

if (lexer.errors().empty())
    for (const LError& parser_error : parser.errors())
        Layers::log("parser: " + std::to_string(parser_error.line) + ": " +
            parser_error.message);

Lowering the tree

A tree without errors is ready for a loader to lower. Lowering expands each declaration into the layers and attributes it names, applies their values and states, and records their base and link paths, which the engine resolves afterward. LEngine::load_files() lexes, parses, and lowers each file for you, skipping any file with errors.

if (lexer.errors().empty() && parser.errors().empty())
    loader.lower(root);

Member Function Documentation

LParser(const std::vector<LToken> & tokens)

Construct a parser for the provided tokens, like those returned by LLexer::build_tokens(). The tokens must end with an ENDFILE token.

const std::vector<LError> & errors()

Returns the errors that were discovered while parsing the tokens.

LLayerNode parse_file()

Parse the token stream into a root layer node representing the whole file. The root has an empty declaration; the file's top-level statements are its members.

Appearance
Theme
—