snapshot of https://github.com/dream-num/univer.git (dev, 2026-09-16; blobs > 131072B omitted)
Some checks failed
📦 Build / build (push) Has been cancelled
🧪 CI Test / test shard (1/4) (push) Has been cancelled
🧪 CI Test / test shard (2/4) (push) Has been cancelled
🧪 CI Test / test shard (3/4) (push) Has been cancelled
🧪 CI Test / test shard (4/4) (push) Has been cancelled
🧪 CI Test / test (push) Has been cancelled
🧪 CI Test / eslint (push) Has been cancelled
🧪 CI Test / typecheck (push) Has been cancelled
🔫 Sync to Pro / dispatch-sync (push) Has been cancelled
🔮 Sync Mirror / sync (push) Has been cancelled
Some checks failed
📦 Build / build (push) Has been cancelled
🧪 CI Test / test shard (1/4) (push) Has been cancelled
🧪 CI Test / test shard (2/4) (push) Has been cancelled
🧪 CI Test / test shard (3/4) (push) Has been cancelled
🧪 CI Test / test shard (4/4) (push) Has been cancelled
🧪 CI Test / test (push) Has been cancelled
🧪 CI Test / eslint (push) Has been cancelled
🧪 CI Test / typecheck (push) Has been cancelled
🔫 Sync to Pro / dispatch-sync (push) Has been cancelled
🔮 Sync Mirror / sync (push) Has been cancelled
This commit is contained in:
209
packages/engine-formula/src/engine/ast-node/union-node.ts
Normal file
209
packages/engine-formula/src/engine/ast-node/union-node.ts
Normal file
@@ -0,0 +1,209 @@
|
||||
/**
|
||||
* Copyright 2023-present DreamNum Co., Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { FunctionVariantType } from '../reference-object/base-reference-object';
|
||||
import { ErrorType } from '../../basics/error-type';
|
||||
import { matchToken } from '../../basics/token';
|
||||
import { IFormulaCurrentConfigService } from '../../services/current-data.service';
|
||||
import { IFunctionService } from '../../services/function.service';
|
||||
import { LexerNode } from '../analysis/lexer-node';
|
||||
import { BaseReferenceObject } from '../reference-object/base-reference-object';
|
||||
import { MultiAreaArrayMode, MultiAreaReferenceObject } from '../reference-object/multi-area-reference-object';
|
||||
import { RangeReferenceObject } from '../reference-object/range-reference-object';
|
||||
import { getRangeReferenceObjectFromCache } from '../utils/value-object';
|
||||
import { ErrorValueObject } from '../value-object/base-value-object';
|
||||
import { BaseAstNode } from './base-ast-node';
|
||||
import { BaseAstNodeFactory, DEFAULT_AST_NODE_FACTORY_Z_INDEX } from './base-ast-node-factory';
|
||||
import { NODE_ORDER_MAP, NodeType } from './node-type';
|
||||
|
||||
// const UNION_EXECUTOR_NAME = 'UNION';
|
||||
|
||||
export class UnionNode extends BaseAstNode {
|
||||
constructor(
|
||||
operatorString: string,
|
||||
private readonly _currentConfigService: Pick<IFormulaCurrentConfigService, 'getSheetsInfo'>
|
||||
) {
|
||||
super(operatorString);
|
||||
}
|
||||
|
||||
override get nodeType() {
|
||||
return NodeType.UNION;
|
||||
}
|
||||
|
||||
override execute() {
|
||||
const children = this.getChildren();
|
||||
const leftChild = children[0];
|
||||
const rightChild = children[1];
|
||||
const leftNode = leftChild.getValue();
|
||||
const rightNode = rightChild.getValue();
|
||||
|
||||
if (leftNode == null || rightNode == null) {
|
||||
console.error('UnionNode execute leftNode or rightNode is null');
|
||||
this.setValue(ErrorValueObject.create(ErrorType.VALUE));
|
||||
return;
|
||||
}
|
||||
|
||||
let result: FunctionVariantType;
|
||||
if (this.getToken() === matchToken.COLON) {
|
||||
result = this._createThreeDimensionalReference(leftChild.getToken(), rightNode)
|
||||
?? this._unionFunction(leftNode, rightNode);
|
||||
} else {
|
||||
result = ErrorValueObject.create(ErrorType.NAME);
|
||||
}
|
||||
this.setValue(result);
|
||||
}
|
||||
|
||||
private _createThreeDimensionalReference(
|
||||
firstSheetToken: string,
|
||||
rightNode: FunctionVariantType
|
||||
): MultiAreaReferenceObject | undefined {
|
||||
if (!(rightNode instanceof BaseReferenceObject)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const source = rightNode;
|
||||
const firstSheetName = this._normalizeSheetName(firstSheetToken);
|
||||
const lastSheetName = this._normalizeSheetName(source.getForcedSheetName());
|
||||
if (!firstSheetName || !lastSheetName) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { sheetOrder, sheetNameMap } = this._currentConfigService.getSheetsInfo();
|
||||
const sheetIdsByName = new Map(
|
||||
Object.entries(sheetNameMap).map(([sheetId, sheetName]) => [sheetName.toLocaleLowerCase(), sheetId])
|
||||
);
|
||||
const firstSheetId = sheetIdsByName.get(firstSheetName.toLocaleLowerCase());
|
||||
const lastSheetId = sheetIdsByName.get(lastSheetName.toLocaleLowerCase());
|
||||
const firstIndex = firstSheetId == null ? -1 : sheetOrder.indexOf(firstSheetId);
|
||||
const lastIndex = lastSheetId == null ? -1 : sheetOrder.indexOf(lastSheetId);
|
||||
if (firstIndex < 0 || lastIndex < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const startIndex = Math.min(firstIndex, lastIndex);
|
||||
const endIndex = Math.max(firstIndex, lastIndex);
|
||||
const areas = sheetOrder.slice(startIndex, endIndex + 1).map((sheetId) => {
|
||||
const reference = new RangeReferenceObject(source.getRangeData(), sheetId, source.getUnitId());
|
||||
this._copyReferenceContext(source, reference);
|
||||
reference.setForcedSheetIdDirect(sheetId);
|
||||
reference.setForcedSheetName(sheetNameMap[sheetId] ?? '');
|
||||
return [reference];
|
||||
});
|
||||
|
||||
return new MultiAreaReferenceObject(
|
||||
`${firstSheetToken}:${source.getToken()}`,
|
||||
areas,
|
||||
MultiAreaArrayMode.STACK_AREAS
|
||||
);
|
||||
}
|
||||
|
||||
private _normalizeSheetName(token: string): string {
|
||||
const trimmed = token.trim();
|
||||
if (trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
||||
return trimmed.slice(1, -1).replace(/''/g, "'");
|
||||
}
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
private _copyReferenceContext(source: BaseReferenceObject, target: BaseReferenceObject): void {
|
||||
target.setDefaultUnitId(source.getDefaultUnitId());
|
||||
target.setDefaultSheetId(source.getDefaultSheetId());
|
||||
target.setUnitData(source.getUnitData());
|
||||
target.setUnitStylesData(source.getUnitStylesData());
|
||||
target.setFilteredOutRows(source.getFilteredOutRows());
|
||||
target.setRuntimeData(source.getRuntimeData());
|
||||
target.setArrayFormulaCellData(source.getArrayFormulaCellData());
|
||||
target.setArrayFormulaRange(source.getArrayFormulaRange());
|
||||
target.setRuntimeArrayFormulaCellData(source.getRuntimeArrayFormulaCellData());
|
||||
target.setRuntimeArrayFormulaRange(source.getRuntimeArrayFormulaRange());
|
||||
target.setRuntimeFeatureCellData(source.getRuntimeFeatureCellData());
|
||||
|
||||
const currentRow = source.getCurrentRow();
|
||||
const currentColumn = source.getCurrentColumn();
|
||||
if (currentRow != null && currentColumn != null) {
|
||||
target.setCurrentRowAndColumn(currentRow, currentColumn);
|
||||
}
|
||||
|
||||
const { x, y } = source.getRefOffset();
|
||||
target.setRefOffset(x, y);
|
||||
}
|
||||
|
||||
private _unionFunction(
|
||||
variant1: FunctionVariantType,
|
||||
variant2: FunctionVariantType
|
||||
): FunctionVariantType {
|
||||
if (variant1.isError() || variant2.isError()) {
|
||||
return ErrorValueObject.create(ErrorType.REF);
|
||||
}
|
||||
|
||||
if (!(variant1 instanceof BaseReferenceObject) || !(variant2 instanceof BaseReferenceObject)) {
|
||||
return ErrorValueObject.create(ErrorType.REF);
|
||||
}
|
||||
|
||||
return getRangeReferenceObjectFromCache(variant1, variant2);
|
||||
|
||||
// if (variant1.isCell() && variant2.isCell()) {
|
||||
|
||||
// return variant1.unionBy(variant2);
|
||||
// }
|
||||
// if (variant1.isRow() && variant2.isRow()) {
|
||||
// return variant1.unionBy(variant2);
|
||||
// }
|
||||
// if (variant1.isColumn() && variant2.isColumn()) {
|
||||
// return variant1.unionBy(variant2);
|
||||
// }
|
||||
|
||||
// // =A1:A gets #NAME?
|
||||
// return ErrorValueObject.create(ErrorType.NAME);
|
||||
}
|
||||
}
|
||||
|
||||
export class UnionNodeFactory extends BaseAstNodeFactory {
|
||||
constructor(
|
||||
@IFunctionService private readonly _functionService: IFunctionService,
|
||||
@IFormulaCurrentConfigService private readonly _currentConfigService: IFormulaCurrentConfigService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
override get zIndex() {
|
||||
return NODE_ORDER_MAP.get(NodeType.UNION) || DEFAULT_AST_NODE_FACTORY_Z_INDEX;
|
||||
}
|
||||
|
||||
override create(param: string): BaseAstNode {
|
||||
return new UnionNode(param, this._currentConfigService);
|
||||
}
|
||||
|
||||
override checkAndCreateNodeType(param: LexerNode | string) {
|
||||
if (!(param instanceof LexerNode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const token = param.getToken();
|
||||
|
||||
const tokenTrim = token.trim();
|
||||
|
||||
if (tokenTrim.charAt(0) === '"' && tokenTrim.charAt(tokenTrim.length - 1) === '"') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tokenTrim !== matchToken.COLON) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this.create(tokenTrim);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user