2020-10-11 17:57:43 +00:00
/*
* Copyright ( c ) 2020 , the SerenityOS developers .
*
2021-04-22 08:24:48 +00:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-10-11 17:57:43 +00:00
*/
# pragma once
2022-12-04 18:02:33 +00:00
# include <AK/DeprecatedString.h>
2020-10-11 17:57:43 +00:00
# include <AK/GenericLexer.h>
# include <AK/HashMap.h>
# include <AK/StringBuilder.h>
namespace AK {
class SourceGenerator {
2020-10-23 16:36:56 +00:00
AK_MAKE_NONCOPYABLE ( SourceGenerator ) ;
2020-10-11 17:57:43 +00:00
public :
2022-12-04 18:02:33 +00:00
using MappingType = HashMap < StringView , DeprecatedString > ;
2020-10-11 17:57:43 +00:00
2020-10-23 16:36:56 +00:00
explicit SourceGenerator ( StringBuilder & builder , char opening = ' @ ' , char closing = ' @ ' )
: m_builder ( builder )
2020-10-11 17:57:43 +00:00
, m_opening ( opening )
, m_closing ( closing )
{
}
2022-04-01 17:58:27 +00:00
explicit SourceGenerator ( StringBuilder & builder , MappingType const & mapping , char opening = ' @ ' , char closing = ' @ ' )
2020-10-23 16:36:56 +00:00
: m_builder ( builder )
2023-05-13 18:26:20 +00:00
, m_mapping ( mapping . clone ( ) . release_value_but_fixme_should_propagate_errors ( ) )
2020-10-11 17:57:43 +00:00
, m_opening ( opening )
, m_closing ( closing )
{
}
2022-02-22 18:20:08 +00:00
SourceGenerator ( SourceGenerator & & ) = default ;
2020-10-23 16:36:56 +00:00
SourceGenerator fork ( ) { return SourceGenerator { m_builder , m_mapping , m_opening , m_closing } ; }
2020-10-11 17:57:43 +00:00
2022-12-04 18:02:33 +00:00
void set ( StringView key , DeprecatedString value )
2022-08-23 15:40:39 +00: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 ( ) ;
}
m_mapping . set ( key , move ( value ) ) ;
}
2022-12-04 18:02:33 +00:00
DeprecatedString get ( StringView key ) const
2022-03-08 17:29:45 +00: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 17:57:43 +00:00
2020-10-23 16:36:56 +00:00
StringView as_string_view ( ) const { return m_builder . string_view ( ) ; }
2023-01-26 18:58:09 +00:00
DeprecatedString as_string ( ) const { return m_builder . to_deprecated_string ( ) ; }
2020-10-11 17:57:43 +00:00
void append ( StringView pattern )
{
GenericLexer lexer { pattern } ;
while ( ! lexer . is_eof ( ) ) {
2020-11-21 18:55:00 +00:00
// FIXME: It is a bit inconvenient, that 'consume_until' also consumes the 'stop' character, this makes
2020-10-11 17:57:43 +00:00
// the method less generic because there is no way to check if the 'stop' character ever appeared.
2022-04-01 17:58:27 +00:00
auto const consume_until_without_consuming_stop_character = [ & ] ( char stop ) {
2020-10-11 17:57:43 +00:00
return lexer . consume_while ( [ & ] ( char ch ) { return ch ! = stop ; } ) ;
} ;
2020-10-23 16:36:56 +00:00
m_builder . append ( consume_until_without_consuming_stop_character ( m_opening ) ) ;
2020-10-11 17:57:43 +00:00
if ( lexer . consume_specific ( m_opening ) ) {
2022-04-01 17:58:27 +00:00
auto const placeholder = consume_until_without_consuming_stop_character ( m_closing ) ;
2020-10-11 17:57:43 +00:00
if ( ! lexer . consume_specific ( m_closing ) )
2021-02-23 19:42:32 +00:00
VERIFY_NOT_REACHED ( ) ;
2020-10-11 17:57:43 +00:00
2020-10-23 16:36:56 +00:00
m_builder . append ( get ( placeholder ) ) ;
2020-10-11 17:57:43 +00:00
} else {
2021-02-23 19:42:32 +00:00
VERIFY ( lexer . is_eof ( ) ) ;
2020-10-11 17:57:43 +00:00
}
}
}
2022-02-22 18:21:33 +00:00
void appendln ( StringView pattern )
{
append ( pattern ) ;
m_builder . append ( ' \n ' ) ;
}
2022-07-12 00:58:29 +00:00
template < size_t N >
2022-12-04 18:02:33 +00:00
DeprecatedString get ( char const ( & key ) [ N ] )
2022-07-12 00:58:29 +00:00
{
return get ( StringView { key , N - 1 } ) ;
}
template < size_t N >
2022-12-04 18:02:33 +00:00
void set ( char const ( & key ) [ N ] , DeprecatedString value )
2022-07-12 00:58:29 +00:00
{
set ( StringView { key , N - 1 } , value ) ;
}
template < size_t N >
void append ( char const ( & pattern ) [ N ] )
{
append ( StringView { pattern , N - 1 } ) ;
}
template < size_t N >
void appendln ( char const ( & pattern ) [ N ] )
{
appendln ( StringView { pattern , N - 1 } ) ;
}
2020-10-11 17:57:43 +00:00
private :
2020-10-23 16:36:56 +00:00
StringBuilder & m_builder ;
2020-10-11 17:57:43 +00:00
MappingType m_mapping ;
char m_opening , m_closing ;
} ;
}
2022-11-26 11:18:30 +00:00
# if USING_AK_GLOBALLY
2020-10-11 17:57:43 +00:00
using AK : : SourceGenerator ;
2022-11-26 11:18:30 +00:00
# endif