// process scope x. ... end scope blocks svoid tok_scopes(L tok, O... _) { if (!tok.contains("scope")) ret; optPar bool autoCloseScopes; // New syntax: scope bla { ... } replaceKeywordBlock(tok, "scope ", "scope $2. ", " end scope "); int i; // Old syntax: scope bla ... end scope while ((i = rjfind(tok, "scope ", (_tok, nIdx) -> !subListContains(_tok, nIdx-1, nIdx+6, "aka"))) >= 0) { S scopeName = tok.get(i+2); int start = i+4; if (eqGet(tok, start, ".")) start += 2; int j = jfind(tok, start, "end scope"); if (j < 0) if (autoCloseScopes) j = l(tok); else fail("Scope " + scopeName + " opened but not closed"); else clearTokens(tok, j, j+3); new HashSet names; new HashSet functions; clearTokens(tok, i, start-1); L subTok = subList(tok, start-1, j); // auto-make #lock variable if (jfind(subTok, "lock #lock") >= 0 && jfind(subTok, "Lock #lock") < 0) tok.set(i, "static Lock " + scopeName + "_lock = lock();\n"); // first pass (find # declarations) for (int k = start; k < j-2; k += 2) { S t = get(tok, k+2); if (eqGet(tok, k, "#") && isIdentifier(t)) { names.add(t); if (eqGetOneOf(tok, k+4, "(", "{", "<", "extends", "implements", ">")) // cover class declarations too functions.add(t); replaceTokens(tok, k, k+3, scopeName + "_" + t); } } // second pass (references to scoped variables) for (int k = start; k < j; k += 2) { S t = get(tok, k); if (isIdentifier(t)) { if (names.contains(t)) { if (eqGet(tok, k-2, ".")) {} else if (eqGet(tok, k+2, "(") && !functions.contains(t)) {} // avoid lock ... and map ... else if (eqOneOf(t, "lock", "map") && isIdentifier(get(tok, k+2))) {} else tok.set(k, scopeName + "_" + t); } else if (eq(t, "__scope")) tok.set(k, quote(scopeName)); } } reTok(tok, i, j+3); } }