import { containsConstruct, findFirstConstruct } from "./analysis"; import { DiscriminateUnion } from "../util/util"; import { CPPConstruct } from "../core/constructs/CPPConstruct"; import { AnalyticDeclaration, AnalyticTypedDeclaration } from "../core/constructs/declarations/analytics"; import { BaseSpecifier } from "../core/constructs/declarations/class/BaseSpecifier"; import { FunctionDefinition } from "../core/constructs/declarations/function/FunctionDefinition"; import { StorageSpecifier } from "../core/constructs/declarations/StorageSpecifier"; import { TypeSpecifier } from "../core/constructs/declarations/TypeSpecifier"; import { GlobalVariableDefinition } from "../core/constructs/declarations/variable/GlobalVariableDefinition"; import { LocalVariableDefinition } from "../core/constructs/declarations/variable/LocalVariableDefinition"; import { VariableEntity } from "../core/compilation/entities"; import { Expression, TypedExpression, ValueCategory } from "../core/constructs/expressions/Expression"; import { AnalyticExpression, AnalyticTypedExpression } from "../core/constructs/expressions/expressions"; import { t_OverloadableOperators } from "../core/constructs/expressions/selectOperatorOverload"; import { OperatorOverloadExpression } from "../core/constructs/expressions/OperatorOverloadExpression"; import { ImplicitConversion } from "../core/constructs/expressions/ImplicitConversion"; import { NumericLiteralExpression } from "../core/constructs/expressions/NumericLiteralExpression"; import { IdentifierExpression } from "../core/constructs/expressions/IdentifierExpression"; import { PostfixIncrementExpression } from "../core/constructs/expressions/PostfixIncrementExpression"; import { ArrowExpression } from "../core/constructs/expressions/ArrowExpression"; import { DotExpression } from "../core/constructs/expressions/DotExpression"; import { SubscriptExpression } from "../core/constructs/expressions/SubscriptExpression"; import { PrefixIncrementExpression } from "../core/constructs/expressions/PrefixIncrementExpression"; import { CompoundAssignmentExpression } from "../core/constructs/expressions/CompoundAssignmentExpression"; import { AssignmentExpression } from "../core/constructs/expressions/AssignmentExpression"; import { FunctionCall } from "../core/constructs/FunctionCall"; import { FunctionCallExpression } from "../core/constructs/expressions/FunctionCallExpression"; import { GlobalObjectAllocator } from "../core/constructs/GlobalObjectAllocator"; import { CtorInitializer } from "../core/constructs/initializers/CtorInitializer"; import { AtomicDirectInitializer } from "../core/constructs/initializers/DirectInitializer"; import { ObjectDeallocator } from "../core/constructs/ObjectDeallocator"; import { AnalyticStatement } from "../core/constructs/statements/statements"; import { TemporaryDeallocator } from "../core/constructs/TemporaryDeallocator"; import { ExpressionType, Type } from "../core/compilation/types"; import { AnalyticInitializer } from "../core/constructs/initializers/initializers"; export type ConstructKind = Cs["construct_type"]; export type AnalyticConstruct = AnalyticDeclaration | TypeSpecifier | StorageSpecifier | AnalyticExpression | AnalyticStatement | GlobalObjectAllocator | ObjectDeallocator | TemporaryDeallocator | BaseSpecifier | FunctionCall | AnalyticInitializer | CtorInitializer; // type TypedKinds = TypedDeclarationKinds & TypedExpressionKinds; // export type AnalyticTyped = // C extends AnalyticDeclaration ? AnalyticTypedDeclaration : // C extends AnalyticExpression ? AnalyticTypedExpression : never; // // export type AnalyticCompiledDeclaration = CompiledDeclarationKinds[C["construct_type"]]; // export type AnalyticCompiled = // C extends AnalyticDeclaration ? AnalyticCompiledDeclaration : // C extends AnalyticExpression ? AnalyticCompiledExpression : never; // let x!: AnalyticTyped, Bool>; export namespace Predicates { // export function compiled(typePredicate?: (o: Type) => o is T) { // return >(decl: Original) => // decl is (Narrowed extends Original ? Narrowed : never)> // ((decl) => typed(typePredicate) && decl.isSuccessfullyCompiled()); // } // export function byKind // (decl: Original) : decl is Narrowed extends Original ? Narrowed : never { // return decl instanceof SimpleDeclaration; // } export function byKind>(constructKind: NarrowedKind) { return >(construct: Original) => construct is (Narrowed extends Original ? Narrowed : never)> ((construct) => construct.construct_type === constructKind); } export function byKinds>(constructKinds: readonly NarrowedKind[]) { return >(construct: Original) => construct is (Narrowed extends Original ? Narrowed : never)> ((construct) => (constructKinds).indexOf(construct.construct_type) !== -1); } // export function isTyped[Original["construct_type"]]> // (decl: Original, typePredicate?: (o: Type) => o is NarrowedT) : decl is (Narrowed extends Original ? Narrowed : never) { // return !!decl.type && (!typePredicate || typePredicate(decl.type)); // } export function byTypedExpression(typePredicate?: (o: ExpressionType) => o is NarrowedT, valueCategory?: NarrowedVC) { return : never)>(construct: Original) => construct is (Narrowed extends Original ? Narrowed : never)> // TODO conditional on this line can probably be removed ((construct) => construct.type && (!typePredicate || typePredicate(construct.type)) && (!valueCategory || construct.valueCategory === valueCategory)); } export function isTypedExpression, Narrowed extends (Original extends AnalyticExpression ? AnalyticTypedExpression : never)> (construct: Original, typePredicate?: (o: ExpressionType) => o is NarrowedT, valueCategory?: NarrowedVC) : construct is (Narrowed extends Original ? Narrowed : Original extends Narrowed ? Original : never); export function isTypedExpression, Narrowed extends (Original extends Expression ? TypedExpression : never)> (construct: Original, typePredicate: (o: ExpressionType) => o is NarrowedT, valueCategory?: NarrowedVC) : construct is (Narrowed extends Original ? Narrowed : Original extends Narrowed ? Original : never); export function isTypedExpression, Narrowed extends (Original extends AnalyticExpression ? AnalyticTypedExpression : never)> (construct: Original, typePredicate?: (o: ExpressionType) => o is NarrowedT, valueCategory?: NarrowedVC) : construct is (Narrowed extends Original ? Narrowed : Original extends Narrowed ? Original : never) { return !!(construct.type && (!typePredicate || typePredicate(construct.type)) && (!valueCategory || construct.valueCategory === valueCategory)); } // Basically copies of above but with Declaration swapping in for Expression and ValueCategory removed export function byTypedDeclaration(typePredicate?: (o: Type) => o is NarrowedT) { return : never)>(construct: Original) => construct is (Narrowed extends Original ? Narrowed : never)> // TODO conditional on this line can probably be removed ((construct) => construct.type && (!typePredicate || typePredicate(construct.type))); } export function isTypedDeclaration : never)> (construct: Original, typePredicate?: (o: Type) => o is NarrowedT) : construct is (Narrowed extends Original ? Narrowed : never) { // TODO conditional on this line can probably be removed return !!(construct.type && (!typePredicate || typePredicate(construct.type))); } export function byVariableName(name: string) { return <(construct: AnalyticConstruct) => construct is (LocalVariableDefinition | GlobalVariableDefinition)> ((construct) => (construct.construct_type === "local_variable_definition" || construct.construct_type === "global_variable_definition") && construct.name === name); } export function byVariableInitialValue(queryValue: number) { return <(construct: AnalyticConstruct) => construct is (LocalVariableDefinition | GlobalVariableDefinition)> ((construct) => { if (! (construct.construct_type === "local_variable_definition" || construct.construct_type === "global_variable_definition")) { return false; } let init = construct.initializer; if (! (init.construct_type === "AtomicDirectInitializer")) { return false; } let expr = init.arg; while (expr.construct_type === "ImplicitConversion") { expr = expr.from; } return expr.construct_type === "numeric_literal_expression" && expr.value.rawEquals(queryValue); }); } // TODO: add compound assignment expressions once implemented export function byVariableUpdate(name: string) { return <(construct: AnalyticConstruct) => construct is (AssignmentExpression | PrefixIncrementExpression | PostfixIncrementExpression)> ((construct) => { if (Predicates.byKinds([ "prefix_increment_expression", "postfix_increment_expression" ])(construct)) { // check for var return !! findFirstConstruct(construct, Predicates.byIdentifierName(name)); } if (Predicates.byKind("assignment_expression")(construct)) { // check for var on lhs and rhs return !! findFirstConstruct(construct.lhs, Predicates.byIdentifierName(name)) && !! findFirstConstruct(construct.rhs, Predicates.byIdentifierName(name)); } return false; }); } export function byFunctionName(name: string) { return <(construct: AnalyticConstruct) => construct is FunctionDefinition> ((construct) => (construct.construct_type === "function_definition") && construct.name === name); } export function byFunctionCallName(name: N) { return <(construct: AnalyticConstruct) => construct is FunctionCallExpression & {call: FunctionCall}> ((construct) => (construct.construct_type === "function_call_expression") && construct.call?.func.name === name); } export function byOperatorOverloadCall(operator: t_OverloadableOperators) { return <(construct: AnalyticConstruct) => construct is OperatorOverloadExpression> ((construct) => isOperatorOverload(construct) && construct.operator === operator); } export function byIdentifierName(name: N) { return <(construct: AnalyticConstruct) => construct is IdentifierExpression & {name: N}> ((construct) => (construct.construct_type === "identifier_expression") && construct.name === name); } export function byVariableIdentifier(v: VE) { return <(construct: AnalyticConstruct) => construct is IdentifierExpression & {entity: VE}> ((construct) => (construct.construct_type === "identifier_expression") && construct.entity === v); } export function byVariableAssignedTo(v: VE) { return <(construct: AnalyticConstruct) => construct is AssignmentExpression | CompoundAssignmentExpression> ((construct) => (construct.construct_type === "assignment_expression" || construct.construct_type === "compound_assignment_expression") && containsConstruct(construct.lhs, Predicates.byVariableIdentifier(v)) ); } export function byVariableIncremented(v: VE) { return <(construct: AnalyticConstruct) => construct is PrefixIncrementExpression | PostfixIncrementExpression> ((construct) => (construct.construct_type === "prefix_increment_expression" || construct.construct_type === "postfix_increment_expression") && containsConstruct(construct.operand, Predicates.byVariableIdentifier(v)) ); } export function byMemberAccessName(memberName: N) { return <(construct: AnalyticConstruct) => construct is DotExpression | ArrowExpression & {memberName: N}> ((construct) => (construct.construct_type === "dot_expression" || construct.construct_type === "arrow_expression") && construct.memberName === memberName); } // export function byCompiled(construct: Original) : construct is AnalyticCompiledDeclaration { // return construct.isSuccessfullyCompiled(); // } export const isLoop = Predicates.byKinds(["while_statement", "for_statement"]); export const isOperatorOverload = Predicates.byKinds(["non_member_operator_overload_expression", "member_operator_overload_expression", "invalid_operator_overload_expression"]); export function isIndexingOperation(construct: AnalyticConstruct) : construct is SubscriptExpression | OperatorOverloadExpression { return Predicates.byKind("subscript_expression")(construct) || Predicates.byOperatorOverloadCall("[]")(construct); } export const isBinaryOperatorExpression = Predicates.byKinds([ "arithmetic_binary_operator_expression", "relational_binary_operator_expression", "logical_binary_operator_expression" ]); }