Windev to Golang Conversion
Convert Windev (WLanguage) code to idiomatic Go, maintaining functionality while adapting to Go best practices.
Core Conversion Principles
1. Comment Handling
- IGNORE: Code commented out in Windev (lines starting with
//at the beginning) - PRESERVE: Descriptive comments explaining functionality, actions, and observations
- TRANSLATE: Convert Windev comment style to Go comment style
- Add Go documentation comments (starting with function name) for exported functions
2. Code Structure
- Convert Windev procedures to Go functions
- Convert Windev web services to Gin handlers
- Transform initialization code to
main()orinit()functions - Adapt cleanup/finalization code to use
deferstatements
3. Mandatory Packages
- Logging: Use
go.uber.org/zapfor all logging operations - APIs: Use
github.com/gin-gonic/ginfor web services and REST APIs - Database: Use
database/sqlwith appropriate drivers
4. Function Discovery
When encountering Windev functions without known Go equivalents:
- Check references/wlanguage-mapping.md first
- If not found, ASK the user: "I need a Go implementation for the Windev function
[FunctionName]. Can you provide the equivalent or describe what it does?" - Wait for clarification before proceeding
- Document new mappings for future reference
Conversion Workflow
Step 1: Analyze Source Code
Read the Windev code and identify:
- Procedures and functions
- Web service endpoints
- Database operations (HyperFileSQL or SQL)
- File operations
- Initialization/cleanup sections
- Global variables and constants
- External dependencies
Step 2: Load Reference Materials
Always read these references before conversion:
view references/wlanguage-mapping.md # Function mappings
view references/windev-patterns.md # Common patterns
Step 3: Plan Go Structure
Determine:
- Package organization
- Required imports
- Global variables (minimize these)
- Configuration approach
- Error handling strategy
Step 4: Convert Code
Follow these priorities:
- Convert structures and types first
- Convert utility functions
- Convert business logic procedures
- Convert API handlers last
- Add proper error handling throughout
- Add logging at key points
Step 5: Add Infrastructure
- Create
main.gowith initialization - Setup database connection with pooling
- Configure Zap logger (development or production mode)
- Setup Gin router with middleware
- Add health check endpoint
Conversion Guidelines
Procedures to Functions
Windev:
PROCEDURE CalculateTotal(nQuantity is int, rPrice is real)
// Calculate the total with tax
rTotal is real
rTotal = nQuantity * rPrice * 1.15
RESULT rTotal
Go:
// CalculateTotal calculates the total price with tax
// quantity: number of items
// price: price per item
// Returns: total price including 15% tax
func CalculateTotal(quantity int, price float64) float64 {
// Calculate the total with tax
total := float64(quantity) * price * 1.15
return total
}
Web Services to Gin Handlers
Windev:
PROCEDURE ws_GetProduct(nProductID is int)
stProduct is ST_Product
HReadSeek(Product, ProductID, nProductID)
IF HFound() THEN
stProduct.Name = Product.Name
stProduct.Price = Product.Price
WebserviceWriteHTTPCode(200)
RESULT VariantToJSON(stProduct)
ELSE
WebserviceWriteHTTPCode(404)
RESULT "Product not found"
END
Go:
// GetProduct retrieves a product by ID
// Converted from Windev: ws_GetProduct
func GetProduct(c *gin.Context) {
productID, err := strconv.Atoi(c.Param("id"))
if err != nil {
logger.Error("invalid product ID", zap.Error(err))
c.JSON(400, gin.H{"error": "Invalid product ID"})
return
}
var product Product
query := "SELECT id, name, price FROM products WHERE id = $1"
err = db.QueryRow(query, productID).Scan(&product.ID, &product.Name, &product.Price)
if err == sql.ErrNoRows {
logger.Warn("product not found", zap.Int("productID", productID))
c.JSON(404, gin.H{"error": "Product not found"})
return
}
if err != nil {
logger.Error("database error", zap.Error(err))
c.JSON(500, gin.H{"error": "Internal server error"})
return
}
logger.Info("product retrieved", zap.Int("productID", productID))
c.JSON(200, product)
}
Database Operations
Convert HyperFileSQL operations to SQL queries:
Windev:
FOR EACH Product WHERE Category = sCategory
stProduct.Name = Product.Name
ArrayAdd(arrProducts, stProduct)
END
Go:
query := "SELECT id, name, price FROM products WHERE category = $1"
rows, err := db.Query(query, category)
if err != nil {
logger.Error("query failed", zap.Error(err))
return nil, fmt.Errorf("failed to query products: %w", err)
}
defer rows.Close()
var products []Product
for rows.Next() {
var product Product
if err := rows.Scan(&product.ID, &product.Name, &product.Price); err != nil {
logger.Error("scan failed", zap.Error(err))
return nil, fmt.Errorf("failed to scan product: %w", err)
}
products = append(products, product)
}
if err = rows.Err(); err != nil {
logger.Error("rows error", zap.Error(err))
return nil, fmt.Errorf("error iterating products: %w", err)
}
File Operations
Windev:
nFileID is int = fOpen(sFilePath, foRead)
WHILE NOT fEndOfFile(nFileID)
sLine = fReadLine(nFileID)
// Process line
END
fClose(nFileID)
Go:
file, err := os.Open(filePath)
if err != nil {
logger.Error("cannot open file", zap.String("path", filePath), zap.Error(err))
return fmt.Errorf("cannot open file: %w", err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
// Process line
}
if err := scanner.Err(); err != nil {
logger.Error("scanner error", zap.Error(err))
return fmt.Errorf("error reading file: %w", err)
}
Error Handling
Always use explicit error handling:
Windev:
WHEN EXCEPTION
Error("Operation failed: " + ExceptionInfo())
END
bResult = DangerousOperation()
Go:
result, err := DangerousOperation()
if err != nil {
logger.Error("operation failed", zap.Error(err))
return fmt.Errorf("operation failed: %w", err)
}
Logging Standards
Use Zap logger consistently:
// Initialization
logger, _ := zap.NewProduction()
defer logger.Sync()
// Debug (detailed diagnostic info)
logger.Debug("processing item", zap.Int("itemID", id))
// Info (general informational messages)
logger.Info("user created", zap.String("username", username))
// Warn (warning conditions)
logger.Warn("item not found", zap.Int("itemID", id))
// Error (error conditions)
logger.Error("database connection failed", zap.Error(err))
// Fatal (application terminating errors)
logger.Fatal("cannot start server", zap.Error(err))
Project Structure
Organize converted code:
project/
├── main.go # Application entry point
├── handlers.go # Gin HTTP handlers (converted web services)
├── models.go # Data structures
├── database.go # Database operations
├── config.go # Configuration management
├── utils.go # Utility functions (converted procedures)
├── go.mod # Go module definition
├── go.sum # Dependencies checksums
└── .env.example # Environment variables template
Templates
Use templates from assets/go-templates/:
main.go: Application initialization and server setuphandlers.go: Example API handlers with CRUD operationsgo.mod: Module definition with required dependencies.env.example: Environment configuration template
Copy templates to workspace and adapt to specific needs.
Common Conversions
Variable Declarations
| Windev | Go |
|---|---|
nValue is int |
var value int or value := 0 |
rPrice is real |
var price float64 or price := 0.0 |
sName is string |
var name string or name := "" |
bFlag is boolean |
var flag bool or flag := false |
dDate is date |
var date time.Time |
arrItems is array of X |
var items []X or items := make([]X, 0) |
Control Structures
| Windev | Go |
|---|---|
IF ... END |
if { } |
SWITCH ... END |
switch { } |
FOR ... END |
for { } |
WHILE ... END |
for condition { } |
FOR EACH ... END |
for _, item := range items { } |
Constants
| Windev | Go |
|---|---|
CONSTANT X = 10 |
const X = 10 |
True / False |
true / false |
Null |
nil |
CRLF |
"\n" |
Conversion Checklist
For each Windev file:
- Read and understand the code purpose
- Identify all procedures and functions
- Check for unknown Windev functions (ask user if needed)
- Remove commented code (lines starting with
//) - Preserve descriptive comments
- Convert variable declarations
- Convert control structures
- Convert database operations to SQL
- Convert file operations to Go standard library
- Add error handling
- Add Zap logging
- Convert web services to Gin handlers
- Test converted code logic
- Add function documentation
- Organize into appropriate package structure
Best Practices
- Error Handling: Never ignore errors. Always check and handle appropriately.
- Context Usage: Use
context.Contextfor API handlers and database operations. - Database Connections: Use connection pooling, set reasonable limits.
- Logging: Log at appropriate levels (Debug, Info, Warn, Error, Fatal).
- Configuration: Use environment variables for configuration.
- Testing: Write tests for converted business logic.
- Documentation: Document exported functions with Go doc comments.
- Code Style: Follow Go conventions (gofmt, golint).
Common Pitfalls
- Not checking errors: Go requires explicit error handling
- Ignoring context: Always use context for cancellation and timeouts
- SQL injection: Use parameterized queries, never string concatenation
- Not closing resources: Use
deferfor cleanup (files, connections, etc.) - Global state: Minimize use of global variables
- Panic usage: Prefer returning errors over
panic()
Example Conversion Session
User provides Windev code → Load references → Identify unknown functions → Ask user if needed → Convert procedures → Convert web services → Add infrastructure → Test → Deliver complete Go project
Additional Resources
When converting complex Windev systems:
- Consult
references/wlanguage-mapping.mdfor function mappings - Review
references/windev-patterns.mdfor common patterns - Use templates from
assets/go-templates/as starting point - Ask user for clarification on business logic when needed
- Document any custom Windev functions for future reference