summaryrefslogtreecommitdiff
path: root/src/minimacro.h
blob: 105a117bab4a3f14d0c0f2adb4e54d2581f4da8c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
 * Copyright (C) 2007 Xagasoft, All rights reserved.
 *
 * This file is part of the libbu++ library and is released under the
 * terms of the license contained in the file LICENSE.
 */

#ifndef BU_MINI_MACRO_H
#define BU_MINI_MACRO_H

#include "bu/hash.h"
#include "bu/fstring.h"

namespace Bu
{
	/**
	 * A processor for Libbu++ brand Mini Macros.  These are really simple, but
	 * still fairly flexible.  It's mainly text replacement, but with a few
	 * extras like filter functions and conditional text segments.  So far we
	 * don't support loops or anything, I'm not sure we ever will.
	 *
	 * Anatomy of a mini macro:
	 * - Every macro begins with a two character code, the first character is
	 *   always '{', the second character determines the operation to perform.
	 * - If the '{' is followed by a character that is not valid it is not
	 *   considered for expansion and the characters are copied to the output.
	 * - Every macro ends with a closing '}'
	 * - Macro types:
	 *   - '=': variable replacement.  The '=' is immediatley followed by the
	 *     name of the variable to replace, then any number of optional filter
	 *     segments.
	 *   - '?': conditional text.  The '?' is immediately followed by the
	 *     variable to test.  This works two ways, the variable can be alone, in
	 *     which case it's existance is tested, or it can be followed by a "="
	 *     and a string to compare to.  This is then followed by a text segment
	 *     that will be used if the test is true, and an optional text segment
	 *     to be used if the test is false.
	 *   - ':': command.  The ':' is immediately followed by a command string,
	 *     of which there's only one right now, but that's ok.  These are not
	 *     put into the output stream, but instead mark something for the
	 *     parser.  Currently supported:
	 *     - {:end}: end of parsing, stop here, also make note of how many input
	 *       characters were used.
	 * - Segments:
	 *   - Each segment is seperated by a colon.
	 *   - Filter segments give the name of the filter, followed by
	 *     parenthesies.  Parameters may be provided within the parenthesies.
	 *   - Text segments should always be quoted, but may contain any characters
	 *     within the quotes, backslash is used as per C/ANSI/ISO standard.
	 *     You can also quote any text using [' '] instead of quotes, which
	 *     allows for nested strings.  The [' token is only recognised within
	 *     a macro.
	 *
	 *@verbatim
	 {=name:tolower()}
	 {=name:ccsplit("_"):toupper()}
	 {?name:"name exists and is {=name}"}
	 {?name:"{=name}":"no name!"}
	 {?name="bob":"You're named bob!":"Who are you?  I only know bob..."}
	 @endverbatim
	 */
	typedef Bu::Hash<Bu::FString, Bu::FString> StrHash;
	class MiniMacro
	{
	public:
		MiniMacro();
		virtual ~MiniMacro();

		Bu::FString parse( const Bu::FString &sIn );
		void addVar( const Bu::FString &sName, const Bu::FString &sValue );

	private:
		const char *sCur;
		Bu::FString parseRepl();
		Bu::FString parseCond();
		Bu::FString parseCmd();
		Bu::FString callFunc(
			const Bu::FString &sIn, const Bu::FString &sFunc );

		StrHash hVars;

	public:
		typedef Bu::List<Bu::FString> StrList;
		class Func
		{
		public:
			Func(){}
			virtual ~Func(){}
			virtual Bu::FString call(
				const Bu::FString &sIn, StrList &lsParam )=0;
		};

		class FuncToUpper : public Func
		{
		public:
			FuncToUpper(){}
			virtual ~FuncToUpper(){}
			virtual Bu::FString call(
				const Bu::FString &sIn, StrList &lsParam )
			{
				Bu::FString sOut( sIn );
				sOut.toUpper();
				return sOut;
			}
		};

		class FuncToLower : public Func
		{
		public:
			FuncToLower(){}
			virtual ~FuncToLower(){}
			virtual Bu::FString call(
				const Bu::FString &sIn, StrList &lsParam )
			{
				Bu::FString sOut( sIn );
				sOut.toLower();
				return sOut;
			}
		};
		
	private:
		typedef Bu::Hash<Bu::FString,class Func *> FuncHash;
		FuncHash hFuncs;
	};
};

#endif