From a10b24250fbfad47def48265848fb5853a1ba553 Mon Sep 17 00:00:00 2001 From: SeongChan Lee Date: Sun, 29 Mar 2020 02:32:03 +0900 Subject: [PATCH] Merge `Fn`s --- src/comparer.ts | 88 +++++++++++++++++++++++++++++++++++------------ src/normalizer.ts | 2 +- src/parser.ts | 10 +++--- 3 files changed, 72 insertions(+), 28 deletions(-) diff --git a/src/comparer.ts b/src/comparer.ts index 46456cb..5a48706 100644 --- a/src/comparer.ts +++ b/src/comparer.ts @@ -82,20 +82,46 @@ function compareType(a: Type, b: Type): number { } function compareTypePath(a: TypePath, b: TypePath): number { - if (a.path < b.path) { + if ("path" in a && "path" in b) { + if (a.path < b.path) { + return -1; + } else if (a.path > b.path) { + return 1; + } + const genericArgsA = a.genericArgs ?? []; + const genericArgsB = b.genericArgs ?? []; + const typeBeginA = genericArgsA.findIndex(x => typeof x !== "string"); + const typeBeginB = genericArgsB.findIndex(x => typeof x !== "string"); + + return compareArray( + genericArgsA.slice(typeBeginA) as Type[], + genericArgsB.slice(typeBeginB) as Type[], + compareType); + } else if ("fn" in a && "fn" in b) { + const fn = defaultCompare(a.fn, b.fn); + if (fn !== 0) { + return fn; + } + const modifiers = defaultCompare(a.modifiers, b.modifiers); + if (modifiers !== 0) { + return modifiers; + } + const inputs = compareArray(a.inputs, b.inputs, compareType); + if (inputs !== 0){ + return inputs + } + if (a.return !== null && b.return !== null) { + return compareType(a.return, b.return); + } else if (a.return != null) { + return -1; + } else { + return 1; + } + } else if ("path" in a) { return -1; - } else if (a.path > b.path) { + } else { return 1; } - const genericArgsA = a.genericArgs ?? []; - const genericArgsB = b.genericArgs ?? []; - const typeBeginA = genericArgsA.findIndex(x => typeof x !== "string"); - const typeBeginB = genericArgsB.findIndex(x => typeof x !== "string"); - - return compareArray( - genericArgsA.slice(typeBeginA) as Type[], - genericArgsB.slice(typeBeginB) as Type[], - compareType); } export function compareTypeParamBound(a: TypeParamBound, b: TypeParamBound): number { @@ -132,6 +158,9 @@ function includesArray(a: T[], b: T[], include: (lhs: T, rhs: T) => boolean): // a includes b export function includes(implA: NormalizedImpl, implB: NormalizedImpl): boolean { function includesType(a: Type, b: Type): boolean { + if (!a.name) { + console.log(a["name"], b["name"]); + } const nameOrd = a.name.localeCompare(b.name); if (nameOrd !== 0) { return false; @@ -188,18 +217,33 @@ export function includes(implA: NormalizedImpl, implB: NormalizedImpl): boolean } function includesTypePath(a: TypePath, b: TypePath): boolean { - if (a.path != b.path) { - return false; - } - const genericArgsA = a.genericArgs ?? []; - const genericArgsB = b.genericArgs ?? []; - const typeBeginA = genericArgsA.findIndex(x => typeof x !== "string"); - const typeBeginB = genericArgsB.findIndex(x => typeof x !== "string"); + if ("path" in a && "path" in b) { + if (a.path != b.path) { + return false; + } + const genericArgsA = a.genericArgs ?? []; + const genericArgsB = b.genericArgs ?? []; + const typeBeginA = genericArgsA.findIndex(x => typeof x !== "string"); + const typeBeginB = genericArgsB.findIndex(x => typeof x !== "string"); - return includesArray( - genericArgsA.slice(typeBeginA) as Type[], - genericArgsB.slice(typeBeginB) as Type[], - includesType); + return includesArray( + genericArgsA.slice(typeBeginA) as Type[], + genericArgsB.slice(typeBeginB) as Type[], + includesType); + } else if ("fn" in a && "fn" in b) { + if (a.fn != b.fn || a.modifiers != b.modifiers) { + return false; + } + if (!includesArray(a.inputs, b.inputs, includesType)) { + return false; + } + if (a.return == null && b.return == null) { + return true; + } else if (a.return !== null && b.return !== null) { + return includesType(a.return, b.return); + } + } + return false; } function includesTypeParamBounds(a: TypeParamBound[], b: TypeParamBound[]): boolean { diff --git a/src/normalizer.ts b/src/normalizer.ts index d55e77d..e88af1a 100644 --- a/src/normalizer.ts +++ b/src/normalizer.ts @@ -39,7 +39,7 @@ export function normalizeImpl(impl: Impl): NormalizedImpl { } function rewriteTypePath(typePath: TypePath): TypePath { - if (typePath.path in paramRewrite) { + if ("path" in typePath && typePath.path in paramRewrite) { return { path: paramRewrite[typePath.path], genericArgs: typePath.genericArgs ? typePath.genericArgs.map(x => typeof x === "string" ? x : rewriteType(x)) : null, diff --git a/src/parser.ts b/src/parser.ts index 8b54134..1ec02bb 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -66,8 +66,8 @@ export type TypeParamBound = LifetimeBound | TraitBound; export type LifetimeBound = string; export type TraitBound = { optional: boolean; typePath: TypePath }; -export type Path = TypePath | FnPath; -export type TypePath = { +export type TypePath = Path | FnPath; +export type Path = { path: string; genericArgs: GenericArg[] | null; }; @@ -146,7 +146,7 @@ export const SimplifiedImpl = P.createLanguage({ LifetimeBounds: (r): P.Parser => r.Lifetime.sepBy1(T("+")), TypePath: r => - P.alt( + P.alt( P.seqObj( [ "modifiers", @@ -156,9 +156,9 @@ export const SimplifiedImpl = P.createLanguage({ ], ["fn", r.TypePathSegments.lookahead(T("("))], ["inputs", Paren(CommaSep(r.Type))], - ["return", Optional(P.seq(T("->"), r.Type))] + ["return", Optional(T("->").then(r.Type))] ), - P.seqObj(["path", r.TypePathSegments], ["genericArgs", Optional(r.GenericArgs)]) + P.seqObj(["path", r.TypePathSegments], ["genericArgs", Optional(r.GenericArgs)]) ), TypePathSegments: r => r.Identifier.sepBy1(T("::")).map(x => x.join("::")), GenericArgs: r =>