diff options
| author | 2026-03-09 23:05:42 +0300 | |
|---|---|---|
| committer | 2026-03-09 23:05:42 +0300 | |
| commit | 00394a80501960ad26787b5c44435ed5ed67ad84 (patch) | |
| tree | 672eb918c552c858f32e9533dc3799af6b75769f /parser/grammar.peg | |
| parent | '-' sign in words accepted (diff) | |
| download | conf-00394a80501960ad26787b5c44435ed5ed67ad84.tar.gz conf-00394a80501960ad26787b5c44435ed5ed67ad84.tar.bz2 conf-00394a80501960ad26787b5c44435ed5ed67ad84.tar.xz conf-00394a80501960ad26787b5c44435ed5ed67ad84.zip | |
Полностью переписал библиотеку. Перевёл с EBNF на PEG.v0.1.0
Diffstat (limited to 'parser/grammar.peg')
| -rw-r--r-- | parser/grammar.peg | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/parser/grammar.peg b/parser/grammar.peg new file mode 100644 index 0000000..38b6dc8 --- /dev/null +++ b/parser/grammar.peg @@ -0,0 +1,126 @@ +{ + // Package parser parses conf language. + package parser + + import ( + "strconv" + "errors" + + "go.neonxp.ru/conf/model" + ) + + func toAnySlice(v any) []any { + if v == nil { + return nil + } + if v := v.([]any); len(v) == 0 { + return nil + } + + return v.([]any) + } +} + +Config ← _ stmts:( Command* ) EOF { + if stmts == nil { + return model.Group{}, nil + } + groupAny := toAnySlice(stmts) + groupSl := make(model.Group, len(groupAny)) + for i, e := range groupAny { + groupSl[i] = e.(model.Command) + } + return groupSl, nil +} + +Group ← '{' _ stmts:( Command* ) _ '}' { + if stmts == nil { + return model.Group{}, nil + } + groupAny := toAnySlice(stmts) + groupSl := make(model.Group, len(groupAny)) + for i, e := range groupAny { + groupSl[i] = e.(model.Command) + } + return groupSl, nil +} + +Command ← name:Ident _ args:Args _ { + var group model.Group + rawArgs := args.([]any) + argsSlice := make([]any, 0, len(rawArgs)) + if len(rawArgs) > 0 { + for _, s := range rawArgs { + if s == nil { + continue + } + if g, ok := s.(model.Group); ok { + group = g + continue + } + if l, ok := s.([]any); ok { + l = slices.DeleteFunc(l, func(x any) bool { return x == nil }) + argsSlice = append(argsSlice, l...) + } + } + } + return model.Command{Name: name.(model.Ident), Args: argsSlice, Group: group}, nil +} + +Args ← Values? (Group / EOS) + +Values ← vals:Value* { return toAnySlice(vals), nil } + +Value ← val:( Ident / String / Number / Boolean ) __ { return val, nil } +String ← ( '"' DoubleStringChar* '"' / "'" SingleStringChar "'" / '`' RawStringChar* '`' ) { + return string(c.text), nil +} + +// Сервисные литералы + +// {{{ Строки +DoubleStringChar ← !( '"' / "\\" / EOL ) SourceChar / "\\" DoubleStringEscape +SingleStringChar ← !( "'" / "\\" / EOL ) SourceChar / "\\" SingleStringEscape +RawStringChar ← !'`' SourceChar + +DoubleStringEscape ← '"' / CommonEscapeSequence +SingleStringEscape ← "'" / CommonEscapeSequence + +CommonEscapeSequence ← SingleCharEscape / OctalEscape / HexEscape / LongUnicodeEscape / ShortUnicodeEscape +SingleCharEscape ← 'a' / 'b' / 'n' / 'f' / 'r' / 't' / 'v' / '\\' +OctalEscape ← OctalDigit OctalDigit OctalDigit +HexEscape ← 'x' HexDigit HexDigit +LongUnicodeEscape ← 'U' HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit +ShortUnicodeEscape ← 'u' HexDigit HexDigit HexDigit HexDigit + +OctalDigit ← [0-7] +DecimalDigit ← [0-9] +HexDigit ← [0-9a-f]i +SourceChar ← . +// }}} + +// {{{ Числа +Number ← '-'? Integer ( '.' DecimalDigit+ )? Exponent? { return strconv.ParseFloat(string(c.text), 64) } +Integer ← '0' / NonZeroDecimalDigit DecimalDigit* +Exponent ← 'e'i [+-]? DecimalDigit+ +DecimalDigit ← [0-9] +NonZeroDecimalDigit ← [1-9] +// }}} + +// {{{ Идентификатор +Ident ← (Alpha / AllowedSpec) (Alpha / AllowedSpec / Number)* { return model.Ident(c.text), nil } +Alpha ← [a-zA-Z] +AllowedSpec ← '$' / '@' / '%' / '_' / '-' / '+' +// }}} + +Boolean ← "true" { return true, nil } / "false" { return false, nil } + +Comment ← '#' ( ![\r\n] . )* +__ ← ( Whitespace / EOL / Comment )* +_ ← ( [ \t\r\n] / Comment )* + +Whitespace ← [ \t\r] +EOL ← '\n' +EOS ← __ ';' { return nil, nil } / _ Comment? EOL { return nil, nil } / __ EOF { return nil, nil } + +EOF ← !.
\ No newline at end of file |
