[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