errors

package
v0.5.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 8, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

README

Enhanced Error Messages for GLYPHLANG

This package provides comprehensive error handling with enhanced error messages, intelligent suggestions, and helpful debugging context.

Features

1. Enhanced "Did you mean?" Suggestions

The error system uses advanced fuzzy matching algorithms to suggest corrections:

// Variable name suggestions
availableVars := []string{"username", "userId", "userEmail"}
suggestion := GetVariableSuggestion("usrname", availableVars)
// Returns: "Did you mean 'username'? Or make sure to define the variable with '$ usrname = value'"

// Function name suggestions
availableFuncs := []string{"println", "print", "printf"}
suggestion := GetFunctionSuggestion("prnt", availableFuncs)
// Returns: "Did you mean 'print' or 'println'?"

// Type name suggestions
availableTypes := []string{"User", "Product", "Order"}
suggestion := GetTypeSuggestion("Usr", availableTypes)
// Returns: "Did you mean 'User'?"

// Route path suggestions
availableRoutes := []string{"/users", "/users/:id", "/products"}
suggestion := GetRouteSuggestion("/usr", availableRoutes)
// Returns: "Did you mean '/users'?"

Common typo corrections:

  • fucntionfunction
  • retrunreturn
  • lenghtlength
  • treutrue
  • flasefalse
  • And many more!
2. Code Snippets with Error Context

Errors show multiple lines of context with exact error position:

source := `@ route /users GET -> array {
    $ userCount: int = "invalid"
    return getUsers()
}`

err := NewTypeError(
    "Type mismatch in variable declaration",
    2,
    24,
    ExtractSourceSnippet(source, 2),
    GetTypeMismatchSuggestion("int", "string", "variable declaration"),
).WithTypes("int", "string").
  WithContext("in route /users GET").
  WithFixedLine(`    $ userCount: int = 0`)

Output:

Type Error in route /users GET at line 2, column 24

     1 | @ route /users GET -> array {
     2 | $ userCount: int = "invalid"
       |                        ^ error here
     2 | $ userCount: int = 0 (suggested fix)
     3 | return getUsers()

Type mismatch in variable declaration

Expected: int
Actual:   string

Suggestion: Convert the string to an integer using parseInt() or ensure the value is numeric
3. Syntax Error Hints

Automatic detection of common syntax errors:

// Missing brackets/braces/parentheses
DetectMissingBracket(source, line, column)
// Returns: "Missing 1 closing brace '}'" or "Unexpected closing bracket ']'"

// Unclosed strings
DetectUnclosedString(source, line)
// Returns: "Unclosed string literal (missing closing \")"

// Common syntax patterns
DetectCommonSyntaxErrors(source, line, errorMsg)
// Detects patterns like missing closing braces, unclosed strings, etc.
4. Type Error Improvements

Enhanced type error messages with clear expected vs actual types:

err := NewTypeError(
    "Type mismatch in assignment",
    2,
    21,
    snippet,
    GetTypeMismatchSuggestion("int", "string", "variable assignment"),
).WithTypes("int", "string")

Type-specific suggestions:

  • intstring: "Convert the string to an integer using parseInt()"
  • stringint: "Convert the integer to a string using toString()"
  • boolint: "Use a boolean value (true or false) or convert using a comparison"
  • floatint: "The integer will be automatically converted to float"
  • array ← other: "Wrap the value in square brackets [] to create an array"
5. Runtime Error Context

Runtime errors include full execution context:

err := NewRuntimeError("Division by zero").
    WithRoute("/calculate POST").
    WithExpression("result = numerator / denominator").
    WithSuggestion(GetRuntimeSuggestion("division_by_zero", nil)).
    WithScope(map[string]interface{}{
        "numerator":   10,
        "denominator": 0,
    }).
    WithStackFrame("calculateResult", "/calculate POST", 5).
    WithStackFrame("handleRequest", "main.glyphc", 12)

Output:

Runtime Error

Division by zero

Route: /calculate POST

Expression:
  result = numerator / denominator

Variables in scope:
  numerator = 10 (int)
  denominator = 0 (int)

Stack trace:
  1. calculateResult at /calculate POST:5
  2. handleRequest at main.glyphc:12

Suggestion: Add a check to ensure the divisor is not zero before dividing: if (divisor != 0) { ... }

Runtime error types:

  • division_by_zero
  • null_reference
  • index_out_of_bounds
  • type_error
  • undefined_property
  • sql_injection
  • xss

Usage Examples

Compile Error with Suggestion
err := NewCompileError(
    "Undefined variable 'totl'",
    3,
    7,
    ExtractSourceSnippet(source, 3),
    GetVariableSuggestion("totl", []string{"total", "count"}),
).WithContext("in route /users GET")

fmt.Println(err.FormatError(true)) // With colors
Parse Error with Hint
err := NewParseError(
    "Missing closing bracket in array literal",
    2,
    24,
    ExtractSourceSnippet(source, 2),
    "Add a closing bracket ']' to complete the array definition",
)

fmt.Println(err.FormatError(false)) // Without colors
Type Error with Expected/Actual Types
err := NewTypeError(
    "Type mismatch in function parameter",
    5,
    15,
    snippet,
    GetTypeMismatchSuggestion("string", "int", "function parameter"),
).WithTypes("string", "int").WithContext("in function calculateAge")
Error Wrapping
// Start with a simple error
baseErr := fmt.Errorf("invalid value")

// Add line information
err := WithLineInfo(baseErr, 2, 13, source)

// Add suggestion
err = WithSuggestion(err, "Check the value type")

// Add filename
err = WithFileName(err, "main.glyphc")

// Format and display
fmt.Println(FormatError(err))

Configuration

Suggestion Configuration
config := &SuggestionConfig{
    MaxSuggestions:      3,     // Maximum number of suggestions to return
    MaxDistance:         3,     // Maximum Levenshtein distance for matches
    MinSimilarityScore:  0.5,   // Minimum similarity score (0.0 - 1.0)
    ShowMultipleSuggestions: true, // Show multiple suggestions
}

results := FindBestSuggestions("cunt", candidates, config)

Advanced Features

Custom Suggestion Formatting
results := FindBestSuggestions(target, candidates, config)
formatted := FormatSuggestions(results, true)
// Returns: "Did you mean 'count', 'counter', or 'total'?"
Similarity Scoring

The similarity score takes into account:

  • Levenshtein distance (edit distance)
  • Common prefixes (first 3 characters)
  • Common suffixes (last 2 characters)
  • Substring matches
  • Case-insensitive matches
Identifier Validation
if !IsValidIdentifier(name) {
    suggestion := SuggestValidIdentifier(name)
    // Returns helpful message about why it's invalid and how to fix it
}

Testing

Run all tests:

go test ./pkg/errors/...

Run benchmarks:

go test ./pkg/errors/... -bench=. -benchmem

Run specific examples:

go test ./pkg/errors/... -v -run Example

Performance

Benchmarks on AMD Ryzen 7 7800X3D:

  • CompileError formatting: ~859 ns/op
  • RuntimeError formatting: ~870 ns/op
  • Levenshtein distance: ~230 ns/op
  • Best suggestions: ~3964 ns/op
  • Similarity score: ~84 ns/op
  • Missing bracket detection: ~240 ns/op
  • Unclosed string detection: ~118 ns/op

Color Support

All error formatters support both colored and non-colored output:

err.FormatError(true)  // With ANSI colors
err.FormatError(false) // Without colors (for logs, files, etc.)

Integration

The error package integrates seamlessly with:

  • Parser (pkg/parser/errors.go) - Parse-time error detection
  • Compiler - Compile-time type checking and validation
  • Runtime (pkg/vm) - Runtime error handling with full context
  • LSP (pkg/lsp) - Language server for IDE integration

Future Enhancements

Planned features:

  • Machine learning-based suggestion ranking
  • Context-aware error messages based on surrounding code
  • Integration with external documentation
  • Multi-language error messages
  • Error recovery suggestions

Documentation

Index

Examples

Constants

View Source
const (
	Reset  = "\033[0m"
	Red    = "\033[31m"
	Green  = "\033[32m"
	Yellow = "\033[33m"
	Blue   = "\033[34m"
	Purple = "\033[35m"
	Cyan   = "\033[36m"
	Gray   = "\033[90m"
	Bold   = "\033[1m"
)

ANSI color codes for terminal output

Variables

This section is empty.

Functions

func DetectCommonSyntaxErrors

func DetectCommonSyntaxErrors(source string, line int, errorMsg string) string

DetectCommonSyntaxErrors detects common syntax error patterns

func DetectMissingBracket

func DetectMissingBracket(source string, line, column int) string

DetectMissingBracket detects missing brackets, braces, or parentheses

Example

Example: Missing bracket detection

source := `@ GET /items GET -> array {
    $ items = [1, 2, 3
    return items
}`

suggestion := DetectMissingBracket(source, 2, 24)

err := NewParseError(
	"Unexpected token at end of line",
	2,
	24,
	ExtractSourceSnippet(source, 2),
	suggestion,
)

fmt.Println(err.FormatError(false))
// Output will suggest adding closing bracket

func DetectUnclosedString

func DetectUnclosedString(source string, line int) string

DetectUnclosedString detects unclosed string literals

Example

Example: Unclosed string detection

source := `@ GET /message GET -> string {
    $ msg = "Hello world
    return msg
}`

suggestion := DetectUnclosedString(source, 2)

err := NewParseError(
	"Unexpected end of line in string literal",
	2,
	24,
	ExtractSourceSnippet(source, 2),
	suggestion,
)

fmt.Println(err.FormatError(false))
// Output will detect unclosed string

func ExtractSourceSnippet

func ExtractSourceSnippet(source string, line int) string

ExtractSourceSnippet extracts a source code snippet around a specific line

func FormatCodeSnippetWithFix

func FormatCodeSnippetWithFix(source string, line, column int, fixedLine string) string

FormatCodeSnippetWithFix formats source code with a suggested fix

func FormatError

func FormatError(err error) string

FormatError formats any error with colors and context This is the main public interface for error formatting

func FormatSuggestions

func FormatSuggestions(results []SuggestionResult, multipleAllowed bool) string

FormatSuggestions formats suggestion results into a human-readable string

func GetFunctionSuggestion

func GetFunctionSuggestion(funcName string, availableFuncs []string) string

GetFunctionSuggestion suggests function names

Example

Example: Function name suggestion

availableFuncs := []string{"println", "print", "printf", "log"}
suggestion := GetFunctionSuggestion("prnt", availableFuncs)

source := `@ GET /test GET -> string {
    prnt("Hello")
    return "ok"
}`
snippet := ExtractSourceSnippet(source, 2)

err := NewCompileError(
	"Undefined function 'prnt'",
	2,
	5,
	snippet,
	suggestion,
)

fmt.Println(err.FormatError(false))

func GetRouteSuggestion

func GetRouteSuggestion(routePath string, availableRoutes []string) string

GetRouteSuggestion suggests route paths

Example

Example: Route path suggestion

availableRoutes := []string{"/users", "/users/:id", "/products", "/orders"}
suggestion := GetRouteSuggestion("/usr", availableRoutes)

err := NewCompileError(
	"Route '/usr' is not defined",
	1,
	1,
	"@ forward /usr",
	suggestion,
)

fmt.Println(err.FormatError(false))

func GetRuntimeSuggestion

func GetRuntimeSuggestion(errorType string, context map[string]interface{}) string

GetRuntimeSuggestion provides context-aware runtime error suggestions

func GetSuggestionForDivisionByZero

func GetSuggestionForDivisionByZero() string

GetSuggestionForDivisionByZero suggests fixes for division by zero

func GetSuggestionForSQLInjection

func GetSuggestionForSQLInjection() string

GetSuggestionForSQLInjection suggests fixes for SQL injection vulnerabilities

func GetSuggestionForTypeMismatch

func GetSuggestionForTypeMismatch(expected, actual string) string

GetSuggestionForTypeMismatch suggests fixes for type mismatches

func GetSuggestionForUndefinedVariable

func GetSuggestionForUndefinedVariable(varName string, availableVars []string) string

GetSuggestionForUndefinedVariable suggests common fixes for undefined variables

func GetTypeMismatchSuggestion

func GetTypeMismatchSuggestion(expected, actual, context string) string

GetTypeMismatchSuggestion provides enhanced type mismatch suggestions

func GetTypeSuggestion

func GetTypeSuggestion(typeName string, availableTypes []string) string

GetTypeSuggestion suggests type names

Example

Example: Type name suggestion

customTypes := []string{"User", "Product", "Order"}
suggestion := GetTypeSuggestion("Usr", customTypes)

source := `@ GET /data GET -> Usr {
    $ user: Usr = getUser()
    return user
}`
snippet := ExtractSourceSnippet(source, 2)

err := NewTypeError(
	"Unknown type 'Usr'",
	2,
	13,
	snippet,
	suggestion,
)

fmt.Println(err.FormatError(false))

func GetVariableSuggestion

func GetVariableSuggestion(varName string, availableVars []string) string

GetVariableSuggestion suggests variable names with enhanced fuzzy matching

func IsValidIdentifier

func IsValidIdentifier(s string) bool

IsValidIdentifier checks if a string is a valid identifier

func SuggestMissingSemicolon

func SuggestMissingSemicolon(source string, line int) bool

SuggestMissingSemicolon checks if a semicolon might be missing (if language requires it)

func SuggestValidIdentifier

func SuggestValidIdentifier(s string) string

SuggestValidIdentifier suggests corrections to make an invalid identifier valid

func WithFileName

func WithFileName(err error, fileName string) error

WithFileName adds a filename to an error

func WithLineInfo

func WithLineInfo(err error, line, col int, source string) error

WithLineInfo wraps an error with line and column information

func WithSuggestion

func WithSuggestion(err error, suggestion string) error

WithSuggestion wraps an error with a helpful suggestion

func Wrap

func Wrap(err error, line, col int, source, fileName, suggestion string) error

Wrap wraps an error with complete context information

Types

type CompileError

type CompileError struct {
	Message       string
	Line          int
	Column        int
	SourceSnippet string
	Suggestion    string
	FileName      string
	ErrorType     string
	FixedLine     string // Suggested fix for the error line
	ExpectedType  string // For type errors
	ActualType    string // For type errors
	Context       string // Additional context (e.g., "in function foo", "in route /users")
}

CompileError represents a compilation error with context

Example (EnhancedTypeError)

Example: Type error with expected vs actual

source := `@ GET /calculate POST -> int {
    $ result: int = "not a number"
    return result
}`
snippet := ExtractSourceSnippet(source, 2)

suggestion := GetTypeMismatchSuggestion("int", "string", "variable assignment")

err := NewTypeError(
	"Type mismatch in assignment",
	2,
	21,
	snippet,
	suggestion,
).WithTypes("int", "string").WithContext("in route /calculate POST")

fmt.Println(err.FormatError(false))
// Output will show expected vs actual types clearly
Example (EnhancedVariableSuggestion)

Example: Enhanced variable suggestion

source := `@ GET /users GET -> array {
    $ userList = getUsers()
    $ totl = userList.length
    return userList
}`
snippet := ExtractSourceSnippet(source, 3)

availableVars := []string{"userList", "total", "count"}
suggestion := GetVariableSuggestion("totl", availableVars)

err := NewCompileError(
	"Undefined variable 'totl'",
	3,
	7,
	snippet,
	suggestion,
).WithContext("in route /users GET")

fmt.Println(err.FormatError(false))
// Output will show enhanced error with "Did you mean 'total'?" suggestion
Example (ParseError)
source := `@ GET /users GET {
    $ users = [1, 2, 3
    return users
}`

err := NewParseError(
	"Missing closing bracket in array literal",
	2,
	24,
	ExtractSourceSnippet(source, 2),
	"Add a closing bracket ']' to complete the array definition",
)

// Print without colors for consistent output
output := err.FormatError(false)
fmt.Print(output)
Example (SyntaxErrorWithFix)

Example: Syntax error with suggested fix

source := `@ GET /data GET -> object {
    $ data = {name: "test", age 25}
    return data
}`
snippet := ExtractSourceSnippet(source, 2)

err := NewParseError(
	"Missing colon in object literal",
	2,
	36,
	snippet,
	"Object properties should be in the format 'key: value'",
).WithFixedLine(`    $ data = {name: "test", age: 25}`)

fmt.Println(err.FormatError(false))
// Output will show the error and suggested fix inline
Example (TypeError)
source := `$ age: int = "twenty-five"`

err := NewTypeError(
	"Type mismatch: cannot assign 'string' to variable of type 'int'",
	1,
	14,
	ExtractSourceSnippet(source, 1),
	"Convert the string to an integer (e.g., 25) or change the type annotation to 'str'",
)

output := err.FormatError(false)
fmt.Print(output)

func NewCompileError

func NewCompileError(message string, line, column int, sourceSnippet, suggestion string) *CompileError

NewCompileError creates a new compile error with context

func NewParseError

func NewParseError(message string, line, column int, sourceSnippet, suggestion string) *CompileError

NewParseError creates a parse-specific error

func NewTypeError

func NewTypeError(message string, line, column int, sourceSnippet, suggestion string) *CompileError

NewTypeError creates a type-checking error

func (*CompileError) Error

func (e *CompileError) Error() string

Error implements the error interface

func (*CompileError) FormatError

func (e *CompileError) FormatError(useColors bool) string

FormatError formats the error with optional color support

func (*CompileError) WithContext

func (e *CompileError) WithContext(context string) *CompileError

WithContext adds contextual information to the error

func (*CompileError) WithFixedLine

func (e *CompileError) WithFixedLine(fixedLine string) *CompileError

WithFixedLine adds a suggested fix line to the error

func (*CompileError) WithTypes

func (e *CompileError) WithTypes(expected, actual string) *CompileError

WithTypes adds type information for type errors

type RuntimeError

type RuntimeError struct {
	Message    string
	Route      string
	Expression string
	StackTrace []StackFrame
	Suggestion string
	ErrorType  string
	Scope      map[string]interface{}
}

RuntimeError represents a runtime error with execution context

Example (DivisionByZero)
err := NewRuntimeError("Division by zero error").
	WithRoute("/calculate POST").
	WithExpression("result = total / count").
	WithScope(map[string]interface{}{
		"total": 100,
		"count": 0,
	}).
	WithSuggestion("Add a check to ensure 'count' is not zero before performing division").
	WithStackFrame("calculateAverage", "/calculate POST", 12).
	WithStackFrame("main", "main.glyph", 5)

output := err.FormatError(false)
fmt.Print(output)
Example (EnhancedFullContext)

Example: Runtime error with full context

err := NewRuntimeError("Division by zero").
	WithRoute("/calculate POST").
	WithExpression("result = numerator / denominator").
	WithSuggestion(GetRuntimeSuggestion("division_by_zero", nil)).
	WithScope(map[string]interface{}{
		"numerator":   10,
		"denominator": 0,
	}).
	WithStackFrame("calculateResult", "/calculate POST", 5).
	WithStackFrame("handleRequest", "main.glyph", 12)

fmt.Println(err.FormatError(false))
// Output will show full runtime context with variables and stack trace
Example (UndefinedVariable)
err := NewRuntimeError("Variable 'usrName' is not defined").
	WithRoute("/profile GET").
	WithExpression("return { name: usrName, id: userId }").
	WithScope(map[string]interface{}{
		"userId":   123,
		"userName": "john_doe",
	}).
	WithSuggestion("Did you mean 'userName'? Or define the variable before using it: $ usrName = value")

output := err.FormatError(false)
fmt.Print(output)

func NewRuntimeError

func NewRuntimeError(message string) *RuntimeError

NewRuntimeError creates a new runtime error

func (*RuntimeError) Error

func (e *RuntimeError) Error() string

Error implements the error interface

func (*RuntimeError) FormatError

func (e *RuntimeError) FormatError(useColors bool) string

FormatError formats the runtime error with optional color support

func (*RuntimeError) WithExpression

func (e *RuntimeError) WithExpression(expr string) *RuntimeError

WithExpression adds expression context to a runtime error

func (*RuntimeError) WithRoute

func (e *RuntimeError) WithRoute(route string) *RuntimeError

WithRoute adds route context to a runtime error

func (*RuntimeError) WithScope

func (e *RuntimeError) WithScope(scope map[string]interface{}) *RuntimeError

WithScope adds variable scope to a runtime error

func (*RuntimeError) WithStackFrame

func (e *RuntimeError) WithStackFrame(function, location string, line int) *RuntimeError

WithStackFrame adds a stack frame to a runtime error

func (*RuntimeError) WithSuggestion

func (e *RuntimeError) WithSuggestion(suggestion string) *RuntimeError

WithSuggestion adds a suggestion to a runtime error

type StackFrame

type StackFrame struct {
	Function string
	Location string
	Line     int
}

StackFrame represents a single frame in the call stack

type SuggestionConfig

type SuggestionConfig struct {
	MaxSuggestions          int
	MaxDistance             int
	MinSimilarityScore      float64
	ShowMultipleSuggestions bool
}

SuggestionConfig controls suggestion behavior

func DefaultSuggestionConfig

func DefaultSuggestionConfig() *SuggestionConfig

DefaultSuggestionConfig returns the default configuration

type SuggestionResult

type SuggestionResult struct {
	Suggestion string
	Distance   int
	Score      float64
}

SuggestionResult contains a suggestion with its confidence score

func FindBestSuggestions

func FindBestSuggestions(target string, candidates []string, config *SuggestionConfig) []SuggestionResult

FindBestSuggestions finds the best matching suggestions for a given name

type SyntaxPattern

type SyntaxPattern struct {
	Pattern     string
	Description string
	Suggestion  string
}

SyntaxPattern represents a common syntax error pattern

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL