2020-10-11 14:57:43 -03:00
/*
* Copyright ( c ) 2020 , the SerenityOS developers .
2023-06-17 10:56:59 -03:00
* Copyright ( c ) 2023 , Sam Atkins < atkinssj @ serenityos . org >
2024-07-07 15:54:59 -03:00
* Copyright ( c ) 2024 , Tim Ledbetter < timledbetter @ gmail . com >
2020-10-11 14:57:43 -03:00
*
2021-04-22 05:24:48 -03:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-10-11 14:57:43 -03:00
*/
# pragma once
2023-12-16 11:19:34 -03:00
# include <AK/ByteString.h>
2020-10-11 14:57:43 -03:00
# include <AK/GenericLexer.h>
# include <AK/HashMap.h>
2023-06-17 10:56:59 -03:00
# include <AK/String.h>
2020-10-11 14:57:43 -03:00
# include <AK/StringBuilder.h>
namespace AK {
class SourceGenerator {
2020-10-23 13:36:56 -03:00
AK_MAKE_NONCOPYABLE ( SourceGenerator ) ;
2020-10-11 14:57:43 -03:00
public :
2023-06-17 10:56:59 -03:00
using MappingType = HashMap < StringView , String > ;
2020-10-11 14:57:43 -03:00
2024-07-07 15:54:59 -03:00
explicit SourceGenerator ( StringBuilder & builder , char opening = ' @ ' , char closing = ' @ ' , char escape = ' \\ ' )
2020-10-23 13:36:56 -03:00
: m_builder ( builder )
2020-10-11 14:57:43 -03:00
, m_opening ( opening )
, m_closing ( closing )
2024-07-07 15:54:59 -03:00
, m_escape ( escape )
2020-10-11 14:57:43 -03:00
{
}
2024-07-07 15:54:59 -03:00
explicit SourceGenerator ( StringBuilder & builder , MappingType & & mapping , char opening = ' @ ' , char closing = ' @ ' , char escape = ' \\ ' )
2020-10-23 13:36:56 -03:00
: m_builder ( builder )
2023-06-17 09:12:36 -03:00
, m_mapping ( move ( mapping ) )
2020-10-11 14:57:43 -03:00
, m_opening ( opening )
, m_closing ( closing )
2024-07-07 15:54:59 -03:00
, m_escape ( escape )
2020-10-11 14:57:43 -03:00
{
}
2022-02-22 15:20:08 -03:00
SourceGenerator ( SourceGenerator & & ) = default ;
2023-06-16 11:03:16 -03:00
// Move-assign is undefinable due to 'StringBuilder& m_builder;'
SourceGenerator & operator = ( SourceGenerator & & ) = delete ;
2022-02-22 15:20:08 -03:00
2023-08-21 11:42:48 -03:00
[ [ nodiscard ] ] SourceGenerator fork ( )
2023-06-17 09:12:36 -03:00
{
2025-06-25 21:38:26 -03:00
return SourceGenerator { m_builder , MUST ( m_mapping . clone ( ) ) , m_opening , m_closing , m_escape } ;
2023-06-17 09:12:36 -03:00
}
2020-10-11 14:57:43 -03:00
2023-08-21 09:38:55 -03:00
void set ( StringView key , String value )
2022-08-23 12:40:39 -03:00
{
if ( key . contains ( m_opening ) | | key . contains ( m_closing ) ) {
warnln ( " SourceGenerator keys cannot contain the opening/closing delimiters `{}` and `{}`. (Keys are only wrapped in these when using them, not when setting them.) " , m_opening , m_closing ) ;
VERIFY_NOT_REACHED ( ) ;
}
2023-08-21 09:38:55 -03:00
m_mapping . set ( key , move ( value ) ) ;
2023-06-17 10:56:59 -03:00
}
String get ( StringView key ) const
2022-03-08 14:29:45 -03:00
{
auto result = m_mapping . get ( key ) ;
if ( ! result . has_value ( ) ) {
warnln ( " No key named `{}` set on SourceGenerator " , key ) ;
VERIFY_NOT_REACHED ( ) ;
}
return result . release_value ( ) ;
}
2020-10-11 14:57:43 -03:00
2025-04-30 16:08:14 -03:00
[ [ nodiscard ] ] MappingType clone_mapping ( ) const { return MUST ( m_mapping . clone ( ) ) ; }
2025-08-30 03:18:47 -03:00
StringView as_string_view ( ) const LIFETIME_BOUND { return m_builder . string_view ( ) ; }
2020-10-11 14:57:43 -03:00
2023-08-21 11:39:43 -03:00
void append ( StringView pattern )
2020-10-11 14:57:43 -03:00
{
GenericLexer lexer { pattern } ;
while ( ! lexer . is_eof ( ) ) {
2024-07-07 15:54:59 -03:00
m_builder . append ( lexer . consume_until ( [ & ] ( char ch ) { return ch = = m_opening | | ch = = m_escape ; } ) ) ;
if ( lexer . consume_specific ( m_escape ) ) {
if ( ! ( lexer . next_is ( m_opening ) | | lexer . next_is ( m_escape ) ) ) {
if ( lexer . is_eof ( ) )
warnln ( " Unexpected EOF while parsing escape sequence on SourceGenerator " ) ;
else
warnln ( " Invalid escape sequence found `{}{}` on SourceGenerator " , m_escape , lexer . peek ( ) ) ;
VERIFY_NOT_REACHED ( ) ;
}
m_builder . append ( lexer . consume ( ) ) ;
continue ;
}
2020-10-11 14:57:43 -03:00
if ( lexer . consume_specific ( m_opening ) ) {
2023-06-16 13:23:59 -03:00
auto const placeholder = lexer . consume_until ( m_closing ) ;
2020-10-11 14:57:43 -03:00
if ( ! lexer . consume_specific ( m_closing ) )
2021-02-23 16:42:32 -03:00
VERIFY_NOT_REACHED ( ) ;
2020-10-11 14:57:43 -03:00
2023-08-21 11:39:43 -03:00
m_builder . append ( get ( placeholder ) ) ;
2020-10-11 14:57:43 -03:00
} else {
2021-02-23 16:42:32 -03:00
VERIFY ( lexer . is_eof ( ) ) ;
2020-10-11 14:57:43 -03:00
}
}
}
2023-08-21 11:06:29 -03:00
void appendln ( StringView pattern )
2022-02-22 15:21:33 -03:00
{
2023-08-21 11:06:29 -03:00
append ( pattern ) ;
m_builder . append ( ' \n ' ) ;
2022-02-22 15:21:33 -03:00
}
2022-07-11 21:58:29 -03:00
template < size_t N >
2023-06-17 10:56:59 -03:00
String get ( char const ( & key ) [ N ] )
2022-07-11 21:58:29 -03:00
{
return get ( StringView { key , N - 1 } ) ;
}
template < size_t N >
2023-08-21 09:38:55 -03:00
void set ( char const ( & key ) [ N ] , String value )
2022-07-11 21:58:29 -03:00
{
2023-08-21 09:38:55 -03:00
set ( StringView { key , N - 1 } , value ) ;
2022-07-11 21:58:29 -03:00
}
2023-06-17 10:56:59 -03:00
template < size_t N >
2023-08-21 11:39:43 -03:00
void append ( char const ( & pattern ) [ N ] )
2023-06-17 10:56:59 -03:00
{
2023-08-21 11:39:43 -03:00
append ( StringView { pattern , N - 1 } ) ;
2023-06-17 10:56:59 -03:00
}
2022-07-11 21:58:29 -03:00
template < size_t N >
2023-08-21 11:06:29 -03:00
void appendln ( char const ( & pattern ) [ N ] )
2022-07-11 21:58:29 -03:00
{
2023-08-21 11:06:29 -03:00
appendln ( StringView { pattern , N - 1 } ) ;
2022-07-11 21:58:29 -03:00
}
2023-06-17 10:56:03 -03:00
// FIXME: These are deprecated.
2023-12-16 11:19:34 -03:00
void set ( StringView key , ByteString value )
2023-06-17 10:56:03 -03:00
{
2023-12-16 11:19:34 -03:00
set ( key , MUST ( String : : from_byte_string ( value ) ) ) ;
2023-06-17 10:56:03 -03:00
}
2022-07-11 21:58:29 -03:00
template < size_t N >
2023-12-16 11:19:34 -03:00
void set ( char const ( & key ) [ N ] , ByteString value )
2022-07-11 21:58:29 -03:00
{
2023-06-17 10:56:03 -03:00
set ( StringView { key , N - 1 } , value ) ;
2022-07-11 21:58:29 -03:00
}
2020-10-11 14:57:43 -03:00
private :
2020-10-23 13:36:56 -03:00
StringBuilder & m_builder ;
2020-10-11 14:57:43 -03:00
MappingType m_mapping ;
2024-07-07 15:54:59 -03:00
char m_opening { ' @ ' } ;
char m_closing { ' @ ' } ;
char m_escape { ' \\ ' } ;
2020-10-11 14:57:43 -03:00
} ;
}
2022-11-26 08:18:30 -03:00
# if USING_AK_GLOBALLY
2020-10-11 14:57:43 -03:00
using AK : : SourceGenerator ;
2022-11-26 08:18:30 -03:00
# endif