hoshi-lang dev
Yet another programming language
Loading...
Searching...
No Matches
visitor.cpp
Go to the documentation of this file.
1//
2// Created by XIaokang00010 on 2024/9/6.
3//
4
5#include "visitor.h"
10#include "compiler/ir/IR.h"
12#include "share/def.hpp"
13#include "share/magic_enum.h"
14#include <algorithm>
15#include <cstdint>
16#include <cstdio>
17#include <exception>
18#include <iterator>
19#include <memory>
20#include <sstream>
21#include <stdexcept>
22#include <string>
23#include <tuple>
24#include <utility>
25#include <vector>
26
27namespace yoi {
28 visitor::visitor(const std::shared_ptr<yoi::moduleContext> &moduleContext,
29 const std::shared_ptr<yoi::IRModule> &irModule,
30 yoi::indexT moduleIndex)
31 : moduleContext(moduleContext), irModule(irModule), currentModuleIndex(moduleIndex) {}
32
33 std::shared_ptr<yoi::IRModule> visitor::visit() {
34 IRDebugInfo debugInfo{irModule->modulePath, 0, 0};
35 auto globInitializer = managedPtr(IRFunctionDefinition{L"yoimiya_glob_initializer",
36 {},
37 moduleContext->getCompilerContext()->getNoneObjectType(),
38 {},
40 debugInfo});
41 irModule->functionTable.put(L"yoimiya_glob_initializer", globInitializer);
43 moduleContext->getIRBuilder().setDebugInfo({irModule->modulePath, 0, 0});
49 return irModule;
50 }
51
53 for (auto &stmt : module->stmts) {
54 visit(stmt);
55 }
56 }
57
59 switch (basicLiterals->node.kind) {
61 moduleContext->getIRBuilder().pushOp(IR::Opcode::push_integer, {IROperand::operandType::integer, basicLiterals->node.basicVal.vInt});
62 break;
63 }
65 moduleContext->getIRBuilder().pushOp(IR::Opcode::push_decimal, {IROperand::operandType::decimal, basicLiterals->node.basicVal.vDeci});
66 break;
67 }
69 auto literalIndex = irModule->stringLiteralPool.addStringLiteral(basicLiterals->node.strVal);
70 moduleContext->getIRBuilder().pushOp(IR::Opcode::push_string, {IROperand::operandType::stringLiteral, literalIndex});
71 break;
72 }
74 moduleContext->getIRBuilder().pushOp(IR::Opcode::push_boolean, {IROperand::operandType::boolean, basicLiterals->node.basicVal.vBool});
75 break;
76 }
78 moduleContext->getIRBuilder().pushOp(IR::Opcode::push_character, {IROperand::operandType::character, basicLiterals->node.strVal[0]});
79 break;
80 }
82 moduleContext->getIRBuilder().pushOp(IR::Opcode::push_short, {IROperand::operandType::shortInt, basicLiterals->node.basicVal.vShort});
83 break;
84 }
86 moduleContext->getIRBuilder().pushOp(IR::Opcode::push_unsigned,
87 {IROperand::operandType::unsignedInt, basicLiterals->node.basicVal.vUint});
88 break;
89 }
91 moduleContext->getIRBuilder().pushOp(IR::Opcode::push_null, {});
92 break;
93 }
94 default: {
95 panic(basicLiterals->node.line, basicLiterals->node.col, "Unexpected basic literal type");
96 break;
97 }
98 }
100 }
101
102 yoi::indexT visitor::visit(yoi::identifier *identifier, bool isStoreOp) {
103 auto &id = identifier->node.strVal;
104 try {
105 auto index = moduleContext->getIRBuilder().irFuncDefinition()->getVariableTable().lookup(id);
106 auto valType = moduleContext->getIRBuilder().irFuncDefinition()->getVariableTable().get(index);
107 if (isStoreOp) {
108 tryCastTo(valType);
109 moduleContext->getIRBuilder().storeOp(IR::Opcode::store_local, {IROperand::operandType::localVar, yoi::indexT{index}});
110 } else {
111 moduleContext->getIRBuilder().loadOp(IR::Opcode::load_local, {IROperand::operandType::localVar, yoi::indexT{index}}, valType);
112 }
114 } catch (std::out_of_range &e) {
115 // let it go, try to find it in global variables
116 }
117 try {
118 auto index = irModule->globalVariables.getIndex(id);
119 auto valType = irModule->globalVariables[index];
120 if (isStoreOp) {
121 tryCastTo(valType);
122 moduleContext->getIRBuilder().storeOp(IR::Opcode::store_global, {IROperand::operandType::globalVar, yoi::indexT{index}});
123 } else {
124 moduleContext->getIRBuilder().loadOp(IR::Opcode::load_global, {IROperand::operandType::globalVar, yoi::indexT{index}}, valType);
125 }
127 } catch (std::out_of_range &e) {
128 panic(identifier->node.line, identifier->node.col, "Undefined identifier: " + wstring2string(id));
129 return 0;
130 }
131 }
132
133 yoi::indexT visitor::visit(yoi::primary *primary, bool isStoreOp) {
134 switch (primary->kind) {
135 case primary::primaryKind::memberExpr:
136 visit(primary->member, isStoreOp);
137 break;
138 case primary::primaryKind::basicLiterals:
139 visit(primary->literals);
140 break;
141 case primary::primaryKind::rExpr:
142 visit(primary->expr);
143 break;
144 case primary::primaryKind::typeIdExpression: {
145 visit(primary->typeId);
146 break;
147 }
148 case primary::primaryKind::dynCastExpression: {
149 visit(primary->dynCast);
150 break;
151 }
152 case primary::primaryKind::newExpression: {
153 visit(primary->newExpr);
154 break;
155 }
156 case primary::primaryKind::lambdaExpr: {
157 auto lambdaStructIndex = createLambdaUnnamedStruct(primary->lambda);
158 auto [lambdaCallableIndex, callableInterface] =
159 createCallableImplementationForLambda(irModule->structTable[lambdaStructIndex], lambdaStructIndex, currentModuleIndex);
160 // moduleContext->getIRBuilder().newInterfaceOp(callableInterface.second, true, callableInterface.first);
161 moduleContext->getIRBuilder().constructInterfaceImplOp(callableInterface, lambdaCallableIndex);
162 break;
163 }
164 case primary::primaryKind::funcExpr: {
165 visit(primary->func);
166 break;
167 }
168 case primary::primaryKind::bracedInitalizerList: {
170 break;
171 }
172 default: {
173 panic(primary->getLine(), primary->getColumn(), "Unexpected primary type");
174 }
175 }
176
178 }
179
180 yoi::indexT visitor::visit(yoi::abstractExpr *abstractExpr, bool isStoreOp) {
181 if (abstractExpr->rhs) {
182 yoi_assert(!isStoreOp, abstractExpr->getLine(), abstractExpr->getColumn(), "trying to apply store op on a boolean expression");
184 visit(abstractExpr->lhs);
186 auto rhs = parseTypeSpec(abstractExpr->rhs);
187
188 if (abstractExpr->op.kind == lexer::token::tokenKind::kImpl) {
189 yoi_assert(rhs.type == IRValueType::valueType::interfaceObject,
192 "RHS of 'impl' operator must be an interface type");
193 auto interfaceImplName = getInterfaceImplName({rhs.typeAffiliateModule, rhs.typeIndex}, lhs);
195 // push the boolean
197 ->getImportedModule(lhs->typeAffiliateModule)
198 ->interfaceImplementationTable.contains(interfaceImplName)) {
199 moduleContext->getIRBuilder().pushOp(IR::Opcode::push_boolean, {IROperand::operandType::boolean, IROperand::operandValue{true}});
200 } else {
201 moduleContext->getIRBuilder().pushOp(IR::Opcode::push_boolean, {IROperand::operandType::boolean, IROperand::operandValue{false}});
202 }
203 } else if (abstractExpr->op.kind == lexer::token::tokenKind::kInterfaceOf) {
204 yoi_assert(lhs->type == IRValueType::valueType::interfaceObject,
207 "LHS of 'interfaceof' operator must be an interface type");
208 // cut off some possibilies here.
209 auto key = std::make_tuple(rhs.type, rhs.typeAffiliateModule, rhs.typeIndex);
210 auto &vec =
211 moduleContext->getCompilerContext()->getImportedModule(lhs->typeAffiliateModule)->interfaceTable[lhs->typeIndex]->implementations;
212 if (std::find(vec.begin(), vec.end(), key) != vec.end()) {
213 // emit typeid op and emit interfaceof
217 } else {
218 // push the boolean
220 moduleContext->getIRBuilder().pushOp(IR::Opcode::push_boolean, {IROperand::operandType::boolean, IROperand::operandValue{false}});
221 }
222 } else if (abstractExpr->op.kind == lexer::token::tokenKind::kAs) {
224 auto typeSpec = managedPtr(rhs);
225 tryCastTo(typeSpec);
226 }
228 } else {
229 return visit(abstractExpr->lhs, isStoreOp);
230 }
231 }
232
233 yoi::indexT visitor::visit(yoi::uniqueExpr *uniqueExpr, bool isStoreOp) {
234 visit(uniqueExpr->lhs, isStoreOp);
235
236 switch (uniqueExpr->getOp().kind) {
237 case lexer::token::tokenKind::incrementSign: {
238 // TODO: add support for operator overloading
240
241 if (lhs->isBasicType()) {
242 moduleContext->getIRBuilder().uniqueArithmeticOp(IR::Opcode::increment);
243 } else {
244 handleUnaryOperatorOverload(L"operator++");
245 }
246 break;
247 }
248 case lexer::token::tokenKind::decrementSign: {
249 // TODO: add support for operator overloading
251 if (lhs->isBasicType()) {
252 moduleContext->getIRBuilder().uniqueArithmeticOp(IR::Opcode::decrement);
253 } else {
254 handleUnaryOperatorOverload(L"operator--");
255 }
256 break;
257 }
258 case lexer::token::tokenKind::binaryNot: {
259 // TODO: add support for operator overloading
261 if (lhs->isBasicType()) {
262 moduleContext->getIRBuilder().uniqueArithmeticOp(IR::Opcode::bitwise_not);
263 } else {
264 handleUnaryOperatorOverload(L"operator~");
265 }
266 break;
267 }
268 case lexer::token::tokenKind::minus: {
270 if (lhs->isBasicType()) {
271 moduleContext->getIRBuilder().uniqueArithmeticOp(IR::Opcode::negate);
272 } else {
273 handleUnaryOperatorOverload(L"operator-");
274 }
275 break;
276 }
277 case lexer::token::tokenKind::unknown: {
278 // means no op
279 break;
280 }
281 default: {
282 panic(uniqueExpr->getOp().line, uniqueExpr->getOp().col, "Unexpected unique expression operator");
283 }
284 }
286 }
287
289 if (leftExpr->hasRhs()) {
290 switch (leftExpr->getOp().kind) {
291 case lexer::token::tokenKind::assignSign: {
292 visit(leftExpr->rhs);
293 visit(leftExpr->lhs, true);
294 visit(leftExpr->lhs);
295 break;
296 }
297 case lexer::token::tokenKind::directAssignSign: {
298 auto lhsPos = visit(leftExpr->lhs);
299 auto rhsPos = visit(leftExpr->rhs);
301 tryCastTo(lhs);
302 moduleContext->getIRBuilder().insert({IR::Opcode::direct_assign, {}, moduleContext->getIRBuilder().getCurrentDebugInfo()});
306 break;
307 }
308 case lexer::token::tokenKind::additionAssignment: {
309 auto lhsPos = visit(leftExpr->lhs);
311 auto rhsPos = visit(leftExpr->rhs);
314
315 if (lhs->isBasicType() && rhs->isBasicType()) {
316 tryCastTo(lhs);
317 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::add);
318 visit(leftExpr->lhs, true);
319 visit(leftExpr->lhs);
321 } else {
322 handleBinaryOperatorOverload(L"operator+=", leftExpr->rhs);
323 }
324 break;
325 }
326 case lexer::token::tokenKind::subtractionAssignment: {
327 auto lhsPos = visit(leftExpr->lhs);
329 auto rhsPos = visit(leftExpr->rhs);
332 if (lhs->isBasicType() && rhs->isBasicType()) {
333 tryCastTo(lhs);
334 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::sub);
335 visit(leftExpr->lhs, true);
336 visit(leftExpr->lhs);
338 } else {
339 handleBinaryOperatorOverload(L"operator-=", leftExpr->rhs);
340 }
341 break;
342 }
343 case lexer::token::tokenKind::multiplicationAssignment: {
344 auto lhsPos = visit(leftExpr->lhs);
346 auto rhsPos = visit(leftExpr->rhs);
349 if (lhs->isBasicType() && rhs->isBasicType()) {
350 tryCastTo(lhs);
351 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::mul);
352 visit(leftExpr->lhs, true);
353 visit(leftExpr->lhs);
355 } else {
356 handleBinaryOperatorOverload(L"operator*=", leftExpr->rhs);
357 }
358 break;
359 }
360 case lexer::token::tokenKind::divisionAssignment: {
361 auto lhsPos = visit(leftExpr->lhs);
363 auto rhsPos = visit(leftExpr->rhs);
366 if (lhs->isBasicType() && rhs->isBasicType()) {
367 tryCastTo(lhs);
368 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::div);
369 visit(leftExpr->lhs, true);
370 visit(leftExpr->lhs);
372 } else {
373 handleBinaryOperatorOverload(L"operator/=", leftExpr->rhs);
374 }
375 break;
376 }
377 default: {
379 leftExpr->getOp().col,
380 "Unexpected left expression operator, received: " + wstring2string(leftExpr->getOp().strVal));
381 }
382 }
383 } else {
384 visit(leftExpr->lhs);
385 }
386
388 }
389
391 auto term = mulExpr->getTerms().begin();
392 auto op = mulExpr->getOp().begin();
393 auto lhsPos = visit(*term); // lhs
394 for (; op != mulExpr->getOp().end(); ++op) {
396 auto rhsPos = visit(*++term); // rhs
399
400 if (lhsType->isBasicType() && rhsType->isBasicType()) {
401 switch (op->kind) {
402 case lexer::token::tokenKind::asterisk:
403 emitBasicCastInBasicArithOpByLhsAndRhs(lhsPos, rhsPos);
404 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::mul);
405 break;
406 case lexer::token::tokenKind::slash:
407 emitBasicCastInBasicArithOpByLhsAndRhs(lhsPos, rhsPos);
408 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::div);
409 break;
410 case lexer::token::tokenKind::percentSign:
411 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::mod);
412 break;
413 default:
414 panic(op->line, op->col, "Unexpected multiplication expression operator");
415 }
417 } else {
418 switch (op->kind) {
419 case lexer::token::tokenKind::asterisk:
420 handleBinaryOperatorOverload(L"operator*", *term);
421 break;
422 case lexer::token::tokenKind::slash:
423 handleBinaryOperatorOverload(L"operator/", *term);
424 break;
425 case lexer::token::tokenKind::percentSign:
426 handleBinaryOperatorOverload(L"operator%", *term);
427 break;
428 default:
429 panic(op->line, op->col, "Unexpected multiplication expression operator");
430 }
431 }
432
434 }
436 }
437
439 auto term = addExpr->getTerms().begin();
440 auto op = addExpr->getOp().begin();
441 auto lhsPos = visit(*term);
442 for (; op != addExpr->getOp().end(); ++op) {
444 auto rhsPos = visit(*++term);
447
448 if (lhsType->isBasicType() && rhsType->isBasicType()) {
449 switch (op->kind) {
450 case lexer::token::tokenKind::plus:
451 emitBasicCastInBasicArithOpByLhsAndRhs(lhsPos, rhsPos);
452 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::add);
453 break;
454 case lexer::token::tokenKind::minus:
455 emitBasicCastInBasicArithOpByLhsAndRhs(lhsPos, rhsPos);
456 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::sub);
457 break;
458 default:
459 panic(op->line, op->col, "Unexpected addition expression operator");
460 }
462 } else {
463 switch (op->kind) {
464 case lexer::token::tokenKind::plus:
465 handleBinaryOperatorOverload(L"operator+", *term);
466 break;
467 case lexer::token::tokenKind::minus:
468 handleBinaryOperatorOverload(L"operator-", *term);
469 break;
470 default:
471 panic(op->line, op->col, "Unexpected addition expression operator");
472 }
473 }
475 }
477 }
478
480 auto term = shiftExpr->getTerms().begin();
481 auto op = shiftExpr->getOp().begin();
482 visit(*term);
483 for (; op != shiftExpr->getOp().end(); ++op) {
485
486 emitBasicCastTo(moduleContext->getCompilerContext()->getIntObjectType());
487
488 visit(*++term);
489
490 emitBasicCastTo(moduleContext->getCompilerContext()->getIntObjectType());
491
494
495 if (lhsType->isBasicType() && rhsType->type == IRValueType::valueType::integerObject) {
496 switch (op->kind) {
497 case lexer::token::tokenKind::binaryShiftLeft:
498 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::left_shift);
499 break;
500 case lexer::token::tokenKind::binaryShiftRight:
501 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::right_shift);
502 break;
503 default:
504 panic(op->line, op->col, "Unexpected shift expression operator");
505 break;
506 }
508 } else {
509 switch (op->kind) {
510 case lexer::token::tokenKind::binaryShiftLeft:
511 handleBinaryOperatorOverload(L"operator<<", *term);
512 break;
513 case lexer::token::tokenKind::binaryShiftRight:
514 handleBinaryOperatorOverload(L"operator>>", *term);
515 break;
516 default:
517 panic(op->line, op->col, "Unexpected shift expression operator");
518 break;
519 }
520 }
521 }
523 }
524
526 auto term = relationalExpr->getTerms().begin();
527 auto op = relationalExpr->getOp().begin();
528 auto lhsPos = visit(*term);
529 for (; op != relationalExpr->getOp().end(); ++op) {
531 auto rhsPos = visit(*++term);
534
535 if (lhsType->isBasicType() && rhsType->isBasicType()) {
536 switch (op->kind) {
537 case lexer::token::tokenKind::lessThan:
538 emitBasicCastInBasicArithOpByLhsAndRhs(lhsPos, rhsPos);
539 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::less_than);
540 break;
541 case lexer::token::tokenKind::greaterThan:
542 emitBasicCastInBasicArithOpByLhsAndRhs(lhsPos, rhsPos);
543 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::greater_than);
544 break;
545 case lexer::token::tokenKind::lessEqual:
546 emitBasicCastInBasicArithOpByLhsAndRhs(lhsPos, rhsPos);
547 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::less_equal);
548 break;
549 case lexer::token::tokenKind::greaterEqual:
550 emitBasicCastInBasicArithOpByLhsAndRhs(lhsPos, rhsPos);
551 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::greater_equal);
552 break;
553 default:
554 panic(op->line, op->col, "Unexpected relational expression operator");
555 }
557 } else {
558 switch (op->kind) {
559 case lexer::token::tokenKind::lessThan:
560 handleBinaryOperatorOverload(L"operator<", *term);
561 break;
562 case lexer::token::tokenKind::greaterThan:
563 handleBinaryOperatorOverload(L"operator>", *term);
564 break;
565 case lexer::token::tokenKind::lessEqual:
566 handleBinaryOperatorOverload(L"operator<=", *term);
567 break;
568 case lexer::token::tokenKind::greaterEqual:
569 handleBinaryOperatorOverload(L"operator>=", *term);
570 break;
571 default:
572 panic(op->line, op->col, "Unexpected relational expression operator");
573 }
574 }
575 lhsPos = rhsPos;
576 }
577
579 }
580
582 auto term = equalityExpr->getTerms().begin();
583 auto op = equalityExpr->getOp().begin();
584 auto lhsPos = visit(*term);
585 for (; op != equalityExpr->getOp().end(); ++op) {
587 auto rhsPos = visit(*++term);
590
591 if (lhsType->isBasicType() && rhsType->isBasicType() || lhsType->type == IRValueType::valueType::pointerObject ||
592 rhsType->type == IRValueType::valueType::pointerObject) {
593 switch (op->kind) {
594 case lexer::token::tokenKind::equal:
595 emitBasicCastInBasicArithOpByLhsAndRhs(lhsPos, rhsPos);
596 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::equal);
597 break;
598 case lexer::token::tokenKind::notEqual:
599 emitBasicCastInBasicArithOpByLhsAndRhs(lhsPos, rhsPos);
600 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::not_equal);
601 break;
602 default:
603 panic(op->line, op->col, "Unexpected equality expression operator");
604 return {};
605 }
607 } else {
608 switch (op->kind) {
609 case lexer::token::tokenKind::equal:
610 handleBinaryOperatorOverload(L"operator==", *term);
611 break;
612 case lexer::token::tokenKind::notEqual:
613 handleBinaryOperatorOverload(L"operator!=", *term);
614 break;
615 default:
616 panic(op->line, op->col, "Unexpected equality expression operator");
617 return {};
618 }
619 }
620 lhsPos = rhsPos;
621 }
623 }
624
626 auto term = andExpr->getTerms().begin();
627 auto op = andExpr->getOp().begin();
628 auto lhsPos = visit(*term);
629 for (; op != andExpr->getOp().end(); ++op) {
631 auto rhsPos = visit(*++term);
634
635 if (lhsType->isBasicType() && rhsType->isBasicType()) {
636 switch (op->kind) {
637 case lexer::token::tokenKind::binaryAnd: {
638 if (lhsType->isBasicType() && lhsType->type != IRValueType::valueType::integerObject) {
639 moduleContext->getIRBuilder().basicCast(moduleContext->getCompilerContext()->getIntObjectType(), lhsPos, true);
640 }
641 if (rhsType->isBasicType() && rhsType->type != IRValueType::valueType::integerObject) {
642 moduleContext->getIRBuilder().basicCast(moduleContext->getCompilerContext()->getIntObjectType(), rhsPos);
643 }
644
645 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::bitwise_and);
646 break;
647 }
648 default: {
649 panic(op->line, op->col, "Unexpected and expression operator");
650 return {};
651 }
652 }
654 } else {
655 switch (op->kind) {
656 case lexer::token::tokenKind::binaryAnd: {
657 handleBinaryOperatorOverload(L"operator&", *term);
658 break;
659 }
660 default: {
661 panic(op->line, op->col, "Unexpected and expression operator");
662 return {};
663 }
664 }
665 }
666
667 lhsPos = rhsPos;
668 }
670 }
671
673 auto term = exclusiveExpr->getTerms().begin();
674 auto op = exclusiveExpr->getOp().begin();
675 auto lhs = visit(*term);
676 for (; op != exclusiveExpr->getOp().end(); ++op) {
678 auto rhs = visit(*++term);
681
682 if (lhsType->isBasicType() && rhsType->isBasicType()) {
683 switch (op->kind) {
684 case lexer::token::tokenKind::binaryXor: {
685 if (lhsType->isBasicType() && lhsType->type != IRValueType::valueType::integerObject) {
686 moduleContext->getIRBuilder().basicCast((moduleContext->getCompilerContext()->getIntObjectType()), lhs, true);
687 }
688 if (rhsType->isBasicType() && rhsType->type != IRValueType::valueType::integerObject) {
689 moduleContext->getIRBuilder().basicCast((moduleContext->getCompilerContext()->getIntObjectType()), rhs);
690 }
691
692 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::bitwise_xor);
693 break;
694 }
695 default: {
696 panic(op->line, op->col, "Unexpected exclusive expression operator");
697 return {};
698 }
699 }
701 } else {
702 switch (op->kind) {
703 case lexer::token::tokenKind::binaryXor: {
704 handleBinaryOperatorOverload(L"operator^", *term);
705 break;
706 }
707 default: {
708 panic(op->line, op->col, "Unexpected exclusive expression operator");
709 }
710 }
711 }
712 lhs = rhs;
713 }
715 }
716
718 auto term = inclusiveExpr->getTerms().begin();
719 auto op = inclusiveExpr->getOp().begin();
720 auto lhs = visit(*term);
721 for (; op != inclusiveExpr->getOp().end(); ++op) {
722 auto rhs = visit(*++term);
725
726 if (lhsType->isBasicType() && rhsType->isBasicType()) {
727 switch (op->kind) {
728 case lexer::token::tokenKind::binaryOr: {
729 if (lhsType->isBasicType() && lhsType->type != IRValueType::valueType::integerObject) {
730 moduleContext->getIRBuilder().basicCast((moduleContext->getCompilerContext()->getIntObjectType()), lhs, true);
731 }
732 if (rhsType->isBasicType() && rhsType->type != IRValueType::valueType::integerObject) {
733 moduleContext->getIRBuilder().basicCast((moduleContext->getCompilerContext()->getIntObjectType()), rhs);
734 }
735
736 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::bitwise_or);
737 break;
738 }
739 default: {
740 panic(op->line, op->col, "Unexpected inclusive expression operator");
741 return {};
742 }
743 }
744 } else {
745 switch (op->kind) {
746 case lexer::token::tokenKind::binaryOr: {
747 handleBinaryOperatorOverload(L"operator|", *term);
748 break;
749 }
750 default: {
751 panic(op->line, op->col, "Unexpected inclusive expression operator");
752 return {};
753 }
754 }
755 }
756 lhs = rhs;
757 }
758
760 }
761
763 if (logicalAndExpr->getOp().empty()) {
764 return visit(logicalAndExpr->getTerms().front());
765 }
766
767 auto finalFalseBlock = moduleContext->getIRBuilder().createCodeBlock();
768 auto endBlock = moduleContext->getIRBuilder().createCodeBlock();
769 auto terms = logicalAndExpr->getTerms().begin();
770 auto ops = logicalAndExpr->getOp().begin();
771
772 visit(*terms);
774 if (termType->type != IRValueType::valueType::booleanObject) {
775 moduleContext->getIRBuilder().basicCast(moduleContext->getCompilerContext()->getBoolObjectType(), {}, true);
776 }
777
778 for (; ops != logicalAndExpr->getOp().end(); ++ops) {
779 auto nextTermBlock = moduleContext->getIRBuilder().createCodeBlock();
780
781 moduleContext->getIRBuilder().jumpIfOp(IR::Opcode::jump_if_false, finalFalseBlock);
782 moduleContext->getIRBuilder().jumpOp(nextTermBlock);
783
785 visit(*++terms);
786
788 if (termType->type != IRValueType::valueType::booleanObject) {
789 moduleContext->getIRBuilder().basicCast(moduleContext->getCompilerContext()->getBoolObjectType(), {}, true);
790 }
791 }
792
793 moduleContext->getIRBuilder().jumpOp(endBlock);
794
795 moduleContext->getIRBuilder().switchCodeBlock(finalFalseBlock);
796 moduleContext->getIRBuilder().insert({IR::Opcode::push_boolean,
797 {{IROperand::operandType::boolean, IROperand::operandValue{false}}},
798 moduleContext->getIRBuilder().getCurrentDebugInfo()});
799 moduleContext->getIRBuilder().jumpOp(endBlock);
800
802
804 }
805
807 auto term = logicalOrExpr->getTerms().begin();
808 auto op = logicalOrExpr->getOp().begin();
809 auto lhs = visit(*term);
810 // The type of the first term on the left
812
813 // Loop through chained operators, e.g., a || b || c
814 for (; op != logicalOrExpr->getOp().end(); ++op) {
815 auto nextConditionBlock = moduleContext->getIRBuilder().createCodeBlock();
816 auto exitWithTrueBlock = moduleContext->getIRBuilder().createCodeBlock();
817 auto exitWithFalseBlock = moduleContext->getIRBuilder().createCodeBlock();
818 auto exitBlock = moduleContext->getIRBuilder().createCodeBlock();
819
821 .getCodeBlock(exitWithTrueBlock)
822 .insert({IR::Opcode::push_boolean, {{IROperand::operandType::boolean, true}}, moduleContext->getIRBuilder().getCurrentDebugInfo()});
824 .getCodeBlock(exitWithTrueBlock)
825 .insert({IR::Opcode::jump,
826 {IROperand{IROperand::operandType::codeBlock, exitBlock}},
827 moduleContext->getIRBuilder().getCurrentDebugInfo()});
828
830 .getCodeBlock(exitWithFalseBlock)
831 .insert({IR::Opcode::push_boolean,
832 {IROperand{IROperand::operandType::boolean, IROperand::operandValue{false}}},
833 moduleContext->getIRBuilder().getCurrentDebugInfo()});
835 .getCodeBlock(exitWithFalseBlock)
836 .insert({IR::Opcode::jump, {{IROperand::operandType::codeBlock, exitBlock}}, moduleContext->getIRBuilder().getCurrentDebugInfo()});
837
838 switch (op->kind) {
839 case lexer::token::tokenKind::logicOr: {
840 yoi_assert(lhsType->isBasicType(), op->line, op->col, "Not basic type for logical or");
841 if (lhsType->type != IRValueType::valueType::booleanObject) {
842 moduleContext->getIRBuilder().basicCast((moduleContext->getCompilerContext()->getBoolObjectType()), lhs, true);
843 }
844
845 // Short-circuit if the LHS (or intermediate result) is true
846 moduleContext->getIRBuilder().jumpIfOp(IR::Opcode::jump_if_true, exitWithTrueBlock);
847 moduleContext->getIRBuilder().jumpOp(nextConditionBlock);
848 moduleContext->getIRBuilder().switchCodeBlock(nextConditionBlock);
849
850 // If not short-circuited, evaluate the RHS
851 auto rhs = visit(*++term);
853 yoi_assert(rhsType->isBasicType(), op->line, op->col, "Not basic type for logical or");
854 if (rhsType->type != IRValueType::valueType::booleanObject) {
855 moduleContext->getIRBuilder().basicCast((moduleContext->getCompilerContext()->getBoolObjectType()), rhs);
856 }
857
858 // The result of the expression is now on the stack
859 moduleContext->getIRBuilder().jumpIfOp(IR::Opcode::jump_if_true, exitWithTrueBlock);
860 moduleContext->getIRBuilder().jumpOp(exitWithFalseBlock);
862
863 lhsType = moduleContext->getCompilerContext()->getBoolObjectType();
864 // same as before
866 break;
867 }
868 default: {
869 panic(op->line, op->col, "Unexpected logical or expression operator");
870 return {};
871 }
872 }
873 }
874
875 if (!logicalOrExpr->getOp().empty()) {
876 // not single term, push a boolean result onto the stack
878 }
879
881 }
882
883 yoi::indexT visitor::visit(yoi::rExpr *rExpr) {
884 return visit(&rExpr->getExpr());
885 }
886
887 void visitor::visit(yoi::codeBlock *codeBlock, bool notEmitNewBlockInstruction) {
888 if (!notEmitNewBlockInstruction) {
892 }
893 moduleContext->getIRBuilder().irFuncDefinition()->getVariableTable().createScope();
894 for (auto stmt : codeBlock->getStmts()) {
895 visit(stmt);
896 }
897 moduleContext->getIRBuilder().irFuncDefinition()->getVariableTable().popScope();
898 }
899
900 yoi::indexT visitor::visit(yoi::memberExpr *memberExpr, bool isStoreOp) {
901 // take a snapshot for builder state
902 auto snapshotIndex = moduleContext->getIRBuilder().saveState();
903
904 auto it = memberExpr->getTerms().begin();
905 yoi::indexT targetModule = -1, lastModule = -1;
906 // 1. Resolve module prefixes (e.g., std::io)
907 while (it + 1 != memberExpr->getTerms().end() && (targetModule = isModuleName((*it)->id, lastModule)) != lastModule) {
908 it++;
909 lastModule = targetModule;
910 }
911
912 // 2. Handle enumerations
913 if (it + 2 == memberExpr->getTerms().end()) {
914 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(targetModule == -1 ? currentModuleIndex : targetModule);
915 if ((*it)->isIdentifier() && !(*it)->id->hasTemplateArg() && (*(it + 1))->isIdentifier() && !(*(it + 1))->id->hasTemplateArg() &&
916 targetedModule->enumerationTable.contains((*it)->id->id->node.strVal)) {
917 try {
918 auto v = targetedModule->enumerationTable[(*it)->id->id->node.strVal]->valueToIndexMap[(*(it + 1))->id->id->node.strVal];
919 IR::Opcode op = IR::Opcode::push_character;
920 IROperand operand;
921 switch (targetedModule->enumerationTable[(*it)->id->id->node.strVal]->getUnderlyingType()) {
922 case IREnumerationType::UnderlyingType::I8: {
923 op = IR::Opcode::push_character;
924 operand = {IROperand::operandType::character, (yoi::wchar)v};
925 break;
926 }
927 case IREnumerationType::UnderlyingType::I16: {
928 op = IR::Opcode::push_short;
929 operand = {IROperand::operandType::character, (short)v};
930 break;
931 }
932 case IREnumerationType::UnderlyingType::I64: {
933 op = IR::Opcode::push_unsigned;
934 operand = {IROperand::operandType::unsignedInt, (yoi::indexT)v};
935 break;
936 }
937 }
938 moduleContext->getIRBuilder().pushOp(op, {operand});
939
942 } catch (std::out_of_range &e) {
943 panic((*(it + 1))->getLine(),
944 (*(it + 1))->getColumn(),
945 "Enumeration value not found: " + yoi::wstring2string((*(it + 1))->id->id->node.strVal));
946 }
947 }
948 }
949
950 // 3. Handle static method calls (e.g., MyType::staticFunc())
951 // This is a special case where the base is a type name, not an instance.
952 std::shared_ptr<IRValueType> staticTypeBase{};
953 try {
954 if (it + 1 != memberExpr->getTerms().end()) {
955 staticTypeBase = managedPtr(parseTypeSpecExtern(*it, targetModule == -1 ? currentModuleIndex : targetModule));
956 }
957 } catch (std::runtime_error &) {
958 // Not a type name, so it's an instance member expression.
959 } catch (std::out_of_range &) {
960 // Not a type name, so it's an instance member expression.
961 }
962
963 if (staticTypeBase) {
964 auto memberNameNode = *(++it);
965 yoi_assert(!memberNameNode->getSubscript().empty() && memberNameNode->getSubscript().front()->isInvocation(),
966 memberNameNode->getLine(),
967 memberNameNode->getColumn(),
968 "Static member access must be a method call.");
969 auto &invocation = memberNameNode->getSubscript().front();
970
971 switch (staticTypeBase->type) {
972 case IRValueType::valueType::structObject: {
973 if (!handleInvocationExtern(
974 memberNameNode->id->getId().node.strVal, invocation->args, staticTypeBase->typeAffiliateModule, staticTypeBase, true,
975 memberNameNode->id->hasTemplateArg() ? &memberNameNode->id->getArg() : nullptr))
976 panic(memberNameNode->getLine(),
977 memberNameNode->getColumn(),
978 "No matching static method found for: " + wstring2string(memberNameNode->id->getId().get().strVal));
979 // After a static call, subsequent member accesses operate on its return value.
980 break;
981 }
982 case IRValueType::valueType::datastructObject: {
983 constructDataStruct(staticTypeBase->typeIndex, staticTypeBase->typeAffiliateModule, invocation->args);
984 break;
985 }
986 default:
987 panic(memberNameNode->getLine(),
988 memberNameNode->getColumn(),
989 "Static member access must be a method call.");
990 }
991 } else {
992 // 3. It's an instance member expression. Visit the base instance.
993 bool isFinalTerm = (it + 1 == memberExpr->getTerms().end());
994 if (targetModule == -1) {
995 visit(*it, isStoreOp && isFinalTerm);
996 } else {
997 visitExtern(*it, targetModule, isStoreOp && isFinalTerm);
998 }
999 }
1000
1001 // 4. Loop through the rest of the terms (.b, .c(), .d[i], etc.)
1002 yoi::vec<IROperand> accessors;
1003 for (it++; it != memberExpr->getTerms().end(); it++) {
1004 if (it == memberExpr->getTerms().end()) {
1005 break;
1006 }
1007
1008 auto currentTermNode = *it;
1009 bool isFinalTerm = (std::next(it) == memberExpr->getTerms().end());
1010
1011 // The type of the object we are operating on (result of the previous term)
1012 auto objectType = moduleContext->getIRBuilder().getRhsFromTempVarStack();
1013 // only when it is a data struct, we need to handle the accessors
1014
1015 // A. Handle the base of the current term (the identifier itself).
1016 // It's either a field access or a method name.
1017 if (currentTermNode->getSubscript().empty()) {
1018 // Case: Simple field access like `obj.field`
1019 if (objectType->isArrayType() || objectType->isDynamicArrayType()) {
1020 if (currentTermNode->id->getId().get().strVal == L"length") {
1022 } else {
1023 panic(currentTermNode->getLine(), currentTermNode->getColumn(), "Only 'length' member is valid on array types.");
1024 }
1025 } else if (objectType->type == IRValueType::valueType::structObject) {
1026 auto structDef =
1027 moduleContext->getCompilerContext()->getImportedModule(objectType->typeAffiliateModule)->structTable[objectType->typeIndex];
1028 auto &memberName = currentTermNode->id->getId().get().strVal;
1029 bool isResolved = false;
1030 try {
1031 auto nameInfo = structDef->lookupName(memberName);
1032 if (nameInfo.type != IRStructDefinition::nameInfo::nameType::field) {
1033 panic(currentTermNode->getLine(),
1034 currentTermNode->getColumn(),
1035 "Cannot access method '" + wstring2string(memberName) + "' as a field.");
1036 }
1037 auto fieldType = structDef->fieldTypes[nameInfo.index];
1038
1039 // A store operation can only happen on the very last term of the expression.
1040 if (isStoreOp && isFinalTerm) {
1042 tryCastTo(fieldType);
1044 moduleContext->getIRBuilder().storeMemberOp({IROperand::operandType::index, nameInfo.index});
1045 } else {
1046 moduleContext->getIRBuilder().loadMemberOp({IROperand::operandType::index, nameInfo.index}, fieldType);
1047 }
1048 isResolved = true;
1049 } catch (std::out_of_range &) {
1050 // ignore
1051 }
1052 // now we attempt to resolve it as a method, check whether it is a method name
1053 if (auto methodName = structDef->name + L"::" + memberName; !isResolved && moduleContext->getCompilerContext()->getImportedModule(objectType->typeAffiliateModule)->functionOverloadIndexies.contains(methodName)) {
1054 // exists
1055 auto &funcIndexies = moduleContext->getCompilerContext()->getImportedModule(objectType->typeAffiliateModule)->functionOverloadIndexies[methodName];
1056 yoi_assert(funcIndexies.size() == 1, (*it)->getLine(), (*it)->getColumn(), "Multiple overloads found for method: " + wstring2string(methodName));
1057 auto funcDef = moduleContext->getCompilerContext()->getImportedModule(objectType->typeAffiliateModule)->functionTable[funcIndexies.front()];
1058 auto impl = createCallableImplementationForFunction(funcDef, funcIndexies.front(), objectType->typeAffiliateModule, true);
1059 createCallableInstanceForFunction(impl.first, impl.second, objectType->typeAffiliateModule, true);
1060 isResolved = true;
1061 }
1062 yoi_assert(isResolved, currentTermNode->getLine(), currentTermNode->getColumn(), "Member access on unknown struct fields or methods: " + wstring2string(currentTermNode->id->getId().get().strVal));
1063 } else if (objectType->type == IRValueType::valueType::datastructObject) {
1064 auto structDef = moduleContext->getCompilerContext()->getImportedModule(objectType->typeAffiliateModule)->dataStructTable[objectType->typeIndex];
1065 yoi_assert(structDef->fields.contains(currentTermNode->id->getId().get().strVal), currentTermNode->getLine(), currentTermNode->getColumn(), "Member access on unknown data struct fields or methods: " + wstring2string(currentTermNode->id->getId().get().strVal));
1066 auto fieldIndex = structDef->fields[currentTermNode->id->getId().get().strVal];
1067 if (accessors.empty()) {
1068 moduleContext->getIRBuilder().pushTempVar(structDef->fieldTypes[fieldIndex]);
1069 } else {
1071 moduleContext->getIRBuilder().pushTempVar(structDef->fieldTypes[fieldIndex]);
1072 }
1073 accessors.emplace_back(IROperand::operandType::index, fieldIndex);
1074
1075 if (isFinalTerm) {
1078 if (isStoreOp) {
1080 tryCastTo(fieldType);
1083 } else {
1084 moduleContext->getIRBuilder().loadFieldOp(accessors, fieldType);
1085 accessors.clear();
1086 }
1087 }
1088 } else {
1089 panic(
1090 currentTermNode->getLine(), currentTermNode->getColumn(), "Member access on a non-struct or non-array type is not allowed.");
1091 }
1092 } else {
1093 // Case: Field access followed by operations `obj.field[i]()`, or a method call `obj.method()`
1094 // We need to resolve if the identifier is a field or method. We prioritize method calls.
1095 auto firstOp = currentTermNode->getSubscript().front();
1096 bool isMethodCall = firstOp->isInvocation();
1097
1098 if (isMethodCall) {
1099 if (objectType->type == IRValueType::valueType::structObject) {
1100 bool isResolved = false;
1101
1102 isResolved = handleInvocationExtern(
1103 currentTermNode->id->getId().get().strVal, firstOp->args, objectType->typeAffiliateModule, objectType, false,
1104 currentTermNode->id->hasTemplateArg() ? &currentTermNode->id->getArg() : nullptr);
1105
1106 if (!isResolved) {
1107 auto structDef = moduleContext->getCompilerContext()
1108 ->getImportedModule(objectType->typeAffiliateModule)
1109 ->structTable[objectType->typeIndex];
1110 try {
1111 // no method call would ever enter this block
1112 auto info = structDef->lookupName(currentTermNode->id->getId().get().strVal);
1113 moduleContext->getIRBuilder().loadMemberOp({IROperand::operandType::index, info.index},
1114 structDef->fieldTypes[info.index]);
1115
1116 yoi_assert(structDef->fieldTypes[info.index]->type == IRValueType::valueType::structObject ||
1117 structDef->fieldTypes[info.index]->type == IRValueType::valueType::interfaceObject,
1118 currentTermNode->getLine(),
1119 currentTermNode->getColumn(),
1120 "Cannot invoke basic types as methods: " + wstring2string(currentTermNode->id->getId().get().strVal));
1121 if (!handleInvocationExtern(L"operator()",
1122 firstOp->args,
1123 structDef->fieldTypes[info.index]->typeAffiliateModule,
1124 structDef->fieldTypes[info.index]))
1125 panic(currentTermNode->getLine(),
1126 currentTermNode->getColumn(),
1127 "No matching method found for: " + wstring2string(currentTermNode->id->getId().get().strVal) +
1128 ".operator()");
1129
1130 isResolved = true;
1131 } catch (std::out_of_range &) {
1132 }
1133 }
1134
1135 if (!isResolved) {
1136 panic(currentTermNode->getLine(),
1137 currentTermNode->getColumn(),
1138 "No matching method found for: " + wstring2string(currentTermNode->id->getId().get().strVal));
1139 }
1140 } else if (objectType->type == IRValueType::valueType::interfaceObject) {
1141 // Interface method call logic... (was already correct)
1142 if (!handleInvocationExtern(
1143 currentTermNode->id->getId().get().strVal, firstOp->args, objectType->typeAffiliateModule, objectType))
1144 panic(currentTermNode->getLine(),
1145 currentTermNode->getColumn(),
1146 "No matching method found for: " + wstring2string(currentTermNode->id->getId().get().strVal));
1147 }
1148 } else {
1149 // It's a field access followed by subscript, e.g., `obj.data[i]`
1150 // First, load the field itself.
1151 if (objectType->type == IRValueType::valueType::structObject) {
1152 auto structDef = moduleContext->getCompilerContext()
1153 ->getImportedModule(objectType->typeAffiliateModule)
1154 ->structTable[objectType->typeIndex];
1155 auto &fieldName = currentTermNode->id->getId().get().strVal;
1156 try {
1157 auto nameInfo = structDef->lookupName(fieldName);
1158 if (nameInfo.type != IRStructDefinition::nameInfo::nameType::field) {
1159 panic(currentTermNode->getLine(),
1160 currentTermNode->getColumn(),
1161 "Cannot subscript method '" + wstring2string(fieldName) + "'.");
1162 }
1163 auto fieldType = structDef->fieldTypes[nameInfo.index];
1164 moduleContext->getIRBuilder().loadMemberOp({IROperand::operandType::index, nameInfo.index}, fieldType);
1165 } catch (std::out_of_range &) {
1166 panic(currentTermNode->getLine(),
1167 currentTermNode->getColumn(),
1168 "Struct '" + wstring2string(structDef->name) + "' has no field named '" + wstring2string(fieldName) + "'.");
1169 }
1170 } else {
1171 panic(currentTermNode->getLine(), currentTermNode->getColumn(), "Member access on a non-struct type is not allowed here.");
1172 }
1173 }
1174
1175 // B. Now, process the chain of `()` and `[]` that follow the identifier.
1176 auto subIt = isMethodCall ? std::next(currentTermNode->getSubscript().begin()) : currentTermNode->getSubscript().begin();
1177 for (; subIt != currentTermNode->getSubscript().end(); ++subIt) {
1178 auto sub = *subIt;
1179 bool isFinalOperation = isFinalTerm && (std::next(subIt) == currentTermNode->getSubscript().end());
1180 auto currentObjectType = moduleContext->getIRBuilder().getRhsFromTempVarStack();
1181
1182 if (sub->isInvocation()) {
1183 // This handles `obj.field[i]()` where `field[i]` returns a callable.
1184 // Or `obj.method()()` where `method()` returns a callable.
1185 if (!handleInvocationExtern(L"operator()", sub->args, currentObjectType->typeAffiliateModule, currentObjectType))
1186 panic(sub->getLine(),
1187 sub->getColumn(),
1188 "No matching method found for: " + wstring2string(currentTermNode->id->getId().get().strVal) + ".operator()");
1189 } else if (sub->isSubscript()) {
1190 if (currentObjectType->isArrayType() || currentObjectType->isDynamicArrayType()) {
1191 visit(sub->expr); // Evaluate the index and push it.
1192 tryCastTo(moduleContext->getCompilerContext()->getUnsignedObjectType());
1194 yoi_assert(indexType->type == IRValueType::valueType::unsignedObject,
1195 sub->getLine(),
1196 sub->getColumn(),
1197 "Array/subscript index must be an integer or unsigned integer.");
1198
1199 if (isStoreOp && isFinalOperation) {
1200 // This handles `... = obj.field[i]`
1201 moduleContext->getIRBuilder().storeOp(IR::Opcode::store_element, {});
1202 } else {
1203 // This handles `let x = obj.field[i]`
1204 moduleContext->getIRBuilder().loadOp(IR::Opcode::load_element, {}, managedPtr(currentObjectType->getElementType()));
1205 }
1206 } else {
1207 // Overloaded operator[]
1208 if (isFinalOperation && isStoreOp) {
1209 // current stack: [..., value, array, index]
1212
1214
1215 visit(sub->expr);
1217
1218 OverloadResult overload;
1219 if (array->type == IRValueType::valueType::structObject)
1220 overload = resolveOverloadExtern(L"operator[]",
1221 {value, array, index},
1222 array->typeAffiliateModule,
1224 ->getImportedModule(array->typeAffiliateModule)
1225 ->structTable[array->typeIndex]);
1226
1227 yoi_assert(overload.found(), sub->getLine(), sub->getColumn(), "No matching overload found for operator[].");
1228 yoi_assert(
1229 !overload.isVariadic, sub->getLine(), sub->getColumn(), "Variadic operator[] overloading is not supported.");
1230
1231 if (overload.isCastRequired) {
1233 // value cannot be rolled back
1234 visit(sub->expr);
1235 tryCastTo(overload.function->argumentTypes.back());
1236 } else {
1238 }
1239
1241 overload.functionIndex, 2, overload.function->returnType, false, true, array->typeAffiliateModule);
1242
1244 } else {
1246 visit(sub->expr);
1247 handleBinaryOperatorOverload(L"operator[]", sub->expr);
1248 }
1249 }
1250 }
1251 }
1252 }
1253 }
1254
1257 }
1258
1261
1262 if (!checkMarcoSatisfaction(inCodeBlockStmt->marco))
1263 return;
1264
1265 switch (inCodeBlockStmt->getKind()) {
1266 case inCodeBlockStmt::vKind::ifStmt:
1268 break;
1269 case inCodeBlockStmt::vKind::whileStmt:
1271 break;
1272 case inCodeBlockStmt::vKind::forStmt:
1274 break;
1275 case inCodeBlockStmt::vKind::forEachStmt:
1277 break;
1278 case inCodeBlockStmt::vKind::returnStmt:
1280 break;
1281 case inCodeBlockStmt::vKind::continueStmt:
1283 break;
1284 case inCodeBlockStmt::vKind::breakStmt:
1286 break;
1287 case inCodeBlockStmt::vKind::letStmt:
1289 break;
1290 case inCodeBlockStmt::vKind::codeBlock:
1292 break;
1293 case inCodeBlockStmt::vKind::yieldStmt:
1295 break;
1296 case inCodeBlockStmt::vKind::rExpr:
1298 // balance the stack
1300 break;
1301 default:
1302 panic(inCodeBlockStmt->getLine(), inCodeBlockStmt->getColumn(), "Invalid in code block stmt");
1303 break;
1304 }
1305 }
1306
1307 yoi::indexT visitor::visit(yoi::subscriptExpr *subscriptExpr, bool isStoreOp) {
1308 if (subscriptExpr->getSubscript().empty()) {
1309 return visit(subscriptExpr->id, isStoreOp);
1310 }
1311
1312 moduleContext->getIRBuilder().saveState(); // for resolving operator[] overload param type checking and resolving
1313
1314 auto it = subscriptExpr->getSubscript().begin();
1315 auto end = subscriptExpr->getSubscript().end();
1316 auto &first_term = *it;
1317
1318 bool isType = false;
1319 std::shared_ptr<IRValueType> baseType;
1320 try {
1321 baseType = managedPtr(parseTypeSpec(subscriptExpr->id));
1322 isType = true;
1323 } catch (const std::runtime_error &) {
1324 isType = false;
1325 }
1326
1327 bool firstTermHandled = false;
1328
1329 // Case 1: Array initializer like `int[2](...)`
1330 if (isType && first_term->isSubscript()) {
1331 yoi::vec<yoi::indexT> dimensions;
1332 yoi::indexT size = 1;
1333 auto dim_it = it;
1334 while (dim_it != end && (*dim_it)->isSubscript()) {
1335 yoi_assert((*dim_it)->expr->getToken().kind == lexer::token::tokenKind::integer,
1336 (*dim_it)->expr->getLine(),
1337 (*dim_it)->expr->getColumn(),
1338 "Array dimension must be an integer.");
1339 dimensions.push_back((*dim_it)->expr->getToken().basicVal.vInt);
1340 size = size * dimensions.back();
1341 dim_it++;
1342 }
1343 yoi::indexT actualSize = 0;
1344 if (dim_it != end && (*dim_it)->isInvocation()) {
1345 for (auto &val : (*dim_it)->args->get()) {
1346 visit(val);
1347 tryCastTo(baseType);
1348 actualSize++;
1349 }
1350 it = ++dim_it;
1351 } else {
1352 it = dim_it;
1353 }
1354
1355 moduleContext->getIRBuilder().newArrayOp(baseType, dimensions, actualSize);
1356 }
1357 // Case 2: Invocation `id<...>(...)` or `id(...)`
1358 else if (first_term->isInvocation()) {
1359 firstTermHandled = true;
1360 auto baseName = subscriptExpr->id->getId().get().strVal;
1361 auto args = first_term->args;
1362 bool resolved = false;
1363
1364 // --- Step 1: Handle explicit template specialization if present ---
1366 auto concreteTemplateArgs = parseTemplateArgs(subscriptExpr->id->getArg());
1367 if (irModule->funcTemplateAsts.contains(baseName)) {
1368 auto astNode = irModule->funcTemplateAsts.at(baseName);
1369 specializeFunctionTemplate(astNode, concreteTemplateArgs, currentModuleIndex);
1370 } else {
1371 try {
1372 auto baseType = managedPtr(parseTypeSpec(subscriptExpr->id));
1373 switch (baseType->type) {
1374 case IRValueType::valueType::structObject:
1375 baseName = moduleContext->getCompilerContext()
1376 ->getImportedModule(baseType->typeAffiliateModule)
1377 ->structTable.getKey(baseType->typeIndex);
1378 break;
1379 case IRValueType::valueType::interfaceObject:
1380 baseName = moduleContext->getCompilerContext()
1381 ->getImportedModule(baseType->typeAffiliateModule)
1382 ->interfaceTable.getKey(baseType->typeIndex);
1383 break;
1384 default:
1387 "Cannot specialize type: except structObject or interfaceObject but got: " +
1388 yoi::wstring2string(baseType->to_string()));
1389 break;
1390 }
1391 } catch (const std::runtime_error &e) {
1394 "Could not resolve template specialization for function '" + wstring2string(baseName) + ": \n" + e.what());
1395 }
1396 }
1397 }
1398
1399 // --- Step 2: Unified Invocation Logic with correct precedence ---
1400
1401 // Attempt 0: Check whether is a accessible variable
1403 {
1404 bool isAccessible = false;
1405 try {
1406 visit(subscriptExpr->id, false);
1407 isAccessible = true;
1409 } catch (const std::runtime_error &) {
1411 }
1412 if (isAccessible) {
1414 if (structObject->type == IRValueType::valueType::structObject || structObject->type == IRValueType::valueType::interfaceObject) {
1415 if (!handleInvocationExtern(L"operator()", args, currentModuleIndex, structObject))
1416 panic(subscriptExpr->getLine(), subscriptExpr->getColumn(), "No matching method found for: " + wstring2string(baseName));
1417 resolved = true;
1418 } else {
1419 panic(
1420 subscriptExpr->getLine(), subscriptExpr->getColumn(), "Cannot call operator() on non-struct object or interface object.");
1421 }
1422 }
1423 }
1424
1426 // Attempt 1: Struct Constructor (handles regular, variadic, and specialized template structs)
1427 if (irModule->structTable.contains(baseName)) {
1428 auto structIndex = irModule->structTable.getIndex(baseName);
1429 auto structType = irModule->structTable[structIndex];
1430 moduleContext->getIRBuilder().newStructOp(structIndex);
1432 if (handleInvocationExtern(L"constructor", args, currentModuleIndex, rhs)) {
1433 resolved = true;
1435 } else {
1438 "Could not resolve constructor for struct '" + wstring2string(baseName) + "'.");
1439 }
1440 } else {
1442 }
1443
1444 // Attempt 2: Data struct constructor
1445 if (!resolved) {
1446 if (irModule->dataStructTable.contains(baseName)) {
1447 constructDataStruct(irModule->dataStructTable.getIndex(baseName), irModule->identifier, args);
1448 resolved = true;
1449 }
1450 }
1451
1452 // Attempt 3: Free Function (handles regular, variadic, and implicit template functions)
1453 if (!resolved) {
1454 resolved = handleInvocationExtern(baseName, args, currentModuleIndex);
1455 }
1456
1457 // Attempt 4: Interface Constructor
1458 if (!resolved) {
1459 if (irModule->interfaceTable.contains(baseName)) {
1461 try {
1462 auto interfaceIndex = irModule->interfaceTable.getIndex(baseName);
1463 auto argTypes = evaluateArguments(args);
1464 yoi_assert(argTypes.size() == 1,
1467 "Interface constructor expects exactly one argument.");
1468 // moduleContext->getIRBuilder().newInterfaceOp(interfaceIndex);
1469 auto interfaceImplName = getInterfaceImplName({currentModuleIndex, interfaceIndex}, argTypes[0]);
1470 auto targetModule = moduleContext->getCompilerContext()->getImportedModule(argTypes[0]->typeAffiliateModule);
1471 auto interfaceImplIndex = targetModule->interfaceImplementationTable.getIndex(interfaceImplName);
1473 {currentModuleIndex, interfaceIndex}, interfaceImplIndex, true, targetModule->identifier);
1474 resolved = true;
1476 } catch (const std::out_of_range &) {
1478 }
1479 }
1480 }
1481
1482 // Attempt 5: Imported Function
1483 if (!resolved) {
1484 if (irModule->externTable.contains(baseName)) {
1486 try {
1487 auto importedFunctionIndex = irModule->externTable.getIndex(baseName);
1488 yoi_assert(irModule->externTable[importedFunctionIndex]->type == IRExternEntry::externType::importedFunction,
1491 "This is not an imported function.");
1492 auto importedFunc = moduleContext->getCompilerContext()
1493 ->getIRFFITable()
1494 ->importedLibraries[irModule->externTable[importedFunctionIndex]->affiliateModule]
1495 .importedFunctionTable[irModule->externTable[importedFunctionIndex]->itemIndex];
1496
1497 auto desiredArgTypes = importedFunc->argumentTypes;
1498 yoi_assert(desiredArgTypes.size() == args->arg.size(),
1499 args->getLine(),
1500 args->getColumn(),
1501 "Number of arguments does not match the function signature.");
1502 for (yoi::indexT i = 0; i < args->arg.size(); i++) {
1503 visit(args->arg[i]);
1504 tryCastTo(managedPtr(moduleContext->getCompilerContext()->normalizeForeignBasicType(desiredArgTypes[i], false)));
1505 }
1506 moduleContext->getIRBuilder().invokeImportedOp(irModule->externTable[importedFunctionIndex]->affiliateModule,
1507 irModule->externTable[importedFunctionIndex]->itemIndex,
1508 desiredArgTypes.size(),
1509 importedFunc->returnType);
1510 resolved = true;
1512 } catch (const std::out_of_range &) {
1514 }
1515 }
1516 }
1517
1518 // Attempt 6: type alias
1519 if (auto it = irModule->typeAliases.find(baseName); it != irModule->typeAliases.end()) {
1520 if (it->second.type == IRValueType::valueType::structObject) {
1521 auto targetModule = moduleContext->getCompilerContext()->getImportedModule(it->second.typeAffiliateModule);
1522 auto structIndex = it->second.typeIndex;
1523 auto structType = targetModule->structTable[structIndex];
1524 moduleContext->getIRBuilder().newStructOp(structIndex, true, targetModule->identifier);
1526 if (handleInvocationExtern(L"constructor", args, targetModule->identifier, rhs)) {
1527 resolved = true;
1529 } else {
1532 "Could not resolve constructor for struct '" + wstring2string(baseName) + "'.");
1533 }
1534 } else if (it->second.type == IRValueType::valueType::interfaceObject) {
1535 auto targetModuleForInterface = moduleContext->getCompilerContext()->getImportedModule(it->second.typeAffiliateModule);
1537 try {
1538 // auto interfaceIndex = targetModuleForInterface->interfaceTable.getIndex(baseName);
1539 auto interfaceIndex = it->second.typeIndex;
1540 auto argTypes = evaluateArguments(args);
1541 yoi_assert(argTypes.size() == 1,
1544 "Interface constructor expects exactly one argument.");
1545 // moduleContext->getIRBuilder().newInterfaceOp(interfaceIndex, true, targetModuleForInterface->identifier);
1546 auto interfaceImplName = getInterfaceImplName({currentModuleIndex, interfaceIndex}, argTypes[0]);
1547 auto targetModule = moduleContext->getCompilerContext()->getImportedModule(argTypes[0]->typeAffiliateModule);
1548 auto interfaceImplIndex = targetModule->interfaceImplementationTable.getIndex(interfaceImplName);
1550 {currentModuleIndex, interfaceIndex}, interfaceImplIndex, true, targetModule->identifier);
1551 resolved = true;
1553 } catch (const std::out_of_range &) {
1555 }
1556 } else {
1557 panic(first_term->getLine(), first_term->getColumn(), "invalid type alias type");
1558 }
1559 }
1560
1561 if (!resolved) {
1564 "Could not resolve call to '" + wstring2string(baseName) +
1565 "'. No matching function, constructor, or template found for the given arguments.");
1566 }
1567 }
1568 // Case 3: First term is a variable access for subsequent subscript `var[...]`
1569 else {
1570 visit(subscriptExpr->id, false); // Load the variable
1571 }
1572
1573 if (firstTermHandled) {
1574 it++;
1575 }
1576
1577 // --- Loop for subsequent terms (e.g., chained array access) ---
1578 while (it != end) {
1579 auto currentTerm = *it;
1580 bool isLastTerm = (std::next(it) == end);
1581 auto objectOnStackType = moduleContext->getIRBuilder().getRhsFromTempVarStack();
1582
1583 if (currentTerm->isSubscript()) {
1584 if (handleSubscript(it, end, isStoreOp, isLastTerm))
1585 continue;
1586 else
1587 return moduleContext->getIRBuilder().getCurrentInsertionPoint(); // avoid releasing the state twice.
1588 } else if (currentTerm->isInvocation()) {
1589 if (objectOnStackType->type == IRValueType::valueType::structObject ||
1590 objectOnStackType->type == IRValueType::valueType::interfaceObject) {
1591 if (!handleInvocationExtern(L"operator()", currentTerm->args, currentModuleIndex, objectOnStackType))
1592 panic(currentTerm->getLine(),
1593 currentTerm->getColumn(),
1594 "No matching method found for: " + wstring2string(subscriptExpr->id->getId().get().strVal));
1595 } else {
1596 panic(currentTerm->getLine(), currentTerm->getColumn(), "Cannot call operator() on non-struct object or interface object.");
1597 }
1598 }
1599 it++;
1600 }
1601
1602 moduleContext->getIRBuilder().discardState(); // release the state after all subscript terms are handled.
1604 }
1605
1606 yoi::indexT visitor::visitExtern(yoi::subscriptExpr *subscriptExpr, yoi::indexT targetModule, bool isStoreOp) {
1607 if (subscriptExpr->getSubscript().empty()) {
1608 return visitExtern(subscriptExpr->id, targetModule, isStoreOp);
1609 }
1610
1611 moduleContext->getIRBuilder().saveState(); // save as visit
1612
1613 auto it = subscriptExpr->getSubscript().begin();
1614 auto end = subscriptExpr->getSubscript().end();
1615 auto &firstTerm = *it;
1616
1617 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(targetModule);
1618
1619 bool isType = false;
1620 std::shared_ptr<IRValueType> baseType;
1621 try {
1622 baseType = managedPtr(parseTypeSpecExtern(subscriptExpr->id, targetModule));
1623 isType = true;
1624 } catch (const std::out_of_range &) {
1625 isType = false;
1626 }
1627
1628 bool firstTermHandled = false;
1629
1630 // Case 1: Extern Array Initializer
1631 if (isType && firstTerm->isSubscript()) {
1632 yoi::vec<yoi::indexT> dimensions;
1633 yoi::indexT size = 1;
1634 auto dim_it = it;
1635 while (dim_it != end && (*dim_it)->isSubscript()) {
1636 yoi_assert((*dim_it)->expr->getToken().kind == lexer::token::tokenKind::integer,
1637 (*dim_it)->expr->getLine(),
1638 (*dim_it)->expr->getColumn(),
1639 "Array dimension must be an integer.");
1640 dimensions.push_back((*dim_it)->expr->getToken().basicVal.vInt);
1641 size = size * dimensions.back();
1642 dim_it++;
1643 }
1644 yoi::indexT actualSize = 0;
1645 if (dim_it != end && (*dim_it)->isInvocation()) {
1646 for (auto &val : (*dim_it)->args->get()) {
1647 visit(val);
1648 tryCastTo(baseType);
1649 actualSize++;
1650 }
1651 it = ++dim_it;
1652 } else {
1653 it = dim_it;
1654 }
1655
1656 moduleContext->getIRBuilder().newArrayOp(baseType, dimensions, actualSize);
1657 }
1658 // Case 2: Extern Invocation
1659 else if (firstTerm->isInvocation()) {
1660 firstTermHandled = true;
1661 auto baseName = subscriptExpr->id->getId().get().strVal;
1662 auto args = firstTerm->args;
1663 bool resolved = false;
1664
1665 // --- Step 1: Handle explicit template specialization if present ---
1667 auto concreteTemplateArgs = parseTemplateArgs(subscriptExpr->id->getArg());
1668 if (targetedModule->funcTemplateAsts.contains(baseName)) {
1669 auto astNode = targetedModule->funcTemplateAsts.at(baseName);
1670 specializeFunctionTemplate(astNode, concreteTemplateArgs, targetModule);
1671 } else {
1672 try {
1673 auto baseType = managedPtr(parseTypeSpecExtern(subscriptExpr->id, targetModule));
1674 switch (baseType->type) {
1675 case IRValueType::valueType::structObject:
1676 baseName = moduleContext->getCompilerContext()
1677 ->getImportedModule(baseType->typeAffiliateModule)
1678 ->structTable.getKey(baseType->typeIndex);
1679 break;
1680 case IRValueType::valueType::interfaceObject:
1681 baseName = moduleContext->getCompilerContext()
1682 ->getImportedModule(baseType->typeAffiliateModule)
1683 ->interfaceTable.getKey(baseType->typeIndex);
1684 break;
1685 default:
1688 "Cannot specialize type: except structObject or interfaceObject but got: " +
1689 yoi::wstring2string(baseType->to_string()));
1690 break;
1691 }
1692 } catch (const std::runtime_error &e) {
1695 "Could not resolve template specialization for function '" + wstring2string(baseName) + "'" + ": \n" + e.what() + "\n");
1696 } catch (const std::out_of_range &e) {
1698 }
1699 }
1700 }
1701
1702 // Attempt 1: Extern Struct Constructor (regular or variadic)
1703 if (targetedModule->structTable.contains(baseName)) {
1704 IRExternEntry externStructEntry;
1705 try {
1706 externStructEntry = getExternEntry(targetModule, baseName);
1707 } catch (const std::out_of_range &) {
1708 panic(subscriptExpr->getLine(), subscriptExpr->getColumn(), "Could not find extern struct entry for " + wstring2string(baseName));
1709 }
1710
1711 auto targetedStruct = targetedModule->structTable[baseName];
1712
1713 moduleContext->getIRBuilder().newStructOp(externStructEntry.itemIndex, true, externStructEntry.affiliateModule);
1715 if (handleInvocationExtern(L"constructor", args, targetModule, rhs)) {
1716 resolved = true;
1717 } else {
1718 moduleContext->getIRBuilder().popFromTempVarStack(); // Pop unused extern struct
1719 }
1720 }
1721
1722 // Attempt 2: Data struct constructor
1723 if (!resolved) {
1724 if (targetedModule->dataStructTable.contains(baseName)) {
1725 constructDataStruct(targetedModule->dataStructTable.getIndex(baseName), targetedModule->identifier, args);
1726 resolved = true;
1727 }
1728 }
1729
1730 // Attempt 4: Extern Free Function (regular or variadic)
1731 if (!resolved) {
1732 resolved = handleInvocationExtern(baseName, args, targetModule);
1733 }
1734
1735 // Attempt 5: Extern Interface Constructor
1736 if (!resolved) {
1737 if (targetedModule->interfaceTable.contains(baseName)) {
1739 try {
1740 auto argTypes = evaluateArguments(args);
1741 yoi_assert(argTypes.size() == 1,
1744 "Interface constructor expects exactly one argument.");
1745
1746 auto concreteThis = moduleContext->getIRBuilder().getRhsFromTempVarStack();
1747
1748 auto externInterface = getExternEntry(targetModule, baseName);
1749 // moduleContext->getIRBuilder().newInterfaceOp(externInterface.itemIndex, true, externInterface.affiliateModule);
1750
1751 auto interfaceImplName = getInterfaceImplName({externInterface.affiliateModule, externInterface.itemIndex}, argTypes[0]);
1752 auto interfaceImplIndex = moduleContext->getCompilerContext()
1753 ->getImportedModule(concreteThis->typeAffiliateModule)
1754 ->interfaceImplementationTable.getIndex(interfaceImplName);
1755 moduleContext->getIRBuilder().constructInterfaceImplOp({externInterface.affiliateModule, externInterface.itemIndex},
1756 interfaceImplIndex,
1757 concreteThis->typeAffiliateModule != currentModuleIndex,
1758 concreteThis->typeAffiliateModule);
1759
1760 resolved = true;
1762 } catch (const std::out_of_range &e) {
1765 "Could not find matched extern interface constructor for " + wstring2string(baseName));
1766 } /* catch (const std::exception &e) {
1767 // panic(subscriptExpr->getLine(), subscriptExpr->getColumn(), "Could not find matched extern interface constructor for " +
1768 wstring2string(baseName)); throw e;
1769 }*/
1770 }
1771 }
1772
1773 // Attempt 6: FFI Imported Function (via an extern module)
1774 if (!resolved) {
1775 if (targetedModule->externTable.contains(baseName)) {
1777 try {
1778 auto argTypes = evaluateArguments(args);
1779 auto externEntry = targetedModule->externTable[baseName];
1780 auto externFunc = moduleContext->getCompilerContext()
1781 ->getIRFFITable()
1782 ->importedLibraries[externEntry->affiliateModule]
1783 .importedFunctionTable[externEntry->itemIndex];
1785 externEntry->affiliateModule, externEntry->itemIndex, argTypes.size(), externFunc->returnType);
1786
1787 resolved = true;
1789 } catch (const std::exception &) {
1791 }
1792 }
1793 }
1794
1795 // Attempt 7: Type alias
1796 if (auto it = targetedModule->typeAliases.find(baseName); it != targetedModule->typeAliases.end()) {
1797 if (it->second.type == IRValueType::valueType::structObject) {
1798 auto targetModule = moduleContext->getCompilerContext()->getImportedModule(it->second.typeAffiliateModule);
1799 auto structIndex = it->second.typeIndex;
1800 auto structType = targetModule->structTable[structIndex];
1801 moduleContext->getIRBuilder().newStructOp(structIndex, true, targetModule->identifier);
1803 if (handleInvocationExtern(L"constructor", args, targetModule->identifier, rhs)) {
1804 resolved = true;
1806 } else {
1809 "Could not resolve constructor for struct '" + wstring2string(baseName) + "'.");
1810 }
1811 } else if (it->second.type == IRValueType::valueType::interfaceObject) {
1812 auto targetModuleForInterface = moduleContext->getCompilerContext()->getImportedModule(it->second.typeAffiliateModule);
1814 try {
1815 // auto interfaceIndex = targetModuleForInterface->interfaceTable.getIndex(baseName);
1816 auto interfaceIndex = it->second.typeIndex;
1817 auto argTypes = evaluateArguments(args);
1818 yoi_assert(argTypes.size() == 1,
1821 "Interface constructor expects exactly one argument.");
1822 // moduleContext->getIRBuilder().newInterfaceOp(interfaceIndex, true, targetModuleForInterface->identifier);
1823 auto interfaceImplName = getInterfaceImplName({currentModuleIndex, interfaceIndex}, argTypes[0]);
1824 auto targetModule = moduleContext->getCompilerContext()->getImportedModule(argTypes[0]->typeAffiliateModule);
1825 auto interfaceImplIndex = targetModule->interfaceImplementationTable.getIndex(interfaceImplName);
1827 {currentModuleIndex, interfaceIndex}, interfaceImplIndex, true, targetModule->identifier);
1828 resolved = true;
1830 } catch (const std::exception &) {
1832 }
1833 } else {
1834 panic(firstTerm->getLine(), firstTerm->getColumn(), "invalid type alias type: " + wstring2string(baseName));
1835 }
1836 }
1837
1838 if (!resolved) {
1841 "Could not find extern function, struct constructor, or interface in module: " + wstring2string(baseName));
1842 }
1843 } else { // First term is a variable access
1844 visitExtern(subscriptExpr->id, targetModule, false);
1845 }
1846
1847 if (firstTermHandled) {
1848 it++;
1849 }
1850
1851 // --- Loop for subsequent terms ---
1852 while (it != end) {
1853 auto currentTerm = *it;
1854 bool isLastTerm = (std::next(it) == end);
1855 auto objectOnStackType = moduleContext->getIRBuilder().getRhsFromTempVarStack();
1856
1857 if (currentTerm->isSubscript()) {
1858 if (handleSubscript(it, end, isStoreOp, isLastTerm))
1859 continue;
1860 else
1861 return moduleContext->getIRBuilder().getCurrentInsertionPoint(); // avoid releasing state twice
1862 } else if (currentTerm->isInvocation()) {
1863 if (objectOnStackType->type == IRValueType::valueType::structObject ||
1864 objectOnStackType->type == IRValueType::valueType::interfaceObject) {
1865 handleInvocationExtern(L"operator()", currentTerm->args, currentModuleIndex, objectOnStackType);
1866 } else {
1867 panic(currentTerm->getLine(), currentTerm->getColumn(), "Cannot call operator() on non-struct object or interface object.");
1868 }
1869 }
1870 it++;
1871 }
1872
1873 moduleContext->getIRBuilder().discardState(); // release the state after all subscript terms are handled.
1875 }
1876
1879 panic(identifierWithTemplateArg->getLine(), identifierWithTemplateArg->getColumn(), "Invalid visit of identifier with template arg.");
1880 return 0;
1881 } else {
1882 return visit(identifierWithTemplateArg->id, isStoreOp);
1883 }
1884 }
1885
1887 auto index = moduleContext->getCompilerContext()->compileModule(useStmt->path.strVal);
1888 irModule->moduleImports[useStmt->name->get().strVal] = index;
1889 moduleContext->getCompilerContext()->getImportedModule(index)->dependentModules.insert(currentModuleIndex);
1891 }
1892
1893 IRValueType visitor::parseTypeSpec(yoi::identifier *identifier) {
1894 auto &typeName = identifier->node.strVal;
1895 try {
1896 return irModule->typeAliases.at(typeName);
1897 } catch (std::out_of_range &e) {
1898 // let it go
1899 }
1900 try {
1901 auto typeIndex = irModule->structTable.getIndex(typeName);
1902 return IRValueType{IRValueType::valueType::structObject, static_cast<yoi::indexT>(currentModuleIndex), typeIndex};
1903 } catch (std::out_of_range &e) {
1904 // let it go
1905 }
1906 try {
1907 auto typeIndex = irModule->dataStructTable.getIndex(typeName);
1908 return IRValueType{IRValueType::valueType::datastructObject, static_cast<yoi::indexT>(currentModuleIndex), typeIndex};
1909 } catch (std::out_of_range &e) {
1910 // let it go
1911 }
1912 try {
1913 auto typeIndex = irModule->interfaceTable.getIndex(typeName);
1914 return IRValueType{IRValueType::valueType::interfaceObject, static_cast<yoi::indexT>(currentModuleIndex), typeIndex};
1915 } catch (std::out_of_range &e) {
1916 // let it go
1917 }
1918 try {
1919 auto incompleteType = getIncompleteType(typeName);
1920 return *incompleteType;
1921 } catch (std::out_of_range &e) {
1922 // let it go
1923 }
1924 if (typeName == L"int") {
1925 return *moduleContext->getCompilerContext()->getIntObjectType();
1926 } else if (typeName == L"bool") {
1927 return *moduleContext->getCompilerContext()->getBoolObjectType();
1928 } else if (typeName == L"deci") {
1929 return *moduleContext->getCompilerContext()->getDeciObjectType();
1930 } else if (typeName == L"string") {
1931 return *moduleContext->getCompilerContext()->getStrObjectType();
1932 } else if (typeName == L"none") {
1933 return *moduleContext->getCompilerContext()->getNoneObjectType();
1934 } else if (typeName == L"char") {
1935 return *moduleContext->getCompilerContext()->getCharObjectType();
1936 } else if (typeName == L"int32") {
1937 return *moduleContext->getCompilerContext()->getForeignInt32ObjectType();
1938 } else if (typeName == L"float") {
1939 return *moduleContext->getCompilerContext()->getForeignFloatObjectType();
1940 } else if (typeName == L"ptr") {
1941 return *moduleContext->getCompilerContext()->getPointerType();
1942 } else if (typeName == L"unsigned") {
1943 return *moduleContext->getCompilerContext()->getUnsignedObjectType();
1944 } else if (typeName == L"short") {
1945 return *moduleContext->getCompilerContext()->getShortObjectType();
1946 } else {
1947 panic(identifier->getLine(), identifier->getColumn(), "Unsupported type: " + wstring2string(typeName));
1948 }
1949 }
1950
1952 auto funcName = funcDefStmt->getId();
1953
1954 if (funcName.hasDefTemplateArg()) {
1955 auto actualName = funcName.getId().node.strVal;
1956 irModule->funcTemplateAsts[actualName] = funcDefStmt;
1957 } else {
1958 bool isVaridic = false;
1959
1960 auto funcType = parseTypeSpec(&funcDefStmt->getResultType());
1962
1963 builder.setDebugInfo({irModule->modulePath, funcDefStmt->getLine(), funcDefStmt->getColumn()});
1964
1965 builder.attrs = getFunctionAttributes(funcDefStmt->attrs);
1966
1967 std::vector<std::shared_ptr<IRValueType>> argTypes;
1968 for (auto &i : funcDefStmt->getArgs().get()) {
1969 if (&i == &funcDefStmt->getArgs().get().back() && i->spec->kind == typeSpec::typeSpecKind::Elipsis /* elipsis */) {
1970 isVaridic = true;
1971 builder.addAttr(IRFunctionDefinition::FunctionAttrs::Variadic);
1972 auto argName = i->getId().node.strVal;
1973 auto argType = managedPtr(i->spec->elipsis ? parseTypeSpec(i->spec->elipsis).getDynamicArrayType()
1974 : moduleContext->getCompilerContext()->getNullInterfaceType()->getDynamicArrayType());
1975 builder.addArgument(argName, argType);
1976 argTypes.push_back(argType);
1977 break;
1978 }
1979
1980 auto argName = i->getId().node.strVal;
1981 auto argType = managedPtr(parseTypeSpec(i->spec));
1982 argTypes.push_back(argType);
1983 builder.addArgument(argName, argType);
1984 }
1985
1986 if (builder.attrs.contains(IRFunctionDefinition::FunctionAttrs::Generator)) {
1987 builder.setReturnType(getGeneratorContext(
1988 std::to_wstring(irModule->identifier) + L"_" + funcName.getId().node.strVal + getFuncUniqueNameStr(argTypes),
1989 managedPtr(funcType)
1990 ));
1991 } else {
1992 builder.setReturnType(managedPtr(funcType));
1993 }
1994
1995 builder.setName(funcName.getId().node.strVal + getFuncUniqueNameStr(argTypes));
1996
1997 auto func = builder.yield();
1998
1999 auto funcIndex = irModule->functionTable.put(builder.name, func);
2000 irModule->functionOverloadIndexies[funcName.getId().node.strVal].push_back(funcIndex);
2001
2003 if (builder.attrs.contains(IRFunctionDefinition::FunctionAttrs::Generator)) {
2004 moduleContext->getIRBuilder().irFuncDefinition()->getVariableTable().put(L"__context__", func->returnType);
2005 }
2008 visit(funcDefStmt->block, true);
2011 }
2013 }
2014
2017 auto &interfaceName = interfaceDefStmt->id->getId().get().strVal;
2018
2019 irModule->templateInterfaceAsts[interfaceName] = interfaceDefStmt;
2020
2022 }
2023
2024 auto &interfaceName = interfaceDefStmt->id->getId().get().strVal;
2025 auto interfaceIndex = irModule->interfaceTable.put(interfaceName, {});
2026
2028 builder.setName(interfaceName);
2029 for (auto &i : interfaceDefStmt->getInner().getInner()) {
2030 bool isVaridic = false;
2031 yoi_assert(i->isMethod(), i->getLine(), i->getColumn(), "Interface member must be a method");
2032
2033 auto methodName = i->getMethod().getName().getId().get().strVal;
2034 auto methodResultType = managedPtr(parseTypeSpec(i->getMethod().resultType));
2036 IRFunctionDefinition::Builder methodBuilder;
2037
2038 methodBuilder.setDebugInfo({irModule->modulePath, i->getLine(), i->getColumn()});
2039
2040 methodBuilder.setReturnType(methodResultType);
2041 for (auto &arg : i->getMethod().getArgs().get()) {
2042 if (&arg == &i->getMethod().getArgs().get().back() && arg->spec->kind == typeSpec::typeSpecKind::Elipsis /* elipsis */) {
2043 isVaridic = true;
2044 methodBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Variadic);
2045 auto argName = arg->getId().node.strVal;
2046 auto argType =
2047 managedPtr(arg->spec->elipsis ? parseTypeSpec(arg->spec->elipsis).getDynamicArrayType()
2048 : moduleContext->getCompilerContext()->getNullInterfaceType()->getDynamicArrayType());
2049 methodBuilder.addArgument(argName, argType);
2050 argTypes.push_back(argType);
2051 break;
2052 }
2053
2054 auto argName = arg->getId().get().strVal;
2055 auto argType = managedPtr(parseTypeSpec(arg->spec));
2056 methodBuilder.addArgument(argName, argType);
2057 argTypes.push_back(argType);
2058 }
2059 auto methodFuncName = L"interface#" + interfaceName + L"#" + methodName;
2060 auto uniq = getFuncUniqueNameStr(argTypes);
2061 methodBuilder.setName(methodFuncName + uniq);
2062
2063 auto func = methodBuilder.yield();
2064 builder.addMethod(methodName, methodName + uniq, func);
2065 }
2066 auto interfaceType = builder.yield();
2067 irModule->interfaceTable[interfaceIndex] = interfaceType;
2069 }
2070
2072 auto &structName = structDefStmt->id->getId().get().strVal;
2073
2075 irModule->structTemplateAsts[structName] = structDefStmt;
2076 } else {
2077 auto structIndex = irModule->structTable.put(structName, {});
2078
2079 generateNullInterfaceImplementation(managedPtr(IRValueType{IRValueType::valueType::structObject, currentModuleIndex, structIndex}));
2080
2082 builder.setName(structName);
2083 for (auto &i : structDefStmt->getInner().getInner()) {
2084 switch (i->kind) {
2085 case 0: {
2086 auto memberName = i->getVar().getId().get().strVal;
2087 auto memberType = managedPtr(parseTypeSpec(i->getVar().spec));
2088 if (i->modifier == structDefInnerPair::Modifier::DataField) {
2089 memberType->metadata.setMetadata(L"STRUCT_DATAFIELD", true);
2090 }
2091 builder.addField(memberName, memberType);
2092 break;
2093 }
2094 case 1: {
2095 bool isVaridic = false;
2096 IRFunctionDefinition::Builder constructorBuilder;
2097
2098 constructorBuilder.setDebugInfo({irModule->modulePath, i->getLine(), i->getColumn()});
2099 constructorBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Constructor);
2100
2102 auto thisType = managedPtr(IRValueType{IRValueType::valueType::structObject, currentModuleIndex, structIndex});
2103 constructorBuilder.setReturnType(thisType);
2104 constructorBuilder.addArgument(L"this", thisType);
2105 constructorBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Constructor);
2106 for (auto &arg : i->getConstructor().getArgs().get()) {
2107 if (&arg == &i->getConstructor().getArgs().get().back() && arg->spec->kind == typeSpec::typeSpecKind::Elipsis) {
2108 isVaridic = true;
2109 constructorBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Variadic);
2110 auto argName = arg->getId().node.strVal;
2111 auto argType = managedPtr(arg->spec->elipsis
2112 ? parseTypeSpec(arg->spec->elipsis).getDynamicArrayType()
2113 : moduleContext->getCompilerContext()->getNullInterfaceType()->getDynamicArrayType());
2114 constructorBuilder.addArgument(argName, argType);
2115 argTypes.push_back(argType);
2116 break;
2117 }
2118 auto argName = arg->getId().get().strVal;
2119 auto argType = managedPtr(parseTypeSpec(arg->spec));
2120 constructorBuilder.addArgument(argName, argType);
2121 argTypes.push_back(argType);
2122 }
2123 auto uniq = getFuncUniqueNameStr(argTypes);
2124 auto mangledName = L"constructor" + uniq;
2125 constructorBuilder.setName(structName + L"::" + mangledName);
2126
2127 auto func = constructorBuilder.yield();
2128 auto funcIndex = irModule->functionTable.put_create(func->name, func);
2129 builder.addMethod(mangledName, funcIndex);
2130 irModule->functionOverloadIndexies[structName + L"::constructor"].push_back(funcIndex);
2131 break;
2132 }
2133 case 2: {
2134 bool isVaridic = false;
2135 auto methodName = i->getMethod().getName().getId().get().strVal;
2136
2137 if (i->getMethod().getName().hasDefTemplateArg()) {
2138 // template method declaration
2139 builder.addTemplateMethodDecl(methodName, i);
2140 break;
2141 }
2142
2143 auto methodType = managedPtr(parseTypeSpec(i->getMethod().resultType));
2144 IRFunctionDefinition::Builder methodBuilder;
2145
2146 methodBuilder.attrs = getFunctionAttributes(i->getMethod().attrs);
2147 methodBuilder.setDebugInfo({irModule->modulePath, i->getLine(), i->getColumn()});
2148
2150
2151 methodBuilder.setReturnType(methodType);
2152 auto thisType = managedPtr(IRValueType{IRValueType::valueType::structObject, currentModuleIndex, structIndex});
2153
2154 if (std::find(methodBuilder.attrs.begin(), methodBuilder.attrs.end(), IRFunctionDefinition::FunctionAttrs::Static) ==
2155 methodBuilder.attrs.end())
2156 methodBuilder.addArgument(L"this", thisType);
2157
2158 for (auto &arg : i->getMethod().getArgs().get()) {
2159 if (&arg == &i->getMethod().getArgs().get().back() && arg->spec->kind == typeSpec::typeSpecKind::Elipsis) {
2160 isVaridic = true;
2161 methodBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Variadic);
2162 auto argName = arg->getId().node.strVal;
2163 auto argType = managedPtr(arg->spec->elipsis
2164 ? parseTypeSpec(arg->spec->elipsis).getDynamicArrayType()
2165 : moduleContext->getCompilerContext()->getNullInterfaceType()->getDynamicArrayType());
2166 methodBuilder.addArgument(argName, argType);
2167 argTypes.push_back(argType);
2168 break;
2169 }
2170 auto argName = arg->getId().get().strVal;
2171 auto argType = managedPtr(parseTypeSpec(arg->spec));
2172 methodBuilder.addArgument(argName, argType);
2173 argTypes.push_back(argType);
2174 }
2175
2176 auto uniq = getFuncUniqueNameStr(argTypes);
2177 auto mangledName = methodName + uniq;
2178 methodBuilder.setName(structName + L"::" + mangledName);
2179 auto func = methodBuilder.yield();
2180 auto funcIndex = irModule->functionTable.put_create(func->name, func);
2181 builder.addMethod(mangledName, funcIndex);
2182 irModule->functionOverloadIndexies[structName + L"::" + methodName].push_back(funcIndex);
2183 break;
2184 }
2185 case 3: {
2186 // finalizer
2187 IRFunctionDefinition::Builder finalizerBuilder;
2188 finalizerBuilder.setName(structName + L"::finalizer");
2189 finalizerBuilder.setDebugInfo({irModule->modulePath, i->getLine(), i->getColumn()});
2190 finalizerBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Finalizer);
2191 finalizerBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Preserve);
2192 auto thisType = managedPtr(IRValueType{IRValueType::valueType::structObject, currentModuleIndex, structIndex});
2193 finalizerBuilder.setReturnType(moduleContext->getCompilerContext()->getNoneObjectType());
2194 finalizerBuilder.addArgument(L"this", thisType);
2195 auto func = finalizerBuilder.yield();
2196 auto funcIndex = irModule->functionTable.put_create(structName + L"::finalizer", func);
2197 builder.addMethod(L"finalizer", funcIndex);
2198 // no need to prepare for manual calling, it is not legal.
2199 break;
2200 }
2201 }
2202 }
2203 auto structType = builder.yield();
2204 irModule->structTable[structIndex] = structType;
2205 }
2207 }
2208
2210 auto &structIdNode = implStmt->getStructId();
2211
2212 auto it = structIdNode.getTerms().begin();
2213 yoi::indexT targetModule = -1, lastModule = -1;
2214 while (it + 1 != structIdNode.getTerms().end() && (targetModule = isModuleName(*it, targetModule)) != lastModule) {
2215 it++;
2216 lastModule = targetModule;
2217 }
2218 if (targetModule == -1) {
2219 targetModule = currentModuleIndex;
2220 }
2221 yoi_assert(it + 1 == structIdNode.getTerms().end(), structIdNode.getLine(), structIdNode.getColumn(), "Invalid interface name");
2222
2223 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(targetModule);
2224 auto structBaseName = (*it)->getId().get().strVal;
2225
2226 if ((*it)->hasTemplateArg()) {
2227 // Impl for a template struct
2228 yoi_assert(targetedModule->structTemplateAsts.contains(structBaseName),
2229 implStmt->getLine(),
2231 "Impl for undefined struct template: " + wstring2string(structBaseName));
2232
2233 yoi::vec<std::shared_ptr<IRValueType>> concreteTemplateArgs = parseTemplateArgs((*it)->getArg());
2234
2235 if (implStmt->isImplForStmt()) {
2236 // interface implementation for a template struct
2237 if (concreteTemplateArgs.empty()) {
2238 targetedModule->templateInterfaceImplAsts[structBaseName].push_back(implStmt);
2239 } else {
2240 // specialize template interface
2241 auto interfaceTemplateAst = targetedModule->templateInterfaceAsts[structBaseName];
2242 auto concreteStructName = getMangledTemplateName(structBaseName, concreteTemplateArgs);
2243 auto concreteStructType = managedPtr(parseTypeSpec(implStmt->structName)); // quick specialization check
2244 yoi_assert(concreteStructType->type == IRValueType::valueType::structObject,
2245 implStmt->getLine(),
2247 "Invalid struct name for struct specialization: " + wstring2string(concreteStructName) +
2248 " (except structObject but got " + wstring2string(concreteStructType->to_string()) + ")");
2249 // FIXED: module index
2250 specializeInterfaceImplementation(implStmt, concreteStructType, concreteStructName, concreteTemplateArgs, targetModule);
2251 }
2252 } else {
2253 if (concreteTemplateArgs.empty()) {
2254 // pure template struct, store them and specialize when used
2255 targetedModule->templateImplAsts[structBaseName] = implStmt;
2256 } else {
2257 // specialize template struct
2258 auto structTemplateAst = targetedModule->structTemplateAsts[structBaseName];
2259 specializeStructTemplate(structBaseName, concreteTemplateArgs, implStmt, targetModule);
2260 }
2261 }
2262
2264 }
2265
2266 if (implStmt->isImplForStmt()) {
2267 auto interfaceName = parseInterfaceName(implStmt->interfaceName);
2268 std::shared_ptr<IRValueType> srcType;
2269 try {
2270 srcType = managedPtr(parseTypeSpec(implStmt->structName));
2271 targetModule = srcType->typeAffiliateModule;
2272 targetedModule = moduleContext->getCompilerContext()->getImportedModule(targetModule);
2273 } catch (std::runtime_error &e) {
2274 panic(implStmt->getLine(), implStmt->getColumn(), "Undefined struct: " + wstring2string(structBaseName));
2275 return {};
2276 }
2277 auto targetInterface =
2278 moduleContext->getCompilerContext()->getImportedModule(interfaceName.first.first)->interfaceTable[interfaceName.first.second];
2279 targetInterface->implementations.emplace_back(srcType->type, srcType->typeAffiliateModule, srcType->typeIndex);
2280 auto interfaceImplName = getInterfaceImplName(interfaceName.first, srcType);
2281
2282 yoi::indexT interfaceImplIndex{};
2283 try {
2284 interfaceImplIndex = targetedModule->interfaceImplementationTable.getIndex(interfaceImplName);
2285 if (targetedModule->interfaceImplementationTable[interfaceImplIndex]) {
2286 panic(
2287 implStmt->getLine(), implStmt->getColumn(), "Redefinition of interface implementation: " + wstring2string(interfaceImplName));
2288 }
2289 } catch (std::out_of_range &e) {
2290 interfaceImplIndex = targetedModule->interfaceImplementationTable.put(interfaceImplName, {});
2291 }
2292 if (implStmt->inner) {
2294 builder.setName(interfaceImplName);
2295 builder.setImplStructIndex({srcType->type, srcType->typeAffiliateModule, srcType->typeIndex});
2296 builder.setImplInterfaceIndex(interfaceName.first);
2297
2298 std::map<yoi::wstr, std::pair<yoi::wstr, std::shared_ptr<IRValueType>>> virtualMethodMap;
2299
2300 for (auto &i : implStmt->getInner().getInner()) {
2301 yoi_assert(i->isMethod(),
2302 i->getLine(),
2303 i->getColumn(),
2304 "impl-for statement only allows method definition, not constructor or finalizer");
2305
2306 bool isVaridic = false;
2307
2308 auto methodName = i->getMethod().getName().getId().get().strVal;
2309 IRFunctionDefinition::Builder methodBuilder;
2310
2311 methodBuilder.setDebugInfo({irModule->modulePath, i->getLine(), i->getColumn()});
2312 methodBuilder.attrs = getFunctionAttributes(i->getMethod().attrs);
2313 methodBuilder.attrs.insert(IRFunctionDefinition::FunctionAttrs::Preserve);
2314
2316
2317 const auto &thisType = srcType;
2318 if (std::find(methodBuilder.attrs.begin(), methodBuilder.attrs.end(), IRFunctionDefinition::FunctionAttrs::Static) ==
2319 methodBuilder.attrs.end())
2320 methodBuilder.addArgument(L"this", thisType);
2321
2322 for (auto &arg : i->getMethod().getArgs().get()) {
2323 if (&arg == &i->getMethod().getArgs().get().back() && arg->spec->kind == typeSpec::typeSpecKind::Elipsis) {
2324 isVaridic = true;
2325 methodBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Variadic);
2326 auto argName = arg->getId().node.strVal;
2327 auto argType =
2328 managedPtr(arg->spec->elipsis ? parseTypeSpec(arg->spec->elipsis).getDynamicArrayType()
2329 : moduleContext->getCompilerContext()->getNullInterfaceType()->getDynamicArrayType());
2330 methodBuilder.addArgument(argName, argType);
2331 argTypes.push_back(argType);
2332 break;
2333 }
2334 auto argName = arg->getId().get().strVal;
2335 auto argType = managedPtr(parseTypeSpec(arg->spec));
2336 methodBuilder.addArgument(argName, argType);
2337 argTypes.push_back(argType);
2338 }
2339 auto uniq = getFuncUniqueNameStr(argTypes);
2340 methodBuilder.setReturnType(managedPtr(parseTypeSpec(i->getMethod().resultType)));
2341 methodBuilder.setName(structBaseName + L"::" + methodName + uniq + L"interfaceImpl#" + interfaceImplName);
2342
2343 auto func = methodBuilder.yield();
2344 auto funcIndex = targetedModule->functionTable.put_create(func->name, func);
2345 targetedModule->functionOverloadIndexies[structBaseName + L"::" + methodName + L"interfaceImpl#" + interfaceImplName].push_back(
2346 funcIndex);
2347 /*builder.addVirtualMethod(
2348 methodName + uniq,
2349 managedPtr(IRValueType{IRValueType::valueType::virtualMethod, targetModule, funcIndex}));*/
2350 virtualMethodMap[methodName + getFuncUniqueNameStr(argTypes, true)] = {
2351 methodName + uniq, managedPtr(IRValueType{IRValueType::valueType::virtualMethod, targetModule, funcIndex})};
2352
2354 moduleContext->getIRBuilder().setDebugInfo({irModule->modulePath, i->getLine(), i->getColumn()});
2356 visit(i->getMethod().block, true);
2359 }
2360
2361 for (auto &method : targetInterface->methodMap) {
2362 yoi_assert(virtualMethodMap.contains(method.first),
2363 implStmt->getLine(),
2365 "Method '" + wstring2string(method.first) + "' not implemented for interface '" +
2366 wstring2string(targetInterface->name) + "'");
2367 builder.addVirtualMethod(virtualMethodMap[method.first].first, virtualMethodMap[method.first].second);
2368 }
2369
2370 targetedModule->interfaceImplementationTable[interfaceImplIndex] = builder.yield();
2371 } else {
2372 // forward-declaration
2373 }
2374 } else {
2375 indexT structIndex;
2376 try {
2377 structIndex = targetedModule->structTable.getIndex(structBaseName);
2378 } catch (std::runtime_error &e) {
2379 panic(implStmt->getLine(), implStmt->getColumn(), "Undefined struct: " + wstring2string(structBaseName));
2380 }
2381
2382 for (auto &i : implStmt->getInner().getInner()) {
2383 yoi::wstr mangledName;
2384 yoi::codeBlock *block{};
2385 if (i->isConstructor()) {
2386 bool isVaridic = false;
2388 for (auto &arg : i->getConstructor().getArgs().get()) {
2389 if (&arg == &i->getConstructor().getArgs().get().back() && arg->spec->kind == typeSpec::typeSpecKind::Elipsis) {
2390 isVaridic = true;
2391 auto argType = managedPtr(moduleContext->getCompilerContext()->getNullInterfaceType()->getDynamicArrayType());
2392 argTypes.push_back(argType);
2393 break;
2394 }
2395 argTypes.push_back(managedPtr(parseTypeSpec(arg->spec)));
2396 }
2397 mangledName = structBaseName + L"::constructor" + getFuncUniqueNameStr(argTypes);
2398 block = i->getConstructor().block;
2399 } else if (i->isFinalizer()) {
2400 mangledName = structBaseName + L"::finalizer";
2401 block = i->getFinalizer().block;
2402 } else {
2403 if (i->getMethod().getName().hasTemplateArg()) {
2404 // template method definition for a non-template struct
2405 auto structDef = targetedModule->structTable[structIndex];
2406 structDef->templateMethodDefs[i->getMethod().getName().getId().get().strVal] = i;
2407 continue;
2408 }
2409 // whole bunch of shit doin' here is to get the mangled name of the method, no actual modification of original func def here.
2410 bool isVaridic = false;
2412 for (auto &arg : i->getMethod().getArgs().get()) {
2413 if (&arg == &i->getMethod().getArgs().get().back() && arg->spec->kind == typeSpec::typeSpecKind::Elipsis) {
2414 isVaridic = true;
2415 auto type =
2416 arg->spec->elipsis ? parseTypeSpec(arg->spec->elipsis) : *moduleContext->getCompilerContext()->getNullInterfaceType();
2417 auto argType = managedPtr(type.getDynamicArrayType());
2418 argTypes.push_back(argType);
2419 break;
2420 }
2421 argTypes.push_back(managedPtr(parseTypeSpec(arg->spec)));
2422 }
2423 mangledName = structBaseName + L"::" + i->getMethod().getName().getId().get().strVal + getFuncUniqueNameStr(argTypes);
2424 block = i->getMethod().block;
2425 }
2426
2427 try {
2428 auto funcIndex = targetedModule->functionTable.getIndex(mangledName);
2429 auto func = targetedModule->functionTable[funcIndex];
2431 moduleContext->getIRBuilder().setDebugInfo({irModule->modulePath, i->getLine(), i->getColumn()});
2433 visit(block, true);
2436 } catch (std::out_of_range &e) {
2437 panic(
2438 i->getLine(), i->getColumn(), "No matched constructor or method declaration found for impl: " + wstring2string(mangledName));
2439 }
2440 }
2441 }
2443 }
2444
2446 for (auto &i : letStmt->terms) {
2447 visit(i->rhs);
2448 auto type = i->type ? managedPtr(parseTypeSpec(i->type)) : moduleContext->getIRBuilder().getRhsFromTempVarStack();
2449 if (i->lhs->kind == letAssignmentPairLHS::vKind::identifier) {
2450 if (isVisitingGlobalScope()) {
2451 // global variable
2452 tryCastTo(type);
2453 auto index = irModule->globalVariables.put(i->lhs->id->node.strVal, type);
2454 moduleContext->getIRBuilder().storeOp(IR::Opcode::store_global, {IROperand::operandType::globalVar, index});
2455
2456 } else {
2457 tryCastTo(type);
2458 auto index = moduleContext->getIRBuilder().irFuncDefinition()->getVariableTable().put(i->lhs->id->node.strVal, type);
2459 moduleContext->getIRBuilder().storeOp(IR::Opcode::store_local, {IROperand::operandType::localVar, index});
2460 }
2461 } else if (i->lhs->kind == letAssignmentPairLHS::vKind::list) {
2462 // structured binding
2463 if (type->isArrayType() || type->isDynamicArrayType()) {
2464 // array binding
2465 IRBuilder::ExtractType extractType{i->lhs->list.back().kind == lexer::token::tokenKind::kThreeDots
2466 ? IRBuilder::ExtractType::First
2467 : IRBuilder::ExtractType::Last};
2468 bool isFull = i->lhs->list.back().kind != lexer::token::tokenKind::kThreeDots &&
2469 i->lhs->list.front().kind != lexer::token::tokenKind::kThreeDots;
2470 auto elementCount = i->lhs->list.size() - !isFull;
2471 moduleContext->getIRBuilder().bindElementsOp(elementCount, extractType);
2472 auto bindType = managedPtr(type->getElementType());
2473 for (yoi::indexT curPos = extractType == IRBuilder::ExtractType::First && !isFull; curPos < elementCount; curPos++) {
2474 if (isVisitingGlobalScope()) {
2475 // global variable
2476 auto index = irModule->globalVariables.put(i->lhs->list[i->lhs->list.size() - 1 - curPos].strVal, bindType);
2477 moduleContext->getIRBuilder().storeOp(IR::Opcode::store_global, {IROperand::operandType::globalVar, index});
2478
2479 } else {
2480 auto index = moduleContext->getIRBuilder().irFuncDefinition()->getVariableTable().put(
2481 i->lhs->list[i->lhs->list.size() - 1 - curPos].strVal, bindType);
2482 moduleContext->getIRBuilder().storeOp(IR::Opcode::store_local, {IROperand::operandType::localVar, index});
2483 }
2484 }
2485 } else if (type->type == IRValueType::valueType::structObject) {
2486 // struct binding
2487 IRBuilder::ExtractType extractType{i->lhs->list.back().kind == lexer::token::tokenKind::kThreeDots
2488 ? IRBuilder::ExtractType::First
2489 : IRBuilder::ExtractType::Last};
2490 bool isFull = i->lhs->list.back().kind != lexer::token::tokenKind::kThreeDots &&
2491 i->lhs->list.front().kind != lexer::token::tokenKind::kThreeDots;
2492 yoi::indexT elementCount = i->lhs->list.size() - !isFull;
2493 yoi::indexT startPos = extractType == IRBuilder::ExtractType::First ? elementCount - 1 : i->lhs->list.size() - 1;
2494 yoi::indexT endPos = extractType == IRBuilder::ExtractType::First ? -1 : 0 - isFull;
2495 moduleContext->getIRBuilder().bindFieldsOp(elementCount, extractType);
2496 for (yoi::indexT curPos = startPos; curPos != endPos; curPos -= 1) {
2498 if (isVisitingGlobalScope()) {
2499 // global variable
2500 auto index = irModule->globalVariables.put(i->lhs->list[curPos].strVal, fieldType);
2501 tryCastTo(fieldType);
2502 moduleContext->getIRBuilder().storeOp(IR::Opcode::store_global, {IROperand::operandType::globalVar, index});
2503
2504 } else {
2505 auto index =
2506 moduleContext->getIRBuilder().irFuncDefinition()->getVariableTable().put(i->lhs->list[curPos].strVal, fieldType);
2507 tryCastTo(fieldType);
2508 moduleContext->getIRBuilder().storeOp(IR::Opcode::store_local, {IROperand::operandType::localVar, index});
2509 }
2510 }
2511 } else {
2512 panic(i->getLine(), i->getColumn(), "Unsupported structured binding");
2513 }
2514 }
2515 }
2517 }
2518
2519 void visitor::visit(yoi::globalStmt *globalStmt) {
2520 if (!checkMarcoSatisfaction(globalStmt->marco))
2521 return;
2522 switch (globalStmt->kind) {
2523 case globalStmt::vKind::useStmt: {
2524 visit(globalStmt->value.useStmtVal);
2525 break;
2526 }
2527 case globalStmt::vKind::implStmt: {
2529 break;
2530 }
2531 case globalStmt::vKind::letStmt: {
2532 visit(globalStmt->value.letStmtVal);
2533 break;
2534 }
2535 case globalStmt::vKind::funcDefStmt: {
2537 break;
2538 }
2539 case globalStmt::vKind::structDefStmt: {
2541 break;
2542 }
2543 case globalStmt::vKind::interfaceDefStmt: {
2545 break;
2546 }
2547 case globalStmt::vKind::importDecl: {
2549 break;
2550 }
2551 case globalStmt::vKind::exportDecl: {
2553 break;
2554 }
2555 case globalStmt::vKind::typeAliasStmt: {
2557 break;
2558 }
2559 case globalStmt::vKind::enumerationDef: {
2561 break;
2562 }
2563 case globalStmt::vKind::dataStructDefStmt: {
2565 break;
2566 }
2567 case globalStmt::vKind::conceptDef: {
2569 break;
2570 }
2571 default: {
2572 panic(globalStmt->getLine(), globalStmt->getColumn(), "Unsupported global statement type");
2573 }
2574 }
2575 }
2576
2577 yoi::indexT visitor::visit(yoi::ifStmt *ifStmt) {
2578 visit(ifStmt->getIfBlock().cond);
2580 yoi_assert(condType->type == IRValueType::valueType::booleanObject,
2581 ifStmt->getLine(),
2582 ifStmt->getColumn(),
2583 "The type in if-condition must be boolean");
2584
2585 auto ifBlock = moduleContext->getIRBuilder().createCodeBlock();
2586 auto outBlock = moduleContext->getIRBuilder().createCodeBlock();
2587
2588 moduleContext->getIRBuilder().jumpIfOp(IR::Opcode::jump_if_true, ifBlock);
2589 auto back = moduleContext->getIRBuilder().switchCodeBlock(ifBlock);
2590 visit(ifStmt->getIfBlock().block, true);
2591 moduleContext->getIRBuilder().jumpOp(outBlock);
2593
2594 for (auto &i : ifStmt->elifB) {
2595 visit(i.cond);
2596 auto elifCondType = moduleContext->getIRBuilder().getRhsFromTempVarStack();
2597 yoi_assert(elifCondType->type == IRValueType::valueType::booleanObject,
2598 i.cond->getLine(),
2599 i.cond->getColumn(),
2600 "The type in elif-condition must be boolean");
2601
2602 auto elifBlock = moduleContext->getIRBuilder().createCodeBlock();
2603 moduleContext->getIRBuilder().jumpIfOp(IR::Opcode::jump_if_true, elifBlock);
2604 auto back = moduleContext->getIRBuilder().switchCodeBlock(elifBlock);
2605 visit(i.block, true);
2606 moduleContext->getIRBuilder().jumpOp(outBlock);
2608 }
2609
2610 if (ifStmt->hasElseBlock()) {
2611 auto elseBlock = moduleContext->getIRBuilder().createCodeBlock();
2612 moduleContext->getIRBuilder().jumpOp(elseBlock);
2613 auto back = moduleContext->getIRBuilder().switchCodeBlock(elseBlock);
2614 visit(ifStmt->elseB, true);
2615 moduleContext->getIRBuilder().jumpOp(outBlock);
2617 } else {
2618 moduleContext->getIRBuilder().jumpOp(outBlock);
2619 }
2622 }
2623
2625 auto condBlock = moduleContext->getIRBuilder().createCodeBlock();
2626 moduleContext->getIRBuilder().jumpOp(condBlock);
2627 auto back = moduleContext->getIRBuilder().switchCodeBlock(condBlock);
2628
2629 visit(whileStmt->cond);
2631 yoi_assert(condType->type == IRValueType::valueType::booleanObject,
2632 whileStmt->getLine(),
2634 "The type in while-condition must be boolean");
2635
2636 auto whileBlock = moduleContext->getIRBuilder().createCodeBlock();
2637 auto outBlock = moduleContext->getIRBuilder().createCodeBlock();
2638
2639 moduleContext->getIRBuilder().jumpIfOp(IR::Opcode::jump_if_true, whileBlock);
2640 moduleContext->getIRBuilder().jumpOp(outBlock);
2642 moduleContext->getIRBuilder().pushLoopContext(outBlock, condBlock);
2643 visit(whileStmt->block, true);
2645
2646 moduleContext->getIRBuilder().jumpOp(condBlock);
2648
2650 }
2651
2653 moduleContext->getIRBuilder().irFuncDefinition()->getVariableTable().createScope();
2654 auto initBlock = moduleContext->getIRBuilder().createCodeBlock();
2655 auto condBlock = moduleContext->getIRBuilder().createCodeBlock();
2657 auto afterBlock = moduleContext->getIRBuilder().createCodeBlock();
2658 auto outBlock = moduleContext->getIRBuilder().createCodeBlock();
2659
2660 moduleContext->getIRBuilder().jumpOp(initBlock);
2661
2663 visit(forStmt->initStmt);
2664
2665 moduleContext->getIRBuilder().jumpOp(condBlock);
2667 visit(forStmt->cond);
2669 yoi_assert(condType->type == IRValueType::valueType::booleanObject,
2670 forStmt->getLine(),
2671 forStmt->getColumn(),
2672 "The type in for-condition must be boolean");
2673
2674 moduleContext->getIRBuilder().jumpIfOp(IR::Opcode::jump_if_true, codeBlock);
2675 moduleContext->getIRBuilder().jumpOp(outBlock);
2677 moduleContext->getIRBuilder().pushLoopContext(outBlock, afterBlock);
2678 visit(forStmt->block, true);
2680
2681 moduleContext->getIRBuilder().jumpOp(afterBlock);
2683 visit(forStmt->afterStmt);
2684
2685 moduleContext->getIRBuilder().jumpOp(condBlock);
2687
2688 moduleContext->getIRBuilder().irFuncDefinition()->getVariableTable().popScope();
2689
2691 }
2692
2693 void visitor::visit(yoi::forEachStmt *forEachStmt) {
2694 // TODO: implement foreach statement
2695 panic(forEachStmt->getLine(), forEachStmt->getColumn(), "forEach statement is not implemented yet");
2696 }
2697
2699 if (returnStmt->hasValue()) {
2700 yoi_assert(!moduleContext->getIRBuilder().irFuncDefinition()->hasAttribute(IRFunctionDefinition::FunctionAttrs::Generator),
2703 "Generator function cannot return a value");
2704 visit(returnStmt->value);
2705 // validate type
2706 auto returnType = moduleContext->getIRBuilder().irFuncDefinition()->returnType;
2707 tryCastTo(returnType);
2709 } else {
2710 // TODO: return void
2712 }
2714 }
2715
2720
2725
2728 auto baseName = identifierWithTemplateArg->getId().node.strVal;
2729 auto concreteTypes = parseTemplateArgs(identifierWithTemplateArg->getArg());
2730
2731 if (irModule->structTemplateAsts.contains(baseName)) {
2732 try {
2733 auto pureTemplateAst = irModule->templateImplAsts.at(baseName);
2734 auto specializedIndex = specializeStructTemplate(baseName, concreteTypes, pureTemplateAst, currentModuleIndex);
2735 return {IRValueType::valueType::structObject, currentModuleIndex, specializedIndex};
2736 } catch (std::out_of_range &e) {
2739 "No implementation block found for struct template: " + wstring2string(baseName));
2740 }
2741 } else if (irModule->templateInterfaceAsts.contains(baseName)) {
2742 auto specializedIndex = specializeInterfaceTemplate(baseName, concreteTypes, currentModuleIndex);
2743 return {IRValueType::valueType::interfaceObject, currentModuleIndex, specializedIndex};
2744 } else {
2746 }
2747 } else {
2748 return parseTypeSpec(identifierWithTemplateArg->id);
2749 }
2750 }
2751
2753 if (!subscriptExpr->getSubscript().empty()) {
2754 // This is an array type like `int[10]`
2755 auto baseType = parseTypeSpec(subscriptExpr->id);
2756 yoi::vec<yoi::indexT> dimensions;
2757 for (auto &sub : subscriptExpr->getSubscript()) {
2758 yoi_assert(sub->isSubscript() && sub->expr->getToken().kind == lexer::token::tokenKind::integer,
2759 sub->getLine(),
2760 sub->getColumn(),
2761 "Expected dimension size for array type.");
2762 dimensions.push_back(sub->expr->getToken().basicVal.vInt);
2763 }
2764 return baseType.getArrayType(dimensions);
2765 } else {
2766 return parseTypeSpec(subscriptExpr->id);
2767 }
2768 }
2769
2770 IRValueType visitor::parseTypeSpecExtern(yoi::identifier *identifier, yoi::indexT targetModule) {
2771 auto mod = moduleContext->getCompilerContext()->getImportedModule(targetModule);
2772 if (auto it = mod->typeAliases.find(identifier->get().strVal); it != mod->typeAliases.end()) {
2773 return it->second;
2774 }
2775 IRExternEntry ex = getExternEntry(targetModule, identifier->node.strVal);
2776 if (ex.type == IRExternEntry::externType::structType)
2777 return {IRValueType::valueType::structObject, ex.affiliateModule, ex.itemIndex};
2778 if (ex.type == IRExternEntry::externType::datastructType)
2779 return {IRValueType::valueType::datastructObject, ex.affiliateModule, ex.itemIndex};
2780 else if (ex.type == IRExternEntry::externType::interfaceType)
2781 return {IRValueType::valueType::interfaceObject, ex.affiliateModule, ex.itemIndex};
2782 else
2783 throw std::out_of_range("Unsupported extern type: " + wstring2string(identifier->node.strVal));
2784 }
2785
2788 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(targetModule);
2789
2790 auto baseName = identifierWithTemplateArg->getId().node.strVal;
2791 auto concreteTypes = parseTemplateArgs(identifierWithTemplateArg->getArg());
2792
2793 if (targetedModule->structTemplateAsts.contains(baseName)) {
2794 try {
2795 auto pureTemplateAst = targetedModule->templateImplAsts.at(baseName);
2796 auto specializedIndex = specializeStructTemplate(baseName, concreteTypes, pureTemplateAst, targetModule);
2797 return {IRValueType::valueType::structObject, targetModule, specializedIndex};
2798 } catch (std::out_of_range &e) {
2801 "No implementation block found for struct template: " + wstring2string(baseName));
2802 }
2803 } else if (targetedModule->templateInterfaceAsts.contains(baseName)) {
2804 auto specializedIndex = specializeInterfaceTemplate(baseName, concreteTypes, targetModule);
2805 return {IRValueType::valueType::interfaceObject, targetModule, specializedIndex};
2806 } else {
2808 }
2809 } else {
2810 return parseTypeSpecExtern(identifierWithTemplateArg->id, targetModule);
2811 }
2812 }
2813
2814 IRValueType visitor::parseTypeSpecExtern(yoi::subscriptExpr *subscriptExpr, yoi::indexT targetModule) {
2815 if (!subscriptExpr->getSubscript().empty()) {
2816 auto baseType = parseTypeSpecExtern(subscriptExpr->id, targetModule);
2817 // TODO: Create and return an extern array type, creating extern entries for dimensions if necessary.
2818 panic(subscriptExpr->getLine(), subscriptExpr->getColumn(), "TODO: Extern array type parsing not fully implemented.");
2819 return {IRValueType::valueType::null};
2820 } else {
2821 return parseTypeSpecExtern(subscriptExpr->id, targetModule);
2822 }
2823 }
2824
2825 IRValueType visitor::parseTypeSpec(yoi::typeSpec *typeSpec) {
2826 switch (typeSpec->kind) {
2827 case typeSpec::typeSpecKind::Member: {
2828 // member
2829 auto it = typeSpec->member->getTerms().begin();
2830 yoi::indexT targetModule = -1, lastModule = -1;
2831 while (it + 1 != typeSpec->member->getTerms().end() && (targetModule = isModuleName(*it, targetModule)) != lastModule) {
2832 it++;
2833 lastModule = targetModule;
2834 }
2835
2836 IRValueType lhs{IRValueType::valueType::integerObject};
2837 try {
2838 if (targetModule == -1) {
2839 lhs = parseTypeSpec(*it);
2840 } else {
2841 lhs = parseTypeSpecExtern(*it, targetModule);
2842 }
2843 } catch (std::out_of_range &e) {
2844 panic(typeSpec->getLine(), typeSpec->getColumn(), e.what());
2845 }
2846 yoi_assert(it + 1 == typeSpec->member->getTerms().end(), typeSpec->getLine(), typeSpec->getColumn(), "Type specifier is not valid.");
2847
2848 if (typeSpec->arraySubscript) {
2849 if (typeSpec->arraySubscript->front() == -1) {
2850 return lhs.getDynamicArrayType();
2851 } else {
2852 return lhs.getArrayType(*typeSpec->arraySubscript);
2853 }
2854 } else {
2855 return lhs;
2856 }
2857 }
2858 case typeSpec::typeSpecKind::Func: {
2859 // func
2860 return parseTypeSpec(typeSpec->func);
2861 }
2862 case typeSpec::typeSpecKind::Null: {
2863 // null
2864 return {IRValueType::valueType::null};
2865 }
2866 case typeSpec::typeSpecKind::DecltypeExpr: {
2867 auto state = moduleContext->getIRBuilder().saveState();
2871 return rhs;
2872 }
2873 case typeSpec::typeSpecKind::Elipsis: {
2874 // elipsis
2875 // let it fallback to invalid
2876 }
2877 default: {
2878 panic(typeSpec->getLine(), typeSpec->getColumn(), "Type specifier is not valid.");
2879 return {IRValueType::valueType::null};
2880 }
2881 }
2882 }
2883
2884 yoi::wstr visitor::parseIdentifierWithTemplateArg(yoi::identifierWithTemplateArg *identifierWithTemplateArg) {
2887 res += L"<";
2888 for (auto &i : identifierWithTemplateArg->getArg().get()) {
2889 res += parseTypeSpec(i->spec).to_string();
2890 res += L",";
2891 }
2892 res.pop_back();
2893 res += L">";
2894 }
2895 return std::move(res);
2896 }
2897
2898 yoi::wstr visitor::getInterfaceImplName(const std::pair<yoi::indexT, yoi::indexT> &interfaceSrc, const std::shared_ptr<IRValueType> &typeSrc) {
2899 return L"interfaceImpl#" + std::to_wstring(interfaceSrc.first) + L"#" + std::to_wstring(interfaceSrc.second) + L"#" + typeSrc->to_string();
2900 }
2901
2902 std::pair<std::pair<yoi::indexT, yoi::indexT>, std::shared_ptr<IRInterfaceInstanceDefinition>>
2903 visitor::parseInterfaceName(yoi::externModuleAccessExpression *structDef) {
2904 // modules~
2905 auto it = structDef->getTerms().begin();
2906 yoi::indexT targetModule = -1, lastModule = -1;
2907 while (it + 1 != structDef->getTerms().end() && (targetModule = isModuleName(*it, targetModule)) != lastModule) {
2908 it++;
2909 lastModule = targetModule;
2910 }
2911 if (targetModule == -1) {
2912 targetModule = currentModuleIndex;
2913 }
2914 yoi_assert(it + 1 == structDef->getTerms().end(), structDef->getLine(), structDef->getColumn(), "Invalid interface name");
2915 auto interfaceName = parseIdentifierWithTemplateArg(*it);
2916 try {
2917 auto target = moduleContext->getCompilerContext()->getImportedModule(targetModule);
2918 auto interfaceIndex = target->interfaceTable.getIndex(interfaceName);
2919 return std::make_pair(std::make_pair(targetModule, interfaceIndex), target->interfaceTable[interfaceIndex]);
2920 } catch (std::out_of_range &) {
2921 panic(structDef->getLine(), structDef->getColumn(), "Undefined interface: " + wstring2string(interfaceName));
2922 }
2923 }
2924
2925 yoi::indexT visitor::isModuleName(identifierWithTemplateArg *it, yoi::indexT currentModule) const {
2926 if (!it->hasTemplateArg()) {
2927 return isModuleName(it->id, currentModule);
2928 } else {
2929 return currentModule;
2930 }
2931 }
2932
2933 yoi::IRExternEntry visitor::getExternEntry(yoi::indexT moduleIndex, const yoi::wstr &identifier) const {
2934 try {
2935 auto res = moduleContext->getCompilerContext()->getImportedModule(moduleIndex)->globalVariables.getIndex(identifier);
2936 return {IRExternEntry::externType::globalVar, identifier, moduleIndex, res};
2937 } catch (std::out_of_range &) {
2938 }
2939 try {
2940 auto res = moduleContext->getCompilerContext()->getImportedModule(moduleIndex)->functionTable.getIndex(identifier);
2941 return {IRExternEntry::externType::function, identifier, moduleIndex, res};
2942 } catch (std::out_of_range &) {
2943 }
2944 try {
2945 auto res = moduleContext->getCompilerContext()->getImportedModule(moduleIndex)->structTable.getIndex(identifier);
2946 return {IRExternEntry::externType::structType, identifier, moduleIndex, res};
2947 } catch (std::out_of_range &) {
2948 }
2949 try {
2950 auto res = moduleContext->getCompilerContext()->getImportedModule(moduleIndex)->dataStructTable.getIndex(identifier);
2951 return {IRExternEntry::externType::datastructType, identifier, moduleIndex, res};
2952 } catch (std::out_of_range &) {
2953 }
2954 try {
2955 auto res = moduleContext->getCompilerContext()->getImportedModule(moduleIndex)->interfaceTable.getIndex(identifier);
2956 return {IRExternEntry::externType::interfaceType, identifier, moduleIndex, res};
2957 } catch (std::out_of_range &) {
2958 }
2959 try {
2960 auto res = moduleContext->getCompilerContext()->getImportedModule(moduleIndex)->interfaceImplementationTable.getIndex(identifier);
2961 return {IRExternEntry::externType::interfaceImplType, identifier, moduleIndex, res};
2962 } catch (std::out_of_range &) {
2963 }
2964
2965 throw std::out_of_range("undefined identifier: not known global variable, function, struct or interface type: " +
2967 }
2968
2969 bool visitor::isVisitingGlobalScope() const {
2970 return moduleContext->getIRBuilder().irFuncDefinition()->name == L"yoimiya_glob_initializer";
2971 }
2972
2973 void visitor::emitBasicCastInBasicArithOpByLhsAndRhs(yoi::indexT lhs, yoi::indexT rhs) {
2976
2977 if (lhsType->isForeignBasicType()) {
2978 lhsType = managedPtr(lhsType->getNormalizedForeignBasicType());
2979 }
2980 if (rhsType->isForeignBasicType()) {
2981 rhsType = managedPtr(rhsType->getNormalizedForeignBasicType());
2982 }
2983
2984 // if bool and char with other, upcast to other
2985 if (lhsType->is1ByteType() && !rhsType->is1ByteType()) {
2986 moduleContext->getIRBuilder().basicCast(rhsType, lhs, true);
2987 } else if (!lhsType->is1ByteType() && rhsType->is1ByteType()) {
2988 moduleContext->getIRBuilder().basicCast(lhsType, rhs);
2989 }
2990 // if short with other, upcast to other
2991 if (lhsType->type == IRValueType::valueType::shortObject && rhsType->type != IRValueType::valueType::shortObject) {
2992 moduleContext->getIRBuilder().basicCast(rhsType, lhs, true);
2993 } else if (lhsType->type != IRValueType::valueType::shortObject && rhsType->type == IRValueType::valueType::shortObject) {
2994 moduleContext->getIRBuilder().basicCast(lhsType, rhs);
2995 }
2996 // if int with deci, upcast to deci
2997 else if (lhsType->type == IRValueType::valueType::integerObject && rhsType->type == IRValueType::valueType::decimalObject) {
2998 moduleContext->getIRBuilder().basicCast(rhsType, lhs, true);
2999 } else if (lhsType->type == IRValueType::valueType::decimalObject && rhsType->type == IRValueType::valueType::integerObject) {
3000 moduleContext->getIRBuilder().basicCast(lhsType, rhs);
3001 }
3002 // if unsigned with int, upcast to int
3003 else if (lhsType->type == IRValueType::valueType::unsignedObject && rhsType->type == IRValueType::valueType::integerObject) {
3004 moduleContext->getIRBuilder().basicCast(rhsType, lhs, true);
3005 } else if (lhsType->type == IRValueType::valueType::integerObject && rhsType->type == IRValueType::valueType::unsignedObject) {
3006 moduleContext->getIRBuilder().basicCast(lhsType, rhs);
3007 }
3008 // if unsigned with deci, upcast to deci
3009 else if (lhsType->type == IRValueType::valueType::unsignedObject && rhsType->type == IRValueType::valueType::decimalObject) {
3010 moduleContext->getIRBuilder().basicCast(rhsType, lhs, true);
3011 } else if (lhsType->type == IRValueType::valueType::decimalObject && rhsType->type == IRValueType::valueType::unsignedObject) {
3012 moduleContext->getIRBuilder().basicCast(lhsType, rhs);
3013 }
3014 // if left or right is pointer, cast the other to pointer
3015 else if (lhsType->type == IRValueType::valueType::pointerObject) {
3016 moduleContext->getIRBuilder().basicCast(lhsType, rhs);
3017 } else if (rhsType->type == IRValueType::valueType::pointerObject) {
3018 moduleContext->getIRBuilder().basicCast(rhsType, lhs, true);
3019 }
3020 }
3021
3022 void visitor::emitBasicCastTo(const std::shared_ptr<IRValueType> &toType) {
3024
3025 if (rhs->type == toType->type) {
3026 return;
3027 } else {
3029 }
3030 }
3031
3032 yoi::wstr visitor::getInterfaceNameStr(const std::pair<yoi::indexT, yoi::indexT> &interfaceSrc) {
3033 return L"interface#" + std::to_wstring(interfaceSrc.first) + L"#" + std::to_wstring(interfaceSrc.second);
3034 }
3035
3036 yoi::wstr visitor::getTypeSpecUniqueNameStr(const std::shared_ptr<IRValueType> &type) {
3037 yoi::wstr res;
3038 switch (type->type) {
3039 case IRValueType::valueType::integerObject:
3040 res = L"int";
3041 break;
3042 case IRValueType::valueType::decimalObject:
3043 res = L"deci";
3044 break;
3045 case IRValueType::valueType::booleanObject:
3046 res = L"bool";
3047 break;
3048 case IRValueType::valueType::stringObject:
3049 res = L"str";
3050 break;
3051 case IRValueType::valueType::characterObject:
3052 res = L"char";
3053 break;
3054 case IRValueType::valueType::shortObject:
3055 res = L"short";
3056 break;
3057 case IRValueType::valueType::unsignedObject:
3058 res = L"unsigned";
3059 break;
3060 case IRValueType::valueType::structObject:
3061 res = L"struct#" + std::to_wstring(type->typeAffiliateModule) + L"#" + std::to_wstring(type->typeIndex);
3062 break;
3063 case IRValueType::valueType::null:
3064 res = L"null";
3065 break;
3066 case IRValueType::valueType::virtualMethod:
3067 res = L"virtual_method#" + std::to_wstring(type->typeAffiliateModule) + L"#" + std::to_wstring(type->typeIndex);
3068 break;
3069 case IRValueType::valueType::incompleteTemplateType:
3070 res = L"incomplete_template_type#" + std::to_wstring(type->typeIndex);
3071 break;
3072 case IRValueType::valueType::interfaceObject:
3073 res = L"interfaceObject#" + std::to_wstring(type->typeAffiliateModule) + L"#" + std::to_wstring(type->typeIndex);
3074 break;
3075 case IRValueType::valueType::pointerObject:
3076 res = L"pointerObject";
3077 break;
3078 case IRValueType::valueType::none:
3079 res = L"none";
3080 break;
3081 case IRValueType::valueType::datastructObject:
3082 res += L"datastructObject#" + std::to_wstring(type->typeAffiliateModule) + L"#" + std::to_wstring(type->typeIndex);
3083 break;
3084 default:
3087 "Invalid type");
3088 break;
3089 }
3090 if (type->isArrayType()) {
3091 yoi::indexT arraySize = 1;
3092 for (auto &dim : type->dimensions) {
3093 arraySize *= dim;
3094 }
3095 res += L"[" + std::to_wstring(arraySize) + L"]";
3096 } else if (type->isDynamicArrayType()) {
3097 res += L"[]";
3098 }
3099 return res;
3100 }
3101
3102 yoi::wstr visitor::getFuncUniqueNameStr(const std::vector<std::shared_ptr<IRValueType>> &argumentTypes, bool whetherIgnoreFirstParam) {
3103 yoi::wstr res = L"#";
3104 bool first = false;
3105 for (auto &arg : argumentTypes) {
3106 if (whetherIgnoreFirstParam && !first || !whetherIgnoreFirstParam)
3107 res += getTypeSpecUniqueNameStr(arg) + L"#";
3108 else
3109 first = false;
3110 }
3111 if (!argumentTypes.empty()) {
3112 res.pop_back();
3113 }
3114 res.shrink_to_fit();
3115 return res;
3116 }
3117
3118 yoi::indexT visitor::visitExtern(yoi::identifier *identifier, yoi::indexT targetModule, bool isStoreOp) {
3119 try {
3120 yoi::IRExternEntry entry = getExternEntry(targetModule, identifier->get().strVal);
3121 yoi_assert(entry.type == IRExternEntry::externType::globalVar,
3124 "Invalid type specifier, expected global variable");
3125 auto valType = moduleContext->getCompilerContext()->getImportedModule(targetModule)->globalVariables[identifier->node.strVal];
3126 if (isStoreOp) {
3127 tryCastTo(valType);
3129 IR::Opcode::store_global, {IROperand::operandType::externVar, entry.itemIndex}, entry.affiliateModule);
3131 } else {
3133 IR::Opcode::load_global, {IROperand::operandType::externVar, entry.itemIndex}, valType, entry.affiliateModule);
3135 }
3136 } catch (std::runtime_error &) {
3137 panic(identifier->getLine(), identifier->getColumn(), "undefined identifier: " + wstring2string(identifier->node.strVal));
3139 } catch (std::out_of_range &) {
3140 panic(identifier->getLine(), identifier->getColumn(), "undefined identifier: " + wstring2string(identifier->node.strVal));
3142 }
3143 }
3144
3145 yoi::indexT visitor::visitExtern(yoi::identifierWithTemplateArg *identifierWithTemplateArg, yoi::indexT targetModule, bool isStoreOp) {
3147 // TODO: what the heck is this
3148 panic(identifierWithTemplateArg->getLine(), identifierWithTemplateArg->getColumn(), "Invalid visit of identifier with template arg.");
3149 return 0;
3150 } else {
3151 return visitExtern(identifierWithTemplateArg->id, targetModule);
3152 }
3153 }
3154
3155 std::shared_ptr<IRValueType> visitor::getIncompleteType(const yoi::wstr &typeName) const {
3156 try {
3157 if (moduleContext->getTemplateBuilders().empty()) {
3158 throw std::out_of_range("No template builder found");
3159 }
3160 auto &templateBuilder = *moduleContext->getTemplateBuilders().rbegin();
3161 auto res = templateBuilder.templateArguments[typeName];
3162 return res.templateType;
3163 } catch (std::out_of_range &e) {
3164 throw std::out_of_range("Cannot find incomplete type: " + yoi::wstring2string(typeName));
3165 }
3166 }
3167
3170 for (auto &arg : templateArgs.spec) {
3171 yoi::wstr name = arg->getId().get().strVal;
3172 auto index = res.put_create(name, {{}});
3173 res[index].templateType = managedPtr(IRValueType{IRValueType::valueType::incompleteTemplateType, currentModuleIndex, index});
3174 }
3175 return res;
3176 }
3177
3178 yoi::vec<std::shared_ptr<IRValueType>> visitor::parseTemplateArgs(const yoi::templateArg &templateArgs) {
3180 for (auto &arg : templateArgs.spec) {
3181 res.push_back(managedPtr(parseTypeSpec(arg->spec)));
3182 }
3183 return res;
3184 }
3185
3186 yoi::indexT visitor::specializeFunctionTemplate(yoi::funcDefStmt *astNode,
3187 const yoi::vec<std::shared_ptr<IRValueType>> &concreteTemplateArgs,
3188 yoi::indexT moduleIndex) {
3189 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(moduleIndex);
3190
3191 yoi::wstr specializedName = getMangledTemplateName(astNode->id->id->get().strVal, concreteTemplateArgs);
3192
3193 // Create a new function definition by specializing the template
3195
3196 builder.setDebugInfo({targetedModule->modulePath, astNode->getLine(), astNode->getColumn()});
3197
3198 // Create specialization context
3199 IRTemplateBuilder specializationContext;
3200 for (yoi::indexT i = 0; i < astNode->id->arg->get().size(); ++i) {
3201 auto paramName = astNode->id->arg->get()[i]->id->get().strVal;
3202 if (astNode->id->hasDefTemplateArg() && astNode->id->arg->get()[i]->satisfyCondition) {
3203 for (auto &c : astNode->id->arg->get()[i]->satisfyCondition->emaes) {
3204 checkConceptSatisfaction(c, paramName, concreteTemplateArgs[i]);
3205 }
3206 }
3207 specializationContext.addTemplateArgument(paramName, concreteTemplateArgs[i]);
3208 }
3209
3210 pushModuleContext(moduleIndex);
3211 moduleContext->pushTemplateBuilder(specializationContext);
3212
3213 // Specialize arguments and return type
3215 for (const auto &argPair : astNode->getArgs().get()) {
3216 auto argName = argPair->getId().get().strVal;
3217 auto argType = managedPtr(parseTypeSpec(&argPair->getSpec()));
3218 builder.addArgument(argName, argType);
3219 paramTypes.push_back(argType);
3220 }
3221
3222 if (targetedModule->functionTable.contains(specializedName + getFuncUniqueNameStr(paramTypes))) {
3223 auto result = targetedModule->functionTable.getIndex(specializedName + getFuncUniqueNameStr(paramTypes));
3224 // restore environment
3226 popModuleContext();
3227 return result;
3228 }
3229
3230 builder.setName(specializedName + getFuncUniqueNameStr(paramTypes));
3231 builder.setReturnType(managedPtr(parseTypeSpec(&astNode->getResultType())));
3232
3233 auto specializedFunc = builder.yield();
3234 auto funcIndex = targetedModule->functionTable.put_create(specializedName + getFuncUniqueNameStr(paramTypes), specializedFunc);
3235 targetedModule->functionOverloadIndexies[specializedName].push_back(funcIndex);
3236
3237 // Visit the body to generate IR
3238 moduleContext->pushIRBuilder({moduleContext->getCompilerContext(), targetedModule, specializedFunc});
3239 moduleContext->getIRBuilder().setDebugInfo({targetedModule->modulePath, astNode->getLine(), astNode->getColumn()});
3241 try {
3242 visit(&astNode->getBlock(), true);
3243 } catch (std::runtime_error &e) {
3244 panic(astNode->getLine(),
3245 astNode->getColumn(),
3246 std::string("Exception occurred while specializing method: ") + yoi::wstring2string(specializedName) + ": " + e.what());
3247 } catch (std::exception &e) {
3248 panic(astNode->getLine(),
3249 astNode->getColumn(),
3250 std::string("Unknown exception occurred while specializing method: ") + yoi::wstring2string(specializedName) + ": " + e.what());
3251 }
3254
3255 // Pop context
3257 popModuleContext();
3258
3259 return funcIndex;
3260 }
3261
3262 yoi::wstr visitor::getMangledTemplateName(const yoi::wstr &baseName, const yoi::vec<std::shared_ptr<IRValueType>> &templateArgs) {
3263 yoi::wstr mangled = baseName + L"<";
3264 for (size_t i = 0; i < templateArgs.size(); ++i) {
3265 mangled += getTypeSpecUniqueNameStr(templateArgs[i]);
3266 if (i < templateArgs.size() - 1) {
3267 mangled += L",";
3268 }
3269 }
3270 mangled += L">";
3271 return mangled;
3272 }
3273
3274 yoi::vec<yoi::wstr> visitor::extractTemplateParamsFromTypeArgs(yoi::templateArg *templateArgs) {
3275 yoi::vec<yoi::wstr> params;
3276 if (!templateArgs)
3277 return params;
3278 for (auto &spec : templateArgs->get()) {
3279 auto typeSpec = &spec->get();
3280 // We expect simple identifier type specs, e.g. T, U
3281 if (typeSpec->kind == typeSpec::typeSpecKind::Member && typeSpec->member && typeSpec->member->getTerms().size() == 1) {
3282 auto term = typeSpec->member->getTerms()[0];
3283 if (!term->hasTemplateArg()) {
3284 params.push_back(term->id->get().strVal);
3285 continue;
3286 }
3287 }
3288 // If complex type or anything else, it's invalid for a definition param
3289 panic(templateArgs->getLine(), templateArgs->getColumn(), "Invalid template parameter definition. Expected identifier.");
3290 }
3291 return params;
3292 }
3293
3294 yoi::vec<yoi::wstr> visitor::extractTemplateParamsFromTypeArgs(yoi::defTemplateArg *templateArgs) {
3295 yoi::vec<yoi::wstr> params;
3296 if (!templateArgs)
3297 return params;
3298 for (auto &spec : templateArgs->get()) {
3299 params.push_back(spec->getId().get().strVal);
3300 }
3301 return params;
3302 }
3303
3304 yoi::indexT visitor::specializeStructTemplate(const yoi::wstr &templateName,
3305 const yoi::vec<std::shared_ptr<IRValueType>> &concreteTemplateArgs,
3306 yoi::implStmt *pureTemplateImplAst,
3307 yoi::indexT moduleIndex) {
3308
3309 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(moduleIndex);
3310
3311 yoi::wstr specializedName = getMangledTemplateName(templateName, concreteTemplateArgs);
3312
3313 if (targetedModule->structTable.contains(specializedName)) {
3314 return targetedModule->structTable.getIndex(specializedName);
3315 }
3316
3317 auto structAst = targetedModule->structTemplateAsts.at(templateName);
3318
3319 IRTemplateBuilder specializationContext;
3320 yoi_assert(concreteTemplateArgs.size() == structAst->id->getArg().get().size(),
3321 0,
3322 0,
3323 "Template argument count mismatch for struct " + wstring2string(templateName));
3324 for (yoi::indexT i = 0; i < concreteTemplateArgs.size(); ++i) {
3325 auto paramName = structAst->id->getArg().get()[i]->getId().get().strVal;
3326 // concept validation logic, partially
3327 if (structAst->id->hasDefTemplateArg() && structAst->id->getArg().get()[i]->satisfyCondition) {
3328 for (auto &c : structAst->id->getArg().get()[i]->satisfyCondition->emaes) {
3329 checkConceptSatisfaction(c, paramName, concreteTemplateArgs[i]);
3330 }
3331 }
3332 specializationContext.addTemplateArgument(paramName, concreteTemplateArgs[i]);
3333 }
3334
3335 auto specializedStructIndex = targetedModule->structTable.put_create(specializedName, nullptr);
3336
3337 generateNullInterfaceImplementation(managedPtr(IRValueType{IRValueType::valueType::structObject, moduleIndex, specializedStructIndex}));
3338 auto selfType = managedPtr(IRValueType{IRValueType::valueType::structObject, moduleIndex, specializedStructIndex});
3339 specializationContext.addTemplateArgument(L"STRUCT", selfType);
3340
3341 pushModuleContext(moduleIndex);
3342 moduleContext->pushTemplateBuilder(specializationContext);
3343
3345 builder.setName(specializedName);
3346 yoi::vec<yoi::wstr> paramNames;
3347 for (yoi::indexT i = 0; i < structAst->id->getArg().get().size(); ++i) {
3348 paramNames.push_back(structAst->id->getArg().get()[i]->getId().get().strVal);
3349 }
3350 builder.setStoredTemplateArgs(paramNames, concreteTemplateArgs);
3351 for (auto &field : structAst->getInner().getInner()) {
3352 if (field->kind == 0) {
3353 auto memberName = field->getVar().getId().get().strVal;
3354 auto memberType = managedPtr(parseTypeSpec(field->getVar().spec));
3355 if (field->modifier == structDefInnerPair::Modifier::DataField) {
3356 memberType->metadata.setMetadata(L"STRUCT_DATAFIELD", true);
3357 }
3358 builder.addField(memberName, memberType);
3359 } else if (field->kind == 2 && field->getMethod().getName().hasDefTemplateArg()) {
3360 // Generic method declaration
3361 builder.addTemplateMethodDecl(field->getMethod().getName().getId().get().strVal, field);
3362 } else {
3363 auto [funcIndex, funcName] =
3364 specializeStructMethodDeclaration(specializationContext, field, specializedName, concreteTemplateArgs, moduleIndex);
3365 builder.addMethod(funcName, funcIndex);
3366 }
3367 }
3368
3369 // Collect generic method definitions from the pure template impl
3370 if (pureTemplateImplAst) {
3371 for (auto &methodAst : pureTemplateImplAst->getInner().getInner()) {
3372 if (methodAst->isMethod() && methodAst->getMethod().getName().hasTemplateArg()) {
3373 builder.addTemplateMethodDef(methodAst->getMethod().getName().getId().get().strVal, methodAst);
3374 }
3375 }
3376 }
3377
3378 auto specializedStruct = builder.yield();
3379 targetedModule->structTable[specializedStructIndex] = specializedStruct;
3380
3381 // Specialize methods defined in `impl MyStruct<T> { ... }`
3382 if (pureTemplateImplAst) {
3383 for (auto &methodAst : pureTemplateImplAst->getInner().getInner()) {
3384 if (methodAst->isMethod() && methodAst->getMethod().getName().hasTemplateArg()) {
3385 // Handled above for templateMethodDefs
3386 continue;
3387 } else {
3388 specializeStructMethodDefinition(
3389 specializationContext, specializedStruct, methodAst, specializedName, concreteTemplateArgs, moduleIndex);
3390 }
3391 }
3392 }
3393
3394 if (targetedModule->templateInterfaceImplAsts.count(templateName)) {
3395 for (auto &implAst : targetedModule->templateInterfaceImplAsts.at(templateName)) {
3396 specializeInterfaceImplementation(
3397 implAst, selfType, specializedName, concreteTemplateArgs, currentModuleIndex); // now we are in the specialized context
3398 }
3399 }
3400
3402 popModuleContext();
3403
3404 return specializedStructIndex;
3405 }
3406
3407 yoi::indexT visitor::specializeStructMethodTemplate(const std::shared_ptr<IRStructDefinition> &structDef,
3409 yoi::implInnerPair *def,
3410 const yoi::wstr &baseMethodName,
3411 const yoi::vec<std::shared_ptr<IRValueType>> &methodTemplateArgs,
3412 yoi::indexT moduleIndex) {
3413 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(moduleIndex);
3414
3415 // Combine struct template args and method template args
3416 IRTemplateBuilder combinedContext;
3417 // Reconstruct struct specialization context
3418 for (size_t i = 0; i < structDef->templateParamNames.size(); ++i) {
3419 combinedContext.addTemplateArgument(structDef->templateParamNames[i], structDef->storedTemplateArgs[i]);
3420 }
3421
3422 // Add method template args
3423 yoi::vec<yoi::wstr> methodParams;
3424 if (decl) {
3425 methodParams = extractTemplateParamsFromTypeArgs(&decl->getMethod().getName().getArg());
3426 } else if (def) {
3427 methodParams = extractTemplateParamsFromTypeArgs(&def->getMethod().getName().getArg());
3428 }
3429
3430 yoi_assert(methodParams.size() == methodTemplateArgs.size(), 0, 0, "Method template argument count mismatch");
3431 for (size_t i = 0; i < methodParams.size(); ++i) {
3432 // here we specialize the template arguments of *this method*
3433 // still check the concept satisfaction
3434 if (decl->getMethod().getName().hasDefTemplateArg() && decl->getMethod().getName().arg->spec[i]->satisfyCondition) {
3435 auto paramName = decl->getMethod().getName().arg->spec[i]->id->get().strVal;
3436 for (auto &c : decl->getMethod().getName().arg->spec[i]->satisfyCondition->emaes) {
3437 checkConceptSatisfaction(c, paramName, methodTemplateArgs[i]);
3438 }
3439 }
3440 combinedContext.addTemplateArgument(methodParams[i], methodTemplateArgs[i]);
3441 }
3442
3443 yoi::wstr specializedMethodName = getMangledTemplateName(baseMethodName, methodTemplateArgs);
3444
3445 pushModuleContext(moduleIndex);
3446 moduleContext->pushTemplateBuilder(combinedContext);
3447
3448 // Reuse specializeStructMethodDeclaration logic but with combined context
3450 funcBuilder.setDebugInfo({targetedModule->modulePath, (decl ? decl->getLine() : def->getLine()), (decl ? decl->getColumn() : def->getColumn())});
3451
3452 auto selfType = managedPtr(IRValueType{IRValueType::valueType::structObject, moduleIndex, targetedModule->structTable.getIndex(structDef->name)});
3453 combinedContext.addTemplateArgument(L"STRUCT", selfType);
3454
3455 yoi::vec<std::shared_ptr<IRValueType>> specializedArgTypes;
3456 if (decl) {
3457 funcBuilder.attrs = getFunctionAttributes(decl->getMethod().attrs);
3458 if (std::find(funcBuilder.attrs.begin(), funcBuilder.attrs.end(), IRFunctionDefinition::FunctionAttrs::Static) == funcBuilder.attrs.end()) {
3459 funcBuilder.addArgument(L"this", selfType);
3460 }
3461 for (auto &arg : decl->getMethod().getArgs().get()) {
3462 auto specializedType = managedPtr(parseTypeSpec(&arg->getSpec()));
3463 funcBuilder.addArgument(arg->getId().get().strVal, specializedType);
3464 specializedArgTypes.push_back(specializedType);
3465 }
3466 funcBuilder.setReturnType(managedPtr(parseTypeSpec(&decl->getMethod().getResultType())));
3467 } else {
3468 // If only definition exists...
3469 funcBuilder.attrs = getFunctionAttributes(def->getMethod().attrs);
3470 if (std::find(funcBuilder.attrs.begin(), funcBuilder.attrs.end(), IRFunctionDefinition::FunctionAttrs::Static) == funcBuilder.attrs.end()) {
3471 funcBuilder.addArgument(L"this", selfType);
3472 }
3473 for (auto &arg : def->getMethod().getArgs().get()) {
3474 auto specializedType = managedPtr(parseTypeSpec(&arg->getSpec()));
3475 funcBuilder.addArgument(arg->getId().get().strVal, specializedType);
3476 specializedArgTypes.push_back(specializedType);
3477 }
3478 funcBuilder.setReturnType(managedPtr(parseTypeSpec(&def->getMethod().getResultType())));
3479 }
3480
3481 yoi::wstr fullMangledName = structDef->name + L"::" + specializedMethodName + getFuncUniqueNameStr(specializedArgTypes);
3482
3483 if (targetedModule->functionTable.contains(fullMangledName)) {
3484 auto res = targetedModule->functionTable.getIndex(fullMangledName);
3486 popModuleContext();
3487 return res;
3488 }
3489
3490 funcBuilder.setName(fullMangledName);
3491 auto specializedFunc = funcBuilder.yield();
3492 auto funcIndex = targetedModule->functionTable.put_create(fullMangledName, specializedFunc);
3493 targetedModule->functionOverloadIndexies[structDef->name + L"::" + baseMethodName].push_back(funcIndex);
3494
3495 // If definition exists, visit it
3496 if (def) {
3497 moduleContext->pushIRBuilder({moduleContext->getCompilerContext(), targetedModule, specializedFunc});
3498 moduleContext->getIRBuilder().setDebugInfo({targetedModule->modulePath, def->getLine(), def->getColumn()});
3500 try {
3501 visit(&def->getMethod().getBlock(), true);
3502 } catch (std::exception &e) {
3503 panic(def->getLine(), def->getColumn(), std::string("Exception occurred while specializing template method: ") + yoi::wstring2string(fullMangledName) + ": " + e.what());
3504 }
3507 }
3508
3510 popModuleContext();
3511
3512 return funcIndex;
3513 }
3514
3515 std::pair<yoi::indexT, yoi::wstr> visitor::specializeStructMethodDeclaration(IRTemplateBuilder &structTemplate,
3516 yoi::structDefInnerPair *methodAstNode,
3517 const yoi::wstr &specializedStructName,
3518 const yoi::vec<std::shared_ptr<IRValueType>> &concreteTemplateArgs,
3519 yoi::indexT moduleIndex) {
3520
3521 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(moduleIndex);
3522
3523 // Push the template's own context to resolve generic types like 'T' to their placeholder
3524 // 'incompleteTemplateType'.
3525 IRTemplateBuilder genericContext;
3526 genericContext.templateArguments = structTemplate.templateArguments;
3527
3528 moduleContext->pushTemplateBuilder(genericContext);
3529
3530 yoi::wstr baseMethodName;
3531 yoi::wstr genericMethodKey;
3533
3534 if (methodAstNode->kind == 1) {
3535 for (yoi::indexT i = 0; i < concreteTemplateArgs.size(); ++i) {
3536 // same as above
3537 if (methodAstNode->getConstructor().tempArgs && methodAstNode->getConstructor().tempArgs->spec[i]->satisfyCondition) {
3538 auto paramName = methodAstNode->getConstructor().tempArgs->spec[i]->id->get().strVal;
3539 for (auto &c : methodAstNode->getConstructor().tempArgs->spec[i]->satisfyCondition->emaes) {
3540 checkConceptSatisfaction(c, paramName, concreteTemplateArgs[i]);
3541 }
3542 }
3543 }
3544
3545 baseMethodName = L"constructor";
3546 for (auto &arg : methodAstNode->getConstructor().getArgs().get()) {
3547 genericArgTypes.push_back(managedPtr(parseTypeSpec(&arg->getSpec())));
3548 }
3549 genericMethodKey = baseMethodName + getFuncUniqueNameStr(genericArgTypes);
3550 } else if (methodAstNode->kind == 2) {
3551 for (yoi::indexT i = 0; i < concreteTemplateArgs.size(); ++i) {
3552 // same as above
3553 if (methodAstNode->getMethod().getName().hasDefTemplateArg() && methodAstNode->getMethod().getName().arg->spec[i]->satisfyCondition) {
3554 auto paramName = methodAstNode->getMethod().getName().arg->spec[i]->id->get().strVal;
3555 for (auto &c : methodAstNode->getMethod().getName().arg->spec[i]->satisfyCondition->emaes) {
3556 checkConceptSatisfaction(c, paramName, concreteTemplateArgs[i]);
3557 }
3558 }
3559 }
3560
3561 baseMethodName = methodAstNode->getMethod().getName().getId().get().strVal;
3562 for (auto &arg : methodAstNode->getMethod().getArgs().get()) {
3563 genericArgTypes.push_back(managedPtr(parseTypeSpec(&arg->getSpec())));
3564 }
3565 genericMethodKey = baseMethodName + getFuncUniqueNameStr(genericArgTypes);
3566 } else if (methodAstNode->kind == 3) {
3567 // finalizer
3568 baseMethodName = L"finalizer";
3569 genericMethodKey = baseMethodName;
3570 }
3571
3572 moduleContext->popTemplateBuilder(); // Done with generic context
3573
3574 IRTemplateBuilder specializationContext;
3575 for (size_t i = 0; i < concreteTemplateArgs.size(); ++i) {
3576 auto paramName = structTemplate.templateArguments.getKey(i);
3577 specializationContext.addTemplateArgument(paramName, concreteTemplateArgs[i]);
3578 }
3579 auto selfType =
3580 managedPtr(IRValueType{IRValueType::valueType::structObject, moduleIndex, targetedModule->structTable.getIndex(specializedStructName)});
3581 specializationContext.addTemplateArgument(L"STRUCT", selfType);
3582 moduleContext->pushTemplateBuilder(specializationContext);
3583
3585
3586 funcBuilder.setDebugInfo({targetedModule->modulePath, methodAstNode->getLine(), methodAstNode->getColumn()});
3587
3588 yoi::vec<std::shared_ptr<IRValueType>> specializedArgTypes;
3589
3590 if (methodAstNode->kind == 1) {
3591 funcBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Constructor);
3592 funcBuilder.addArgument(L"this", selfType); // Specialized 'this'
3593 for (auto &arg : methodAstNode->getConstructor().getArgs().get()) {
3594 auto specializedType = managedPtr(parseTypeSpec(&arg->getSpec()));
3595 funcBuilder.addArgument(arg->getId().get().strVal, specializedType);
3596 specializedArgTypes.push_back(specializedType);
3597 }
3598 funcBuilder.setReturnType(selfType);
3599 } else if (methodAstNode->kind == 2) {
3600 funcBuilder.attrs = getFunctionAttributes(methodAstNode->getMethod().attrs);
3601 if (std::find(funcBuilder.attrs.begin(), funcBuilder.attrs.end(), IRFunctionDefinition::FunctionAttrs::Static) ==
3602 funcBuilder.attrs.end()) {
3603 funcBuilder.addArgument(L"this", selfType); // Specialized 'this'
3604 }
3605 for (auto &arg : methodAstNode->getMethod().getArgs().get()) {
3606 auto specializedType = managedPtr(parseTypeSpec(&arg->getSpec()));
3607 funcBuilder.addArgument(arg->getId().get().strVal, specializedType);
3608 specializedArgTypes.push_back(specializedType);
3609 }
3610 funcBuilder.setReturnType(managedPtr(parseTypeSpec(&methodAstNode->getMethod().getResultType())));
3611 } else if (methodAstNode->kind == 3) {
3612 funcBuilder.setName(specializedStructName + L"::finalizer");
3613 funcBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Finalizer);
3614 funcBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Preserve);
3615 funcBuilder.addArgument(L"this", selfType); // Specialized 'this'
3616 funcBuilder.setReturnType(moduleContext->getCompilerContext()->getNoneObjectType());
3617 }
3618
3619 yoi::wstr specializedMethodName = specializedStructName + L"::" + baseMethodName;
3620 funcBuilder.setName(specializedMethodName + getFuncUniqueNameStr(specializedArgTypes));
3621
3622 auto specializedFunc = funcBuilder.yield();
3623 auto funcIndex = targetedModule->functionTable.put_create(specializedMethodName + getFuncUniqueNameStr(specializedArgTypes), specializedFunc);
3624 targetedModule->functionOverloadIndexies[specializedMethodName].push_back(funcIndex);
3625
3627 return {funcIndex, baseMethodName + getFuncUniqueNameStr(specializedArgTypes)};
3628 }
3629
3630 void visitor::specializeStructMethodDefinition(IRTemplateBuilder &structTemplate,
3631 const std::shared_ptr<IRStructDefinition> &specializedStruct,
3632 yoi::implInnerPair *methodAstNode,
3633 const yoi::wstr &specializedStructName,
3634 const yoi::vec<std::shared_ptr<IRValueType>> &concreteTemplateArgs,
3635 yoi::indexT moduleIndex) {
3636
3637 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(moduleIndex);
3638
3639 // Push the template's own context to resolve generic types like 'T' to their placeholder
3640 // 'incompleteTemplateType'.
3641 IRTemplateBuilder genericContext;
3642 genericContext.templateArguments = structTemplate.templateArguments;
3643
3644 moduleContext->pushTemplateBuilder(genericContext);
3645
3646 yoi::wstr baseMethodName;
3647 yoi::wstr genericMethodKey;
3649
3650 if (methodAstNode->isConstructor()) {
3651 baseMethodName = L"constructor";
3652 for (auto &arg : methodAstNode->getConstructor().getArgs().get()) {
3653 genericArgTypes.push_back(managedPtr(parseTypeSpec(&arg->getSpec())));
3654 }
3655 genericMethodKey = baseMethodName + getFuncUniqueNameStr(genericArgTypes);
3656 } else if (methodAstNode->isFinalizer()) {
3657 baseMethodName = L"finalizer";
3658 for (auto &arg : methodAstNode->getConstructor().getArgs().get()) {
3659 genericArgTypes.push_back(managedPtr(parseTypeSpec(&arg->getSpec())));
3660 }
3661 genericMethodKey = baseMethodName + getFuncUniqueNameStr(genericArgTypes);
3662 } else {
3663 baseMethodName = methodAstNode->getMethod().getName().getId().get().strVal;
3664 for (auto &arg : methodAstNode->getMethod().getArgs().get()) {
3665 genericArgTypes.push_back(managedPtr(parseTypeSpec(&arg->getSpec())));
3666 }
3667 genericMethodKey = baseMethodName + getFuncUniqueNameStr(genericArgTypes);
3668 }
3669
3670 moduleContext->popTemplateBuilder(); // Done with generic context
3671
3672 IRTemplateBuilder specializationContext;
3673 for (size_t i = 0; i < concreteTemplateArgs.size(); ++i) {
3674 auto paramName = structTemplate.templateArguments.getKey(i);
3675 specializationContext.addTemplateArgument(paramName, concreteTemplateArgs[i]);
3676 }
3677 auto selfType =
3678 managedPtr(IRValueType{IRValueType::valueType::structObject, moduleIndex, targetedModule->structTable.getIndex(specializedStructName)});
3679 specializationContext.addTemplateArgument(L"STRUCT", selfType);
3680 moduleContext->pushTemplateBuilder(specializationContext);
3681
3682 yoi::vec<std::shared_ptr<IRValueType>> specializedArgTypes;
3683
3684 if (methodAstNode->isConstructor()) {
3685 for (auto &arg : methodAstNode->getConstructor().getArgs().get()) {
3686 auto specializedType = managedPtr(parseTypeSpec(&arg->getSpec()));
3687 specializedArgTypes.push_back(specializedType);
3688 }
3689 } else if (methodAstNode->isFinalizer()) {
3690 // no args
3691 } else {
3692 for (auto &arg : methodAstNode->getMethod().getArgs().get()) {
3693 auto specializedType = managedPtr(parseTypeSpec(&arg->getSpec()));
3694 specializedArgTypes.push_back(specializedType);
3695 }
3696 }
3697
3698 yoi::wstr specializedMethodName = specializedStructName + L"::" + baseMethodName + getFuncUniqueNameStr(specializedArgTypes);
3699
3700 auto funcIndex = targetedModule->functionTable.getIndex(specializedMethodName);
3701
3702 moduleContext->pushIRBuilder({moduleContext->getCompilerContext(), targetedModule, targetedModule->functionTable[funcIndex]});
3703 moduleContext->getIRBuilder().setDebugInfo({targetedModule->modulePath, methodAstNode->getLine(), methodAstNode->getColumn()});
3705 try {
3706 visit(methodAstNode->isConstructor() ? &methodAstNode->getConstructor().getBlock() : &methodAstNode->getMethod().getBlock(), true);
3707 } catch (std::exception &e) {
3708 set_current_file_path(moduleContextStack.top().first->getIRBuilder().getCurrentDebugInfo().sourceFile);
3709 panic(moduleContextStack.top().first->getIRBuilder().getCurrentDebugInfo().line,
3710 moduleContextStack.top().first->getIRBuilder().getCurrentDebugInfo().column,
3711 std::string("Exception occurred while specializing method: ") + yoi::wstring2string(specializedMethodName) + ": " + e.what() +
3712 "\n");
3713 }
3714
3718 }
3719
3720 yoi::wstr visitor::getSpecializedMangledMethodName(yoi::indexTable<yoi::wstr, IRTemplateBuilder::Argument> &templateArgs,
3721 const yoi::wstr &baseMethodName,
3722 const yoi::vec<std::shared_ptr<IRValueType>> &specializedArgTypes) {
3723 auto res = baseMethodName;
3724 for (yoi::indexT i = 0; i < specializedArgTypes.size(); ++i) {
3725 auto &arg = templateArgs[i];
3726 auto strRepl1 = templateArgs[i].templateType->to_string();
3727 auto strRepl2 = specializedArgTypes[i]->to_string();
3728 replace_all(res, strRepl1, strRepl2);
3729 }
3730 return res;
3731 }
3732
3734 auto exportIdentifier = exportDecl->as->node.strVal;
3735 try {
3736 auto parsedType = managedPtr(parseTypeSpec(exportDecl->from));
3737
3738 moduleContext->getCompilerContext()->getIRFFITable()->addForeignType(exportIdentifier, parsedType);
3740 } catch (std::runtime_error &e) {
3741 // failed as type, try function
3742 }
3743
3744 try {
3745 auto it = exportDecl->from->member->getTerms().begin();
3746 yoi::indexT targetModule = -1, lastModule = -1;
3747 while (it + 1 != exportDecl->from->member->getTerms().end() && (targetModule = isModuleName(*it, targetModule)) != lastModule) {
3748 it++;
3749 lastModule = targetModule;
3750 }
3751 yoi_assert(it + 1 == exportDecl->from->member->getTerms().end(),
3754 "Expected a identifier after modules but this is not the final term of expression.");
3755 targetModule = targetModule == -1 ? currentModuleIndex : targetModule;
3756
3757 yoi::indexT funcIndex = -1;
3758
3759 if (!(*it)->hasTemplateArg()) {
3760 for (auto funcIt = moduleContext->getCompilerContext()->getImportedModule(targetModule)->functionTable.begin();
3761 funcIt != moduleContext->getCompilerContext()->getImportedModule(targetModule)->functionTable.end();
3762 funcIt++) {
3763 if (funcIt->first.starts_with((*it)->id->get().strVal + L"#")) {
3764 // an mangled name of target function
3765 funcIndex =
3766 std::distance(moduleContext->getCompilerContext()->getImportedModule(targetModule)->functionTable.begin(), funcIt);
3767 }
3768 }
3769 }
3770
3771 if (funcIndex != -1) {
3772 auto attrs = getFunctionAttributes(exportDecl->attrs);
3773 moduleContext->getCompilerContext()->getIRFFITable()->addExportedFunction(exportIdentifier, targetModule, funcIndex, attrs);
3775 } else {
3776 // try template
3777 auto templateName = (*it)->id->get().strVal;
3778 if (!moduleContext->getCompilerContext()->getImportedModule(targetModule)->funcTemplateAsts.contains(templateName)) {
3779 throw std::out_of_range("Cannot find the template: " + wstring2string(templateName));
3780 }
3781
3782 yoi_assert((*it)->hasTemplateArg(),
3785 "Expected template arguments for template: " + wstring2string(templateName));
3786
3787 auto templateArgs = parseTemplateArgs((*it)->getArg());
3788
3789 auto funcIndex = specializeFunctionTemplate(
3790 moduleContext->getCompilerContext()->getImportedModule(targetModule)->funcTemplateAsts[templateName], templateArgs, targetModule);
3791
3792 auto attrs = getFunctionAttributes(exportDecl->attrs);
3793
3794 moduleContext->getCompilerContext()->getIRFFITable()->addExportedFunction(exportIdentifier, targetModule, funcIndex, attrs);
3796 }
3797 } catch (std::out_of_range &e) {
3800 "None of the existing types and functions match the name: " + wstring2string(exportDecl->as->node.strVal));
3801 }
3802 }
3803
3805 yoi::wstr from{};
3806
3807 if (importDecl->from_path.strVal == L"builtin") {
3808 from = L"builtin";
3809 } else {
3810 for (auto &prep : moduleContext->getCompilerContext()->getBuildConfig()->searchPaths) {
3811 try {
3812 std::filesystem::path final = std::filesystem::path(prep) / importDecl->from_path.strVal;
3813 from = realpath(final.wstring());
3814 break;
3815 } catch (std::runtime_error &e) {
3816 continue;
3817 }
3818 }
3819 }
3820 yoi_assert(
3821 !from.empty(), importDecl->getLine(), importDecl->getColumn(), "Cannot find the file: " + wstring2string(importDecl->from_path.strVal));
3822
3823 // import method implementation
3824 // parse method signature and add to import table
3825 auto funcName = importDecl->inner->name->getId().get().strVal;
3827
3828 builder.attrs = getFunctionAttributes(importDecl->inner->attrs);
3829 builder.setDebugInfo({irModule->modulePath, importDecl->inner->getLine(), importDecl->inner->getColumn()});
3830
3831 builder.setReturnType(managedPtr(parseTypeSpec(importDecl->inner->resultType)));
3832 for (auto &arg : importDecl->inner->args->get()) {
3833 auto argType = managedPtr(parseTypeSpec(&arg->getSpec()));
3834 builder.addArgument(arg->getId().get().strVal, argType);
3835 }
3836 builder.setName(funcName);
3837 auto importedFunc = builder.yield();
3838 auto importedIndex = moduleContext->getCompilerContext()->getIRFFITable()->addImportedFunction(from, funcName, importedFunc);
3839
3840 // add to extern table
3841 irModule->externTable.put_create(
3842 funcName,
3843 managedPtr(IRExternEntry{IRExternEntry::externType::importedFunction,
3844 funcName,
3845 moduleContext->getCompilerContext()->getIRFFITable()->importedLibraries.getIndex(from),
3846 importedIndex}));
3847
3849 }
3850
3851 void visitor::tryCastTo(const std::shared_ptr<IRValueType> &toType) {
3853 if (rhs->isForeignBasicType()) {
3854 rhs = managedPtr(rhs->getNormalizedForeignBasicType());
3855 }
3856
3857 if (*rhs == *toType) {
3858 return;
3859 } else if (rhs->type == IRValueType::valueType::pointerObject || rhs->type == IRValueType::valueType::pointer ||
3860 rhs->type == IRValueType::valueType::null || toType->type == IRValueType::valueType::pointerObject ||
3861 toType->type == IRValueType::valueType::pointer) {
3862 // no cast needed for pointer type
3863 return;
3864 } else if (rhs->isBasicType() && toType->isBasicType() && !rhs->isDynamicArrayType() && !toType->isDynamicArrayType() &&
3865 !rhs->isArrayType() && !toType->isArrayType() &&
3866 (rhs->type != IRValueType::valueType::stringObject || toType->type == IRValueType::valueType::pointerObject)) {
3867 emitBasicCastTo(toType);
3868 } else if ((toType->isArrayType() || toType->isDynamicArrayType()) && rhs->type == IRValueType::valueType::bracedInitalizerList) {
3869 auto elementType = managedPtr(toType->getElementType());
3870 auto elementCount = rhs->bracedTypes.size();
3871 if (toType->isArrayType()) {
3873 moduleContext->getIRBuilder().newArrayOp(elementType, toType->dimensions, elementCount);
3874 } else {
3876 moduleContext->getIRBuilder().newDynamicArrayOp(elementType, elementCount);
3877 }
3878 } else if (toType->type == IRValueType::valueType::interfaceObject && !toType->isArrayType() && !toType->isDynamicArrayType()) {
3879 // check implemented interfaces
3880 try {
3881 auto implName = getInterfaceImplName({toType->typeAffiliateModule, toType->typeIndex}, rhs);
3882 auto implIndex =
3883 moduleContext->getCompilerContext()->getImportedModule(rhs->typeAffiliateModule)->interfaceImplementationTable.getIndex(implName);
3884 // construct interface object
3885 // moduleContext->getIRBuilder().newInterfaceOp(toType->typeIndex, toType->typeAffiliateModule != currentModuleIndex,
3886 // toType->typeAffiliateModule);
3887 moduleContext->getIRBuilder().constructInterfaceImplOp({toType->typeAffiliateModule, toType->typeIndex},
3888 implIndex,
3889 rhs->typeAffiliateModule != currentModuleIndex,
3890 rhs->typeAffiliateModule);
3891 } catch (std::out_of_range &e) {
3894 "Cannot cast type " + yoi::wstring2string((rhs->to_string())) + " to interface " + yoi::wstring2string((toType->to_string())) +
3895 ": no implementation found.");
3896 }
3897 } else if (toType->type == IRValueType::valueType::structObject && !toType->isArrayType() && !toType->isDynamicArrayType()) {
3898 // check whether owns the constructor
3899 auto structType = moduleContext->getCompilerContext()->getImportedModule(toType->typeAffiliateModule)->structTable[toType->typeIndex];
3900 auto result = resolveOverloadExtern(L"constructor", {rhs}, toType->typeAffiliateModule, structType);
3901 if (result.found()) {
3902 if (result.isCastRequired) {
3903 tryCastTo(result.function->argumentTypes.back());
3904 }
3905 moduleContext->getIRBuilder().newStructOp(toType->typeIndex, true, toType->typeAffiliateModule);
3907 result.functionIndex, 2, result.function->returnType, true, toType->typeAffiliateModule);
3908 } else {
3911 "Cannot cast type " + yoi::wstring2string((rhs->to_string())) + " to " + yoi::wstring2string((toType->to_string())) +
3912 ": no viable conversion found.");
3913 }
3914 } else {
3917 "Cannot cast type " + yoi::wstring2string((rhs->to_string())) + " to " + yoi::wstring2string((toType->to_string())) +
3918 ": no viable conversion found.");
3919 }
3920 }
3921
3922 bool visitor::canCastTo(const std::shared_ptr<IRValueType> &fromType, const std::shared_ptr<IRValueType> &toType) {
3923 auto rhs = fromType;
3924 if (fromType->isForeignBasicType()) {
3925 rhs = managedPtr(rhs->getNormalizedForeignBasicType());
3926 }
3927 if (*rhs == *toType) {
3928 return true;
3929 } else if (rhs->isBasicType() && toType->isBasicType() && !rhs->isDynamicArrayType() && !toType->isDynamicArrayType() &&
3930 !rhs->isArrayType() && !toType->isArrayType() && (toType->type != IRValueType::valueType::stringObject) &&
3931 (rhs->type != IRValueType::valueType::stringObject || toType->type == IRValueType::valueType::pointerObject)) {
3932 return true;
3933 } else if ((toType->isArrayType() || toType->isDynamicArrayType()) && fromType->type == IRValueType::valueType::bracedInitalizerList) {
3934 auto e = toType->getElementType();
3935 for (auto &i : fromType->bracedTypes) {
3936 if (i != e) {
3937 return false;
3938 }
3939 }
3940 return true;
3941 } else if (rhs->type == IRValueType::valueType::pointerObject) {
3942 // no cast needed for pointer type
3943 return true;
3944 } else if (toType->type == IRValueType::valueType::interfaceObject && !toType->isArrayType() && !toType->isDynamicArrayType()) {
3945 // check implemented interfaces
3946 try {
3947 auto implName = getInterfaceImplName({toType->typeAffiliateModule, toType->typeIndex}, rhs);
3948 auto implIndex =
3949 moduleContext->getCompilerContext()->getImportedModule(rhs->typeAffiliateModule)->interfaceImplementationTable.getIndex(implName);
3950 return true;
3951 } catch (std::out_of_range &e) {
3952 return false;
3953 }
3954 } else if (toType->type == IRValueType::valueType::structObject && !toType->isArrayType() && !toType->isDynamicArrayType()) {
3955 // check whether owns the constructor
3956 auto structType = moduleContext->getCompilerContext()->getImportedModule(toType->typeAffiliateModule)->structTable[toType->typeIndex];
3957 auto result = resolveOverloadExtern(L"constructor", {rhs}, toType->typeAffiliateModule, structType);
3958 return result.found();
3959 } else {
3960 return false;
3961 }
3962 }
3963
3965 if (typeIdExpression->type) {
3966 auto parsedType = managedPtr(parseTypeSpec(typeIdExpression->type));
3967 moduleContext->getIRBuilder().typeIdOp(parsedType);
3968 } else {
3970 visit(typeIdExpression->expr);
3974 }
3976 }
3977
3979 visit(dynCastExpression->expr);
3981 auto toType = managedPtr(parseTypeSpec(dynCastExpression->type));
3982 yoi_assert(rhs->type == IRValueType::valueType::interfaceObject,
3985 "dynamic cast can only be applied to interface objects to struct objects. Type: " + yoi::wstring2string(rhs->to_string()));
3986
3987 auto &impls =
3988 moduleContext->getCompilerContext()->getImportedModule(rhs->typeAffiliateModule)->interfaceTable[rhs->typeIndex]->implementations;
3989
3990 if (auto it = std::find(impls.begin(), impls.end(), std::make_tuple(toType->type, toType->typeAffiliateModule, toType->typeIndex));
3991 it != impls.end())
3993 else
3996 "Cannot cast type " + yoi::wstring2string((rhs->to_string())) + " to " + yoi::wstring2string((toType->to_string())) +
3997 ": no implementation found.");
3998
4000 }
4001
4002 yoi::indexT visitor::generateNullInterfaceImplementation(const std::shared_ptr<IRValueType> &structType) {
4003 auto nullInterface = std::make_pair(HOSHI_COMPILER_CTX_GLOB_ID_CONST, 0);
4004 auto nullImplName = getInterfaceImplName(nullInterface, structType);
4005 try {
4007 ->getImportedModule(structType->typeAffiliateModule)
4008 ->interfaceImplementationTable.getIndex(nullImplName);
4009 } catch (std::out_of_range &e) {
4011 ->getImportedModule(HOSHI_COMPILER_CTX_GLOB_ID_CONST)
4012 ->interfaceTable[0]
4013 ->implementations.emplace_back(structType->type, structType->typeAffiliateModule, structType->typeIndex);
4014 auto nullImpl = managedPtr(IRInterfaceImplementationDefinition{nullImplName,
4015 {structType->type, structType->typeAffiliateModule, structType->typeIndex},
4017 {},
4018 {}});
4020 ->getImportedModule(structType->typeAffiliateModule)
4021 ->interfaceImplementationTable.put_create(nullImplName, nullImpl);
4022 }
4023 }
4024
4025 std::set<IRFunctionDefinition::FunctionAttrs> visitor::getFunctionAttributes(const yoi::vec<lexer::token> &attrs) {
4026 std::set<IRFunctionDefinition::FunctionAttrs> res;
4027 for (auto &attr : attrs) {
4028 switch (attr.kind) {
4029 case lexer::token::tokenKind::kAlwaysInline:
4030 res.insert(IRFunctionDefinition::FunctionAttrs::AlwaysInline);
4031 break;
4032 case lexer::token::tokenKind::kNoFFI:
4033 res.insert(IRFunctionDefinition::FunctionAttrs::NoFFI);
4034 break;
4035 case lexer::token::tokenKind::kStatic:
4036 res.insert(IRFunctionDefinition::FunctionAttrs::Static);
4037 break;
4038 case lexer::token::tokenKind::kIntrinsic:
4039 res.insert(IRFunctionDefinition::FunctionAttrs::Intrinsic);
4040 break;
4041 case lexer::token::tokenKind::kGenerator:
4042 res.insert(IRFunctionDefinition::FunctionAttrs::Generator);
4043 break;
4044 default:
4045 break;
4046 }
4047 }
4048 return std::move(res);
4049 }
4050
4052 auto baseType = parseTypeSpec(newExpression->type);
4053 for (auto &i : newExpression->args->get()) {
4054 visit(i);
4055 tryCastTo(managedPtr(baseType));
4056 }
4057 if (newExpression->length)
4058 visit(newExpression->length->expr);
4059 else
4060 moduleContext->getIRBuilder().pushOp(IR::Opcode::push_integer,
4061 IROperand{IROperand::operandType::integer, yoi::indexT{newExpression->args->get().size()}});
4064 }
4065
4066 yoi::indexT visitor::isModuleName(identifier *it, yoi::indexT currentModule) const {
4067 std::shared_ptr<yoi::IRModule> target =
4068 currentModule == -1 ? irModule : moduleContext->getCompilerContext()->getImportedModule(currentModule);
4069 if (auto x = target->moduleImports.find(it->node.strVal); x != target->moduleImports.end()) {
4070 return x->second;
4071 } else {
4072 return currentModule;
4073 }
4074 }
4075
4076 IRValueType visitor::parseTypeSpec(yoi::externModuleAccessExpression *emaExpression) {
4077 auto it = emaExpression->getTerms().begin();
4078 yoi::indexT targetModule = -1, lastModule = -1;
4079 while (it + 1 != emaExpression->getTerms().end() && (targetModule = isModuleName((*it)->id, lastModule)) != lastModule) {
4080 it++;
4081 lastModule = targetModule;
4082 }
4083
4084 bool whetherLastTerm = it + 1 == emaExpression->getTerms().end();
4085 if (targetModule == -1 || targetModule == currentModuleIndex)
4086 return parseTypeSpec((*it));
4087 else
4088 return parseTypeSpecExtern((*it), targetModule);
4089 }
4090
4091 bool visitor::OverloadResult::found() const {
4092 return functionIndex != -1;
4093 }
4094
4097 for (auto &arg : args->get()) {
4098 visit(arg);
4099 argTypes.push_back(moduleContext->getIRBuilder().getRhsFromTempVarStack());
4100 }
4101 return argTypes;
4102 }
4103
4104 visitor::OverloadResult visitor::resolveOverloadExtern(const yoi::wstr &baseName,
4105 const yoi::vec<std::shared_ptr<IRValueType>> &argTypes,
4106 yoi::indexT targetModule,
4107 const std::shared_ptr<IRStructDefinition> &structContext) {
4108 OverloadResult result;
4109 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(targetModule);
4110
4111 // Pass 1: Look for an exact, non-variadic match in the target module.
4112 auto exactMangledName = baseName + getFuncUniqueNameStr(argTypes);
4113 yoi::wstr lookupName = structContext ? structContext->name + L"::" + exactMangledName : exactMangledName;
4114
4115 if (targetedModule->functionTable.contains(lookupName)) {
4116 result.functionIndex = targetedModule->functionTable.getIndex(lookupName);
4117 result.function = targetedModule->functionTable[result.functionIndex];
4118 // if (result.function->isVariadic) {
4119 if (std::find(result.function->attrs.begin(), result.function->attrs.end(), IRFunctionDefinition::FunctionAttrs::Variadic) !=
4120 result.function->attrs.end()) {
4121 result.isVariadic = true;
4122 result.fixedArgCount = result.function->argumentTypes.size() - 1;
4123 result.variadicElementType = managedPtr(result.function->argumentTypes.back()->getElementType());
4124 }
4125 return result;
4126 }
4127
4128 // Pass 2: Look for a compatible variadic match in the target module.
4129 auto findVariadicMatch = [&](const yoi::wstr &funcKey, bool skipFirstParam = false) {
4130 auto func = targetedModule->functionTable[funcKey];
4131 const auto &paramTypes = func->argumentTypes;
4132 size_t fixedParamCount = paramTypes.size() - 1 - (skipFirstParam && paramTypes.size() > 1 ? 1 : 0);
4133 if (std::find(func->attrs.begin(), func->attrs.end(), IRFunctionDefinition::FunctionAttrs::Variadic) != func->attrs.end()) {
4134 if (argTypes.size() >= fixedParamCount) {
4135 bool fixedMatch = true;
4136 for (size_t i = 0; i < fixedParamCount; ++i) {
4137 if (!canCastTo(argTypes[i], paramTypes[i + skipFirstParam])) {
4138 fixedMatch = false;
4139 break;
4140 }
4141 }
4142 if (fixedMatch) {
4143 result.functionIndex = targetedModule->functionTable.getIndex(funcKey);
4144 result.isVariadic = true;
4145 result.fixedArgCount = fixedParamCount;
4146 result.variadicElementType = managedPtr(paramTypes.back()->getElementType());
4147 result.function = func;
4148 return true;
4149 }
4150 }
4151 } else {
4152 if (argTypes.size() != fixedParamCount + 1 ||
4153 paramTypes.size() != fixedParamCount + 1 + skipFirstParam) // balance the variadic argument
4154 return false;
4155
4156 for (size_t i = 0; i < fixedParamCount + 1; ++i) {
4157 if (!canCastTo(argTypes[i], paramTypes[i + skipFirstParam])) {
4158 return false;
4159 }
4160 }
4161
4162 result.functionIndex = targetedModule->functionTable.getIndex(funcKey);
4163 result.isVariadic = false;
4164 result.fixedArgCount = fixedParamCount;
4165 result.function = func;
4166 result.isCastRequired = true;
4167
4168 return true;
4169 }
4170 return false;
4171 };
4172
4173 yoi::wstr prefix = structContext ? structContext->name + L"::" + baseName : baseName;
4174 for (const auto it : targetedModule->functionOverloadIndexies[prefix]) {
4175 const auto &key = targetedModule->functionTable.getKey(it);
4176 if (key.starts_with(prefix)) {
4177 if (findVariadicMatch(key,
4178 structContext != nullptr &&
4179 !targetedModule->functionTable[it]->hasAttribute(IRFunctionDefinition::FunctionAttrs::Static)))
4180 return result;
4181 }
4182 }
4183
4184 if (!structContext && targetedModule->funcTemplateAsts.contains(baseName)) {
4185 try {
4186 auto astNode = targetedModule->funcTemplateAsts.at(baseName);
4187 auto templateArgs = getTemplateArgs(astNode->id->getArg());
4188
4189 yoi::vec<std::shared_ptr<IRValueType>> deducedArgs(templateArgs.size());
4190
4191 for (yoi::indexT i = 0; i < argTypes.size(); i++) {
4192 if (i < templateArgs.size() && templateArgs[i].templateType->type == IRValueType::valueType::incompleteTemplateType) {
4193 auto &srcTypeToPlace = argTypes[i];
4194 auto incompleteTypeIndex = templateArgs[i].templateType->typeIndex;
4195 if (deducedArgs[incompleteTypeIndex] && *deducedArgs[incompleteTypeIndex] != *srcTypeToPlace) {
4196 throw std::runtime_error("Template argument type mismatch during deduction.");
4197 }
4198 deducedArgs[incompleteTypeIndex] = srcTypeToPlace;
4199 }
4200 }
4201 for (yoi::indexT i = 0; i < deducedArgs.size(); i++) {
4202 if (deducedArgs[i] == nullptr) {
4203 throw std::runtime_error("Cannot deduce all template arguments for: " + yoi::wstring2string(baseName));
4204 }
4205 }
4206
4207 auto specializedFuncIndex = specializeFunctionTemplate(astNode, deducedArgs, targetModule);
4208 result.functionIndex = specializedFuncIndex;
4209 result.function = targetedModule->functionTable[specializedFuncIndex];
4210
4211 // The newly specialized function might itself be variadic
4212 if (std::find(result.function->attrs.begin(), result.function->attrs.end(), IRFunctionDefinition::FunctionAttrs::Variadic) !=
4213 result.function->attrs.end()) {
4214 result.isVariadic = true;
4215 result.fixedArgCount = result.function->argumentTypes.size() - 1;
4216 result.variadicElementType = managedPtr(result.function->argumentTypes.back()->getElementType());
4217 }
4218 return result;
4219 } catch (const std::out_of_range &) {
4220 result.functionIndex = -1;
4221 }
4222 }
4223
4224 return result; // Not found
4225 }
4226
4227 bool visitor::handleInvocationExtern(const yoi::wstr &baseName,
4229 yoi::indexT targetModule,
4230 const std::shared_ptr<IRValueType> &structContext,
4231 bool noThisCall,
4232 yoi::templateArg *templateArgs) {
4234 auto argTypes = evaluateArguments(args);
4235 OverloadResult overload;
4236 if (structContext && structContext->type == IRValueType::valueType::structObject) {
4237 auto structType =
4238 moduleContext->getCompilerContext()->getImportedModule(structContext->typeAffiliateModule)->structTable[structContext->typeIndex];
4239 overload = resolveOverloadExtern(baseName, argTypes, targetModule, structType);
4240
4241 if (!overload.found()) {
4242 // Check if it's a template method
4243 if (structType->templateMethodDecls.contains(baseName) || structType->templateMethodDefs.contains(baseName)) {
4245 structType->templateMethodDecls.contains(baseName) ? structType->templateMethodDecls.at(baseName) : nullptr;
4246 yoi::implInnerPair *def =
4247 structType->templateMethodDefs.contains(baseName) ? structType->templateMethodDefs.at(baseName) : nullptr;
4248
4249 yoi::vec<std::shared_ptr<IRValueType>> concreteMethodTemplateArgs;
4250 if (templateArgs) {
4251 // full specialization, if provided
4252 concreteMethodTemplateArgs = parseTemplateArgs(*templateArgs);
4253 } else {
4254 // automatically deduce the template arguments based on the arguments
4255 yoi::vec<yoi::wstr> methodTemplateParams;
4256 if (decl)
4257 methodTemplateParams = extractTemplateParamsFromTypeArgs(&decl->getMethod().getName().getArg());
4258 else if (def)
4259 methodTemplateParams = extractTemplateParamsFromTypeArgs(&def->getMethod().getName().getArg());
4260
4261 concreteMethodTemplateArgs.resize(methodTemplateParams.size());
4262 auto &astArgs = decl ? decl->getMethod().getArgs().get() : def->getMethod().getArgs().get();
4263 for (size_t i = 0; i < astArgs.size() && i < argTypes.size(); ++i) {
4264 auto &spec = *astArgs[i]->spec;
4265 if (spec.kind == typeSpec::typeSpecKind::Member && spec.member && spec.member->getTerms().size() == 1) {
4266 auto term = spec.member->getTerms()[0];
4267 yoi::wstr typeName = term->id->get().strVal;
4268 for (size_t j = 0; j < methodTemplateParams.size(); ++j) {
4269 if (methodTemplateParams[j] == typeName) {
4270 concreteMethodTemplateArgs[j] = argTypes[i];
4271 break;
4272 }
4273 }
4274 }
4275 }
4276 }
4277
4278 bool allDeduced = true;
4279 for (auto &arg : concreteMethodTemplateArgs) {
4280 if (!arg) {
4281 allDeduced = false;
4282 break;
4283 }
4284 }
4285
4286 if (allDeduced && !concreteMethodTemplateArgs.empty()) {
4287 // if all deduced, we can use this to invoke the target
4288 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(targetModule);
4289 auto specializedFuncIndex =
4290 specializeStructMethodTemplate(structType, decl, def, baseName, concreteMethodTemplateArgs, targetModule);
4291 overload.functionIndex = specializedFuncIndex;
4292 overload.function = targetedModule->functionTable[specializedFuncIndex];
4293 }
4294 }
4295 }
4296 } else if (structContext && structContext->type == IRValueType::valueType::interfaceObject) {
4297 auto interfaceType =
4298 moduleContext->getCompilerContext()->getImportedModule(structContext->typeAffiliateModule)->interfaceTable[structContext->typeIndex];
4299 overload = resolveOverloadInterface(baseName, argTypes, targetModule, interfaceType);
4300 } else {
4301 overload = resolveOverloadExtern(baseName, argTypes, targetModule, nullptr);
4302 }
4303
4304 if (!overload.found()) {
4306 return false;
4307 }
4308
4309 auto fullMangledName = overload.function->name;
4310 bool skipFirstParam = structContext != nullptr && !noThisCall && structContext->type != IRValueType::valueType::interfaceObject;
4311
4312 if (overload.isVariadic) {
4314 for (size_t i = 0; i < overload.fixedArgCount; ++i) {
4315 visit(args->get()[i]);
4316 tryCastTo(overload.function->argumentTypes[i + skipFirstParam]);
4317 }
4318 auto variadicArgCount = argTypes.size() - overload.fixedArgCount;
4319 if (variadicArgCount > 0) {
4320 for (size_t i = 0; i < variadicArgCount; ++i) {
4321 visit(args->get()[i + overload.fixedArgCount]);
4322 tryCastTo(overload.variadicElementType);
4323 }
4325 overload.variadicElementType, {static_cast<yoi::indexT>(variadicArgCount)}, variadicArgCount);
4326 } else {
4328 }
4329 } else if (overload.isCastRequired) {
4331 for (size_t i = 0; i < overload.fixedArgCount + 1; ++i) { // balanced for interface
4332 visit(args->get()[i]);
4333 tryCastTo(overload.function->argumentTypes[i + skipFirstParam]);
4334 }
4335 } else {
4337 }
4338
4339 size_t finalParamCount = overload.function->argumentTypes.size();
4340 if (structContext && structContext->type == IRValueType::valueType::structObject) {
4341 IRExternEntry externEntry = getExternEntry(targetModule, fullMangledName);
4342 auto isStaticMethod =
4343 std::find(overload.function->attrs.begin(), overload.function->attrs.end(), IRFunctionDefinition::FunctionAttrs::Static) !=
4344 overload.function->attrs.end();
4345 bool usePureStaticLogic = noThisCall && isStaticMethod;
4346
4347 if (usePureStaticLogic) {
4349 externEntry.itemIndex, finalParamCount, overload.function->returnType, true, externEntry.affiliateModule);
4350 } else {
4352 finalParamCount - !isStaticMethod,
4353 overload.function->returnType,
4354 isStaticMethod,
4355 true,
4356 externEntry.affiliateModule);
4357 }
4358 } else if (structContext && structContext->type == IRValueType::valueType::interfaceObject) {
4360 structContext->typeIndex,
4361 finalParamCount,
4362 overload.function->returnType,
4363 true,
4364 structContext->typeAffiliateModule);
4365 } else {
4366 auto externEntry = getExternEntry(targetModule, fullMangledName);
4368 externEntry.itemIndex, finalParamCount, overload.function->returnType, true, externEntry.affiliateModule);
4369 }
4370 return true;
4371 }
4372
4373 template <typename T> yoi::indexT visitor::handleBinaryOperatorOverload(const yoi::wstr &overloadName, T *rhsAST) {
4376 bool isResolved = false;
4377
4378 if (lhs->type == IRValueType::valueType::structObject) {
4379 auto resolved =
4380 resolveOverloadExtern(overloadName,
4381 {lhs, rhs},
4382 lhs->typeAffiliateModule,
4383 moduleContext->getCompilerContext()->getImportedModule(lhs->typeAffiliateModule)->structTable[lhs->typeIndex]);
4384 if (resolved.found()) {
4385 yoi_assert(resolved.isVariadic == false, 0, 0, "Binary operator overloading with variadic functions is not supported.");
4386 yoi_assert(std::find(resolved.function->attrs.begin(), resolved.function->attrs.end(), IRFunctionDefinition::FunctionAttrs::Static) !=
4387 resolved.function->attrs.end(),
4390 "Binary operator overloading with non-static functions is not supported.");
4391
4392 if (resolved.isCastRequired) {
4394 tryCastTo(resolved.function->argumentTypes.front());
4395 visit(rhsAST);
4396 tryCastTo(resolved.function->argumentTypes.back());
4397 } else {
4399 }
4400
4401 // same as below
4403 resolved.functionIndex, 1, resolved.function->returnType, false, true, lhs->typeAffiliateModule);
4404 isResolved = true;
4405 }
4406 }
4407 if (!isResolved && rhs->type == IRValueType::valueType::structObject) {
4408 auto resolved =
4409 resolveOverloadExtern(overloadName,
4410 {lhs, rhs},
4411 rhs->typeAffiliateModule,
4412 moduleContext->getCompilerContext()->getImportedModule(rhs->typeAffiliateModule)->structTable[rhs->typeIndex]);
4413 if (resolved.found()) {
4414 yoi_assert(resolved.isVariadic == false,
4417 "Binary operator overloading with variadic functions is not supported.");
4418 yoi_assert(std::find(resolved.function->attrs.begin(), resolved.function->attrs.end(), IRFunctionDefinition::FunctionAttrs::Static) !=
4419 resolved.function->attrs.end(),
4422 "Binary operator overloading with non-static functions is not supported.");
4423
4424 if (resolved.isCastRequired) {
4426 tryCastTo(resolved.function->argumentTypes.front());
4427 visit(rhsAST);
4428 tryCastTo(resolved.function->argumentTypes.back());
4429 } else {
4431 }
4432
4433 // trick here: since when we set isStatic to true, we need 3 elements on the stack, which this ptr should also be present.
4434 // however, we only have 2 elements on the stack which is lhs and rhs, so, we set isStatic to false here.
4435 // to trick the invoke method op into generating the correct code
4436 // this way, this method would take two elements from the stack and push the result to the stack.
4438 resolved.functionIndex, 1, resolved.function->returnType, false, true, rhs->typeAffiliateModule);
4439 isResolved = true;
4440 }
4441 }
4442
4443 if (!isResolved && lhs->type == IRValueType::valueType::interfaceObject) {
4444 const auto &baseName = overloadName;
4445 auto mangledName = getFuncUniqueNameStr({rhs});
4446
4447 auto resolved = resolveOverloadInterface(
4448 baseName,
4449 {lhs, rhs},
4450 lhs->typeAffiliateModule,
4451 moduleContext->getCompilerContext()->getImportedModule(lhs->typeAffiliateModule)->interfaceTable[lhs->typeIndex]);
4452
4453 if (resolved.found()) {
4454 if (resolved.isCastRequired) {
4456 tryCastTo(resolved.function->argumentTypes.front());
4457 visit(rhsAST);
4458 tryCastTo(resolved.function->argumentTypes.back());
4459 } else {
4461 }
4462
4464 resolved.functionIndex, lhs->typeIndex, 1, resolved.function->returnType, true, lhs->typeAffiliateModule);
4465 isResolved = true;
4466 }
4467 }
4468
4469 if (!isResolved) {
4471 }
4472
4473 yoi_assert(isResolved,
4476 "Binary operator overloading not found for " + yoi::wstring2string(overloadName));
4477
4479 }
4480
4481 yoi::indexT visitor::handleUnaryOperatorOverload(const yoi::wstr &overloadName) {
4483 bool isResolved = false;
4484
4485 if (rhs->type == IRValueType::valueType::structObject) {
4486 auto resolved =
4487 resolveOverloadExtern(overloadName,
4488 {rhs},
4489 rhs->typeAffiliateModule,
4490 moduleContext->getCompilerContext()->getImportedModule(rhs->typeAffiliateModule)->structTable[rhs->typeIndex]);
4491 if (resolved.found()) {
4492 yoi_assert(resolved.isVariadic == false,
4495 "Unary operator overloading with variadic functions is not supported.");
4496 yoi_assert(std::find(resolved.function->attrs.begin(), resolved.function->attrs.end(), IRFunctionDefinition::FunctionAttrs::Static) !=
4497 resolved.function->attrs.end(),
4500 "Unary operator overloading with non-static functions is not supported.");
4501 // why isStatic = false? check the comment in handleBinaryOperatorOverload
4503 resolved.functionIndex, 0, resolved.function->returnType, false, true, rhs->typeAffiliateModule);
4504 isResolved = true;
4505 }
4506 }
4507 if (rhs->type == IRValueType::valueType::interfaceObject) {
4508 const auto &baseName = overloadName;
4509 auto mangledName = getFuncUniqueNameStr({});
4510
4511 auto methodIdx = moduleContext->getCompilerContext()
4512 ->getImportedModule(rhs->typeAffiliateModule)
4513 ->interfaceTable[rhs->typeIndex]
4514 ->methodMap.getIndex(baseName + mangledName);
4515 auto method = moduleContext->getCompilerContext()
4516 ->getImportedModule(rhs->typeAffiliateModule)
4517 ->interfaceTable[rhs->typeIndex]
4518 ->methodMap[methodIdx];
4519 yoi_assert(method->argumentTypes.size() == 1,
4522 "Argument count does not match");
4523 moduleContext->getIRBuilder().invokeVirtualOp(methodIdx, rhs->typeIndex, 0, method->returnType, true, rhs->typeAffiliateModule);
4524 isResolved = true;
4525 }
4526 yoi_assert(isResolved,
4529 "Unary operator overloading not found for " + yoi::wstring2string(overloadName));
4530
4532 }
4533
4534 yoi::indexT visitor::specializeInterfaceTemplate(const yoi::wstr &templateName,
4535 const yoi::vec<std::shared_ptr<IRValueType>> &concreteTemplateArgs,
4536 yoi::indexT moduleIndex) {
4537 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(moduleIndex);
4538 yoi::wstr specializedName = getMangledTemplateName(templateName, concreteTemplateArgs);
4539 if (targetedModule->interfaceTable.contains(specializedName)) {
4540 return targetedModule->interfaceTable.getIndex(specializedName);
4541 }
4542
4543 yoi_assert(targetedModule->templateInterfaceAsts.contains(templateName), 0, 0, "Unknown interface template: " + wstring2string(templateName));
4544
4545 auto interfaceAst = targetedModule->templateInterfaceAsts.at(templateName);
4546
4547 IRTemplateBuilder specializationContext;
4548 yoi_assert(concreteTemplateArgs.size() == interfaceAst->id->arg->get().size(),
4549 0,
4550 0,
4551 "Template argument count mismatch for interface " + wstring2string(templateName));
4552 for (yoi::indexT i = 0; i < concreteTemplateArgs.size(); ++i) {
4553 auto paramName = interfaceAst->id->arg->get()[i]->getId().get().strVal;
4554 specializationContext.addTemplateArgument(paramName, concreteTemplateArgs[i]);
4555 }
4556
4557 pushModuleContext(moduleIndex);
4558 moduleContext->pushTemplateBuilder(specializationContext);
4559
4561 builder.setName(specializedName);
4562
4563 for (auto &i : interfaceAst->getInner().getInner()) {
4564 bool isVaridic = false;
4565 yoi_assert(i->isMethod(), i->getLine(), i->getColumn(), "Interface member must be a method");
4566 auto methodName = i->getMethod().getName().getId().get().strVal;
4567 auto methodResultType = managedPtr(parseTypeSpec(i->getMethod().resultType));
4569 IRFunctionDefinition::Builder methodBuilder;
4570 methodBuilder.setDebugInfo({irModule->modulePath, i->getLine(), i->getColumn()});
4571 methodBuilder.setReturnType(methodResultType);
4572 for (auto &arg : i->getMethod().getArgs().get()) {
4573 if (&arg == &i->getMethod().getArgs().get().back() && arg->spec->kind == typeSpec::typeSpecKind::Elipsis) {
4574 isVaridic = true;
4575 methodBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Variadic);
4576 auto argName = arg->getId().node.strVal;
4577 auto argType =
4578 managedPtr(arg->spec->elipsis ? parseTypeSpec(arg->spec->elipsis).getDynamicArrayType()
4579 : moduleContext->getCompilerContext()->getNullInterfaceType()->getDynamicArrayType());
4580 methodBuilder.addArgument(argName, argType);
4581 argTypes.push_back(argType);
4582 break;
4583 }
4584 auto argName = arg->getId().get().strVal;
4585 auto argType = managedPtr(parseTypeSpec(arg->spec));
4586 methodBuilder.addArgument(argName, argType);
4587 argTypes.push_back(argType);
4588 }
4589 auto uniq = getFuncUniqueNameStr(argTypes);
4590 methodBuilder.setName(L"interface#" + specializedName + L"#" + methodName + uniq);
4591 builder.addMethod(methodName, methodName + uniq, methodBuilder.yield());
4592 }
4593
4594 auto specializedInterface = builder.yield();
4595 auto interfaceIndex = irModule->interfaceTable.put_create(
4596 specializedName, specializedInterface); // since module context is still in foreign module, no need to change to targetedModule
4597
4599 popModuleContext();
4600 return interfaceIndex;
4601 }
4602
4603 void visitor::specializeInterfaceImplementation(yoi::implStmt *implAst,
4604 const std::shared_ptr<IRValueType> &concreteStructType,
4605 const yoi::wstr &specializedStructName,
4606 const yoi::vec<std::shared_ptr<IRValueType>> &concreteTemplateArgs,
4607 yoi::indexT targetModule) {
4608
4609 yoi_assert(implAst->isImplForStmt(),
4610 implAst->getLine(),
4611 implAst->getColumn(),
4612 "Expected 'impl for' AST node for interface implementation specialization.");
4613
4614 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(targetModule);
4615
4616 // The active specialization context (from specializeStructTemplate) resolves types like `T` to concrete types.
4617 auto concreteInterfaceType = managedPtr(parseTypeSpec(implAst->interfaceName));
4618 yoi_assert(concreteInterfaceType->type == IRValueType::valueType::interfaceObject,
4619 implAst->getLine(),
4620 implAst->getColumn(),
4621 "Expected an interface type.");
4622
4623 // pushModuleContext(targetModule);
4624
4625 auto interfaceSrcPair = std::make_pair(concreteInterfaceType->typeAffiliateModule, concreteInterfaceType->typeIndex);
4626
4627 auto targetInterface =
4628 moduleContext->getCompilerContext()->getImportedModule(interfaceSrcPair.first)->interfaceTable[interfaceSrcPair.second];
4629
4630 targetInterface->implementations.emplace_back(
4631 concreteStructType->type, concreteStructType->typeAffiliateModule, concreteStructType->typeIndex);
4632
4633 auto implName = getInterfaceImplName(interfaceSrcPair, concreteStructType);
4634 if (irModule->interfaceImplementationTable.contains(implName)) {
4635 return; // Already specialized and created.
4636 }
4637
4638 yoi::indexT implIndex{};
4639 try {
4640 implIndex = targetedModule->interfaceImplementationTable.getIndex(implName);
4641 if (targetedModule->interfaceImplementationTable[implIndex]) {
4642 panic(implAst->getLine(), implAst->getColumn(), "Redefinition of interface implementation: " + yoi::wstring2string(implName));
4643 }
4644 } catch (std::out_of_range &e) {
4645 implIndex = targetedModule->interfaceImplementationTable.put_create(implName, nullptr);
4646 }
4647
4648 if (implAst->inner) {
4650 builder.setName(implName);
4651 builder.setImplStructIndex({concreteStructType->type, concreteStructType->typeAffiliateModule, concreteStructType->typeIndex});
4652 builder.setImplInterfaceIndex(interfaceSrcPair);
4653
4654 std::map<yoi::wstr, std::pair<yoi::wstr, std::shared_ptr<IRValueType>>> virtualMethodMap;
4655
4656 for (auto &methodNode : implAst->getInner().getInner()) {
4657 yoi_assert(!methodNode->isConstructor(),
4658 methodNode->getLine(),
4659 methodNode->getColumn(),
4660 "Only methods are allowed in interface implementations.");
4661 auto &methodAst = methodNode->getMethod();
4662
4663 IRFunctionDefinition::Builder methodBuilder;
4664 methodBuilder.setDebugInfo({irModule->modulePath, methodAst.getLine(), methodAst.getColumn()});
4665 methodBuilder.attrs = getFunctionAttributes(methodAst.attrs);
4666 methodBuilder.attrs.insert(IRFunctionDefinition::FunctionAttrs::Preserve);
4667
4668 yoi::vec<std::shared_ptr<IRValueType>> specializedArgTypes;
4669
4670 if (std::find(methodBuilder.attrs.begin(), methodBuilder.attrs.end(), IRFunctionDefinition::FunctionAttrs::Static) ==
4671 methodBuilder.attrs.end()) {
4672 methodBuilder.addArgument(L"this", concreteStructType);
4673 }
4674
4675 for (auto &arg : methodAst.getArgs().get()) {
4676 auto specializedArgType = managedPtr(parseTypeSpec(arg->spec));
4677 methodBuilder.addArgument(arg->getId().get().strVal, specializedArgType);
4678 specializedArgTypes.push_back(specializedArgType);
4679 }
4680
4681 auto uniq = getFuncUniqueNameStr(specializedArgTypes);
4682 auto baseMethodName = methodAst.getName().getId().get().strVal;
4683
4684 methodBuilder.setReturnType(managedPtr(parseTypeSpec(methodAst.resultType)));
4685 methodBuilder.setName(specializedStructName + L"::" + baseMethodName + uniq);
4686
4687 auto func = methodBuilder.yield();
4688 auto funcIndex = irModule->functionTable.put_create(func->name, func);
4689 irModule->functionOverloadIndexies[specializedStructName + L"::" + baseMethodName].emplace_back(funcIndex);
4690
4692 moduleContext->getIRBuilder().setDebugInfo({irModule->modulePath, methodAst.getLine(), methodAst.getColumn()});
4694 visit(methodAst.block, true);
4697 virtualMethodMap[baseMethodName + getFuncUniqueNameStr(specializedArgTypes, true)] = {
4698 baseMethodName + uniq, managedPtr(IRValueType{IRValueType::valueType::virtualMethod, currentModuleIndex, funcIndex})};
4699 }
4700 for (auto &method : targetInterface->methodMap) {
4701 yoi_assert(virtualMethodMap.contains(method.first),
4702 implAst->getLine(),
4703 implAst->getColumn(),
4704 "Interface method not found in implementation: " + wstring2string(method.first));
4705 builder.addVirtualMethod(virtualMethodMap[method.first].first, virtualMethodMap[method.first].second);
4706 }
4707
4708 // popModuleContext();
4709
4710 targetedModule->interfaceImplementationTable[implIndex] = builder.yield();
4711 } else {
4712 // forward-declaration
4713 }
4714 }
4715
4716 visitor::OverloadResult visitor::resolveOverloadInterface(const yoi::wstr &baseName,
4717 const yoi::vec<std::shared_ptr<IRValueType>> &argTypes,
4718 yoi::indexT targetModule,
4719 const std::shared_ptr<IRInterfaceInstanceDefinition> &interfaceContext) {
4720 OverloadResult result;
4721 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(targetModule);
4722
4723 auto exactMangledName = baseName + getFuncUniqueNameStr(argTypes);
4724
4725 if (interfaceContext->methodMap.contains(exactMangledName)) {
4726 result.isVirtual = true;
4727 result.functionIndex = interfaceContext->methodMap.getIndex(exactMangledName);
4728 result.function = interfaceContext->methodMap[result.functionIndex];
4729 if (std::find(result.function->attrs.begin(), result.function->attrs.end(), IRFunctionDefinition::FunctionAttrs::Variadic) !=
4730 result.function->attrs.end()) {
4731 result.isVariadic = true;
4732 result.fixedArgCount = result.function->argumentTypes.size() - 1;
4733 result.variadicElementType = managedPtr(result.function->argumentTypes.back()->getElementType());
4734 }
4735 return result;
4736 }
4737
4738 auto findVariadicMatch = [&](const yoi::wstr &funcKey) {
4739 auto func = interfaceContext->methodMap[funcKey];
4740 const auto &paramTypes = func->argumentTypes;
4741 size_t fixedParamCount = paramTypes.size() - 1;
4742 if (std::find(func->attrs.begin(), func->attrs.end(), IRFunctionDefinition::FunctionAttrs::Variadic) != func->attrs.end()) {
4743 if (argTypes.size() >= fixedParamCount) {
4744 bool fixedMatch = true;
4745 for (size_t i = 0; i < fixedParamCount; ++i) {
4746 if (*paramTypes[i] != *argTypes[i]) {
4747 fixedMatch = false;
4748 break;
4749 }
4750 }
4751 if (fixedMatch) {
4752 result.functionIndex = interfaceContext->methodMap.getIndex(funcKey);
4753 result.isVariadic = true;
4754 result.isVirtual = true;
4755 result.fixedArgCount = fixedParamCount;
4756 result.variadicElementType = managedPtr(paramTypes.back()->getElementType());
4757 result.function = func;
4758 return true;
4759 }
4760 }
4761 } else {
4762 if (argTypes.size() != fixedParamCount + 1) // balance the variadic argument
4763 return false;
4764
4765 for (size_t i = 0; i < fixedParamCount; ++i) {
4766 if (!canCastTo(argTypes[i], paramTypes[i])) {
4767 return false;
4768 }
4769 }
4770
4771 result.functionIndex = interfaceContext->methodMap.getIndex(funcKey);
4772 result.isVariadic = false;
4773 result.fixedArgCount = fixedParamCount;
4774 result.function = func;
4775 result.isCastRequired = true;
4776
4777 return true;
4778 }
4779 return false;
4780 };
4781
4782 // if not even a single overload exists, return an empty result
4783 if (!interfaceContext->functionOverloadIndexies.contains(baseName))
4784 return result;
4785
4786 for (const auto &it : interfaceContext->functionOverloadIndexies[baseName]) {
4787 if (findVariadicMatch(interfaceContext->methodMap.getKey(it)))
4788 return result;
4789 }
4790
4791 return result; // Not found
4792 }
4793
4794 void visitor::pushModuleContext(yoi::indexT moduleIndex) {
4795 // printf("push module context\n");
4796 moduleContextStack.emplace(moduleContext, currentModuleIndex);
4797 this->moduleContext = moduleContext->getCompilerContext()->getModuleContext(moduleIndex);
4798 this->irModule = moduleContext->getCompilerContext()->getImportedModule(moduleIndex);
4799 currentModuleIndex = moduleIndex;
4800 }
4801
4802 void visitor::popModuleContext() {
4803 // printf("pop module context\n");
4804 this->moduleContext = moduleContextStack.top().first;
4805 currentModuleIndex = moduleContextStack.top().second;
4806 this->irModule = moduleContext->getCompilerContext()->getImportedModule(currentModuleIndex);
4807 moduleContextStack.pop();
4808 }
4809
4810 bool
4811 visitor::handleSubscript(yoi::vec<yoi::subscript *>::iterator &it, yoi::vec<yoi::subscript *>::iterator end, bool isStoreOp, bool isLastTerm) {
4812 auto objectOnStackType = moduleContext->getIRBuilder().getRhsFromTempVarStack();
4813
4814 auto currentTerm = *it;
4815
4816 if (objectOnStackType->isArrayType() || objectOnStackType->isDynamicArrayType()) {
4817 const auto &dimensions = objectOnStackType->dimensions;
4818 yoi::vec<yoi::indexT> strides(dimensions.size());
4819 strides.back() = 1;
4820 for (long long i = static_cast<long long>(dimensions.size()) - 2; i >= 0; --i) {
4821 strides[i] = strides[i + 1] * dimensions[i + 1];
4822 }
4823
4824 moduleContext->getIRBuilder().pushOp(IR::Opcode::push_unsigned,
4825 {IROperand::operandType::unsignedInt, IROperand::operandValue{static_cast<int64_t>(0)}});
4826
4827 yoi::indexT currentDim = 0;
4828 while (it != end && (*it)->isSubscript()) {
4829 yoi_assert(currentDim < dimensions.size(), (*it)->getLine(), (*it)->getColumn(), "Too many indices for array dimension.");
4830 visit((*it)->expr);
4831 tryCastTo(moduleContext->getCompilerContext()->getUnsignedObjectType());
4832 yoi_assert(moduleContext->getIRBuilder().getRhsFromTempVarStack()->type == IRValueType::valueType::unsignedObject,
4833 (*it)->getLine(),
4834 (*it)->getColumn(),
4835 "Array subscript index must be an integer or unsigned integer.");
4836 moduleContext->getIRBuilder().pushOp(IR::Opcode::push_unsigned, {IROperand::operandType::unsignedInt, strides[currentDim]});
4837 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::mul);
4838 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::add);
4839 it++;
4840 currentDim++;
4841 }
4842
4843 yoi_assert(currentDim == dimensions.size() || (isStoreOp && isLastTerm),
4844 currentTerm->getLine(),
4845 currentTerm->getColumn(),
4846 "Partial array access is not a loadable value. Not enough indices provided.");
4847
4848 if (isStoreOp && isLastTerm) {
4849 moduleContext->getIRBuilder().storeOp(IR::Opcode::store_element, {});
4850 return false;
4851 } else {
4852 auto elementType = managedPtr(objectOnStackType->getElementType());
4853 moduleContext->getIRBuilder().loadOp(IR::Opcode::load_element, {}, elementType);
4854 return true;
4855 }
4856 } else {
4857 if (isLastTerm && isStoreOp) {
4858 // current stack: [..., value, array, index]
4859
4862 visit(currentTerm->expr);
4864
4865 OverloadResult overload;
4866 if (array->type == IRValueType::valueType::structObject)
4867 overload = resolveOverloadExtern(
4868 L"operator[]",
4869 {value, array, index},
4870 array->typeAffiliateModule,
4871 moduleContext->getCompilerContext()->getImportedModule(array->typeAffiliateModule)->structTable[array->typeIndex]);
4872
4873 yoi_assert(overload.found(), currentTerm->getLine(), currentTerm->getColumn(), "No matching overload found for operator[].");
4874 yoi_assert(
4875 !overload.isVariadic, currentTerm->getLine(), currentTerm->getColumn(), "Variadic operator[] overloading is not supported.");
4876
4877 // FIXED: 前面value已经被运算了而且没有保存状态,不知道要怎么搞了,除非每次入栈的时候顺便记录一下当前insertion point
4878 if (overload.isCastRequired) {
4879 tryCastTo(overload.function->argumentTypes.back());
4881 tryCastTo(overload.function->argumentTypes.front()); // 天才啊
4882 moduleContext->getIRBuilder().commitState(); // this would commit the state.
4883 } else {
4884 // discard the state if no cast is required
4886 }
4887
4889 overload.functionIndex, 2, overload.function->returnType, false, true, array->typeAffiliateModule);
4890
4892 return false;
4893 } else {
4895 visit(currentTerm->expr);
4896 handleBinaryOperatorOverload(L"operator[]", currentTerm->expr);
4897 return false;
4898 }
4899 }
4900 }
4901
4902 IRValueType visitor::parseTypeSpec(yoi::funcTypeSpec *typeSpec) {
4904 for (auto &arg : typeSpec->args->types) {
4905 argTypes.push_back(managedPtr(parseTypeSpec(arg)));
4906 }
4907 auto returnType = managedPtr(parseTypeSpec(typeSpec->resultType));
4908
4909 return IRValueType{IRValueType::valueType::interfaceObject, HOSHI_COMPILER_CTX_GLOB_ID_CONST, createCallableInterface(argTypes, returnType)};
4910 }
4911
4912 yoi::indexT visitor::createCallableInterface(const yoi::vec<std::shared_ptr<IRValueType>> &parameterTypes,
4913 const std::shared_ptr<IRValueType> &returnType) {
4914 auto callableInterfaceName = L"callable" + getFuncUniqueNameStr(parameterTypes);
4915 callableInterfaceName += getTypeSpecUniqueNameStr(returnType);
4917 ->getImportedModule(HOSHI_COMPILER_CTX_GLOB_ID_CONST)
4918 ->interfaceTable.contains(callableInterfaceName)) {
4920 ->getImportedModule(HOSHI_COMPILER_CTX_GLOB_ID_CONST)
4921 ->interfaceTable.getIndex(callableInterfaceName);
4922 }
4923
4924 auto interfaceIndex = moduleContext->getCompilerContext()
4925 ->getImportedModule(HOSHI_COMPILER_CTX_GLOB_ID_CONST)
4926 ->interfaceTable.put_create(callableInterfaceName, {});
4927
4929 for (auto &arg : parameterTypes) {
4930 argTypes.emplace_back(L"arg", arg);
4931 }
4933 builder.setName(callableInterfaceName);
4934 builder.addMethod(L"operator()",
4935 L"operator()" + getFuncUniqueNameStr(parameterTypes),
4936 managedPtr(IRFunctionDefinition{L"operator()" + getFuncUniqueNameStr(parameterTypes), argTypes, returnType, {}, {}, {}}));
4937
4938 moduleContext->getCompilerContext()->getImportedModule(HOSHI_COMPILER_CTX_GLOB_ID_CONST)->interfaceTable[interfaceIndex] = builder.yield();
4939
4940 return interfaceIndex;
4941 }
4942
4943 yoi::indexT visitor::createLambdaUnnamedStruct(yoi::lambdaExpr *lambdaExpr) {
4944 auto structName = L"lambda" + std::to_wstring(lambdaExpr->getLine()) + L"_" + std::to_wstring(lambdaExpr->getColumn());
4945
4946 if (irModule->structTable.contains(structName)) {
4947 // when triggering re-evaluation due to cast required, we may already have the struct in the table, a quick fix for that.
4948 // but our tempVarStack rolled back, re-evaluate it then
4949 auto index = irModule->structTable.getIndex(structName);
4950 auto structType = managedPtr(IRValueType{IRValueType::valueType::structObject, currentModuleIndex, index});
4953 for (auto &i : lambdaExpr->captures) {
4954 visit(i);
4956 }
4957 auto funcName = structName + L"::constructor" + getFuncUniqueNameStr(argTypes);
4959 irModule->functionTable.getIndex(funcName), argTypes.size(), structType, false, true, currentModuleIndex);
4960 return index;
4961 }
4962
4963 auto structIndex = irModule->structTable.put_create(structName, nullptr);
4964
4965 auto structType = managedPtr(IRValueType{IRValueType::valueType::structObject, currentModuleIndex, structIndex});
4966
4968 builder.setName(structName);
4969 // add captured variables as fields
4970 IRFunctionDefinition::Builder callableBuilder;
4972
4973 callableBuilder.setDebugInfo({irModule->modulePath, lambdaExpr->getLine(), lambdaExpr->getColumn()});
4974 callableBuilder.attrs.insert(IRFunctionDefinition::FunctionAttrs::Preserve);
4975 callableBuilder.addArgument(L"this", structType);
4976 for (auto &i : lambdaExpr->args->spec) {
4977 auto argType = managedPtr(parseTypeSpec(i->spec));
4978 callableBuilder.addArgument(i->id->node.strVal, argType);
4979 argTypes.push_back(argType);
4980 }
4981 auto returnType = managedPtr(parseTypeSpec(lambdaExpr->resultType));
4982 callableBuilder.setReturnType(returnType);
4983 callableBuilder.setName(structName + L"::operator()" + getFuncUniqueNameStr(argTypes));
4984 auto callableFunc = callableBuilder.yield();
4985 auto callableFuncIndex = irModule->functionTable.put_create(callableFunc->name, callableFunc);
4986 irModule->functionOverloadIndexies[structName + L"::operator()"].push_back(callableFuncIndex);
4987 builder.addMethod(L"operator()" + getFuncUniqueNameStr(argTypes), callableFuncIndex);
4988
4989 // add captured variables as fields
4990 // now a trick here, we put new_struct op first, so that we can build the IR without rolling back the builder state
4991 // when we add captured variables as fields
4992 argTypes.clear();
4993 moduleContext->getIRBuilder().newStructOp(structIndex);
4994 for (auto &i : lambdaExpr->captures) {
4995 visit(i);
4996 auto capturedVar = moduleContext->getIRBuilder().getRhsFromTempVarStack();
4997 // i guess the IRValueType here is referenceable.
4998 capturedVar->addAttribute(IRValueType::ValueAttr::Nullable);
4999 argTypes.push_back(managedPtr(*capturedVar));
5000 builder.addField(i->node.strVal, managedPtr(*capturedVar));
5001 }
5002 // add the constructor method
5003 IRFunctionDefinition::Builder constructorBuilder;
5004 constructorBuilder.setDebugInfo({irModule->modulePath, lambdaExpr->getLine(), lambdaExpr->getColumn()});
5005 constructorBuilder.addArgument(L"this", structType);
5006 constructorBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Constructor);
5007 constructorBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::NoRawAndNullOptimization);
5008 for (yoi::indexT i = 0; i < argTypes.size(); ++i) {
5009 constructorBuilder.addArgument(L"capture#" + lambdaExpr->captures[i]->node.strVal, argTypes[i]);
5010 }
5011 constructorBuilder.setReturnType(structType);
5012 constructorBuilder.setName(structName + L"::constructor" + getFuncUniqueNameStr(argTypes));
5013 auto constructorFunc = constructorBuilder.yield();
5014 auto constructorFuncIndex = irModule->functionTable.put_create(constructorFunc->name, constructorFunc);
5015 irModule->functionOverloadIndexies[structName + L"::constructor"].push_back(constructorFuncIndex);
5016 builder.addMethod(L"constructor" + getFuncUniqueNameStr(argTypes), constructorFuncIndex);
5017
5018 // now we add the struct to the module
5019 irModule->structTable[structIndex] = builder.yield();
5020
5021 // now we invokes the constructor method to initialize the struct
5022 moduleContext->getIRBuilder().invokeMethodOp(constructorFuncIndex, argTypes.size(), structType, false, true, currentModuleIndex);
5023
5024 // finally, we generate the implementations for both operator() and constructor
5025 moduleContext->pushIRBuilder(IRBuilder{moduleContext->getCompilerContext(), irModule, irModule->functionTable[callableFuncIndex]});
5028 visit(lambdaExpr->block, true);
5031
5032 moduleContext->pushIRBuilder(IRBuilder{moduleContext->getCompilerContext(), irModule, irModule->functionTable[constructorFuncIndex]});
5035 for (yoi::indexT i = 0; i < lambdaExpr->captures.size(); ++i) {
5036 // we store our parameters into the fields of the struct
5037 // load local in accordance with the order of arguments
5038 moduleContext->getIRBuilder().loadOp(IR::Opcode::load_local,
5039 {IROperand::operandType::localVar, i + 1},
5040 argTypes[i]); // take advantages of the argTypes which we haven't clear it yet.
5041 // store the parameter into the field
5042 // now we load the this pointer, and store the parameter into the field
5044 IR::Opcode::load_local, {IROperand::operandType::localVar, IROperand::operandValue{static_cast<yoi::indexT>(0)}}, structType);
5045 moduleContext->getIRBuilder().storeMemberOp({IROperand::operandType::index, i});
5046 }
5048 IR::Opcode::load_local, {IROperand::operandType::localVar, IROperand::operandValue{static_cast<yoi::indexT>(0)}}, structType);
5052
5053 return structIndex;
5054 }
5055
5056 std::pair<yoi::indexT, std::pair<yoi::indexT, yoi::indexT>> visitor::createCallableImplementationForLambda(
5057 const std::shared_ptr<IRStructDefinition> &lambda, yoi::indexT lambdaStructIndex, yoi::indexT moduleIndex) {
5058 yoi::wstr callableName;
5059 yoi::indexT callableIndex;
5061 for (auto &[key, value] : lambda->nameIndexMap) {
5062 if (key.starts_with(L"operator()")) {
5063 callableName = key;
5064 callableIndex = value.index;
5065 break;
5066 }
5067 }
5068 auto callableFunc = moduleContext->getCompilerContext()->getImportedModule(moduleIndex)->functionTable[callableIndex];
5069 // ignore the first argument, which is the this pointer
5070 for (yoi::indexT i = 1; i < callableFunc->argumentTypes.size(); ++i) {
5071 argTypes.push_back(callableFunc->argumentTypes[i]);
5072 }
5073 auto returnType = callableFunc->returnType;
5074
5075 auto interfaceSrc = std::pair{HOSHI_COMPILER_CTX_GLOB_ID_CONST, createCallableInterface(argTypes, returnType)};
5076 auto interfaceImpl = getInterfaceImplName(interfaceSrc, moduleContext->getIRBuilder().getRhsFromTempVarStack());
5077
5078 if (irModule->interfaceImplementationTable.contains(interfaceImpl)) {
5079 // same fix here
5080 return {irModule->interfaceImplementationTable.getIndex(interfaceImpl), interfaceSrc};
5081 }
5082
5084 builder.setImplInterfaceIndex(interfaceSrc)
5085 .setImplStructIndex({IRValueType::valueType::structObject, moduleIndex, lambdaStructIndex})
5086 .setName(interfaceImpl)
5087 .addVirtualMethod(callableName, managedPtr(IRValueType{IRValueType::valueType::virtualMethod, moduleIndex, callableIndex}));
5088 auto implIndex = irModule->interfaceImplementationTable.put_create(interfaceImpl, builder.yield());
5089
5090 return {implIndex, interfaceSrc};
5091 }
5092
5093 bool visitor::checkMarcoSatisfaction(yoi::marcoDescriptor *desc) {
5094 if (!desc)
5095 return true;
5096 bool satisfied = true;
5097
5098 auto convertToSameType = [](lexer::token &lhs, lexer::token &rhs) -> std::pair<lexer::token, lexer::token> {
5099 switch (lhs.kind) {
5100 case lexer::token::tokenKind::integer:
5101 switch (rhs.kind) {
5102 case lexer::token::tokenKind::integer:
5103 return {lhs, rhs};
5104 case lexer::token::tokenKind::decimal:
5105 return {lexer::token{0, 0, lexer::token::tokenKind::decimal, static_cast<double>(lhs.basicVal.vDeci)}, rhs};
5106 default:
5107 panic(lhs.line, lhs.col, "Cannot convert marco value to comparable type.");
5108 }
5109 case lexer::token::tokenKind::decimal:
5110 switch (rhs.kind) {
5111 case lexer::token::tokenKind::integer:
5112 return {lhs, lexer::token{0, 0, lexer::token::tokenKind::decimal, static_cast<double>(rhs.basicVal.vUint)}};
5113 case lexer::token::tokenKind::decimal:
5114 return {lhs, rhs};
5115 default:
5116 panic(lhs.line, lhs.col, "Cannot convert marco value to comparable type.");
5117 }
5118 case lexer::token::tokenKind::string:
5119 switch (rhs.kind) {
5120 case lexer::token::tokenKind::string:
5121 return {lhs, rhs};
5122 case lexer::token::tokenKind::boolean:
5123 return {lexer::token{0, 0, lexer::token::tokenKind::integer, static_cast<uint64_t>(lhs.strVal == rhs.strVal)}, rhs};
5124 default:
5125 panic(lhs.line, lhs.col, "Cannot convert marco value to comparable type.");
5126 }
5127 case lexer::token::tokenKind::boolean:
5128 switch (rhs.kind) {
5129 case lexer::token::tokenKind::string:
5130 return {lexer::token{0, 0, lexer::token::tokenKind::integer, static_cast<uint64_t>(lhs.strVal == rhs.strVal)}, rhs};
5131 case lexer::token::tokenKind::boolean:
5132 return {lhs, rhs};
5133 default:
5134 panic(lhs.line, lhs.col, "Cannot convert marco value to comparable type.");
5135 }
5136 default:;
5137 }
5138 return {lhs, rhs};
5139 };
5140 auto compare = [&](lexer::token &lhs, lexer::token &rhs, lexer::token::tokenKind op) {
5141 auto [lhsTok, rhsTok] = convertToSameType(lhs, rhs);
5142 switch (op) {
5143 case lexer::token::tokenKind::equal:
5144 return lhsTok.basicVal.vUint == rhsTok.basicVal.vUint && lhsTok.strVal == rhsTok.strVal;
5145 case lexer::token::tokenKind::notEqual:
5146 return lhsTok.basicVal.vUint != rhsTok.basicVal.vUint || lhsTok.strVal != rhsTok.strVal;
5147 case lexer::token::tokenKind::greaterThan:
5148 switch (lhsTok.kind) {
5149 case lexer::token::tokenKind::integer:
5150 return lhsTok.basicVal.vUint > rhsTok.basicVal.vUint;
5151 case lexer::token::tokenKind::decimal:
5152 return lhsTok.basicVal.vDeci > rhsTok.basicVal.vDeci;
5153 default:
5154 panic(lhs.line, lhs.col, "Cannot compare marco value.");
5155 }
5156 case lexer::token::tokenKind::greaterEqual:
5157 switch (lhsTok.kind) {
5158 case lexer::token::tokenKind::integer:
5159 return lhsTok.basicVal.vUint >= rhsTok.basicVal.vUint;
5160 case lexer::token::tokenKind::decimal:
5161 return lhsTok.basicVal.vDeci >= rhsTok.basicVal.vDeci;
5162 default:
5163 panic(lhs.line, lhs.col, "Cannot compare marco value.");
5164 }
5165 case lexer::token::tokenKind::lessThan:
5166 switch (lhsTok.kind) {
5167 case lexer::token::tokenKind::integer:
5168 return lhsTok.basicVal.vUint < rhsTok.basicVal.vUint;
5169 case lexer::token::tokenKind::decimal:
5170 return lhsTok.basicVal.vDeci < rhsTok.basicVal.vDeci;
5171 default:
5172 panic(lhs.line, lhs.col, "Cannot compare marco value.");
5173 }
5174 case lexer::token::tokenKind::lessEqual:
5175 switch (lhsTok.kind) {
5176 case lexer::token::tokenKind::integer:
5177 return lhsTok.basicVal.vUint <= rhsTok.basicVal.vUint;
5178 case lexer::token::tokenKind::decimal:
5179 return lhsTok.basicVal.vDeci <= rhsTok.basicVal.vDeci;
5180 default:
5181 panic(lhs.line, lhs.col, "Cannot compare marco value.");
5182 }
5183 default:;
5184 }
5185 return false;
5186 };
5187
5188 auto &marcos = moduleContext->getCompilerContext()->getBuildConfig()->marcos;
5189 for (auto &i : desc->pairs) {
5190 bool currentSatisfied = false;
5191 auto &marco = i->identifier.strVal;
5192 yoi_assert(marcos.contains(marco), desc->getLine(), desc->getColumn(), "Undefined marco: " + yoi::wstring2string(marco));
5193 auto &value = marcos[marco];
5194 auto tok = lexer(std::wstringstream(value)).scan();
5195 tok.kind = tok.kind == lexer::token::tokenKind::identifier ? lexer::token::tokenKind::string : tok.kind;
5196
5197 auto &targetValue = i->rhs;
5198 switch (i->constraint.kind) {
5199 case lexer::token::tokenKind::equal: {
5200 currentSatisfied = tok.basicVal.vUint == targetValue.basicVal.vUint && tok.strVal == targetValue.strVal;
5201 break;
5202 }
5203 case lexer::token::tokenKind::notEqual: {
5204 currentSatisfied = tok.basicVal.vUint != targetValue.basicVal.vUint || tok.strVal != targetValue.strVal;
5205 break;
5206 }
5207 case lexer::token::tokenKind::greaterThan:
5208 case lexer::token::tokenKind::greaterEqual:
5209 case lexer::token::tokenKind::lessThan:
5210 case lexer::token::tokenKind::lessEqual: {
5211 currentSatisfied = compare(tok, targetValue, i->constraint.kind);
5212 break;
5213 }
5214 default: {
5215 panic(desc->getLine(),
5216 desc->getColumn(),
5217 "Unsupported marco constraint kind: " + std::string{magic_enum::enum_name(i->constraint.kind)});
5218 break;
5219 }
5220 }
5221 if (!currentSatisfied) {
5222 satisfied = false;
5223 break;
5224 }
5225 }
5226 return satisfied;
5227 }
5228
5229 void visitor::visit(yoi::typeAliasStmt *typeAlias) {
5230 if (typeAlias->lhs->hasDefTemplateArg()) {
5231 panic(typeAlias->getLine(), typeAlias->getColumn(), "type alias template not implemented yet");
5232 } else {
5233 auto aliasName = typeAlias->lhs->getId().node.strVal;
5234 auto rhs = parseTypeSpec(typeAlias->rhs);
5235 if (irModule->typeAliases.contains(aliasName)) {
5236 panic(typeAlias->getLine(), typeAlias->getColumn(), "Redefinition of type alias: " + yoi::wstring2string(aliasName));
5237 } else {
5238 irModule->typeAliases[aliasName] = rhs;
5239 }
5240 }
5241 }
5242
5243 std::shared_ptr<IRValueType> visitor::mapEnumTypeToBasicType(yoi::indexT targetModule, yoi::indexT targetEnumType) {
5244 auto enumDef = moduleContext->getCompilerContext()->getImportedModule(targetModule)->enumerationTable[targetEnumType];
5245 switch (enumDef->getUnderlyingType()) {
5246 case IREnumerationType::UnderlyingType::I8:
5247 return moduleContext->getCompilerContext()->getCharObjectType();
5248 case IREnumerationType::UnderlyingType::I16:
5249 return moduleContext->getCompilerContext()->getShortObjectType();
5250 case IREnumerationType::UnderlyingType::I64:
5251 return moduleContext->getCompilerContext()->getUnsignedObjectType();
5252 default:
5253 return nullptr;
5254 }
5255 }
5256
5260 yoi::indexT idx = 0;
5261 for (auto &node : enumerationDefinition->values) {
5262 idx = node->value.kind != lexer::token::tokenKind::unknown ? node->value.basicVal.vInt : idx;
5263 builder.addValue(node->name->get().strVal, idx++);
5264 }
5265 auto enumType = builder.yield();
5266 auto enumIndex = irModule->enumerationTable.put_create(enumType->name, enumType);
5267 auto underlyingEnumType = mapEnumTypeToBasicType(currentModuleIndex, enumIndex);
5268 irModule->typeAliases[enumerationDefinition->name->get().strVal] = *underlyingEnumType;
5269 }
5270
5271 yoi::indexT visitor::visit(yoi::funcExpr *func) {
5272 auto it = func->name->getTerms().begin();
5273 yoi::indexT targetModule = -1, lastModule = -1;
5274 // 1. Resolve module prefixes (e.g., std.io)
5275 while (it + 1 != func->name->getTerms().end() && (targetModule = isModuleName((*it)->id, lastModule)) != lastModule) {
5276 it++;
5277 lastModule = targetModule;
5278 }
5279
5280 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(targetModule == -1 ? currentModuleIndex : targetModule);
5281 enum class CreateStrategy { Plain, IncludeThis } strategy{CreateStrategy::Plain};
5282 yoi::indexT funcIndex = -1;
5283
5284 // 1. Struct Static Method
5285 if (it + 2 == func->name->getTerms().end()) {
5286 auto nameNode = *(it);
5287 auto funcNameNode = *(it + 1);
5288 std::shared_ptr<IRStructDefinition> structType;
5289
5290 if (nameNode->hasTemplateArg() && targetedModule->structTemplateAsts.contains(nameNode->getId().node.strVal)) {
5291 auto concreteTypes = parseTemplateArgs(nameNode->getArg());
5292 auto specializedIndex = specializeStructTemplate(
5293 nameNode->id->node.strVal, concreteTypes, targetedModule->templateImplAsts[nameNode->getId().node.strVal], targetModule);
5294 structType = targetedModule->structTable[specializedIndex];
5295
5296 } else if (targetedModule->structTable.contains(nameNode->getId().node.strVal)) {
5297 structType = targetedModule->structTable[nameNode->getId().node.strVal];
5298 } else {
5299 panic(nameNode->getLine(), nameNode->getColumn(), "Undefined struct: " + yoi::wstring2string(nameNode->getId().node.strVal));
5300 }
5301
5302 yoi::wstr baseName = structType->name + L"::" + funcNameNode->getId().node.strVal;
5303
5304 yoi_assert(targetedModule->functionOverloadIndexies.contains(baseName),
5305 funcNameNode->getLine(),
5306 funcNameNode->getColumn(),
5307 "Undefined method: " + yoi::wstring2string(baseName));
5308
5309 // check whether explicit param types specified
5310 if (func->args) {
5312 for (auto &arg : func->args->types) {
5313 argTypes.push_back(managedPtr(parseTypeSpec(arg)));
5314 }
5315 yoi::wstr fullFuncName = baseName + getFuncUniqueNameStr(argTypes);
5316 yoi_assert(targetedModule->functionTable.contains(fullFuncName),
5317 funcNameNode->getLine(),
5318 funcNameNode->getColumn(),
5319 "No matching function overload found with explicit param types: " + yoi::wstring2string(fullFuncName));
5320 yoi_assert(targetedModule->functionTable[fullFuncName]->hasAttribute(IRFunctionDefinition::FunctionAttrs::Static),
5321 funcNameNode->getLine(),
5322 funcNameNode->getColumn(),
5323 "Cannot call non-static method: " + yoi::wstring2string(fullFuncName));
5324 funcIndex = targetedModule->functionTable.getIndex(fullFuncName);
5325 strategy = CreateStrategy::Plain;
5326 } else {
5327 // no params, check whether the function table contains only one
5328 yoi_assert(targetedModule->functionOverloadIndexies[baseName].size() == 1,
5329 funcNameNode->getLine(),
5330 funcNameNode->getColumn(),
5331 "Inplicit specification on multiple overloads of method: " + yoi::wstring2string(baseName));
5332 auto candidateIndex = targetedModule->functionOverloadIndexies[baseName][0];
5333 yoi_assert(targetedModule->functionTable[candidateIndex]->hasAttribute(IRFunctionDefinition::FunctionAttrs::Static),
5334 funcNameNode->getLine(),
5335 funcNameNode->getColumn(),
5336 "Cannot call non-static method: " + yoi::wstring2string(baseName));
5337 funcIndex = candidateIndex;
5338 strategy = CreateStrategy::Plain;
5339 }
5340 } else if (it + 1 == func->name->getTerms().end()) {
5341 // 2. Global Function
5342 auto funcNameNode = *(it);
5343 yoi_assert(targetedModule->functionOverloadIndexies.contains(funcNameNode->getId().node.strVal),
5344 funcNameNode->getLine(),
5345 funcNameNode->getColumn(),
5346 "Undefined function: " + yoi::wstring2string(funcNameNode->getId().node.strVal));
5347 // If explicit param types specified, use full-qualified name first
5348 if (func->args) {
5350 for (auto &arg : func->args->types) {
5351 argTypes.push_back(managedPtr(parseTypeSpec(arg)));
5352 }
5353 yoi::wstr fullFuncName = funcNameNode->getId().node.strVal + getFuncUniqueNameStr(argTypes);
5354 yoi_assert(targetedModule->functionTable.contains(fullFuncName),
5355 funcNameNode->getLine(),
5356 funcNameNode->getColumn(),
5357 "No matching function overload found with explicit param types: " + yoi::wstring2string(fullFuncName));
5358 funcIndex = targetedModule->functionTable.getIndex(fullFuncName);
5359 strategy = CreateStrategy::Plain;
5360 } else {
5361 // no params, check whether the function table contains only one
5362 yoi_assert(targetedModule->functionOverloadIndexies[funcNameNode->getId().node.strVal].size() == 1,
5363 funcNameNode->getLine(),
5364 funcNameNode->getColumn(),
5365 "Inplicit specification on multiple overloads of function: " + yoi::wstring2string(funcNameNode->getId().node.strVal));
5366 funcIndex = targetedModule->functionOverloadIndexies[funcNameNode->getId().node.strVal][0];
5367 strategy = CreateStrategy::Plain;
5368 }
5369 } else {
5370 yoi_assert(false, func->getLine(), func->getColumn(), "invalid function expression");
5371 }
5372
5373 yoi_assert(funcIndex != -1, func->getLine(), func->getColumn(), "Cannot resolve function overload");
5374 switch (strategy) {
5375 case CreateStrategy::Plain: {
5376 auto funcDef = targetedModule->functionTable[funcIndex];
5377 auto impl = createCallableImplementationForFunction(funcDef, funcIndex, targetModule == -1 ? currentModuleIndex : targetModule, false);
5378 createCallableInstanceForFunction(impl.first, impl.second, targetModule == -1 ? currentModuleIndex : targetModule, false);
5379 break;
5380 }
5381 case CreateStrategy::IncludeThis: {
5382 panic(func->getLine(), func->getColumn(), "Not implemented yet");
5383 break;
5384 }
5385 default: {
5386 panic(func->getLine(), func->getColumn(), "Unsupported create strategy");
5387 break;
5388 }
5389 }
5390
5392 }
5393
5394 std::pair<yoi::indexT, std::pair<yoi::indexT, yoi::indexT>> visitor::createCallableImplementationForFunction(
5395 const std::shared_ptr<IRFunctionDefinition> &func, yoi::indexT funcIndex, yoi::indexT moduleIndex, bool hasThis) {
5396 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(moduleIndex);
5397 auto objectType = hasThis ? func->argumentTypes[0] : nullptr;
5398
5400 for (auto index = hasThis ? 1 : 0; index < func->argumentTypes.size(); index++) {
5401 argTypes.push_back(func->argumentTypes[index]);
5402 }
5403
5404 auto callableInterface = std::pair{HOSHI_COMPILER_CTX_GLOB_ID_CONST, createCallableInterface(argTypes, func->returnType)};
5405
5406 auto uniqueName = L"callableWrapper#" + func->name + getFuncUniqueNameStr(argTypes);
5407 if (targetedModule->structTable.contains(uniqueName)) {
5408 auto interfaceImplName = getInterfaceImplName(
5409 callableInterface,
5410 managedPtr(IRValueType{IRValueType::valueType::structObject, moduleIndex, targetedModule->structTable.getIndex(uniqueName)}));
5411 return {targetedModule->interfaceImplementationTable.getIndex(interfaceImplName), callableInterface};
5412 }
5413
5414 yoi::indexT structTypeIndex = targetedModule->structTable.put_create(uniqueName, {});
5415 yoi::wstr constructorName = hasThis ? uniqueName + L"::constructor#" + getTypeSpecUniqueNameStr(objectType) : uniqueName + L"::constructor#";
5416 yoi::indexT constructorIndex = targetedModule->functionTable.put_create(constructorName, {});
5417 yoi::wstr callableName = uniqueName + L"::operator()" + getFuncUniqueNameStr(func->argumentTypes);
5418 yoi::indexT callableIndex = targetedModule->functionTable.put_create(callableName, {});
5419
5421
5422 if (hasThis) {
5423 builder.addField(L"object_this", objectType);
5424 }
5425
5426 auto constructorUniqueName = hasThis ? L"constructor#" + getTypeSpecUniqueNameStr(objectType) : L"constructor#";
5427 builder.setName(uniqueName).addMethod(constructorUniqueName, constructorIndex);
5428 builder.setName(uniqueName).addMethod(L"operator()" + getFuncUniqueNameStr(func->argumentTypes), callableIndex);
5429 targetedModule->structTable[structTypeIndex] = builder.yield();
5430
5431 auto structType = managedPtr(IRValueType{IRValueType::valueType::structObject, moduleIndex, structTypeIndex});
5432
5433 IRFunctionDefinition::Builder constructorBuilder;
5434 constructorBuilder.setName(constructorName);
5435 constructorBuilder.addArgument(L"this", structType);
5436 if (hasThis) {
5437 constructorBuilder.addArgument(L"object_this", objectType);
5438 }
5439 constructorBuilder.setReturnType(structType);
5440 constructorBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::NoRawAndNullOptimization);
5441 constructorBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Preserve);
5443 targetedModule->functionTable[constructorIndex] = constructorBuilder.yield();
5444 IRFunctionDefinition::Builder callableBuilder;
5445 callableBuilder.setName(callableName);
5446 callableBuilder.addArgument(L"this", structType);
5447 for (yoi::indexT argIndex = hasThis ? 1 : 0; argIndex < func->argumentTypes.size(); argIndex++) {
5448 auto arg = func->argumentTypes[argIndex];
5449 callableBuilder.addArgument(L"param" + std::to_wstring(argIndex), arg);
5450 }
5451 callableBuilder.setReturnType(func->returnType);
5452 callableBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Preserve);
5454 targetedModule->functionTable[callableIndex] = callableBuilder.yield();
5455
5456 moduleContext->pushIRBuilder(IRBuilder{moduleContext->getCompilerContext(), targetedModule, targetedModule->functionTable[constructorIndex]});
5458 // setup this
5459 if (hasThis) {
5461 IR::Opcode::load_local, {IROperand::operandType::index, IROperand::operandValue{(yoi::indexT)1}}, objectType, moduleIndex);
5463 IR::Opcode::load_local, {IROperand::operandType::index, IROperand::operandValue{(yoi::indexT)0}}, structType, moduleIndex);
5465 IR::Opcode::store_member, {IROperand::operandType::index, IROperand::operandValue{(yoi::indexT)0}}, moduleIndex);
5466 }
5468 IR::Opcode::load_local, {IROperand::operandType::index, IROperand::operandValue{(yoi::indexT)0}}, structType, moduleIndex);
5472
5473 moduleContext->pushIRBuilder(IRBuilder{moduleContext->getCompilerContext(), targetedModule, targetedModule->functionTable[callableIndex]});
5475 if (hasThis) {
5477 IR::Opcode::load_local, {IROperand::operandType::index, IROperand::operandValue{(yoi::indexT)0}}, structType, moduleIndex);
5479 IR::Opcode::load_member, {IROperand::operandType::index, IROperand::operandValue{(yoi::indexT)0}}, objectType, moduleIndex);
5480 }
5481 for (yoi::indexT argIndex = hasThis ? 1 : 0; argIndex < func->argumentTypes.size(); argIndex++) {
5482 auto arg = func->argumentTypes[argIndex];
5484 IR::Opcode::load_local, {IROperand::operandType::index, (yoi::indexT)(argIndex + 1)}, arg, moduleIndex);
5485 }
5486 moduleContext->getIRBuilder().invokeOp(funcIndex, func->argumentTypes.size(), func->returnType, true, moduleIndex);
5487 moduleContext->getIRBuilder().retOp(func->returnType->type == IRValueType::valueType::none);
5490
5491 auto interfaceImplName = getInterfaceImplName(
5492 callableInterface,
5493 managedPtr(IRValueType{IRValueType::valueType::structObject, moduleIndex, targetedModule->structTable.getIndex(uniqueName)}));
5494
5495 auto interfaceImplIndex = targetedModule->interfaceImplementationTable.put_create(
5496 interfaceImplName,
5498 .setName(interfaceImplName)
5499 .addVirtualMethod(L"operator()" + getFuncUniqueNameStr(func->argumentTypes),
5500 managedPtr(IRValueType{IRValueType::valueType::virtualMethod, moduleIndex, callableIndex}))
5501 .setImplInterfaceIndex(callableInterface)
5502 .setImplStructIndex({IRValueType::valueType::structObject, moduleIndex, structTypeIndex})
5503 .yield());
5504
5505 return {interfaceImplIndex, callableInterface};
5506 }
5507
5508 void visitor::createCallableInstanceForFunction(yoi::indexT implIndex,
5509 std::pair<yoi::indexT, yoi::indexT> callableInterfaceIndex,
5510 yoi::indexT moduleIndex, bool hasThis) {
5511 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(moduleIndex);
5512 auto implDef = targetedModule->interfaceImplementationTable[implIndex];
5513 auto structIndex = implDef->implStructIndex;
5514 // moduleContext->getCompilerContext()->getImportedModule(std::get<1>(structIndex))->structTable[std]
5515 if (hasThis) {
5516 auto objectPtrOnStack = moduleContext->getIRBuilder().getRhsFromTempVarStack();
5517 moduleContext->getIRBuilder().newStructOp(std::get<2>(structIndex), true, std::get<1>(structIndex));
5518 // since we gained the object ptr, the next thing we wish to do is to invoke the constructor
5519 auto constructorIndex = targetedModule->structTable[std::get<2>(structIndex)]->nameIndexMap.at(L"constructor#" + getTypeSpecUniqueNameStr(objectPtrOnStack));
5520 moduleContext->getIRBuilder().invokeDanglingOp(constructorIndex.index, 2, objectPtrOnStack, true, moduleIndex);
5521 // now we have the newly created struct on the stack
5522 // we can safely construct interface impl now
5523 } else {
5524 moduleContext->getIRBuilder().newStructOp(std::get<2>(structIndex), true, std::get<1>(structIndex));
5525 }
5526 moduleContext->getIRBuilder().constructInterfaceImplOp(callableInterfaceIndex, implIndex, true, moduleIndex);
5527 }
5528
5530 yoi::vec<IRValueType> bracedTypes;
5531 for (auto &i : bracedInitalizerList->exprs) {
5532 visit(i);
5533 bracedTypes.push_back(*moduleContext->getIRBuilder().getRhsFromTempVarStack());
5534 }
5535 moduleContext->getIRBuilder().pushTempVar(managedPtr(IRValueType{IRValueType::valueType::bracedInitalizerList, bracedTypes}));
5537 }
5538
5540 auto placeholder = irModule->dataStructTable.put_create(dataStructDefStmt->id->get().strVal, {});
5541 auto builder = IRDataStructDefinition::Builder()
5543
5544 for (auto &i : dataStructDefStmt->getInner().getInner()) {
5545 auto &id = i->getVar().id->get().strVal;
5546 auto spec = parseTypeSpec(i->getVar().spec);
5547 builder.addField(id, managedPtr(spec));
5548 }
5549
5550 irModule->dataStructTable[placeholder] = builder.yield();
5551 }
5552
5553 void
5554 visitor::constructDataStruct(yoi::indexT datastructIndex, yoi::indexT moduleIndex, yoi::invocationArguments *args) {
5555 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(moduleIndex);
5556 auto datastructDef = targetedModule->dataStructTable[datastructIndex];
5557
5558 moduleContext->getIRBuilder().newDataStructOp(datastructIndex, true, moduleIndex);
5559
5560 if (args->arg.empty()) {
5561 return;
5562 }
5563
5564 yoi_assert(args->arg.size() == datastructDef->fieldTypes.size(), args->getLine(), args->getColumn(), "expected " + std::to_string(datastructDef->fields.size()) + " arguments to construct data struct " + yoi::wstring2string(datastructDef->name) + ", got " + std::to_string(args->arg.size()));
5565 for (yoi::indexT i = 0; i < args->arg.size(); i++) {
5566 visit(args->arg[i]);
5567 tryCastTo(datastructDef->fieldTypes[i]);
5568 }
5570
5571 }
5572
5573 yoi::indexT visitor::visit(yoi::yieldStmt *stmt) {
5574 yoi_assert(moduleContext->getIRBuilder().irFuncDefinition()->hasAttribute(IRFunctionDefinition::FunctionAttrs::Generator), stmt->getLine(), stmt->getColumn(), "yield can only be used in generator function");
5575 auto ctxIndex = moduleContext->getIRBuilder().irFuncDefinition()->getVariableTable().lookup(L"__context__");
5576 auto ctxType = moduleContext->getIRBuilder().irFuncDefinition()->returnType;
5577 moduleContext->getIRBuilder().loadOp(IR::Opcode::load_local, {IROperand::operandType::index, ctxIndex}, ctxType);
5578 moduleContext->getIRBuilder().loadMemberOp({IROperand::operandType::index, IROperand::operandValue{yoi::indexT(0)}}, moduleContext->getCompilerContext()->getUnsignedObjectType());
5579
5580 if (stmt->expr) {
5581 visit(stmt->expr);
5583 } else {
5584
5586 }
5588 }
5589
5590 std::shared_ptr<IRValueType> visitor::getGeneratorContext(const yoi::wstr &funcName, const std::shared_ptr<IRValueType> &yieldType) {
5591 auto builtinModule = moduleContext->getCompilerContext()->getImportedModule(HOSHI_COMPILER_CTX_GLOB_ID_CONST);
5592 auto generatorContextName = L"GeneratorContext#" + funcName;
5593 auto generatorContextIndex = builtinModule->structTable.put_create(generatorContextName, {});
5594 auto generatorContextType = managedPtr(IRValueType{
5595 IRValueType::valueType::structObject,
5597 generatorContextIndex
5598 });
5599
5600 auto generatorConstructorName = L"constructor#" + getTypeSpecUniqueNameStr(moduleContext->getCompilerContext()->getUnsignedObjectType());
5601 auto generatorConstructorIndex = builtinModule->functionTable.put_create(generatorContextName + L"::" + generatorConstructorName, {});
5602 auto generatorNextName = L"next#";
5603 auto generatorNextIndex = builtinModule->functionTable.put_create(generatorContextName + L"::" + generatorNextName, {});
5604
5605 auto unsignedDataField = managedPtr(*moduleContext->getCompilerContext()->getUnsignedObjectType());
5606 unsignedDataField->metadata.setMetadata(L"STRUCT_DATAFIELD", true);
5607
5608 auto builder = IRStructDefinition::Builder()
5609 .setName(generatorContextName)
5610 .addField(L"raw_ctx", unsignedDataField)
5611 .addField(L"yields", yieldType)
5612 .addMethod(generatorConstructorName, generatorConstructorIndex)
5613 .addMethod(generatorNextName, generatorNextIndex);
5614
5615 builtinModule->structTable[generatorContextIndex] = builder.yield();
5616
5617 builtinModule->functionTable[generatorConstructorIndex] = IRFunctionDefinition::Builder()
5618 .setName(generatorContextName + L"::" + generatorConstructorName)
5619 .addArgument(L"this", generatorContextType)
5620 .addArgument(L"raw_ctx", moduleContext->getCompilerContext()->getUnsignedObjectType())
5621 .setReturnType(generatorContextType)
5622 .addAttr(IRFunctionDefinition::FunctionAttrs::Preserve)
5623 .setDebugInfo({builtinModule->modulePath, 0, 0})
5624 .yield();
5625
5626 builtinModule->functionTable[generatorNextIndex] = IRFunctionDefinition::Builder()
5627 .setName(generatorContextName + L"::" + generatorNextName)
5628 .addArgument(L"this", generatorContextType)
5629 .setReturnType(yieldType)
5630 .addAttr(IRFunctionDefinition::FunctionAttrs::Preserve)
5631 .setDebugInfo({builtinModule->modulePath, 0, 0})
5632 .yield();
5633
5634 builtinModule->functionOverloadIndexies[generatorContextName + L"::constructor"].push_back(generatorConstructorIndex);
5635 builtinModule->functionOverloadIndexies[generatorContextName + L"::next"].push_back(generatorNextIndex);
5636
5639 builtinModule,
5640 builtinModule->functionTable[generatorConstructorIndex]
5641 });
5643 moduleContext->getIRBuilder().loadOp(IR::Opcode::load_local, {IROperand::operandType::index, IROperand::operandValue{yoi::indexT(1)}}, moduleContext->getCompilerContext()->getUnsignedObjectType());
5644 moduleContext->getIRBuilder().loadOp(IR::Opcode::load_local, {IROperand::operandType::index, IROperand::operandValue{yoi::indexT(0)}}, generatorContextType);
5645 moduleContext->getIRBuilder().storeMemberOp({IROperand::operandType::index, IROperand::operandValue{yoi::indexT(0)}});
5646 moduleContext->getIRBuilder().loadOp(IR::Opcode::load_local, {IROperand::operandType::index, IROperand::operandValue{yoi::indexT(0)}}, generatorContextType);
5650
5653 builtinModule,
5654 builtinModule->functionTable[generatorNextIndex]
5655 });
5657 // in the first suspend, we just only return the allocated generator context, but doing nothing.
5658 // we only begin yielding value after first resume.
5659 moduleContext->getIRBuilder().loadOp(IR::Opcode::load_local, {IROperand::operandType::index, IROperand::operandValue{yoi::indexT(0)}}, generatorContextType);
5661 moduleContext->getIRBuilder().loadOp(IR::Opcode::load_local, {IROperand::operandType::index, IROperand::operandValue{yoi::indexT(0)}}, generatorContextType);
5662 moduleContext->getIRBuilder().loadMemberOp({IROperand::operandType::index, IROperand::operandValue{yoi::indexT(1)}}, yieldType);
5666
5667 return managedPtr(IRValueType{IRValueType::valueType::structObject, HOSHI_COMPILER_CTX_GLOB_ID_CONST, generatorContextIndex});
5668 }
5669
5671 auto conceptName = conceptDefinition->name.strVal;
5672 irModule->concepts[conceptName] = managedPtr(IRConcept{
5673 conceptName,
5674 irModule->identifier,
5676 });
5677 }
5678
5679 void visitor::setupTemporaryConceptEvaluationEnvironment(yoi::indexT moduleIndex, const yoi::wstr &conceptName, const std::vector<std::shared_ptr<IRValueType>> &args) {
5680 yoi_assert(
5681 moduleContext->getCompilerContext()->getImportedModule(moduleIndex)->concepts[conceptName]->def->typeParams.size() == args.size(),
5684 "Concept type parameter count does not match the number of arguments."
5685 );
5686
5687 IRTemplateBuilder specializationContext;
5688 for (yoi::indexT i = 0; i < args.size(); i += 1) {
5689 specializationContext.addTemplateArgument(
5690 moduleContext->getCompilerContext()->getImportedModule(moduleIndex)->concepts[conceptName]->def->typeParams[i].strVal,
5691 args[i]
5692 );
5693 }
5694 moduleContext->pushTemplateBuilder(specializationContext);
5695 // specialize the params
5697
5698 for (yoi::indexT i = 0; i < moduleContext->getCompilerContext()->getImportedModule(moduleIndex)->concepts[conceptName]->def->algebraParams.size(); i += 1) {
5699 auto node = moduleContext->getCompilerContext()->getImportedModule(moduleIndex)->concepts[conceptName]->def->algebraParams[i];
5700 params.push_back({
5701 node->id->node.strVal,
5702 managedPtr(parseTypeSpec(node->spec))
5703 });
5704 }
5705 // create fake function and push IRBuilder
5708 moduleContext->getCompilerContext()->getImportedModule(moduleIndex),
5710 L"temporary",
5711 params,
5712 {},
5713 {},
5714 {},
5715 {}
5716 })
5717 });
5719 }
5720
5721 void visitor::ejectTemporaryConceptEvaluationEnvironment() {
5724 }
5725
5726 void visitor::evaluateConstraint(yoi::conceptStmt *stmt, const IRDebugInfo &currentDebugInfo) {
5727 switch (stmt->kind) {
5729 checkConceptSatisfaction(stmt->value.satisfyStmt->emae);
5730 break;
5733 try {
5734 visit(stmt->value.expression);
5735 } catch (std::runtime_error &e) {
5736 panic(currentDebugInfo.line, currentDebugInfo.column, "Constraint evaluation failed: " + std::string(e.what()));
5737 }
5739 break;
5740 default:
5741 break;
5742 }
5743 }
5744
5745 std::pair<std::shared_ptr<IRConcept>, templateArg *> visitor::parseConceptName(yoi::externModuleAccessExpression *conceptName) {
5746 yoi::indexT currentModIndex = conceptName->getTerms().size() > 1 ? -1 : currentModuleIndex;
5747 for (yoi::indexT i = 0; i < conceptName->getTerms().size() - 1; i += 1) {
5748 auto term = conceptName->getTerms()[i];
5749 yoi_assert(!term->hasTemplateArg(), term->getLine(), term->getColumn(), "template arguments is not allowed except in the last term");
5750 yoi_assert(moduleContext->getCompilerContext()->getImportedModule(currentModIndex)->moduleImports.contains(term->id->node.strVal), term->getLine(), term->getColumn(), "module not found");
5751 currentModIndex = moduleContext->getCompilerContext()->getImportedModule(currentModIndex)->moduleImports[term->id->node.strVal];
5752 }
5753 auto name = conceptName->getTerms().back()->id->node.strVal;
5754 yoi_assert(moduleContext->getCompilerContext()->getImportedModule(currentModIndex)->concepts.contains(name), conceptName->getLine(), conceptName->getColumn(), "concept not found");
5755
5756 return {
5757 moduleContext->getCompilerContext()->getImportedModule(currentModIndex)->concepts[name],
5758 conceptName->getTerms().back()->arg
5759 };
5760 }
5761
5762 void visitor::checkConceptSatisfaction(yoi::externModuleAccessExpression *stmt) {
5763 auto [conceptDef, parsedTemplateArg] = parseConceptName(stmt);
5764
5766
5767 for (auto &i : parsedTemplateArg->spec) {
5768 args.push_back(managedPtr(parseTypeSpec(i->spec)));
5769 }
5770
5771 setupTemporaryConceptEvaluationEnvironment(currentModuleIndex, conceptDef->name, args);
5772
5773 for (auto constraint : conceptDef->def->conceptBlock) {
5774 evaluateConstraint(constraint, {
5776 stmt->getLine(),
5777 stmt->getColumn()
5778 });
5779 }
5780
5781 ejectTemporaryConceptEvaluationEnvironment();
5782 }
5783
5784 void visitor::checkConceptSatisfaction(yoi::externModuleAccessExpression *stmt,
5785 const yoi::wstr &paramName,
5786 const std::shared_ptr<IRValueType> &args) {
5788 t.addTemplateArgument(paramName, args);
5790 checkConceptSatisfaction(stmt);
5792 }
5793} // namespace yoi
#define HOSHI_COMPILER_CTX_GLOB_ID_CONST
yoi::indexT getColumn()
Definition ast.cpp:1037
yoi::indexT getLine()
Definition ast.cpp:1041
void pushLoopContext(yoi::indexT breakTarget, yoi::indexT continueTarget)
Definition IR.cpp:1524
void invokeOp(yoi::indexT funcIndex, yoi::indexT funcArgsCount, const std::shared_ptr< IRValueType > &returnType, bool externalInvocation=false, yoi::indexT moduleIndex=-1)
Invoke a function with the given arguments.
Definition IR.cpp:382
yoi::indexT saveState()
Definition IR.cpp:1164
void continueOp()
Definition IR.cpp:1494
std::shared_ptr< IRValueType > & getLhsFromTempVarStack()
Definition IR.cpp:159
void newDataStructOp(yoi::indexT structIndex, bool isExternal=false, yoi::indexT moduleIndex=-1)
Definition IR.cpp:462
const IRDebugInfo & getCurrentDebugInfo()
Definition IR.cpp:1207
void popOp()
Definition IR.cpp:1189
void yieldOp(bool yieldNone=false)
Definition IR.cpp:1698
void invokeVirtualOp(yoi::indexT funcIndex, yoi::indexT interfaceIndex, yoi::indexT methodArgsCount, const std::shared_ptr< IRValueType > &returnType, bool externalInvocation=false, yoi::indexT moduleIndex=-1)
Definition IR.cpp:420
void pushOp(IR::Opcode op, const yoi::IROperand &constV)
Definition IR.cpp:303
void interfaceOfOp()
Definition IR.cpp:1345
IRCodeBlock & getCodeBlock(yoi::indexT index)
Definition IR.cpp:128
void storeOp(IR::Opcode op, const yoi::IROperand &operand, yoi::indexT moduleIndex=-1)
Definition IR.cpp:350
void basicCast(const std::shared_ptr< IRValueType > &valType, yoi::indexT insertionPoint, bool lhs=false)
Definition IR.cpp:169
yoi::indexT createCodeBlock()
Definition IR.cpp:123
void breakOp()
Definition IR.cpp:1489
void constructInterfaceImplOp(const std::pair< yoi::indexT, yoi::indexT > &interfaceId, yoi::indexT interfaceImplIndex, bool isExternal=false, yoi::indexT moduleIndex=-1)
Definition IR.cpp:471
void loadFieldOp(yoi::vec< yoi::IROperand > &accessors, const std::shared_ptr< IRValueType > &expectedType)
Definition IR.cpp:1680
void yield()
Definition IR.cpp:132
std::shared_ptr< IRFunctionDefinition > irFuncDefinition()
Definition IR.cpp:502
void pushTempVar(const std::shared_ptr< IRValueType > &type)
Definition IR.cpp:1185
void newArrayOp(const std::shared_ptr< IRValueType > &elementType, const yoi::vec< yoi::indexT > &dimensions, yoi::indexT onstackElementCount)
Definition IR.cpp:1106
void loadOp(IR::Opcode op, const yoi::IROperand &source, const std::shared_ptr< IRValueType > &expectedType, yoi::indexT moduleIndex=-1)
Definition IR.cpp:329
void storeFieldOp(yoi::vec< yoi::IROperand > &accessors)
Definition IR.cpp:1687
void typeIdOp(const std::shared_ptr< IRValueType > &type)
Definition IR.cpp:1222
void invokeImportedOp(yoi::indexT libIndex, yoi::indexT funcIndex, yoi::indexT funcArgsCount, const std::shared_ptr< IRValueType > &returnType)
Definition IR.cpp:1070
void newStructOp(yoi::indexT structIndex, bool isExternal=false, yoi::indexT moduleIndex=-1)
Definition IR.cpp:453
yoi::indexT switchCodeBlock(yoi::indexT index)
Definition IR.cpp:492
void discardState()
Definition IR.cpp:1169
void discardStateUntil(yoi::indexT stateIndex)
Definition IR.cpp:1456
void bindElementsOp(yoi::indexT extractElementCount, ExtractType extractType)
Definition IR.cpp:1499
void insert(const IR &ir, yoi::indexT insertionPoint=0xffffffff)
Definition IR.cpp:147
void invokeMethodOp(yoi::indexT funcIndex, yoi::indexT methodArgsCount, const std::shared_ptr< IRValueType > &returnType, bool isStatic, bool externalInvocation=false, yoi::indexT moduleIndex=-1)
Definition IR.cpp:398
void uniqueArithmeticOp(IR::Opcode op)
Definition IR.cpp:233
void loadMemberOp(const yoi::IROperand &memberIndex, const std::shared_ptr< IRValueType > &memberType)
Definition IR.cpp:344
void arrayLengthOp()
Definition IR.cpp:1339
void popLoopContext()
Definition IR.cpp:1485
void commitState()
Definition IR.cpp:1444
void initializeFieldsOp(yoi::indexT parameterCount)
Definition IR.cpp:1673
void resumeOp()
Definition IR.cpp:1693
void jumpOp(yoi::indexT target)
Definition IR.cpp:286
void bindFieldsOp(yoi::indexT extractFieldCount, ExtractType extractType)
Definition IR.cpp:1511
void restoreState()
Definition IR.cpp:1174
void jumpIfOp(IR::Opcode op, yoi::indexT target)
Definition IR.cpp:292
yoi::indexT getCurrentInsertionPoint()
Definition IR.cpp:484
void restoreStateTemporarily()
Definition IR.cpp:1433
void invokeDanglingOp(yoi::indexT funcIndex, yoi::indexT funcArgsCount, const std::shared_ptr< IRValueType > &returnType, bool externalInvocation=false, yoi::indexT moduleIndex=-1)
invoke a function with the given arguments, but the last param will be taken as the first param.
Definition IR.cpp:1530
void newDynamicArrayOp(const std::shared_ptr< IRValueType > &elementType, yoi::indexT initializerSize=0)
Definition IR.cpp:1282
void popFromTempVarStack()
Definition IR.cpp:488
void storeMemberOp(const yoi::IROperand &memberIndex)
Definition IR.cpp:375
void arithmeticOp(IR::Opcode op)
Definition IR.cpp:242
void dynCastOp(const std::shared_ptr< IRValueType > &type)
Definition IR.cpp:1247
std::shared_ptr< IRValueType > & getRhsFromTempVarStack()
Definition IR.cpp:164
void retOp(bool returnWithNone=false)
Definition IR.cpp:438
void setDebugInfo(const IRDebugInfo &debugInfo)
Definition IR.cpp:1202
void insert(const IR &ir)
Definition IR.cpp:506
Builder & addValue(const yoi::wstr &valueName, yoi::indexT valueIndex)
Definition IR.cpp:1573
std::shared_ptr< IREnumerationType > yield()
Definition IR.cpp:1607
Builder & setName(const yoi::wstr &name)
Definition IR.cpp:1568
yoi::indexT itemIndex
Definition IR.h:825
yoi::indexT affiliateModule
Definition IR.h:824
enum yoi::IRExternEntry::externType type
yoi::indexTable< yoi::wstr, Argument > templateArguments
Definition IR.h:537
IRTemplateBuilder & addTemplateArgument(const yoi::wstr &templateName, const std::shared_ptr< IRValueType > &templateType, const yoi::vec< externModuleAccessExpression * > &satisfyConditions={})
Definition IR.cpp:1010
Opcode
Definition IR.h:266
externModuleAccessExpression * rhs
Definition ast.hpp:446
primary * lhs
Definition ast.hpp:444
lexer::token op
Definition ast.hpp:445
vec< mulExpr * > & getTerms()
Definition ast.cpp:151
vec< lexer::token > & getOp()
Definition ast.cpp:155
vec< equalityExpr * > & getTerms()
Definition ast.cpp:199
vec< lexer::token > & getOp()
Definition ast.cpp:203
lexer::token node
Definition ast.hpp:253
yoi::vec< yoi::rExpr * > exprs
Definition ast.hpp:216
vec< inCodeBlockStmt * > & getStmts()
Definition ast.cpp:471
lexer::token name
Definition ast.hpp:1104
union yoi::conceptStmt::ConceptStmtValue value
enum yoi::conceptStmt::Kind kind
defTemplateArg * tempArgs
Definition ast.hpp:985
definitionArguments & getArgs()
Definition ast.cpp:983
codeBlock & getBlock()
Definition ast.cpp:991
definitionArguments & getArgs()
Definition ast.cpp:987
structDefInner & getInner()
Definition ast.cpp:339
identifier * id
Definition ast.hpp:715
rExpr * expr
Definition ast.hpp:621
vec< defTemplateArgSpec * > & get()
Definition ast.cpp:27
vec< defTemplateArgSpec * > spec
Definition ast.hpp:285
vec< identifierWithTypeSpec * > spec
Definition ast.hpp:313
vec< identifierWithTypeSpec * > & get()
Definition ast.cpp:43
vec< enumerationPair * > values
Definition ast.hpp:1088
vec< relationalExpr * > & getTerms()
Definition ast.cpp:187
vec< lexer::token > & getOp()
Definition ast.cpp:191
vec< andExpr * > & getTerms()
Definition ast.cpp:211
vec< lexer::token > & getOp()
Definition ast.cpp:215
typeSpec * from
Definition ast.hpp:1039
identifier * as
Definition ast.hpp:1040
yoi::vec< lexer::token > attrs
Definition ast.hpp:1038
vec< identifierWithTemplateArg * > & getTerms()
Definition ast.cpp:999
codeBlock * block
Definition ast.hpp:873
inCodeBlockStmt * afterStmt
Definition ast.hpp:872
inCodeBlockStmt * initStmt
Definition ast.hpp:870
rExpr * cond
Definition ast.hpp:871
codeBlock * block
Definition ast.hpp:630
typeSpec & getResultType()
Definition ast.cpp:279
codeBlock & getBlock()
Definition ast.cpp:283
identifierWithDefTemplateArg * id
Definition ast.hpp:627
definitionArguments & getArgs()
Definition ast.cpp:275
identifierWithDefTemplateArg & getId()
Definition ast.cpp:271
yoi::vec< lexer::token > attrs
Definition ast.hpp:626
externModuleAccessExpression * name
Definition ast.hpp:247
unnamedDefinitionArguments * args
Definition ast.hpp:248
union yoi::globalStmt::vValue value
enum yoi::globalStmt::vKind kind
marcoDescriptor * marco
Definition ast.hpp:809
defTemplateArg & getArg() const
Definition ast.cpp:83
identifier & getId() const
Definition ast.cpp:79
identifier & getId() const
Definition ast.cpp:67
bool hasTemplateArg() const
Definition ast.cpp:75
templateArg & getArg() const
Definition ast.cpp:71
lexer::token node
Definition ast.hpp:260
lexer::token & get()
Definition ast.cpp:12
vec< ifBlock > elifB
Definition ast.hpp:846
codeBlock * elseB
Definition ast.hpp:847
ifBlock & getIfBlock()
Definition ast.cpp:403
bool hasElseBlock() const
Definition ast.cpp:415
bool isFinalizer() const
Definition ast.cpp:1201
innerMethodDef & getMethod()
Definition ast.cpp:347
constructorDef & getConstructor()
Definition ast.cpp:343
bool isConstructor() const
Definition ast.cpp:351
vec< implInnerPair * > & getInner()
Definition ast.cpp:355
bool isImplForStmt()
Definition ast.cpp:367
implInner * inner
Definition ast.hpp:756
implInner & getInner()
Definition ast.cpp:371
externModuleAccessExpression & getStructId()
Definition ast.cpp:363
externModuleAccessExpression * structName
Definition ast.hpp:755
externModuleAccessExpression * interfaceName
Definition ast.hpp:754
lexer::token from_path
Definition ast.hpp:1046
innerMethodDecl * inner
Definition ast.hpp:1045
vKind & getKind()
Definition ast.cpp:463
marcoDescriptor * marco
Definition ast.hpp:928
vValue & getValue()
Definition ast.cpp:467
vec< lexer::token > & getOp()
Definition ast.cpp:227
vec< exclusiveExpr * > & getTerms()
Definition ast.cpp:223
yoi::indexT put_create(const A &a, const B &b)
Definition def.hpp:171
typeSpec & getResultType()
Definition ast.cpp:963
definitionArguments & getArgs()
Definition ast.cpp:959
typeSpec * resultType
Definition ast.hpp:957
yoi::vec< lexer::token > attrs
Definition ast.hpp:954
identifierWithDefTemplateArg * name
Definition ast.hpp:955
definitionArguments * args
Definition ast.hpp:956
identifierWithDefTemplateArg & getName()
Definition ast.cpp:955
typeSpec & getResultType()
Definition ast.cpp:975
identifierWithTemplateArg & getName()
Definition ast.cpp:967
codeBlock & getBlock()
Definition ast.cpp:979
definitionArguments & getArgs()
Definition ast.cpp:971
yoi::vec< lexer::token > attrs
Definition ast.hpp:968
vec< interfaceDefInnerPair * > & getInner()
Definition ast.cpp:299
identifierWithDefTemplateArg * id
Definition ast.hpp:665
interfaceDefInner & getInner()
Definition ast.cpp:307
vec< rExpr * > & get()
Definition ast.cpp:39
vec< rExpr * > arg
Definition ast.hpp:306
codeBlock * block
Definition ast.hpp:242
typeSpec * resultType
Definition ast.hpp:241
vec< yoi::identifier * > captures
Definition ast.hpp:239
definitionArguments * args
Definition ast.hpp:240
rExpr * rhs
Definition ast.hpp:471
uniqueExpr * lhs
Definition ast.hpp:470
lexer::token & getOp()
Definition ast.cpp:123
bool hasRhs() const
Definition ast.cpp:135
vec< letAssignmentPair * > terms
Definition ast.hpp:787
token scan()
Definition lexer.cpp:29
vec< lexer::token > & getOp()
Definition ast.cpp:239
vec< inclusiveExpr * > & getTerms()
Definition ast.cpp:235
vec< logicalAndExpr * > & getTerms()
Definition ast.cpp:247
vec< lexer::token > & getOp()
Definition ast.cpp:251
yoi::vec< marcoPair * > pairs
Definition ast.hpp:234
vec< subscriptExpr * > & getTerms()
Definition ast.cpp:95
yoi::IRBuilder & getIRBuilder()
void pushIRBuilder(const yoi::IRBuilder &builder)
yoi::hoshiModule & getModuleAST()
void pushTemplateBuilder(IRTemplateBuilder &builder)
std::vector< IRTemplateBuilder > & getTemplateBuilders()
std::shared_ptr< yoi::compilerContext > getCompilerContext()
vec< lexer::token > & getOp()
Definition ast.cpp:143
vec< leftExpr * > & getTerms()
Definition ast.cpp:139
subscript * length
Definition ast.hpp:405
invocationArguments * args
Definition ast.hpp:406
externModuleAccessExpression * type
Definition ast.hpp:404
lambdaExpr * lambda
Definition ast.hpp:430
enum yoi::primary::primaryKind kind
funcExpr * func
Definition ast.hpp:431
memberExpr * member
Definition ast.hpp:424
rExpr * expr
Definition ast.hpp:426
basicLiterals * literals
Definition ast.hpp:425
newExpression * newExpr
Definition ast.hpp:429
bracedInitalizerList * bracedInitalizer
Definition ast.hpp:432
typeIdExpression * typeId
Definition ast.hpp:427
dynCastExpression * dynCast
Definition ast.hpp:428
logicalOrExpr & getExpr() const
Definition ast.cpp:259
vec< shiftExpr * > & getTerms()
Definition ast.cpp:175
vec< lexer::token > & getOp()
Definition ast.cpp:179
rExpr * value
Definition ast.hpp:899
bool hasValue() const
Definition ast.cpp:459
externModuleAccessExpression * emae
Definition ast.hpp:1129
vec< lexer::token > & getOp()
Definition ast.cpp:167
vec< addExpr * > & getTerms()
Definition ast.cpp:163
innerMethodDecl & getMethod()
Definition ast.cpp:319
constructorDecl & getConstructor()
Definition ast.cpp:315
vec< structDefInnerPair * > & getInner()
Definition ast.cpp:323
identifierWithDefTemplateArg * id
Definition ast.hpp:705
identifierWithDefTemplateArg & getId()
Definition ast.cpp:327
structDefInner & getInner()
Definition ast.cpp:331
vec< subscript * > & getSubscript()
Definition ast.cpp:1079
identifierWithTemplateArg * id
Definition ast.hpp:387
rExpr * expr
Definition ast.hpp:351
vec< templateArgSpec * > spec
Definition ast.hpp:299
vec< templateArgSpec * > & get()
Definition ast.cpp:35
yoi::identifierWithDefTemplateArg * lhs
Definition ast.hpp:221
yoi::typeSpec * rhs
Definition ast.hpp:222
typeSpec * type
Definition ast.hpp:1070
decltypeExpr * decltypeExpression
Definition ast.hpp:340
yoi::vec< uint64_t > * arraySubscript
Definition ast.hpp:342
externModuleAccessExpression * member
Definition ast.hpp:337
funcTypeSpec * func
Definition ast.hpp:338
enum yoi::typeSpec::typeSpecKind kind
lexer::token & getOp()
Definition ast.cpp:111
abstractExpr * lhs
Definition ast.hpp:458
vec< typeSpec * > types
Definition ast.hpp:1082
identifier * name
Definition ast.hpp:611
lexer::token path
Definition ast.hpp:612
std::shared_ptr< yoi::IRModule > visit()
Definition visitor.cpp:33
visitor(const std::shared_ptr< yoi::moduleContext > &moduleContext, const std::shared_ptr< yoi::IRModule > &irModule, yoi::indexT moduleIndex)
Definition visitor.cpp:28
std::shared_ptr< yoi::IRModule > irModule
Definition visitor.h:42
codeBlock * block
Definition ast.hpp:861
rExpr * cond
Definition ast.hpp:860
rExpr * expr
Definition ast.hpp:1099
std::string wstring2string(const std::wstring &v)
Definition def.cpp:184
std::shared_ptr< T > managedPtr(const T &v)
Definition def.hpp:324
wstr::value_type wchar
Definition def.hpp:49
std::vector< t > vec
Definition def.hpp:53
yoi::wstr realpath(const std::wstring &path)
Definition def.cpp:190
thread_local yoi::wstr __current_file_path
Definition def.cpp:14
void yoi_assert(bool condition, yoi::indexT line, yoi::indexT col, const std::string &msg)
Asserts a condition that would be true and throws a runtime_error if it is false.
Definition def.cpp:171
void set_current_file_path(const std::wstring &path)
Definition def.cpp:113
std::wstring wstr
Definition def.hpp:48
uint64_t indexT
Definition def.hpp:51
void panic(yoi::indexT line, yoi::indexT col, const std::string &msg)
Definition def.cpp:131
std::string replace_all(std::string str, const std::string &from, const std::string &to)
Definition string.cpp:36
Builder & setName(const yoi::wstr &name)
Definition IR.cpp:1642
yoi::indexT column
Definition IR.h:81
yoi::indexT line
Definition IR.h:80
Builder & setDebugInfo(const IRDebugInfo &debugInfo)
Definition IR.cpp:1211
yoi::vec< std::pair< yoi::wstr, std::shared_ptr< IRValueType > > > argumentTypes
Definition IR.h:504
std::shared_ptr< IRFunctionDefinition > yield()
Definition IR.cpp:601
Builder & setName(const yoi::wstr &name)
Definition IR.cpp:541
Builder & addArgument(const yoi::wstr &argumentName, const std::shared_ptr< IRValueType > &argumentType)
Definition IR.cpp:590
Builder & setReturnType(const std::shared_ptr< IRValueType > &returnType)
Definition IR.cpp:596
Builder & addAttr(FunctionAttrs attr)
Definition IR.cpp:1271
std::set< FunctionAttrs > attrs
Definition IR.h:506
std::shared_ptr< IRInterfaceImplementationDefinition > yield()
Definition IR.cpp:570
Builder & setImplStructIndex(std::tuple< IRValueType::valueType, yoi::indexT, yoi::indexT > implStructIndex)
Definition IR.cpp:552
Builder & setImplInterfaceIndex(const std::pair< yoi::indexT, yoi::indexT > &implInterfaceIndex)
Definition IR.cpp:558
Builder & addVirtualMethod(const yoi::wstr &methodName, const std::shared_ptr< IRValueType > &methodType)
Definition IR.cpp:564
Builder & setName(const yoi::wstr &name)
Definition IR.cpp:546
std::shared_ptr< IRInterfaceInstanceDefinition > yield()
Definition IR.cpp:586
Builder & setName(const yoi::wstr &name)
Definition IR.cpp:575
Builder & addMethod(const yoi::wstr &methodNameOri, const yoi::wstr &methodName, const std::shared_ptr< IRFunctionDefinition > &methodSignature)
Definition IR.cpp:580
std::shared_ptr< IRStructDefinition > yield()
Definition IR.cpp:821
Builder & setStoredTemplateArgs(const yoi::vec< yoi::wstr > &paramNames, const yoi::vec< std::shared_ptr< IRValueType > > &args)
Definition IR.cpp:804
Builder & addMethod(const yoi::wstr &methodName, yoi::indexT index)
Definition IR.cpp:799
Builder & addTemplateMethodDef(const yoi::wstr &name, yoi::implInnerPair *def)
Definition IR.cpp:816
Builder & addField(const yoi::wstr &fieldName, const std::shared_ptr< IRValueType > &fieldType)
Definition IR.cpp:793
Builder & addTemplateMethodDecl(const yoi::wstr &name, yoi::structDefInnerPair *decl)
Definition IR.cpp:811
Builder & setName(const yoi::wstr &name)
Definition IR.cpp:788
codeBlock * block
Definition ast.hpp:838
uint64_t col
Definition lexer.hpp:26
enum yoi::lexer::token::tokenKind kind
uint64_t line
Definition lexer.hpp:26
union yoi::lexer::token::vBasicValue basicVal
std::shared_ptr< IRValueType > variadicElementType
Definition visitor.h:28
std::shared_ptr< IRFunctionDefinition > function
Definition visitor.h:29
dataStructDefStmt * dataStructDefStmtVal
Definition ast.hpp:815
enumerationDefinition * enumerationDefVal
Definition ast.hpp:822
useStmt * useStmtVal
Definition ast.hpp:812
implStmt * implStmtVal
Definition ast.hpp:816
interfaceDefStmt * interfaceDefStmtVal
Definition ast.hpp:813
letStmt * letStmtVal
Definition ast.hpp:817
conceptDefinition * conceptDefVal
Definition ast.hpp:823
funcDefStmt * funcDefStmtVal
Definition ast.hpp:818
typeAliasStmt * typeAliasStmtVal
Definition ast.hpp:821
exportDecl * exportDeclVal
Definition ast.hpp:820
structDefStmt * structDefStmtVal
Definition ast.hpp:814
importDecl * importDeclVal
Definition ast.hpp:819
forEachStmt * forEachStmtVal
Definition ast.hpp:933
returnStmt * returnStmtVal
Definition ast.hpp:934
continueStmt * continueStmtVal
Definition ast.hpp:935