mirror of
https://github.com/strongdm/comply
synced 2024-11-25 00:54:54 +00:00
115 lines
2.2 KiB
Go
115 lines
2.2 KiB
Go
|
package ace
|
||
|
|
||
|
import "strings"
|
||
|
|
||
|
// ParseSource parses the source and returns the result.
|
||
|
func ParseSource(src *source, opts *Options) (*result, error) {
|
||
|
// Initialize the options.
|
||
|
opts = InitializeOptions(opts)
|
||
|
|
||
|
rslt := newResult(nil, nil, nil)
|
||
|
|
||
|
base, err := parseBytes(src.base.data, rslt, src, opts, src.base)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
inner, err := parseBytes(src.inner.data, rslt, src, opts, src.inner)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
includes := make(map[string][]element)
|
||
|
|
||
|
for _, f := range src.includes {
|
||
|
includes[f.path], err = parseBytes(f.data, rslt, src, opts, f)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
rslt.base = base
|
||
|
rslt.inner = inner
|
||
|
rslt.includes = includes
|
||
|
|
||
|
return rslt, nil
|
||
|
}
|
||
|
|
||
|
// parseBytes parses the byte data and returns the elements.
|
||
|
func parseBytes(data []byte, rslt *result, src *source, opts *Options, f *File) ([]element, error) {
|
||
|
var elements []element
|
||
|
|
||
|
lines := strings.Split(formatLF(string(data)), lf)
|
||
|
|
||
|
i := 0
|
||
|
l := len(lines)
|
||
|
|
||
|
// Ignore the last empty line.
|
||
|
if l > 0 && lines[l-1] == "" {
|
||
|
l--
|
||
|
}
|
||
|
|
||
|
for i < l {
|
||
|
// Fetch a line.
|
||
|
ln := newLine(i+1, lines[i], opts, f)
|
||
|
i++
|
||
|
|
||
|
// Ignore the empty line.
|
||
|
if ln.isEmpty() {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
if ln.isTopIndent() {
|
||
|
e, err := newElement(ln, rslt, src, nil, opts)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
// Append child elements to the element.
|
||
|
if err := appendChildren(e, rslt, lines, &i, l, src, opts, f); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
elements = append(elements, e)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return elements, nil
|
||
|
}
|
||
|
|
||
|
// appendChildren parses the lines and appends the children to the element.
|
||
|
func appendChildren(parent element, rslt *result, lines []string, i *int, l int, src *source, opts *Options, f *File) error {
|
||
|
for *i < l {
|
||
|
// Fetch a line.
|
||
|
ln := newLine(*i+1, lines[*i], opts, f)
|
||
|
|
||
|
// Check if the line is a child of the parent.
|
||
|
ok, err := ln.childOf(parent)
|
||
|
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if !ok {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
child, err := newElement(ln, rslt, src, parent, opts)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
parent.AppendChild(child)
|
||
|
|
||
|
*i++
|
||
|
|
||
|
if child.CanHaveChildren() {
|
||
|
if err := appendChildren(child, rslt, lines, i, l, src, opts, f); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|