Skip to content

Commit fd948f0

Browse files
author
Mad Sheogorath
committed
Initial complete implementation.
1 parent a9166e8 commit fd948f0

File tree

9 files changed

+1784
-75
lines changed

9 files changed

+1784
-75
lines changed

example/generated/example-posts.generated.mjs

Lines changed: 676 additions & 0 deletions
Large diffs are not rendered by default.

example/generated/example-users.generated.mjs

Lines changed: 777 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
import {PackMe, PackMeMessage} from 'packme';
2+
3+
/** @enum {number} */
4+
const TypeEnum = {
5+
one: 0,
6+
two: 1,
7+
four: 2,
8+
};
9+
10+
class NestedObject extends PackMeMessage {
11+
/** @type {!number} */ a;
12+
/** @type {!string} */ b;
13+
14+
constructor(
15+
/** !number */ a,
16+
/** !string */ b,
17+
) {
18+
super();
19+
this.$check('a', a);
20+
this.$check('b', b);
21+
this.a = a;
22+
this.b = b;
23+
}
24+
25+
/** @return {number} */
26+
$estimate() {
27+
this.$reset();
28+
let bytes = 1;
29+
bytes += this.$stringBytes(this.b);
30+
return bytes;
31+
}
32+
33+
/** @return {undefined} */
34+
$pack() {
35+
this.$packUint8(this.a);
36+
this.$packString(this.b);
37+
}
38+
39+
/** @return {undefined} */
40+
$unpack() {
41+
this.a = this.$unpackUint8();
42+
this.b = this.$unpackString();
43+
}
44+
45+
/** @return {string} */
46+
toString() {
47+
return `NestedObject\x1b[0m(a: ${PackMe.dye(this.a)}, b: ${PackMe.dye(this.b)})`;
48+
}
49+
}
50+
51+
class TestMessage extends PackMeMessage {
52+
/** @type {!number} */ reqInt8;
53+
/** @type {!number} */ reqUint16;
54+
/** @type {!number} */ reqDouble;
55+
/** @type {!boolean} */ reqBool;
56+
/** @type {!string} */ reqString;
57+
/** @type {?number} */ optInt8;
58+
/** @type {?number} */ optUint16;
59+
/** @type {?number} */ optDouble;
60+
/** @type {?boolean} */ optBool;
61+
/** @type {?string} */ optString;
62+
/** @type {!number[]} */ reqList;
63+
/** @type {?number[]} */ optList;
64+
/** @type {!TypeEnum} */ reqEnum;
65+
/** @type {?TypeEnum} */ optEnum;
66+
/** @type {!NestedObject} */ reqNested;
67+
/** @type {?NestedObject} */ optNested;
68+
69+
constructor(
70+
/** !number */ reqInt8,
71+
/** !number */ reqUint16,
72+
/** !number */ reqDouble,
73+
/** !boolean */ reqBool,
74+
/** !string */ reqString,
75+
/** ?number */ optInt8,
76+
/** ?number */ optUint16,
77+
/** ?number */ optDouble,
78+
/** ?boolean */ optBool,
79+
/** ?string */ optString,
80+
/** !number[] */ reqList,
81+
/** ?number[] */ optList,
82+
/** !TypeEnum */ reqEnum,
83+
/** ?TypeEnum */ optEnum,
84+
/** !NestedObject */ reqNested,
85+
/** ?NestedObject */ optNested,
86+
) {
87+
super();
88+
this.$check('reqInt8', reqInt8);
89+
this.$check('reqUint16', reqUint16);
90+
this.$check('reqDouble', reqDouble);
91+
this.$check('reqBool', reqBool);
92+
this.$check('reqString', reqString);
93+
this.$check('reqList', reqList);
94+
this.$check('reqEnum', reqEnum);
95+
this.$check('reqNested', reqNested);
96+
this.reqInt8 = reqInt8;
97+
this.reqUint16 = reqUint16;
98+
this.reqDouble = reqDouble;
99+
this.reqBool = reqBool;
100+
this.reqString = reqString;
101+
this.optInt8 = optInt8;
102+
this.optUint16 = optUint16;
103+
this.optDouble = optDouble;
104+
this.optBool = optBool;
105+
this.optString = optString;
106+
this.reqList = reqList;
107+
this.optList = optList;
108+
this.reqEnum = reqEnum;
109+
this.optEnum = optEnum;
110+
this.reqNested = reqNested;
111+
this.optNested = optNested;
112+
}
113+
114+
/** @return {number} */
115+
$estimate() {
116+
this.$reset();
117+
let bytes = 22;
118+
bytes += this.$stringBytes(this.reqString);
119+
this.$setFlag(this.optInt8 != null);
120+
if (this.optInt8 != null) {
121+
bytes += 1;
122+
}
123+
this.$setFlag(this.optUint16 != null);
124+
if (this.optUint16 != null) {
125+
bytes += 2;
126+
}
127+
this.$setFlag(this.optDouble != null);
128+
if (this.optDouble != null) {
129+
bytes += 8;
130+
}
131+
this.$setFlag(this.optBool != null);
132+
if (this.optBool != null) {
133+
bytes += 1;
134+
}
135+
this.$setFlag(this.optString != null);
136+
if (this.optString != null) {
137+
bytes += this.$stringBytes(this.optString);
138+
}
139+
bytes += 4;
140+
bytes += 1 * this.reqList.length;
141+
this.$setFlag(this.optList != null);
142+
if (this.optList != null) {
143+
bytes += 4;
144+
bytes += 1 * this.optList.length;
145+
}
146+
this.$setFlag(this.optEnum != null);
147+
if (this.optEnum != null) {
148+
bytes += 1;
149+
}
150+
bytes += this.reqNested.$estimate();
151+
this.$setFlag(this.optNested != null);
152+
if (this.optNested != null) {
153+
bytes += this.optNested.$estimate();
154+
}
155+
return bytes;
156+
}
157+
158+
/** @return {undefined} */
159+
$pack() {
160+
this.$initPack(475203406);
161+
for (let i = 0; i < 1; i++) this.$packUint8(this.$flags[i]);
162+
this.$packInt8(this.reqInt8);
163+
this.$packUint16(this.reqUint16);
164+
this.$packDouble(this.reqDouble);
165+
this.$packBool(this.reqBool);
166+
this.$packString(this.reqString);
167+
if (this.optInt8 != null) this.$packInt8(this.optInt8);
168+
if (this.optUint16 != null) this.$packUint16(this.optUint16);
169+
if (this.optDouble != null) this.$packDouble(this.optDouble);
170+
if (this.optBool != null) this.$packBool(this.optBool);
171+
if (this.optString != null) this.$packString(this.optString);
172+
this.$packUint32(this.reqList.length);
173+
for (let item of this.reqList) this.$packUint8(item);
174+
if (this.optList != null) {
175+
this.$packUint32(this.optList.length);
176+
for (let item of this.optList) this.$packUint8(item);
177+
}
178+
this.$packUint8(this.reqEnum);
179+
if (this.optEnum != null) this.$packUint8(this.optEnum);
180+
this.$packMessage(this.reqNested);
181+
if (this.optNested != null) this.$packMessage(this.optNested);
182+
}
183+
184+
/** @return {undefined} */
185+
$unpack() {
186+
this.$initUnpack();
187+
for (let i = 0; i < 1; i++) this.$flags.push(this.$unpackUint8());
188+
this.reqInt8 = this.$unpackInt8();
189+
this.reqUint16 = this.$unpackUint16();
190+
this.reqDouble = this.$unpackDouble();
191+
this.reqBool = this.$unpackBool();
192+
this.reqString = this.$unpackString();
193+
if (this.$getFlag()) {
194+
this.optInt8 = this.$unpackInt8();
195+
}
196+
if (this.$getFlag()) {
197+
this.optUint16 = this.$unpackUint16();
198+
}
199+
if (this.$getFlag()) {
200+
this.optDouble = this.$unpackDouble();
201+
}
202+
if (this.$getFlag()) {
203+
this.optBool = this.$unpackBool();
204+
}
205+
if (this.$getFlag()) {
206+
this.optString = this.$unpackString();
207+
}
208+
this.reqList = [];
209+
let reqListLength = this.$unpackUint32();
210+
for (let i = 0; i < reqListLength; i++) {
211+
this.reqList.push(this.$unpackUint8());
212+
}
213+
if (this.$getFlag()) {
214+
this.optList = [];
215+
let optListLength = this.$unpackUint32();
216+
for (let i = 0; i < optListLength; i++) {
217+
this.optList.push(this.$unpackUint8());
218+
}
219+
}
220+
this.reqEnum = this.$unpackUint8();
221+
if (this.$getFlag()) {
222+
this.optEnum = this.$unpackUint8();
223+
}
224+
this.reqNested = this.$unpackMessage(new NestedObject());
225+
if (this.$getFlag()) {
226+
this.optNested = this.$unpackMessage(new NestedObject());
227+
}
228+
}
229+
230+
/** @return {string} */
231+
toString() {
232+
return `TestMessage\x1b[0m(reqInt8: ${PackMe.dye(this.reqInt8)}, reqUint16: ${PackMe.dye(this.reqUint16)}, reqDouble: ${PackMe.dye(this.reqDouble)}, reqBool: ${PackMe.dye(this.reqBool)}, reqString: ${PackMe.dye(this.reqString)}, optInt8: ${PackMe.dye(this.optInt8)}, optUint16: ${PackMe.dye(this.optUint16)}, optDouble: ${PackMe.dye(this.optDouble)}, optBool: ${PackMe.dye(this.optBool)}, optString: ${PackMe.dye(this.optString)}, reqList: ${PackMe.dye(this.reqList)}, optList: ${PackMe.dye(this.optList)}, reqEnum: ${PackMe.dye(this.reqEnum)}, optEnum: ${PackMe.dye(this.optEnum)}, reqNested: ${PackMe.dye(this.reqNested)}, optNested: ${PackMe.dye(this.optNested)})`;
233+
}
234+
}
235+
236+
const exampleMessageFactory = {
237+
'475203406': () => new TestMessage(),
238+
};

lib/compiler/enum.mjs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@ class Enum extends FieldType {
2121

2222
/// Return resulting code for Enum.
2323
output() {
24+
let i = 0;
2425
return [
25-
`enum ${this.name} {`,
26-
...this.values.map((value) => `${value},`),
27-
'}\n',
26+
'/** @enum {number} */',
27+
`const ${this.name} = {`,
28+
...this.values.map((value) => `${value}: ${i++},`),
29+
'};\n',
2830
];
2931
}
3032
}

lib/compiler/field.mjs

Lines changed: 35 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -19,32 +19,27 @@ class MessageField {
1919
this.array = array;
2020
}
2121

22-
/// Returns field name including exclamation mark if necessary.
23-
get #name() {
24-
return `${this.name}${this.optional ? '!' : ''}`;
25-
}
26-
27-
/// Returns required Dart Type depending on field type.
22+
/// Returns required JS Type depending on field type.
2823
get #type() {
2924
switch (this.type) {
3025
case 'bool':
31-
return 'bool';
26+
return 'boolean';
3227
case 'int8':
3328
case 'uint8':
3429
case 'int16':
3530
case 'uint16':
3631
case 'int32':
3732
case 'uint32':
38-
case 'int64':
39-
case 'uint64':
40-
return 'int';
4133
case 'float':
4234
case 'double':
43-
return 'double';
35+
return 'number';
36+
case 'int64':
37+
case 'uint64':
38+
return 'bigint';
4439
case 'datetime':
45-
return 'DateTime';
40+
return 'Date';
4641
case 'string':
47-
return 'String';
42+
return 'string';
4843
default:
4944
if (this.type instanceof Enum) return this.type.name;
5045
else if (this.type instanceof Message) return this.type.name;
@@ -69,47 +64,50 @@ class MessageField {
6964
case 'datetime': return `packDateTime(${name})`;
7065
case 'string': return `packString(${name})`;
7166
default:
72-
if (this.type instanceof Enum) return `packUint8(${name}.index)`;
67+
if (this.type instanceof Enum) return `packUint8(${name})`;
7368
else if (this.type instanceof Message) return `packMessage(${name})`;
7469
else throw new Error(`Unknown data type "${this.type}" for "${this.name}" in "${this.message.filename}".`);
7570
}
7671
}
7772

7873
/// Returns required unpack method depending on field type.
7974
get #unpack() {
80-
if (this.type instanceof Enum) return `${this.#type}.values[$unpackUint8()]`;
81-
else if (this.type instanceof Message) return `$unpackMessage(${this.type.name}.$empty())`;
75+
if (this.type instanceof Enum) return `$unpackUint8()`;
76+
else if (this.type instanceof Message) return `$unpackMessage(new ${this.type.name}())`;
8277
else return `$un${this.#pack('')}`;
8378
}
8479

80+
/// Returns type of the field.
81+
get typeof() {
82+
return `${this.optional ? '?' : '!'}${this.#type}${this.array ? '[]' : ''}`;
83+
}
84+
8585
/// Returns code of class field declaration.
8686
get declaration() {
87-
if (!this.array) return `${this.optional ? '' : 'late '}${this.#type}${this.optional ? '?' : ''} ${this.name};`;
88-
else return `${this.optional ? '' : 'late '}List<${this.#type}>${this.optional ? '?' : ''} ${this.name};`;
87+
return `/** @type {${this.typeof}} */ ${this.name};`;
8988
}
9089

9190
/// Returns code of field declaration as method attribute.
9291
get attribute() {
93-
if (!this.array) return `${this.optional ? '' : 'required '}${this.#type}${this.optional ? '?' : ''} ${this.name},`;
94-
else return `${this.optional ? '' : 'required '}List<${this.#type}>${this.optional ? '?' : ''} ${this.name},`;
92+
return `/** ${this.typeof} */ ${this.name}`;
9593
}
9694

9795
/// Returns code required to estimate size in bytes of this field.
9896
get estimate() {
9997
return [
100-
...(this.optional ? [`$setFlag(${this.name} != null);`] : []),
101-
...(this.optional ? [`if (${this.name} != null) {`] : []),
98+
...(this.optional ? [`this.$setFlag(this.${this.name} != null);`] : []),
99+
...(this.optional ? [`if (this.${this.name} != null) {`] : []),
102100
...(!this.array ? [
103101
(typeof this.type === 'string' || this.type instanceof Enum) && this.type !== 'string' ? `bytes += ${sizeOf(this.type)};`
104-
: this.type === 'string' ? `bytes += $stringBytes(${this.#name});`
105-
: this.type instanceof Message ? `bytes += ${this.#name}.$estimate();`
102+
: this.type === 'string' ? `bytes += this.$stringBytes(this.${this.name});`
103+
: this.type instanceof Message ? `bytes += this.${this.name}.$estimate();`
106104
: (() => { throw new Error(`Wrong type "${this.type}" for field "${this.name}" in "${this.message.filename}".`); })()
107105
]
108106
: [
109107
'bytes += 4;',
110-
(typeof this.type === 'string' || this.type instanceof Enum) && this.type !== 'string' ? `bytes += ${sizeOf(this.type)} * ${this.#name}.length;`
111-
: this.type === 'string' ? `for (int i = 0; i < ${this.#name}.length; i++) bytes += $stringBytes(${this.#name}[i]);`
112-
: this.type instanceof Message ? `for (int i = 0; i < ${this.#name}.length; i++) bytes += ${this.#name}[i].$estimate();`
108+
(typeof this.type === 'string' || this.type instanceof Enum) && this.type !== 'string' ? `bytes += ${sizeOf(this.type)} * this.${this.name}.length;`
109+
: this.type === 'string' ? `for (let i = 0; i < this.${this.name}.length; i++) bytes += this.$stringBytes(this.${this.name}[i]);`
110+
: this.type instanceof Message ? `for (let i = 0; i < this.${this.name}.length; i++) bytes += this.${this.name}[i].$estimate();`
113111
: (() => { throw new Error(`Wrong type "${this.type}" for field "${this.name}" in "${this.message.filename}".`); })()
114112
]),
115113
...(this.optional ? ['}'] : []),
@@ -119,11 +117,11 @@ class MessageField {
119117
/// Returns code required to pack this field.
120118
get pack() {
121119
return [
122-
...(!this.array ? [`${this.optional ? `if (${this.name} != null) ` : ''}$${this.#pack(this.#name)};`]
120+
...(!this.array ? [`${this.optional ? `if (this.${this.name} != null) ` : ''}this.$${this.#pack(`this.${this.name}`)};`]
123121
: [
124-
...(this.optional ? [`if (${this.name} != null) {`] : []),
125-
`$packUint32(${this.#name}.length);`,
126-
`for (final ${this.#type} item in ${this.#name}) $${this.#pack('item')};`,
122+
...(this.optional ? [`if (this.${this.name} != null) {`] : []),
123+
`this.$packUint32(this.${this.name}.length);`,
124+
`for (let item of this.${this.name}) this.$${this.#pack('item')};`,
127125
...(this.optional ? ['}'] : []),
128126
])
129127
];
@@ -132,13 +130,13 @@ class MessageField {
132130
/// Returns code required to unpack this field.
133131
get unpack() {
134132
return [
135-
...(this.optional ? ['if ($getFlag()) {'] : []),
136-
...(!this.array ? [`${this.name} = ${this.#unpack};`]
133+
...(this.optional ? ['if (this.$getFlag()) {'] : []),
134+
...(!this.array ? [`this.${this.name} = this.${this.#unpack};`]
137135
: [
138-
`${this.name} = <${this.#type}>[];`,
139-
`final int ${this.name}Length = $unpackUint32();`,
140-
`for (int i = 0; i < ${this.name}Length; i++) {`,
141-
`${this.#name}.add(${this.#unpack});`,
136+
`this.${this.name} = [];`,
137+
`let ${this.name}Length = this.$unpackUint32();`,
138+
`for (let i = 0; i < ${this.name}Length; i++) {`,
139+
`this.${this.name}.push(this.${this.#unpack});`,
142140
'}',
143141
]),
144142
...(this.optional ? ['}'] : []),

0 commit comments

Comments
 (0)