diff options
-rw-r--r-- | site/404.html | 1 | ||||
-rw-r--r-- | site/index.html | 1 | ||||
-rw-r--r-- | site/main.css | 7 | ||||
-rw-r--r-- | site/spec.html | 244 |
4 files changed, 218 insertions, 35 deletions
diff --git a/site/404.html b/site/404.html index 3f9e5ac..b5a6bc4 100644 --- a/site/404.html +++ b/site/404.html @@ -3,6 +3,7 @@ <head> <meta charset="utf-8"> <meta content="width=device-width,initial-scale=1" name="viewport"> + <link rel="icon" href="data:,"><!--TODO--> </head> <body> <h3>Page not found</h3> diff --git a/site/index.html b/site/index.html index 026778b..ce3d6e7 100644 --- a/site/index.html +++ b/site/index.html @@ -3,6 +3,7 @@ <head> <meta charset="utf-8"> <meta content="width=device-width,initial-scale=1" name="viewport"> + <link rel="icon" href="data:,"><!--TODO--> </head> <body> <h3>Coming soon</h3> diff --git a/site/main.css b/site/main.css deleted file mode 100644 index b771e2a..0000000 --- a/site/main.css +++ /dev/null @@ -1,7 +0,0 @@ -td, th { - border: 2px solid black; - padding: 0.5em; -} -table { - border-collapse: collapse; -} diff --git a/site/spec.html b/site/spec.html index c3ae3fa..90573d6 100644 --- a/site/spec.html +++ b/site/spec.html @@ -3,7 +3,15 @@ <head> <meta charset="utf-8"> <meta content="width=device-width,initial-scale=1" name="viewport"> - <link rel="stylesheet" href="/main.css"> + <style> + td, th { + border: 2px solid black; + padding: 0.5em; + } + table { + border-collapse: collapse; + } + </style> <title>POM Language Specification</title> <link rel="icon" href="data:,"><!--TODO--> </head> @@ -16,7 +24,9 @@ <h2>Introduction</h2> <p> POM is a “markup” language, primarily intended for software configuration, - and designed to be easy to parse and use. + and designed to be easy to parse without any third-party libraries + (e.g. for looking up Unicode classes or matching regular expressions), + while still being terse and legible. The POM specification is quite strict, to avoid cases where dubious files can be accepted by some parsers while being rejected by others. POM files should use the <code>.pom</code> file extension to identify themselves. @@ -147,7 +157,7 @@ time = 35 min <ul> <li> The ASCII characters <code>a</code>–<code>z</code>, <code>A</code>–<code>Z</code>, <code>0</code>–<code>9</code>, as well as each of - <code>./-+*_</code>. + <code>./-*_</code>. </li> <li> Any non-ASCII code point (U+0080–10FFFF). @@ -232,9 +242,9 @@ time = 35 min </li> <li> Otherwise, accepted-spaces at the end of the line are removed; - then, the value is the text starting from <i>c</i> and ending at the next line feed. + then, the value is the text starting from <i>c</i> and going to the end of the line. </li> - <li>If the value is not a valid value (see above), an error occurs.</li> + <li>If the value is not a valid value (i.e. it contains a null character), an error occurs.</li> <li> The key is equal to the relative-key if the current-section is empty; otherwise, it is equal to the concatenation of current-section, a dot, and the relative-key. @@ -274,10 +284,12 @@ time = 35 min </tr> <tr><td><code>\u{</code><i>digits</i><code>}</code></td> <td>Unicode code point <i>digits</i>,<br> - interpreted as hexidecimal<br> + interpreted as hexadecimal.<br> <i>digits</i> must be 1–6 characters long,<br> and may contain leading zeros,<br> - but must not be zero.</td> + but must not be zero and<br> + must not be a UTF-16 surrogate<br> + half D800–DFFF.</td> </tr> </tbody> </table> @@ -287,10 +299,12 @@ time = 35 min Although POM does not have a way of specially designating a value as being a list, there is a recommended syntax for encoding them. Specifically, a value can be treated as a list by first splitting it into comma-delimited parts (treating <code>\,</code> as a literal comma - in a list entry), then removing any accepted-spaces surrounding list entries. List entries may be empty. + in a list entry), then removing any accepted-spaces surrounding list entries. </p> <p> - An empty string is considered to be an empty list. + List entries may be empty, but if the last entry in a list is empty, it is removed + (if there are two or more empty entries at the end of a list, only one is removed). + As a consequence, an empty string is considered to be an empty list. </p> <p> If a list's order is irrelevant and it might be large or benefit from labelling its entries, @@ -298,6 +312,9 @@ time = 35 min (see the <code>ingredients</code> “list” in the opening example). </p> <h3>Examples</h3> +<p> + The following lines describe 3-entry lists. +</p> <table> <thead> <tr><th>POM line</th><th>Entry 1</th><th>Entry 2</th><th>Entry 3</th></tr> @@ -321,6 +338,12 @@ time = 35 min <td><code></code></td> <td><code>76</code></td> </tr> + <tr> + <td><code>empties = ,,,,</code></td> + <td><code></code></td> + <td><code></code></td> + <td><code></code></td> + </tr> </tbody> </table> @@ -345,13 +368,6 @@ time = 35 min the user configuration would be merged into the global configuration). </p> -<h2>Extensions</h2> -<p> - If needed for a particular domain, an parser may accept an extended form of the POM syntax. - Ideally, extensions should use lines beginning with invalid key characters (e.g. <code>!&%</code>) - so that there is no ambiguity, and the file cannot be interpreted without the extension. -</p> - <h2>Schemas</h2> <p> A <i>schema</i> is a POM file that describes how other POM files should be formatted (i.e. what keys they should @@ -359,11 +375,15 @@ time = 35 min all of the schema’s rules. </p> <p> + POM’s schema format is not powerful to enforce all possible restrictions; + some will have to be enforced by the application. +</p> +<p> Every schema key is of the form <i>k</i><code>.</code><i>rule</i>, where <i>k</i> is a valid key, and <i>rule</i> is one of the rule names listed below. </p> <p> - For any valid key <i>k</i> the value of the rule <i>rule</i> is determined for <i>k</i> as follows: + For any valid key <i>k</i> the value of the rule <i>rule</i> for <i>k</i> is determined as follows: </p> <ul> <li>Break <i>k</i> down into its <i>n</i> components.</li> @@ -376,15 +396,33 @@ time = 35 min </li> </ul></li> <li>If the candidate-list is empty, use the default value for the rule.</li> - <li>If the candidate-list has exactly one schema key, use the value for that key.</li> + <li>If the candidate-list has exactly one schema key, use the value of that schema key.</li> <li> Otherwise select the schema key in the candidate-list with the latest first <code>*</code>-component (in terms of component index), preferring keys with no <code>*</code>, breaking ties by the latest second <code>*</code>-component, preferring keys with only one <code>*</code>, etc. - Use its value for the key. + Use its value. </li> </ul> +<h3>Example</h3> +<p> +Given the following schema: +</p> +<pre><code> +*.*.id.type = Int +vehicle.*.id.type = UInt +*.truck.id.type = Float +vehicle.car.id.type = String +</code></pre> +<p> +The value of <code>type</code> rule for vehicle.car.id is String, +for vehicle.truck.id is UInt, +for my.truck.id is Float, +for my.car.id is Int, +and for my.nephews.car.id is String (no schema key matches, so the default of String is used). +</p> + <h3><code>type</code> rule</h3> <p> Default: <code>String</code>. @@ -418,6 +456,9 @@ time = 35 min of lists above). Nested lists are not permitted. </li> </ul> +<p> + A type may optionally have accepted-spaces on either side; this does not change its meaning. +</p> <h3><code>allow_unknown</code> rule</h3> <p> @@ -430,7 +471,9 @@ time = 35 min </p> <p> If a key is encountered in a configuration - and the value of its <code>allow_unknown</code> rule is <code>no</code>, the configuration does not follow the schema. + and the value of its <code>allow_unknown</code> rule is <code>no</code>, + and it has no matching <code>type</code> rule, + the configuration does not follow the schema. </p> <h3><code>min</code>, <code>max</code> rules</h3> <p> @@ -457,6 +500,15 @@ Additionally, if there is a schema key <i>j</i><code>.*.</code><i>k</i><code>.ty and no correspoding <code>default</code> schema key, where <i>k</i> does not contain any <code>*</code>-components, then a configuration which contains a key <i>x</i> matching <i>j</i><code>.*</code> must also contain the key <i>x</i><code>.</code><i>k</i>. </p> + +<h2>Extensions</h2> +<p> + If needed for a particular domain, an parser may accept an extended form of the POM syntax. + Ideally, extensions should use lines containing invalid key characters (e.g. <code>!&%</code>) + before the <code>=</code> (if any) + so that there is no ambiguity, and the file cannot be parsed without the extension. +</p> + <h2>API recommendations</h2> <p> The following functions are (lightly) recommended @@ -473,14 +525,14 @@ which contains a key <i>x</i> matching <i>j</i><code>.*</code> must also contain Convenience function for loading by path (may be overloaded with <code>load</code> if language supports it). </li> <li> - <code>get(conf: Configuration, key: String) -> Optional<String></code><br> - Get value associated with <code>key</code>, if any exists. - </li> - <li> <code>has(conf: Configuration, key: String) -> Bool</code><br> Returns whether <code>key</code> is associated with any value. </li> <li> + <code>get(conf: Configuration, key: String) -> Optional<String></code><br> + Get value associated with <code>key</code>, if any exists. + </li> + <li> <code>get_or_default(conf: Configuration, key: String, default: String) -> String</code><br> Get value associated with <code>key</code>, if any exists, returning <code>default</code> if not. </li> @@ -514,9 +566,10 @@ which contains a key <i>x</i> matching <i>j</i><code>.*</code> must also contain Returns an error if the key exists but is not one of the above values. </li> <li> - <code>get_list(conf: Configuration, key: String) -> List<String></code><br> - Get value associated with <code>key</code>, if any exists, and parse it as a list, - returning an empty list if the key isn’t present. + <code>get_list(conf: Configuration, key: String) -> Optional<List<String>></code><br> + <code>get_list_or_default(conf: Configuration, key: String, default: List<String>) -> List<String></code><br> + Get value associated with <code>key</code>, if any exists, and parse it as a list + (returning <code>default</code> if the key isn’t present). </li> <li> <code>section(conf: Configuration, key: String) -> Configuration</code><br> @@ -538,8 +591,112 @@ which contains a key <i>x</i> matching <i>j</i><code>.*</code> must also contain </ul> <h2>Examples</h2> +<p> + This section lists some examples of POM files. For more examples, see the <code>tests/</code> + directory in the main POM repository. +</p> + +<h3>All syntax</h3> +This is a configuration which demonstrates almost all of the syntactic forms of POM. -<h3>A schema for a text editor's configuration</h3> +<pre><code> +title = Crème brûlée +0-*/_description_/*-0 =`A 'beautiful' crème br\u{FB}l\u{0000e9}e recipe +that\'s sure to delight your friends!` +author == Jean\0\\"P." D'Martingale +[ingredients.flour] + quantity= '100 g' + type="all-purpose" +[ingredients.sugar] + quantity = 50 g + type = 'br\x6f\u{77}n' +[ingrédients] + œufs.quantité=3 + œufs.type = "extra large\,farm fresh\\,free-range" +[] +DIRECTIONS.en_CA.version.5 = " +1. Separate the egg yolks from the \"whites\". +2. Mix the yolks in a bowl with the sugar. +… +59. Enjoy! +" +</code></pre> +<p> +This configuration has the following mapping of keys to values: +</p> +<table> + <thead> + <tr><th>Key</th><th>Value</th></tr> + </thead> + <tbody> + <tr><td>title</td><td>Crème brûlée</td></tr> + <tr><td>0-*/_description_/*-0</td><td>A 'beautiful' crème brûlée recipe<br> +that's sure to delight your friends!</td></tr> + <tr><td>author</td><td>= Jean\0\\"P."D'Martingale</td></tr> + <tr><td>ingredients.flour.quantity</td><td>100 g</td></tr> + <tr><td>ingredients.flour.type</td><td>all-purpose</td></tr> + <tr><td>ingredients.sugar.quantity</td><td>50 g</td></tr> + <tr><td>ingredients.sugar.type</td><td>brown</td></tr> + <tr><td>ingrédients.œufs.quantité</td><td>3</td></tr> + <tr><td>ingrédients.œufs.type</td><td>extra large\,farm fresh\,free-range</td></tr> + <tr><td>DIRECTIONS.en_CA.version.5</td><td><br>1. Separate the egg yolks from the "whites".<br> +2. Mix the yolks in a bowl with the sugar.<br> +…<br> +59. Enjoy!<br><br></td></tr> + </tbody> +</table> + +<h3>Configuration for a text editor</h3> +<pre><code> +indent-using-spaces = yes +show-line-numbers = yes +tab-size = 4 +font-size = 18 + +[file-extensions] +C = .c +C++ = .cpp, .h, .hpp + +[plug-in.edit-over-ssh] +path = ~/misc/edit-over-ssh.so +enabled = yes + +[plug-in.edit-over-ssh.settings] +favourite-host = my-web-server + +[plug-in.edit-over-ssh.settings.hosts.my-web-server] +address = example.org +port = 22 +ssh-key = ~/.ssh/id_ed25519 + +</code></pre> +<p> +This configuration has the following mapping of keys to values: +</p> +<table> + <thead> + <tr><th>Key</th><th>Value</th></tr> + </thead> + <tbody> + <tr><td>indent-using-spaces</td><td>yes</td></tr> + <tr><td>show-line-numbers</td><td>yes</td></tr> + <tr><td>tab-size</td><td>4</td></tr> + <tr><td>font-size</td><td>18</td></tr> + <tr><td>file-extensions.C</td><td>.c</td></tr> + <tr><td>file-extensions.C++</td><td>.cpp, .h, .hpp</td></tr> + <tr><td>plug-in.edit-over-ssh.path</td><td>~/misc/edit-over-ssh.so</td></tr> + <tr><td>plug-in.edit-over-ssh.enabled</td><td>yes</td></tr> + <tr><td>plug-in.edit-over-ssh.settings.favourite-host</td><td>my-web-server</td></tr> + <tr><td>plug-in.edit-over-ssh.settings.hosts.my-web-server.address</td><td>example.org</td></tr> + <tr><td>plug-in.edit-over-ssh.settings.hosts.my-web-server.port</td><td>22</td></tr> + <tr><td>plug-in.edit-over-ssh.settings.hosts.my-web-server.ssh-key</td><td>~/.ssh/id_ed25519</td></tr> + </tbody> +</table> + +<h3>Schema for text editor's configuration</h3> +<p> + Here is a schema which a text editor might use. The example text editor configuration above follows it. +</p> <pre><code> # don't allow unknown keys by default *.allow_unknown = no @@ -563,6 +720,8 @@ max = 100 default = 14 [plug-in] +*.enabled.type = Bool +*.enabled.default = yes *.path.type = String # everyone be nice to the Microsoft Windows *.path.maxlength = 260 @@ -578,6 +737,35 @@ C-sharp.type = List[String] C-sharp.default = .cs </code></pre> +<h3>Errors</h3> +<p> +This section lists some erroneous lines that might appear in a POM file: +</p> +<pre><code> +# Invalid key character '!' +cool-key! = 23 +# Invalid key character ' ' +fun times = yes +# Missing equals +music is on +# No closing ] +[my.section +# Invalid key character ' ' +[ my.section ] +# Invalid escape sequence "\?" +no_trigraph = "a?\?=b" +# Invalid escape sequence "\xCE" — even though "\xCE\x92" is valid UTF-8. +# ("\u{392}" should be used instead) +capital_beta = "\xCE\x92" +# Invalid escape sequence "\x00" / Invalid character in value (null character) +C_string = "Hello, world!\x00" +# Stray characters after closing " +name = "Andy" B +# Duplicate key 'tab-size' +tab-size = 4 +tab-size = 8 +</code></pre> + </body> </html> |