Updates.
This commit is contained in:
74
packages/go/docs/core-api.inc.tce
Normal file
74
packages/go/docs/core-api.inc.tce
Normal file
@@ -0,0 +1,74 @@
|
||||
Heading 2 Core API
|
||||
class mt-12
|
||||
Markdown
|
||||
**Note:** The Core API uses C-style conventions to optimize memory management
|
||||
and improve portability to other environments and languages.
|
||||
It is unwieldy and does not follow Go best practices.
|
||||
|
||||
For most projects you'll want to use the [Document API](#document-api) instead.
|
||||
It provides an ergonomic wrapper around the Core API and lets you focus on parsing
|
||||
your documents.
|
||||
|
||||
Heading 3 LineData
|
||||
class mb-4 mt-12
|
||||
CodeBlock go
|
||||
// Type Definition
|
||||
// Holds the parsed information from each line.
|
||||
type LineData struct {
|
||||
// Which character is being used for indentation.
|
||||
Indent rune
|
||||
// How many indent characters are present in the current line.
|
||||
Level int
|
||||
// The number of characters before the start of the line's "head" section.
|
||||
OffsetHead int
|
||||
// The number of characters before the start of the line's "tail" section.
|
||||
OffsetTail int
|
||||
}
|
||||
|
||||
Heading 3 NewLineData()
|
||||
class mb-4 mt-12
|
||||
Markdown
|
||||
| Parameter | Type | Description
|
||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||
| indent | rune | The character used for indentation in the document. Only a single character is permitted.
|
||||
| **@returns** | *LineData | A LineData instance with the specified indent character and all other values initialized to 0.
|
||||
|
||||
Initialize a LineData instance with default values to pass to [ParseLine()](#parse-line).
|
||||
|
||||
CodeBlock go
|
||||
// Function Definition
|
||||
func NewLineData(indent rune) *LineData
|
||||
|
||||
// Import Path
|
||||
import "terrace.go"
|
||||
|
||||
// Usage
|
||||
lineData := terrace.NewLineData(' ')
|
||||
fmt.Printf("%+v\n", lineData)
|
||||
// &{Indent:32 Level:0 OffsetHead:0 OffsetTail:0}
|
||||
// Use the same lineData object for all calls to ParseLine in the same document.
|
||||
|
||||
Heading 3 ParseLine()
|
||||
class mb-4 mt-12
|
||||
Markdown
|
||||
| Parameter | Type | Description
|
||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||
| line | string | A string containing a line to parse. Shouldn't end with a newline.
|
||||
| lineData | *LineData | A LineData object to store information about the current line, from [NewLineData()](#new-line-data).<br/>**Mutated in-place!**
|
||||
| **@returns** | error | Returns an error if the input parameters are invalid, nil otherwise.
|
||||
|
||||
Core Terrace parser function, sets `Level`, `OffsetHead`, and `OffsetTail` in a [LineData](#line-data) object based on the passed line.
|
||||
Note that this is a C-style function, `lineData` is treated as a reference and mutated in-place.
|
||||
|
||||
CodeBlock go
|
||||
// Function Definition
|
||||
func ParseLine(line string, lineData *LineData) error
|
||||
|
||||
// Import Path
|
||||
import "terrace.go"
|
||||
|
||||
// Usage
|
||||
lineData := terrace.NewLineData(' ')
|
||||
terrace.ParseLine("title Example Title", lineData)
|
||||
fmt.Printf("%+v\n", lineData)
|
||||
// &{Indent:32 Level:0 OffsetHead:0 OffsetTail:5}
|
||||
151
packages/go/docs/document-api.inc.tce
Normal file
151
packages/go/docs/document-api.inc.tce
Normal file
@@ -0,0 +1,151 @@
|
||||
Heading 2 Document API
|
||||
class mt-12
|
||||
|
||||
Heading 3 NewTerraceDocument()
|
||||
class mb-4 mt-12
|
||||
Markdown
|
||||
| Parameter | Type | Description
|
||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||
| reader | [Reader](#reader) | An interface that reads lines from a document.
|
||||
| indent | rune | The character used for indentation in the document. Only a single character is permitted.
|
||||
| **@returns** | *TerraceDocument | A pointer to a TerraceDocument, which is an iterator for parsing a document line by line.
|
||||
|
||||
Provides a simple set of convenience functions around ParseLine for more ergonomic parsing of Terrace documents.
|
||||
CodeBlock go
|
||||
// Function Definition
|
||||
func NewTerraceDocument(reader Reader, indent rune) *TerraceDocument
|
||||
|
||||
// Import Path
|
||||
import "terrace.go"
|
||||
|
||||
Heading 3 TerraceDocument
|
||||
class mb-4 mt-12
|
||||
Markdown
|
||||
Container for a handful of convenience functions for parsing documents.
|
||||
Obtained from [NewTerraceDocument()](#newterracedocument) above
|
||||
CodeBlock go
|
||||
// Type Definition
|
||||
type TerraceDocument struct {
|
||||
// ... (private fields)
|
||||
}
|
||||
|
||||
Heading 3 TerraceDocument.Next()
|
||||
class mb-4 mt-12
|
||||
|
||||
Markdown
|
||||
| Parameter | Type | Description
|
||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||
| **@returns** | (*TerraceNode, error) | Returns a pointer to the next TerraceNode and an error. The error is `io.EOF` at the end of the document.
|
||||
|
||||
Advances the current position in the terrace document and returns the next node.
|
||||
|
||||
Returns `io.EOF` upon reaching the end of the document.
|
||||
|
||||
Intended to be used inside a for loop to parse a section of a Terrace document.
|
||||
|
||||
CodeBlock go
|
||||
// Method Definition
|
||||
func (d *TerraceDocument) Next() (*TerraceNode, error)
|
||||
|
||||
// Import Path
|
||||
import "terrace.go"
|
||||
|
||||
// Usage
|
||||
doc := terrace.NewTerraceDocument(...)
|
||||
for {
|
||||
node, err := doc.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
// Do something with each node.
|
||||
}
|
||||
|
||||
Heading 3 TerraceNode
|
||||
class mb-4 mt-12
|
||||
Markdown
|
||||
Represents a single node/line in a Terrace document.
|
||||
CodeBlock go
|
||||
// Type Definition
|
||||
type TerraceNode struct {
|
||||
// ... (private fields)
|
||||
}
|
||||
|
||||
Heading 3 TerraceNode.Level()
|
||||
class mb-4 mt-12
|
||||
Markdown
|
||||
| Parameter | Type | Description
|
||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||
| **@returns** | int | The indent level of the current node
|
||||
|
||||
Returns the number of indent characters of the current node.
|
||||
|
||||
Given the following document, `Level()` would return 0, 1, 2, and 5 respectively for each line.
|
||||
CodeBlock terrace
|
||||
block
|
||||
block
|
||||
block
|
||||
block
|
||||
|
||||
CodeBlock go
|
||||
// Method Definition
|
||||
func (n *TerraceNode) Level() int
|
||||
|
||||
Heading 3 TerraceNode.Content()
|
||||
class mb-4 mt-12
|
||||
Markdown
|
||||
| Parameter | Type | Description
|
||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||
| **@returns** | string | The line contents starting from the first non-indent character.
|
||||
|
||||
Get a string with the current line contents. Skips all indent characters.
|
||||
|
||||
Given the following document
|
||||
CodeBlock terrace
|
||||
root
|
||||
sub-line
|
||||
Markdown
|
||||
- Calling `Content()` on the second line returns "sub-line", trimming off the leading indent characters.
|
||||
|
||||
CodeBlock go
|
||||
// Method Definition
|
||||
func (n *TerraceNode) Content() string
|
||||
|
||||
Heading 3 TerraceNode.Head()
|
||||
class mb-4 mt-12
|
||||
Markdown
|
||||
| Parameter | Type | Description
|
||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||
| **@returns** | string | The `head` portion (first word) of a line
|
||||
|
||||
Get the first "word" of a line, starting from the first non-indent character to the first space or end of the line.
|
||||
Often used for deciding how to parse a block.
|
||||
|
||||
Terrace DSLs do not *need* to use head-tail line structure, but support for them is built into the parser
|
||||
|
||||
Given the following line, `Head()` returns "title"
|
||||
CodeBlock terrace
|
||||
title An Important Document
|
||||
CodeBlock go
|
||||
// Method Definition
|
||||
func (n *TerraceNode) Head() string
|
||||
|
||||
Heading 3 TerraceNode.Tail()
|
||||
class mb-4 mt-12
|
||||
Markdown
|
||||
| Parameter | Type | Description
|
||||
| -------------- | --------------------- | -----------------------------------------------------------------------
|
||||
| **@returns** | string | The remainder of the line following the `Head()` portion, with no leading space
|
||||
|
||||
Get all text following the first "word" of a line, starting from the first character after the space at the end of `Head()`
|
||||
|
||||
Terrace DSLs do not *need* to use head-tail line structure, but support for them is built into the parser
|
||||
|
||||
Given the following line, `Tail()` returns "An Important Document"
|
||||
CodeBlock terrace
|
||||
title An Important Document
|
||||
CodeBlock go
|
||||
// Method Definition
|
||||
func (n *TerraceNode) Tail() string
|
||||
42
packages/go/docs/index.tce
Normal file
42
packages/go/docs/index.tce
Normal file
@@ -0,0 +1,42 @@
|
||||
layout layout.njk
|
||||
title Go Documentation - Terrace
|
||||
description
|
||||
Go language documentation for the Terrace programming language
|
||||
|
||||
Section light
|
||||
class flex flex-col md:flex-row gap-16
|
||||
|
||||
Block
|
||||
class w-full lg:w-1/3
|
||||
TableOfContents
|
||||
|
||||
Block
|
||||
Heading 1 Terrace Go Documentation
|
||||
class -ml-2
|
||||
|
||||
Markdown
|
||||
Documentation is available for the following languages:
|
||||
- [C](/docs/c/) - 100% Complete
|
||||
- [JavaScript](/docs/javascript/) - 75% Complete
|
||||
- [Go](/docs/go/) - 50% Complete
|
||||
- [Python](/docs/python/) - 100% Complete
|
||||
- [Rust](/docs/rust/) - 100% Complete
|
||||
|
||||
Heading 2 Getting Started
|
||||
class mt-12 mb-6
|
||||
Markdown
|
||||
Install Terrace using `go get`:
|
||||
|
||||
CodeBlock bash
|
||||
$ go get terrace.go
|
||||
|
||||
Include ./core-api.inc.tce
|
||||
Include ./document-api.inc.tce
|
||||
Include ./reader-api.inc.tce
|
||||
|
||||
Heading 2 Contributing
|
||||
class mt-12
|
||||
|
||||
Section dark
|
||||
Footer
|
||||
class w-full
|
||||
101
packages/go/docs/reader-api.inc.tce
Normal file
101
packages/go/docs/reader-api.inc.tce
Normal file
@@ -0,0 +1,101 @@
|
||||
Heading 2 Reader API
|
||||
class mt-12
|
||||
Markdown
|
||||
The [Document API](#document-api) requires a `Reader` interface to iterate through lines
|
||||
in a document. A `Reader` has a `Read()` method that returns a string and an error. Each time it is called, it returns the next line from whichever source it is pulling them.
|
||||
|
||||
Terrace for Go does not provide built-in readers, but you can easily create your own.
|
||||
|
||||
Heading 3 Reader
|
||||
class mb-4 mt-12
|
||||
Markdown
|
||||
An interface with a `Read()` method that returns the next line in a document and an error. The error should be `io.EOF` when the end of the document has been reached.
|
||||
|
||||
CodeBlock go
|
||||
// Interface Definition
|
||||
type Reader interface {
|
||||
Read() (string, error)
|
||||
}
|
||||
|
||||
Heading 3 StringReader
|
||||
class mb-4 mt-12
|
||||
Markdown
|
||||
You can implement a `Reader` that reads from a string.
|
||||
|
||||
CodeBlock go
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type StringReader struct {
|
||||
reader *strings.Reader
|
||||
}
|
||||
|
||||
func (r *StringReader) Read() (string, error) {
|
||||
line, err := r.reader.ReadString('\n')
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.TrimRight(line, "\n"), nil
|
||||
}
|
||||
|
||||
Markdown
|
||||
**Usage**
|
||||
CodeBlock go
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"terrace.go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := `
|
||||
title Example Title
|
||||
line 2
|
||||
`
|
||||
reader := &StringReader{reader: strings.NewReader(data)}
|
||||
doc := terrace.NewTerraceDocument(reader, ' ')
|
||||
|
||||
for {
|
||||
node, err := doc.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("%d %s\n", node.Level(), node.Content())
|
||||
}
|
||||
}
|
||||
|
||||
Heading 3 FileReader
|
||||
class mb-4 mt-12
|
||||
Markdown
|
||||
You can use the `bufio` package to create a `Reader` for a file.
|
||||
|
||||
CodeBlock go
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
)
|
||||
|
||||
type FileReader struct {
|
||||
scanner *bufio.Scanner
|
||||
}
|
||||
|
||||
func NewFileReader(file *os.File) *FileReader {
|
||||
return &FileReader{scanner: bufio.NewScanner(file)}
|
||||
}
|
||||
|
||||
func (r *FileReader) Read() (string, error) {
|
||||
if r.scanner.Scan() {
|
||||
return r.scanner.Text(), nil
|
||||
}
|
||||
if err := r.scanner.Err(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "", io.EOF
|
||||
}
|
||||
204
packages/go/docs/recipes.inc.tce
Normal file
204
packages/go/docs/recipes.inc.tce
Normal file
@@ -0,0 +1,204 @@
|
||||
Heading 2 Recipes
|
||||
class mt-12
|
||||
|
||||
Heading 3 Parse object properties
|
||||
class mb-2
|
||||
Markdown
|
||||
Read known properties from a Terrace block and write them to a struct.
|
||||
CodeBlock go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"terrace.go"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
StringProperty string
|
||||
NumericProperty int
|
||||
}
|
||||
|
||||
func main() {
|
||||
input := `object
|
||||
string_property An example string
|
||||
numeric_property 42`
|
||||
|
||||
reader := &StringReader{reader: strings.NewReader(input)}
|
||||
doc := terrace.NewTerraceDocument(reader, ' ')
|
||||
|
||||
config := Config{}
|
||||
|
||||
for {
|
||||
node, err := doc.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if node.Head() == "object" {
|
||||
objectLevel := node.Level()
|
||||
for {
|
||||
node, err := doc.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if node.Level() <= objectLevel {
|
||||
// We've exited the object block
|
||||
break
|
||||
}
|
||||
|
||||
switch node.Head() {
|
||||
case "string_property":
|
||||
config.StringProperty = node.Tail()
|
||||
case "numeric_property":
|
||||
if val, err := strconv.Atoi(node.Tail()); err == nil {
|
||||
config.NumericProperty = val
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("%+v\n", config)
|
||||
// {StringProperty:An example string NumericProperty:42}
|
||||
}
|
||||
|
||||
Markdown
|
||||
Read *all* properties as strings from a Terrace block and write them to a map.
|
||||
CodeBlock go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"terrace.go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
input := `object
|
||||
property1 Value 1
|
||||
property2 Value 2
|
||||
random_property igazi3ii4quaC5OdoB5quohnah1beeNg`
|
||||
|
||||
reader := &StringReader{reader: strings.NewReader(input)}
|
||||
doc := terrace.NewTerraceDocument(reader, ' ')
|
||||
|
||||
output := make(map[string]string)
|
||||
|
||||
for {
|
||||
node, err := doc.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if node.Head() == "object" {
|
||||
objectLevel := node.Level()
|
||||
for {
|
||||
node, err := doc.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if node.Level() <= objectLevel {
|
||||
// We've exited the object block
|
||||
break
|
||||
}
|
||||
|
||||
// Skip empty lines
|
||||
if node.Content() == "" {
|
||||
continue
|
||||
}
|
||||
// Add any properties to the map as strings using the
|
||||
// line Head() as the key and Tail() as the value
|
||||
output[node.Head()] = node.Tail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("%+v\n", output)
|
||||
// map[property1:Value 1 property2:Value 2 random_property:igazi3ii4quaC5OdoB5quohnah1beeNg]
|
||||
}
|
||||
|
||||
Heading 3 Process nested blocks
|
||||
class mb-2
|
||||
Markdown
|
||||
Handle hierarchically nested blocks with recursive processing.
|
||||
CodeBlock go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"terrace.go"
|
||||
)
|
||||
|
||||
type Block struct {
|
||||
Name string
|
||||
Content string
|
||||
Children []Block
|
||||
}
|
||||
|
||||
func parseBlock(doc *terrace.TerraceDocument, parentLevel int) []Block {
|
||||
var blocks []Block
|
||||
|
||||
for {
|
||||
node, err := doc.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// If we've returned to the parent level or higher, we're done
|
||||
if node.Level() <= parentLevel {
|
||||
break
|
||||
}
|
||||
|
||||
block := Block{
|
||||
Name: node.Head(),
|
||||
Content: node.Tail(),
|
||||
}
|
||||
|
||||
// Parse any nested children
|
||||
block.Children = parseBlock(doc, node.Level())
|
||||
blocks = append(blocks, block)
|
||||
}
|
||||
|
||||
return blocks
|
||||
}
|
||||
|
||||
func main() {
|
||||
input := `root
|
||||
section1 Section 1 Content
|
||||
subsection1 Subsection 1 Content
|
||||
subsection2 Subsection 2 Content
|
||||
section2 Section 2 Content
|
||||
nested
|
||||
deeply Nested Content`
|
||||
|
||||
reader := &StringReader{reader: strings.NewReader(input)}
|
||||
doc := terrace.NewTerraceDocument(reader, ' ')
|
||||
|
||||
blocks := parseBlock(doc, -1)
|
||||
|
||||
fmt.Printf("%+v\n", blocks)
|
||||
}
|
||||
Reference in New Issue
Block a user