PEBL 2.2
Psychology Experiment Building Language - Cross-platform psychological experiment development system
PEBLValidator.cpp File Reference
#include "../base/Variant.h"
#include "../base/PNode.h"
#include "../base/grammar.tab.hpp"
#include "../utility/PEBLPath.h"
#include "../utility/PEBLUtility.h"
#include "../utility/PError.h"
#include <iostream>
#include <string>
#include <vector>
#include "../base/FunctionMap.h"
#include "../base/VariableMap.h"
#include "../base/Evaluator.h"
#include "../base/Loader.h"
#include "../devices/PEventLoop.h"

Go to the source code of this file.

Functions

PNodeparse (const char *filename)
 
void PrintUsage ()
 
void PrintJSONResults (const string &filename)
 
void PrintTextResults (const string &filename)
 
int main (int argc, char *argv[])
 

Variables

void * myEnv = NULL
 
EvaluatormyEval = NULL
 
bool gSyntaxValid = true
 
vector< string > gErrors
 
vector< string > gWarnings
 

Function Documentation

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 156 of file PEBLValidator.cpp.

156 {
157 // Disable GUI error dialogs for validator (errors still go to stderr)
159
160 // Enable validator mode (throw exceptions instead of exiting on errors)
162
163 if (argc < 2) {
164 PrintUsage();
165 return 2;
166 }
167
168 string filename;
169 bool json_output = false;
170
171 // Parse command-line arguments
172 for (int i = 1; i < argc; i++) {
173 string arg = argv[i];
174 if (arg == "--help") {
175 PrintUsage();
176 return 0;
177 } else if (arg == "--json") {
178 json_output = true;
179 } else if (filename.empty()) {
180 filename = arg;
181 } else {
182 cerr << "Error: Unknown argument: " << arg << "\n";
183 PrintUsage();
184 return 2;
185 }
186 }
187
188 if (filename.empty()) {
189 cerr << "Error: No file specified\n";
190 PrintUsage();
191 return 2;
192 }
193
194 // Check if file exists using PEBLUtility
195 if (!PEBLUtility::FileExists(filename)) {
196 gSyntaxValid = false;
197 gErrors.push_back("File not found: " + filename);
198 if (json_output) {
199 PrintJSONResults(filename);
200 } else {
201 PrintTextResults(filename);
202 }
203 return 1;
204 }
205
206 // Initialize path system (needed to find library files)
207 std::list<std::string> files;
208 files.push_back("pebl-validator"); // Executable name
209 files.push_back(filename); // User's file
211
212 // Parse the user's file
213 PNode * head = NULL;
214 PNode * tmp = NULL;
215 Loader * myLoader = NULL;
216
217 try {
218 cerr << "Parsing user file: " << filename << endl;
219 head = parse(filename.c_str());
220
221 if (!head) {
222 gSyntaxValid = false;
223 gErrors.push_back("Parse failed - syntax error in file");
224 } else {
225 // Parse and combine standard library files (like PEBL.cpp lines 341-370)
226 for (int i = 0; STANDARD_LIBRARIES[i] != NULL; i++) {
227 string libpath = Evaluator::gPath.FindFile(STANDARD_LIBRARIES[i]);
228 if (libpath != "" && !Evaluator::gPath.IsDirectory(libpath)) {
229 cerr << "Loading library: " << STANDARD_LIBRARIES[i] << endl;
230 tmp = parse(libpath.c_str());
231 if (tmp) {
232 // Combine library with existing parse tree
233 head = new OpNode(PEBL_FUNCTIONS, head, tmp, "INTERNAL PEBL STRUCTURE", -1);
234 }
235 }
236 }
237
238 // Now validate functions using Loader (like PEBL.cpp lines 179-188)
239 cerr << "Validating functions..." << endl;
240 myLoader = new Loader();
242
243 // Validate Start() function has exactly one parameter
244 PNode* startFunc = myLoader->GetMainPEBLFunction();
245 if (startFunc) {
246 OpNode* startOpNode = dynamic_cast<OpNode*>(startFunc);
247 if (startOpNode) {
248 // For PEBL_FUNCTION nodes, left child is parameter list
249 PNode* paramList = startOpNode->GetLeft();
250 if (!paramList) {
251 // Start() defined with no parameters: define Start()
252 gErrors.push_back("Start() function must have exactly one parameter to receive command-line arguments (e.g., define Start(p))");
253 gSyntaxValid = false;
254 }
255 }
256 } else {
257 gWarnings.push_back("No Start() function found - PEBL scripts should define a Start() function as the entry point");
258 }
259
261
262 // LoadLibraryFunctions() will throw exception on undefined functions in validator mode
263 try {
265 } catch (const std::runtime_error& e) {
266 // Catch validation errors (undefined functions, etc.)
267 gSyntaxValid = false;
268 gErrors.push_back(e.what());
269 }
270
271 // Clean up
272 ((OpNode*)head)->DestroyFunctionTree();
273 delete head;
274 delete myLoader;
275 }
276 } catch (const std::exception& e) {
277 gSyntaxValid = false;
278 gErrors.push_back(string("Parse exception: ") + e.what());
279 if (head) {
280 ((OpNode*)head)->DestroyFunctionTree();
281 delete head;
282 }
283 if (myLoader) delete myLoader;
284 } catch (...) {
285 gSyntaxValid = false;
286 gErrors.push_back("Validation failed - unknown error");
287 if (head) {
288 ((OpNode*)head)->DestroyFunctionTree();
289 delete head;
290 }
291 if (myLoader) delete myLoader;
292 }
293
294 // Output results
295 if (json_output) {
296 PrintJSONResults(filename);
297 } else {
298 PrintTextResults(filename);
299 }
300
301 // Return exit code
302 return gSyntaxValid ? 0 : 1;
303}
#define NULL
Definition BinReloc.cpp:317
bool gSyntaxValid
void PrintJSONResults(const string &filename)
vector< string > gErrors
void PrintTextResults(const string &filename)
void PrintUsage()
vector< string > gWarnings
PNode * head
Definition PEBL.cpp:220
Loader * myLoader
Definition PEBL.cpp:219
PNode * parse()
static PEBLPath gPath
void LoadUserFunctions(OpNode *node)
Definition Loader.cpp:147
void LoadLibraryFunctions()
Definition Loader.cpp:195
void FindFunctions(const PNode *Node)
Definition Loader.cpp:88
PNode * GetMainPEBLFunction()
Definition Loader.cpp:372
PNode * GetLeft() const
Definition PNode.h:114
std::string FindFile(const string &filename)
Definition PEBLPath.cpp:368
void Initialize(std::list< std::string >)
Definition PEBLPath.cpp:60
Definition PNode.h:45
Variant IsDirectory(Variant v)
Variant FileExists(std::string path)
bool gValidatorMode
Definition PError.cpp:59
bool gShowErrorDialogs
Definition PError.cpp:56

References PEBLUtility::FileExists(), PEBLPath::FindFile(), Loader::FindFunctions(), gErrors, OpNode::GetLeft(), Loader::GetMainPEBLFunction(), Evaluator::gPath, PError::gShowErrorDialogs, gSyntaxValid, PError::gValidatorMode, gWarnings, head, PEBLPath::Initialize(), Loader::LoadLibraryFunctions(), Loader::LoadUserFunctions(), myLoader, NULL, parse(), PrintJSONResults(), PrintTextResults(), and PrintUsage().

◆ parse()

PNode * parse ( const char *  filename)
extern

◆ PrintJSONResults()

void PrintJSONResults ( const string &  filename)

Definition at line 94 of file PEBLValidator.cpp.

94 {
95 cout << "{\n";
96 cout << " \"file\": \"" << filename << "\",\n";
97 cout << " \"syntax_valid\": " << (gSyntaxValid ? "true" : "false") << ",\n";
98 cout << " \"errors\": [\n";
99 for (size_t i = 0; i < gErrors.size(); i++) {
100 // Escape quotes in error messages
101 string msg = gErrors[i];
102 size_t pos = 0;
103 while ((pos = msg.find('"', pos)) != string::npos) {
104 msg.replace(pos, 1, "\\\"");
105 pos += 2;
106 }
107 cout << " \"" << msg << "\"";
108 if (i < gErrors.size() - 1) cout << ",";
109 cout << "\n";
110 }
111 cout << " ],\n";
112 cout << " \"warnings\": [\n";
113 for (size_t i = 0; i < gWarnings.size(); i++) {
114 // Escape quotes in warning messages
115 string msg = gWarnings[i];
116 size_t pos = 0;
117 while ((pos = msg.find('\"', pos)) != string::npos) {
118 msg.replace(pos, 1, "\\\"");
119 pos += 2;
120 }
121 cout << " \"" << msg << "\"";
122 if (i < gWarnings.size() - 1) cout << ",";
123 cout << "\n";
124 }
125 cout << " ]\n";
126 cout << "}\n";
127}

References gErrors, gSyntaxValid, and gWarnings.

Referenced by main().

◆ PrintTextResults()

void PrintTextResults ( const string &  filename)

Definition at line 129 of file PEBLValidator.cpp.

129 {
130 cout << "PEBL Validator Results\n";
131 cout << "======================\n";
132 cout << "File: " << filename << "\n\n";
133
134 if (gSyntaxValid) {
135 cout << "✓ Syntax: VALID\n";
136 } else {
137 cout << "✗ Syntax: INVALID\n";
138 }
139
140 if (!gErrors.empty()) {
141 cout << "\nErrors:\n";
142 for (const auto& err : gErrors) {
143 cout << " ✗ " << err << "\n";
144 }
145 }
146
147 if (!gWarnings.empty()) {
148 cout << "\nWarnings:\n";
149 for (const auto& warn : gWarnings) {
150 cout << " ⚠ " << warn << "\n";
151 }
152 }
153
154}

References gErrors, gSyntaxValid, and gWarnings.

Referenced by main().

◆ PrintUsage()

void PrintUsage ( )

Definition at line 78 of file PEBLValidator.cpp.

78 {
79 cout << "PEBL Validator - Syntax and Function Checker\n";
80 cout << "Usage: pebl-validator <file.pbl> [options]\n\n";
81 cout << "Options:\n";
82 cout << " --json Output results as JSON\n";
83 cout << " --help Show this help message\n\n";
84 cout << "Exit codes:\n";
85 cout << " 0 = Valid syntax and all functions defined\n";
86 cout << " 1 = Invalid syntax or undefined functions\n";
87 cout << " 2 = Usage error\n\n";
88 cout << "Features:\n";
89 cout << " - Parses PEBL syntax without execution\n";
90 cout << " - Validates all function calls against standard libraries\n";
91 cout << " - Detects undefined functions\n";
92}

Referenced by main().

Variable Documentation

◆ gErrors

vector<string> gErrors

Definition at line 75 of file PEBLValidator.cpp.

Referenced by main(), PrintJSONResults(), and PrintTextResults().

◆ gSyntaxValid

bool gSyntaxValid = true

Definition at line 74 of file PEBLValidator.cpp.

Referenced by main(), PrintJSONResults(), and PrintTextResults().

◆ gWarnings

vector<string> gWarnings

Definition at line 76 of file PEBLValidator.cpp.

Referenced by main(), PrintJSONResults(), and PrintTextResults().

◆ myEnv

◆ myEval