Creation of context through a template system
I'm moving !542 (merged)'s proposal here (with some changes) since it won't be done right away and there are several syntaxes that would benefit from it, not just JSON. (We should merge the MR :p)
Some syntaxes define identical contexts with only the attribute
or/and context
fields changing. When contexts are a bit large or when there are several levels, it becomes difficult to find one's way around and synchronize them. This is the case, for example, with todo.xml, which is incomplete for this reason, or markdown styles, which redefine bold, italic, etc. for lists, headings, tables, etc.
I'm proposing a template system to generate variants via parameter transmission when changing context. All this is compile-time, with only the parser and resolveContext() needing to be modified.
For a simple example, I'm using JSON, which has 2 string styles: Key and Value. Apart from the associated style, they are strictly identical and describe via 4 contexts. Here's what the xml looks like:
<context name="String_Key" attribute="Style_String_Key">
<!-- ~~~ or Value ~~~ or Value -->
<DetectChar char=""" context="#pop" attribute="Style_String_Key"/>
<!-- ~~~ or Value -->
<DetectChar char="\" context="String_Key_Char" lookAhead="1"/>
<!-- ~~~ or Value -->
</context>
<context name="String_Key_Char" attribute="Style_Normal">
<!-- ~~~ or Value -->
<RegExpr String="\\(?:["\\/bfnrt]|u[0-9a-fA-f]{4})" context="#pop" attribute="Style_String_Key_Char"/>
<!-- ~~~ or Value -->
<RegExpr String="\\(u[0-9a-fA-f]+|.)?" context="#pop" attribute="Style_Error"/>
</context>
With a template that groups *Key*
and *Value*
it looks like this:
<template name="String_${Type}" attribute="Style_String_${Type}">
<DetectChar char=""" context="#pop" attribute="Style_String_${Type}"/>
<DetectChar char="\" context="String_${Type}_Char" lookAhead="1" contextParams="Type=${Type}"/>
</template>
<template name="String_${Type}_Char" attribute="Style_Normal">
<RegExpr String="\\(?:["\\/bfnrt]|u[0-9a-fA-f]{4})" context="#pop" attribute="Style_String_${Type}_Char"/>
<RegExpr String="\\(u[0-9a-fA-f]+|.)?" context="#pop" attribute="Style_Error"/>
</template>
<template>
replaces <context>
and ${paramName}
corresponds to a "dynamic" value. When a rule or context refers to a template, it must send it parameters through contextParams
, lineEndContextParams
, etc. The actual context name and attributes will be constructed at this point.
The parameter separator is enew line ; spaces in the name are ignored ; spaces in values are retained. In this way, the following rules are equivalent:
<Rule context="${name}" contextParams="param1= value1 param2=value2 param3=value3"/>
<Rule context="${name}" contextParams="
param1= value1
param2=value2
param3=value3
"/>
<!-- ^ makes visible the space after "value2"
A context can be referenced before being resolved. For example, String_Key
can be used (no template form) and resolved later via a rule that uses String_${Type}
+ parameter Type=Key
. This avoids the need to systematically pass all parameters for the same context. As it's generally simpler to always use the fully qualified name, I think we should add a node for resolving templates outside a rule:
<resolveTemplate name="String_${Type}" params="Type=Key"/> <!-- create String_Key and String_Key_Char -->
<resolveTemplate name="String_${Type}" params="Type=Value"/> <!-- create String_Value and String_Value_Char -->
At the moment I don't know whether a syntax should be allowed to use a template from another syntax. If it is allowed, the new styles created must be associated with the original syntax rather than the one describing the template. But this causes problems when several syntaxes refer to the same name.