-- | Plat is a template engine, and, as such, it is designed to help you present your data
-- as simple text with the markup of your choice.
-- In order to use it, you'll have to do three things.
-- * Prepare your data;
-- * Create a template to insert this data into; and
-- * Render the template with this data.
-- See the following sections for explanations and examples.

module Plat

-- * Context

-- $contextDoc


-- ** Context elements


-- * Template

-- $templateDoc


-- ** Template errors


-- * Rendering

-- $renderDoc


-- ** Rendering errors


-- * Position

 ) where
import Plat.Context
import Plat.Template
import Plat.Rendering

-- $contextDoc
-- Let's repeat: Plat is a template engine. Therefore, it's impossible to do calculations
-- in the template, even small ones, like counting the lines. You need to have your data
-- prepared before you render the template, and that includes sorting, indexing, etc.
-- There are different types of data, which are used differently. As for now, there are
-- four types, although in the future there could be more. They are:
-- * Strings, that are inserted into the template;
-- * Booleans, that are checked during rendering;
-- * Arrays, that are iterated over; and
-- * Records, that keep other values of different types.
-- Using one type instead of the other results in a run-time error.
-- Records and arrays form a hierarchy, the root of which should always be a record.
-- This root becomes a context which the template is rendered with. Again: it can't be
-- a string, or a boolean, or even an array.
-- Defining strings and booleans is pretty straightforward, usual Haskell 'String's and
-- 'Boolean's will do, and Haskell lists are a way to define arrays. As for records,
-- we provide a handy 'Context' monad, which allows us to define records with just one
-- '=:' operator.
-- Below is an example of data, prepared to be inserted into a template. It's a simple
-- list of employees in a fictional company named "Mac's tools". For each employee we
-- provide his name, numerical index (as we know, it's impossible to implement this
-- numbering in Plat itself), and, optionaly a boolean "bad", which, probably, is a Mac's
-- evaluation of this particular employee's performance.
-- >ctx =
-- >    do "name" =: "Mac's tools"
-- >       "staff" =: [
-- >        do "index" =: "1"
-- >           "name" =: "Alice"
-- >        ,
-- >        do "name" =: "Bob"
-- >           "index" =: "2"
-- >           "bad" =: True
-- >        ,
-- >        do "index" =: "3"
-- >           "name" =: "Nicolás"
-- >        ]
-- Of course, as this is nothing but a simple Haskell value, one can use all power of
-- Haskell to create such data automatically.

-- $templateDoc
-- Unlike contexts, templates are not created in Haskell. Instead, they are typically
-- held in separate files and written in a special markup language. Of course, there isn't
-- anything to prevent them from being held in strings inside Haskell source code.
-- However, they are compiled into a special opaque data type 'Template' before they are
-- used. This compilation needs to happen just once, unless the template is changed.
-- All template commands start from the letter \'\@\'. Therefore, all \'\@\'s that should
-- be in the rendering result need to be escaped. In fact, that is one of the commands:
-- [@\@\@@] Represent the string \"\@\".
-- There is a way to insert comments in the template. For now, we only support one-line
-- comments. They won't be present in the result of rendering.
-- [@\@#@] Starts a one-line comment, continued up to the end of the current line.
-- There is also a command that does nothing.
-- [@\@.@] Does nothing.
-- It can be used as a separator between a command and some other text. For example,
-- if you want the letter \'a\' to follow the output of the command \'\@foo\'
-- without any space between them, you can write \'\@foo\@.a\'.
-- There is one command to insert the string from the context into the template.
-- [@\@/expr/@] Insert the value of the expression @\'/expr/\'@, which should be a string.
-- For now, the expression syntax is very simple. Any expression is just a sequence
-- of names separated by dots (\'.\'). Expressions are evaluated from left to right,
-- starting with the context, used to render the template. Each name is just a name
-- of a field in the current record, and the value of this field replaces that record.
-- For example, if the expression is @\'foo.bar.baz\'@, then it's value is the value
-- of the field @\'baz\'@ of the record, which is the value of the field @\'bar\'@ of
-- another record, which, in turn, is the value if the field @\'foo\'@ of the context.
-- It's a runtime error if the required field doesn't exist or if the current value is
-- not a record. There are two exceptions. First, if the value of @\'/expr/\'@ is boolean,
-- then the expression @\'/expr/.not\'@ is valid and it's value is also boolean,
-- complement to the value of @\'/expr/\'@. Second, if the value of @\'/expr/\'@ is
-- an array, then the expression @\'/expr/.empty\'@ is, again, boolean, and it is true
-- if and only if the value of @\'/expr/\'@ is an empty array. Of course, neither of this
-- two expressions can be inserted into the template as a string.
-- There is a command to check for the value of a boolean expression.
-- [@\@!/expr/@] Checks the value of the expression @\'/expr/\'@, which must be true.
-- It's a runtime error if the value of @\'/expr/\'@ is not boolean, or if it's false.
-- However, there is a difference between this two variants. If the expression
-- @\'/expr/\'@ is not valid, then the expression @\'/expr/.not\'@ is also not valid,
-- but if @\'/expr/\'@ is false, then @\'/expr/.not\'@ is valid and true.
-- Of course, checking the boolean value is not very useful, unless you do it between
-- the branching commands.
-- [@\@{@] Starts the list of branches.
-- [@\@|@] Separates branches in the list.
-- [@\@}@] Ends the list of branches.
-- Each branch is a separate template, which is rendered with the same context as the
-- list of branches itself. Plat chooses the first branch that doesn't fail and uses it
-- instead of the whole list as if there was no failure. It's a runtime error
-- if all branches fail. It's a compile-time error to have unbalanced starting or ending
-- branching command, or to have the separating command not surrounded by them. Here,
-- \'compile-time\' means \'when the template is compiled\', not when the Haskell source
-- is compiled.
-- At last, there are two looping commands.
-- [@\@/expr/\[/name/@] Starts the loop.
-- [@\@\]@] Ends the loop.
-- Here, the value of @\'/expr/\'@ should be an array. Each of it's items, in turn, is
-- added to the context under the name @\'/name/\'@, and the template between these
-- commands is rendered with this new context.
-- An example:
-- >List of employees at @name:
-- >@staff[person
-- >@person.index@.. @person.name@{@!person.bad (going to be fired)@|@}@
-- >@]@# There won't be an empty line in the result
-- This is a simple template, which can be used with the data example above. Note that
-- if the employee is marked as \'bad\', then there would be a note that he is going to be
-- fired; otherwise, there won't be anything, as the second branch is empty. Of course,
-- you can use several branches, not just two of them.
-- There is just one quirk here. If the line in the template contains only some control
-- commands (i.e. branching, looping, or checking commands), padded with whitespaces
-- at the beginning and the end, then this line won't be present in the result of
-- rendering. All the whitespace, together with the line break, would be removed.
-- So it's safe, for example, to end the loop on a separate line. On the other hand,
-- if the line contains nothing but whitespace, then it won't be removed.
-- If you don't want a line to be removed, you can just insert the @\'\@.\'@ command.

-- $renderDoc
-- Now, when you have a 'Context' and a 'Template', it's time to bring them together.
-- With the examples given above, the result of rendering would be the following:
-- >List of employees at Mac's tools:
-- >1. Alice
-- >2. Bob (going to be fired)
-- >3. Nicolás