OXYGENHUB
◆ main openmsx / src / commands / TclArgParser.hh
3.2 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef TCLARGPARSER_HH
2
#define TCLARGPARSER_HH
3
4
#include "CommandException.hh"
5
#include "TclObject.hh"
6
#include <functional>
7
#include <optional>
8
#include <span>
9
#include <string_view>
10
#include <vector>
11
12
namespace openmsx {
13
14
namespace detail {
15
	template<typename T> struct GetArg;
16
17
	template<> struct GetArg<bool> {
18
		void operator()(Interpreter& interp, const TclObject& obj, bool& result) const {
19
			result = obj.getBoolean(interp);
20
		}
21
	};
22
	template<> struct GetArg<int> {
23
		void operator()(Interpreter& interp, const TclObject& obj, int& result) const {
24
			result = obj.getInt(interp);
25
		}
26
	};
27
	template<> struct GetArg<double> {
28
		void operator()(Interpreter& interp, const TclObject& obj, double& result) const {
29
			result = obj.getDouble(interp);
30
		}
31
	};
32
	template<> struct GetArg<std::string_view> {
33
		void operator()(Interpreter& /*interp*/, const TclObject& obj, std::string_view& result) const {
34
			result = obj.getString();
35
		}
36
	};
37
	template<> struct GetArg<std::string> {
38
		void operator()(Interpreter& /*interp*/, const TclObject& obj, std::string& result) const {
39
			result = std::string(obj.getString());
40
		}
41
	};
42
	template<> struct GetArg<TclObject> {
43
		void operator()(Interpreter& /*interp*/, const TclObject& obj, TclObject& result) const {
44
			result = obj;
45
		}
46
	};
47
48
	template<typename T> struct GetArg<std::optional<T>> {
49
		void operator()(Interpreter& interp, const TclObject& obj, std::optional<T>& result) const {
50
			T t;
51
			GetArg<T>{}(interp, obj, t);
52
			result = std::move(t);
53
		}
54
	};
55
56
	template<typename T> struct GetArg<std::vector<T>> {
57
		void operator()(Interpreter& interp, const TclObject& obj, std::vector<T>& result) const {
58
			result.emplace_back();
59
			GetArg<T>{}(interp, obj, result.back());
60
		}
61
	};
62
}
63
64
// A Tcl-argument-parser description is made out of ArgsInfo objects
65
struct ArgsInfo
66
{
67
	std::string_view name;
68
	std::function<unsigned(Interpreter&, std::span<const TclObject>)> func;
69
};
70
71
// Parse a flag.
72
[[nodiscard]] inline ArgsInfo flagArg(std::string_view name, bool& flag)
73
{
74
	return {
75
		.name = name,
76
		.func = [&flag](Interpreter& /*interp*/, std::span<const TclObject> /*args*/) {
77
			flag = true;
78
			return 0;
79
		}
80
	};
81
}
82
83
// Option with a single value, handled by a callback
84
[[nodiscard]] inline ArgsInfo funcArg(
85
	std::string_view name,
86
	std::function<void(Interpreter&, const TclObject&)> func)
87
{
88
	return {
89
		.name = name,
90
		.func = [name, func = std::move(func)](Interpreter& interp, std::span<const TclObject> args) {
91
			if (args.empty()) {
92
				throw CommandException("missing argument for ", name);
93
			}
94
			func(interp, args.front());
95
			return 1;
96
		}
97
	};
98
}
99
100
// Parse a value (like a flag but with associated value).
101
template<typename T>
102
[[nodiscard]] ArgsInfo valueArg(std::string_view name, T& value)
103
{
104
	return funcArg(name, [&value](Interpreter& interp, const TclObject& arg) {
105
		detail::GetArg<T>{}(interp, arg, value);
106
	});
107
}
108
109
// Parse the given 'inArgs' arguments.
110
// The recognized flags/values are described in 'table'.
111
// The result of this parser is the collection of non-flag arguments.
112
// See src/unittest/TclArgParser.cc for example usages.
113
[[nodiscard]] std::vector<TclObject> parseTclArgs(
114
	Interpreter& interp, std::span<const TclObject> inArgs, std::span<const ArgsInfo> table);
115
116
} // namespace openmsx
117
118
#endif