MayaFlux 0.5.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
FieldSource.hpp
Go to the documentation of this file.
1#pragma once
2
3namespace MayaFlux::Kinesis {
4
5/**
6 * @struct FieldSource
7 * @brief Parsed representation of a stringified field lambda.
8 *
9 * Produced by MF_FIELD, which stringifies the lambda text at the call site.
10 * Shares an input shape with Portal::Graphics::KernelSource but not a consumer,
11 * and differs in one respect: the parameter list is retained verbatim rather
12 * than stripped to identifiers, because a field is emitted as a standalone GLSL
13 * function above main() where the signature needs types. KernelSource strips
14 * them because a main-injected body receives its operands as file-scope
15 * declarations.
16 *
17 * Nothing here knows about ShaderSpec. The four members map onto the four
18 * arguments of ShaderSpec::Assemble::function(), and that call happens at the
19 * site assembling a spec, which is above both Kinesis and Portal.
20 *
21 * @code
22 * auto spec = ShaderSpec::Assemble{}
23 * .ssbo("pos", BindingDirection::InOut, Kakshya::GpuDataFormat::VEC4_F32)
24 * .function(swirl.source.return_type, swirl.source.name,
25 * swirl.source.params, swirl.source.body)
26 * .kernel(MF_KERNEL(...))
27 * .build();
28 * @endcode
29 */
31 std::string name;
32 std::string return_type;
33 std::string params;
34 std::string body;
35
36 /**
37 * @brief Extract return type, parameter list and body from lambda text.
38 *
39 * Requires a trailing return type: the return type is read from between the
40 * arrow and the opening brace. A lambda without one yields an empty
41 * return_type, which valid() reports as a parse failure.
42 *
43 * @param fn_name Name the emitted GLSL function will carry.
44 * @param text Raw text produced by MF_FIELD.
45 * @return Populated FieldSource.
46 */
47 [[nodiscard]] static FieldSource parse(std::string fn_name, std::string_view text)
48 {
49 FieldSource fs;
50 fs.name = std::move(fn_name);
51
52 const auto bracket = text.find('[');
53 const auto paren_open = text.find('(', bracket);
54 if (paren_open == std::string_view::npos)
55 return fs;
56
57 std::size_t depth = 1;
58 std::size_t paren_close = paren_open + 1;
59 while (paren_close < text.size() && depth > 0) {
60 if (text[paren_close] == '(') {
61 ++depth;
62 } else if (text[paren_close] == ')') {
63 --depth;
64 }
65 ++paren_close;
66 }
67 --paren_close;
68
69 fs.params = std::string(text.substr(paren_open + 1, paren_close - paren_open - 1));
70
71 const auto arrow = text.find("->", paren_close);
72 const auto brace_open = text.find('{', paren_close);
73 if (brace_open == std::string_view::npos)
74 return fs;
75
76 if (arrow != std::string_view::npos && arrow < brace_open) {
77 auto rt = text.substr(arrow + 2, brace_open - arrow - 2);
78 const auto b = rt.find_first_not_of(" \t\n\r");
79 const auto e = rt.find_last_not_of(" \t\n\r");
80 if (b != std::string_view::npos)
81 fs.return_type = std::string(rt.substr(b, e - b + 1));
82 }
83
84 depth = 1;
85 std::size_t brace_close = brace_open + 1;
86 while (brace_close < text.size() && depth > 0) {
87 if (text[brace_close] == '{') {
88 ++depth;
89 } else if (text[brace_close] == '}') {
90 --depth;
91 }
92 ++brace_close;
93 }
94 --brace_close;
95
96 fs.body = std::string(text.substr(brace_open + 1, brace_close - brace_open - 1));
97 return fs;
98 }
99
100 /**
101 * @brief Whether parsing produced a usable function definition.
102 */
103 [[nodiscard]] bool valid() const noexcept
104 {
105 return !name.empty() && !return_type.empty() && !body.empty();
106 }
107};
108
109} // namespace MayaFlux::Kinesis
size_t b
uint32_t depth
static FieldSource parse(std::string fn_name, std::string_view text)
Extract return type, parameter list and body from lambda text.
bool valid() const noexcept
Whether parsing produced a usable function definition.
Parsed representation of a stringified field lambda.