B3.Syntax Summary
B3.Syntax Summary
In scenarios where templates are used, it is particularly desirable that the template syntax
does not destroy the syntax of the target file
and that the two coexist without interference.
For example, when generating java with velocity, I hope the template can be checked and highlighted in both velocity and java syntax. when generating html, the template should be able to preview directly in the browser without breaking the html syntax.
template syntax
- syntax of template engine, such as FreeMarker, Velocity.target syntax
- aka.native syntax
, syntax of the target file, such as java, html.meepo syntax
- simple markup directives that use the comments of the target syntax to translate the template.- All text order is left-to-right, right-to-left language is not supported.
The directive is made by comment
of the native syntax
and the replacement is processed line by line to output the underlay template (backend)
.
The processing of the native syntax
is divided into two processes, parse
and merge
, and the lookup in parsing depends on regular expressions. When merging, except for RNA
, it is output directly, and the effectiveness is equal to StringBuilder.append
.
There is no complex flow control
and execute function
in RNA, so parsing
once and the subsequent merging
is very efficient.
- Without
RNA
, equivalent to a static string for idempotent operations, merge only once, used directly afterwards RNA
relies on anexecution engine
, equivalent toMap
+StringBuilder
except for dynamic languagejava
execution engine, dynamically compiled to bytecode, equal to native java class after first compilationStringBuilder
pre-calculates the length to avoid expansion copying in the process
B3.1.Template Features
There are some basic concepts and conventions in Meepo syntax, as follows,
blank
- one0x20
or0x09
, i.e. space or\t
alphanum
-[a-zA-z0-9]
, letters and numbers, case-sensitivenative comment
- comments of native language, e.g.,//
,/*
and*/
directive
- special annotation in Meepo, such as a prefixDNA
- Defined Native AnnotationRNA
- Runnable Native Annotation? +*
-[0,1]
,[1,∞)
,[0,∞)
, respectivelydirective line
- directive line is only parsed byMeepo
and invisible in mergeline
- refers to[^\n]\n
or[^\n]$
format
For simplicity, the native comment
+ blank
before the directive
is omitted in the following,
HI-MEEPO
Hi! Miepo, definenavite comment
for subsequent parsingDNA:SET
Set replacement, define a substitution and its scopeDNA:END
End effect, stop acting when or whereDNA:BKB
Effect Immunity, the region beforeEND
is not parsedDNA:RAW
Native raw string, after execution, output the raw string behind itDNA:SON
Sub-template, used as a component to import other templates during parsingRNA:PUT
Put variable, execute theexecute body
and store the result in the environmentRNA:USE
Use variable, use the built-in orPUT
ed variable in environmentRNA:RUN
Execute every time, executesfunction body
every time, such as counterRNA:WHEN
Conditional execution, combined into if-elseif-else logic blocksRNA:EACH
Loop execution, loop in an array or collectionRNA:ELSE
Else condition, the else branch forWHEN
andEACH
RNA:DONE
Stop executing, ends the scope ofWHEN
andEACH
Always use \n
as line terminators
to break line, even if \r\n
in window is processed as \n
. In the single line comment style that ends with\n
, the\n
is considered as a syntax terminator, and will not be output in the merge.
Some RegRxp background knowledge is required, as Java's RegExp is used to parse the template.
- In searching,
.^$?+*{}()[]\|
is always misused, no need to escape some chars in[]
- In replacement,
\
is mainly used as aback reference
, and some of the()
combinations have special meanings.
The regular compile options are UNIX_LINES
and MULTILINE
, set by the embedded flag
,
(?idmsuxU-idmsuxU)
Nothing, but turns matchflags
on/off(?idmsux-idmsux:X)
X, as a non-capturing group with the givenflags
on/off- i Pattern.CASE_INSENSITIVE Not case-sensitive, default off
- d Pattern.UNIX_LINES Only
\n
asline terminators
, default on - m Pattern.MULTILINE
^
and$
will matchline terminators
, default on - s Pattern.DOTTAL
.
matchline terminators
, default off - u Pattern.UNICODE_CASE Unicode-aware case folding, default off
- x Pattern.COMMENTS whitespace and comments in pattern, default off
- U Pattern.UNICODE_CHARACTER_CLASS, default off
B3.2.HI-MEEPO Hi! Meepo
Syntax: comment head
blank
+ HI-MEEPO
!
? blank
+ comment tail
?
Define comment
and identify this file as the native
file that Meepo
will parse.
comment head
- The first part of a single or multi comment, the previous non-blank
stringHI-MEEPO
- The strange name (hi meepo) is to avoid repetition and escape!
- The!
preserves theblank
before and after the directive, explained latercomment tail
- The end of multi-line comment, the latter non-blank
string
Hi! Meepo
must be on a separate line, and using blank
can improve the readability. Similar to using DELIMITER
in sql to define the terminator, for example,
- java -
// HI-MEEPO
,//
is comment - java -
/* HI-MEEPO */
,/*
and*/
are comment - sql -
-- HI-MEEPO
,--
is comment - bash -
# HI-MEEPO
,#
is comment - html -
<!-- HI-MEEPO -->
,<!--
and-->
are comment
Note: that the comment head
can have repeated letters, and Meepo only handles the repetition of the same character, for example,
/*
-/***** DNA:RAW
, invalid, nothing to do//
-////// DNA:RAW
, valid, handle the repeats#
-##### DNA:RAW
, valid, handle the repeats
For the following text (DNA and RNA) parsing, there are 2 types of parsing, line parsing and block parsing, rules as follows,
HI-MEEPO
is always a line parser and must occupy a separate line.single line comment
style Meepo is parsed line by line.Multi-line comment
style Meepo is read across lines and parsed by block.- Parsing is not always done line by line, so
^
and$
are not always at the beginning and end of a line in the regular matching.
HI-MEEPO!
and HI-MEEPO
handle the first blank
of the directive line according to the following rules,
- Without
!
and the whole line directive will ignore its line in the output, i.e. the first\n
after the directive line. - With
!
, only the directive between the head and tail of the Meepo is processed, and the blanks before and after are preserved. DNA:RAW
is special, the!
has no effect on it, it keeps its outside and removes the first blank inside it.- In
@<!--_DNA:RAW_SUPER_-->@
,@
and_
denote reserved and removed blanks, respectively.
In subsequent examples, // HI-MEEPO
is used as an example, but omitted.
B3.3.Factory DNA, Static Replacement
DNA is like a factory director that defines replacement directives for efficient static text replacement at parse time.
B3.4.DNA:SET Setting Replacement
Syntax: DNA:SET
blank
+ delim
find
delim
repl
delim
effect
?
Replaces the pattern matching string within a specified scope or times.
delim
-delimiter
, the 1st non-(blank
,!
,alphanum
) 1-2byte char, such as/
find
- RexExp pattern (withoutdelim
), refer tobackreference
if grouping existsfind
is empty, thisSET
is ignored.repl
-replace
, string (withoutdelim
), refer tobackreference
if grouping existsrepl
is empty, it means delete, i.e. replace with emptyeffect
- The number of times to take effect, i.e. when/where to stop, notblank
The backreference
refers to the case where there is ()
in find
or the \1
inrepl
. This affects the delimiter of the find/replace string, and also avoid writing complex expressions with the following convention rules.
If there is no group in
find
, use group(0), i.e., match all.If
find
has group, take the first(
, i.e. group(1) content.If
((A)(B(C))
, count(
in the order from left to right.- group(1) - ((A)(B(C)))
- group(2) - (A)
- group(3) - (B(C))
- group(4) - (C)
times
, values separated by,
or closed range with-
, e.g.1-3,15
.named
, infinite times that can be terminated byEND
.
// DNA:SET /false/{{user.male}}/
var isMale = false;
/* Replace only false in above line with the variable user.male. the output is :
var isMale = {{user.male}};
*/
B3.5.DNA:END End Effect
Syntax: DNA:END
(blank
+ effect
)+
End the scope of effect
s created by directives, such as the named scope of SET
.
// DNA:SET /1010100/{{id}}/id
// DNA:SET /"(VAR)"/{{desc}}/1
// DNA:SET /VAR/{{info}}/2
SUPER(1010100, "ConstantEnumTemplate", "VAR", "VAR")
// DNA:END id
/* Defines named id, desc's group(1), info's 2 matches. the output is :
SUPER({{id}}, "ConstantEnumTemplate", "{{desc}}", "{{info}}")
*/
B3.6.DNA:BKB Effect Immunity
Syntax: DNA:BKB
blank
+ effect
Define a named
global effect inmmuity scope that can be ended by END
, and the text and directive within it will not be processed.
- text - any text that is not Meppo directive
- directive - treated as text except for the END which corresponds to the current BKB.
- There can only be one BKB currently at a time.
// DNA:BKB KING
// DNA:SET /"(VAR)"/desc/1
SUPER(1010100, "ConstantEnumTemplate", "VAR", "VAR")
// DNA:END KING
/* ignore the SET directive, the output is :
// DNA:SET /"(VAR)"/desc/1
SUPER(1010100, "ConstantEnumTemplate", "VAR", "VAR")
*/
B3.7.DNA:RAW Native Raw String
Syntax: DNA:RAW
blank
+ raw string
Define a template
with comment syntax to compensate for cases where the native
syntax is not supported. The use of single-line comment is simple and clear. and the use of multi-line comment to keep only the content between head and taili.
The effect is to remove the comment head
, DNA:RAW
, comment tail
and the blank
in them.
/* The following 2 lines have the same output i.e. `// DNA:RAW ` */
SUPER(1010100, "ConstantEnumTemplate", "VAR", "VAR")
// DNA:RAW SUPER(1010100, "ConstantEnumTemplate", "VAR", "VAR")
B3.8.DNA:SON Sub-Template
Syntax: DNA:SON
blank
+ path
Reads the resource in UTF8 from path and expands its contents at the current position, and then parse them all. The path can contain a protocol, classpath by default, only the following protocols are supported.
http://
,https://
, read by GET requestfile://
,/
, read from file systemclasspath:
, read from the classloader, Note no//
here- Starting with
/
or.
means the relative path to the host template, but is not recommended.
Note: the son templates must include HI-MEEPO
separately, which is a static parsing in the separate context and later merged into the current parent template.
B3.9.Workshop RNA, Dynamic Execution
RNA is like a workshop manager, defining execution directives, calling the execution engine
at merge time, and using its result as a replacement.
- An
execution engine
can executefunc
(function body) of multipletypes
, where one type is referred to as anengine
. - The name of
engines
must bealphanum
, case sensitive, e.g.js
. - Engine whose name endwith
!
such asjs!
, will ignore errors ,continue execution, returnsnull
. - If the execution returns
null
,empty string
is used to merge the template.
The default engine
in RNA is map
. Users can register other engines with RnaManager, described later.
map
-session
level, usefunc
as key, go value fromenvironment
, if not, return the key.raw
-nothing
level, return thefunc
directly as a string without expanding the escapes.
Meepo uses multi-line block parsing for multi-line comments, so the func
naturally supports multi-line to improve readability.
B3.A.RNA:PUT Put Variable
Syntax: RNA:PUT
blank
+ engine
? delim
var
delim
func
delim
Specify the engine
to execute the func
and store the function
or execution result
in the environment
(referes map engine) for other RNA
to use.
environment
is the Meepo context and some scripting engine's contextengine
see engine description for detailsdelim
is the same asSET
.var
is the variable stored into the context, not the native literal.func
is executed by a specific engine, such as spring, then it can be executed a SpEL.- if
var
orfunc
is empty, nothing is executed.
// DNA:PUT os/who/basename $(pwd)/
/* Take the output of `basename $(pwd)` and store it in context with `who` as the key */
B3.B.RNA:USE Use Variable
Syntax: RNA:USE
blank
+ delim
find
delim
var
delim
effect
?
RNA
version of SET
, the difference is the var
value is get from the map
engine, not the literal replacement of the underlying template. The rules for getting variable(e.g., navigation class objects, pipeline handling functions) are described in the map engine section.
Automatic multi-paragraph indentation
support is performed when merging vars
, depending on the type of var value
satisfying the follows,
find string
starts with indented whitespace.var value
is an Array or Collection and its size is greater than 1.
Indenting more than 2 elements will align with the 1st element. sometimes lines may be unintelligent and look bad. eg.
- Indented object, no
\n
ending, no line break, like zebra stripes - Unindented object, contains
\n
, with line break, look interlaced
// DNA:USE /meepo/user.home/
var userHome = "meepo";
/* get System.getProperty("user.home"). the output is:
var userHome = "/home/trydofor";
*/
B3.C.RNA:RUN Execute Every Time
Syntax: RNA:RUN
blank
+ engine
? delim
find
delim
func
delim
effect
?
combine PUT
and USE
, support indentation, the difference are,
find
, empty means execute only, no replacefunc
, use execution result directly, no store tovar
- execute every time, eg. counter function, increment on each call, no cache.
// DNA:RUN os/rand/echo $RANDOM/1-3
var userName = "meepo-rand";
var userPass = "rand-rand";
/* get random number each time and print. the output is:
var userName = "meepo-12599";
var userPass = "16345-31415";
*/
B3.D.RNA:WHEN Conditional Execution
Syntax: RNA:WHEN
blank
+ engine
? delim
bool
delim
func
delim
group
Multiple WHEN
can be combined into if
-else if
-else
logic blocks.
bool
- Must bey|yes|n|no|not
, indicatingtrue
orfalse
func
- Evaluate the execution result to boolgroup
- Must bealphanum
, groupELSE
andDONE
in the logic scope
Evalue the following cases get false
, evalue not
to false
get true
- boolean
false
- object
null
- number
NaN
or between positive/negative0.000000001
(9 digits) empty
string, zero size of Array/Collection/Map
<!-- RNA:WHEN /yes/it.rem0/bg -->
<li value="code">rem0-name</li>
<!-- RNA:WHEN /not/it.rem1/bg -->
<li value="code">rem2-name</li>
<!-- RNA:ELSE bg -->
<li value="code">rem1-name</li>
<!-- RNA:DONE bg -->
Equivalent to the if(a){}else if(!b){}else{}
in following js pseudocode
if (it.rem0){
console.log('<li value="code">rem0-name</li>')
} else if (!it.rem1){
console.log('<li value="code">rem2-name</li>')
} else {
console.log('<li value="code">rem1-name</li>')
}
B3.E.RNA:EACH Loop Execution
Syntax: RNA:EACH
blank
+ engine
? delim
step
delim
func
delim
group
Using group
to refer to the current element in the loop. if the group
is named it
, then it.x
represents the x
attribute of the element.
step
- must be-?[0-9]+
, the order and step, negative isreverse
loopingfunc
- engine execution result, must be array/collection, otherwise equal toRNA:PUT
group
- Must bealphanum
, groupELSE
andDONE
in the logic scope, and refer to current element
Depending on the data type, different loop processing is performed, null or empty is skipped and can be executed within ELSE
.
- Array - Class.isArray()
Collection<E>
- instance of Collection- Other types, do not loop
- Reverse-order loop, not (RandomAccess or ReverseIterator) are converted to toArray
In the loop, the following built-in properties indicate the current status, given the group
named it
, then
it
- The current element referenct, should avoid the name conflict to pollute the context- to reference the
x
attribute of the current element useit.x
it._count
- Built-in variable, current loop counter, 1-base, 0 means not loopedit._total
- Built-in variable, total number of elements in thegroup
it._first
- Built-in variable, whether the first elementit._last
- Built-in variable, whether the last element- These built-in variables are not removed at the end of the loop and can be used outside the loop.
Since Meepo is a professional non-professional
template engine, this for-each
is very low-level,
- Limited support for object navigation, separated by
.
, see themap
engine for details. - The element in the loop supports only
Map<String,? >
and JavaBean's Getter. - No scope isolation, the
group
name can override the variables within the context.
<!-- RNA:EACH map/2/items/it -->
<!-- RNA:USE /name/it.name/* -->
<li value="code">rem0-name</li>
<!-- RNA:ELSE it -->
<li>no item</li>
<!-- RNA:DONE it -->
<!-- RNA:USE /total/it._total/ -->
<!-- RNA:USE /count/it._count/ -->
<div>result=count/total</div>
Equivalent to the for(;;)
or for-in
loop logic of the following js pseudo-code, depending on the collection
type and the step
positive or negative.
let step=2 // Loop steps, negative numbers in reverse order, must not 0
let index=0 // Temporary variables in the process
let it = null, count=0, total=items.length; // built-in variable
for(it in items){
if(index++ % step !== 0) continue // Control step
count++
console.log('<li value="code">rem0-'+it.name+'</li>')
}
if(count === 0){
console.log('<li>no item</li>')
}
console.log('<div>result='+count+'/'+total+'</div>')
B3.F.RNA:ELSE Else Condition
Syntax: RNA:ELSE
blank
+ group
group by group
and handle else
branche on WHEN
or EACH
with the same group.
- If
WHEN
, it means none of theWHEN
is executed - If
EACH
, it means the loop body is never executed (e.g. no elements) EACH-ELSE
has the same semantics aspebble
, is different from python'sfor-else
B3.G.RNA:DONE Stop Executing
Syntax: RNA:DONE
(blank
+ group
)+
group by group
to stop executing of one or more WHEN
and EACH
with the same group.
B3.H.Placeholder Template
Simplified template to perform only expression-level replacement or function handling, rather than the full Meepo template syntax. For example, placeholders in configuration files usually require simple replacement or string conversion.
To use it, just customize the boundary
around the variable, {{
and }}
by default.
Define escaping
char can escape the boundary
, default is empty
, no escaping. The escaping has the following characteristics, using \
for example,
- Available only for
boundar
, e.g.\{{
and\}}
to{{
and}}
- Escape itself before the boundar, such as
\\{{var}}
to\
+var
value - Placeholder, paired from left to right, use the closest pairs, non-matching boundary is treated as plain text.
- Other cases are invalid, such as
\n
- Nested Placeholders is not supported
- Variable names cannot contain spaces, or they will be resolved as a function
B3.I.Limitation of Using RNA
Since the template generates a syntax tree during static parsing, the conditionals and loop execution in RNA
do not recognize the runtime structure.
The following template intent is, to use the first truthy value between GitHash and ModTime by pattern hash
. Intuitively, this format is more consistent with procedure-oriented conditional assignment, but causes a crossover scope error during syntax checking.
// HI-MEEPO
// RNA:WHEN /yes/GitHash/bg
// RNA:USE /hash/GitHash/
// RNA:ELSE bg
// RNA:USE /hash/ModTime/
// RNA:DONE bg
project hash
The crossover error occurs because the pattern hash
has are two RNA:USE
using it, In static parsing, the runtime value is not available, so it can not determine the correct the syntax tree to belong to, change it as follows
// HI-MEEPO
// RNA:USE /hash/GitHash/
// RNA:USE /time/ModTime/
// RNA:WHEN /yes/GitHash/bg
project hash
// RNA:ELSE bg
project time
// RNA:DONE bg
Or Use the fun:see
function to help
// HI-MEEPO
// RNA:USE /hash/fun:see GitHash ModTime/
project hash