[Scummvm-git-logs] scummvm refcount -> 3dc4bb38cd78c39098b855db7dfd7d6b18bce51e

moralrecordings code at moral.net.au
Tue May 12 10:06:13 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:
594f435ed8 DIRECTOR: LINGO: Add reference counter to Symbol and Datum
ceb81566df DIRECTOR: LINGO: Add copy assignment operator for Datum/Symbol
3dc4bb38cd DIRECTOR: LINGO: Precalculate array size for b_addAt


Commit: 594f435ed8abb1e058bb931951f6f5e3dada4628
    https://github.com/scummvm/scummvm/commit/594f435ed8abb1e058bb931951f6f5e3dada4628
Author: Scott Percival (code at moral.net.au)
Date: 2020-05-12T01:13:18+08:00

Commit Message:
DIRECTOR: LINGO: Add reference counter to Symbol and Datum

Changed paths:
    engines/director/lingo/lingo-builtins.cpp
    engines/director/lingo/lingo-bytecode.cpp
    engines/director/lingo/lingo-code.cpp
    engines/director/lingo/lingo-code.h
    engines/director/lingo/lingo-codegen.cpp
    engines/director/lingo/lingo-funcs.cpp
    engines/director/lingo/lingo-the.cpp
    engines/director/lingo/lingo.cpp
    engines/director/lingo/lingo.h
    engines/director/util.cpp
    engines/director/util.h


diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index 01d9819e5a..3ad6e07416 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -315,7 +315,7 @@ void Lingo::printSTUBWithArglist(const char *funcname, int nargs, const char *pr
 	for (int i = 0; i < nargs; i++) {
 		Datum d = _stack[_stack.size() - nargs + i];
 
-		s += d.getPrintable();
+		s += d.asString(true);
 
 		if (i != nargs - 1)
 			s += ", ";
@@ -365,125 +365,101 @@ void LB::b_abs(int nargs) {
 
 void LB::b_atan(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeFloat();
-	d.u.f = atan(d.u.f);
-	g_lingo->push(d);
+	Datum res(atan(d.asFloat()));
+	g_lingo->push(res);
 }
 
 void LB::b_cos(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeFloat();
-	d.u.f = cos(d.u.f);
-	g_lingo->push(d);
+	Datum res(cos(d.asFloat()));
+	g_lingo->push(res);
 }
 
 void LB::b_exp(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeInt(); // Lingo uses int, so we're enforcing it
-	d.makeFloat();
-	d.u.f = exp(d.u.f);
-	g_lingo->push(d);
+	// Lingo uses int, so we're enforcing it
+	Datum res(exp(d.asInt()));
+	g_lingo->push(res);
 }
 
 void LB::b_float(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeFloat();
-	g_lingo->push(d);
+	Datum res(d.asFloat());
+	g_lingo->push(res);
 }
 
 void LB::b_integer(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeInt();
-	g_lingo->push(d);
+	Datum res(d.asInt());
+	g_lingo->push(res);
 }
 
 void LB::b_log(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeFloat();
-	d.u.f = log(d.u.f);
-	g_lingo->push(d);
+	Datum res(log(d.asFloat()));
+	g_lingo->push(res);
 }
 
 void LB::b_pi(int nargs) {
-	Datum d;
-	d.makeFloat();
-	d.u.f = M_PI;
-	g_lingo->push(d);
+	Datum res(M_PI);
+	g_lingo->push(res);
 }
 
 void LB::b_power(int nargs) {
 	Datum d1 = g_lingo->pop();
 	Datum d2 = g_lingo->pop();
-	d1.makeFloat();
-	d2.makeFloat();
-	d1.u.f = pow(d2.u.f, d1.u.f);
+	Datum res(pow(d2.asFloat(), d1.asFloat()));
 	g_lingo->push(d1);
 }
 
 void LB::b_random(int nargs) {
 	Datum max = g_lingo->pop();
-	Datum res;
-
-	max.makeInt();
-
-	res.u.i = g_lingo->_vm->_rnd.getRandomNumber(max.u.i - 1) + 1;
-	res.type = INT;
-
+	Datum res((int)(g_lingo->_vm->_rnd.getRandomNumber(max.asInt() - 1) + 1));
 	g_lingo->push(res);
 }
 
 void LB::b_sin(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeFloat();
-	d.u.f = sin(d.u.f);
-	g_lingo->push(d);
+	Datum res(sin(d.asFloat()));
+	g_lingo->push(res);
 }
 
 void LB::b_sqrt(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeFloat();
-	d.u.f = sqrt(d.u.f);
-	g_lingo->push(d);
+	Datum res(sqrt(d.asFloat()));
+	g_lingo->push(res);
 }
 
 void LB::b_tan(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeFloat();
-	d.u.f = tan(d.u.f);
-	g_lingo->push(d);
+	Datum res(tan(d.asFloat()));
+	g_lingo->push(res);
 }
 
 ///////////////////
 // String
 ///////////////////
 void LB::b_chars(int nargs) {
-	Datum to = g_lingo->pop();
-	Datum from = g_lingo->pop();
+	int to = g_lingo->pop().asInt();
+	int from = g_lingo->pop().asInt();
 	Datum s = g_lingo->pop();
+	TYPECHECK2(s, STRING, REFERENCE);
 
-	if (s.type == REFERENCE)
-		s.makeString();
-
-	TYPECHECK(s, STRING);
+	Common::String src = s.asString();
 
-	to.makeInt();
-	from.makeInt();
+	int len = strlen(src.c_str());
+	int f = MAX(0, MIN(len, from - 1));
+	int t = MAX(0, MIN(len, to));
 
-	int len = strlen(s.u.s->c_str());
-	int f = MAX(0, MIN(len, from.u.i - 1));
-	int t = MAX(0, MIN(len, to.u.i));
-
-	Common::String *res;
+	Common::String *result;
 	if (f > t) {
-		res = new Common::String("");
+		result = new Common::String("");
 	} else {
-		res = new Common::String(&(s.u.s->c_str()[f]), &(s.u.s->c_str()[t]));
+		result = new Common::String(&(src.c_str()[f]), &(src.c_str()[t]));
 	}
 
-	Datum ret;
-	ret.type = STRING;
-	ret.u.s = res;
-	g_lingo->push(ret);
+	Datum res(result);
+	g_lingo->push(res);
 }
 
 void LB::b_charToNum(int nargs) {
@@ -491,55 +467,50 @@ void LB::b_charToNum(int nargs) {
 
 	TYPECHECK(d, STRING);
 
-	byte chr = d.u.s->c_str()[0];
-	delete d.u.s;
+	int chr = (uint8)d.u.s->c_str()[0];
 
-	d.u.i = chr;
-	d.type = INT;
-	g_lingo->push(d);
+	Datum res(chr);
+	g_lingo->push(res);
 }
 
 void LB::b_delete(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeInt();
+	Datum res(d.asInt());
 
 	warning("STUB: b_delete");
 
-	g_lingo->push(Datum((char)d.u.i));
+	g_lingo->push(res);
 }
 
 void LB::b_hilite(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeInt();
+	Datum res(d.asInt());
 
 	warning("STUB: b_hilite");
 
-	g_lingo->push(Datum((char)d.u.i));
+	g_lingo->push(res);
 }
 
 void LB::b_length(int nargs) {
 	Datum d = g_lingo->pop();
-	if (d.type == REFERENCE)
-		d.makeString();
+	TYPECHECK2(d, STRING, REFERENCE);
 
-	TYPECHECK(d, STRING);
+	int len = strlen(d.asString().c_str());
 
-	int len = strlen(d.u.s->c_str());
-	delete d.u.s;
-
-	d.u.i = len;
-	d.type = INT;
-	g_lingo->push(d);
+	Datum res(len);
+	g_lingo->push(res);
 }
 
 void LB::b_numToChar(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeInt();
+	char result[2];
+	result[0] = (char)d.asInt();
+	result[1] = 0;
 
-	g_lingo->push(Datum((char)d.u.i));
+	g_lingo->push(Datum(Common::String(result)));
 }
 
 void LB::b_offset(int nargs) {
@@ -547,11 +518,8 @@ void LB::b_offset(int nargs) {
 		b_offsetRect(nargs);
 		return;
 	}
-	Datum target = g_lingo->pop();
-	Datum source = g_lingo->pop();
-
-	target.makeString();
-	source.makeString();
+	Common::String target = g_lingo->pop().asString();
+	Common::String source = g_lingo->pop().asString();
 
 	warning("STUB: b_offset()");
 
@@ -560,15 +528,14 @@ void LB::b_offset(int nargs) {
 
 void LB::b_string(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeString();
-	g_lingo->push(d);
+	Datum res(d.asString());
+	g_lingo->push(res);
 }
 
 void LB::b_value(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeInt();
 	warning("STUB: b_value()");
-	g_lingo->push(d);
+	g_lingo->push(Datum(0));
 }
 
 ///////////////////
@@ -584,19 +551,18 @@ void LB::b_addAt(int nargs) {
 	ARGNUMCHECK(3);
 
 	Datum value = g_lingo->pop();
-	Datum index = g_lingo->pop();
+	Datum indexD = g_lingo->pop();
 	Datum list = g_lingo->pop();
 
-	TYPECHECK(index, INT);
-	if (index.type == FLOAT)
-		index.makeInt();
+	TYPECHECK2(indexD, INT, FLOAT);
+	int index = indexD.asInt();
 	TYPECHECK(list, ARRAY);
 
-	if (!((uint)index.u.i < list.u.farr->size())) {
-		for (uint i = 0; i < index.u.i-list.u.farr->size()-1; i++)
+	if (!((uint)index < list.u.farr->size())) {
+		for (uint i = 0; i < index - list.u.farr->size() - 1; i++)
 			list.u.farr->push_back(Datum(0));
 	}
-	list.u.farr->insert_at(index.u.i-1, value);
+	list.u.farr->insert_at(index - 1, value);
 }
 
 void LB::b_addProp(int nargs) {
@@ -649,21 +615,21 @@ void LB::b_count(int nargs) {
 void LB::b_deleteAt(int nargs) {
 	ARGNUMCHECK(2);
 
-	Datum index = g_lingo->pop();
+	Datum indexD = g_lingo->pop();
 	Datum list = g_lingo->pop();
-	if (index.type == FLOAT)
-		index.makeInt();
-	TYPECHECK(index, INT);
+	TYPECHECK2(indexD, INT, FLOAT);
+	TYPECHECK2(list, ARRAY, PARRAY);
+	int index = indexD.asInt();
 
 	switch (list.type) {
 	case ARRAY:
-		list.u.farr->remove_at(index.u.i-1);
+		list.u.farr->remove_at(index - 1);
 		break;
 	case PARRAY:
-		list.u.parr->remove_at(index.u.i-1);
+		list.u.parr->remove_at(index - 1);
 		break;
 	default:
-		TYPECHECK2(list, ARRAY, PARRAY);
+		break;
 	}
 }
 
@@ -672,6 +638,7 @@ void LB::b_deleteProp(int nargs) {
 
 	Datum prop = g_lingo->pop();
 	Datum list = g_lingo->pop();
+	TYPECHECK2(list, ARRAY, PARRAY);
 
 	switch (list.type) {
 	case ARRAY:
@@ -682,12 +649,12 @@ void LB::b_deleteProp(int nargs) {
 	case PARRAY: {
 		int index = LC::compareArrays(LC::eqData, list, prop, true).u.i;
 		if (index > 0) {
-			list.u.parr->remove_at(index-1);
+			list.u.parr->remove_at(index - 1);
 		}
 		break;
 	}
 	default:
-		TYPECHECK2(list, ARRAY, PARRAY);
+		break;
 	}
 }
 
@@ -711,26 +678,25 @@ void LB::b_findPos(int nargs) {
 void LB::b_findPosNear(int nargs) {
 	ARGNUMCHECK(2);
 
-	Datum prop = g_lingo->pop();
+	Common::String prop = g_lingo->pop().asString();
 	Datum list = g_lingo->pop();
-	Datum d(0);
+	Datum res(0);
 	TYPECHECK(list, PARRAY);
 
 	// FIXME: Integrate with compareTo framework
-	prop = prop.makeString();
-	prop.u.s->toLowercase();
+	prop.toLowercase();
 
 	for (uint i = 0; i < list.u.parr->size(); i++) {
 		Datum p = *list.u.parr->operator[](i).p;
-		p.makeString();
-		p.u.s->toLowercase();
-		if (p.u.s->find(prop.u.s->c_str()) == 0) {
-			d.u.i = i+1;
+		Common::String tgt = p.asString();
+		tgt.toLowercase();
+		if (tgt.find(prop.c_str()) == 0) {
+			res.u.i = i + 1;
 			break;
 		}
 	}
 
-	g_lingo->push(d);
+	g_lingo->push(res);
 }
 
 void LB::b_getaProp(int nargs) {
@@ -761,20 +727,19 @@ void LB::b_getaProp(int nargs) {
 void LB::b_getAt(int nargs) {
 	ARGNUMCHECK(2);
 
-	Datum index = g_lingo->pop();
+	Datum indexD = g_lingo->pop();
+	TYPECHECK2(indexD, INT, FLOAT);
 	Datum list = g_lingo->pop();
-	if (index.type == FLOAT)
-		index.makeInt();
-	TYPECHECK(index, INT);
+	int index = indexD.asInt();
 
 	switch (list.type) {
 	case ARRAY:
-		ARRBOUNDSCHECK(index.u.i, list);
-		g_lingo->push(list.u.farr->operator[](index.u.i-1));
+		ARRBOUNDSCHECK(index, list);
+		g_lingo->push(list.u.farr->operator[](index - 1));
 		break;
 	case PARRAY:
-		ARRBOUNDSCHECK(index.u.i, list);
-		g_lingo->push(*list.u.parr->operator[](index.u.i-1).v);
+		ARRBOUNDSCHECK(index, list);
+		g_lingo->push(*list.u.parr->operator[](index - 1).v);
 		break;
 	default:
 		TYPECHECK2(list, ARRAY, PARRAY);
@@ -826,12 +791,10 @@ void LB::b_getPos(int nargs) {
 	ARGNUMCHECK(2);
 	Datum val = g_lingo->pop();
 	Datum list = g_lingo->pop();
+	TYPECHECK2(list, ARRAY, PARRAY);
 
 	switch (list.type) {
 	case ARRAY: {
-		if (val.type == FLOAT)
-			val.makeInt();
-		TYPECHECK(val, INT);
 		Datum d(0);
 		int index = LC::compareArrays(LC::eqData, list, val, true).u.i;
 		if (index > 0) {
@@ -850,7 +813,7 @@ void LB::b_getPos(int nargs) {
 		break;
 	}
 	default:
-		TYPECHECK2(list, ARRAY, PARRAY);
+		break;
 	}
 }
 
@@ -858,6 +821,7 @@ void LB::b_getProp(int nargs) {
 	ARGNUMCHECK(2);
 	Datum prop = g_lingo->pop();
 	Datum list = g_lingo->pop();
+	TYPECHECK2(list, ARRAY, PARRAY);
 
 	switch (list.type) {
 	case ARRAY:
@@ -870,26 +834,22 @@ void LB::b_getProp(int nargs) {
 		if (index > 0) {
 			g_lingo->push(*list.u.parr->operator[](index-1).v);
 		} else {
-			error("b_getProp: Property %s not found", prop.makeString()->c_str());
+			error("b_getProp: Property %s not found", prop.asString().c_str());
 		}
 		break;
 	}
 	default:
-		TYPECHECK2(list, ARRAY, PARRAY);
+		break;
 	}
 }
 
 void LB::b_getPropAt(int nargs) {
 	ARGNUMCHECK(2);
-	Datum index = g_lingo->pop();
+	int index = g_lingo->pop().asInt();
 	Datum list = g_lingo->pop();
 	TYPECHECK(list, PARRAY);
 
-	if (index.type == FLOAT)
-		index.makeInt();
-	TYPECHECK(index, INT);
-
-	g_lingo->push(*list.u.parr->operator[](index.u.i-1).p);
+	g_lingo->push(*list.u.parr->operator[](index-1).p);
 }
 
 void LB::b_list(int nargs) {
@@ -1010,27 +970,26 @@ void LB::b_setaProp(int nargs) {
 void LB::b_setAt(int nargs) {
 	ARGNUMCHECK(3);
 	Datum value = g_lingo->pop();
-	Datum index = g_lingo->pop();
+	int index = g_lingo->pop().asInt();
 	Datum list = g_lingo->pop();
-	if (index.type == FLOAT)
-		index.makeInt();
-	TYPECHECK(index, INT);
+
+	TYPECHECK2(list, ARRAY, PARRAY);
 
 	switch (list.type) {
 	case ARRAY:
-		if ((uint)index.u.i < list.u.farr->size()) {
-			list.u.farr->operator[](index.u.i-1) = value;
+		if ((uint)index < list.u.farr->size()) {
+			list.u.farr->operator[](index-1) = value;
 		} else {
 			// TODO: Extend the list if we request an index beyond it
-			ARRBOUNDSCHECK(index.u.i, list);
+			ARRBOUNDSCHECK(index, list);
 		}
 		break;
 	case PARRAY:
-		ARRBOUNDSCHECK(index.u.i, list);
-		*list.u.parr->operator[](index.u.i-1).v = value;
+		ARRBOUNDSCHECK(index, list);
+		*list.u.parr->operator[](index-1).v = value;
 		break;
 	default:
-		TYPECHECK2(list, ARRAY, PARRAY);
+		break;
 	}
 }
 
@@ -1067,21 +1026,13 @@ void LB::b_closeDA(int nargs) {
 void LB::b_closeResFile(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
-
-	warning("STUB: b_closeResFile(%s)", d.u.s->c_str());
-
-	delete d.u.s;
+	warning("STUB: b_closeResFile(%s)", d.asString().c_str());
 }
 
 void LB::b_closeXlib(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
-
-	warning("STUB: b_closeXlib(%s)", d.u.s->c_str());
-
-	delete d.u.s;
+	warning("STUB: b_closeXlib(%s)", d.asString().c_str());
 }
 
 void LB::b_getNthFileNameInFolder(int nargs) {
@@ -1095,31 +1046,19 @@ void LB::b_getNthFileNameInFolder(int nargs) {
 void LB::b_openDA(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
-
-	warning("STUB: b_openDA(%s)", d.u.s->c_str());
-
-	delete d.u.s;
+	warning("STUB: b_openDA(%s)", d.asString().c_str());
 }
 
 void LB::b_openResFile(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
-
-	warning("STUB: b_openResFile(%s)", d.u.s->c_str());
-
-	delete d.u.s;
+	warning("STUB: b_openResFile(%s)", d.asString().c_str());
 }
 
 void LB::b_openXlib(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
-
-	warning("STUB: b_openXlib(%s)", d.u.s->c_str());
-
-	delete d.u.s;
+	warning("STUB: b_openXlib(%s)", d.asString().c_str());
 }
 
 void LB::b_saveMovie(int nargs) {
@@ -1135,31 +1074,19 @@ void LB::b_setCallBack(int nargs) {
 void LB::b_showResFile(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
-
-	warning("STUB: b_showResFile(%s)", d.u.s->c_str());
-
-	delete d.u.s;
+	warning("STUB: b_showResFile(%s)", d.asString().c_str());
 }
 
 void LB::b_showXlib(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
-
-	warning("STUB: b_showXlib(%s)", d.u.s->c_str());
-
-	delete d.u.s;
+	warning("STUB: b_showXlib(%s)", d.asString().c_str());
 }
 
 void LB::b_xFactoryList(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
-
-	warning("STUB: b_xFactoryList(%s)", d.u.s->c_str());
-
-	delete d.u.s;
+	warning("STUB: b_xFactoryList(%s)", d.asString().c_str());
 }
 
 ///////////////////
@@ -1184,15 +1111,13 @@ void LB::b_nothing(int nargs) {
 
 void LB::b_delay(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeInt();
 
-	g_director->getCurrentScore()->_nextFrameTime = g_system->getMillis() + (float)d.u.i / 60 * 1000;
+	g_director->getCurrentScore()->_nextFrameTime = g_system->getMillis() + (float)d.asInt() / 60 * 1000;
 }
 
 void LB::b_do(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeString();
-	warning("STUB: b_do(%s)", d.u.s->c_str());
+	warning("STUB: b_do(%s)", d.asString().c_str());
 }
 
 void LB::b_go(int nargs) {
@@ -1350,42 +1275,34 @@ void LB::b_startTimer(int nargs) {
 ///////////////////
 void LB::b_factoryP(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeInt();
-	d.u.i = 1;
-	g_lingo->push(d);
+	Datum res(d.asInt());
+	g_lingo->push(res);
 
 	warning("STUB: b_factoryP");
 }
 
 void LB::b_floatP(int nargs) {
 	Datum d = g_lingo->pop();
-	int res = (d.type == FLOAT) ? 1 : 0;
-	d.makeInt();
-	d.u.i = res;
-	g_lingo->push(d);
+	Datum res((d.type == FLOAT) ? 1 : 0);
+	g_lingo->push(res);
 }
 
 void LB::b_ilk(int nargs) {
 	Datum d = g_lingo->pop();
-	d.u.s = new Common::String(d.type2str(true));
-	d.type = SYMBOL;
-	g_lingo->push(d);
+	Datum res(new Common::String(d.type2str(true)));
+	g_lingo->push(res);
 }
 
 void LB::b_integerp(int nargs) {
 	Datum d = g_lingo->pop();
-	int res = (d.type == INT) ? 1 : 0;
-	d.makeInt();
-	d.u.i = res;
-	g_lingo->push(d);
+	Datum res((d.type == INT) ? 1 : 0);
+	g_lingo->push(res);
 }
 
 void LB::b_objectp(int nargs) {
 	Datum d = g_lingo->pop();
-	int res = (d.type == OBJECT) ? 1 : 0;
-	d.makeInt();
-	d.u.i = res;
-	g_lingo->push(d);
+	Datum res ((d.type == OBJECT) ? 1 : 0);
+	g_lingo->push(res);
 }
 
 void LB::b_pictureP(int nargs) {
@@ -1396,26 +1313,20 @@ void LB::b_pictureP(int nargs) {
 
 void LB::b_stringp(int nargs) {
 	Datum d = g_lingo->pop();
-	int res = (d.type == STRING) ? 1 : 0;
-	d.makeInt();
-	d.u.i = res;
-	g_lingo->push(d);
+	Datum res((d.type == STRING) ? 1 : 0);
+	g_lingo->push(res);
 }
 
 void LB::b_symbolp(int nargs) {
 	Datum d = g_lingo->pop();
-	int res = (d.type == SYMBOL) ? 1 : 0;
-	d.makeInt();
-	d.u.i = res;
-	g_lingo->push(d);
+	Datum res((d.type == SYMBOL) ? 1 : 0);
+	g_lingo->push(res);
 }
 
 void LB::b_voidP(int nargs) {
 	Datum d = g_lingo->pop();
-	int res = (d.type == VOID) ? 1 : 0;
-	d.makeInt();
-	d.u.i = res;
-	g_lingo->push(d);
+	Datum res((d.type == VOID) ? 1 : 0);
+	g_lingo->push(res);
 }
 
 
@@ -1425,11 +1336,7 @@ void LB::b_voidP(int nargs) {
 void LB::b_alert(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
-
-	warning("STUB: b_alert(%s)", d.u.s->c_str());
-
-	delete d.u.s;
+	warning("STUB: b_alert(%s)", d.asString().c_str());
 }
 
 void LB::b_birth(int nargs) {
@@ -1452,13 +1359,10 @@ void LB::b_cursor(int nargs) {
 	if (d.type == ARRAY) {
 		Datum sprite = d.u.farr->operator[](0);
 		Datum mask = d.u.farr->operator[](1);
-		sprite.makeInt();
-		mask.makeInt();
 
-		g_lingo->func_cursor(sprite.u.i, mask.u.i);
+		g_lingo->func_cursor(sprite.asInt(), mask.asInt());
 	} else {
-		d.makeInt();
-		g_lingo->func_cursor(d.u.i, -1);
+		g_lingo->func_cursor(d.asInt(), -1);
 	}
 }
 
@@ -1477,10 +1381,7 @@ void LB::b_constrainH(int nargs) {
 	Datum num = g_lingo->pop();
 	Datum sprite = g_lingo->pop();
 
-	num.makeInt();
-	sprite.makeInt();
-
-	warning("STUB: b_constrainH(%d, %d)", sprite.u.i, num.u.i);
+	warning("STUB: b_constrainH(%d, %d)", sprite.asInt(), num.asInt());
 
 	g_lingo->push(Datum(0));
 }
@@ -1489,10 +1390,7 @@ void LB::b_constrainV(int nargs) {
 	Datum num = g_lingo->pop();
 	Datum sprite = g_lingo->pop();
 
-	num.makeInt();
-	sprite.makeInt();
-
-	warning("STUB: b_constrainV(%d, %d)", sprite.u.i, num.u.i);
+	warning("STUB: b_constrainV(%d, %d)", sprite.asInt(), num.asInt());
 
 	g_lingo->push(Datum(0));
 }
@@ -1549,15 +1447,15 @@ void LB::b_installMenu(int nargs) {
 	// installMenu castNum
 	Datum d = g_lingo->pop();
 
-	d.makeInt();
+	int castId = d.asInt();
 
 	if (g_director->getVersion() < 4)
-		d.u.i += g_director->getCurrentScore()->_castIDoffset;
+		castId += g_director->getCurrentScore()->_castIDoffset;
 
-	const Stxt *stxt = g_director->getCurrentScore()->_loadedStxts->getVal(d.u.i, nullptr);
+	const Stxt *stxt = g_director->getCurrentScore()->_loadedStxts->getVal(castId, nullptr);
 
 	if (!stxt) {
-		warning("installMenu: Unknown cast number #%d", d.u.i);
+		warning("installMenu: Unknown cast number #%d", castId);
 		return;
 	}
 
@@ -1682,16 +1580,14 @@ Common::String Lingo::genMenuHandler(int *commandId, Common::String &command) {
 
 void LB::b_label(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeInt();
-	warning("STUB: b_label(%d)", d.u.i);
+	warning("STUB: b_label(%d)", d.asInt());
 
 	g_lingo->push(Datum(0));
 }
 
 void LB::b_marker(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeInt();
-	int marker = g_lingo->func_marker(d.u.i);
+	int marker = g_lingo->func_marker(d.asInt());
 	g_lingo->push(marker);
 }
 
@@ -1779,7 +1675,7 @@ void LB::b_puppetSprite(int nargs) {
 
 void LB::b_puppetTempo(int nargs) {
 	Datum d = g_lingo->pop();
-	warning("STUB: b_puppetTempo(%d)", d.u.i);
+	warning("STUB: b_puppetTempo(%d)", d.asInt());
 }
 
 void LB::b_puppetTransition(int nargs) {
@@ -1797,12 +1693,8 @@ void LB::b_ramNeeded(int nargs) {
 
 void LB::b_rollOver(int nargs) {
 	Datum d = g_lingo->pop();
-
-	d.makeInt();
-
-	int arg = d.u.i;
-
-	d.u.i = 0; // FALSE
+	Datum res(0);
+	int arg = d.asInt();
 
 	if (!g_director->getCurrentScore()) {
 		warning("b_rollOver: Reference to an empty score");
@@ -1812,16 +1704,16 @@ void LB::b_rollOver(int nargs) {
 	Frame *frame = g_director->getCurrentScore()->_frames[g_director->getCurrentScore()->getCurrentFrame()];
 
 	if (arg >= (int32) frame->_sprites.size()) {
-		g_lingo->push(d);
+		g_lingo->push(res);
 		return;
 	}
 
 	Common::Point pos = g_system->getEventManager()->getMousePos();
 
 	if (frame->checkSpriteIntersection(arg, pos))
-		d.u.i = 1; // TRUE
+		res.u.i = 1; // TRUE
 
-	g_lingo->push(d);
+	g_lingo->push(res);
 }
 
 void LB::b_spriteBox(int nargs) {
@@ -1856,37 +1748,32 @@ void LB::b_zoomBox(int nargs) {
 	int delayTicks = 1;
 	if (nargs > 2) {
 		Datum d = g_lingo->pop();
-		d.makeInt();
-
-		delayTicks = d.u.i;
+		delayTicks = d.asInt();
 	}
 
-	Datum endSprite = g_lingo->pop();
-	Datum startSprite = g_lingo->pop();
-
-	startSprite.makeInt();
-	endSprite.makeInt();
+	int endSprite = g_lingo->pop().asInt();
+	int startSprite = g_lingo->pop().asInt();
 
 	Score *score = g_director->getCurrentScore();
 	uint16 curFrame = score->getCurrentFrame();
 	Frame *frame = score->_frames[curFrame];
 
-	Common::Rect *startRect = frame->getSpriteRect(startSprite.u.i);
+	Common::Rect *startRect = frame->getSpriteRect(startSprite);
 	if (!startRect) {
-		warning("b_zoomBox: unknown start sprite #%d", startSprite.u.i);
+		warning("b_zoomBox: unknown start sprite #%d", startSprite);
 		return;
 	}
 
 	// Looks for endSprite in the current frame, otherwise
 	// Looks for endSprite in the next frame
-	Common::Rect *endRect = frame->getSpriteRect(endSprite.u.i);
+	Common::Rect *endRect = frame->getSpriteRect(endSprite);
 	if (!endRect) {
 		if ((uint)curFrame + 1 < score->_frames.size())
-			score->_frames[curFrame + 1]->getSpriteRect(endSprite.u.i);
+			score->_frames[curFrame + 1]->getSpriteRect(endSprite);
 	}
 
 	if (!endRect) {
-		warning("b_zoomBox: unknown end sprite #%d", endSprite.u.i);
+		warning("b_zoomBox: unknown end sprite #%d", endSprite);
 		return;
 	}
 
@@ -1953,13 +1840,10 @@ void LB::b_moveToFront(int nargs) {
 // Point
 ///////////////////
 void LB::b_point(int nargs) {
-	Datum y = g_lingo->pop();
-	Datum x = g_lingo->pop();
+	Datum y(g_lingo->pop().asFloat());
+	Datum x(g_lingo->pop().asFloat());
 	Datum d;
 
-	x.makeFloat();
-	y.makeFloat();
-
 	d.u.farr = new DatumArray;
 
 	d.u.farr->push_back(x);
@@ -2034,17 +1918,13 @@ void LB::b_beep(int nargs) {
 void LB::b_mci(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
-
-	g_lingo->func_mci(*d.u.s);
+	g_lingo->func_mci(d.asString());
 }
 
 void LB::b_mciwait(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
-
-	g_lingo->func_mciwait(*d.u.s);
+	g_lingo->func_mciwait(d.asString());
 }
 
 void LB::b_sound(int nargs) {
@@ -2197,10 +2077,9 @@ void Lingo::factoryCall(Common::String &name, int nargs) {
 	debugC(3, kDebugLingoExec, "Stack size after call: %d", _stack.size());
 
 	if (!method.u.s->compareToIgnoreCase("mNew")) {
-		Datum d;
+		Datum d(name);
 
 		d.type = OBJECT;
-		d.u.s = new Common::String(name);
 
 		g_lingo->push(d);
 	}
@@ -2214,20 +2093,17 @@ void LB::b_cast(int nargs) {
 
 	warning("STUB: b_cast");
 
-	d.type = REFERENCE;
-	d.u.i = 0;
-
-	g_lingo->push(d);
+	Datum res(0);
+	res.type = REFERENCE;
+	g_lingo->push(res);
 }
 
 void LB::b_field(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.u.i = g_lingo->castIdFetch(d);
-
-	d.type = REFERENCE;
-
-	g_lingo->push(d);
+	Datum res(g_lingo->castIdFetch(d));
+	res.type = REFERENCE;
+	g_lingo->push(res);
 }
 
 void LB::b_script(int nargs) {
@@ -2235,10 +2111,9 @@ void LB::b_script(int nargs) {
 
 	warning("STUB: b_script");
 
+	Datum res(0);
 	d.type = REFERENCE;
-	d.u.i = 0;
-
-	g_lingo->push(d);
+	g_lingo->push(res);
 }
 
 void LB::b_window(int nargs) {
@@ -2246,126 +2121,99 @@ void LB::b_window(int nargs) {
 
 	warning("STUB: b_window");
 
-	d.type = REFERENCE;
-	d.u.i = 0;
-
-	g_lingo->push(d);
+	Datum res(0);
+	res.type = REFERENCE;
+	g_lingo->push(res);
 }
 
 void LB::b_numberofchars(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeString();
 
-	int len = strlen(d.u.s->c_str());
-	delete d.u.s;
+	int len = strlen(d.asString().c_str());
 
-	d.u.i = len;
-	d.type = INT;
-	g_lingo->push(d);
+	Datum res(len);
+	g_lingo->push(res);
 }
 
 void LB::b_numberofitems(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
 	int numberofitems = 1;
-	Common::String contents = *d.u.s;
-	for (uint32 i = 0;  i < d.u.s->size(); i++) {
+	Common::String contents = d.asString();
+	for (uint32 i = 0;  i < contents.size(); i++) {
 		if (contents[i] == ',')
 			numberofitems++;
 	}
-	delete d.u.s;
-
-	d.u.i = numberofitems;
-	d.type = INT;
 
-	g_lingo->push(d);
+	Datum res(numberofitems);
+	g_lingo->push(res);
 }
 
 void LB::b_numberoflines(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
 	int numberoflines = 1;
-	Common::String contents = *d.u.s;
-	for (uint32 i = 0; i < d.u.s->size(); i++) {
+	Common::String contents = d.asString();
+	for (uint32 i = 0; i < contents.size(); i++) {
 		if (contents[i] == '\n')
 			numberoflines++;
 	}
-	delete d.u.s;
 
-	d.u.i = numberoflines;
-	d.type = INT;
-
-	g_lingo->push(d);
+	Datum res(numberoflines);
+	g_lingo->push(res);
 }
 
 void LB::b_numberofwords(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
 	int numberofwords = 0;
-	Common::String contents = *d.u.s;
+	Common::String contents = d.asString();
 	if (contents.empty()) {
-		d.u.i = 0;
-		d.type = INT;
-
-		g_lingo->push(d);
-
+		g_lingo->push(Datum(0));
 		return;
 	}
-	for (uint32 i = 1; i < d.u.s->size(); i++) {
+	for (uint32 i = 1; i < contents.size(); i++) {
 		if (Common::isSpace(contents[i]) && !Common::isSpace(contents[i - 1]))
 			numberofwords++;
 	}
 	// Count the last word
-	if (!Common::isSpace(contents[d.u.s->size() - 1]))
+	if (!Common::isSpace(contents[contents.size() - 1]))
 		numberofwords++;
 
-	d.u.i = numberofwords;
-	d.type = INT;
-
-	g_lingo->push(d);
+	Datum res(numberofwords);
+	g_lingo->push(res);
 }
 
 void LB::b_lastcharof(int nargs) {
 	Datum d = g_lingo->pop();
 
 	warning("STUB: b_lastcharof");
-	d.makeInt();
-	d.u.i = 0;
 
-	g_lingo->push(d);
+	g_lingo->push(Datum(0));
 }
 
 void LB::b_lastitemof(int nargs) {
 	Datum d = g_lingo->pop();
 
 	warning("STUB: b_lastitemof");
-	d.makeInt();
-	d.u.i = 0;
 
-	g_lingo->push(d);
+	g_lingo->push(Datum(0));
 }
 
 void LB::b_lastlineof(int nargs) {
 	Datum d = g_lingo->pop();
 
 	warning("STUB: b_lastlineof");
-	d.makeInt();
-	d.u.i = 0;
 
-	g_lingo->push(d);
+	g_lingo->push(Datum(0));
 }
 
 void LB::b_lastwordof(int nargs) {
 	Datum d = g_lingo->pop();
 
 	warning("STUB: b_lastwordof");
-	d.makeInt();
-	d.u.i = 0;
 
-	g_lingo->push(d);
+	g_lingo->push(Datum(0));
 }
 
 } // End of namespace Director
diff --git a/engines/director/lingo/lingo-bytecode.cpp b/engines/director/lingo/lingo-bytecode.cpp
index b54306830f..868fa4f1d8 100644
--- a/engines/director/lingo/lingo-bytecode.cpp
+++ b/engines/director/lingo/lingo-bytecode.cpp
@@ -283,9 +283,8 @@ void LC::cb_localcall() {
 
 void LC::cb_methodcall() {
 	g_lingo->readInt();
-	Datum obj = g_lingo->pop();
-	obj.makeString();
-	warning("STUB: cb_methodcall(%s)", obj.u.s->c_str());
+	Common::String name = g_lingo->pop().asString();
+	warning("STUB: cb_methodcall(%s)", name.c_str());
 
 	Datum nargs = g_lingo->pop();
 	if ((nargs.type == ARGC) || (nargs.type == ARGCNORET)) {
@@ -513,22 +512,21 @@ void LC::cb_varassign() {
 void LC::cb_v4theentitypush() {
 	int bank = g_lingo->readInt();
 
-	Datum firstArg = g_lingo->pop();
-	firstArg.makeInt();
+	int firstArg = g_lingo->pop().asInt();
 	Datum result;
 	result.u.s = NULL;
 	result.type = VOID;
 
-	int key = (bank << 8) + firstArg.u.i;
+	int key = (bank << 8) + firstArg;
 	if (g_lingo->_lingoV4TheEntity.contains(key)) {
-		debugC(3, kDebugLingoExec, "cb_v4theentitypush: mapping 0x%02x, 0x%02x", bank, firstArg.u.i);
+		debugC(3, kDebugLingoExec, "cb_v4theentitypush: mapping 0x%02x, 0x%02x", bank, firstArg);
 		int entity = g_lingo->_lingoV4TheEntity[key]->entity;
 		int field = g_lingo->_lingoV4TheEntity[key]->field;
 		switch (g_lingo->_lingoV4TheEntity[key]->type) {
 		case kTEANOArgs:
 			{
 				Datum id;
-				id.u.s = NULL;
+				id.u.i = 0;
 				id.type = VOID;
 				debugC(3, kDebugLingoExec, "cb_v4theentitypush: calling getTheEntity(0x%02x, NULL, 0x%02x)", entity, field);
 				result = g_lingo->getTheEntity(entity, id, field);
@@ -559,7 +557,7 @@ void LC::cb_v4theentitypush() {
 			break;
 		}
 	} else {
-		warning("cb_v4theentitypush: unhandled mapping 0x%02x 0x%02x", bank, firstArg.u.i);
+		warning("cb_v4theentitypush: unhandled mapping 0x%02x 0x%02x", bank, firstArg);
 	}
 
 	g_lingo->push(result);
@@ -599,24 +597,23 @@ void LC::cb_v4theentitynamepush() {
 void LC::cb_v4theentityassign() {
 	int bank = g_lingo->readInt();
 
-	Datum firstArg = g_lingo->pop();
-	firstArg.makeInt();
+	int firstArg = g_lingo->pop().asInt();
 	Datum value = g_lingo->pop();
 	Datum result;
 	result.u.s = NULL;
 	result.type = VOID;
 
-	int key = (bank << 8) + firstArg.u.i;
+	int key = (bank << 8) + firstArg;
 	if (!g_lingo->_lingoV4TheEntity.contains(key)) {
-		warning("cb_v4theentityassign: unhandled mapping 0x%02x 0x%02x", bank, firstArg.u.i);
+		warning("cb_v4theentityassign: unhandled mapping 0x%02x 0x%02x", bank, firstArg);
 
 		return;
 	}
 
-	debugC(3, kDebugLingoExec, "cb_v4theentityassign: mapping 0x%02x, 0x%02x", bank, firstArg.u.i);
+	debugC(3, kDebugLingoExec, "cb_v4theentityassign: mapping 0x%02x, 0x%02x", bank, firstArg);
 
 	if (!g_lingo->_lingoV4TheEntity[key]->writable) {
-		warning("cb_v4theentityassign: non-writable mapping 0x%02x 0x%02x", bank, firstArg.u.i);
+		warning("cb_v4theentityassign: non-writable mapping 0x%02x 0x%02x", bank, firstArg);
 
 		return;
 	}
diff --git a/engines/director/lingo/lingo-code.cpp b/engines/director/lingo/lingo-code.cpp
index 124f8cdd0c..e629a5342c 100644
--- a/engines/director/lingo/lingo-code.cpp
+++ b/engines/director/lingo/lingo-code.cpp
@@ -226,22 +226,22 @@ void LC::c_printtop(void) {
 		}
 		break;
 	case STRING:
-		warning("%s", d.u.s->c_str());
+		warning("%s", d.asString(true).c_str());
 		break;
 	case POINT:
-		warning("point(%s, %s", (*d.u.farr)[0].getPrintable().c_str(), (*d.u.farr)[1].getPrintable().c_str());
+		warning("point(%s, %s", (*d.u.farr)[0].asString(true).c_str(), (*d.u.farr)[1].asString(true).c_str());
 		break;
 	case SYMBOL:
 		warning("%s", d.type2str(true));
 		break;
 	case OBJECT:
-		warning("#%s", d.u.s->c_str());
+		warning("#%s", d.asString(true).c_str());
 		break;
 	case ARRAY:
-		warning("%s", d.getPrintable().c_str());
+		warning("%s", d.asString(true).c_str());
 		break;
 	case PARRAY:
-		warning("%s", d.getPrintable().c_str());
+		warning("%s", d.asString(true).c_str());
 		break;
 	default:
 		warning("--unknown--");
@@ -249,10 +249,8 @@ void LC::c_printtop(void) {
 }
 
 void LC::c_intpush() {
-	Datum d;
-	d.u.i = g_lingo->readInt();
-	d.type = INT;
-	g_lingo->push(d);
+	int value = g_lingo->readInt();
+	g_lingo->push(Datum(value));
 }
 
 void LC::c_voidpush() {
@@ -263,15 +261,12 @@ void LC::c_voidpush() {
 }
 
 void LC::c_floatpush() {
-	Datum d;
-	d.u.f = g_lingo->readFloat();
-	d.type = FLOAT;
-	g_lingo->push(d);
+	double value = g_lingo->readFloat();
+	g_lingo->push(Datum(value));
 }
 
 void LC::c_stringpush() {
 	char *s = g_lingo->readString();
-
 	g_lingo->push(Datum(new Common::String(s)));
 }
 
@@ -516,7 +511,7 @@ void LC::c_swap() {
 	g_lingo->push(d1);
 }
 
-Datum LC::mapBinaryOp(Datum (*mapFunc)(Datum, Datum), Datum d1, Datum d2) {
+Datum LC::mapBinaryOp(Datum (*mapFunc)(Datum &, Datum &), Datum &d1, Datum &d2) {
 	// At least one of d1 and d2 must be an array
 	uint arraySize;
 	if (d1.type == ARRAY && d2.type == ARRAY) {
@@ -543,16 +538,22 @@ Datum LC::mapBinaryOp(Datum (*mapFunc)(Datum, Datum), Datum d1, Datum d2) {
 	return res;
 }
 
-Datum LC::addData(Datum d1, Datum d2) {
+Datum LC::addData(Datum &d1, Datum &d2) {
 	if (d1.type == ARRAY || d2.type == ARRAY) {
 		return LC::mapBinaryOp(LC::addData, d1, d2);
 	}
-	if (g_lingo->alignTypes(d1, d2) == FLOAT) {
-		d1.u.f += d2.u.f;
+
+	int alignedType = g_lingo->getAlignedType(d1, d2);
+
+	Datum result;
+	if (alignedType == FLOAT) {
+		result = Datum(d1.asFloat() + d2.asFloat());
+	} else if (alignedType == INT) {
+		result = Datum(d1.asInt() + d2.asInt());
 	} else {
-		d1.u.i += d2.u.i;
+		warning("LC::addData: not supported between types %s and %s", d1.type2str(), d2.type2str());
 	}
-	return d1;
+	return result;
 }
 
 void LC::c_add() {
@@ -561,16 +562,22 @@ void LC::c_add() {
 	g_lingo->push(LC::addData(d1, d2));
 }
 
-Datum LC::subData(Datum d1, Datum d2) {
+Datum LC::subData(Datum &d1, Datum &d2) {
 	if (d1.type == ARRAY || d2.type == ARRAY) {
 		return LC::mapBinaryOp(LC::subData, d1, d2);
 	}
-	if (g_lingo->alignTypes(d1, d2) == FLOAT) {
-		d1.u.f -= d2.u.f;
+
+	int alignedType = g_lingo->getAlignedType(d1, d2);
+
+	Datum result;
+	if (alignedType == FLOAT) {
+		result = Datum(d1.asFloat() - d2.asFloat());
+	} else if (alignedType == INT) {
+		result = Datum(d1.asInt() - d2.asInt());
 	} else {
-		d1.u.i -= d2.u.i;
+		warning("LC::subData: not supported between types %s and %s", d1.type2str(), d2.type2str());
 	}
-	return d1;
+	return result;
 }
 
 void LC::c_sub() {
@@ -579,16 +586,22 @@ void LC::c_sub() {
 	g_lingo->push(LC::subData(d1, d2));
 }
 
-Datum LC::mulData(Datum d1, Datum d2) {
+Datum LC::mulData(Datum &d1, Datum &d2) {
 	if (d1.type == ARRAY || d2.type == ARRAY) {
 		return LC::mapBinaryOp(LC::mulData, d1, d2);
 	}
-	if (g_lingo->alignTypes(d1, d2) == FLOAT) {
-		d1.u.f *= d2.u.f;
+
+	int alignedType = g_lingo->getAlignedType(d1, d2);
+
+	Datum result;
+	if (alignedType == FLOAT) {
+		result = Datum(d1.asFloat() * d2.asFloat());
+	} else if (alignedType == INT) {
+		result = Datum(d1.asInt() * d2.asInt());
 	} else {
-		d1.u.i *= d2.u.i;
+		warning("LC::mulData: not supported between types %s and %s", d1.type2str(), d2.type2str());
 	}
-	return d1;
+	return result;
 }
 
 void LC::c_mul() {
@@ -597,7 +610,7 @@ void LC::c_mul() {
 	g_lingo->push(LC::mulData(d1, d2));
 }
 
-Datum LC::divData(Datum d1, Datum d2) {
+Datum LC::divData(Datum &d1, Datum &d2) {
 	if (d1.type == ARRAY || d2.type == ARRAY) {
 		return LC::mapBinaryOp(LC::divData, d1, d2);
 	}
@@ -606,11 +619,17 @@ Datum LC::divData(Datum d1, Datum d2) {
 			(d2.type == FLOAT && d2.u.f == 0.0))
 		error("division by zero");
 
-	if (g_lingo->alignTypes(d1, d2) == FLOAT) {
-		d1.u.f /= d2.u.f;
+	int alignedType = g_lingo->getAlignedType(d1, d2);
+
+	Datum result;
+	if (alignedType == FLOAT) {
+		result = Datum(d1.asFloat() / d2.asFloat());
+	} else if (alignedType == INT) {
+		result = Datum(d1.asInt() / d2.asInt());
 	} else {
-		d1.u.i /= d2.u.i;
+		warning("LC::divData: not supported between types %s and %s", d1.type2str(), d2.type2str());
 	}
+
 	return d1;
 }
 
@@ -620,18 +639,18 @@ void LC::c_div() {
 	g_lingo->push(divData(d1, d2));
 }
 
-Datum LC::modData(Datum d1, Datum d2) {
+Datum LC::modData(Datum &d1, Datum &d2) {
 	if (d1.type == ARRAY || d2.type == ARRAY) {
 		return LC::mapBinaryOp(LC::modData, d1, d2);
 	}
 
-	d1.makeInt();
-	d2.makeInt();
-	if (d2.u.i == 0)
+	int i1 = d1.asInt();
+	int i2 = d2.asInt();
+	if (i2 == 0)
 		error("division by zero");
 
-	d1.u.i %= d2.u.i;
-	return d1;
+	Datum res(i1 % i2);
+	return res;
 }
 
 void LC::c_mod() {
@@ -640,7 +659,7 @@ void LC::c_mod() {
 	g_lingo->push(LC::modData(d1, d2));
 }
 
-Datum LC::negateData(Datum d) {
+Datum LC::negateData(Datum &d) {
 	if (d.type == ARRAY) {
 		uint arraySize = d.u.farr->size();
 		Datum res;
@@ -652,11 +671,15 @@ Datum LC::negateData(Datum d) {
 		return res;
 	}
 
-	if (d.type == INT) {
-		d.u.i = -d.u.i;
-	} else if (d.type == FLOAT) {
-		d.u.f = -d.u.f;
+	Datum res = d;
+	if (res.type == INT) {
+		res.u.i = -res.u.i;
+	} else if (res.type == FLOAT) {
+		res.u.f = -res.u.f;
+	} else {
+		warning("LC::negateData: not supported for type %s", res.type2str());
 	}
+
 	return d;
 }
 
@@ -669,14 +692,8 @@ void LC::c_ampersand() {
 	Datum d2 = g_lingo->pop();
 	Datum d1 = g_lingo->pop();
 
-	d1.makeString();
-	d2.makeString();
-
-	*d1.u.s += *d2.u.s;
-
-	delete d2.u.s;
-
-	g_lingo->push(d1);
+	Datum res(d1.asString() + d2.asString());
+	g_lingo->push(res);
 }
 
 void LC::c_before() {
@@ -687,70 +704,38 @@ void LC::c_after() {
 	Datum d2 = g_lingo->pop();
 	Datum d1 = g_lingo->pop();
 
-	d1.makeString();
-	d2.makeString();
-
-	*d1.u.s = *d2.u.s + *d1.u.s;
-
-	delete d2.u.s;
-
-	g_lingo->push(d1);
+	Datum res(d2.asString() + d1.asString());
+	g_lingo->push(res);
 }
 
 void LC::c_concat() {
 	Datum d2 = g_lingo->pop();
 	Datum d1 = g_lingo->pop();
 
-	d1.makeString();
-	d2.makeString();
-
-	*d1.u.s += " ";
-	*d1.u.s += *d2.u.s;
-
-	delete d2.u.s;
-
-	g_lingo->push(d1);
+	Datum res(d1.asString() + " " + d2.asString());
+	g_lingo->push(res);
 }
 
 void LC::c_contains() {
 	Datum d2 = g_lingo->pop();
 	Datum d1 = g_lingo->pop();
 
-	d1.makeString();
-	d2.makeString();
+	Common::String s1 = toLowercaseMac(d1.asString());
+	Common::String s2 = toLowercaseMac(d2.asString());
 
-	Common::String *s1 = toLowercaseMac(d1.u.s);
-	Common::String *s2 = toLowercaseMac(d2.u.s);
+	int res = s1.contains(s2) ? 1 : 0;
 
-	int res = s1->contains(*s2) ? 1 : 0;
-
-	delete d1.u.s;
-	delete d2.u.s;
-	delete s1;
-	delete s2;
-
-	d1.type = INT;
-	d1.u.i = res;
-
-	g_lingo->push(d1);
+	g_lingo->push(Datum(res));
 }
 
 void LC::c_starts() {
 	Datum d2 = g_lingo->pop();
 	Datum d1 = g_lingo->pop();
 
-	d1.makeString();
-	d2.makeString();
+	Common::String s1 = toLowercaseMac(d1.asString());
+	Common::String s2 = toLowercaseMac(d2.asString());
 
-	Common::String *s1 = toLowercaseMac(d1.u.s);
-	Common::String *s2 = toLowercaseMac(d2.u.s);
-
-	int res = s1->hasPrefix(*s2) ? 1 : 0;
-
-	delete d1.u.s;
-	delete d2.u.s;
-	delete s1;
-	delete s2;
+	int res = s1.hasPrefix(s2) ? 1 : 0;
 
 	d1.type = INT;
 	d1.u.i = res;
@@ -788,8 +773,7 @@ void LC::c_of() {
 	Datum last_char = g_lingo->pop();
 	Datum first_char = g_lingo->pop();
 
-	target.makeString();
-	Common::String result = *target.u.s;
+	Common::String result = target.asString();
 
 	if (first_line.u.i > 0) {
 		Common::String newline("\r");
@@ -975,34 +959,26 @@ void LC::c_and() {
 	Datum d2 = g_lingo->pop();
 	Datum d1 = g_lingo->pop();
 
-	d1.makeInt();
-	d2.makeInt();
-
-	d1.u.i = (d1.u.i && d2.u.i) ? 1 : 0;
+	Datum res((d1.asInt() && d2.asInt()) ? 1 : 0);
 
-	g_lingo->push(d1);
+	g_lingo->push(res);
 }
 
 void LC::c_or() {
 	Datum d2 = g_lingo->pop();
 	Datum d1 = g_lingo->pop();
 
-	d1.makeInt();
-	d2.makeInt();
-
-	d1.u.i = (d1.u.i || d2.u.i) ? 1 : 0;
+	Datum res((d1.asInt() || d2.asInt()) ? 1 : 0);
 
-	g_lingo->push(d1);
+	g_lingo->push(res);
 }
 
 void LC::c_not() {
 	Datum d = g_lingo->pop();
 
-	d.makeInt();
+	Datum res(~d.asInt() ? 1 : 0);
 
-	d.u.i = ~d.u.i ? 1 : 0;
-
-	g_lingo->push(d);
+	g_lingo->push(res);
 }
 
 Datum LC::compareArrays(Datum (*compareFunc)(Datum, Datum), Datum d1, Datum d2, bool location, bool value) {
@@ -1159,9 +1135,8 @@ void LC::c_jump() {
 
 void LC::c_jumpifz() {
 	uint jump = g_lingo->readInt();
-	Datum test = g_lingo->pop();
-	test.makeInt();
-	if (test.u.i == 0) {
+	int test = g_lingo->pop().asInt();
+	if (test == 0) {
 		g_lingo->_pc = jump;
 	}
 }
@@ -1174,10 +1149,9 @@ void LC::c_repeatwhilecode(void) {
 	uint end =  g_lingo->getInt(savepc + 1);
 
 	g_lingo->execute(savepc + 2);	/* condition */
-	d = g_lingo->pop();
-	d.makeInt();
+	int test = g_lingo->pop().asInt();
 
-	while (d.u.i) {
+	while (test) {
 		g_lingo->execute(body + savepc - 1);	/* body */
 		g_lingo->_nextRepeat = false;
 
@@ -1190,8 +1164,7 @@ void LC::c_repeatwhilecode(void) {
 		}
 
 		g_lingo->execute(savepc + 2);	/* condition */
-		d = g_lingo->pop();
-		d.makeInt();
+		test = g_lingo->pop().asInt();
 	}
 
 	if (!g_lingo->_returning)
@@ -1199,7 +1172,6 @@ void LC::c_repeatwhilecode(void) {
 }
 
 void LC::c_repeatwithcode(void) {
-	Datum d;
 	int savepc = g_lingo->_pc;
 
 	uint init = g_lingo->getInt(savepc);
@@ -1239,9 +1211,7 @@ void LC::c_repeatwithcode(void) {
 	}
 
 	g_lingo->execute(init + savepc - 1);	/* condition */
-	d = g_lingo->pop();
-	d.makeInt();
-	counter->u.i = d.u.i;
+	counter->u.i = g_lingo->pop().asInt();
 	counter->type = INT;
 
 	while (true) {
@@ -1258,10 +1228,9 @@ void LC::c_repeatwithcode(void) {
 
 		counter->u.i += inc;
 		g_lingo->execute(finish + savepc - 1);	/* condition */
-		d = g_lingo->pop();
-		d.makeInt();
+		int base = g_lingo->pop().asInt();
 
-		if (counter->u.i == d.u.i + inc)
+		if (counter->u.i == base + inc)
 			break;
 	}
 
@@ -1293,7 +1262,7 @@ void LC::c_ifcode(void) {
 
 	d = g_lingo->pop();
 
-	if (d.makeInt()) {
+	if (d.asInt()) {
 		debugC(8, kDebugLingoExec, "executing then");
 		g_lingo->execute(then + savepc - 1);
 	} else if (elsep) { /* else part? */
@@ -1345,7 +1314,7 @@ void LC::c_tellcode() {
 	uint start = g_lingo->_pc;
 	uint end = g_lingo->readInt() + start - 1;
 
-	warning("STUB: c_tellcode(%s)", d1.getPrintable().c_str());
+	warning("STUB: c_tellcode(%s)", d1.asString(true).c_str());
 
 	g_lingo->_pc = end;
 }
@@ -1622,10 +1591,7 @@ void LC::c_open() {
 	Datum d2 = g_lingo->pop();
 	Datum d1 = g_lingo->pop();
 
-	d1.makeString();
-	d2.makeString();
-
-	warning("STUB: c_open(%s, %s)", d1.u.s->c_str(), d2.u.s->c_str());
+	warning("STUB: c_open(%s, %s)", d1.asString().c_str(), d2.asString().c_str());
 }
 
 void LC::c_hilite() {
diff --git a/engines/director/lingo/lingo-code.h b/engines/director/lingo/lingo-code.h
index 6a5789e51d..82b2be01db 100644
--- a/engines/director/lingo/lingo-code.h
+++ b/engines/director/lingo/lingo-code.h
@@ -29,18 +29,18 @@ namespace LC {
 	void c_xpop();
 	void c_printtop();
 
-	Datum mapBinaryOp(Datum (*func)(Datum, Datum), Datum d1, Datum d2);
-	Datum addData(Datum d1, Datum d2);
+	Datum mapBinaryOp(Datum (*func)(Datum &, Datum &), Datum &d1, Datum &d2);
+	Datum addData(Datum &d1, Datum &d2);
 	void c_add();
-	Datum subData(Datum d1, Datum d2);
+	Datum subData(Datum &d1, Datum &d2);
 	void c_sub();
-	Datum mulData(Datum d1, Datum d2);
+	Datum mulData(Datum &d1, Datum &d2);
 	void c_mul();
-	Datum divData(Datum d1, Datum d2);
+	Datum divData(Datum &d1, Datum &d2);
 	void c_div();
-	Datum modData(Datum d1, Datum d2);
+	Datum modData(Datum &d1, Datum &d2);
 	void c_mod();
-	Datum negateData(Datum d1);
+	Datum negateData(Datum &d1);
 	void c_negate();
 
 	void c_and();
diff --git a/engines/director/lingo/lingo-codegen.cpp b/engines/director/lingo/lingo-codegen.cpp
index d60fa60594..ab0cfaff6c 100644
--- a/engines/director/lingo/lingo-codegen.cpp
+++ b/engines/director/lingo/lingo-codegen.cpp
@@ -92,7 +92,7 @@ void Lingo::printStack(const char *s, uint pc) {
 
 	for (uint i = 0; i < _stack.size(); i++) {
 		Datum d = _stack[i];
-		stack += Common::String::format("<%s> ", d.getPrintable().c_str());
+		stack += Common::String::format("<%s> ", d.asString(true).c_str());
 	}
 	debugC(5, kDebugLingoExec, "[%3d]: %s", pc, stack.c_str());
 }
@@ -506,11 +506,11 @@ int Lingo::castIdFetch(Datum &var) {
 		else
 			warning("castIdFetch: reference to non-existent cast member: %s", var.u.s->c_str());
 	} else if (var.type == INT || var.type == FLOAT) {
-		var.makeInt();
-		if (!score->_loadedCast->contains(var.u.i))
-			warning("castIdFetch: reference to non-existent cast ID: %d", var.u.i);
+		int castId = var.asInt();
+		if (!score->_loadedCast->contains(castId))
+			warning("castIdFetch: reference to non-existent cast ID: %d", castId);
 		else
-			id = var.u.i;
+			id = castId;
 	} else {
 		error("castIdFetch: was expecting STRING or INT, got %s", var.type2str());
 	}
@@ -587,9 +587,7 @@ void Lingo::varAssign(Datum &var, Datum &value) {
 		if (cast) {
 			switch (cast->_type) {
 			case kCastText:
-				value.makeString();
-				((TextCast *)cast)->setText(value.u.s->c_str());
-				delete value.u.s;
+				((TextCast *)cast)->setText(value.asString().c_str());
 				break;
 			default:
 				warning("varAssign: Unhandled cast type %s", tag2str(cast->_type));
@@ -621,7 +619,7 @@ Datum Lingo::varFetch(Datum &var) {
 		else if (sym->type == FLOAT)
 			result.u.f = sym->u.f;
 		else if (sym->type == STRING)
-			result.u.s = new Common::String(*sym->u.s);
+			result.u.s = sym->u.s;
 		else if (sym->type == POINT)
 			result.u.farr = sym->u.farr;
 		else if (sym->type == SYMBOL)
diff --git a/engines/director/lingo/lingo-funcs.cpp b/engines/director/lingo/lingo-funcs.cpp
index 86f03a1757..8cb2d66675 100644
--- a/engines/director/lingo/lingo-funcs.cpp
+++ b/engines/director/lingo/lingo-funcs.cpp
@@ -72,10 +72,11 @@ struct MCIToken {
 	{ kMCITokenNone, kMCITokenNone,   0, 0 }
 };
 
-void Lingo::func_mci(Common::String &s) {
+void Lingo::func_mci(const Common::String &name) {
 	Common::String params[5];
 	MCITokenType command = kMCITokenNone;
 
+	Common::String s = name;
 	s.trim();
 	s.toLowercase();
 
@@ -170,8 +171,8 @@ void Lingo::func_mci(Common::String &s) {
 	}
 }
 
-void Lingo::func_mciwait(Common::String &s) {
-	warning("STUB: MCI wait file: %s", s.c_str());
+void Lingo::func_mciwait(const Common::String &name) {
+	warning("STUB: MCI wait file: %s", name.c_str());
 }
 
 void Lingo::func_goto(Datum &frame, Datum &movie) {
@@ -181,9 +182,8 @@ void Lingo::func_goto(Datum &frame, Datum &movie) {
 		return;
 
 	if (movie.type != VOID) {
-		movie.makeString();
-
-		Common::String movieFilename = pathMakeRelative(*movie.u.s);
+		Common::String movieFilenameRaw = movie.asString();
+		Common::String movieFilename = pathMakeRelative(movieFilenameRaw);
 		Common::String cleanedFilename;
 
 		bool fileExists = false;
@@ -213,7 +213,7 @@ void Lingo::func_goto(Datum &frame, Datum &movie) {
 			}
 		}
 
-		debug(1, "func_goto: '%s' -> '%s' -> '%s' -> '%s'", movie.u.s->c_str(), convertPath(*movie.u.s).c_str(),
+		debug(1, "func_goto: '%s' -> '%s' -> '%s' -> '%s'", movieFilenameRaw.c_str(), convertPath(movieFilenameRaw).c_str(),
 				movieFilename.c_str(), cleanedFilename.c_str());
 
 		if (!fileExists) {
@@ -235,9 +235,7 @@ void Lingo::func_goto(Datum &frame, Datum &movie) {
 			return;
 		}
 
-		frame.makeInt();
-
-		_vm->_nextMovie.frameI = frame.u.i;
+		_vm->_nextMovie.frameI = frame.asInt();
 
 		return;
 	}
@@ -253,10 +251,8 @@ void Lingo::func_goto(Datum &frame, Datum &movie) {
 		return;
 	}
 
-	frame.makeInt();
-
 	if (_vm->getCurrentScore())
-		_vm->getCurrentScore()->setCurrentFrame(frame.u.i);
+		_vm->getCurrentScore()->setCurrentFrame(frame.asInt());
 }
 
 void Lingo::func_gotoloop() {
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index 71c655ef80..77756e8f1c 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -480,7 +480,7 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
 
 void Lingo::setTheEntity(int entity, Datum &id, int field, Datum &d) {
 	if (debugChannelSet(3, kDebugLingoExec)) {
-		debugC(3, kDebugLingoExec, "Lingo::setTheEntity(\"%s\", %s, \"%s\", %s)", field2str(field), id.getPrintable().c_str(), entity2str(entity), d.getPrintable().c_str());
+		debugC(3, kDebugLingoExec, "Lingo::setTheEntity(\"%s\", %s, \"%s\", %s)", field2str(field), id.asString(true).c_str(), entity2str(entity), d.asString(true).c_str());
 	}
 
 	switch (entity) {
@@ -488,13 +488,13 @@ void Lingo::setTheEntity(int entity, Datum &id, int field, Datum &d) {
 		setTheCast(id, field, d);
 		break;
 	case kTheColorDepth:
-		_vm->_colorDepth = d.makeInt();
+		_vm->_colorDepth = d.asInt();
 
 		// bpp. 1, 2, 4, 8, 32
 		warning("STUB: Lingo::setTheEntity(): Set color depth to %d", _vm->_colorDepth);
 		break;
 	case kTheFloatPrecision:
-		_floatPrecision = d.makeInt();
+		_floatPrecision = d.asInt();
 		_floatPrecision = MAX(0, MIN(_floatPrecision, 19)); // 0 to 19
 		_floatPrecisionFormat = Common::String::format("%%.%df", _floatPrecision);
 		break;
@@ -510,13 +510,13 @@ void Lingo::setTheEntity(int entity, Datum &id, int field, Datum &d) {
 }
 
 void Lingo::setTheMenuItemEntity(int entity, Datum &menuId, int field, Datum &menuItemId, Datum &d) {
-	warning("STUB: setTheMenuItemEntity(%s, %s, %s, %s, %s)", entity2str(entity), menuId.getPrintable().c_str(), field2str(field),
-				menuItemId.getPrintable().c_str(), d.getPrintable().c_str());
+	warning("STUB: setTheMenuItemEntity(%s, %s, %s, %s, %s)", entity2str(entity), menuId.asString(true).c_str(), field2str(field),
+				menuItemId.asString(true).c_str(), d.asString(true).c_str());
 }
 
 Datum Lingo::getTheMenuItemEntity(int entity, Datum &menuId, int field, Datum &menuItemId) {
-	warning("STUB: getTheMenuItemEntity(%s, %s, %s, %s)", entity2str(entity), menuId.getPrintable().c_str(), field2str(field),
-				menuItemId.getPrintable().c_str());
+	warning("STUB: getTheMenuItemEntity(%s, %s, %s, %s)", entity2str(entity), menuId.asString(true).c_str(), field2str(field),
+				menuItemId.asString(true).c_str());
 
 	return Datum();
 }
@@ -562,8 +562,7 @@ Datum Lingo::getTheSprite(Datum &id1, int field) {
 		d.u.i = sprite->_constraint;
 		break;
 	case kTheEditableText:
-		d.makeString();
-		d.u.s = &sprite->_editableText;
+		d = Datum(sprite->_editableText);
 		break;
 	case kTheForeColor:
 		d.u.i = sprite->_foreColor;
@@ -644,8 +643,6 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
 	int id = 0;
 	Score *score = _vm->getCurrentScore();
 
-	d.makeInt(); // Enforce Integer
-
 	if (!score) {
 		warning("Lingo::setTheSprite(): The sprite %d field \"%s\" setting over non-active score", id, field2str(field));
 		return;
@@ -665,94 +662,94 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
 
 	switch (field) {
 	case kTheBackColor:
-		sprite->_backColor = d.u.i;
+		sprite->_backColor = d.asInt();
 		break;
 	case kTheBlend:
-		sprite->_blend = d.u.i;
+		sprite->_blend = d.asInt();
 		break;
 	case kTheBottom:
-		sprite->_bottom = d.u.i;
+		sprite->_bottom = d.asInt();
 		break;
 	case kTheCastNum:
-		if (score->_loadedCast->contains(d.u.i)) {
-			score->loadCastInto(sprite, d.u.i);
-			sprite->_castId = d.u.i;
+		if (score->_loadedCast->contains(d.asInt())) {
+			score->loadCastInto(sprite, d.asInt());
+			sprite->_castId = d.asInt();
 		}
 		break;
 	case kTheConstraint:
-		sprite->_constraint = d.u.i;
+		sprite->_constraint = d.asInt();
 		break;
 	case kTheEditableText:
-		sprite->_editableText = *d.makeString();
+		sprite->_editableText = d.asString();
 		break;
 	case kTheForeColor:
-		sprite->_foreColor = d.u.i;
+		sprite->_foreColor = d.asInt();
 		break;
 	case kTheHeight:
-		sprite->_height = d.u.i;
+		sprite->_height = d.asInt();
 		break;
 	case kTheInk:
-		sprite->_ink = static_cast<InkType>(d.u.i);
+		sprite->_ink = static_cast<InkType>(d.asInt());
 		break;
 	case kTheLeft:
-		sprite->_left = d.u.i;
+		sprite->_left = d.asInt();
 		break;
 	case kTheLineSize:
-		sprite->_thickness = d.u.i;
+		sprite->_thickness = d.asInt();
 		break;
 	case kTheLocH:
-		sprite->_currentPoint.x = d.u.i;
+		sprite->_currentPoint.x = d.asInt();
 		break;
 	case kTheLocV:
-		sprite->_currentPoint.y = d.u.i;
+		sprite->_currentPoint.y = d.asInt();
 		break;
 	case kTheMoveableSprite:
-		sprite->_moveable = d.u.i;
+		sprite->_moveable = d.asInt();
 		if (!d.u.i)
 			sprite->_currentPoint = sprite->_startPoint;
 		break;
 	case kTheMovieRate:
-		sprite->_movieRate = d.u.i;
+		sprite->_movieRate = d.asInt();
 		break;
 	case kTheMovieTime:
-		sprite->_movieTime = d.u.i;
+		sprite->_movieTime = d.asInt();
 		break;
 	case kThePattern:
-		sprite->setPattern(d.u.i);
+		sprite->setPattern(d.asInt());
 		break;
 	case kThePuppet:
-		sprite->_puppet = d.u.i;
+		sprite->_puppet = d.asInt();
 		break;
 	case kTheRight:
-		sprite->_right = d.u.i;
+		sprite->_right = d.asInt();
 		break;
 	case kTheStartTime:
-		sprite->_startTime = d.u.i;
+		sprite->_startTime = d.asInt();
 		break;
 	case kTheStopTime:
-		sprite->_stopTime = d.u.i;
+		sprite->_stopTime = d.asInt();
 		break;
 	case kTheStretch:
-		sprite->_stretch = d.u.i;
+		sprite->_stretch = d.asInt();
 		break;
 	case kTheTop:
-		sprite->_top = d.u.i;
+		sprite->_top = d.asInt();
 		break;
 	case kTheTrails:
-		sprite->_trails = d.u.i;
+		sprite->_trails = d.asInt();
 		break;
 	case kTheType:
-		sprite->_spriteType = static_cast<SpriteType>(d.u.i);
+		sprite->_spriteType = static_cast<SpriteType>(d.asInt());
 		break;
 	case kTheVisibility:
 	case kTheVisible:
-		sprite->_visible = (d.u.i == 0 ? false : true);
+		sprite->_visible = (d.asInt() == 0 ? false : true);
 		break;
 	case kTheVolume:
-		sprite->_volume = d.u.i;
+		sprite->_volume = d.asInt();
 		break;
 	case kTheWidth:
-		sprite->_width = d.u.i;
+		sprite->_width = d.asInt();
 		break;
 	default:
 		warning("Lingo::setTheSprite(): Unprocessed setting field \"%s\" of sprite", field2str(field));
@@ -809,8 +806,7 @@ Datum Lingo::getTheCast(Datum &id1, int field) {
 		d.u.i = castType;
 		break;
 	case kTheFileName:
-		d.makeString();
-		d.u.s = &castInfo->fileName;
+		d = Datum(castInfo->fileName);
 		break;
 	case kTheForeColor:
 		{
@@ -831,24 +827,24 @@ Datum Lingo::getTheCast(Datum &id1, int field) {
 		d.u.i = 1; //Not loaded handled above
 		break;
 	case kTheName:
-		d.type = STRING;
-		d.u.s = new Common::String(castInfo->name.c_str());
+		d = Datum(castInfo->name);
 		break;
 	case kTheScriptText:
-		d.type = STRING;
-		d.u.s = new Common::String(castInfo->script.c_str());
+		d = Datum(castInfo->script);
 		break;
 	case kTheText:
-		d.makeString();
-		*d.u.s = "";
-		if (castType == kCastText) {
-			if (score->_loadedCast->contains(id) && score->_loadedCast->getVal(id)->_type == kCastText) {
-				*d.u.s = ((TextCast *)score->_loadedCast->getVal(id))->getText();
+		{
+			Common::String text;
+			if (castType == kCastText) {
+				if (score->_loadedCast->contains(id) && score->_loadedCast->getVal(id)->_type == kCastText) {
+					text = ((TextCast *)score->_loadedCast->getVal(id))->getText();
+				} else {
+					warning("Lingo::getTheCast(): Unknown STXT cast id %d", id);
+				}
 			} else {
-				warning("Lingo::getTheCast(): Unknown STXT cast id %d", id);
+				warning("Lingo::getTheCast(): Unprocessed getting text of cast %d type %d", id, castType);
 			}
-		} else {
-			warning("Lingo::getTheCast(): Unprocessed getting text of cast %d type %d", id, castType);
+			d = Datum(text);
 		}
 		break;
 	case kTheWidth:
@@ -893,8 +889,7 @@ void Lingo::setTheCast(Datum &id1, int field, Datum &d) {
 			}
 			ShapeCast *shape = (ShapeCast *)score->_loadedCast->getVal(id);
 
-			d.makeInt();
-			shape->_bgCol = d.u.i;
+			shape->_bgCol = d.asInt();
 			shape->_modified = 1;
 		}
 		break;
@@ -909,8 +904,7 @@ void Lingo::setTheCast(Datum &id1, int field, Datum &d) {
 			warning("Lingo::setTheCast(): The cast %d not found. type: %d", id, castType);
 			return;
 		}
-		d.makeString();
-		castInfo->fileName = *d.u.s;
+		castInfo->fileName = d.asString();
 		break;
 	case kTheForeColor:
 		{
@@ -924,8 +918,7 @@ void Lingo::setTheCast(Datum &id1, int field, Datum &d) {
 		}
 		break;
 	case kTheHeight:
-		d.makeInt();
-		score->getCastMemberInitialRect(id).setHeight(d.u.i);
+		score->getCastMemberInitialRect(id).setHeight(d.asInt());
 		score->setCastMemberModified(id);
 		break;
 	case kTheName:
@@ -933,24 +926,21 @@ void Lingo::setTheCast(Datum &id1, int field, Datum &d) {
 			warning("Lingo::setTheCast(): The cast %d not found. type: %d", id, castType);
 			return;
 		}
-		d.makeString();
-		castInfo->name = *d.u.s;
+		castInfo->name = d.asString();
 		break;
 	case kTheScriptText:
 		if (!castInfo) {
 			warning("Lingo::setTheCast(): The cast %d not found. type: %d", id, castType);
 			return;
 		}
-		d.makeString();
 		addCode(d.u.s->c_str(), kSpriteScript, id);
 
-		castInfo->script = *d.u.s;
+		castInfo->script = d.asString();
 		break;
 	case kTheText:
 		if (castType == kCastText) {
 			if (score->_loadedCast->contains(id) && score->_loadedCast->getVal(id)->_type == kCastText) {
-				d.makeString();
-				((TextCast *)score->_loadedCast->getVal(id))->setText(d.u.s->c_str());
+				((TextCast *)score->_loadedCast->getVal(id))->setText(d.asString().c_str());
 			} else {
 				warning("Lingo::setTheCast(): Unknown STXT cast id %d", id);
 				return;
@@ -960,8 +950,7 @@ void Lingo::setTheCast(Datum &id1, int field, Datum &d) {
 		}
 		break;
 	case kTheWidth:
-		d.makeInt();
-		score->getCastMemberInitialRect(id).setWidth(d.u.i);
+		score->getCastMemberInitialRect(id).setWidth(d.asInt());
 		score->setCastMemberModified(id);
 		break;
 	default:
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index 1372bd40c0..e72f2ec8de 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -40,6 +40,8 @@ Lingo *g_lingo;
 Symbol::Symbol() {
 	type = VOID;
 	u.s = nullptr;
+	refCount = new int;
+	*refCount = 1;
 	nargs = 0;
 	maxArgs = 0;
 	parens = true;
@@ -50,6 +52,56 @@ Symbol::Symbol() {
 	archiveIndex = 0;
 }
 
+Symbol::Symbol(const Symbol &s) {
+	type = s.type;
+	u.s = s.u.s;
+	refCount = s.refCount;
+	*refCount += 1;
+	nargs = s.nargs;
+	maxArgs = s.maxArgs;
+	parens = s.parens;
+	global = s.global;
+	argNames = s.argNames;
+	varNames = s.varNames;
+	ctx = s.ctx;
+	archiveIndex = s.archiveIndex;
+}
+
+Symbol::~Symbol() {
+	*refCount -= 1;
+	if (*refCount <= 0) {
+		switch (type) {
+			case HANDLER:
+				delete u.defn;
+				break;
+			case STRING:
+				delete u.s;
+				break;
+			case ARRAY:
+				// fallthrough
+			case POINT:
+				// fallthrough
+			case RECT:
+				delete u.farr;
+				break;
+			case PARRAY:
+				delete u.parr;
+				break;
+			case VAR:
+				// fallthrough
+			case REFERENCE:
+				// fallthrough
+			case INT:
+				// fallthrough
+			case FLOAT:
+				// fallthrough
+			default:
+				break;
+		}
+		delete refCount;
+	}
+}
+
 PCell::PCell() {
 	p = nullptr;
 	v = nullptr;
@@ -347,113 +399,101 @@ void Lingo::restartLingo() {
 	// tuneousScript is not reset
 }
 
-int Lingo::alignTypes(Datum &d1, Datum &d2) {
+int Lingo::getAlignedType(Datum &d1, Datum &d2) {
 	int opType = VOID;
 
-	if (d1.type == REFERENCE || d1.type == SYMBOL)
-		d1.makeString();
+	int d1Type = d1.type;
+	int d2Type = d2.type;
 
-	if (d2.type == REFERENCE || d2.type == SYMBOL)
-		d2.makeString();
-
-	if (d1.type == STRING) {
+	if (d1Type == STRING || d1Type == REFERENCE) {
+		Common::String src = d1.asString();
 		char *endPtr = 0;
-		double d = strtod(d1.u.s->c_str(), &endPtr);
+		strtod(src.c_str(), &endPtr);
 		if (*endPtr == 0) {
-			d1.type = FLOAT;
-			d1.u.f = d;
+			d1Type = FLOAT;
 		} else {
-			warning("Unable to parse '%s' as a number", d1.u.s->c_str());
+			warning("getAlignedType(): Unable to parse '%s' as a number", src.c_str());
 		}
 	}
-	if (d2.type == STRING) {
+	if (d2Type == STRING || d1Type == REFERENCE) {
+		Common::String src = d1.asString();
 		char *endPtr = 0;
-		double d = strtod(d2.u.s->c_str(), &endPtr);
+		strtod(src.c_str(), &endPtr);
 		if (*endPtr == 0) {
-			d2.type = FLOAT;
-			d2.u.f = d;
+			d2Type = FLOAT;
 		} else {
-			warning("Unable to parse '%s' as a number", d2.u.s->c_str());
+			warning("getAlignedType(): Unable to parse '%s' as a number", src.c_str());
 		}
 	}
 
-
-	if (d1.type == FLOAT || d2.type == FLOAT) {
+	if (d1Type == FLOAT || d2Type == FLOAT) {
 		opType = FLOAT;
-		d1.makeFloat();
-		d2.makeFloat();
-	} else if (d1.type == INT && d2.type == INT) {
+	} else if (d1Type == INT && d2Type == INT) {
 		opType = INT;
 	} else {
-		warning("No numeric type alignment available");
+		warning("getAlignedType(): No numeric type alignment available");
 	}
 
 	return opType;
 }
 
-int Datum::makeInt() {
+int Datum::asInt() {
+	int res = 0;
+
 	switch (type) {
 	case REFERENCE:
-		makeString();
 		// fallthrough
 	case STRING:
 		{
+			Common::String src = asString();
 			char *endPtr = 0;
-			int result = strtol(u.s->c_str(), &endPtr, 10);
+			int result = strtol(src.c_str(), &endPtr, 10);
 			if (*endPtr == 0) {
-				u.i = result;
+				res = result;
 			} else {
-				warning("Invalid int '%s'", u.s->c_str());
-				u.i = 0;
+				warning("Invalid int '%s'", src.c_str());
 			}
 		}
 		break;
 	case VOID:
-		u.i = 0;
+		// no-op
 		break;
 	case INT:
-		// no-op
+		res = u.i;
 		break;
 	case FLOAT:
-		{
-			int tmp = (int)u.f;
-			u.i = tmp;
-			break;
-		}
+		res = (int)u.f;
+		break;
 	default:
-		warning("Incorrect operation makeInt() for type: %s", type2str());
+		warning("Incorrect operation asInt() for type: %s", type2str());
 	}
 
-	type = INT;
-
-	return u.i;
+	return res;
 }
 
-double Datum::makeFloat() {
+double Datum::asFloat() {
+	double res = 0.0;
+
 	switch (type) {
 	case REFERENCE:
-		makeString();
 		// fallthrough
 	case STRING:
 		{
+			Common::String src = asString();
 			char *endPtr = 0;
-			double result = strtod(u.s->c_str(), &endPtr);
+			double result = strtod(src.c_str(), &endPtr);
 			if (*endPtr == 0) {
-				u.f = result;
+				res = result;
 			} else {
-				warning("Invalid float '%s'", u.s->c_str());
-				u.f = 0.0;
+				warning("Invalid float '%s'", src.c_str());
 			}
 		}
 		break;
 	case VOID:
-		u.f = 0.0;
+		// no-op
 		break;
 	case INT:
-		{
-			double tmp = (double)u.i;
-			u.f = tmp;
-		}
+		res = (double)u.i;
 		break;
 	case FLOAT:
 		// no-op
@@ -462,54 +502,52 @@ double Datum::makeFloat() {
 		warning("Incorrect operation makeFloat() for type: %s", type2str());
 	}
 
-	type = FLOAT;
-
-	return u.f;
+	return res;
 }
 
-Common::String *Datum::makeString(bool printonly) {
-	Common::String *s = new Common::String();
+Common::String Datum::asString(bool printonly) {
+	Common::String s;
 	switch (type) {
 	case INT:
-		*s = Common::String::format("%d", u.i);
+		s = Common::String::format("%d", u.i);
 		break;
 	case ARGC:
-		*s = Common::String::format("argc: %d", u.i);
+		s = Common::String::format("argc: %d", u.i);
 		break;
 	case ARGCNORET:
-		*s = Common::String::format("argcnoret: %d", u.i);
+		s = Common::String::format("argcnoret: %d", u.i);
 		break;
 	case FLOAT:
-		*s = Common::String::format(g_lingo->_floatPrecisionFormat.c_str(), u.f);
+		s = Common::String::format(g_lingo->_floatPrecisionFormat.c_str(), u.f);
 		if (printonly)
-			*s += "f";		// 0.0f
+			s += "f";		// 0.0f
 		break;
 	case STRING:
 		if (!printonly) {
-			*s = *u.s;
+			s = *u.s;
 		} else {
-			*s = Common::String::format("\"%s\"", u.s->c_str());
+			s = Common::String::format("\"%s\"", u.s->c_str());
 		}
 		break;
 	case SYMBOL:
 		if (!printonly) {
-			*s = Common::String::format("#%s", u.s->c_str());
+			s = Common::String::format("#%s", u.s->c_str());
 		} else {
-			*s = Common::String::format("symbol: #%s", u.s->c_str());
+			s = Common::String::format("symbol: #%s", u.s->c_str());
 		}
 		break;
 	case OBJECT:
 		if (!printonly) {
-			*s = Common::String::format("#%s", u.s->c_str());
+			s = Common::String::format("#%s", u.s->c_str());
 		} else {
-			*s = Common::String::format("object: #%s", u.s->c_str());
+			s = Common::String::format("object: #%s", u.s->c_str());
 		}
 		break;
 	case VOID:
-		*s = "#void";
+		s = "#void";
 		break;
 	case VAR:
-		*s = Common::String::format("var: #%s", u.sym->name.c_str());
+		s = Common::String::format("var: #%s", u.sym->name.c_str());
 		break;
 	case REFERENCE:
 		{
@@ -517,15 +555,15 @@ Common::String *Datum::makeString(bool printonly) {
 			Score *score = g_director->getCurrentScore();
 
 			if (!score) {
-				warning("makeString(): No score");
-				*s = "";
+				warning("asString(): No score");
+				s = "";
 				break;
 			}
 
 			if (!score->_loadedCast->contains(idx)) {
 				if (!score->_loadedCast->contains(idx - score->_castIDoffset)) {
-					warning("makeString(): Unknown REFERENCE %d", idx);
-					*s = "";
+					warning("asString(): Unknown REFERENCE %d", idx);
+					s = "";
 					break;
 				} else {
 					idx -= 1024;
@@ -533,49 +571,43 @@ Common::String *Datum::makeString(bool printonly) {
 			}
 
 			if (!printonly) {
-				*s = ((TextCast *)score->_loadedCast->getVal(idx))->getText();
+				s = ((TextCast *)score->_loadedCast->getVal(idx))->getText();
 			} else {
-				*s = Common::String::format("reference: \"%s\"", ((TextCast *)score->_loadedCast->getVal(idx))->getText().c_str());
+				s = Common::String::format("reference: \"%s\"", ((TextCast *)score->_loadedCast->getVal(idx))->getText().c_str());
 			}
 		}
 		break;
 	case ARRAY:
-		*s = "[";
+		s = "[";
 
 		for (uint i = 0; i < u.farr->size(); i++) {
 			if (i > 0)
-				*s += ", ";
+				s += ", ";
 			Datum d = u.farr->operator[](i);
-			*s += *d.makeString(printonly);
+			s += d.asString(printonly);
 		}
 
-		*s += "]";
+		s += "]";
 		break;
 	case PARRAY:
-		*s = "[";
+		s = "[";
 		if (u.parr->size() == 0)
-			*s += ":";
+			s += ":";
 		for (uint i = 0; i < u.parr->size(); i++) {
 			if (i > 0)
-				*s += ", ";
+				s += ", ";
 			Datum p = *u.parr->operator[](i).p;
 			Datum v = *u.parr->operator[](i).v;
-			*s += Common::String::format("%s:%s", p.makeString(printonly)->c_str(), v.makeString(printonly)->c_str());
+			s += Common::String::format("%s:%s", p.asString(printonly).c_str(), v.asString(printonly).c_str());
 		}
 
-		*s += "]";
+		s += "]";
 		break;
 	default:
-		warning("Incorrect operation makeString() for type: %s", type2str());
+		warning("Incorrect operation asString() for type: %s", type2str());
 	}
 
-	if (printonly)
-		return s;
-
-	u.s = s;
-	type = STRING;
-
-	return u.s;
+	return s;
 }
 
 const char *Datum::type2str(bool isk) {
@@ -608,31 +640,40 @@ const char *Datum::type2str(bool isk) {
 	}
 }
 
-int Datum::compareTo(Datum d, bool ignoreCase) {
+int Datum::compareTo(Datum &d, bool ignoreCase) {
 	if (type == STRING && d.type == STRING) {
 		if (ignoreCase) {
-			return toLowercaseMac(u.s)->compareTo(*toLowercaseMac(d.u.s));
+			return toLowercaseMac(*u.s).compareTo(toLowercaseMac(*d.u.s));
 		} else {
 			return u.s->compareTo(*d.u.s);
 		}
 	} else if (type == SYMBOL && d.type == SYMBOL) {
 		// TODO: Implement union comparisons
 		return ignoreCase ? u.sym->name.compareToIgnoreCase(d.u.sym->name) : u.sym->name.compareTo(d.u.sym->name);
-	} else if (g_lingo->alignTypes(*this, d) == FLOAT) {
-		if (u.f < d.u.f) {
-			return -1;
-		} else if (u.f == d.u.f) {
-			return 0;
-		} else {
-			return 1;
-		}
 	} else {
-		if (u.i < d.u.i) {
-			return -1;
-		} else if (u.i == d.u.i) {
-			return 0;
+		int alignType = g_lingo->getAlignedType(*this, d);
+		if (alignType == FLOAT) {
+			double f1 = asFloat();
+			double f2 = d.asFloat();
+			if (f1 < f2) {
+				return -1;
+			} else if (f1 == f2) {
+				return 0;
+			} else {
+				return 1;
+			}
+		} else if (alignType == INT) {
+			double i1 = asInt();
+			double i2 = asInt();
+			if (i1 < i2) {
+				return -1;
+			} else if (i1 == i2) {
+				return 0;
+			} else {
+				return 1;
+			}
 		} else {
-			return 1;
+			error("Invalid comparison between types %s and %s", type2str(), d.type2str());
 		}
 	}
 }
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index 733bacd373..dec242fe3a 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -73,13 +73,16 @@ struct Symbol {	/* symbol table entry */
 	union {
 		int		i;			/* VAR */
 		double	f;			/* FLOAT */
-		ScriptData	*defn;	/* FUNCTION, PROCEDURE */
+		ScriptData	*defn;	/* HANDLER */
 		void (*func)();		/* OPCODE */
 		void (*bltin)(int);	/* BUILTIN */
 		Common::String	*s;	/* STRING */
 		DatumArray *farr;	/* ARRAY, POINT, RECT */
 		PropertyArray *parr;
 	} u;
+
+	int *refCount;
+
 	int nargs;		/* number of arguments */
 	int maxArgs;	/* maximal number of arguments, for builtins */
 	bool parens;	/* whether parens required or not, for builitins */
@@ -91,6 +94,8 @@ struct Symbol {	/* symbol table entry */
 	int archiveIndex; 		/* optional archive to execute with */
 
 	Symbol();
+	Symbol(const Symbol &s);
+	~Symbol();
 };
 
 struct PCell {
@@ -113,19 +118,83 @@ struct Datum {	/* interpreter stack type */
 		PropertyArray *parr; /* PARRAY */
 	} u;
 
-	Datum() { u.sym = NULL; type = VOID; }
-	Datum(int val) { u.i = val; type = INT; }
-	Datum(double val) { u.f = val; type = FLOAT; }
-	Datum(Common::String *val) { u.s = val; type = STRING; }
+	int *refCount;
+
+	Datum() {
+		u.sym = NULL;
+		type = VOID;
+		refCount = new int;
+		*refCount = 1;
+	}
+	Datum(const Datum &d) {
+		type = d.type;
+		u = d.u;
+		refCount = d.refCount;
+		*refCount += 1;
+	}
+	Datum(int val) {
+		u.i = val;
+		type = INT;
+		refCount = new int;
+		*refCount = 1;
+	}
+	Datum(double val) {
+		u.f = val;
+		type = FLOAT;
+		refCount = new int;
+		*refCount = 1;
+	}
+	Datum(const Common::String &val) {
+		u.s = new Common::String(val);
+		type = STRING;
+		refCount = new int;
+		*refCount = 1;
+	}
+	Datum(Common::String *val) {
+		u.s = val;
+		type = STRING;
+		refCount = new int;
+		*refCount = 1;
+	}
+	~Datum() {
+		*refCount -= 1;
+		if (*refCount <= 0) {
+			switch (type) {
+				case STRING:
+					delete u.s;
+					break;
+				case ARRAY:
+					// fallthrough
+				case POINT:
+					// fallthrough
+				case RECT:
+					delete u.farr;
+					break;
+				case PARRAY:
+					delete u.parr;
+					break;
+				case VAR:
+					// fallthrough
+				case REFERENCE:
+					// fallthrough
+				case INT:
+					// fallthrough
+				case FLOAT:
+					// fallthrough
+				default:
+					break;
+			}
+			delete refCount;
+		}
+	}
 
-	double makeFloat();
-	int makeInt();
-	Common::String *makeString(bool printonly = false);
-	Common::String getPrintable() { return *makeString(true); }
+	double asFloat();
+	int asInt();
+	Common::String asString(bool printonly = false);
 
 	const char *type2str(bool isk = false);
 
-	int compareTo(Datum d, bool ignoreCase = false);
+	int compareTo(Datum &d, bool ignoreCase = false);
 };
 
 struct Builtin {
@@ -225,7 +294,7 @@ public:
 	void varAssign(Datum &var, Datum &value);
 	Datum varFetch(Datum &var);
 
-	int alignTypes(Datum &d1, Datum &d2);
+	int getAlignedType(Datum &d1, Datum &d2);
 
 	void printAllVars();
 
@@ -271,8 +340,8 @@ public:
 
 	void factoryCall(Common::String &name, int nargs);
 
-	void func_mci(Common::String &s);
-	void func_mciwait(Common::String &s);
+	void func_mci(const Common::String &name);
+	void func_mciwait(const Common::String &name);
 	void func_beep(int repeats);
 	void func_goto(Datum &frame, Datum &movie);
 	void func_gotoloop();
diff --git a/engines/director/util.cpp b/engines/director/util.cpp
index 599f64abd3..04755940ce 100644
--- a/engines/director/util.cpp
+++ b/engines/director/util.cpp
@@ -84,22 +84,22 @@ static char lowerCaseConvert[] =
 ".. aao.." // c8
 "--.....y";// d0-d8
 
-Common::String *toLowercaseMac(Common::String *s) {
-	Common::String *res = new Common::String;
-	const unsigned char *p = (const unsigned char *)s->c_str();
+Common::String toLowercaseMac(const Common::String &s) {
+	Common::String res;
+	const unsigned char *p = (const unsigned char *)s.c_str();
 
 	while (*p) {
 		if (*p >= 0x80 && *p <= 0xd8) {
 			if (lowerCaseConvert[*p - 0x80] != '.')
-				*res += lowerCaseConvert[*p - 0x80];
+				res += lowerCaseConvert[*p - 0x80];
 			else
-				*res += *p;
+				res += *p;
 		} else if (*p < 0x80) {
-			*res += tolower(*p);
+			res += tolower(*p);
 		} else {
 			warning("Unacceptable symbol in toLowercaseMac: %c", *p);
 
-			*res += *p;
+			res += *p;
 		}
 		p++;
 	}
diff --git a/engines/director/util.h b/engines/director/util.h
index f9401f3f6b..23447da4bf 100644
--- a/engines/director/util.h
+++ b/engines/director/util.h
@@ -32,7 +32,7 @@ namespace Director {
 int castNumToNum(const char *str);
 char *numToCastNum(int num);
 
-Common::String *toLowercaseMac(Common::String *s);
+Common::String toLowercaseMac(const Common::String &s);
 
 Common::String convertPath(Common::String &path);
 


Commit: ceb81566df7e31ad1946e8f29be546b5e7766a6d
    https://github.com/scummvm/scummvm/commit/ceb81566df7e31ad1946e8f29be546b5e7766a6d
Author: Scott Percival (code at moral.net.au)
Date: 2020-05-12T01:13:19+08:00

Commit Message:
DIRECTOR: LINGO: Add copy assignment operator for Datum/Symbol

Changed paths:
    engines/director/lingo/lingo-builtins.cpp
    engines/director/lingo/lingo-codegen.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 3ad6e07416..b024345ed5 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -714,7 +714,7 @@ void LB::b_getaProp(int nargs) {
 		Datum d;
 		int index = LC::compareArrays(LC::eqData, list, prop, true).u.i;
 		if (index > 0) {
-			d = *list.u.parr->operator[](index-1).v;
+			d = *list.u.parr->operator[](index - 1).v;
 		}
 		g_lingo->push(d);
 		break;
@@ -777,7 +777,7 @@ void LB::b_getOne(int nargs) {
 		Datum d;
 		int index = LC::compareArrays(LC::eqData, list, val, true, true).u.i;
 		if (index > 0) {
-			d = *list.u.parr->operator[](index-1).p;
+			d = *list.u.parr->operator[](index - 1).p;
 		}
 		g_lingo->push(d);
 		break;
@@ -791,6 +791,7 @@ void LB::b_getPos(int nargs) {
 	ARGNUMCHECK(2);
 	Datum val = g_lingo->pop();
 	Datum list = g_lingo->pop();
+	TYPECHECK2(val, INT, FLOAT);
 	TYPECHECK2(list, ARRAY, PARRAY);
 
 	switch (list.type) {
@@ -832,7 +833,7 @@ void LB::b_getProp(int nargs) {
 	case PARRAY: {
 		int index = LC::compareArrays(LC::eqData, list, prop, true).u.i;
 		if (index > 0) {
-			g_lingo->push(*list.u.parr->operator[](index-1).v);
+			g_lingo->push(*list.u.parr->operator[](index - 1).v);
 		} else {
 			error("b_getProp: Property %s not found", prop.asString().c_str());
 		}
@@ -845,11 +846,14 @@ void LB::b_getProp(int nargs) {
 
 void LB::b_getPropAt(int nargs) {
 	ARGNUMCHECK(2);
-	int index = g_lingo->pop().asInt();
+
+	Datum indexD = g_lingo->pop();
 	Datum list = g_lingo->pop();
+	TYPECHECK2(indexD, INT, FLOAT);
 	TYPECHECK(list, PARRAY);
+	int index = indexD.asInt();
 
-	g_lingo->push(*list.u.parr->operator[](index-1).p);
+	g_lingo->push(*list.u.parr->operator[](index - 1).p);
 }
 
 void LB::b_list(int nargs) {
@@ -955,7 +959,7 @@ void LB::b_setaProp(int nargs) {
 	case PARRAY: {
 		int index = LC::compareArrays(LC::eqData, list, prop, true).u.i;
 		if (index > 0) {
-			*list.u.parr->operator[](index-1).v = value;
+			*list.u.parr->operator[](index - 1).v = value;
 		} else {
 			PCell cell = PCell(prop, value);
 			list.u.parr->push_back(cell);
@@ -970,15 +974,17 @@ void LB::b_setaProp(int nargs) {
 void LB::b_setAt(int nargs) {
 	ARGNUMCHECK(3);
 	Datum value = g_lingo->pop();
-	int index = g_lingo->pop().asInt();
+	Datum indexD = g_lingo->pop();
 	Datum list = g_lingo->pop();
 
+	TYPECHECK2(indexD, INT, FLOAT);
 	TYPECHECK2(list, ARRAY, PARRAY);
+	int index = indexD.asInt();
 
 	switch (list.type) {
 	case ARRAY:
 		if ((uint)index < list.u.farr->size()) {
-			list.u.farr->operator[](index-1) = value;
+			list.u.farr->operator[](index - 1) = value;
 		} else {
 			// TODO: Extend the list if we request an index beyond it
 			ARRBOUNDSCHECK(index, list);
@@ -986,7 +992,7 @@ void LB::b_setAt(int nargs) {
 		break;
 	case PARRAY:
 		ARRBOUNDSCHECK(index, list);
-		*list.u.parr->operator[](index-1).v = value;
+		*list.u.parr->operator[](index - 1).v = value;
 		break;
 	default:
 		break;
@@ -1004,7 +1010,7 @@ void LB::b_setProp(int nargs) {
 
 	int index = LC::compareArrays(LC::eqData, list, prop, true).u.i;
 	if (index > 0) {
-		*list.u.parr->operator[](index-1).v = value;
+		*list.u.parr->operator[](index - 1).v = value;
 	} else {
 		warning("b_setProp: Property not found");
 	}
diff --git a/engines/director/lingo/lingo-codegen.cpp b/engines/director/lingo/lingo-codegen.cpp
index ab0cfaff6c..417318805b 100644
--- a/engines/director/lingo/lingo-codegen.cpp
+++ b/engines/director/lingo/lingo-codegen.cpp
@@ -269,10 +269,10 @@ Symbol *Lingo::define(Common::String &name, int nargs, ScriptData *code) {
 		warning("Redefining handler '%s'", name.c_str());
 
 		// Do not attempt to remove code from built-ins
-		if (sym->type == HANDLER)
-			delete sym->u.defn;
-		else
-			sym->type = HANDLER;
+		sym->reset();
+		sym->refCount = new int;
+		*sym->refCount = 1;
+		sym->type = HANDLER;
 	}
 
 	sym->u.defn = code;
@@ -538,27 +538,20 @@ void Lingo::varAssign(Datum &var, Datum &value) {
 			return;
 		}
 
-		if ((sym->type == STRING || sym->type == VOID) && sym->u.s) // Free memory if needed
-			delete var.u.sym->u.s;
-
-		if (sym->type == POINT || sym->type == RECT || sym->type == ARRAY)
-			delete var.u.sym->u.farr;
-		else if (sym->type == PARRAY)
-			delete var.u.sym->u.parr;
-
+		sym->reset();
+		sym->refCount = value.refCount;
+		*sym->refCount += 1;
 		sym->type = value.type;
 		if (value.type == INT) {
 			sym->u.i = value.u.i;
 		} else if (value.type == FLOAT) {
 			sym->u.f = value.u.f;
 		} else if (value.type == STRING) {
-			sym->u.s = new Common::String(*value.u.s);
-			delete value.u.s;
+			sym->u.s = value.u.s;
 		} else if (value.type == POINT || value.type == ARRAY) {
-			sym->u.farr = new DatumArray(*value.u.farr);
-			delete value.u.farr;
+			sym->u.farr = value.u.farr;
 		} else if (value.type == PARRAY) {
-			sym->u.parr = new PropertyArray(*value.u.parr);
+			sym->u.parr = value.u.parr;
 		} else if (value.type == SYMBOL) {
 			sym->u.s = value.u.s;
 		} else if (value.type == OBJECT) {
@@ -575,15 +568,16 @@ void Lingo::varAssign(Datum &var, Datum &value) {
 			warning("varAssign: Assigning to a reference to an empty score");
 			return;
 		}
-		if (!score->_loadedCast->contains(var.u.i)) {
-			if (!score->_loadedCast->contains(var.u.i - score->_castIDoffset)) {
-				warning("varAssign: Unknown REFERENCE %d", var.u.i);
+		int referenceId = var.u.i;
+		if (!score->_loadedCast->contains(referenceId)) {
+			if (!score->_loadedCast->contains(referenceId - score->_castIDoffset)) {
+				warning("varAssign: Unknown REFERENCE %d", referenceId);
 				return;
 			} else {
-				var.u.i -= score->_castIDoffset;
+				referenceId -= score->_castIDoffset;
 			}
 		}
-		Cast *cast = score->_loadedCast->getVal(var.u.i);
+		Cast *cast = score->_loadedCast->getVal(referenceId);
 		if (cast) {
 			switch (cast->_type) {
 			case kCastText:
@@ -613,6 +607,9 @@ Datum Lingo::varFetch(Datum &var) {
 		}
 
 		result.type = sym->type;
+		delete result.refCount;
+		result.refCount = sym->refCount;
+		*result.refCount += 1;
 
 		if (sym->type == INT)
 			result.u.i = sym->u.i;
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index e72f2ec8de..76a08ae76d 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -67,7 +67,26 @@ Symbol::Symbol(const Symbol &s) {
 	archiveIndex = s.archiveIndex;
 }
 
-Symbol::~Symbol() {
+Symbol& Symbol::operator=(const Symbol &s) {
+	if (this != &s) {
+		reset();
+		type = s.type;
+		u.s = s.u.s;
+		refCount = s.refCount;
+		*refCount += 1;
+		nargs = s.nargs;
+		maxArgs = s.maxArgs;
+		parens = s.parens;
+		global = s.global;
+		argNames = s.argNames;
+		varNames = s.varNames;
+		ctx = s.ctx;
+		archiveIndex = s.archiveIndex;
+	}
+	return *this;
+}
+
+void Symbol::reset() {
 	*refCount -= 1;
 	if (*refCount <= 0) {
 		switch (type) {
@@ -102,6 +121,10 @@ Symbol::~Symbol() {
 	}
 }
 
+Symbol::~Symbol() {
+	reset();
+}
+
 PCell::PCell() {
 	p = nullptr;
 	v = nullptr;
@@ -664,7 +687,7 @@ int Datum::compareTo(Datum &d, bool ignoreCase) {
 			}
 		} else if (alignType == INT) {
 			double i1 = asInt();
-			double i2 = asInt();
+			double i2 = d.asInt();
 			if (i1 < i2) {
 				return -1;
 			} else if (i1 == i2) {
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index dec242fe3a..b460e840b5 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -95,6 +95,8 @@ struct Symbol {	/* symbol table entry */
 
 	Symbol();
 	Symbol(const Symbol &s);
+	Symbol& operator=(const Symbol &s);
+	void reset();
 	~Symbol();
 };
 
@@ -132,6 +134,16 @@ struct Datum {	/* interpreter stack type */
 		refCount = d.refCount;
 		*refCount += 1;
 	}
+	Datum& operator=(const Datum &d) {
+		if (this != &d) {
+			reset();
+			type = d.type;
+			u = d.u;
+			refCount = d.refCount;
+			*refCount += 1;
+		}
+		return *this;
+	}
 	Datum(int val) {
 		u.i = val;
 		type = INT;
@@ -156,7 +168,7 @@ struct Datum {	/* interpreter stack type */
 		refCount = new int;
 		*refCount = 1;
 	}
-	~Datum() {
+	void reset() {
 		*refCount -= 1;
 		if (*refCount <= 0) {
 			switch (type) {
@@ -186,6 +198,11 @@ struct Datum {	/* interpreter stack type */
 			}
 			delete refCount;
 		}
+
+	}
+
+	~Datum() {
+		reset();
 	}
 
 	double asFloat();


Commit: 3dc4bb38cd78c39098b855db7dfd7d6b18bce51e
    https://github.com/scummvm/scummvm/commit/3dc4bb38cd78c39098b855db7dfd7d6b18bce51e
Author: Scott Percival (code at moral.net.au)
Date: 2020-05-12T18:05:14+08:00

Commit Message:
DIRECTOR: LINGO: Precalculate array size for b_addAt

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


diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index b024345ed5..f70285ca55 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -558,8 +558,9 @@ void LB::b_addAt(int nargs) {
 	int index = indexD.asInt();
 	TYPECHECK(list, ARRAY);
 
-	if (!((uint)index < list.u.farr->size())) {
-		for (uint i = 0; i < index - list.u.farr->size() - 1; i++)
+	int size = list.u.farr->size();
+	if (index > size) {
+		for (int i = 0; i < index - size - 1; i++)
 			list.u.farr->push_back(Datum(0));
 	}
 	list.u.farr->insert_at(index - 1, value);




More information about the Scummvm-git-logs mailing list