Skip to content

Commit

Permalink
toLeopard: factor out uniqueLocalVarName, reuse across script
Browse files Browse the repository at this point in the history
  • Loading branch information
towerofnix committed Jun 25, 2024
1 parent 3321cda commit 5a74826
Showing 1 changed file with 29 additions and 20 deletions.
49 changes: 29 additions & 20 deletions src/io/leopard/toLeopard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,12 @@ export default function toLeopard(
// Leopard names (JS function arguments, which are identifiers).
let customBlockArgNameMap: Map<Script, { [key: string]: string }> = new Map();

// Maps scripts to a function (from uniqueNameFactory) which produces unique
// names based on the provided default names. This is for "unqualified"
// identifiers, which basically means ordinary variables. That namespace is
// shared with custom block arguments!
let uniqueLocalVarNameMap: Map<Script, (name: string) => string> = new Map();

// Maps variables and lists' Scratch IDs to corresponding Leopard names
// (JS properties on `this.vars`). This is shared across all sprites, so
// that global (stage) variables' IDs map to the same name regardless what
Expand Down Expand Up @@ -482,6 +488,8 @@ export default function toLeopard(
}
}
}

uniqueLocalVarNameMap.set(script, uniqueNameFactory(Object.values(argNameMap)));
}
}

Expand Down Expand Up @@ -590,6 +598,17 @@ export default function toLeopard(
}

function blockToJSWithContext(block: Block, target: Target, script?: Script): string {
// This will be shared by all contained blockToJS calls, which should include
// all following/descendant relative to the provided one. Officially local names
// should be unique to the script, but if we don't have a script, they will still
// be unique to these "nearby" blocks (part of the same blockToJSWithContext call).
let uniqueLocalVarName: (name: string) => string;
if (script && uniqueLocalVarNameMap.has(script)) {
uniqueLocalVarName = uniqueLocalVarNameMap.get(script)!;
} else {
uniqueLocalVarName = uniqueNameFactory();
}

return blockToJS(block);

function increase(leftSide: string, input: BlockInput.Any, allowIncrementDecrement: boolean): string {
Expand Down Expand Up @@ -1324,34 +1343,24 @@ export default function toLeopard(
case OpCode.control_repeat: {
satisfiesInputShape = InputShape.Stack;

const timesIsStatic = block.inputs.TIMES.type === "number";

// Of course we convert blocks in a descending recursive hierarchy,
// but we still need to make sure we get the relevant local var names
// *before* processing the substack - which might include more "repeat"
// blocks!
const iVar = uniqueLocalVarName("i");
const timesVar = timesIsStatic ? null : uniqueLocalVarName("times");

const times = inputToJS(block.inputs.TIMES, InputShape.Number);
const substack = inputToJS(block.inputs.SUBSTACK, InputShape.Stack);

// Note that although this is a useful-seeming utility function, it can't be
// factored out for general `blockToJS` usage. The variables in a `for` construct
// are only unique, disregarding all other blocks, *because* they are defined and
// accessed in a brand new scope, and deeper scopes can overshadow the name
// without causing any trouble.
let uniqueLocalVarName: (name: string) => string;
if (script && customBlockArgNameMap.has(script)) {
// Avoid overshadowing the name of a custom block input, which is just a normal
// local variable.
const argNames = customBlockArgNameMap.get(script)!;
uniqueLocalVarName = uniqueNameFactory(Object.values(argNames));
} else {
// Nothing to overshadow, the name provided will be unique. (Since we're only
// going to pass two names, right as part of this block!)
uniqueLocalVarName = (name: string) => name;
}

const iVar = uniqueLocalVarName("i");
if (block.inputs.TIMES.type === "number") {
if (timesIsStatic) {
blockSource = `for (let ${iVar} = 0; ${iVar} < ${times}; ${iVar}++) {
${substack};
${warp ? "" : "yield;"}
}`;
} else {
const timesVar = uniqueLocalVarName("times");
blockSource = `for (let ${iVar} = 0, ${timesVar} = ${times}; ${iVar} < ${timesVar}; ${iVar}++) {
${substack};
${warp ? "" : "yield;"}
Expand Down

0 comments on commit 5a74826

Please sign in to comment.