@suss/resolution 0.30.0 → 0.31.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +997 -70
- package/dist/index.d.cts +216 -21
- package/dist/index.d.ts +216 -21
- package/dist/index.js +985 -70
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -312,6 +312,62 @@ interface SpannedNode<N> {
|
|
|
312
312
|
*/
|
|
313
313
|
declare function nodeOfKey<N extends SpannedNode<N>>(rootsByFile: ReadonlyMap<string, N>, key: string): N | null;
|
|
314
314
|
|
|
315
|
+
/**
|
|
316
|
+
* packWords.ts: the facts a pack states about its own library.
|
|
317
|
+
*
|
|
318
|
+
* Nothing in a source file says that `Account.find(id)` gives back one
|
|
319
|
+
* Account, or that entering `httpx.Client()` gives back the client it
|
|
320
|
+
* built. The library knows, the pack writes it down, and an adapter puts
|
|
321
|
+
* it in the store. Every adapter did that with a loop of its own, so
|
|
322
|
+
* each new word had to be written three times. `addPackWords` is the one
|
|
323
|
+
* loop; an adapter maps its own pack type onto `PackWords` and calls it.
|
|
324
|
+
*
|
|
325
|
+
* The field names match the fact vocabulary at the top of `index.ts`.
|
|
326
|
+
*/
|
|
327
|
+
|
|
328
|
+
/** A method on a class reaching `base` gives back one of that class. */
|
|
329
|
+
interface GivesBackOne {
|
|
330
|
+
base: string;
|
|
331
|
+
method: string;
|
|
332
|
+
}
|
|
333
|
+
/** The same, for a library that takes the class at position `argument` instead of as the receiver. */
|
|
334
|
+
interface GivesBackOneOfArgument extends GivesBackOne {
|
|
335
|
+
argument: number;
|
|
336
|
+
}
|
|
337
|
+
/** The same again, for the bare function `module` exports under `name`. */
|
|
338
|
+
interface GivesBackOneOfImport {
|
|
339
|
+
module: string;
|
|
340
|
+
name: string;
|
|
341
|
+
argument: number;
|
|
342
|
+
}
|
|
343
|
+
/** Entering one of `module`'s `name` gives back that same object. */
|
|
344
|
+
interface EntersAsSelf {
|
|
345
|
+
module: string;
|
|
346
|
+
name: string;
|
|
347
|
+
}
|
|
348
|
+
/** Calling `callee` out of `module` gives back its argument at `argument`. */
|
|
349
|
+
interface UnwrapsByName {
|
|
350
|
+
callee: string;
|
|
351
|
+
argument: number;
|
|
352
|
+
module: string;
|
|
353
|
+
}
|
|
354
|
+
/** A field given a call of `module`'s `name` declares an association. */
|
|
355
|
+
interface AssociationConstructor {
|
|
356
|
+
module: string;
|
|
357
|
+
name: string;
|
|
358
|
+
}
|
|
359
|
+
/** What a run's packs say about their own libraries, in one language-neutral shape. */
|
|
360
|
+
interface PackWords {
|
|
361
|
+
givesBackOne?: ReadonlyArray<GivesBackOne>;
|
|
362
|
+
givesBackOneOfArgument?: ReadonlyArray<GivesBackOneOfArgument>;
|
|
363
|
+
givesBackOneOfImport?: ReadonlyArray<GivesBackOneOfImport>;
|
|
364
|
+
entersAsSelf?: ReadonlyArray<EntersAsSelf>;
|
|
365
|
+
unwrapsByName?: ReadonlyArray<UnwrapsByName>;
|
|
366
|
+
associationConstructor?: ReadonlyArray<AssociationConstructor>;
|
|
367
|
+
}
|
|
368
|
+
/** Put a run's pack declarations in the store, so the shared rules can read them. */
|
|
369
|
+
declare function addPackWords(db: Database, words: PackWords): void;
|
|
370
|
+
|
|
315
371
|
/**
|
|
316
372
|
* The rules an adapter evaluates, and how a question is put to them.
|
|
317
373
|
*
|
|
@@ -334,11 +390,24 @@ declare const ASKING_RELATIONS: readonly string[];
|
|
|
334
390
|
* reaches it. Built once per language and kept, because the rewrite
|
|
335
391
|
* does not depend on the facts.
|
|
336
392
|
*
|
|
393
|
+
* The questions asked under an allocation site are left out, which
|
|
394
|
+
* drops every rule behind them, so a caller that never mentions a
|
|
395
|
+
* context pays nothing for the second closure.
|
|
396
|
+
*
|
|
337
397
|
* `SUSS_RESOLUTION_ON_DEMAND=0` runs the same rules unrestricted. Both
|
|
338
398
|
* settings give the same answers; they differ in how much never gets
|
|
339
399
|
* derived at all.
|
|
340
400
|
*/
|
|
341
401
|
declare function resolutionProgram(languageRules?: readonly Rule[]): OnDemandRules;
|
|
402
|
+
/**
|
|
403
|
+
* The same rules with the three questions under an allocation site
|
|
404
|
+
* added, which is what `askResolutionUnder` evaluates.
|
|
405
|
+
*
|
|
406
|
+
* Running both programs over one database costs the context-free one
|
|
407
|
+
* its resume state, so a caller with many context-free questions and a
|
|
408
|
+
* few under a site is better off asking the context-free ones first.
|
|
409
|
+
*/
|
|
410
|
+
declare function resolutionUnderProgram(languageRules?: readonly Rule[]): OnDemandRules;
|
|
342
411
|
/**
|
|
343
412
|
* What a caller takes back once it has read an answer: the question and
|
|
344
413
|
* every relation derived under it. Empty when nothing is demand-driven,
|
|
@@ -357,6 +426,59 @@ declare function queryFacts(program: OnDemandRules): readonly string[];
|
|
|
357
426
|
* question, which is how each adapter reads a project.
|
|
358
427
|
*/
|
|
359
428
|
declare function askResolution(db: Database, keys: Iterable<string>, asking?: string, program?: OnDemandRules): void;
|
|
429
|
+
/**
|
|
430
|
+
* How many rows the joins may read for one question under a site.
|
|
431
|
+
*
|
|
432
|
+
* The biggest question a project could answer read 200k rows on the
|
|
433
|
+
* largest public corpus target and 600k on the regression fixtures. A
|
|
434
|
+
* question that cannot be answered walks every node under every context
|
|
435
|
+
* and reads that much per rule, round after round, without settling.
|
|
436
|
+
* The gap is wide enough for thirty times the biggest healthy question,
|
|
437
|
+
* which is a few seconds before the walk is given up on.
|
|
438
|
+
*/
|
|
439
|
+
declare const UNDER_QUESTION_ROW_BUDGET = 20000000;
|
|
440
|
+
/**
|
|
441
|
+
* How many rows the joins may read for every under-question a run asks,
|
|
442
|
+
* together.
|
|
443
|
+
*
|
|
444
|
+
* The per-question budget stops one question walking forever. It says
|
|
445
|
+
* nothing about how many questions a project asks, and a value read
|
|
446
|
+
* under every site of a class built in seventy places is seventy
|
|
447
|
+
* questions, each a fixpoint of its own. Twenty of those at the
|
|
448
|
+
* per-question limit is seven minutes, which is a hang however well
|
|
449
|
+
* each behaved on its own.
|
|
450
|
+
*
|
|
451
|
+
* This is two runaway questions' worth, or sixty-six of the biggest
|
|
452
|
+
* one measured. Past it a run keeps the context-free answer.
|
|
453
|
+
*/
|
|
454
|
+
declare const UNDER_RUN_ROW_BUDGET = 40000000;
|
|
455
|
+
/** Whether a question was worked through, or given up on a budget. */
|
|
456
|
+
type UnderOutcome = "answered" | "abandoned";
|
|
457
|
+
/** What the under-questions of one run have cost it so far. */
|
|
458
|
+
interface UnderSpend {
|
|
459
|
+
rows: number;
|
|
460
|
+
asked: number;
|
|
461
|
+
abandoned: number;
|
|
462
|
+
skipped: number;
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* What the under-questions of this database have cost, for a caller
|
|
466
|
+
* reporting on a run.
|
|
467
|
+
*/
|
|
468
|
+
declare function underQuestionSpend(db: Database): Readonly<UnderSpend>;
|
|
469
|
+
/**
|
|
470
|
+
* `askResolution` for a value read under one allocation site. Each pair
|
|
471
|
+
* is a question of its own, so asking about a value under two sites is
|
|
472
|
+
* two rows, and asking the same pair twice costs nothing.
|
|
473
|
+
*
|
|
474
|
+
* A question that runs past `questionBudget`, or one asked after the
|
|
475
|
+
* run has spent `runBudget` on questions before it, is abandoned: the
|
|
476
|
+
* rows it added come back out, the answer relations stay as empty as
|
|
477
|
+
* they were, and the caller is told so it can keep the context-free
|
|
478
|
+
* answer instead. The pair stays marked as asked either way, so nobody
|
|
479
|
+
* pays for it twice.
|
|
480
|
+
*/
|
|
481
|
+
declare function askResolutionUnder(db: Database, pairs: Iterable<readonly [string, string]>, program?: OnDemandRules, questionBudget?: number, runBudget?: number): UnderOutcome;
|
|
360
482
|
|
|
361
483
|
/**
|
|
362
484
|
* The result shape a why session hands back, shared by every language
|
|
@@ -418,22 +540,58 @@ interface ExplainResolvedKeyOptions {
|
|
|
418
540
|
declare function explainResolvedKey(options: ExplainResolvedKeyOptions): WhyExplained | null;
|
|
419
541
|
|
|
420
542
|
/**
|
|
421
|
-
*
|
|
422
|
-
*
|
|
423
|
-
*
|
|
424
|
-
*
|
|
425
|
-
*
|
|
543
|
+
* What counts as an answer to a question shaped `[key, answer]`, such as
|
|
544
|
+
* `wantedIsWrittenAs` or `wantedSubjectWritten`. A call is written as
|
|
545
|
+
* itself, so a call asked about directly always matches its own key; that
|
|
546
|
+
* row is dropped before the count so one other answer settles it instead
|
|
547
|
+
* of counting as two.
|
|
426
548
|
*
|
|
427
549
|
* A placeholder write, `client = None` before a guard fills it in, is
|
|
428
550
|
* set aside the same way when the key has any other answer. A key
|
|
429
551
|
* written only as a placeholder keeps it.
|
|
552
|
+
*
|
|
553
|
+
* A caller that can only use one answer takes `singleAnswers`; one with
|
|
554
|
+
* something to say about a value written two ways takes `answersByKey`.
|
|
430
555
|
*/
|
|
431
556
|
|
|
432
|
-
/**
|
|
557
|
+
/** Every answer each key has, in the order the rows arrive, with the two drops above applied. */
|
|
558
|
+
declare function answersByKey(rows: Iterable<Tuple>, placeholders?: ReadonlySet<string>): Map<string, string[]>;
|
|
559
|
+
/** The one answer each key settles on, for a caller that treats several as none. */
|
|
433
560
|
declare function singleAnswers(rows: Iterable<Tuple>, placeholders?: ReadonlySet<string>): Map<string, string>;
|
|
434
561
|
/** The keys an adapter marked `placeholderValue`, for passing to `singleAnswers`. */
|
|
435
562
|
declare function placeholderValues(db: Database): ReadonlySet<string>;
|
|
436
563
|
|
|
564
|
+
/**
|
|
565
|
+
* Reading an answer that was asked for under one allocation site.
|
|
566
|
+
*
|
|
567
|
+
* The context-free readers take a key and get everything the rules
|
|
568
|
+
* settled it on. These take a key and a site, and get what the value is
|
|
569
|
+
* when the receiver behind it is the one that site made, so two clients
|
|
570
|
+
* of one class answer apart here and together context-free.
|
|
571
|
+
*
|
|
572
|
+
* Nothing is derived until `askResolutionUnder` has put the pair as a
|
|
573
|
+
* question, the same way the context-free readers need `askResolution`.
|
|
574
|
+
*/
|
|
575
|
+
|
|
576
|
+
/** Every expression the value was written as under this site. */
|
|
577
|
+
declare function isWrittenAsUnder(db: Database, key: string, site: string): string[];
|
|
578
|
+
/** Every function or object the value comes down to under this site. */
|
|
579
|
+
declare function comesToUnder(db: Database, key: string, site: string): string[];
|
|
580
|
+
/** Every object the value refers to under this site, sites included. */
|
|
581
|
+
declare function objectOfUnder(db: Database, key: string, site: string): string[];
|
|
582
|
+
/**
|
|
583
|
+
* The single expression the value was written as under this site, under
|
|
584
|
+
* the policy the context-free reader applies: two answers are ambiguity,
|
|
585
|
+
* and ambiguity is nothing.
|
|
586
|
+
*/
|
|
587
|
+
declare function writtenValueUnder(db: Database, key: string, site: string): string | null;
|
|
588
|
+
/**
|
|
589
|
+
* Every site a class was made at, once `askResolution` has asked
|
|
590
|
+
* `wantedSites` about it. These are the sites to put a value question
|
|
591
|
+
* under.
|
|
592
|
+
*/
|
|
593
|
+
declare function allocationSitesOf(db: Database, cls: string): string[];
|
|
594
|
+
|
|
437
595
|
/**
|
|
438
596
|
* What a name written more than once comes down to.
|
|
439
597
|
*
|
|
@@ -483,13 +641,29 @@ interface NameWrite {
|
|
|
483
641
|
*/
|
|
484
642
|
declare function valueLeftByWrites(writes: readonly NameWrite[], ordered: boolean): string | null;
|
|
485
643
|
|
|
644
|
+
type Ask = (keys: readonly string[]) => void;
|
|
486
645
|
/**
|
|
487
646
|
* The single expression a value was written as, once the caller has
|
|
488
647
|
* asked the rules about `key`. A call to a project function is asked
|
|
489
648
|
* about as well, through `ask`, so the answer is what that function
|
|
490
649
|
* returns rather than the call itself.
|
|
491
650
|
*/
|
|
492
|
-
declare function writtenValueOf(db: Database, key: string, ask:
|
|
651
|
+
declare function writtenValueOf(db: Database, key: string, ask: Ask, relation?: string): string | null;
|
|
652
|
+
/**
|
|
653
|
+
* Every expression a value was written as. More than one is a value with
|
|
654
|
+
* more than one possible source, which a caller says something about at
|
|
655
|
+
* the site rather than reading as the same nothing as a chain that went
|
|
656
|
+
* nowhere.
|
|
657
|
+
*/
|
|
658
|
+
declare function writtenValuesOf(db: Database, key: string, ask: Ask, relation?: string): string[];
|
|
659
|
+
/**
|
|
660
|
+
* The one expression each key was written as, for a caller with several
|
|
661
|
+
* keys at once. Keys the rules settled on nothing, or on more than one
|
|
662
|
+
* expression, are left out. One round of asking covers them all, which
|
|
663
|
+
* is what a caller gets here that a loop over `writtenValueOf` would
|
|
664
|
+
* not.
|
|
665
|
+
*/
|
|
666
|
+
declare function writtenValuesByKey(db: Database, keys: readonly string[], ask: Ask, relation?: string): Map<string, string>;
|
|
493
667
|
|
|
494
668
|
/** A step to the value x is written as. */
|
|
495
669
|
declare const VALUE_STEP: _suss_datalog.Term;
|
|
@@ -501,23 +675,35 @@ declare const VALUE_STEP: _suss_datalog.Term;
|
|
|
501
675
|
*/
|
|
502
676
|
declare const NAMESPACE_IMPORT_NAME = "*";
|
|
503
677
|
declare const NAMESPACE_IMPORT: _suss_datalog.Term;
|
|
678
|
+
/**
|
|
679
|
+
* The label on the `comesFrom` rule for a member read off a whole-module
|
|
680
|
+
* import. `explain` tells that proof from the two import ones by it.
|
|
681
|
+
*/
|
|
682
|
+
declare const NAMESPACE_MEMBER_RULE = "namespace member";
|
|
683
|
+
/**
|
|
684
|
+
* The label on the `contains` rule that walks a class's ancestry.
|
|
685
|
+
* `explain` says a name came from a base class when it fired.
|
|
686
|
+
*/
|
|
687
|
+
declare const BASE_CLASS_RULE = "base class";
|
|
688
|
+
/** A step from an instance to the class it is one of. */
|
|
689
|
+
declare const INSTANCE_STEP: _suss_datalog.Term;
|
|
504
690
|
/** A step to what running the call x is handed back. */
|
|
505
691
|
declare const RESULT_STEP: _suss_datalog.Term;
|
|
692
|
+
/** The context a value read outside every allocation site is read under. */
|
|
693
|
+
declare const NO_CONTEXT_NAME = "none";
|
|
694
|
+
declare const NO_CONTEXT: _suss_datalog.Term;
|
|
506
695
|
/**
|
|
507
|
-
*
|
|
508
|
-
* rules onto these before evaluating.
|
|
509
|
-
*
|
|
510
|
-
* Every construct states its hops once, as `stepsTo(x, y, kind)`, which
|
|
511
|
-
* says x leads to y. A value step goes to the value x is written as, and a
|
|
512
|
-
* result step runs the call x is and goes to what that call handed back.
|
|
513
|
-
* `reaches` is the closure of those steps, and a walk counts as a result
|
|
514
|
-
* walk once it has run a call anywhere along it.
|
|
696
|
+
* Rules with a `stepsTo` twin for each hop among them.
|
|
515
697
|
*
|
|
516
|
-
*
|
|
517
|
-
*
|
|
518
|
-
*
|
|
698
|
+
* `reaches` reads `stepsTo` and `reachesUnder` reads `hop`. A rule
|
|
699
|
+
* passing one through to the other would look tidier and costs far
|
|
700
|
+
* more: the demand for `stepsTo` is one of the largest relations a run
|
|
701
|
+
* derives, and every row of it would be copied into a demand for `hop`
|
|
702
|
+
* whether or not anybody asked about a context. A language that states
|
|
703
|
+
* a hop of its own passes it through here for the same reason.
|
|
519
704
|
*/
|
|
520
|
-
declare
|
|
705
|
+
declare function alsoSteps(rules: readonly Rule[]): Rule[];
|
|
706
|
+
declare const RESOLUTION_RULES: Rule[];
|
|
521
707
|
/**
|
|
522
708
|
* The questions a caller asks, written as rules. Two facts say somebody
|
|
523
709
|
* is asking: `wanted(x)` for what a value is, and `wantedOrigin(x)` for
|
|
@@ -535,8 +721,17 @@ declare const RESOLUTION_RULES: _suss_datalog.Rule[];
|
|
|
535
721
|
* the value's function makes, so a caller that only wants to know what a
|
|
536
722
|
* handler resolves to should not pay for that.
|
|
537
723
|
*/
|
|
538
|
-
declare const RESOLUTION_QUESTIONS:
|
|
724
|
+
declare const RESOLUTION_QUESTIONS: Rule[];
|
|
539
725
|
/** The relations `RESOLUTION_QUESTIONS` answers into. */
|
|
540
726
|
declare const ANSWER_RELATIONS: string[];
|
|
727
|
+
/**
|
|
728
|
+
* The three of those a caller asks under one allocation site.
|
|
729
|
+
*
|
|
730
|
+
* They are listed apart because leaving them out of what a program has
|
|
731
|
+
* to answer drops the whole second closure from it. A run that never
|
|
732
|
+
* mentions a context would otherwise carry a thousand rewritten rules
|
|
733
|
+
* it can never fire, and the engine reads every rule once a round.
|
|
734
|
+
*/
|
|
735
|
+
declare const UNDER_ANSWER_RELATIONS: string[];
|
|
541
736
|
|
|
542
|
-
export { ANSWER_RELATIONS, ASKING_RELATIONS, type CalleeOutcome, type CaseFiles, type ChainReads, type ContractCase, type ContractOptions, type DescribeAtom, type ExplainOptions, type ExplainResolvedKeyOptions, type ExplainStats, FACT_CONTRACT_CASES, type FactsOf, type MountEdge, type MountEdges, NAMESPACE_IMPORT, NAMESPACE_IMPORT_NAME, type NameReads, type NameWrite, type OrderedWrite, RESOLUTION_QUESTIONS, RESOLUTION_RULES, RESULT_STEP, type ReadNode, type ResolutionExplanation, type ResolutionStep, type SpannedNode, type StepContext, type StepPhrase, VALUE_STEP, type ValueLocation, type WhyExplained, agreedMountPrefix, askResolution, calleeOutcomeOf, calleeOutcomes, checkFactContract, couldBeSettled, explainResolutionProof, explainResolvedKey, joinMountedPath, mountPathsOf, nodeOfKey, placeholderValues, queryFacts, renderExplanation, resolutionProgram, singleAnswers, startsAtName, valueLeftByWrites, writesRunInOrder, writtenSourcesOf, writtenValueOf };
|
|
737
|
+
export { ANSWER_RELATIONS, ASKING_RELATIONS, type AssociationConstructor, BASE_CLASS_RULE, type CalleeOutcome, type CaseFiles, type ChainReads, type ContractCase, type ContractOptions, type DescribeAtom, type EntersAsSelf, type ExplainOptions, type ExplainResolvedKeyOptions, type ExplainStats, FACT_CONTRACT_CASES, type FactsOf, type GivesBackOne, type GivesBackOneOfArgument, type GivesBackOneOfImport, INSTANCE_STEP, type MountEdge, type MountEdges, NAMESPACE_IMPORT, NAMESPACE_IMPORT_NAME, NAMESPACE_MEMBER_RULE, NO_CONTEXT, NO_CONTEXT_NAME, type NameReads, type NameWrite, type OrderedWrite, type PackWords, RESOLUTION_QUESTIONS, RESOLUTION_RULES, RESULT_STEP, type ReadNode, type ResolutionExplanation, type ResolutionStep, type SpannedNode, type StepContext, type StepPhrase, UNDER_ANSWER_RELATIONS, UNDER_QUESTION_ROW_BUDGET, UNDER_RUN_ROW_BUDGET, type UnderOutcome, type UnwrapsByName, VALUE_STEP, type ValueLocation, type WhyExplained, addPackWords, agreedMountPrefix, allocationSitesOf, alsoSteps, answersByKey, askResolution, askResolutionUnder, calleeOutcomeOf, calleeOutcomes, checkFactContract, comesToUnder, couldBeSettled, explainResolutionProof, explainResolvedKey, isWrittenAsUnder, joinMountedPath, mountPathsOf, nodeOfKey, objectOfUnder, placeholderValues, queryFacts, renderExplanation, resolutionProgram, resolutionUnderProgram, singleAnswers, startsAtName, underQuestionSpend, valueLeftByWrites, writesRunInOrder, writtenSourcesOf, writtenValueOf, writtenValueUnder, writtenValuesByKey, writtenValuesOf };
|
package/dist/index.d.ts
CHANGED
|
@@ -312,6 +312,62 @@ interface SpannedNode<N> {
|
|
|
312
312
|
*/
|
|
313
313
|
declare function nodeOfKey<N extends SpannedNode<N>>(rootsByFile: ReadonlyMap<string, N>, key: string): N | null;
|
|
314
314
|
|
|
315
|
+
/**
|
|
316
|
+
* packWords.ts: the facts a pack states about its own library.
|
|
317
|
+
*
|
|
318
|
+
* Nothing in a source file says that `Account.find(id)` gives back one
|
|
319
|
+
* Account, or that entering `httpx.Client()` gives back the client it
|
|
320
|
+
* built. The library knows, the pack writes it down, and an adapter puts
|
|
321
|
+
* it in the store. Every adapter did that with a loop of its own, so
|
|
322
|
+
* each new word had to be written three times. `addPackWords` is the one
|
|
323
|
+
* loop; an adapter maps its own pack type onto `PackWords` and calls it.
|
|
324
|
+
*
|
|
325
|
+
* The field names match the fact vocabulary at the top of `index.ts`.
|
|
326
|
+
*/
|
|
327
|
+
|
|
328
|
+
/** A method on a class reaching `base` gives back one of that class. */
|
|
329
|
+
interface GivesBackOne {
|
|
330
|
+
base: string;
|
|
331
|
+
method: string;
|
|
332
|
+
}
|
|
333
|
+
/** The same, for a library that takes the class at position `argument` instead of as the receiver. */
|
|
334
|
+
interface GivesBackOneOfArgument extends GivesBackOne {
|
|
335
|
+
argument: number;
|
|
336
|
+
}
|
|
337
|
+
/** The same again, for the bare function `module` exports under `name`. */
|
|
338
|
+
interface GivesBackOneOfImport {
|
|
339
|
+
module: string;
|
|
340
|
+
name: string;
|
|
341
|
+
argument: number;
|
|
342
|
+
}
|
|
343
|
+
/** Entering one of `module`'s `name` gives back that same object. */
|
|
344
|
+
interface EntersAsSelf {
|
|
345
|
+
module: string;
|
|
346
|
+
name: string;
|
|
347
|
+
}
|
|
348
|
+
/** Calling `callee` out of `module` gives back its argument at `argument`. */
|
|
349
|
+
interface UnwrapsByName {
|
|
350
|
+
callee: string;
|
|
351
|
+
argument: number;
|
|
352
|
+
module: string;
|
|
353
|
+
}
|
|
354
|
+
/** A field given a call of `module`'s `name` declares an association. */
|
|
355
|
+
interface AssociationConstructor {
|
|
356
|
+
module: string;
|
|
357
|
+
name: string;
|
|
358
|
+
}
|
|
359
|
+
/** What a run's packs say about their own libraries, in one language-neutral shape. */
|
|
360
|
+
interface PackWords {
|
|
361
|
+
givesBackOne?: ReadonlyArray<GivesBackOne>;
|
|
362
|
+
givesBackOneOfArgument?: ReadonlyArray<GivesBackOneOfArgument>;
|
|
363
|
+
givesBackOneOfImport?: ReadonlyArray<GivesBackOneOfImport>;
|
|
364
|
+
entersAsSelf?: ReadonlyArray<EntersAsSelf>;
|
|
365
|
+
unwrapsByName?: ReadonlyArray<UnwrapsByName>;
|
|
366
|
+
associationConstructor?: ReadonlyArray<AssociationConstructor>;
|
|
367
|
+
}
|
|
368
|
+
/** Put a run's pack declarations in the store, so the shared rules can read them. */
|
|
369
|
+
declare function addPackWords(db: Database, words: PackWords): void;
|
|
370
|
+
|
|
315
371
|
/**
|
|
316
372
|
* The rules an adapter evaluates, and how a question is put to them.
|
|
317
373
|
*
|
|
@@ -334,11 +390,24 @@ declare const ASKING_RELATIONS: readonly string[];
|
|
|
334
390
|
* reaches it. Built once per language and kept, because the rewrite
|
|
335
391
|
* does not depend on the facts.
|
|
336
392
|
*
|
|
393
|
+
* The questions asked under an allocation site are left out, which
|
|
394
|
+
* drops every rule behind them, so a caller that never mentions a
|
|
395
|
+
* context pays nothing for the second closure.
|
|
396
|
+
*
|
|
337
397
|
* `SUSS_RESOLUTION_ON_DEMAND=0` runs the same rules unrestricted. Both
|
|
338
398
|
* settings give the same answers; they differ in how much never gets
|
|
339
399
|
* derived at all.
|
|
340
400
|
*/
|
|
341
401
|
declare function resolutionProgram(languageRules?: readonly Rule[]): OnDemandRules;
|
|
402
|
+
/**
|
|
403
|
+
* The same rules with the three questions under an allocation site
|
|
404
|
+
* added, which is what `askResolutionUnder` evaluates.
|
|
405
|
+
*
|
|
406
|
+
* Running both programs over one database costs the context-free one
|
|
407
|
+
* its resume state, so a caller with many context-free questions and a
|
|
408
|
+
* few under a site is better off asking the context-free ones first.
|
|
409
|
+
*/
|
|
410
|
+
declare function resolutionUnderProgram(languageRules?: readonly Rule[]): OnDemandRules;
|
|
342
411
|
/**
|
|
343
412
|
* What a caller takes back once it has read an answer: the question and
|
|
344
413
|
* every relation derived under it. Empty when nothing is demand-driven,
|
|
@@ -357,6 +426,59 @@ declare function queryFacts(program: OnDemandRules): readonly string[];
|
|
|
357
426
|
* question, which is how each adapter reads a project.
|
|
358
427
|
*/
|
|
359
428
|
declare function askResolution(db: Database, keys: Iterable<string>, asking?: string, program?: OnDemandRules): void;
|
|
429
|
+
/**
|
|
430
|
+
* How many rows the joins may read for one question under a site.
|
|
431
|
+
*
|
|
432
|
+
* The biggest question a project could answer read 200k rows on the
|
|
433
|
+
* largest public corpus target and 600k on the regression fixtures. A
|
|
434
|
+
* question that cannot be answered walks every node under every context
|
|
435
|
+
* and reads that much per rule, round after round, without settling.
|
|
436
|
+
* The gap is wide enough for thirty times the biggest healthy question,
|
|
437
|
+
* which is a few seconds before the walk is given up on.
|
|
438
|
+
*/
|
|
439
|
+
declare const UNDER_QUESTION_ROW_BUDGET = 20000000;
|
|
440
|
+
/**
|
|
441
|
+
* How many rows the joins may read for every under-question a run asks,
|
|
442
|
+
* together.
|
|
443
|
+
*
|
|
444
|
+
* The per-question budget stops one question walking forever. It says
|
|
445
|
+
* nothing about how many questions a project asks, and a value read
|
|
446
|
+
* under every site of a class built in seventy places is seventy
|
|
447
|
+
* questions, each a fixpoint of its own. Twenty of those at the
|
|
448
|
+
* per-question limit is seven minutes, which is a hang however well
|
|
449
|
+
* each behaved on its own.
|
|
450
|
+
*
|
|
451
|
+
* This is two runaway questions' worth, or sixty-six of the biggest
|
|
452
|
+
* one measured. Past it a run keeps the context-free answer.
|
|
453
|
+
*/
|
|
454
|
+
declare const UNDER_RUN_ROW_BUDGET = 40000000;
|
|
455
|
+
/** Whether a question was worked through, or given up on a budget. */
|
|
456
|
+
type UnderOutcome = "answered" | "abandoned";
|
|
457
|
+
/** What the under-questions of one run have cost it so far. */
|
|
458
|
+
interface UnderSpend {
|
|
459
|
+
rows: number;
|
|
460
|
+
asked: number;
|
|
461
|
+
abandoned: number;
|
|
462
|
+
skipped: number;
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* What the under-questions of this database have cost, for a caller
|
|
466
|
+
* reporting on a run.
|
|
467
|
+
*/
|
|
468
|
+
declare function underQuestionSpend(db: Database): Readonly<UnderSpend>;
|
|
469
|
+
/**
|
|
470
|
+
* `askResolution` for a value read under one allocation site. Each pair
|
|
471
|
+
* is a question of its own, so asking about a value under two sites is
|
|
472
|
+
* two rows, and asking the same pair twice costs nothing.
|
|
473
|
+
*
|
|
474
|
+
* A question that runs past `questionBudget`, or one asked after the
|
|
475
|
+
* run has spent `runBudget` on questions before it, is abandoned: the
|
|
476
|
+
* rows it added come back out, the answer relations stay as empty as
|
|
477
|
+
* they were, and the caller is told so it can keep the context-free
|
|
478
|
+
* answer instead. The pair stays marked as asked either way, so nobody
|
|
479
|
+
* pays for it twice.
|
|
480
|
+
*/
|
|
481
|
+
declare function askResolutionUnder(db: Database, pairs: Iterable<readonly [string, string]>, program?: OnDemandRules, questionBudget?: number, runBudget?: number): UnderOutcome;
|
|
360
482
|
|
|
361
483
|
/**
|
|
362
484
|
* The result shape a why session hands back, shared by every language
|
|
@@ -418,22 +540,58 @@ interface ExplainResolvedKeyOptions {
|
|
|
418
540
|
declare function explainResolvedKey(options: ExplainResolvedKeyOptions): WhyExplained | null;
|
|
419
541
|
|
|
420
542
|
/**
|
|
421
|
-
*
|
|
422
|
-
*
|
|
423
|
-
*
|
|
424
|
-
*
|
|
425
|
-
*
|
|
543
|
+
* What counts as an answer to a question shaped `[key, answer]`, such as
|
|
544
|
+
* `wantedIsWrittenAs` or `wantedSubjectWritten`. A call is written as
|
|
545
|
+
* itself, so a call asked about directly always matches its own key; that
|
|
546
|
+
* row is dropped before the count so one other answer settles it instead
|
|
547
|
+
* of counting as two.
|
|
426
548
|
*
|
|
427
549
|
* A placeholder write, `client = None` before a guard fills it in, is
|
|
428
550
|
* set aside the same way when the key has any other answer. A key
|
|
429
551
|
* written only as a placeholder keeps it.
|
|
552
|
+
*
|
|
553
|
+
* A caller that can only use one answer takes `singleAnswers`; one with
|
|
554
|
+
* something to say about a value written two ways takes `answersByKey`.
|
|
430
555
|
*/
|
|
431
556
|
|
|
432
|
-
/**
|
|
557
|
+
/** Every answer each key has, in the order the rows arrive, with the two drops above applied. */
|
|
558
|
+
declare function answersByKey(rows: Iterable<Tuple>, placeholders?: ReadonlySet<string>): Map<string, string[]>;
|
|
559
|
+
/** The one answer each key settles on, for a caller that treats several as none. */
|
|
433
560
|
declare function singleAnswers(rows: Iterable<Tuple>, placeholders?: ReadonlySet<string>): Map<string, string>;
|
|
434
561
|
/** The keys an adapter marked `placeholderValue`, for passing to `singleAnswers`. */
|
|
435
562
|
declare function placeholderValues(db: Database): ReadonlySet<string>;
|
|
436
563
|
|
|
564
|
+
/**
|
|
565
|
+
* Reading an answer that was asked for under one allocation site.
|
|
566
|
+
*
|
|
567
|
+
* The context-free readers take a key and get everything the rules
|
|
568
|
+
* settled it on. These take a key and a site, and get what the value is
|
|
569
|
+
* when the receiver behind it is the one that site made, so two clients
|
|
570
|
+
* of one class answer apart here and together context-free.
|
|
571
|
+
*
|
|
572
|
+
* Nothing is derived until `askResolutionUnder` has put the pair as a
|
|
573
|
+
* question, the same way the context-free readers need `askResolution`.
|
|
574
|
+
*/
|
|
575
|
+
|
|
576
|
+
/** Every expression the value was written as under this site. */
|
|
577
|
+
declare function isWrittenAsUnder(db: Database, key: string, site: string): string[];
|
|
578
|
+
/** Every function or object the value comes down to under this site. */
|
|
579
|
+
declare function comesToUnder(db: Database, key: string, site: string): string[];
|
|
580
|
+
/** Every object the value refers to under this site, sites included. */
|
|
581
|
+
declare function objectOfUnder(db: Database, key: string, site: string): string[];
|
|
582
|
+
/**
|
|
583
|
+
* The single expression the value was written as under this site, under
|
|
584
|
+
* the policy the context-free reader applies: two answers are ambiguity,
|
|
585
|
+
* and ambiguity is nothing.
|
|
586
|
+
*/
|
|
587
|
+
declare function writtenValueUnder(db: Database, key: string, site: string): string | null;
|
|
588
|
+
/**
|
|
589
|
+
* Every site a class was made at, once `askResolution` has asked
|
|
590
|
+
* `wantedSites` about it. These are the sites to put a value question
|
|
591
|
+
* under.
|
|
592
|
+
*/
|
|
593
|
+
declare function allocationSitesOf(db: Database, cls: string): string[];
|
|
594
|
+
|
|
437
595
|
/**
|
|
438
596
|
* What a name written more than once comes down to.
|
|
439
597
|
*
|
|
@@ -483,13 +641,29 @@ interface NameWrite {
|
|
|
483
641
|
*/
|
|
484
642
|
declare function valueLeftByWrites(writes: readonly NameWrite[], ordered: boolean): string | null;
|
|
485
643
|
|
|
644
|
+
type Ask = (keys: readonly string[]) => void;
|
|
486
645
|
/**
|
|
487
646
|
* The single expression a value was written as, once the caller has
|
|
488
647
|
* asked the rules about `key`. A call to a project function is asked
|
|
489
648
|
* about as well, through `ask`, so the answer is what that function
|
|
490
649
|
* returns rather than the call itself.
|
|
491
650
|
*/
|
|
492
|
-
declare function writtenValueOf(db: Database, key: string, ask:
|
|
651
|
+
declare function writtenValueOf(db: Database, key: string, ask: Ask, relation?: string): string | null;
|
|
652
|
+
/**
|
|
653
|
+
* Every expression a value was written as. More than one is a value with
|
|
654
|
+
* more than one possible source, which a caller says something about at
|
|
655
|
+
* the site rather than reading as the same nothing as a chain that went
|
|
656
|
+
* nowhere.
|
|
657
|
+
*/
|
|
658
|
+
declare function writtenValuesOf(db: Database, key: string, ask: Ask, relation?: string): string[];
|
|
659
|
+
/**
|
|
660
|
+
* The one expression each key was written as, for a caller with several
|
|
661
|
+
* keys at once. Keys the rules settled on nothing, or on more than one
|
|
662
|
+
* expression, are left out. One round of asking covers them all, which
|
|
663
|
+
* is what a caller gets here that a loop over `writtenValueOf` would
|
|
664
|
+
* not.
|
|
665
|
+
*/
|
|
666
|
+
declare function writtenValuesByKey(db: Database, keys: readonly string[], ask: Ask, relation?: string): Map<string, string>;
|
|
493
667
|
|
|
494
668
|
/** A step to the value x is written as. */
|
|
495
669
|
declare const VALUE_STEP: _suss_datalog.Term;
|
|
@@ -501,23 +675,35 @@ declare const VALUE_STEP: _suss_datalog.Term;
|
|
|
501
675
|
*/
|
|
502
676
|
declare const NAMESPACE_IMPORT_NAME = "*";
|
|
503
677
|
declare const NAMESPACE_IMPORT: _suss_datalog.Term;
|
|
678
|
+
/**
|
|
679
|
+
* The label on the `comesFrom` rule for a member read off a whole-module
|
|
680
|
+
* import. `explain` tells that proof from the two import ones by it.
|
|
681
|
+
*/
|
|
682
|
+
declare const NAMESPACE_MEMBER_RULE = "namespace member";
|
|
683
|
+
/**
|
|
684
|
+
* The label on the `contains` rule that walks a class's ancestry.
|
|
685
|
+
* `explain` says a name came from a base class when it fired.
|
|
686
|
+
*/
|
|
687
|
+
declare const BASE_CLASS_RULE = "base class";
|
|
688
|
+
/** A step from an instance to the class it is one of. */
|
|
689
|
+
declare const INSTANCE_STEP: _suss_datalog.Term;
|
|
504
690
|
/** A step to what running the call x is handed back. */
|
|
505
691
|
declare const RESULT_STEP: _suss_datalog.Term;
|
|
692
|
+
/** The context a value read outside every allocation site is read under. */
|
|
693
|
+
declare const NO_CONTEXT_NAME = "none";
|
|
694
|
+
declare const NO_CONTEXT: _suss_datalog.Term;
|
|
506
695
|
/**
|
|
507
|
-
*
|
|
508
|
-
* rules onto these before evaluating.
|
|
509
|
-
*
|
|
510
|
-
* Every construct states its hops once, as `stepsTo(x, y, kind)`, which
|
|
511
|
-
* says x leads to y. A value step goes to the value x is written as, and a
|
|
512
|
-
* result step runs the call x is and goes to what that call handed back.
|
|
513
|
-
* `reaches` is the closure of those steps, and a walk counts as a result
|
|
514
|
-
* walk once it has run a call anywhere along it.
|
|
696
|
+
* Rules with a `stepsTo` twin for each hop among them.
|
|
515
697
|
*
|
|
516
|
-
*
|
|
517
|
-
*
|
|
518
|
-
*
|
|
698
|
+
* `reaches` reads `stepsTo` and `reachesUnder` reads `hop`. A rule
|
|
699
|
+
* passing one through to the other would look tidier and costs far
|
|
700
|
+
* more: the demand for `stepsTo` is one of the largest relations a run
|
|
701
|
+
* derives, and every row of it would be copied into a demand for `hop`
|
|
702
|
+
* whether or not anybody asked about a context. A language that states
|
|
703
|
+
* a hop of its own passes it through here for the same reason.
|
|
519
704
|
*/
|
|
520
|
-
declare
|
|
705
|
+
declare function alsoSteps(rules: readonly Rule[]): Rule[];
|
|
706
|
+
declare const RESOLUTION_RULES: Rule[];
|
|
521
707
|
/**
|
|
522
708
|
* The questions a caller asks, written as rules. Two facts say somebody
|
|
523
709
|
* is asking: `wanted(x)` for what a value is, and `wantedOrigin(x)` for
|
|
@@ -535,8 +721,17 @@ declare const RESOLUTION_RULES: _suss_datalog.Rule[];
|
|
|
535
721
|
* the value's function makes, so a caller that only wants to know what a
|
|
536
722
|
* handler resolves to should not pay for that.
|
|
537
723
|
*/
|
|
538
|
-
declare const RESOLUTION_QUESTIONS:
|
|
724
|
+
declare const RESOLUTION_QUESTIONS: Rule[];
|
|
539
725
|
/** The relations `RESOLUTION_QUESTIONS` answers into. */
|
|
540
726
|
declare const ANSWER_RELATIONS: string[];
|
|
727
|
+
/**
|
|
728
|
+
* The three of those a caller asks under one allocation site.
|
|
729
|
+
*
|
|
730
|
+
* They are listed apart because leaving them out of what a program has
|
|
731
|
+
* to answer drops the whole second closure from it. A run that never
|
|
732
|
+
* mentions a context would otherwise carry a thousand rewritten rules
|
|
733
|
+
* it can never fire, and the engine reads every rule once a round.
|
|
734
|
+
*/
|
|
735
|
+
declare const UNDER_ANSWER_RELATIONS: string[];
|
|
541
736
|
|
|
542
|
-
export { ANSWER_RELATIONS, ASKING_RELATIONS, type CalleeOutcome, type CaseFiles, type ChainReads, type ContractCase, type ContractOptions, type DescribeAtom, type ExplainOptions, type ExplainResolvedKeyOptions, type ExplainStats, FACT_CONTRACT_CASES, type FactsOf, type MountEdge, type MountEdges, NAMESPACE_IMPORT, NAMESPACE_IMPORT_NAME, type NameReads, type NameWrite, type OrderedWrite, RESOLUTION_QUESTIONS, RESOLUTION_RULES, RESULT_STEP, type ReadNode, type ResolutionExplanation, type ResolutionStep, type SpannedNode, type StepContext, type StepPhrase, VALUE_STEP, type ValueLocation, type WhyExplained, agreedMountPrefix, askResolution, calleeOutcomeOf, calleeOutcomes, checkFactContract, couldBeSettled, explainResolutionProof, explainResolvedKey, joinMountedPath, mountPathsOf, nodeOfKey, placeholderValues, queryFacts, renderExplanation, resolutionProgram, singleAnswers, startsAtName, valueLeftByWrites, writesRunInOrder, writtenSourcesOf, writtenValueOf };
|
|
737
|
+
export { ANSWER_RELATIONS, ASKING_RELATIONS, type AssociationConstructor, BASE_CLASS_RULE, type CalleeOutcome, type CaseFiles, type ChainReads, type ContractCase, type ContractOptions, type DescribeAtom, type EntersAsSelf, type ExplainOptions, type ExplainResolvedKeyOptions, type ExplainStats, FACT_CONTRACT_CASES, type FactsOf, type GivesBackOne, type GivesBackOneOfArgument, type GivesBackOneOfImport, INSTANCE_STEP, type MountEdge, type MountEdges, NAMESPACE_IMPORT, NAMESPACE_IMPORT_NAME, NAMESPACE_MEMBER_RULE, NO_CONTEXT, NO_CONTEXT_NAME, type NameReads, type NameWrite, type OrderedWrite, type PackWords, RESOLUTION_QUESTIONS, RESOLUTION_RULES, RESULT_STEP, type ReadNode, type ResolutionExplanation, type ResolutionStep, type SpannedNode, type StepContext, type StepPhrase, UNDER_ANSWER_RELATIONS, UNDER_QUESTION_ROW_BUDGET, UNDER_RUN_ROW_BUDGET, type UnderOutcome, type UnwrapsByName, VALUE_STEP, type ValueLocation, type WhyExplained, addPackWords, agreedMountPrefix, allocationSitesOf, alsoSteps, answersByKey, askResolution, askResolutionUnder, calleeOutcomeOf, calleeOutcomes, checkFactContract, comesToUnder, couldBeSettled, explainResolutionProof, explainResolvedKey, isWrittenAsUnder, joinMountedPath, mountPathsOf, nodeOfKey, objectOfUnder, placeholderValues, queryFacts, renderExplanation, resolutionProgram, resolutionUnderProgram, singleAnswers, startsAtName, underQuestionSpend, valueLeftByWrites, writesRunInOrder, writtenSourcesOf, writtenValueOf, writtenValueUnder, writtenValuesByKey, writtenValuesOf };
|