diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/cmdline.h | 2 | ||||
| -rw-r--r-- | src/qregisters.cpp | 74 | ||||
| -rw-r--r-- | src/qregisters.h | 47 | ||||
| -rw-r--r-- | src/spawn.h | 2 | 
4 files changed, 95 insertions, 30 deletions
diff --git a/src/cmdline.h b/src/cmdline.h index 9a78605..05506fa 100644 --- a/src/cmdline.h +++ b/src/cmdline.h @@ -104,7 +104,7 @@ extern bool quit_requested;  class StateSaveCmdline : public StateExpectQReg {  public: -	StateSaveCmdline() : StateExpectQReg(true) {} +	StateSaveCmdline() : StateExpectQReg(QREG_OPTIONAL_INIT) {}  private:  	State *got_register(QRegister *reg); diff --git a/src/qregisters.cpp b/src/qregisters.cpp index a82e219..e47415b 100644 --- a/src/qregisters.cpp +++ b/src/qregisters.cpp @@ -849,6 +849,11 @@ StateString:  done:  	if (mode > MODE_NORMAL) { +		/* +		 * StateExpectQRegs with type != OPTIONAL +		 * will never see this NULL pointer beyond +		 * BEGIN_EXEC() +		 */  		result = NULL;  		return true;  	} @@ -856,12 +861,24 @@ done:  	QRegisterTable &table = is_local ? *QRegisters::locals  	                                 : QRegisters::globals; -	result = table[name]; -	if (!result) { -		if (!initialize) -			throw InvalidQRegError(name, is_local); -		result = table.insert(name); -		table.undo_remove(result); +	switch (type) { +	case QREG_REQUIRED: +		result = table[name]; +		if (!result) +			fail(); +		break; + +	case QREG_OPTIONAL: +		result = table[name]; +		break; + +	case QREG_OPTIONAL_INIT: +		result = table[name]; +		if (!result) { +			result = table.insert(name); +			table.undo_remove(result); +		} +		break;  	}  	return true; @@ -871,7 +888,7 @@ done:   * Command states   */ -StateExpectQReg::StateExpectQReg(bool initialize) : State(), machine(initialize) +StateExpectQReg::StateExpectQReg(QRegSpecType type) : machine(type)  {  	transitions['\0'] = this;  } @@ -1000,9 +1017,9 @@ StateSaveQReg::got_file(const gchar *filename)  }  /*$ - * Qq -> n -- Query Q-Register integer or string + * Qq -> n -- Query Q-Register existence, its integer or string characters   * <position>Qq -> character - * :Qq -> size + * :Qq -> -1 | size   *   * Without any arguments, get and return the integer-part of   * Q-Register <q>. @@ -1012,13 +1029,26 @@ StateSaveQReg::got_file(const gchar *filename)   * Positions are handled like buffer positions \(em they   * begin at 0 up to the length of the string minus 1.   * An error is thrown for invalid positions. + * Both non-colon-modified forms of Q require register <q> + * to be defined and fail otherwise.   *   * When colon-modified, Q does not pop any arguments from   * the expression stack and returns the <size> of the string - * in Q-Register <q>. + * in Q-Register <q> if register <q> exists (i.e. is defined).   * Naturally, for empty strings, 0 is returned. - * - * The command fails for undefined registers. + * When colon-modified and Q-Register <q> is undefined, + * -1 is returned instead. + * Therefore checking the return value \fB:Q\fP for values smaller + * 0 allows checking the existence of a register. + * Note that if <q> exists, its string part is not initialized, + * so \fB:Q\fP may be used to handle purely numeric data structures + * without creating Scintilla documents by accident. + * These semantics allow the useful idiom \(lq:Q\fIq\fP">\(rq for + * checking whether a Q-Register exists and has a non-empty string. + * Note also that the return value of \fB:Q\fP may be interpreted + * as a condition boolean that represents the non-existence of <q>. + * If <q> is undefined, it returns \fIsuccess\fP, else a \fIfailure\fP + * boolean.   */  State *  StateQueryQReg::got_register(QRegister *reg) @@ -1028,9 +1058,23 @@ StateQueryQReg::got_register(QRegister *reg)  	expressions.eval();  	if (eval_colon()) { -		/* Query Q-Register string size */ -		expressions.push(reg->get_string_size()); -	} else if (expressions.args() > 0) { +		/* Query Q-Register's existence or string size */ +		expressions.push(reg ? reg->get_string_size() +		                     : (tecoInt)-1); +		return &States::start; +	} + +	/* +	 * NOTE: This command is special since the QRegister is required +	 * without colon and otherwise optional. +	 * While it may be clearer to model this as two States, +	 * we cannot currently let parsing depend on the colon-modifier. +	 * That's why we have to delegate exception throwing to QRegSpecMachine. +	 */ +	if (!reg) +		machine.fail(); + +	if (expressions.args() > 0) {  		/* Query character from Q-Register string */  		gint c = reg->get_character(expressions.pop_num_calc());  		if (c < 0) diff --git a/src/qregisters.h b/src/qregisters.h index f4f944d..1c55066 100644 --- a/src/qregisters.h +++ b/src/qregisters.h @@ -368,18 +368,30 @@ public:  	bool pop(QRegister ®);  }; +enum QRegSpecType { +	/** Register must exist, else fail */ +	QREG_REQUIRED, +	/** +	 * Return NULL if register does not exist. +	 * You can still call QRegSpecMachine::fail() to require it. +	 */ +	QREG_OPTIONAL, +	/** Initialize register if it does not already exist */ +	QREG_OPTIONAL_INIT +}; +  class QRegSpecMachine : public MicroStateMachine<QRegister *> {  	StringBuildingMachine string_machine; -	bool initialize; +	QRegSpecType type;  	bool is_local;  	gint nesting;  	gchar *name;  public: -	QRegSpecMachine(bool _init = false) +	QRegSpecMachine(QRegSpecType _type = QREG_REQUIRED)  		       : MicroStateMachine<QRegister *>(), -			 initialize(_init), +			 type(_type),  			 is_local(false), nesting(0), name(NULL) {}  	~QRegSpecMachine() @@ -390,6 +402,12 @@ public:  	void reset(void);  	bool input(gchar chr, QRegister *&result); + +	inline void +	fail(void) G_GNUC_NORETURN +	{ +		throw InvalidQRegError(name, is_local); +	}  };  /* @@ -400,15 +418,15 @@ public:   * Super class for states accepting Q-Register specifications   */  class StateExpectQReg : public State { -	QRegSpecMachine machine; -  public: -	StateExpectQReg(bool initialize = false); +	StateExpectQReg(QRegSpecType type = QREG_REQUIRED);  private:  	State *custom(gchar chr);  protected: +	QRegSpecMachine machine; +  	virtual State *got_register(QRegister *reg) = 0;  }; @@ -419,7 +437,7 @@ private:  class StatePopQReg : public StateExpectQReg {  public: -	StatePopQReg() : StateExpectQReg(true) {} +	StatePopQReg() : StateExpectQReg(QREG_OPTIONAL_INIT) {}  private:  	State *got_register(QRegister *reg); @@ -427,7 +445,7 @@ private:  class StateEQCommand : public StateExpectQReg {  public: -	StateEQCommand() : StateExpectQReg(true) {} +	StateEQCommand() : StateExpectQReg(QREG_OPTIONAL_INIT) {}  private:  	State *got_register(QRegister *reg); @@ -449,13 +467,16 @@ private:  };  class StateQueryQReg : public StateExpectQReg { +public: +	StateQueryQReg() : StateExpectQReg(QREG_OPTIONAL) {} +  private:  	State *got_register(QRegister *reg);  };  class StateCtlUCommand : public StateExpectQReg {  public: -	StateCtlUCommand() : StateExpectQReg(true) {} +	StateCtlUCommand() : StateExpectQReg(QREG_OPTIONAL_INIT) {}  private:  	State *got_register(QRegister *reg); @@ -463,7 +484,7 @@ private:  class StateEUCommand : public StateExpectQReg {  public: -	StateEUCommand() : StateExpectQReg(true) {} +	StateEUCommand() : StateExpectQReg(QREG_OPTIONAL_INIT) {}  private:  	State *got_register(QRegister *reg); @@ -488,7 +509,7 @@ private:  class StateSetQRegInteger : public StateExpectQReg {  public: -	StateSetQRegInteger() : StateExpectQReg(true) {} +	StateSetQRegInteger() : StateExpectQReg(QREG_OPTIONAL_INIT) {}  private:  	State *got_register(QRegister *reg); @@ -496,7 +517,7 @@ private:  class StateIncreaseQReg : public StateExpectQReg {  public: -	StateIncreaseQReg() : StateExpectQReg(true) {} +	StateIncreaseQReg() : StateExpectQReg(QREG_OPTIONAL_INIT) {}  private:  	State *got_register(QRegister *reg); @@ -514,7 +535,7 @@ private:  class StateCopyToQReg : public StateExpectQReg {  public: -	StateCopyToQReg() : StateExpectQReg(true) {} +	StateCopyToQReg() : StateExpectQReg(QREG_OPTIONAL_INIT) {}  private:  	State *got_register(QRegister *reg); diff --git a/src/spawn.h b/src/spawn.h index e65f18e..61c073f 100644 --- a/src/spawn.h +++ b/src/spawn.h @@ -57,7 +57,7 @@ private:  class StateEGCommand : public StateExpectQReg {  public: -	StateEGCommand() : StateExpectQReg(true) {} +	StateEGCommand() : StateExpectQReg(QREG_OPTIONAL_INIT) {}  private:  	State *got_register(QRegister *reg);  | 
