Grammar move to regex WIP

This commit is contained in:
barsdeveloper
2023-02-11 17:23:25 +01:00
parent 500965bcfc
commit d1ef250689
8 changed files with 221 additions and 167 deletions

View File

@@ -40,6 +40,20 @@ let P = Parsimmon
export default class Grammar {
static Regex = {
ByteInteger: /0*(?:25[0-5]|2[0-4]\d|1?\d?\d|)(?!\d)/, // A integer between 0 and 255
HexDigit: /[0-9a-fA-F]/,
InlineOptWhitespace: /[^\S\n]*/,
InlineWhitespace: /[^\S\n]+/,
InsideString: /(?:[^"\\]|\\.)*/,
Integer: /[\-\+]?\d+/,
MultilineWhitespace: /\s*\n\s*/,
Number: /[-\+]?\d+(?:\.\d+)?/,
RealUnit: /^\+?(?:0(?:\.\d+)?|1(?:\.0+)?)(?![\.\d])/, // A number between 0 and 1 included
Symbol: /[a-zA-Z_]\w*/,
Word: /[a-zA-Z_]+/,
}
/* --- Factory --- */
/** @param {Grammar} r */
@@ -92,6 +106,8 @@ export default class Grammar {
return r.Integer
case InvariantTextEntity:
return r.InvariantText
case KeyBindingEntity:
return r.KeyBinding
case LinearColorEntity:
return r.LinearColor
case LocalizedTextEntity:
@@ -218,56 +234,37 @@ export default class Grammar {
/* --- General --- */
/** @param {Grammar} r */
InlineWhitespace = r => P.regex(/[^\S\n]+/).desc("single line whitespace")
Null = r => P.regex(new RegExp(String.raw`\(${Grammar.Regex.InlineOptWhitespace.source}\)`)).map(() => null).desc("null: ()")
/** @param {Grammar} r */
InlineOptWhitespace = r => P.regex(/[^\S\n]*/).desc("single line optional whitespace")
/** @param {Grammar} r */
MultilineWhitespace = r => P.regex(/[^\S\n]*\n\s*/).desc("whitespace with at least a newline")
/** @param {Grammar} r */
Null = r => P.seq(P.string("("), r.InlineOptWhitespace, P.string(")")).map(() => null).desc("null: ()")
/** @param {Grammar} r */
Boolean = r => P.alt(
P.string("True"),
P.string("true"),
P.string("False"),
P.string("false"),
).map(v => v.toLocaleLowerCase() === "true" ? true : false)
Boolean = r => P.regex(/true|false/i).map(v => v.toLocaleLowerCase() === "true" ? true : false)
.desc("either True or False")
/** @param {Grammar} r */
HexDigit = r => P.regex(/[0-9a-fA-f]/).desc("hexadecimal digit")
Number = r => P.regex(Grammar.Regex.Number).map(Number).desc("a number")
/** @param {Grammar} r */
Number = r => P.regex(/[-\+]?[0-9]+(?:\.[0-9]+)?/).map(Number).desc("a number")
BigInt = r => P.regex(Grammar.Regex.Integer).map(v => BigInt(v)).desc("a big integer")
/** @param {Grammar} r */
BigInt = r => P.regex(/[\-\+]?[0-9]+/).map(v => BigInt(v)).desc("a big integer")
/** @param {Grammar} r */
RealNumber = r => P.regex(/[-\+]?[0-9]+\.[0-9]+/).map(Number).desc("a number written as real")
/** @param {Grammar} r */
RealUnit = r => P.regex(/\+?[0-9]+(?:\.[0-9]+)?/).map(Number).assert(v => v >= 0 && v <= 1).desc("a number between 0 and 1")
RealUnit = r => P.regex(Grammar.Regex.RealUnit).map(Number).desc("a number between 0 and 1")
/** @param {Grammar} r */
NaturalNumber = r => P.regex(/0|[1-9]\d*/).map(Number).desc("a natural number")
/** @param {Grammar} r */
ColorNumber = r => r.NaturalNumber.assert(n => 0 <= n && n < 256, "the color must be between 0 and 256 excluded")
ColorNumber = r => P.regexp(Grammar.Regex.ByteInteger).desc("a number between 0 and 255")
/** @param {Grammar} r */
Word = r => P.regex(/[a-zA-Z_]+/).desc("a word")
Word = r => P.regexp(Grammar.Regex.Word).desc("a word")
/** @param {Grammar} r */
String = r => P.regex(/(?:[^"\\]|\\.)*/).wrap(P.string('"'), P.string('"')).map(Utility.unescapeString)
String = r => P.regexp(new RegExp(`"(${Grammar.Regex.InsideString.source})"`), 1).map(Utility.unescapeString)
.desc('string (with possibility to escape the quote using \")')
/** @param {Grammar} r */
AttributeName = r => r.Word.sepBy1(P.string(".")).tieWith(".").desc("dot-separated words")
AttributeName = r => P.regexp(new RegExp(String.raw`(?:(?:^|(?<!^)\.)${Grammar.Regex.Word.source})+`))
.desc("dot-separated words")
/* --- Entity --- */
@@ -278,32 +275,30 @@ export default class Grammar {
Integer64 = r => r.BigInt.map(v => new Integer64Entity(v)).desc("an integer64")
/** @param {Grammar} r */
Integer = r => P.regex(/[\-\+]?[0-9]+/).map(v => new IntegerEntity(v)).desc("an integer")
Integer = r => P.regex(Grammar.Regex.Integer).map(v => new IntegerEntity(v)).desc("an integer")
/** @param {Grammar} r */
Byte = r => P.regex(/\+?[0-9]+/)
.map(v => parseInt(v))
.assert(v => v >= 0 && v < 1 << 8)
.map(v => new ByteEntity(v))
.desc("a Byte")
Byte = r => P.regex(Grammar.Regex.ByteInteger).map(v => new ByteEntity(parseInt(v))).desc("a Byte")
/** @param {Grammar} r */
Guid = r => r.HexDigit.times(32).tie().map(v => new GuidEntity({ value: v })).desc("32 digit hexadecimal value")
Guid = r => P.regexp(new RegExp(`${Grammar.Regex.HexDigit.source}{32}`))
.map(v => new GuidEntity({ value: v }))
.desc("32 digit hexadecimal value")
/** @param {Grammar} r */
Identifier = r => P.regex(/\w+/).map(v => new IdentifierEntity(v))
/** @param {Grammar} r */
PathSymbol = r => P.regex(/[0-9\w]+/).map(v => new PathSymbolEntity({ value: v }))
PathSymbol = r => P.regex(/\w+/).map(v => new PathSymbolEntity({ value: v }))
/** @param {Grammar} r */
PathSymbolOptSpaces = r => P.regex(/[0-9\w]+(?: [0-9\w]+)+|[0-9\w]+/).map(v => new PathSymbolEntity({ value: v }))
PathSymbolOptSpaces = r => P.regex(/(?:(?:^|(?<!^) )\w+)+/).map(v => new PathSymbolEntity({ value: v }))
/** @param {Grammar} r */
Symbol = r => P.regex(/[a-zA-Z_]\w*/).map(v => new SymbolEntity({ value: v }))
Symbol = r => P.regex(Grammar.Regex.Symbol).map(v => new SymbolEntity({ value: v }))
/** @param {Grammar} r */
Enum = r => P.regex(/[a-zA-Z_]\w*/).map(v => new EnumEntity({ value: v }))
Enum = r => P.regex(Grammar.Regex.Symbol).map(v => new EnumEntity({ value: v }))
/** @param {Grammar} r */
ObjectReference = r => P.alt(
@@ -458,8 +453,7 @@ export default class Grammar {
/** @param {Grammar} r */
CustomProperties = r =>
P.string("CustomProperties")
.then(P.whitespace)
P.regex(/CustomProperties\s+/)
.then(r.Pin)
.map(pin => entity => {
/** @type {Array} */
@@ -470,14 +464,14 @@ export default class Grammar {
/** @param {Grammar} r */
Object = r => P.seqMap(
P.seq(P.string("Begin"), P.whitespace, P.string("Object"), P.whitespace),
P.regexp(/Begin\s+Object\s+/),
P
.alt(
r.CustomProperties,
Grammar.createAttributeGrammar(r, ObjectEntity)
)
.sepBy1(P.whitespace),
P.seq(r.MultilineWhitespace, P.string("End"), P.whitespace, P.string("Object")),
P.regexp(/\s+End\s+Object/),
(_0, attributes, _2) => {
let values = {}
attributes.forEach(attributeSetter => attributeSetter(values))