Skip to content

Commit

Permalink
feat: impl expanding blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
iyxan23 committed Sep 12, 2024
1 parent 69a399d commit 9ef6c7e
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 7 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"sideEffects": false,
"dependencies": {
"@zip.js/zip.js": "^2.7.52",
"deepmerge": "^4.3.1",
"fast-xml-parser": "^4.5.0"
},
"peerDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion src/sheet/expression/extractor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { ExpressionCell, Expression } from "./parser";
// startBlock expressions yet, it's a limitation of the current implementation
// and i don't find myself needing that. so i'm going to leave it as is for now

type Block = {
export type Block = {
identifier: string;
arg: Expression;
indexVariableIdentifier: string;
Expand Down
118 changes: 113 additions & 5 deletions src/sheet/sheet-templater.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type ExpressionCell, parseExpressionCell } from "./expression/parser";
import { extractHoistsAndBlocks } from "./expression/extractor";
import { Block, extractHoistsAndBlocks } from "./expression/extractor";
import { Sheet } from "./sheet";
import { z } from "zod";
import {
Expand All @@ -10,6 +10,7 @@ import {
} from "./expression/evaluate";
import { resultSymbol, success } from "./expression/result";
import { Result } from "./expression/result";
import * as deepmerge from "deepmerge";

interface TemplatableCell {
getTextContent(): string;
Expand Down Expand Up @@ -156,7 +157,6 @@ export class SheetTemplater<SheetT extends TemplatableCell, RowInfo, ColInfo> {
const parsedExpressions = this.parseExpressions();

// stage 1: extract hoists and blocks
// @ts-expect-error
const { variableHoists, blocks } =
extractHoistsAndBlocks(parsedExpressions);

Expand All @@ -167,7 +167,7 @@ export class SheetTemplater<SheetT extends TemplatableCell, RowInfo, ColInfo> {
if (sheetCell === null) {
throw new Error(
`cannot find the cell referenced by variable hoist on` +
` col ${col} row ${row}`,
` col ${col} row ${row}`,
);
}

Expand All @@ -191,6 +191,15 @@ export class SheetTemplater<SheetT extends TemplatableCell, RowInfo, ColInfo> {
globalVariables[expr.identifier] = result.result;
}

// stage 3: block expansion
// @ts-expect-error will be used later
const localVariables = this.expandBlocks(
parsedExpressions,
blocks,
(fName) => this.functions[fName]?.call,
(vName) => globalVariables[vName] ?? data[vName],
);

return {
sym: resultSymbol,
status: "success",
Expand All @@ -199,8 +208,107 @@ export class SheetTemplater<SheetT extends TemplatableCell, RowInfo, ColInfo> {
};
}

// @ts-expect-error will be used later
private evaluateExpression(
private expandBlocks<T>(
sheet: Sheet<T>,
blocks: Block[],
lookupFunction: (
name: string,
) => TemplaterFunction<any>["call"] | undefined,
lookupVariable: (name: string) => any | undefined,
): Result<Record<number, Record<number, Record<string, any>>>> {
const issues: Issue[] = [];
let localVariables: Record<
number,
Record<number, Record<string, any>>
> = {};

for (const block of blocks) {
// expand inner blocks first
const result = this.expandBlocks(
sheet,
block.innerBlocks,
lookupFunction,
lookupVariable,
);

if (result.status === "failed") return result;
issues.push(...result.issues);

localVariables = deepmerge(localVariables, result.result);

const repeatAmountResult = evaluateExpression(
block.arg,
{
col: block.start.col,
row: block.start.row,
callTree: [`${block.identifier} block`],
},
(fName) => lookupFunction(fName),
(vName) => lookupVariable(vName),
);

if (repeatAmountResult.status === "failed") {
return repeatAmountResult;
}

issues.push(...repeatAmountResult.issues);
const repeatAmount = repeatAmountResult.result;

if (block.identifier === "repeatRow") {
for (let i = 0; i < repeatAmount; i++) {
sheet.cloneMapRow({
row: block.start.row,
colStart: block.start.col,
colEnd: block.end.col,
count: repeatAmount,
map: ({ relativeCol, relativeRow, previousData }) => {
const row = block.start.row + relativeRow;
const col = block.start.col + relativeCol;
const ident = block.indexVariableIdentifier;

if (!localVariables[row]) {
localVariables[row] = { [col]: { [ident]: i } };
} else if (!localVariables[row][col]) {
localVariables[row][col] = { [ident]: i };
} else if (!localVariables[row][col][ident]) {
localVariables[row][col][ident] = i;
}

return previousData;
},
});
}
} else if (block.identifier === "repeatCol") {
for (let i = 0; i < repeatAmount; i++) {
sheet.cloneMapCol({
col: block.start.col,
rowStart: block.start.row,
rowEnd: block.end.row,
count: repeatAmount,
map: ({ relativeCol, relativeRow, previousData }) => {
const row = block.start.row + relativeRow;
const col = block.start.col + relativeCol;
const ident = block.indexVariableIdentifier;

if (!localVariables[row]) {
localVariables[row] = { [col]: { [ident]: i } };
} else if (!localVariables[row][col]) {
localVariables[row][col] = { [ident]: i };
} else if (!localVariables[row][col][ident]) {
localVariables[row][col][ident] = i;
}

return previousData;
},
});
}
}
}

return success(localVariables, issues);
}

private evaluateExpressionCell(
cell: ExpressionCell,
sheetCell: SheetT,
{
Expand Down

0 comments on commit 9ef6c7e

Please sign in to comment.