Scala-Chef-Redux as an external DSL. See https://github.com/l-hoang/scala-chef-redux for original Scala-Chef-Redux.
- Comments are currently not optional.
- The comments must not have any new lines in them (i.e. one paragraph only).
- Method statements cannot have more than one new line between them.
- Instead of specifying a mixing bowl with an ordinal identifier, you specify it by number, e.g. "mixing bowl 1" instead of "the first mixing bowl".
- To be safe, put at least 1 blank line (i.e. 2 new lines) between each "section" of a recipe (e.g. ingredients, methods, titles, etc.).
The following assumes your working directly is the src
directory, and a bin
directory exists in the directory above src
.
There are dependences in the files, so you will have to compile them in an order that satisfies the dependences. Here is one such order.
scalac -d ../bin/ -cp ../bin scalachefredux/Enums.scala
scalac -d ../bin/ -cp ../bin scalachefredux/ChefLines.scala
scalac -d ../bin/ -cp ../bin scalachefredux/ChefHelpers.scala
scalac -d ../bin/ -cp ../bin scalachefredux/ChefText.scala
scalac -d ../bin/ -cp ../bin scalachefredux/ChefState.scala
scalac -d ../bin/ -cp ../bin scalachefredux/LineBuilder.scala
scalac -d ../bin/ -cp ../bin scalachefredux/ChefRunner.scala
scalac -d ../bin/ -cp ../bin scalachefredux/ChefParser.scala
scalac -d ../bin/ -cp ../bin scalachefredux/ScalaChefRedux.scala
The external DSL nature of this implementation allows you to write the Chef program in a separate file.
The syntax of the program should basically follow the original Chef spec found on the website aside from the changes mentioned above in the Important Notes section.
Once you have written a Chef program, you can run it with the following:
scala -cp <path to bin> scalachefredux.ScalaChefRedux <chef program here>
The error messages you will get on failure are admittedly not very helpful, so if you have an error, please recheck the syntax changes above as well as the original Chef syntax.
Note that these descriptions are the same as ScalaChefRedux's descriptions except for ChefHelpers, ChefParser, and ScalaChefRedux.
Contains the helper classes ChefIngredient
and ChefStack
, which
represent a Chef Ingredient and stack for holding ingredients respectively.
There are also helper functions for copying state.
For the external DSL implementation, it also contains the ChefResult
class
which is used by the parser when returning parse results.
Contains case class definitions for the different Chef lines (corresponding to different Chef operations).
Contains the ChefRunner class which given a program state and program text will be responsible for running the program by going through the text and updating the program state.
Contains the ChefState class which holds all of the "runtime information" and state for a running Chef program.
Contains the ChefText class which holds the lines that are parsed in order to be run later.
Contains various enumerations (case objects) for the code. Notably contains the objects for certain words so that they can be parsed.
Contains the LineBuilder class which is what builds ChefLines by being fed information by the main parser.
Contains the parser for the Chef programs you write. Parses and creates ChefLines.
The main class that puts everything together to run the Chef program. Uses the ChefParser to parse the lines in order to construct the inner representation of the Chef program and runs the Chef program.
The parsing occurs using Scala's parsing combinators. A parsing combinators is responsible for parsing some kind of token and returning whatever result you specify it to return, whether it be the parsed value or a transformation applied to the parsed value. They are particularly powerful as you can combine parsing combinators together to form a new parsing combinator that is capable of parsing what its parts are capable of parsing.
The important thing is that ChefLines are being returned by some of the parsers, which allows me to take advantage of my existing code from the internal DSL version of Chef since I can then replace the internal DSL parsing infrastructure with the parsing combinator version.
Regex is used with the parsing combinators to do parsing of the Chef program.
For more details on how it works, see the ChefParser
file where I have
extensively commented on how it works + what I am doing (at least
for the non-Chef-line parsers: the Chef line parsers are all somewhat
the same, so I only commented once + where I feel it would help). Also see the
ScalaChefRedux
file for an idea of how I integrate the ChefParser
.
Here are some helpful sources on these parsing combinators and how to use them.
https://wiki.scala-lang.org/display/SW/Parser+Combinators--Getting+Started
https://enear.github.io/2016/03/31/parser-combinators/
https://kerflyn.wordpress.com/2012/08/25/playing-with-scala-parser-combinator/
There is also a README.md
located in src/scalachefredux
that gives something
of a tutorial on the use of the parser combinators in the implementation.
The syntax is basically the original Chef syntax except for the changes mentioned in the Important Notes section above. This is possible due to not being limited by internal DSL conventions.