zen_template 0.1.0

A simple template engine based on rust.
Documentation
= Template 设计文档
:experimental:
:icons: font
:toc: right
:toc-title: 目录
:toclevels: 4
:source-highlighter: rouge

== 语法

=== 变量类型

变量由以下几种类型组成:

* *Number*: 对应 *rust* 的 `i64`
* *Float*: 对应 *rust* 的 `f64`
* *Text*: 对应 *rust* 的 `String`
* *Bool*: 对应 *rust* 的 `bool`
* *Array*: 对应 *rust* 的 `Vec`
* *Table*: 对应 *rust* 的 `struct`
* *None*: 内部空数据标记

=== 定义变量

你可以将一组表达式映射为一个新的变量,此变量仅可用在当前作用域,具体如下所示:

变量命名必须符合此 `^[_a-zA-Z][_a-zA-Z0-9]*$` 正则表达式。

WARNING: 此变量会在当前作用域覆盖之前的变量,直到离开此作用域。如果此表达式不存在则会导致渲染失败。

[source,text]
----
如果你创建了一个变量,那么你就创建了一个变量
{{let new_var = oldvar.child}}
你也可对象进行解构 (需要返回值为 Array )
{{let (index,value) = item.with_index()}}
----

=== 输出表达式

想要直接输出表达式,可直接在文档的任何地方填充 `{{ expr }}`,例如

[source,text]
----
Hello {{ expr }}
----

=== 表达式

以下均为表达式:

[source,text]
----
{{ data }} : 结果为变量的值
{{ data.items }} : 会被翻译为 data.get('items') ==> get(data,'items')
{{ x?:y }} : 会被翻译为 x.get_or_default(y) ==> get_or_default(x,y)
{{ data?.items }} : 会被翻译为 data.get_or_none('items') ==> get_or_none(data,'items')
{{ data.items[0] }} : 会被翻译为 data.get('items').get(0) ==> get(get(data,'items'),0)
{{ x+y }} :  会被翻译为 x.add(y) => add(x,y)
{{ x-y }} :  会被翻译为 x.sub(y) ==> sub(x,y)
{{ x*y }} :  会被翻译为 x.multi(y) ==> multi(x,y)
{{ x/y }} :  会被翻译为 x.div(y) ==> div(x,y)
{{ x%y }} :  会被翻译为 x.mod(y) ==> mod(x,y)
{{ x<y }} :  会被翻译为 x.l_angle(y) ==> l_angle(x,y)
{{ x>y }} :  会被翻译为 x.r_angle(y) ==> r_angle(x,y)
{{ x>=y }} : 会被翻译为 x.ge(y) ==> ge(x,y)
{{ x<=y }} : 会被翻译为 x.le(y) ==> le(x,y)
{{ x == y }} : 会被翻译为 x.eq(y) ==> eq(x,y)
{{ x != y }} : 会被翻译为 x.not_eq(y) ==> not_eq(x,y)
{{ x && y }} :  会被翻译为 x.and(y) => and(x,y)
{{ x || y }} :  会被翻译为 x.or(y) => or(x,y)
{{ x is 'Number' }} :  会被翻译为 x.type() == 'Number' => eq(type(x),'Number')
{{ (a + b) * c }} :  会被翻译为 mult(group(add(a,b)),c)

----

优先级顺序可查看 link:src/syntax.rs[syntax.rs#default_expr_syntax] 方法。

像此表达式最终会被翻译为如下原语

.SRC
[source,text]
----
{{ (earth.asia.us?:earth.europe.cn?:mars.asia?.us?:china + 12).format('utc') }}
----

.LANG
[source,text]
----

----

.LANG
[source,text]
----
format(
    add(
        get_or_default(
            get_or_default(
                get(get(earth,'asia'),'us'),
                get(get(earth,'europe'),'cn')
            ),
            get_or_default(
                get_or_none(get(mars,'asia'),'us'),
                china
            )
        ),
        12
    ),
    'utc'
)
----

=== 条件判断

条件判断的语法结构如下所示:

[source,text]
----
条件判断
{{if expr }}
匹配条件一
{{else-if expr }}
匹配条件二
{{else}}
默认结果
{{end-if}}
----

其中,`expr` 为表达式,表达式的返回数据类型 *必须* 为 `Bool`

你也可以在判断的同时重映射变量

[source,text]
----
{{if let value = expr }}
如果此值存在
{{else}}
如果此值不存在
{{end-if}}
----

=== 循环

循环的结构如下:

[source,text]
----
迭代循环
{{for item in expr }}
循环内可写条件判断
{{if item.dosomething() }}
循环也可被提前结束
{{break}}
{{end-if}}
{{end-for}}
现在循环结束
----

其中 `expr` 的类型必须为 `Array`

== 原语

原语是整个模板引擎的最小单位,所有原语均在外部预定义 (原语参与语法解析)。

要创建一条原语,需要提供原语的名称、参数的数量,其中原语的命名规范与变量一致。