[be][env] Move EnvironmentOptions -> EnvironmentConfig

--- 

Simplify Environment options by: 

- EnvironmentOptions -> EnvironmentConfig 

config is now directly passed around instead of being eagerly merged. 

- Moving merging / initialization logic into `Environment` constructor. From my 
understanding, there is no need to decouple merged options from an environment. 

This prepares Environment for the next PR, which adds non-stateful properties to 
Environment (i.e. a `GlobalRegistry`) that should be converted from config 
values (i.e. not directly exposed to the user due to potentially inconsistent 
inputs)
This commit is contained in:
Mofei Zhang
2023-03-30 15:03:09 -04:00
parent 8e37df6dab
commit 45331ef21b
5 changed files with 35 additions and 50 deletions
+2 -2
View File
@@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import { EnvironmentOptions } from "../HIR/Environment";
import { EnvironmentConfig } from "../HIR/Environment";
export type PluginOptions = {
/**
@@ -13,7 +13,7 @@ export type PluginOptions = {
*/
enableOnlyOnUseForgetDirective: boolean;
environment: Partial<EnvironmentOptions> | null;
environment: EnvironmentConfig | null;
logger: Logger | null;
+5 -5
View File
@@ -12,7 +12,7 @@ import {
mergeConsecutiveBlocks,
ReactiveFunction,
} from "./HIR";
import { EnvironmentOptions, mergeOptions } from "./HIR/Environment";
import { EnvironmentConfig, Environment } from "./HIR/Environment";
import { validateConsistentIdentifiers } from "./HIR/ValidateConsistentIdentifiers";
import {
analyseFunctions,
@@ -51,9 +51,9 @@ export type CompilerPipelineValue =
export function* run(
func: NodePath<t.FunctionDeclaration>,
options?: Partial<EnvironmentOptions> | null
config?: EnvironmentConfig | null
): Generator<CompilerPipelineValue, t.FunctionDeclaration> {
const hir = lower(func, mergeOptions(options ?? null)).unwrap();
const hir = lower(func, new Environment(config ?? null)).unwrap();
yield log({ kind: "hir", name: "HIR", value: hir });
mergeConsecutiveBlocks(hir);
@@ -147,7 +147,7 @@ export function* run(
});
pruneNonEscapingScopes(reactiveFunction, {
memoizeJsxElements: options?.memoizeJsxElements ?? true,
memoizeJsxElements: config?.memoizeJsxElements ?? true,
});
yield log({
kind: "reactive",
@@ -205,7 +205,7 @@ export function* run(
export function compile(
func: NodePath<t.FunctionDeclaration>,
options?: Partial<EnvironmentOptions> | null
options?: Partial<EnvironmentConfig> | null
): t.FunctionDeclaration {
let generator = run(func, options);
while (true) {
+5 -8
View File
@@ -12,7 +12,7 @@ import invariant from "invariant";
import { CompilerError, ErrorSeverity } from "../CompilerError";
import { Err, Ok, Result } from "../Utils/Result";
import { assertExhaustive } from "../Utils/utils";
import { Environment, EnvironmentOptions } from "./Environment";
import { Environment } from "./Environment";
import {
ArrayPattern,
BlockId,
@@ -57,13 +57,11 @@ import HIRBuilder from "./HIRBuilder";
*/
export function lower(
func: NodePath<t.Function>,
options: EnvironmentOptions | null,
env: Environment,
capturedRefs: t.Identifier[] = [],
// the outermost function being compiled, in case lower() is called recursively (for lambdas)
parent: NodePath<t.Function> | null = null,
environment: Environment | null = null
parent: NodePath<t.Function> | null = null
): Result<HIRFunction, CompilerError> {
const env = environment ?? new Environment(options);
const builder = new HIRBuilder(env, parent ?? func, capturedRefs);
const context: Place[] = [];
@@ -2013,10 +2011,9 @@ function lowerFunctionExpression(
// identify the correct references.
const lowering = lower(
expr,
builder.environment.options,
builder.environment,
[...builder.context, ...captured.identifiers],
builder.parentFunction,
builder.environment
builder.parentFunction
);
let loweredFunc: HIRFunction;
if (lowering.isErr()) {
+18 -30
View File
@@ -11,41 +11,29 @@ import {
ValueKind,
} from "./HIR";
import { BUILTIN_HOOKS, Hook } from "./Hooks";
import { BUILTIN_SHAPES, FunctionSignature } from "./ObjectShape";
import {
BUILTIN_SHAPES,
FunctionSignature,
ShapeRegistry,
} from "./ObjectShape";
const HOOK_PATTERN = /^_?use/;
export type EnvironmentOptions = {
export type EnvironmentConfig = Partial<{
customHooks: Map<string, Hook>;
globals: Set<string>;
memoizeJsxElements: boolean;
};
const DEFAULT_OPTIONS: EnvironmentOptions = {
customHooks: new Map(),
globals: DEFAULT_GLOBALS,
memoizeJsxElements: true,
};
export function mergeOptions(
options: Partial<EnvironmentOptions> | null
): EnvironmentOptions {
return {
...DEFAULT_OPTIONS,
...(options ?? {}),
};
}
}>;
export class Environment {
#options: EnvironmentOptions;
#customHooks: Map<string, Hook>;
#globals: Set<string>;
#shapes: ShapeRegistry;
#nextIdentifer: number = 0;
constructor(options: EnvironmentOptions | null) {
this.#options = options ?? DEFAULT_OPTIONS;
}
get options(): EnvironmentOptions {
return this.#options;
constructor(config: EnvironmentConfig | null) {
this.#customHooks = config?.customHooks ?? new Map();
this.#shapes = BUILTIN_SHAPES;
this.#globals = DEFAULT_GLOBALS;
}
get nextIdentifierId(): IdentifierId {
@@ -53,7 +41,7 @@ export class Environment {
}
getGlobalDeclaration(name: string): Global | null {
if (!this.#options.globals.has(name)) {
if (!this.#globals.has(name)) {
log(() => `Undefined global '${name}'`);
}
return { name };
@@ -63,7 +51,7 @@ export class Environment {
if (!name.match(HOOK_PATTERN)) {
return null;
}
const hook = BUILTIN_HOOKS.get(name) ?? this.#options.customHooks.get(name);
const hook = BUILTIN_HOOKS.get(name) ?? this.#customHooks.get(name);
if (hook !== undefined) {
return hook;
}
@@ -83,7 +71,7 @@ export class Environment {
if (shapeId !== null) {
// If an object or function has a shapeId, it must have been assigned
// by Forget (and be present in a builtin or user-defined registry)
const shape = BUILTIN_SHAPES.get(shapeId);
const shape = this.#shapes.get(shapeId);
invariant(
shape !== undefined,
`[HIR] Forget internal error: cannot resolve shape ${shapeId}`
@@ -97,7 +85,7 @@ export class Environment {
getFunctionSignature(type: FunctionType): FunctionSignature | null {
const { shapeId } = type;
if (shapeId !== null) {
const shape = BUILTIN_SHAPES.get(shapeId);
const shape = this.#shapes.get(shapeId);
invariant(
shape !== undefined,
`[HIR] Forget internal error: cannot resolve shape ${shapeId}`
+5 -5
View File
@@ -7,19 +7,19 @@
"use strict";
import * as t from "@babel/types";
import { parse } from "@babel/parser";
import traverse, { NodePath } from "@babel/traverse";
import * as t from "@babel/types";
import path from "path";
import invariant from "invariant";
import * as CompilerPipeline from "../CompilerPipeline";
import { Effect, ValueKind } from "../HIR";
import { EnvironmentConfig } from "../HIR/Environment";
import { printFunction } from "../HIR/PrintHIR";
import { EnvironmentOptions } from "../HIR/Environment";
import { Result, Ok, Err } from "../Utils/Result";
import { toggleLogging } from "../Utils/logger";
import { Err, Ok, Result } from "../Utils/Result";
import generateTestsFromFixtures from "./test-utils/generateTestsFromFixtures";
import invariant from "invariant";
// TODO: make pipeline names an enum
// Currently, this is the last pass that operates on hir
@@ -81,7 +81,7 @@ type CompileResult = {
function compile(
source: string,
language: "flow" | "typescript",
compilerEnv: Partial<EnvironmentOptions>
compilerEnv: Partial<EnvironmentConfig>
): Result<Array<CompileResult>, Error> {
const transformedFns = new Array<CompileResult>();
const babelAsts = parseFunctions(source, language);