[Scummvm-git-logs] scummvm master -> a7d6abbcdc39e5ede5e2fa3b868a92d468ec6f14

sev- noreply at scummvm.org
Sun Apr 12 22:01:22 UTC 2026


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

Summary:
a7d6abbcdc DIRECTOR: LINGO: Fixed logic of the `value` built-in, added tests


Commit: a7d6abbcdc39e5ede5e2fa3b868a92d468ec6f14
    https://github.com/scummvm/scummvm/commit/a7d6abbcdc39e5ede5e2fa3b868a92d468ec6f14
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2026-04-12T23:57:15+02:00

Commit Message:
DIRECTOR: LINGO: Fixed logic of the `value` built-in, added tests

The original had a shortcut for numbers and strings, allowing
pure garbage be at the end. At the same time, look-ahead guarded
for valid expressions.

Fixes day/night bell computations in 'melements', that contained
the following Lingo:

  set seconds to value(item 3 of (the long time))

That yields string like "22 PM" which should parse into "22"

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


diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index 89980d98237..a5d83adde2c 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -832,6 +832,71 @@ void LB::b_value(int nargs) {
 		g_lingo->push(Datum(0));
 		return;
 	}
+
+	bool maybeExpression = false;
+
+	// First, let's check that it is a number
+	if (expr[0] == '-' || expr[0] == '+' || (expr[0] >= '0' && expr[0] <= '9') ||
+			(expr[0] == '.' && expr.size() > 1 && expr[1] >= '0' && expr[1] <= '9')) {
+		char *endPtr = nullptr;
+		double result = strtof(expr.c_str(), &endPtr);
+
+		// Maybe it is part of an expression?
+		if (endPtr && *endPtr) {
+			while (*endPtr && Common::isSpace(*endPtr))
+				endPtr++;
+
+			if (strchr("-+*/%^:,()><&|", *endPtr) != NULL) {
+				maybeExpression = true;
+			}
+		}
+
+		if (!maybeExpression) {
+			if (result < INT_MAX && floor(result) == result) {
+				g_lingo->push(Datum((int)result));
+			} else {
+				g_lingo->push(Datum(result));
+			}
+			return;
+		}
+	}
+
+	// Or maybe it is a string with quotes around it?
+	if (expr.size() >= 2 && expr[0] == '"') {
+		// scan for the end quote, ignoring escaped quotes
+		bool escaped = false;
+		size_t i;
+		for (i = 1; i < expr.size(); i++) {
+			if (expr[i] == '"' && !escaped) {
+				break;
+			}
+			escaped = (expr[i] == '\\' && !escaped);
+		}
+		if (i == expr.size()) {
+			// No closing quote found, push void
+			g_lingo->pushVoid();
+			return;
+		}
+
+		if (i + 1 < expr.size()) {
+			// There are extra characters after the closing quote, this is not a simple string
+			size_t j = i + 1;
+			while (expr[j] && Common::isSpace(expr[j]))
+				j++;
+
+			if (strchr("&", expr[j]) != NULL) {
+				maybeExpression = true;
+			}
+		}
+
+		if (!maybeExpression) {
+			g_lingo->push(expr.substr(1, i - 1));
+			return;
+		}
+	}
+
+	// There is no simple way, feed it to the Lingo parser
+
 	Common::String code = "return " + expr;
 	// Compile the code to an anonymous function and call it
 	ScriptContext *sc = g_lingo->_compiler->compileAnonymous(code, kLPPTrimGarbage);
@@ -4244,6 +4309,9 @@ void LB::b_scummvmassertequal(int nargs) {
 		result = LC::eqData(d1, d2).u.i;
 	} else if (d1.type == PARRAY && d2.type == PARRAY) {
 		result = LC::eqData(d1, d2).u.i;
+	} else if (d1.type == FLOAT && d2.type == FLOAT) {
+		// Use tolerance
+		result = (ABS(d1.asFloat() - d2.asFloat()) < 0.000001) ? 1 : 0;
 	} else {
 		result = (d1 == d2);
 	}
diff --git a/engines/director/lingo/tests/value.lingo b/engines/director/lingo/tests/value.lingo
index 8a0650a54d9..a9b9fcc60fb 100644
--- a/engines/director/lingo/tests/value.lingo
+++ b/engines/director/lingo/tests/value.lingo
@@ -11,6 +11,30 @@ scummvmAssertEqual([#a: 1, #b: 2], value("[#a: 1, #b: 2]"))
 -- expressions
 scummvmAssertEqual(9, value("3*3"))
 
+-- empty line is special
+scummvmAssertEqual(Void, value(""))
+
+-- simple expressions with garbage
+scummvmAssertEqual(55, value("55 5"))
+scummvmAssertEqual(55, value("55 abra"))
+scummvmAssertEqual(12, value("12 PM"))
+
+-- simple string
+set test = QUOTE & "abra" & QUOTE
+scummvmAssertEqual("abra", value(test))
+
+-- string with garbage
+set test = QUOTE & "abra" & QUOTE & " 55"
+scummvmAssertEqual("abra", value(test))
+
+-- broken string
+set test = QUOTE & "abra"
+scummvmAssertEqual("Void, value(test))
+
+-- string, starting expression
+set test = QUOTE & "abra" & QUOTE & " & " & QUOTE & "kadabra" & QUOTE
+scummvmAssertEqual("abrakadabra", value(test))
+
 -- the kicker; you are allowed to have garbage on the end!!!
 -- if it hits a token it doesn't understand, the parser should try again but stopping just before that token.
 scummvmNoFatalError(true)




More information about the Scummvm-git-logs mailing list