@@ -1262,31 +1262,68 @@ nullCoalescion(lhs:Code,rhs:Code):Expr := (
12621262 else e);
12631263setup(QuestionQuestionS, nullify, nullCoalescion);
12641264
1265+ HashTableOrNull := HashTable or null;
1266+
1267+ -- check if code is x#k or x.k (where x is a hash table)
1268+ -- if so, lock it and return (so we can unlock it later)
1269+ maybeLock(c:Code):HashTableOrNull := (
1270+ when c
1271+ is x:binaryCode do (
1272+ if x.f == DotS.symbol.binary || x.f == SharpS.symbol.binary
1273+ then (
1274+ y := eval(x.lhs);
1275+ when y is z:HashTable do (
1276+ if !z.beingInitialized then lockWrite(z.mutex);
1277+ HashTableOrNull(z))
1278+ else HashTableOrNull(null()))
1279+ else HashTableOrNull(null()))
1280+ else HashTableOrNull(null()));
1281+
1282+ maybeUnlock(x:HashTableOrNull):void := (
1283+ when x
1284+ is y:HashTable do (
1285+ if !y.beingInitialized then unlock(y.mutex))
1286+ else nothing);
1287+
12651288augmentedAssignmentFun(x:augmentedAssignmentCode):Expr := (
12661289 when lookup(x.oper.word, augmentedAssignmentOperatorTable)
12671290 is null do buildErrorPacket("unknown augmented assignment operator")
12681291 is s:Symbol do (
1292+ -- check if we' re modifying a hash table and lock if so
1293+ table := maybeLock(x.lhs);
12691294 -- evaluate the left- hand side first
12701295 lexpr := nullE;
12711296 if s.word.name == = " ??" -- x ??= y is treated like x ?? (x = y)
12721297 then (
12731298 e := nullify(x.lhs);
12741299 when e
12751300 is Nothing do nothing
1276- else return e)
1301+ else (
1302+ maybeUnlock(table);
1303+ return e))
12771304 else lexpr = eval(x.lhs);
1278- when lexpr is e:Error do return lexpr else nothing;
1305+ when lexpr is e:Error do (
1306+ maybeUnlock(table);
1307+ return lexpr)
1308+ else nothing;
12791309 -- check if user- defined method exists
12801310 meth := lookup(Class(lexpr), Expr(SymbolClosure(globalFrame, x.oper)));
12811311 if meth != nullE then (
12821312 rexpr := eval(x.rhs);
1283- when rexpr is e:Error do return rexpr else nothing;
1313+ when rexpr is e:Error do (
1314+ maybeUnlock(table);
1315+ return rexpr)
1316+ else nothing;
12841317 r := applyEEE(meth, lexpr, rexpr);
12851318 when r
12861319 is s:SymbolClosure do (
12871320 if s.symbol.word.name == = " Default" then nothing
1288- else return r)
1289- else return r);
1321+ else (
1322+ maybeUnlock(table);
1323+ return r))
1324+ else (
1325+ maybeUnlock(table);
1326+ return r));
12901327 -- if not, use default behavior
12911328 left := evaluatedCode(lexpr, codePosition(x.lhs));
12921329 when x.lhs
@@ -1305,7 +1342,10 @@ augmentedAssignmentFun(x:augmentedAssignmentCode):Expr := (
13051342 is y:binaryCode do (
13061343 r := Code(binaryCode(s.binary, Code(left), x.rhs, x.position));
13071344 if y.f == DotS.symbol.binary || y.f == SharpS.symbol.binary
1308- then AssignElemFun(y.lhs, y.rhs, r)
1345+ then (
1346+ z := AssignElemFun(y.lhs, y.rhs, r);
1347+ maybeUnlock(table);
1348+ z)
13091349 else InstallValueFun(CodeSequence(
13101350 convertGlobalOperator(x.info), y.lhs, y.rhs, r)))
13111351 is y:adjacentCode do (
0 commit comments