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 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
|
#ifndef EXECUTOR_H
#define EXECUTOR_H
//===-- qlogo/kernel.h - Kernel class definition -------*- C++ -*-===//
//
// Copyright 2017-2024 Jason Sikes
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the conditions specified in the
// license found in the LICENSE file in the project root.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file contains the declaration of the Kernel class, which is the
/// executor proper of the QLogo language.
///
//===----------------------------------------------------------------------===//
#include "controller/textstream.h"
#include "datum.h"
#include "procedurehelper.h"
#include "sharedconstants.h"
#include "workspace/callframe.h"
#include "workspace/procedures.h"
#include "workspace/propertylists.h"
#include <QColor>
#include <QFile>
#include <QFont>
#include <QRandomGenerator>
#include <QSet>
#include <QVector>
class Parser;
class Turtle;
class ProcedureScope;
/// @brief The Kernel class does most of the work for the QLogo interpreter.
/// @details The Kernel class is the core of the QLogo interpreter. It is the evaluator of the QLogo
/// language. It maintains the state of execution of the Logo code. It owns the objects that
/// support the execution of the code, such as the parser, the procedures, and
/// the turtle.
class Kernel
{
friend class ProcedureHelper;
friend class StreamRedirect;
Parser *parser;
Procedures *procedures;
DatumPtr filePrefix;
int repcount = -1;
int pauseLevel = 0;
bool isPausing = false;
Turtle *turtle;
QVector<QColor> palette;
PropertyLists plists;
QRandomGenerator randomGenerator;
Help help;
QHash<QString, TextStream *> fileStreams;
QSet<TextStream *> writableStreams;
QSet<TextStream *> readableStreams;
TextStream *readStream;
TextStream *systemReadStream;
TextStream *writeStream;
TextStream *systemWriteStream;
TextStream *stdioStream;
DatumPtr currentError;
DatumPtr currentLine;
DatumPtr editFileName;
QString workspaceText;
// Recursive searches need to make sure we don't get caught in infinite loops.
// Remember what we searched so we don't search it again.
QSet<void *> searchedContainers;
QSet<void *> comparedContainers;
ASTNode *astnodeValue(DatumPtr caller, DatumPtr value);
bool numbersFromList(QVector<double> &retval, DatumPtr l);
DatumPtr contentslistFromDatumPtr(DatumPtr sourceNode);
void processContentsListWithMethod(DatumPtr contentsList, void (Workspace::*method)(const QString &aName));
DatumPtr queryContentsListWithMethod(DatumPtr contentslist, bool (Workspace::*method)(const QString &aName));
void makeVarLocal(const QString &varname);
DatumPtr executeProcedureCore(DatumPtr node);
void inputProcedure(DatumPtr nodeP);
bool colorFromDatumPtr(QColor &retval, DatumPtr colorP);
QString filepathForFilename(DatumPtr filenameP);
TextStream *openFileStream(DatumPtr filenameP, QIODevice::OpenMode mode);
TextStream *createStringStream(DatumPtr filenameP, QIODevice::OpenMode mode);
TextStream *getStream(ProcedureHelper &h);
TextStream *open(ProcedureHelper &h, QIODevice::OpenMode openFlags);
void close(const QString &filename);
void closeAll();
void editAndRunFile();
void editAndRunWorkspaceText();
void initPalette(void);
/// Initialize LOGO system variables
void initVariables(void);
DatumPtr buildContentsList(showContents_t showWhat);
QString createPrintoutFromContentsList(DatumPtr contentslist, bool shouldValidate = true);
/// Check for interrupts and handle them accordingly.
SignalsEnum_t interruptCheck();
bool searchContainerForDatum(DatumPtr containerP, DatumPtr thingP, bool ignoreCase);
// Compare two datums, return true iff equal.
bool areDatumsEqual(DatumPtr datumP1, DatumPtr datumP2, bool ignoreCase);
// Return the butfirst of a word or list
DatumPtr butfirst(DatumPtr srcValue);
// Determine if the given list contains at least as many items as the
// integer given.
bool doesListHaveCountOrMore(List *list, int count);
public:
/// @brief Constructor.
Kernel();
/// @brief Destructor.
~Kernel();
/// @brief The procedure frame stack
///
/// @todo
CallFrameStack callStack;
/// @brief Get the next line of input and run it.
/// @param shouldHandleError Set to true to tell the method to handle errors.
/// @return True if line was read and executed successfully, false otherwise.
bool getLineAndRunIt(bool shouldHandleError = true);
/// @brief Execute text. Can be any number of lines of text.
/// @param text The text to execute.
/// @return The result of the execution.
QString executeText(const QString &text);
/// @brief Print a string to the standard output.
/// @param text The text to print.
/// @details This method prints a string to the standard output. The standard
/// output can either be the console or a file, or both in the case of dribbling.
void stdPrint(const QString &text);
/// @brief Print a string to the system output.
/// @param text The text to print.
/// @details This method prints a string to the system output. The system
/// output is the console, except in the case of executing text from a file,
/// where the output is also a file.
void sysPrint(const QString &text);
/// @brief Register an error.
/// @param anError The error to register.
/// @param allowErract Set to true to allow the error to be recovered.
/// @param allowRecovery Set to true to allow the error to be recovered.
/// @return The error that was registered.
DatumPtr registerError(DatumPtr anError, bool allowErract = false, bool allowRecovery = false);
/// @brief Pause execution. Enable the user to interact with the execution environment.
/// @return The result of the pause if user provided a parameter with the continue command.
DatumPtr pause();
/// @brief Return true if input is something other than standard input.
/// @return false if input is standard input; true otherwise.
bool isInputRedirected();
/// @brief Run a list.
/// @param listP The list to run.
/// @param startTag If not null, search for the tag in the list and run from there.
/// @return The result of the last expression in the list.
DatumPtr runList(DatumPtr listP, QString startTag = QString());
/// @brief NOOP
/// @details This is a no-op. It is a token that gets passed when GOTO is used.
DatumPtr excGotoToken(DatumPtr);
/// @brief Execute a procedure.
/// @param node The procedure to execute.
/// @return The output of the procedure.
DatumPtr executeProcedure(DatumPtr node);
/// @brief Execute a macro.
/// @param node The macro to execute.
/// @return The result of the macro.
/// @details The macro is a procedure that outputs a list. The list is run in the caller's stack frame
/// after the procedure's stack frame is torn down.
DatumPtr executeMacro(DatumPtr node);
/// @brief Simply return a literal.
/// @param node The literal.
/// @return The literal.
DatumPtr executeLiteral(DatumPtr node);
/// @brief Return the value of a variable.
/// @param node The variable to return the value of.
/// @return The value of the variable.
DatumPtr executeValueOf(DatumPtr node);
/// @brief Set the value of a variable.
/// @param node The variable to set the value of.
/// @return The new value of the variable.
DatumPtr excSetfoo(DatumPtr node);
/// @brief Return the value of a variable.
/// @param node The variable to return the value of.
/// @return The value of the variable.
DatumPtr excFoo(DatumPtr node);
// Since every primitive requires a declaration, a help file entry, a function definition, and an entry in the pimitives table.
// It is far easier to include all the information about a primitive in one place. In QLogo, all the information about
// every primitive can be found in its implimentation file. Various scripts extract the relevant information.
// The python script, 'generate_command_table.py', generates the declarations for the primitives and places them in
// the 'primitives.h' file.
#include "primitives.h"
/// @brief No operation.
/// @param node Dummy value.
/// @return Nothing.
/// @details This is a no-op. Some UCBLogo commands have no action in QLogo.
DatumPtr excNoop(DatumPtr node);
/// @brief Throw an error because the GUI is not available.
/// @param node Dummy value.
/// @return Nothing.
/// @details In environments that do not support the GUI, this primitive throws an error.
DatumPtr excErrorNoGui(DatumPtr node);
// SPECIAL VARIABLES
/// if TRUE, prints the names of procedures defined when loading
/// from a file (including the temporary file made by EDIT).
bool varLOADNOISILY();
/// if TRUE, indicates that an attempt to use a procedure that doesn't
/// exist should be taken as an implicit getter or setter procedure
/// (setter if the first three letters of the name are SET) for a variable
/// of the same name (without the SET if appropriate).
bool varALLOWGETSET();
/// if nonempty, should be an instruction list that will be evaluated
/// whenever a mouse button is pressed. Note that the user may have
DatumPtr varBUTTONACT();
/// if nonempty, should be an instruction list that will be evaluated
/// whenever a key is pressed.
DatumPtr varKEYACT();
/// if TRUE, any output will be printed in a manner suitable for re-reading
/// by QLogo to produce the same value.
bool varFULLPRINTP();
/// indicates the maximum depth of sublist structure that will be printed.
int varPRINTDEPTHLIMIT();
/// indicates the maximum number of members in any one list that will be printed.
int varPRINTWIDTHLIMIT();
/// if assigned a list value in a file loaded by LOAD, that value is
/// run as an instructionlist after loading.
DatumPtr varSTARTUP();
/// if TRUE, causes any procedure defined during EDIT or LOAD to be
/// unburied when editing a file.
bool varUNBURYONEDIT();
/// if TRUE, indicates that lower case and upper case letters should be
/// considered equal by EQUALP, BEFOREP, MEMBERP, etc.
bool varCASEIGNOREDP();
};
/// @brief Redirects the standard input and output streams.
/// @details This class redirects the standard input and output streams to a
/// new stream for RAII. When the redirection is done, the original streams are
/// saved so they can be restored later when the object is deallocated.
class StreamRedirect
{
TextStream *originalWriteStream;
TextStream *originalSystemWriteStream;
TextStream *originalReadStream;
TextStream *originalSystemReadStream;
Parser *originalParser;
public:
/// @brief Constructor.
/// @param newReadStream The new read stream.
/// @param newWriteStream The new write stream.
/// @param newParser The new parser.
/// @details The constructor redirects the standard input and output streams
/// to a new stream.
StreamRedirect(TextStream *newReadStream, TextStream *newWriteStream, Parser *newParser);
/// @brief Destructor.
/// @details The destructor restores the original standard input and output
/// streams.
~StreamRedirect();
};
#endif // EXECUTOR_H
|