Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

basic stack traces #261

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
Open

Conversation

doyougnu
Copy link
Collaborator

@doyougnu doyougnu commented Jan 4, 2025

Todos:

  • add tests for >>= tail and pair
  • refine the stack trace output, some of them are a bit wonkey
  • no more todos in the code
  • add some commentary
  • remove the printing of the unique ids, they are not deterministic
  • cleanup, this pr in still a bit of a mess

@gelisam @david-christiansen, sorry for the size of this one. I wanted to open this to get some eyes on it.

How can I test the InMacroBindTL and pair cases? No matter what kind of klister I wrote, I could not get those to show up.

Also, you'll notice that I chose to add a hardline to separate the error message from the error context. We should decide on a format in the next meeting

Summary by CodeRabbit

Release Notes

  • New Features

    • Added a new debugging framework with enhanced error reporting capabilities.
    • Introduced stack trace functionality for better error diagnostics.
  • Improvements

    • Refactored error handling across multiple modules to use a more robust debugging approach.
    • Enhanced type checking and expansion error reporting.
    • Improved pretty-printing and output formatting.
  • Internal Changes

    • Replaced exception-based error handling with a more flexible debugging mechanism.
    • Updated type signatures and error handling in several core modules.
    • Added new debugging and stack trace tracking utilities.
  • Development Environment

    • Updated development shell configuration.
    • Added cabal-install to development tools.

Copy link

coderabbitai bot commented Jan 4, 2025

Warning

Rate limit exceeded

@doyougnu has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 8 minutes and 31 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 4de0c16 and c8b2b6c.

📒 Files selected for processing (32)
  • examples/non-examples/bad-lexical-env.golden (1 hunks)
  • examples/non-examples/bad-lexical-env.kl (1 hunks)
  • examples/non-examples/error.golden (1 hunks)
  • examples/non-examples/stack-traces/.#error-in-cons-head.golden (1 hunks)
  • examples/non-examples/stack-traces/error-in-arg.golden (1 hunks)
  • examples/non-examples/stack-traces/error-in-arg.kl (1 hunks)
  • examples/non-examples/stack-traces/error-in-bind-head.golden (1 hunks)
  • examples/non-examples/stack-traces/error-in-bind-head.kl (1 hunks)
  • examples/non-examples/stack-traces/error-in-bind-tail.golden (1 hunks)
  • examples/non-examples/stack-traces/error-in-bind-tail.kl (1 hunks)
  • examples/non-examples/stack-traces/error-in-case-constructor.golden (1 hunks)
  • examples/non-examples/stack-traces/error-in-case-constructor.kl (1 hunks)
  • examples/non-examples/stack-traces/error-in-cons-head.golden (1 hunks)
  • examples/non-examples/stack-traces/error-in-cons-head.kl (1 hunks)
  • examples/non-examples/stack-traces/error-in-constructor.golden (1 hunks)
  • examples/non-examples/stack-traces/error-in-constructor.kl (1 hunks)
  • examples/non-examples/stack-traces/error-in-let.golden (1 hunks)
  • examples/non-examples/stack-traces/error-in-let.kl (1 hunks)
  • examples/non-examples/stack-traces/error-in-list.golden (1 hunks)
  • examples/non-examples/stack-traces/error-in-list.kl (1 hunks)
  • examples/non-examples/stack-traces/error-in-pure-macro.golden (1 hunks)
  • examples/non-examples/stack-traces/error-in-pure-macro.kl (1 hunks)
  • examples/non-examples/stack-traces/in-arg-error.golden (1 hunks)
  • examples/non-examples/stack-traces/in-arg-error.kl (1 hunks)
  • flake.nix (2 hunks)
  • klister.cabal (1 hunks)
  • src/Debugger.hs (1 hunks)
  • src/Evaluator.hs (10 hunks)
  • src/Expander.hs (26 hunks)
  • src/Expander/Error.hs (2 hunks)
  • src/Expander/Monad.hs (13 hunks)
  • src/Pretty.hs (6 hunks)

Walkthrough

This pull request introduces a comprehensive set of changes across multiple files in the Klister programming language project, focusing on error handling, debugging capabilities, and code formatting. The primary modifications include the introduction of a new Debugger module, refactoring error handling mechanisms to use debugging instead of throwing errors, and making various formatting improvements across example files and source code.

Changes

File Change Summary
src/Debugger.hs New module implementing a Common Lisp-style debugger with Debug monad and MonadDebugger type class
src/Evaluator.hs Extended Kont data type, updated EState, improved pattern matching and debugging
src/Expander.hs, src/Expander/Monad.hs Replaced error throwing with debug logging, integrated new Debugger module
examples/* Numerous formatting changes, including type signature and comment formatting
flake.nix Added cabal-install to dev tools, configured KLISTERPATH
klister.cabal Added Debugger module to exposed modules

Suggested labels

CodeRabbit

Suggested reviewers

  • gelisam

Poem

🐰 In the realm of code, a rabbit's delight,
Debugging now shines, errors take flight!
From CEK to expander, traces unfurl,
A debugger's magic begins to swirl 🌟
Klister evolves, with clarity bright! 🔍

Possibly related PRs

  • A CEK Evaluator #223: The changes in the main PR regarding the formatting of constructor declarations are related to the modifications in the Evaluator.hs file, which also involve updates to the handling of evaluation processes and error reporting, indicating a focus on improving readability and structure in both cases.

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Nitpick comments (57)
examples/non-examples/error.golden (1)

1-5: Great improvement in formatting the error message

The transition to a multi-line format is much clearer and easier to read. As a further enhancement, consider adding more detail to the stack trace—such as which function or binding triggered the error—to give users deeper insight into the error’s origin.

examples/tiny-types.golden (2)

3-4: Consistent indentation recommended
The formatting change increases clarity by separating the annotation and syntax symbol onto separate lines. However, consider using consistent indentation (e.g., 2 or 4 spaces) rather than a single leading space for <foo> to improve readability across the file.


5-6: Maintain uniform spacing for annotations and syntax symbols
Similar to lines 3-4, this change clarifies the code’s meaning, but line 6 uses additional leading spaces (six spaces) compared with other lines. Adopting a standard indentation convention will help maintain an overall uniform look.

examples/primitives-documentation.golden (2)

31-33: Consider aligning or grouping the type variables consistently.
Currently, ∀(α : *) is on a separate line from (β : *), which may be inconsistent with the style used elsewhere. Consolidate them if you prefer a uniform approach.


53-55: Maintain consistent line breaks for type variables.
Like for bind-IO, grouping both (α : *) and (β : *) on a single line might keep it uniform with other similar signatures.

examples/non-examples/stack-traces/error-in-cons-head.golden (1)

1-2: Consider adding a more descriptive message for clarity.
The current error message shows "Unknown" but doesn't specify what went wrong or how to fix it. Including further context (e.g., the type of error, expected vs. actual) can help users quickly diagnose the issue.

examples/non-examples/stack-traces/error-in-bind-head.kl (1)

1-3: Confirm the intended error-handling behavior in monadic context.
This example returns the result of (pure x) after an error occurs. Clarify if this demonstration accurately reflects how >>= should propagate errors or if additional handling is required.

examples/non-examples/stack-traces/.#error-in-cons-head.golden (1)

1-1: Potentially sensitive file path.
Revealing an absolute path in error messages can expose user-specific environment details. Consider redacting or abstracting these paths if they are not vital to debugging.

examples/non-examples/stack-traces/error-in-cons-head.kl (1)

1-10: Consider utilizing the function argument and addressing the TODO.

Here, (define fail (lambda (thing) (car '(1 2 'something-else)))) never uses the thing parameter, which may be confusing. If it’s intentional, consider documenting why. Also, the file has a TODO about testing pairs—ensure these tests are added for thorough coverage.

Would you like me to draft a minimal test for pair scenarios?

examples/non-examples/stack-traces/error-in-case-constructor.kl (2)

5-7: Consider clarifying the purpose of this large Alphabet type.
This type enumerates a range of letters, which may be overkill unless you're testing or demonstrating patterns. If this is purely for illustrative error handling, clarify or reduce to only the necessary constructors.


15-15: Provide a test or commentary for the (example ...) invocation.
If (fail (l)) is designed to trigger an error, consider explaining how this example is verified (e.g., via a golden file or an automated test).

examples/non-examples/stack-traces/error-in-constructor.kl (3)

5-7: Evaluate necessity of Pair type in this demo.
If you only need the pair constructor for an error demonstration, consider referencing a simpler or pre-existing type to keep this example self-contained. Alternatively, add clarity on why a new type is introduced.


8-11: Add an inline comment explaining how fst is tested.
Given that this example focuses on error handling for fail, clarify that fst is a utility. Document or reference where its behavior is validated.


20-20: Consider expanded testing for (fail 23).
If this example is meant to produce a deterministic error trace, add explanation or a golden file capturing the exact stack trace. This ensures clarity and consistency in the demonstration.

Would you like me to provide a script or snippet that checks for a matching error message in your golden file tests?

examples/non-examples/stack-traces/error-in-bind-tail.kl (2)

4-6: Potential mismatch with the syntax-error usage.

Within a monadic setting, calling (syntax-error x) directly in the continuation may not always yield the desired effect. Depending on how syntax-error is implemented, it could short-circuit the evaluation or trigger an upstream macro expansion issue.

If you’d like, I can investigate how syntax-error behaves under monadic bindings by searching for its definition or usage across the codebase. Let me know if you want me to open a GitHub issue or propose a direct fix.


7-7: Clarify the TODO.

It appears the TODO comment is asking why (syntax-error x) does not propagate as expected. Capturing or clarifying that logic may involve analyzing the macro expansion flow or ensuring the error is thrown in the correct phase.

I can assist by walking through the expansion phases or verifying the macro expansion to confirm if (syntax-error x) is correctly recognized. Let me know if that’s helpful.

src/Debugger.hs (2)

1-22: Consider documenting module usage and error-handling model.

You've introduced a brand-new debugger module and monad but haven't provided high-level documentation for how end-users, or other contributors, should utilize it. Consider adding a top-level Haddock comment or README references discussing:
• The typical usage pattern of Debug r e a.
• How errors are meant to be surfaced (via debug, catch, etc.).
• Basic examples or recommended best practices.


103-112: Consider including stack tracing details in debug.

Your MonadDebugger implementation logs errors using debug e, but does not appear to attach any additional context like location, call site, or partial state. Including more contextual details can drastically improve debugging experience, especially for advanced use-cases.

src/Expander/TC.hs (8)

36-36: Check for additional error context.

debug $ InternalError "Dangling type metavar"

While this is a valid usage, consider providing more context (e.g., which type metavar is dangling) to make errors more actionable.


82-82: Verify the correctness of occurs-check error.

debug $ TypeCheckError $ OccursCheckFailed ptr t'

Ensure the ptr and the normalized t' are enough to diagnose the exact nature of the failed occurs-check. You might want location data or more descriptive text for better debugging.


113-113: Potential mismatch error detail.

debug $ InternalError "Mismatch in number of type vars"

If possible, include the expected vs. actual counts for clarity, preventing confusion for future maintainers and users.


198-198: Clarify generalization error.

debug $ InternalError "Can't generalize in scheme"

It's unclear why the code can't generalize here. Consider specifying the cause or the relevant scheme pointer to enhance debugging.


292-296: Include deeper type mismatch context if possible.

debug $ TypeCheckError $ TypeMismatch loc e' r' Nothing
...
debug $ TypeCheckError $ TypeMismatch loc outerE' outerR' (Just (e', r'))

These error sites are crucial. If there's a possibility to retrieve surrounding type context or call site, it may improve support for diagnosing tricky type mismatches.


305-305: Add pointer reference to "Type variable not found!"

debug $ InternalError "Type variable not found!"

Consider including the missing pointer or relevant state. This can greatly reduce time to locate issues in large expansions.


327-327: Clarify kind mismatch.

debug $ KindMismatch loc k1' k2'

If you can, include more context or potential resolution steps in the error message. For instance, mention which type or constructor triggered the mismatch.


381-381: Consider alternative approach.

debug $ InternalError "Tried to find kind in open context"

If this scenario arises frequently, you may want to unify or infer the kind more gracefully rather than throwing an internal error. Evaluate if there's a legitimate fallback or partial solution.

src/Evaluator.hs (2)

162-169: Enhance documentation for new constructors.

InCasePattern
InDataCasePattern

You've introduced these pattern-specific constructors to track matched patterns in the stack trace. Ensure test coverage includes scenarios in which these new constructors appear, verifying correct debugging output.


703-706: Guard projectError usage carefully.

projectError (Er err _env _kont) = err
projectError _                   = error "projectError not used on an error!"

Accidentally calling projectError on a non-error state raises an exception. Consider Either or safer checks to avoid runtime crashes in unforeseen situations.

src/Pretty.hs (4)

5-5: Ensure LambdaCase extension usage is minimal.

Using LambdaCase can improve conciseness, but if used heavily, it may reduce readability for some developers. Make sure usage is consistent and documented to keep code approachable.


113-114: Refine let-binding layout.

hang 2 $
vsep [ text "let" <+> hang 2 ...

While hang and vsep produce readable blocks, test against deeply nested structures or large let blocks to ensure it doesn't become unwieldy. You might prefer using group or more advanced layout combinators for large expressions.


368-372: Tailor function arrow printing.

(TyF TFun [a, b]) -> ...

Here, you print the function arrow in a multi-line format. Verify this remains legible in large, curried function types. Some teams prefer single-line for short types, and multiline only when needed. Possibly consider group to handle multi-line gracefully.


810-812: Consider partial expansions for macros.

(InBindMacroTl action _env k) -> ...

Highlight partial expansions or placeholders in logs. If macros are partially expanded, having a marker in the final pretty print might help.

src/Expander/Monad.hs (9)

599-599: Investigate incomplete module.

Nothing -> debug $ InternalError "Incomplete module after expansion"

You might want a reference to ptr or module name for more clarity, helping identify which module is incomplete.


610-610: Missing decl detail.

Nothing -> debug $ InternalError "Missing decl after expansion"

Likewise, consider specifying the pointer or the expected declaration name for faster troubleshooting.


619-623: Missing expr or scheme references.

Nothing -> debug $ InternalError "Missing expr after expansion"
...
Nothing -> debug $ InternalError "Missing scheme after expansion"

In each of these checks, incorporate the missing pointers or user-located code snippet references.


632-632: Enhance define macros message.

Nothing -> debug $ InternalError "Missing expr after expansion"

DefineMacros might be trickier to debug if you have no info about which macro is missing. Consider including the macro’s name or pointer ID.


648-648: Adding pointer detail for missing types.

debug $ InternalError "Missing type after expansion"

If you have a pointer or constructor name, it would be an excellent reference in the error to help locate which type was lost.


668-668: Missing action detail.

debug $ InternalError "Missing action after expansion"

Similar to other missing expansions, referencing the pointer or call site helps track down the culprit.


785-785: Likewise for unknown datatype.

debug $ InternalError $ "Unknown datatype " ++ show datatype

Same principle: referencing the unknown entity is helpful. Confirm that any place you look up this datatype includes relevant phase or module context if multi-phase expansions are possible.


851-851: Preventing stuck expansions.

debug (NoProgress (map (view _3) remainingTasks))

Ensure that each NoProgress case is properly tested, and the user receives enough info to fix the stuck expansions. Possibly indicate the tasks themselves or current environment state.


867-870: Distinguishing macro evaluation failures.

case evaluateIn env evalAction of
  Left e_state -> debug $ MacroEvaluationError p e_state
  Right val -> return val

Differentiate macro runtime errors from type or resolution issues if possible. This helps end-users identify macro-level logic errors vs. type mismatch expansions.

examples/non-examples/stack-traces/error-in-list.kl (2)

9-9: Rename the function for clarity or confirm its intended semantics.

fail is misleading since it doesn't fail but instead increments its argument. Choose a more descriptive name such as increment or confirm that this is essentially a "fail" for test scenarios.


11-12: Add tests to validate fail and error usage.

A TODO remains regarding testing. Consider verifying that (fail the-error) indeed produces an appropriate error scenario, and that (fail thing) gives the expected numeric result if thing is numeric.

src/StackTraces.hs (3)

29-32: Add environment context to printed error messages.

printStack prints the error but doesn't show contextual details about the environment or continuation. Consider including printEnv env or relevant details from printKont k to make debugging more thorough.


33-35: Add descriptive comments for complex continuations.

Although printKont uses alignment and vertical separation, it's not immediately clear how complex continuations are displayed. A comment or docstring explaining the structure of the printed output would be beneficial.


39-40: Consider additional environment details in printEnv.

printEnv uses default pretty-printing. Evaluate whether you want more context (e.g., variable name-value pairs) in the output for debugging complex scenarios.

repl/Main.hs (1)

150-150: Potential Enhancement for Error Reporting
Currently, evalErr is printed directly. Consider providing more structured error information (e.g., stack traces or REPL hints) if the user is meant to debug runtime errors in-depth.

src/Expander/Syntax.hs (2)

18-18: Debugger Import
Importing Debugger indicates an intent to shift from throwing errors to logging or debugging. Ensure consistent usage of debug across this module and that there's no leftover throwError.


60-60: Import Error for Modules
Returning debug (ImportError err) can help track modules not found. Consider logging the actual file path to aid debugging.

src/Expander/Error.hs (6)

128-128: NotEmpty Pretty Printer
Replacing old code with hang 2 $ vsep [...]. Keep consistent indentation for clarity in the final output.


136-136: NotInteger
Retain example or context in error messages for user clarity if possible.


141-141: NotString
Same comment as above—string literal info might help.


192-192: ValueNotSyntax
Consider logging what the actual value was for deeper insights.


218-218: NotValidType
If there's a partial explanation for why it's invalid, consider adding it to the error.


241-242: CircularImports
Just ensure that any large cycles produce manageable error logs.

Would you like me to propose a limit on the depth or size of displayed cycles?

src/Expander.hs (2)

Line range hint 1392-1392: Address TODO for error message in module body handling.

There's a TODO comment for implementing a proper error message for malformed module bodies.

Would you like me to help implement a proper error message for malformed module bodies? I can suggest an implementation or create a GitHub issue to track this task.


Line range hint 1-1447: Consider implementing a centralized error handling strategy.

The codebase would benefit from a more systematic approach to error handling. Consider:

  1. Creating an error type hierarchy that covers all possible error cases
  2. Implementing a centralized error handling mechanism
  3. Using smart constructors for error creation to ensure consistency
  4. Adding error context information for better debugging

This would improve the consistency of error handling and make the stack traces more useful.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 750d792 and 95a0ba5.

📒 Files selected for processing (78)
  • examples/ambiguous-kind.golden (1 hunks)
  • examples/bound-identifier.golden (1 hunks)
  • examples/contract.golden (1 hunks)
  • examples/datatype-macro.golden (1 hunks)
  • examples/datatypes.golden (1 hunks)
  • examples/defun-test.golden (1 hunks)
  • examples/error.golden (1 hunks)
  • examples/eta-case.golden (1 hunks)
  • examples/failing-examples/bound-vs-free.golden (1 hunks)
  • examples/failing-examples/incorrect-context.golden (1 hunks)
  • examples/failing-examples/keyword-used-incorrectly.golden (1 hunks)
  • examples/failing-examples/wrong-keyword.golden (1 hunks)
  • examples/fix.golden (1 hunks)
  • examples/hygiene.golden (1 hunks)
  • examples/import-scoping.golden (1 hunks)
  • examples/import.golden (1 hunks)
  • examples/lambda-case-test.golden (1 hunks)
  • examples/lang.golden (1 hunks)
  • examples/let.golden (1 hunks)
  • examples/lets.golden (1 hunks)
  • examples/list-syntax.golden (1 hunks)
  • examples/list-test.golden (1 hunks)
  • examples/meta-macro.golden (1 hunks)
  • examples/monad.golden (1 hunks)
  • examples/non-examples/bad-lexical-env.golden (1 hunks)
  • examples/non-examples/bad-lexical-env.kl (1 hunks)
  • examples/non-examples/circular-1.golden (1 hunks)
  • examples/non-examples/circular-2.golden (1 hunks)
  • examples/non-examples/error.golden (1 hunks)
  • examples/non-examples/import-phase.golden (1 hunks)
  • examples/non-examples/missing-import.golden (1 hunks)
  • examples/non-examples/stack-traces/.#error-in-cons-head.golden (1 hunks)
  • examples/non-examples/stack-traces/error-in-arg.golden (1 hunks)
  • examples/non-examples/stack-traces/error-in-arg.kl (1 hunks)
  • examples/non-examples/stack-traces/error-in-bind-head.golden (1 hunks)
  • examples/non-examples/stack-traces/error-in-bind-head.kl (1 hunks)
  • examples/non-examples/stack-traces/error-in-bind-tail.golden (1 hunks)
  • examples/non-examples/stack-traces/error-in-bind-tail.kl (1 hunks)
  • examples/non-examples/stack-traces/error-in-case-constructor.golden (1 hunks)
  • examples/non-examples/stack-traces/error-in-case-constructor.kl (1 hunks)
  • examples/non-examples/stack-traces/error-in-cons-head.golden (1 hunks)
  • examples/non-examples/stack-traces/error-in-cons-head.kl (1 hunks)
  • examples/non-examples/stack-traces/error-in-constructor.golden (1 hunks)
  • examples/non-examples/stack-traces/error-in-constructor.kl (1 hunks)
  • examples/non-examples/stack-traces/error-in-let.golden (1 hunks)
  • examples/non-examples/stack-traces/error-in-let.kl (1 hunks)
  • examples/non-examples/stack-traces/error-in-list.golden (1 hunks)
  • examples/non-examples/stack-traces/error-in-list.kl (1 hunks)
  • examples/non-examples/stack-traces/error-in-pure-macro.golden (1 hunks)
  • examples/non-examples/stack-traces/error-in-pure-macro.kl (1 hunks)
  • examples/non-examples/stack-traces/in-arg-error.golden (1 hunks)
  • examples/non-examples/stack-traces/in-arg-error.kl (1 hunks)
  • examples/non-examples/type-errors.golden (1 hunks)
  • examples/pmatch.golden (1 hunks)
  • examples/prelude-test.golden (1 hunks)
  • examples/primitives-documentation.golden (2 hunks)
  • examples/product-type.golden (1 hunks)
  • examples/quasiquote-syntax-test.golden (1 hunks)
  • examples/syntax-loc.golden (1 hunks)
  • examples/temporaries-test.golden (1 hunks)
  • examples/test-quasiquote.golden (1 hunks)
  • examples/tiny-types.golden (1 hunks)
  • examples/two-defs.golden (1 hunks)
  • examples/unknown-type.golden (1 hunks)
  • examples/which-problem.golden (1 hunks)
  • flake.nix (2 hunks)
  • klister.cabal (2 hunks)
  • repl/Main.hs (3 hunks)
  • src/Debugger.hs (1 hunks)
  • src/Evaluator.hs (10 hunks)
  • src/Expander.hs (26 hunks)
  • src/Expander/Error.hs (7 hunks)
  • src/Expander/Monad.hs (13 hunks)
  • src/Expander/Primitives.hs (5 hunks)
  • src/Expander/Syntax.hs (6 hunks)
  • src/Expander/TC.hs (9 hunks)
  • src/Pretty.hs (22 hunks)
  • src/StackTraces.hs (1 hunks)
✅ Files skipped from review due to trivial changes (40)
  • examples/non-examples/circular-2.golden
  • examples/failing-examples/wrong-keyword.golden
  • examples/bound-identifier.golden
  • examples/non-examples/circular-1.golden
  • examples/lang.golden
  • examples/failing-examples/incorrect-context.golden
  • examples/non-examples/import-phase.golden
  • examples/temporaries-test.golden
  • examples/lets.golden
  • examples/non-examples/missing-import.golden
  • examples/non-examples/type-errors.golden
  • examples/non-examples/bad-lexical-env.golden
  • examples/eta-case.golden
  • examples/failing-examples/keyword-used-incorrectly.golden
  • examples/lambda-case-test.golden
  • examples/two-defs.golden
  • examples/datatype-macro.golden
  • examples/error.golden
  • examples/ambiguous-kind.golden
  • examples/fix.golden
  • examples/contract.golden
  • examples/pmatch.golden
  • examples/let.golden
  • examples/defun-test.golden
  • examples/failing-examples/bound-vs-free.golden
  • examples/prelude-test.golden
  • examples/list-test.golden
  • examples/syntax-loc.golden
  • examples/import-scoping.golden
  • examples/quasiquote-syntax-test.golden
  • examples/import.golden
  • examples/meta-macro.golden
  • examples/product-type.golden
  • examples/hygiene.golden
  • examples/list-syntax.golden
  • examples/test-quasiquote.golden
  • examples/datatypes.golden
  • examples/monad.golden
  • examples/which-problem.golden
  • examples/unknown-type.golden
🔇 Additional comments (90)
examples/non-examples/bad-lexical-env.kl (2)

3-3: Potentially undefined variable y.

Inside the function f, the variable y is referenced but never defined in this scope or in a surrounding scope, which may produce a lexical error unless intentionally used to demonstrate the environment error mechanic. Verify that you indeed intend to reference a free variable here for testing or demonstration.


4-4: No argument passed to f.

The function g calls f without passing any arguments, despite f having a parameter (ff). If this is intentional for error demonstration, it’s fine, but otherwise consider supplying the needed argument to avoid runtime errors.

examples/tiny-types.golden (2)

10-11: Clear separation of annotations and identifiers
Moving <a> to a separate line makes the code structure more readable. This is a valuable improvement.


12-13: Good formatting clarification for free identifier <b>
Separating <b> onto its own line improves readability, matching the adjustments made for <a>. Nicely done!

examples/primitives-documentation.golden (5)

29-30: Good separation of type variables to improve readability.
The new multiline format for pure-IO’s signature is clear and accurately expresses the type relationship.


45-46: No issues detected with the nothing signature.
This multiline formatting is consistent and improves clarity.


47-48: nil signature is clearly expressed.
No functional or stylistic concerns; this line break pattern matches the rest of the file.


51-52: id signature is well-formatted.
No change to logic; looks good as is.


56-59: compose signature refactor is clear and readable.
Breaking out each type variable on its own line is understandable, but ensure it’s consistently applied throughout the file for clarity.

examples/non-examples/stack-traces/error-in-pure-macro.kl (1)

1-3: Validate that the example effectively demonstrates the error scenario.
The example sets up a pure macro that triggers an error, which is good for ensuring that error handling logic is tested. Verify that any upstream or downstream code referencing this file treats the error as expected.

examples/non-examples/stack-traces/in-arg-error.golden (1)

1-6: Good clarity and specificity in the error message.
The mismatch details are clearly itemized by showing the expected and actual types. This approach aids rapid debugging. If needed, consider unifying message formats project-wide for consistency.

examples/non-examples/stack-traces/error-in-arg.kl (3)

1-2: Consistent language specification.
The usage of #lang "prelude.kl" is in line with the existing examples, so no changes are needed here.


3-3: Validate numeric input for (fail).
The function assumes thing is numeric. In tests or higher-level logic, ensure that calling (fail) with a non-numeric argument either raises a clear error or is validated beforehand.


5-5: Intentional error example looks good.
Invoking (error 'bad) is a useful demonstration for stack-trace behavior. No changes required.

examples/non-examples/stack-traces/error-in-list.golden (1)

1-5: Clear and concise error message format.
This new format provides a straightforward location reference, an error description, and a stack trace. It’s consistent and easy to follow. No issues found.

examples/non-examples/stack-traces/in-arg-error.kl (3)

1-2: Language specification confirmed.
The file correctly uses #lang "prelude.kl". No changes needed here.


3-3: Check numeric assumption for (fail).
As with the other example, confirm that something is numeric or handle invalid input gracefully.


5-5: Error scenario is properly illustrated.
This line shows the function raising an error to demonstrate stack-trace handling. Good for testing.

examples/non-examples/stack-traces/error-in-arg.golden (1)

1-6: Structured error format looks consistent.

The newly introduced error message and stack trace align with the improved style described in the PR objectives. This should help users quickly locate and diagnose the issue in error-in-arg.kl.

examples/non-examples/stack-traces/error-in-pure-macro.golden (1)

1-6: Good consistency in error framing.

This example’s error output provides a clear message and a concise stack trace for a pure macro. Keeping a uniform style across all .golden files will aid debugging and maintain clarity.

examples/non-examples/stack-traces/error-in-case-constructor.golden (1)

1-6: Clear presentation of case-constructor error.

This error and stack trace demonstrate a consistent style with the other .golden files. No further issues spotted.

examples/non-examples/stack-traces/error-in-let.kl (1)

1-7: Example snippet successfully demonstrates the error mechanism.

The snippet correctly illustrates the behavior of throwing an error and halting the program flow. This is useful for verifying that the new stack trace enhancements are working as intended.

examples/non-examples/stack-traces/error-in-bind-head.golden (1)

1-9: Please verify accuracy of error references.

The error message and stack trace are clearly structured. However, ensure that the file reference error-in-bind-head.kl:3.29-3.30 aligns precisely with the location of the failing expression.

examples/non-examples/stack-traces/error-in-let.golden (1)

1-8: Maintain consistent error references.

This new structured error output is aligned with other error reporting. As a suggestion, verify the file and line references (error-in-let.kl:4.42-4.53 and #[error-in-let.kl:4.22-4.24]) to ensure their accuracy in pointing to the offending code.

examples/non-examples/stack-traces/error-in-constructor.golden (1)

1-9: Confirm constructor location and field references.

The detailed stack trace is helpful. Double-check that the error location error-in-constructor.kl:17.45-17.56 and field index “2” in the constructor pair are indeed correct. Inconsistencies in trace indexing can cause confusion.

examples/non-examples/stack-traces/error-in-case-constructor.kl (1)

9-13: Confirm the handling of (else the-other).
the-other isn't defined in this snippet, implying it's either an unbound symbol or intentionally a placeholder. If it's a placeholder, consider naming it more clearly or documenting it for clarity.

examples/non-examples/stack-traces/error-in-constructor.kl (1)

16-18: Double-check the error strategy in fail.
Here, fail constructs a pair whose second element is always an error. If the goal is to illustrate a stack trace at construction, that’s fine; otherwise, consider deferring the error until the pair is accessed.

examples/non-examples/stack-traces/error-in-bind-tail.golden (1)

1-5: Good addition to illustrate the error scenario in binding tails.

This golden file snippet effectively demonstrates how an error is triggered and traced in the binding tail of a macro scenario. It’s helpful to see the exact points in the code (#[error-in-bind-tail.kl:4.15-4.28]) where the failure occurs, aiding debugging and clarifying the error context. No issues detected; the changes are aligned with the PR’s goal of improving stack trace outputs.

examples/non-examples/stack-traces/error-in-bind-tail.kl (2)

1-3: Solid demonstration setup for error handling tests.

The inclusion of a prelude.kl language mode and the (example ...) construct is appropriate for testing macro-related errors in a controlled manner. This ensures coverage for the tail-binding scenario referenced in the .golden file.


8-8: Neat final bind.

Returning (pure y) ensures the final result is well-formed if no error is triggered. Coupled with the preceding monadic steps, this lines up with the stated goals of testing stack traces and error handling in a tail-binding scenario.

src/Debugger.hs (2)

45-47: Confirm that debugRunT is consistent with your monad design.

While debugRunT simply flips runDebug, ensure that all code paths call it appropriately. If other modules expect a function with the signature r -> Debug r e a -> IO (Either e a), confirm consistency so that you don’t inadvertently cause confusion when wrapping or unwrapping the runDebug function.


50-51: Validate the mapDebugT transformation.

The function composes fmap and second, suggesting transformation of both left (error) and right (value) sides. Verify that the intent is indeed to allow transformations of the successful result while preserving the error. If, for any reason, you need to transform the error side as well, you might consider a more comprehensive approach to mapping both sides of the Either.

src/Expander/TC.hs (1)

20-20: Import check.

The added import Debugger is consistent with your broader shift toward using the Debug monad. Ensure all references to the old error-handling approach (if any remain) are removed to avoid confusion.

src/Evaluator.hs (2)

256-258: Confirm that mediator logic is correct.

(InCasePattern _ kont) -> Up v e kont
(InDataCasePattern _ kont) -> Up v e kont

You’re passing the value v up with no additional transformation or pattern checks. Confirm that skipping further case analysis (beyond capturing the pattern in the continuation) is intended behavior; if so, it makes sense, but you might want explicit docstrings explaining why no additional evaluation is needed here.

✅ Verification successful

Let me gather more information about the case pattern handling in the evaluator.


The mediator logic for case patterns is correct and well-documented

The behavior is intentionally designed this way, as explained in the Note [InCasePattern] comment found in the codebase:

In case pattern is strictly not necessary, we could do this evaluation in the host's runtime instead of in the evaluator but doing so would mean that the debugger would not be able to capture the pattern that was matched.

The pattern matching and environment setup is actually done before reaching these continuation handlers, as evidenced by the match function calls where:

  • The environment is properly extended with matched values
  • The pattern is stored in the continuation for debugging purposes
  • The continuation handlers (InCasePattern and InDataCasePattern) simply pass the value up after the match is complete

This design ensures that the debugger can track which patterns were matched while keeping the actual pattern handling logic clean and efficient.

🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for InCasePattern and InDataCasePattern definitions and usages
ast-grep --pattern 'data $_ = InCasePattern $$ | InDataCasePattern $$'

# Look for comments or documentation about case pattern handling
rg -B 2 -A 2 "InCasePattern|InDataCasePattern" 

# Search for Note about InCasePattern
rg "\[InCasePattern\]"

Length of output: 4429


707-710: Potential utility in partial states.

projectKont (Er _ _ k) = k
projectKont (Up _ _ k) = k
projectKont (Down _ _ k) = k

Similar to projectError, ensure that usage in partial states won't lead to misinterpretation. If other code might rely on the presence of a particular value in the continuation, consider clarifying the usage contract in docstrings.

✅ Verification successful

Let me gather more information about the usage of projectKont and related functions to verify the concern.


Let me search for more context about the EState type and its usage.


Based on the gathered information, I can now provide the final response:

projectKont is safely used in partial states

The codebase shows that EState is a well-defined sum type with three constructors (Down, Up, and Er), each carrying a continuation (Kont) as their last parameter. The projectKont function is implemented correctly for all three constructors, and its usage pattern is consistent with the evaluation model:

  • The evaluation step function (step) handles all three states appropriately
  • The continuation is consistently used across state transitions
  • Error states (Er) preserve the continuation for proper error handling and stack traces
  • The function is used in conjunction with projectError for error reporting
🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for projectKont usage and implementation
rg "projectKont" -A 3

# Search for EState type definition and related types
ast-grep --pattern 'data EState = $_'

# Look for similar projection functions
rg "project.*\s*::\s*EState" -A 2

# Search for functions that use the continuation (k)
rg "k\s*=\s*projectKont" -A 3

Length of output: 794


Script:

#!/bin/bash
# Search for EState data type definition
rg "data EState" -A 10

# Search for Kont type definition
rg "type Kont" -A 3

# Search for functions that construct EState values
rg "Er\s+|Up\s+|Down\s+" --type haskell -A 2

# Look for functions that pattern match on EState
ast-grep --pattern 'case $_ of
  Er $$ -> $$
  Up $$ -> $$
  Down $$ -> $$'

Length of output: 16311

src/Pretty.hs (2)

697-698: Validate new EState pretty-print approach.

instance Pretty VarInfo EState where
  pp env st = printStack env st

Make sure that printStack provides enough detail about the CEK machine state for typical debugging. If users often need more detail, you might consider more granular or layered printing options.


74-80: Check for layout configuration consistency.

pretty x = renderStrict (layoutSmart defaultLayoutOptions (pp Env.empty x))
prettyPrint x = putDocW 80 (pp Env.empty x)
prettyPrintLn x = putDocW 80 (pp Env.empty x) >> putStrLn ""

You're using a mix of layoutSmart and putDocW 80. Verify the chosen layout width aligns with your team’s style guidelines and remains consistent across all pretty-print calls.

✅ Verification successful

Let me gather information about the layout configuration usage across the codebase.


Let me search for any configuration files or constants that might define layout settings.


Let me check the entire Pretty.hs file to understand the complete context of pretty printing usage.


Layout configuration is consistently used across pretty-printing functions

After analyzing the codebase, I can confirm that the mix of layoutSmart and putDocW 80 is intentional and correct:

  • pretty function uses layoutSmart defaultLayoutOptions because it's for rendering to Text, where smart layout decisions are beneficial for the output format
  • prettyPrint and prettyPrintLn use putDocW 80 because they're specifically for terminal output where a fixed width of 80 columns is a standard convention

The layout configuration is consistent with their respective purposes:

  • Text rendering: Smart layout for flexible output
  • Terminal output: Fixed 80-column width for readability
🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for layoutSmart and defaultLayoutOptions usage
rg "layoutSmart|defaultLayoutOptions" -A 2

# Search for putDocW usage to check layout width configurations
rg "putDocW" -A 2

# Search for any other pretty printing related configuration
rg "layoutOptions|pageWidth" -A 2

Length of output: 862


Script:

#!/bin/bash
# Search for any layout-related constants or configurations
rg -g '!*.lock' -g '!dist*' "pageWidth|layoutWidth|lineWidth|columns" -A 2

# Look for any pretty-printing related configuration files
fd -e yaml -e toml -e json -e conf -e config . | xargs rg "layout|pretty|print|width"

# Search for any module that might contain pretty-printing configurations
fd "Pretty|Format|Layout" -t f

Length of output: 211


Script:

#!/bin/bash
# Get the complete content of Pretty.hs
cat src/Pretty.hs

Length of output: 28201

src/Expander/Monad.hs (4)

177-177: Confirm removal of legacy error handling.

import Debugger

Now that you're pulling in Debugger, ensure any leftover references to ExceptT or throwError are replaced throughout. Mixed usage can lead to confusion during expansions.


775-775: Unknown constructor.

debug $ InternalError $ "Unknown constructor " ++ show ctor

This is more descriptive. Good job including the failing constructor's name. Ensure coverage for datatypes as well.


929-929: Handling circular imports.

debug $ CircularImports ...

You do mention how the cycle is composed. Good job. Ensure it’s easy for a user to see the chain of modules. Possibly advise a fix or an alternate approach to break the cycle.


208-212: Check monad transformer stacking.

newtype Expand a = Expand
  { runExpand :: ReaderT ExpanderContext (Debug DebugContext ExpansionErr) a
  }
  deriving (Functor, Applicative, Monad, MonadIO, MonadDebugger ExpansionErr, MonadReader ExpanderContext)

This is a significant shift to Debug. Validate that all places formerly relying on MonadError semantics now handle or interpret ExpansionErr via debug.

✅ Verification successful

Let me gather information about the usage of MonadError and Debug in the codebase.


Let me search for more specific error handling patterns to understand how errors are handled in the codebase.


Based on the gathered information, I can now provide the final response:

The shift to Debug monad is properly handled with MonadDebugger instances

The codebase has been properly adapted to use the Debug monad transformer through the MonadDebugger typeclass. The key findings show:

  1. All error handling previously done through MonadError has been systematically replaced with MonadDebugger's debug and catch operations.
  2. The Expand monad correctly derives MonadDebugger ExpansionErr instance, ensuring proper error handling throughout the expander.
  3. Error propagation is consistently handled via the Debug monad's semantics, with proper instances for transformer stacks (Reader, State).
  4. The codebase shows systematic use of debug for error reporting across all expansion-related modules (Expander.Syntax, Expander.TC, etc.).
🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for MonadError usage
rg "MonadError" -A 3

# Search for Debug type and its usage
rg "Debug\s+\w+\s+\w+" -A 3

# Search for ExpansionErr
rg "ExpansionErr" -A 3

# Look for error handling patterns
ast-grep --pattern 'throwError $_'

Length of output: 4753


Script:

#!/bin/bash
# Search for debug error handling patterns
rg "debug\s+" -A 3

# Search for catch usage
rg "catch\s+" -A 3

# Look for MonadDebugger type class definition
ast-grep --pattern 'class MonadDebugger'

# Search for error handling in Expand monad
rg "Expand.*Error" -A 3

Length of output: 24368

examples/non-examples/stack-traces/error-in-list.kl (1)

7-7: Ensure appropriate handling when calling (fail the-error).

the-error is a symbolic error object, while fail expects a numeric argument. This will likely result in an error if these are combined at runtime. Consider adding type checks or clarifying usage to avoid unexpected failures.

src/StackTraces.hs (1)

36-37: Ensure all EvalError variants are displayed consistently.

printErr uses pretty, but some EvalError variants might need specialized formatting to provide optimal troubleshooting information. Verify that these variants are handled as intended.

flake.nix (2)

24-24: Confirm that cabal-install is necessary in all development scenarios.

Including cabal-install may be desirable for local builds. Ensure that the rest of the team also installs or uses it consistently to avoid environment disparities.


55-57: Validate the KLISTERPATH environment variable.

Setting KLISTERPATH to examples/ helps with local testing but may need refinement if code examples or tests exist in other directories. Confirm the correct path to ensure all examples are found.

klister.cabal (1)

63-63: Adding Debugger as an exposed module looks good.

This new module is properly declared and consistent with the rest of the code changes aimed at improving error handling and debug support.

repl/Main.hs (4)

36-36: Encapsulation Benefit from newtype
Switching Options to a newtype is a good practice, providing a more transparent type at runtime while maintaining a clear separation at the type level. This helps avoid accidental misuse of the underlying constructor.


37-38: Addition of runOptBindingInfo
The new boolean field runOptBindingInfo should be tested to verify its impact. If its usage influences output conditionally, ensure there's a test covering that path.


41-41: Consistency in Using newtype ReplOptions
Using newtype for ReplOptions improves type safety and consistency with Options.


66-67: Subcommand Parser Readability
The parser updates increase readability by removing extra parentheses. Ensure help text and usage messages remain accurate for the "run" and "repl" commands.

src/Expander/Syntax.hs (15)

6-6: TypeOperators Language Extension
Enabling TypeOperators here is common for more advanced type-level constructs. Confirm there's a team-wide agreement on using these language extensions for broad consistency.


28-28: Use of debug (NotIdentifier other)
Replacing error throws with debug calls avoids immediate failure but might degrade discoverability of certain logic mistakes. Review downstream usage to ensure essential errors still surface properly.


32-32: Empty List Check
debug (NotEmpty other) clarifies an expected shape. Double-check that any code relying on the older thrown exception pattern is updated to handle the new debug approach.


36-36: Cons Check
debug (NotCons other) fits the pattern for logging errors in Syntax checks. Ensure the user or developer receives appropriate feedback when syntax is invalid.


40-40: Cons-Cons Check
debug (NotConsCons other) is consistent with the new debugging approach. Confirm that the build or test suite covers scenarios that trigger this message.


45-45: List Check
debug (NotList other)—similarly be sure this debug message is tested so real syntax mistakes become discoverable.


49-49: Integer Check
debug (NotInteger other) might obscure type-level errors if not tested. Consider a test covering non-integer inputs.


53-53: String Check
debug (NotString other) continues the same logging approach. Keep consistency for user-facing messages.


65-65: Not a Module Name
debug (NotModName other)—the user might need to see the invalid name in context. Double-check that the diagnostic includes a helpful snippet.


78-78: List Length Error
debug (NotRightLength lengths stx)—helpful for understanding mismatched macro patterns. Ensure tests exist for multiple valid lengths.


80-80: Not a List
debug (NotList other) triggered if the shape is not a List at all. Same checks about coverage apply.


145-146: mustHaveShape for Empty
debug (NotEmpty other) and debug (NotList other) replaced older error approach. Please confirm call sites that rely on a thrown error are updated.


157-158: mustHaveShape for Pairs
debug (NotCons other) and debug (NotList other)—similar note on verifying code that depends on the older approach.


167-167: mustHaveShape for Lists
debug (NotList other) might cause silent debugging logs if unhandled. Confirm there's an integration test for this scenario.


Line range hint 691-691: UnknownPattern
debug (UnknownPattern other) replaces a thrown error. Ensure there's a mechanism to handle unknown patterns gracefully or fail fast if needed in production.

src/Expander/Error.hs (20)

3-3: LambdaCase Extension
Enabling LambdaCase is consistent with the rest of the codebase. No issues noted.


54-55: MacroEvaluationError & ValueNotMacro
Switching to EState ties them more closely to the new debugging framework. This can help track evaluation context in logs. Confirm all references to old error types are updated.


130-130: NotCons Pretty Printer
Good alignment with the new debugging phrasing.


132-132: NotConsCons
All good. No suggestions beyond verifying final error string.


134-134: NotList Pretty Printer
Clearer error messages are beneficial.


146-146: NotModName
Ensuring the expected module name gets clarified in error. Looks good.


151-151: NotRightLength
The alts function is a neat approach to handle multiple expected lengths. The error text is user-friendly.


166-166: NotVec
Indicates an expectation for square-bracketed syntax. The error message is now consistent with other Not* style messages.


168-168: NotImportSpec
No concerns. The code is consistent with the new style.


170-170: NotExportSpec
Same note as above regarding consistency.


172-172: UnknownPattern
Ensures that unrecognized patterns become a known debugging scenario.


177-177: MacroRaisedSyntaxError
Displaying additional locations is helpful. Make sure there's no performance overhead if the location list grows large.


186-186: MacroEvaluationError
Now references EState. This design fits the new debugging approach well.


196-196: NotExported
It’s good you’re including the phase in the message. Ensure the location is well formatted for large codebases.


205-205: WrongSyntacticCategory
The structure is more streamlined.


207-211: Neat Separation of Expected vs. Supported
The use of hinges (hang) + vsep for multi-line output is a nice improvement for error readability.


228-228: NotAConstructor
Error text for constructor mismatch is consistent with the new style.


236-238: KindMismatch
Using maybe (text "unknown location") ... elegantly handles possible missing source locations.


246-263: TypeMismatch
Good to see the more explicit detail in the error message. The “Specifically” block helps highlight submismatches.


269-270: OccursCheckFailed
The error text is direct, describing the pointer and type. All good.

src/Expander/Primitives.hs (4)

76-76: Debugger Import
Consistent with the rest of the codebase’s shift to debugging.


522-522: WrongTypeArity Handling
Using debug ensures the code logs an error rather than raising an exception. Confirm that calling code can proceed gracefully if the arity is wrong.


534-534: Patterned WrongTypeArity
Again, ensure that shifting from a thrown error to a debug call does not break any expected short-circuit behavior.


592-592: NotValidType in makeLocalType
Previously, an invalid type might raise an exception. Now it's logged via debug. Double-check any dependent logic that might assume an exception.

src/Expander.hs (1)

61-61: LGTM! New import aligns with PR objectives.

The addition of the Debugger import supports the transition to improved stack trace functionality.

Comment on lines +73 to +79
instance Monad (Debug r e) where
Debug m >>= f = Debug $ \r -> do
ma <- m r
case ma of
Left err -> return (Left err)
Right val -> fmap (debugRunT r) f val

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Potential issue in Monad (Debug r e) bind.

Debug m >>= f = Debug $ \r -> do
  ma <- m r
  case ma of
    Left err  -> return (Left err)
    Right val -> fmap (debugRunT r) f val

This snippet uses fmap (debugRunT r) f val, which looks suspicious and might not apply the function f val in the usual monadic style. It's typically f val → some Debug r e b, and then you'd call runDebug (f val) r. Double-check the logic to ensure you properly chain monadic computations.

Comment on lines +736 to +743
let ppPattern = \case
SyntaxPatternIdentifier i _ -> pp e i
SyntaxPatternInteger i _ -> pp e i
SyntaxPatternString i _ -> pp e i
SyntaxPatternCons il _iv rl _rv -> pp e il <> pp e rl
SyntaxPatternList ls -> foldMap (\(i, _) -> pp e i) ls
SyntaxPatternAny -> text "_"
SyntaxPatternEmpty -> text "()"
in text "in case pattern" <> ppPattern p <> pp e k
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Clarify pattern printing.

SyntaxPatternIdentifier i _
SyntaxPatternInteger i _
SyntaxPatternString i _
SyntaxPatternCons ...
SyntaxPatternList ...
SyntaxPatternAny
SyntaxPatternEmpty

In printKont, you display only the main pattern parts. If debugging intricate macros, you might want the variable names or capturing environment. Evaluate if more detail is necessary for diagnosing pattern failures.


execExpand :: ExpanderContext -> Expand a -> IO (Either ExpansionErr a)
execExpand ctx act = runExceptT $ runReaderT (runExpand act) ctx

execExpand ctx act = runDebug (runReaderT (runExpand act) ctx) initialContext
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Review execExpand for partial results.

execExpand ctx act = runDebug (runReaderT (runExpand act) ctx) initialContext

While returning Either ExpansionErr a, confirm that partial expansions (e.g., incomplete tasks) are consistently handled or re-queued. If not, it might silently skip expansions.

Comment on lines 657 to 661
Nothing -> debug $ InternalError "Missing expr after expansion"
Just e' ->
linkedScheme schPtr >>=
\case
Nothing -> throwError $ InternalError "Missing example scheme after expansion"
Nothing -> debug $ InternalError "Missing example scheme after expansion"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Based on the gathered information, I can now provide the final response:

Enhance error messages with source location for missing examples

The error messages should include the source location (loc) that's already available in the Example constructor. Update the error messages to:

Nothing -> debug $ InternalError $ "Missing expr after expansion at " <> show loc
Nothing -> debug $ InternalError $ "Missing example scheme after expansion at " <> show loc

The Example constructor already carries location information (SrcLoc) which includes file path, start, and end positions. This information should be used to help users identify which example is incomplete.

🔗 Analysis chain

Enhance example’s error.

Nothing -> debug $ InternalError "Missing expr after expansion"
Nothing -> debug $ InternalError "Missing example scheme after expansion"

Examples are user-facing. Provide the user with either a source location or snippet to identify which example is incomplete.


Let me gather more information about the error handling and example-related code to provide a thorough verification.


Let me search for more context about the Example constructor and location information.


Let me try one more search to find the location-related information.

🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for the context around the error handling
rg -B 5 -A 5 "Missing (expr|example scheme) after expansion" src/

# Look for example-related types and data structures
ast-grep --pattern 'data Example = $_'

# Find where examples are processed
rg -B 3 -A 3 "linkedScheme" src/

Length of output: 4268


Script:

#!/bin/bash
# Look for Example constructor definition and usage
ast-grep --pattern 'Example $_ $_ $_'

# Search for location-related types and usage
rg -B 2 -A 2 "type Loc = " src/
rg "data Loc = " src/

Length of output: 1431


Script:

#!/bin/bash
# Search for location usage in error messages and source locations
rg -B 2 -A 2 "stxSrcLoc|srcLoc|SrcLoc" src/

# Look for the Example constructor in data type definitions
rg -B 3 -A 3 "data (Decl|Tree|AST|Syntax)" src/

Length of output: 15343

klister.cabal Outdated
@@ -42,6 +42,7 @@ common deps
megaparsec >= 7.0.5 && < 9.7,
mtl >= 2.2.2 && < 2.4,
prettyprinter >= 1.2 && < 1.8,
prettyprinter >= 1.2 && < 1.8,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove redundant prettyprinter dependency entry.

Line 45 duplicates the prettyprinter constraint. Consider removing one entry to maintain clarity and avoid potential confusion in dependency management.

src/Expander.hs Outdated Show resolved Hide resolved
src/Expander.hs Outdated
Comment on lines 1330 to 1336
Nothing -> error $ show $ InternalError $
"No transformer yet created for " ++ shortShow ident ++
" (" ++ show transformerName ++ ") at phase " ++ shortShow p
Just other -> throwError $ ValueNotMacro other
-- debug $ InternalError $
-- "No transformer yet created for " ++ shortShow ident ++
-- " (" ++ show transformerName ++ ") at phase " ++ shortShow p
Just other -> error "debug $ ValueNotMacro other"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Replace error calls with debug for transformer-related errors.

The error handling for transformer-related issues uses direct error calls and has commented-out debug statements.

Apply this diff to maintain consistency:

-            Nothing -> error $ show $ InternalError $
-              "No transformer yet created for " ++ shortShow ident ++
-              " (" ++ show transformerName ++ ") at phase " ++ shortShow p
-              -- debug $ InternalError $
-              -- "No transformer yet created for " ++ shortShow ident ++
-              -- " (" ++ show transformerName ++ ") at phase " ++ shortShow p
-            Just other -> error "debug $ ValueNotMacro other"
+            Nothing -> debug $ InternalError $
+              "No transformer yet created for " ++ shortShow ident ++
+              " (" ++ show transformerName ++ ") at phase " ++ shortShow p
+            Just other -> debug $ ValueNotMacro other
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Nothing -> error $ show $ InternalError $
"No transformer yet created for " ++ shortShow ident ++
" (" ++ show transformerName ++ ") at phase " ++ shortShow p
Just other -> throwError $ ValueNotMacro other
-- debug $ InternalError $
-- "No transformer yet created for " ++ shortShow ident ++
-- " (" ++ show transformerName ++ ") at phase " ++ shortShow p
Just other -> error "debug $ ValueNotMacro other"
Nothing -> debug $ InternalError $
"No transformer yet created for " ++ shortShow ident ++
" (" ++ show transformerName ++ ") at phase " ++ shortShow p
Just other -> debug $ ValueNotMacro other

Comment on lines +564 to 565
Left err -> error (T.unpack (pretty err))
Right vioy -> pure vioy
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Replace direct error call with debug for consistent error handling.

The error handling here is inconsistent with the rest of the changes in the file. Other locations use the new debug functionality for error reporting.

Apply this diff to maintain consistency:

-                      Left err -> error (T.unpack (pretty err))
+                      Left err -> debug $ MacroEvaluationError p err

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +1340 to +1347
debug $ InternalError "All modules should be identifier-headed"
DeclTreeDest {} ->
throwError $ InternalError "All declarations should be identifier-headed"
debug $ InternalError "All declarations should be identifier-headed"
TypeDest {} ->
throwError $ NotValidType stx
debug $ NotValidType stx
ExprDest t dest ->
case syntaxE stx of
List xs -> expandOneExpression t dest (addApp stx xs)
Integer n -> expandOneExpression t dest (addIntegerLiteral stx n)
String s -> expandOneExpression t dest (addStringLiteral stx s)
Id _ -> error "Impossible happened - identifiers are identifier-headed!"
PatternDest {} ->
throwError $ InternalError "All patterns should be identifier-headed"
debug $ InternalError "All patterns should be identifier-headed"
TypePatternDest {} ->
throwError $ InternalError "All type patterns should be identifier-headed"
debug $ InternalError "All type patterns should be identifier-headed"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Replace internal error calls with debug for consistent error handling.

Multiple internal errors are using direct error calls instead of the new debug functionality.

Apply this diff to maintain consistency:

-        debug $ InternalError "All modules should be identifier-headed"
+        debug $ NotValidSyntax "All modules should be identifier-headed" stx
-        debug $ InternalError "All declarations should be identifier-headed"
+        debug $ NotValidSyntax "All declarations should be identifier-headed" stx
-        debug $ NotValidType stx
+        debug $ NotValidType stx
-          Id _ -> error "Impossible happened - identifiers are identifier-headed!"
+          Id _ -> debug $ InternalError "Impossible happened - identifiers are identifier-headed!"
-        debug $ InternalError "All patterns should be identifier-headed"
+        debug $ NotValidSyntax "All patterns should be identifier-headed" stx
-        debug $ InternalError "All type patterns should be identifier-headed"
+        debug $ NotValidSyntax "All type patterns should be identifier-headed" stx
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
debug $ InternalError "All modules should be identifier-headed"
DeclTreeDest {} ->
throwError $ InternalError "All declarations should be identifier-headed"
debug $ InternalError "All declarations should be identifier-headed"
TypeDest {} ->
throwError $ NotValidType stx
debug $ NotValidType stx
ExprDest t dest ->
case syntaxE stx of
List xs -> expandOneExpression t dest (addApp stx xs)
Integer n -> expandOneExpression t dest (addIntegerLiteral stx n)
String s -> expandOneExpression t dest (addStringLiteral stx s)
Id _ -> error "Impossible happened - identifiers are identifier-headed!"
PatternDest {} ->
throwError $ InternalError "All patterns should be identifier-headed"
debug $ InternalError "All patterns should be identifier-headed"
TypePatternDest {} ->
throwError $ InternalError "All type patterns should be identifier-headed"
debug $ InternalError "All type patterns should be identifier-headed"
debug $ NotValidSyntax "All modules should be identifier-headed" stx
DeclTreeDest {} ->
debug $ NotValidSyntax "All declarations should be identifier-headed" stx
TypeDest {} ->
debug $ NotValidType stx
ExprDest t dest ->
case syntaxE stx of
List xs -> expandOneExpression t dest (addApp stx xs)
Integer n -> expandOneExpression t dest (addIntegerLiteral stx n)
String s -> expandOneExpression t dest (addStringLiteral stx s)
Id _ -> debug $ InternalError "Impossible happened - identifiers are identifier-headed!"
PatternDest {} ->
debug $ NotValidSyntax "All patterns should be identifier-headed" stx
TypePatternDest {} ->
debug $ NotValidSyntax "All type patterns should be identifier-headed" stx

Copy link
Collaborator

@david-christiansen david-christiansen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation looks like a great application of the CEK-style evaluator!

Two things:

  1. The pretty-printer changes seem to be almost entirely regressions, grouping unrelated things and separating related things. They also make the diff harder to follow, because there's tons of noise in tests. Reverting most of the deletions of group should fix that, I think. What problem was it solving?
  2. Why is there a list of EStates in a debug context? It seems to me that the debugger should get a single evaluator state.

examples/ambiguous-kind.golden Outdated Show resolved Hide resolved
examples/contract.golden Outdated Show resolved Hide resolved
error-in-arg.kl:5.24-5.27:
bad
stack trace:
---- with function #<closure>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we provide more info here? Perhaps closures can contain the source position of their corresponding lambda?

@@ -0,0 +1,3 @@
#lang "prelude.kl"

(example (>>= (pure (error 'e)) (lambda (x) (pure x))))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing newline!

(>>= (pure 'hello-go-boom)
(lambda (x)
(>>= (syntax-error x)
-- TODO: why doesn't this work?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a strange error indeed!

src/Pretty.hs Outdated Show resolved Hide resolved
src/Pretty.hs Outdated Show resolved Hide resolved
src/Pretty.hs Outdated Show resolved Hide resolved

printKont :: Env Var () -> Kont -> Doc VarInfo
-- the basics
printKont _ Halt = text "Halt"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In empty traces, this was a bit confusing. What about suppressing it, and then special-casing empty continuations at the outside?

<> pp e k

-- pairs
-- TODO: DYG: how to test the cons?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about adding unsafeCoerce as a primitive for testing?

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/Expander.hs (1)

1333-1347: 🛠️ Refactor suggestion

Consider using NotValidSyntax for better error reporting.

Replace InternalError with NotValidSyntax for better error messages when handling invalid syntax.

Apply this diff to improve error reporting:

-        debug $ InternalError "All modules should be identifier-headed"
+        debug $ NotValidSyntax "All modules should be identifier-headed" stx
-        debug $ InternalError "All declarations should be identifier-headed"
+        debug $ NotValidSyntax "All declarations should be identifier-headed" stx
-        debug $ InternalError "All patterns should be identifier-headed"
+        debug $ NotValidSyntax "All patterns should be identifier-headed" stx
-        debug $ InternalError "All type patterns should be identifier-headed"
+        debug $ NotValidSyntax "All type patterns should be identifier-headed" stx
🧹 Nitpick comments (3)
src/Evaluator.hs (3)

11-25: Consider enhancing the module documentation.

While the module header is well-structured, it would benefit from additional details about:

  • How the CEK machine state is converted to stack traces
  • The relationship between debugging and stack traces
  • Examples of stack trace output format

160-166: Consider documenting performance implications.

While the Note [InCasePattern] explains the debugging benefits, it would be helpful to document:

  • Performance overhead of evaluating patterns in the interpreter vs. host runtime
  • Any benchmarking results if available
  • Scenarios where this overhead might be significant

629-667: Consider refactoring pattern matching logic.

The pattern matching implementation in match functions shows similar patterns that could be abstracted:

  • Common pattern of extending environment and wrapping with InCasePattern
  • Similar error handling paths

Consider introducing a helper function:

matchWithPattern :: SyntaxPattern -> Core -> Value -> VEnv -> Kont -> EState -> (VEnv -> EState) -> EState
matchWithPattern pat rhs scrutinee env k next success =
  case (pat, scrutinee) of
    (SyntaxPatternIdentifier n x, v@(ValueSyntax (Syntax (Stx _ _ (Id _))))) ->
      success $ extend n x v env
    _ -> next
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 95a0ba5 and 4de0c16.

📒 Files selected for processing (4)
  • klister.cabal (1 hunks)
  • src/Evaluator.hs (10 hunks)
  • src/Expander.hs (26 hunks)
  • src/Expander/Monad.hs (13 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • klister.cabal
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: macOS-latest / ghc 9.6
  • GitHub Check: ubuntu-latest / ghc 9.2.5
  • GitHub Check: ubuntu-latest / ghc 9.4
  • GitHub Check: ubuntu-latest / ghc 9.6
  • GitHub Check: stack / ghc 9.2.8
🔇 Additional comments (18)
src/Evaluator.hs (1)

583-593: Plan to remove stopgap error handling.

The constructErrorType function is marked as a temporary solution. Consider:

  • Creating a tracking issue for its removal
  • Documenting the proper error handling approach that should replace it
  • Adding tests to ensure consistent error handling behavior

Would you like me to help create a GitHub issue to track this technical debt?

src/Expander/Monad.hs (8)

177-177: LGTM!

The Debugger module import is correctly placed and aligns with the new error handling approach.


208-212: LGTM! Monad transformation looks good.

The change from ExceptT to Debug monad is well-structured and maintains the required type class instances. The MonadDebugger instance is correctly derived.


215-215: Verify handling of partial results in execExpand.

While the change to use runDebug is correct, ensure that partial expansions are properly handled.

Run this script to check for potential partial expansion scenarios:

#!/bin/bash
# Search for expansion tasks that might be incomplete
rg -B 2 -A 2 "forkExpanderTask|stillStuck" src/

599-599: LGTM! Error handling is consistent.

The error handling is properly updated to use debug and provides a clear error message.


Line range hint 610-623: LGTM! Error handling is consistent.

The error handling is properly updated to use debug with appropriate error messages for missing declarations and expressions.


632-632: LGTM! Error handling is consistent.

The error handling for missing expressions in macro definitions is properly updated to use debug.


657-661: LGTM! Enhanced error messages with location information.

The error handling for missing expressions and schemes in examples is properly updated to use debug and includes helpful source location information.


668-668: LGTM! Error handling is consistent.

The error handling for missing actions is properly updated to use debug.

src/Expander.hs (9)

153-156: LGTM! Error handling is consistent.

The error handling for file existence and reader errors is properly updated to use debug.


199-199: LGTM! Error handling is consistent.

The error handling for non-exported identifiers is properly updated to use debug.


851-851: LGTM! Error handling is consistent.

The error handling for no progress in tasks is properly updated to use debug.


Line range hint 867-870: LGTM! Error handling is consistent.

The error handling for macro evaluation errors is properly updated to use debug.


915-919: LGTM! Error handling is consistent.

The error handling for type case evaluation errors is properly updated to use debug.


1324-1329: LGTM! Error handling is consistent.

The error handling for macro expansion errors is properly updated to use debug with appropriate error messages for various failure cases.


1411-1417: LGTM! Error handling is consistent.

The error handling for macro evaluation errors is properly updated to use debug with appropriate error messages.


1424-1432: LGTM! Error handling is consistent.

The error handling for identifier comparison is properly updated to use debug with appropriate error messages and exception handling.


1440-1440: LGTM! Error handling is consistent.

The error handling for invalid syntax objects is properly updated to use debug.

Comment on lines +713 to +715
projectError :: EState -> EvalError
projectError (Er err _env _kont) = err
projectError _ = error "projectError not used on an error!"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve type safety of projectError.

The projectError function could panic if called with non-error states. Consider:

  • Using Haskell's type system to prevent invalid usage
  • Returning Maybe EvalError instead of using error
projectError :: EState -> Maybe EvalError
projectError (Er err _env _kont) = Just err
projectError _                   = Nothing

@doyougnu doyougnu force-pushed the doyougnu/stack-traces branch from 4de0c16 to cc73f7f Compare January 8, 2025 19:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants