From a34be2351ecd8aca969f41f2e27fb57befe0c9bc Mon Sep 17 00:00:00 2001 From: barsdeveloper Date: Fri, 22 Oct 2021 18:44:44 +0200 Subject: [PATCH] Grammar fixed --- dist/ueblueprint.js | 138 +++++++++++++++++---------- js/entity/Entity.js | 5 +- js/entity/FunctionReferenceEntity.js | 5 +- js/entity/Integer.js | 20 +++- js/entity/LocalizedTextEntity.js | 15 +++ js/entity/ObjectEntity.js | 2 +- js/entity/ObjectReferenceEntity.js | 8 +- js/entity/PinEntity.js | 4 +- js/serialization/Grammar.js | 82 +++++++++------- ueblueprint.html | 6 +- 10 files changed, 188 insertions(+), 97 deletions(-) create mode 100644 js/entity/LocalizedTextEntity.js diff --git a/dist/ueblueprint.js b/dist/ueblueprint.js index cc2a88f..984280f 100644 --- a/dist/ueblueprint.js +++ b/dist/ueblueprint.js @@ -1302,10 +1302,7 @@ class Entity { fullKey, target[property], defaultValue, - (t, _, v) => { - console.log(v); - t.push(v); - }); + (t, _, v) => t.push(v)); continue } if (defaultValue instanceof TypeInitialization) { @@ -1358,7 +1355,7 @@ class Guid { class ObjectReferenceEntity extends Entity { static attributes = { - type: "None", + type: "", path: "" } @@ -1367,14 +1364,33 @@ class ObjectReferenceEntity extends Entity { } toString() { - return this.type + (this.path ? `'"${this.path}"'` : "") + return (this.type ?? "") + ( + this.path + ? this.type ? `'"${this.path}"'` : this.path + : "" + ) } } +class LocalizedTextEntity extends Entity { + + static attributes = { + namespace: "", + key: "", + value: "" + } + + getAttributes() { + return LocalizedTextEntity.attributes + } + +} + class PinEntity$1 extends Entity { static attributes = { PinId: Guid, - PinName: [new TypeInitialization(5, true), "ciao"], + PinName: "", + PinFriendlyName: new TypeInitialization(new LocalizedTextEntity(), false), PinToolTip: "", Direction: new TypeInitialization("", false), PinType: { @@ -1422,10 +1438,7 @@ var Parsimmon = /*@__PURE__*/getDefaultExportFromCjs(parsimmon_umd_min.exports); class FunctionReferenceEntity extends Entity { static attributes = { - MemberParent: new ObjectReferenceEntity({ - type: "Class", - path: "/Script/Engine.GameplayStatics" - }), + MemberParent: ObjectReferenceEntity, MemberName: "" } @@ -1435,9 +1448,25 @@ class FunctionReferenceEntity extends Entity { } class Integer extends Entity { + + static attributes = { + value: 0 + } + constructor(value) { - super(); - this.value = Math.round(new Number(value).valueOf()); + if (value?.constructor === String) { + value = Number(value); + } + if (value?.constructor === Number) { + value = { + value: Math.round(value.valueOf()) + }; + } + super(value); + } + + getAttributes() { + return Integer.attributes } } @@ -1456,7 +1485,7 @@ class VariableReferenceEntity extends Entity { class ObjectEntity extends Entity { static attributes = { - Class: "", + Class: ObjectReferenceEntity, Name: "", bIsPureFunc: new TypeInitialization(false, false), VariableReference: new TypeInitialization(new VariableReferenceEntity(), false), @@ -1477,18 +1506,18 @@ let P = Parsimmon; class Grammar { // General - InlineWhitespace = _ => P.regex(/[^\S\n]+/) - InlineOptWhitespace = _ => P.regex(/[^\S\n]*/) - WhitespaceNewline = _ => P.regex(/[^\S\n]*\n\s*/) + InlineWhitespace = _ => P.regex(/[^\S\n]+/).desc("inline whitespace") + InlineOptWhitespace = _ => P.regex(/[^\S\n]*/).desc("inline optional whitespace") + WhitespaceNewline = _ => P.regex(/[^\S\n]*\n\s*/).desc("whitespace with at least a newline") Null = r => P.seq(P.string("("), r.InlineOptWhitespace, P.string(")")).map(_ => null).desc("null: ()") None = _ => P.string("None").map(_ => new ObjectReferenceEntity({ type: "None" })).desc("none") Boolean = _ => P.alt(P.string("True"), P.string("False")).map(v => v === "True" ? true : false).desc("either True or False") Number = _ => P.regex(/[0-9]+(?:\.[0-9]+)?/).map(Number).desc("a number") - Integer = _ => P.regex(/[0-9]+/).map(Integer).desc("an integer") + Integer = _ => P.regex(/[0-9]+/).map(v => new Integer(v)).desc("an integer") String = _ => P.regex(/(?:[^"\\]|\\")*/).wrap(P.string('"'), P.string('"')).desc('string (with possibility to escape the quote using \")') Word = _ => P.regex(/[a-zA-Z]+/).desc("a word") Guid = _ => P.regex(/[0-9a-zA-Z]{32}/).desc("32 digit hexadecimal (accepts all the letters for safety) value") - ReferencePath = _ => P.seq(P.string("/"), P.regex(/[a-zA-Z_]+/).sepBy1(P.string(".")).tieWith(".")) + ReferencePath = _ => P.seq(P.string("/"), P.regex(/[0-9a-zA-Z_]+/).sepBy1(P.string(".")).tieWith(".")) .tie() .atLeast(2) .tie() @@ -1511,7 +1540,21 @@ class Grammar { ) ) AttributeName = r => r.Word.sepBy1(P.string(".")).tieWith(".").desc('words separated by ""') - AttributeAnyValue = r => P.alt(r.Null, r.None, r.Boolean, r.Number, r.Integer, r.String, r.Guid, r.Reference) + AttributeAnyValue = r => P.alt(r.Null, r.None, r.Boolean, r.Number, r.Integer, r.String, r.Guid, r.Reference, r.LocalizedText) + LocalizedText = r => P.seqMap( + P.string("NSLOCTEXT").skip(P.optWhitespace).skip(P.string("(")), + r.String.trim(P.optWhitespace), + P.string(","), + r.String.trim(P.optWhitespace), + P.string(","), + r.String.trim(P.optWhitespace), + P.string(")"), + (_, namespace, __, key, ___, value, ____) => new LocalizedTextEntity({ + namespace: namespace, + key: key, + value: value + }) + ) static getGrammarForType(r, type, defaultGrammar) { switch (type) { case Boolean: @@ -1526,13 +1569,19 @@ class Grammar { return r.Guid case ObjectReferenceEntity: return r.Reference + case LocalizedTextEntity: + return r.LocalizedText + case FunctionReferenceEntity: + return r.FunctionReference + case PinEntity$1: + return r.Pin default: return defaultGrammar } } // Meta grammar - static CreateAttributeGrammar = (r, attributeGrammar, attributeSupplier, valueSeparator = P.string("=")) => - attributeGrammar.skip(valueSeparator.trim(P.optWhitespace)) + static CreateAttributeGrammar = (r, attributeGrammar, attributeSupplier, valueSeparator = P.string("=").trim(P.optWhitespace)) => + attributeGrammar.skip(valueSeparator) .chain(attributeName => { const attributeKey = attributeName.split("."); const attribute = attributeSupplier(attributeKey); @@ -1552,34 +1601,29 @@ class Grammar { /** @type {Array} */ let array = Utility.objectGet(entity, attributeKey, []); array.push(attributeValue); - return Utility.objectSet(entity, attributeKey, array) + return Utility.objectSet(entity, attributeKey, array, true) } - : entity => Utility.objectSet(entity, attributeKey, attributeValue) + : entity => Utility.objectSet(entity, attributeKey, attributeValue, true) ) // returns attributeSetter }) // Meta grammar static CreateMultiAttributeGrammar = (r, keyGrammar, entityType, attributeSupplier) => /** - * Basically this creates a parser that looks for a string like 'AttributeName (A=False,B="Something",)' + * Basically this creates a parser that looks for a string like 'Key (A=False,B="Something",)' * Then it populates an object of type EntityType with the attribute values found inside the parentheses. */ - P.seqObj( - keyGrammar, - P.optWhitespace, - P.string("("), - [ - "attributes", // this is the name of the attribute of object passed to map chained next - Grammar.CreateAttributeGrammar(r, r.AttributeName, attributeSupplier) - .trim(P.optWhitespace) - .sepBy(P.string(",")) - .skip(P.regex(/,?/).then(P.optWhitespace)) // Optional trailing comma - ], - P.string(')') - ).map(object => { - let result = new entityType(); - object.attributes.forEach(attributeSetter => attributeSetter(result)); - return result - }) + P.seqMap( + P.seq(keyGrammar, P.optWhitespace, P.string("(")), + Grammar.CreateAttributeGrammar(r, r.AttributeName, attributeSupplier) + .trim(P.optWhitespace) + .sepBy(P.string(",")) + .skip(P.regex(/,?/).then(P.optWhitespace)), // Optional trailing comma + P.string(')'), + (_, attributes, __) => { + let result = new entityType(); + attributes.forEach(attributeSetter => attributeSetter(result)); + return result + }) FunctionReference = r => Grammar.CreateMultiAttributeGrammar( r, P.succeed(), @@ -1595,13 +1639,11 @@ class Grammar { Object = r => P.seqMap( P.seq(P.string("Begin"), P.whitespace, P.string("Object"), P.whitespace), P.alt( - Grammar.CreateAttributeGrammar(r, P.string("CustomProperties"), _ => ObjectEntity.attributes.CustomProperties, P.string(" ")), - Grammar.CreateAttributeGrammar(r, r.AttributeName, attributeKey => Utility.objectGet(ObjectEntity, attributeKey)) + Grammar.CreateAttributeGrammar(r, P.string("CustomProperties"), _ => ObjectEntity.attributes.CustomProperties, P.whitespace), + Grammar.CreateAttributeGrammar(r, r.AttributeName, attributeKey => Utility.objectGet(ObjectEntity.attributes, attributeKey)) ) - .trim(r.InlineOptWhitespace) // whitespace which is NOT newline - .sepBy(P.string("\n")) - .skip(r.WhitespaceNewline), // Optional trailing comma - P.seq(P.string("End"), P.whitespace, P.string("Object")), + .sepBy1(P.whitespace), + P.seq(r.WhitespaceNewline, P.string("End"), P.whitespace, P.string("Object")), (_, attributes, __) => { let result = new ObjectEntity(); attributes.forEach(attributeSetter => attributeSetter(result)); diff --git a/js/entity/Entity.js b/js/entity/Entity.js index c35c47d..c5e3d6f 100644 --- a/js/entity/Entity.js +++ b/js/entity/Entity.js @@ -39,10 +39,7 @@ export default class Entity { fullKey, target[property], defaultValue, - (t, _, v) => { - console.log(v) - t.push(v) - }) + (t, _, v) => t.push(v)) continue } if (defaultValue instanceof TypeInitialization) { diff --git a/js/entity/FunctionReferenceEntity.js b/js/entity/FunctionReferenceEntity.js index e876236..630a85f 100644 --- a/js/entity/FunctionReferenceEntity.js +++ b/js/entity/FunctionReferenceEntity.js @@ -3,10 +3,7 @@ import ObjectReferenceEntity from "./ObjectReferenceEntity" export default class FunctionReferenceEntity extends Entity { static attributes = { - MemberParent: new ObjectReferenceEntity({ - type: "Class", - path: "/Script/Engine.GameplayStatics" - }), + MemberParent: ObjectReferenceEntity, MemberName: "" } diff --git a/js/entity/Integer.js b/js/entity/Integer.js index 1f0c9bd..34305fc 100644 --- a/js/entity/Integer.js +++ b/js/entity/Integer.js @@ -1,8 +1,24 @@ import Entity from "./Entity" export default class Integer extends Entity { + + static attributes = { + value: 0 + } + constructor(value) { - super() - this.value = Math.round(new Number(value).valueOf()) + if (value?.constructor === String) { + value = Number(value) + } + if (value?.constructor === Number) { + value = { + value: Math.round(value.valueOf()) + } + } + super(value) + } + + getAttributes() { + return Integer.attributes } } \ No newline at end of file diff --git a/js/entity/LocalizedTextEntity.js b/js/entity/LocalizedTextEntity.js new file mode 100644 index 0000000..cddc9b7 --- /dev/null +++ b/js/entity/LocalizedTextEntity.js @@ -0,0 +1,15 @@ +import Entity from "./Entity" + +export default class LocalizedTextEntity extends Entity { + + static attributes = { + namespace: "", + key: "", + value: "" + } + + getAttributes() { + return LocalizedTextEntity.attributes + } + +} \ No newline at end of file diff --git a/js/entity/ObjectEntity.js b/js/entity/ObjectEntity.js index 6a2c8bd..8348f1a 100644 --- a/js/entity/ObjectEntity.js +++ b/js/entity/ObjectEntity.js @@ -10,7 +10,7 @@ import VariableReferenceEntity from "./VariableReferenceEntity" export default class ObjectEntity extends Entity { static attributes = { - Class: "", + Class: ObjectReferenceEntity, Name: "", bIsPureFunc: new TypeInitialization(false, false), VariableReference: new TypeInitialization(new VariableReferenceEntity(), false), diff --git a/js/entity/ObjectReferenceEntity.js b/js/entity/ObjectReferenceEntity.js index 0e62dbd..0e7fb96 100644 --- a/js/entity/ObjectReferenceEntity.js +++ b/js/entity/ObjectReferenceEntity.js @@ -3,7 +3,7 @@ import Entity from "./Entity" export default class ObjectReferenceEntity extends Entity { static attributes = { - type: "None", + type: "", path: "" } @@ -12,6 +12,10 @@ export default class ObjectReferenceEntity extends Entity { } toString() { - return this.type + (this.path ? `'"${this.path}"'` : "") + return (this.type ?? "") + ( + this.path + ? this.type ? `'"${this.path}"'` : this.path + : "" + ) } } \ No newline at end of file diff --git a/js/entity/PinEntity.js b/js/entity/PinEntity.js index f6d2397..169ae2a 100644 --- a/js/entity/PinEntity.js +++ b/js/entity/PinEntity.js @@ -2,11 +2,13 @@ import Entity from "./Entity"; import Guid from "../Guid"; import ObjectReferenceEntity from "./ObjectReferenceEntity"; import TypeInitialization from "./TypeInitialization"; +import LocalizedTextEntity from "./LocalizedTextEntity"; export default class PinEntity extends Entity { static attributes = { PinId: Guid, - PinName: [new TypeInitialization(5, true), "ciao"], + PinName: "", + PinFriendlyName: new TypeInitialization(new LocalizedTextEntity(), false), PinToolTip: "", Direction: new TypeInitialization("", false), PinType: { diff --git a/js/serialization/Grammar.js b/js/serialization/Grammar.js index bf27a5c..cd0dfd0 100644 --- a/js/serialization/Grammar.js +++ b/js/serialization/Grammar.js @@ -6,23 +6,24 @@ import Parsimmon from "parsimmon" import PinEntity from "../entity/PinEntity" import Utility from "../Utility" import ObjectEntity from "../entity/ObjectEntity" +import LocalizedTextEntity from "../entity/LocalizedTextEntity" let P = Parsimmon export default class Grammar { // General - InlineWhitespace = _ => P.regex(/[^\S\n]+/) - InlineOptWhitespace = _ => P.regex(/[^\S\n]*/) - WhitespaceNewline = _ => P.regex(/[^\S\n]*\n\s*/) + InlineWhitespace = _ => P.regex(/[^\S\n]+/).desc("inline whitespace") + InlineOptWhitespace = _ => P.regex(/[^\S\n]*/).desc("inline optional whitespace") + WhitespaceNewline = _ => P.regex(/[^\S\n]*\n\s*/).desc("whitespace with at least a newline") Null = r => P.seq(P.string("("), r.InlineOptWhitespace, P.string(")")).map(_ => null).desc("null: ()") None = _ => P.string("None").map(_ => new ObjectReferenceEntity({ type: "None" })).desc("none") Boolean = _ => P.alt(P.string("True"), P.string("False")).map(v => v === "True" ? true : false).desc("either True or False") Number = _ => P.regex(/[0-9]+(?:\.[0-9]+)?/).map(Number).desc("a number") - Integer = _ => P.regex(/[0-9]+/).map(Integer).desc("an integer") + Integer = _ => P.regex(/[0-9]+/).map(v => new Integer(v)).desc("an integer") String = _ => P.regex(/(?:[^"\\]|\\")*/).wrap(P.string('"'), P.string('"')).desc('string (with possibility to escape the quote using \")') Word = _ => P.regex(/[a-zA-Z]+/).desc("a word") Guid = _ => P.regex(/[0-9a-zA-Z]{32}/).desc("32 digit hexadecimal (accepts all the letters for safety) value") - ReferencePath = _ => P.seq(P.string("/"), P.regex(/[a-zA-Z_]+/).sepBy1(P.string(".")).tieWith(".")) + ReferencePath = _ => P.seq(P.string("/"), P.regex(/[0-9a-zA-Z_]+/).sepBy1(P.string(".")).tieWith(".")) .tie() .atLeast(2) .tie() @@ -45,7 +46,21 @@ export default class Grammar { ) ) AttributeName = r => r.Word.sepBy1(P.string(".")).tieWith(".").desc('words separated by ""') - AttributeAnyValue = r => P.alt(r.Null, r.None, r.Boolean, r.Number, r.Integer, r.String, r.Guid, r.Reference) + AttributeAnyValue = r => P.alt(r.Null, r.None, r.Boolean, r.Number, r.Integer, r.String, r.Guid, r.Reference, r.LocalizedText) + LocalizedText = r => P.seqMap( + P.string("NSLOCTEXT").skip(P.optWhitespace).skip(P.string("(")), + r.String.trim(P.optWhitespace), + P.string(","), + r.String.trim(P.optWhitespace), + P.string(","), + r.String.trim(P.optWhitespace), + P.string(")"), + (_, namespace, __, key, ___, value, ____) => new LocalizedTextEntity({ + namespace: namespace, + key: key, + value: value + }) + ) static getGrammarForType(r, type, defaultGrammar) { switch (type) { case Boolean: @@ -60,13 +75,19 @@ export default class Grammar { return r.Guid case ObjectReferenceEntity: return r.Reference + case LocalizedTextEntity: + return r.LocalizedText + case FunctionReferenceEntity: + return r.FunctionReference + case PinEntity: + return r.Pin default: return defaultGrammar } } // Meta grammar - static CreateAttributeGrammar = (r, attributeGrammar, attributeSupplier, valueSeparator = P.string("=")) => - attributeGrammar.skip(valueSeparator.trim(P.optWhitespace)) + static CreateAttributeGrammar = (r, attributeGrammar, attributeSupplier, valueSeparator = P.string("=").trim(P.optWhitespace)) => + attributeGrammar.skip(valueSeparator) .chain(attributeName => { const attributeKey = attributeName.split(".") const attribute = attributeSupplier(attributeKey) @@ -86,34 +107,29 @@ export default class Grammar { /** @type {Array} */ let array = Utility.objectGet(entity, attributeKey, []) array.push(attributeValue) - return Utility.objectSet(entity, attributeKey, array) + return Utility.objectSet(entity, attributeKey, array, true) } - : entity => Utility.objectSet(entity, attributeKey, attributeValue) + : entity => Utility.objectSet(entity, attributeKey, attributeValue, true) ) // returns attributeSetter }) // Meta grammar static CreateMultiAttributeGrammar = (r, keyGrammar, entityType, attributeSupplier) => /** - * Basically this creates a parser that looks for a string like 'AttributeName (A=False,B="Something",)' + * Basically this creates a parser that looks for a string like 'Key (A=False,B="Something",)' * Then it populates an object of type EntityType with the attribute values found inside the parentheses. */ - P.seqObj( - keyGrammar, - P.optWhitespace, - P.string("("), - [ - "attributes", // this is the name of the attribute of object passed to map chained next - Grammar.CreateAttributeGrammar(r, r.AttributeName, attributeSupplier) - .trim(P.optWhitespace) - .sepBy(P.string(",")) - .skip(P.regex(/,?/).then(P.optWhitespace)) // Optional trailing comma - ], - P.string(')') - ).map(object => { - let result = new entityType() - object.attributes.forEach(attributeSetter => attributeSetter(result)) - return result - }) + P.seqMap( + P.seq(keyGrammar, P.optWhitespace, P.string("(")), + Grammar.CreateAttributeGrammar(r, r.AttributeName, attributeSupplier) + .trim(P.optWhitespace) + .sepBy(P.string(",")) + .skip(P.regex(/,?/).then(P.optWhitespace)), // Optional trailing comma + P.string(')'), + (_, attributes, __) => { + let result = new entityType() + attributes.forEach(attributeSetter => attributeSetter(result)) + return result + }) FunctionReference = r => Grammar.CreateMultiAttributeGrammar( r, P.succeed(), @@ -129,13 +145,11 @@ export default class Grammar { Object = r => P.seqMap( P.seq(P.string("Begin"), P.whitespace, P.string("Object"), P.whitespace), P.alt( - Grammar.CreateAttributeGrammar(r, P.string("CustomProperties"), _ => ObjectEntity.attributes.CustomProperties, P.string(" ")), - Grammar.CreateAttributeGrammar(r, r.AttributeName, attributeKey => Utility.objectGet(ObjectEntity, attributeKey)) + Grammar.CreateAttributeGrammar(r, P.string("CustomProperties"), _ => ObjectEntity.attributes.CustomProperties, P.whitespace), + Grammar.CreateAttributeGrammar(r, r.AttributeName, attributeKey => Utility.objectGet(ObjectEntity.attributes, attributeKey)) ) - .trim(r.InlineOptWhitespace) // whitespace which is NOT newline - .sepBy(P.string("\n")) - .skip(r.WhitespaceNewline), // Optional trailing comma - P.seq(P.string("End"), P.whitespace, P.string("Object")), + .sepBy1(P.whitespace), + P.seq(r.WhitespaceNewline, P.string("End"), P.whitespace, P.string("Object")), (_, attributes, __) => { let result = new ObjectEntity() attributes.forEach(attributeSetter => attributeSetter(result)) diff --git a/ueblueprint.html b/ueblueprint.html index 3f06729..91b4142 100644 --- a/ueblueprint.html +++ b/ueblueprint.html @@ -15,7 +15,11 @@
Hello