1 /**
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file EXPECT in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <gtest/gtest.h>
17 #include <iostream>
18
19 #include "assembly-emitter.h"
20 #include "assembly-parser.h"
21 #include "class_data_accessor-inl.h"
22 #include "code_data_accessor-inl.h"
23 #include "debug_data_accessor-inl.h"
24 #include "field_data_accessor-inl.h"
25 #include "file_items.h"
26 #include "lexer.h"
27 #include "method_data_accessor-inl.h"
28 #include "param_annotations_data_accessor.h"
29 #include "proto_data_accessor-inl.h"
30 #include "utils/span.h"
31 #include "utils/leb128.h"
32 #include "utils/utf.h"
33 #include "bytecode_instruction-inl.h"
34
35 using namespace testing::ext;
36
37 namespace panda::pandasm {
38 class AssemblyEmitterTest : public testing::Test {
39 };
40
GetTypeDescriptor(const std::string & name,std::string * storage)41 static const uint8_t *GetTypeDescriptor(const std::string &name, std::string *storage)
42 {
43 *storage = "L" + name + ";";
44 std::replace(storage->begin(), storage->end(), '.', '/');
45 return utf::CStringAsMutf8(storage->c_str());
46 }
47
GetSpecialOpcode(uint32_t pc_inc,int32_t line_inc)48 uint8_t GetSpecialOpcode(uint32_t pc_inc, int32_t line_inc)
49 {
50 return static_cast<uint8_t>(line_inc - panda_file::LineNumberProgramItem::LINE_BASE) +
51 static_cast<uint8_t>(pc_inc * panda_file::LineNumberProgramItem::LINE_RANGE) +
52 panda_file::LineNumberProgramItem::OPCODE_BASE;
53 }
54
55 /**
56 * @tc.name: assembly_emitter_test_001
57 * @tc.desc: Verify the EnumerateMethods function.
58 * @tc.type: FUNC
59 * @tc.require: issueNumber
60 */
61 HWTEST_F(AssemblyEmitterTest, assembly_emitter_test_001, TestSize.Level1)
62 {
63 Parser p;
64 auto source = R"(
65 .record R {}
66 .function void R.foo(R a0) <ctor> {}
67 )";
68
69 auto res = p.Parse(source);
70 EXPECT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
71
72 auto pf = AsmEmitter::Emit(res.Value());
73 EXPECT_NE(pf, nullptr);
74
75 std::string descriptor;
76
77 auto class_id = pf->GetClassId(GetTypeDescriptor("R", &descriptor));
78 EXPECT_TRUE(class_id.IsValid());
79
80 panda_file::ClassDataAccessor cda(*pf, class_id);
81
__anon9d5bb8020102(panda_file::MethodDataAccessor &mda) 82 cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) {
83 auto *name = utf::Mutf8AsCString(pf->GetStringData(mda.GetNameId()).data);
84 EXPECT_STREQ(name, ".ctor");
85 });
86 }
87
88 /**
89 * @tc.name: assembly_emitter_test_002
90 * @tc.desc: Verify the EnumerateMethods function.
91 * @tc.type: FUNC
92 * @tc.require: issueNumber
93 */
94 HWTEST_F(AssemblyEmitterTest, assembly_emitter_test_002, TestSize.Level1)
95 {
96 Parser p;
97
98 auto source = R"( # 1
99 .record R { # 2
100 i32 sf <static> # 3
101 i8 if # 4
102 } # 5
103 # 6
104 .function void main() { # 7
105 return # 8
106 } # 9
107 )";
108
109 std::string source_filename = "source.pa";
110 auto res = p.Parse(source, source_filename);
111 EXPECT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
112
113 auto pf = AsmEmitter::Emit(res.Value());
114 EXPECT_NE(pf, nullptr);
115
116 {
117 std::string descriptor;
118 auto class_id = pf->GetClassId(GetTypeDescriptor("_GLOBAL", &descriptor));
119 EXPECT_TRUE(class_id.IsValid());
120 EXPECT_FALSE(pf->IsExternal(class_id));
121
122 panda_file::ClassDataAccessor cda(*pf, class_id);
123 EXPECT_EQ(cda.GetSuperClassId().GetOffset(), 0U);
124 EXPECT_EQ(cda.GetAccessFlags(), ACC_PUBLIC);
125 EXPECT_EQ(cda.GetFieldsNumber(), 0U);
126 EXPECT_EQ(cda.GetMethodsNumber(), 1U);
127 EXPECT_EQ(cda.GetIfacesNumber(), 0U);
128
129 EXPECT_FALSE(cda.GetSourceFileId().has_value());
130
__anon9d5bb8020202(panda_file::File::EntityId) 131 cda.EnumerateAnnotations([](panda_file::File::EntityId) { EXPECT_TRUE(false); });
132
__anon9d5bb8020302(panda_file::FieldDataAccessor &) 133 cda.EnumerateFields([](panda_file::FieldDataAccessor &) { EXPECT_TRUE(false); });
134
__anon9d5bb8020402(panda_file::MethodDataAccessor &mda) 135 cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) {
136 EXPECT_FALSE(mda.IsExternal());
137 EXPECT_EQ(mda.GetClassId(), class_id);
138 EXPECT_EQ(utf::CompareMUtf8ToMUtf8(pf->GetStringData(mda.GetNameId()).data, utf::CStringAsMutf8("main")),
139 0);
140
141 panda_file::ProtoDataAccessor pda(*pf, mda.GetProtoId());
142 EXPECT_EQ(pda.GetNumArgs(), 0U);
143 EXPECT_EQ(pda.GetReturnType().GetId(), panda_file::Type::TypeId::VOID);
144
145 EXPECT_EQ(mda.GetAccessFlags(), ACC_STATIC);
146 EXPECT_TRUE(mda.GetCodeId().has_value());
147
148 panda_file::CodeDataAccessor cdacc(*pf, mda.GetCodeId().value());
149 EXPECT_EQ(cdacc.GetNumVregs(), 0U);
150 EXPECT_EQ(cdacc.GetNumArgs(), 0U);
151 EXPECT_EQ(cdacc.GetCodeSize(), 1U);
152 EXPECT_EQ(cdacc.GetTriesSize(), 0U);
153
154 EXPECT_FALSE(mda.GetRuntimeParamAnnotationId().has_value());
155 EXPECT_FALSE(mda.GetParamAnnotationId().has_value());
156 EXPECT_TRUE(mda.GetDebugInfoId().has_value());
157
158 panda_file::DebugInfoDataAccessor dda(*pf, mda.GetDebugInfoId().value());
159 EXPECT_EQ(dda.GetLineStart(), 8U);
160 EXPECT_EQ(dda.GetNumParams(), 0U);
161
162 mda.EnumerateAnnotations([](panda_file::File::EntityId) {});
163 });
164 }
165 {
166 std::string descriptor;
167 auto class_id = pf->GetClassId(GetTypeDescriptor("R", &descriptor));
168 EXPECT_TRUE(class_id.IsValid());
169 EXPECT_FALSE(pf->IsExternal(class_id));
170
171 panda_file::ClassDataAccessor cda(*pf, class_id);
172 EXPECT_EQ(cda.GetSuperClassId().GetOffset(), 0U);
173 EXPECT_EQ(cda.GetAccessFlags(), 0U);
174 EXPECT_EQ(cda.GetFieldsNumber(), 2U);
175 EXPECT_EQ(cda.GetMethodsNumber(), 0U);
176 EXPECT_EQ(cda.GetIfacesNumber(), 0U);
177
178 // We emit SET_FILE in debuginfo
179 EXPECT_TRUE(cda.GetSourceFileId().has_value());
180
181 EXPECT_EQ(std::string(reinterpret_cast<const char *>(pf->GetStringData(cda.GetSourceFileId().value()).data)),
182 source_filename);
183
184 struct FieldData {
185 std::string name;
186 panda_file::Type::TypeId type_id;
187 uint32_t access_flags;
188 };
189
190 std::vector<FieldData> fields {{"sf", panda_file::Type::TypeId::I32, ACC_STATIC},
191 {"if", panda_file::Type::TypeId::I8, 0}};
192
193 size_t i = 0;
__anon9d5bb8020602(panda_file::FieldDataAccessor &fda) 194 cda.EnumerateFields([&](panda_file::FieldDataAccessor &fda) {
195 EXPECT_FALSE(fda.IsExternal());
196 EXPECT_EQ(fda.GetClassId(), class_id);
197 EXPECT_EQ(utf::CompareMUtf8ToMUtf8(pf->GetStringData(fda.GetNameId()).data,
198 utf::CStringAsMutf8(fields[i].name.c_str())),
199 0);
200
201 EXPECT_EQ(fda.GetType(), panda_file::Type(fields[i].type_id).GetFieldEncoding());
202 EXPECT_EQ(fda.GetAccessFlags(), fields[i].access_flags);
203
204 fda.EnumerateAnnotations([](panda_file::File::EntityId) { EXPECT_TRUE(false); });
205
206 ++i;
207 });
208
__anon9d5bb8020802(panda_file::MethodDataAccessor &) 209 cda.EnumerateMethods([&](panda_file::MethodDataAccessor &) { EXPECT_TRUE(false); });
210 }
211 }
212
213 /**
214 * @tc.name: assembly_emitter_test_003
215 * @tc.desc: Verify the EnumerateMethods function.
216 * @tc.type: FUNC
217 * @tc.require: issueNumber
218 */
219 HWTEST_F(AssemblyEmitterTest, assembly_emitter_test_003, TestSize.Level1)
220 {
221 Parser p;
222
223 auto source = R"(
224 .function void main() {
225 ldai 0 # line 3, pc 0
226 # line 4
227 # line 5
228 # line 6
229 # line 7
230 # line 8
231 # line 9
232 # line 10
233 # line 11
234 # line 12
235 # line 13
236 # line 14
237 ldai 1 # line 15, pc 9
238 return # line 16, pc 18
239 }
240 )";
241
242 std::string source_filename = "source.pa";
243 auto res = p.Parse(source, source_filename);
244 EXPECT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
245
246 auto pf = AsmEmitter::Emit(res.Value());
247 EXPECT_NE(pf, nullptr);
248
249 std::string descriptor;
250 auto class_id = pf->GetClassId(GetTypeDescriptor("_GLOBAL", &descriptor));
251 EXPECT_TRUE(class_id.IsValid());
252
253 panda_file::ClassDataAccessor cda(*pf, class_id);
254
__anon9d5bb8020902(panda_file::MethodDataAccessor &mda) 255 cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) {
256 panda_file::CodeDataAccessor cdacc(*pf, mda.GetCodeId().value());
257 EXPECT_TRUE(mda.GetDebugInfoId().has_value());
258
259 panda_file::DebugInfoDataAccessor dda(*pf, mda.GetDebugInfoId().value());
260 EXPECT_EQ(dda.GetLineStart(), 3U);
261 EXPECT_EQ(dda.GetNumParams(), 0U);
262
263 dda.GetLineNumberProgram();
264 Span<const uint8_t> constant_pool = dda.GetConstantPool();
265
266 std::vector<uint8_t> opcodes {static_cast<uint8_t>(panda_file::LineNumberProgramItem::Opcode::SET_FILE),
267 static_cast<uint8_t>(panda_file::LineNumberProgramItem::Opcode::ADVANCE_PC),
268 static_cast<uint8_t>(panda_file::LineNumberProgramItem::Opcode::ADVANCE_LINE),
269 GetSpecialOpcode(0, 0),
270 GetSpecialOpcode(9, 1),
271 static_cast<uint8_t>(panda_file::LineNumberProgramItem::Opcode::END_SEQUENCE)};
272
273 size_t size {};
274 bool is_full {};
275 size_t constant_pool_offset = 0;
276
277 uint32_t offset {};
278
279 std::tie(offset, size, is_full) = leb128::DecodeUnsigned<uint32_t>(&constant_pool[constant_pool_offset]);
280 constant_pool_offset += size;
281 EXPECT_TRUE(is_full);
282 EXPECT_EQ(
283 std::string(reinterpret_cast<const char *>(pf->GetStringData(panda_file::File::EntityId(offset)).data)),
284 source_filename);
285
286 uint32_t pc_inc;
287 std::tie(pc_inc, size, is_full) = leb128::DecodeUnsigned<uint32_t>(&constant_pool[constant_pool_offset]);
288 constant_pool_offset += size;
289 EXPECT_TRUE(is_full);
290 EXPECT_EQ(pc_inc, 0U);
291
292 int32_t line_inc;
293 std::tie(line_inc, size, is_full) = leb128::DecodeSigned<int32_t>(&constant_pool[constant_pool_offset]);
294 constant_pool_offset += size;
295 EXPECT_TRUE(is_full);
296 EXPECT_EQ(line_inc, 5);
297
298 EXPECT_EQ(constant_pool_offset + 1, constant_pool.size());
299 });
300 }
301
302 /**
303 * @tc.name: assembly_emitter_test_004
304 * @tc.desc: Verify the EnumerateMethods function.
305 * @tc.type: FUNC
306 * @tc.require: issueNumber
307 */
308 HWTEST_F(AssemblyEmitterTest, assembly_emitter_test_004, TestSize.Level1)
309 {
310 Parser p;
311
312 auto source = R"(
313 .record Exception1 {}
314 .record Exception2 {}
315
316 .function any myFunction(any a0, any a1, any a2) <static> {
317 mov v0, a0
318 mov v1, a1
319 mov v2, a2
320 ldundefined
321 sta v4
322 try_begin:
323 jmp handler_begin1
324 handler_begin1:
325 ldhole
326 sta v5
327 jmp handler_end2
328 handler_begin2:
329 sta v5
330 handler_end2:
331 lda v4
332 sta v6
333 ldundefined
334 eq 0x0, v6
335 jeqz jump_label_4
336 sta v4
337 jump_label_4:
338 lda v5
339 sta v6
340 ldhole
341 sta v7
342 lda v6
343 noteq 0x1, v7
344 jeqz jump_label_5
345 lda v6
346 throw
347 jump_label_5:
348 ldundefined
349 returnundefined
350
351 .catchall try_begin, try_begin, handler_begin1
352 .catchall try_begin, handler_begin1, handler_begin2, handler_end2
353 }
354 )";
355
356 auto res = p.Parse(source);
357 EXPECT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
358 auto pf = AsmEmitter::Emit(res.Value());
359 EXPECT_NE(pf, nullptr);
360
361 std::string descriptor;
362
363 auto class_id = pf->GetClassId(GetTypeDescriptor("_GLOBAL", &descriptor));
364 EXPECT_TRUE(class_id.IsValid());
365
366 panda_file::ClassDataAccessor cda(*pf, class_id);
367
368 size_t i = 0;
__anon9d5bb8020a02(panda_file::MethodDataAccessor &mda) 369 cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) {
370 panda_file::CodeDataAccessor cdacc(*pf, mda.GetCodeId().value());
371 // The NumVregs of arguments is 8U
372 // The NumArgs of arguments is 3U
373 // The tries size is 2U
374 EXPECT_EQ(cdacc.GetNumVregs(), 8U);
375 EXPECT_EQ(cdacc.GetNumArgs(), 3U);
376 EXPECT_EQ(cdacc.GetTriesSize(), 2U);
377
378 cdacc.EnumerateTryBlocks([&](panda_file::CodeDataAccessor::TryBlock &try_block) {
379 // Try start Pc is 9U
380 // Catches number is 1U
381 EXPECT_EQ(try_block.GetStartPc(), 9U);
382 EXPECT_EQ(try_block.GetNumCatches(), 1U);
383
384 struct CatchInfo {
385 panda_file::File::EntityId type_id;
386 uint32_t handler_pc;
387 };
388 // Exception1 class ID is 11.
389 // Exception2 class ID is 16.
390 // The file entity ID is 6 * 9.
391 std::vector<CatchInfo> catch_infos {{pf->GetClassId(GetTypeDescriptor("Exception1", &descriptor)), 11},
392 {pf->GetClassId(GetTypeDescriptor("Exception2", &descriptor)), 16},
393 {panda_file::File::EntityId(), 6 * 9}};
394
395 try_block.EnumerateCatchBlocks([&](panda_file::CodeDataAccessor::CatchBlock &catch_block) {
396 EXPECT_EQ(catch_block.GetHandlerPc(), catch_infos[i].handler_pc);
397 ++i;
398
399 return true;
400 });
401
402 return true;
403 });
404 });
405 }
406
407 /**
408 * @tc.name: assembly_emitter_test_005
409 * @tc.desc: Verify the AsmEmitter::GetLastError() function.
410 * @tc.type: FUNC
411 * @tc.require: issueNumber
412 */
413 HWTEST_F(AssemblyEmitterTest, assembly_emitter_test_005, TestSize.Level1)
414 {
415 {
416 Parser p;
417 auto source = R"(
418 .record A {
419 B b
420 }
421 )";
422
423 auto res = p.Parse(source);
424 EXPECT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
425
426 auto pf = AsmEmitter::Emit(res.Value());
427 EXPECT_EQ(pf, nullptr);
428 EXPECT_EQ(AsmEmitter::GetLastError(), "Field A.b has undefined type");
429 }
430
431 {
432 Parser p;
433 auto source = R"(
434 .function void A.b() {}
435 )";
436
437 auto res = p.Parse(source);
438 EXPECT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
439
440 auto pf = AsmEmitter::Emit(res.Value());
441 EXPECT_EQ(pf, nullptr);
442 EXPECT_EQ(AsmEmitter::GetLastError(), "Function A.b is bound to undefined record A");
443 }
444
445 {
446 Parser p;
447 auto source = R"(
448 .function A b() {}
449 )";
450
451 auto res = p.Parse(source);
452 EXPECT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
453
454 auto pf = AsmEmitter::Emit(res.Value());
455 EXPECT_EQ(pf, nullptr);
456 EXPECT_EQ(AsmEmitter::GetLastError(), "Function b has undefined return type");
457 }
458
459 {
460 Parser p;
461 auto source = R"(
462 .function void a(b a0) {}
463 )";
464
465 auto res = p.Parse(source);
466 EXPECT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
467
468 auto pf = AsmEmitter::Emit(res.Value());
469 EXPECT_EQ(pf, nullptr);
470 EXPECT_EQ(AsmEmitter::GetLastError(), "Argument 0 of function a has undefined type");
471 }
472
473 {
474 Parser p;
475 auto source = R"(
476 .record A <external>
477 .function void A.x() {}
478 )";
479
480 auto res = p.Parse(source);
481 EXPECT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
482
483 auto pf = AsmEmitter::Emit(res.Value());
484 EXPECT_EQ(pf, nullptr);
485 EXPECT_EQ(AsmEmitter::GetLastError(), "Non-external function A.x is bound to external record");
486 }
487 }
488
489 /**
490 * @tc.name: assembly_emitter_test_006
491 * @tc.desc: Verify the EnumerateMethods function.
492 * @tc.type: FUNC
493 * @tc.require: issueNumber
494 */
495 HWTEST_F(AssemblyEmitterTest, assembly_emitter_test_006, TestSize.Level1)
496 {
497 Parser p;
498 auto source = R"(
499 .function void foo() {}
500 )";
501
502 auto res = p.Parse(source);
503 EXPECT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
504
505 auto pf = AsmEmitter::Emit(res.Value());
506 EXPECT_NE(pf, nullptr);
507
508 std::string descriptor;
509
510 auto class_id = pf->GetClassId(GetTypeDescriptor("_GLOBAL", &descriptor));
511 EXPECT_TRUE(class_id.IsValid());
512
513 panda_file::ClassDataAccessor cda(*pf, class_id);
514
515 EXPECT_FALSE(cda.GetSourceLang());
516
__anon9d5bb8020d02(panda_file::MethodDataAccessor &mda) 517 cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) { EXPECT_FALSE(mda.GetSourceLang()); });
518 }
519
520 /**
521 * @tc.name: assembly_emitter_test_007
522 * @tc.desc: Verify the EnumerateMethods function.
523 * @tc.type: FUNC
524 * @tc.require: issueNumber
525 */
526 HWTEST_F(AssemblyEmitterTest, assembly_emitter_test_007, TestSize.Level1)
527 {
528 {
529 Parser p;
530 auto source = R"(
531 .record R {}
532 .function void R.foo(R a0) <ctor> {}
533 )";
534
535 auto res = p.Parse(source);
536 EXPECT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
537
538 auto pf = AsmEmitter::Emit(res.Value());
539 EXPECT_NE(pf, nullptr);
540
541 std::string descriptor;
542
543 auto class_id = pf->GetClassId(GetTypeDescriptor("R", &descriptor));
544 EXPECT_TRUE(class_id.IsValid());
545
546 panda_file::ClassDataAccessor cda(*pf, class_id);
547
__anon9d5bb8020e02(panda_file::MethodDataAccessor &mda) 548 cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) {
549 auto *name = utf::Mutf8AsCString(pf->GetStringData(mda.GetNameId()).data);
550 EXPECT_STREQ(name, ".ctor");
551 });
552 }
553
554 {
555 Parser p;
556 auto source = R"(
557 .record R {}
558 .function void R.foo(R a0) <cctor> {}
559 )";
560
561 auto res = p.Parse(source);
562 EXPECT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
563
564 auto pf = AsmEmitter::Emit(res.Value());
565 EXPECT_NE(pf, nullptr);
566
567 std::string descriptor;
568
569 auto class_id = pf->GetClassId(GetTypeDescriptor("R", &descriptor));
570 EXPECT_TRUE(class_id.IsValid());
571
572 panda_file::ClassDataAccessor cda(*pf, class_id);
573
__anon9d5bb8020f02(panda_file::MethodDataAccessor &mda) 574 cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) {
575 auto *name = utf::Mutf8AsCString(pf->GetStringData(mda.GetNameId()).data);
576 EXPECT_STREQ(name, ".cctor");
577 });
578 }
579 }
580
581 /**
582 * @tc.name: assembly_emitter_test_008
583 * @tc.desc: Verify the EnumerateFields function.
584 * @tc.type: FUNC
585 * @tc.require: issueNumber
586 */
587 HWTEST_F(AssemblyEmitterTest, assembly_emitter_test_008, TestSize.Level1)
588 {
589 Parser p;
590
591 auto source = R"(
592 .record panda.String <external>
593
594 .record R {
595 u1 f_u1 <value=1>
596 i8 f_i8 <value=2>
597 u8 f_u8 <value=128>
598 i16 f_i16 <value=256>
599 u16 f_u16 <value=32768>
600 i32 f_i32 <value=65536>
601 u32 f_u32 <value=2147483648>
602 i64 f_i64 <value=4294967296>
603 u64 f_u64 <value=9223372036854775808>
604 f32 f_f32 <value=1.0>
605 f64 f_f64 <value=2.0>
606 panda.String f_str <value="str">
607 }
608 )";
609
610 struct FieldData {
611 std::string name;
612 panda_file::Type::TypeId type_id;
613 std::variant<int32_t, uint32_t, int64_t, uint64_t, float, double, std::string> value;
614 };
615
616 uint32_t f_u1 = 1;
617 int32_t f_i8 = 2;
618 uint32_t f_u8 = 128;
619 int32_t f_i16 = 256;
620 uint32_t f_u16 = 32768;
621 int32_t f_i32 = 65536;
622 uint32_t f_u32 = 2147483648;
623 int64_t f_i64 = 4294967296;
624 uint64_t f_u64 = 9223372036854775808ULL;
625 float f_f32 = 1.0;
626 double f_f64 = 2.0;
627
628 std::vector<FieldData> data {
629 {"f_u1", panda_file::Type::TypeId::U1, f_u1}, {"f_i8", panda_file::Type::TypeId::I8, f_i8},
630 {"f_u8", panda_file::Type::TypeId::U8, f_u8}, {"f_i16", panda_file::Type::TypeId::I16, f_i16},
631 {"f_u16", panda_file::Type::TypeId::U16, f_u16}, {"f_i32", panda_file::Type::TypeId::I32, f_i32},
632 {"f_u32", panda_file::Type::TypeId::U32, f_u32}, {"f_i64", panda_file::Type::TypeId::I64, f_i64},
633 {"f_u64", panda_file::Type::TypeId::U64, f_u64}, {"f_f32", panda_file::Type::TypeId::F32, f_f32},
634 {"f_f64", panda_file::Type::TypeId::F64, f_f64}, {"f_str", panda_file::Type::TypeId::REFERENCE, "str"}};
635
636 auto res = p.Parse(source);
637 EXPECT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
638
639 auto pf = AsmEmitter::Emit(res.Value());
640 EXPECT_NE(pf, nullptr);
641
642 std::string descriptor;
643 auto class_id = pf->GetClassId(GetTypeDescriptor("R", &descriptor));
644 EXPECT_TRUE(class_id.IsValid());
645 EXPECT_FALSE(pf->IsExternal(class_id));
646
647 panda_file::ClassDataAccessor cda(*pf, class_id);
648 EXPECT_EQ(cda.GetFieldsNumber(), data.size());
649
650 auto panda_string_id = pf->GetClassId(GetTypeDescriptor("panda.String", &descriptor));
651
652 size_t idx = 0;
__anon9d5bb8021002(panda_file::FieldDataAccessor &fda) 653 cda.EnumerateFields([&](panda_file::FieldDataAccessor &fda) {
654 const FieldData &field_data = data[idx];
655
656 EXPECT_EQ(utf::CompareMUtf8ToMUtf8(pf->GetStringData(fda.GetNameId()).data,
657 utf::CStringAsMutf8(field_data.name.c_str())),
658 0);
659
660 panda_file::Type type(field_data.type_id);
661 uint32_t type_value;
662 if (type.IsReference()) {
663 type_value = panda_string_id.GetOffset();
664 } else {
665 type_value = type.GetFieldEncoding();
666 }
667
668 switch (field_data.type_id) {
669 case panda_file::Type::TypeId::U1: {
670 auto result = fda.GetValue<uint8_t>();
671 EXPECT_TRUE(result);
672 EXPECT_EQ(result.value(), std::get<uint32_t>(field_data.value));
673 break;
674 }
675 case panda_file::Type::TypeId::I8: {
676 auto result = fda.GetValue<int8_t>();
677 EXPECT_TRUE(result);
678 EXPECT_EQ(result.value(), std::get<int32_t>(field_data.value));
679 break;
680 }
681 case panda_file::Type::TypeId::U8: {
682 auto result = fda.GetValue<uint8_t>();
683 EXPECT_TRUE(result);
684 EXPECT_EQ(result.value(), std::get<uint32_t>(field_data.value));
685 break;
686 }
687 case panda_file::Type::TypeId::I16: {
688 auto result = fda.GetValue<int16_t>();
689 EXPECT_TRUE(result);
690 EXPECT_EQ(result.value(), std::get<int32_t>(field_data.value));
691 break;
692 }
693 case panda_file::Type::TypeId::U16: {
694 auto result = fda.GetValue<uint16_t>();
695 EXPECT_TRUE(result);
696 EXPECT_EQ(result.value(), std::get<uint32_t>(field_data.value));
697 break;
698 }
699 case panda_file::Type::TypeId::I32: {
700 auto result = fda.GetValue<int32_t>();
701 EXPECT_TRUE(result);
702 EXPECT_EQ(result.value(), std::get<int32_t>(field_data.value));
703 break;
704 }
705 case panda_file::Type::TypeId::U32: {
706 auto result = fda.GetValue<uint32_t>();
707 EXPECT_TRUE(result);
708 EXPECT_EQ(result.value(), std::get<uint32_t>(field_data.value));
709 break;
710 }
711 case panda_file::Type::TypeId::I64: {
712 auto result = fda.GetValue<int64_t>();
713 EXPECT_TRUE(result);
714 EXPECT_EQ(result.value(), std::get<int64_t>(field_data.value));
715 break;
716 }
717 case panda_file::Type::TypeId::U64: {
718 auto result = fda.GetValue<uint64_t>();
719 EXPECT_TRUE(result);
720 EXPECT_EQ(result.value(), std::get<uint64_t>(field_data.value));
721 break;
722 }
723 case panda_file::Type::TypeId::F32: {
724 auto result = fda.GetValue<float>();
725 EXPECT_TRUE(result);
726 EXPECT_EQ(result.value(), std::get<float>(field_data.value));
727 break;
728 }
729 case panda_file::Type::TypeId::F64: {
730 auto result = fda.GetValue<double>();
731 EXPECT_TRUE(result);
732 EXPECT_EQ(result.value(), std::get<double>(field_data.value));
733 break;
734 }
735 case panda_file::Type::TypeId::REFERENCE: {
736 auto result = fda.GetValue<uint32_t>();
737 EXPECT_TRUE(result);
738
739 panda_file::File::EntityId string_id(result.value());
740 auto val = std::get<std::string>(field_data.value);
741
742 EXPECT_EQ(utf::CompareMUtf8ToMUtf8(pf->GetStringData(string_id).data, utf::CStringAsMutf8(val.c_str())),
743 0);
744 break;
745 }
746 default: {
747 UNREACHABLE();
748 break;
749 }
750 }
751
752 ++idx;
753 });
754 }
755
756 /**
757 * @tc.name: assembly_emitter_test_009
758 * @tc.desc: Verify the EnumerateMethods function.
759 * @tc.type: FUNC
760 * @tc.require: issueNumber
761 */
762 HWTEST_F(AssemblyEmitterTest, assembly_emitter_test_009, TestSize.Level1)
763 {
764 Parser p;
765 auto source = R"(
766 .function any foo(any a0) <noimpl>
767 )";
768
769 auto res = p.Parse(source);
770 EXPECT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
771
772 auto pf = AsmEmitter::Emit(res.Value());
773 EXPECT_NE(pf, nullptr);
774
775 std::string descriptor;
776
777 auto class_id = pf->GetClassId(GetTypeDescriptor("_GLOBAL", &descriptor));
778 EXPECT_TRUE(class_id.IsValid());
779
780 panda_file::ClassDataAccessor cda(*pf, class_id);
781
782 int32_t num_methods = 0;
783 const auto tagged = panda_file::Type(panda_file::Type::TypeId::TAGGED);
__anon9d5bb8021102(panda_file::MethodDataAccessor &mda) 784 cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) {
785 panda_file::ProtoDataAccessor pda(*pf, mda.GetProtoId());
786 EXPECT_EQ(tagged, pda.GetReturnType());
787 EXPECT_EQ(1u, pda.GetNumArgs());
788 EXPECT_EQ(tagged, pda.GetArgType(0));
789
790 ++num_methods;
791 });
792 EXPECT_EQ(1, num_methods);
793 }
794
795 /**
796 * @tc.name: assembly_emitter_test_010
797 * @tc.desc: Verify the AsmEmitter::Emit function.
798 * @tc.type: FUNC
799 * @tc.require: issueNumber
800 */
801 HWTEST_F(AssemblyEmitterTest, assembly_emitter_test_010, TestSize.Level1)
802 {
803 Parser p;
804 auto source = R"(
805 .record Test {
806 any foo
807 }
808 )";
809
810 auto res = p.Parse(source);
811 EXPECT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
812
813 auto pf = AsmEmitter::Emit(res.Value());
814 EXPECT_NE(pf, nullptr);
815
816 std::string descriptor;
817
818 auto class_id = pf->GetClassId(GetTypeDescriptor("Test", &descriptor));
819 EXPECT_TRUE(class_id.IsValid());
820
821 panda_file::ClassDataAccessor cda(*pf, class_id);
822
823 size_t num_fields = 0;
824 const auto tagged = panda_file::Type(panda_file::Type::TypeId::TAGGED);
__anon9d5bb8021202(panda_file::FieldDataAccessor &fda) 825 cda.EnumerateFields([&](panda_file::FieldDataAccessor &fda) {
826 uint32_t type = fda.GetType();
827 EXPECT_EQ(tagged.GetFieldEncoding(), type);
828
829 ++num_fields;
830 });
831 EXPECT_EQ(1, num_fields);
832 }
833
834 /**
835 * @tc.name: assembly_emitter_test_011
836 * @tc.desc: Verify the AsmEmitter::Emit function.
837 * @tc.type: FUNC
838 * @tc.require: issueNumber
839 */
840 HWTEST_F(AssemblyEmitterTest, assembly_emitter_test_011, TestSize.Level1)
841 {
842 Parser p1;
843 auto source1 = R"(
844 .record Test {
845 any foo
846 }
847 )";
848 Parser p2;
849 auto source2 = R"(
850 .function void main() {
851 ldai 0
852 ldai 1
853 return
854 }
855 )";
856 auto res1 = p1.Parse(source1);
857 EXPECT_EQ(p1.ShowError().err, Error::ErrorType::ERR_NONE);
858
859 auto res2 = p2.Parse(source2);
860 EXPECT_EQ(p2.ShowError().err, Error::ErrorType::ERR_NONE);
861
862 std::vector<Program *> progs;
863 progs.push_back(&res1.Value());
864 progs.push_back(&res2.Value());
865 const std::string filename = "source.pa";;
866 auto pf = AsmEmitter::EmitPrograms(filename, progs, false);
867 EXPECT_TRUE(pf);
868 }
869
870 /**
871 * @tc.name: assembly_emitter_test_012
872 * @tc.desc: Verify the AsmEmitter::Emit function.
873 * @tc.type: FUNC
874 * @tc.require: issueNumber
875 */
876 HWTEST_F(AssemblyEmitterTest, assembly_emitter_test_012, TestSize.Level1)
877 {
878 Parser par;
879 auto source = R"(
880 .record Math <external>
881 .function i64 Math.minI64(i64 a0) <external>
882 .function i64 main(i64 a0, i64 a1) {
883 ldglobalvar 0x9, "Math.minI64"
884 callarg1 0x4, a0
885 return
886 }
887 )";
888 auto ret = par.Parse(source);
889 EXPECT_EQ(par.ShowError().err, Error::ErrorType::ERR_NONE);
890 auto pf = AsmEmitter::Emit(ret.Value());
891 EXPECT_NE(pf, nullptr);
892
893 std::string descriptors;
894
895 auto class_id = pf->GetClassId(GetTypeDescriptor("Math", &descriptors));
896 EXPECT_TRUE(class_id.IsValid());
897 }
898
899 /**
900 * @tc.name: assembly_emitter_test_013
901 * @tc.desc: Verify the AsmEmitter::Emit function.
902 * @tc.type: FUNC
903 * @tc.require: issueNumber
904 */
905 HWTEST_F(AssemblyEmitterTest, assembly_emitter_test_013, TestSize.Level1)
906 {
907 Parser par;
908 auto source = R"(
909 .array array {
910 u1 1
911 u8 2
912 i8 -30
913 u16 400
914 i16 -5000
915 u32 60000
916 i32 -700000
917 u64 8000000
918 i64 -90000000
919 f32 12
920 f64 12
921 }
922 )";
923 std::string source_filename = "source.pa";
924 auto program = par.Parse(source, source_filename);
925 EXPECT_EQ(par.ShowError().err, Error::ErrorType::ERR_NONE);
926 auto pf = AsmEmitter::Emit(program.Value());
927 EXPECT_NE(pf, nullptr);
928 }
929
930 /**
931 * @tc.name: assembly_emitter_test_014
932 * @tc.desc: Verify the AsmEmitter::Emit function.
933 * @tc.type: FUNC
934 * @tc.require: issueNumber
935 */
936 HWTEST_F(AssemblyEmitterTest, assembly_emitter_test_014, TestSize.Level1)
937 {
938 std::vector<std::vector<panda::pandasm::Token>> v;
939 Lexer l;
940 Parser par;
941 v.push_back(l.TokenizeString(".array array {").first);
942 v.push_back(l.TokenizeString("panda.String \"a\"").first);
943 v.push_back(l.TokenizeString("panda.String \"ab\"").first);
944 v.push_back(l.TokenizeString("panda.String \"abc\"").first);
945 v.push_back(l.TokenizeString("}").first);
946 v.push_back(l.TokenizeString(".array array_static panda.String 3 { \"a\" \"ab\" \"abc\" }").first);
947 auto program = par.Parse(v);
948 EXPECT_EQ(par.ShowError().err, Error::ErrorType::ERR_NONE);
949 auto pf = AsmEmitter::Emit(program.Value());
950 EXPECT_NE(pf, nullptr);
951 }
952
953 /**
954 * @tc.name: assembly_emitter_test_015
955 * @tc.desc: Verify the AsmEmitter::Emit function.
956 * @tc.type: FUNC
957 * @tc.require: issueNumber
958 */
959 HWTEST_F(AssemblyEmitterTest, assembly_emitter_test_015, TestSize.Level1)
960 {
961 Parser par;
962 auto source = R"(
963 .record R {
964 R[][] f
965 }
966 .function any f(i8 a0) {
967 sta a0
968 }
969 .array array {
970 u1 1
971 }
972 )";
973 std::string source_filename = "source.pa";
974 auto program = par.Parse(source, source_filename);
975 EXPECT_EQ(par.ShowError().err, Error::ErrorType::ERR_NONE);
976
977 panda::pandasm::Type type;
978 ScalarValue insn_order(ScalarValue::Create<panda::pandasm::Value::Type::RECORD>(type));
979 program.Value().record_table.at("R").field_list[0].metadata->SetValue(insn_order);
980
981 auto pf = AsmEmitter::Emit(program.Value());
982 EXPECT_NE(pf, nullptr);
983
984 program.Value().literalarray_table.at("array").literals_[0].tag_ = panda_file::LiteralTag::LITERALARRAY;
985 program.Value().literalarray_table.at("array").literals_[0].value_.emplace<std::string>("array");
986 ScalarValue insn_order_lite(ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>("array"));
987 program.Value().record_table.at("R").field_list[0].metadata->SetValue(insn_order_lite);
988 auto pf1 = AsmEmitter::Emit(program.Value());
989 EXPECT_NE(pf1, nullptr);
990
991 ScalarValue insn_order_enum(ScalarValue::Create<panda::pandasm::Value::Type::ENUM>("R.f"));
992 program.Value().record_table.at("R").field_list[0].metadata->SetValue(insn_order_enum);
993 program.Value().record_table.at("R").field_list[0].metadata->SetAttributeValue("external", "enum");
994 auto pf2 = AsmEmitter::Emit(program.Value());
995 EXPECT_NE(pf2, nullptr);
996
997 ScalarValue insn_order_method(ScalarValue::Create<panda::pandasm::Value::Type::METHOD>("f:(i8)"));
998 program.Value().record_table.at("R").field_list[0].metadata->SetValue(insn_order_method);
999 auto pf3 = AsmEmitter::Emit(program.Value());
1000 EXPECT_NE(pf3, nullptr);
1001
1002 ScalarValue insn_orders(ScalarValue::Create<panda::pandasm::Value::Type::I32>(1));
1003 std::vector<panda::pandasm::ScalarValue> elements;
1004 elements.emplace_back(std::move(insn_orders));
1005
1006 ArrayValue array_value(panda::pandasm::Value::Type::I32, elements);
1007 AnnotationElement anno_element("_TypeOfInstruction", std::make_unique<ArrayValue>(array_value));
1008 AnnotationData annotation("_ESSlotNumberAnnotation");
1009 annotation.AddElement(std::move(anno_element));
1010
1011
1012 ScalarValue insn_order_anno(ScalarValue::Create<panda::pandasm::Value::Type::ANNOTATION>(annotation));
1013
1014 program.Value().record_table.at("R").field_list[0].metadata->SetValue(insn_order_anno);
1015 auto pf4 = AsmEmitter::Emit(program.Value());
1016 EXPECT_NE(pf4, nullptr);
1017
1018 }
1019
1020 /**
1021 * @tc.name: assembly_emitter_test_016
1022 * @tc.desc: Verify the AsmEmitter::Emit function.
1023 * @tc.type: FUNC
1024 * @tc.require: issueNumber
1025 */
1026 HWTEST_F(AssemblyEmitterTest, assembly_emitter_test_016, TestSize.Level1)
1027 {
1028 Parser par;
1029 std::vector<std::vector<panda::pandasm::Token>> v;
1030 Lexer l;
1031 v.push_back(l.TokenizeString(".array array {").first);
1032 v.push_back(l.TokenizeString("u1 1").first);
1033 v.push_back(l.TokenizeString("u8 2").first);
1034 v.push_back(l.TokenizeString("i8 -30").first);
1035 v.push_back(l.TokenizeString("u16 400").first);
1036 v.push_back(l.TokenizeString("i16 -5000").first);
1037 v.push_back(l.TokenizeString("u32 60000").first);
1038 v.push_back(l.TokenizeString("i32 -700000").first);
1039 v.push_back(l.TokenizeString("u64 8000000").first);
1040 v.push_back(l.TokenizeString("i64 -90000000").first);
1041 v.push_back(l.TokenizeString("}").first);
1042 v.push_back(l.TokenizeString(".function any f(i8 a0) { sta a0 }").first);
1043 std::string source_filename = "source.pa";
1044 auto item = par.Parse(v, source_filename);
1045 EXPECT_EQ(par.ShowError().err, Error::ErrorType::ERR_NONE);
1046
1047 item.Value().literalarray_table.at("array").literals_[0].tag_ = panda_file::LiteralTag::BOOL;
1048 item.Value().literalarray_table.at("array").literals_[0].value_.emplace<0>(true);
1049
1050 item.Value().literalarray_table.at("array").literals_[1].tag_ = panda_file::LiteralTag::METHODAFFILIATE;
1051 item.Value().literalarray_table.at("array").literals_[1].value_.emplace<uint16_t>(1);
1052
1053 item.Value().literalarray_table.at("array").literals_[2].tag_ = panda_file::LiteralTag::FLOAT;
1054 item.Value().literalarray_table.at("array").literals_[2].value_.emplace<float>(1.0);
1055
1056 item.Value().literalarray_table.at("array").literals_[3].tag_ = panda_file::LiteralTag::DOUBLE;
1057 item.Value().literalarray_table.at("array").literals_[3].value_.emplace<double>(1.0);
1058
1059 item.Value().literalarray_table.at("array").literals_[4].tag_ = panda_file::LiteralTag::STRING;
1060 item.Value().literalarray_table.at("array").literals_[4].value_.emplace<std::string>("1.0");
1061
1062 item.Value().literalarray_table.at("array").literals_[5].tag_ = panda_file::LiteralTag::ASYNCGENERATORMETHOD;
1063 item.Value().literalarray_table.at("array").literals_[5].value_.emplace<std::string>("f:(i8)");
1064
1065 item.Value().literalarray_table.at("array").literals_[6].tag_ = panda_file::LiteralTag::LITERALARRAY;
1066 item.Value().literalarray_table.at("array").literals_[6].value_.emplace<std::string>("array");
1067
1068 auto pf = AsmEmitter::Emit(item.Value());
1069 EXPECT_NE(pf, nullptr);
1070 }
1071
1072 /**
1073 * @tc.name: assembly_emitter_test_017
1074 * @tc.desc: Verify the AsmEmitter::Emit function.
1075 * @tc.type: FUNC
1076 * @tc.require: issueNumber
1077 */
1078 HWTEST_F(AssemblyEmitterTest, assembly_emitter_test_017, TestSize.Level1)
1079 {
1080 Parser par;
1081 auto source = R"(
1082 .record Asm1 {
1083 i64 asm1
1084 void asm2
1085 i32 asm3
1086 }
1087 )";
1088 std::string source_filename = "source.pa";
1089 auto item = par.Parse(source, source_filename);
1090 EXPECT_EQ(par.ShowError().err, Error::ErrorType::ERR_NONE);
1091
1092 EXPECT_EQ(item.Value().record_table.at("Asm1").name, "Asm1");
1093 EXPECT_EQ(item.Value().record_table.at("Asm1").field_list[0].name, "asm1");
1094 EXPECT_EQ(item.Value().record_table.at("Asm1").field_list[0].type.GetId(), panda::panda_file::Type::TypeId::I64);
1095 EXPECT_EQ(item.Value().record_table.at("Asm1").field_list[1].name, "asm2");
1096 EXPECT_EQ(item.Value().record_table.at("Asm1").field_list[1].type.GetId(), panda::panda_file::Type::TypeId::VOID);
1097 EXPECT_EQ(item.Value().record_table.at("Asm1").field_list[2].name, "asm3");
1098 EXPECT_EQ(item.Value().record_table.at("Asm1").field_list[2].type.GetId(), panda::panda_file::Type::TypeId::I32);
1099
1100 auto pf = AsmEmitter::Emit(item.Value());
1101 EXPECT_NE(pf, nullptr);
1102 }
1103
1104 /**
1105 * @tc.name: assembly_emitter_test_018
1106 * @tc.desc: Verify the AsmEmitter::Emit function.
1107 * @tc.type: FUNC
1108 * @tc.require: issueNumber
1109 */
1110 HWTEST_F(AssemblyEmitterTest, assembly_emitter_test_018, TestSize.Level1)
1111 {
1112 Parser par;
1113 auto source = R"(
1114 .function any f(i8 a0) {
1115 sta a0
1116 }
1117 )";
1118 std::string source_filename = "source.pa";
1119 AsmEmitter::PandaFileToPandaAsmMaps *maps = nullptr;
1120 auto items = panda::panda_file::ItemContainer {};
1121 auto program = par.Parse(source, source_filename);
1122 program.Value().function_table.at("f:(i8)").metadata->SetAttribute("external");
1123 EXPECT_EQ(par.ShowError().err, Error::ErrorType::ERR_NONE);
1124 auto pf = AsmEmitter::Emit(&items, program.Value(), maps, false);
1125 EXPECT_EQ(pf, true);
1126 }
1127
1128 /**
1129 * @tc.name: assembly_emitter_test_019
1130 * @tc.desc: Verify the AsmEmitter::Emit function.
1131 * @tc.type: FUNC
1132 * @tc.require: issueNumber
1133 */
1134 HWTEST_F(AssemblyEmitterTest, assembly_emitter_test_019, TestSize.Level1)
1135 {
1136 Parser par;
1137 auto source = R"(
1138 .function any f(i8 a0) {
1139 sta a0
1140 }
1141 )";
1142 std::string source_filename = "source.pa";
1143
1144 auto program = par.Parse(source, source_filename);
1145 program.Value().function_table.at("f:(i8)").metadata->SetAttribute("external");
1146 panda::pandasm::debuginfo::LocalVariable local;
1147 local.name = "test";
1148 local.signature = "test";
1149 local.signature_type = "test";
1150 program.Value().function_table.at("f:(i8)").local_variable_debug.push_back(local);
1151 EXPECT_EQ(par.ShowError().err, Error::ErrorType::ERR_NONE);
1152 auto success = AsmEmitter::Emit(program.Value());
1153 EXPECT_NE(success, nullptr);
1154 }
1155
1156 /**
1157 * @tc.name: assembly_emitter_test_020
1158 * @tc.desc: Verify the EmitPrograms function.
1159 * @tc.type: FUNC
1160 * @tc.require: issueNumber
1161 */
1162 HWTEST_F(AssemblyEmitterTest, assembly_emitter_test_020, TestSize.Level1)
1163 {
1164 Parser p1;
1165 auto source1 = R"(
1166 .record Test {
1167 any foo
1168 }
1169 )";
1170 Parser p2;
1171 auto source2 = R"(
1172 .function void main() {
1173 ldai 0
1174 ldai 1
1175 return
1176 }
1177 )";
1178 auto res1 = p1.Parse(source1);
1179 EXPECT_EQ(p1.ShowError().err, Error::ErrorType::ERR_NONE);
1180
1181 auto res2 = p2.Parse(source2);
1182 EXPECT_EQ(p2.ShowError().err, Error::ErrorType::ERR_NONE);
1183
1184 std::vector<Program *> progs;
1185 progs.push_back(&res1.Value());
1186 progs.push_back(&res2.Value());
1187 const std::string filename = "source.pa";;
1188 auto success = AsmEmitter::EmitPrograms(filename, progs, true);
1189 EXPECT_TRUE(success);
1190 }
1191 }