diff --git a/README.md b/README.md index c49f748..54ee23b 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,6 @@ TODO ### gir.js * Make VM and transformMultiplyLoops use a Proxied object that gives out 0 for nonexistent elements for tape and allows using [] interface -* Keep a cache of compiled programs in `ircbotRun()` * Support for other types of EOF? ### gir.html diff --git a/gir.js b/gir.js index 7241402..1532938 100644 --- a/gir.js +++ b/gir.js @@ -928,10 +928,64 @@ function compile(program, enableExtensions = true) { return optimize(parse(program, enableExtensions)); } +const programCacheSize = 16; +// string → {compiled: [flatCommandObjects], extensions: bool} +let programCache = new Map(); + +// (string, bool) → [flatCommandObjects] +function cachedCompile(program, enableExtensions = true) { + function compileToCache() { + console.log('compile'); //debg + // Are we already in the cache? If yes, drop the old one, + // since something must have been changed if we're called + if(programCache.has(program)) { + programCache.delete(program); + } + + let compiled = compile(program, enableExtensions); + programCache.set(program, {compiled: compiled, + extensions: enableExtensions}); + + // Are we over the cache size? If yes, drop the least + // recently added + if(programCache.size > programCacheSize) { + console.log('delete'); + // .keys() gives them in insertion order. Since + // there isn't a nice way to extract a thing out + // of an iterator, use a for loop and break out + // after first round + for(let leastRecentlyUsed of programCache.keys()) { + programCache.delete(leastRecentlyUsed); + break; + } + } + } + + if(programCache.has(program)) { + // There is a compiled version of this program + let {compiled, extensions} = programCache.get(program); + + // If extensions enabled state is the same as ours, we can + // just update the useOrder and return this + // If not, we need to compile a new program + if(extensions == enableExtensions) { + return compiled; + } else { + compileToCache(); + let {compiled} = programCache.get(program); + return compiled; + } + } else { + compileToCache(); + let {compiled} = programCache.get(program); + return compiled; + } +} + // (string, string, int) → string function ircbotRun(program, input, maxCycles = 400000) { // TODO; Cache programs - let compiled = compile(program); + let compiled = cachedCompile(program); let vm = newVM(compiled, encodeUTF8(input)); let result = runVM(vm, maxCycles);