1 module jcli.commandgraph.wrapper;
2 
3 import jcli.commandgraph;
4 import jcli.commandgraph.internal;
5 
6 private alias State = MatchAndExecuteState;
7 
8 struct MatchAndParseContextWrapper(
9     alias CommandTypeContext,
10     // Either pointer to MatchAndExecuteContext, or that itself
11     ContextType = MatchAndExecuteContext)
12 {
13     ContextType _context;
14     alias _context this;
15 
16     pure nothrow @nogc:
17 
18     auto contextPointer() inout
19     {
20         static if (is(ContextType : T*, T))
21             return _context;
22         else
23             return &_context;
24     }
25 
26     auto command(int typeIndex)()
27     {
28         return IndexHelper!(typeIndex, CommandTypeContext)(contextPointer);
29     }
30 
31     auto command(CommandType)()
32     {
33         enum index = CommandTypeContext.indexOf!CommandType;
34         return IndexHelper!(index, CommandTypeContext)(contextPointer);
35     }
36 
37     SpecialThings specialThing() const
38     {
39         assert(_context._state == State.specialThing);
40         return _context._specialThing;
41     }
42     
43     inout(ExecuteCommandResult) executeCommandResult() inout
44     {
45         assert(_context._state == State.intermediateExecutionResult
46             || _context._state == State.finalExecutionResult);
47         return _context._executeCommandResult;
48     }
49 
50     string matchedName() const
51     {
52         assert(_context._state == State.matchedNextCommand
53             || _context._state == State.matchedRootCommand);
54         return _context._matchedName;
55     }
56     
57     string notMatchedName() const
58     {
59         assert(_context._state == State.notMatchedNextCommand
60             || _context._state == State.notMatchedRootCommand);
61         return _context._notMatchedName;
62     }
63 
64     State state() const @safe { return _state; }
65 
66     // SumType-like match, maybe?
67     // template match();
68 }
69 
70 auto wrapContext(Types)(scope ref MatchAndExecuteContext context) return
71 {
72     return *cast(MatchAndParseContextWrapper!Types*) &context;
73 }
74 
75 // This is kind of what I mean by a type-safe wrapper, but it also needs getters for everything
76 // that would assert if the state is right and stuff like that.
77 // Currently, this one is only used for tests.
78 struct SimpleMatchAndExecuteHelper(alias Graph)
79 {
80     alias bindArgument = jcli.argbinder.bindArgument!();
81     alias _CommandTypeContext = CommandTypeContext!(Graph);
82     alias TypeContext = MatchAndExecuteTypeContext!(bindArgument, _CommandTypeContext);
83 
84     MatchAndParseContextWrapper!_CommandTypeContext context;
85     TypeContext.ParsingContext parsingContext;
86     ArgTokenizer!(string[]) tokenizer;
87     ErrorCodeHandler errorHandler;
88 
89 
90     this(string[] args)
91     {
92         tokenizer = argTokenizer(args);
93         parsingContext = TypeContext.ParsingContext();
94         context = MatchAndParseContextWrapper!_CommandTypeContext();
95         errorHandler = createErrorCodeHandler();
96     }
97 
98     void advance()
99     {
100         TypeContext.advanceState(context, parsingContext, tokenizer, errorHandler);
101     }
102 }