diff --git a/compiler/forget/src/Babel/PluginOptions.ts b/compiler/forget/src/Babel/PluginOptions.ts index 6a1aedbc56..c850265b41 100644 --- a/compiler/forget/src/Babel/PluginOptions.ts +++ b/compiler/forget/src/Babel/PluginOptions.ts @@ -13,7 +13,7 @@ export type PluginOptions = { */ enableOnlyOnUseForgetDirective: boolean; - environment: EnvironmentOptions | null; + environment: Partial | null; }; export const defaultOptions: PluginOptions = { diff --git a/compiler/forget/src/CompilerPipeline.ts b/compiler/forget/src/CompilerPipeline.ts index 829fa3a16e..8865b82c59 100644 --- a/compiler/forget/src/CompilerPipeline.ts +++ b/compiler/forget/src/CompilerPipeline.ts @@ -12,7 +12,7 @@ import { mergeConsecutiveBlocks, ReactiveFunction, } from "./HIR"; -import { EnvironmentOptions } from "./HIR/Environment"; +import { EnvironmentOptions, mergeOptions } from "./HIR/Environment"; import { analyseFunctions, dropMemoCalls, @@ -49,9 +49,9 @@ export type CompilerPipelineValue = export function* run( func: NodePath, - options?: EnvironmentOptions | null + options?: Partial | null ): Generator { - const hir = lower(func, options ?? null).unwrap(); + const hir = lower(func, mergeOptions(options ?? null)).unwrap(); yield log({ kind: "hir", name: "HIR", value: hir }); mergeConsecutiveBlocks(hir); @@ -190,7 +190,7 @@ export function* run( export function compile( func: NodePath, - options?: EnvironmentOptions | null + options?: Partial | null ): t.Function { let generator = run(func, options); while (true) { diff --git a/compiler/forget/src/HIR/Environment.ts b/compiler/forget/src/HIR/Environment.ts index fb24629264..05c062a50a 100644 --- a/compiler/forget/src/HIR/Environment.ts +++ b/compiler/forget/src/HIR/Environment.ts @@ -1,3 +1,5 @@ +import { log } from "../Utils/logger"; +import { DEFAULT_GLOBALS, Global } from "./Globals"; import { Effect, IdentifierId, makeIdentifierId, ValueKind } from "./HIR"; import { BUILTIN_HOOKS, Hook } from "./Hooks"; @@ -5,12 +7,23 @@ const HOOK_PATTERN = /^_?use/; export type EnvironmentOptions = { customHooks: Map; + globals: Set; }; const DEFAULT_OPTIONS: EnvironmentOptions = { customHooks: new Map(), + globals: DEFAULT_GLOBALS, }; +export function mergeOptions( + options: Partial | null +): EnvironmentOptions { + return { + ...DEFAULT_OPTIONS, + ...(options ?? {}), + }; +} + export class Environment { #options: EnvironmentOptions; #nextIdentifer: number = 0; @@ -27,6 +40,13 @@ export class Environment { return makeIdentifierId(this.#nextIdentifer++); } + getGlobalDeclaration(name: string): Global | null { + if (!this.#options.globals.has(name)) { + log(() => `Undefined global '${name}'`); + } + return { name }; + } + getHookDeclaration(name: string): Hook | null { if (!name.match(HOOK_PATTERN)) { return null; diff --git a/compiler/forget/src/HIR/Globals.ts b/compiler/forget/src/HIR/Globals.ts index fee658ea7c..5e868d234a 100644 --- a/compiler/forget/src/HIR/Globals.ts +++ b/compiler/forget/src/HIR/Globals.ts @@ -5,25 +5,51 @@ * LICENSE file in the root directory of this source tree. */ -import * as t from "@babel/types"; - -const GLOBALS: Map = new Map([ - ["Map", t.identifier("Map")], - ["Set", t.identifier("Set")], - ["Math", t.identifier("Math")], +export const DEFAULT_GLOBALS: Set = new Set([ + "String", + "Object", + "Function", + "Array", + "Number", + "RegExp", + "Date", + "Math", + "Error", + "Function", + "TypeError", + "RangeError", + "ReferenceError", + "SyntaxError", + "URIError", + "EvalError", + "Boolean", + "DataView", + "Float32Array", + "Float64Array", + "Int8Array", + "Int16Array", + "Int32Array", + "Map", + "Set", + "WeakMap", + "Uint8Array", + "Uint8ClampedArray", + "Uint16Array", + "Uint32Array", + "ArrayBuffer", + "JSON", + "parseFloat", + "parseInt", + "console", + "isNaN", + "eval", + "isFinite", + "encodeURI", + "decodeURI", + "encodeURIComponent", + "decodeURIComponent", ]); export type Global = { name: string; }; - -// TODO: This will work as a stopgap but it isn't really correct. We need proper handling of globals -// and module-scoped variables, which means understanding module constants and imports. -export function getGlobalDeclaration(identifierName: string): Global | null { - const ident = GLOBALS.get(identifierName); - if (ident != null) { - return ident; - } - // TODO: return null if not explicitly configured by the user - return { name: identifierName }; -} diff --git a/compiler/forget/src/HIR/HIRBuilder.ts b/compiler/forget/src/HIR/HIRBuilder.ts index ed6a2ad107..d37aa91c8d 100644 --- a/compiler/forget/src/HIR/HIRBuilder.ts +++ b/compiler/forget/src/HIR/HIRBuilder.ts @@ -12,7 +12,7 @@ import { CompilerError } from "../CompilerError"; import { logHIR } from "../Utils/logger"; import { assertExhaustive } from "../Utils/utils"; import { Environment } from "./Environment"; -import { getGlobalDeclaration, Global } from "./Globals"; +import { Global } from "./Globals"; import { BasicBlock, BlockId, @@ -137,7 +137,7 @@ export default class HIRBuilder { } resolveGlobal(path: NodePath): Global | null { - return getGlobalDeclaration(path.node.name); + return this.#env.getGlobalDeclaration(path.node.name); } /**