Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief Source for yanlr plugin
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : *
8 : */
9 :
10 : // -- Imports ------------------------------------------------------------------------------------------------------------------------------
11 :
12 : #include <iostream>
13 :
14 : #include <kdb.hpp>
15 : #include <kdberrors.h>
16 :
17 : #include <antlr4-runtime.h>
18 :
19 : #include "YAML.h"
20 : #include "error_listener.hpp"
21 : #include "listener.hpp"
22 : #include "yaml_lexer.hpp"
23 : #include "yanlr.hpp"
24 :
25 : using CppKey = kdb::Key;
26 : using CppKeySet = kdb::KeySet;
27 :
28 : using yanlr::ErrorListener;
29 : using yanlr::KeyListener;
30 : using yanlr::YAML;
31 : using yanlr::YAMLLexer;
32 :
33 : using antlr4::ANTLRInputStream;
34 : using antlr4::CommonTokenStream;
35 : using antlr4::DiagnosticErrorListener;
36 : using ParserATNSimulator = antlr4::atn::ParserATNSimulator;
37 : using PredictionMode = antlr4::atn::PredictionMode;
38 : using ParseTree = antlr4::tree::ParseTree;
39 : using ParseTreeWalker = antlr4::tree::ParseTreeWalker;
40 :
41 : using std::ifstream;
42 :
43 : // -- Functions ----------------------------------------------------------------------------------------------------------------------------
44 :
45 : namespace
46 : {
47 : /**
48 : * @brief This function returns a key set containing the contract of this plugin.
49 : *
50 : * @return A contract describing the functionality of this plugin.
51 : */
52 160 : CppKeySet getContract ()
53 : {
54 : return CppKeySet{ 30,
55 : keyNew ("system/elektra/modules/yanlr", KEY_VALUE, "yanlr plugin waits for your orders", KEY_END),
56 : keyNew ("system/elektra/modules/yanlr/exports", KEY_END),
57 : keyNew ("system/elektra/modules/yanlr/exports/get", KEY_FUNC, elektraYanlrGet, KEY_END),
58 : #include ELEKTRA_README
59 : keyNew ("system/elektra/modules/yanlr/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END),
60 160 : KS_END };
61 : }
62 :
63 : /**
64 : * @brief This function parses the content of a YAML file and saves the result in the given key set.
65 : *
66 : * @param file This file contains the YAML content this function should parse.
67 : * @param keys The function adds the key set representing `file` in this key set, if the parsing process finished successfully.
68 : * @param parent The function uses this parameter to emit error information.
69 : *
70 : * @retval ELEKTRA_PLUGIN_STATUS_NO_UPDATE If parsing was successful and `keys` was not updated
71 : * @retval ELEKTRA_PLUGIN_STATUS_SUCCESS If parsing was successful and `keys` was updated
72 : * @retval ELEKTRA_PLUGIN_STATUS_ERROR If there was an error parsing `file`
73 : */
74 31 : int parseYAML (ifstream & file, CppKeySet & keys, CppKey & parent)
75 : {
76 62 : ANTLRInputStream input{ file };
77 62 : YAMLLexer lexer{ &input };
78 62 : CommonTokenStream tokens{ &lexer };
79 62 : YAML parser{ &tokens };
80 93 : ParseTreeWalker walker{};
81 93 : KeyListener listener{ parent };
82 :
83 93 : ErrorListener errorListener{ parent.getString () };
84 31 : parser.removeErrorListeners ();
85 31 : parser.addErrorListener (&errorListener);
86 : #if DEBUG
87 62 : DiagnosticErrorListener diagErrorListener;
88 31 : parser.addErrorListener (&diagErrorListener);
89 62 : parser.getInterpreter<ParserATNSimulator> ()->setPredictionMode (PredictionMode::LL_EXACT_AMBIG_DETECTION);
90 : #endif
91 :
92 31 : ParseTree * tree = parser.yaml ();
93 31 : if (parser.getNumberOfSyntaxErrors () > 0)
94 : {
95 6 : ELEKTRA_SET_VALIDATION_SYNTACTIC_ERROR (parent.getKey (), errorListener.message ());
96 : return ELEKTRA_PLUGIN_STATUS_ERROR;
97 : }
98 28 : walker.walk (&listener, tree);
99 :
100 28 : auto readKeys = listener.keySet ();
101 28 : keys.append (readKeys);
102 28 : return readKeys.size () <= 0 ? ELEKTRA_PLUGIN_STATUS_NO_UPDATE : ELEKTRA_PLUGIN_STATUS_SUCCESS;
103 : }
104 :
105 : } // end namespace
106 :
107 : extern "C" {
108 : // ====================
109 : // = Plugin Interface =
110 : // ====================
111 :
112 : /** @see elektraDocGet */
113 191 : int elektraYanlrGet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned, Key * parentKey)
114 : {
115 382 : CppKey parent{ parentKey };
116 382 : CppKeySet keys{ returned };
117 :
118 573 : if (parent.getName () == "system/elektra/modules/yanlr")
119 : {
120 480 : keys.append (getContract ());
121 160 : keys.release ();
122 : parent.release ();
123 :
124 : return ELEKTRA_PLUGIN_STATUS_SUCCESS;
125 : }
126 :
127 93 : ifstream file (parent.getString ());
128 31 : if (!file.is_open ())
129 : {
130 0 : ELEKTRA_SET_RESOURCE_ERRORF (parent.getKey (), "Unable to open file '%s'", parent.getString ().c_str ());
131 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
132 : }
133 :
134 31 : int status = parseYAML (file, keys, parent);
135 :
136 31 : keys.release ();
137 : parent.release ();
138 :
139 : return status;
140 : }
141 :
142 356 : Plugin * ELEKTRA_PLUGIN_EXPORT
143 : {
144 356 : return elektraPluginExport ("yanlr", ELEKTRA_PLUGIN_GET, &elektraYanlrGet, ELEKTRA_PLUGIN_END);
145 : }
146 :
147 140 : } // end extern "C"
|