parser

package
v1.0.4 Latest Latest
Warning

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

Go to latest
Published: Jun 12, 2022 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package parser is the configurable parser for the conf package.

The primary type exported by this package is Parser. You can use the default parser:

var DefaultParser = Parser{
	Runes: Runes{
		Assign:       []rune{'='},
		Quote:        []rune{'\'', '"', '`'},
		SectionOpen:  []rune{'['},
		SectionClose: []rune{']'},
	},
}

or create your own:

myParser := parser.Parser{
	Runes: Runes{
		Assign:       []rune{'='},
		Quote:        []rune{'`'}, // Backtick quotes only.
		SectionOpen:  []rune{'{'}, // Curly bracket sections.
		SectionClose: []rune{'}'},
	},
}

The given runes should be mutually exclusive sets when creating a Parser; the behavior for disregarding this rule is undefined.

The Parsed Type

When parsing succeeds a type Parsed is returned. It is a map[string]*SectionBlock. Semantically it is a map["section-name"]*SectionBlock.

Global Section

When parsing the input the default starting section is an unnammed section represented by an empty string. Once a section name is parsed all configuration goes into that section and any following sections. No more configuration can be placed in the global section.

See example Global Section under Parser.

Repeated Sections

A SectionBlock contains two members:

Last Section
Slice []Section

The Slice member will contain all sections with the same name in the order they were encountered. The Last member contains the last setion encountered.

The example configuration:

[domain]
listen = 0.0.0.0

[domain]
listen = example.com

Creates a SectionBlock where:

Slice[0] is the section where listen = 0.0.0.0
Slice[1] is the section where listen = example.com
Last is the same section as Slice[1]

Section and its Values

The Section and Value types repeat some of concepts encountered already. A Section is a map[string]Value or semantically a map["key"]Value. A Value contains two members:

Last string
Slice []string

The Slice member will contain all key=value lines with the same key-name in the order they were encountered. The Last member contains the last key=value encountered for a specific key-name.

The example configuration:

[domains]
listen = 0.0.0.0
listen = example.com

Creates a Section where:

Section["listen"].Slice[0] = 0.0.0.0
Section["listen"].Slice[1] = example.com
Section["listen"].Last is the same as Section["listen"].Slice[1]

The End Result

The end result is a convenient configuration syntax that allows repeated sections and repeated key=values without adding any special syntax.

Index

Examples

Constants

This section is empty.

Variables

View Source
var DefaultParser = Parser{
	Runes: Runes{
		Assign:       []rune{'='},
		Quote:        []rune{'\'', '"', '`'},
		SectionOpen:  []rune{'['},
		SectionClose: []rune{']'},
	},
}

DefaultParser is a Parser with common settings.

Functions

This section is empty.

Types

type IsAssign

type IsAssign func(rune) bool

IsAssign is a function that returns true if the given rune is used to assign a value to a key.

type IsQuote

type IsQuote func(rune) bool

IsQuote is a function that returns true if the given rune is used to quote strings.

type Parsed

type Parsed map[string]*SectionBlock

Parsed is a named map of name=SectionBlock.

func (Parsed) Map

func (me Parsed) Map() map[string][]map[string][]string

Map returns parsed as a map[string][]map[string][]string

type Parser

type Parser struct {
	Runes
}

Parser parses a string into a Configuration.

Example (GlobalSection)
package main

import (
	"fmt"

	"github.com/nofeaturesonlybugs/conf/parser"
)

func main() {
	s := `
hello = world
foo = bar
`
	//
	if parsed, err := parser.DefaultParser.Parse(s); err != nil {
		fmt.Println(err)
	} else if _, ok := parsed[""]; ok {
		fmt.Printf("The global section.\n")
		fmt.Printf("hello = %v\n", parsed[""].Last["hello"].Last)
		fmt.Printf("foo = %v", parsed[""].Last["foo"].Last)
	} else {
		fmt.Println("Global section not found.")
	}
}
Output:

The global section.
hello = world
foo = bar
Example (Options)
package main

import (
	"fmt"

	"github.com/nofeaturesonlybugs/conf/parser"
)

func main() {
	s := `
(main)
message ~ /Hello World!/
`
	//
	parser := &parser.Parser{
		Runes: parser.Runes{
			Assign:       []rune{'~'},
			Quote:        []rune{'/'},
			SectionOpen:  []rune{'('},
			SectionClose: []rune{')'},
		},
	}
	if parsed, err := parser.Parse(s); err != nil {
		fmt.Println(err)
	} else if _, ok := parsed["main"]; ok {
		fmt.Printf("Section `main` exists.\n")
		fmt.Printf("message = %v\n", parsed["main"].Last["message"].Last)
	} else {
		fmt.Println("Section `main` not found.")
	}
}
Output:

Section `main` exists.
message = Hello World!
Example (Reader)
package main

import (
	"fmt"
	"strings"

	"github.com/nofeaturesonlybugs/conf/parser"
)

func main() {
	s := `
[main]
hello = world
foo = bar
`
	reader := strings.NewReader(s)
	//
	if parsed, err := parser.DefaultParser.ParseReader(reader); err != nil {
		fmt.Println(err)
	} else if _, ok := parsed["main"]; ok {
		fmt.Printf("Section `main` exists.\n")
		fmt.Printf("hello = %v\n", parsed["main"].Last["hello"].Last)
		fmt.Printf("foo = %v", parsed["main"].Last["foo"].Last)
	} else {
		fmt.Println("Section `main` not found.")
	}
}
Output:

Section `main` exists.
hello = world
foo = bar
Example (String)
package main

import (
	"fmt"

	"github.com/nofeaturesonlybugs/conf/parser"
)

func main() {
	s := `
[main]
hello = world
foo = bar
`
	//
	if parsed, err := parser.DefaultParser.Parse(s); err != nil {
		fmt.Println(err)
	} else if _, ok := parsed["main"]; ok {
		fmt.Printf("Section `main` exists.\n")
		fmt.Printf("hello = %v\n", parsed["main"].Last["hello"].Last)
		fmt.Printf("foo = %v\n", parsed["main"].Last["foo"].Last)
	} else {
		fmt.Println("Section `main` not found.")
	}
}
Output:

Section `main` exists.
hello = world
foo = bar

func (Parser) Parse

func (me Parser) Parse(s string) (Parsed, error)

Parse parses a string.

func (Parser) ParseReader

func (me Parser) ParseReader(r io.Reader) (Parsed, error)

ParseReader parses the reader.

type Runes

type Runes struct {
	// Any rune present in SectionOpen begins a configuration section line.
	SectionOpen []rune
	// Any rune present in SectionClose ends a configuration section line.
	SectionClose []rune
	// Any rune present in Assign acts as an assignment rune and delimits <key ASSIGN value>.
	Assign []rune
	// Any rune present in Quote acts as a quotation rune; quoted values must use the same rune
	// to start and end the quotation.
	Quote []rune
}

Runes defines some important runes for a parser.

func (Runes) IsAssign

func (me Runes) IsAssign(r rune) bool

IsAssign returns true if the rune is an assignment rune.

func (Runes) IsCloseSection

func (me Runes) IsCloseSection(r rune) bool

IsCloseSection returns true if the rune closes a section.

func (Runes) IsOpenSection

func (me Runes) IsOpenSection(r rune) bool

IsOpenSection returns true if the rune opens a section.

func (Runes) IsQuote

func (me Runes) IsQuote(r rune) bool

IsQuote returns true if the rune is a quotation rune.

func (Runes) Within

func (me Runes) Within(r rune, possible []rune) bool

Within tests if r is within possible.

type Section

type Section map[string]*Value

Section is the key=value store of a configuration section.

func (Section) Map

func (me Section) Map() map[string][]string

Map returns section as a map[string][]string.

type SectionBlock

type SectionBlock struct {
	Last  Section
	Slice []Section
}

SectionBlock contains a slice of all sections that had the same name as well as the last section that had the name.

func (*SectionBlock) Map

func (me *SectionBlock) Map() []map[string][]string

Map returns the section block as a []map[string][]string.

type State

type State int

State describes the parser state.

const (
	StateNone    State = 1 << iota
	StateComment State = 1 << iota
	StateSection State = 1 << iota
	StateKey     State = 1 << iota
	StateValue   State = 1 << iota
)

Enums for parser state.

func (State) String

func (s State) String() string

String returns the State as a string.

type Token

type Token int

Token describes a token type.

const (
	TokenNone       Token = 1 << iota
	TokenAlphaNum   Token = 1 << iota
	TokenNewline    Token = 1 << iota
	TokenPunct      Token = 1 << iota
	TokenWhiteSpace Token = 1 << iota
)

Enums for token types returned from the Tokenizer.

func (Token) String

func (t Token) String() string

String returns the Token as a string.

type Tokenizer

type Tokenizer interface {
	// EOF returns true when the tokenizer has no more tokens to return.
	EOF() bool
	// Memory records the current Tokenizer position and a call to Rewid() will reset the Tokenizer to
	// this position.  Use this to make consecutive calls to Peek() or Next() for look-ahead past a single token.
	Memory()
	// Peek returns the next token and its type without advancing the internal counters; an empty string signals
	// the end of the Tokenizer's input.
	Peek() (string, Token)
	// Next returns the token and its type that would be returned by Peek() but then advances internal
	// counters to the next possible token.
	Next() (string, Token)
	// Rewind resets the Tokenizer to the position recorded by calling Memory() or to the beginning
	// of the string if Memory was never called.
	Rewind()
}

Tokenizer returns tokens.

func NewTokenizer

func NewTokenizer(s string) Tokenizer

NewTokenizer creates a new Tokenizer type.

type Value

type Value struct {
	Last  string
	Slice []string
}

Value is the value in a key=value configuration section; values can be singular or slices.

Jump to

Keyboard shortcuts

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