Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.20)
# Keep this version in sync with [project] version in pyproject.toml.
project(neml2-hit VERSION 0.3.5 LANGUAGES CXX)
project(neml2-hit VERSION 0.3.6 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,9 @@ Only `param_str()` (and its `param_optional_str` variant) is allowed.

A whitespace-delimited sequence of elements enclosed in single quotes **or double quotes** —
both delimiters are completely equivalent. Elements may be integers, floating-point numbers, or unquoted tokens
(none of which may contain `;`, `#`, `$`, `'`, `"`, or `\`).
(none of which may contain `;`, `#`, `$`, `'`, or `"`). Backslashes **are** permitted inside
quoted values, so a single-element quoted string can hold a Windows path, e.g.
`path = 'C:\Users\me\model'`. (Unquoted values still exclude `\` — quote such paths.)

```
vals = '1 2 3'
Expand Down Expand Up @@ -613,6 +615,9 @@ Pre-generated parser/lexer sources are committed to `generated/` and used
automatically for non-Debug build types, so end users and CI release builds do
not need flex or bison installed.

nmhit builds and is tested on **Linux, macOS, and Windows**, with GCC, Clang,
or MSVC. Windows uses the Visual Studio generator (no developer shell needed).

### Configure and build

**Release build** (no flex or bison required — uses committed generated sources):
Expand Down
268 changes: 133 additions & 135 deletions generated/Lexer.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"

[project]
name = "nmhit"
version = "0.3.5" # Keep in sync with VERSION in CMakeLists.txt.
version = "0.3.6" # Keep in sync with VERSION in CMakeLists.txt.
description = "Python bindings for the nmhit NEML2-flavored HIT parser"
readme = "README.md"
requires-python = ">=3.9"
Expand Down
11 changes: 11 additions & 0 deletions python/tests/test_nmhit.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,17 @@ def test_parse_file_pre_kwarg(tmp_path):
assert root.param_int("a") == 1


def test_backslash_path_in_quoted_string():
"""Backslashes survive inside quoted strings, so Windows paths parse.

A single backslash in the HIT text is written here with a raw string. The
value has no spaces because both quote styles tokenise as arrays and
whitespace still separates elements.
"""
root = nmhit.parse_text(r"path = 'C:\Users\me\model'")
assert root.param_str("path") == r"C:\Users\me\model"


# ── find / children ───────────────────────────────────────────────────────────


Expand Down
4 changes: 2 additions & 2 deletions src/Lexer.l
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ COMMENT #[^\n]*
<IN_ARRAY>"${" { DRIVER->begin_brace(); DRIVER->set_yymore(); yymore(); BEGIN(IN_ARRAY_BRACE); }
<IN_ARRAY>{FLOAT} { TOK_S(TOK_FLOAT); }
<IN_ARRAY>{INTEGER} { TOK_S(TOK_INTEGER); }
<IN_ARRAY>[^ \t\n\r;#$'"\\]+ { TOK_S(TOK_ARRAY_ELEM); }
<IN_ARRAY>[^ \t\n\r;#$'"]+ { TOK_S(TOK_ARRAY_ELEM); }
<IN_ARRAY>. { DRIVER->lex_error(yytext, yylineno); }

<IN_ARRAY_BRACE>"${" { DRIVER->begin_brace(); DRIVER->set_yymore(); yymore(); }
Expand All @@ -124,7 +124,7 @@ COMMENT #[^\n]*
<IN_DARRAY>"${" { DRIVER->begin_brace(); DRIVER->set_yymore(); yymore(); BEGIN(IN_DARRAY_BRACE); }
<IN_DARRAY>{FLOAT} { TOK_S(TOK_FLOAT); }
<IN_DARRAY>{INTEGER} { TOK_S(TOK_INTEGER); }
<IN_DARRAY>[^ \t\n\r;#$'"\\]+ { TOK_S(TOK_ARRAY_ELEM); }
<IN_DARRAY>[^ \t\n\r;#$'"]+ { TOK_S(TOK_ARRAY_ELEM); }
<IN_DARRAY>. { DRIVER->lex_error(yytext, yylineno); }

<IN_DARRAY_BRACE>"${" { DRIVER->begin_brace(); DRIVER->set_yymore(); yymore(); }
Expand Down
12 changes: 12 additions & 0 deletions tests/test_hit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,18 @@ main()
EXPECT(a1 == a2);
});

run("backslash_path_in_quotes", []() {
// Backslashes must survive inside quoted strings so Windows paths are
// representable. Both quote styles tokenise as arrays, so the value has no
// spaces (whitespace still separates array elements). The C++ literals
// below use \\ per source escaping; the HIT text and parsed value each hold
// single backslashes.
auto sq = p("path = 'C:\\Users\\me\\model'");
EXPECT(sq->param<std::string>("path") == "C:\\Users\\me\\model");
auto dq = p("path = \"C:\\Users\\me\\model\"");
EXPECT(dq->param<std::string>("path") == "C:\\Users\\me\\model");
});

// ── 2. Bool values ────────────────────────────────────────────────────────

run("bool_true", []() {
Expand Down
Loading