[Scummvm-git-logs] scummvm master -> 8df374f6a4420ad9a5afea1a677d131cfed70deb

djsrv dservilla at gmail.com
Sun Jun 14 21:29:43 UTC 2020


This automated email contains information about 3 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
a7cbe1fbd2 DIRECTOR: LINGO: Reduce compile/execute var reuse
1974e2ec79 DIRECTOR: LINGO: Allow for anonymous functions
8df374f6a4 DIRECTOR: LINGO: Implement b_value


Commit: a7cbe1fbd295518012cf7e342c92dff16ef4e142
    https://github.com/scummvm/scummvm/commit/a7cbe1fbd295518012cf7e342c92dff16ef4e142
Author: djsrv (dservilla at gmail.com)
Date: 2020-06-14T17:09:39-04:00

Commit Message:
DIRECTOR: LINGO: Reduce compile/execute var reuse

The compile/execute steps can and do happen at the same time, so this
makes things slightly less messy.

Changed paths:
    engines/director/lingo/lingo-builtins.cpp
    engines/director/lingo/lingo-bytecode.cpp
    engines/director/lingo/lingo-codegen.cpp
    engines/director/lingo/lingo-events.cpp
    engines/director/lingo/lingo-the.cpp
    engines/director/lingo/lingo.cpp
    engines/director/lingo/lingo.h
    engines/director/resource.cpp
    engines/director/score-loading.cpp
    engines/director/score.cpp
    engines/director/score.h


diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index 0e154e8d28..35c1442c18 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -1617,7 +1617,7 @@ void LB::b_installMenu(int nargs) {
 	}
 
 	// TODO: Menu callbacks should probably not be in the movie's lingo archive
-	g_lingo->addCode(handlers.c_str(), kMovieScript, 1337);
+	g_lingo->addCode(handlers.c_str(), 0, kMovieScript, 1337);
 }
 
 Common::String Lingo::genMenuHandler(int *commandId, Common::String &command) {
diff --git a/engines/director/lingo/lingo-bytecode.cpp b/engines/director/lingo/lingo-bytecode.cpp
index 4782579f3e..b11c218ba8 100644
--- a/engines/director/lingo/lingo-bytecode.cpp
+++ b/engines/director/lingo/lingo-bytecode.cpp
@@ -703,7 +703,7 @@ void LC::cb_zeropush() {
 	g_lingo->push(d);
 }
 
-void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType type, uint16 id, Common::String &archName) {
+void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, int archiveIndex, ScriptType type, uint16 id, Common::String &archName) {
 	debugC(1, kDebugCompile, "Add V4 bytecode for type %s with id %d", scriptType2str(type), id);
 
 	if (getScriptContext(type, id)) {
@@ -713,9 +713,10 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty
 		return;
 	}
 
-	_currentScriptContext = new ScriptContext;
+	_assemblyArchive = archiveIndex;
+	_assemblyContext = new ScriptContext;
 	_currentEntityId = id;
-	_archives[_archiveIndex].scriptContexts[type][id] = _currentScriptContext;
+	_archives[_assemblyArchive].scriptContexts[type][id] = _assemblyContext;
 
 	if (stream.size() < 0x5c) {
 		warning("Lscr header too small");
@@ -764,8 +765,8 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty
 	stream.seek(globalsOffset);
 	for (uint16 i = 0; i < globalsCount; i++) {
 		uint16 index = stream.readUint16();
-		if (index < _archives[_archiveIndex].names.size()) {
-			const char *name = _archives[_archiveIndex].names[index].c_str();
+		if (index < _archives[_assemblyArchive].names.size()) {
+			const char *name = _archives[_assemblyArchive].names[index].c_str();
 			debugC(5, kDebugLoading, "%d: %s", i, name);
 			if (!_globalvars.contains(name)) {
 				_globalvars[name] = Symbol();
@@ -909,7 +910,7 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty
 			break;
 		}
 
-		_currentScriptContext->constants.push_back(constant);
+		_assemblyContext->constants.push_back(constant);
 	}
 	free(constsStore);
 
@@ -989,8 +990,8 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty
 				uint16 index = (uint16)READ_BE_UINT16(&codeStore[namePointer]);
 				namePointer += 2;
 				Common::String name;
-				if (index < _archives[_archiveIndex].names.size()) {
-					name = _archives[_archiveIndex].names[index];
+				if (index < _archives[_assemblyArchive].names.size()) {
+					name = _archives[_assemblyArchive].names[index];
 					argMap[j] = index;
 				} else {
 					name = Common::String::format("arg_%d", j);
@@ -1015,8 +1016,8 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty
 				uint16 index = (uint16)READ_BE_UINT16(&codeStore[namePointer]);
 				namePointer += 2;
 				Common::String name;
-				if (index < _archives[_archiveIndex].names.size()) {
-					name = _archives[_archiveIndex].names[index];
+				if (index < _archives[_assemblyArchive].names.size()) {
+					name = _archives[_assemblyArchive].names[index];
 					varMap[j] = index;
 				} else {
 					name = Common::String::format("var_%d", j);
@@ -1057,7 +1058,7 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty
 					warning("Opcode 0x%02x arg %d not a multiple of 6!", opcode, arg);
 				}
 				arg /= 6;
-				Datum constant = _currentScriptContext->constants[arg];
+				Datum constant = _assemblyContext->constants[arg];
 				switch (constant.type) {
 				case INT:
 					g_lingo->code1(LC::c_intpush);
@@ -1202,9 +1203,9 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty
 
 		// Attach to handlers
 		Symbol sym;
-		if (nameIndex < _archives[_archiveIndex].names.size()) {
-			debugC(5, kDebugLoading, "Function %d binding: %s()", i, _archives[_archiveIndex].names[nameIndex].c_str());
-			sym = g_lingo->define(_archives[_archiveIndex].names[nameIndex], argCount, _currentAssembly, argNames, varNames);
+		if (nameIndex < _archives[_assemblyArchive].names.size()) {
+			debugC(5, kDebugLoading, "Function %d binding: %s()", i, _archives[_assemblyArchive].names[nameIndex].c_str());
+			sym = g_lingo->define(_archives[_assemblyArchive].names[nameIndex], argCount, _currentAssembly, argNames, varNames);
 		} else {
 			warning("Function has unknown name id %d, skipping define", nameIndex);
 			sym.name = new Common::String();
@@ -1217,8 +1218,8 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty
 		}
 
 		if (!skipdump && ConfMan.getBool("dump_scripts")) {
-			if (nameIndex < _archives[_archiveIndex].names.size())
-				out.writeString(Common::String::format("function %s, %d args\n", _archives[_archiveIndex].names[nameIndex].c_str(), argCount));
+			if (nameIndex < _archives[_assemblyArchive].names.size())
+				out.writeString(Common::String::format("function %s, %d args\n", _archives[_assemblyArchive].names[nameIndex].c_str(), argCount));
 			else
 				out.writeString(Common::String::format("<noname>, %d args\n", argCount));
 
@@ -1231,7 +1232,7 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty
 			out.writeString(Common::String::format("<end code>\n\n"));
 		}
 
-		_currentScriptContext->functions.push_back(sym);
+		_assemblyContext->functions.push_back(sym);
 		_currentAssembly = nullptr;
 	}
 
@@ -1244,7 +1245,7 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty
 }
 
 
-void Lingo::addNamesV4(Common::SeekableSubReadStreamEndian &stream) {
+void Lingo::addNamesV4(Common::SeekableSubReadStreamEndian &stream, int archiveIndex) {
 	debugC(1, kDebugCompile, "Add V4 script name index");
 
 	if (stream.size() < 0x14) {
@@ -1276,7 +1277,7 @@ void Lingo::addNamesV4(Common::SeekableSubReadStreamEndian &stream) {
 
 	stream.seek(offset);
 
-	_archives[_archiveIndex].names.clear();
+	_archives[archiveIndex].names.clear();
 
 	Common::Array<Common::String> names;
 	for (uint32 i = 0; i < count; i++) {
@@ -1285,7 +1286,7 @@ void Lingo::addNamesV4(Common::SeekableSubReadStreamEndian &stream) {
 		for (uint8 j = 0; j < size; j++) {
 			name += stream.readByte();
 		}
-		_archives[_archiveIndex].names.push_back(name);
+		_archives[archiveIndex].names.push_back(name);
 		debugC(5, kDebugLoading, "%d: \"%s\"", i, name.c_str());
 	}
 
diff --git a/engines/director/lingo/lingo-codegen.cpp b/engines/director/lingo/lingo-codegen.cpp
index 1b5a00d527..7378a1f08f 100644
--- a/engines/director/lingo/lingo-codegen.cpp
+++ b/engines/director/lingo/lingo-codegen.cpp
@@ -73,8 +73,8 @@ Symbol Lingo::define(Common::String &name, int nargs, ScriptData *code, Common::
 	sym.maxArgs = nargs;
 	sym.argNames = argNames;
 	sym.varNames = varNames;
-	sym.ctx = _currentScriptContext;
-	sym.archiveIndex = _archiveIndex;
+	sym.ctx = _assemblyContext;
+	sym.archiveIndex = _assemblyArchive;
 
 	if (debugChannelSet(1, kDebugCompile)) {
 		uint pc = 0;
@@ -97,9 +97,9 @@ Symbol Lingo::define(Common::String &name, int nargs, ScriptData *code, Common::
 			warning("Redefining handler '%s'", name.c_str());
 
 		if (!_eventHandlerTypeIds.contains(name)) {
-			_archives[_archiveIndex].functionHandlers[name] = sym;
+			_archives[_assemblyArchive].functionHandlers[name] = sym;
 		} else {
-			_archives[_archiveIndex].eventHandlers[ENTITY_INDEX(_eventHandlerTypeIds[name], _currentEntityId)] = sym;
+			_archives[_assemblyArchive].eventHandlers[ENTITY_INDEX(_eventHandlerTypeIds[name], _currentEntityId)] = sym;
 		}
 	}
 
diff --git a/engines/director/lingo/lingo-events.cpp b/engines/director/lingo/lingo-events.cpp
index 6e70c96a8b..0f1c0e05db 100644
--- a/engines/director/lingo/lingo-events.cpp
+++ b/engines/director/lingo/lingo-events.cpp
@@ -102,8 +102,8 @@ int Lingo::getEventCount() {
 
 void Lingo::setPrimaryEventHandler(LEvent event, const Common::String &code) {
 	debugC(3, kDebugLingoExec, "setting primary event handler (%s)", _eventHandlerTypes[event]);
-	_archives[_archiveIndex].primaryEventHandlers[event] = code;
-	addCode(code.c_str(), kGlobalScript, event);
+	_archives[0].primaryEventHandlers[event] = code;
+	addCode(code.c_str(), 0, kGlobalScript, event);
 }
 
 void Lingo::primaryEventHandler(LEvent event) {
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index bba027ad5e..fe708fe907 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -378,15 +378,15 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
 		break;
 	case kTheKeyDownScript:
 		d.type = STRING;
-		if (_archives[_archiveIndex].primaryEventHandlers.contains(kEventKeyDown))
-			d.u.s = new Common::String(_archives[_archiveIndex].primaryEventHandlers[kEventKeyDown]);
+		if (_archives[0].primaryEventHandlers.contains(kEventKeyDown))
+			d.u.s = new Common::String(_archives[0].primaryEventHandlers[kEventKeyDown]);
 		else
 			d.u.s = new Common::String();
 		break;
 	case kTheKeyUpScript:
 		d.type = STRING;
-		if (_archives[_archiveIndex].primaryEventHandlers.contains(kEventKeyUp))
-			d.u.s = new Common::String(_archives[_archiveIndex].primaryEventHandlers[kEventKeyUp]);
+		if (_archives[0].primaryEventHandlers.contains(kEventKeyUp))
+			d.u.s = new Common::String(_archives[0].primaryEventHandlers[kEventKeyUp]);
 		else
 			d.u.s = new Common::String();
 		break;
@@ -480,8 +480,8 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
 		break;
 	case kTheMouseDownScript:
 		d.type = STRING;
-		if (_archives[_archiveIndex].primaryEventHandlers.contains(kEventMouseDown))
-			d.u.s = new Common::String(_archives[_archiveIndex].primaryEventHandlers[kEventMouseDown]);
+		if (_archives[0].primaryEventHandlers.contains(kEventMouseDown))
+			d.u.s = new Common::String(_archives[0].primaryEventHandlers[kEventMouseDown]);
 		else
 			d.u.s = new Common::String();
 		break;
@@ -499,8 +499,8 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
 		break;
 	case kTheMouseUpScript:
 		d.type = STRING;
-		if (_archives[_archiveIndex].primaryEventHandlers.contains(kEventMouseUp))
-			d.u.s = new Common::String(_archives[_archiveIndex].primaryEventHandlers[kEventMouseUp]);
+		if (_archives[0].primaryEventHandlers.contains(kEventMouseUp))
+			d.u.s = new Common::String(_archives[0].primaryEventHandlers[kEventMouseUp]);
 		else
 			d.u.s = new Common::String();
 		break;
@@ -563,8 +563,8 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
 		break;
 	case kTheTimeoutScript:
 		d.type = STRING;
-		if (_archives[_archiveIndex].primaryEventHandlers.contains(kEventTimeout))
-			d.u.s = new Common::String(_archives[_archiveIndex].primaryEventHandlers[kEventTimeout]);
+		if (_archives[0].primaryEventHandlers.contains(kEventTimeout))
+			d.u.s = new Common::String(_archives[0].primaryEventHandlers[kEventTimeout]);
 		else
 			d.u.s = new Common::String();
 		break;
@@ -1082,7 +1082,8 @@ void Lingo::setTheCast(Datum &id1, int field, Datum &d) {
 			warning("Lingo::setTheCast(): The cast %d not found. type: %d", id, castType);
 			return;
 		}
-		addCode(d.u.s->c_str(), kSpriteScript, id);
+		// FIXME: What if the cast member is in a different archive than the current one?
+		addCode(d.u.s->c_str(), _archiveIndex, kSpriteScript, id);
 
 		castInfo->script = d.asString();
 		break;
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index c3e5fd2d18..ae1edd1478 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -156,6 +156,10 @@ Lingo::Lingo(DirectorEngine *vm) : _vm(vm) {
 	_currentScript = 0;
 	_currentScriptContext = nullptr;
 
+	_assemblyArchive = 0;
+	_currentAssembly = nullptr;
+	_assemblyContext = nullptr;
+
 	_currentEntityId = 0;
 	_currentChannelId = -1;
 	_pc = 0;
@@ -286,9 +290,7 @@ const char *Lingo::findNextDefinition(const char *s) {
 	return NULL;
 }
 
-void Lingo::addCode(const char *code, ScriptType type, uint16 id) {
-	pushContext();
-
+void Lingo::addCode(const char *code, int archiveIndex, ScriptType type, uint16 id) {
 	debugC(1, kDebugCompile, "Add code for type %s(%d) with id %d\n"
 			"***********\n%s\n\n***********", scriptType2str(type), type, id, code);
 
@@ -299,10 +301,11 @@ void Lingo::addCode(const char *code, ScriptType type, uint16 id) {
 		warning("Script already defined for type %d, id %d", id, type);
 	}
 
-	_currentScriptContext = new ScriptContext;
+	_assemblyArchive = archiveIndex;
+	_assemblyContext = new ScriptContext;
 	_currentAssembly = new ScriptData;
 	_currentEntityId = id;
-	_archives[_archiveIndex].scriptContexts[type][id] = _currentScriptContext;
+	_archives[_assemblyArchive].scriptContexts[type][id] = _assemblyContext;
 
 	_methodVars = new Common::HashMap<Common::String, VarType, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo>();
 	_linenumber = _colnumber = 1;
@@ -399,7 +402,7 @@ void Lingo::addCode(const char *code, ScriptType type, uint16 id) {
 		currentFunc.name = new Common::String("[unknown]");
 	}
 	currentFunc.ctx = _currentScriptContext;
-	currentFunc.archiveIndex = _archiveIndex;
+	currentFunc.archiveIndex = _assemblyArchive;
 	// arg names should be empty, but just in case
 	Common::Array<Common::String> *argNames = new Common::Array<Common::String>;
 	for (uint i = 0; i < _argstack.size(); i++) {
@@ -429,10 +432,9 @@ void Lingo::addCode(const char *code, ScriptType type, uint16 id) {
 
 	currentFunc.argNames = argNames;
 	currentFunc.varNames = varNames;
-	_currentScriptContext->functions.push_back(currentFunc);
+	_assemblyContext->functions.push_back(currentFunc);
+	_assemblyContext = nullptr;
 	_currentAssembly = nullptr;
-
-	popContext();
 }
 
 void Lingo::printStack(const char *s, uint pc) {
@@ -1019,7 +1021,7 @@ void Lingo::runTests() {
 			debug(">> Compiling file %s of size %d, id: %d", fileList[i].c_str(), size, counter);
 
 			_hadError = false;
-			addCode(script, kMovieScript, counter);
+			addCode(script, 0, kMovieScript, counter);
 
 			if (!debugChannelSet(-1, kDebugCompileOnly)) {
 				if (!_hadError)
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index 99374a5b5f..b13070e384 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -315,9 +315,9 @@ public:
 
 	void restartLingo(bool keepSharedCast);
 
-	void addCode(const char *code, ScriptType type, uint16 id);
-	void addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType type, uint16 id, Common::String &archName);
-	void addNamesV4(Common::SeekableSubReadStreamEndian &stream);
+	void addCode(const char *code, int archiveIndex, ScriptType type, uint16 id);
+	void addCodeV4(Common::SeekableSubReadStreamEndian &stream, int archiveIndex, ScriptType type, uint16 id, Common::String &archName);
+	void addNamesV4(Common::SeekableSubReadStreamEndian &stream, int archiveIndex);
 	void executeHandler(const Common::String &name);
 	void executeScript(ScriptType type, uint16 id, uint16 function);
 	void printStack(const char *s, uint pc);
@@ -468,6 +468,8 @@ public:
 	void processIf(int toplabel, int endlabel);
 	void varCreate(const Common::String &name, bool global, SymbolHash *localvars = nullptr);
 
+	int _assemblyArchive;
+	ScriptContext *_assemblyContext;
 	ScriptData *_currentAssembly;
 	LexerDefineState _indef;
 	LexerDefineState _indefStore;
diff --git a/engines/director/resource.cpp b/engines/director/resource.cpp
index 3250dce926..ae85dc053a 100644
--- a/engines/director/resource.cpp
+++ b/engines/director/resource.cpp
@@ -79,7 +79,7 @@ void DirectorEngine::loadEXE(const Common::String movie) {
 	if (iniStream) {
 		char *script = (char *)calloc(iniStream->size() + 1, 1);
 		iniStream->read(script, iniStream->size());
-		_lingo->addCode(script, kMovieScript, 0);
+		_lingo->addCode(script, 0, kMovieScript, 0);
 		_lingo->processEvent(kEventStartUp);
 		free(script);
 	} else {
@@ -304,11 +304,9 @@ void DirectorEngine::loadSharedCastsFrom(Common::String filename) {
 	debug(0, "@@@@ Loading Shared cast '%s'", filename.c_str());
 	debug(0, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
 
-	_lingo->_archiveIndex = 1;
 	_sharedScore = new Score(this);
 	_sharedScore->setArchive(sharedCast);
 	_sharedScore->loadArchive(true);
-	_lingo->_archiveIndex = 0;
 }
 
 Cast *DirectorEngine::getCastMember(int castId) {
diff --git a/engines/director/score-loading.cpp b/engines/director/score-loading.cpp
index 208d73fa7b..5a44fe95ee 100644
--- a/engines/director/score-loading.cpp
+++ b/engines/director/score-loading.cpp
@@ -78,6 +78,8 @@ void Score::setArchive(Archive *archive) {
 }
 
 bool Score::loadArchive(bool isSharedCast) {
+	_lingoArchive = isSharedCast ? 1 : 0;
+
 	Common::Array<uint16> clutList = _movieArchive->getResourceIDList(MKTAG('C', 'L', 'U', 'T'));
 	Common::SeekableSubReadStreamEndian *r = nullptr;
 
@@ -876,7 +878,7 @@ void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream, uint16 id,
 			if (scriptId < _castScriptIds.size()) {
 				int resourceId = _castScriptIds[scriptId];
 				Common::SeekableSubReadStreamEndian *r;
-				_lingo->addCodeV4(*(r = _movieArchive->getResource(MKTAG('L', 's', 'c', 'r'), resourceId)), ((ScriptCast *)member)->_scriptType, id, _macName);
+				_lingo->addCodeV4(*(r = _movieArchive->getResource(MKTAG('L', 's', 'c', 'r'), resourceId)), _lingoArchive, ((ScriptCast *)member)->_scriptType, id, _macName);
 				delete r;
 			} else {
 				warning("Score::loadCastData(): Lingo context missing a resource entry for script %d referenced in cast %d", scriptId, id);
@@ -888,7 +890,7 @@ void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream, uint16 id,
 					if (ConfMan.getBool("dump_scripts"))
 						dumpScript(ci->script.c_str(), ((ScriptCast *)member)->_scriptType, id);
 
-					_lingo->addCode(ci->script.c_str(), ((ScriptCast *)member)->_scriptType, id);
+					_lingo->addCode(ci->script.c_str(), _lingoArchive, ((ScriptCast *)member)->_scriptType, id);
 				} else {
 					warning("Score::loadCastData(): Wrong cast type: %d", member->_type);
 				}
@@ -1012,7 +1014,7 @@ void Score::loadActions(Common::SeekableSubReadStreamEndian &stream) {
 			// continue;
 		}
 		if (!j->_value.empty()) {
-			_lingo->addCode(j->_value.c_str(), kFrameScript, j->_key);
+			_lingo->addCode(j->_value.c_str(), _lingoArchive, kFrameScript, j->_key);
 
 			processImmediateFrameScript(j->_value, j->_key);
 		}
@@ -1023,7 +1025,7 @@ void Score::loadActions(Common::SeekableSubReadStreamEndian &stream) {
 
 void Score::loadLingoNames(Common::SeekableSubReadStreamEndian &stream) {
 	if (_vm->getVersion() >= 4) {
-		_lingo->addNamesV4(stream);
+		_lingo->addNamesV4(stream, _lingoArchive);
 	} else {
 		error("Score::loadLingoNames: unsuported Director version (%d)", _vm->getVersion());
 	}
@@ -1098,7 +1100,7 @@ void Score::loadScriptText(Common::SeekableSubReadStreamEndian &stream) {
 	if (script.contains("\nmenu:") || script.hasPrefix("menu:"))
 		return;
 
-	_lingo->addCode(script.c_str(), kMovieScript, _movieScriptCount);
+	_lingo->addCode(script.c_str(), _lingoArchive, kMovieScript, _movieScriptCount);
 
 	_movieScriptCount++;
 }
@@ -1129,7 +1131,7 @@ void Score::loadCastInfo(Common::SeekableSubReadStreamEndian &stream, uint16 id)
 		dumpScript(ci->script.c_str(), kSpriteScript, id);
 
 	if (!ci->script.empty())
-		_lingo->addCode(ci->script.c_str(), kSpriteScript, id);
+		_lingo->addCode(ci->script.c_str(), _lingoArchive, kSpriteScript, id);
 
 	ci->name = getString(castStrings[1]);
 	ci->directory = getString(castStrings[2]);
@@ -1157,7 +1159,7 @@ void Score::loadFileInfo(Common::SeekableSubReadStreamEndian &stream) {
 		dumpScript(_script.c_str(), kMovieScript, _movieScriptCount);
 
 	if (!_script.empty())
-		_lingo->addCode(_script.c_str(), kMovieScript, _movieScriptCount);
+		_lingo->addCode(_script.c_str(), _lingoArchive, kMovieScript, _movieScriptCount);
 
 	_movieScriptCount++;
 	_changedBy = fileInfoStrings[1];
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index e86a260e99..bbcf30d8bd 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -45,6 +45,7 @@ Score::Score(DirectorEngine *vm) {
 	_backSurface = nullptr;
 	_backSurface2 = nullptr;
 	_lingo = _vm->getLingo();
+	_lingoArchive = 0;
 	_soundManager = _vm->getSoundManager();
 	_currentMouseDownSpriteId = 0;
 	_currentClickOnSpriteId = 0;
diff --git a/engines/director/score.h b/engines/director/score.h
index e65d527c09..ca5abdaabf 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -239,6 +239,7 @@ private:
 	uint16 _castArrayEnd;
 	uint16 _movieScriptCount;
 	Lingo *_lingo;
+	int _lingoArchive;
 	DirectorSound *_soundManager;
 	DirectorEngine *_vm;
 


Commit: 1974e2ec79054e84c3fef953b83583d4d292f02a
    https://github.com/scummvm/scummvm/commit/1974e2ec79054e84c3fef953b83583d4d292f02a
Author: djsrv (dservilla at gmail.com)
Date: 2020-06-14T17:09:39-04:00

Commit Message:
DIRECTOR: LINGO: Allow for anonymous functions

Changed paths:
    engines/director/lingo/lingo-bytecode.cpp
    engines/director/lingo/lingo-code.cpp
    engines/director/lingo/lingo-codegen.cpp
    engines/director/lingo/lingo-events.cpp
    engines/director/lingo/lingo.cpp
    engines/director/lingo/lingo.h


diff --git a/engines/director/lingo/lingo-bytecode.cpp b/engines/director/lingo/lingo-bytecode.cpp
index b11c218ba8..06c58f0554 100644
--- a/engines/director/lingo/lingo-bytecode.cpp
+++ b/engines/director/lingo/lingo-bytecode.cpp
@@ -706,7 +706,7 @@ void LC::cb_zeropush() {
 void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, int archiveIndex, ScriptType type, uint16 id, Common::String &archName) {
 	debugC(1, kDebugCompile, "Add V4 bytecode for type %s with id %d", scriptType2str(type), id);
 
-	if (getScriptContext(type, id)) {
+	if (getScriptContext(archiveIndex, type, id)) {
 		// We can't undefine context data because it could be used in e.g. symbols.
 		// Abort on double definitions.
 		error("Script already defined for type %d, id %d", id, type);
diff --git a/engines/director/lingo/lingo-code.cpp b/engines/director/lingo/lingo-code.cpp
index 0a6ad4844c..a4bb678102 100644
--- a/engines/director/lingo/lingo-code.cpp
+++ b/engines/director/lingo/lingo-code.cpp
@@ -207,7 +207,7 @@ void LC::c_xpop() {
 	g_lingo->pop();
 }
 
-void Lingo::pushContext(const Symbol *funcSym, bool newVarFrame) {
+void Lingo::pushContext(const Symbol *funcSym, bool preserveVarFrame) {
 	debugC(5, kDebugLingoExec, "Pushing frame %d", g_lingo->_callstack.size() + 1);
 	CFrame *fp = new CFrame;
 
@@ -221,7 +221,9 @@ void Lingo::pushContext(const Symbol *funcSym, bool newVarFrame) {
 		fp->sp = *funcSym;
 
 	g_lingo->_currentMe = Datum();
-	if (newVarFrame)
+	// Functions with an archiveIndex of -1 are anonymous.
+	// Execute them within the current var frame.
+	if (!preserveVarFrame && funcSym && funcSym->archiveIndex >= 0)
 		g_lingo->_localvars = new SymbolHash;
 
 	g_lingo->_callstack.push_back(fp);
@@ -243,8 +245,10 @@ void Lingo::popContext() {
 	g_lingo->_currentMe = fp->retMe;
 
 	// Restore local variables
-	g_lingo->cleanLocalVars();
-	g_lingo->_localvars = fp->localvars;
+	if (fp->sp.archiveIndex >= 0) {
+		g_lingo->cleanLocalVars();
+		g_lingo->_localvars = fp->localvars;
+	}
 
 	if (debugChannelSet(5, kDebugLingoExec)) {
 		g_lingo->printCallStack(g_lingo->_pc);
@@ -1380,48 +1384,50 @@ void LC::call(const Symbol &funcSym, int nargs, Datum target) {
 		g_lingo->push(d);
 	}
 
-	g_lingo->pushContext(&funcSym, false);
-
-	// Create new set of local variables
-	SymbolHash *localvars = new SymbolHash;
-	if (funcSym.argNames) {
-		int symNArgs = funcSym.nargs;
-		if ((int)funcSym.argNames->size() < symNArgs) {
-			int dropSize = symNArgs - funcSym.argNames->size();
-			warning("%d arg names defined for %d args! Dropping the last %d values", funcSym.argNames->size(), symNArgs, dropSize);
-			for (int i = 0; i < dropSize; i++) {
-				g_lingo->pop();
-				symNArgs -= 1;
+	g_lingo->pushContext(&funcSym, true);
+
+	if (funcSym.archiveIndex >= 0) {
+		// Create new set of local variables
+		SymbolHash *localvars = new SymbolHash;
+		if (funcSym.argNames) {
+			int symNArgs = funcSym.nargs;
+			if ((int)funcSym.argNames->size() < symNArgs) {
+				int dropSize = symNArgs - funcSym.argNames->size();
+				warning("%d arg names defined for %d args! Dropping the last %d values", funcSym.argNames->size(), symNArgs, dropSize);
+				for (int i = 0; i < dropSize; i++) {
+					g_lingo->pop();
+					symNArgs -= 1;
+				}
+			} else if ((int)funcSym.argNames->size() > symNArgs) {
+				warning("%d arg names defined for %d args! Ignoring the last %d names", funcSym.argNames->size(), symNArgs, funcSym.argNames->size() - symNArgs);
 			}
-		} else if ((int)funcSym.argNames->size() > symNArgs) {
-			warning("%d arg names defined for %d args! Ignoring the last %d names", funcSym.argNames->size(), symNArgs, funcSym.argNames->size() - symNArgs);
-		}
-		for (int i = symNArgs - 1; i >= 0; i--) {
-			Common::String name = (*funcSym.argNames)[i];
-			if (!localvars->contains(name)) {
-				g_lingo->varCreate(name, false, localvars);
-				Datum arg(name);
-				arg.type = VAR;
-				Datum value = g_lingo->pop();
-				g_lingo->varAssign(arg, value, false, localvars);
-			} else {
-				warning("Argument %s already defined", name.c_str());
-				g_lingo->pop();
+			for (int i = symNArgs - 1; i >= 0; i--) {
+				Common::String name = (*funcSym.argNames)[i];
+				if (!localvars->contains(name)) {
+					g_lingo->varCreate(name, false, localvars);
+					Datum arg(name);
+					arg.type = VAR;
+					Datum value = g_lingo->pop();
+					g_lingo->varAssign(arg, value, false, localvars);
+				} else {
+					warning("Argument %s already defined", name.c_str());
+					g_lingo->pop();
+				}
 			}
 		}
-	}
-	if (funcSym.varNames) {
-		for (Common::Array<Common::String>::iterator it = funcSym.varNames->begin(); it != funcSym.varNames->end(); ++it) {
-			Common::String name = *it;
-			if (!localvars->contains(name)) {
-				(*localvars)[name] = Symbol();
-				(*localvars)[name].name = new Common::String(name);
-			} else {
-				warning("Variable %s already defined", name.c_str());
+		if (funcSym.varNames) {
+			for (Common::Array<Common::String>::iterator it = funcSym.varNames->begin(); it != funcSym.varNames->end(); ++it) {
+				Common::String name = *it;
+				if (!localvars->contains(name)) {
+					(*localvars)[name] = Symbol();
+					(*localvars)[name].name = new Common::String(name);
+				} else {
+					warning("Variable %s already defined", name.c_str());
+				}
 			}
 		}
+		g_lingo->_localvars = localvars;
 	}
-	g_lingo->_localvars = localvars;
 
 	if (target.type == OBJECT) {
 		g_lingo->_currentMe = target;
diff --git a/engines/director/lingo/lingo-codegen.cpp b/engines/director/lingo/lingo-codegen.cpp
index 7378a1f08f..d6d3e856bd 100644
--- a/engines/director/lingo/lingo-codegen.cpp
+++ b/engines/director/lingo/lingo-codegen.cpp
@@ -91,7 +91,7 @@ Symbol Lingo::define(Common::String &name, int nargs, ScriptData *code, Common::
 			warning("Redefining method '%s' on factory '%s'", name.c_str(), factory->name->c_str());
 		}
 		factory->methods[name] = sym;
-	} else {
+	} else if (_assemblyArchive >= 0) {
 		Symbol existing = getHandler(name);
 		if (existing.type != VOID)
 			warning("Redefining handler '%s'", name.c_str());
diff --git a/engines/director/lingo/lingo-events.cpp b/engines/director/lingo/lingo-events.cpp
index 0f1c0e05db..5f64b79f6a 100644
--- a/engines/director/lingo/lingo-events.cpp
+++ b/engines/director/lingo/lingo-events.cpp
@@ -330,7 +330,7 @@ void Lingo::processEvent(LEvent event, ScriptType st, int entityId, int channelI
 		_archives[1].eventHandlers.contains(ENTITY_INDEX(event, entityId))) {
 		debugC(1, kDebugEvents, "Lingo::processEvent(%s, %s, %d), _eventHandler", _eventHandlerTypes[event], scriptType2str(st), entityId);
 		executeHandler(_eventHandlerTypes[event]); // D4+ Events
-	} else if (_vm->getVersion() < 4 && event == kEventNone && getScriptContext(st, entityId)) {
+	} else if (_vm->getVersion() < 4 && event == kEventNone && getScriptContext(_archiveIndex, st, entityId)) {
 		debugC(1, kDebugEvents, "Lingo::processEvent(%s, %s, %d), script", _eventHandlerTypes[event], scriptType2str(st), entityId);
 
 		executeScript(st, entityId, 0); // D3 list of scripts.
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index ae1edd1478..050c4c3499 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -205,13 +205,16 @@ Lingo::~Lingo() {
 	cleanupBuiltins();
 }
 
-ScriptContext *Lingo::getScriptContext(ScriptType type, uint16 id) {
-	if (type >= ARRAYSIZE(_archives[_archiveIndex].scriptContexts) ||
-			!_archives[_archiveIndex].scriptContexts[type].contains(id)) {
+ScriptContext *Lingo::getScriptContext(int archiveIndex, ScriptType type, uint16 id) {
+	if (archiveIndex < 0)
+		return NULL;
+
+	if (type >= ARRAYSIZE(_archives[archiveIndex].scriptContexts) ||
+			!_archives[archiveIndex].scriptContexts[type].contains(id)) {
 		return NULL;
 	}
 
-	return _archives[_archiveIndex].scriptContexts[type][id];
+	return _archives[archiveIndex].scriptContexts[type][id];
 }
 
 Common::String Lingo::getName(uint16 id) {
@@ -290,11 +293,11 @@ const char *Lingo::findNextDefinition(const char *s) {
 	return NULL;
 }
 
-void Lingo::addCode(const char *code, int archiveIndex, ScriptType type, uint16 id) {
+ScriptContext *Lingo::addCode(const char *code, int archiveIndex, ScriptType type, uint16 id) {
 	debugC(1, kDebugCompile, "Add code for type %s(%d) with id %d\n"
 			"***********\n%s\n\n***********", scriptType2str(type), type, id, code);
 
-	if (getScriptContext(type, id)) {
+	if (getScriptContext(archiveIndex, type, id)) {
 		// We can't undefine context data because it could be used in e.g. symbols.
 		// Although it has a legit case when kTheScriptText re sets code.
 		// Warn on double definitions.
@@ -302,10 +305,11 @@ void Lingo::addCode(const char *code, int archiveIndex, ScriptType type, uint16
 	}
 
 	_assemblyArchive = archiveIndex;
-	_assemblyContext = new ScriptContext;
+	ScriptContext *sc = _assemblyContext = new ScriptContext;
 	_currentAssembly = new ScriptData;
 	_currentEntityId = id;
-	_archives[_assemblyArchive].scriptContexts[type][id] = _assemblyContext;
+	if (archiveIndex >= 0)
+		_archives[_assemblyArchive].scriptContexts[type][id] = _assemblyContext;
 
 	_methodVars = new Common::HashMap<Common::String, VarType, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo>();
 	_linenumber = _colnumber = 1;
@@ -317,7 +321,7 @@ void Lingo::addCode(const char *code, int archiveIndex, ScriptType type, uint16
 		debugC(1, kDebugCompile, "Parsing menu");
 		parseMenu(code);
 
-		return;
+		return nullptr;
 	}
 
 	// Preprocess the code for ease of the parser
@@ -435,6 +439,7 @@ void Lingo::addCode(const char *code, int archiveIndex, ScriptType type, uint16
 	_assemblyContext->functions.push_back(currentFunc);
 	_assemblyContext = nullptr;
 	_currentAssembly = nullptr;
+	return sc;
 }
 
 void Lingo::printStack(const char *s, uint pc) {
@@ -600,7 +605,7 @@ void Lingo::execute(uint pc) {
 }
 
 void Lingo::executeScript(ScriptType type, uint16 id, uint16 function) {
-	ScriptContext *sc = getScriptContext(type, id);
+	ScriptContext *sc = getScriptContext(_archiveIndex, type, id);
 
 	if (!sc) {
 		debugC(3, kDebugLingoExec, "Request to execute non-existant script type %d id %d", type, id);
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index b13070e384..e19126dba4 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -315,7 +315,7 @@ public:
 
 	void restartLingo(bool keepSharedCast);
 
-	void addCode(const char *code, int archiveIndex, ScriptType type, uint16 id);
+	ScriptContext *addCode(const char *code, int archiveIndex, ScriptType type, uint16 id);
 	void addCodeV4(Common::SeekableSubReadStreamEndian &stream, int archiveIndex, ScriptType type, uint16 id, Common::String &archName);
 	void addNamesV4(Common::SeekableSubReadStreamEndian &stream, int archiveIndex);
 	void executeHandler(const Common::String &name);
@@ -360,7 +360,7 @@ private:
 	Common::Queue<LingoEvent> _eventQueue;
 
 public:
-	ScriptContext *getScriptContext(ScriptType type, uint16 id);
+	ScriptContext *getScriptContext(int archiveIndex, ScriptType type, uint16 id);
 	Common::String getName(uint16 id);
 	ScriptType event2script(LEvent ev);
 	Symbol getHandler(const Common::String &name);
@@ -372,7 +372,7 @@ public:
 
 public:
 	void execute(uint pc);
-	void pushContext(const Symbol *funcSym = nullptr, bool newVarFrame = true);
+	void pushContext(const Symbol *funcSym = nullptr, bool preserveVarFrame = false);
 	void popContext();
 	void cleanLocalVars();
 	int castIdFetch(Datum &var);


Commit: 8df374f6a4420ad9a5afea1a677d131cfed70deb
    https://github.com/scummvm/scummvm/commit/8df374f6a4420ad9a5afea1a677d131cfed70deb
Author: djsrv (dservilla at gmail.com)
Date: 2020-06-14T17:09:40-04:00

Commit Message:
DIRECTOR: LINGO: Implement b_value

Changed paths:
    engines/director/lingo/lingo-builtins.cpp
    engines/director/lingo/lingo-builtins.h


diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index 35c1442c18..9588c7a968 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -155,6 +155,7 @@ static struct BuiltinProto {
 	{ "quit",			LB::b_quit,			0, 0, false, 2, BLTIN },	// D2 c
 	{ "restart",		LB::b_restart,		0, 0, false, 2, BLTIN },	// D2 c
 	{ "return",			LB::b_return,		0, 1, false, 2, BLTIN },	// D2 f
+	{ "scummvm_returnNumber", LB::b_returnNumber, 0, 1, false, 2, BLTIN },	// D2 f
 	{ "shutDown",		LB::b_shutDown,		0, 0, false, 2, BLTIN },	// D2 c
 	{ "startTimer",		LB::b_startTimer,	0, 0, false, 2, BLTIN },	// D2 c
 		// when keyDown													// D2
@@ -511,8 +512,12 @@ void LB::b_string(int nargs) {
 
 void LB::b_value(int nargs) {
 	Datum d = g_lingo->pop();
-	warning("STUB: b_value()");
-	g_lingo->push(Datum(0));
+	Common::String code = "scummvm_returnNumber " + d.asString();
+	// Compile the code to an anonymous function and call it
+	ScriptContext *sc = g_lingo->addCode(code.c_str(), -1, kNoneScript, 0);
+	Symbol sym = sc->functions[0];
+	LC::call(sym, 0);
+	delete sc;
 }
 
 ///////////////////
@@ -1278,6 +1283,16 @@ void LB::b_return(int nargs) {
 	LC::c_procret();
 }
 
+void LB::b_returnNumber(int nargs) {
+	Datum d = g_lingo->pop();
+	// Only return numeric values
+	if (d.type == INT || d.type == FLOAT)
+		g_lingo->push(d);
+	else
+		g_lingo->push(Datum());
+	LC::c_procret();
+}
+
 void LB::b_restart(int nargs) {
 	b_quit(nargs);
 
diff --git a/engines/director/lingo/lingo-builtins.h b/engines/director/lingo/lingo-builtins.h
index 77b1c80da0..2e45aad618 100644
--- a/engines/director/lingo/lingo-builtins.h
+++ b/engines/director/lingo/lingo-builtins.h
@@ -144,6 +144,7 @@ namespace LB {
 	void b_shutDown(int nargs);
 	void b_startTimer(int nargs);
 	void b_return(int nargs);
+	void b_returnNumber(int nargs);
 
 	void b_closeDA(int nargs);
 	void b_closeResFile(int nargs);




More information about the Scummvm-git-logs mailing list