normand.git
3 months agoREADME.adoc: "normand" -> "Normand" master
Philippe Proulx [Wed, 24 Jan 2024 18:36:49 +0000 (13:36 -0500)] 
README.adoc: "normand" -> "Normand"

Change-Id: I196f29acebeba0f76f4d684cbdad093532aae316
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
6 months agoREADME.adoc: local `typing` module also needed for 3.5
Philippe Proulx [Mon, 30 Oct 2023 15:50:19 +0000 (11:50 -0400)] 
README.adoc: local `typing` module also needed for 3.5

This is because the standard `typing` module of 3.5 doesn't offer
`NoReturn` which `normand.py` uses.

Change-Id: I20bdb6f226fdaa6627e39d3b2877404d837b0085
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
6 months agoImplement REUSE with SPDX identifiers
Michael Jeanson [Mon, 23 Oct 2023 21:11:34 +0000 (17:11 -0400)] 
Implement REUSE with SPDX identifiers

The SPDX identifiers [1] are a legally binding shorthand, which can be
used instead of the full boiler plate text. The REUSE specification [2]
defines a standardized method for declaring copyright and licensing for
software projects.

The objective is to facilitate copyright and licensing audits and
compliance for users of our software. We are currently in the process of
converting our projects to REUSE and this will facilitate the vendoring
of normand in those projects.

For files that lacked licensing information, I used the following
guidelines. For code and build system use 'MIT', for documentation
'CC-BY-SA-4.0' and for data files 'CC0-1.0'. This can be altered to your
liking.

Changes to the original patch by Philippe:

* Keep the original copyright notice and MIT license text in
  `normand/normand.py` to keep this module file portable and independent
  from the project.

* Remove newlines between SPDX lines.

[1] https://spdx.org/ids-how
[2] https://reuse.software/tutorial/

Change-Id: I58861cb873585dc773f3993338766c520bf92747
Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
Reviewed-on: https://review.lttng.org/c/normand/+/11135
Reviewed-by: Philippe Proulx <eeppeliteloop@gmail.com>
6 months agoREADME.adoc: fix plural "lengths"
Philippe Proulx [Wed, 11 Oct 2023 18:54:44 +0000 (14:54 -0400)] 
README.adoc: fix plural "lengths"

Change-Id: I7c2b5074f892301c1a1f51f7901c7b7f2eb92e27
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
6 months agoREADME.adoc: fix internal `leb128-integer` link
Philippe Proulx [Wed, 11 Oct 2023 18:44:35 +0000 (14:44 -0400)] 
README.adoc: fix internal `leb128-integer` link

Change-Id: I0a74047f716253dd0698f60444755c924af4e8a9
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
6 months agoNormand 0.23.0 v0.23.0
Philippe Proulx [Wed, 11 Oct 2023 18:31:41 +0000 (14:31 -0400)] 
Normand 0.23.0

Change-Id: I77aef30159a28510f9be62f909f90e54fd68da19
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
6 months agoAdd fixed-length number byte order override
Philippe Proulx [Wed, 11 Oct 2023 18:23:52 +0000 (14:23 -0400)] 
Add fixed-length number byte order override

This patch makes it possible to specify an immediate byte order (suffix
of encoding length) to encode a fixed-length number, overriding the
current byte order without changing it:

    !be
    11 22 33 44
    [0xaabbccdd : 32]
    [0xaabbccdd : 32le]
    [0xaabbccdd : 32]
    ff ff ff ff

Result:

    11 22 33 44
    aa bb cc dd
    dd cc bb aa
    aa bb cc dd
    ff ff ff ff

Change-Id: I3d0c9cb3f0f30ef2f74980bf9c63a93be3bdca64
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Reviewed-on: https://review.lttng.org/c/normand/+/11040
Tested-by: jenkins <jenkins@lttng.org>
6 months agoREADME.adoc: fix "encoded block" -> "transformation block"
Philippe Proulx [Wed, 11 Oct 2023 17:00:13 +0000 (13:00 -0400)] 
README.adoc: fix "encoded block" -> "transformation block"

Change-Id: I29af961df45414c769933f7ebfe6acf7cbe03720
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
6 months agoUse only naked `{` and `}` for variable assignment v0.22.0
Philippe Proulx [Wed, 11 Oct 2023 16:39:07 +0000 (12:39 -0400)] 
Use only naked `{` and `}` for variable assignment

This patch:

* Makes a fixed-length number, an LEB128, or a string item use
  `[` and `]` instead of `{` and `}`.

* Changes `{be}` and `{le}` to `!be` and `!le`.

* Removes the `[` and `]` symbols from the insignificant symbol set
  (I knew this day would come).

This means anything between `{` and `}` is now a valid Python 3
expression. A side effect of this patch is to also simplify the parser
because when expecting an item, `{` already means a variable assignment.

`README.adoc` and tests are changed accordingly.

Change-Id: I071978b0eae9349b779be44843e5f8dd0a162461
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Reviewed-on: https://review.lttng.org/c/normand/+/11036
Tested-by: jenkins <jenkins@lttng.org>
6 months agoAdd transformation block support v0.21.0
Philippe Proulx [Wed, 11 Oct 2023 14:48:28 +0000 (10:48 -0400)] 
Add transformation block support

A transformation block represents the transformed bytes of one or more
items, for example:

    !transform base64
      "hello how are you"
      {ICITTE:8} * 20
    !end

    61 47 56 73 62 47 38 67  61 47 39 33 49 47 46 79  ┆ aGVsbG8gaG93IGFy
    5a 53 42 35 62 33 55 52  45 68 4d 55 46 52 59 58  ┆ ZSB5b3UREhMUFRYX
    47 42 6b 61 47 78 77 64  48 68 38 67 49 53 49 6a  ┆ GBkaGxwdHh8gISIj
    4a 41 3d 3d                                       ┆ JA==

It's effectively calling a function with the bytes of the block items.

As of this version, Normand only features a specific set of
transformation functions. In the future the user should be able to
define its own transformations (named functions passed to
normand.parse() I guess).

The gzip and bzip2 formats include a timestamp, so the `tests/*.nt`
approach doesn't work here: adding `tests/test_trans_gz_bz2.py` which
uses normand.parse() to compress some data D, and then decompresses the
result using the correct module and compares to D.

Change-Id: I31eb296fa9ba726ee9695cc1cf049abd7cabaf52
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Reviewed-on: https://review.lttng.org/c/normand/+/11030
Tested-by: jenkins <jenkins@lttng.org>
6 months agoParse comments between tokens v0.20.0
Philippe Proulx [Tue, 10 Oct 2023 23:14:52 +0000 (19:14 -0400)] 
Parse comments between tokens

This patch replaces many whitespace parsing between the individual
tokens of an item by whitespace and comment parsing.

This makes it possible to comment out parts of items:

    aa bb cc @#32#64#~ffh# 88

Result:

    aa bb cc 00 00 00 00 00 88

Moreover, insignificant symbols are only supported between and around
items, hexadecimal nibbles, and binary bits now. This is where they're
the most useful to improve readability, not between tokens of an item.
For example, this is not useful:

    s/:?latin1,"hello world"=*|5

The new `tests/pass-comment-all.nt` file tests comments in all positions
between eligible tokens.

Change-Id: I7167440723010c2549f614fc6ab41621df0fd8b4
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Reviewed-on: https://review.lttng.org/c/normand/+/11020
Tested-by: jenkins <jenkins@lttng.org>
6 months agoAdd many string features v0.19.0
Philippe Proulx [Tue, 10 Oct 2023 18:03:30 +0000 (14:03 -0400)] 
Add many string features

This patch improves the string features of Normand.

Specifically, this patch:

• Adds support for the Latin-1 to Latin-10 string encodings:

      s:latin1"bonne journée!"

      62 6f 6e 6e 65 20 6a 6f  75 72 6e e9 65 21  ┆ bonne journ•e!

  The `s:` prefix is needed and also works with existing UTF encoding
  names:

      s:u32le "yo la gang 👋"

• Adds the variable string item.

  The syntax is one of:

      u16le{some_expr}

      {some_expr : s:u16le}

  Any `bool`, `int`, `float`, or `str` variable/label is accepted in the
  expression.

  For the suffix encoding form, the `s:` prefix is required.

• Makes it possible to use a string, possibly literal, as a macro
  expansion parameter:

      m:meow(42, "mix")

• Adds the `--var-str` CLI option to add a variable having a string
  value:

      normand '--var-str=my_var=salut la gang' [...]

See the updated `README.adoc` for more details.

Adding tests and updating existing ones.

Change-Id: I01426bb5ffa53097bb8c85937f54f1b4b498ec06
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Reviewed-on: https://review.lttng.org/c/normand/+/11019
Tested-by: jenkins <jenkins@lttng.org>
6 months agoCLI: --var/--label: accept the usual int./floating point number form v0.18.0
Philippe Proulx [Mon, 9 Oct 2023 14:06:58 +0000 (10:06 -0400)] 
CLI: --var/--label: accept the usual int./floating point number form

This patch makes the `--var` and `--label` options accept the usual
constant integer and floating point number (just for `--var`) forms of
the Normand language.

For example:

    --var=meow=-45.2e17
    --label=zoom=15ABh
    --var=mix=0b11010010

Also adding the `-v` short option for `--var` and accepting whitespaces
around the `=` of a `--var`/`--label` argument.

Change-Id: I3ecb1e85a68168e2304f550d48fdc6ccd447a706
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Reviewed-on: https://review.lttng.org/c/normand/+/11018
Tested-by: jenkins <jenkins@lttng.org>
6 months agoAllow constant floating point numbers as macro expansion parameter v0.17.0
Philippe Proulx [Sun, 8 Oct 2023 20:41:11 +0000 (16:41 -0400)] 
Allow constant floating point numbers as macro expansion parameter

Change-Id: I695ff0a5b41cf61f20b0ac237149bc4801e23fea
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Reviewed-on: https://review.lttng.org/c/normand/+/11017
Tested-by: jenkins <jenkins@lttng.org>
6 months agoMake it possible to specify more that one byte with `%` v0.16.0
Philippe Proulx [Fri, 6 Oct 2023 20:52:52 +0000 (16:52 -0400)] 
Make it possible to specify more that one byte with `%`

This patch makes it possible to specify more than one consecutive bytes
in binary by using two or more `%` prefixes. The number of `%` indicates
the number of subsequent bytes.

This makes it possible to put a 32-bit binary constant, for example,
without any delimiter. Instead of:

    %11011101 %11110010 %01001101 %11101101

you may write:

    %%%%11011101111100100100110111101101

I don't have a choice to use something (number of `%` here) to indicate
the number of bytes after that because this won't work:

    %11011101111100100100110111101101

This last example is equivalent to:

    %11011101 11 11 00 10 01 00 11 01 11 10 11 01

which really is 13 bytes.

This patch also fixes `normand.py` for Python 3.4.

Change-Id: I4945c9fc5925ab7a32c9015c41b6593db893cdd3
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
6 months agoREADME.adoc: add "Design goals" section
Philippe Proulx [Fri, 6 Oct 2023 19:39:48 +0000 (15:39 -0400)] 
README.adoc: add "Design goals" section

Change-Id: I197a5d4eefc6d3950ad685651c7f66ffd76030b1
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
6 months agoREADME.adoc: fix IEEE 754-2008 link
Philippe Proulx [Fri, 6 Oct 2023 18:15:17 +0000 (14:15 -0400)] 
README.adoc: fix IEEE 754-2008 link

Change-Id: I728f2eb9476656382f8771d5325bd93e4dd8477d
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
6 months agoREADME.adoc: add missing "filling" item in enumeration
Philippe Proulx [Fri, 6 Oct 2023 18:09:37 +0000 (14:09 -0400)] 
README.adoc: add missing "filling" item in enumeration

Change-Id: I1df2cc6c1699172d827e42f75f39bb8e940b92bb
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
6 months agoMake `normand.ParseError` contain a list of messages v0.15.0
Philippe Proulx [Fri, 6 Oct 2023 15:24:53 +0000 (11:24 -0400)] 
Make `normand.ParseError` contain a list of messages

A `normand.ParseError` instance now contains a list of
`normand.ParseErrorMessage`.

A `normand.ParseErrorMessage` instance contains a message text and a
source text location.

This adds precious context to a parsing error.

For example, with

    !macro meow(yeah)
      {yeah:8}
    !end

    !macro mix(yeah)
      aa bb m:meow({yeah * 2})
    !end

    m:mix(12)
    "hello" m:mix(899)
    m:mix(16)
    m:mix(19)

we now get

    10:9 - While expanding the macro `mix`:
    6:9 - While expanding the macro `meow`:
    2:4 - Value 1,798 is outside the 8-bit range when evaluating
          expression `yeah`

Without this patch, the only available message would be the last one,
and you wouldn't know which macro expansion(s) triggered the parsing
error.

The CLI and `tests/conftest.py` are modified to take multiple parsing
error messages into account.

There was a little challenge with fixed-length number item instances
handled after the rest (in _Gen._gen_fl_num_item_insts()): at this
point, there's no current try/except context for macro expansions
because they're already handled. My current strategy is to keep a
current stack of parsing error messages (`self._parse_error_msgs`)
during the generation: when the generator initially fails to evaluate
the expression of a fixed-length number item, it copies a snapshot of
those messages to the `_FlNumItemInst` object so that we can restore
them if there's a parsing error later during
_Gen._gen_fl_num_item_insts().

Adding two nested macro expansion test to make sure we get all the
expected parsing error messages. Other tests are unchanged (single
parsing error message).

Change-Id: Iba8499608f86165e02d6d040795222cafcbca4a9
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
6 months agoAdd `!else` support for conditional block v0.14.0
Philippe Proulx [Thu, 5 Oct 2023 20:57:57 +0000 (16:57 -0400)] 
Add `!else` support for conditional block

This patch adds the support of `!else` within an `!if` context:

    !if something
      11 22 33
    !else
      44 55 66
    !end

This is just equivalent to:

    !if something
      11 22 33
    !end

    !if {not something}
      44 55 66
    !end

but more readable/natural.

Change-Id: I0efa68a65c485d7dbf8124cd51fc5ed3c1ac9f46
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
6 months agoAccept many more prefixes and suffixes for a constant integer v0.13.0
Philippe Proulx [Thu, 5 Oct 2023 04:31:07 +0000 (00:31 -0400)] 
Accept many more prefixes and suffixes for a constant integer

This patch makes Normand accept the `0o`/`0O` and `0b`/`0B` prefixes for
a constant integer, as well as the `h`/`H`/`q`/`Q`/`o`/`O`/`b`/`B`
suffixes.

Those suffixes are common in tools such as MASM [1]:

> You can also specify hexadecimal numbers by adding an h after the
> number. You can use uppercase or lowercase letters within numbers. For
> example, "0x4AB3", "0X4aB3", "4AB3h", "4ab3h", and "4aB3H" have the
> same meaning.

as well as NASM [2]:

> NASM allows you to specify numbers in a variety of number bases, in a
> variety of ways: you can suffix `H`, `Q` or `O`, and `B` for hex,
> octal, and binary, or you can prefix `0x` for hex in the style of C,
> [...]

This constant integer form is available anywhere outside a Python
expression string, for example:

    55 * 28Fh

    +0o755~11010001b

    m:my_macro(-126q, 0b101)

Internally, the _norm_const_int() function transforms any suffix form
into a Python prefix form (for int()), keeping the negative `-` if
present.

[1]: https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/masm-numbers-and-operators
[2]: https://www.tortall.net/projects/yasm/manual/html/nasm-const.html

Change-Id: I708494e84080b9f4292397c6a81e67e335d330cd
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
6 months agoAdd "fill until" support v0.12.0
Philippe Proulx [Thu, 5 Oct 2023 01:30:36 +0000 (21:30 -0400)] 
Add "fill until" support

This patch adds an item to add bytes until some offset is reached:

    89 89 aa ff cc dd +0x3c {ICITTE:8}

Result:

    89 89 aa ff cc dd 00 00  00 00 00 00 00 00 00 00  ┆ ••••••••••••••••
    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ┆ ••••••••••••••••
    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ┆ ••••••••••••••••
    00 00 00 00 00 00 00 00  00 00 00 00 3c           ┆ ••••••••••••<

The item forms are:

    +EXPR
    +EXPR~PAD

where EXPR is a positive constant integer, a name, or an expression
between `{` and `}`, and PAD is a positive constant integer padding byte
value (0 by default).

The item `+EXPR~PAD` is functionally equivalent to
`PAD * {(EXPR) - ICITTE}`: it's just an alias for what I think is a
common operation.

For example, you might only want to write the first few fields of some
header:

    {le}
    "FRMT"          # Magic
    {0x7855:32}     # Total pixel count
    {data_beg:32}   # Data beginning pointer
    +0x80

    <data_beg>
    "the pixels"    # Here they are

Result:

    46 52 4d 54 55 78 00 00  80 00 00 00 00 00 00 00  ┆ FRMTUx••••••••••
    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ┆ ••••••••••••••••
    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ┆ ••••••••••••••••
    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ┆ ••••••••••••••••
    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ┆ ••••••••••••••••
    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ┆ ••••••••••••••••
    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ┆ ••••••••••••••••
    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ┆ ••••••••••••••••
    74 68 65 20 70 69 78 65  6c 73                    ┆ the pixels

Change-Id: Ibd3a2bd243c15e1d4f9a9d5b5aa0076e19f9f9f7
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
6 months agoAdd macro support v0.11.0
Philippe Proulx [Wed, 4 Oct 2023 14:14:33 +0000 (10:14 -0400)] 
Add macro support

This patch makes Normand support macro definitions and macro expansions.

The macro system doesn't support recursion, and to expand a given macro
by name, it needs to be already defined.

A macro definition may only exist at the root level, not within a group
(including not within a repetition, condition, or other macro definition
which all have implicit groups). The form is:

    !macro name(a, b, c)
        ...
    !end

Parameters are optional, but you always need the parentheses after the
macro name.

Parameter names must be unique for a given macro definition.

A parameter becomes a variable for the items of the macro group.

A macro expansion has the form:

    m:name(1, 2, 3)

Again, you always need the parentheses.

To expand a macro, its definition needs to exist completely before (no
recursion).

A parameter value is one of:

* A constant integer.
* A variable/label name.
* An expression between `{` and `}`.

The initial state of a macro expansion is:

Current offset:
    Copied

Current byte order:
    Copied

Variables:
    Parameter values (using parameter names)

Labels:
    None

The final state, after handling a macro expansion, is:

Current offset:
    Incremented by the size of the generated macro expansion data,
    _not_ its final current offset.

Current byte order:
    The one before the expansion.

Variables:
    The ones before the expansion.

Labels:
    The ones before the expansion.

Change-Id: I493c89009d7f7ce61b22f04e70881b253429c3b8
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
6 months agoAdd the directive form of a group (`!group`) v0.10.0
Philippe Proulx [Mon, 2 Oct 2023 16:02:02 +0000 (12:02 -0400)] 
Add the directive form of a group (`!group`)

This is to add some consistency regarding items which may contain other
items: I want all of them to have an available `!xyz` form.

Normand already has `!if` and `!repeat`, not it has `!group` (and the
alias `!g`).

The following two groups are equivalent:

    (
      aa bb cc
    ) * 5

    !group
      aa bb cc
    !end * 5

Change-Id: I00b2789c078c9b9216ab9b732bc3adeff39b0642
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
6 months agoAdd conditional block parsing failure tests
Philippe Proulx [Mon, 2 Oct 2023 15:55:48 +0000 (11:55 -0400)] 
Add conditional block parsing failure tests

Change-Id: I49da1387c68b2a521050b449ffe93c00d80f5e87
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
6 months agoAdd conditional block support v0.9.0
Philippe Proulx [Mon, 2 Oct 2023 04:28:01 +0000 (00:28 -0400)] 
Add conditional block support

This patch adds the `!if` directive to support conditional blocks.

A conditional block is functionally equivalent to a repetition block
when casting the expression to `bool`:

    !if {meow + mix > 32}
      # ...
    !end

    !repeat {meow + mix > 32}
      # ...
    !end

In other words, a conditional block is a repetition of its contained
items zero or one time.

The expression of a fixed-length number, an LEB128 integer, a variable
assignment, and a repetition may now evaluate to a `bool` value: Normand
converts it to `int` (0 or 1) automatically.

Change-Id: I3b686a3196d1ea8daa5741e78320c031b40abc00
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
6 months agoAdd the directive form of a repetition (`!repeat`) v0.8.0
Philippe Proulx [Mon, 2 Oct 2023 03:33:09 +0000 (23:33 -0400)] 
Add the directive form of a repetition (`!repeat`)

This patch introduces the first directive amongst other ones I'd like to
add later.

`!repeat` is equivalent to what's now called the post-item repetition
form:

    aa (bb cc dd) * 3 ee ff

    aa
    !repeat 3
      bb cc dd
    !end
    ff

`!repeat` (or the shorter `!r` alias) accepts exactly what's accepted
after a `*`: a constant integer, an expression, and (new) a name.

Obviously, the `!` symbol isn't considered a comment anymore.

See `README.adoc` and the new tests to learn more.

This patch also:

* Makes it legal to refer to the special `ICITTE` name within a
  repetition count expression.

  It's less natural for the post-item form, but it works nevertheless.

* Decouples the variables and labels dictionary types as `VariablesT`
  and `LabelsT`. Indeed, a variable value is (for the moment) an `int`
  or `float` instance, while a label value is always an integer (because
  it's an offset snapshot).

Change-Id: I77cd4c9f29639082612534940c48964a61e51392
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
7 months agoREADME.adoc: "an current offset" -> "a current offset"
Philippe Proulx [Sun, 1 Oct 2023 02:29:22 +0000 (22:29 -0400)] 
README.adoc: "an current offset" -> "a current offset"

Change-Id: If7bc2a399d99d06be98bafc12d3d7f9808e0e2b5
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
7 months agoAdd offset alignment support v0.7.0
Philippe Proulx [Sun, 1 Oct 2023 02:13:50 +0000 (22:13 -0400)] 
Add offset alignment support

This patch adds a new item which is meant to update the current offset
so that it satisfies a given alignment.

The form is:

    @32
    @64~39
    @16~0xcc

What follows `@` is the alignment value in bits (any multiple of eight
greater than zero). The optional part starting with `~` is the value of
the padding bytes to add to satisfy the alignment requirement.

See the new tests and the `README.adoc` examples to learn more.

`@` used to be an insignificant symbol, but it's not anymore (not
consider as a comment).

Also fixing missing repr() calls at some places.

Change-Id: I9f5ac1da6988c060391640bf2784567a76e9fc48
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
7 months agotests/test_api.py: apply Black and Pyright
Philippe Proulx [Fri, 29 Sep 2023 20:34:21 +0000 (16:34 -0400)] 
tests/test_api.py: apply Black and Pyright

Change-Id: I5f15a309a0ff0c79717f46461fb3b4aaca7af5b0
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
7 months agoFix: normand.py: update `SymbolsT` to accept `float` value v0.6.2
Philippe Proulx [Fri, 29 Sep 2023 20:33:28 +0000 (16:33 -0400)] 
Fix: normand.py: update `SymbolsT` to accept `float` value

Change-Id: I3cc65f7452458c9ebdb03e1ef8c615af279fcbb3
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
7 months agoAdd basic API tests
Philippe Proulx [Fri, 29 Sep 2023 20:28:35 +0000 (16:28 -0400)] 
Add basic API tests

Change-Id: I4c1aeac08e7da9b350b1a49baf460969a1e67a06
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
7 months agoFix: normand.py: accept floating point number variable v0.6.1
Philippe Proulx [Fri, 29 Sep 2023 20:20:04 +0000 (16:20 -0400)] 
Fix: normand.py: accept floating point number variable

Change-Id: I6681cedabaaf458245bfa72495c7619960d260da
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
7 months agoAdd fixed-length floating point number support v0.6.0
Philippe Proulx [Fri, 29 Sep 2023 19:30:49 +0000 (15:30 -0400)] 
Add fixed-length floating point number support

This patch adds support to encode binary32 and binary64 (as per
IEEE 754-2008) floating point numbers, big and little endian.

The Normand form is the same as a fixed-length integer:

    { 32.87 : 32 }

The type of the result of the evaluation determines how to encode it:
integer or floating point number.

Some "fixed-length integer" terms are changed to "fixed-length number"
when they're meant to be general.

With this patch, you may also assign a variable to a floating point
number value. However, the result type of an LEB128 integer or
repetition count expression must still be `int`.

Change-Id: Ic13ed747276a365ed2fd8854545ab2b0e1c343a0
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
7 months agoREADME.adoc: add missing "Output:" paragraph
Philippe Proulx [Fri, 29 Sep 2023 18:11:16 +0000 (14:11 -0400)] 
README.adoc: add missing "Output:" paragraph

Change-Id: If49b43a25eb9681e30f4cdbe1862679866cc8422
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
7 months agoREADME.adoc: use the correct `python3-api` section ID
Philippe Proulx [Fri, 29 Sep 2023 18:09:15 +0000 (14:09 -0400)] 
README.adoc: use the correct `python3-api` section ID

Change-Id: Ic1d24284a71e19e075ab7b66e22c75290a1aed19
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
7 months agoRename `normand.VarsT` to `normand.SymbolsT` v0.5.0
Philippe Proulx [Fri, 29 Sep 2023 18:06:24 +0000 (14:06 -0400)] 
Rename `normand.VarsT` to `normand.SymbolsT`

This term is more general and applies to both labels and variables.

Change-Id: Iad4d72fa1cf26b934d04ebd014acf51b6881c817
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
7 months agoAdd LEB128 integer support v0.4.0
Philippe Proulx [Fri, 29 Sep 2023 17:10:59 +0000 (13:10 -0400)] 
Add LEB128 integer support

This patch adds unsigned and signed LEB128 [1] integer support with the
following Normand format:

    {my_val : uleb128}
    {my_val : sleb128}

LEB128 is a popular variable-length integer encoding which has
CTF 2 [2], Android, HP, DWARF, WebAssembly, the xz format, and many more
as its users.

To avoid any confusion, the term "value" in the Normand project is
renamed to "fixed-length integer" (`README.adoc`, test names, and the
code itself).

The challenge for a LEB128 item is similar to a repetition with an
expression: you don't know the final length when parsing because it can
depend on preceding labels and variables. Therefore the repetition item
validation and handling code is reused.

The new test files with names containing `-byte` were randomly generated
using the `leb128` package, therefore Normand agrees with another LEB128
implementation.

[1]: https://en.wikipedia.org/wiki/LEB128
[2]: https://diamon.org/ctf/

Change-Id: Ieac783dcdd093e1b5c70396a12fc2b568c9885bb
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
7 months agoAdd initial tests
Philippe Proulx [Wed, 27 Sep 2023 19:24:06 +0000 (15:24 -0400)] 
Add initial tests

The tests are meant to be run by pytest (just run `pytest` in the root
or `tests` directory once Normand is installed).

Each `.nt` file is a test, its prefix indicating the expectation:

`pass-`:
    Everything above the `---` line is the valid Normand input
    to test.

    Everything below the `---` line is the expected data
    (whitespace-separated hexadecimal bytes).

`fail-`:
    Everything above the `---` line is the invalid Normand input
    to test.

    Everything below the `---` line is the expected error message
    having this form:

        LINE:COL - MESSAGE

Change-Id: I65c0276f418c252735f75e583023772194b9eb4a
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
7 months agoAdd variable repetition count support v0.3.0
Philippe Proulx [Thu, 28 Sep 2023 20:34:38 +0000 (16:34 -0400)] 
Add variable repetition count support

This patch makes it possible to do this:

    {meow = 23}
    aa <lbl> bb (cc dd) * {9 * meow + lbl} ff

The repetition count expression cannot refer to a "future" label name,
to an inner label name, or to any variable of which the value was
computed using, directly or indirectly, one of those labels.

For example, this is invalid:

    aa
    {meow = mix}
    {zoom = meow}
    bb * {zoom}
    <mix>

However this is valid:

    aa
    {meow = mix}
    {zoom = meow}
    {meow = 23}
    bb * {meow}
    <mix>

An interesting side effect of this feature is to make Normand support
conditional sections by using zero vs. one repetition:

    (
      <beg>
      aa bb cc dd
      <end>
      {include = int(beg >= 4 * (end - beg))}
      (11 22 33 44) * {include}
    ) * 10

Result:

    aa bb cc dd aa bb cc dd  aa bb cc dd aa bb cc dd  ┆ ••••••••••••••••
    aa bb cc dd 11 22 33 44  aa bb cc dd 11 22 33 44  ┆ •••••"3D•••••"3D
    aa bb cc dd 11 22 33 44  aa bb cc dd 11 22 33 44  ┆ •••••"3D•••••"3D
    aa bb cc dd 11 22 33 44  aa bb cc dd 11 22 33 44  ┆ •••••"3D•••••"3D

This becomes interesting with externally-provided variables, for
example:

    aa bb cc dd
    (beef) * {has_beef}
    "salut"

You may include or exclude the `be ef` bytes with `--var=has_beef=1` and
`--var=has_beef=0` (or the equivalent API way).

Also update the `README.adoc` usage and examples.

Change-Id: I8cd8aa7078cbe48038b00c541aa40a067c9f79bf
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
7 months agoFix: _dict_from_arg(): actually fill the dictionary v0.2.1
Philippe Proulx [Fri, 29 Sep 2023 05:00:22 +0000 (01:00 -0400)] 
Fix: _dict_from_arg(): actually fill the dictionary

Change-Id: Ib86c8df44986eeec5b45908bce2d15c44d053d99
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
7 months agonormand.py: add comment about the portable module
Philippe Proulx [Thu, 28 Sep 2023 01:02:05 +0000 (21:02 -0400)] 
normand.py: add comment about the portable module

Change-Id: I8e7792f0864bdb0c7786eabcc0a46e00122734b7
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
7 months agoMake text locations of some items and errors more precise v0.2.0
Philippe Proulx [Wed, 27 Sep 2023 21:36:32 +0000 (17:36 -0400)] 
Make text locations of some items and errors more precise

Using the text location before parsing the item instead of after it
feels more natural.

Change-Id: I0390d3885bf388e1d3ac37e8520ca1894de8474b
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
7 months agoFix: parse a 0-item repetition v0.1.1
Philippe Proulx [Wed, 27 Sep 2023 17:59:58 +0000 (13:59 -0400)] 
Fix: parse a 0-item repetition

Change-Id: I89d3d01db51a78a0ff543650d95486208eb91d26
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
7 months agoAdd `.gitreview`
Philippe Proulx [Wed, 27 Sep 2023 16:53:15 +0000 (12:53 -0400)] 
Add `.gitreview`

Change-Id: I4e21512c102ab4d4f150fce2a789da330295f11e
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
7 months agoREADME.adoc: add logo
Philippe Proulx [Wed, 27 Sep 2023 16:45:38 +0000 (12:45 -0400)] 
README.adoc: add logo

Change-Id: I039e3a475101c79699891687c7843936f2c456ff
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
7 months agoREADME.adoc: remove redundant internal links
Philippe Proulx [Tue, 26 Sep 2023 22:38:10 +0000 (18:38 -0400)] 
README.adoc: remove redundant internal links

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
7 months agoREADME.adoc: make it work offline too
Philippe Proulx [Tue, 26 Sep 2023 22:37:54 +0000 (18:37 -0400)] 
README.adoc: make it work offline too

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
7 months agoThe earliest commit (also Normand 0.1.0) v0.1.0
Philippe Proulx [Mon, 25 Sep 2023 21:16:28 +0000 (17:16 -0400)] 
The earliest commit (also Normand 0.1.0)

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
This page took 0.035959 seconds and 4 git commands to generate.