Add offsets to commands
This commit is contained in:
parent
39890cdc5a
commit
2b6b6a96fb
|
@ -15,3 +15,4 @@ Gir supports following optimizations:
|
||||||
|
|
||||||
* Turn runs of +- or <> into one command
|
* Turn runs of +- or <> into one command
|
||||||
* Turn [-] or [+] into one command
|
* Turn [-] or [+] into one command
|
||||||
|
* Add offsets to commands that modify tape, to reduce moving tape head
|
||||||
|
|
104
gir.js
104
gir.js
|
@ -8,17 +8,22 @@
|
||||||
// Unsure if this helps in any way over strings, but I feel it neater
|
// Unsure if this helps in any way over strings, but I feel it neater
|
||||||
|
|
||||||
// +++++ → {type: add, value: 5}
|
// +++++ → {type: add, value: 5}
|
||||||
|
// Can have offset property
|
||||||
const add = Symbol('add');
|
const add = Symbol('add');
|
||||||
// > → {type: moveHead, value: 1}
|
// > → {type: moveHead, value: 1}
|
||||||
const moveHead = Symbol('moveHead');
|
const moveHead = Symbol('moveHead');
|
||||||
// . → {type: writeByte}
|
// . → {type: writeByte}
|
||||||
|
// Can have offset property
|
||||||
const writeByte = Symbol('writeByte');
|
const writeByte = Symbol('writeByte');
|
||||||
// , → {type: readByte}
|
// , → {type: readByte}
|
||||||
|
// Can have offset property
|
||||||
const readByte = Symbol('readByte');
|
const readByte = Symbol('readByte');
|
||||||
// [-] → {type: loop, contents: [{type: add, value: -1}]}
|
// [-] → {type: loop, contents: [{type: add, value: -1}]}
|
||||||
|
// Can have isBalanced property
|
||||||
const loop = Symbol('loop');
|
const loop = Symbol('loop');
|
||||||
|
|
||||||
// [-] → {type: clear}
|
// [-] → {type: clear}
|
||||||
|
// Can have offset property
|
||||||
const clear = Symbol('clear');
|
const clear = Symbol('clear');
|
||||||
|
|
||||||
// TODO: Add extensions from Eldis
|
// TODO: Add extensions from Eldis
|
||||||
|
@ -149,30 +154,45 @@ function parse(program) {
|
||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ([commandObjects]) <io>
|
// ([commandObjects/offsetCommandObjects]) <io>
|
||||||
function prettyPrint(parsed) {
|
function prettyPrint(parsed) {
|
||||||
// ([commandObjects], string) <io>
|
// ([commandObjects/offsetCommandObjects], string) <io>
|
||||||
function printIndented(parsed, indent = '') {
|
function printIndented(parsed, indent = '') {
|
||||||
for(let command of parsed) {
|
for(let command of parsed) {
|
||||||
let line = indent;
|
let line = indent;
|
||||||
if(command.type == add) {
|
if(command.type == add) {
|
||||||
line += `add ${command.value}`;
|
line += `add ${command.value}`;
|
||||||
|
if('offset' in command) {
|
||||||
|
line += ` (${command.offset})`;
|
||||||
|
}
|
||||||
console.log(line);
|
console.log(line);
|
||||||
} else if(command.type == moveHead) {
|
} else if(command.type == moveHead) {
|
||||||
line += `moveHead ${command.value}`;
|
line += `moveHead ${command.value}`;
|
||||||
console.log(line);
|
console.log(line);
|
||||||
} else if(command.type == writeByte) {
|
} else if(command.type == writeByte) {
|
||||||
line += 'writeByte';
|
line += 'writeByte';
|
||||||
|
if('offset' in command) {
|
||||||
|
line += ` (${command.offset})`;
|
||||||
|
}
|
||||||
console.log(line);
|
console.log(line);
|
||||||
} else if(command.type == readByte) {
|
} else if(command.type == readByte) {
|
||||||
line += 'readByte';
|
line += 'readByte';
|
||||||
|
if('offset' in command) {
|
||||||
|
line += ` (${command.offset})`;
|
||||||
|
}
|
||||||
console.log(line);
|
console.log(line);
|
||||||
} else if(command.type == loop) {
|
} else if(command.type == loop) {
|
||||||
line += 'loop';
|
line += 'loop';
|
||||||
|
if('isBalanced' in command) {
|
||||||
|
line += ` (balanced: ${command.isBalanced})`;
|
||||||
|
}
|
||||||
console.log(line);
|
console.log(line);
|
||||||
printIndented(command.contents, indent + ' ');
|
printIndented(command.contents, indent + ' ');
|
||||||
} else if(command.type == clear) {
|
} else if(command.type == clear) {
|
||||||
line += 'clear';
|
line += 'clear';
|
||||||
|
if('offset' in command) {
|
||||||
|
line += ` (${command.offset})`;
|
||||||
|
}
|
||||||
console.log(line);
|
console.log(line);
|
||||||
} else {
|
} else {
|
||||||
line += `unknown ${command.type}`;
|
line += `unknown ${command.type}`;
|
||||||
|
@ -187,6 +207,8 @@ function prettyPrint(parsed) {
|
||||||
// Optimization passes
|
// Optimization passes
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
|
class UnknownIRError extends Error {}
|
||||||
|
|
||||||
// ([commandObjects]) → [commandObjects]
|
// ([commandObjects]) → [commandObjects]
|
||||||
function joinAdjacentOps(parsed) {
|
function joinAdjacentOps(parsed) {
|
||||||
// ([commandObjects], commandType) → [commandObjects]
|
// ([commandObjects], commandType) → [commandObjects]
|
||||||
|
@ -255,9 +277,83 @@ function transformClearLoops(parsed) {
|
||||||
return optimized;
|
return optimized;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ([commandObjects]) → [commandObjects]
|
// ([commandObjects]) → [offsetCommandObjects]
|
||||||
|
function addOffsetProperties(parsed) {
|
||||||
|
// ([commandObjects]) → {offsetted: [offsetCommandObjects], isBalanced: bool}
|
||||||
|
function worker(parsed) {
|
||||||
|
let offsetted = [];
|
||||||
|
let isBalanced = true;
|
||||||
|
let headChange = 0;
|
||||||
|
|
||||||
|
let offset = 0;
|
||||||
|
for(let command of parsed) {
|
||||||
|
if(command.type == add) {
|
||||||
|
offsetted.push({type: add,
|
||||||
|
value: command.value,
|
||||||
|
offset: offset});
|
||||||
|
} else if(command.type == moveHead) {
|
||||||
|
offset += command.value;
|
||||||
|
} else if(command.type == writeByte) {
|
||||||
|
offsetted.push({type: writeByte,
|
||||||
|
offset: offset});
|
||||||
|
} else if(command.type == readByte) {
|
||||||
|
offsetted.push({type: readByte,
|
||||||
|
offset: offset});
|
||||||
|
} else if(command.type == clear) {
|
||||||
|
offsetted.push({type: clear,
|
||||||
|
offset: offset});
|
||||||
|
} else if(command.type == loop) {
|
||||||
|
// A loop should be self-contained
|
||||||
|
// If offset is not 0, add a moveHead
|
||||||
|
if(offset != 0) {
|
||||||
|
offsetted.push({type: moveHead,
|
||||||
|
value: offset});
|
||||||
|
// Mark we've moved the head
|
||||||
|
headChange += offset;
|
||||||
|
}
|
||||||
|
offset = 0;
|
||||||
|
|
||||||
|
// Run optimization on the loop
|
||||||
|
let result = worker(command.contents);
|
||||||
|
// We're only balanced if our loops are
|
||||||
|
isBalanced = isBalanced && result.isBalanced;
|
||||||
|
offsetted.push({type: loop,
|
||||||
|
contents: result.offsetted,
|
||||||
|
isBalanced: result.isBalanced});
|
||||||
|
// headChange's value becomes invalid if the
|
||||||
|
// loop is not balanced. However, we only
|
||||||
|
// care about its value when figuring out
|
||||||
|
// our isBalanced, which will be forced to
|
||||||
|
// false if any inner loop is not balanced
|
||||||
|
} else {
|
||||||
|
throw new UnknownIRError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to move the tape head in the end anyways, so
|
||||||
|
// generate moveHead is offseet is not 0
|
||||||
|
if(offset != 0) {
|
||||||
|
offsetted.push({type: moveHead,
|
||||||
|
value: offset});
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're only balanced if relative to start of the loop ends
|
||||||
|
// up as 0
|
||||||
|
isBalanced = isBalanced && offset + headChange == 0;
|
||||||
|
|
||||||
|
return {offsetted, isBalanced};
|
||||||
|
}
|
||||||
|
|
||||||
|
return worker(parsed).offsetted;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ([commandObjects]) → [offsetCommandObjects]
|
||||||
function optimize(parsed) {
|
function optimize(parsed) {
|
||||||
const optimizations = [joinAdjacentOps, transformClearLoops];
|
const optimizations = [
|
||||||
|
joinAdjacentOps,
|
||||||
|
transformClearLoops,
|
||||||
|
addOffsetProperties
|
||||||
|
]
|
||||||
return optimizations.reduce((IR, optimization) =>
|
return optimizations.reduce((IR, optimization) =>
|
||||||
optimization(IR), parsed);
|
optimization(IR), parsed);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue