Skip to content
63 changes: 63 additions & 0 deletions common/errors/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package errors

import "fmt"

type IndexOutOfBoundsError struct {
index int
length int
}

func (e IndexOutOfBoundsError) Error() string {
return fmt.Sprintf("Index %d out of bounds for length %d", e.index, e.length)
}

func (e IndexOutOfBoundsError) GetIndex() int {
return e.index
}

func (e IndexOutOfBoundsError) GetLength() int {
return e.length
}

func NewIndexOutOfBoundsError(index, length int) *IndexOutOfBoundsError {
return &IndexOutOfBoundsError{
index: index,
length: length,
}
}

type IllegalArgumentError struct {
argument interface{}
}

func (e IllegalArgumentError) Error() string {
return fmt.Sprintf("Illegal argument: %v", e.argument)
}

func (e IllegalArgumentError) GetArgument() interface{} {
return e.argument
}

func NewIllegalArgumentError(argument interface{}) *IllegalArgumentError {
return &IllegalArgumentError{
argument: argument,
}
}
90 changes: 90 additions & 0 deletions tools/diagnostics/default-diagnostic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package diagnostics

import (
"ballerina-lang-go/tools/text"
"fmt"
)

// DefaultDiagnostic is an internal implementation of the Diagnostic interface that is used by the DiagnosticFactory
// to create diagnostics.
type DefaultDiagnostic interface {
Diagnostic
}

type defaultDiagnosticImpl struct {
diagnosticBase
diagnosticInfo DiagnosticInfo
location Location
properties []DiagnosticProperty[interface{}]
message string
}

func NewDefaultDiagnostic(diagnosticInfo DiagnosticInfo, location Location, properties []DiagnosticProperty[any], args ...interface{}) DefaultDiagnostic {
message := formatMessage(diagnosticInfo.MessageFormat(), args...)
return &defaultDiagnosticImpl{
diagnosticBase: diagnosticBase{},
diagnosticInfo: diagnosticInfo,
location: location,
properties: properties,
message: message,
}
}

func (dd *defaultDiagnosticImpl) Location() Location {
return dd.location
}

func (dd *defaultDiagnosticImpl) DiagnosticInfo() DiagnosticInfo {
return dd.diagnosticInfo
}

func (dd *defaultDiagnosticImpl) Message() string {
return dd.message
}

func (dd *defaultDiagnosticImpl) Properties() []DiagnosticProperty[any] {
return dd.properties
}

func (dd *defaultDiagnosticImpl) String() string {
lineRange := dd.location.LineRange()
filePath := lineRange.FileName()

startLine := lineRange.StartLine()
endLine := lineRange.EndLine()

oneBasedStartLine := text.LinePositionFromLineAndOffset(startLine.Line()+1, startLine.Offset()+1)
oneBasedEndLine := text.LinePositionFromLineAndOffset(endLine.Line()+1, endLine.Offset()+1)
oneBasedLineRange := text.LineRangeFromLinePositions(filePath, oneBasedStartLine, oneBasedEndLine)

return fmt.Sprintf("%s [%s:%s] %s",
dd.diagnosticInfo.Severity().String(),
filePath,
oneBasedLineRange.String(),
dd.Message())
}

func formatMessage(format string, args ...interface{}) string {
if len(args) == 0 {
return format
}
return fmt.Sprintf(format, args...)
}
27 changes: 27 additions & 0 deletions tools/diagnostics/diagnostic-code.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package diagnostics

// DiagnosticCode represents a diagnostic code.
// Diagnostic code uniquely identifies a diagnostic.
type DiagnosticCode interface {
Severity() DiagnosticSeverity
DiagnosticId() string
MessageKey() string
}
44 changes: 44 additions & 0 deletions tools/diagnostics/diagnostic-factory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package diagnostics

// CreateDiagnostic creates a Diagnostic instance from the given details.
//
// Parameters:
// - diagnosticInfo: static diagnostic information
// - location: the location of the diagnostic
// - args: arguments to diagnostic message format
//
// Returns a Diagnostic instance.
func CreateDiagnostic(diagnosticInfo DiagnosticInfo, location Location, args ...interface{}) Diagnostic {
return NewDefaultDiagnostic(diagnosticInfo, location, []DiagnosticProperty[any]{}, args...)
}

// CreateDiagnosticWithProperties creates a Diagnostic instance from the given details.
//
// Parameters:
// - diagnosticInfo: static diagnostic information
// - location: the location of the diagnostic
// - properties: properties associated with the diagnostic
// - args: arguments to diagnostic message format
//
// Returns a Diagnostic instance.
func CreateDiagnosticWithProperties(diagnosticInfo DiagnosticInfo, location Location, properties []DiagnosticProperty[any], args ...interface{}) Diagnostic {
return NewDefaultDiagnostic(diagnosticInfo, location, properties, args...)
}
79 changes: 79 additions & 0 deletions tools/diagnostics/diagnostic-info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package diagnostics

// DiagnosticInfo represents an abstract shape of a Diagnostic that is independent of
// the location and message arguments.
type DiagnosticInfo interface {
Code() string
MessageFormat() string
Severity() DiagnosticSeverity
DiagnosticInfoLookupKey() DiagnosticInfoLookupKey
}

// DiagnosticInfoLookupKey represents the comparable fields of DiagnosticInfo for equality/hashing.
type DiagnosticInfoLookupKey struct {
Code *string // pointer to handle nil values
MessageFormat string
Severity DiagnosticSeverity
}

type diagnosticInfoImpl struct {
code *string // pointer to handle nil values
messageFormat string
severity DiagnosticSeverity
}

// NewDiagnosticInfo constructs an abstract shape of a Diagnostic.
//
// Parameters:
// - code: a code that can be used to uniquely identify a diagnostic category
// - messageFormat: a pattern that can be formatted with message formatting utilities
// - severity: the severity of the diagnostic
func NewDiagnosticInfo(code *string, messageFormat string, severity DiagnosticSeverity) DiagnosticInfo {
return &diagnosticInfoImpl{
code: code,
messageFormat: messageFormat,
severity: severity,
}
}

func (di diagnosticInfoImpl) Code() string {
if di.code == nil {
return ""
}
return *di.code
}

func (di diagnosticInfoImpl) MessageFormat() string {
return di.messageFormat
}

func (di diagnosticInfoImpl) Severity() DiagnosticSeverity {
return di.severity
}

// DiagnosticInfoLookupKey returns the lookup key for equality comparisons.
func (di diagnosticInfoImpl) DiagnosticInfoLookupKey() DiagnosticInfoLookupKey {
return DiagnosticInfoLookupKey{
Code: di.code,
MessageFormat: di.messageFormat,
Severity: di.severity,
}
}
48 changes: 48 additions & 0 deletions tools/diagnostics/diagnostic-property-kind.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package diagnostics

// DiagnosticPropertyKind represents the kind of the diagnostic property.
type DiagnosticPropertyKind uint8

const (
Symbolic DiagnosticPropertyKind = iota
String
Numeric
Collection
Other
)

// String returns the string representation of the diagnostic property kind.
func (dpk DiagnosticPropertyKind) String() string {
switch dpk {
case Symbolic:
return "SYMBOLIC"
case String:
return "STRING"
case Numeric:
return "NUMERIC"
case Collection:
return "COLLECTION"
case Other:
return "OTHER"
default:
return "UNKNOWN"
}
}
25 changes: 25 additions & 0 deletions tools/diagnostics/diagnostic-property.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package diagnostics

// DiagnosticProperty represents properties passed when diagnostic logging.
type DiagnosticProperty[T interface{}] interface {
Kind() DiagnosticPropertyKind
Value() T
}
Loading
Loading