Skip to content

Commit

Permalink
some more docs
Browse files Browse the repository at this point in the history
  • Loading branch information
TheDeathlyCow committed Nov 10, 2023
1 parent 779a01a commit 1f4ae7f
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 14 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ Each time `generate()` runs, it evaluates the tree and randomly selects variatio
int main(int argc, char *argv[])
{
// ...
// ... Grammar construction from previous example ...
calyx::Options& options = grammar.getOptions();
std::cout << grammar.generate(errors)->getText(options) << "\n";
// > "Hey world."
Expand Down
4 changes: 2 additions & 2 deletions src/calyx/filters.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ namespace calyx
namespace filters
{
/**
* @brief A custom type for filters, provided for convenience. Filters transform the String_t input into a new string, for example
* to return an uppercase copy.
* @brief A custom type for filters, provided for convenience. Filters apply some processing to transform the String_t input
* into a new string. For example, to return an uppercase copy.
*/
using Filter_t = std::function<String_t(const String_t&, Options&)>;

Expand Down
4 changes: 2 additions & 2 deletions src/calyx/grammar.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ namespace calyx
[[nodiscard]] std::optional<Result> generate(const String_t& start, ErrorHolder& errors) noexcept;

/**
* @brief Adds filters to the grammar, as a map of filter names to filter functions.
* @brief Adds multiple filters to the grammar, as a map of filter names to filter functions.
*
* Filters are functions that can transform the output of an evaluated production. For example, to convert the string to
* upper case. See filters.h for more details.
Expand All @@ -226,7 +226,7 @@ namespace calyx
void filters(const std::map<String_t, filters::Filter_t>& filters) noexcept;

/**
* @brief Add a filters to the grammar.
* @brief Add a single filter to the grammar.
*
* Filters are functions that can transform the output of an evaluated production. For example, to convert the string to
* upper case. See filters.h for more details.
Expand Down
53 changes: 47 additions & 6 deletions src/production.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,68 @@

namespace calyx
{

class Registry;

/**
* @brief Base interface for all productions. A production is an individual rule in a grammar, and can be
* evaluated to produce an expansion tree.
*/
class Production
{
public:
/**
* @brief Evaluates the production. Returns a randomly generated expansion tree if no errors occur.
*
* @param registry The registry that called for this expansion. Used for things that require some external
* context, like memoization and unique expansions.
* @param options Options for evaluation, used primarily for its random access.
* @param errors Error holder for errors that may occur in the expansion.
* @return Returns an optional containing the randomly generated expansion tree, if and only if no error
* has occured.
*/
virtual std::optional<Expansion> evaluate(
Registry& registry,
Options& options,
ErrorHolder& errors
) const = 0;

virtual ~Production() = default;

};

class ProductionBranch: public Production
/**
* @brief Contains several productions and picks one randomly according to some rule. For example, randomly pick a child production
* with uniform probability.
*/
class ProductionBranch : public Production
{
public:
/**
* @brief Picks and expands a production at some index, according to its random distribution rule.
*
* @param registry The registry that called for this expansion. Used for things that require some external
* context, like memoization and unique expansions.
* @param options Options for evaluation, used primarily for its random access.
* @param errors Error holder for errors that may occur in the expansion.
* @return Returns an optional containing the randomly generated expansion tree, if and only if no error
* has occured.
*/
std::optional<Expansion> evaluate(
Registry& registry,
Options& options,
ErrorHolder& errors
) const override = 0;

/**
* @brief Expands the child production at the specified index.
*
* @param index The index of the child production to expand.
* @param registry The registry that called for this expansion. Used for things that require some external
* context, like memoization and unique expansions.
* @param options Options for evaluation, used primarily for its random access.
* @param errors Error holder for errors that may occur in the expansion.
* @return Returns an optional containing the randomly generated expansion tree, if and only if no error
* has occured.
*/
virtual std::optional<Expansion> evaluateAt(
std::size_t index,
Registry& registry,
Expand All @@ -35,7 +78,5 @@ namespace calyx
) const = 0;

virtual std::size_t length() const = 0;

};

}
}
34 changes: 33 additions & 1 deletion src/registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,39 @@

namespace calyx
{

/**
* @brief Central registry that tracks the rules of a grammar, as well as evaluation context like memoization, unique expansions,
* and evaluation mode.
*
* The registry stores all of the rules of a Context-Free Grammar (CFG), as well as some additional context. Consider the following example,
* which defines a grammar that can be used to generate strings that are palindromes over the alphabet {a, b}.
*
* @code
* start -> a{start}a
* start -> b{start}b
* start -> {end}
* end -> a
* end -> b
* @endcode
*
* Each lower case a, b is an atomic string, and strings enclosed in {} are expansions. Each line of the form X -> Y, is a rule in the grammar.
* The left hand side of the line is the name of the rule, and the right hand side is the Production it expands to.
*
* When expanding a grammar that has multiple rules with the same name, one rule is picked at random. Users may specify that the rules are
* picked with a uniform or weighted random distribution.
*
* By convention, evaluation begins from the "start" rule, however it is possible to start from any rule. The registry also provides for
* the following additional facilities around grammars that are not typically available in CFGs:
*
* - Memoization (denoted by starting the template with @): Every call will always return the same expansion, useful for things like
* names.
* - Unique expansions (denoted by starting the template with $): Every call will return a different expansion. When all possible options have
* been exhausted, it will then 'cycle' and produce the same options, but in a different order.
* - Filters (denoted by dot-chaining the production): Transforms the output to some new string, like converting to all upper case characters
* or returning the length of the string as a base-10 number. See calyx/filters.h for more information on the filters API, and how to add your
* own filters to a registry and grammar.
*
*/
class Registry
{
public:
Expand Down
3 changes: 3 additions & 0 deletions src/rule.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@

namespace calyx
{
/**
* @brief A mapping of a named rule to a production.
*/
class Rule
{
public:
Expand Down
17 changes: 15 additions & 2 deletions test/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,21 @@
#include <catch2/catch_all.hpp>
#include <catch2/catch_session.hpp>

#include <iostream>
#include "calyx/grammar.h"

int main(int argc, char *argv[])
{
int result = Catch::Session().run(argc, argv);
return result;
calyx::Grammar grammar = calyx::Grammar();
calyx::ErrorHolder errors;
grammar.rule(
"hello",
"Hello world.",
errors
);

calyx::Options& options = grammar.getOptions();
std::cout << grammar.generate("hello", errors)->getText(options) << "\n";

return Catch::Session().run(argc, argv);
}

0 comments on commit 1f4ae7f

Please sign in to comment.