A Go parser for HOCON (Human-Optimized Config Object Notation) that returns an Abstract Syntax Tree (AST).
Features
Full HOCON Support:
- JSON superset (comments, trailing commas, unquoted keys)
- Object merging and concatenation
- Substitutions (
${path}and optional${?path}) - Include files (
include file(...)) - Multiline strings (
"""...""") - Duration literals (
10s,500ms,2h,7d) - Size literals (
512MB,2GB,64KB)
Pure Go: Only imports from Go stdlib or
golang.org/x/...yacc-based: Uses
goyaccto generate the parser from a formal grammarAST Output: Preserves full structure for inspection and transformation
Installation
go get src.d10.dev/conf
Code Generator
The conf CLI tool generates type-safe Go code from HOCON configuration files, similar to sqlc:
Installation
go install src.d10.dev/conf/cmd/conf@latest
Usage
# Generate code with defaults (package=main, output=conf_gen.go, name=Conf)
conf generate config.conf
# Customize output
conf generate -package=config -name=AppConfig -output=config.go app.conf
Example
Input (config.conf):
{
database: { host: localhost, port: 5432, timeout: 30s }
cache: { size: 512MB }
servers: ["host1", "host2"]
debug: true
}
Generate:
conf generate -name=AppConfig config.conf
Generated (conf_gen.go):
```go
package main
import ( "time" "src.d10.dev/conf/ast" )
type Database struct { Host string Port int64 Timeout time.Duration }
type Cache struct { Size int64 }
type AppConfig struct { Database Database Cache Cache Servers []string Debug bool }
func LoadAppConfig(root ast.Root) (AppConfig, error) { // ... unmarshal logic ... } ```
Use: ```go package main
import ( "log" "src.d10.dev/conf" )
func main() { root, err := conf.ParseFile("config.conf") if err != nil { log.Fatal(err) }
config, err := LoadAppConfig(root)
if err != nil {
log.Fatal(err)
}
// Type-safe access
println(config.Database.Host)
println(config.Database.Timeout.String())
} ```
Parsing Usage
Basic Parsing
package main
import (
"fmt"
"log"
"src.d10.dev/conf"
)
func main() {
input := `{ name: "example", value: 42 }`
root, err := conf.ParseString(input)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Parsed: %v\n", root)
}
Parse from File
root, err := conf.ParseFile("config.conf")
if err != nil {
log.Fatal(err)
}
Parse with Include Resolution
// Resolves include directives
root, err := conf.ParseWithIncludes("config.conf")
if err != nil {
log.Fatal(err)
}
Parse with Full Resolution
// Resolves both includes and substitutions
root, err := conf.ParseWithResolution("config.conf")
if err != nil {
log.Fatal(err)
}
HOCON Syntax Examples
Basic Object
{
name: "John"
age: 30
active: true
}
Or with commas:
{
name: "John",
age: 30,
active: true
}
Unquoted Keys and Values
{
database.host: localhost,
database.port: 5432
}
Nested Objects
{
server: {
host: 0.0.0.0,
port: 8080
}
}
Arrays
{
items: [1, 2, 3],
names: ["Alice", "Bob"]
}
Substitutions
{
name: "example",
greeting: "Hello, ${name}!",
optional: ${?missing.value}
}
Comments
{
# This is a comment
value: 42 // Another comment
}
Multiline Strings
{
description: """
This is a multiline
string value
"""
}
Duration Literals
{
timeout: 30s
interval: 500ms
delay: 2h
period: 7d
}
Supported units: ns, us, ms, s, m, h, d
Size Literals
{
memory: 512MB
disk: 2GB
cache: 64KB
maxSize: 1.5TB
}
Supported units: B, KB, MB, GB, TB, PB, EB, ZB
Architecture
The parser is built in layers:
- Lexer (
lexer.go): Tokenizes HOCON input with state management - Parser (
parser.go): Generated from yacc grammar (hocon.y) - AST (
ast/): Type-safe representation of HOCON structure - Resolvers (
resolver/):merge.go: Object merging logicinclude.go: Include directive resolutionsubstitution.go: Variable substitution resolution
AST Structure
The AST preserves all HOCON constructs:
Root: Top-level documentObject: HOCON object with fieldsField: Key-value pair with pathArray: Ordered collectionString: Quoted, unquoted, or multiline stringsNumber: Numeric literalsBoolean:true/falseNull:nullvalueDuration: Duration literals with unit (e.g.,10s,500ms) - normalized to nanosecondsSize: Size literals with unit (e.g.,512MB,2GB) - normalized to bytesSubstitution:${path}referencesInclude: Include directives (for resolution)
Building
To regenerate the parser from the grammar:
goyacc -o hocon_gen.go hocon.y
Testing
go test -v
Limitations
- URL and classpath includes are not implemented
- Self-referential substitutions have basic support