- разбор документа по языку конвенций: шапка, области правил, блоки под метками - проверки формы правила, распространения, ссылок и самого suite.toml - словарь языка живёт в бинаре реестром «версия × естественный язык», темы и префиксы берутся только из манифеста
81 lines
2.5 KiB
Go
81 lines
2.5 KiB
Go
package doc
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// Front — шапка файла. Ключей немного и все они плоские, поэтому разбор здесь
|
|
// свой: тащить YAML ради четырёх строк `ключ: значение` не за что.
|
|
//
|
|
// Ось слоя объявляется здесь ключами lang и stack, а не выводится из пути
|
|
// (META-38); отсутствие обоих означает базовый слой темы.
|
|
type Front struct {
|
|
Topic string
|
|
Prefix string
|
|
Lang string
|
|
Stack string
|
|
Extends string
|
|
|
|
// At — номер строки, на которой объявлен ключ; нужен, чтобы находка
|
|
// показывала на объявление, а не на начало файла.
|
|
At map[string]int
|
|
// Unknown — ключи, которых модель не знает.
|
|
Unknown []string
|
|
// End — номер строки закрывающего разделителя. Тело файла начинается
|
|
// со следующей.
|
|
End int
|
|
// Present — была ли шапка вообще.
|
|
Present bool
|
|
}
|
|
|
|
// Axis отвечает, объявлена ли у слоя ось. Слой без ключей оси — базовый.
|
|
func (f Front) Axis() bool {
|
|
return f.Lang != "" || f.Stack != ""
|
|
}
|
|
|
|
// parseFront разбирает шапку из строк файла. Возвращает шапку и номер первой
|
|
// строки тела.
|
|
func parseFront(lines []string) (Front, int, error) {
|
|
front := Front{At: make(map[string]int)}
|
|
if len(lines) == 0 || strings.TrimSpace(lines[0]) != "---" {
|
|
return front, 1, nil
|
|
}
|
|
front.Present = true
|
|
|
|
for i := 1; i < len(lines); i++ {
|
|
line := lines[i]
|
|
num := i + 1
|
|
if strings.TrimSpace(line) == "---" {
|
|
front.End = num
|
|
return front, num + 1, nil
|
|
}
|
|
if strings.TrimSpace(line) == "" {
|
|
continue
|
|
}
|
|
key, value, ok := strings.Cut(line, ":")
|
|
if !ok {
|
|
return front, num, fmt.Errorf("строка %d шапки не имеет вида «ключ: значение»", num)
|
|
}
|
|
key = strings.TrimSpace(key)
|
|
value = strings.TrimSpace(value)
|
|
front.At[key] = num
|
|
|
|
switch key {
|
|
case "topic":
|
|
front.Topic = value
|
|
case "prefix":
|
|
front.Prefix = value
|
|
case "lang":
|
|
front.Lang = value
|
|
case "stack":
|
|
front.Stack = value
|
|
case "extends":
|
|
front.Extends = value
|
|
default:
|
|
front.Unknown = append(front.Unknown, key)
|
|
}
|
|
}
|
|
return front, len(lines) + 1, fmt.Errorf("шапка не закрыта разделителем ---")
|
|
}
|