Implement some basic cache program generation (#4840)

Implement some basic cache program generation

A bit ago, @jessfraz added the ability to control reexecution from the
executor. When we did this, it used the digest to determine if there
was a code change rather than a non-code change (whitespace, comment,
etc).

This allows the creation of a new program to be run without clearing the
scene. This, in conjunction with being able to delete Engine objects by
ID will allow us to do some clever stuff when incrementally executing
a program.

I'm still working on something a bit more advanced, but a good first
step to derisk some of the caching behavior here fully is to implement a
basic "changed program" stub.

This process the ast programs (old and new) if it doesn't exactly match.
This would have been a complete refresh before this commit.

 1) Check all overlapping top-level statements of the body of the new and
    old AST and ensure they all match.
      - If this is true, this means that one of the two AST programs has more
        elements then the other, and they all otherwise match (addition or
        deletion of the end of the program). We continue to #2 in this
        case.
      - If this is false, we have a meaingful difference in a section of
        overlapping code. This will result in a cache miss and rebuild
        the scene. We short-cut here and the scene is rebuilt.

 2) Check the lengths of the two bodies.
   - If they're the same, we shouldn't have even been called. We will
     short-cut with a noop cache return (no clear, no program).
   - if the old ast is longer, we've removed instructions from the
     program. We can't delete things now, so this will result in a cache
     miss and rebuild the scene. We short-cut here and the scene is
     rebuilt.
   - If the new ast is longer, we have an insertion of code at the end.

 3) construct a new program using only the new elements from the new
    ast, and return a `CacheResult` that *does not clear the scene*.
    This means nothing will be rebuilt, and only a new object will polp
    onto the scene. This is the first case where we diverge with
    existing behavior.

Signed-off-by: Paul R. Tagliamonte <paul@zoo.dev>
This commit is contained in:
Paul Tagliamonte
2024-12-19 16:18:35 -05:00
committed by GitHub
parent 63a3bc7bc6
commit d535a2862d
2 changed files with 137 additions and 8 deletions

View File

@ -76,7 +76,7 @@ test.describe('Editor tests', () => {
await u.openDebugPanel()
await expect(
page.locator('[data-receive-command-type="scene_clear_all"]')
).toHaveCount(2)
).toHaveCount(1)
await expect(
page.locator('[data-message-type="execution-done"]')
).toHaveCount(2)
@ -100,7 +100,60 @@ test.describe('Editor tests', () => {
).toHaveCount(3)
await expect(
page.locator('[data-receive-command-type="scene_clear_all"]')
).toHaveCount(1)
})
test('ensure we use the cache, and do not clear on append', async ({
homePage,
page,
}) => {
const u = await getUtils(page)
await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene()
await u.waitForPageLoad()
await u.codeLocator.click()
await page.keyboard.type(`sketch001 = startSketchOn('XY')
|> startProfileAt([-10, -10], %)
|> line([20, 0], %)
|> line([0, 20], %)
|> line([-20, 0], %)
|> close(%)`)
// Ensure we execute the first time.
await u.openDebugPanel()
await expect(
page.locator('[data-receive-command-type="scene_clear_all"]')
).toHaveCount(1)
await expect(
page.locator('[data-message-type="execution-done"]')
).toHaveCount(2)
// Add whitespace to the end of the code.
await u.codeLocator.click()
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('End')
await page.keyboard.press('Enter')
await page.keyboard.press('Enter')
await page.keyboard.type('const x = 1')
await page.keyboard.press('Enter')
await u.openDebugPanel()
await expect(
page.locator('[data-message-type="execution-done"]')
).toHaveCount(3)
await expect(
page.locator('[data-receive-command-type="scene_clear_all"]')
).toHaveCount(1)
})
test('if you click the format button it formats your code', async ({