aboutsummaryrefslogtreecommitdiff
path: root/parser/grammar.peg
diff options
context:
space:
mode:
author2026-03-10 14:44:50 +0300
committer2026-03-10 14:44:50 +0300
commit92d84f6633767830ed964ebab8c3b94c77663394 (patch)
tree5e087e3631d46e6cb81ccf895c408a79bc154ee2 /parser/grammar.peg
parentПолностью переписал библиотеку. Перевёл с... (diff)
downloadconf-0.2.0.tar.gz
conf-0.2.0.tar.bz2
conf-0.2.0.tar.xz
conf-0.2.0.zip
Отполировал библиотеку, чтобы в идеале больше её не менять долгие годыv1.0.0v0.2.0
Diffstat (limited to '')
-rw-r--r--parser/grammar.peg111
1 files changed, 66 insertions, 45 deletions
diff --git a/parser/grammar.peg b/parser/grammar.peg
index 38b6dc8..760257f 100644
--- a/parser/grammar.peg
+++ b/parser/grammar.peg
@@ -1,5 +1,21 @@
{
// Package parser parses conf language.
+ //
+ // This file is part of conf library.
+ // Copyright (C) 2026 Alexander NeonXP Kiryukhin <i@neonxp.ru>
+ //
+ // This program is free software: you can redistribute it and/or modify
+ // it under the terms of the GNU General Public License as published by
+ // the Free Software Foundation, either version 3 of the License, or
+ // (at your option) any later version.
+ //
+ // This program is distributed in the hope that it will be useful,
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ // GNU General Public License for more details.
+ //
+ // You should have received a copy of the GNU General Public License
+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
package parser
import (
@@ -13,7 +29,7 @@
if v == nil {
return nil
}
- if v := v.([]any); len(v) == 0 {
+ if v, ok := v.([]any); ok && len(v) == 0 {
return nil
}
@@ -21,32 +37,31 @@
}
}
-Config ← _ stmts:( Command* ) EOF {
- if stmts == nil {
+Config ← _ directives:( Directive* ) EOF {
+ if directives == nil {
return model.Group{}, nil
}
- groupAny := toAnySlice(stmts)
+ groupAny := toAnySlice(directives)
groupSl := make(model.Group, len(groupAny))
for i, e := range groupAny {
- groupSl[i] = e.(model.Command)
+ groupSl[i] = e.(model.Directive)
}
return groupSl, nil
}
-Group ← '{' _ stmts:( Command* ) _ '}' {
- if stmts == nil {
+Group ← '{' _ directives:( Directive* ) _ '}' {
+ if directives == nil {
return model.Group{}, nil
}
- groupAny := toAnySlice(stmts)
+ groupAny := toAnySlice(directives)
groupSl := make(model.Group, len(groupAny))
for i, e := range groupAny {
- groupSl[i] = e.(model.Command)
+ groupSl[i] = e.(model.Directive)
}
return groupSl, nil
}
-Command ← name:Ident _ args:Args _ {
- var group model.Group
+Directive ← name:Ident _ args:Args _ {
rawArgs := args.([]any)
argsSlice := make([]any, 0, len(rawArgs))
if len(rawArgs) > 0 {
@@ -54,73 +69,79 @@ Command ← name:Ident _ args:Args _ {
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
+ return model.Directive{Name: name.(model.Ident), RawValues: argsSlice}, 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
-}
-
-// Сервисные литералы
+Value ← val:( Ident / String / Number ) __ { return val, nil }
// {{{ Строки
+String ← ( '"' DoubleStringChar* '"' / "'" SingleStringChar "'" / '`' RawStringChar* '`' ) {
+ return strconv.Unquote(string(c.text))
+}
DoubleStringChar ← !( '"' / "\\" / EOL ) SourceChar / "\\" DoubleStringEscape
SingleStringChar ← !( "'" / "\\" / EOL ) SourceChar / "\\" SingleStringEscape
-RawStringChar ← !'`' SourceChar
+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
+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]
+Number ← '-'? UInteger ('.' DecimalDigit+)? Exponent? {
+ if i, err := strconv.Atoi(string(c.text)); err == nil {
+ return i, nil
+ }
+ return strconv.ParseFloat(string(c.text), 64)
+}
+
+UInteger ← '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]
+Ident ← (Alpha / AllowedSpec) (Alpha / AllowedSpec / Number)* {
+ switch string(c.text) {
+ case "true":
+ return true, nil
+ case "false":
+ return false, nil
+ default:
+ 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 )*
-
+// {{{ Оставшиеся спец моменты
+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
+EOL ← '\n'
+EOS ← __ ';' { return nil, nil } / _ Comment? EOL { return nil, nil } / __ EOF { return nil, nil }
+EOF ← !.
+// }}} \ No newline at end of file