import type { AnalyticConstruct } from "../../../analysis/predicates"; import { ExpressionASTNode } from "../../../ast/ast_expressions"; import { ExpressionOutlet } from "../../../view/constructs/ExpressionOutlets"; import { ConstructOutlet } from "../../../view/constructs/ConstructOutlet"; import { areAllSemanticallyEquivalent, ConstructDescription, ExpressionContext, SemanticContext } from "../../compilation/contexts"; import { FunctionEntity } from "../../compilation/entities"; import { AtomicType, CompleteObjectType, ExpressionType, FunctionType, Type } from "../../compilation/types"; import { CPPObject } from "../../runtime/objects"; import { Value } from "../../runtime/Value"; import { CPPConstruct, SuccessfullyCompiled } from "../CPPConstruct"; import { PotentialFullExpression } from "../PotentialFullExpression"; import { CompiledTemporaryDeallocator } from "../TemporaryDeallocator"; import { AnalyticExpression } from "./expressions"; import { StringLiteralExpression } from "./StringLiteralExpression"; export type ValueCategory = "prvalue" | "lvalue"; export abstract class Expression extends PotentialFullExpression { public readonly t_analytic!: AnalyticExpression; public abstract readonly type?: ExpressionType; public abstract readonly valueCategory?: ValueCategory; public readonly conversionLength: number = 0; public readonly foo?: string; protected constructor(context: ExpressionContext, ast: ASTType | undefined) { super(context, ast); } // public abstract createRuntimeExpression(this: CompiledExpression, parent: RuntimeConstruct) : RuntimeExpression; public abstract createDefaultOutlet(this: CompiledExpression, element: JQuery, parent?: ConstructOutlet): ExpressionOutlet; public isWellTyped(): this is TypedExpression { return !!this.type && !!this.valueCategory; } public isPrvalue(this: TypedExpression): this is TypedExpression { return this.valueCategory === "prvalue"; } public isLvalue(this: TypedExpression): this is TypedExpression { return this.valueCategory === "lvalue"; } public isStringLiteralExpression(): this is StringLiteralExpression { return false; } // public isSuccessfullyCompiled() : this is Compiled { // return !this.hasErrors; // } public isTailChild(child: CPPConstruct) { return { isTail: false }; } public abstract describeEvalResult(depth: number): ConstructDescription; public analytic() : AnalyticExpression { return this; } public isSemanticallyEquivalent_impl(other: AnalyticConstruct, ec: SemanticContext): boolean { return other.construct_type === this.construct_type && areAllSemanticallyEquivalent(this.children, other.children, ec); } } export interface t_TypedExpression { readonly _t_isTyped: never; // workaround for https://github.com/microsoft/TypeScript/issues/40035 } export interface TypedExpression extends Expression { readonly type: T; readonly valueCategory: V; } export interface CompiledExpression extends TypedExpression, SuccessfullyCompiled { readonly temporaryDeallocator?: CompiledTemporaryDeallocator; // to match CompiledPotentialFullExpression structure } export type SpecificCompiledExpression = V extends ValueCategory ? CompiledExpression : never; export interface WellTyped { readonly type: T; readonly valueCategory: V; } export type SpecificTypedExpression = TypedExpression; export function allWellTyped(expressions: Expression[]): expressions is TypedExpression[]; export function allWellTyped(expressions: readonly Expression[]): expressions is readonly TypedExpression[]; export function allWellTyped(expressions: readonly Expression[]): expressions is readonly TypedExpression[] { return expressions.every((expr) => { return expr.isWellTyped(); }); } export function allObjectTyped(expressions: Expression[]): expressions is TypedExpression[]; export function allObjectTyped(expressions: readonly Expression[]): expressions is readonly TypedExpression[]; export function allObjectTyped(expressions: readonly Expression[]): expressions is readonly TypedExpression[] { return expressions.every((expr) => { return expr.isWellTyped() && expr.type!.isCompleteObjectType() }); } export type VCResultTypes = T extends FunctionType ? ( V extends "prvalue" ? never : V extends "xvalue" ? never : FunctionEntity // lvalue ) : T extends AtomicType ? ( V extends "prvalue" ? Value : V extends "xvalue" ? CPPObject : CPPObject // lvalue ) : T extends CompleteObjectType ? ( // e.g. If T is actually ObjectType, then it could be an AtomicType and we go with the first option Value | CPPObject. // However, if T is actually ClassType, then it can't be an AtomicType and we go with the second option of only CPPObject V extends "prvalue" ? (AtomicType extends T ? Value | CPPObject : CPPObject) : V extends "xvalue" ? CPPObject : CPPObject // lvalue ) : /*ObjectType extends T ?*/ ( // That is, T is more general, so it's possible T is an AtomicType or an ObjectType V extends "prvalue" ? Value | CPPObject : V extends "xvalue" ? CPPObject : CPPObject // lvalue )