[Scummvm-git-logs] scummvm master -> 662e2cdddb2adfddc830e76ca567356adade7fe6

djsrv dservilla at gmail.com
Tue Jun 23 23:42:19 UTC 2020


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

Summary:
f220a0c469 DIRECTOR: LINGO: Give each Object a script context
662e2cdddb DIRECTOR: LINGO: Rename ScriptContext::getObject


Commit: f220a0c4690968b9cbe51dc51997fdd00a6650f4
    https://github.com/scummvm/scummvm/commit/f220a0c4690968b9cbe51dc51997fdd00a6650f4
Author: djsrv (dservilla at gmail.com)
Date: 2020-06-23T19:34:49-04:00

Commit Message:
DIRECTOR: LINGO: Give each Object a script context

Since symbols are bound to a script context, this will allow objects and
their methods to persist between movie changes. By extension, symbols
are now bound to a target object, eliminating the need for the extra
LC::call parameter.

Changed paths:
    engines/director/lingo/lingo-code.cpp
    engines/director/lingo/lingo-code.h
    engines/director/lingo/lingo-codegen.cpp
    engines/director/lingo/lingo-object.cpp
    engines/director/lingo/lingo.cpp
    engines/director/lingo/lingo.h
    engines/director/lingo/xlibs/fileio.cpp
    engines/director/lingo/xlibs/fileio.h


diff --git a/engines/director/lingo/lingo-code.cpp b/engines/director/lingo/lingo-code.cpp
index 6f2036ad1c..6efc74773b 100644
--- a/engines/director/lingo/lingo-code.cpp
+++ b/engines/director/lingo/lingo-code.cpp
@@ -209,7 +209,7 @@ void LC::c_xpop() {
 	g_lingo->pop();
 }
 
-void Lingo::pushContext(const Symbol *funcSym, bool preserveVarFrame) {
+void Lingo::pushContext(const Symbol funcSym, bool preserveVarFrame) {
 	debugC(5, kDebugLingoExec, "Pushing frame %d", g_lingo->_callstack.size() + 1);
 	CFrame *fp = new CFrame;
 
@@ -219,13 +219,18 @@ void Lingo::pushContext(const Symbol *funcSym, bool preserveVarFrame) {
 	fp->retarchive = g_lingo->_archiveIndex;
 	fp->localvars = g_lingo->_localvars;
 	fp->retMe = g_lingo->_currentMe;
-	if (funcSym)
-		fp->sp = *funcSym;
+	fp->sp = funcSym;
+
+	g_lingo->_currentScript = funcSym.u.defn;
+	if (funcSym.ctx) {
+		g_lingo->_currentScriptContext = funcSym.ctx;
+		g_lingo->_currentMe = funcSym.ctx->_target;
+	}
+	g_lingo->_archiveIndex = funcSym.archiveIndex;
 
-	g_lingo->_currentMe = Datum();
 	// Functions with an archiveIndex of -1 are anonymous.
 	// Execute them within the current var frame.
-	if (!preserveVarFrame && funcSym && funcSym->archiveIndex >= 0)
+	if (!preserveVarFrame && funcSym.archiveIndex >= 0)
 		g_lingo->_localvars = new DatumHash;
 
 	g_lingo->_callstack.push_back(fp);
@@ -1322,23 +1327,24 @@ void LC::call(const Common::String &name, int nargs) {
 
 	// Script/Xtra method call
 	if (nargs > 0) {
-		Datum target = g_lingo->peek(nargs - 1);
-		if (target.type == OBJECT && (target.u.obj->type & (kScriptObj | kXtraObj))) {
-			debugC(3, kDebugLingoExec, "Method called on object: <%s>", target.asString(true).c_str());
+		Datum d = g_lingo->peek(nargs - 1);
+		if (d.type == OBJECT && (d.u.obj->type & (kScriptObj | kXtraObj))) {
+			debugC(3, kDebugLingoExec, "Method called on object: <%s>", d.asString(true).c_str());
+			Object *target = d.u.obj;
 			if (name.equalsIgnoreCase("birth") || name.equalsIgnoreCase("new")) {
-				target = Datum(target.u.obj->clone());
+				target = target->clone();
 			}
-			funcSym = target.u.obj->getMethod(name);
+			funcSym = target->getMethod(name);
 			if (funcSym.type != VOID) {
-				if (target.u.obj->type == kScriptObj && funcSym.type == HANDLER) {
+				if (target->type == kScriptObj && funcSym.type == HANDLER) {
 					// For kScriptObj handlers the target is the first argument
-					g_lingo->_stack[g_lingo->_stack.size() - nargs] = target;
+					g_lingo->_stack[g_lingo->_stack.size() - nargs] = funcSym.ctx->_target;
 				} else {
 					// Otherwise, take the target object out of the stack
 					g_lingo->_stack.remove_at(g_lingo->_stack.size() - nargs);
 					nargs -= 1;
 				}
-				call(funcSym, nargs, target);
+				call(funcSym, nargs);
 				return;
 			}
 		}
@@ -1351,24 +1357,23 @@ void LC::call(const Common::String &name, int nargs) {
 	if (funcSym.type == VOID) {
 		Datum objName(name);
 		objName.type = VAR;
-		Datum target = g_lingo->varFetch(objName);
-		if (target.type == OBJECT && (target.u.obj->type & (kFactoryObj | kXObj))) {
-			debugC(3, kDebugLingoExec, "Method called on object: <%s>", target.asString(true).c_str());
+		Datum d = g_lingo->varFetch(objName);
+		if (d.type == OBJECT && (d.u.obj->type & (kFactoryObj | kXObj))) {
+			debugC(3, kDebugLingoExec, "Method called on object: <%s>", d.asString(true).c_str());
+			Object *target = d.u.obj;
 			Datum methodName = g_lingo->_stack.remove_at(g_lingo->_stack.size() - nargs); // Take method name out of stack
 			nargs -= 1;
 			if (methodName.u.s->equalsIgnoreCase("mNew")) {
-				target = Datum(target.u.obj->clone());
+				target = target->clone();
 			}
-			funcSym = target.u.obj->getMethod(*methodName.u.s);
-			call(funcSym, nargs, target);
-			return;
+			funcSym = target->getMethod(*methodName.u.s);
 		}
 	}
 
 	call(funcSym, nargs);
 }
 
-void LC::call(const Symbol &funcSym, int nargs, Datum target) {
+void LC::call(const Symbol &funcSym, int nargs) {
 	bool dropArgs = false;
 
 	if (funcSym.type == VOID) {
@@ -1406,6 +1411,11 @@ void LC::call(const Symbol &funcSym, int nargs, Datum target) {
 	if (funcSym.type == BLTIN || funcSym.type == FBLTIN || funcSym.type == RBLTIN) {
 		int stackSize = g_lingo->_stack.size() - nargs;
 
+		Datum target;
+		if (funcSym.ctx) {
+			target = funcSym.ctx->_target;
+		}
+
 		if (target.type == OBJECT) {
 			// Only need to update the me obj
 			// Pushing an entire stack frame is not necessary
@@ -1437,7 +1447,7 @@ void LC::call(const Symbol &funcSym, int nargs, Datum target) {
 		g_lingo->push(d);
 	}
 
-	g_lingo->pushContext(&funcSym, true);
+	g_lingo->pushContext(funcSym, true);
 
 	DatumHash *localvars = g_lingo->_localvars;
 	if (funcSym.archiveIndex >= 0) {
@@ -1485,16 +1495,6 @@ void LC::call(const Symbol &funcSym, int nargs, Datum target) {
 	}
 	g_lingo->_localvars = localvars;
 
-	if (target.type == OBJECT) {
-		g_lingo->_currentMe = target;
-	}
-
-	g_lingo->_currentScript = funcSym.u.defn;
-	if (funcSym.ctx) {
-		g_lingo->_currentScriptContext = funcSym.ctx;
-	}
-	g_lingo->_archiveIndex = funcSym.archiveIndex;
-
 	g_lingo->_pc = 0;
 }
 
diff --git a/engines/director/lingo/lingo-code.h b/engines/director/lingo/lingo-code.h
index 2837aa6ec7..8eb6ea2a10 100644
--- a/engines/director/lingo/lingo-code.h
+++ b/engines/director/lingo/lingo-code.h
@@ -114,7 +114,7 @@ namespace LC {
 	void c_jumpifz();
 	void c_call();
 
-	void call(const Symbol &targetSym, int nargs, Datum target = Datum());
+	void call(const Symbol &targetSym, int nargs);
 	void call(const Common::String &name, int nargs);
 
 	void c_procret();
diff --git a/engines/director/lingo/lingo-codegen.cpp b/engines/director/lingo/lingo-codegen.cpp
index 8dd872c1f0..0dc1e27daa 100644
--- a/engines/director/lingo/lingo-codegen.cpp
+++ b/engines/director/lingo/lingo-codegen.cpp
@@ -49,6 +49,7 @@
 #include "director/lingo/lingo.h"
 #include "director/lingo/lingo-builtins.h"
 #include "director/lingo/lingo-code.h"
+#include "director/types.h"
 
 #include "director/util.h"
 
@@ -87,10 +88,10 @@ Symbol Lingo::define(Common::String &name, int nargs, ScriptData *code, Common::
 	}
 
 	if (factory) {
-		if (factory->methods.contains(name)) {
+		if (factory->ctx->_functionHandlers.contains(name)) {
 			warning("Redefining method '%s' on factory '%s'", name.c_str(), factory->name->c_str());
 		}
-		factory->methods[name] = sym;
+		factory->ctx->_functionHandlers[name] = sym;
 	} else if (_assemblyArchive >= 0) {
 		Symbol existing = getHandler(name);
 		if (existing.type != VOID)
@@ -294,7 +295,8 @@ void Lingo::varCreate(const Common::String &name, bool global, DatumHash *localv
 }
 
 void Lingo::codeFactory(Common::String &name) {
-	Object *obj = new Object(name, kFactoryObj);
+	ScriptContext *ctx = new ScriptContext(kNoneScript, name);
+	Object *obj = new Object(name, kFactoryObj, ctx);
 
 	_currentFactory = obj;
 	if (!_globalvars.contains(name)) {
diff --git a/engines/director/lingo/lingo-object.cpp b/engines/director/lingo/lingo-object.cpp
index 60fe49309d..c878ef0ee1 100644
--- a/engines/director/lingo/lingo-object.cpp
+++ b/engines/director/lingo/lingo-object.cpp
@@ -108,11 +108,9 @@ void Lingo::openXLib(const Common::String &name, ObjectType type) {
 }
 
 Object *Object::clone() {
-	Object *res = new Object(*name, type);
+	Object *res = new Object(*name, type, new ScriptContext(*ctx));
 	res->disposed = disposed;
-	res->prototype = this;
 	res->properties = properties;
-	res->methods = methods;
 	res->inheritanceLevel = inheritanceLevel + 1;
 	if (objArray) {
 		res->objArray = new Common::HashMap<uint32, Datum>(*objArray);
@@ -126,15 +124,15 @@ Symbol Object::getMethod(const Common::String &methodName) {
 	}
 
 	// instance method (factory, script object, and Xtra)
-	if ((type | (kFactoryObj & kScriptObj & kXtraObj)) && methods.contains(methodName)) {
-		return methods[methodName];
+	if ((type | (kFactoryObj & kScriptObj & kXtraObj)) && ctx->_functionHandlers.contains(methodName)) {
+		return ctx->_functionHandlers[methodName];
 	}
 
 	if ((type & (kFactoryObj | kXObj)) && methodName.hasPrefixIgnoreCase("m")) {
 		Common::String shortName = methodName.substr(1);
 		// instance method (XObject)
-		if (type == kXObj && methods.contains(shortName) && inheritanceLevel > 1) {
-			return methods[shortName];
+		if (type == kXObj && ctx->_functionHandlers.contains(shortName) && inheritanceLevel > 1) {
+			return ctx->_functionHandlers[shortName];
 		}
 		// predefined method (factory and XObject)
 		if (g_lingo->_methods.contains(shortName) && (type & g_lingo->_methods[shortName].type)) {
@@ -269,7 +267,7 @@ void LM::m_perform(int nargs) {
 	Datum methodName = g_lingo->_stack.remove_at(g_lingo->_stack.size() - nargs); // Take method name out of stack
 	nargs -= 1;
 	Symbol funcSym = me->getMethod(*methodName.u.s);
-	LC::call(funcSym, nargs, g_lingo->_currentMe);
+	LC::call(funcSym, nargs);
 }
 
 // XObject
@@ -283,7 +281,7 @@ void LM::m_instanceRespondsTo(int nargs) {
 	Datum d = g_lingo->pop();
 	Common::String methodName = d.asString();
 
-	if (me->methods.contains(methodName)) {
+	if (me->ctx->_functionHandlers.contains(methodName)) {
 		g_lingo->push(Datum(1));
 		return;
 	}
@@ -309,7 +307,7 @@ void LM::m_respondsTo(int nargs) {
 	Datum d = g_lingo->pop();
 	Common::String methodName = d.asString();
 
-	if (me->methods.contains(methodName) && me->inheritanceLevel > 1) {
+	if (me->ctx->_functionHandlers.contains(methodName) && me->inheritanceLevel > 1) {
 		g_lingo->push(Datum(1));
 		return;
 	}
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index 883d5ae0b0..a53636132b 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -685,6 +685,9 @@ int Lingo::getAlignedType(Datum &d1, Datum &d2) {
 }
 
 void Datum::reset() {
+	if (!refCount)
+		return;
+
 	*refCount -= 1;
 	if (*refCount <= 0) {
 		switch (type) {
@@ -1077,7 +1080,7 @@ void Lingo::executePerFrameHook(int frame, int subframe) {
 			debugC(1, kDebugLingoExec, "Executing perFrameHook : <%s>(mAtFrame, %d, %d)", _perFrameHook.asString(true).c_str(), frame, subframe);
 			push(Datum(frame));
 			push(Datum(subframe));
-			LC::call(method, 2, _perFrameHook);
+			LC::call(method, 2);
 			execute(_pc);
 		}
 	}
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index cda2b856ad..1618471839 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -220,12 +220,29 @@ public:
 	ScriptType _type;
 	Common::String _name;
 	Common::Array<Common::String> _functionNames; // used by cb_localcall
-	Common::HashMap<uint32, Symbol> _eventHandlers;
 	SymbolHash _functionHandlers;
+	Common::HashMap<uint32, Symbol> _eventHandlers;
 	Common::Array<Datum> _constants;
 	Common::Array<Common::String> _propNames;
+	Datum _target;
 
 	ScriptContext(ScriptType type, Common::String name) : _type(type), _name(name) {}
+	ScriptContext(const ScriptContext &sc) {
+		_type = sc._type;
+		_name = sc._name;
+		_functionNames = sc._functionNames;
+		for (SymbolHash::iterator it = sc._functionHandlers.begin(); it != sc._functionHandlers.end(); ++it) {
+			_functionHandlers[it->_key] = it->_value;
+			_functionHandlers[it->_key].ctx = this;
+		}
+		for (Common::HashMap<uint32, Symbol>::iterator it = sc._eventHandlers.begin(); it != sc._eventHandlers.end(); ++it) {
+			_eventHandlers[it->_key] = it->_value;
+			_eventHandlers[it->_key].ctx = this;
+		}
+		_constants = sc._constants;
+		_propNames = sc._propNames;
+	}
+
 	Datum getObject();
 
 private:
@@ -246,20 +263,25 @@ struct Object {
 	ObjectType type;
 	bool disposed;
 
-	Object *prototype;
 	DatumHash properties;
-	SymbolHash methods;
+	ScriptContext *ctx;
 	int inheritanceLevel; // 1 for original object
 
 	// used only for factories
 	Common::HashMap<uint32, Datum> *objArray;
 
-	Object(const Common::String &objName, ObjectType objType) {
+	Object(const Common::String &objName, ObjectType objType, ScriptContext *objCtx) {
 		name = new Common::String(objName);
 		type = objType;
 		disposed = false;
 		inheritanceLevel = 1;
-		prototype = nullptr;
+		ctx = objCtx;
+		ctx->_target = this;
+
+		// Don't include the ctx's reference to me in the refCount.
+		// Once that's the only remaining reference,
+		// I should be destroyed, killing the ctx with me.
+		*ctx->_target.refCount -= 1;
 
 		if (objType == kFactoryObj) {
 			objArray = new Common::HashMap<uint32, Datum>;
@@ -271,6 +293,8 @@ struct Object {
 	virtual ~Object() {
 		delete name;
 		delete objArray;
+		ctx->_target.refCount = nullptr; // refCount has already been freed
+		delete ctx;
 	}
 
 	virtual Object *clone();
@@ -385,7 +409,7 @@ public:
 
 public:
 	void execute(uint pc);
-	void pushContext(const Symbol *funcSym = nullptr, bool preserveVarFrame = false);
+	void pushContext(const Symbol funcSym, bool preserveVarFrame = false);
 	void popContext();
 	void cleanLocalVars();
 	int castIdFetch(Datum &var);
diff --git a/engines/director/lingo/xlibs/fileio.cpp b/engines/director/lingo/xlibs/fileio.cpp
index 724cf3e87f..64bcf231ce 100644
--- a/engines/director/lingo/xlibs/fileio.cpp
+++ b/engines/director/lingo/xlibs/fileio.cpp
@@ -28,6 +28,7 @@
 #include "director/director.h"
 #include "director/lingo/lingo.h"
 #include "director/lingo/xlibs/fileio.h"
+#include "director/types.h"
 
 namespace Director {
 
@@ -60,7 +61,8 @@ static struct MethodProto {
 void FileIO::initialize(int type) {
 	if (type & kXObj) {
 		if (!g_lingo->_globalvars.contains(xlibName)) {
-			FileObject *xobj = new FileObject(kXObj);
+			ScriptContext *ctx = new ScriptContext(kNoneScript, Common::String(xlibName));
+			FileObject *xobj = new FileObject(kXObj, ctx);
 			xobj->initMethods();
 			g_lingo->_globalvars[xlibName] = Datum();
 			g_lingo->_globalvars[xlibName].type = OBJECT;
@@ -88,16 +90,14 @@ void FileObject::initMethods() {
 		sym.maxArgs = mtd->maxArgs;
 		sym.targetType = mtd->type;
 		sym.u.bltin = mtd->func;
-		methods[mtd->name] = sym;
+		ctx->_functionHandlers[mtd->name] = sym;
 	}
 }
 
 Object *FileObject::clone() {
-	FileObject *res = new FileObject(type);
+	FileObject *res = new FileObject(type, new ScriptContext(*ctx));
 	res->disposed = disposed;
-	res->prototype = this;
 	res->properties = properties;
-	res->methods = methods;
 	res->inheritanceLevel = inheritanceLevel + 1;
 	return res;
 }
diff --git a/engines/director/lingo/xlibs/fileio.h b/engines/director/lingo/xlibs/fileio.h
index 5a93a3182d..d20bd65c61 100644
--- a/engines/director/lingo/xlibs/fileio.h
+++ b/engines/director/lingo/xlibs/fileio.h
@@ -57,7 +57,7 @@ struct FileObject : Object {
 	Common::OutSaveFile *outFile;
 	Common::MemoryWriteStreamDynamic *outStream;
 
-	FileObject(ObjectType objType) : Object("FileIO", objType) {
+	FileObject(ObjectType objType, ScriptContext *objCtx) : Object("FileIO", objType, objCtx) {
 		filename = nullptr;
 		inFile = nullptr;
 		inStream = nullptr;


Commit: 662e2cdddb2adfddc830e76ca567356adade7fe6
    https://github.com/scummvm/scummvm/commit/662e2cdddb2adfddc830e76ca567356adade7fe6
Author: djsrv (dservilla at gmail.com)
Date: 2020-06-23T19:34:54-04:00

Commit Message:
DIRECTOR: LINGO: Rename ScriptContext::getObject

Should be less confusing since a ctx can have a target object now.

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


diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index 87b896078e..8444605811 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -2162,7 +2162,7 @@ void LB::b_script(int nargs) {
 		}
 
 		if (script) {
-			g_lingo->push(Datum(script->getObject()));
+			g_lingo->push(Datum(script->getParentScript()));
 			return;
 		}
 	}
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index a53636132b..b0c434d676 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -992,20 +992,15 @@ int Datum::compareTo(Datum &d, bool ignoreCase) {
 	}
 }
 
-Datum ScriptContext::getObject() {
-	if (_obj.type != OBJECT) {
-		_obj.type = OBJECT;
-		_obj.u.obj = new Object(_name, kScriptObj);
+Datum ScriptContext::getParentScript() {
+	if (_parentScript.type != OBJECT) {
+		_parentScript.type = OBJECT;
+		_parentScript.u.obj = new Object(_name, kScriptObj, new ScriptContext(*this));
 		for (Common::Array<Common::String>::iterator it = _propNames.begin(); it != _propNames.end(); ++it) {
-			_obj.u.obj->properties[*it] = Datum();
-		}
-		for (SymbolHash::iterator it = _functionHandlers.begin(); it != _functionHandlers.end(); ++it) {
-			Symbol sym = it->_value;
-			sym.targetType = kScriptObj;
-			_obj.u.obj->methods[it->_key] = sym;
+			_parentScript.u.obj->properties[*it] = Datum();
 		}
 	}
-	return _obj;
+	return _parentScript;
 }
 
 void Lingo::parseMenu(const char *code) {
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index 1618471839..cba18f9fbb 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -243,10 +243,10 @@ public:
 		_propNames = sc._propNames;
 	}
 
-	Datum getObject();
+	Datum getParentScript();
 
 private:
-	Datum _obj;
+	Datum _parentScript;
 };
 
 enum ObjectType {




More information about the Scummvm-git-logs mailing list