DIRECTOR: LINGO: Implement chunk refs

This commit is contained in:
djsrv 2020-08-21 21:35:53 -04:00
parent 3bf6f79a3e
commit c147a5c979
8 changed files with 1058 additions and 1059 deletions

View file

@ -875,266 +875,226 @@ void LC::c_within() {
} }
} }
Datum LC::chunkRef(ChunkType type, int startChunk, int endChunk, const Datum &src) {
// A chunk expression is made up of 0 or more chunks within a source text.
// These chunks are called chars, words, items, or lines, but it's easier to think of them
// as a substring between 0 or more skip characters and a break character (or the end of the string).
// This function returns a reference to the source text, the start index of the first chunk,
// and the end index of the last chunk in the chunk expression.
if (startChunk < 1 || (0 > endChunk && endChunk < startChunk))
return src;
if (endChunk < 1)
endChunk = startChunk;
Common::String skipChars;
Common::String breakChars;
switch (type) {
case kChunkChar:
skipChars = "";
breakChars = "";
break;
case kChunkWord:
skipChars = "\t\n\r ";
breakChars = "\t\n\r ";
break;
case kChunkItem:
skipChars = "";
breakChars = Common::String::format("%c", g_lingo->_itemDelimiter);
break;
case kChunkLine:
skipChars = "";
breakChars = "\n\r";
break;
}
Common::String str = src.asString();
int idx = 0;
int chunkNum = 0;
int startIdx = -1;
int endIdx = -1;
while (true) {
// each iteration processes one chunk
// find the start of the chunk
while (idx < (int)str.size() && skipChars.contains(str[idx])) {
idx++;
}
chunkNum++;
if (chunkNum == startChunk) {
startIdx = idx; // found start of chunk expression
}
// find the end of the chunk
if (!breakChars.empty()) {
while (idx < (int)str.size() && !breakChars.contains(str[idx])) {
idx++;
}
} else if (idx < (int)str.size()) {
idx++;
}
if (chunkNum == endChunk || idx == (int)str.size()) {
endIdx = idx; // found end of chunk expression
break;
}
if (!breakChars.empty())
idx++; // skip break char
}
if (startIdx < 0)
startIdx = endIdx;
Datum res;
res.u.cref = new ChunkReference(src, startIdx, endIdx);
res.type = CHUNKREF;
return res;
}
void LC::c_of() { void LC::c_of() {
// put char 5 of word 1 of line 2 into field "thing" // put char 5 of word 1 of line 2 into field "thing"
Datum target = g_lingo->pop(); Datum src = g_lingo->pop();
Datum last_line = g_lingo->pop(); Datum lastLine = g_lingo->pop();
Datum first_line = g_lingo->pop(); Datum firstLine = g_lingo->pop();
Datum last_item = g_lingo->pop(); Datum lastItem = g_lingo->pop();
Datum first_item = g_lingo->pop(); Datum firstItem = g_lingo->pop();
Datum last_word = g_lingo->pop(); Datum lastWord = g_lingo->pop();
Datum first_word = g_lingo->pop(); Datum firstWord = g_lingo->pop();
Datum last_char = g_lingo->pop(); Datum lastChar = g_lingo->pop();
Datum first_char = g_lingo->pop(); Datum firstChar = g_lingo->pop();
Common::String result = target.asString(); Datum res = src;
if (first_line.u.i > 0) { if (firstChar.asInt() > 0)
Common::String newline("\r"); res = LC::chunkRef(kChunkChar, firstChar.asInt(), lastChar.asInt(), src);
int first = first_line.u.i; else if (firstWord.asInt() > 0)
int last = first; res = LC::chunkRef(kChunkWord, firstWord.asInt(), lastWord.asInt(), src);
if (last_line.u.i > 0) { else if (firstItem.asInt() > 0)
if ((first_item.u.i > 0) || (first_word.u.i > 0) || (first_char.u.i > 0)) { res = LC::chunkRef(kChunkItem, firstItem.asInt(), lastItem.asInt(), src);
warning("LC::c_of(): last_line defined but unused"); else if (lastLine.asInt() > 0)
} else if (last_line.u.i < first_line.u.i) { res = LC::chunkRef(kChunkLine, firstLine.asInt(), lastLine.asInt(), src);
warning("LC::c_of(): last_line before first_line, ignoring");
} else {
last = last_line.u.i;
}
}
uint32 pointer = 0;
int curLine = 0;
int firstIndex = -1;
int lastIndex = -1;
while (pointer < result.size()) {
curLine += 1;
if (curLine == first) {
firstIndex = pointer;
}
pointer = result.find(newline, pointer);
if (curLine == last) {
lastIndex = pointer;
break;
}
}
if (firstIndex < 0 || lastIndex < 0) {
warning("LC::c_of(): first_line or last_line out of range");
result = "";
} else {
result = result.substr(firstIndex, lastIndex);
}
}
if (first_item.u.i > 0 || last_item.u.i > 0) { g_lingo->push(res);
warning("STUB: LC::c_of() item indexing");
}
if (first_word.u.i > 0) {
int first = first_word.u.i;
int last = first;
if (last_word.u.i > 0) {
if (first_char.u.i > 0) {
warning("LC::c_of(): last_word defined but unused");
} else if (last_word.u.i < first_word.u.i) {
warning("LC::c_of(): last_word before first_word, ignoring");
} else {
last = last_word.u.i;
}
}
uint32 pointer = 0;
int curWord = 0;
int firstIndex = -1;
int lastIndex = -1;
bool inWord = false;
while (pointer < result.size()) {
if ((result[pointer] == '\r') || (result[pointer] == '\t') ||
(result[pointer] == '\n') || (result[pointer] == ' ')) {
if (inWord) {
inWord = false;
if (last == curWord) {
break;
}
}
} else {
if (!inWord) {
inWord = true;
curWord += 1;
if (first == curWord) {
firstIndex = pointer;
}
}
}
pointer += 1;
}
lastIndex = pointer;
if (firstIndex < 0) {
warning("LC::c_of(): first_word out of range");
result = "";
} else {
result = result.substr(firstIndex, lastIndex - firstIndex);
}
}
if (first_char.u.i > 0) {
int first = first_char.u.i;
int last = first;
if (last_char.u.i > 0) {
if (last_char.u.i < first_char.u.i) {
warning("LC::c_of(): last_char before first_char, ignoring");
} else {
last = last_char.u.i;
}
}
result = result.substr(first - 1, last - first);
}
target = Datum(result);
g_lingo->push(target);
} }
void LC::c_charOf() { void LC::c_charOf() {
Datum d2 = g_lingo->pop(); // string Datum src = g_lingo->pop(false);
Datum d1 = g_lingo->pop(); // index Datum index = g_lingo->pop();
if ((d1.type != INT && d1.type != FLOAT) || d2.type != STRING) { if ((index.type != INT && index.type != FLOAT)
warning("LC::c_charOf(): Called with wrong data types: %s and %s", d1.type2str(), d2.type2str()); || (src.type != STRING && src.type != VAR && src.type != FIELDREF && src.type != CHUNKREF && src.type != CASTREF)) {
g_lingo->lingoError("LC::c_charOf(): Called with wrong data types: %s and %s", index.type2str(), src.type2str());
g_lingo->push(Datum("")); g_lingo->push(Datum(""));
return; return;
} }
Datum res; g_lingo->push(LC::chunkRef(kChunkChar, index.asInt(), 0, src));
int index = d1.asInt();
Common::String chunkExpr = *d2.u.s;
if (index < 1)
res = Datum(chunkExpr);
else if (uint(index) > chunkExpr.size())
res = Datum("");
else
res = Datum(Common::String(chunkExpr[index - 1]));
g_lingo->push(res);
} }
void LC::c_charToOf() { void LC::c_charToOf() {
Datum d3 = g_lingo->pop(); // string Datum src = g_lingo->pop(false);
Datum d2 = g_lingo->pop(); // indexFrom Datum indexTo = g_lingo->pop();
Datum d1 = g_lingo->pop(); // indexTo Datum indexFrom = g_lingo->pop();
if ((d1.type != INT && d1.type != FLOAT) || (d2.type != INT && d2.type != FLOAT) || d3.type != STRING) { if ((indexTo.type != INT && indexTo.type != FLOAT) || (indexFrom.type != INT && indexFrom.type != FLOAT)
warning("LC::c_charToOf(): Called with wrong data types: %s, %s and %s", d1.type2str(), d2.type2str(), d3.type2str()); || (src.type != STRING && src.type != VAR && src.type != FIELDREF && src.type != CHUNKREF && src.type != CASTREF)) {
warning("LC::c_charToOf(): Called with wrong data types: %s, %s and %s", indexTo.type2str(), indexFrom.type2str(), src.type2str());
g_lingo->push(Datum("")); g_lingo->push(Datum(""));
return; return;
} }
int indexFrom = d1.asInt(); g_lingo->push(LC::chunkRef(kChunkChar, indexFrom.asInt(), indexTo.asInt(), src));
int indexTo = d2.asInt();
Common::String chunkExpr = *d3.u.s;
Datum res;
// The if order is important. It mimicks the checks, i.e. bugs, of Director 4.
if (indexFrom < 1)
res = Datum(chunkExpr);
else if (indexTo < 1)
res = Datum(Common::String(chunkExpr[indexFrom - 1])); // treat as charOf
else if (indexFrom > indexTo)
res = Datum("");
else if (uint(indexFrom) > chunkExpr.size())
res = Datum("");
else
res = Datum(chunkExpr.substr(indexFrom - 1, indexTo - indexFrom + 1));
g_lingo->push(res);
} }
void LC::c_itemOf() { void LC::c_itemOf() {
Datum src = g_lingo->pop(false);
Datum index = g_lingo->pop();
Datum d2 = g_lingo->pop(); // chunkExpression if ((index.type != INT && index.type != FLOAT)
Datum d1 = g_lingo->pop(); // index || (src.type != STRING && src.type != VAR && src.type != FIELDREF && src.type != CHUNKREF && src.type != CASTREF)) {
warning("LC::c_itemOf(): Called with wrong data types: %s and %s", index.type2str(), src.type2str());
char delimiter = g_lingo->_itemDelimiter;
if ((d1.type != INT && d1.type != FLOAT) || d2.type != STRING) {
warning("LC::c_itemOf(): Called with wrong data types: %s and %s", d1.type2str(), d2.type2str());
g_lingo->push(Datum("")); g_lingo->push(Datum(""));
return; return;
} }
int index = d1.asInt(); g_lingo->push(LC::chunkRef(kChunkItem, index.asInt(), 0, src));
if (index < 1) {
// returns the input string
g_lingo->push(d2);
return;
}
Common::String chunkExpr = *d2.u.s;
uint startPos = 0;
while (index-- > 1) {
startPos = chunkExpr.find(delimiter, startPos);
if (startPos == Common::String::npos)
break;
startPos++; // skipping comma
}
Datum res;
if (startPos == Common::String::npos) {
res = Datum("");
} else {
uint endPos = chunkExpr.find(delimiter, startPos);
if (endPos == Common::String::npos)
endPos = chunkExpr.size();
res = Datum(chunkExpr.substr(startPos, endPos - startPos));
}
g_lingo->push(res);
} }
void LC::c_itemToOf() { void LC::c_itemToOf() {
Datum d3 = g_lingo->pop(); Datum src = g_lingo->pop(false);
Datum d2 = g_lingo->pop(); Datum indexTo = g_lingo->pop();
Datum d1 = g_lingo->pop(); Datum indexFrom = g_lingo->pop();
warning("STUB: LC::c_itemToOf(): %d %d %d", d1.u.i, d2.u.i, d3.u.i); if ((indexTo.type != INT && indexTo.type != FLOAT) || (indexFrom.type != INT && indexFrom.type != FLOAT)
|| (src.type != STRING && src.type != VAR && src.type != FIELDREF && src.type != CHUNKREF && src.type != CASTREF)) {
warning("LC::c_itemToOf(): Called with wrong data types: %s, %s and %s", indexTo.type2str(), indexFrom.type2str(), src.type2str());
g_lingo->push(Datum(""));
return;
}
g_lingo->push(d1); g_lingo->push(LC::chunkRef(kChunkItem, indexFrom.asInt(), indexTo.asInt(), src));
} }
void LC::c_lineOf() { void LC::c_lineOf() {
Datum d2 = g_lingo->pop(); Datum src = g_lingo->pop(false);
Datum d1 = g_lingo->pop(); Datum index = g_lingo->pop();
warning("STUB: LC::c_lineOf(): %d %d", d1.u.i, d2.u.i); if ((index.type != INT && index.type != FLOAT)
|| (src.type != STRING && src.type != VAR && src.type != FIELDREF && src.type != CHUNKREF && src.type != CASTREF)) {
warning("LC::c_lineOf(): Called with wrong data types: %s and %s", index.type2str(), src.type2str());
g_lingo->push(Datum(""));
return;
}
g_lingo->push(d1); g_lingo->push(LC::chunkRef(kChunkLine, index.asInt(), 0, src));
} }
void LC::c_lineToOf() { void LC::c_lineToOf() {
Datum d3 = g_lingo->pop(); Datum src = g_lingo->pop(false);
Datum d2 = g_lingo->pop(); Datum indexTo = g_lingo->pop();
Datum d1 = g_lingo->pop(); Datum indexFrom = g_lingo->pop();
warning("STUB: LC::c_lineToOf(): %d %d %d", d1.u.i, d2.u.i, d3.u.i); if ((indexTo.type != INT && indexTo.type != FLOAT) || (indexFrom.type != INT && indexFrom.type != FLOAT)
|| (src.type != STRING && src.type != VAR && src.type != FIELDREF && src.type != CHUNKREF && src.type != CASTREF)) {
warning("LC::c_lineToOf(): Called with wrong data types: %s, %s and %s", indexTo.type2str(), indexFrom.type2str(), src.type2str());
g_lingo->push(Datum(""));
return;
}
g_lingo->push(d1); g_lingo->push(LC::chunkRef(kChunkLine, indexFrom.asInt(), indexTo.asInt(), src));
} }
void LC::c_wordOf() { void LC::c_wordOf() {
Datum d2 = g_lingo->pop(); Datum src = g_lingo->pop(false);
Datum d1 = g_lingo->pop(); Datum index = g_lingo->pop();
warning("STUB: LC::c_wordOf(): %d %d", d1.u.i, d2.u.i); if ((index.type != INT && index.type != FLOAT)
|| (src.type != STRING && src.type != VAR && src.type != FIELDREF && src.type != CHUNKREF && src.type != CASTREF)) {
warning("LC::c_wordOf(): Called with wrong data types: %s and %s", index.type2str(), src.type2str());
g_lingo->push(Datum(""));
return;
}
g_lingo->push(d1); g_lingo->push(LC::chunkRef(kChunkWord, index.asInt(), 0, src));
} }
void LC::c_wordToOf() { void LC::c_wordToOf() {
Datum d3 = g_lingo->pop(); Datum src = g_lingo->pop(false);
Datum d2 = g_lingo->pop(); Datum indexTo = g_lingo->pop();
Datum d1 = g_lingo->pop(); Datum indexFrom = g_lingo->pop();
warning("STUB: LC::c_wordToOf(): %d %d %d", d1.u.i, d2.u.i, d3.u.i); if ((indexTo.type != INT && indexTo.type != FLOAT) || (indexFrom.type != INT && indexFrom.type != FLOAT)
|| (src.type != STRING && src.type != VAR && src.type != FIELDREF && src.type != CHUNKREF && src.type != CASTREF)) {
warning("LC::c_wordToOf(): Called with wrong data types: %s, %s and %s", indexTo.type2str(), indexFrom.type2str(), src.type2str());
g_lingo->push(Datum(""));
return;
}
g_lingo->push(d1); g_lingo->push(LC::chunkRef(kChunkWord, indexFrom.asInt(), indexTo.asInt(), src));
} }
void LC::c_and() { void LC::c_and() {

View file

@ -56,6 +56,7 @@ void c_starts();
void c_intersects(); void c_intersects();
void c_within(); void c_within();
Datum chunkRef(ChunkType type, int startChunk, int endChunk, const Datum &src);
void c_of(); void c_of();
void c_charOf(); void c_charOf();
void c_charToOf(); void c_charToOf();

File diff suppressed because it is too large Load diff

View file

@ -65,81 +65,82 @@ extern int yydebug;
PARRAY = 266, /* PARRAY */ PARRAY = 266, /* PARRAY */
CASTREF = 267, /* CASTREF */ CASTREF = 267, /* CASTREF */
FIELDREF = 268, /* FIELDREF */ FIELDREF = 268, /* FIELDREF */
INT = 269, /* INT */ CHUNKREF = 269, /* CHUNKREF */
ARGC = 270, /* ARGC */ INT = 270, /* INT */
ARGCNORET = 271, /* ARGCNORET */ ARGC = 271, /* ARGC */
THEENTITY = 272, /* THEENTITY */ ARGCNORET = 272, /* ARGCNORET */
THEENTITYWITHID = 273, /* THEENTITYWITHID */ THEENTITY = 273, /* THEENTITY */
THEMENUITEMENTITY = 274, /* THEMENUITEMENTITY */ THEENTITYWITHID = 274, /* THEENTITYWITHID */
THEMENUITEMSENTITY = 275, /* THEMENUITEMSENTITY */ THEMENUITEMENTITY = 275, /* THEMENUITEMENTITY */
FLOAT = 276, /* FLOAT */ THEMENUITEMSENTITY = 276, /* THEMENUITEMSENTITY */
THEFUNC = 277, /* THEFUNC */ FLOAT = 277, /* FLOAT */
THEFUNCINOF = 278, /* THEFUNCINOF */ THEFUNC = 278, /* THEFUNC */
VARID = 279, /* VARID */ THEFUNCINOF = 279, /* THEFUNCINOF */
STRING = 280, /* STRING */ VARID = 280, /* VARID */
SYMBOL = 281, /* SYMBOL */ STRING = 281, /* STRING */
ENDCLAUSE = 282, /* ENDCLAUSE */ SYMBOL = 282, /* SYMBOL */
tPLAYACCEL = 283, /* tPLAYACCEL */ ENDCLAUSE = 283, /* ENDCLAUSE */
tMETHOD = 284, /* tMETHOD */ tPLAYACCEL = 284, /* tPLAYACCEL */
THEOBJECTPROP = 285, /* THEOBJECTPROP */ tMETHOD = 285, /* tMETHOD */
tCAST = 286, /* tCAST */ THEOBJECTPROP = 286, /* THEOBJECTPROP */
tFIELD = 287, /* tFIELD */ tCAST = 287, /* tCAST */
tSCRIPT = 288, /* tSCRIPT */ tFIELD = 288, /* tFIELD */
tWINDOW = 289, /* tWINDOW */ tSCRIPT = 289, /* tSCRIPT */
tDOWN = 290, /* tDOWN */ tWINDOW = 290, /* tWINDOW */
tELSE = 291, /* tELSE */ tDOWN = 291, /* tDOWN */
tELSIF = 292, /* tELSIF */ tELSE = 292, /* tELSE */
tEXIT = 293, /* tEXIT */ tELSIF = 293, /* tELSIF */
tGLOBAL = 294, /* tGLOBAL */ tEXIT = 294, /* tEXIT */
tGO = 295, /* tGO */ tGLOBAL = 295, /* tGLOBAL */
tGOLOOP = 296, /* tGOLOOP */ tGO = 296, /* tGO */
tIF = 297, /* tIF */ tGOLOOP = 297, /* tGOLOOP */
tIN = 298, /* tIN */ tIF = 298, /* tIF */
tINTO = 299, /* tINTO */ tIN = 299, /* tIN */
tMACRO = 300, /* tMACRO */ tINTO = 300, /* tINTO */
tMOVIE = 301, /* tMOVIE */ tMACRO = 301, /* tMACRO */
tNEXT = 302, /* tNEXT */ tMOVIE = 302, /* tMOVIE */
tOF = 303, /* tOF */ tNEXT = 303, /* tNEXT */
tPREVIOUS = 304, /* tPREVIOUS */ tOF = 304, /* tOF */
tPUT = 305, /* tPUT */ tPREVIOUS = 305, /* tPREVIOUS */
tREPEAT = 306, /* tREPEAT */ tPUT = 306, /* tPUT */
tSET = 307, /* tSET */ tREPEAT = 307, /* tREPEAT */
tTHEN = 308, /* tTHEN */ tSET = 308, /* tSET */
tTO = 309, /* tTO */ tTHEN = 309, /* tTHEN */
tWHEN = 310, /* tWHEN */ tTO = 310, /* tTO */
tWITH = 311, /* tWITH */ tWHEN = 311, /* tWHEN */
tWHILE = 312, /* tWHILE */ tWITH = 312, /* tWITH */
tFACTORY = 313, /* tFACTORY */ tWHILE = 313, /* tWHILE */
tOPEN = 314, /* tOPEN */ tFACTORY = 314, /* tFACTORY */
tPLAY = 315, /* tPLAY */ tOPEN = 315, /* tOPEN */
tINSTANCE = 316, /* tINSTANCE */ tPLAY = 316, /* tPLAY */
tGE = 317, /* tGE */ tINSTANCE = 317, /* tINSTANCE */
tLE = 318, /* tLE */ tGE = 318, /* tGE */
tEQ = 319, /* tEQ */ tLE = 319, /* tLE */
tNEQ = 320, /* tNEQ */ tEQ = 320, /* tEQ */
tAND = 321, /* tAND */ tNEQ = 321, /* tNEQ */
tOR = 322, /* tOR */ tAND = 322, /* tAND */
tNOT = 323, /* tNOT */ tOR = 323, /* tOR */
tMOD = 324, /* tMOD */ tNOT = 324, /* tNOT */
tAFTER = 325, /* tAFTER */ tMOD = 325, /* tMOD */
tBEFORE = 326, /* tBEFORE */ tAFTER = 326, /* tAFTER */
tCONCAT = 327, /* tCONCAT */ tBEFORE = 327, /* tBEFORE */
tCONTAINS = 328, /* tCONTAINS */ tCONCAT = 328, /* tCONCAT */
tSTARTS = 329, /* tSTARTS */ tCONTAINS = 329, /* tCONTAINS */
tCHAR = 330, /* tCHAR */ tSTARTS = 330, /* tSTARTS */
tITEM = 331, /* tITEM */ tCHAR = 331, /* tCHAR */
tLINE = 332, /* tLINE */ tITEM = 332, /* tITEM */
tWORD = 333, /* tWORD */ tLINE = 333, /* tLINE */
tSPRITE = 334, /* tSPRITE */ tWORD = 334, /* tWORD */
tINTERSECTS = 335, /* tINTERSECTS */ tSPRITE = 335, /* tSPRITE */
tWITHIN = 336, /* tWITHIN */ tINTERSECTS = 336, /* tINTERSECTS */
tTELL = 337, /* tTELL */ tWITHIN = 337, /* tWITHIN */
tPROPERTY = 338, /* tPROPERTY */ tTELL = 338, /* tTELL */
tON = 339, /* tON */ tPROPERTY = 339, /* tPROPERTY */
tENDIF = 340, /* tENDIF */ tON = 340, /* tON */
tENDREPEAT = 341, /* tENDREPEAT */ tENDIF = 341, /* tENDIF */
tENDTELL = 342, /* tENDTELL */ tENDREPEAT = 342, /* tENDREPEAT */
tASSERTERROR = 343 /* tASSERTERROR */ tENDTELL = 343, /* tENDTELL */
tASSERTERROR = 344 /* tASSERTERROR */
}; };
typedef enum yytokentype yytoken_kind_t; typedef enum yytokentype yytoken_kind_t;
#endif #endif
@ -163,7 +164,7 @@ union YYSTYPE
Common::String *prop; Common::String *prop;
} objectprop; } objectprop;
#line 167 "engines/director/lingo/lingo-gr.h" #line 168 "engines/director/lingo/lingo-gr.h"
}; };
typedef union YYSTYPE YYSTYPE; typedef union YYSTYPE YYSTYPE;

View file

@ -196,7 +196,7 @@ static void mVar(Common::String *s, VarType type) {
// Datum types // Datum types
%token VOID VAR POINT RECT ARRAY OBJECT LEXERROR PARRAY %token VOID VAR POINT RECT ARRAY OBJECT LEXERROR PARRAY
%token CASTREF FIELDREF %token CASTREF FIELDREF CHUNKREF
%token<i> INT ARGC ARGCNORET %token<i> INT ARGC ARGCNORET
%token<e> THEENTITY THEENTITYWITHID THEMENUITEMENTITY THEMENUITEMSENTITY %token<e> THEENTITY THEENTITYWITHID THEMENUITEMENTITY THEMENUITEMSENTITY

View file

@ -838,6 +838,9 @@ void Datum::reset() {
delete u.obj; delete u.obj;
} }
break; break;
case CHUNKREF:
delete u.cref;
break;
default: default:
break; break;
} }
@ -848,7 +851,7 @@ void Datum::reset() {
} }
Datum Datum::eval() { Datum Datum::eval() {
if (type == VAR || type == FIELDREF) { if (type == VAR || type == FIELDREF || type == CHUNKREF) {
return g_lingo->varFetch(*this); return g_lingo->varFetch(*this);
} }
@ -982,6 +985,12 @@ Common::String Datum::asString(bool printonly) const {
s = Common::String::format("field: \"%s\"", ((TextCastMember *)member)->getText().c_str()); s = Common::String::format("field: \"%s\"", ((TextCastMember *)member)->getText().c_str());
} }
break; break;
case CHUNKREF:
{
Common::String src = u.cref->source.asString(true);
s = Common::String::format("chunk: char %d to %d of %s", u.cref->start, u.cref->end, src.c_str());
}
break;
case POINT: case POINT:
s = "point:"; s = "point:";
// fallthrough // fallthrough
@ -1076,6 +1085,8 @@ const char *Datum::type2str(bool isk) const {
return isk ? "#object" : "OBJECT"; return isk ? "#object" : "OBJECT";
case FIELDREF: case FIELDREF:
return "FIELDREF"; return "FIELDREF";
case CHUNKREF:
return "CHUNKREF";
case VAR: case VAR:
return isk ? "#var" : "VAR"; return isk ? "#var" : "VAR";
default: default:
@ -1360,6 +1371,10 @@ Datum Lingo::varFetch(Datum &var, bool global, DatumHash *localvars, bool silent
warning("varFetch: Unhandled cast type %d", member->_type); warning("varFetch: Unhandled cast type %d", member->_type);
break; break;
} }
} else if (var.type == CHUNKREF) {
Common::String src = var.u.cref->source.eval().asString();
result.type = STRING;
result.u.s = new Common::String(src.substr(var.u.cref->start, var.u.cref->end - var.u.cref->start));
} else { } else {
warning("varFetch: fetch from non-variable"); warning("varFetch: fetch from non-variable");
} }

View file

@ -37,6 +37,7 @@ class SeekableReadStreamEndian;
namespace Director { namespace Director {
struct ChunkReference;
struct TheEntity; struct TheEntity;
struct TheEntityField; struct TheEntityField;
struct LingoArchive; struct LingoArchive;
@ -116,7 +117,8 @@ struct Datum { /* interpreter stack type */
Common::String *s; /* STRING, VAR, OBJECT */ Common::String *s; /* STRING, VAR, OBJECT */
DatumArray *farr; /* ARRAY, POINT, RECT */ DatumArray *farr; /* ARRAY, POINT, RECT */
PropertyArray *parr; /* PARRAY */ PropertyArray *parr; /* PARRAY */
AbstractObject *obj; AbstractObject *obj; /* OBJECT */
ChunkReference *cref; /* CHUNKREF */
} u; } u;
int *refCount; int *refCount;
@ -146,6 +148,14 @@ struct Datum { /* interpreter stack type */
int compareTo(Datum &d, bool ignoreCase = false) const; int compareTo(Datum &d, bool ignoreCase = false) const;
}; };
struct ChunkReference {
Datum source;
int start;
int end;
ChunkReference(const Datum &src, uint s, uint e) : source(src), start(s), end(e) {}
};
struct PCell { struct PCell {
Datum p; Datum p;
Datum v; Datum v;

View file

@ -307,6 +307,13 @@ enum SymbolType {
HANDLER // user-defined handler HANDLER // user-defined handler
}; };
enum ChunkType {
kChunkChar,
kChunkWord,
kChunkItem,
kChunkLine
};
struct Datum; struct Datum;
struct PCell; struct PCell;
typedef Common::Array<Datum> DatumArray; typedef Common::Array<Datum> DatumArray;