{
package generator
import (
"math"
"strings"
)
func asString(values []interface{}) string {
var builder strings.Builder
for _, value := range values {
bites := value.([]byte)
builder.Write(bites)
}
return builder.String()
}
}
EOF = !.
NewLine = [\n\r]
Space = [ \t]
LineComment = `//` comment:[^\n\r]* (NewLine / EOF)
{
return strings.Trim(asString(comment.([]interface{})), ` `), nil
}
BlockComment = `/*` comment:(([^*] / ('*' !'/'))*) `*/`
{
return string(c.text), nil
}
LineEnding = NewLine / EOF / ';' / &'}'
RestOfLine = Space* BlockComment? (LineComment / LineEnding)
Spacey = Space / NewLine / BlockComment / LineComment
CustomIdentifier = first:[\pL]i rest:[\pL0-9_]i*
{
firstStr := string(first.([]byte))
if rest == nil {
return firstStr, nil
} else {
return firstStr + asString(rest.([]interface{})), nil
}
}
// Type identifiers
TypeIdentifier = TypeIdentifierBaseArraySuffix / TypeIdentifierArrayPrefix / TypeIdentifierMapPrefixArraySuffix / TypeCustomIdentifierArraySuffix
TypeIdentifierBase = name:(`bool` / `byte` / `uint8` / `int8` / `uint16` / `int16` / `uint32` / `int32` / `uint64` / `int64` / `float32` / `float64` / `string` / `guid` / `date`)
{
return NewBaseType(string(name.([]byte)))
}
TypeIdentifierBaseArraySuffix = tipe:TypeIdentifierBase arrays:`[]`*
{
return NewArrayOfType(tipe.(BaseType), arrays)
}
TypeIdentifierArrayPrefix = `array[` Spacey* of:TypeIdentifier Spacey* `]`
{
return ArrayType{Of: of.(Type)}, nil
}
TypeIdentifierMapPrefixArraySuffix = `map[` Spacey* key:TypeIdentifier Spacey* `,` Spacey* value:TypeIdentifier Spacey* `]` arrays:`[]`*
{
return NewArrayOfType(MapType{Key: key.(Type), Value: value.(Type)}, arrays)
}
TypeCustomIdentifierArraySuffix = name:CustomIdentifier arrays:`[]`*
{
return NewArrayOfType(NewCustomType(name.(string)), arrays)
}
// Literal Values
LiteralValue = HexInteger / DecimalNumber / Integer / FloatSpecial / String / Bool
HexInteger = `0x` HexDigit+
{
return strconv.ParseInt(string(c.text), 0, 64)
}
DecimalNumber = Integer '.' DecimalDigit+ Exponent?
{
return strconv.ParseFloat(string(c.text), 64)
}
Integer = ('-' NonZeroDecimalDigit DecimalDigit*
{
return strconv.ParseInt(string(c.text), 0, 64)
}) / NonNegativeInteger
NonNegativeInteger = ('0' { return uint64(0), nil }) / (sign:'+'? NonZeroDecimalDigit DecimalDigit* {
if sign == nil {
return strconv.ParseUint(string(c.text), 0, 64)
} else {
return strconv.ParseUint(string(c.text[1:]), 0, 64)
}
})
Exponent = 'e'i [+-]? DecimalDigit+
FloatSpecial = (sign:[+-]? `inf`i
{
if sign == nil || (sign.([]byte))[0] == '+' {
return math.Inf(1), nil
} else {
return math.Inf(-1), nil
}
}) / (`nan`i
{
return math.NaN(), nil
})
String = '"' ( !EscapedChar . / '\\' EscapeSequence )* '"'
{
c.text = bytes.Replace(c.text, []byte(`\/`), []byte(`/`), -1)
return strconv.Unquote(string(c.text))
}
EscapedChar = [\x00-\x1f"\\]
EscapeSequence = SingleCharEscape / UnicodeEscape
SingleCharEscape = ["\\/bfnrt]
UnicodeEscape = 'u' HexDigit HexDigit HexDigit HexDigit
DecimalDigit = [0-9]
NonZeroDecimalDigit = [1-9]
HexDigit = [0-9a-f]i
Bool = `true` { return true, nil } / `false` { return false, nil }
// Const
Const = `const`i Spacey+ tipe:TypeIdentifierBase Spacey+ name:CustomIdentifier Spacey* '=' Spacey* value:LiteralValue
{
return NewConst(c, tipe.(BaseType), name.(string), value)
}
// Enum
Flags = '[' Spacey* `flags`i Spacey* ']'
Deprecated = '[' Spacey* `deprecated`i Spacey* reason:( '(' Spacey* String Spacey* ')' Spacey* )? ']'
{
return NewDeprecated(c, reason)
}
Enum = flags:(Flags Spacey*)?
`enum`i Spacey+ name:CustomIdentifier tipe:(Spacey* ':' Spacey* TypeIdentifierBase)? Spacey+
'{' fields:EnumField+ Spacey* '}'
{
return NewEnum(c, flags, tipe, name.(string), fields)
}
EnumField = Spacey* deprecated:(Deprecated Spacey*)? name:CustomIdentifier Spacey* '=' Spacey* value:(HexInteger / Integer) RestOfLine
{
valueInt64 := asInt64(value)
return NewEnumField(c, deprecated, name.(string), valueInt64)
}
// Struct
Opcode = '[' Spacey* `opcode`i Spacey* number:( '(' Spacey* (String / HexInteger / Integer) Spacey* ')' Spacey* )? ']'
{
return NewOpcode(c, number)
}
Readonly = `readonly`i
Struct = opcode:(Opcode Spacey*)?
readonly:(Readonly Spacey+)?
`struct`i Spacey+ name:CustomIdentifier Spacey*
'{' fields:StructField* Spacey* '}'
{
return NewStruct(c, opcode, readonly, name.(string), fields)
}
StructField = Spacey* tipe:TypeIdentifier Spacey+ name:CustomIdentifier RestOfLine
{
return NewStructField(c, tipe.(Type), name.(string))
}
// Message
Message = opcode:(Opcode Spacey*)?
`message`i Spacey+ name:CustomIdentifier Spacey*
'{' fields:MessageField* Spacey* '}'
{
return NewMessage(c, opcode, name.(string), fields)
}
MessageField = Spacey* deprecated:(Deprecated Spacey*)? index:NonNegativeInteger Spacey* `->` Spacey* tipe:TypeIdentifier Spacey+ name:CustomIdentifier RestOfLine
{
return NewMessageField(c, deprecated, index.(uint64), tipe.(Type), name.(string))
}
// Union
Union = opcode:(Opcode Spacey*)?
`union`i Spacey+ name:CustomIdentifier Spacey*
'{' fields:UnionField+ Spacey* '}'
{
return NewUnion(c, opcode, name.(string), fields)
}
UnionField = Spacey* index:NonNegativeInteger Spacey* `->` Spacey* content:(Struct / Message) RestOfLine
{
return NewUnionField(c, index.(uint64), content)
}
// Import
Import = `import`i Spacey+ path:String
{
return NewImport(c, path.(string))
}
// Root
Root = (Spacey* (
(ipt:Import #{
c.state[`file`].(*File).AddImport(ipt.(*Import))
return nil
}) / (konst:Const #{
c.state[`file`].(*File).AddConst(konst.(*Const))
return nil
}) / (enum:Enum #{
c.state[`file`].(*File).AddEnum(enum.(*Enum))
return nil
}) / (strukt:Struct #{
c.state[`file`].(*File).AddStruct(strukt.(*Struct))
return nil
}) / (message:Message #{
c.state[`file`].(*File).AddMessage(message.(*Message))
return nil
}) / (union:Union #{
c.state[`file`].(*File).AddUnion(union.(*Union))
return nil
})) RestOfLine)* Spacey* EOF {
return c.state[`file`], nil
}