Skip to content

Commit

Permalink
feat: partials specs
Browse files Browse the repository at this point in the history
  • Loading branch information
alandefreitas committed Aug 7, 2023
1 parent 7e5250e commit 5a0409a
Show file tree
Hide file tree
Showing 7 changed files with 1,201 additions and 144 deletions.
65 changes: 54 additions & 11 deletions include/mrdox/Support/Handlebars.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,20 @@ struct HandlebarsOptions
*/
bool ignoreStandalone = false;

/** Disables implicit context for partials
When enabled, partials that are not passed a context value will
execute against an empty object.
*/
bool explicitPartialContext = false;

/** Enable recursive field lookup
When enabled, fields will be looked up recursively in objects
and arrays.
*/
bool compat = false;

/** Custom private data object
This variable can be used to pass in an object to define custom
Expand Down Expand Up @@ -106,6 +120,9 @@ namespace detail {

using partials_map = std::unordered_map<
std::string, std::string, string_hash, std::equal_to<>>;

using partials_view_map = std::unordered_map<
std::string, std::string_view, string_hash, std::equal_to<>>;
}

/** Reference to output stream used by handlebars
Expand All @@ -124,8 +141,8 @@ class MRDOX_DECL OutputRef
using fptr = void (*)(void * out, std::string_view sv);
void * out_;
fptr fptr_;
std::size_t indent_ = 0;

private:
template<class St>
static
void
Expand Down Expand Up @@ -164,6 +181,9 @@ class MRDOX_DECL OutputRef
, fptr_( &noop_output )
{}

OutputRef&
write_impl( std::string_view sv );

public:
/** Constructor for std::string output
Expand Down Expand Up @@ -209,8 +229,7 @@ class MRDOX_DECL OutputRef
OutputRef&
operator<<( std::string_view sv )
{
fptr_( out_, sv );
return *this;
return write_impl( sv );
}

/** Write to output
Expand All @@ -221,8 +240,7 @@ class MRDOX_DECL OutputRef
OutputRef&
operator<<( char c )
{
fptr_( out_, std::string_view( &c, 1 ) );
return *this;
return write_impl( std::string_view( &c, 1 ) );
}

/** Write to output
Expand All @@ -233,8 +251,7 @@ class MRDOX_DECL OutputRef
OutputRef&
operator<<( char const * c )
{
fptr_( out_, std::string_view( c ) );
return *this;
return write_impl( std::string_view( c ) );
}

/** Write to output
Expand All @@ -248,8 +265,19 @@ class MRDOX_DECL OutputRef
operator<<( T v )
{
std::string s = fmt::format( "{}", v );
fptr_( out_, s );
return *this;
return write_impl( s );
}

void
setIndent(std::size_t indent)
{
indent_ = indent;
}

std::size_t
getIndent() noexcept
{
return indent_;
}
};

Expand Down Expand Up @@ -842,9 +870,16 @@ class Handlebars {
std::string
render(
std::string_view templateText,
dom::Value const& context = {},
dom::Value const& context,
HandlebarsOptions const& options = {}) const;

std::string
render(std::string_view templateText) const
{
dom::Object const& context = {};
return render(templateText, context);
}

/** Render a handlebars template
This function renders the specified handlebars template and
Expand Down Expand Up @@ -1136,6 +1171,7 @@ class Handlebars {
Handlebars::Tag const& tag,
OutputRef &out,
dom::Value const& context,
HandlebarsOptions const& opt,
detail::RenderState& state) const;

void
Expand All @@ -1152,17 +1188,24 @@ class Handlebars {
dom::Value const& context,
detail::RenderState& state,
dom::Array &args,
HandlebarsCallback& opt) const;
HandlebarsCallback& cb,
HandlebarsOptions const& opt) const;

std::pair<dom::Value, bool>
evalExpr(
dom::Value const &context,
std::string_view expression,
detail::RenderState &state,
HandlebarsOptions const& opt,
bool evalLiterals) const;

std::pair<helper_type const&, bool>
getHelper(std::string_view name, bool isBlock) const;

std::pair<std::string_view, bool>
getPartial(
std::string_view name,
detail::RenderState const& state) const;
};

/** Determine if a value is truthy
Expand Down
24 changes: 24 additions & 0 deletions share/gdb/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
= GDB pretty printers

Create or modify your `.gdbinit` file to contain the following:

[source,python]
----
python
import sys
sys.path.insert(0, '/path/share/gdb') <1>
from mrdox_printers import register_mrdox_printers <2>
register_mrdox_printers() <3>
end
----

<1> Make GDB see the directory with the printers
<2> Import the function that registers the printers with GDB
<3> Effectively register the printers

Note that this pattern does not register the printers unless the user explicitly asks for it by calling the `register_mrdox_printers` function.
This helps the scripts separate these concerns.

NOTE: The printers require Python 3


1 change: 1 addition & 0 deletions share/gdb/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Intentionally empty
116 changes: 116 additions & 0 deletions share/gdb/mrdox_printers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#
# Copyright (c) 2023 alandefreitas ([email protected])
#
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
#

import gdb


class utils:
@staticmethod
def resolve_type(t):
if t.code == gdb.TYPE_CODE_REF:
t = t.target()
t = t.unqualified().strip_typedefs()
typename = t.tag
if typename is None:
return None
return t

@staticmethod
def resolved_typename(val):
t = val.type
t = utils.resolve_type(t)
if t is not None:
return str(t)
else:
return str(val.type)

@staticmethod
def pct_decode(s: str):
return urllib.parse.unquote(s)

sv_pool = []

@staticmethod
def make_string_view(cstr: gdb.Value, n: int):
sv_ptr: gdb.Value = gdb.parse_and_eval('malloc(sizeof(class boost::core::basic_string_view<char>))')
sv_ptr_str = cstr.format_string(format='x')
gdb.execute(
f'call ((boost::core::basic_string_view<char>*){sv_ptr})->basic_string_view((const char*){sv_ptr_str}, {n})',
to_string=True)
sv = gdb.parse_and_eval(f'*((boost::core::basic_string_view<char>*){sv_ptr})')
copy: gdb.Value = sv
utils.sv_pool.append(sv_ptr)
if len(utils.sv_pool) > 5000:
gdb.execute(f'call free({utils.sv_pool[0]})', to_string=True)
utils.sv_pool.pop(0)
return copy

pct_sv_pool = []

@staticmethod
def make_pct_string_view(cstr: gdb.Value, n: int):
sv_ptr: gdb.Value = gdb.parse_and_eval('malloc(sizeof(class boost::urls::pct_string_view))')
sv_ptr_str = cstr.format_string(format='x')
gdb.execute(
f'call ((boost::urls::pct_string_view*){sv_ptr})->pct_string_view((const char*){sv_ptr_str}, {n})',
to_string=True)
sv = gdb.parse_and_eval(f'*((boost::urls::pct_string_view*){sv_ptr})')
copy: gdb.Value = sv
utils.pct_sv_pool.append(sv_ptr)
if len(utils.sv_pool) > 5000:
gdb.execute(f'call free({utils.pct_sv_pool[0]})', to_string=True)
utils.sv_pool.pop(0)
return copy


class DomValuePrinter:
def __init__(self, value):
self.value = value

def children(self):
# Get kind enum
kind = self.value['kind_']
if kind == 1:
yield 'Boolean', self.value['b_']
elif kind == 2:
yield 'Integer', self.value['i_']
elif kind == 3:
yield 'String', self.value['str_']
elif kind == 4:
yield 'Array', self.value['arr_']
elif kind == 5:
yield 'Object', self.value['obj_']['impl_']['_M_ptr']
elif kind == 6:
yield 'Function', self.value['fn_']
else:
yield 'kind_', self.value['kind_']


class EnumPrinter:
def __init__(self, value):
self.value = value

def to_string(self):
s: str = self.value.format_string(raw=True)
return s.rsplit(':', 1)[-1]


if __name__ != "__main__":
def lookup_function(val: gdb.Value):
if val.type.code == gdb.TYPE_CODE_ENUM:
return EnumPrinter(val)

typename: str = utils.resolved_typename(val)
if typename == 'clang::mrdox::dom::Value':
return DomValuePrinter(val)
return None


def register_mrdox_printers(obj=None):
if obj is None:
obj = gdb
obj.pretty_printers.append(lookup_function)
Loading

0 comments on commit 5a0409a

Please sign in to comment.