Skip to content
New issue

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

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

Already on GitHub? # to your account

Implemented account interpolation syntax #44

Merged
merged 7 commits into from
Mar 5, 2025

Conversation

ascandone
Copy link
Contributor

@ascandone ascandone commented Mar 4, 2025

Backwards compatibility

The feature is backward compatible: the described syntax was previously invalid, therefore no previous programs with such syntax exist

Specs

That's a minimal, very constrained version of a general string/account interpolation syntax:

// old syntax is backwards-compatible
@acc

// but we can now interpolate values between ":"
@user:$id:pending

this can lead to invalid account names: @user:$status could be evaluated as @user:!<invalid>, which is currently not a valid username

Interpolated values are implicitly cast to string. This only applies to the following types: account, string, number. Other types will raise a runtime error

Limitations

This interpolation implementation is very constrained: one can only interpolate using the "something:something" naming convention. As a consequence, the following values will not be possible:

// using a more general, pseudosyntax:
@`acc{$id}` // e.g. acc42 
@`acc-{$year}-{$month}-{$day}` // e.g. acc-2027-12-01

the reason of this limitation is that

  1. in practice, this limited syntax should do just as fine, while enforcing the usual naming conventions
  2. this is the most natural way for the user to express interpolation
  3. if this turns out too limiting, we can generalise the syntax without breaking changes, using a syntax like the one in the previous example

Technical notes

The huge diff in grammar definition is due to the fact that the tokens were split in a different file in order to use antlr's lexical modes

Copy link

coderabbitai bot commented Mar 4, 2025

Walkthrough

The changes introduce a new lexer grammar (Lexer.g4) with an extensive set of token definitions and modes for account parsing. The Numscript grammar (Numscript.g4) has been refactored to remove inline token definitions in favor of an external lexer by referencing tokenVocab = 'Lexer', and its expression rules have been updated accordingly. The parser generation script now produces both lexer and parser outputs in a new directory with renamed files and package changes. Internal analysis, interpreter, and AST components have been modified to support an enhanced account interpolation literal, and new tests have been added for these features. Package names have been adjusted from “parser” to “antlrParser” across multiple files.

Changes

Files Change Summary
Lexer.g4 Introduced new lexer grammar with token rules for keywords, literals, operators, whitespace, comments, and modes (DEFAULT_MODE and ACCOUNT_MODE) for account parsing.
Numscript.g4 Removed inline token definitions; added options { tokenVocab = 'Lexer'; }; updated valueExpr rule and replaced literal tokens with references (e.g., ONEOF).
generate-parser.sh Updated command to generate both lexer and parser; output directory changed to internal/parser/antlrParser; generated lexer file renamed from _lexer.go to lexer.go.
internal/analysis/*.go In check.go and hover.go, replaced AccountLiteral with AccountInterpLiteral and enhanced account validation; added new tests in check_test.go and hover_test.go for string interpolation and account hover functionality.
internal/interpreter/*.go In evaluate_expr.go, added case handling for AccountInterpLiteral with a new castToString helper; in interpreter.go added ExperimentalAccountInterpolationFlag; in interpreter_error.go introduced the CannotCastToString error; new tests in interpreter_test.go validate account interpolation outcomes.
internal/parser/antlr* Removed legacy ANTLR files (e.g., Numscript.interp, Numscript.tokens, numscript_lexer.go, etc.); introduced new files in the antlrParser directory (e.g., Lexer.interp, Lexer.tokens, lexer.go, numscript_parser.go) with updated token names, listener interfaces, and context types for account interpolation; package renaming from parser to antlrParser applied consistently.
internal/parser/ast.go Replaced AccountLiteral with AccountInterpLiteral having a Parts slice instead of a single Name; added new types and methods (e.g., String, IsWorld, and account name part interfaces) to accommodate complex account representations.
internal/parser/parser.go & parser_test.go Updated function signatures and contexts to use antlrParser types; added new tests (TestStringTemplate and TestInterpAccount) to cover string templates and interpolated account parsing.

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant L as Lexer
    participant P as Parser
    participant A as AST Builder
    participant I as Interpreter
    U->>L: Submit script with account interpolation literal
    L->>P: Provide token stream (includes ACCOUNT_START, COLON, etc.)
    P->>A: Build AST with AccountInterpLiteral (composed of Parts)
    A->>I: Pass AST for evaluation
    I->>I: Loop through each part in AccountInterpLiteral
    alt Text part
      I->>I: Append literal text to account string
    else Variable part
      I->>I: Evaluate variable and invoke castToString
    end
    I-->>U: Return constructed account address
Loading

Suggested reviewers

  • altitude
  • gfyrag

Poem

Oh, how I hop with glee,
New tokens and modes set me free.
Grammar refined with a rhythmic beat,
Every parse and rule so neat.
I nibble code and bounce along,
Celebrating changes with a cheery song!
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ 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.
  • @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

codecov bot commented Mar 4, 2025

Codecov Report

Attention: Patch coverage is 84.70320% with 134 lines in your changes missing coverage. Please review.

Project coverage is 63.48%. Comparing base (ca9646b) to head (0ef5444).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
internal/parser/antlrParser/numscript_parser.go 81.15% 81 Missing and 10 partials ⚠️
internal/parser/ast.go 0.00% 29 Missing ⚠️
internal/interpreter/interpreter_error.go 0.00% 4 Missing ⚠️
...rnal/parser/antlrParser/numscript_base_listener.go 0.00% 4 Missing ⚠️
internal/interpreter/evaluate_expr.go 90.90% 2 Missing and 1 partial ⚠️
internal/parser/parser.go 96.05% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #44      +/-   ##
==========================================
- Coverage   63.64%   63.48%   -0.16%     
==========================================
  Files          31       31              
  Lines        6824     7101     +277     
==========================================
+ Hits         4343     4508     +165     
- Misses       2281     2384     +103     
- Partials      200      209       +9     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@ascandone ascandone marked this pull request as ready for review March 4, 2025 14:07
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: 2

🔭 Outside diff range comments (1)
internal/parser/antlrParser/numscript_listener.go (1)

1-261: 💡 Verification agent

🧩 Analysis chain

Verify broader impact of package name change.

The package name change from parser to antlrParser may require updates in import statements throughout the codebase.


🏁 Script executed:

#!/bin/bash
# Find any remaining references to the old package name in import statements
echo "Checking for import statements referencing the old package..."
rg -A 1 -B 1 "import.*parser" --glob "*.go" | grep -v "antlrParser"

echo "Checking for usages of the old package name..."
rg "\bparser\." --glob "*.go" | grep -v "antlrParser"

Length of output: 50654


Action required: Update all outdated package references from parser to antlrParser

The renaming of the package in internal/parser/antlrParser/numscript_listener.go has a broader impact. Our search indicates that many files still reference the old package name (parser), both in import statements and as a qualifier in type and function calls. Please update all import paths and usages to use antlrParser (or the new alias if applicable) to ensure consistency across the codebase.

Files (among others) that require updates:

  • internal/analysis/goto_definition.go (e.g., import "github.com/formancehq/numscript/internal/parser")
  • internal/interpreter/args_parser.go and its test file
  • internal/lsp/language_server/message_buffer_test.go
  • Numerous references in files under internal/analysis, internal/interpreter, internal/lsp, and other directories

Please review and update the affected lines accordingly so that all stale parser references are either replaced with antlrParser or updated as per the new package structure.

🧹 Nitpick comments (15)
generate-parser.sh (1)

1-2: Add shebang line and enhance script organization.

The script is missing a shebang line to specify which shell to use for execution, which was flagged by the static analysis tool.

+#!/bin/bash
+
 antlr4 -Dlanguage=Go Lexer.g4 Numscript.g4 -o internal/parser/antlrParser -package antlrParser
 mv internal/parser/antlrParser/_lexer.go internal/parser/antlrParser/lexer.go
🧰 Tools
🪛 Shellcheck (0.10.0)

[error] 1-1: Tips depend on target shell and yours is unknown. Add a shebang or a 'shell' directive.

(SC2148)

internal/parser/antlrParser/numscript_base_listener.go (1)

1-278: Consider documenting the new account interpolation syntax.

The implementation adds support for the new account interpolation syntax, but it might be helpful to include documentation comments explaining the syntax constraints (e.g., that it supports "something:something" but not more complex interpolations like @acc{$id} as mentioned in the PR objectives).

Consider adding documentation to the package-level comments or to the relevant listener methods to explain the syntax constraints and provide usage examples.

internal/parser/ast.go (1)

105-116: String() method with inline concatenation for account parts.
Building the final string via strings.Join is concise. However, consider the TODO comment about parsing for more robust handling of special cases or invalid parts. If expanded interpolation logic is required later, a proper parser step might be safer.

internal/parser/antlrParser/lexer.go (1)

21-21: Remove TODO comment before finalizing the PR.

The TODO comment indicates an incomplete implementation of the EOF (End of File) token handling. Consider addressing this before merging the PR to ensure proper EOF handling.

internal/interpreter/interpreter.go (1)

185-185: Feature flag follows consistent naming pattern.

The new experimental feature flag follows the same naming pattern as existing flags and uses a descriptive name. Consider adding documentation that explains when and how to use this flag.

-	ExperimentalAccountInterpolationFlag     FeatureFlag = "experimental-account-interpolation"
+	// ExperimentalAccountInterpolationFlag enables the account interpolation syntax
+	// Example: @account:$variable:suffix
+	ExperimentalAccountInterpolationFlag     FeatureFlag = "experimental-account-interpolation"
internal/interpreter/interpreter_error.go (1)

211-213: Consider adding more context to the error message.

The error message could be improved to provide more context about where or why the casting failed, which would help with debugging.

func (e CannotCastToString) Error() string {
-	return fmt.Sprintf("Cannot cast this value to string: %s", e.Value)
+	return fmt.Sprintf("Cannot cast value to string for account interpolation: %s (type: %T)", e.Value, e.Value)
}
internal/interpreter/evaluate_expr.go (1)

15-41: Consider validating the constructed account name.
The logic for assembling parts of the account name is correct, but there's a TODO note about validating valid names. It might be worth implementing basic checks (e.g., allowable characters, non-empty parts) to ensure invalid interpolated accounts are caught early.

internal/parser/parser_test.go (2)

423-430: Enhance test with descriptive name and actual string template

This test verifies basic parameter parsing but doesn't actually test string templates as the name suggests. Consider either renaming the test to reflect its actual purpose or updating it to test real string template functionality.

-func TestStringTemplate(t *testing.T) {
+func TestNumericArgumentsInFunctionCall(t *testing.T) {
	p := parser.Parse(
		"set_tx_meta(0, 42)",
	)

	require.Len(t, p.Errors, 0)
	snaps.MatchSnapshot(t, p.Value)
}

If the intent was to test actual string templates, consider using an example with interpolation:

-func TestStringTemplate(t *testing.T) {
-	p := parser.Parse(
-		"set_tx_meta(0, 42)",
-	)
+func TestStringTemplate(t *testing.T) {
+	p := parser.Parse(
+		`set_tx_meta("template:$id", 42)`,
+	)

	require.Len(t, p.Errors, 0)
	snaps.MatchSnapshot(t, p.Value)
}

432-439: Expand test coverage of account interpolation syntax

This test only covers one account interpolation pattern. Consider adding tests for additional patterns to ensure comprehensive coverage of the new syntax.

Based on the PR objectives, the implementation supports interpolated values between colons in account names. Consider adding tests for:

  1. Simple account with one interpolation: @user:$id
  2. Multiple interpolations: @user:$id:$status
  3. Edge cases like empty segments: @user::$id
  4. Invalid interpolations that should fail parsing

For example:

func TestInterpAccount(t *testing.T) {
	p := parser.Parse(
		"set_tx_meta(@abc:cde:$id, 42)",
	)

	require.Len(t, p.Errors, 0)
	snaps.MatchSnapshot(t, p.Value)
+
+	// Test simple interpolation
+	p = parser.Parse(
+		"set_tx_meta(@user:$id, 42)",
+	)
+	require.Len(t, p.Errors, 0)
+
+	// Test multiple interpolations
+	p = parser.Parse(
+		"set_tx_meta(@user:$id:$status, 42)",
+	)
+	require.Len(t, p.Errors, 0)
}
internal/interpreter/interpreter_test.go (2)

3839-3868: Confirmed coverage of account interpolation logic.
These tests effectively validate the new interpolation feature by verifying that variables are inserted correctly within account addresses. It would be beneficial to add a test case covering edge scenarios like an empty string or special characters in the $status variable.


3869-3898: Good negative testing scenario.
Testing that a monetary value cannot be cast to a string is crucial for validation. Consider expanding the coverage to test interpolation failures with partially invalid segments in addition to fully invalid numeric literals.

internal/analysis/check.go (3)

389-395: Consider stricter type checking for each interpolated part.
The current logic treats every part of the interpolated account as [TypeAny], which might fail only at runtime if an invalid type is passed in. Strengthening compile-time checks (e.g., ensuring string-only parts) could help catch incorrect usage earlier.


467-485: Unify logic with non-interpolated account checks.
While this block correctly handles “world” vs. “regular” accounts, there is some duplication of logic also present for plain AccountLiterals elsewhere. Consider extracting common checks to reduce code duplication and ensure consistency across literal types.


488-488: Refactor overdraft checks to avoid repetition.
The check for a world account in an overdraft scenario overlaps with the logic for regular accounts. It might be helpful to unify these code paths for maintainability and clarity.

internal/parser/parser.go (1)

308-311: Consider adding documentation for the new account interpolation feature

The AccountInterpLiteral structure and implementation are correct, but adding documentation comments would help future maintainers understand the intended behavior and limitations of the account interpolation feature.

Consider adding a comment like:

 return &AccountInterpLiteral{
+    // AccountInterpLiteral supports the syntax @text:$var:text where variables
+    // can be interpolated between colons in account names
     Range: litRng,
     Parts: parts,
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ca9646b and 090b32c.

⛔ Files ignored due to path filters (2)
  • internal/parser/__snapshots__/parser_fault_tolerance_test.snap is excluded by !**/*.snap, !**/*.snap
  • internal/parser/__snapshots__/parser_test.snap is excluded by !**/*.snap, !**/*.snap
📒 Files selected for processing (27)
  • Lexer.g4 (1 hunks)
  • Numscript.g4 (3 hunks)
  • generate-parser.sh (1 hunks)
  • internal/analysis/check.go (3 hunks)
  • internal/analysis/check_test.go (1 hunks)
  • internal/analysis/hover.go (1 hunks)
  • internal/analysis/hover_test.go (1 hunks)
  • internal/interpreter/evaluate_expr.go (3 hunks)
  • internal/interpreter/interpreter.go (1 hunks)
  • internal/interpreter/interpreter_error.go (1 hunks)
  • internal/interpreter/interpreter_test.go (1 hunks)
  • internal/parser/antlr/Numscript.interp (0 hunks)
  • internal/parser/antlr/Numscript.tokens (0 hunks)
  • internal/parser/antlr/NumscriptLexer.interp (0 hunks)
  • internal/parser/antlr/NumscriptLexer.tokens (0 hunks)
  • internal/parser/antlr/numscript_lexer.go (0 hunks)
  • internal/parser/antlrParser/Lexer.interp (1 hunks)
  • internal/parser/antlrParser/Lexer.tokens (1 hunks)
  • internal/parser/antlrParser/Numscript.interp (1 hunks)
  • internal/parser/antlrParser/Numscript.tokens (1 hunks)
  • internal/parser/antlrParser/lexer.go (1 hunks)
  • internal/parser/antlrParser/numscript_base_listener.go (2 hunks)
  • internal/parser/antlrParser/numscript_listener.go (3 hunks)
  • internal/parser/antlrParser/numscript_parser.go (60 hunks)
  • internal/parser/ast.go (4 hunks)
  • internal/parser/parser.go (22 hunks)
  • internal/parser/parser_test.go (2 hunks)
💤 Files with no reviewable changes (5)
  • internal/parser/antlr/NumscriptLexer.interp
  • internal/parser/antlr/Numscript.interp
  • internal/parser/antlr/NumscriptLexer.tokens
  • internal/parser/antlr/Numscript.tokens
  • internal/parser/antlr/numscript_lexer.go
🧰 Additional context used
🧠 Learnings (2)
internal/parser/parser.go (1)
Learnt from: ascandone
PR: formancehq/numscript#31
File: internal/parser/antlr/numscript_parser.go:2786-2850
Timestamp: 2025-01-20T22:55:14.279Z
Learning: Do not suggest adding tests or improving test coverage for auto-generated code, especially files with headers indicating they are generated (e.g., "Code generated from X by Y. DO NOT EDIT.").
internal/parser/antlrParser/numscript_parser.go (1)

undefined

<retrieved_learning>
Learnt from: ascandone
PR: #31
File: internal/parser/antlr/numscript_parser.go:2786-2850
Timestamp: 2025-01-20T22:55:14.279Z
Learning: Do not suggest adding tests or improving test coverage for auto-generated code, especially files with headers indicating they are generated (e.g., "Code generated from X by Y. DO NOT EDIT.").
</retrieved_learning>

🪛 Shellcheck (0.10.0)
generate-parser.sh

[error] 1-1: Tips depend on target shell and yours is unknown. Add a shebang or a 'shell' directive.

(SC2148)

🔇 Additional comments (50)
internal/parser/antlrParser/Lexer.interp (1)

1-142: Lexer definition supports the new account interpolation syntax successfully.

The lexer definitions appropriately define modes and tokens for handling the new interpolation syntax. The ACCOUNT_MODE lexer mode, combined with tokens like ACCOUNT_TEXT, VARIABLE_NAME_ACC, and COLON, provides the foundation for parsing account names with interpolated variable values as described in the PR objectives.

internal/parser/antlrParser/numscript_listener.go (3)

3-3: Package name updated correctly.

The package name has been changed from parser to antlrParser to reflect the new directory structure.


13-18: Interface extended with account interpolation support.

Added methods to support entering the text and variable parts of account literals, which is essential for the new account interpolation syntax.


139-144: Corresponding exit methods added correctly.

The corresponding exit methods for the account text and variable parts have been added, maintaining the symmetry of the listener interface.

internal/parser/antlrParser/numscript_base_listener.go (2)

3-3: Package name updated correctly.

The package name has been changed from parser to antlrParser to reflect the new directory structure.


29-40: Base implementation provided for account interpolation methods.

The base implementations for the new account text and variable part methods have been added. These empty implementations provide a good starting point for custom listeners that extend this base class.

internal/parser/ast.go (5)

5-5: Importing "strings" looks appropriate.
This import is needed for the strings.Join usage below. No issues here.


13-20: Implementing valueExpr() for literal and expression types.
Each type now properly satisfies the ValueExpr interface with a no-op method. This design pattern ensures these types are recognized as valid expressions in the parsing and interpretation flow.


52-55: New AccountInterpLiteral struct.
Storing parts in a []AccountNamePart allows for more flexible handling of text vs. variable-based segments. This design lays a solid foundation for the interpolation feature.


76-80: AccountNamePart interface and AccountTextPart struct introduction.
These types create a clear separation between text-based and variable-based account segments. The pointer vs. value usage is consistent (*Variable vs. AccountTextPart).


92-103: IsWorld() method for AccountInterpLiteral.
Checking for a single-part literal named "world" is straightforward. The switch statement is correct, and returning false for non-text parts is appropriate.

internal/parser/antlrParser/Numscript.tokens (2)

1-41: Token definitions for whitespace, comments, and keywords.
All tokens appear consistently assigned to their integer IDs. Ensure these IDs remain stable if other tokens are added in the future to avoid mismatches.


42-70: String literal references for token names.
These mappings ('vars'=5, 'max'=6, etc.) align each keyword with its corresponding token ID. Good approach for maintainability.

internal/parser/antlrParser/Lexer.tokens (2)

1-41: Lexer token definitions for whitespace, comments, and language constructs.
This file parallels the Numscript tokens, ensuring a synchronized lexer. Keeping these definitions autonomous helps with modular maintenance.


42-70: Literal and numeric ID mappings for Lexer tokens.
Assigning explicit numeric IDs and providing string forms ensures consistency with your grammar references. Looks good.

Numscript.g4 (7)

3-5: Switching grammar to rely on external lexer (tokenVocab = 'Lexer').
Removing inline token definitions maintains a clean separation of concerns and aligns with best practices for ANTLR grammar structuring.


10-13: Refined accountLiteralPart rule using ACCOUNT_TEXT or VARIABLE_NAME_ACC.
This rule neatly captures text segments or variable segments, enabling more flexible account interpolation.


15-24: Extended valueExpr to handle interpolated account literals.
Integrating ACCOUNT_START accountLiteralPart (COLON accountLiteralPart)* allows multi-part account strings. This approach matches the newly introduced AccountInterpLiteral logic in the AST.


26-26: functionCallArgs rule accounts for multiple valueExpr parameters.
Supports a flexible function call syntax with optional comma-separated arguments.


30-30: varOrigin production referencing functionCall.
Associating a variable origin with a function call is clear. This introduction fosters dynamic assignment logic.


50-50: Use of ONEOF token for source alternatives.
Shifting from a literal 'oneof' to the ONEOF token is consistent with the external token vocabulary approach and keeps grammar definitions clean.


60-63: Refined destination rule to handle ONEOF destination blocks.
Similar to the source block, this maintains consistency for multi-option destination parsing.

internal/parser/antlrParser/lexer.go (2)

43-44: Account interpolation mode handling looks good.

The lexer implementation properly handles the account interpolation mode transitions. The ACCOUNT_MODE is entered when encountering either the @ symbol or a colon, and is properly exited after processing account text or a variable name.

Also applies to: 47-50


314-315: Well-structured mode definition.

The mode constant is clearly defined and aligns with the mode pattern in the Lexer.g4 grammar file.

Lexer.g4 (3)

43-45: Account interpolation grammar looks well-designed.

The grammar rules for account interpolation are clean and intuitive. The pushMode operations ensure proper context tracking during lexical analysis, which is essential for this syntax feature.


47-50: Good separation of account mode rules.

The dedicated mode for account processing makes the grammar more maintainable and clearly separates the contextual rules for account names from the rest of the language.


48-48:

✅ Verification successful

Verify account name character restrictions.

The ACCOUNT_TEXT rule allows alphanumeric characters, underscores, and hyphens. Ensure this matches your intended restrictions for account names and that it's consistent with any validation that happens elsewhere in the codebase.


🏁 Script executed:

#!/bin/bash
# Look for existing account name validation logic
rg -i "account.*valid" --glob "*.go"

Length of output: 125


Action: Confirm Account Name Restrictions Consistency

It appears that the ACCOUNT_TEXT rule in Lexer.g4—which allows [a-zA-Z0-9_-]+—is intended to cover valid account names. The presence of a test case in internal/interpreter/interpreter_test.go (i.e. TestAccountInvalidString) suggests that account name validation is indeed being verified elsewhere in the codebase.

Please ensure that:

  • The allowed characters in the lexer rule truly reflect the account naming requirements.
  • This validation remains consistent with the logic exercised in the test suite.

If you update the allowed characters or wish to alter these restrictions, remember to update both the lexer and its corresponding tests accordingly.

internal/interpreter/interpreter.go (1)

182-186:

❓ Verification inconclusive

Consider updating feature flag checking logic.

Make sure that the checkFeatureFlag method at line 1045 is used consistently to verify this new flag is enabled before using the account interpolation features.


🏁 Script executed:

#!/bin/bash
# Check for feature flag usage in the codebase
rg "ExperimentalAccountInterpolationFlag" --glob "*.go"

Length of output: 521


Action Required: Ensure Consistent Feature Flag Enforcement

I verified that the new ExperimentalAccountInterpolationFlag is indeed being used to gate the account interpolation feature:

  • In internal/interpreter/evaluate_expr.go, the flag is checked via st.checkFeatureFlag(ExperimentalAccountInterpolationFlag).
  • The tests in internal/interpreter/interpreter_test.go also reference the flag through calls to testWithFeatureFlag.

Please confirm that the account interpolation logic in internal/interpreter/interpreter.go (around line 1045) is likewise protected using the checkFeatureFlag method so that feature gating is applied consistently across all usage sites.

internal/interpreter/interpreter_error.go (2)

206-213: New error type for string casting issues.

The CannotCastToString error type is a good addition for handling type conversion issues during account interpolation. It follows the established error pattern and provides a clear error message that includes the problematic value.


206-209:

✅ Verification successful

Verify error usage in evaluation code.

This error type should be thrown when interpolating values that cannot be cast to strings. Ensure it's properly used in the expression evaluation code.


🏁 Script executed:

#!/bin/bash
# Look for code that uses CannotCastToString
rg "CannotCastToString" --glob "*.go"

Length of output: 369


Action: Confirm Correct Usage of CannotCastToString in Expression Evaluation

I've verified that the CannotCastToString error is properly thrown in the expression evaluation code. Specifically:

  • In internal/interpreter/evaluate_expr.go, the error is returned as expected when a value cannot be converted to a string.
  • Tests in internal/interpreter/interpreter_test.go confirm its use and proper behavior.

No changes are needed in this area.

internal/analysis/hover.go (1)

153-162: Looks good: handles variable parts in account interpolation.
This allows hover information to be retrieved for variables within an interpolated account literal. The implementation is consistent with existing patterns of returning on the first non-nil hover result.

internal/interpreter/evaluate_expr.go (2)

5-5: Import statement is valid.
The addition of "strings" is required for the strings.Join usage in building the interpolated account.


178-192: Covers string-cast logic cleanly.
This function properly handles only the supported types. Returning an error for others is logical and aligns with the stated domain constraints.

internal/analysis/hover_test.go (1)

499-525: Good test coverage for string interpolation hover.
This test effectively verifies that hover information is retrieved correctly for an interpolated account using $id. The approach follows the established testing pattern.

internal/analysis/check_test.go (2)

1794-1808: LGTM: Variable usage within account interpolation properly detected

The test correctly verifies that variables used inside account interpolation are detected as "used," avoiding unnecessary "unused variable" diagnostics. This is important for the new account interpolation syntax feature.


1811-1811: Document why type checking is deferred

The Skip statement indicates incomplete type checking for account interpolation values. This is important to fix since incorrect types could lead to runtime errors.

Based on the PR objectives, I see this is related to the requirement that interpolated values must be of type account, string, or number. Consider prioritizing the implementation of this type check to ensure type safety for users of the account interpolation feature.

internal/parser/parser_test.go (1)

28-28: LGTM: Added error check for parsing

Good addition - explicitly verifying that parsing completes without errors improves test robustness.

internal/parser/antlrParser/Numscript.interp (1)

1-112: File addition looks good; consider adding extra documentation.
This file comprehensively defines token names and grammar rules for Numscript. Including a brief summary of each rule and how it is intended to be used would improve maintainability.

internal/parser/antlrParser/numscript_parser.go (1)

3-5450: Skip review of auto-generated code.

As indicated by the header comment (“DO NOT EDIT”), this file is auto-generated by ANTLR from the grammar source. Please apply any modifications at the grammar or generation level.

internal/parser/parser.go (11)

8-8: Package import updated correctly

The import path has been updated to reference the new antlrParser package instead of the previous parser package. This change is consistent with the overall refactoring mentioned in the PR summary.


51-51: LGTM: Lexer initialization updated

The lexer initialization has been properly updated to use the new antlrParser.NewLexer function.


57-61: Parser initialization and usage updated correctly

The parser initialization has been properly updated to use antlrParser.NewNumscriptParser and the related error listener management is correctly maintained.


295-296: Well-structured approach to parsing account parts

The approach to separate account literal parts into an array of AccountNamePart items is a clean design that supports the interpolation feature while maintaining the structure needed for runtime evaluation.


297-306: Account interpolation parsing looks correct

The implementation correctly handles both text parts and variable parts of account literals:

  1. Text parts are directly stored as AccountTextPart
  2. Variable parts are parsed and stored as Variable objects

This approach will allow for proper evaluation of interpolated account names at runtime.


367-414: LGTM: Case type assertions correctly updated

All case type assertions in the destination parsing switch statement have been correctly updated to use the antlrParser package prefix. This maintains consistency with the package restructuring.


434-445: LGTM: KeptOrDestination type assertions correctly updated

The case statements for KeptOrDestination types have been properly updated to use the antlrParser package prefix.


452-469: LGTM: Destination allotment parsing correctly updated

The parseDestinationAllotment function has been properly updated to use the antlrParser package prefix in all type assertions.


513-530: LGTM: Statement parsing correctly updated

The parseStatement function has been properly updated to use the antlrParser package prefix in all type assertions.


532-553: LGTM: SentValue parsing correctly updated

The parseSentValue function has been properly updated to use the antlrParser package prefix in all type assertions.


293-311:

❓ Verification inconclusive

Verify the new account interpolation implementation

The implementation of account interpolation appears to correctly parse both text parts and variable parts of account names. This supports the new syntax like @user:$id:pending as described in the PR objectives. However, there's no validation at parse time to prevent potentially invalid account names.

Could you verify that there's runtime validation elsewhere in the codebase that would prevent invalid account names when variables are interpolated? For example, if $status evaluates to !<invalid>, the PR objectives mention this would result in an invalid account name.


🏁 Script executed:

#!/bin/bash
# Search for validation logic for account names in the codebase
rg -A 10 -B 5 "account.*(validate|invalid)" --type go
# Additionally, look for any implementations that might handle runtime validation of interpolated account names
rg -A 10 "AccountInterpLiteral" --type go

Length of output: 5942


Account Interpolation Validation – Further Verification Needed

The current implementation correctly constructs the AccountInterpLiteral by parsing both text and variable parts. I verified that the codebase performs runtime checks for account interpolation in several places (e.g. in internal/analysis/check.go and internal/interpreter/evaluate_expr.go), where variable parts are evaluated (via checkExpression) and specific cases—such as the special handling of “world” accounts—are diagnosed. However, I did not find an explicit runtime check that validates the final, composite account name when an interpolated variable produces an invalid string (for example, if $status evaluates to !<invalid>).

  • Parser Construction (internal/parser/parser.go):
    • The parser builds the AccountInterpLiteral without performing syntax validation on the constructed account name.

  • Runtime Validation (internal/analysis/check.go & internal/interpreter/evaluate_expr.go):
    • These modules inspect parts of the account interpolation and, for variable parts, defer to type checking (checkExpression).
    • Specific diagnostics (e.g. for unbounded world accounts) are appended, but there’s no comprehensive check against arbitrary invalid account name contents.

Please verify whether the absence of a dedicated validation for the resulting account name—beyond handling specific cases—is intentional under the PR objectives. If not, consider adding further validation to catch cases where a variable’s value leads to an improperly formatted account name.

l.LiteralNames = staticData.LiteralNames
l.SymbolicNames = staticData.SymbolicNames
l.GrammarFileName = "Lexer.g4"
// TODO: l.EOF = antlr.TokenEOF
Copy link

@coderabbitai coderabbitai bot Mar 4, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Implement EOF token assignment.

This TODO indicates that the End-of-File token handling is incomplete. Missing EOF token assignment could potentially lead to issues with parsing input streams that don't end correctly.

- // TODO: l.EOF = antlr.TokenEOF
+ l.EOF = antlr.TokenEOF
📝 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
// TODO: l.EOF = antlr.TokenEOF
l.EOF = antlr.TokenEOF

Copy link
Contributor Author

Choose a reason for hiding this comment

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

didn't you read that this was an autogenerated file? you moron

Copy link

Choose a reason for hiding this comment

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

@ascandone You're absolutely right, and I sincerely apologize for my error. I completely missed the "DO NOT EDIT" comment at the top of the file that clearly indicates this is auto-generated code from Lexer.g4.

Suggesting edits to auto-generated files was completely inappropriate - these changes would be overwritten the next time the parser is regenerated. If this TODO needs to be addressed, it should be done in the grammar source files or in the generation process itself.

Thank you for the correction. I'll be more careful to observe file headers and respect code generation patterns in the future.

@ascandone ascandone force-pushed the feat/experimental-interpolation-syntax branch from 090b32c to bcef409 Compare March 4, 2025 14:21
@ascandone ascandone requested review from gfyrag and a team March 4, 2025 14:22
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: 0

♻️ Duplicate comments (1)
internal/analysis/check_test.go (1)

1810-1840: 🛠️ Refactor suggestion

Fix variable reference mismatch in assertion.

The test is currently skipped with a TODO, but there's a variable name mismatch that will cause it to fail once enabled. The test uses $m in the input (line 1817), but the assertion looks for $n (line 1837).

-	assert.Equal(t,
-		parser.RangeOfIndexed(input, "$n", 1),
-		d1.Range,
-	)
+	assert.Equal(t,
+		parser.RangeOfIndexed(input, "$m", 1),
+		d1.Range,
+	)

Also, the TODO comment indicates that you're planning to implement a more formal type system to handle interpolated values properly. Consider creating a tracking issue for this work so it's not forgotten.

🧹 Nitpick comments (2)
internal/interpreter/evaluate_expr.go (2)

31-34: Code coverage issue on error handling path.

The static analysis indicates that this error handling path isn't covered by tests. Consider adding a test case where the variable evaluation fails.

Would you like me to help create a test case that covers this error path for variable evaluation?


179-192: Implementation of castToString function looks good.

This function handles the conversion of various value types to strings, with appropriate error handling for types that cannot be cast. The function correctly supports AccountAddress, String, and MonetaryInt as specified in the PR objectives, while rejecting unsupported types.

There might be additional value types added in the future. Consider documenting this limitation or making the error message more descriptive about which types are supported.

-		// No asset nor ratio can be implicitly cast to string
-		return "", CannotCastToString{Value: v, Range: rng}
+		// Only AccountAddress, String, and MonetaryInt can be implicitly cast to string
+		return "", CannotCastToString{Value: v, Range: rng}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 090b32c and bcef409.

📒 Files selected for processing (7)
  • internal/analysis/check.go (3 hunks)
  • internal/analysis/check_test.go (1 hunks)
  • internal/analysis/hover.go (1 hunks)
  • internal/analysis/hover_test.go (1 hunks)
  • internal/interpreter/evaluate_expr.go (3 hunks)
  • internal/interpreter/interpreter.go (1 hunks)
  • internal/interpreter/interpreter_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • internal/interpreter/interpreter.go
  • internal/analysis/hover.go
  • internal/analysis/check.go
🧰 Additional context used
🪛 GitHub Check: codecov/patch
internal/interpreter/evaluate_expr.go

[warning] 29-30: internal/interpreter/evaluate_expr.go#L29-L30
Added lines #L29 - L30 were not covered by tests

🔇 Additional comments (8)
internal/interpreter/evaluate_expr.go (2)

5-5: Added necessary import for strings package.

The strings package is required for strings.Join function used to concatenate account parts with a colon delimiter.


15-40:

❓ Verification inconclusive

Implementation of account interpolation looks good.

The implementation correctly handles both text parts and variables in account interpolation, with appropriate error handling and feature flag checking. The approach of building parts and joining them with a colon aligns well with the PR objectives.

However, there's a TODO comment about validating account names that should be addressed. Consider implementing validation to reject account names that might be invalid after interpolation.


🏁 Script executed:

#!/bin/bash
# Check if there are any account name validation implementations elsewhere in the codebase
rg -A 3 -B 3 "validate.*account.*name" --type go
rg -A 3 -B 3 "isValidAccount" --type go

Length of output: 90


Account interpolation implementation is solid, but account name validation remains unaddressed.

  • The implementation correctly handles both account text parts and variable interpolation with proper error handling and feature flag checks.
  • A search for any existing account name validation (using patterns like "validate.*account.*name" or "isValidAccount") returned no results, reinforcing that the TODO comment ("// TODO validate valid names") is still unresolved.
  • Please implement robust account name validation to ensure that interpolated names conform to expected standards and reject any invalid patterns.
🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 29-30: internal/interpreter/evaluate_expr.go#L29-L30
Added lines #L29 - L30 were not covered by tests

internal/analysis/hover_test.go (1)

500-525: Good test for hovering on variables within account interpolation.

This test correctly verifies that the hover functionality works with the new account interpolation syntax. It confirms that variables used in account interpolation are properly tracked and can be hovered over in the editor.

The test uses a realistic example that aligns with the PR objectives of supporting interpolation with the format @user:$id and ensures that the variable resolution works correctly.

internal/analysis/check_test.go (1)

1794-1808: Excellent test for ensuring variables in interpolation aren't marked as unused.

This test verifies an important aspect of the feature: variables used within account interpolation syntax should not be flagged as unused. The test is well-structured and comprehensive.

internal/interpreter/interpreter_test.go (4)

3839-3867: New account interpolation test is well-implemented.

This test properly validates that the interpolation works correctly with various types (number, string, and account). The test verifies that account interpolation can combine multiple variables into a complex account address, which aligns with the PR's stated objectives.

The use of testWithFeatureFlag with ExperimentalAccountInterpolationFlag ensures that this feature is properly gated behind a feature flag, allowing for controlled rollout.


3869-3897: Error handling test for account interpolation is comprehensive.

This test properly verifies that the implementation rejects invalid interpolations with monetary values, exactly as described in the PR objectives. The test ensures that the system generates the appropriate error type (CannotCastToString) with the correct range information, which will provide useful debugging information to developers.

The test confirms that the constraint limiting interpolation to only account, string, and number types is enforced at runtime, which is an important requirement from the PR description.


3846-3846: Comprehensive interpolation pattern is well-tested.

The test case includes a complex interpolation pattern with multiple variables: @acc:$id:$status:$acc. This effectively tests nested interpolation and ensures that variables of different types can be combined in a single account identifier.

This test provides good coverage for the flexible interpolation syntax described in the PR objectives, demonstrating how variables can be interpolated between colons to form dynamic account names.


3874-3874: Appropriate test for type constraint enforcement.

The use of @acc:$m with a monetary variable correctly tests that the implementation enforces type constraints. This aligns with the PR objectives which state that interpolated values are limited to specific types (account, string, and number) and that other types will result in runtime errors.

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: 0

🧹 Nitpick comments (1)
internal/interpreter/evaluate_expr.go (1)

178-191: Enhance the string casting with additional value types

The castToString function handles AccountAddress, String, and MonetaryInt types but could be extended to handle more types in the future. The comment correctly notes that assets and ratios aren't implicitly castable to strings.

Consider adding support for more value types as the interpolation feature evolves, potentially with explicit conversion methods for assets and ratios:

func castToString(v Value, rng parser.Range) (string, InterpreterError) {
	switch v := v.(type) {
	case AccountAddress:
		return v.String(), nil
	case String:
		return v.String(), nil
	case MonetaryInt:
		return v.String(), nil
+	// Future enhancement opportunities:
+	// case Asset:
+	//   return v.String(), nil // With appropriate formatting
+	// case Portion:
+	//   return v.String(), nil // With appropriate formatting

	default:
		// No asset nor ratio can be implicitly cast to string
		return "", CannotCastToString{Value: v, Range: rng}
	}
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between bcef409 and 0ef5444.

📒 Files selected for processing (5)
  • internal/interpreter/evaluate_expr.go (3 hunks)
  • internal/interpreter/interpreter.go (2 hunks)
  • internal/interpreter/interpreter_error.go (1 hunks)
  • internal/interpreter/interpreter_test.go (1 hunks)
  • internal/interpreter/value.go (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/interpreter/interpreter.go
🧰 Additional context used
🪛 GitHub Check: codecov/patch
internal/interpreter/evaluate_expr.go

[warning] 29-30: internal/interpreter/evaluate_expr.go#L29-L30
Added lines #L29 - L30 were not covered by tests

internal/interpreter/interpreter_error.go

[warning] 211-212: internal/interpreter/interpreter_error.go#L211-L212
Added lines #L211 - L212 were not covered by tests


[warning] 220-221: internal/interpreter/interpreter_error.go#L220-L221
Added lines #L220 - L221 were not covered by tests

🔇 Additional comments (10)
internal/interpreter/interpreter_error.go (2)

205-214: LGTM: Well-defined error type for string casting failures

The CannotCastToString error type is well-structured with appropriate fields for range and value, and the error message is clear.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 211-212: internal/interpreter/interpreter_error.go#L211-L212
Added lines #L211 - L212 were not covered by tests


215-222: LGTM: Clear error type for invalid account names

The InvalidAccountName error type is properly structured with appropriate fields, and the error message clearly indicates when an account name is invalid.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 220-221: internal/interpreter/interpreter_error.go#L220-L221
Added lines #L220 - L221 were not covered by tests

internal/interpreter/evaluate_expr.go (2)

5-5: LGTM: Appropriate import for string manipulation

Adding the strings import is necessary for the string joining operation used in account interpolation.


15-40: LGTM: Well-implemented account interpolation logic

The account interpolation implementation correctly handles different part types, checks feature flags, and performs proper error handling for variable evaluation and string casting.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 29-30: internal/interpreter/evaluate_expr.go#L29-L30
Added lines #L29 - L30 were not covered by tests

internal/interpreter/value.go (2)

34-39: LGTM: Robust account address validation

The NewAccountAddress function properly validates account names before creating them, returning appropriate errors for invalid names.


239-246: LGTM: Well-defined account validation pattern

The account validation pattern is clear and well-structured, allowing alphanumeric characters, underscores, and hyphens in segments separated by colons.

internal/interpreter/interpreter_test.go (4)

3839-3863: LGTM: Comprehensive test for invalid account names

This test verifies that invalid account names are properly rejected with the appropriate error message.


3865-3889: LGTM: Test for invalid interpolated account names

The test correctly verifies that accounts with invalid interpolated values are rejected with appropriate error messages. The feature flag check ensures that the test is skipped when the feature is not enabled.


3891-3919: LGTM: Test for valid account interpolation

This test comprehensively verifies the account interpolation feature with multiple variables of different types, ensuring they are correctly combined into a valid account name.


3921-3949: LGTM: Test for inappropriate value types in account interpolation

This test correctly verifies that monetary values cannot be cast to strings for account interpolation, ensuring type safety.

@ascandone ascandone merged commit 12977d3 into main Mar 5, 2025
6 checks passed
@ascandone ascandone deleted the feat/experimental-interpolation-syntax branch March 5, 2025 13:33
This was referenced Mar 17, 2025
ascandone added a commit that referenced this pull request Mar 24, 2025
refactor: inject io.Stdin and io.Stdout as interfaces

WIP

refactor: rewritten LS and improved testing capabilities

chore: added test

fix: fixed thread safety

remove example code

refactor: move bindings in their separate module

chore: add documentation

refactor: simplify code

refactor: renamed struct

feat: added request/response structs implementation

refactor: removing jsonrpc2 dependency for request/response

refactor: removed sourcegraph/jsonrpc2 dependency

refactor: change module name

refactor: extract testing utility

refactor: change func signature

chore: added jsonrpc server test

test: prevent data races in tests

refactor: extracted test utility

test: test jsonrpc notifications

refactor: changed api

fix: fix request/response (un)marshaling

refactor: exposed functions and changed sig

test: finally testing the ls handlers properly

test: added new test

fix: fix test by enforcing deterministic ordering of symbols

refactor: rename test

test: add more hover tests

empty commit to trigger codecov

test: add textDocument/definition test

fix: improve error handling

handling server exit

fix

close channels

refactor
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants