[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