Compare commits

..

2 Commits

Author SHA1 Message Date
Sipka Dániel
9b27c7db88 no wrapper 2020-02-12 20:58:52 +01:00
Sipka Dániel
c2ec0d9ce8 boost -> std 2020-02-12 20:53:14 +01:00
84 changed files with 1489 additions and 1033 deletions

93
.clang-format Normal file
View File

@ -0,0 +1,93 @@
---
Language: Cpp
# BasedOnStyle: Google
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: false
AlignEscapedNewlinesLeft: true
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: InlineOnly
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: true
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeTernaryOperators: true
#BreakConstructorInitializers: BeforeComma
BreakConstructorInitializersBeforeComma: true
ColumnLimit: 96
CommentPragmas: '^ IWYU pragma:'
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 8
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
IncludeCategories:
- Regex: '^<.*\.h>'
Priority: 1
- Regex: '^<.*'
Priority: 2
- Regex: '.*'
Priority: 3
IndentCaseLabels: false
SpaceAfterTemplateKeyword: false
FixNamespaceComments: true
PointerAlignment: Left
IndentWidth: 4
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: false
PenaltyBreakBeforeFirstCallParameter: 200
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 5000
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 400
BreakBeforeInheritanceComma: true
ReflowComments: true
SortIncludes: true
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Auto
TabWidth: 4
UseTab: Never
...

View File

@ -6,12 +6,12 @@ option(WITH_BENCHMARK "enable building benchmark executable" OFF)
set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON) set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
set(CMAKE_BUILD_TYPE Release) set(CMAKE_BUILD_TYPE Debug)
set(mstch_VERSION 1.0.1) set(mstch_VERSION 1.0.1)
if(NOT MSVC) if(NOT MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wextra -O3") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Wall -Wextra -O3")
endif() endif()
add_subdirectory(src) add_subdirectory(src)

437
CMakeLists.txt.user Normal file
View File

@ -0,0 +1,437 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.6.0, 2020-02-12T19:36:25. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{6c3a783b-4a95-47a1-a553-14efac437a7d}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">2</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap">
<valuelist type="QVariantList" key="ClangCodeModel.CustomCommandLineKey"/>
<value type="bool" key="ClangCodeModel.UseGlobalConfig">true</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Unnamed</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Unnamed</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{85ec3516-307e-4a38-9ec9-10c74ad47576}</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<valuelist type="QVariantList" key="CMake.Configuration">
<value type="QString">CMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}</value>
<value type="QString">CMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}</value>
<value type="QString">CMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX}</value>
<value type="QString">QT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable}</value>
<value type="QString">WITH_UNIT_TESTS:BOOL=ON</value>
</valuelist>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/msd/work/build-mstch-Unnamed-Default</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">CMake Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">CMake Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Default</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Default</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
<valuelist type="QVariantList" key="CMake.Configuration">
<value type="QString">CMAKE_BUILD_TYPE:STRING=Debug</value>
</valuelist>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/msd/work/build-mstch-Unnamed-Debug</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">CMake Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">CMake Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
<valuelist type="QVariantList" key="CMake.Configuration">
<value type="QString">CMAKE_BUILD_TYPE:STRING=Release</value>
</valuelist>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/msd/work/build-mstch-Unnamed-Release</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">CMake Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">CMake Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.3">
<valuelist type="QVariantList" key="CMake.Configuration">
<value type="QString">CMAKE_BUILD_TYPE:STRING=RelWithDebInfo</value>
</valuelist>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/msd/work/build-mstch-Unnamed-Release with Debug Information</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">CMake Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">CMake Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Release with Debug Information</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release with Debug Information</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.4">
<valuelist type="QVariantList" key="CMake.Configuration">
<value type="QString">CMAKE_BUILD_TYPE:STRING=MinSizeRel</value>
</valuelist>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/msd/work/build-mstch-Unnamed-Minimum Size Release</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">CMake Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">CMake Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Minimum Size Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Minimum Size Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">5</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy Configuration</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguation.Title">headerize</value>
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.Arguments"></value>
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.UserWorkingDirectory"></value>
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.UserWorkingDirectory.default">/tmp/QtCreator-poSNJS/qtc-cmake-DajvkCJW/vendor/headerize/src</value>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">headerize</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.headerize</value>
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.1">
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguation.Title">mstch_test</value>
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.Arguments"></value>
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.UserWorkingDirectory"></value>
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.UserWorkingDirectory.default">/tmp/QtCreator-poSNJS/qtc-cmake-DajvkCJW/test</value>
<value type="int" key="PE.EnvironmentAspect.Base">-1</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">mstch_test</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.mstch_test</value>
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">2</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">18</value>
</data>
<data>
<variable>Version</variable>
<value type="int">18</value>
</data>
</qtcreator>

View File

@ -1,62 +1,60 @@
#pragma once #pragma once
#include <vector>
#include <map>
#include <string>
#include <memory>
#include <functional> #include <functional>
#include <map>
#include <boost/variant.hpp> #include <memory>
#include <string>
#include <variant>
#include <vector>
namespace mstch { namespace mstch {
struct config { struct config {
static std::function<std::string(const std::string&)> escape; static std::function<std::string(const std::string&)> escape;
}; };
namespace internal { namespace internal {
template<class N> template<class N>
class object_t { class object_t {
public: public:
const N& at(const std::string& name) const { const N& at(const std::string& name) const {
cache[name] = (methods.at(name))(); cache[name] = (methods.at(name))();
return cache[name]; return cache[name];
} }
bool has(const std::string name) const { bool has(const std::string name) const { return methods.count(name) != 0; }
return methods.count(name) != 0;
}
protected: protected:
template<class S> template<class S>
void register_methods(S* s, std::map<std::string,N(S::*)()> methods) { void register_methods(S* s, std::map<std::string, N (S::*)()> methods) {
for(auto& item: methods) for (auto& item : methods)
this->methods.insert({item.first, std::bind(item.second, s)}); this->methods.insert({item.first, std::bind(item.second, s)});
} }
private: private:
std::map<std::string, std::function<N()>> methods; std::map<std::string, std::function<N()>> methods;
mutable std::map<std::string, N> cache; mutable std::map<std::string, N> cache;
}; };
template<class T, class N> template<class T, class N>
class is_fun { class is_fun {
private: private:
using not_fun = char; using not_fun = char;
using fun_without_args = char[2]; using fun_without_args = char[2];
using fun_with_args = char[3]; using fun_with_args = char[3];
template <typename U, U> struct really_has; template<typename U, U>
template <typename C> static fun_without_args& test( struct really_has;
really_has<N(C::*)() const, &C::operator()>*); template<typename C>
template <typename C> static fun_with_args& test( static fun_without_args& test(really_has<N (C::*)() const, &C::operator()>*);
really_has<N(C::*)(const std::string&) const, template<typename C>
&C::operator()>*); static fun_with_args& test(really_has<N (C::*)(const std::string&) const, &C::operator()>*);
template <typename> static not_fun& test(...); template<typename>
static not_fun& test(...);
public: public:
static bool const no_args = sizeof(test<T>(0)) == sizeof(fun_without_args); static bool const no_args = sizeof(test<T>(0)) == sizeof(fun_without_args);
static bool const has_args = sizeof(test<T>(0)) == sizeof(fun_with_args); static bool const has_args = sizeof(test<T>(0)) == sizeof(fun_with_args);
}; };
template<class N> template<class N>
@ -64,50 +62,68 @@ using node_renderer = std::function<std::string(const N& n)>;
template<class N> template<class N>
class lambda_t { class lambda_t {
public: public:
template<class F> template<class F>
lambda_t(F f, typename std::enable_if<is_fun<F, N>::no_args>::type* = 0): lambda_t(F f, typename std::enable_if<is_fun<F, N>::no_args>::type* = 0)
fun([f](node_renderer<N> renderer, const std::string&) { : fun([f](node_renderer<N> renderer, const std::string&) { return renderer(f()); })
return renderer(f()); {}
})
{
}
template<class F> template<class F>
lambda_t(F f, typename std::enable_if<is_fun<F, N>::has_args>::type* = 0): lambda_t(F f, typename std::enable_if<is_fun<F, N>::has_args>::type* = 0)
fun([f](node_renderer<N> renderer, const std::string& text) { : fun([f](node_renderer<N> renderer, const std::string& text) {
return renderer(f(text)); return renderer(f(text));
}) })
{ {}
}
std::string operator()(node_renderer<N> renderer, std::string operator()(node_renderer<N> renderer, const std::string& text = "") const {
const std::string& text = "") const return fun(renderer, text);
{ }
return fun(renderer, text);
}
private: private:
std::function<std::string(node_renderer<N> renderer, const std::string&)> fun; std::function<std::string(node_renderer<N> renderer, const std::string&)> fun;
}; };
} } // namespace internal
struct object_wrapper;
struct map_wrapper;
struct array_wrapper;
struct lambda_wrapper;
using node = std::variant<std::nullptr_t,
std::string,
int,
double,
bool,
lambda_wrapper,
object_wrapper,
map_wrapper,
array_wrapper>;
using node = boost::make_recursive_variant<
std::nullptr_t, std::string, int, double, bool,
internal::lambda_t<boost::recursive_variant_>,
std::shared_ptr<internal::object_t<boost::recursive_variant_>>,
std::map<const std::string, boost::recursive_variant_>,
std::vector<boost::recursive_variant_>>::type;
using object = internal::object_t<node>; using object = internal::object_t<node>;
using lambda = internal::lambda_t<node>; using lambda = internal::lambda_t<node>;
using map = std::map<const std::string, node>; using map = std::map<const std::string, node>;
using array = std::vector<node>; using array = std::vector<node>;
std::string render( struct array_wrapper {
const std::string& tmplt, array values;
const node& root, };
const std::map<std::string,std::string>& partials =
std::map<std::string,std::string>());
} struct map_wrapper {
map values;
};
struct object_wrapper {
std::shared_ptr<object> values;
};
struct lambda_wrapper {
lambda values;
};
std::string render(const std::string& tmplt,
const node& root,
const std::map<std::string, std::string>& partials =
std::map<std::string, std::string>());
} // namespace mstch

View File

@ -1,11 +1,8 @@
find_package(Boost 1.54 REQUIRED)
set(mstch_INCLUDE_DIR set(mstch_INCLUDE_DIR
${PROJECT_SOURCE_DIR}/include CACHE STRING "mstch include directory") ${PROJECT_SOURCE_DIR}/include CACHE STRING "mstch include directory")
include_directories( include_directories(
${mstch_INCLUDE_DIR} ${mstch_INCLUDE_DIR})
${Boost_INCLUDE_DIR})
set(SRC set(SRC
state/in_section.cpp state/in_section.cpp

View File

@ -7,14 +7,13 @@ using namespace mstch;
std::function<std::string(const std::string&)> mstch::config::escape; std::function<std::string(const std::string&)> mstch::config::escape;
std::string mstch::render( std::string mstch::render(const std::string& tmplt,
const std::string& tmplt, const node& root,
const node& root, const std::map<std::string, std::string>& partials)
const std::map<std::string,std::string>& partials)
{ {
std::map<std::string, template_type> partial_templates; std::map<std::string, template_type> partial_templates;
for (auto& partial: partials) for (auto& partial : partials)
partial_templates.insert({partial.first, {partial.second}}); partial_templates.insert({partial.first, {partial.second}});
return render_context(root, partial_templates).render(tmplt); return render_context(root, partial_templates).render(tmplt);
} }

View File

@ -6,67 +6,62 @@ using namespace mstch;
const mstch::node render_context::null_node; const mstch::node render_context::null_node;
render_context::push::push(render_context& context, const mstch::node& node): render_context::push::push(render_context& context, const mstch::node& node)
m_context(context) : m_context(context)
{ {
context.m_nodes.emplace_front(node); context.m_nodes.emplace_front(node);
context.m_node_ptrs.emplace_front(&node); context.m_node_ptrs.emplace_front(&node);
context.m_state.push(std::unique_ptr<render_state>(new outside_section)); context.m_state.push(std::unique_ptr<render_state>(new outside_section));
} }
render_context::push::~push() { render_context::push::~push() {
m_context.m_nodes.pop_front(); m_context.m_nodes.pop_front();
m_context.m_node_ptrs.pop_front(); m_context.m_node_ptrs.pop_front();
m_context.m_state.pop(); m_context.m_state.pop();
} }
std::string render_context::push::render(const template_type& templt) { std::string render_context::push::render(const template_type& templt) {
return m_context.render(templt); return m_context.render(templt);
} }
render_context::render_context( render_context::render_context(const mstch::node& node,
const mstch::node& node, const std::map<std::string, template_type>& partials)
const std::map<std::string, template_type>& partials): : m_partials(partials), m_nodes(1, node), m_node_ptrs(1, &node)
m_partials(partials), m_nodes(1, node), m_node_ptrs(1, &node)
{ {
m_state.push(std::unique_ptr<render_state>(new outside_section)); m_state.push(std::unique_ptr<render_state>(new outside_section));
} }
const mstch::node& render_context::find_node( const mstch::node& render_context::find_node(const std::string& token,
const std::string& token, std::list<node const*> current_nodes)
std::list<node const*> current_nodes)
{ {
if (token != "." && token.find('.') != std::string::npos) if (token != "." && token.find('.') != std::string::npos)
return find_node(token.substr(token.rfind('.') + 1), return find_node(token.substr(token.rfind('.') + 1),
{&find_node(token.substr(0, token.rfind('.')), current_nodes)}); {&find_node(token.substr(0, token.rfind('.')), current_nodes)});
else else
for (auto& node: current_nodes) for (auto& node : current_nodes)
if (visit(has_token(token), *node)) if (visit(has_token(token), *node))
return visit(get_token(token, *node), *node); return visit(get_token(token, *node), *node);
return null_node; return null_node;
} }
const mstch::node& render_context::get_node(const std::string& token) { const mstch::node& render_context::get_node(const std::string& token) {
return find_node(token, m_node_ptrs); return find_node(token, m_node_ptrs);
} }
std::string render_context::render( std::string render_context::render(const template_type& templt, const std::string& prefix) {
const template_type& templt, const std::string& prefix) std::string output;
{ bool prev_eol = true;
std::string output; for (auto& token : templt) {
bool prev_eol = true; if (prev_eol && prefix.length() != 0)
for (auto& token: templt) { output += m_state.top()->render(*this, {prefix});
if (prev_eol && prefix.length() != 0) output += m_state.top()->render(*this, token);
output += m_state.top()->render(*this, {prefix}); prev_eol = token.eol();
output += m_state.top()->render(*this, token); }
prev_eol = token.eol(); return output;
}
return output;
} }
std::string render_context::render_partial( std::string render_context::render_partial(const std::string& partial_name,
const std::string& partial_name, const std::string& prefix) const std::string& prefix)
{ {
return m_partials.count(partial_name) ? return m_partials.count(partial_name) ? render(m_partials.at(partial_name), prefix) : "";
render(m_partials.at(partial_name), prefix) : "";
} }

View File

@ -3,8 +3,8 @@
#include <deque> #include <deque>
#include <list> #include <list>
#include <sstream> #include <sstream>
#include <string>
#include <stack> #include <stack>
#include <string>
#include "mstch/mstch.hpp" #include "mstch/mstch.hpp"
#include "state/render_state.hpp" #include "state/render_state.hpp"
@ -13,39 +13,35 @@
namespace mstch { namespace mstch {
class render_context { class render_context {
public: public:
class push { class push {
public: public:
push(render_context& context, const mstch::node& node = {}); push(render_context& context, const mstch::node& node = {});
~push(); ~push();
std::string render(const template_type& templt); std::string render(const template_type& templt);
private:
render_context& m_context;
};
render_context( private:
const mstch::node& node, render_context& m_context;
const std::map<std::string, template_type>& partials); };
const mstch::node& get_node(const std::string& token);
std::string render(
const template_type& templt, const std::string& prefix = "");
std::string render_partial(
const std::string& partial_name, const std::string& prefix);
template<class T, class... Args>
void set_state(Args&& ... args) {
m_state.top() = std::unique_ptr<render_state>(
new T(std::forward<Args>(args)...));
}
private: render_context(const mstch::node& node,
static const mstch::node null_node; const std::map<std::string, template_type>& partials);
const mstch::node& find_node( const mstch::node& get_node(const std::string& token);
const std::string& token, std::string render(const template_type& templt, const std::string& prefix = "");
std::list<node const*> current_nodes); std::string render_partial(const std::string& partial_name, const std::string& prefix);
std::map<std::string, template_type> m_partials; template<class T, class... Args>
std::deque<mstch::node> m_nodes; void set_state(Args&&... args) {
std::list<const mstch::node*> m_node_ptrs; m_state.top() = std::unique_ptr<render_state>(new T(std::forward<Args>(args)...));
std::stack<std::unique_ptr<render_state>> m_state; }
private:
static const mstch::node null_node;
const mstch::node& find_node(const std::string& token,
std::list<node const*> current_nodes);
std::map<std::string, template_type> m_partials;
std::deque<mstch::node> m_nodes;
std::list<const mstch::node*> m_node_ptrs;
std::stack<std::unique_ptr<render_state>> m_state;
}; };
} } // namespace mstch

View File

@ -5,30 +5,30 @@
using namespace mstch; using namespace mstch;
in_section::in_section(type type, const token& start_token): in_section::in_section(type type, const token& start_token)
m_type(type), m_start_token(start_token), m_skipped_openings(0) : m_type(type), m_start_token(start_token), m_skipped_openings(0)
{ {
} }
std::string in_section::render(render_context& ctx, const token& token) { std::string in_section::render(render_context& ctx, const token& token) {
if (token.token_type() == token::type::section_close) if (token.token_type() == token::type::section_close)
if (token.name() == m_start_token.name() && m_skipped_openings == 0) { if (token.name() == m_start_token.name() && m_skipped_openings == 0) {
auto& node = ctx.get_node(m_start_token.name()); auto& node = ctx.get_node(m_start_token.name());
std::string out; std::string out;
if (m_type == type::normal && !visit(is_node_empty(), node)) if (m_type == type::normal && !visit(is_node_empty(), node))
out = visit(render_section(ctx, m_section, m_start_token.delims()), node); out = visit(render_section(ctx, m_section, m_start_token.delims()), node);
else if (m_type == type::inverted && visit(is_node_empty(), node)) else if (m_type == type::inverted && visit(is_node_empty(), node))
out = render_context::push(ctx).render(m_section); out = render_context::push(ctx).render(m_section);
ctx.set_state<outside_section>(); ctx.set_state<outside_section>();
return out; return out;
} else } else
m_skipped_openings--; m_skipped_openings--;
else if (token.token_type() == token::type::inverted_section_open || else if (token.token_type() == token::type::inverted_section_open ||
token.token_type() == token::type::section_open) token.token_type() == token::type::section_open)
m_skipped_openings++; m_skipped_openings++;
m_section << token; m_section << token;
return ""; return "";
} }

View File

@ -8,17 +8,17 @@
namespace mstch { namespace mstch {
class in_section: public render_state { class in_section : public render_state {
public: public:
enum class type { inverted, normal }; enum class type { inverted, normal };
in_section(type type, const token& start_token); in_section(type type, const token& start_token);
std::string render(render_context& context, const token& token) override; std::string render(render_context& context, const token& token) override;
private: private:
const type m_type; const type m_type;
const token& m_start_token; const token& m_start_token;
template_type m_section; template_type m_section;
int m_skipped_openings; int m_skipped_openings;
}; };
} } // namespace mstch

View File

@ -1,32 +1,30 @@
#include "outside_section.hpp" #include "outside_section.hpp"
#include "visitor/render_node.hpp"
#include "in_section.hpp" #include "in_section.hpp"
#include "render_context.hpp" #include "render_context.hpp"
#include "visitor/render_node.hpp"
using namespace mstch; using namespace mstch;
std::string outside_section::render( std::string outside_section::render(render_context& ctx, const token& token) {
render_context& ctx, const token& token) using flag = render_node::flag;
{ switch (token.token_type()) {
using flag = render_node::flag;
switch (token.token_type()) {
case token::type::section_open: case token::type::section_open:
ctx.set_state<in_section>(in_section::type::normal, token); ctx.set_state<in_section>(in_section::type::normal, token);
break; break;
case token::type::inverted_section_open: case token::type::inverted_section_open:
ctx.set_state<in_section>(in_section::type::inverted, token); ctx.set_state<in_section>(in_section::type::inverted, token);
break; break;
case token::type::variable: case token::type::variable:
return visit(render_node(ctx, flag::escape_html), ctx.get_node(token.name())); return visit(render_node(ctx, flag::escape_html), ctx.get_node(token.name()));
case token::type::unescaped_variable: case token::type::unescaped_variable:
return visit(render_node(ctx, flag::none), ctx.get_node(token.name())); return visit(render_node(ctx, flag::none), ctx.get_node(token.name()));
case token::type::text: case token::type::text:
return token.raw(); return token.raw();
case token::type::partial: case token::type::partial:
return ctx.render_partial(token.name(), token.partial_prefix()); return ctx.render_partial(token.name(), token.partial_prefix());
default: default:
break; break;
} }
return ""; return "";
} }

View File

@ -4,9 +4,9 @@
namespace mstch { namespace mstch {
class outside_section: public render_state { class outside_section : public render_state {
public: public:
std::string render(render_context& context, const token& token) override; std::string render(render_context& context, const token& token) override;
}; };
} } // namespace mstch

View File

@ -9,9 +9,9 @@ namespace mstch {
class render_context; class render_context;
class render_state { class render_state {
public: public:
virtual ~render_state() {} virtual ~render_state() {}
virtual std::string render(render_context& context, const token& token) = 0; virtual std::string render(render_context& context, const token& token) = 0;
}; };
} } // namespace mstch

View File

@ -2,103 +2,98 @@
using namespace mstch; using namespace mstch;
template_type::template_type(const std::string& str, const delim_type& delims): template_type::template_type(const std::string& str, const delim_type& delims)
m_open(delims.first), m_close(delims.second) : m_open(delims.first), m_close(delims.second)
{ {
tokenize(str); tokenize(str);
strip_whitespace(); strip_whitespace();
} }
template_type::template_type(const std::string& str): template_type::template_type(const std::string& str) : m_open("{{"), m_close("}}") {
m_open("{{"), m_close("}}") tokenize(str);
{ strip_whitespace();
tokenize(str);
strip_whitespace();
} }
void template_type::process_text(citer begin, citer end) { void template_type::process_text(citer begin, citer end) {
if (begin == end) if (begin == end)
return; return;
auto start = begin; auto start = begin;
for (auto it = begin; it != end; ++it) for (auto it = begin; it != end; ++it)
if (*it == '\n' || it == end - 1) { if (*it == '\n' || it == end - 1) {
m_tokens.push_back({{start, it + 1}}); m_tokens.push_back({{start, it + 1}});
start = it + 1; start = it + 1;
} }
} }
void template_type::tokenize(const std::string& tmp) { void template_type::tokenize(const std::string& tmp) {
citer beg = tmp.begin(); citer beg = tmp.begin();
auto npos = std::string::npos; auto npos = std::string::npos;
for (std::size_t cur_pos = 0; cur_pos < tmp.size();) { for (std::size_t cur_pos = 0; cur_pos < tmp.size();) {
auto open_pos = tmp.find(m_open, cur_pos); auto open_pos = tmp.find(m_open, cur_pos);
auto close_pos = tmp.find( auto close_pos = tmp.find(m_close, open_pos == npos ? open_pos : open_pos + 1);
m_close, open_pos == npos ? open_pos : open_pos + 1);
if (close_pos != npos && open_pos != npos) { if (close_pos != npos && open_pos != npos) {
if (*(beg + open_pos + m_open.size()) == '{' && if (*(beg + open_pos + m_open.size()) == '{' &&
*(beg + close_pos + m_close.size()) == '}') *(beg + close_pos + m_close.size()) == '}')
++close_pos; ++close_pos;
process_text(beg + cur_pos, beg + open_pos); process_text(beg + cur_pos, beg + open_pos);
cur_pos = close_pos + m_close.size(); cur_pos = close_pos + m_close.size();
m_tokens.push_back({{beg + open_pos, beg + close_pos + m_close.size()}, m_tokens.push_back({{beg + open_pos, beg + close_pos + m_close.size()},
m_open.size(), m_close.size()}); m_open.size(),
m_close.size()});
if (cur_pos == tmp.size()) { if (cur_pos == tmp.size()) {
m_tokens.push_back({{""}}); m_tokens.push_back({{""}});
m_tokens.back().eol(true); m_tokens.back().eol(true);
} }
if (*(beg + open_pos + m_open.size()) == '=' && if (*(beg + open_pos + m_open.size()) == '=' && *(beg + close_pos - 1) == '=') {
*(beg + close_pos - 1) == '=') auto tok_beg = beg + open_pos + m_open.size() + 1;
{ auto tok_end = beg + close_pos - 1;
auto tok_beg = beg + open_pos + m_open.size() + 1; auto front_skip = first_not_ws(tok_beg, tok_end);
auto tok_end = beg + close_pos - 1; auto back_skip = first_not_ws(reverse(tok_end), reverse(tok_beg));
auto front_skip = first_not_ws(tok_beg, tok_end); m_open = {front_skip, beg + tmp.find(' ', front_skip - beg)};
auto back_skip = first_not_ws(reverse(tok_end), reverse(tok_beg)); m_close = {beg + tmp.rfind(' ', back_skip - beg) + 1, back_skip + 1};
m_open = {front_skip, beg + tmp.find(' ', front_skip - beg)}; }
m_close = {beg + tmp.rfind(' ', back_skip - beg) + 1, back_skip + 1}; } else {
} process_text(beg + cur_pos, tmp.end());
} else { cur_pos = close_pos;
process_text(beg + cur_pos, tmp.end()); }
cur_pos = close_pos;
} }
}
} }
void template_type::strip_whitespace() { void template_type::strip_whitespace() {
auto line_begin = m_tokens.begin(); auto line_begin = m_tokens.begin();
bool has_tag = false, non_space = false; bool has_tag = false, non_space = false;
for (auto it = m_tokens.begin(); it != m_tokens.end(); ++it) { for (auto it = m_tokens.begin(); it != m_tokens.end(); ++it) {
auto type = (*it).token_type(); auto type = (*it).token_type();
if (type != token::type::text && type != token::type::variable && if (type != token::type::text && type != token::type::variable &&
type != token::type::unescaped_variable) type != token::type::unescaped_variable)
has_tag = true; has_tag = true;
else if (!(*it).ws_only()) else if (!(*it).ws_only())
non_space = true; non_space = true;
if ((*it).eol()) { if ((*it).eol()) {
if (has_tag && !non_space) { if (has_tag && !non_space) {
store_prefixes(line_begin); store_prefixes(line_begin);
auto c = line_begin; auto c = line_begin;
for (bool end = false; !end; (*c).ws_only() ? c = m_tokens.erase(c) : ++c) for (bool end = false; !end; (*c).ws_only() ? c = m_tokens.erase(c) : ++c)
if ((end = (*c).eol())) if ((end = (*c).eol()))
it = c - 1; it = c - 1;
} }
non_space = has_tag = false; non_space = has_tag = false;
line_begin = it + 1; line_begin = it + 1;
}
} }
}
} }
void template_type::store_prefixes(std::vector<token>::iterator beg) { void template_type::store_prefixes(std::vector<token>::iterator beg) {
for (auto cur = beg; !(*cur).eol(); ++cur) for (auto cur = beg; !(*cur).eol(); ++cur)
if ((*cur).token_type() == token::type::partial && if ((*cur).token_type() == token::type::partial && cur != beg && (*(cur - 1)).ws_only())
cur != beg && (*(cur - 1)).ws_only()) (*cur).partial_prefix((*(cur - 1)).raw());
(*cur).partial_prefix((*(cur - 1)).raw());
} }

View File

@ -9,22 +9,22 @@
namespace mstch { namespace mstch {
class template_type { class template_type {
public: public:
template_type() = default; template_type() = default;
template_type(const std::string& str); template_type(const std::string& str);
template_type(const std::string& str, const delim_type& delims); template_type(const std::string& str, const delim_type& delims);
std::vector<token>::const_iterator begin() const { return m_tokens.begin(); } std::vector<token>::const_iterator begin() const { return m_tokens.begin(); }
std::vector<token>::const_iterator end() const { return m_tokens.end(); } std::vector<token>::const_iterator end() const { return m_tokens.end(); }
void operator<<(const token& token) { m_tokens.push_back(token); } void operator<<(const token& token) { m_tokens.push_back(token); }
private: private:
std::vector<token> m_tokens; std::vector<token> m_tokens;
std::string m_open; std::string m_open;
std::string m_close; std::string m_close;
void strip_whitespace(); void strip_whitespace();
void process_text(citer beg, citer end); void process_text(citer beg, citer end);
void tokenize(const std::string& tmp); void tokenize(const std::string& tmp);
void store_prefixes(std::vector<token>::iterator beg); void store_prefixes(std::vector<token>::iterator beg);
}; };
} } // namespace mstch

View File

@ -4,39 +4,45 @@
using namespace mstch; using namespace mstch;
token::type token::token_info(char c) { token::type token::token_info(char c) {
switch (c) { switch (c) {
case '>': return type::partial; case '>':
case '^': return type::inverted_section_open; return type::partial;
case '/': return type::section_close; case '^':
case '&': return type::unescaped_variable; return type::inverted_section_open;
case '#': return type::section_open; case '/':
case '!': return type::comment; return type::section_close;
default: return type::variable; case '&':
} return type::unescaped_variable;
case '#':
return type::section_open;
case '!':
return type::comment;
default:
return type::variable;
}
} }
token::token(const std::string& str, std::size_t left, std::size_t right): token::token(const std::string& str, std::size_t left, std::size_t right)
m_raw(str), m_eol(false), m_ws_only(false) : m_raw(str), m_eol(false), m_ws_only(false)
{ {
if (left != 0 && right != 0) { if (left != 0 && right != 0) {
if (str[left] == '=' && str[str.size() - right - 1] == '=') { if (str[left] == '=' && str[str.size() - right - 1] == '=') {
m_type = type::delimiter_change; m_type = type::delimiter_change;
} else if (str[left] == '{' && str[str.size() - right - 1] == '}') { } else if (str[left] == '{' && str[str.size() - right - 1] == '}') {
m_type = type::unescaped_variable; m_type = type::unescaped_variable;
m_name = {first_not_ws(str.begin() + left + 1, str.end() - right), m_name = {first_not_ws(str.begin() + left + 1, str.end() - right),
first_not_ws(str.rbegin() + 1 + right, str.rend() - left) + 1}; first_not_ws(str.rbegin() + 1 + right, str.rend() - left) + 1};
} else {
auto c = first_not_ws(str.begin() + left, str.end() - right);
m_type = token_info(*c);
if (m_type != type::variable)
c = first_not_ws(c + 1, str.end() - right);
m_name = {c, first_not_ws(str.rbegin() + right, str.rend() - left) + 1};
m_delims = {{str.begin(), str.begin() + left}, {str.end() - right, str.end()}};
}
} else { } else {
auto c = first_not_ws(str.begin() + left, str.end() - right); m_type = type::text;
m_type = token_info(*c); m_eol = (str.size() > 0 && str[str.size() - 1] == '\n');
if (m_type != type::variable) m_ws_only = (str.find_first_not_of(" \r\n\t") == std::string::npos);
c = first_not_ws(c + 1, str.end() - right);
m_name = {c, first_not_ws(str.rbegin() + right, str.rend() - left) + 1};
m_delims = {{str.begin(), str.begin() + left},
{str.end() - right, str.end()}};
} }
} else {
m_type = type::text;
m_eol = (str.size() > 0 && str[str.size() - 1] == '\n');
m_ws_only = (str.find_first_not_of(" \r\n\t") == std::string::npos);
}
} }

View File

@ -7,33 +7,40 @@ namespace mstch {
using delim_type = std::pair<std::string, std::string>; using delim_type = std::pair<std::string, std::string>;
class token { class token {
public: public:
enum class type { enum class type {
text, variable, section_open, section_close, inverted_section_open, text,
unescaped_variable, comment, partial, delimiter_change variable,
}; section_open,
token(const std::string& str, std::size_t left = 0, std::size_t right = 0); section_close,
type token_type() const { return m_type; }; inverted_section_open,
const std::string& raw() const { return m_raw; }; unescaped_variable,
const std::string& name() const { return m_name; }; comment,
const std::string& partial_prefix() const { return m_partial_prefix; }; partial,
const delim_type& delims() const { return m_delims; }; delimiter_change
void partial_prefix(const std::string& p_partial_prefix) { };
m_partial_prefix = p_partial_prefix; token(const std::string& str, std::size_t left = 0, std::size_t right = 0);
}; type token_type() const { return m_type; };
bool eol() const { return m_eol; } const std::string& raw() const { return m_raw; };
void eol(bool eol) { m_eol = eol; } const std::string& name() const { return m_name; };
bool ws_only() const { return m_ws_only; } const std::string& partial_prefix() const { return m_partial_prefix; };
const delim_type& delims() const { return m_delims; };
void partial_prefix(const std::string& p_partial_prefix) {
m_partial_prefix = p_partial_prefix;
};
bool eol() const { return m_eol; }
void eol(bool eol) { m_eol = eol; }
bool ws_only() const { return m_ws_only; }
private: private:
type m_type; type m_type;
std::string m_name; std::string m_name;
std::string m_raw; std::string m_raw;
std::string m_partial_prefix; std::string m_partial_prefix;
delim_type m_delims; delim_type m_delims;
bool m_eol; bool m_eol;
bool m_ws_only; bool m_ws_only;
type token_info(char c); type token_info(char c);
}; };
} } // namespace mstch

View File

@ -2,43 +2,58 @@
#include "mstch/mstch.hpp" #include "mstch/mstch.hpp"
mstch::citer mstch::first_not_ws(mstch::citer begin, mstch::citer end) { mstch::citer mstch::first_not_ws(mstch::citer begin, mstch::citer end) {
for (auto it = begin; it != end; ++it) for (auto it = begin; it != end; ++it)
if (*it != ' ') return it; if (*it != ' ')
return end; return it;
return end;
} }
mstch::citer mstch::first_not_ws(mstch::criter begin, mstch::criter end) { mstch::citer mstch::first_not_ws(mstch::criter begin, mstch::criter end) {
for (auto rit = begin; rit != end; ++rit) for (auto rit = begin; rit != end; ++rit)
if (*rit != ' ') return --(rit.base()); if (*rit != ' ')
return --(end.base()); return --(rit.base());
return --(end.base());
} }
mstch::criter mstch::reverse(mstch::citer it) { mstch::criter mstch::reverse(mstch::citer it) {
return std::reverse_iterator<mstch::citer>(it); return std::reverse_iterator<mstch::citer>(it);
} }
std::string mstch::html_escape(const std::string& str) { std::string mstch::html_escape(const std::string& str) {
if (mstch::config::escape) if (mstch::config::escape)
return mstch::config::escape(str); return mstch::config::escape(str);
std::string out; std::string out;
citer start = str.begin(); citer start = str.begin();
auto add_escape = [&out, &start](const std::string& escaped, citer& it) { auto add_escape = [&out, &start](const std::string& escaped, citer& it) {
out += std::string{start, it} + escaped; out += std::string{start, it} + escaped;
start = it + 1; start = it + 1;
}; };
for (auto it = str.begin(); it != str.end(); ++it) for (auto it = str.begin(); it != str.end(); ++it)
switch (*it) { switch (*it) {
case '&': add_escape("&amp;", it); break; case '&':
case '\'': add_escape("&#39;", it); break; add_escape("&amp;", it);
case '"': add_escape("&quot;", it); break; break;
case '<': add_escape("&lt;", it); break; case '\'':
case '>': add_escape("&gt;", it); break; add_escape("&#39;", it);
case '/': add_escape("&#x2F;", it); break; break;
default: break; case '"':
} add_escape("&quot;", it);
break;
case '<':
add_escape("&lt;", it);
break;
case '>':
add_escape("&gt;", it);
break;
case '/':
add_escape("&#x2F;", it);
break;
default:
break;
}
return out + std::string{start, str.end()}; return out + std::string{start, str.end()};
} }

View File

@ -1,11 +1,11 @@
#pragma once #pragma once
#include <string> #include <string>
#include <boost/variant/apply_visitor.hpp> #include <variant>
namespace mstch { namespace mstch {
using citer = std::string::const_iterator; using citer = std::string::const_iterator;
using criter = std::string::const_reverse_iterator; using criter = std::string::const_reverse_iterator;
citer first_not_ws(citer begin, citer end); citer first_not_ws(citer begin, citer end);
@ -14,10 +14,8 @@ std::string html_escape(const std::string& str);
criter reverse(citer it); criter reverse(citer it);
template<class... Args> template<class... Args>
auto visit(Args&&... args) -> decltype(boost::apply_visitor( auto visit(Args&&... args) -> decltype(std::visit(std::forward<Args>(args)...)) {
std::forward<Args>(args)...)) return std::visit(std::forward<Args>(args)...);
{
return boost::apply_visitor(std::forward<Args>(args)...);
} }
} } // namespace mstch

View File

@ -1,35 +1,32 @@
#pragma once #pragma once
#include <boost/variant/static_visitor.hpp>
#include "mstch/mstch.hpp"
#include "has_token.hpp" #include "has_token.hpp"
#include "mstch/mstch.hpp"
namespace mstch { namespace mstch {
class get_token: public boost::static_visitor<const mstch::node&> { class get_token {
public: public:
get_token(const std::string& token, const mstch::node& node): get_token(const std::string& token, const mstch::node& node)
m_token(token), m_node(node) : m_token(token), m_node(node)
{ {}
}
template<class T> template<class T>
const mstch::node& operator()(const T&) const { const mstch::node& operator()(const T&) const {
return m_node; return m_node;
} }
const mstch::node& operator()(const map& map) const { const mstch::node& operator()(const map_wrapper& map) const {
return map.at(m_token); return map.values.at(m_token);
} }
const mstch::node& operator()(const std::shared_ptr<object>& object) const { const mstch::node& operator()(const object_wrapper& object) const {
return object->at(m_token); return object.values->at(m_token);
} }
private: private:
const std::string& m_token; const std::string& m_token;
const mstch::node& m_node; const mstch::node& m_node;
}; };
} } // namespace mstch

View File

@ -1,31 +1,24 @@
#pragma once #pragma once
#include <boost/variant/static_visitor.hpp>
#include "mstch/mstch.hpp" #include "mstch/mstch.hpp"
namespace mstch { namespace mstch {
class has_token: public boost::static_visitor<bool> { class has_token {
public: public:
has_token(const std::string& token): m_token(token) { has_token(const std::string& token) : m_token(token) {}
}
template<class T> template<class T>
bool operator()(const T&) const { bool operator()(const T&) const {
return m_token == "."; return m_token == ".";
} }
bool operator()(const map& map) const { bool operator()(const map_wrapper& map) const { return map.values.count(m_token) == 1; }
return map.count(m_token) == 1;
}
bool operator()(const std::shared_ptr<object>& object) const { bool operator()(const object_wrapper& object) const { return object.values->has(m_token); }
return object->has(m_token);
}
private: private:
const std::string& m_token; const std::string& m_token;
}; };
} } // namespace mstch

View File

@ -1,41 +1,27 @@
#pragma once #pragma once
#include <boost/variant/static_visitor.hpp>
#include "mstch/mstch.hpp" #include "mstch/mstch.hpp"
namespace mstch { namespace mstch {
class is_node_empty: public boost::static_visitor<bool> { class is_node_empty {
public: public:
template<class T> template<class T>
bool operator()(const T&) const { bool operator()(const T&) const {
return false; return false;
} }
bool operator()(const std::nullptr_t&) const { bool operator()(const std::nullptr_t&) const { return true; }
return true;
}
bool operator()(const int& value) const { bool operator()(const int& value) const { return value == 0; }
return value == 0;
}
bool operator()(const double& value) const { bool operator()(const double& value) const { return value == 0; }
return value == 0;
}
bool operator()(const bool& value) const { bool operator()(const bool& value) const { return !value; }
return !value;
}
bool operator()(const std::string& value) const { bool operator()(const std::string& value) const { return value == ""; }
return value == "";
}
bool operator()(const array& array) const { bool operator()(const array_wrapper& array) const { return array.values.size() == 0; }
return array.size() == 0;
}
}; };
} } // namespace mstch

View File

@ -1,56 +1,48 @@
#pragma once #pragma once
#include <sstream> #include <sstream>
#include <boost/variant/static_visitor.hpp>
#include "render_context.hpp"
#include "mstch/mstch.hpp" #include "mstch/mstch.hpp"
#include "render_context.hpp"
#include "utils.hpp" #include "utils.hpp"
namespace mstch { namespace mstch {
class render_node: public boost::static_visitor<std::string> { class render_node {
public: public:
enum class flag { none, escape_html }; enum class flag { none, escape_html };
render_node(render_context& ctx, flag p_flag = flag::none): render_node(render_context& ctx, flag p_flag = flag::none) : m_ctx(ctx), m_flag(p_flag) {}
m_ctx(ctx), m_flag(p_flag)
{
}
template<class T> template<class T>
std::string operator()(const T&) const { std::string operator()(const T&) const {
return ""; return "";
} }
std::string operator()(const int& value) const { std::string operator()(const int& value) const { return std::to_string(value); }
return std::to_string(value);
}
std::string operator()(const double& value) const { std::string operator()(const double& value) const {
std::stringstream ss; std::stringstream ss;
ss << value; ss << value;
return ss.str(); return ss.str();
} }
std::string operator()(const bool& value) const { std::string operator()(const bool& value) const { return value ? "true" : "false"; }
return value ? "true" : "false";
}
std::string operator()(const lambda& value) const { std::string operator()(const lambda_wrapper& value) const {
template_type interpreted{value([this](const mstch::node& n) { template_type interpreted{value.values(
return visit(render_node(m_ctx), n); [this](const mstch::node& n) { return visit(render_node(m_ctx), n); })};
})};
auto rendered = render_context::push(m_ctx).render(interpreted);
return (m_flag == flag::escape_html) ? html_escape(rendered) : rendered;
}
std::string operator()(const std::string& value) const { auto rendered = render_context::push(m_ctx).render(interpreted);
return (m_flag == flag::escape_html) ? html_escape(value) : value; return (m_flag == flag::escape_html) ? html_escape(rendered) : rendered;
} }
private: std::string operator()(const std::string& value) const {
render_context& m_ctx; return (m_flag == flag::escape_html) ? html_escape(value) : value;
flag m_flag; }
private:
render_context& m_ctx;
flag m_flag;
}; };
} } // namespace mstch

View File

@ -1,57 +1,57 @@
#pragma once #pragma once
#include <boost/variant/static_visitor.hpp>
#include "render_context.hpp"
#include "mstch/mstch.hpp" #include "mstch/mstch.hpp"
#include "utils.hpp" #include "render_context.hpp"
#include "render_node.hpp" #include "render_node.hpp"
#include "utils.hpp"
namespace mstch { namespace mstch {
class render_section: public boost::static_visitor<std::string> { class render_section {
public: public:
enum class flag { none, keep_array }; enum class flag { none, keep_array };
render_section( render_section(render_context& ctx,
render_context& ctx, const template_type& section,
const template_type& section, const delim_type& delims,
const delim_type& delims, flag p_flag = flag::none)
flag p_flag = flag::none): : m_ctx(ctx), m_section(section), m_delims(delims), m_flag(p_flag)
m_ctx(ctx), m_section(section), m_delims(delims), m_flag(p_flag) {}
{
}
template<class T> template<class T>
std::string operator()(const T& t) const { std::string operator()(const T& t) const {
return render_context::push(m_ctx, t).render(m_section); return render_context::push(m_ctx, t).render(m_section);
} }
std::string operator()(const lambda& fun) const { std::string operator()(const lambda_wrapper& fun) const {
std::string section_str; std::string section_str;
for (auto& token: m_section) for (auto& token : m_section)
section_str += token.raw(); section_str += token.raw();
template_type interpreted{fun([this](const mstch::node& n) { template_type interpreted{fun.values(
return visit(render_node(m_ctx), n); [this](const mstch::node& n) {
}, section_str), m_delims}; return visit(render_node(m_ctx), n);
return render_context::push(m_ctx).render(interpreted); },
} section_str),
m_delims};
return render_context::push(m_ctx).render(interpreted);
}
std::string operator()(const array& array) const { std::string operator()(const array_wrapper& array) const {
std::string out; std::string out;
if (m_flag == flag::keep_array)
return render_context::push(m_ctx, array).render(m_section);
else
for (auto& item: array)
out += visit(render_section(
m_ctx, m_section, m_delims, flag::keep_array), item);
return out;
}
private: if (m_flag == flag::keep_array)
render_context& m_ctx; return render_context::push(m_ctx, array).render(m_section);
const template_type& m_section;
const delim_type& m_delims; for (auto& item : array.values)
flag m_flag; out += visit(render_section(m_ctx, m_section, m_delims, flag::keep_array), item);
return out;
}
private:
render_context& m_ctx;
const template_type& m_section;
const delim_type& m_delims;
flag m_flag;
}; };
} } // namespace mstch

View File

@ -1,3 +1,2 @@
const auto ampersand_escape_data = mstch::map{ const mstch::node ampersand_escape_data =
{"message", std::string{"Some <code>"}} mstch::map_wrapper{{{"message", std::string{"Some <code>"}}}};
};

View File

@ -1,4 +1,2 @@
const auto apostrophe_data = mstch::map{ const mstch::node apostrophe_data =
{"apos", std::string{"'"}}, mstch::map_wrapper{{{"apos", std::string{"'"}}, {"control", std::string{"X"}}}};
{"control", std::string{"X"}}
};

View File

@ -1,3 +1,3 @@
const auto array_of_strings_data = mstch::map{ const mstch::node array_of_strings_data = mstch::map_wrapper{
{"array_of_strings", mstch::array{std::string{"hello"}, std::string{"world"}}} {{"array_of_strings",
}; mstch::array_wrapper{{std::string{"hello"}, std::string{"world"}}}}}};

View File

@ -1,3 +1 @@
const auto backslashes_data = mstch::map{ const mstch::node backslashes_data = mstch::map_wrapper{{{"value", std::string{"\\abc"}}}};
{"value", std::string{"\\abc"}}
};

View File

@ -1,3 +1,2 @@
const auto bug_11_eating_whitespace_data = mstch::map{ const mstch::node bug_11_eating_whitespace_data =
{"tag", std::string{"yo"}} mstch::map_wrapper{{{"tag", std::string{"yo"}}}};
};

View File

@ -1,3 +1,2 @@
const auto bug_length_property_data = mstch::map{ const mstch::node bug_length_property_data =
{"length", std::string{"hello"}} mstch::map_wrapper{{{"length", std::string{"hello"}}}};
};

View File

@ -1,4 +1,2 @@
const mstch::node changing_delimiters_data = mstch::map{ const mstch::node changing_delimiters_data = mstch::map_wrapper{
{"foo", std::string{"foooooooooooooo"}}, {{"foo", std::string{"foooooooooooooo"}}, {"bar", std::string{"<b>bar!</b>"}}}};
{"bar", std::string{"<b>bar!</b>"}}
};

View File

@ -1,3 +1,4 @@
const mstch::node comments_data = mstch::map{ const mstch::node comments_data =
{"title", mstch::lambda{[]()->mstch::node{return std::string{"A Comedy of Errors"};}}} mstch::map_wrapper{{{"title", mstch::lambda_wrapper{{[]() -> mstch::node {
}; return std::string{"A Comedy of Errors"};
}}}}}};

View File

@ -1,69 +1,61 @@
class complex_item: public mstch::object { class complex_item : public mstch::object {
private: private:
std::string m_name; std::string m_name;
bool m_current; bool m_current;
std::string m_url; std::string m_url;
public: public:
complex_item(const std::string& name, bool current, const std::string& url): complex_item(const std::string& name, bool current, const std::string& url)
m_name(name), m_current(current), m_url(url) : m_name(name), m_current(current), m_url(url)
{ {
register_methods(this, std::map<std::string,mstch::node(complex_item::*)()>{ register_methods(this,
{"name", &complex_item::name}, {"current", &complex_item::current}, std::map<std::string, mstch::node (complex_item::*)()>{
{"url", &complex_item::url}, {"link", &complex_item::link} {"name", &complex_item::name},
}); {"current", &complex_item::current},
} {"url", &complex_item::url},
{"link", &complex_item::link}});
}
mstch::node current() { mstch::node current() { return m_current; }
return m_current;
}
mstch::node url() { mstch::node url() { return m_url; }
return m_url;
}
mstch::node name() { mstch::node name() { return m_name; }
return m_name;
}
mstch::node link() { mstch::node link() { return !m_current; }
return !m_current;
}
}; };
class complex: public mstch::object { class complex : public mstch::object {
private: private:
std::string m_header; std::string m_header;
mstch::array m_item; mstch::array m_item;
public: public:
complex(): complex()
m_header("Colors"), : m_header("Colors")
m_item(mstch::array{ , m_item(mstch::array{mstch::object_wrapper{
std::make_shared<complex_item>("red", true, "#Red"), std::make_shared<complex_item>("red", true, "#Red")},
std::make_shared<complex_item>("green", false, "#Green"), mstch::object_wrapper{
std::make_shared<complex_item>("blue", false, "#Blue") std::make_shared<complex_item>("green", false, "#Green")},
}) mstch::object_wrapper{std::make_shared<complex_item>("blue",
{ false,
register_methods(this, std::map<std::string,mstch::node(complex::*)()>{ "#Blue")}})
{"header", &complex::header}, {"item", &complex::item}, {
{"list", &complex::list}, {"empty", &complex::empty} register_methods(
}); this,
} std::map<std::string, mstch::node (complex::*)()>{{"header", &complex::header},
{"item", &complex::item},
{"list", &complex::list},
{"empty", &complex::empty}});
}
mstch::node header() { mstch::node header() { return m_header; }
return m_header;
}
mstch::node item() { mstch::node item() { return mstch::array_wrapper{m_item}; }
return m_item;
}
mstch::node list() { mstch::node list() { return m_item.size() != 0; }
return m_item.size() != 0;
}
mstch::node empty() { mstch::node empty() { return m_item.size() == 0; }
return m_item.size() == 0;
}
}; };
const auto complex_data = std::make_shared<complex>(); const auto complex_data = mstch::object_wrapper{std::make_shared<complex>()};

View File

@ -1,8 +1,3 @@
const auto context_lookup_data = mstch::map{ const mstch::node context_lookup_data = mstch::map_wrapper{
{"outer", mstch::map{ {{"outer",
{"id", 1}, mstch::map_wrapper{{{"id", 1}, {"second", mstch::map_wrapper{{{"nothing", 2}}}}}}}}};
{"second", mstch::map{
{"nothing", 2}
}}
}}
};

View File

@ -1,6 +1,5 @@
const mstch::node delimiters_data = mstch::map{ const mstch::node delimiters_data = mstch::map_wrapper{
{"first", std::string{"It worked the first time."}}, {{"first", std::string{"It worked the first time."}},
{"second", std::string{"And it worked the second time."}}, {"second", std::string{"And it worked the second time."}},
{"third", std::string{"Then, surprisingly, it worked the third time."}}, {"third", std::string{"Then, surprisingly, it worked the third time."}},
{"fourth", std::string{"Fourth time also fine!."}} {"fourth", std::string{"Fourth time also fine!."}}}};
};

View File

@ -1,4 +1,2 @@
const auto disappearing_whitespace_data = mstch::map{ const mstch::node disappearing_whitespace_data =
{"bedrooms", true}, mstch::map_wrapper{{{"bedrooms", true}, {"total", 1}}};
{"total", 1}
};

View File

@ -1,34 +1,32 @@
class dot_notation_price: public mstch::object { class dot_notation_price : public mstch::object {
private: private:
int m_value; int m_value;
mstch::map m_currency; mstch::map m_currency;
public: public:
dot_notation_price(): dot_notation_price()
m_value(200), m_currency(mstch::map{{"symbol", std::string{"$"}}, {"name", std::string{"USD"}}}) : m_value(200)
{ , m_currency(mstch::map{{"symbol", std::string{"$"}}, {"name", std::string{"USD"}}})
register_methods(this, std::map<std::string,mstch::node(dot_notation_price::*)()>{ {
{"value", &dot_notation_price::value}, register_methods(this,
{"vat", &dot_notation_price::vat}, std::map<std::string, mstch::node (dot_notation_price::*)()>{
{"currency", &dot_notation_price::currency}}); {"value", &dot_notation_price::value},
} {"vat", &dot_notation_price::vat},
{"currency", &dot_notation_price::currency}});
}
mstch::node value() { mstch::node value() { return m_value; }
return m_value;
}
mstch::node vat() { mstch::node vat() { return m_value * 0.2; }
return m_value * 0.2;
}
mstch::node currency() { mstch::node currency() { return mstch::map_wrapper{m_currency}; }
return m_currency;
}
}; };
const auto dot_notation_data = mstch::map{ const mstch::node dot_notation_data = mstch::map_wrapper{
{"name", std::string{"A Book"}}, {{"name", std::string{"A Book"}},
{"authors", mstch::array{std::string{"John Power"}, std::string{"Jamie Walsh"}}}, {"authors",
{"price", std::make_shared<dot_notation_price>()}, mstch::array_wrapper{{std::string{"John Power"}, std::string{"Jamie Walsh"}}}},
{"availability", mstch::map{{"status", true}, {"text", std::string{"In Stock"}}}}, {"price", mstch::object_wrapper{std::make_shared<dot_notation_price>()}},
{"truthy", mstch::map{{"zero", 0}, {"notTrue", false}}} {"availability",
}; mstch::map_wrapper{{{"status", true}, {"text", std::string{"In Stock"}}}}},
{"truthy", mstch::map_wrapper{{{"zero", 0}, {"notTrue", false}}}}}};

View File

@ -1,5 +1,2 @@
const auto double_render_data = mstch::map{ const mstch::node double_render_data = mstch::map_wrapper{
{"foo", true}, {{"foo", true}, {"bar", std::string{"{{win}}"}}, {"win", std::string{"FAIL"}}}};
{"bar", std::string{"{{win}}"}},
{"win", std::string{"FAIL"}}
};

View File

@ -1,3 +1 @@
const auto empty_list_data = mstch::map{ const mstch::node empty_list_data = mstch::map_wrapper{{{"jobs", mstch::array_wrapper{}}}};
{"jobs", mstch::array{}}
};

View File

@ -1 +1 @@
const auto empty_sections_data = mstch::map{}; const mstch::node empty_sections_data = mstch::map_wrapper{{}};

View File

@ -1,6 +1,5 @@
const auto empty_string_data = mstch::map{ #include "mstch/mstch.hpp"
{"description", std::string{"That is all!"}},
{"child", mstch::map{ const auto empty_string_data =
{"description", std::string{""}} mstch::map_wrapper{{{"description", std::string{"That is all!"}},
}} {"child", mstch::map_wrapper{{{"description", std::string{""}}}}}}};
};

View File

@ -1 +1 @@
const auto empty_template_data = mstch::map{}; const mstch::node empty_template_data = mstch::map_wrapper{{}};

View File

@ -1,3 +1,2 @@
const auto error_eof_in_section_data = mstch::map{ const mstch::node error_eof_in_section_data = mstch::map_wrapper{
{"hello", mstch::array{std::string{"a"}, std::string{"b"}}} {{"hello", mstch::array_wrapper{{std::string{"a"}, std::string{"b"}}}}}};
};

View File

@ -1 +1 @@
const auto error_eof_in_tag_data = mstch::map{{"hello", std::string{"world"}}}; const mstch::node error_eof_in_tag_data = mstch::map_wrapper{{{"hello", std::string{"world"}}}};

View File

@ -1,3 +1 @@
const auto error_not_found_data = mstch::map{ const mstch::node error_not_found_data = mstch::map_wrapper{{{"bar", 2}}};
{"bar", 2}
};

View File

@ -1,4 +1,6 @@
const mstch::node escaped_data = mstch::map{ const mstch::node escaped_data = mstch::map_wrapper{
{"title", mstch::lambda{[]()->mstch::node{ return std::string{"Bear > Shark"}; }}}, {{"title",
{"entities", mstch::lambda{[]()->mstch::node{ return std::string{"&quot; \"'<>/"}; }}} mstch::lambda_wrapper{{[]() -> mstch::node { return std::string{"Bear > Shark"}; }}}},
}; {"entities", mstch::lambda_wrapper{{[]() -> mstch::node {
return std::string{"&quot; \"'<>/"};
}}}}}};

View File

@ -1,6 +1,4 @@
const auto falsy_data = mstch::map{ const auto falsy_data = mstch::map_wrapper{{{"emptyString", std::string{""}},
{"emptyString", std::string{""}}, {"emptyArray", mstch::array_wrapper{}},
{"emptyArray", mstch::array{}}, {"zero", 0},
{"zero", 0}, {"null", mstch::node{}}}};
{"null", mstch::node{}}
};

View File

@ -1,8 +1,7 @@
const auto falsy_array_data = mstch::map{ const auto falsy_array_data = mstch::map_wrapper{
{"list", mstch::array{ {{"list",
mstch::array{std::string{""}, std::string{"emptyString"}}, mstch::array_wrapper{
mstch::array{mstch::array{}, std::string{"emptyArray"}}, {mstch::array_wrapper{{std::string{""}, std::string{"emptyString"}}},
mstch::array{0, std::string{"zero"}}, mstch::array_wrapper{{mstch::array_wrapper{}, std::string{"emptyArray"}}},
mstch::array{mstch::node{}, std::string{"null"}}} mstch::array_wrapper{{0, std::string{"zero"}}},
} mstch::array_wrapper{{mstch::node{}, std::string{"null"}}}}}}}};
};

View File

@ -1,19 +1,22 @@
const auto grandparent_context_data = mstch::map{ const auto grandparent_context_data = mstch::map_wrapper{
{"grand_parent_id", std::string{"grand_parent1"}}, {{"grand_parent_id", std::string{"grand_parent1"}},
{"parent_contexts", mstch::array{ {"parent_contexts",
mstch::map{ mstch::array_wrapper{
{"parent_id", std::string{"parent1"}}, {mstch::map_wrapper{
{"child_contexts", mstch::array{ {{"parent_id", std::string{"parent1"}},
mstch::map{{"child_id", std::string{"parent1-child1"}}}, {"child_contexts",
mstch::map{{"child_id", std::string{"parent1-child2"}}} mstch::array_wrapper{
}} {mstch::map_wrapper{
}, {{"child_id", std::string{"parent1-child1"}}}},
mstch::map{ mstch::map_wrapper{
{"parent_id", std::string{"parent2"}}, {{"child_id",
{"child_contexts", mstch::array{ std::string{"parent1-child2"}}}}}}}}},
mstch::map{{"child_id", std::string{"parent2-child1"}}}, mstch::map_wrapper{
mstch::map{{"child_id", std::string{"parent2-child2"}}} {{"parent_id", std::string{"parent2"}},
}} {"child_contexts",
} mstch::array_wrapper{
}} {mstch::map_wrapper{
}; {{"child_id", std::string{"parent2-child1"}}}},
mstch::map_wrapper{
{{"child_id",
std::string{"parent2-child2"}}}}}}}}}}}}}};

View File

@ -1,28 +1,26 @@
class higher_order_sections: public mstch::object { class higher_order_sections : public mstch::object {
private: private:
std::string m_helper; std::string m_helper;
public:
higher_order_sections(): m_helper("To tinker?") {
register_methods(this, std::map<std::string,mstch::node(higher_order_sections::*)()>{
{"name", &higher_order_sections::name},
{"helper", &higher_order_sections::helper},
{"bolder", &higher_order_sections::bolder}
});
}
mstch::node name() { public:
return std::string{"Tater"}; higher_order_sections() : m_helper("To tinker?") {
} register_methods(this,
std::map<std::string, mstch::node (higher_order_sections::*)()>{
{"name", &higher_order_sections::name},
{"helper", &higher_order_sections::helper},
{"bolder", &higher_order_sections::bolder}});
}
mstch::node helper() { mstch::node name() { return std::string{"Tater"}; }
return m_helper;
}
mstch::node bolder() { mstch::node helper() { return m_helper; }
return mstch::lambda{[this](const std::string& text) -> mstch::node {
return "<b>" + text + "</b> " + m_helper; mstch::node bolder() {
}}; return mstch::lambda_wrapper{{[this](const std::string& text) -> mstch::node {
} return "<b>" + text + "</b> " + m_helper;
}}};
}
}; };
const mstch::node higher_order_sections_data = std::make_shared<higher_order_sections>(); const mstch::node higher_order_sections_data =
mstch::object_wrapper{std::make_shared<higher_order_sections>()};

View File

@ -1,8 +1,5 @@
const auto implicit_iterator_data = mstch::map{ const auto implicit_iterator_data = mstch::map_wrapper{
{"data", mstch::map{ {{"data",
{"author", mstch::map{ mstch::map_wrapper{{{"author",
{"twitter_id", 819606}, mstch::map_wrapper{{{"twitter_id", 819606},
{"name", std::string{"janl"}} {"name", std::string{"janl"}}}}}}}}}};
}}
}}
};

View File

@ -1,3 +1,2 @@
const auto included_tag_data = mstch::map{ const mstch::node included_tag_data =
{"html", std::string{"I like {{mustache}}"}} mstch::map_wrapper{{{"html", std::string{"I like {{mustache}}"}}}};
};

View File

@ -1,3 +1 @@
const auto inverted_section_data = mstch::map{ const auto inverted_section_data = mstch::map_wrapper{{{"repos", mstch::array_wrapper{}}}};
{"repos", mstch::array{}}
};

View File

@ -1,5 +1,2 @@
const auto keys_with_questionmarks_data = mstch::map{ const auto keys_with_questionmarks_data =
{"person?", mstch::map{ mstch::map_wrapper{{{"person?", mstch::map_wrapper{{{"name", std::string{"Jon"}}}}}}};
{"name", std::string{"Jon"}}
}}
};

View File

@ -1 +1 @@
const auto multiline_comment_data = mstch::map{}; const mstch::node multiline_comment_data = mstch::map_wrapper{{}};

View File

@ -1 +1 @@
const auto nested_dot_data = mstch::map{{"name", std::string{"Bruno"}}}; const mstch::node nested_dot_data = mstch::map_wrapper{{{"name", std::string{"Bruno"}}}};

View File

@ -1,6 +1,5 @@
const mstch::node nested_higher_order_sections_data = mstch::map{ const mstch::node nested_higher_order_sections_data = mstch::map_wrapper{
{"bold", mstch::lambda{[](const std::string& text) -> mstch::node { {{"bold", mstch::lambda_wrapper{{[](const std::string& text) -> mstch::node {
return std::string{"<b>"} + text + std::string{"</b>"}; return std::string{"<b>"} + text + std::string{"</b>"};
}}}, }}}},
{"person", mstch::map{{"name", std::string{"Jonas"}}}} {"person", mstch::map_wrapper{{{"name", std::string{"Jonas"}}}}}}};
};

View File

@ -1,8 +1,7 @@
const auto nested_iterating_data = mstch::map{ const mstch::node nested_iterating_data = mstch::map_wrapper{
{"inner", mstch::array{mstch::map{ {{"inner",
{"foo", std::string{"foo"}}, mstch::array_wrapper{
{"inner", mstch::array{mstch::map{ {mstch::map_wrapper{{{"foo", std::string{"foo"}},
{"bar", std::string{"bar"}} {"inner",
}}} mstch::array_wrapper{{mstch::map_wrapper{
}}} {{"bar", std::string{"bar"}}}}}}}}}}}}}};
};

View File

@ -1,7 +1,6 @@
const auto nesting_data = mstch::map{ const mstch::node nesting_data = mstch::map_wrapper{
{"foo", mstch::array{ {{"foo",
mstch::map{{"a", mstch::map{{"b", 1}}}}, mstch::array_wrapper{
mstch::map{{"a", mstch::map{{"b", 2}}}}, {mstch::map_wrapper{{{"a", mstch::map_wrapper{{{"b", 1}}}}}},
mstch::map{{"a", mstch::map{{"b", 3}}}} mstch::map_wrapper{{{"a", mstch::map_wrapper{{{"b", 2}}}}}},
}} mstch::map_wrapper{{{"a", mstch::map_wrapper{{{"b", 3}}}}}}}}}}};
};

View File

@ -1,8 +1,5 @@
const auto nesting_same_name_data = mstch::map{ const mstch::node nesting_same_name_data = mstch::map_wrapper{
{"items", mstch::array{ {{"items",
mstch::map{ mstch::array_wrapper{
{"name", std::string{"name"}}, {mstch::map_wrapper{{{"name", std::string{"name"}},
{"items", mstch::array{1, 2, 3, 4}} {"items", mstch::array_wrapper{{1, 2, 3, 4}}}}}}}}}};
}
}}
};

View File

@ -1,8 +1,8 @@
const auto null_lookup_array_data = mstch::map{ const mstch::node null_lookup_array_data = mstch::map_wrapper{
{"name", std::string{"David"}}, {{"name", std::string{"David"}},
{"twitter", std::string{"@dasilvacontin"}}, {"twitter", std::string{"@dasilvacontin"}},
{"farray", mstch::array{ {"farray",
mstch::array{std::string{"Flor"}, std::string{"@florrts"}}, mstch::array_wrapper{{
mstch::array{std::string{"Miquel"}, mstch::node{}}, mstch::array_wrapper{{std::string{"Flor"}, std::string{"@florrts"}}},
}} mstch::array_wrapper{{std::string{"Miquel"}, mstch::node{}}},
}; }}}}};

View File

@ -1,14 +1,8 @@
const auto null_lookup_object_data = mstch::map{ const mstch::node null_lookup_object_data = mstch::map_wrapper{
{"name", std::string{"David"}}, {{"name", std::string{"David"}},
{"twitter", std::string{"@dasilvacontin"}}, {"twitter", std::string{"@dasilvacontin"}},
{"fobject", mstch::array{ {"fobject",
mstch::map{ mstch::array_wrapper{{{mstch::map_wrapper{{{"name", std::string{"Flor"}},
{"name", std::string{"Flor"}}, {"twitter", std::string{"@florrts"}}}}},
{"twitter", std::string{"@florrts"}} mstch::map_wrapper{{{"name", std::string{"Miquel"}},
}, {"twitter", mstch::node{}}}}}}}}};
mstch::map{
{"name", std::string{"Miquel"}},
{"twitter", mstch::node{}}
}
}}
};

View File

@ -1,6 +1,4 @@
const auto null_string_data = mstch::map{ const mstch::node null_string_data = mstch::map_wrapper{{{"name", std::string{"Elise"}},
{"name", std::string{"Elise"}}, {"glytch", true},
{"glytch", true}, {"binary", false},
{"binary", false}, {"value", mstch::node{}}}};
{"value", mstch::node{}}
};

View File

@ -1,4 +1,2 @@
const auto null_view_data = mstch::map{ const mstch::node null_view_data =
{"name", std::string{"Joe"}}, mstch::map_wrapper{{{"name", std::string{"Joe"}}, {"friends", mstch::node{}}}};
{"friends", mstch::node{}}
};

View File

@ -1,3 +1,4 @@
const auto partial_array_data = mstch::map{ const mstch::node partial_array_data = mstch::map_wrapper{
{"array", mstch::array{std::string{"1"}, std::string{"2"}, std::string{"3"}, std::string{"4"}}} {{"array",
}; mstch::array_wrapper{
{std::string{"1"}, std::string{"2"}, std::string{"3"}, std::string{"4"}}}}}};

View File

@ -1,8 +1,6 @@
const auto partial_array_of_partials_data = mstch::map{ const mstch::node partial_array_of_partials_data = mstch::map_wrapper{
{"numbers", mstch::array{ {{"numbers",
mstch::map{{"i", std::string{"1"}}}, mstch::array_wrapper{{mstch::map_wrapper{{{"i", std::string{"1"}}}},
mstch::map{{"i", std::string{"2"}}}, mstch::map_wrapper{{{"i", std::string{"2"}}}},
mstch::map{{"i", std::string{"3"}}}, mstch::map_wrapper{{{"i", std::string{"3"}}}},
mstch::map{{"i", std::string{"4"}}} mstch::map_wrapper{{{"i", std::string{"4"}}}}}}}}};
}}
};

View File

@ -1,3 +1,4 @@
const auto partial_array_of_partials_implicit_data = mstch::map{ const mstch::node partial_array_of_partials_implicit_data = mstch::map_wrapper{
{"numbers", mstch::array{std::string{"1"}, std::string{"2"}, std::string{"3"}, std::string{"4"}}} {{"numbers",
}; mstch::array_wrapper{
{std::string{"1"}, std::string{"2"}, std::string{"3"}, std::string{"4"}}}}}};

View File

@ -1,3 +1 @@
const auto partial_empty_data = mstch::map{ const mstch::node partial_empty_data = mstch::map_wrapper{{{"foo", 1}}};
{"foo", 1}
};

View File

@ -1,4 +1,6 @@
const mstch::node partial_template_data = mstch::map{ const mstch::node partial_template_data = mstch::map_wrapper{{
{"title", mstch::lambda{[]()->mstch::node{ return std::string{"Welcome"}; }}}, {"title",
{"again", mstch::lambda{[]()->mstch::node{ return std::string{"Goodbye"}; }}}, mstch::lambda_wrapper{{[]() -> mstch::node { return std::string{"Welcome"}; }}}},
}; {"again",
mstch::lambda_wrapper{{[]() -> mstch::node { return std::string{"Goodbye"}; }}}},
}};

View File

@ -39,4 +39,4 @@ public:
} }
}; };
const auto partial_view_data = std::make_shared<partial_view>(); const mstch::node partial_view_data = mstch::object_wrapper{std::make_shared<partial_view>()};

View File

@ -1,41 +1,31 @@
class partial_whitespace: public mstch::object { class partial_whitespace : public mstch::object {
private: private:
int m_value; int m_value;
public: public:
partial_whitespace(): m_value(10000) { partial_whitespace() : m_value(10000) {
register_methods(this, std::map<std::string,mstch::node(partial_whitespace::*)()>{ register_methods(this,
{"greeting", &partial_whitespace::greeting}, std::map<std::string, mstch::node (partial_whitespace::*)()>{
{"farewell", &partial_whitespace::farewell}, {"greeting", &partial_whitespace::greeting},
{"name", &partial_whitespace::name}, {"farewell", &partial_whitespace::farewell},
{"value", &partial_whitespace::value}, {"name", &partial_whitespace::name},
{"taxed_value", &partial_whitespace::taxed_value}, {"value", &partial_whitespace::value},
{"in_ca", &partial_whitespace::in_ca} {"taxed_value", &partial_whitespace::taxed_value},
}); {"in_ca", &partial_whitespace::in_ca}});
} }
mstch::node greeting() { mstch::node greeting() { return std::string{"Welcome"}; }
return std::string{"Welcome"};
}
mstch::node farewell() { mstch::node farewell() { return std::string{"Fair enough, right?"}; }
return std::string{"Fair enough, right?"};
}
mstch::node name() { mstch::node name() { return std::string{"Chris"}; }
return std::string{"Chris"};
}
mstch::node value() { mstch::node value() { return m_value; }
return m_value;
}
mstch::node taxed_value() { mstch::node taxed_value() { return static_cast<int>(m_value - (m_value * 0.4)); }
return static_cast<int>(m_value - (m_value * 0.4));
}
mstch::node in_ca() { mstch::node in_ca() { return true; }
return true;
}
}; };
const auto partial_whitespace_data = std::make_shared<partial_whitespace>(); const mstch::node partial_whitespace_data =
mstch::object_wrapper{std::make_shared<partial_whitespace>()};

View File

@ -1,8 +1,7 @@
const auto recursion_with_same_names_data = mstch::map{ const mstch::node recursion_with_same_names_data = mstch::map_wrapper{
{"name", std::string{"name"}}, {{"name", std::string{"name"}},
{"description", std::string{"desc"}}, {"description", std::string{"desc"}},
{"terms", mstch::array{ {"terms",
mstch::map{{"name", std::string{"t1"}}, {"index", 0}}, mstch::array_wrapper{
mstch::map{{"name", std::string{"t2"}}, {"index", 1}} {mstch::map_wrapper{{{"name", std::string{"t1"}}, {"index", 0}}},
}} mstch::map_wrapper{{{"name", std::string{"t2"}}, {"index", 1}}}}}}}};
};

View File

@ -1,6 +1,5 @@
const auto reuse_of_enumerables_data = mstch::map{ const mstch::node reuse_of_enumerables_data = mstch::map_wrapper{
{"terms", mstch::array{ {{"terms",
mstch::map{{"name", std::string{"t1"}}, {"index", 0}}, mstch::array_wrapper{
mstch::map{{"name", std::string{"t2"}}, {"index", 1}} {mstch::map_wrapper{{{"name", std::string{"t1"}}, {"index", 0}}},
}} mstch::map_wrapper{{{"name", std::string{"t2"}}, {"index", 1}}}}}}}};
};

View File

@ -1,10 +1,9 @@
const auto section_as_context_data = mstch::map{ const mstch::node section_as_context_data = mstch::map_wrapper{
{"a_object", mstch::map{ {{"a_object",
{"title", std::string{"this is an object"}}, mstch::map_wrapper{
{"description", std::string{"one of its attributes is a list"}}, {{"title", std::string{"this is an object"}},
{"a_list", mstch::array{ {"description", std::string{"one of its attributes is a list"}},
mstch::map{{"label", std::string{"listitem1"}}}, {"a_list",
mstch::map{{"label", std::string{"listitem2"}}} mstch::array_wrapper{
}} {mstch::map_wrapper{{{"label", std::string{"listitem1"}}}},
}} mstch::map_wrapper{{{"label", std::string{"listitem2"}}}}}}}}}}}};
};

View File

@ -1,5 +1,4 @@
const mstch::node section_functions_in_partials_data = mstch::map{ const mstch::node section_functions_in_partials_data = mstch::map_wrapper{
{"bold", mstch::lambda{[](const std::string& text) -> mstch::node { {{"bold", mstch::lambda_wrapper{{[](const std::string& text) -> mstch::node {
return std::string{"<b>"} + text + std::string{"</b>"}; return std::string{"<b>"} + text + std::string{"</b>"};
}}} }}}}}};
};

View File

@ -29,4 +29,4 @@ public:
} }
}; };
const auto simple_data = std::make_shared<simple>(); const mstch::node simple_data = mstch::object_wrapper{std::make_shared<simple>()};

View File

@ -1,4 +1,4 @@
const auto string_as_context_data = mstch::map{ const mstch::node string_as_context_data = mstch::map_wrapper{
{"a_string", std::string{"aa"}}, {{"a_string", std::string{"aa"}},
{"a_list", mstch::array{std::string{"a"},std::string{"b"},std::string{"c"}}} {"a_list",
}; mstch::array_wrapper{{std::string{"a"}, std::string{"b"}, std::string{"c"}}}}}};

View File

@ -1,4 +1,2 @@
const auto two_in_a_row_data = mstch::map{ const mstch::node two_in_a_row_data = mstch::map_wrapper{
{"name", std::string{"Joe"}}, {{"name", std::string{"Joe"}}, {"greeting", std::string{"Welcome"}}}};
{"greeting", std::string{"Welcome"}}
};

View File

@ -1 +1 @@
const auto two_sections_data = mstch::map{}; const mstch::node two_sections_data = mstch::map_wrapper{{}};

View File

@ -1,3 +1,4 @@
const mstch::node unescaped_data = mstch::map{ const mstch::node unescaped_data =
{"title", mstch::lambda{[]()->mstch::node{ return std::string{"Bear > Shark"}; }}} mstch::map_wrapper{{{"title", mstch::lambda_wrapper{{[]() -> mstch::node {
}; return std::string{"Bear > Shark"};
}}}}}};

View File

@ -1,4 +1,2 @@
const auto whitespace_data = mstch::map{ const mstch::node whitespace_data =
{"tag1", std::string{"Hello"}}, mstch::map_wrapper{{{"tag1", std::string{"Hello"}}, {"tag2", std::string{"World"}}}};
{"tag2", std::string{"World"}}
};

View File

@ -1 +1,2 @@
const auto zero_view_data = mstch::map{{"nums", mstch::array{0, 1, 2}}}; const mstch::node zero_view_data =
mstch::map_wrapper{{{"nums", mstch::array_wrapper{{0, 1, 2}}}}};

View File

@ -1,32 +1,36 @@
std::map<std::string,mstch::node> specs_lambdas { std::map<std::string, mstch::node> specs_lambdas{
{"Interpolation", mstch::lambda{[](const std::string&) -> mstch::node { {"Interpolation", mstch::lambda_wrapper{{[](const std::string&) -> mstch::node {
return std::string{"world"}; return std::string{"world"};
}}}, }}}},
{"Interpolation - Expansion", mstch::lambda{[](const std::string&) -> mstch::node { {"Interpolation - Expansion",
return std::string{"{{planet}}"}; mstch::lambda_wrapper{{[](const std::string&) -> mstch::node {
}}}, return std::string{"{{planet}}"};
{"Interpolation - Alternate Delimiters", mstch::lambda{[](const std::string&) -> mstch::node { }}}},
return std::string{"|planet| => {{planet}}"}; {"Interpolation - Alternate Delimiters",
}}}, mstch::lambda_wrapper{{[](const std::string&) -> mstch::node {
{"Interpolation - Multiple Calls", mstch::lambda{[](const std::string&) -> mstch::node { return std::string{"|planet| => {{planet}}"};
static int calls = 0; return ++calls; }}}},
}}}, {"Interpolation - Multiple Calls",
{"Escaping", mstch::lambda{[](const std::string&) -> mstch::node { mstch::lambda_wrapper{{[](const std::string&) -> mstch::node {
return std::string{">"}; static int calls = 0;
}}}, return ++calls;
{"Section", mstch::lambda{[](const std::string& txt) -> mstch::node { }}}},
return std::string{(txt == "{{x}}") ? "yes" : "no"}; {"Escaping", mstch::lambda_wrapper{{[](const std::string&) -> mstch::node {
}}}, return std::string{">"};
{"Section - Expansion", mstch::lambda{[](const std::string& txt) -> mstch::node { }}}},
return txt + std::string{"{{planet}}"} + txt; {"Section", mstch::lambda_wrapper{{[](const std::string& txt) -> mstch::node {
}}}, return std::string{(txt == "{{x}}") ? "yes" : "no"};
{"Section - Alternate Delimiters", mstch::lambda{[](const std::string& txt) -> mstch::node { }}}},
return txt + std::string{"{{planet}} => |planet|"} + txt; {"Section - Expansion",
}}}, mstch::lambda_wrapper{{[](const std::string& txt) -> mstch::node {
{"Section - Multiple Calls", mstch::lambda{[](const std::string& txt) -> mstch::node { return txt + std::string{"{{planet}}"} + txt;
return "__" + txt + "__"; }}}},
}}}, {"Section - Alternate Delimiters",
{"Inverted Section", mstch::lambda{[](const std::string&) -> mstch::node { mstch::lambda_wrapper{{[](const std::string& txt) -> mstch::node {
return false; return txt + std::string{"{{planet}} => |planet|"} + txt;
}}} }}}},
}; {"Section - Multiple Calls",
mstch::lambda_wrapper{
{[](const std::string& txt) -> mstch::node { return "__" + txt + "__"; }}}},
{"Inverted Section",
mstch::lambda_wrapper{{[](const std::string&) -> mstch::node { return false; }}}}};

View File

@ -1,91 +1,99 @@
#define CATCH_CONFIG_MAIN #define CATCH_CONFIG_MAIN
#include "catch.hpp" #include "catch.hpp"
#include "rapidjson/document.h"
#include "mstch/mstch.hpp" #include "mstch/mstch.hpp"
#include "test_context.hpp" #include "rapidjson/document.h"
#include "test_data.hpp"
#include "specs_data.hpp" #include "specs_data.hpp"
#include "specs_lambdas.hpp" #include "specs_lambdas.hpp"
#include "test_context.hpp"
#include "test_data.hpp"
using namespace mstchtest; using namespace mstchtest;
mstch::node to_value(const rapidjson::Value& val) { mstch::node to_value(const rapidjson::Value& val) {
if (val.IsString()) if (val.IsString())
return std::string{val.GetString()}; return std::string{val.GetString()};
if (val.IsBool()) if (val.IsBool())
return val.GetBool(); return val.GetBool();
if (val.IsDouble()) if (val.IsDouble())
return val.GetDouble(); return val.GetDouble();
if (val.IsInt()) if (val.IsInt())
return val.GetInt(); return val.GetInt();
return mstch::node{}; return mstch::node{};
} }
mstch::array to_array(const rapidjson::Value& val); mstch::array to_array(const rapidjson::Value& val);
mstch::map to_object(const rapidjson::Value& val) { mstch::map to_object(const rapidjson::Value& val) {
mstch::map ret; mstch::map ret;
for (auto i = val.MemberBegin(); i != val.MemberEnd(); ++i) { for (auto i = val.MemberBegin(); i != val.MemberEnd(); ++i) {
if (i->value.IsArray()) if (i->value.IsArray())
ret.insert(std::make_pair(i->name.GetString(), to_array(i->value))); ret.insert(std::make_pair(i->name.GetString(),
else if (i->value.IsObject()) mstch::array_wrapper{to_array(i->value)}));
ret.insert(std::make_pair(i->name.GetString(), to_object(i->value))); else if (i->value.IsObject())
else ret.insert(std::make_pair(i->name.GetString(),
ret.insert(std::make_pair(i->name.GetString(), to_value(i->value))); mstch::map_wrapper{to_object(i->value)}));
} else
return ret; ret.insert(std::make_pair(i->name.GetString(), to_value(i->value)));
}
return ret;
} }
mstch::array to_array(const rapidjson::Value& val) { mstch::array to_array(const rapidjson::Value& val) {
mstch::array ret; mstch::array ret;
for (auto i = val.Begin(); i != val.End(); ++i) { for (auto i = val.Begin(); i != val.End(); ++i) {
if (i->IsArray()) if (i->IsArray())
ret.push_back(to_array(*i)); ret.push_back(mstch::array_wrapper{to_array(*i)});
else if (i->IsObject()) else if (i->IsObject())
ret.push_back(to_object(*i)); ret.push_back(mstch::map_wrapper{to_object(*i)});
else else
ret.push_back(to_value(*i)); ret.push_back(to_value(*i));
} }
return ret; return ret;
} }
mstch::node parse_with_rapidjson(const std::string& str) { mstch::node parse_with_rapidjson(const std::string& str) {
rapidjson::Document doc; rapidjson::Document doc;
doc.Parse(str.c_str()); doc.Parse(str.c_str());
return to_object(doc); return mstch::map_wrapper{to_object(doc)};
} }
#define MSTCH_PARTIAL_TEST(x) TEST_CASE(#x) { \ #define MSTCH_PARTIAL_TEST(x) \
REQUIRE(x ## _txt == mstch::render(x ## _mustache, x ## _data, {{"partial", x ## _partial}})); \ TEST_CASE(#x) { \
} REQUIRE(x##_txt == mstch::render(x##_mustache, x##_data, {{"partial", x##_partial}})); \
}
#define MSTCH_TEST(x) TEST_CASE(#x) { \ #define MSTCH_TEST(x) \
REQUIRE(x ## _txt == mstch::render(x ## _mustache, x ## _data)); \ TEST_CASE(#x) { REQUIRE(x##_txt == mstch::render(x##_mustache, x##_data)); }
}
#define SPECS_TEST(x) TEST_CASE("specs_" #x) { \ #define SPECS_TEST(x) \
using boost::get; \ TEST_CASE("specs_" #x) { \
auto data = parse_with_rapidjson(x ## _json); \ auto data = parse_with_rapidjson(x##_json); \
for (auto& test_item: get<mstch::array>(get<mstch::map>(data)["tests"])) {\ for (auto& test_item : std::get<mstch::array_wrapper>( \
auto test = get<mstch::map>(test_item); \ std::get<mstch::map_wrapper>(data).values["tests"]) \
std::map<std::string,std::string> partials; \ .values) { \
if (test.count("partials")) \ auto test = std::get<mstch::map_wrapper>(test_item).values; \
for (auto& partial_item: get<mstch::map>(test["partials"])) \ std::map<std::string, std::string> partials; \
partials.insert(std::make_pair(partial_item.first, get<std::string>(partial_item.second))); \ if (test.count("partials")) \
mstch::map context; \ for (auto& partial_item : \
for (auto& data_item: get<mstch::map>(test["data"])) \ std::get<mstch::map_wrapper>(test["partials"]).values) \
if (data_item.first == "lambda") \ partials.insert( \
context.insert(std::make_pair(data_item.first, specs_lambdas[get<std::string>(test["name"])])); \ std::make_pair(partial_item.first, \
else \ std::get<std::string>(partial_item.second))); \
context.insert(data_item); \ mstch::map context; \
SECTION(get<std::string>(test["name"])) \ for (auto& data_item : std::get<mstch::map_wrapper>(test["data"]).values) \
REQUIRE(mstch::render( \ if (data_item.first == "lambda") \
get<std::string>(test["template"]), \ context.insert(std::make_pair( \
context, partials) == \ data_item.first, \
get<std::string>(test["expected"])); \ specs_lambdas[std::get<std::string>(test["name"])])); \
} \ else \
} context.insert(data_item); \
SECTION(std::get<std::string>(test["name"])) \
REQUIRE(mstch::render(std::get<std::string>(test["template"]), \
mstch::map_wrapper{context}, \
partials) == std::get<std::string>(test["expected"])); \
} \
}
MSTCH_TEST(ampersand_escape) MSTCH_TEST(ampersand_escape)
MSTCH_TEST(apostrophe) MSTCH_TEST(apostrophe)