Skip to content

Feat: Implement Noise#12

Merged
ItsMeBrianD merged 5 commits intomainfrom
feat/worldgen/noise
Sep 5, 2025
Merged

Feat: Implement Noise#12
ItsMeBrianD merged 5 commits intomainfrom
feat/worldgen/noise

Conversation

@ItsMeBrianD
Copy link
Copy Markdown
Contributor

@ItsMeBrianD ItsMeBrianD commented Sep 5, 2025

Description by Korbit AI

What change is being made?

Add a new 'Noise' feature to the codebase with associated grammar and implementation, and refactor the surface condition related to noise conditions to use 'NoiseThreshold'.

Why are these changes being made?

The addition of the 'Noise' feature enhances the world generation capabilities by defining customizable noise settings that can affect surface rules. Refactoring to use 'NoiseThreshold' aligns with the updated specification for distinguishing noise conditions, improving readability and maintainability within the code.

Is this description stale? Ask me to generate a new description by commenting /korbit-generate-pr-description

Summary by CodeRabbit

  • New Features

    • Added Noise blocks with amplitude builders and JSON export; new symbol "type" included in exported symbol data.
  • Refactor

    • Surface grammar and listener/lexer interfaces reorganized (surfaceBlock / NoiseThreshold naming); builder-dispatch and traversal wiring normalized; If-rules no longer support negation.
  • Bug Fixes

    • Deduplicated diagnostics output, safer empty-condition handling, and improved build/parse logging.
  • Documentation

    • Updated example badlands surface rules to use the minecraft namespace and NoiseThreshold.

@ItsMeBrianD ItsMeBrianD self-assigned this Sep 5, 2025
@ItsMeBrianD ItsMeBrianD added the worldgen World Generation Related label Sep 5, 2025
@korbit-ai
Copy link
Copy Markdown

korbit-ai bot commented Sep 5, 2025

Korbit doesn't automatically review large (3000+ lines changed) pull requests such as this one. If you want me to review anyway, use /korbit-review.

@ItsMeBrianD
Copy link
Copy Markdown
Contributor Author

/korbit-review

@ItsMeBrianD ItsMeBrianD closed this Sep 5, 2025
@ItsMeBrianD ItsMeBrianD reopened this Sep 5, 2025
@ItsMeBrianD
Copy link
Copy Markdown
Contributor Author

@coderabbitai full

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Sep 5, 2025

@ItsMeBrianD I'll perform a full review of all the changes in this PR.

✅ Actions performed

Full review triggered.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Sep 5, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Adds a Noise DSL and Noise construct: grammar updated (new Noise.g4, surface→surfaceBlock, NoiseThreshold renames), generated parser/lexer regenerated, new Go noise construct with export, traversal/symbol typing and nil guards, diagnostics dedup via lib.Unique, removal of IfRule negation, builder-chain dispatch and invocation hardening, and small build log tweaks.

Changes

Cohort / File(s) Summary
Build logging
cmd/build.go
Adjusts error logging messages and adds explicit parse error handling.
Example: badlands noise and thresholds
examples/overworld-noise-settings/surface-rules/badlands.mms
Changes namespace to minecraft; replaces Noise(...) usages with NoiseThreshold(...) in TerracottaBands.
Core grammar sources
grammar/MinecraftMetascript.g4, grammar/Surface.g4, grammar/Noise.g4
Adds Noise grammar; renames surfacesurfaceBlock; introduces NoiseThreshold alternatives; allows leading NLs and noise blocks/builders.
Generated grammar/artifacts
lang/grammar/MinecraftMetascript.interp, lang/grammar/MinecraftMetascript.tokens, lang/grammar/MinecraftMetascriptLexer.interp, lang/grammar/MinecraftMetascriptLexer.tokens, lang/grammar/minecraftmetascript_lexer.go, lang/grammar/minecraftmetascript_listener.go, lang/grammar/minecraftmetascript_base_listener.go
Regenerated parser/lexer artifacts: new/renamed tokens and rules (Noise, NoiseThreshold, surfaceBlock, noiseBlock, noise builders), token reindexing, updated listener/base-listener signatures and added noise hooks.
Noise construct implementation
lang/constructs/worldgen/noise/Noise.go
New noise package and Noise type (FirstOctave, Amplitudes), traversal constructors, validation diagnostics, MarshalJSON, and ExportSymbol that writes JSON under namespace/worldgen/noise/.
Surface rules & traversal updates
lang/constructs/worldgen/surface_rules/Condition_Noise.go, lang/constructs/worldgen/surface_rules/Rule_If.go, lang/constructs/worldgen/surface_rules/SurfaceConditions.go, lang/constructs/worldgen/surface_rules/SurfaceRules.go
Switches Noise→NoiseThreshold contexts/builders and builder wiring; removes IfRule.Negate and associated logic; guards empty SurfaceCondition parse nodes; calls ProcessDeclaration with an extra kind string ("SurfaceRule" / "SurfaceCondition").
BuilderChain runtime dispatch
lang/builder_chain/BuilderChain.go
Changes Invoke to runtime-type dispatch (drops generic C param); normalizes pointer vs non-pointer context types for registration, Require, and duplicate detection.
Builder invocation robustness
lang/constructs/worldgen/surface_rules/Condition_*.go (AboveWater, StoneDepth, VerticalGradient, YAbove)
Move builder-chain construction into registration closures; invoke builders on first child (GetChild(0)) with nil checks to avoid panics.
Traversal safety & symbol typing
lang/traversal/Construct.go, lang/traversal/Symbol.go
Adds nil guard in Construct; Symbol gains GetType(); ProcessDeclaration gains typeName arg and records identifier reference/nameLocation; symbol JSON now includes Type.
Project wiring & diagnostics dedup
lang/Project.go, main_wasm.go
Blank-import worldgen/noise; Diagnostics() returns lib.Unique(diagnostics); WASM getFileDiag JSON-serializes unique diagnostics.
Utility: unique helper
lib/Unique.go
Adds generic Unique[T comparable]([]T) []T to deduplicate slices while preserving order.
TypeScript API update
wasm/mms.d.ts
Adds required type: string field to exported MmsSymbol.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant U as User (.mms)
  participant P as Parser (ANTLR)
  participant T as Traversal
  participant B as BuilderChain
  participant S as SymbolTable
  participant N as Noise Construct
  participant E as Exporter/FS

  rect rgb(240,248,255)
    U->>P: Parse source (surfaceBlock + noiseBlock)
    P-->>T: Parse tree (surfaceBlock, noiseBlock, builders)
  end

  rect rgb(245,255,240)
    T->>T: ProcessDeclaration(ctx,..., kind)
    alt kind == "Noise"
      T->>N: Build Noise (FirstOctave, Amplitudes) via constructor
      T->>B: Invoke builder chain on builder child contexts
      B-->>T: builder values
      T->>S: Register Symbol(name, type="Noise", ref, locations)
    end
  end

  rect rgb(255,250,240)
    T->>E: ExportSymbol(Noise) -> write namespace/worldgen/noise/<name>.json
  end
Loading
sequenceDiagram
  autonumber
  participant D as Declaration
  participant T as Traversal
  participant S as Symbol
  participant W as WASM API

  D->>T: ProcessDeclaration(..., "SurfaceRule" / "SurfaceCondition")
  T->>S: Create symbol with Type = kind
  Note over S: Symbol JSON includes Type field
  T-->>W: Emit serialized symbols (includes type)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • Feat: Implement Noise #12 — appears to make the same Noise-related grammar and construct changes (Noise/NoiseThreshold renames and Noise.go), touching the same files; likely directly related.

Poem

I tap my paw to octave beats,
New Noise hums through grammar streets.
Thresholds hop where surfaces play,
Negation slips and bounds away.
Symbols wear their type with pride—one-by-one duplicates hide. 🐇🎶


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d214f94 and b9b126c.

📒 Files selected for processing (2)
  • lang/constructs/worldgen/surface_rules/Condition_Noise.go (2 hunks)
  • lang/constructs/worldgen/surface_rules/Condition_YAbove.go (2 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/worldgen/noise

🪧 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.
    • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit 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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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
Copy Markdown

@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: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
lang/traversal/Symbol.go (1)

47-52: Panic risk: nil dereference of s.ref during JSON marshal when Identifier() is missing.

If id is nil, out.ref remains nil; MarshalJSON dereferences it.

Apply these defensive fixes:

@@
-	if id := ctx.Identifier(); id == nil {
-		scope.DiagnoseSemanticError("Missing Identifier", ctx)
-	} else {
+	if id := ctx.Identifier(); id == nil {
+		scope.DiagnoseSemanticError("Missing Identifier", ctx)
+		return nil
+	} else {
 		out.ref = NewReference(id.GetText(), namespace)
 		out.nameLocation = TerminalNodeLocation(id, scope.CurrentFile)
 	}
@@
-func (s BaseSymbol) MarshalJSON() ([]byte, error) {
-	return json.Marshal(struct {
+func (s BaseSymbol) MarshalJSON() ([]byte, error) {
+	var ref Reference
+	if s.ref != nil {
+		ref = *s.ref
+	}
+	return json.Marshal(struct {
 		NameLocation    TextLocation `json:"nameLocation"`
 		ContentLocation TextLocation `json:"contentLocation"`
 		Value           Construct    `json:"value"`
 		Ref             Reference    `json:"ref"`
 		Type            string       `json:"type"`
 	}{
 		NameLocation:    s.nameLocation,
 		ContentLocation: s.contentLocation,
 		Value:           s.GetValue(),
-		Ref:             *s.ref,
+		Ref:             ref,
 		Type:            s.GetType(),
 	})
 }

Also applies to: 86-99

grammar/Surface.g4 (1)

15-24: And/Or allow a single operand — likely unintended

Current forms accept one condition; typically And/Or should require 2+. Recommend enforcing 2+.

Apply:

-surfaceCondition_And: 'And' NL* '(' NL* (surfaceCondition NL*)* surfaceCondition NL* ')';
-surfaceCondition_Or: 'Or'  NL* '(' NL* (surfaceCondition NL*)* surfaceCondition NL* ')';
+surfaceCondition_And: 'And' NL* '(' NL* surfaceCondition (NL* surfaceCondition)+ NL* ')';
+surfaceCondition_Or:  'Or'  NL* '(' NL* surfaceCondition (NL* surfaceCondition)+ NL* ')';
lang/constructs/worldgen/surface_rules/Rule_If.go (2)

94-106: Fix: propagate scope in AND expansion to avoid nil deref during MarshalJSON

Nested IfRule instances created in the AND rewrite don’t carry scope. If a nested condition is a ReferenceCondition, MarshalJSON will call c.scope.Get(...) and panic. Add scope propagation.

-            current = IfRule{
-                Condition: cond,
-                Action:    next,
-            }
+            current = IfRule{
+                Condition: cond,
+                Action:    next,
+                scope:     c.scope,
+            }

16-21: Use pointer type in ConstructRegistry key for SurfaceRule_IfContext
In lang/constructs/worldgen/surface_rules/Rule_If.go at line 16, replace

reflect.TypeFor[grammar.SurfaceRule_IfContext]()

with

reflect.TypeFor[*grammar.SurfaceRule_IfContext]()

so the registry key matches the actual *SurfaceRule_IfContext pointer type.

♻️ Duplicate comments (2)
lang/grammar/minecraftmetascript_listener.go (2)

178-180: ExitSurfaceBlock rename mirrors Enter—no further action


235-246: Exit NoiseThreshold renames mirror Enter—ensure consumer exits updated

🧹 Nitpick comments (21)
lib/Unique.go (1)

4-11: Micro-opt: use struct{} set and preallocate capacities.

Saves a bool per entry and reduces reallocations.

Apply this diff:

-func Unique[T comparable](arr []T) []T {
-	seen := make(map[T]bool) // A map to store seen elements
-	result := make([]T, 0)   // The array to store unique elements
+// Unique returns the first occurrence of each element in input order.
+func Unique[T comparable](arr []T) []T {
+	seen := make(map[T]struct{}, len(arr)) // Set of seen elements
+	result := make([]T, 0, len(arr))       // Preallocate upper bound
@@
-		if _, ok := seen[v]; !ok { // If element not in map (not seen yet)
-			seen[v] = true             // Mark as seen
+		if _, ok := seen[v]; !ok { // If element not in map (not seen yet)
+			seen[v] = struct{}{}       // Mark as seen
wasm/mms.d.ts (1)

33-39: Add minimal docs or a discriminant type for MmsSymbol.type.

If possible, narrow from string to a union of known symbol kinds, or at least document examples to aid consumers.

Apply this small doc diff:

 export type MmsSymbol = {
@@
-    type: string
+    /** Discriminant for the construct type (e.g., "Noise", "SurfaceRule", "NoiseThreshold"). */
+    type: string
 }
cmd/build.go (3)

67-73: Handle JSON marshal errors explicitly.

Avoid continuing with a bad payload; log and return early.

Apply this diff:

-		r, err := json.MarshalIndent(project.BuildFsLike(outFile), "", "  ")
+		r, err := json.MarshalIndent(project.BuildFsLike(outFile), "", "  ")
+		if err != nil {
+			log.Println("Error marshaling project:", err)
+			return
+		}
@@
-				string(r),
-				err,
+				string(r),
+				nil,

39-41: Nit: prefer log.Printf over log.Println(fmt.Sprintf()).

Removes an allocation and is idiomatic.

Apply this diff:

-			log.Println(
-				fmt.Sprintf("Building your project from %s to %s", inFile, outFile),
-			)
+			log.Printf("Building your project from %s to %s", inFile, outFile)

47-49: Optional: use os.Stat for path parity with os.ReadFile.

fs.Stat(os.DirFS("."), inFile) restricts paths to CWD; os.ReadFile(inFile) doesn’t. Using os.Stat keeps behavior consistent.

Apply this diff:

-		stat, err := fs.Stat(os.DirFS("."), inFile)
+		stat, err := os.Stat(inFile)
lang/traversal/Symbol.go (2)

29-36: NewSymbol doesn’t set _type; JSON emits type:"".

Either thread type through constructor or provide a typed variant to avoid empty discriminants.

Add a typed constructor:

 func NewSymbol(nameLocation TextLocation, contentLocation TextLocation, value Construct, ref *Reference) BaseSymbol {
 	return BaseSymbol{
 		nameLocation:    nameLocation,
 		contentLocation: contentLocation,
 		value:           value,
 		ref:             ref,
 	}
 }
+
+// NewSymbolWithType constructs a BaseSymbol with a type discriminant.
+func NewSymbolWithType(nameLocation TextLocation, contentLocation TextLocation, value Construct, ref *Reference, typeName string) BaseSymbol {
+	return BaseSymbol{
+		nameLocation:    nameLocation,
+		contentLocation: contentLocation,
+		value:           value,
+		ref:             ref,
+		_type:           typeName,
+	}
+}

43-46: Minor: set type at initialization.

Cleaner and avoids a separate assignment.

Apply this diff:

-func ProcessDeclaration(ctx DeclarationContext, valueCtx antlr.ParserRuleContext, scope *Scope, namespace string, typeName string) Symbol {
-	out := &BaseSymbol{}
-	out._type = typeName
+func ProcessDeclaration(ctx DeclarationContext, valueCtx antlr.ParserRuleContext, scope *Scope, namespace string, typeName string) Symbol {
+	out := &BaseSymbol{_type: typeName}
grammar/Surface.g4 (1)

50-54: NoiseThreshold builders look good; consider labeled alternatives for stable API

Optional: use labeled alternatives to generate stable listener/visitor method names without separate rules.

Example:

-surfaceCondition_NoiseThresholdBuilder: surfaceCondition_NoiseThresholdBuilder_Max | surfaceCondition_NoiseThresholdBuilder_Min;
-surfaceCondition_NoiseThresholdBuilder_Min: '.Min(' number ')';
-surfaceCondition_NoiseThresholdBuilder_Max: '.Max(' number ')';
+surfaceCondition_NoiseThresholdBuilder
+  : '.Min(' number ')' #NoiseThresholdMin
+  | '.Max(' number ')' #NoiseThresholdMax
+  ;
lang/Project.go (1)

23-24: Diagnostic is fully comparable; key-based dedup remains optional
Verified that Diagnostic only contains comparable fields (string, TextLocation, Severity), so lib.Unique(diagnostics) compiles without error. If you’d rather dedupe by a subset of fields (e.g. message + location), introduce a UniqueBy helper (and a Diagnostic.Key() or similar) for custom‐key deduplication.

main_wasm.go (1)

82-82: Consolidate diagnostic deduplication to a single stage
Remove the redundant lib.Unique call in either lang/Project.go:24 or main_wasm.go:82 so diagnostics are only deduplicated once.

examples/overworld-noise-settings/surface-rules/badlands.mms (1)

21-23: NoiseThreshold used consistently for conditions
No remaining raw Noise(…) calls in condition contexts; the Noise(-4)… block at the top is the intended noise generator, not a threshold.

  • Audit spelling of “Bandlands” in grammar/Surface.g4 (surfaceRule_Bandlands) vs “Badlands” in examples/overworld-noise-settings/surface-rules/badlands.mms to ensure consistency.
lang/constructs/worldgen/surface_rules/SurfaceRules.go (1)

39-39: Approve ProcessDeclaration signature updates

  • All ProcessDeclaration call sites (Noise, SurfaceRules, SurfaceConditions) now include the new typeName argument, matching the updated signature.
  • Optional: extract symbol kind strings (e.g. "SurfaceRule") into shared const definitions (e.g. KindSurfaceRule) to prevent string drift.
grammar/Noise.g4 (2)

11-11: Allow trailing comma in amplitudes for friendlier diffs.

Optional but common in config-like DSLs.

- noise_Builder_Amplitudes: '.Amplitudes' NL* '(' NL* number (NL* ',' NL* number)* NL* ')';
+ noise_Builder_Amplitudes: '.Amplitudes' NL* '(' NL* number (NL* ',' NL* number)* (NL* ',')? NL* ')';

4-4: Consider requiring at least one declaration inside Noise { ... }.

Prevents empty blocks that don’t produce artifacts.

- noiseBlock: 'Noise' NL* '{' NL* (noiseDeclaration NL*)* NL* '}';
+ noiseBlock: 'Noise' NL* '{' NL* noiseDeclaration (NL+ noiseDeclaration)* NL* '}';
lang/constructs/worldgen/surface_rules/Rule_If.go (1)

108-121: Optional: use pointers for consistency and to reduce copying

OR-branch uses &IfRule while AND-branch boxes values. Consider using pointers in both branches for consistency and less copying.

-            next := c.Action
+            next := c.Action
             if i > 0 {
-                next = current
+                next = &current
             }
-            current = IfRule{ ... }
+            current = IfRule{ ... } // or make current a *IfRule and thread pointers throughout
lang/constructs/worldgen/noise/Noise.go (1)

79-89: Nit: preallocate amplitudes when possible

If grammar exposes count, consider preallocating Amplitudes to avoid reslices. Not blocking.

lang/grammar/MinecraftMetascript.tokens (1)

85-87: ‘Noise(’ and ‘.Amplitudes(’ enforce no whitespace before ‘(’. Confirm this is intentional for the DSL.

This mirrors existing builder tokens (e.g., ‘.Mul(’), but it rejects forms like Noise ( ... ). If you want to allow a space, consider parsing Noise then ( instead of a single literal token.

lang/grammar/minecraftmetascript_lexer.go (1)

49-52: Noise builder tokens added—document adjacency constraint.

Like other builders, ‘Noise(’ and ‘.Amplitudes(’ forbid whitespace. Add a note in the language reference to avoid author friction.

lang/grammar/MinecraftMetascript.interp (2)

39-41: Noise DSL literals introduced; confirm whitespace policy.

‘Noise(’ and ‘.Amplitudes(’ require no space before ‘(’. If you want to accept Noise ( ... ), switch to tokenizing Noise and ( separately in the grammar for builders.


108-156: New rule set (noiseBlock, noiseDeclaration, noise, builder, amplitudes) integrated into contentBlocks—nice.

Please add golden tests parsing a small Noise block and a Surface rule using NoiseThreshold min/max to lock this in.

I can draft minimal inputs and Go tests against the parser to exercise these paths.

lang/grammar/minecraftmetascript_base_listener.go (1)

369-399: New Noise hooks added—LGTM; pin codegen toolchain

Hooks look correct. Recommend pinning ANTLR (4.13.2) in your generation step to avoid drift across environments.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f21eaee and 3f7595b.

📒 Files selected for processing (23)
  • cmd/build.go (1 hunks)
  • examples/overworld-noise-settings/surface-rules/badlands.mms (2 hunks)
  • grammar/MinecraftMetascript.g4 (1 hunks)
  • grammar/Noise.g4 (1 hunks)
  • grammar/Surface.g4 (3 hunks)
  • lang/Project.go (2 hunks)
  • lang/constructs/worldgen/noise/Noise.go (1 hunks)
  • lang/constructs/worldgen/surface_rules/Condition_Noise.go (2 hunks)
  • lang/constructs/worldgen/surface_rules/Rule_If.go (2 hunks)
  • lang/constructs/worldgen/surface_rules/SurfaceConditions.go (1 hunks)
  • lang/constructs/worldgen/surface_rules/SurfaceRules.go (1 hunks)
  • lang/grammar/MinecraftMetascript.interp (6 hunks)
  • lang/grammar/MinecraftMetascript.tokens (3 hunks)
  • lang/grammar/MinecraftMetascriptLexer.interp (5 hunks)
  • lang/grammar/MinecraftMetascriptLexer.tokens (3 hunks)
  • lang/grammar/minecraftmetascript_base_listener.go (3 hunks)
  • lang/grammar/minecraftmetascript_lexer.go (2 hunks)
  • lang/grammar/minecraftmetascript_listener.go (6 hunks)
  • lang/traversal/Construct.go (1 hunks)
  • lang/traversal/Symbol.go (4 hunks)
  • lib/Unique.go (1 hunks)
  • main_wasm.go (1 hunks)
  • wasm/mms.d.ts (1 hunks)
🔇 Additional comments (28)
lib/Unique.go (1)

3-14: LGTM: stable, order-preserving dedup.

Implementation is correct and idiomatic Go generics.

cmd/build.go (1)

47-52: Good: include underlying error when build stat fails.

This improves diagnosability.

lang/traversal/Symbol.go (3)

56-57: Good: semantic error now anchors to decl ctx when value is missing.

Better UX for error locations.


9-15: Ignore interface-expansion warning: only BaseSymbol implements Symbol and it already defines GetType(), no other implementations exist.

Likely an incorrect or invalid review comment.


86-93: Approve addition of “type” field
No TS/JS consumers reference symbol.type, so including this field in the JSON output is safe.

lang/traversal/Construct.go (1)

41-43: Nil-guard prevents reflect panic — LGTM

This early return avoids a nil dereference on t.Kind() when ctx is a typed nil. Good defensive fix.

lang/grammar/MinecraftMetascriptLexer.tokens (1)

71-71: Regenerated artifacts reflect new tokens and all downstream references updated
All lexer/parser stubs include NoiseThreshold, Noise(), and .Amplitudes(), and no stale references remain.

grammar/Surface.g4 (1)

4-4: Rename surface → surfaceBlock: no legacy hooks found
Search across Go listener/visitor code reveals no occurrences of EnterSurface/ExitSurface or SurfaceContext; no consumer updates required.

lang/Project.go (1)

10-10: Noise constructs registration via side‑effect import looks correct

Blank import ensures package init runs and registers Noise constructs.

grammar/MinecraftMetascript.g4 (1)

3-10: Imports and contentBlocks rules verified; no leftover Surface( references detected. Regenerate the parser/lexer and sanity-parse representative scripts to confirm there are no FIRST/FOLLOW conflicts.

examples/overworld-noise-settings/surface-rules/badlands.mms (1)

2-4: Example Noise block addition reads well

Nice concise example showcasing Noise DSL usage.

grammar/Noise.g4 (1)

11-11: number parser rule confirmed present (defined as number: Int | Float;), no fallback needed.

lang/constructs/worldgen/surface_rules/SurfaceConditions.go (1)

49-50: Verified ProcessDeclaration usage: all call sites now use the 5-argument signature.

lang/grammar/MinecraftMetascriptLexer.interp (1)

39-41: Split composite tokens into separate symbols
At lang/grammar/MinecraftMetascriptLexer.interp (lines 39–41, 140–142), the lexer currently emits 'Noise(' and '.Amplitudes(' as single tokens, preventing valid inputs like Noise (1) or .Amplitudes ( … ). Update Noise.g4 so identifiers (e.g. Noise, .Amplitudes) and ( are distinct tokens, regenerate the lexer, and verify that whitespace variants parse correctly.

lang/constructs/worldgen/noise/Noise.go (1)

28-60: LGTM: solid Noise construct and declaration handling

Parsing, diagnostics, and symbol export look good. JSON shape matches expectations.

lang/constructs/worldgen/surface_rules/Condition_Noise.go (2)

64-76: LGTM: JSON field names align with NoiseThreshold spec

Field names noise_threshold, min_threshold, max_threshold look consistent.


30-33: No ctx type inconsistency in ConstructRegistry.Register
All surface_rules registrations use reflect.TypeFor[T]()—which returns the pointer type—and then cast via ctx.(*T), so the registered type matches the asserted pointer context in every case.

lang/grammar/MinecraftMetascript.tokens (2)

71-71: Rename from ‘Noise’ to ‘NoiseThreshold’ looks correct and resolves ambiguity.

Placement before the ‘Noise’ token ensures ‘NoiseThreshold’ is matched as a single token, not split. LGTM.


40-48: Confirm no raw 40–48 token ID usage. Ripgrep shows only named constants (MinecraftMetascriptLexerStoneDepthMode…LineComment) in minecraftmetascript_lexer.go, but verify no code, tests, or external consumers hardcode literals 40–48.

lang/grammar/minecraftmetascript_lexer.go (2)

56-58: Symbolic names update aligns with inserted T__36–T__38; no issues.


340-351: Literal token cases safe; no changes required
RG search found only case 1–3 in Reference.go and the generated parser, which map to T__0–T__2 and remain unchanged after adding T__36–T__38. No cases using literals ≥ 37 were found, so downstream code isn’t affected by the reindexing.

lang/grammar/MinecraftMetascript.interp (2)

25-25: Surface condition rename to ‘NoiseThreshold’ is consistent and desirable.

The rename avoids confusion with the new Noise DSL. Good change.


158-158: ATN table changed due to grammar edits—ack.

Generated delta only; nothing actionable here.

lang/grammar/minecraftmetascript_base_listener.go (2)

49-54: Surface→SurfaceBlock rename is API-breaking—verify downstream listeners/traversals are updated

Looks consistent with the grammar change; just ensure any custom listeners no longer reference Surface/SurfaceContext.


187-217: NoiseBuilder→NoiseThreshold rename propagated—confirm consumers migrated

Update any code using:

  • SurfaceCondition_NoiseBuilder_{Min,Max} → SurfaceCondition_NoiseThresholdBuilder_{Min,Max}
  • SurfaceCondition_NoiseBuilder → SurfaceCondition_NoiseThresholdBuilder
  • SurfaceCondition_Noise → SurfaceCondition_NoiseThreshold
lang/grammar/minecraftmetascript_listener.go (3)

79-90: NoiseThreshold method renames—ensure traversal implements new hooks

Map and update:

  • EnterSurfaceCondition_NoiseBuilder_{Min,Max} → EnterSurfaceCondition_NoiseThresholdBuilder_{Min,Max}
  • EnterSurfaceCondition_NoiseBuilder → EnterSurfaceCondition_NoiseThresholdBuilder
  • EnterSurfaceCondition_Noise → EnterSurfaceCondition_NoiseThreshold

151-165: New Noise productions (Enter)—wire into traversal and add parser tests*

Add handling for NoiseBlock/Declaration/Builder/Amplitudes and a couple of DSL samples to tests.


307-320: New Noise productions (Exit)—LGTM*

Comment thread cmd/build.go Outdated
Comment thread grammar/Noise.g4 Outdated
Comment thread lang/constructs/worldgen/noise/Noise.go
Comment thread lang/constructs/worldgen/surface_rules/Condition_Noise.go Outdated
Comment on lines +36 to +43
if conditionCtx.GetChildCount() > 0 {
return traversal.ConstructRegistry.Construct(
conditionCtx.GetChild(0).(antlr.ParserRuleContext),
currentNamespace,
scope,
)
}
return nil
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid panic: first child may be a terminal, not a ParserRuleContext.

Casting GetChild(0) to antlr.ParserRuleContext can panic when the first child is a token (e.g., !). Scan for the first rule child instead.

- if conditionCtx.GetChildCount() > 0 {
-   return traversal.ConstructRegistry.Construct(
-     conditionCtx.GetChild(0).(antlr.ParserRuleContext),
-     currentNamespace,
-     scope,
-   )
- }
+ if conditionCtx.GetChildCount() > 0 {
+   var inner antlr.ParserRuleContext
+   for i := 0; i < conditionCtx.GetChildCount(); i++ {
+     if c, ok := conditionCtx.GetChild(i).(antlr.ParserRuleContext); ok {
+       inner = c
+       break
+     }
+   }
+   if inner != nil {
+     return traversal.ConstructRegistry.Construct(inner, currentNamespace, scope)
+   }
+ }
  return nil
📝 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
if conditionCtx.GetChildCount() > 0 {
return traversal.ConstructRegistry.Construct(
conditionCtx.GetChild(0).(antlr.ParserRuleContext),
currentNamespace,
scope,
)
}
return nil
if conditionCtx.GetChildCount() > 0 {
var inner antlr.ParserRuleContext
for i := 0; i < conditionCtx.GetChildCount(); i++ {
if c, ok := conditionCtx.GetChild(i).(antlr.ParserRuleContext); ok {
inner = c
break
}
}
if inner != nil {
return traversal.ConstructRegistry.Construct(
inner,
currentNamespace,
scope,
)
}
}
return nil
🤖 Prompt for AI Agents
In lang/constructs/worldgen/surface_rules/SurfaceConditions.go around lines 36
to 43, the code casts conditionCtx.GetChild(0) to antlr.ParserRuleContext which
can panic if the first child is a terminal; instead iterate children (from 0 to
conditionCtx.GetChildCount()-1), find the first child that implements
antlr.ParserRuleContext, pass that child to traversal.Construct with
currentNamespace and scope, and return its result; if no rule-child is found
return nil.

Comment on lines +49 to 52
"'NoiseThreshold'", "'StoneDepth('", "'.SecondaryDepthRange('", "'VerticalGradient'",
"'.Top'", "'.Bottom'", "'AboveWater'", "'YAbove'", "'Block'", "'['",
"']'", "'Bandlands'", "'If'", "':'",
"']'", "'Bandlands'", "'If'", "':'", "'Noise'", "'Noise('", "'.Amplitudes('",
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Typo in literal: ‘Bandlands’ → ‘Badlands’.

User-facing keyword is misspelled. This will confuse authors and break examples that use “Badlands”.

Apply in grammar sources (then regenerate):

--- a/lang/grammar/Surface.g4
+++ b/lang/grammar/Surface.g4
- 'Bandlands'
+ 'Badlands'

If the rule name also encodes this (seen in interp as surfaceRule_Bandlands), rename it:

--- a/lang/grammar/Surface.g4
+++ b/lang/grammar/Surface.g4
- surfaceRule_Bandlands
+ surfaceRule_Badlands

I can push a follow-up commit that updates both grammar and regenerated artifacts.

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

🤖 Prompt for AI Agents
In lang/grammar/minecraftmetascript_lexer.go around lines 49 to 52, the
user-facing literal "'Bandlands'" is misspelled and should be "'Badlands'";
update the token/literal in the grammar source to "Badlands", search the grammar
and related source files for any rule names or identifiers encoding "Bandlands"
(e.g., surfaceRule_Bandlands) and rename them to use "Badlands", then regenerate
the lexer/parser/artifacts so all references and generated code match the
corrected spelling.

Comment on lines +22 to 24
// EnterSurfaceBlock is called when entering the surfaceBlock production.
EnterSurfaceBlock(c *SurfaceBlockContext)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Surface→SurfaceBlock interface rename: breaking change—document or bump module version

Good change, but it breaks any external implementers. Add migration notes or a semver-major bump.

Run to find outdated usages:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
# Old listener methods/contexts
rg -nP -g '!**/vendor/**' '\b(Enter|Exit)Surface\('
rg -nP -g '!**/vendor/**' '\bSurfaceContext\b'
# Old Noise* names
rg -nP -g '!**/vendor/**' '\bSurfaceCondition_NoiseBuilder(_Min|_Max)?\b|\bSurfaceCondition_Noise\b'
# Sanity: new names present
rg -nP -g '!**/vendor/**' '\bSurfaceBlockContext\b|\b(Enter|Exit)SurfaceBlock\('

Length of output: 73


🏁 Script executed:

#!/bin/bash
set -uo pipefail

echo "Searching for old listener methods (Enter/Exit Surface)..."
rg -nP -g '!**/vendor/**' '\b(Enter|Exit)Surface\(' || true

echo "Searching for old SurfaceContext uses..."
rg -nP -g '!**/vendor/**' '\bSurfaceContext\b' || true

echo "Searching for old Noise* type names..."
rg -nP -g '!**/vendor/**' '\bSurfaceCondition_NoiseBuilder(_Min|_Max)?\b|\bSurfaceCondition_Noise\b' || true

echo "Verifying new SurfaceBlock names are present..."
rg -nP -g '!**/vendor/**' '\bSurfaceBlockContext\b|\b(Enter|Exit)SurfaceBlock\(' || true

Length of output: 3203


🏁 Script executed:

#!/bin/bash
set -euo pipefail
if [ -f go.mod ]; then
  echo "go.mod first lines:"
  head -n 5 go.mod
else
  echo "go.mod not found"
fi

Length of output: 169


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Checking for CHANGELOG.md..."
if [ -f CHANGELOG.md ]; then head -n 20 CHANGELOG.md; else echo "No CHANGELOG.md found"; fi

echo "Checking README.md for migration notes..."
if [ -f README.md ]; then rg -n 'SurfaceBlock' README.md || echo "No mention of SurfaceBlock in README.md"; else echo "No README.md found"; fi

Length of output: 328


Document breaking change or bump MAJOR version
Renaming EnterSurface/ExitSurface to EnterSurfaceBlock/ExitSurfaceBlock is a semver-major change. Add a migration note (e.g. in a new CHANGELOG.md) and bump the module’s major version accordingly.

🤖 Prompt for AI Agents
In lang/grammar/minecraftmetascript_listener.go around lines 22–24, the API was
changed by renaming EnterSurface/ExitSurface to
EnterSurfaceBlock/ExitSurfaceBlock which is a semver-major breaking change; add
a migration note (create or update CHANGELOG.md) documenting the renames and
code examples for migrating callers, then bump the module major version: update
the module path in go.mod to the next major (e.g. add /v2), update any internal
imports to the new path, run go mod tidy, and create the corresponding vN.0.0
git tag/release so downstream users can adopt the breaking change.

Comment on lines +37 to +48
T__36=37
T__37=38
T__38=39
StoneDepthMode=40
Int=41
Float=42
String=43
NL=44
WS=45
Identifier=46
BlockComment=47
LineComment=48
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Token ID renumbering: verify no hard-coded numeric token checks

IDs shifted (new T__36..38), which can break code comparing GetTokenType() to integers. Ensure all comparisons use generated constants, not raw numbers.

Run to spot suspicious numeric token checks:


🏁 Script executed:

#!/bin/bash
# numeric token comparisons
rg -nP '\b(GetTokenType|GetToken)\s*\(\)\s*==\s*\d+'
# switch cases on numeric literals (scan likely parser utils)
rg -nP 'case\s+\d+\s*:' --iglob '!**/vendor/**'

Length of output: 359


Replace hard-coded token numbers in lang/traversal/Reference.go
Switch on raw values (case 1, case 2) at lines 21 and 23 must use the generated token constants (e.g. MinecraftMetascriptLexer.T__1) instead of literals.

🤖 Prompt for AI Agents
In lang/traversal/Reference.go around lines 21 to 23, the switch statements use
hard-coded numeric token values (e.g., case 1, case 2); replace those numeric
literals with the corresponding generated token constants from
lang/grammar/MinecraftMetascriptLexer (for example
MinecraftMetascriptLexer.T__1, MinecraftMetascriptLexer.T__2) so the code
references named tokens instead of raw integers; update any import or package
qualifier if needed to reference the MinecraftMetascriptLexer symbols and run a
build to confirm the constants are resolved.

Copy link
Copy Markdown

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

♻️ Duplicate comments (1)
lang/constructs/worldgen/surface_rules/Condition_Noise.go (1)

26-28: Fix incorrect label in Builder_GetFloat call

The second Builder_GetFloat call incorrectly uses "Min" as the label when setting the Max field. This will produce misleading error messages.

Apply this diff to fix the label:

 func(ctx *grammar.SurfaceCondition_NoiseThresholdBuilder_MaxContext, out *NoiseCondition, scope *traversal.Scope, _ string) {
-    builder_chain.Builder_GetFloat(ctx, func(v float64) { out.Max = v }, scope, "Min")
+    builder_chain.Builder_GetFloat(ctx, func(v float64) { out.Max = v }, scope, "Max")
 },
🧹 Nitpick comments (2)
lang/constructs/worldgen/surface_rules/Condition_StoneDepth.go (1)

20-24: Nit: align diagnostic label with JSON/key naming

Consider using "Secondary Depth Range" consistently with the JSON key or switch to "secondary depth range" for uniform messages.

lang/constructs/worldgen/surface_rules/Condition_Noise.go (1)

52-65: Consider using pointer type directly for Require calls

Since Require now handles pointer normalization internally, you could simplify the code by using the pointer type directly without reflect.TypeFor.

You could simplify the type specifications:

 builder_chain.Require(
     noiseBuildChain,
     noise,
     scope,
-    reflect.TypeFor[*grammar.SurfaceCondition_NoiseThresholdBuilder_MinContext](),
+    reflect.TypeOf((*grammar.SurfaceCondition_NoiseThresholdBuilder_MinContext)(nil)).Elem(),
     ".Min",
 )

Though the current approach with TypeFor is actually clearer and more maintainable, so you may want to keep it as is.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3f7595b and d214f94.

📒 Files selected for processing (11)
  • cmd/build.go (1 hunks)
  • examples/overworld-noise-settings/surface-rules/badlands.mms (2 hunks)
  • grammar/Noise.g4 (1 hunks)
  • lang/builder_chain/BuilderChain.go (2 hunks)
  • lang/constructs/worldgen/surface_rules/Condition_AboveWater.go (1 hunks)
  • lang/constructs/worldgen/surface_rules/Condition_Noise.go (2 hunks)
  • lang/constructs/worldgen/surface_rules/Condition_StoneDepth.go (2 hunks)
  • lang/constructs/worldgen/surface_rules/Condition_VerticalGradient.go (2 hunks)
  • lang/constructs/worldgen/surface_rules/Condition_YAbove.go (2 hunks)
  • lang/constructs/worldgen/surface_rules/Rule_If.go (3 hunks)
  • lang/traversal/Symbol.go (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • cmd/build.go
  • grammar/Noise.g4
  • examples/overworld-noise-settings/surface-rules/badlands.mms
🧰 Additional context used
🧬 Code graph analysis (8)
lang/constructs/worldgen/surface_rules/Condition_VerticalGradient.go (3)
lang/builder_chain/BuilderChain.go (3)
  • NewBuilderChain (75-84)
  • Build (62-73)
  • Invoke (20-41)
lang/builder_chain/SharedBuilder.go (1)
  • Builder_GetVerticalAnchor (84-107)
lang/constructs/primitives/VerticalAnchor.go (1)
  • VerticalAnchor (63-67)
lang/builder_chain/BuilderChain.go (1)
lang/traversal/Scope.go (1)
  • Scope (11-16)
lang/constructs/worldgen/surface_rules/Condition_YAbove.go (2)
lang/builder_chain/BuilderChain.go (3)
  • NewBuilderChain (75-84)
  • Build (62-73)
  • Invoke (20-41)
lang/builder_chain/SharedBuilder.go (2)
  • Builder_GetInt (39-59)
  • SharedBuilder_Add (30-37)
lang/constructs/worldgen/surface_rules/Condition_AboveWater.go (1)
lang/builder_chain/BuilderChain.go (3)
  • NewBuilderChain (75-84)
  • Build (62-73)
  • Invoke (20-41)
lang/constructs/worldgen/surface_rules/Condition_StoneDepth.go (2)
lang/builder_chain/BuilderChain.go (3)
  • NewBuilderChain (75-84)
  • Build (62-73)
  • Invoke (20-41)
lang/builder_chain/SharedBuilder.go (2)
  • Builder_GetInt (39-59)
  • SharedBuilder_Add (30-37)
lang/constructs/worldgen/surface_rules/Condition_Noise.go (3)
lang/traversal/Scope.go (1)
  • Scope (11-16)
lang/builder_chain/BuilderChain.go (4)
  • NewBuilderChain (75-84)
  • Build (62-73)
  • Invoke (20-41)
  • Require (43-53)
lang/builder_chain/SharedBuilder.go (1)
  • Builder_GetFloat (61-82)
lang/constructs/worldgen/surface_rules/Rule_If.go (2)
lang/traversal/Scope.go (1)
  • Scope (11-16)
lang/traversal/Construct.go (1)
  • Construct (12-16)
lang/traversal/Symbol.go (4)
lang/traversal/Location.go (1)
  • TextLocation (14-21)
lang/traversal/Construct.go (1)
  • Construct (12-16)
lang/traversal/Reference.go (2)
  • Reference (30-36)
  • Ref (46-48)
lang/traversal/Scope.go (1)
  • Scope (11-16)
🔇 Additional comments (14)
lang/constructs/worldgen/surface_rules/Condition_StoneDepth.go (1)

19-35: Builder-chain construction moved in-scope: LGTM

Creating the chain inside the registration closure avoids shared state and aligns with other conditions.

lang/constructs/worldgen/surface_rules/Condition_YAbove.go (1)

20-31: In-scope builder-chain refactor: LGTM

Localizing yAboveBuilder and field wiring look correct.

lang/constructs/worldgen/surface_rules/Condition_AboveWater.go (1)

19-40: Builder chain localized: LGTM

Offset/Add/Multiplier builders are correctly registered; float multiplier label is clear.

lang/constructs/worldgen/surface_rules/Condition_VerticalGradient.go (1)

20-31: Builder-chain refactor: LGTM

Top/Bottom anchors via Builder_GetVerticalAnchor are wired correctly.

lang/constructs/worldgen/surface_rules/Rule_If.go (2)

104-105: Scope propagation in expanded rules: LGTM

Carrying c.scope into nested IfRule and OR-sequence entries preserves late reference resolution context.

Also applies to: 118-119


16-16: No issues—pointer vs non-pointer handled uniformly
ConstructRegistry.Register strips pointers (ctxType.Elem()), and Construct() looks up by the underlying type, so registrations using reflect.TypeFor[*…] or non-pointer both normalize correctly—no dispatch gaps.

lang/builder_chain/BuilderChain.go (4)

20-24: Good runtime type normalization approach

The change from compile-time generic parameter to runtime type resolution with consistent pointer normalization is a solid improvement. This unifies dispatch semantics and handles both pointer and non-pointer contexts correctly.


30-38: Good duplicate detection with improved type handling

The duplicate builder call detection now correctly uses the normalized non-pointer type, which prevents false negatives when the same context is passed with different pointer indirections.


44-46: Consistent type normalization in Require method

Good addition of pointer normalization in the Require method to match the changes in Invoke. This ensures that requirement checking uses the same type resolution logic.


63-68: Well-implemented registration with type normalization

The Build function correctly derives and normalizes the context type at registration time, ensuring consistency with the runtime dispatch logic in Invoke.

lang/traversal/Symbol.go (4)

14-14: Clean implementation of symbol type tracking

The addition of GetType() to the Symbol interface and its implementation in BaseSymbol provides a clean way to track and expose symbol types, which will be useful for type-aware operations and JSON serialization.

Also applies to: 22-27


43-45: Good addition of type parameter to ProcessDeclaration

Adding the typeName parameter allows callers to specify the semantic type of symbols at creation time, improving type awareness throughout the system.


56-56: Correct error context for missing value diagnostic

Good fix - using the declaration context (ctx) instead of the value context (valueCtx) for the missing value error provides better error location information to users.


91-92: Proper JSON serialization of new type field

The MarshalJSON implementation correctly includes the new Type field and properly serializes the reference as a pointer, maintaining backward compatibility while exposing the new type information.

Also applies to: 97-98

Comment on lines +45 to +49
child := r.GetChild(0)
if child == nil {
continue
}
builder_chain.Invoke(waterBuildChain, child.(antlr.ParserRuleContext), out, scope, namespace)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid panic: guard child type before cast

Protect the cast and surface a warning for unexpected nodes.

Apply:

 for _, r := range aboveWater.AllSurfaceCondition_AboveWaterBuilder() {
   child := r.GetChild(0)
   if child == nil {
     continue
   }
-  builder_chain.Invoke(waterBuildChain, child.(antlr.ParserRuleContext), out, scope, namespace)
+  if childCtx, ok := child.(antlr.ParserRuleContext); ok {
+    builder_chain.Invoke(waterBuildChain, childCtx, out, scope, namespace)
+  } else {
+    scope.DiagnoseSemanticWarning("Ignoring unexpected builder node; expected rule context", r)
+  }
 }
📝 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
child := r.GetChild(0)
if child == nil {
continue
}
builder_chain.Invoke(waterBuildChain, child.(antlr.ParserRuleContext), out, scope, namespace)
for _, r := range aboveWater.AllSurfaceCondition_AboveWaterBuilder() {
child := r.GetChild(0)
if child == nil {
continue
}
if childCtx, ok := child.(antlr.ParserRuleContext); ok {
builder_chain.Invoke(waterBuildChain, childCtx, out, scope, namespace)
} else {
scope.DiagnoseSemanticWarning("Ignoring unexpected builder node; expected rule context", r)
}
}
🤖 Prompt for AI Agents
In lang/constructs/worldgen/surface_rules/Condition_AboveWater.go around lines
45 to 49, the code directly type-asserts child.(antlr.ParserRuleContext) which
can panic if the node is not the expected type; instead perform a safe type
assertion (childAsCtx, ok := child.(antlr.ParserRuleContext)), and if ok is
false emit a warning (using the existing logger or fmt.Errorf/LogWarn) that
includes the unexpected child type and its index, then continue the loop without
invoking builder_chain; only call builder_chain.Invoke when the assertion
succeeds.

Comment on lines +45 to +49
child := r.GetChild(0)
if child == nil {
continue
}
builder_chain.Invoke(noiseBuildChain, child.(antlr.ParserRuleContext), out, scope, namespace)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add nil check before type assertion

The code performs a type assertion on child.(antlr.ParserRuleContext) without verifying that the child can be cast to this type. While the nil check on line 46 prevents nil pointer issues, it doesn't guarantee the type assertion will succeed.

Apply this diff to add proper type checking:

 for _, r := range noise.AllSurfaceCondition_NoiseThresholdBuilder() {
     child := r.GetChild(0)
-    if child == nil {
-        continue
+    if childCtx, ok := child.(antlr.ParserRuleContext); ok && childCtx != nil {
+        builder_chain.Invoke(noiseBuildChain, childCtx, out, scope, namespace)
     }
-    builder_chain.Invoke(noiseBuildChain, child.(antlr.ParserRuleContext), out, scope, namespace)
 }
📝 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
child := r.GetChild(0)
if child == nil {
continue
}
builder_chain.Invoke(noiseBuildChain, child.(antlr.ParserRuleContext), out, scope, namespace)
for _, r := range noise.AllSurfaceCondition_NoiseThresholdBuilder() {
child := r.GetChild(0)
if childCtx, ok := child.(antlr.ParserRuleContext); ok && childCtx != nil {
builder_chain.Invoke(noiseBuildChain, childCtx, out, scope, namespace)
}
}
🤖 Prompt for AI Agents
In lang/constructs/worldgen/surface_rules/Condition_Noise.go around lines 45 to
49, the code does a direct type assertion child.(antlr.ParserRuleContext) which
can panic if the runtime type is different; change it to perform a safe type
assertion using the comma-ok form (e.g., pr, ok :=
child.(antlr.ParserRuleContext)) and only call
builder_chain.Invoke(noiseBuildChain, pr, out, scope, namespace) when ok is true
(otherwise continue); keep the existing nil check if desired but ensure you
guard the type cast before invoking.

Comment on lines +46 to 51
child := r.GetChild(0)
if child == nil {
continue
}
builder_chain.Invoke(stoneDepthBuildChain, child.(antlr.ParserRuleContext), out, scope, namespace)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid panic: guard child type before cast

child may be a terminal; direct cast to antlr.ParserRuleContext can panic. Add a safe assertion and warn.

Apply:

 for _, r := range stoneDepth.AllSurfaceCondition_StoneDepthBuilder() {
   child := r.GetChild(0)
   if child == nil {
     continue
   }
-  builder_chain.Invoke(stoneDepthBuildChain, child.(antlr.ParserRuleContext), out, scope, namespace)
+  if childCtx, ok := child.(antlr.ParserRuleContext); ok {
+    builder_chain.Invoke(stoneDepthBuildChain, childCtx, out, scope, namespace)
+  } else {
+    scope.DiagnoseSemanticWarning("Ignoring unexpected builder node; expected rule context", r)
+  }
 }
📝 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
child := r.GetChild(0)
if child == nil {
continue
}
builder_chain.Invoke(stoneDepthBuildChain, child.(antlr.ParserRuleContext), out, scope, namespace)
}
for _, r := range stoneDepth.AllSurfaceCondition_StoneDepthBuilder() {
child := r.GetChild(0)
if child == nil {
continue
}
if childCtx, ok := child.(antlr.ParserRuleContext); ok {
builder_chain.Invoke(stoneDepthBuildChain, childCtx, out, scope, namespace)
} else {
scope.DiagnoseSemanticWarning("Ignoring unexpected builder node; expected rule context", r)
}
}
🤖 Prompt for AI Agents
In lang/constructs/worldgen/surface_rules/Condition_StoneDepth.go around lines
46 to 51, the code unconditionally casts child to antlr.ParserRuleContext which
can panic if child is a terminal; replace the direct cast with a safe type
assertion (ctx, ok := child.(antlr.ParserRuleContext)), and if !ok log or warn
about unexpected terminal type and continue the loop; only call
builder_chain.Invoke(stoneDepthBuildChain, ctx, out, scope, namespace) when ok
is true.

Comment on lines +46 to 52
child := r.GetChild(0)
if child == nil {
continue
}
builder_chain.Invoke(
verticalGradientBuilder, r, out, scope, ns,
verticalGradientBuilder, child.(antlr.ParserRuleContext), out, scope, ns,
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid panic: guard child type before cast

Same safety improvement as other files.

Apply:

 child := r.GetChild(0)
 if child == nil {
   continue
 }
-builder_chain.Invoke(
-  verticalGradientBuilder, child.(antlr.ParserRuleContext), out, scope, ns,
-)
+if childCtx, ok := child.(antlr.ParserRuleContext); ok {
+  builder_chain.Invoke(
+    verticalGradientBuilder, childCtx, out, scope, ns,
+  )
+} else {
+  scope.DiagnoseSemanticWarning("Ignoring unexpected builder node; expected rule context", r)
+}
📝 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
child := r.GetChild(0)
if child == nil {
continue
}
builder_chain.Invoke(
verticalGradientBuilder, r, out, scope, ns,
verticalGradientBuilder, child.(antlr.ParserRuleContext), out, scope, ns,
)
child := r.GetChild(0)
if child == nil {
continue
}
if childCtx, ok := child.(antlr.ParserRuleContext); ok {
builder_chain.Invoke(
verticalGradientBuilder, childCtx, out, scope, ns,
)
} else {
scope.DiagnoseSemanticWarning("Ignoring unexpected builder node; expected rule context", r)
}
🤖 Prompt for AI Agents
In lang/constructs/worldgen/surface_rules/Condition_VerticalGradient.go around
lines 46 to 52, the code directly type-asserts child.(antlr.ParserRuleContext)
which can panic if the child is not that type; change to a safe assertion: call
child := r.GetChild(0), keep the nil check, then do ctx, ok :=
child.(antlr.ParserRuleContext) and if !ok { continue } before invoking
builder_chain.Invoke with ctx, out, scope, ns so the function no longer panics
on unexpected child types.

Comment on lines +22 to +24
func(ctx *grammar.SharedBuilder_MulIntContext, target *YAboveCondition, scope *traversal.Scope, namespace string) {
builder_chain.Builder_GetInt(ctx, func(v int) { target.Multiplier = v }, scope, "Top")
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix mislabeled diagnostic: "Top" → "Multiplier"

This error label is confusing for users when validating the multiplier value.

Apply:

-            builder_chain.Builder_GetInt(ctx, func(v int) { target.Multiplier = v }, scope, "Top")
+            builder_chain.Builder_GetInt(ctx, func(v int) { target.Multiplier = v }, scope, "Multiplier")
📝 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
func(ctx *grammar.SharedBuilder_MulIntContext, target *YAboveCondition, scope *traversal.Scope, namespace string) {
builder_chain.Builder_GetInt(ctx, func(v int) { target.Multiplier = v }, scope, "Top")
},
func(ctx *grammar.SharedBuilder_MulIntContext, target *YAboveCondition, scope *traversal.Scope, namespace string) {
builder_chain.Builder_GetInt(ctx, func(v int) { target.Multiplier = v }, scope, "Multiplier")
},
🤖 Prompt for AI Agents
In lang/constructs/worldgen/surface_rules/Condition_YAbove.go around lines 22 to
24, the diagnostic label passed to builder_chain.Builder_GetInt is incorrectly
"Top" and should be "Multiplier"; update the fourth argument of Builder_GetInt
from "Top" to "Multiplier" so the validation/error messages correctly refer to
the Multiplier field.

Comment on lines +45 to +49
child := r.GetChild(0)
if child == nil {
continue
}
builder_chain.Invoke(yAboveBuilder, child.(antlr.ParserRuleContext), out, scope, ns)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid panic: guard child type before cast

Same risk as other conditions; protect the cast.

Apply:

 for _, r := range yAbove.AllSurfaceCondition_YAboveBuilder() {
   child := r.GetChild(0)
   if child == nil {
     continue
   }
-  builder_chain.Invoke(yAboveBuilder, child.(antlr.ParserRuleContext), out, scope, ns)
+  if childCtx, ok := child.(antlr.ParserRuleContext); ok {
+    builder_chain.Invoke(yAboveBuilder, childCtx, out, scope, ns)
+  } else {
+    scope.DiagnoseSemanticWarning("Ignoring unexpected builder node; expected rule context", r)
+  }
 }
📝 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
child := r.GetChild(0)
if child == nil {
continue
}
builder_chain.Invoke(yAboveBuilder, child.(antlr.ParserRuleContext), out, scope, ns)
for _, r := range yAbove.AllSurfaceCondition_YAboveBuilder() {
child := r.GetChild(0)
if child == nil {
continue
}
if childCtx, ok := child.(antlr.ParserRuleContext); ok {
builder_chain.Invoke(yAboveBuilder, childCtx, out, scope, ns)
} else {
scope.DiagnoseSemanticWarning("Ignoring unexpected builder node; expected rule context", r)
}
}
🤖 Prompt for AI Agents
In lang/constructs/worldgen/surface_rules/Condition_YAbove.go around lines 45 to
49, the code currently casts child to antlr.ParserRuleContext without verifying
its dynamic type which can panic; change the cast to a safe type assertion (e.g.
ctx, ok := child.(antlr.ParserRuleContext)) and only call
builder_chain.Invoke(yAboveBuilder, ctx, out, scope, ns) when ok is true,
otherwise continue; keep the existing nil check for child.

Comment on lines +20 to 21
scope: scope,
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Harden reference resolver against nil scope

The resolver closure captures scope; if nil, dereference will panic at runtime. Use out.scope with a nil check.

Update the resolver (shown here for clarity; change occurs where SetResolver is defined):

ref.Ref.SetResolver(func() error {
	if out.scope == nil {
		return nil
	}
	if next, ok := out.scope.Get(*ref.Ref); ok {
		out.Condition = next.GetValue()
	}
	return nil
})
🤖 Prompt for AI Agents
In lang/constructs/worldgen/surface_rules/Rule_If.go around lines 20-21, the
resolver closure captures scope and can panic if scope is nil; modify the
resolver passed to SetResolver to reference out.scope and first check if
out.scope == nil, returning early if so, otherwise perform the lookup
(out.scope.Get) and update out.Condition when found; ensure the closure returns
nil on early exit and after successful resolution.

@ItsMeBrianD ItsMeBrianD merged commit 2451322 into main Sep 5, 2025
@ItsMeBrianD ItsMeBrianD deleted the feat/worldgen/noise branch September 5, 2025 04:55
@coderabbitai coderabbitai bot mentioned this pull request Sep 8, 2025
@coderabbitai coderabbitai bot mentioned this pull request Oct 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

worldgen World Generation Related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant