diff --git a/compiler/forget/src/CompilerError.ts b/compiler/forget/src/CompilerError.ts index 9d072725e0..2695c0d7e1 100644 --- a/compiler/forget/src/CompilerError.ts +++ b/compiler/forget/src/CompilerError.ts @@ -13,7 +13,7 @@ export enum ErrorSeverity { export type CompilerErrorOptions = { reason: string; severity: ErrorSeverity; - nodePath: AnyNodePath; + nodePath: AnyNodePath | null; }; type AnyNodePath = NodePath; type CompilerErrorKind = typeof InvalidInputError | typeof TodoError; diff --git a/compiler/forget/src/CompilerPipeline.ts b/compiler/forget/src/CompilerPipeline.ts index e55e152389..88b654485b 100644 --- a/compiler/forget/src/CompilerPipeline.ts +++ b/compiler/forget/src/CompilerPipeline.ts @@ -46,11 +46,7 @@ export type CompilerPipelineValue = export function* run( func: NodePath ): Generator { - const lowering = lower(func).orElse((error) => { - throw error; - }); - - const hir = lowering.unwrap(); + const hir = lower(func).unwrap(); yield log({ kind: "hir", name: "HIR", value: hir }); mergeConsecutiveBlocks(hir); @@ -153,7 +149,7 @@ export function* run( value: reactiveFunction, }); - const ast = codegenReactiveFunction(reactiveFunction); + const ast = codegenReactiveFunction(reactiveFunction).unwrap(); yield log({ kind: "ast", name: "Codegen", value: ast }); return ast; diff --git a/compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts b/compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts index b119b6fd37..db1f42003b 100644 --- a/compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts +++ b/compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts @@ -7,6 +7,7 @@ import * as t from "@babel/types"; import invariant from "invariant"; +import { CompilerError, ErrorSeverity } from "../CompilerError"; import { BlockId, GeneratedSource, @@ -24,12 +25,12 @@ import { ReactiveValue, SourceLocation, } from "../HIR/HIR"; -import { todoInvariant } from "../Utils/todo"; +import { Err, Ok, Result } from "../Utils/Result"; import { assertExhaustive } from "../Utils/utils"; export function codegenReactiveFunction( fn: ReactiveFunction -): t.FunctionDeclaration { +): Result { const cx = new Context(); const params = fn.params.map((param) => convertIdentifier(param.identifier)); const body = codegenBlock(cx, fn.body); @@ -56,13 +57,20 @@ export function codegenReactiveFunction( ]) ); } - return createFunctionDeclaration( - fn.loc, - fn.id !== null ? convertIdentifier(fn.id) : null, - params, - body, - fn.generator, - fn.async + + if (cx.errors.hasErrors()) { + return Err(cx.errors); + } + + return Ok( + createFunctionDeclaration( + fn.loc, + fn.id !== null ? convertIdentifier(fn.id) : null, + params, + body, + fn.generator, + fn.async + ) ); } @@ -70,6 +78,7 @@ class Context { #nextCacheIndex: number = 0; #identifiers: Set = new Set(); temp: Temporaries = new Map(); + errors: CompilerError = new CompilerError(); get nextCacheIndex(): number { return this.#nextCacheIndex++; @@ -711,17 +720,22 @@ function codegenInstructionValue( } else { if (t.isVariableDeclaration(stmt)) { const declarator = stmt.declarations[0]; - todoInvariant( - false, - `Cannot declare variables in a value block, tried to declare '${ + cx.errors.push({ + reason: `(CodegenReactiveFunction::codegenInstructionValue) Cannot declare variables in a value block, tried to declare '${ (declarator.id as t.Identifier).name - }'` - ); + }'`, + severity: ErrorSeverity.Todo, + nodePath: null, + }); + return t.stringLiteral(`TODO handle ${declarator.id}`); + } else { + cx.errors.push({ + reason: `(CodegenReactiveFunction::codegenInstructionValue) Handle conversion of ${stmt.type} to expression`, + severity: ErrorSeverity.Todo, + nodePath: null, + }); + return t.stringLiteral(`TODO handle ${stmt.type}`); } - todoInvariant( - false, - `Handle conversion of ${stmt.type} to expression` - ); } }); if (expressions.length === 0) { @@ -788,7 +802,6 @@ function codegenValue( } function codegenPlace(cx: Context, place: Place): t.Expression { - todoInvariant(place.kind === "Identifier", "support scope values"); let tmp = cx.temp.get(place.identifier.id); if (tmp != null) { return tmp; diff --git a/compiler/forget/src/Utils/Result.ts b/compiler/forget/src/Utils/Result.ts index e2130f14d0..d4f928e65f 100644 --- a/compiler/forget/src/Utils/Result.ts +++ b/compiler/forget/src/Utils/Result.ts @@ -167,6 +167,9 @@ class OkImpl implements Result { } unwrapErr(): never { + if (this.val instanceof Error) { + throw this.val; + } throw new Error(`Can't unwrap \`Ok\` to \`Err\`: ${this.val}`); } } @@ -227,6 +230,9 @@ class ErrImpl implements Result { } unwrap(): never { + if (this.val instanceof Error) { + throw this.val; + } throw new Error(`Can't unwrap \`Err\` to \`Ok\`: ${this.val}`); } diff --git a/compiler/forget/src/__tests__/Result-test.ts b/compiler/forget/src/__tests__/Result-test.ts index f1e8fbc480..254abe5e5b 100644 --- a/compiler/forget/src/__tests__/Result-test.ts +++ b/compiler/forget/src/__tests__/Result-test.ts @@ -1,3 +1,4 @@ +import { CompilerError } from "../CompilerError"; import { Err, Ok, Result } from "../Utils/Result"; function addMax10(a: number, b: number): Result { @@ -9,6 +10,8 @@ function onlyFoo(foo: string): Result { return foo === "foo" ? Ok(foo) : Err(foo); } +class CustomDummyError extends Error {} + describe("Result", () => { test(".map", () => { expect(addMax10(1, 1).map((n) => n * 2)).toEqual(Ok(4)); @@ -107,6 +110,9 @@ describe("Result", () => { }).toThrowErrorMatchingInlineSnapshot( `"Can't unwrap \`Err\` to \`Ok\`: 20 is too high"` ); + expect(() => { + Err(new CustomDummyError("oops")).unwrap(); + }).toThrowErrorMatchingInlineSnapshot(`"oops"`); }); test(".unwrapOr", () => { @@ -126,5 +132,8 @@ describe("Result", () => { `"Can't unwrap \`Ok\` to \`Err\`: 2"` ); expect(addMax10(10, 10).unwrapErr()).toEqual("20 is too high"); + expect(() => { + Ok(new CustomDummyError("oops")).unwrapErr(); + }).toThrowErrorMatchingInlineSnapshot(`"oops"`); }); }); diff --git a/compiler/forget/src/__tests__/fixtures/hir/error.while-with-assignment-in-test.expect.md b/compiler/forget/src/__tests__/fixtures/hir/error.while-with-assignment-in-test.expect.md index 70ac4bf9a0..08a6728aa7 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/error.while-with-assignment-in-test.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/error.while-with-assignment-in-test.expect.md @@ -19,7 +19,7 @@ function f(reader) { ## Error ``` -TODO: Cannot declare variables in a value block, tried to declare 'value$0' +[ReactForget] Todo: (CodegenReactiveFunction::codegenInstructionValue) Cannot declare variables in a value block, tried to declare 'value$0' ``` \ No newline at end of file