Skip to content

Commit bb3fbcc

Browse files
authored
Merge pull request #818 from davidgiven/convert
Add a fe-convert (plus all the necessary backend work).
2 parents c8edcd9 + 8b6073c commit bb3fbcc

File tree

182 files changed

+27938
-359
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

182 files changed

+27938
-359
lines changed

.github/workflows/ccpp.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
path: 'fluxengine-testdata'
2121
- name: apt
2222
run: |
23-
sudo apt install libudev-dev libsqlite3-dev protobuf-compiler libwxgtk3.0-gtk3-dev libfmt-dev libprotobuf-dev wx-common
23+
sudo apt install libudev-dev libsqlite3-dev protobuf-compiler libwxgtk3.0-gtk3-dev libfmt-dev libprotobuf-dev
2424
- name: make
2525
run: CXXFLAGS="-Wp,-D_GLIBCXX_ASSERTIONS" make -j`nproc` -C fluxengine
2626

Makefile

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ ifeq ($(BUILDTYPE),windows)
2525
EXT = .exe
2626
else
2727
CC = gcc
28-
CXX = g++ -std=c++17
29-
CFLAGS = -g -O3
28+
CXX = g++ -std=c++20
29+
CFLAGS = -g -O3 \
30+
-Wno-deprecated-enum-float-conversion \
31+
-Wno-deprecated-enum-enum-conversion
3032
LDFLAGS =
3133
AR = ar
3234
PKG_CONFIG = pkg-config
@@ -37,7 +39,7 @@ else
3739
endif
3840

3941
HOSTCC = gcc
40-
HOSTCXX = g++ -std=c++17
42+
HOSTCXX = g++ -std=c++20
4143
HOSTCFLAGS = -g -O3
4244
HOSTLDFLAGS =
4345

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ choices because they can store multiple types of file system.
137137
| [`rx50`](doc/disk-rx50.md) | Digital RX50: 400kB 5.25" 80-track 10-sector SSDD | 🦖 | 🦖 | |
138138
| [`smaky6`](doc/disk-smaky6.md) | Smaky 6: 308kB 5.25" 77-track 16-sector SSDD, hard sectored | 🦖 | | SMAKY6 |
139139
| [`tartu`](doc/disk-tartu.md) | Tartu: The Palivere and variations | 🦄 | 🦖 | CPMFS |
140+
| [`ti99`](doc/disk-ti99.md) | TI-99: 90kB 35-track SSSD | 🦖 | | |
140141
| [`tids990`](doc/disk-tids990.md) | Texas Instruments DS990: 1126kB 8" DSSD | 🦖 | 🦖 | |
141142
| [`tiki`](doc/disk-tiki.md) | Tiki 100: CP/M | | | CPMFS |
142143
| [`victor9k`](doc/disk-victor9k.md) | Victor 9000 / Sirius One: 1224kB 5.25" DSDD GCR | 🦖 | 🦖 | |
@@ -258,6 +259,10 @@ package, written by Robert Leslie et al, taken from
258259
https://www.mars.org/home/rob/proj/hfs. It is GPL 2.0 licensed. Please see the
259260
contents of the directory for the full text.
260261

262+
As an exception, `dep/lexy` contains a partial copy of the lexy package, written
263+
by foonathen@github, taken from https://github.com/foonathan/lexy. It is BSL 1.0
264+
licensed. Please see the contents of the directory for the full text.
265+
261266
__Important:__ Because of all these exceptions, if you distribute the
262267
FluxEngine package as a whole, you must comply with the terms of _all_ of the
263268
licensing terms. This means that __effectively the FluxEngine package is

dep/lexy/LICENSE

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
Boost Software License - Version 1.0 - August 17th, 2003
2+
3+
Permission is hereby granted, free of charge, to any person or organization
4+
obtaining a copy of the software and accompanying documentation covered by
5+
this license (the "Software") to use, reproduce, display, distribute,
6+
execute, and transmit the Software, and to prepare derivative works of the
7+
Software, and to permit third-parties to whom the Software is furnished to
8+
do so, all subject to the following:
9+
10+
The copyright notices in the Software and this entire statement, including
11+
the above license grant, this restriction and the following disclaimer,
12+
must be included in all copies of the Software, in whole or in part, and
13+
all derivative works of the Software, unless such copies or derivative
14+
works are solely in the form of machine-executable object code generated by
15+
a source language processor.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
20+
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
21+
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
22+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23+
DEALINGS IN THE SOFTWARE.

dep/lexy/README.adoc

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
= lexy
2+
3+
ifdef::env-github[]
4+
image:https://img.shields.io/endpoint?url=https%3A%2F%2Fwww.jonathanmueller.dev%2Fproject%2Flexy%2Findex.json[Project Status,link=https://www.jonathanmueller.dev/project/]
5+
image:https://github.com/foonathan/lexy/workflows/Main%20CI/badge.svg[Build Status]
6+
image:https://img.shields.io/badge/try_it_online-blue[Playground,link=https://lexy.foonathan.net/playground]
7+
endif::[]
8+
9+
lexy is a parser combinator library for {cpp}17 and onwards.
10+
It allows you to write a parser by specifying it in a convenient {cpp} DSL,
11+
which gives you all the flexibility and control of a handwritten parser without any of the manual work.
12+
13+
ifdef::env-github[]
14+
*Documentation*: https://lexy.foonathan.net/[lexy.foonathan.net]
15+
endif::[]
16+
17+
.IPv4 address parser
18+
--
19+
ifndef::env-github[]
20+
[.godbolt-example]
21+
.+++<a href="https://godbolt.org/z/scvajjE17", title="Try it online">{{< svg "icons/play.svg" >}}</a>+++
22+
endif::[]
23+
[source,cpp]
24+
----
25+
namespace dsl = lexy::dsl;
26+
27+
// Parse an IPv4 address into a `std::uint32_t`.
28+
struct ipv4_address
29+
{
30+
// What is being matched.
31+
static constexpr auto rule = []{
32+
// Match a sequence of (decimal) digits and convert it into a std::uint8_t.
33+
auto octet = dsl::integer<std::uint8_t>;
34+
35+
// Match four of them separated by periods.
36+
return dsl::times<4>(octet, dsl::sep(dsl::period)) + dsl::eof;
37+
}();
38+
39+
// How the matched output is being stored.
40+
static constexpr auto value
41+
= lexy::callback<std::uint32_t>([](std::uint8_t a, std::uint8_t b, std::uint8_t c, std::uint8_t d) {
42+
return (a << 24) | (b << 16) | (c << 8) | d;
43+
});
44+
};
45+
----
46+
--
47+
48+
== Features
49+
50+
Full control::
51+
* *Describe the parser, not some abstract grammar*:
52+
Unlike parser generators that use some table driven magic for parsing, lexy's grammar is just syntax sugar for a hand-written recursive descent parser.
53+
The parsing algorithm does exactly what you've instructed it to do -- no more ambiguities or weird shift/reduce errors!
54+
* *No implicit backtracking or lookahead*:
55+
It will only backtrack when you say it should, and only lookahead when and how far you want it.
56+
Don't worry about rules that have side-effects, they won't be executed unnecessarily thanks to the user-specified lookahead conditions.
57+
https://lexy.foonathan.net/playground?example=peek[Try it online].
58+
* *Escape hatch for manual parsing*:
59+
Sometimes you want to parse something that can't be expressed easily with lexy's facilities.
60+
Don't worry, you can integrate a hand-written parser into the grammar at any point.
61+
https://lexy.foonathan.net/playground/?example=scan[Try it online].
62+
* *Tracing*:
63+
Figure out why the grammar isn't working the way you want it to.
64+
https://lexy.foonathan.net/playground/?example=trace&mode=trace[Try it online].
65+
66+
Easily integrated::
67+
* *A pure {cpp} DSL*:
68+
No need to use an external grammar file; embed the grammar directly in your {cpp} project using operator overloading and functions.
69+
* *Bring your own data structures*:
70+
You can directly store results into your own types and have full control over all heap allocations.
71+
* *Fully `constexpr` parsing*:
72+
You want to parse a string literal at compile-time? You can do so.
73+
* *Minimal standard library dependencies*:
74+
The core parsing library only depends on fundamental headers such as `<type_traits>` or `<cstddef>`; no big includes like `<vector>` or `<algorithm>`.
75+
* *Header-only core library* (by necessity, not by choice -- it's `constexpr` after all).
76+
77+
ifdef::env-github[Designed for text::]
78+
ifndef::env-github[Designed for text (e.g. {{< github-example json >}}, {{< github-example xml >}}, {{< github-example email >}}) ::]
79+
* *Unicode support*: parse UTF-8, UTF-16, or UTF-32, and access the Unicode character database to query char classes or perform case folding.
80+
https://lexy.foonathan.net/playground?example=identifier-unicode[Try it online].
81+
* *Convenience*:
82+
Built-in rules for parsing nested structures, quotes and escape sequences.
83+
https://lexy.foonathan.net/playground?example=parenthesized[Try it online].
84+
* *Automatic whitespace skipping*:
85+
No need to manually handle whitespace or comments.
86+
https://lexy.foonathan.net/playground/?example=whitespace_comment[Try it online].
87+
88+
ifdef::env-github[Designed for programming languages::]
89+
ifndef::env-github[Designed for programming languages (e.g. {{< github-example calculator >}}, {{< github-example shell >}})::]
90+
* *Keyword and identifier parsing*:
91+
Reserve a set of keywords that won't be matched as regular identifiers.
92+
https://lexy.foonathan.net/playground/?example=reserved_identifier[Try it online].
93+
* *Operator parsing*:
94+
Parse unary/binary operators with different precedences and associativity, including chained comparisons `a < b < c`.
95+
https://lexy.foonathan.net/playground/?example=expr[Try it online].
96+
* *Automatic error recovery*:
97+
Log an error, recover, and continue parsing!
98+
https://lexy.foonathan.net/playground/?example=recover[Try it online].
99+
100+
ifdef::env-github[Designed for binary input::]
101+
ifndef::env-github[Designed for binary input (e.g. {{< github-example protobuf >}})::]
102+
* *Bytes*: Rules for parsing `N` bytes or Nbit big/little endian integer.
103+
* *Bits*: Rules for parsing individual bit patterns.
104+
* *Blobs*: Rules for parsing TLV formats.
105+
106+
== FAQ
107+
108+
Why should I use lexy over XYZ?::
109+
lexy is closest to other PEG parsers.
110+
However, they usually do more implicit backtracking, which can hurt performance and you need to be very careful with rules that have side-effects.
111+
This is not the case for lexy, where backtracking is controlled using branch conditions.
112+
lexy also gives you a lot of control over error reporting, supports error recovery, special support for operator precedence parsing, and other advanced features.
113+
114+
http://boost-spirit.com/home/[Boost.Spirit]:::
115+
The main difference: it is not a Boost library.
116+
In addition, Boost.Spirit is quite old and doesn't support e.g. non-common ranges as input.
117+
Boost.Spirit also eagerly creates attributes from the rules, which can lead to nested tuples/variants while lexy uses callbacks which enables zero-copy parsing directly into your own data structure.
118+
However, lexy's grammar is more verbose and designed to parser bigger grammars instead of the small one-off rules that Boost.Spirit is good at.
119+
https://github.com/taocpp/PEGTL[PEGTL]:::
120+
PEGTL is very similar and was a big inspiration.
121+
The biggest difference is that lexy uses an operator based DSL instead of inheriting from templated classes as PEGTL does;
122+
depending on your preference this can be an advantage or disadvantage.
123+
Hand-written Parsers:::
124+
Writing a handwritten parser is more manual work and error prone.
125+
lexy automates that away without having to sacrifice control.
126+
You can use it to quickly prototype a parser and then slowly replace more and more with a handwritten parser over time;
127+
mixing a hand-written parser and a lexy grammar works seamlessly.
128+
129+
How bad are the compilation times?::
130+
They're not as bad as you might expect (in debug mode, that is).
131+
+
132+
The example JSON parser compiles in about 2s on my machine.
133+
If we remove all the lexy specific parts and just benchmark the time it takes for the compiler to process the datastructure (and stdlib includes),
134+
that takes about 700ms.
135+
If we validate JSON only instead of parsing it, so remove the data structures and keep only the lexy specific parts, we're looking at about 840ms.
136+
+
137+
Keep in mind, that you can fully isolate lexy in a single translation unit that only needs to be touched when you change the parser.
138+
You can also split a lexy grammar into multiple translation units using the `dsl::subgrammar` rule.
139+
140+
How bad are the {cpp} error messages if you mess something up?::
141+
They're certainly worse than the error message lexy gives you.
142+
The big problem here is that the first line gives you the error, followed by dozens of template instantiations, which end at your `lexy::parse` call.
143+
Besides providing an external tool to filter those error messages, there is nothing I can do about that.
144+
145+
How fast is it?::
146+
Benchmarks are available in the `benchmarks/` directory.
147+
A sample result of the JSON validator benchmark which compares the example JSON parser with various other implementations is available https://lexy.foonathan.net/benchmark_json/[here].
148+
149+
Why is it called lexy?::
150+
I previously had a tokenizer library called foonathan/lex.
151+
I've tried adding a parser to it, but found that the line between pure tokenization and parsing has become increasingly blurred.
152+
lexy is a re-imagination on of the parser I've added to foonathan/lex, and I've simply kept a similar name.
153+
154+
ifdef::env-github[]
155+
== Documentation
156+
157+
The documentation, including tutorials, reference documentation, and an interactive playground can be found at https://lexy.foonathan.net/[lexy.foonathan.net].
158+
159+
A minimal `CMakeLists.txt` that uses lexy can look like this:
160+
161+
.`CMakeLists.txt`
162+
```cmake
163+
project(lexy-example)
164+
165+
include(FetchContent)
166+
FetchContent_Declare(lexy URL https://lexy.foonathan.net/download/lexy-src.zip)
167+
FetchContent_MakeAvailable(lexy)
168+
169+
add_executable(lexy_example)
170+
target_sources(lexy_example PRIVATE main.cpp)
171+
target_link_libraries(lexy_example PRIVATE foonathan::lexy)
172+
```
173+
174+
endif::[]
175+

dep/lexy/UPSTREAM.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
This is a heavily truncated copy of https://github.com/foonathan/lexy, commit
2+
20926cf.

dep/lexy/build.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from build.c import cxxlibrary
2+
from glob import glob
3+
4+
cxxlibrary(
5+
name="lexy",
6+
srcs=[],
7+
hdrs={
8+
h: f"./include/{h}"
9+
for h in glob("**/*.hpp", root_dir="dep/lexy/include", recursive=True)
10+
},
11+
)
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright (C) 2020-2025 Jonathan Müller and lexy contributors
2+
// SPDX-License-Identifier: BSL-1.0
3+
4+
#ifndef LEXY_DETAIL_ANY_REF_HPP_INCLUDED
5+
#define LEXY_DETAIL_ANY_REF_HPP_INCLUDED
6+
7+
#include <lexy/_detail/config.hpp>
8+
9+
// Essentially a void*, but we can cast it in a constexpr context.
10+
// The cost is an extra layer of indirection.
11+
12+
namespace lexy::_detail
13+
{
14+
template <typename T>
15+
class any_holder;
16+
17+
// Store a pointer to this instead of a void*.
18+
class any_base
19+
{
20+
public:
21+
any_base(const any_base&) = delete;
22+
any_base& operator=(const any_base&) = delete;
23+
24+
template <typename T>
25+
constexpr T& get() noexcept
26+
{
27+
return static_cast<any_holder<T>*>(this)->get();
28+
}
29+
template <typename T>
30+
constexpr const T& get() const noexcept
31+
{
32+
return static_cast<const any_holder<T>*>(this)->get();
33+
}
34+
35+
private:
36+
constexpr any_base() = default;
37+
~any_base() = default;
38+
39+
template <typename T>
40+
friend class any_holder;
41+
};
42+
43+
using any_ref = any_base*;
44+
using any_cref = const any_base*;
45+
46+
// Need to store the object in here.
47+
template <typename T>
48+
class any_holder : public any_base
49+
{
50+
public:
51+
constexpr explicit any_holder(T&& obj) : _obj(LEXY_MOV(obj)) {}
52+
53+
constexpr T& get() noexcept
54+
{
55+
return _obj;
56+
}
57+
constexpr const T& get() const noexcept
58+
{
59+
return _obj;
60+
}
61+
62+
private:
63+
T _obj;
64+
};
65+
} // namespace lexy::_detail
66+
67+
#endif // LEXY_DETAIL_ANY_REF_HPP_INCLUDED
68+
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright (C) 2020-2025 Jonathan Müller and lexy contributors
2+
// SPDX-License-Identifier: BSL-1.0
3+
4+
#ifndef LEXY_DETAIL_ASSERT_HPP_INCLUDED
5+
#define LEXY_DETAIL_ASSERT_HPP_INCLUDED
6+
7+
#include <lexy/_detail/config.hpp>
8+
9+
#ifndef LEXY_ENABLE_ASSERT
10+
11+
// By default, enable assertions if NDEBUG is not defined.
12+
13+
# if NDEBUG
14+
# define LEXY_ENABLE_ASSERT 0
15+
# else
16+
# define LEXY_ENABLE_ASSERT 1
17+
# endif
18+
19+
#endif
20+
21+
#if LEXY_ENABLE_ASSERT
22+
23+
// We want assertions: use assert() if that's available, otherwise abort.
24+
// We don't use assert() directly as that's not constexpr.
25+
26+
# if NDEBUG
27+
28+
# include <cstdlib>
29+
# define LEXY_PRECONDITION(Expr) ((Expr) ? void(0) : std::abort())
30+
# define LEXY_ASSERT(Expr, Msg) ((Expr) ? void(0) : std::abort())
31+
32+
# else
33+
34+
# include <cassert>
35+
36+
# define LEXY_PRECONDITION(Expr) ((Expr) ? void(0) : assert(Expr))
37+
# define LEXY_ASSERT(Expr, Msg) ((Expr) ? void(0) : assert((Expr) && (Msg)))
38+
39+
# endif
40+
41+
#else
42+
43+
// We don't want assertions.
44+
45+
# define LEXY_PRECONDITION(Expr) static_cast<void>(sizeof(Expr))
46+
# define LEXY_ASSERT(Expr, Msg) static_cast<void>(sizeof(Expr))
47+
48+
#endif
49+
50+
#endif // LEXY_DETAIL_ASSERT_HPP_INCLUDED
51+

0 commit comments

Comments
 (0)