Przeglądaj źródła

Update flatc.js

Lutz Roeder 9 miesięcy temu
rodzic
commit
e4f928daa2
1 zmienionych plików z 82 dodań i 6 usunięć
  1. 82 6
      tools/flatc.js

+ 82 - 6
tools/flatc.js

@@ -141,6 +141,14 @@ flatc.Enum = class extends flatc.Type {
     }
 };
 
+flatc.Alias = class extends flatc.Type {
+
+    constructor(parent, name, type) {
+        super(parent, name);
+        this.type = type;
+    }
+};
+
 flatc.Union = class extends flatc.Type {
 
     constructor(parent, name) {
@@ -154,7 +162,14 @@ flatc.Union = class extends flatc.Type {
             for (const value of this.values) {
                 value.index = value.index === undefined ? index : value.index;
                 index = value.index + 1;
-                value.type = this.parent.find(value.type, flatc.Type);
+                const name = this.parent.find(value.name, flatc.Type);
+                const type = value.type ? this.parent.find(value.type, flatc.Type) : null;
+                value.type = name;
+                if (!name && type) {
+                    value.type = new flatc.Alias(this.parent, value.name, type);
+                    type.aliases.add(value.type);
+                    this.root.aliases.push(value);
+                }
             }
             super.resolve();
         }
@@ -166,6 +181,7 @@ flatc.Table = class extends flatc.Type {
     constructor(parent, name) {
         super(parent, name);
         this.fields = new Map();
+        this.aliases = new Set();
     }
 
     resolve() {
@@ -397,7 +413,7 @@ flatc.Parser = class {
                 this._tokenizer.expect('{');
                 while (!this._tokenizer.eat('}')) {
                     const name = this._tokenizer.identifier();
-                    const type = this._tokenizer.eat(':') ? this._tokenizer.identifier() : name;
+                    const type = this._tokenizer.eat(':') ? this._tokenizer.identifier() : null;
                     const index = this._tokenizer.eat('=') ? this._tokenizer.integer() : undefined;
                     union.values.push({ name, type, index });
                     this._parseMetadata(new Map());
@@ -792,9 +808,18 @@ flatc.Root = class extends flatc.Object {
 
     resolve() {
         if (!this.resolved) {
+            this.aliases = [];
             for (const namespace of this._namespaces.values()) {
                 namespace.resolve();
             }
+            for (const value of this.aliases) {
+                if (value.type instanceof flatc.Alias && value.type.type.aliases.size <= 1) {
+                    value.type.type.aliases.delete(value.type);
+                    value.type.parent.children.delete(value.type.name);
+                    value.type = value.type.type;
+                }
+            }
+            delete this.aliases;
             super.resolve();
         }
     }
@@ -918,8 +943,12 @@ flatc.Generator = class {
                 this._buildStruct(child);
             } else if (child instanceof flatc.Union) {
                 this._buildUnion(child);
+            } else if (child instanceof flatc.Alias) {
+                this._buildAlias(child);
             } else if (child instanceof flatc.Enum) {
                 this._buildEnum(child);
+            } else {
+                throw new flatc.Error(`Unsupported type '${child.name}'.`);
             }
         }
     }
@@ -964,9 +993,15 @@ flatc.Generator = class {
             }
 
             this._builder.add('');
-            this._builder.add(type.fields.size === 0 ? 'static decode(/* reader, position */) {' : 'static decode(reader, position) {');
+            if (type.aliases.size > 0) {
+                this._builder.add('static decode(reader, position, $) {');
+            } else if (type.fields.size === 0) {
+                this._builder.add('static decode(/* reader, position */) {');
+            } else {
+                this._builder.add('static decode(reader, position) {');
+            }
             this._builder.indent();
-                this._builder.add(`const $ = new ${typeReference}();`);
+                this._builder.add(type.aliases.size > 0 ? `$ = $ || new ${typeReference}();` : `const $ = new ${typeReference}();`);
                 for (const field of type.fields.values()) {
                     const fieldType = field.type instanceof flatc.Enum ? field.type.base : field.type;
                     if (field.repeated) {
@@ -1024,9 +1059,15 @@ flatc.Generator = class {
 
             if (this._text) {
                 this._builder.add('');
-                this._builder.add(type.fields.size === 0 ? 'static decodeText(/* reader, json */) {' : 'static decodeText(reader, json) {');
+                if (type.aliases.size > 0) {
+                    this._builder.add('static decodeText(reader, json, $) {');
+                } else if (type.fields.size === 0) {
+                    this._builder.add('static decodeText(/* reader, json */) {');
+                } else {
+                    this._builder.add('static decodeText(reader, json) {');
+                }
                 this._builder.indent();
-                    this._builder.add(`const $ = new ${typeReference}();`);
+                    this._builder.add(type.aliases.size > 0 ? `$ = $ || new ${typeReference}();` : `const $ = new ${typeReference}();`);
                     for (const field of type.fields.values()) {
                         if (field.repeated) {
                             if (field.type instanceof flatc.PrimitiveType) {
@@ -1153,6 +1194,41 @@ flatc.Generator = class {
         /* eslint-enable indent */
     }
 
+    _buildAlias(type) {
+
+        const typeName = `${type.parent.name}.${type.name}`;
+        const typeReference = `${typeName}`;
+
+        /* eslint-disable indent */
+        this._builder.add('');
+        this._builder.add(`${typeReference} = class ${type.name} {`);
+        this._builder.indent();
+
+            this._builder.add('');
+            this._builder.add('static decode(reader, position) {');
+            this._builder.indent();
+                this._builder.add(`const $ = new ${typeReference}();`);
+                this._builder.add(`${type.type.parent.name}.${type.type.name}.decode(reader, position, $);`);
+                this._builder.add('return $;');
+            this._builder.outdent();
+            this._builder.add('}');
+
+            if (this._text) {
+                this._builder.add('');
+                this._builder.add('static decodeText(reader, json) {');
+                this._builder.indent();
+                    this._builder.add(`const $ = new ${typeReference}();`);
+                    this._builder.add(`${type.type.parent.name}.${type.type.name}.decode(reader, json, $);`);
+                    this._builder.add('return $;');
+                this._builder.outdent();
+                this._builder.add('}');
+            }
+
+        this._builder.outdent();
+        this._builder.add('};');
+        /* eslint-enable indent */
+    }
+
     _buildUnion(type) {
 
         /* eslint-disable indent */