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 if (i->modifier == structDefInnerPair::Modifier::Weak) {
2092 memberType->addAttribute(IRValueType::ValueAttr::WeakRef);
2093 }
2094 builder.addField(memberName, memberType);
2095 break;
2096 }
2097 case 1: {
2098 bool isVaridic = false;
2099 IRFunctionDefinition::Builder constructorBuilder;
2100
2101 constructorBuilder.setDebugInfo({irModule->modulePath, i->getLine(), i->getColumn()});
2102 constructorBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Constructor);
2103
2105 auto thisType = managedPtr(IRValueType{IRValueType::valueType::structObject, currentModuleIndex, structIndex});
2106 constructorBuilder.setReturnType(thisType);
2107 constructorBuilder.addArgument(L"this", thisType);
2108 constructorBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Constructor);
2109 for (auto &arg : i->getConstructor().getArgs().get()) {
2110 if (&arg == &i->getConstructor().getArgs().get().back() && arg->spec->kind == typeSpec::typeSpecKind::Elipsis) {
2111 isVaridic = true;
2112 constructorBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Variadic);
2113 auto argName = arg->getId().node.strVal;
2114 auto argType = managedPtr(arg->spec->elipsis
2115 ? parseTypeSpec(arg->spec->elipsis).getDynamicArrayType()
2116 : moduleContext->getCompilerContext()->getNullInterfaceType()->getDynamicArrayType());
2117 constructorBuilder.addArgument(argName, argType);
2118 argTypes.push_back(argType);
2119 break;
2120 }
2121 auto argName = arg->getId().get().strVal;
2122 auto argType = managedPtr(parseTypeSpec(arg->spec));
2123 constructorBuilder.addArgument(argName, argType);
2124 argTypes.push_back(argType);
2125 }
2126 auto uniq = getFuncUniqueNameStr(argTypes);
2127 auto mangledName = L"constructor" + uniq;
2128 constructorBuilder.setName(structName + L"::" + mangledName);
2129
2130 auto func = constructorBuilder.yield();
2131 auto funcIndex = irModule->functionTable.put_create(func->name, func);
2132 builder.addMethod(mangledName, funcIndex);
2133 irModule->functionOverloadIndexies[structName + L"::constructor"].push_back(funcIndex);
2134 break;
2135 }
2136 case 2: {
2137 bool isVaridic = false;
2138 auto methodName = i->getMethod().getName().getId().get().strVal;
2139
2140 if (i->getMethod().getName().hasDefTemplateArg()) {
2141 // template method declaration
2142 builder.addTemplateMethodDecl(methodName, i);
2143 break;
2144 }
2145
2146 auto methodType = managedPtr(parseTypeSpec(i->getMethod().resultType));
2147 IRFunctionDefinition::Builder methodBuilder;
2148
2149 methodBuilder.attrs = getFunctionAttributes(i->getMethod().attrs);
2150 methodBuilder.setDebugInfo({irModule->modulePath, i->getLine(), i->getColumn()});
2151
2153
2154 methodBuilder.setReturnType(methodType);
2155 auto thisType = managedPtr(IRValueType{IRValueType::valueType::structObject, currentModuleIndex, structIndex});
2156
2157 if (std::find(methodBuilder.attrs.begin(), methodBuilder.attrs.end(), IRFunctionDefinition::FunctionAttrs::Static) ==
2158 methodBuilder.attrs.end())
2159 methodBuilder.addArgument(L"this", thisType);
2160
2161 for (auto &arg : i->getMethod().getArgs().get()) {
2162 if (&arg == &i->getMethod().getArgs().get().back() && arg->spec->kind == typeSpec::typeSpecKind::Elipsis) {
2163 isVaridic = true;
2164 methodBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Variadic);
2165 auto argName = arg->getId().node.strVal;
2166 auto argType = managedPtr(arg->spec->elipsis
2167 ? parseTypeSpec(arg->spec->elipsis).getDynamicArrayType()
2168 : moduleContext->getCompilerContext()->getNullInterfaceType()->getDynamicArrayType());
2169 methodBuilder.addArgument(argName, argType);
2170 argTypes.push_back(argType);
2171 break;
2172 }
2173 auto argName = arg->getId().get().strVal;
2174 auto argType = managedPtr(parseTypeSpec(arg->spec));
2175 methodBuilder.addArgument(argName, argType);
2176 argTypes.push_back(argType);
2177 }
2178
2179 auto uniq = getFuncUniqueNameStr(argTypes);
2180 auto mangledName = methodName + uniq;
2181 methodBuilder.setName(structName + L"::" + mangledName);
2182 auto func = methodBuilder.yield();
2183 auto funcIndex = irModule->functionTable.put_create(func->name, func);
2184 builder.addMethod(mangledName, funcIndex);
2185 irModule->functionOverloadIndexies[structName + L"::" + methodName].push_back(funcIndex);
2186 break;
2187 }
2188 case 3: {
2189 // finalizer
2190 IRFunctionDefinition::Builder finalizerBuilder;
2191 finalizerBuilder.setName(structName + L"::finalizer");
2192 finalizerBuilder.setDebugInfo({irModule->modulePath, i->getLine(), i->getColumn()});
2193 finalizerBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Finalizer);
2194 finalizerBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Preserve);
2195 auto thisType = managedPtr(IRValueType{IRValueType::valueType::structObject, currentModuleIndex, structIndex});
2196 finalizerBuilder.setReturnType(moduleContext->getCompilerContext()->getNoneObjectType());
2197 finalizerBuilder.addArgument(L"this", thisType);
2198 auto func = finalizerBuilder.yield();
2199 auto funcIndex = irModule->functionTable.put_create(structName + L"::finalizer", func);
2200 builder.addMethod(L"finalizer", funcIndex);
2201 // no need to prepare for manual calling, it is not legal.
2202 break;
2203 }
2204 }
2205 }
2206 auto structType = builder.yield();
2207 irModule->structTable[structIndex] = structType;
2208 }
2210 }
2211
2213 auto &structIdNode = implStmt->getStructId();
2214
2215 auto it = structIdNode.getTerms().begin();
2216 yoi::indexT targetModule = -1, lastModule = -1;
2217 while (it + 1 != structIdNode.getTerms().end() && (targetModule = isModuleName(*it, targetModule)) != lastModule) {
2218 it++;
2219 lastModule = targetModule;
2220 }
2221 if (targetModule == -1) {
2222 targetModule = currentModuleIndex;
2223 }
2224 yoi_assert(it + 1 == structIdNode.getTerms().end(), structIdNode.getLine(), structIdNode.getColumn(), "Invalid interface name");
2225
2226 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(targetModule);
2227 auto structBaseName = (*it)->getId().get().strVal;
2228
2229 if ((*it)->hasTemplateArg()) {
2230 // Impl for a template struct
2231 yoi_assert(targetedModule->structTemplateAsts.contains(structBaseName),
2232 implStmt->getLine(),
2234 "Impl for undefined struct template: " + wstring2string(structBaseName));
2235
2236 yoi::vec<std::shared_ptr<IRValueType>> concreteTemplateArgs = parseTemplateArgs((*it)->getArg());
2237
2238 if (implStmt->isImplForStmt()) {
2239 // interface implementation for a template struct
2240 if (concreteTemplateArgs.empty()) {
2241 targetedModule->templateInterfaceImplAsts[structBaseName].push_back(implStmt);
2242 } else {
2243 // specialize template interface
2244 auto interfaceTemplateAst = targetedModule->templateInterfaceAsts[structBaseName];
2245 auto concreteStructName = getMangledTemplateName(structBaseName, concreteTemplateArgs);
2246 auto concreteStructType = managedPtr(parseTypeSpec(implStmt->structName)); // quick specialization check
2247 yoi_assert(concreteStructType->type == IRValueType::valueType::structObject,
2248 implStmt->getLine(),
2250 "Invalid struct name for struct specialization: " + wstring2string(concreteStructName) +
2251 " (except structObject but got " + wstring2string(concreteStructType->to_string()) + ")");
2252 // FIXED: module index
2253 specializeInterfaceImplementation(implStmt, concreteStructType, concreteStructName, concreteTemplateArgs, targetModule);
2254 }
2255 } else {
2256 if (concreteTemplateArgs.empty()) {
2257 // pure template struct, store them and specialize when used
2258 targetedModule->templateImplAsts[structBaseName] = implStmt;
2259 } else {
2260 // specialize template struct
2261 auto structTemplateAst = targetedModule->structTemplateAsts[structBaseName];
2262 specializeStructTemplate(structBaseName, concreteTemplateArgs, implStmt, targetModule);
2263 }
2264 }
2265
2267 }
2268
2269 if (implStmt->isImplForStmt()) {
2270 auto interfaceName = parseInterfaceName(implStmt->interfaceName);
2271 std::shared_ptr<IRValueType> srcType;
2272 try {
2273 srcType = managedPtr(parseTypeSpec(implStmt->structName));
2274 targetModule = srcType->typeAffiliateModule;
2275 targetedModule = moduleContext->getCompilerContext()->getImportedModule(targetModule);
2276 } catch (std::runtime_error &e) {
2277 panic(implStmt->getLine(), implStmt->getColumn(), "Undefined struct: " + wstring2string(structBaseName));
2278 return {};
2279 }
2280 auto targetInterface =
2281 moduleContext->getCompilerContext()->getImportedModule(interfaceName.first.first)->interfaceTable[interfaceName.first.second];
2282 targetInterface->implementations.emplace_back(srcType->type, srcType->typeAffiliateModule, srcType->typeIndex);
2283 auto interfaceImplName = getInterfaceImplName(interfaceName.first, srcType);
2284
2285 yoi::indexT interfaceImplIndex{};
2286 try {
2287 interfaceImplIndex = targetedModule->interfaceImplementationTable.getIndex(interfaceImplName);
2288 if (targetedModule->interfaceImplementationTable[interfaceImplIndex]) {
2289 panic(
2290 implStmt->getLine(), implStmt->getColumn(), "Redefinition of interface implementation: " + wstring2string(interfaceImplName));
2291 }
2292 } catch (std::out_of_range &e) {
2293 interfaceImplIndex = targetedModule->interfaceImplementationTable.put(interfaceImplName, {});
2294 }
2295 if (implStmt->inner) {
2297 builder.setName(interfaceImplName);
2298 builder.setImplStructIndex({srcType->type, srcType->typeAffiliateModule, srcType->typeIndex});
2299 builder.setImplInterfaceIndex(interfaceName.first);
2300
2301 std::map<yoi::wstr, std::pair<yoi::wstr, std::shared_ptr<IRValueType>>> virtualMethodMap;
2302
2303 for (auto &i : implStmt->getInner().getInner()) {
2304 yoi_assert(i->isMethod(),
2305 i->getLine(),
2306 i->getColumn(),
2307 "impl-for statement only allows method definition, not constructor or finalizer");
2308
2309 bool isVaridic = false;
2310
2311 auto methodName = i->getMethod().getName().getId().get().strVal;
2312 IRFunctionDefinition::Builder methodBuilder;
2313
2314 methodBuilder.setDebugInfo({irModule->modulePath, i->getLine(), i->getColumn()});
2315 methodBuilder.attrs = getFunctionAttributes(i->getMethod().attrs);
2316 methodBuilder.attrs.insert(IRFunctionDefinition::FunctionAttrs::Preserve);
2317
2319
2320 const auto &thisType = srcType;
2321 if (std::find(methodBuilder.attrs.begin(), methodBuilder.attrs.end(), IRFunctionDefinition::FunctionAttrs::Static) ==
2322 methodBuilder.attrs.end())
2323 methodBuilder.addArgument(L"this", thisType);
2324
2325 for (auto &arg : i->getMethod().getArgs().get()) {
2326 if (&arg == &i->getMethod().getArgs().get().back() && arg->spec->kind == typeSpec::typeSpecKind::Elipsis) {
2327 isVaridic = true;
2328 methodBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Variadic);
2329 auto argName = arg->getId().node.strVal;
2330 auto argType =
2331 managedPtr(arg->spec->elipsis ? parseTypeSpec(arg->spec->elipsis).getDynamicArrayType()
2332 : moduleContext->getCompilerContext()->getNullInterfaceType()->getDynamicArrayType());
2333 methodBuilder.addArgument(argName, argType);
2334 argTypes.push_back(argType);
2335 break;
2336 }
2337 auto argName = arg->getId().get().strVal;
2338 auto argType = managedPtr(parseTypeSpec(arg->spec));
2339 methodBuilder.addArgument(argName, argType);
2340 argTypes.push_back(argType);
2341 }
2342 auto uniq = getFuncUniqueNameStr(argTypes);
2343 methodBuilder.setReturnType(managedPtr(parseTypeSpec(i->getMethod().resultType)));
2344 methodBuilder.setName(structBaseName + L"::" + methodName + uniq + L"interfaceImpl#" + interfaceImplName);
2345
2346 auto func = methodBuilder.yield();
2347 auto funcIndex = targetedModule->functionTable.put_create(func->name, func);
2348 targetedModule->functionOverloadIndexies[structBaseName + L"::" + methodName + L"interfaceImpl#" + interfaceImplName].push_back(
2349 funcIndex);
2350 /*builder.addVirtualMethod(
2351 methodName + uniq,
2352 managedPtr(IRValueType{IRValueType::valueType::virtualMethod, targetModule, funcIndex}));*/
2353 virtualMethodMap[methodName + getFuncUniqueNameStr(argTypes, true)] = {
2354 methodName + uniq, managedPtr(IRValueType{IRValueType::valueType::virtualMethod, targetModule, funcIndex})};
2355
2357 moduleContext->getIRBuilder().setDebugInfo({irModule->modulePath, i->getLine(), i->getColumn()});
2359 visit(i->getMethod().block, true);
2362 }
2363
2364 for (auto &method : targetInterface->methodMap) {
2365 yoi_assert(virtualMethodMap.contains(method.first),
2366 implStmt->getLine(),
2368 "Method '" + wstring2string(method.first) + "' not implemented for interface '" +
2369 wstring2string(targetInterface->name) + "'");
2370 builder.addVirtualMethod(virtualMethodMap[method.first].first, virtualMethodMap[method.first].second);
2371 }
2372
2373 targetedModule->interfaceImplementationTable[interfaceImplIndex] = builder.yield();
2374 } else {
2375 // forward-declaration
2376 }
2377 } else {
2378 indexT structIndex;
2379 try {
2380 structIndex = targetedModule->structTable.getIndex(structBaseName);
2381 } catch (std::runtime_error &e) {
2382 panic(implStmt->getLine(), implStmt->getColumn(), "Undefined struct: " + wstring2string(structBaseName));
2383 }
2384
2385 for (auto &i : implStmt->getInner().getInner()) {
2386 yoi::wstr mangledName;
2387 yoi::codeBlock *block{};
2388 if (i->isConstructor()) {
2389 bool isVaridic = false;
2391 for (auto &arg : i->getConstructor().getArgs().get()) {
2392 if (&arg == &i->getConstructor().getArgs().get().back() && arg->spec->kind == typeSpec::typeSpecKind::Elipsis) {
2393 isVaridic = true;
2394 auto argType = managedPtr(moduleContext->getCompilerContext()->getNullInterfaceType()->getDynamicArrayType());
2395 argTypes.push_back(argType);
2396 break;
2397 }
2398 argTypes.push_back(managedPtr(parseTypeSpec(arg->spec)));
2399 }
2400 mangledName = structBaseName + L"::constructor" + getFuncUniqueNameStr(argTypes);
2401 block = i->getConstructor().block;
2402 } else if (i->isFinalizer()) {
2403 mangledName = structBaseName + L"::finalizer";
2404 block = i->getFinalizer().block;
2405 } else {
2406 if (i->getMethod().getName().hasTemplateArg()) {
2407 // template method definition for a non-template struct
2408 auto structDef = targetedModule->structTable[structIndex];
2409 structDef->templateMethodDefs[i->getMethod().getName().getId().get().strVal] = i;
2410 continue;
2411 }
2412 // whole bunch of shit doin' here is to get the mangled name of the method, no actual modification of original func def here.
2413 bool isVaridic = false;
2415 for (auto &arg : i->getMethod().getArgs().get()) {
2416 if (&arg == &i->getMethod().getArgs().get().back() && arg->spec->kind == typeSpec::typeSpecKind::Elipsis) {
2417 isVaridic = true;
2418 auto type =
2419 arg->spec->elipsis ? parseTypeSpec(arg->spec->elipsis) : *moduleContext->getCompilerContext()->getNullInterfaceType();
2420 auto argType = managedPtr(type.getDynamicArrayType());
2421 argTypes.push_back(argType);
2422 break;
2423 }
2424 argTypes.push_back(managedPtr(parseTypeSpec(arg->spec)));
2425 }
2426 mangledName = structBaseName + L"::" + i->getMethod().getName().getId().get().strVal + getFuncUniqueNameStr(argTypes);
2427 block = i->getMethod().block;
2428 }
2429
2430 try {
2431 auto funcIndex = targetedModule->functionTable.getIndex(mangledName);
2432 auto func = targetedModule->functionTable[funcIndex];
2434 moduleContext->getIRBuilder().setDebugInfo({irModule->modulePath, i->getLine(), i->getColumn()});
2436 visit(block, true);
2439 } catch (std::out_of_range &e) {
2440 panic(
2441 i->getLine(), i->getColumn(), "No matched constructor or method declaration found for impl: " + wstring2string(mangledName));
2442 }
2443 }
2444 }
2446 }
2447
2449 for (auto &i : letStmt->terms) {
2450 visit(i->rhs);
2451 auto type = i->type ? managedPtr(parseTypeSpec(i->type)) : moduleContext->getIRBuilder().getRhsFromTempVarStack();
2452 if (i->lhs->kind == letAssignmentPairLHS::vKind::identifier) {
2453 if (isVisitingGlobalScope()) {
2454 // global variable
2455 tryCastTo(type);
2456 auto index = irModule->globalVariables.put(i->lhs->id->node.strVal, type);
2457 moduleContext->getIRBuilder().storeOp(IR::Opcode::store_global, {IROperand::operandType::globalVar, index});
2458
2459 } else {
2460 tryCastTo(type);
2461 auto index = moduleContext->getIRBuilder().irFuncDefinition()->getVariableTable().put(i->lhs->id->node.strVal, type);
2462 moduleContext->getIRBuilder().storeOp(IR::Opcode::store_local, {IROperand::operandType::localVar, index});
2463 }
2464 } else if (i->lhs->kind == letAssignmentPairLHS::vKind::list) {
2465 // structured binding
2466 if (type->isArrayType() || type->isDynamicArrayType()) {
2467 // array binding
2468 IRBuilder::ExtractType extractType{i->lhs->list.back().kind == lexer::token::tokenKind::kThreeDots
2469 ? IRBuilder::ExtractType::First
2470 : IRBuilder::ExtractType::Last};
2471 bool isFull = i->lhs->list.back().kind != lexer::token::tokenKind::kThreeDots &&
2472 i->lhs->list.front().kind != lexer::token::tokenKind::kThreeDots;
2473 auto elementCount = i->lhs->list.size() - !isFull;
2474 moduleContext->getIRBuilder().bindElementsOp(elementCount, extractType);
2475 auto bindType = managedPtr(type->getElementType());
2476 for (yoi::indexT curPos = extractType == IRBuilder::ExtractType::First && !isFull; curPos < elementCount; curPos++) {
2477 if (isVisitingGlobalScope()) {
2478 // global variable
2479 auto index = irModule->globalVariables.put(i->lhs->list[i->lhs->list.size() - 1 - curPos].strVal, bindType);
2480 moduleContext->getIRBuilder().storeOp(IR::Opcode::store_global, {IROperand::operandType::globalVar, index});
2481
2482 } else {
2483 auto index = moduleContext->getIRBuilder().irFuncDefinition()->getVariableTable().put(
2484 i->lhs->list[i->lhs->list.size() - 1 - curPos].strVal, bindType);
2485 moduleContext->getIRBuilder().storeOp(IR::Opcode::store_local, {IROperand::operandType::localVar, index});
2486 }
2487 }
2488 } else if (type->type == IRValueType::valueType::structObject) {
2489 // struct binding
2490 IRBuilder::ExtractType extractType{i->lhs->list.back().kind == lexer::token::tokenKind::kThreeDots
2491 ? IRBuilder::ExtractType::First
2492 : IRBuilder::ExtractType::Last};
2493 bool isFull = i->lhs->list.back().kind != lexer::token::tokenKind::kThreeDots &&
2494 i->lhs->list.front().kind != lexer::token::tokenKind::kThreeDots;
2495 yoi::indexT elementCount = i->lhs->list.size() - !isFull;
2496 yoi::indexT startPos = extractType == IRBuilder::ExtractType::First ? elementCount - 1 : i->lhs->list.size() - 1;
2497 yoi::indexT endPos = extractType == IRBuilder::ExtractType::First ? -1 : 0 - isFull;
2498 moduleContext->getIRBuilder().bindFieldsOp(elementCount, extractType);
2499 for (yoi::indexT curPos = startPos; curPos != endPos; curPos -= 1) {
2501 if (isVisitingGlobalScope()) {
2502 // global variable
2503 auto index = irModule->globalVariables.put(i->lhs->list[curPos].strVal, fieldType);
2504 tryCastTo(fieldType);
2505 moduleContext->getIRBuilder().storeOp(IR::Opcode::store_global, {IROperand::operandType::globalVar, index});
2506
2507 } else {
2508 auto index =
2509 moduleContext->getIRBuilder().irFuncDefinition()->getVariableTable().put(i->lhs->list[curPos].strVal, fieldType);
2510 tryCastTo(fieldType);
2511 moduleContext->getIRBuilder().storeOp(IR::Opcode::store_local, {IROperand::operandType::localVar, index});
2512 }
2513 }
2514 } else {
2515 panic(i->getLine(), i->getColumn(), "Unsupported structured binding");
2516 }
2517 }
2518 }
2520 }
2521
2522 void visitor::visit(yoi::globalStmt *globalStmt) {
2523 if (!checkMarcoSatisfaction(globalStmt->marco))
2524 return;
2525 switch (globalStmt->kind) {
2526 case globalStmt::vKind::useStmt: {
2527 visit(globalStmt->value.useStmtVal);
2528 break;
2529 }
2530 case globalStmt::vKind::implStmt: {
2532 break;
2533 }
2534 case globalStmt::vKind::letStmt: {
2535 visit(globalStmt->value.letStmtVal);
2536 break;
2537 }
2538 case globalStmt::vKind::funcDefStmt: {
2540 break;
2541 }
2542 case globalStmt::vKind::structDefStmt: {
2544 break;
2545 }
2546 case globalStmt::vKind::interfaceDefStmt: {
2548 break;
2549 }
2550 case globalStmt::vKind::importDecl: {
2552 break;
2553 }
2554 case globalStmt::vKind::exportDecl: {
2556 break;
2557 }
2558 case globalStmt::vKind::typeAliasStmt: {
2560 break;
2561 }
2562 case globalStmt::vKind::enumerationDef: {
2564 break;
2565 }
2566 case globalStmt::vKind::dataStructDefStmt: {
2568 break;
2569 }
2570 case globalStmt::vKind::conceptDef: {
2572 break;
2573 }
2574 default: {
2575 panic(globalStmt->getLine(), globalStmt->getColumn(), "Unsupported global statement type");
2576 }
2577 }
2578 }
2579
2580 yoi::indexT visitor::visit(yoi::ifStmt *ifStmt) {
2581 visit(ifStmt->getIfBlock().cond);
2583 yoi_assert(condType->type == IRValueType::valueType::booleanObject,
2584 ifStmt->getLine(),
2585 ifStmt->getColumn(),
2586 "The type in if-condition must be boolean");
2587
2588 auto ifBlock = moduleContext->getIRBuilder().createCodeBlock();
2589 auto outBlock = moduleContext->getIRBuilder().createCodeBlock();
2590
2591 moduleContext->getIRBuilder().jumpIfOp(IR::Opcode::jump_if_true, ifBlock);
2592 auto back = moduleContext->getIRBuilder().switchCodeBlock(ifBlock);
2593 visit(ifStmt->getIfBlock().block, true);
2594 moduleContext->getIRBuilder().jumpOp(outBlock);
2596
2597 for (auto &i : ifStmt->elifB) {
2598 visit(i.cond);
2599 auto elifCondType = moduleContext->getIRBuilder().getRhsFromTempVarStack();
2600 yoi_assert(elifCondType->type == IRValueType::valueType::booleanObject,
2601 i.cond->getLine(),
2602 i.cond->getColumn(),
2603 "The type in elif-condition must be boolean");
2604
2605 auto elifBlock = moduleContext->getIRBuilder().createCodeBlock();
2606 moduleContext->getIRBuilder().jumpIfOp(IR::Opcode::jump_if_true, elifBlock);
2607 auto back = moduleContext->getIRBuilder().switchCodeBlock(elifBlock);
2608 visit(i.block, true);
2609 moduleContext->getIRBuilder().jumpOp(outBlock);
2611 }
2612
2613 if (ifStmt->hasElseBlock()) {
2614 auto elseBlock = moduleContext->getIRBuilder().createCodeBlock();
2615 moduleContext->getIRBuilder().jumpOp(elseBlock);
2616 auto back = moduleContext->getIRBuilder().switchCodeBlock(elseBlock);
2617 visit(ifStmt->elseB, true);
2618 moduleContext->getIRBuilder().jumpOp(outBlock);
2620 } else {
2621 moduleContext->getIRBuilder().jumpOp(outBlock);
2622 }
2625 }
2626
2628 auto condBlock = moduleContext->getIRBuilder().createCodeBlock();
2629 moduleContext->getIRBuilder().jumpOp(condBlock);
2630 auto back = moduleContext->getIRBuilder().switchCodeBlock(condBlock);
2631
2632 visit(whileStmt->cond);
2634 yoi_assert(condType->type == IRValueType::valueType::booleanObject,
2635 whileStmt->getLine(),
2637 "The type in while-condition must be boolean");
2638
2639 auto whileBlock = moduleContext->getIRBuilder().createCodeBlock();
2640 auto outBlock = moduleContext->getIRBuilder().createCodeBlock();
2641
2642 moduleContext->getIRBuilder().jumpIfOp(IR::Opcode::jump_if_true, whileBlock);
2643 moduleContext->getIRBuilder().jumpOp(outBlock);
2645 moduleContext->getIRBuilder().pushLoopContext(outBlock, condBlock);
2646 visit(whileStmt->block, true);
2648
2649 moduleContext->getIRBuilder().jumpOp(condBlock);
2651
2653 }
2654
2656 moduleContext->getIRBuilder().irFuncDefinition()->getVariableTable().createScope();
2657 auto initBlock = moduleContext->getIRBuilder().createCodeBlock();
2658 auto condBlock = moduleContext->getIRBuilder().createCodeBlock();
2660 auto afterBlock = moduleContext->getIRBuilder().createCodeBlock();
2661 auto outBlock = moduleContext->getIRBuilder().createCodeBlock();
2662
2663 moduleContext->getIRBuilder().jumpOp(initBlock);
2664
2666 visit(forStmt->initStmt);
2667
2668 moduleContext->getIRBuilder().jumpOp(condBlock);
2670 visit(forStmt->cond);
2672 yoi_assert(condType->type == IRValueType::valueType::booleanObject,
2673 forStmt->getLine(),
2674 forStmt->getColumn(),
2675 "The type in for-condition must be boolean");
2676
2677 moduleContext->getIRBuilder().jumpIfOp(IR::Opcode::jump_if_true, codeBlock);
2678 moduleContext->getIRBuilder().jumpOp(outBlock);
2680 moduleContext->getIRBuilder().pushLoopContext(outBlock, afterBlock);
2681 visit(forStmt->block, true);
2683
2684 moduleContext->getIRBuilder().jumpOp(afterBlock);
2686 visit(forStmt->afterStmt);
2687
2688 moduleContext->getIRBuilder().jumpOp(condBlock);
2690
2691 moduleContext->getIRBuilder().irFuncDefinition()->getVariableTable().popScope();
2692
2694 }
2695
2696 void visitor::visit(yoi::forEachStmt *forEachStmt) {
2697 // TODO: implement foreach statement
2698 panic(forEachStmt->getLine(), forEachStmt->getColumn(), "forEach statement is not implemented yet");
2699 }
2700
2702 if (returnStmt->hasValue()) {
2703 yoi_assert(!moduleContext->getIRBuilder().irFuncDefinition()->hasAttribute(IRFunctionDefinition::FunctionAttrs::Generator),
2706 "Generator function cannot return a value");
2707 visit(returnStmt->value);
2708 // validate type
2709 auto returnType = moduleContext->getIRBuilder().irFuncDefinition()->returnType;
2710 tryCastTo(returnType);
2712 } else {
2713 // TODO: return void
2715 }
2717 }
2718
2723
2728
2731 auto baseName = identifierWithTemplateArg->getId().node.strVal;
2732 auto concreteTypes = parseTemplateArgs(identifierWithTemplateArg->getArg());
2733
2734 if (irModule->structTemplateAsts.contains(baseName)) {
2735 try {
2736 auto pureTemplateAst = irModule->templateImplAsts.at(baseName);
2737 auto specializedIndex = specializeStructTemplate(baseName, concreteTypes, pureTemplateAst, currentModuleIndex);
2738 return {IRValueType::valueType::structObject, currentModuleIndex, specializedIndex};
2739 } catch (std::out_of_range &e) {
2742 "No implementation block found for struct template: " + wstring2string(baseName));
2743 }
2744 } else if (irModule->templateInterfaceAsts.contains(baseName)) {
2745 auto specializedIndex = specializeInterfaceTemplate(baseName, concreteTypes, currentModuleIndex);
2746 return {IRValueType::valueType::interfaceObject, currentModuleIndex, specializedIndex};
2747 } else {
2749 }
2750 } else {
2751 return parseTypeSpec(identifierWithTemplateArg->id);
2752 }
2753 }
2754
2756 if (!subscriptExpr->getSubscript().empty()) {
2757 // This is an array type like `int[10]`
2758 auto baseType = parseTypeSpec(subscriptExpr->id);
2759 yoi::vec<yoi::indexT> dimensions;
2760 for (auto &sub : subscriptExpr->getSubscript()) {
2761 yoi_assert(sub->isSubscript() && sub->expr->getToken().kind == lexer::token::tokenKind::integer,
2762 sub->getLine(),
2763 sub->getColumn(),
2764 "Expected dimension size for array type.");
2765 dimensions.push_back(sub->expr->getToken().basicVal.vInt);
2766 }
2767 return baseType.getArrayType(dimensions);
2768 } else {
2769 return parseTypeSpec(subscriptExpr->id);
2770 }
2771 }
2772
2773 IRValueType visitor::parseTypeSpecExtern(yoi::identifier *identifier, yoi::indexT targetModule) {
2774 auto mod = moduleContext->getCompilerContext()->getImportedModule(targetModule);
2775 if (auto it = mod->typeAliases.find(identifier->get().strVal); it != mod->typeAliases.end()) {
2776 return it->second;
2777 }
2778 IRExternEntry ex = getExternEntry(targetModule, identifier->node.strVal);
2779 if (ex.type == IRExternEntry::externType::structType)
2780 return {IRValueType::valueType::structObject, ex.affiliateModule, ex.itemIndex};
2781 if (ex.type == IRExternEntry::externType::datastructType)
2782 return {IRValueType::valueType::datastructObject, ex.affiliateModule, ex.itemIndex};
2783 else if (ex.type == IRExternEntry::externType::interfaceType)
2784 return {IRValueType::valueType::interfaceObject, ex.affiliateModule, ex.itemIndex};
2785 else
2786 throw std::out_of_range("Unsupported extern type: " + wstring2string(identifier->node.strVal));
2787 }
2788
2791 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(targetModule);
2792
2793 auto baseName = identifierWithTemplateArg->getId().node.strVal;
2794 auto concreteTypes = parseTemplateArgs(identifierWithTemplateArg->getArg());
2795
2796 if (targetedModule->structTemplateAsts.contains(baseName)) {
2797 try {
2798 auto pureTemplateAst = targetedModule->templateImplAsts.at(baseName);
2799 auto specializedIndex = specializeStructTemplate(baseName, concreteTypes, pureTemplateAst, targetModule);
2800 return {IRValueType::valueType::structObject, targetModule, specializedIndex};
2801 } catch (std::out_of_range &e) {
2804 "No implementation block found for struct template: " + wstring2string(baseName));
2805 }
2806 } else if (targetedModule->templateInterfaceAsts.contains(baseName)) {
2807 auto specializedIndex = specializeInterfaceTemplate(baseName, concreteTypes, targetModule);
2808 return {IRValueType::valueType::interfaceObject, targetModule, specializedIndex};
2809 } else {
2811 }
2812 } else {
2813 return parseTypeSpecExtern(identifierWithTemplateArg->id, targetModule);
2814 }
2815 }
2816
2817 IRValueType visitor::parseTypeSpecExtern(yoi::subscriptExpr *subscriptExpr, yoi::indexT targetModule) {
2818 if (!subscriptExpr->getSubscript().empty()) {
2819 auto baseType = parseTypeSpecExtern(subscriptExpr->id, targetModule);
2820 // TODO: Create and return an extern array type, creating extern entries for dimensions if necessary.
2821 panic(subscriptExpr->getLine(), subscriptExpr->getColumn(), "TODO: Extern array type parsing not fully implemented.");
2822 return {IRValueType::valueType::null};
2823 } else {
2824 return parseTypeSpecExtern(subscriptExpr->id, targetModule);
2825 }
2826 }
2827
2828 IRValueType visitor::parseTypeSpec(yoi::typeSpec *typeSpec) {
2829 switch (typeSpec->kind) {
2830 case typeSpec::typeSpecKind::Member: {
2831 // member
2832 auto it = typeSpec->member->getTerms().begin();
2833 yoi::indexT targetModule = -1, lastModule = -1;
2834 while (it + 1 != typeSpec->member->getTerms().end() && (targetModule = isModuleName(*it, targetModule)) != lastModule) {
2835 it++;
2836 lastModule = targetModule;
2837 }
2838
2839 IRValueType lhs{IRValueType::valueType::integerObject};
2840 try {
2841 if (targetModule == -1) {
2842 lhs = parseTypeSpec(*it);
2843 } else {
2844 lhs = parseTypeSpecExtern(*it, targetModule);
2845 }
2846 } catch (std::out_of_range &e) {
2847 panic(typeSpec->getLine(), typeSpec->getColumn(), e.what());
2848 }
2849 yoi_assert(it + 1 == typeSpec->member->getTerms().end(), typeSpec->getLine(), typeSpec->getColumn(), "Type specifier is not valid.");
2850
2851 if (typeSpec->arraySubscript) {
2852 if (typeSpec->arraySubscript->front() == -1) {
2853 return lhs.getDynamicArrayType();
2854 } else {
2855 return lhs.getArrayType(*typeSpec->arraySubscript);
2856 }
2857 } else {
2858 return lhs;
2859 }
2860 }
2861 case typeSpec::typeSpecKind::Func: {
2862 // func
2863 return parseTypeSpec(typeSpec->func);
2864 }
2865 case typeSpec::typeSpecKind::Null: {
2866 // null
2867 return {IRValueType::valueType::null};
2868 }
2869 case typeSpec::typeSpecKind::DecltypeExpr: {
2870 auto state = moduleContext->getIRBuilder().saveState();
2874 return rhs;
2875 }
2876 case typeSpec::typeSpecKind::Elipsis: {
2877 // elipsis
2878 // let it fallback to invalid
2879 }
2880 default: {
2881 panic(typeSpec->getLine(), typeSpec->getColumn(), "Type specifier is not valid.");
2882 return {IRValueType::valueType::null};
2883 }
2884 }
2885 }
2886
2887 yoi::wstr visitor::parseIdentifierWithTemplateArg(yoi::identifierWithTemplateArg *identifierWithTemplateArg) {
2890 res += L"<";
2891 for (auto &i : identifierWithTemplateArg->getArg().get()) {
2892 res += parseTypeSpec(i->spec).to_string();
2893 res += L",";
2894 }
2895 res.pop_back();
2896 res += L">";
2897 }
2898 return std::move(res);
2899 }
2900
2901 yoi::wstr visitor::getInterfaceImplName(const std::pair<yoi::indexT, yoi::indexT> &interfaceSrc, const std::shared_ptr<IRValueType> &typeSrc) {
2902 return L"interfaceImpl#" + std::to_wstring(interfaceSrc.first) + L"#" + std::to_wstring(interfaceSrc.second) + L"#" + typeSrc->to_string();
2903 }
2904
2905 std::pair<std::pair<yoi::indexT, yoi::indexT>, std::shared_ptr<IRInterfaceInstanceDefinition>>
2906 visitor::parseInterfaceName(yoi::externModuleAccessExpression *structDef) {
2907 // modules~
2908 auto it = structDef->getTerms().begin();
2909 yoi::indexT targetModule = -1, lastModule = -1;
2910 while (it + 1 != structDef->getTerms().end() && (targetModule = isModuleName(*it, targetModule)) != lastModule) {
2911 it++;
2912 lastModule = targetModule;
2913 }
2914 if (targetModule == -1) {
2915 targetModule = currentModuleIndex;
2916 }
2917 yoi_assert(it + 1 == structDef->getTerms().end(), structDef->getLine(), structDef->getColumn(), "Invalid interface name");
2918 auto interfaceName = parseIdentifierWithTemplateArg(*it);
2919 try {
2920 auto target = moduleContext->getCompilerContext()->getImportedModule(targetModule);
2921 auto interfaceIndex = target->interfaceTable.getIndex(interfaceName);
2922 return std::make_pair(std::make_pair(targetModule, interfaceIndex), target->interfaceTable[interfaceIndex]);
2923 } catch (std::out_of_range &) {
2924 panic(structDef->getLine(), structDef->getColumn(), "Undefined interface: " + wstring2string(interfaceName));
2925 }
2926 }
2927
2928 yoi::indexT visitor::isModuleName(identifierWithTemplateArg *it, yoi::indexT currentModule) const {
2929 if (!it->hasTemplateArg()) {
2930 return isModuleName(it->id, currentModule);
2931 } else {
2932 return currentModule;
2933 }
2934 }
2935
2936 yoi::IRExternEntry visitor::getExternEntry(yoi::indexT moduleIndex, const yoi::wstr &identifier) const {
2937 try {
2938 auto res = moduleContext->getCompilerContext()->getImportedModule(moduleIndex)->globalVariables.getIndex(identifier);
2939 return {IRExternEntry::externType::globalVar, identifier, moduleIndex, res};
2940 } catch (std::out_of_range &) {
2941 }
2942 try {
2943 auto res = moduleContext->getCompilerContext()->getImportedModule(moduleIndex)->functionTable.getIndex(identifier);
2944 return {IRExternEntry::externType::function, identifier, moduleIndex, res};
2945 } catch (std::out_of_range &) {
2946 }
2947 try {
2948 auto res = moduleContext->getCompilerContext()->getImportedModule(moduleIndex)->structTable.getIndex(identifier);
2949 return {IRExternEntry::externType::structType, identifier, moduleIndex, res};
2950 } catch (std::out_of_range &) {
2951 }
2952 try {
2953 auto res = moduleContext->getCompilerContext()->getImportedModule(moduleIndex)->dataStructTable.getIndex(identifier);
2954 return {IRExternEntry::externType::datastructType, identifier, moduleIndex, res};
2955 } catch (std::out_of_range &) {
2956 }
2957 try {
2958 auto res = moduleContext->getCompilerContext()->getImportedModule(moduleIndex)->interfaceTable.getIndex(identifier);
2959 return {IRExternEntry::externType::interfaceType, identifier, moduleIndex, res};
2960 } catch (std::out_of_range &) {
2961 }
2962 try {
2963 auto res = moduleContext->getCompilerContext()->getImportedModule(moduleIndex)->interfaceImplementationTable.getIndex(identifier);
2964 return {IRExternEntry::externType::interfaceImplType, identifier, moduleIndex, res};
2965 } catch (std::out_of_range &) {
2966 }
2967
2968 throw std::out_of_range("undefined identifier: not known global variable, function, struct or interface type: " +
2970 }
2971
2972 bool visitor::isVisitingGlobalScope() const {
2973 return moduleContext->getIRBuilder().irFuncDefinition()->name == L"yoimiya_glob_initializer";
2974 }
2975
2976 void visitor::emitBasicCastInBasicArithOpByLhsAndRhs(yoi::indexT lhs, yoi::indexT rhs) {
2979
2980 if (lhsType->isForeignBasicType()) {
2981 lhsType = managedPtr(lhsType->getNormalizedForeignBasicType());
2982 }
2983 if (rhsType->isForeignBasicType()) {
2984 rhsType = managedPtr(rhsType->getNormalizedForeignBasicType());
2985 }
2986
2987 // if bool and char with other, upcast to other
2988 if (lhsType->is1ByteType() && !rhsType->is1ByteType()) {
2989 moduleContext->getIRBuilder().basicCast(rhsType, lhs, true);
2990 } else if (!lhsType->is1ByteType() && rhsType->is1ByteType()) {
2991 moduleContext->getIRBuilder().basicCast(lhsType, rhs);
2992 }
2993 // if short with other, upcast to other
2994 if (lhsType->type == IRValueType::valueType::shortObject && rhsType->type != IRValueType::valueType::shortObject) {
2995 moduleContext->getIRBuilder().basicCast(rhsType, lhs, true);
2996 } else if (lhsType->type != IRValueType::valueType::shortObject && rhsType->type == IRValueType::valueType::shortObject) {
2997 moduleContext->getIRBuilder().basicCast(lhsType, rhs);
2998 }
2999 // if int with deci, upcast to deci
3000 else if (lhsType->type == IRValueType::valueType::integerObject && rhsType->type == IRValueType::valueType::decimalObject) {
3001 moduleContext->getIRBuilder().basicCast(rhsType, lhs, true);
3002 } else if (lhsType->type == IRValueType::valueType::decimalObject && rhsType->type == IRValueType::valueType::integerObject) {
3003 moduleContext->getIRBuilder().basicCast(lhsType, rhs);
3004 }
3005 // if unsigned with int, upcast to int
3006 else if (lhsType->type == IRValueType::valueType::unsignedObject && rhsType->type == IRValueType::valueType::integerObject) {
3007 moduleContext->getIRBuilder().basicCast(rhsType, lhs, true);
3008 } else if (lhsType->type == IRValueType::valueType::integerObject && rhsType->type == IRValueType::valueType::unsignedObject) {
3009 moduleContext->getIRBuilder().basicCast(lhsType, rhs);
3010 }
3011 // if unsigned with deci, upcast to deci
3012 else if (lhsType->type == IRValueType::valueType::unsignedObject && rhsType->type == IRValueType::valueType::decimalObject) {
3013 moduleContext->getIRBuilder().basicCast(rhsType, lhs, true);
3014 } else if (lhsType->type == IRValueType::valueType::decimalObject && rhsType->type == IRValueType::valueType::unsignedObject) {
3015 moduleContext->getIRBuilder().basicCast(lhsType, rhs);
3016 }
3017 // if left or right is pointer, cast the other to pointer
3018 else if (lhsType->type == IRValueType::valueType::pointerObject) {
3019 moduleContext->getIRBuilder().basicCast(lhsType, rhs);
3020 } else if (rhsType->type == IRValueType::valueType::pointerObject) {
3021 moduleContext->getIRBuilder().basicCast(rhsType, lhs, true);
3022 }
3023 }
3024
3025 void visitor::emitBasicCastTo(const std::shared_ptr<IRValueType> &toType) {
3027
3028 if (rhs->type == toType->type) {
3029 return;
3030 } else {
3032 }
3033 }
3034
3035 yoi::wstr visitor::getInterfaceNameStr(const std::pair<yoi::indexT, yoi::indexT> &interfaceSrc) {
3036 return L"interface#" + std::to_wstring(interfaceSrc.first) + L"#" + std::to_wstring(interfaceSrc.second);
3037 }
3038
3039 yoi::wstr visitor::getTypeSpecUniqueNameStr(const std::shared_ptr<IRValueType> &type) {
3040 yoi::wstr res;
3041 switch (type->type) {
3042 case IRValueType::valueType::integerObject:
3043 res = L"int";
3044 break;
3045 case IRValueType::valueType::decimalObject:
3046 res = L"deci";
3047 break;
3048 case IRValueType::valueType::booleanObject:
3049 res = L"bool";
3050 break;
3051 case IRValueType::valueType::stringObject:
3052 res = L"str";
3053 break;
3054 case IRValueType::valueType::characterObject:
3055 res = L"char";
3056 break;
3057 case IRValueType::valueType::shortObject:
3058 res = L"short";
3059 break;
3060 case IRValueType::valueType::unsignedObject:
3061 res = L"unsigned";
3062 break;
3063 case IRValueType::valueType::structObject:
3064 res = L"struct#" + std::to_wstring(type->typeAffiliateModule) + L"#" + std::to_wstring(type->typeIndex);
3065 break;
3066 case IRValueType::valueType::null:
3067 res = L"null";
3068 break;
3069 case IRValueType::valueType::virtualMethod:
3070 res = L"virtual_method#" + std::to_wstring(type->typeAffiliateModule) + L"#" + std::to_wstring(type->typeIndex);
3071 break;
3072 case IRValueType::valueType::incompleteTemplateType:
3073 res = L"incomplete_template_type#" + std::to_wstring(type->typeIndex);
3074 break;
3075 case IRValueType::valueType::interfaceObject:
3076 res = L"interfaceObject#" + std::to_wstring(type->typeAffiliateModule) + L"#" + std::to_wstring(type->typeIndex);
3077 break;
3078 case IRValueType::valueType::pointerObject:
3079 res = L"pointerObject";
3080 break;
3081 case IRValueType::valueType::none:
3082 res = L"none";
3083 break;
3084 case IRValueType::valueType::datastructObject:
3085 res += L"datastructObject#" + std::to_wstring(type->typeAffiliateModule) + L"#" + std::to_wstring(type->typeIndex);
3086 break;
3087 default:
3090 "Invalid type");
3091 break;
3092 }
3093 if (type->isArrayType()) {
3094 yoi::indexT arraySize = 1;
3095 for (auto &dim : type->dimensions) {
3096 arraySize *= dim;
3097 }
3098 res += L"[" + std::to_wstring(arraySize) + L"]";
3099 } else if (type->isDynamicArrayType()) {
3100 res += L"[]";
3101 }
3102 return res;
3103 }
3104
3105 yoi::wstr visitor::getFuncUniqueNameStr(const std::vector<std::shared_ptr<IRValueType>> &argumentTypes, bool whetherIgnoreFirstParam) {
3106 yoi::wstr res = L"#";
3107 bool first = false;
3108 for (auto &arg : argumentTypes) {
3109 if (whetherIgnoreFirstParam && !first || !whetherIgnoreFirstParam)
3110 res += getTypeSpecUniqueNameStr(arg) + L"#";
3111 else
3112 first = false;
3113 }
3114 if (!argumentTypes.empty()) {
3115 res.pop_back();
3116 }
3117 res.shrink_to_fit();
3118 return res;
3119 }
3120
3121 yoi::indexT visitor::visitExtern(yoi::identifier *identifier, yoi::indexT targetModule, bool isStoreOp) {
3122 try {
3123 yoi::IRExternEntry entry = getExternEntry(targetModule, identifier->get().strVal);
3124 yoi_assert(entry.type == IRExternEntry::externType::globalVar,
3127 "Invalid type specifier, expected global variable");
3128 auto valType = moduleContext->getCompilerContext()->getImportedModule(targetModule)->globalVariables[identifier->node.strVal];
3129 if (isStoreOp) {
3130 tryCastTo(valType);
3132 IR::Opcode::store_global, {IROperand::operandType::externVar, entry.itemIndex}, entry.affiliateModule);
3134 } else {
3136 IR::Opcode::load_global, {IROperand::operandType::externVar, entry.itemIndex}, valType, entry.affiliateModule);
3138 }
3139 } catch (std::runtime_error &) {
3140 panic(identifier->getLine(), identifier->getColumn(), "undefined identifier: " + wstring2string(identifier->node.strVal));
3142 } catch (std::out_of_range &) {
3143 panic(identifier->getLine(), identifier->getColumn(), "undefined identifier: " + wstring2string(identifier->node.strVal));
3145 }
3146 }
3147
3148 yoi::indexT visitor::visitExtern(yoi::identifierWithTemplateArg *identifierWithTemplateArg, yoi::indexT targetModule, bool isStoreOp) {
3150 // TODO: what the heck is this
3151 panic(identifierWithTemplateArg->getLine(), identifierWithTemplateArg->getColumn(), "Invalid visit of identifier with template arg.");
3152 return 0;
3153 } else {
3154 return visitExtern(identifierWithTemplateArg->id, targetModule);
3155 }
3156 }
3157
3158 std::shared_ptr<IRValueType> visitor::getIncompleteType(const yoi::wstr &typeName) const {
3159 try {
3160 if (moduleContext->getTemplateBuilders().empty()) {
3161 throw std::out_of_range("No template builder found");
3162 }
3163 auto &templateBuilder = *moduleContext->getTemplateBuilders().rbegin();
3164 auto res = templateBuilder.templateArguments[typeName];
3165 return res.templateType;
3166 } catch (std::out_of_range &e) {
3167 throw std::out_of_range("Cannot find incomplete type: " + yoi::wstring2string(typeName));
3168 }
3169 }
3170
3173 for (auto &arg : templateArgs.spec) {
3174 yoi::wstr name = arg->getId().get().strVal;
3175 auto index = res.put_create(name, {{}});
3176 res[index].templateType = managedPtr(IRValueType{IRValueType::valueType::incompleteTemplateType, currentModuleIndex, index});
3177 }
3178 return res;
3179 }
3180
3181 yoi::vec<std::shared_ptr<IRValueType>> visitor::parseTemplateArgs(const yoi::templateArg &templateArgs) {
3183 for (auto &arg : templateArgs.spec) {
3184 res.push_back(managedPtr(parseTypeSpec(arg->spec)));
3185 }
3186 return res;
3187 }
3188
3189 yoi::indexT visitor::specializeFunctionTemplate(yoi::funcDefStmt *astNode,
3190 const yoi::vec<std::shared_ptr<IRValueType>> &concreteTemplateArgs,
3191 yoi::indexT moduleIndex) {
3192 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(moduleIndex);
3193
3194 yoi::wstr specializedName = getMangledTemplateName(astNode->id->id->get().strVal, concreteTemplateArgs);
3195
3196 // Create a new function definition by specializing the template
3198
3199 builder.setDebugInfo({targetedModule->modulePath, astNode->getLine(), astNode->getColumn()});
3200
3201 // Create specialization context
3202 IRTemplateBuilder specializationContext;
3203 for (yoi::indexT i = 0; i < astNode->id->arg->get().size(); ++i) {
3204 auto paramName = astNode->id->arg->get()[i]->id->get().strVal;
3205 if (astNode->id->hasDefTemplateArg() && astNode->id->arg->get()[i]->satisfyCondition) {
3206 for (auto &c : astNode->id->arg->get()[i]->satisfyCondition->emaes) {
3207 checkConceptSatisfaction(c, paramName, concreteTemplateArgs[i]);
3208 }
3209 }
3210 specializationContext.addTemplateArgument(paramName, concreteTemplateArgs[i]);
3211 }
3212
3213 pushModuleContext(moduleIndex);
3214 moduleContext->pushTemplateBuilder(specializationContext);
3215
3216 // Specialize arguments and return type
3218 for (const auto &argPair : astNode->getArgs().get()) {
3219 auto argName = argPair->getId().get().strVal;
3220 auto argType = managedPtr(parseTypeSpec(&argPair->getSpec()));
3221 builder.addArgument(argName, argType);
3222 paramTypes.push_back(argType);
3223 }
3224
3225 if (targetedModule->functionTable.contains(specializedName + getFuncUniqueNameStr(paramTypes))) {
3226 auto result = targetedModule->functionTable.getIndex(specializedName + getFuncUniqueNameStr(paramTypes));
3227 // restore environment
3229 popModuleContext();
3230 return result;
3231 }
3232
3233 builder.setName(specializedName + getFuncUniqueNameStr(paramTypes));
3234 builder.setReturnType(managedPtr(parseTypeSpec(&astNode->getResultType())));
3235
3236 auto specializedFunc = builder.yield();
3237 auto funcIndex = targetedModule->functionTable.put_create(specializedName + getFuncUniqueNameStr(paramTypes), specializedFunc);
3238 targetedModule->functionOverloadIndexies[specializedName].push_back(funcIndex);
3239
3240 // Visit the body to generate IR
3241 moduleContext->pushIRBuilder({moduleContext->getCompilerContext(), targetedModule, specializedFunc});
3242 moduleContext->getIRBuilder().setDebugInfo({targetedModule->modulePath, astNode->getLine(), astNode->getColumn()});
3244 try {
3245 visit(&astNode->getBlock(), true);
3246 } catch (std::runtime_error &e) {
3247 panic(astNode->getLine(),
3248 astNode->getColumn(),
3249 std::string("Exception occurred while specializing method: ") + yoi::wstring2string(specializedName) + ": " + e.what());
3250 } catch (std::exception &e) {
3251 panic(astNode->getLine(),
3252 astNode->getColumn(),
3253 std::string("Unknown exception occurred while specializing method: ") + yoi::wstring2string(specializedName) + ": " + e.what());
3254 }
3257
3258 // Pop context
3260 popModuleContext();
3261
3262 return funcIndex;
3263 }
3264
3265 yoi::wstr visitor::getMangledTemplateName(const yoi::wstr &baseName, const yoi::vec<std::shared_ptr<IRValueType>> &templateArgs) {
3266 yoi::wstr mangled = baseName + L"<";
3267 for (size_t i = 0; i < templateArgs.size(); ++i) {
3268 mangled += getTypeSpecUniqueNameStr(templateArgs[i]);
3269 if (i < templateArgs.size() - 1) {
3270 mangled += L",";
3271 }
3272 }
3273 mangled += L">";
3274 return mangled;
3275 }
3276
3277 yoi::vec<yoi::wstr> visitor::extractTemplateParamsFromTypeArgs(yoi::templateArg *templateArgs) {
3278 yoi::vec<yoi::wstr> params;
3279 if (!templateArgs)
3280 return params;
3281 for (auto &spec : templateArgs->get()) {
3282 auto typeSpec = &spec->get();
3283 // We expect simple identifier type specs, e.g. T, U
3284 if (typeSpec->kind == typeSpec::typeSpecKind::Member && typeSpec->member && typeSpec->member->getTerms().size() == 1) {
3285 auto term = typeSpec->member->getTerms()[0];
3286 if (!term->hasTemplateArg()) {
3287 params.push_back(term->id->get().strVal);
3288 continue;
3289 }
3290 }
3291 // If complex type or anything else, it's invalid for a definition param
3292 panic(templateArgs->getLine(), templateArgs->getColumn(), "Invalid template parameter definition. Expected identifier.");
3293 }
3294 return params;
3295 }
3296
3297 yoi::vec<yoi::wstr> visitor::extractTemplateParamsFromTypeArgs(yoi::defTemplateArg *templateArgs) {
3298 yoi::vec<yoi::wstr> params;
3299 if (!templateArgs)
3300 return params;
3301 for (auto &spec : templateArgs->get()) {
3302 params.push_back(spec->getId().get().strVal);
3303 }
3304 return params;
3305 }
3306
3307 yoi::indexT visitor::specializeStructTemplate(const yoi::wstr &templateName,
3308 const yoi::vec<std::shared_ptr<IRValueType>> &concreteTemplateArgs,
3309 yoi::implStmt *pureTemplateImplAst,
3310 yoi::indexT moduleIndex) {
3311
3312 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(moduleIndex);
3313
3314 yoi::wstr specializedName = getMangledTemplateName(templateName, concreteTemplateArgs);
3315
3316 if (targetedModule->structTable.contains(specializedName)) {
3317 return targetedModule->structTable.getIndex(specializedName);
3318 }
3319
3320 auto structAst = targetedModule->structTemplateAsts.at(templateName);
3321
3322 IRTemplateBuilder specializationContext;
3323 yoi_assert(concreteTemplateArgs.size() == structAst->id->getArg().get().size(),
3324 0,
3325 0,
3326 "Template argument count mismatch for struct " + wstring2string(templateName));
3327 for (yoi::indexT i = 0; i < concreteTemplateArgs.size(); ++i) {
3328 auto paramName = structAst->id->getArg().get()[i]->getId().get().strVal;
3329 // concept validation logic, partially
3330 if (structAst->id->hasDefTemplateArg() && structAst->id->getArg().get()[i]->satisfyCondition) {
3331 for (auto &c : structAst->id->getArg().get()[i]->satisfyCondition->emaes) {
3332 checkConceptSatisfaction(c, paramName, concreteTemplateArgs[i]);
3333 }
3334 }
3335 specializationContext.addTemplateArgument(paramName, concreteTemplateArgs[i]);
3336 }
3337
3338 auto specializedStructIndex = targetedModule->structTable.put_create(specializedName, nullptr);
3339
3340 generateNullInterfaceImplementation(managedPtr(IRValueType{IRValueType::valueType::structObject, moduleIndex, specializedStructIndex}));
3341 auto selfType = managedPtr(IRValueType{IRValueType::valueType::structObject, moduleIndex, specializedStructIndex});
3342 specializationContext.addTemplateArgument(L"STRUCT", selfType);
3343
3344 pushModuleContext(moduleIndex);
3345 moduleContext->pushTemplateBuilder(specializationContext);
3346
3348 builder.setName(specializedName);
3349 yoi::vec<yoi::wstr> paramNames;
3350 for (yoi::indexT i = 0; i < structAst->id->getArg().get().size(); ++i) {
3351 paramNames.push_back(structAst->id->getArg().get()[i]->getId().get().strVal);
3352 }
3353 builder.setStoredTemplateArgs(paramNames, concreteTemplateArgs);
3354 for (auto &field : structAst->getInner().getInner()) {
3355 if (field->kind == 0) {
3356 auto memberName = field->getVar().getId().get().strVal;
3357 auto memberType = managedPtr(parseTypeSpec(field->getVar().spec));
3358 if (field->modifier == structDefInnerPair::Modifier::DataField) {
3359 memberType->metadata.setMetadata(L"STRUCT_DATAFIELD", true);
3360 }
3361 if (field->modifier == structDefInnerPair::Modifier::Weak) {
3362 memberType->addAttribute(IRValueType::ValueAttr::WeakRef);
3363 }
3364 builder.addField(memberName, memberType);
3365 } else if (field->kind == 2 && field->getMethod().getName().hasDefTemplateArg()) {
3366 // Generic method declaration
3367 builder.addTemplateMethodDecl(field->getMethod().getName().getId().get().strVal, field);
3368 } else {
3369 auto [funcIndex, funcName] =
3370 specializeStructMethodDeclaration(specializationContext, field, specializedName, concreteTemplateArgs, moduleIndex);
3371 builder.addMethod(funcName, funcIndex);
3372 }
3373 }
3374
3375 // Collect generic method definitions from the pure template impl
3376 if (pureTemplateImplAst) {
3377 for (auto &methodAst : pureTemplateImplAst->getInner().getInner()) {
3378 if (methodAst->isMethod() && methodAst->getMethod().getName().hasTemplateArg()) {
3379 builder.addTemplateMethodDef(methodAst->getMethod().getName().getId().get().strVal, methodAst);
3380 }
3381 }
3382 }
3383
3384 auto specializedStruct = builder.yield();
3385 targetedModule->structTable[specializedStructIndex] = specializedStruct;
3386
3387 // Specialize methods defined in `impl MyStruct<T> { ... }`
3388 if (pureTemplateImplAst) {
3389 for (auto &methodAst : pureTemplateImplAst->getInner().getInner()) {
3390 if (methodAst->isMethod() && methodAst->getMethod().getName().hasTemplateArg()) {
3391 // Handled above for templateMethodDefs
3392 continue;
3393 } else {
3394 specializeStructMethodDefinition(
3395 specializationContext, specializedStruct, methodAst, specializedName, concreteTemplateArgs, moduleIndex);
3396 }
3397 }
3398 }
3399
3400 if (targetedModule->templateInterfaceImplAsts.count(templateName)) {
3401 for (auto &implAst : targetedModule->templateInterfaceImplAsts.at(templateName)) {
3402 specializeInterfaceImplementation(
3403 implAst, selfType, specializedName, concreteTemplateArgs, currentModuleIndex); // now we are in the specialized context
3404 }
3405 }
3406
3408 popModuleContext();
3409
3410 return specializedStructIndex;
3411 }
3412
3413 yoi::indexT visitor::specializeStructMethodTemplate(const std::shared_ptr<IRStructDefinition> &structDef,
3415 yoi::implInnerPair *def,
3416 const yoi::wstr &baseMethodName,
3417 const yoi::vec<std::shared_ptr<IRValueType>> &methodTemplateArgs,
3418 yoi::indexT moduleIndex) {
3419 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(moduleIndex);
3420
3421 // Combine struct template args and method template args
3422 IRTemplateBuilder combinedContext;
3423 // Reconstruct struct specialization context
3424 for (size_t i = 0; i < structDef->templateParamNames.size(); ++i) {
3425 combinedContext.addTemplateArgument(structDef->templateParamNames[i], structDef->storedTemplateArgs[i]);
3426 }
3427
3428 // Add method template args
3429 yoi::vec<yoi::wstr> methodParams;
3430 if (decl) {
3431 methodParams = extractTemplateParamsFromTypeArgs(&decl->getMethod().getName().getArg());
3432 } else if (def) {
3433 methodParams = extractTemplateParamsFromTypeArgs(&def->getMethod().getName().getArg());
3434 }
3435
3436 yoi_assert(methodParams.size() == methodTemplateArgs.size(), 0, 0, "Method template argument count mismatch");
3437 for (size_t i = 0; i < methodParams.size(); ++i) {
3438 // here we specialize the template arguments of *this method*
3439 // still check the concept satisfaction
3440 if (decl->getMethod().getName().hasDefTemplateArg() && decl->getMethod().getName().arg->spec[i]->satisfyCondition) {
3441 auto paramName = decl->getMethod().getName().arg->spec[i]->id->get().strVal;
3442 for (auto &c : decl->getMethod().getName().arg->spec[i]->satisfyCondition->emaes) {
3443 checkConceptSatisfaction(c, paramName, methodTemplateArgs[i]);
3444 }
3445 }
3446 combinedContext.addTemplateArgument(methodParams[i], methodTemplateArgs[i]);
3447 }
3448
3449 yoi::wstr specializedMethodName = getMangledTemplateName(baseMethodName, methodTemplateArgs);
3450
3451 pushModuleContext(moduleIndex);
3452 moduleContext->pushTemplateBuilder(combinedContext);
3453
3454 // Reuse specializeStructMethodDeclaration logic but with combined context
3456 funcBuilder.setDebugInfo({targetedModule->modulePath, (decl ? decl->getLine() : def->getLine()), (decl ? decl->getColumn() : def->getColumn())});
3457
3458 auto selfType = managedPtr(IRValueType{IRValueType::valueType::structObject, moduleIndex, targetedModule->structTable.getIndex(structDef->name)});
3459 combinedContext.addTemplateArgument(L"STRUCT", selfType);
3460
3461 yoi::vec<std::shared_ptr<IRValueType>> specializedArgTypes;
3462 if (decl) {
3463 funcBuilder.attrs = getFunctionAttributes(decl->getMethod().attrs);
3464 if (std::find(funcBuilder.attrs.begin(), funcBuilder.attrs.end(), IRFunctionDefinition::FunctionAttrs::Static) == funcBuilder.attrs.end()) {
3465 funcBuilder.addArgument(L"this", selfType);
3466 }
3467 for (auto &arg : decl->getMethod().getArgs().get()) {
3468 auto specializedType = managedPtr(parseTypeSpec(&arg->getSpec()));
3469 funcBuilder.addArgument(arg->getId().get().strVal, specializedType);
3470 specializedArgTypes.push_back(specializedType);
3471 }
3472 funcBuilder.setReturnType(managedPtr(parseTypeSpec(&decl->getMethod().getResultType())));
3473 } else {
3474 // If only definition exists...
3475 funcBuilder.attrs = getFunctionAttributes(def->getMethod().attrs);
3476 if (std::find(funcBuilder.attrs.begin(), funcBuilder.attrs.end(), IRFunctionDefinition::FunctionAttrs::Static) == funcBuilder.attrs.end()) {
3477 funcBuilder.addArgument(L"this", selfType);
3478 }
3479 for (auto &arg : def->getMethod().getArgs().get()) {
3480 auto specializedType = managedPtr(parseTypeSpec(&arg->getSpec()));
3481 funcBuilder.addArgument(arg->getId().get().strVal, specializedType);
3482 specializedArgTypes.push_back(specializedType);
3483 }
3484 funcBuilder.setReturnType(managedPtr(parseTypeSpec(&def->getMethod().getResultType())));
3485 }
3486
3487 yoi::wstr fullMangledName = structDef->name + L"::" + specializedMethodName + getFuncUniqueNameStr(specializedArgTypes);
3488
3489 if (targetedModule->functionTable.contains(fullMangledName)) {
3490 auto res = targetedModule->functionTable.getIndex(fullMangledName);
3492 popModuleContext();
3493 return res;
3494 }
3495
3496 funcBuilder.setName(fullMangledName);
3497 auto specializedFunc = funcBuilder.yield();
3498 auto funcIndex = targetedModule->functionTable.put_create(fullMangledName, specializedFunc);
3499 targetedModule->functionOverloadIndexies[structDef->name + L"::" + baseMethodName].push_back(funcIndex);
3500
3501 // If definition exists, visit it
3502 if (def) {
3503 moduleContext->pushIRBuilder({moduleContext->getCompilerContext(), targetedModule, specializedFunc});
3504 moduleContext->getIRBuilder().setDebugInfo({targetedModule->modulePath, def->getLine(), def->getColumn()});
3506 try {
3507 visit(&def->getMethod().getBlock(), true);
3508 } catch (std::exception &e) {
3509 panic(def->getLine(), def->getColumn(), std::string("Exception occurred while specializing template method: ") + yoi::wstring2string(fullMangledName) + ": " + e.what());
3510 }
3513 }
3514
3516 popModuleContext();
3517
3518 return funcIndex;
3519 }
3520
3521 std::pair<yoi::indexT, yoi::wstr> visitor::specializeStructMethodDeclaration(IRTemplateBuilder &structTemplate,
3522 yoi::structDefInnerPair *methodAstNode,
3523 const yoi::wstr &specializedStructName,
3524 const yoi::vec<std::shared_ptr<IRValueType>> &concreteTemplateArgs,
3525 yoi::indexT moduleIndex) {
3526
3527 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(moduleIndex);
3528
3529 // Push the template's own context to resolve generic types like 'T' to their placeholder
3530 // 'incompleteTemplateType'.
3531 IRTemplateBuilder genericContext;
3532 genericContext.templateArguments = structTemplate.templateArguments;
3533
3534 moduleContext->pushTemplateBuilder(genericContext);
3535
3536 yoi::wstr baseMethodName;
3537 yoi::wstr genericMethodKey;
3539
3540 if (methodAstNode->kind == 1) {
3541 for (yoi::indexT i = 0; i < concreteTemplateArgs.size(); ++i) {
3542 // same as above
3543 if (methodAstNode->getConstructor().tempArgs && methodAstNode->getConstructor().tempArgs->spec[i]->satisfyCondition) {
3544 auto paramName = methodAstNode->getConstructor().tempArgs->spec[i]->id->get().strVal;
3545 for (auto &c : methodAstNode->getConstructor().tempArgs->spec[i]->satisfyCondition->emaes) {
3546 checkConceptSatisfaction(c, paramName, concreteTemplateArgs[i]);
3547 }
3548 }
3549 }
3550
3551 baseMethodName = L"constructor";
3552 for (auto &arg : methodAstNode->getConstructor().getArgs().get()) {
3553 genericArgTypes.push_back(managedPtr(parseTypeSpec(&arg->getSpec())));
3554 }
3555 genericMethodKey = baseMethodName + getFuncUniqueNameStr(genericArgTypes);
3556 } else if (methodAstNode->kind == 2) {
3557 for (yoi::indexT i = 0; i < concreteTemplateArgs.size(); ++i) {
3558 // same as above
3559 if (methodAstNode->getMethod().getName().hasDefTemplateArg() && methodAstNode->getMethod().getName().arg->spec[i]->satisfyCondition) {
3560 auto paramName = methodAstNode->getMethod().getName().arg->spec[i]->id->get().strVal;
3561 for (auto &c : methodAstNode->getMethod().getName().arg->spec[i]->satisfyCondition->emaes) {
3562 checkConceptSatisfaction(c, paramName, concreteTemplateArgs[i]);
3563 }
3564 }
3565 }
3566
3567 baseMethodName = methodAstNode->getMethod().getName().getId().get().strVal;
3568 for (auto &arg : methodAstNode->getMethod().getArgs().get()) {
3569 genericArgTypes.push_back(managedPtr(parseTypeSpec(&arg->getSpec())));
3570 }
3571 genericMethodKey = baseMethodName + getFuncUniqueNameStr(genericArgTypes);
3572 } else if (methodAstNode->kind == 3) {
3573 // finalizer
3574 baseMethodName = L"finalizer";
3575 genericMethodKey = baseMethodName;
3576 }
3577
3578 moduleContext->popTemplateBuilder(); // Done with generic context
3579
3580 IRTemplateBuilder specializationContext;
3581 for (size_t i = 0; i < concreteTemplateArgs.size(); ++i) {
3582 auto paramName = structTemplate.templateArguments.getKey(i);
3583 specializationContext.addTemplateArgument(paramName, concreteTemplateArgs[i]);
3584 }
3585 auto selfType =
3586 managedPtr(IRValueType{IRValueType::valueType::structObject, moduleIndex, targetedModule->structTable.getIndex(specializedStructName)});
3587 specializationContext.addTemplateArgument(L"STRUCT", selfType);
3588 moduleContext->pushTemplateBuilder(specializationContext);
3589
3591
3592 funcBuilder.setDebugInfo({targetedModule->modulePath, methodAstNode->getLine(), methodAstNode->getColumn()});
3593
3594 yoi::vec<std::shared_ptr<IRValueType>> specializedArgTypes;
3595
3596 if (methodAstNode->kind == 1) {
3597 funcBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Constructor);
3598 funcBuilder.addArgument(L"this", selfType); // Specialized 'this'
3599 for (auto &arg : methodAstNode->getConstructor().getArgs().get()) {
3600 auto specializedType = managedPtr(parseTypeSpec(&arg->getSpec()));
3601 funcBuilder.addArgument(arg->getId().get().strVal, specializedType);
3602 specializedArgTypes.push_back(specializedType);
3603 }
3604 funcBuilder.setReturnType(selfType);
3605 } else if (methodAstNode->kind == 2) {
3606 funcBuilder.attrs = getFunctionAttributes(methodAstNode->getMethod().attrs);
3607 if (std::find(funcBuilder.attrs.begin(), funcBuilder.attrs.end(), IRFunctionDefinition::FunctionAttrs::Static) ==
3608 funcBuilder.attrs.end()) {
3609 funcBuilder.addArgument(L"this", selfType); // Specialized 'this'
3610 }
3611 for (auto &arg : methodAstNode->getMethod().getArgs().get()) {
3612 auto specializedType = managedPtr(parseTypeSpec(&arg->getSpec()));
3613 funcBuilder.addArgument(arg->getId().get().strVal, specializedType);
3614 specializedArgTypes.push_back(specializedType);
3615 }
3616 funcBuilder.setReturnType(managedPtr(parseTypeSpec(&methodAstNode->getMethod().getResultType())));
3617 } else if (methodAstNode->kind == 3) {
3618 funcBuilder.setName(specializedStructName + L"::finalizer");
3619 funcBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Finalizer);
3620 funcBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Preserve);
3621 funcBuilder.addArgument(L"this", selfType); // Specialized 'this'
3622 funcBuilder.setReturnType(moduleContext->getCompilerContext()->getNoneObjectType());
3623 }
3624
3625 yoi::wstr specializedMethodName = specializedStructName + L"::" + baseMethodName;
3626 funcBuilder.setName(specializedMethodName + getFuncUniqueNameStr(specializedArgTypes));
3627
3628 auto specializedFunc = funcBuilder.yield();
3629 auto funcIndex = targetedModule->functionTable.put_create(specializedMethodName + getFuncUniqueNameStr(specializedArgTypes), specializedFunc);
3630 targetedModule->functionOverloadIndexies[specializedMethodName].push_back(funcIndex);
3631
3633 return {funcIndex, baseMethodName + getFuncUniqueNameStr(specializedArgTypes)};
3634 }
3635
3636 void visitor::specializeStructMethodDefinition(IRTemplateBuilder &structTemplate,
3637 const std::shared_ptr<IRStructDefinition> &specializedStruct,
3638 yoi::implInnerPair *methodAstNode,
3639 const yoi::wstr &specializedStructName,
3640 const yoi::vec<std::shared_ptr<IRValueType>> &concreteTemplateArgs,
3641 yoi::indexT moduleIndex) {
3642
3643 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(moduleIndex);
3644
3645 // Push the template's own context to resolve generic types like 'T' to their placeholder
3646 // 'incompleteTemplateType'.
3647 IRTemplateBuilder genericContext;
3648 genericContext.templateArguments = structTemplate.templateArguments;
3649
3650 moduleContext->pushTemplateBuilder(genericContext);
3651
3652 yoi::wstr baseMethodName;
3653 yoi::wstr genericMethodKey;
3655
3656 if (methodAstNode->isConstructor()) {
3657 baseMethodName = L"constructor";
3658 for (auto &arg : methodAstNode->getConstructor().getArgs().get()) {
3659 genericArgTypes.push_back(managedPtr(parseTypeSpec(&arg->getSpec())));
3660 }
3661 genericMethodKey = baseMethodName + getFuncUniqueNameStr(genericArgTypes);
3662 } else if (methodAstNode->isFinalizer()) {
3663 baseMethodName = L"finalizer";
3664 for (auto &arg : methodAstNode->getConstructor().getArgs().get()) {
3665 genericArgTypes.push_back(managedPtr(parseTypeSpec(&arg->getSpec())));
3666 }
3667 genericMethodKey = baseMethodName + getFuncUniqueNameStr(genericArgTypes);
3668 } else {
3669 baseMethodName = methodAstNode->getMethod().getName().getId().get().strVal;
3670 for (auto &arg : methodAstNode->getMethod().getArgs().get()) {
3671 genericArgTypes.push_back(managedPtr(parseTypeSpec(&arg->getSpec())));
3672 }
3673 genericMethodKey = baseMethodName + getFuncUniqueNameStr(genericArgTypes);
3674 }
3675
3676 moduleContext->popTemplateBuilder(); // Done with generic context
3677
3678 IRTemplateBuilder specializationContext;
3679 for (size_t i = 0; i < concreteTemplateArgs.size(); ++i) {
3680 auto paramName = structTemplate.templateArguments.getKey(i);
3681 specializationContext.addTemplateArgument(paramName, concreteTemplateArgs[i]);
3682 }
3683 auto selfType =
3684 managedPtr(IRValueType{IRValueType::valueType::structObject, moduleIndex, targetedModule->structTable.getIndex(specializedStructName)});
3685 specializationContext.addTemplateArgument(L"STRUCT", selfType);
3686 moduleContext->pushTemplateBuilder(specializationContext);
3687
3688 yoi::vec<std::shared_ptr<IRValueType>> specializedArgTypes;
3689
3690 if (methodAstNode->isConstructor()) {
3691 for (auto &arg : methodAstNode->getConstructor().getArgs().get()) {
3692 auto specializedType = managedPtr(parseTypeSpec(&arg->getSpec()));
3693 specializedArgTypes.push_back(specializedType);
3694 }
3695 } else if (methodAstNode->isFinalizer()) {
3696 // no args
3697 } else {
3698 for (auto &arg : methodAstNode->getMethod().getArgs().get()) {
3699 auto specializedType = managedPtr(parseTypeSpec(&arg->getSpec()));
3700 specializedArgTypes.push_back(specializedType);
3701 }
3702 }
3703
3704 yoi::wstr specializedMethodName = specializedStructName + L"::" + baseMethodName + getFuncUniqueNameStr(specializedArgTypes);
3705
3706 auto funcIndex = targetedModule->functionTable.getIndex(specializedMethodName);
3707
3708 moduleContext->pushIRBuilder({moduleContext->getCompilerContext(), targetedModule, targetedModule->functionTable[funcIndex]});
3709 moduleContext->getIRBuilder().setDebugInfo({targetedModule->modulePath, methodAstNode->getLine(), methodAstNode->getColumn()});
3711 try {
3712 visit(methodAstNode->isConstructor() ? &methodAstNode->getConstructor().getBlock() : &methodAstNode->getMethod().getBlock(), true);
3713 } catch (std::exception &e) {
3714 set_current_file_path(moduleContextStack.top().first->getIRBuilder().getCurrentDebugInfo().sourceFile);
3715 panic(moduleContextStack.top().first->getIRBuilder().getCurrentDebugInfo().line,
3716 moduleContextStack.top().first->getIRBuilder().getCurrentDebugInfo().column,
3717 std::string("Exception occurred while specializing method: ") + yoi::wstring2string(specializedMethodName) + ": " + e.what() +
3718 "\n");
3719 }
3720
3724 }
3725
3726 yoi::wstr visitor::getSpecializedMangledMethodName(yoi::indexTable<yoi::wstr, IRTemplateBuilder::Argument> &templateArgs,
3727 const yoi::wstr &baseMethodName,
3728 const yoi::vec<std::shared_ptr<IRValueType>> &specializedArgTypes) {
3729 auto res = baseMethodName;
3730 for (yoi::indexT i = 0; i < specializedArgTypes.size(); ++i) {
3731 auto &arg = templateArgs[i];
3732 auto strRepl1 = templateArgs[i].templateType->to_string();
3733 auto strRepl2 = specializedArgTypes[i]->to_string();
3734 replace_all(res, strRepl1, strRepl2);
3735 }
3736 return res;
3737 }
3738
3740 auto exportIdentifier = exportDecl->as->node.strVal;
3741 try {
3742 auto parsedType = managedPtr(parseTypeSpec(exportDecl->from));
3743
3744 moduleContext->getCompilerContext()->getIRFFITable()->addForeignType(exportIdentifier, parsedType);
3746 } catch (std::runtime_error &e) {
3747 // failed as type, try function
3748 }
3749
3750 try {
3751 auto it = exportDecl->from->member->getTerms().begin();
3752 yoi::indexT targetModule = -1, lastModule = -1;
3753 while (it + 1 != exportDecl->from->member->getTerms().end() && (targetModule = isModuleName(*it, targetModule)) != lastModule) {
3754 it++;
3755 lastModule = targetModule;
3756 }
3757 yoi_assert(it + 1 == exportDecl->from->member->getTerms().end(),
3760 "Expected a identifier after modules but this is not the final term of expression.");
3761 targetModule = targetModule == -1 ? currentModuleIndex : targetModule;
3762
3763 yoi::indexT funcIndex = -1;
3764
3765 if (!(*it)->hasTemplateArg()) {
3766 for (auto funcIt = moduleContext->getCompilerContext()->getImportedModule(targetModule)->functionTable.begin();
3767 funcIt != moduleContext->getCompilerContext()->getImportedModule(targetModule)->functionTable.end();
3768 funcIt++) {
3769 if (funcIt->first.starts_with((*it)->id->get().strVal + L"#")) {
3770 // an mangled name of target function
3771 funcIndex =
3772 std::distance(moduleContext->getCompilerContext()->getImportedModule(targetModule)->functionTable.begin(), funcIt);
3773 }
3774 }
3775 }
3776
3777 if (funcIndex != -1) {
3778 auto attrs = getFunctionAttributes(exportDecl->attrs);
3779 moduleContext->getCompilerContext()->getIRFFITable()->addExportedFunction(exportIdentifier, targetModule, funcIndex, attrs);
3781 } else {
3782 // try template
3783 auto templateName = (*it)->id->get().strVal;
3784 if (!moduleContext->getCompilerContext()->getImportedModule(targetModule)->funcTemplateAsts.contains(templateName)) {
3785 throw std::out_of_range("Cannot find the template: " + wstring2string(templateName));
3786 }
3787
3788 yoi_assert((*it)->hasTemplateArg(),
3791 "Expected template arguments for template: " + wstring2string(templateName));
3792
3793 auto templateArgs = parseTemplateArgs((*it)->getArg());
3794
3795 auto funcIndex = specializeFunctionTemplate(
3796 moduleContext->getCompilerContext()->getImportedModule(targetModule)->funcTemplateAsts[templateName], templateArgs, targetModule);
3797
3798 auto attrs = getFunctionAttributes(exportDecl->attrs);
3799
3800 moduleContext->getCompilerContext()->getIRFFITable()->addExportedFunction(exportIdentifier, targetModule, funcIndex, attrs);
3802 }
3803 } catch (std::out_of_range &e) {
3806 "None of the existing types and functions match the name: " + wstring2string(exportDecl->as->node.strVal));
3807 }
3808 }
3809
3811 yoi::wstr from{};
3812
3813 if (importDecl->from_path.strVal == L"builtin") {
3814 from = L"builtin";
3815 } else {
3816 for (auto &prep : moduleContext->getCompilerContext()->getBuildConfig()->searchPaths) {
3817 try {
3818 std::filesystem::path final = std::filesystem::path(prep) / importDecl->from_path.strVal;
3819 from = realpath(final.wstring());
3820 break;
3821 } catch (std::runtime_error &e) {
3822 continue;
3823 }
3824 }
3825 }
3826 yoi_assert(
3827 !from.empty(), importDecl->getLine(), importDecl->getColumn(), "Cannot find the file: " + wstring2string(importDecl->from_path.strVal));
3828
3829 // import method implementation
3830 // parse method signature and add to import table
3831 auto funcName = importDecl->inner->name->getId().get().strVal;
3833
3834 builder.attrs = getFunctionAttributes(importDecl->inner->attrs);
3835 builder.setDebugInfo({irModule->modulePath, importDecl->inner->getLine(), importDecl->inner->getColumn()});
3836
3837 builder.setReturnType(managedPtr(parseTypeSpec(importDecl->inner->resultType)));
3838 for (auto &arg : importDecl->inner->args->get()) {
3839 auto argType = managedPtr(parseTypeSpec(&arg->getSpec()));
3840 builder.addArgument(arg->getId().get().strVal, argType);
3841 }
3842 builder.setName(funcName);
3843 auto importedFunc = builder.yield();
3844 auto importedIndex = moduleContext->getCompilerContext()->getIRFFITable()->addImportedFunction(from, funcName, importedFunc);
3845
3846 // add to extern table
3847 irModule->externTable.put_create(
3848 funcName,
3849 managedPtr(IRExternEntry{IRExternEntry::externType::importedFunction,
3850 funcName,
3851 moduleContext->getCompilerContext()->getIRFFITable()->importedLibraries.getIndex(from),
3852 importedIndex}));
3853
3855 }
3856
3857 void visitor::tryCastTo(const std::shared_ptr<IRValueType> &toType) {
3859 if (rhs->isForeignBasicType()) {
3860 rhs = managedPtr(rhs->getNormalizedForeignBasicType());
3861 }
3862
3863 if (*rhs == *toType) {
3864 return;
3865 } else if (rhs->type == IRValueType::valueType::pointerObject || rhs->type == IRValueType::valueType::pointer ||
3866 rhs->type == IRValueType::valueType::null || toType->type == IRValueType::valueType::pointerObject ||
3867 toType->type == IRValueType::valueType::pointer) {
3868 // no cast needed for pointer type
3869 return;
3870 } else if (rhs->isBasicType() && toType->isBasicType() && !rhs->isDynamicArrayType() && !toType->isDynamicArrayType() &&
3871 !rhs->isArrayType() && !toType->isArrayType() &&
3872 (rhs->type != IRValueType::valueType::stringObject || toType->type == IRValueType::valueType::pointerObject)) {
3873 emitBasicCastTo(toType);
3874 } else if ((toType->isArrayType() || toType->isDynamicArrayType()) && rhs->type == IRValueType::valueType::bracedInitalizerList) {
3875 auto elementType = managedPtr(toType->getElementType());
3876 auto elementCount = rhs->bracedTypes.size();
3877 if (toType->isArrayType()) {
3879 moduleContext->getIRBuilder().newArrayOp(elementType, toType->dimensions, elementCount);
3880 } else {
3882 moduleContext->getIRBuilder().newDynamicArrayOp(elementType, elementCount);
3883 }
3884 } else if (toType->type == IRValueType::valueType::interfaceObject && !toType->isArrayType() && !toType->isDynamicArrayType()) {
3885 // check implemented interfaces
3886 try {
3887 auto implName = getInterfaceImplName({toType->typeAffiliateModule, toType->typeIndex}, rhs);
3888 auto implIndex =
3889 moduleContext->getCompilerContext()->getImportedModule(rhs->typeAffiliateModule)->interfaceImplementationTable.getIndex(implName);
3890 // construct interface object
3891 // moduleContext->getIRBuilder().newInterfaceOp(toType->typeIndex, toType->typeAffiliateModule != currentModuleIndex,
3892 // toType->typeAffiliateModule);
3893 moduleContext->getIRBuilder().constructInterfaceImplOp({toType->typeAffiliateModule, toType->typeIndex},
3894 implIndex,
3895 rhs->typeAffiliateModule != currentModuleIndex,
3896 rhs->typeAffiliateModule);
3897 } catch (std::out_of_range &e) {
3900 "Cannot cast type " + yoi::wstring2string((rhs->to_string())) + " to interface " + yoi::wstring2string((toType->to_string())) +
3901 ": no implementation found.");
3902 }
3903 } else if (toType->type == IRValueType::valueType::structObject && !toType->isArrayType() && !toType->isDynamicArrayType()) {
3904 // check whether owns the constructor
3905 auto structType = moduleContext->getCompilerContext()->getImportedModule(toType->typeAffiliateModule)->structTable[toType->typeIndex];
3906 auto result = resolveOverloadExtern(L"constructor", {rhs}, toType->typeAffiliateModule, structType);
3907 if (result.found()) {
3908 if (result.isCastRequired) {
3909 tryCastTo(result.function->argumentTypes.back());
3910 }
3911 moduleContext->getIRBuilder().newStructOp(toType->typeIndex, true, toType->typeAffiliateModule);
3913 result.functionIndex, 2, result.function->returnType, true, toType->typeAffiliateModule);
3914 } else {
3917 "Cannot cast type " + yoi::wstring2string((rhs->to_string())) + " to " + yoi::wstring2string((toType->to_string())) +
3918 ": no viable conversion found.");
3919 }
3920 } else {
3923 "Cannot cast type " + yoi::wstring2string((rhs->to_string())) + " to " + yoi::wstring2string((toType->to_string())) +
3924 ": no viable conversion found.");
3925 }
3926 }
3927
3928 bool visitor::canCastTo(const std::shared_ptr<IRValueType> &fromType, const std::shared_ptr<IRValueType> &toType) {
3929 auto rhs = fromType;
3930 if (fromType->isForeignBasicType()) {
3931 rhs = managedPtr(rhs->getNormalizedForeignBasicType());
3932 }
3933 if (*rhs == *toType) {
3934 return true;
3935 } else if (rhs->isBasicType() && toType->isBasicType() && !rhs->isDynamicArrayType() && !toType->isDynamicArrayType() &&
3936 !rhs->isArrayType() && !toType->isArrayType() && (toType->type != IRValueType::valueType::stringObject) &&
3937 (rhs->type != IRValueType::valueType::stringObject || toType->type == IRValueType::valueType::pointerObject)) {
3938 return true;
3939 } else if ((toType->isArrayType() || toType->isDynamicArrayType()) && fromType->type == IRValueType::valueType::bracedInitalizerList) {
3940 auto e = toType->getElementType();
3941 for (auto &i : fromType->bracedTypes) {
3942 if (i != e) {
3943 return false;
3944 }
3945 }
3946 return true;
3947 } else if (rhs->type == IRValueType::valueType::pointerObject) {
3948 // no cast needed for pointer type
3949 return true;
3950 } else if (toType->type == IRValueType::valueType::interfaceObject && !toType->isArrayType() && !toType->isDynamicArrayType()) {
3951 // check implemented interfaces
3952 try {
3953 auto implName = getInterfaceImplName({toType->typeAffiliateModule, toType->typeIndex}, rhs);
3954 auto implIndex =
3955 moduleContext->getCompilerContext()->getImportedModule(rhs->typeAffiliateModule)->interfaceImplementationTable.getIndex(implName);
3956 return true;
3957 } catch (std::out_of_range &e) {
3958 return false;
3959 }
3960 } else if (toType->type == IRValueType::valueType::structObject && !toType->isArrayType() && !toType->isDynamicArrayType()) {
3961 // check whether owns the constructor
3962 auto structType = moduleContext->getCompilerContext()->getImportedModule(toType->typeAffiliateModule)->structTable[toType->typeIndex];
3963 auto result = resolveOverloadExtern(L"constructor", {rhs}, toType->typeAffiliateModule, structType);
3964 return result.found();
3965 } else {
3966 return false;
3967 }
3968 }
3969
3971 if (typeIdExpression->type) {
3972 auto parsedType = managedPtr(parseTypeSpec(typeIdExpression->type));
3973 moduleContext->getIRBuilder().typeIdOp(parsedType);
3974 } else {
3976 visit(typeIdExpression->expr);
3980 }
3982 }
3983
3985 visit(dynCastExpression->expr);
3987 auto toType = managedPtr(parseTypeSpec(dynCastExpression->type));
3988 yoi_assert(rhs->type == IRValueType::valueType::interfaceObject,
3991 "dynamic cast can only be applied to interface objects to struct objects. Type: " + yoi::wstring2string(rhs->to_string()));
3992
3993 auto &impls =
3994 moduleContext->getCompilerContext()->getImportedModule(rhs->typeAffiliateModule)->interfaceTable[rhs->typeIndex]->implementations;
3995
3996 if (auto it = std::find(impls.begin(), impls.end(), std::make_tuple(toType->type, toType->typeAffiliateModule, toType->typeIndex));
3997 it != impls.end())
3999 else
4002 "Cannot cast type " + yoi::wstring2string((rhs->to_string())) + " to " + yoi::wstring2string((toType->to_string())) +
4003 ": no implementation found.");
4004
4006 }
4007
4008 yoi::indexT visitor::generateNullInterfaceImplementation(const std::shared_ptr<IRValueType> &structType) {
4009 auto nullInterface = std::make_pair(HOSHI_COMPILER_CTX_GLOB_ID_CONST, 0);
4010 auto nullImplName = getInterfaceImplName(nullInterface, structType);
4011 try {
4013 ->getImportedModule(structType->typeAffiliateModule)
4014 ->interfaceImplementationTable.getIndex(nullImplName);
4015 } catch (std::out_of_range &e) {
4017 ->getImportedModule(HOSHI_COMPILER_CTX_GLOB_ID_CONST)
4018 ->interfaceTable[0]
4019 ->implementations.emplace_back(structType->type, structType->typeAffiliateModule, structType->typeIndex);
4020 auto nullImpl = managedPtr(IRInterfaceImplementationDefinition{nullImplName,
4021 {structType->type, structType->typeAffiliateModule, structType->typeIndex},
4023 {},
4024 {}});
4026 ->getImportedModule(structType->typeAffiliateModule)
4027 ->interfaceImplementationTable.put_create(nullImplName, nullImpl);
4028 }
4029 }
4030
4031 std::set<IRFunctionDefinition::FunctionAttrs> visitor::getFunctionAttributes(const yoi::vec<lexer::token> &attrs) {
4032 std::set<IRFunctionDefinition::FunctionAttrs> res;
4033 for (auto &attr : attrs) {
4034 switch (attr.kind) {
4035 case lexer::token::tokenKind::kAlwaysInline:
4036 res.insert(IRFunctionDefinition::FunctionAttrs::AlwaysInline);
4037 break;
4038 case lexer::token::tokenKind::kNoFFI:
4039 res.insert(IRFunctionDefinition::FunctionAttrs::NoFFI);
4040 break;
4041 case lexer::token::tokenKind::kStatic:
4042 res.insert(IRFunctionDefinition::FunctionAttrs::Static);
4043 break;
4044 case lexer::token::tokenKind::kIntrinsic:
4045 res.insert(IRFunctionDefinition::FunctionAttrs::Intrinsic);
4046 break;
4047 case lexer::token::tokenKind::kGenerator:
4048 res.insert(IRFunctionDefinition::FunctionAttrs::Generator);
4049 break;
4050 default:
4051 break;
4052 }
4053 }
4054 return std::move(res);
4055 }
4056
4058 auto baseType = parseTypeSpec(newExpression->type);
4059 for (auto &i : newExpression->args->get()) {
4060 visit(i);
4061 tryCastTo(managedPtr(baseType));
4062 }
4063 if (newExpression->length)
4064 visit(newExpression->length->expr);
4065 else
4066 moduleContext->getIRBuilder().pushOp(IR::Opcode::push_integer,
4067 IROperand{IROperand::operandType::integer, yoi::indexT{newExpression->args->get().size()}});
4070 }
4071
4072 yoi::indexT visitor::isModuleName(identifier *it, yoi::indexT currentModule) const {
4073 std::shared_ptr<yoi::IRModule> target =
4074 currentModule == -1 ? irModule : moduleContext->getCompilerContext()->getImportedModule(currentModule);
4075 if (auto x = target->moduleImports.find(it->node.strVal); x != target->moduleImports.end()) {
4076 return x->second;
4077 } else {
4078 return currentModule;
4079 }
4080 }
4081
4082 IRValueType visitor::parseTypeSpec(yoi::externModuleAccessExpression *emaExpression) {
4083 auto it = emaExpression->getTerms().begin();
4084 yoi::indexT targetModule = -1, lastModule = -1;
4085 while (it + 1 != emaExpression->getTerms().end() && (targetModule = isModuleName((*it)->id, lastModule)) != lastModule) {
4086 it++;
4087 lastModule = targetModule;
4088 }
4089
4090 bool whetherLastTerm = it + 1 == emaExpression->getTerms().end();
4091 if (targetModule == -1 || targetModule == currentModuleIndex)
4092 return parseTypeSpec((*it));
4093 else
4094 return parseTypeSpecExtern((*it), targetModule);
4095 }
4096
4097 bool visitor::OverloadResult::found() const {
4098 return functionIndex != -1;
4099 }
4100
4103 for (auto &arg : args->get()) {
4104 visit(arg);
4105 argTypes.push_back(moduleContext->getIRBuilder().getRhsFromTempVarStack());
4106 }
4107 return argTypes;
4108 }
4109
4110 visitor::OverloadResult visitor::resolveOverloadExtern(const yoi::wstr &baseName,
4111 const yoi::vec<std::shared_ptr<IRValueType>> &argTypes,
4112 yoi::indexT targetModule,
4113 const std::shared_ptr<IRStructDefinition> &structContext) {
4114 OverloadResult result;
4115 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(targetModule);
4116
4117 // Pass 1: Look for an exact, non-variadic match in the target module.
4118 auto exactMangledName = baseName + getFuncUniqueNameStr(argTypes);
4119 yoi::wstr lookupName = structContext ? structContext->name + L"::" + exactMangledName : exactMangledName;
4120
4121 if (targetedModule->functionTable.contains(lookupName)) {
4122 result.functionIndex = targetedModule->functionTable.getIndex(lookupName);
4123 result.function = targetedModule->functionTable[result.functionIndex];
4124 // if (result.function->isVariadic) {
4125 if (std::find(result.function->attrs.begin(), result.function->attrs.end(), IRFunctionDefinition::FunctionAttrs::Variadic) !=
4126 result.function->attrs.end()) {
4127 result.isVariadic = true;
4128 result.fixedArgCount = result.function->argumentTypes.size() - 1;
4129 result.variadicElementType = managedPtr(result.function->argumentTypes.back()->getElementType());
4130 }
4131 return result;
4132 }
4133
4134 // Pass 2: Look for a compatible variadic match in the target module.
4135 auto findVariadicMatch = [&](const yoi::wstr &funcKey, bool skipFirstParam = false) {
4136 auto func = targetedModule->functionTable[funcKey];
4137 const auto &paramTypes = func->argumentTypes;
4138 size_t fixedParamCount = paramTypes.size() - 1 - (skipFirstParam && paramTypes.size() > 1 ? 1 : 0);
4139 if (std::find(func->attrs.begin(), func->attrs.end(), IRFunctionDefinition::FunctionAttrs::Variadic) != func->attrs.end()) {
4140 if (argTypes.size() >= fixedParamCount) {
4141 bool fixedMatch = true;
4142 for (size_t i = 0; i < fixedParamCount; ++i) {
4143 if (!canCastTo(argTypes[i], paramTypes[i + skipFirstParam])) {
4144 fixedMatch = false;
4145 break;
4146 }
4147 }
4148 if (fixedMatch) {
4149 result.functionIndex = targetedModule->functionTable.getIndex(funcKey);
4150 result.isVariadic = true;
4151 result.fixedArgCount = fixedParamCount;
4152 result.variadicElementType = managedPtr(paramTypes.back()->getElementType());
4153 result.function = func;
4154 return true;
4155 }
4156 }
4157 } else {
4158 if (argTypes.size() != fixedParamCount + 1 ||
4159 paramTypes.size() != fixedParamCount + 1 + skipFirstParam) // balance the variadic argument
4160 return false;
4161
4162 for (size_t i = 0; i < fixedParamCount + 1; ++i) {
4163 if (!canCastTo(argTypes[i], paramTypes[i + skipFirstParam])) {
4164 return false;
4165 }
4166 }
4167
4168 result.functionIndex = targetedModule->functionTable.getIndex(funcKey);
4169 result.isVariadic = false;
4170 result.fixedArgCount = fixedParamCount;
4171 result.function = func;
4172 result.isCastRequired = true;
4173
4174 return true;
4175 }
4176 return false;
4177 };
4178
4179 yoi::wstr prefix = structContext ? structContext->name + L"::" + baseName : baseName;
4180 for (const auto it : targetedModule->functionOverloadIndexies[prefix]) {
4181 const auto &key = targetedModule->functionTable.getKey(it);
4182 if (key.starts_with(prefix)) {
4183 if (findVariadicMatch(key,
4184 structContext != nullptr &&
4185 !targetedModule->functionTable[it]->hasAttribute(IRFunctionDefinition::FunctionAttrs::Static)))
4186 return result;
4187 }
4188 }
4189
4190 if (!structContext && targetedModule->funcTemplateAsts.contains(baseName)) {
4191 try {
4192 auto astNode = targetedModule->funcTemplateAsts.at(baseName);
4193 auto templateArgs = getTemplateArgs(astNode->id->getArg());
4194
4195 yoi::vec<std::shared_ptr<IRValueType>> deducedArgs(templateArgs.size());
4196
4197 for (yoi::indexT i = 0; i < argTypes.size(); i++) {
4198 if (i < templateArgs.size() && templateArgs[i].templateType->type == IRValueType::valueType::incompleteTemplateType) {
4199 auto &srcTypeToPlace = argTypes[i];
4200 auto incompleteTypeIndex = templateArgs[i].templateType->typeIndex;
4201 if (deducedArgs[incompleteTypeIndex] && *deducedArgs[incompleteTypeIndex] != *srcTypeToPlace) {
4202 throw std::runtime_error("Template argument type mismatch during deduction.");
4203 }
4204 deducedArgs[incompleteTypeIndex] = srcTypeToPlace;
4205 }
4206 }
4207 for (yoi::indexT i = 0; i < deducedArgs.size(); i++) {
4208 if (deducedArgs[i] == nullptr) {
4209 throw std::runtime_error("Cannot deduce all template arguments for: " + yoi::wstring2string(baseName));
4210 }
4211 }
4212
4213 auto specializedFuncIndex = specializeFunctionTemplate(astNode, deducedArgs, targetModule);
4214 result.functionIndex = specializedFuncIndex;
4215 result.function = targetedModule->functionTable[specializedFuncIndex];
4216
4217 // The newly specialized function might itself be variadic
4218 if (std::find(result.function->attrs.begin(), result.function->attrs.end(), IRFunctionDefinition::FunctionAttrs::Variadic) !=
4219 result.function->attrs.end()) {
4220 result.isVariadic = true;
4221 result.fixedArgCount = result.function->argumentTypes.size() - 1;
4222 result.variadicElementType = managedPtr(result.function->argumentTypes.back()->getElementType());
4223 }
4224 return result;
4225 } catch (const std::out_of_range &) {
4226 result.functionIndex = -1;
4227 }
4228 }
4229
4230 return result; // Not found
4231 }
4232
4233 bool visitor::handleInvocationExtern(const yoi::wstr &baseName,
4235 yoi::indexT targetModule,
4236 const std::shared_ptr<IRValueType> &structContext,
4237 bool noThisCall,
4238 yoi::templateArg *templateArgs) {
4240 auto argTypes = evaluateArguments(args);
4241 OverloadResult overload;
4242 if (structContext && structContext->type == IRValueType::valueType::structObject) {
4243 auto structType =
4244 moduleContext->getCompilerContext()->getImportedModule(structContext->typeAffiliateModule)->structTable[structContext->typeIndex];
4245 overload = resolveOverloadExtern(baseName, argTypes, targetModule, structType);
4246
4247 if (!overload.found()) {
4248 // Check if it's a template method
4249 if (structType->templateMethodDecls.contains(baseName) || structType->templateMethodDefs.contains(baseName)) {
4251 structType->templateMethodDecls.contains(baseName) ? structType->templateMethodDecls.at(baseName) : nullptr;
4252 yoi::implInnerPair *def =
4253 structType->templateMethodDefs.contains(baseName) ? structType->templateMethodDefs.at(baseName) : nullptr;
4254
4255 yoi::vec<std::shared_ptr<IRValueType>> concreteMethodTemplateArgs;
4256 if (templateArgs) {
4257 // full specialization, if provided
4258 concreteMethodTemplateArgs = parseTemplateArgs(*templateArgs);
4259 } else {
4260 // automatically deduce the template arguments based on the arguments
4261 yoi::vec<yoi::wstr> methodTemplateParams;
4262 if (decl)
4263 methodTemplateParams = extractTemplateParamsFromTypeArgs(&decl->getMethod().getName().getArg());
4264 else if (def)
4265 methodTemplateParams = extractTemplateParamsFromTypeArgs(&def->getMethod().getName().getArg());
4266
4267 concreteMethodTemplateArgs.resize(methodTemplateParams.size());
4268 auto &astArgs = decl ? decl->getMethod().getArgs().get() : def->getMethod().getArgs().get();
4269 for (size_t i = 0; i < astArgs.size() && i < argTypes.size(); ++i) {
4270 auto &spec = *astArgs[i]->spec;
4271 if (spec.kind == typeSpec::typeSpecKind::Member && spec.member && spec.member->getTerms().size() == 1) {
4272 auto term = spec.member->getTerms()[0];
4273 yoi::wstr typeName = term->id->get().strVal;
4274 for (size_t j = 0; j < methodTemplateParams.size(); ++j) {
4275 if (methodTemplateParams[j] == typeName) {
4276 concreteMethodTemplateArgs[j] = argTypes[i];
4277 break;
4278 }
4279 }
4280 }
4281 }
4282 }
4283
4284 bool allDeduced = true;
4285 for (auto &arg : concreteMethodTemplateArgs) {
4286 if (!arg) {
4287 allDeduced = false;
4288 break;
4289 }
4290 }
4291
4292 if (allDeduced && !concreteMethodTemplateArgs.empty()) {
4293 // if all deduced, we can use this to invoke the target
4294 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(targetModule);
4295 auto specializedFuncIndex =
4296 specializeStructMethodTemplate(structType, decl, def, baseName, concreteMethodTemplateArgs, targetModule);
4297 overload.functionIndex = specializedFuncIndex;
4298 overload.function = targetedModule->functionTable[specializedFuncIndex];
4299 }
4300 }
4301 }
4302 } else if (structContext && structContext->type == IRValueType::valueType::interfaceObject) {
4303 auto interfaceType =
4304 moduleContext->getCompilerContext()->getImportedModule(structContext->typeAffiliateModule)->interfaceTable[structContext->typeIndex];
4305 overload = resolveOverloadInterface(baseName, argTypes, targetModule, interfaceType);
4306 } else {
4307 overload = resolveOverloadExtern(baseName, argTypes, targetModule, nullptr);
4308 }
4309
4310 if (!overload.found()) {
4312 return false;
4313 }
4314
4315 auto fullMangledName = overload.function->name;
4316 bool skipFirstParam = structContext != nullptr && !noThisCall && structContext->type != IRValueType::valueType::interfaceObject;
4317
4318 if (overload.isVariadic) {
4320 for (size_t i = 0; i < overload.fixedArgCount; ++i) {
4321 visit(args->get()[i]);
4322 tryCastTo(overload.function->argumentTypes[i + skipFirstParam]);
4323 }
4324 auto variadicArgCount = argTypes.size() - overload.fixedArgCount;
4325 if (variadicArgCount > 0) {
4326 for (size_t i = 0; i < variadicArgCount; ++i) {
4327 visit(args->get()[i + overload.fixedArgCount]);
4328 tryCastTo(overload.variadicElementType);
4329 }
4331 overload.variadicElementType, {static_cast<yoi::indexT>(variadicArgCount)}, variadicArgCount);
4332 } else {
4334 }
4335 } else if (overload.isCastRequired) {
4337 for (size_t i = 0; i < overload.fixedArgCount + 1; ++i) { // balanced for interface
4338 visit(args->get()[i]);
4339 tryCastTo(overload.function->argumentTypes[i + skipFirstParam]);
4340 }
4341 } else {
4343 }
4344
4345 size_t finalParamCount = overload.function->argumentTypes.size();
4346 if (structContext && structContext->type == IRValueType::valueType::structObject) {
4347 IRExternEntry externEntry = getExternEntry(targetModule, fullMangledName);
4348 auto isStaticMethod =
4349 std::find(overload.function->attrs.begin(), overload.function->attrs.end(), IRFunctionDefinition::FunctionAttrs::Static) !=
4350 overload.function->attrs.end();
4351 bool usePureStaticLogic = noThisCall && isStaticMethod;
4352
4353 if (usePureStaticLogic) {
4355 externEntry.itemIndex, finalParamCount, overload.function->returnType, true, externEntry.affiliateModule);
4356 } else {
4358 finalParamCount - !isStaticMethod,
4359 overload.function->returnType,
4360 isStaticMethod,
4361 true,
4362 externEntry.affiliateModule);
4363 }
4364 } else if (structContext && structContext->type == IRValueType::valueType::interfaceObject) {
4366 structContext->typeIndex,
4367 finalParamCount,
4368 overload.function->returnType,
4369 true,
4370 structContext->typeAffiliateModule);
4371 } else {
4372 auto externEntry = getExternEntry(targetModule, fullMangledName);
4374 externEntry.itemIndex, finalParamCount, overload.function->returnType, true, externEntry.affiliateModule);
4375 }
4376 return true;
4377 }
4378
4379 template <typename T> yoi::indexT visitor::handleBinaryOperatorOverload(const yoi::wstr &overloadName, T *rhsAST) {
4382 bool isResolved = false;
4383
4384 if (lhs->type == IRValueType::valueType::structObject) {
4385 auto resolved =
4386 resolveOverloadExtern(overloadName,
4387 {lhs, rhs},
4388 lhs->typeAffiliateModule,
4389 moduleContext->getCompilerContext()->getImportedModule(lhs->typeAffiliateModule)->structTable[lhs->typeIndex]);
4390 if (resolved.found()) {
4391 yoi_assert(resolved.isVariadic == false, 0, 0, "Binary operator overloading with variadic functions is not supported.");
4392 yoi_assert(std::find(resolved.function->attrs.begin(), resolved.function->attrs.end(), IRFunctionDefinition::FunctionAttrs::Static) !=
4393 resolved.function->attrs.end(),
4396 "Binary operator overloading with non-static functions is not supported.");
4397
4398 if (resolved.isCastRequired) {
4400 tryCastTo(resolved.function->argumentTypes.front());
4401 visit(rhsAST);
4402 tryCastTo(resolved.function->argumentTypes.back());
4403 } else {
4405 }
4406
4407 // same as below
4409 resolved.functionIndex, 1, resolved.function->returnType, false, true, lhs->typeAffiliateModule);
4410 isResolved = true;
4411 }
4412 }
4413 if (!isResolved && rhs->type == IRValueType::valueType::structObject) {
4414 auto resolved =
4415 resolveOverloadExtern(overloadName,
4416 {lhs, rhs},
4417 rhs->typeAffiliateModule,
4418 moduleContext->getCompilerContext()->getImportedModule(rhs->typeAffiliateModule)->structTable[rhs->typeIndex]);
4419 if (resolved.found()) {
4420 yoi_assert(resolved.isVariadic == false,
4423 "Binary operator overloading with variadic functions is not supported.");
4424 yoi_assert(std::find(resolved.function->attrs.begin(), resolved.function->attrs.end(), IRFunctionDefinition::FunctionAttrs::Static) !=
4425 resolved.function->attrs.end(),
4428 "Binary operator overloading with non-static functions is not supported.");
4429
4430 if (resolved.isCastRequired) {
4432 tryCastTo(resolved.function->argumentTypes.front());
4433 visit(rhsAST);
4434 tryCastTo(resolved.function->argumentTypes.back());
4435 } else {
4437 }
4438
4439 // trick here: since when we set isStatic to true, we need 3 elements on the stack, which this ptr should also be present.
4440 // however, we only have 2 elements on the stack which is lhs and rhs, so, we set isStatic to false here.
4441 // to trick the invoke method op into generating the correct code
4442 // this way, this method would take two elements from the stack and push the result to the stack.
4444 resolved.functionIndex, 1, resolved.function->returnType, false, true, rhs->typeAffiliateModule);
4445 isResolved = true;
4446 }
4447 }
4448
4449 if (!isResolved && lhs->type == IRValueType::valueType::interfaceObject) {
4450 const auto &baseName = overloadName;
4451 auto mangledName = getFuncUniqueNameStr({rhs});
4452
4453 auto resolved = resolveOverloadInterface(
4454 baseName,
4455 {lhs, rhs},
4456 lhs->typeAffiliateModule,
4457 moduleContext->getCompilerContext()->getImportedModule(lhs->typeAffiliateModule)->interfaceTable[lhs->typeIndex]);
4458
4459 if (resolved.found()) {
4460 if (resolved.isCastRequired) {
4462 tryCastTo(resolved.function->argumentTypes.front());
4463 visit(rhsAST);
4464 tryCastTo(resolved.function->argumentTypes.back());
4465 } else {
4467 }
4468
4470 resolved.functionIndex, lhs->typeIndex, 1, resolved.function->returnType, true, lhs->typeAffiliateModule);
4471 isResolved = true;
4472 }
4473 }
4474
4475 if (!isResolved) {
4477 }
4478
4479 yoi_assert(isResolved,
4482 "Binary operator overloading not found for " + yoi::wstring2string(overloadName));
4483
4485 }
4486
4487 yoi::indexT visitor::handleUnaryOperatorOverload(const yoi::wstr &overloadName) {
4489 bool isResolved = false;
4490
4491 if (rhs->type == IRValueType::valueType::structObject) {
4492 auto resolved =
4493 resolveOverloadExtern(overloadName,
4494 {rhs},
4495 rhs->typeAffiliateModule,
4496 moduleContext->getCompilerContext()->getImportedModule(rhs->typeAffiliateModule)->structTable[rhs->typeIndex]);
4497 if (resolved.found()) {
4498 yoi_assert(resolved.isVariadic == false,
4501 "Unary operator overloading with variadic functions is not supported.");
4502 yoi_assert(std::find(resolved.function->attrs.begin(), resolved.function->attrs.end(), IRFunctionDefinition::FunctionAttrs::Static) !=
4503 resolved.function->attrs.end(),
4506 "Unary operator overloading with non-static functions is not supported.");
4507 // why isStatic = false? check the comment in handleBinaryOperatorOverload
4509 resolved.functionIndex, 0, resolved.function->returnType, false, true, rhs->typeAffiliateModule);
4510 isResolved = true;
4511 }
4512 }
4513 if (rhs->type == IRValueType::valueType::interfaceObject) {
4514 const auto &baseName = overloadName;
4515 auto mangledName = getFuncUniqueNameStr({});
4516
4517 auto methodIdx = moduleContext->getCompilerContext()
4518 ->getImportedModule(rhs->typeAffiliateModule)
4519 ->interfaceTable[rhs->typeIndex]
4520 ->methodMap.getIndex(baseName + mangledName);
4521 auto method = moduleContext->getCompilerContext()
4522 ->getImportedModule(rhs->typeAffiliateModule)
4523 ->interfaceTable[rhs->typeIndex]
4524 ->methodMap[methodIdx];
4525 yoi_assert(method->argumentTypes.size() == 1,
4528 "Argument count does not match");
4529 moduleContext->getIRBuilder().invokeVirtualOp(methodIdx, rhs->typeIndex, 0, method->returnType, true, rhs->typeAffiliateModule);
4530 isResolved = true;
4531 }
4532 yoi_assert(isResolved,
4535 "Unary operator overloading not found for " + yoi::wstring2string(overloadName));
4536
4538 }
4539
4540 yoi::indexT visitor::specializeInterfaceTemplate(const yoi::wstr &templateName,
4541 const yoi::vec<std::shared_ptr<IRValueType>> &concreteTemplateArgs,
4542 yoi::indexT moduleIndex) {
4543 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(moduleIndex);
4544 yoi::wstr specializedName = getMangledTemplateName(templateName, concreteTemplateArgs);
4545 if (targetedModule->interfaceTable.contains(specializedName)) {
4546 return targetedModule->interfaceTable.getIndex(specializedName);
4547 }
4548
4549 yoi_assert(targetedModule->templateInterfaceAsts.contains(templateName), 0, 0, "Unknown interface template: " + wstring2string(templateName));
4550
4551 auto interfaceAst = targetedModule->templateInterfaceAsts.at(templateName);
4552
4553 IRTemplateBuilder specializationContext;
4554 yoi_assert(concreteTemplateArgs.size() == interfaceAst->id->arg->get().size(),
4555 0,
4556 0,
4557 "Template argument count mismatch for interface " + wstring2string(templateName));
4558 for (yoi::indexT i = 0; i < concreteTemplateArgs.size(); ++i) {
4559 auto paramName = interfaceAst->id->arg->get()[i]->getId().get().strVal;
4560 specializationContext.addTemplateArgument(paramName, concreteTemplateArgs[i]);
4561 }
4562
4563 pushModuleContext(moduleIndex);
4564 moduleContext->pushTemplateBuilder(specializationContext);
4565
4567 builder.setName(specializedName);
4568
4569 for (auto &i : interfaceAst->getInner().getInner()) {
4570 bool isVaridic = false;
4571 yoi_assert(i->isMethod(), i->getLine(), i->getColumn(), "Interface member must be a method");
4572 auto methodName = i->getMethod().getName().getId().get().strVal;
4573 auto methodResultType = managedPtr(parseTypeSpec(i->getMethod().resultType));
4575 IRFunctionDefinition::Builder methodBuilder;
4576 methodBuilder.setDebugInfo({irModule->modulePath, i->getLine(), i->getColumn()});
4577 methodBuilder.setReturnType(methodResultType);
4578 for (auto &arg : i->getMethod().getArgs().get()) {
4579 if (&arg == &i->getMethod().getArgs().get().back() && arg->spec->kind == typeSpec::typeSpecKind::Elipsis) {
4580 isVaridic = true;
4581 methodBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Variadic);
4582 auto argName = arg->getId().node.strVal;
4583 auto argType =
4584 managedPtr(arg->spec->elipsis ? parseTypeSpec(arg->spec->elipsis).getDynamicArrayType()
4585 : moduleContext->getCompilerContext()->getNullInterfaceType()->getDynamicArrayType());
4586 methodBuilder.addArgument(argName, argType);
4587 argTypes.push_back(argType);
4588 break;
4589 }
4590 auto argName = arg->getId().get().strVal;
4591 auto argType = managedPtr(parseTypeSpec(arg->spec));
4592 methodBuilder.addArgument(argName, argType);
4593 argTypes.push_back(argType);
4594 }
4595 auto uniq = getFuncUniqueNameStr(argTypes);
4596 methodBuilder.setName(L"interface#" + specializedName + L"#" + methodName + uniq);
4597 builder.addMethod(methodName, methodName + uniq, methodBuilder.yield());
4598 }
4599
4600 auto specializedInterface = builder.yield();
4601 auto interfaceIndex = irModule->interfaceTable.put_create(
4602 specializedName, specializedInterface); // since module context is still in foreign module, no need to change to targetedModule
4603
4605 popModuleContext();
4606 return interfaceIndex;
4607 }
4608
4609 void visitor::specializeInterfaceImplementation(yoi::implStmt *implAst,
4610 const std::shared_ptr<IRValueType> &concreteStructType,
4611 const yoi::wstr &specializedStructName,
4612 const yoi::vec<std::shared_ptr<IRValueType>> &concreteTemplateArgs,
4613 yoi::indexT targetModule) {
4614
4615 yoi_assert(implAst->isImplForStmt(),
4616 implAst->getLine(),
4617 implAst->getColumn(),
4618 "Expected 'impl for' AST node for interface implementation specialization.");
4619
4620 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(targetModule);
4621
4622 // The active specialization context (from specializeStructTemplate) resolves types like `T` to concrete types.
4623 auto concreteInterfaceType = managedPtr(parseTypeSpec(implAst->interfaceName));
4624 yoi_assert(concreteInterfaceType->type == IRValueType::valueType::interfaceObject,
4625 implAst->getLine(),
4626 implAst->getColumn(),
4627 "Expected an interface type.");
4628
4629 // pushModuleContext(targetModule);
4630
4631 auto interfaceSrcPair = std::make_pair(concreteInterfaceType->typeAffiliateModule, concreteInterfaceType->typeIndex);
4632
4633 auto targetInterface =
4634 moduleContext->getCompilerContext()->getImportedModule(interfaceSrcPair.first)->interfaceTable[interfaceSrcPair.second];
4635
4636 targetInterface->implementations.emplace_back(
4637 concreteStructType->type, concreteStructType->typeAffiliateModule, concreteStructType->typeIndex);
4638
4639 auto implName = getInterfaceImplName(interfaceSrcPair, concreteStructType);
4640 if (irModule->interfaceImplementationTable.contains(implName)) {
4641 return; // Already specialized and created.
4642 }
4643
4644 yoi::indexT implIndex{};
4645 try {
4646 implIndex = targetedModule->interfaceImplementationTable.getIndex(implName);
4647 if (targetedModule->interfaceImplementationTable[implIndex]) {
4648 panic(implAst->getLine(), implAst->getColumn(), "Redefinition of interface implementation: " + yoi::wstring2string(implName));
4649 }
4650 } catch (std::out_of_range &e) {
4651 implIndex = targetedModule->interfaceImplementationTable.put_create(implName, nullptr);
4652 }
4653
4654 if (implAst->inner) {
4656 builder.setName(implName);
4657 builder.setImplStructIndex({concreteStructType->type, concreteStructType->typeAffiliateModule, concreteStructType->typeIndex});
4658 builder.setImplInterfaceIndex(interfaceSrcPair);
4659
4660 std::map<yoi::wstr, std::pair<yoi::wstr, std::shared_ptr<IRValueType>>> virtualMethodMap;
4661
4662 for (auto &methodNode : implAst->getInner().getInner()) {
4663 yoi_assert(!methodNode->isConstructor(),
4664 methodNode->getLine(),
4665 methodNode->getColumn(),
4666 "Only methods are allowed in interface implementations.");
4667 auto &methodAst = methodNode->getMethod();
4668
4669 IRFunctionDefinition::Builder methodBuilder;
4670 methodBuilder.setDebugInfo({irModule->modulePath, methodAst.getLine(), methodAst.getColumn()});
4671 methodBuilder.attrs = getFunctionAttributes(methodAst.attrs);
4672 methodBuilder.attrs.insert(IRFunctionDefinition::FunctionAttrs::Preserve);
4673
4674 yoi::vec<std::shared_ptr<IRValueType>> specializedArgTypes;
4675
4676 if (std::find(methodBuilder.attrs.begin(), methodBuilder.attrs.end(), IRFunctionDefinition::FunctionAttrs::Static) ==
4677 methodBuilder.attrs.end()) {
4678 methodBuilder.addArgument(L"this", concreteStructType);
4679 }
4680
4681 for (auto &arg : methodAst.getArgs().get()) {
4682 auto specializedArgType = managedPtr(parseTypeSpec(arg->spec));
4683 methodBuilder.addArgument(arg->getId().get().strVal, specializedArgType);
4684 specializedArgTypes.push_back(specializedArgType);
4685 }
4686
4687 auto uniq = getFuncUniqueNameStr(specializedArgTypes);
4688 auto baseMethodName = methodAst.getName().getId().get().strVal;
4689
4690 methodBuilder.setReturnType(managedPtr(parseTypeSpec(methodAst.resultType)));
4691 methodBuilder.setName(specializedStructName + L"::" + baseMethodName + uniq);
4692
4693 auto func = methodBuilder.yield();
4694 auto funcIndex = irModule->functionTable.put_create(func->name, func);
4695 irModule->functionOverloadIndexies[specializedStructName + L"::" + baseMethodName].emplace_back(funcIndex);
4696
4698 moduleContext->getIRBuilder().setDebugInfo({irModule->modulePath, methodAst.getLine(), methodAst.getColumn()});
4700 visit(methodAst.block, true);
4703 virtualMethodMap[baseMethodName + getFuncUniqueNameStr(specializedArgTypes, true)] = {
4704 baseMethodName + uniq, managedPtr(IRValueType{IRValueType::valueType::virtualMethod, currentModuleIndex, funcIndex})};
4705 }
4706 for (auto &method : targetInterface->methodMap) {
4707 yoi_assert(virtualMethodMap.contains(method.first),
4708 implAst->getLine(),
4709 implAst->getColumn(),
4710 "Interface method not found in implementation: " + wstring2string(method.first));
4711 builder.addVirtualMethod(virtualMethodMap[method.first].first, virtualMethodMap[method.first].second);
4712 }
4713
4714 // popModuleContext();
4715
4716 targetedModule->interfaceImplementationTable[implIndex] = builder.yield();
4717 } else {
4718 // forward-declaration
4719 }
4720 }
4721
4722 visitor::OverloadResult visitor::resolveOverloadInterface(const yoi::wstr &baseName,
4723 const yoi::vec<std::shared_ptr<IRValueType>> &argTypes,
4724 yoi::indexT targetModule,
4725 const std::shared_ptr<IRInterfaceInstanceDefinition> &interfaceContext) {
4726 OverloadResult result;
4727 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(targetModule);
4728
4729 auto exactMangledName = baseName + getFuncUniqueNameStr(argTypes);
4730
4731 if (interfaceContext->methodMap.contains(exactMangledName)) {
4732 result.isVirtual = true;
4733 result.functionIndex = interfaceContext->methodMap.getIndex(exactMangledName);
4734 result.function = interfaceContext->methodMap[result.functionIndex];
4735 if (std::find(result.function->attrs.begin(), result.function->attrs.end(), IRFunctionDefinition::FunctionAttrs::Variadic) !=
4736 result.function->attrs.end()) {
4737 result.isVariadic = true;
4738 result.fixedArgCount = result.function->argumentTypes.size() - 1;
4739 result.variadicElementType = managedPtr(result.function->argumentTypes.back()->getElementType());
4740 }
4741 return result;
4742 }
4743
4744 auto findVariadicMatch = [&](const yoi::wstr &funcKey) {
4745 auto func = interfaceContext->methodMap[funcKey];
4746 const auto &paramTypes = func->argumentTypes;
4747 size_t fixedParamCount = paramTypes.size() - 1;
4748 if (std::find(func->attrs.begin(), func->attrs.end(), IRFunctionDefinition::FunctionAttrs::Variadic) != func->attrs.end()) {
4749 if (argTypes.size() >= fixedParamCount) {
4750 bool fixedMatch = true;
4751 for (size_t i = 0; i < fixedParamCount; ++i) {
4752 if (*paramTypes[i] != *argTypes[i]) {
4753 fixedMatch = false;
4754 break;
4755 }
4756 }
4757 if (fixedMatch) {
4758 result.functionIndex = interfaceContext->methodMap.getIndex(funcKey);
4759 result.isVariadic = true;
4760 result.isVirtual = true;
4761 result.fixedArgCount = fixedParamCount;
4762 result.variadicElementType = managedPtr(paramTypes.back()->getElementType());
4763 result.function = func;
4764 return true;
4765 }
4766 }
4767 } else {
4768 if (argTypes.size() != fixedParamCount + 1) // balance the variadic argument
4769 return false;
4770
4771 for (size_t i = 0; i < fixedParamCount; ++i) {
4772 if (!canCastTo(argTypes[i], paramTypes[i])) {
4773 return false;
4774 }
4775 }
4776
4777 result.functionIndex = interfaceContext->methodMap.getIndex(funcKey);
4778 result.isVariadic = false;
4779 result.fixedArgCount = fixedParamCount;
4780 result.function = func;
4781 result.isCastRequired = true;
4782
4783 return true;
4784 }
4785 return false;
4786 };
4787
4788 // if not even a single overload exists, return an empty result
4789 if (!interfaceContext->functionOverloadIndexies.contains(baseName))
4790 return result;
4791
4792 for (const auto &it : interfaceContext->functionOverloadIndexies[baseName]) {
4793 if (findVariadicMatch(interfaceContext->methodMap.getKey(it)))
4794 return result;
4795 }
4796
4797 return result; // Not found
4798 }
4799
4800 void visitor::pushModuleContext(yoi::indexT moduleIndex) {
4801 // printf("push module context\n");
4802 moduleContextStack.emplace(moduleContext, currentModuleIndex);
4803 this->moduleContext = moduleContext->getCompilerContext()->getModuleContext(moduleIndex);
4804 this->irModule = moduleContext->getCompilerContext()->getImportedModule(moduleIndex);
4805 currentModuleIndex = moduleIndex;
4806 }
4807
4808 void visitor::popModuleContext() {
4809 // printf("pop module context\n");
4810 this->moduleContext = moduleContextStack.top().first;
4811 currentModuleIndex = moduleContextStack.top().second;
4812 this->irModule = moduleContext->getCompilerContext()->getImportedModule(currentModuleIndex);
4813 moduleContextStack.pop();
4814 }
4815
4816 bool
4817 visitor::handleSubscript(yoi::vec<yoi::subscript *>::iterator &it, yoi::vec<yoi::subscript *>::iterator end, bool isStoreOp, bool isLastTerm) {
4818 auto objectOnStackType = moduleContext->getIRBuilder().getRhsFromTempVarStack();
4819
4820 auto currentTerm = *it;
4821
4822 if (objectOnStackType->isArrayType() || objectOnStackType->isDynamicArrayType()) {
4823 const auto &dimensions = objectOnStackType->dimensions;
4824 yoi::vec<yoi::indexT> strides(dimensions.size());
4825 strides.back() = 1;
4826 for (long long i = static_cast<long long>(dimensions.size()) - 2; i >= 0; --i) {
4827 strides[i] = strides[i + 1] * dimensions[i + 1];
4828 }
4829
4830 moduleContext->getIRBuilder().pushOp(IR::Opcode::push_unsigned,
4831 {IROperand::operandType::unsignedInt, IROperand::operandValue{static_cast<int64_t>(0)}});
4832
4833 yoi::indexT currentDim = 0;
4834 while (it != end && (*it)->isSubscript()) {
4835 yoi_assert(currentDim < dimensions.size(), (*it)->getLine(), (*it)->getColumn(), "Too many indices for array dimension.");
4836 visit((*it)->expr);
4837 tryCastTo(moduleContext->getCompilerContext()->getUnsignedObjectType());
4838 yoi_assert(moduleContext->getIRBuilder().getRhsFromTempVarStack()->type == IRValueType::valueType::unsignedObject,
4839 (*it)->getLine(),
4840 (*it)->getColumn(),
4841 "Array subscript index must be an integer or unsigned integer.");
4842 moduleContext->getIRBuilder().pushOp(IR::Opcode::push_unsigned, {IROperand::operandType::unsignedInt, strides[currentDim]});
4843 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::mul);
4844 moduleContext->getIRBuilder().arithmeticOp(IR::Opcode::add);
4845 it++;
4846 currentDim++;
4847 }
4848
4849 yoi_assert(currentDim == dimensions.size() || (isStoreOp && isLastTerm),
4850 currentTerm->getLine(),
4851 currentTerm->getColumn(),
4852 "Partial array access is not a loadable value. Not enough indices provided.");
4853
4854 if (isStoreOp && isLastTerm) {
4855 moduleContext->getIRBuilder().storeOp(IR::Opcode::store_element, {});
4856 return false;
4857 } else {
4858 auto elementType = managedPtr(objectOnStackType->getElementType());
4859 moduleContext->getIRBuilder().loadOp(IR::Opcode::load_element, {}, elementType);
4860 return true;
4861 }
4862 } else {
4863 if (isLastTerm && isStoreOp) {
4864 // current stack: [..., value, array, index]
4865
4868 visit(currentTerm->expr);
4870
4871 OverloadResult overload;
4872 if (array->type == IRValueType::valueType::structObject)
4873 overload = resolveOverloadExtern(
4874 L"operator[]",
4875 {value, array, index},
4876 array->typeAffiliateModule,
4877 moduleContext->getCompilerContext()->getImportedModule(array->typeAffiliateModule)->structTable[array->typeIndex]);
4878
4879 yoi_assert(overload.found(), currentTerm->getLine(), currentTerm->getColumn(), "No matching overload found for operator[].");
4880 yoi_assert(
4881 !overload.isVariadic, currentTerm->getLine(), currentTerm->getColumn(), "Variadic operator[] overloading is not supported.");
4882
4883 // FIXED: 前面value已经被运算了而且没有保存状态,不知道要怎么搞了,除非每次入栈的时候顺便记录一下当前insertion point
4884 if (overload.isCastRequired) {
4885 tryCastTo(overload.function->argumentTypes.back());
4887 tryCastTo(overload.function->argumentTypes.front()); // 天才啊
4888 moduleContext->getIRBuilder().commitState(); // this would commit the state.
4889 } else {
4890 // discard the state if no cast is required
4892 }
4893
4895 overload.functionIndex, 2, overload.function->returnType, false, true, array->typeAffiliateModule);
4896
4898 return false;
4899 } else {
4901 visit(currentTerm->expr);
4902 handleBinaryOperatorOverload(L"operator[]", currentTerm->expr);
4903 return false;
4904 }
4905 }
4906 }
4907
4908 IRValueType visitor::parseTypeSpec(yoi::funcTypeSpec *typeSpec) {
4910 for (auto &arg : typeSpec->args->types) {
4911 argTypes.push_back(managedPtr(parseTypeSpec(arg)));
4912 }
4913 auto returnType = managedPtr(parseTypeSpec(typeSpec->resultType));
4914
4915 return IRValueType{IRValueType::valueType::interfaceObject, HOSHI_COMPILER_CTX_GLOB_ID_CONST, createCallableInterface(argTypes, returnType)};
4916 }
4917
4918 yoi::indexT visitor::createCallableInterface(const yoi::vec<std::shared_ptr<IRValueType>> &parameterTypes,
4919 const std::shared_ptr<IRValueType> &returnType) {
4920 auto callableInterfaceName = L"callable" + getFuncUniqueNameStr(parameterTypes);
4921 callableInterfaceName += getTypeSpecUniqueNameStr(returnType);
4923 ->getImportedModule(HOSHI_COMPILER_CTX_GLOB_ID_CONST)
4924 ->interfaceTable.contains(callableInterfaceName)) {
4926 ->getImportedModule(HOSHI_COMPILER_CTX_GLOB_ID_CONST)
4927 ->interfaceTable.getIndex(callableInterfaceName);
4928 }
4929
4930 auto interfaceIndex = moduleContext->getCompilerContext()
4931 ->getImportedModule(HOSHI_COMPILER_CTX_GLOB_ID_CONST)
4932 ->interfaceTable.put_create(callableInterfaceName, {});
4933
4935 for (auto &arg : parameterTypes) {
4936 argTypes.emplace_back(L"arg", arg);
4937 }
4939 builder.setName(callableInterfaceName);
4940 builder.addMethod(L"operator()",
4941 L"operator()" + getFuncUniqueNameStr(parameterTypes),
4942 managedPtr(IRFunctionDefinition{L"operator()" + getFuncUniqueNameStr(parameterTypes), argTypes, returnType, {}, {}, {}}));
4943
4944 moduleContext->getCompilerContext()->getImportedModule(HOSHI_COMPILER_CTX_GLOB_ID_CONST)->interfaceTable[interfaceIndex] = builder.yield();
4945
4946 return interfaceIndex;
4947 }
4948
4949 yoi::indexT visitor::createLambdaUnnamedStruct(yoi::lambdaExpr *lambdaExpr) {
4950 auto structName = L"lambda" + std::to_wstring(lambdaExpr->getLine()) + L"_" + std::to_wstring(lambdaExpr->getColumn());
4951
4952 if (irModule->structTable.contains(structName)) {
4953 // when triggering re-evaluation due to cast required, we may already have the struct in the table, a quick fix for that.
4954 // but our tempVarStack rolled back, re-evaluate it then
4955 auto index = irModule->structTable.getIndex(structName);
4956 auto structType = managedPtr(IRValueType{IRValueType::valueType::structObject, currentModuleIndex, index});
4959 for (auto &i : lambdaExpr->captures) {
4960 visit(i->identifier);
4962 switch (i->attr) {
4963 case structDefInnerPair::Modifier::DataField:
4964 // capture by value
4965 argTypes.back()->addAttribute(IRValueType::ValueAttr::Raw);
4966 case structDefInnerPair::Modifier::Weak:
4967 // nothing
4968 break;
4969 case structDefInnerPair::Modifier::None:
4970 break;
4971 }
4972 }
4973 auto funcName = structName + L"::constructor" + getFuncUniqueNameStr(argTypes);
4975 irModule->functionTable.getIndex(funcName), argTypes.size(), structType, false, true, currentModuleIndex);
4976 return index;
4977 }
4978
4979 auto structIndex = irModule->structTable.put_create(structName, nullptr);
4980
4981 auto structType = managedPtr(IRValueType{IRValueType::valueType::structObject, currentModuleIndex, structIndex});
4982
4984 builder.setName(structName);
4985 // add captured variables as fields
4986 IRFunctionDefinition::Builder callableBuilder;
4988
4989 callableBuilder.setDebugInfo({irModule->modulePath, lambdaExpr->getLine(), lambdaExpr->getColumn()});
4990 callableBuilder.attrs.insert(IRFunctionDefinition::FunctionAttrs::Preserve);
4991 callableBuilder.addArgument(L"this", structType);
4992 for (auto &i : lambdaExpr->args->spec) {
4993 auto argType = managedPtr(parseTypeSpec(i->spec));
4994 callableBuilder.addArgument(i->id->node.strVal, argType);
4995 argTypes.push_back(argType);
4996 }
4997 auto returnType = managedPtr(parseTypeSpec(lambdaExpr->resultType));
4998 callableBuilder.setReturnType(returnType);
4999 callableBuilder.setName(structName + L"::operator()" + getFuncUniqueNameStr(argTypes));
5000 auto callableFunc = callableBuilder.yield();
5001 auto callableFuncIndex = irModule->functionTable.put_create(callableFunc->name, callableFunc);
5002 irModule->functionOverloadIndexies[structName + L"::operator()"].push_back(callableFuncIndex);
5003 builder.addMethod(L"operator()" + getFuncUniqueNameStr(argTypes), callableFuncIndex);
5004
5005 // add captured variables as fields
5006 // now a trick here, we put new_struct op first, so that we can build the IR without rolling back the builder state
5007 // when we add captured variables as fields
5008 argTypes.clear();
5009 moduleContext->getIRBuilder().newStructOp(structIndex);
5010 for (auto &i : lambdaExpr->captures) {
5011 // get attributes
5012 visit(i->identifier);
5013 auto capturedVar = moduleContext->getIRBuilder().getRhsFromTempVarStack();
5014 auto fieldType = managedPtr(*capturedVar);
5015 switch (i->attr) {
5016 case structDefInnerPair::Modifier::DataField:
5017 // capture by value
5018 argTypes.back()->addAttribute(IRValueType::ValueAttr::Raw);
5019 case structDefInnerPair::Modifier::Weak:
5020 capturedVar->addAttribute(IRValueType::ValueAttr::Nullable);
5021 fieldType->addAttribute(IRValueType::ValueAttr::WeakRef);
5022 break;
5023 case structDefInnerPair::Modifier::None:
5024 capturedVar->addAttribute(IRValueType::ValueAttr::Nullable);
5025 break;
5026 }
5027 // i guess the IRValueType here is referenceable.
5028 argTypes.push_back(managedPtr(*capturedVar));
5029 builder.addField(i->identifier->node.strVal, fieldType);
5030
5031 }
5032 // add the constructor method
5033 IRFunctionDefinition::Builder constructorBuilder;
5034 constructorBuilder.setDebugInfo({irModule->modulePath, lambdaExpr->getLine(), lambdaExpr->getColumn()});
5035 constructorBuilder.addArgument(L"this", structType);
5036 constructorBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Constructor);
5037 constructorBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::NoRawAndNullOptimization);
5038 for (yoi::indexT i = 0; i < argTypes.size(); ++i) {
5039 constructorBuilder.addArgument(L"capture#" + lambdaExpr->captures[i]->identifier->node.strVal, argTypes[i]);
5040 }
5041 constructorBuilder.setReturnType(structType);
5042 constructorBuilder.setName(structName + L"::constructor" + getFuncUniqueNameStr(argTypes));
5043 auto constructorFunc = constructorBuilder.yield();
5044 auto constructorFuncIndex = irModule->functionTable.put_create(constructorFunc->name, constructorFunc);
5045 irModule->functionOverloadIndexies[structName + L"::constructor"].push_back(constructorFuncIndex);
5046 builder.addMethod(L"constructor" + getFuncUniqueNameStr(argTypes), constructorFuncIndex);
5047
5048 // now we add the struct to the module
5049 irModule->structTable[structIndex] = builder.yield();
5050
5051 // now we invokes the constructor method to initialize the struct
5052 moduleContext->getIRBuilder().invokeMethodOp(constructorFuncIndex, argTypes.size(), structType, false, true, currentModuleIndex);
5053
5054 // finally, we generate the implementations for both operator() and constructor
5055 moduleContext->pushIRBuilder(IRBuilder{moduleContext->getCompilerContext(), irModule, irModule->functionTable[callableFuncIndex]});
5058 visit(lambdaExpr->block, true);
5061
5062 moduleContext->pushIRBuilder(IRBuilder{moduleContext->getCompilerContext(), irModule, irModule->functionTable[constructorFuncIndex]});
5065 for (yoi::indexT i = 0; i < lambdaExpr->captures.size(); ++i) {
5066 // we store our parameters into the fields of the struct
5067 // load local in accordance with the order of arguments
5068 moduleContext->getIRBuilder().loadOp(IR::Opcode::load_local,
5069 {IROperand::operandType::localVar, i + 1},
5070 argTypes[i]); // take advantages of the argTypes which we haven't clear it yet.
5071 // store the parameter into the field
5072 // now we load the this pointer, and store the parameter into the field
5074 IR::Opcode::load_local, {IROperand::operandType::localVar, IROperand::operandValue{static_cast<yoi::indexT>(0)}}, structType);
5075 moduleContext->getIRBuilder().storeMemberOp({IROperand::operandType::index, i});
5076 }
5078 IR::Opcode::load_local, {IROperand::operandType::localVar, IROperand::operandValue{static_cast<yoi::indexT>(0)}}, structType);
5082
5083 return structIndex;
5084 }
5085
5086 std::pair<yoi::indexT, std::pair<yoi::indexT, yoi::indexT>> visitor::createCallableImplementationForLambda(
5087 const std::shared_ptr<IRStructDefinition> &lambda, yoi::indexT lambdaStructIndex, yoi::indexT moduleIndex) {
5088 yoi::wstr callableName;
5089 yoi::indexT callableIndex;
5091 for (auto &[key, value] : lambda->nameIndexMap) {
5092 if (key.starts_with(L"operator()")) {
5093 callableName = key;
5094 callableIndex = value.index;
5095 break;
5096 }
5097 }
5098 auto callableFunc = moduleContext->getCompilerContext()->getImportedModule(moduleIndex)->functionTable[callableIndex];
5099 // ignore the first argument, which is the this pointer
5100 for (yoi::indexT i = 1; i < callableFunc->argumentTypes.size(); ++i) {
5101 argTypes.push_back(callableFunc->argumentTypes[i]);
5102 }
5103 auto returnType = callableFunc->returnType;
5104
5105 auto interfaceSrc = std::pair{HOSHI_COMPILER_CTX_GLOB_ID_CONST, createCallableInterface(argTypes, returnType)};
5106 auto interfaceDef = moduleContext->getCompilerContext()->getImportedModule(interfaceSrc.first)->interfaceTable[interfaceSrc.second];
5107 auto interfaceImpl = getInterfaceImplName(interfaceSrc, moduleContext->getIRBuilder().getRhsFromTempVarStack());
5108
5109 if (irModule->interfaceImplementationTable.contains(interfaceImpl)) {
5110 // same fix here
5111 return {irModule->interfaceImplementationTable.getIndex(interfaceImpl), interfaceSrc};
5112 }
5113
5115 builder.setImplInterfaceIndex(interfaceSrc)
5116 .setImplStructIndex({IRValueType::valueType::structObject, moduleIndex, lambdaStructIndex})
5117 .setName(interfaceImpl)
5118 .addVirtualMethod(callableName, managedPtr(IRValueType{IRValueType::valueType::virtualMethod, moduleIndex, callableIndex}));
5119 auto implIndex = irModule->interfaceImplementationTable.put_create(interfaceImpl, builder.yield());
5120 interfaceDef->implementations.emplace_back(std::tuple{IRValueType::valueType::structObject, currentModuleIndex, implIndex});
5121
5122 return {implIndex, interfaceSrc};
5123 }
5124
5125 bool visitor::checkMarcoSatisfaction(yoi::marcoDescriptor *desc) {
5126 if (!desc)
5127 return true;
5128 bool satisfied = true;
5129
5130 auto convertToSameType = [](lexer::token &lhs, lexer::token &rhs) -> std::pair<lexer::token, lexer::token> {
5131 switch (lhs.kind) {
5132 case lexer::token::tokenKind::integer:
5133 switch (rhs.kind) {
5134 case lexer::token::tokenKind::integer:
5135 return {lhs, rhs};
5136 case lexer::token::tokenKind::decimal:
5137 return {lexer::token{0, 0, lexer::token::tokenKind::decimal, static_cast<double>(lhs.basicVal.vDeci)}, rhs};
5138 default:
5139 panic(lhs.line, lhs.col, "Cannot convert marco value to comparable type.");
5140 }
5141 case lexer::token::tokenKind::decimal:
5142 switch (rhs.kind) {
5143 case lexer::token::tokenKind::integer:
5144 return {lhs, lexer::token{0, 0, lexer::token::tokenKind::decimal, static_cast<double>(rhs.basicVal.vUint)}};
5145 case lexer::token::tokenKind::decimal:
5146 return {lhs, rhs};
5147 default:
5148 panic(lhs.line, lhs.col, "Cannot convert marco value to comparable type.");
5149 }
5150 case lexer::token::tokenKind::string:
5151 switch (rhs.kind) {
5152 case lexer::token::tokenKind::string:
5153 return {lhs, rhs};
5154 case lexer::token::tokenKind::boolean:
5155 return {lexer::token{0, 0, lexer::token::tokenKind::integer, static_cast<uint64_t>(lhs.strVal == rhs.strVal)}, rhs};
5156 default:
5157 panic(lhs.line, lhs.col, "Cannot convert marco value to comparable type.");
5158 }
5159 case lexer::token::tokenKind::boolean:
5160 switch (rhs.kind) {
5161 case lexer::token::tokenKind::string:
5162 return {lexer::token{0, 0, lexer::token::tokenKind::integer, static_cast<uint64_t>(lhs.strVal == rhs.strVal)}, rhs};
5163 case lexer::token::tokenKind::boolean:
5164 return {lhs, rhs};
5165 default:
5166 panic(lhs.line, lhs.col, "Cannot convert marco value to comparable type.");
5167 }
5168 default:;
5169 }
5170 return {lhs, rhs};
5171 };
5172 auto compare = [&](lexer::token &lhs, lexer::token &rhs, lexer::token::tokenKind op) {
5173 auto [lhsTok, rhsTok] = convertToSameType(lhs, rhs);
5174 switch (op) {
5175 case lexer::token::tokenKind::equal:
5176 return lhsTok.basicVal.vUint == rhsTok.basicVal.vUint && lhsTok.strVal == rhsTok.strVal;
5177 case lexer::token::tokenKind::notEqual:
5178 return lhsTok.basicVal.vUint != rhsTok.basicVal.vUint || lhsTok.strVal != rhsTok.strVal;
5179 case lexer::token::tokenKind::greaterThan:
5180 switch (lhsTok.kind) {
5181 case lexer::token::tokenKind::integer:
5182 return lhsTok.basicVal.vUint > rhsTok.basicVal.vUint;
5183 case lexer::token::tokenKind::decimal:
5184 return lhsTok.basicVal.vDeci > rhsTok.basicVal.vDeci;
5185 default:
5186 panic(lhs.line, lhs.col, "Cannot compare marco value.");
5187 }
5188 case lexer::token::tokenKind::greaterEqual:
5189 switch (lhsTok.kind) {
5190 case lexer::token::tokenKind::integer:
5191 return lhsTok.basicVal.vUint >= rhsTok.basicVal.vUint;
5192 case lexer::token::tokenKind::decimal:
5193 return lhsTok.basicVal.vDeci >= rhsTok.basicVal.vDeci;
5194 default:
5195 panic(lhs.line, lhs.col, "Cannot compare marco value.");
5196 }
5197 case lexer::token::tokenKind::lessThan:
5198 switch (lhsTok.kind) {
5199 case lexer::token::tokenKind::integer:
5200 return lhsTok.basicVal.vUint < rhsTok.basicVal.vUint;
5201 case lexer::token::tokenKind::decimal:
5202 return lhsTok.basicVal.vDeci < rhsTok.basicVal.vDeci;
5203 default:
5204 panic(lhs.line, lhs.col, "Cannot compare marco value.");
5205 }
5206 case lexer::token::tokenKind::lessEqual:
5207 switch (lhsTok.kind) {
5208 case lexer::token::tokenKind::integer:
5209 return lhsTok.basicVal.vUint <= rhsTok.basicVal.vUint;
5210 case lexer::token::tokenKind::decimal:
5211 return lhsTok.basicVal.vDeci <= rhsTok.basicVal.vDeci;
5212 default:
5213 panic(lhs.line, lhs.col, "Cannot compare marco value.");
5214 }
5215 default:;
5216 }
5217 return false;
5218 };
5219
5220 auto &marcos = moduleContext->getCompilerContext()->getBuildConfig()->marcos;
5221 for (auto &i : desc->pairs) {
5222 bool currentSatisfied = false;
5223 auto &marco = i->identifier.strVal;
5224 yoi_assert(marcos.contains(marco), desc->getLine(), desc->getColumn(), "Undefined marco: " + yoi::wstring2string(marco));
5225 auto &value = marcos[marco];
5226 auto tok = lexer(std::wstringstream(value)).scan();
5227 tok.kind = tok.kind == lexer::token::tokenKind::identifier ? lexer::token::tokenKind::string : tok.kind;
5228
5229 auto &targetValue = i->rhs;
5230 switch (i->constraint.kind) {
5231 case lexer::token::tokenKind::equal: {
5232 currentSatisfied = tok.basicVal.vUint == targetValue.basicVal.vUint && tok.strVal == targetValue.strVal;
5233 break;
5234 }
5235 case lexer::token::tokenKind::notEqual: {
5236 currentSatisfied = tok.basicVal.vUint != targetValue.basicVal.vUint || tok.strVal != targetValue.strVal;
5237 break;
5238 }
5239 case lexer::token::tokenKind::greaterThan:
5240 case lexer::token::tokenKind::greaterEqual:
5241 case lexer::token::tokenKind::lessThan:
5242 case lexer::token::tokenKind::lessEqual: {
5243 currentSatisfied = compare(tok, targetValue, i->constraint.kind);
5244 break;
5245 }
5246 default: {
5247 panic(desc->getLine(),
5248 desc->getColumn(),
5249 "Unsupported marco constraint kind: " + std::string{magic_enum::enum_name(i->constraint.kind)});
5250 break;
5251 }
5252 }
5253 if (!currentSatisfied) {
5254 satisfied = false;
5255 break;
5256 }
5257 }
5258 return satisfied;
5259 }
5260
5261 void visitor::visit(yoi::typeAliasStmt *typeAlias) {
5262 if (typeAlias->lhs->hasDefTemplateArg()) {
5263 panic(typeAlias->getLine(), typeAlias->getColumn(), "type alias template not implemented yet");
5264 } else {
5265 auto aliasName = typeAlias->lhs->getId().node.strVal;
5266 auto rhs = parseTypeSpec(typeAlias->rhs);
5267 if (irModule->typeAliases.contains(aliasName)) {
5268 panic(typeAlias->getLine(), typeAlias->getColumn(), "Redefinition of type alias: " + yoi::wstring2string(aliasName));
5269 } else {
5270 irModule->typeAliases[aliasName] = rhs;
5271 }
5272 }
5273 }
5274
5275 std::shared_ptr<IRValueType> visitor::mapEnumTypeToBasicType(yoi::indexT targetModule, yoi::indexT targetEnumType) {
5276 auto enumDef = moduleContext->getCompilerContext()->getImportedModule(targetModule)->enumerationTable[targetEnumType];
5277 switch (enumDef->getUnderlyingType()) {
5278 case IREnumerationType::UnderlyingType::I8:
5279 return moduleContext->getCompilerContext()->getCharObjectType();
5280 case IREnumerationType::UnderlyingType::I16:
5281 return moduleContext->getCompilerContext()->getShortObjectType();
5282 case IREnumerationType::UnderlyingType::I64:
5283 return moduleContext->getCompilerContext()->getUnsignedObjectType();
5284 default:
5285 return nullptr;
5286 }
5287 }
5288
5292 yoi::indexT idx = 0;
5293 for (auto &node : enumerationDefinition->values) {
5294 idx = node->value.kind != lexer::token::tokenKind::unknown ? node->value.basicVal.vInt : idx;
5295 builder.addValue(node->name->get().strVal, idx++);
5296 }
5297 auto enumType = builder.yield();
5298 auto enumIndex = irModule->enumerationTable.put_create(enumType->name, enumType);
5299 auto underlyingEnumType = mapEnumTypeToBasicType(currentModuleIndex, enumIndex);
5300 irModule->typeAliases[enumerationDefinition->name->get().strVal] = *underlyingEnumType;
5301 }
5302
5303 yoi::indexT visitor::visit(yoi::funcExpr *func) {
5304 auto it = func->name->getTerms().begin();
5305 yoi::indexT targetModule = -1, lastModule = -1;
5306 // 1. Resolve module prefixes (e.g., std.io)
5307 while (it + 1 != func->name->getTerms().end() && (targetModule = isModuleName((*it)->id, lastModule)) != lastModule) {
5308 it++;
5309 lastModule = targetModule;
5310 }
5311
5312 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(targetModule == -1 ? currentModuleIndex : targetModule);
5313 enum class CreateStrategy { Plain, IncludeThis } strategy{CreateStrategy::Plain};
5314 yoi::indexT funcIndex = -1;
5315
5316 // 1. Struct Static Method
5317 if (it + 2 == func->name->getTerms().end()) {
5318 auto nameNode = *(it);
5319 auto funcNameNode = *(it + 1);
5320 std::shared_ptr<IRStructDefinition> structType;
5321
5322 if (nameNode->hasTemplateArg() && targetedModule->structTemplateAsts.contains(nameNode->getId().node.strVal)) {
5323 auto concreteTypes = parseTemplateArgs(nameNode->getArg());
5324 auto specializedIndex = specializeStructTemplate(
5325 nameNode->id->node.strVal, concreteTypes, targetedModule->templateImplAsts[nameNode->getId().node.strVal], targetModule);
5326 structType = targetedModule->structTable[specializedIndex];
5327
5328 } else if (targetedModule->structTable.contains(nameNode->getId().node.strVal)) {
5329 structType = targetedModule->structTable[nameNode->getId().node.strVal];
5330 } else {
5331 panic(nameNode->getLine(), nameNode->getColumn(), "Undefined struct: " + yoi::wstring2string(nameNode->getId().node.strVal));
5332 }
5333
5334 yoi::wstr baseName = structType->name + L"::" + funcNameNode->getId().node.strVal;
5335
5336 yoi_assert(targetedModule->functionOverloadIndexies.contains(baseName),
5337 funcNameNode->getLine(),
5338 funcNameNode->getColumn(),
5339 "Undefined method: " + yoi::wstring2string(baseName));
5340
5341 // check whether explicit param types specified
5342 if (func->args) {
5344 for (auto &arg : func->args->types) {
5345 argTypes.push_back(managedPtr(parseTypeSpec(arg)));
5346 }
5347 yoi::wstr fullFuncName = baseName + getFuncUniqueNameStr(argTypes);
5348 yoi_assert(targetedModule->functionTable.contains(fullFuncName),
5349 funcNameNode->getLine(),
5350 funcNameNode->getColumn(),
5351 "No matching function overload found with explicit param types: " + yoi::wstring2string(fullFuncName));
5352 yoi_assert(targetedModule->functionTable[fullFuncName]->hasAttribute(IRFunctionDefinition::FunctionAttrs::Static),
5353 funcNameNode->getLine(),
5354 funcNameNode->getColumn(),
5355 "Cannot call non-static method: " + yoi::wstring2string(fullFuncName));
5356 funcIndex = targetedModule->functionTable.getIndex(fullFuncName);
5357 strategy = CreateStrategy::Plain;
5358 } else {
5359 // no params, check whether the function table contains only one
5360 yoi_assert(targetedModule->functionOverloadIndexies[baseName].size() == 1,
5361 funcNameNode->getLine(),
5362 funcNameNode->getColumn(),
5363 "Inplicit specification on multiple overloads of method: " + yoi::wstring2string(baseName));
5364 auto candidateIndex = targetedModule->functionOverloadIndexies[baseName][0];
5365 yoi_assert(targetedModule->functionTable[candidateIndex]->hasAttribute(IRFunctionDefinition::FunctionAttrs::Static),
5366 funcNameNode->getLine(),
5367 funcNameNode->getColumn(),
5368 "Cannot call non-static method: " + yoi::wstring2string(baseName));
5369 funcIndex = candidateIndex;
5370 strategy = CreateStrategy::Plain;
5371 }
5372 } else if (it + 1 == func->name->getTerms().end()) {
5373 // 2. Global Function
5374 auto funcNameNode = *(it);
5375 yoi_assert(targetedModule->functionOverloadIndexies.contains(funcNameNode->getId().node.strVal),
5376 funcNameNode->getLine(),
5377 funcNameNode->getColumn(),
5378 "Undefined function: " + yoi::wstring2string(funcNameNode->getId().node.strVal));
5379 // If explicit param types specified, use full-qualified name first
5380 if (func->args) {
5382 for (auto &arg : func->args->types) {
5383 argTypes.push_back(managedPtr(parseTypeSpec(arg)));
5384 }
5385 yoi::wstr fullFuncName = funcNameNode->getId().node.strVal + getFuncUniqueNameStr(argTypes);
5386 yoi_assert(targetedModule->functionTable.contains(fullFuncName),
5387 funcNameNode->getLine(),
5388 funcNameNode->getColumn(),
5389 "No matching function overload found with explicit param types: " + yoi::wstring2string(fullFuncName));
5390 funcIndex = targetedModule->functionTable.getIndex(fullFuncName);
5391 strategy = CreateStrategy::Plain;
5392 } else {
5393 // no params, check whether the function table contains only one
5394 yoi_assert(targetedModule->functionOverloadIndexies[funcNameNode->getId().node.strVal].size() == 1,
5395 funcNameNode->getLine(),
5396 funcNameNode->getColumn(),
5397 "Inplicit specification on multiple overloads of function: " + yoi::wstring2string(funcNameNode->getId().node.strVal));
5398 funcIndex = targetedModule->functionOverloadIndexies[funcNameNode->getId().node.strVal][0];
5399 strategy = CreateStrategy::Plain;
5400 }
5401 } else {
5402 yoi_assert(false, func->getLine(), func->getColumn(), "invalid function expression");
5403 }
5404
5405 yoi_assert(funcIndex != -1, func->getLine(), func->getColumn(), "Cannot resolve function overload");
5406 switch (strategy) {
5407 case CreateStrategy::Plain: {
5408 auto funcDef = targetedModule->functionTable[funcIndex];
5409 auto impl = createCallableImplementationForFunction(funcDef, funcIndex, targetModule == -1 ? currentModuleIndex : targetModule, false);
5410 createCallableInstanceForFunction(impl.first, impl.second, targetModule == -1 ? currentModuleIndex : targetModule, false);
5411 break;
5412 }
5413 case CreateStrategy::IncludeThis: {
5414 panic(func->getLine(), func->getColumn(), "Not implemented yet");
5415 break;
5416 }
5417 default: {
5418 panic(func->getLine(), func->getColumn(), "Unsupported create strategy");
5419 break;
5420 }
5421 }
5422
5424 }
5425
5426 std::pair<yoi::indexT, std::pair<yoi::indexT, yoi::indexT>> visitor::createCallableImplementationForFunction(
5427 const std::shared_ptr<IRFunctionDefinition> &func, yoi::indexT funcIndex, yoi::indexT moduleIndex, bool hasThis) {
5428 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(moduleIndex);
5429 auto objectType = hasThis ? func->argumentTypes[0] : nullptr;
5430
5432 for (auto index = hasThis ? 1 : 0; index < func->argumentTypes.size(); index++) {
5433 argTypes.push_back(func->argumentTypes[index]);
5434 }
5435
5436 auto callableInterface = std::pair{HOSHI_COMPILER_CTX_GLOB_ID_CONST, createCallableInterface(argTypes, func->returnType)};
5437
5438 auto uniqueName = L"callableWrapper#" + func->name + getFuncUniqueNameStr(argTypes);
5439 if (targetedModule->structTable.contains(uniqueName)) {
5440 auto interfaceImplName = getInterfaceImplName(
5441 callableInterface,
5442 managedPtr(IRValueType{IRValueType::valueType::structObject, moduleIndex, targetedModule->structTable.getIndex(uniqueName)}));
5443 return {targetedModule->interfaceImplementationTable.getIndex(interfaceImplName), callableInterface};
5444 }
5445
5446 yoi::indexT structTypeIndex = targetedModule->structTable.put_create(uniqueName, {});
5447 yoi::wstr constructorName = hasThis ? uniqueName + L"::constructor#" + getTypeSpecUniqueNameStr(objectType) : uniqueName + L"::constructor#";
5448 yoi::indexT constructorIndex = targetedModule->functionTable.put_create(constructorName, {});
5449 yoi::wstr callableName = uniqueName + L"::operator()" + getFuncUniqueNameStr(func->argumentTypes);
5450 yoi::indexT callableIndex = targetedModule->functionTable.put_create(callableName, {});
5451
5453
5454 if (hasThis) {
5455 builder.addField(L"object_this", objectType);
5456 }
5457
5458 auto constructorUniqueName = hasThis ? L"constructor#" + getTypeSpecUniqueNameStr(objectType) : L"constructor#";
5459 builder.setName(uniqueName).addMethod(constructorUniqueName, constructorIndex);
5460 builder.setName(uniqueName).addMethod(L"operator()" + getFuncUniqueNameStr(func->argumentTypes), callableIndex);
5461 targetedModule->structTable[structTypeIndex] = builder.yield();
5462
5463 auto structType = managedPtr(IRValueType{IRValueType::valueType::structObject, moduleIndex, structTypeIndex});
5464
5465 IRFunctionDefinition::Builder constructorBuilder;
5466 constructorBuilder.setName(constructorName);
5467 constructorBuilder.addArgument(L"this", structType);
5468 if (hasThis) {
5469 constructorBuilder.addArgument(L"object_this", objectType);
5470 }
5471 constructorBuilder.setReturnType(structType);
5472 constructorBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::NoRawAndNullOptimization);
5473 constructorBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Preserve);
5475 targetedModule->functionTable[constructorIndex] = constructorBuilder.yield();
5476 IRFunctionDefinition::Builder callableBuilder;
5477 callableBuilder.setName(callableName);
5478 callableBuilder.addArgument(L"this", structType);
5479 for (yoi::indexT argIndex = hasThis ? 1 : 0; argIndex < func->argumentTypes.size(); argIndex++) {
5480 auto arg = func->argumentTypes[argIndex];
5481 callableBuilder.addArgument(L"param" + std::to_wstring(argIndex), arg);
5482 }
5483 callableBuilder.setReturnType(func->returnType);
5484 callableBuilder.addAttr(IRFunctionDefinition::FunctionAttrs::Preserve);
5486 targetedModule->functionTable[callableIndex] = callableBuilder.yield();
5487
5488 moduleContext->pushIRBuilder(IRBuilder{moduleContext->getCompilerContext(), targetedModule, targetedModule->functionTable[constructorIndex]});
5490 // setup this
5491 if (hasThis) {
5493 IR::Opcode::load_local, {IROperand::operandType::index, IROperand::operandValue{(yoi::indexT)1}}, objectType, moduleIndex);
5495 IR::Opcode::load_local, {IROperand::operandType::index, IROperand::operandValue{(yoi::indexT)0}}, structType, moduleIndex);
5497 IR::Opcode::store_member, {IROperand::operandType::index, IROperand::operandValue{(yoi::indexT)0}}, moduleIndex);
5498 }
5500 IR::Opcode::load_local, {IROperand::operandType::index, IROperand::operandValue{(yoi::indexT)0}}, structType, moduleIndex);
5504
5505 moduleContext->pushIRBuilder(IRBuilder{moduleContext->getCompilerContext(), targetedModule, targetedModule->functionTable[callableIndex]});
5507 if (hasThis) {
5509 IR::Opcode::load_local, {IROperand::operandType::index, IROperand::operandValue{(yoi::indexT)0}}, structType, moduleIndex);
5511 IR::Opcode::load_member, {IROperand::operandType::index, IROperand::operandValue{(yoi::indexT)0}}, objectType, moduleIndex);
5512 }
5513 for (yoi::indexT argIndex = hasThis ? 1 : 0; argIndex < func->argumentTypes.size(); argIndex++) {
5514 auto arg = func->argumentTypes[argIndex];
5516 IR::Opcode::load_local, {IROperand::operandType::index, (yoi::indexT)(argIndex + 1)}, arg, moduleIndex);
5517 }
5518 moduleContext->getIRBuilder().invokeOp(funcIndex, func->argumentTypes.size(), func->returnType, true, moduleIndex);
5519 moduleContext->getIRBuilder().retOp(func->returnType->type == IRValueType::valueType::none);
5522
5523 auto interfaceImplName = getInterfaceImplName(
5524 callableInterface,
5525 managedPtr(IRValueType{IRValueType::valueType::structObject, moduleIndex, targetedModule->structTable.getIndex(uniqueName)}));
5526
5527 auto interfaceImplIndex = targetedModule->interfaceImplementationTable.put_create(
5528 interfaceImplName,
5530 .setName(interfaceImplName)
5531 .addVirtualMethod(L"operator()" + getFuncUniqueNameStr(func->argumentTypes),
5532 managedPtr(IRValueType{IRValueType::valueType::virtualMethod, moduleIndex, callableIndex}))
5533 .setImplInterfaceIndex(callableInterface)
5534 .setImplStructIndex({IRValueType::valueType::structObject, moduleIndex, structTypeIndex})
5535 .yield());
5536
5537 return {interfaceImplIndex, callableInterface};
5538 }
5539
5540 void visitor::createCallableInstanceForFunction(yoi::indexT implIndex,
5541 std::pair<yoi::indexT, yoi::indexT> callableInterfaceIndex,
5542 yoi::indexT moduleIndex, bool hasThis) {
5543 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(moduleIndex);
5544 auto implDef = targetedModule->interfaceImplementationTable[implIndex];
5545 auto structIndex = implDef->implStructIndex;
5546 // moduleContext->getCompilerContext()->getImportedModule(std::get<1>(structIndex))->structTable[std]
5547 if (hasThis) {
5548 auto objectPtrOnStack = moduleContext->getIRBuilder().getRhsFromTempVarStack();
5549 moduleContext->getIRBuilder().newStructOp(std::get<2>(structIndex), true, std::get<1>(structIndex));
5550 // since we gained the object ptr, the next thing we wish to do is to invoke the constructor
5551 auto constructorIndex = targetedModule->structTable[std::get<2>(structIndex)]->nameIndexMap.at(L"constructor#" + getTypeSpecUniqueNameStr(objectPtrOnStack));
5552 moduleContext->getIRBuilder().invokeDanglingOp(constructorIndex.index, 2, objectPtrOnStack, true, moduleIndex);
5553 // now we have the newly created struct on the stack
5554 // we can safely construct interface impl now
5555 } else {
5556 moduleContext->getIRBuilder().newStructOp(std::get<2>(structIndex), true, std::get<1>(structIndex));
5557 }
5558 moduleContext->getIRBuilder().constructInterfaceImplOp(callableInterfaceIndex, implIndex, true, moduleIndex);
5559 }
5560
5562 yoi::vec<IRValueType> bracedTypes;
5563 for (auto &i : bracedInitalizerList->exprs) {
5564 visit(i);
5565 bracedTypes.push_back(*moduleContext->getIRBuilder().getRhsFromTempVarStack());
5566 }
5567 moduleContext->getIRBuilder().pushTempVar(managedPtr(IRValueType{IRValueType::valueType::bracedInitalizerList, bracedTypes}));
5569 }
5570
5572 auto placeholder = irModule->dataStructTable.put_create(dataStructDefStmt->id->get().strVal, {});
5573 auto builder = IRDataStructDefinition::Builder()
5575
5576 for (auto &i : dataStructDefStmt->getInner().getInner()) {
5577 auto &id = i->getVar().id->get().strVal;
5578 auto spec = parseTypeSpec(i->getVar().spec);
5579 builder.addField(id, managedPtr(spec));
5580 }
5581
5582 irModule->dataStructTable[placeholder] = builder.yield();
5583 }
5584
5585 void
5586 visitor::constructDataStruct(yoi::indexT datastructIndex, yoi::indexT moduleIndex, yoi::invocationArguments *args) {
5587 auto targetedModule = moduleContext->getCompilerContext()->getImportedModule(moduleIndex);
5588 auto datastructDef = targetedModule->dataStructTable[datastructIndex];
5589
5590 moduleContext->getIRBuilder().newDataStructOp(datastructIndex, true, moduleIndex);
5591
5592 if (args->arg.empty()) {
5593 return;
5594 }
5595
5596 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()));
5597 for (yoi::indexT i = 0; i < args->arg.size(); i++) {
5598 visit(args->arg[i]);
5599 tryCastTo(datastructDef->fieldTypes[i]);
5600 }
5602
5603 }
5604
5605 yoi::indexT visitor::visit(yoi::yieldStmt *stmt) {
5606 yoi_assert(moduleContext->getIRBuilder().irFuncDefinition()->hasAttribute(IRFunctionDefinition::FunctionAttrs::Generator), stmt->getLine(), stmt->getColumn(), "yield can only be used in generator function");
5607 auto ctxIndex = moduleContext->getIRBuilder().irFuncDefinition()->getVariableTable().lookup(L"__context__");
5608 auto ctxType = moduleContext->getIRBuilder().irFuncDefinition()->returnType;
5609 moduleContext->getIRBuilder().loadOp(IR::Opcode::load_local, {IROperand::operandType::index, ctxIndex}, ctxType);
5610 moduleContext->getIRBuilder().loadMemberOp({IROperand::operandType::index, IROperand::operandValue{yoi::indexT(0)}}, moduleContext->getCompilerContext()->getUnsignedObjectType());
5611
5612 if (stmt->expr) {
5613 visit(stmt->expr);
5615 } else {
5616
5618 }
5620 }
5621
5622 std::shared_ptr<IRValueType> visitor::getGeneratorContext(const yoi::wstr &funcName, const std::shared_ptr<IRValueType> &yieldType) {
5623 auto builtinModule = moduleContext->getCompilerContext()->getImportedModule(HOSHI_COMPILER_CTX_GLOB_ID_CONST);
5624 auto generatorContextName = L"GeneratorContext#" + funcName;
5625 auto generatorContextIndex = builtinModule->structTable.put_create(generatorContextName, {});
5626 auto generatorContextType = managedPtr(IRValueType{
5627 IRValueType::valueType::structObject,
5629 generatorContextIndex
5630 });
5631
5632 auto generatorConstructorName = L"constructor#" + getTypeSpecUniqueNameStr(moduleContext->getCompilerContext()->getUnsignedObjectType());
5633 auto generatorConstructorIndex = builtinModule->functionTable.put_create(generatorContextName + L"::" + generatorConstructorName, {});
5634 auto generatorNextName = L"next#";
5635 auto generatorNextIndex = builtinModule->functionTable.put_create(generatorContextName + L"::" + generatorNextName, {});
5636
5637 auto unsignedDataField = managedPtr(*moduleContext->getCompilerContext()->getUnsignedObjectType());
5638 unsignedDataField->metadata.setMetadata(L"STRUCT_DATAFIELD", true);
5639
5640 auto builder = IRStructDefinition::Builder()
5641 .setName(generatorContextName)
5642 .addField(L"raw_ctx", unsignedDataField)
5643 .addField(L"yields", yieldType)
5644 .addMethod(generatorConstructorName, generatorConstructorIndex)
5645 .addMethod(generatorNextName, generatorNextIndex);
5646
5647 builtinModule->structTable[generatorContextIndex] = builder.yield();
5648
5649 builtinModule->functionTable[generatorConstructorIndex] = IRFunctionDefinition::Builder()
5650 .setName(generatorContextName + L"::" + generatorConstructorName)
5651 .addArgument(L"this", generatorContextType)
5652 .addArgument(L"raw_ctx", moduleContext->getCompilerContext()->getUnsignedObjectType())
5653 .setReturnType(generatorContextType)
5654 .addAttr(IRFunctionDefinition::FunctionAttrs::Preserve)
5655 .setDebugInfo({builtinModule->modulePath, 0, 0})
5656 .yield();
5657
5658 builtinModule->functionTable[generatorNextIndex] = IRFunctionDefinition::Builder()
5659 .setName(generatorContextName + L"::" + generatorNextName)
5660 .addArgument(L"this", generatorContextType)
5661 .setReturnType(yieldType)
5662 .addAttr(IRFunctionDefinition::FunctionAttrs::Preserve)
5663 .setDebugInfo({builtinModule->modulePath, 0, 0})
5664 .yield();
5665
5666 builtinModule->functionOverloadIndexies[generatorContextName + L"::constructor"].push_back(generatorConstructorIndex);
5667 builtinModule->functionOverloadIndexies[generatorContextName + L"::next"].push_back(generatorNextIndex);
5668
5671 builtinModule,
5672 builtinModule->functionTable[generatorConstructorIndex]
5673 });
5675 moduleContext->getIRBuilder().loadOp(IR::Opcode::load_local, {IROperand::operandType::index, IROperand::operandValue{yoi::indexT(1)}}, moduleContext->getCompilerContext()->getUnsignedObjectType());
5676 moduleContext->getIRBuilder().loadOp(IR::Opcode::load_local, {IROperand::operandType::index, IROperand::operandValue{yoi::indexT(0)}}, generatorContextType);
5677 moduleContext->getIRBuilder().storeMemberOp({IROperand::operandType::index, IROperand::operandValue{yoi::indexT(0)}});
5678 moduleContext->getIRBuilder().loadOp(IR::Opcode::load_local, {IROperand::operandType::index, IROperand::operandValue{yoi::indexT(0)}}, generatorContextType);
5682
5685 builtinModule,
5686 builtinModule->functionTable[generatorNextIndex]
5687 });
5689 // in the first suspend, we just only return the allocated generator context, but doing nothing.
5690 // we only begin yielding value after first resume.
5691 moduleContext->getIRBuilder().loadOp(IR::Opcode::load_local, {IROperand::operandType::index, IROperand::operandValue{yoi::indexT(0)}}, generatorContextType);
5693 moduleContext->getIRBuilder().loadOp(IR::Opcode::load_local, {IROperand::operandType::index, IROperand::operandValue{yoi::indexT(0)}}, generatorContextType);
5694 moduleContext->getIRBuilder().loadMemberOp({IROperand::operandType::index, IROperand::operandValue{yoi::indexT(1)}}, yieldType);
5698
5699 return managedPtr(IRValueType{IRValueType::valueType::structObject, HOSHI_COMPILER_CTX_GLOB_ID_CONST, generatorContextIndex});
5700 }
5701
5703 auto conceptName = conceptDefinition->name.strVal;
5704 irModule->concepts[conceptName] = managedPtr(IRConcept{
5705 conceptName,
5706 irModule->identifier,
5708 });
5709 }
5710
5711 void visitor::setupTemporaryConceptEvaluationEnvironment(yoi::indexT moduleIndex, const yoi::wstr &conceptName, const std::vector<std::shared_ptr<IRValueType>> &args) {
5712 yoi_assert(
5713 moduleContext->getCompilerContext()->getImportedModule(moduleIndex)->concepts[conceptName]->def->typeParams.size() == args.size(),
5716 "Concept type parameter count does not match the number of arguments."
5717 );
5718
5719 IRTemplateBuilder specializationContext;
5720 for (yoi::indexT i = 0; i < args.size(); i += 1) {
5721 specializationContext.addTemplateArgument(
5722 moduleContext->getCompilerContext()->getImportedModule(moduleIndex)->concepts[conceptName]->def->typeParams[i].strVal,
5723 args[i]
5724 );
5725 }
5726 moduleContext->pushTemplateBuilder(specializationContext);
5727 // specialize the params
5729
5730 for (yoi::indexT i = 0; i < moduleContext->getCompilerContext()->getImportedModule(moduleIndex)->concepts[conceptName]->def->algebraParams.size(); i += 1) {
5731 auto node = moduleContext->getCompilerContext()->getImportedModule(moduleIndex)->concepts[conceptName]->def->algebraParams[i];
5732 params.push_back({
5733 node->id->node.strVal,
5734 managedPtr(parseTypeSpec(node->spec))
5735 });
5736 }
5737 // create fake function and push IRBuilder
5740 moduleContext->getCompilerContext()->getImportedModule(moduleIndex),
5742 L"temporary",
5743 params,
5744 {},
5745 {},
5746 {},
5747 {}
5748 })
5749 });
5751 }
5752
5753 void visitor::ejectTemporaryConceptEvaluationEnvironment() {
5756 }
5757
5758 void visitor::evaluateConstraint(yoi::conceptStmt *stmt, const IRDebugInfo &currentDebugInfo) {
5759 switch (stmt->kind) {
5761 checkConceptSatisfaction(stmt->value.satisfyStmt->emae);
5762 break;
5765 try {
5766 visit(stmt->value.expression);
5767 } catch (std::runtime_error &e) {
5768 panic(currentDebugInfo.line, currentDebugInfo.column, "Constraint evaluation failed: " + std::string(e.what()));
5769 }
5771 break;
5772 default:
5773 break;
5774 }
5775 }
5776
5777 std::pair<std::shared_ptr<IRConcept>, templateArg *> visitor::parseConceptName(yoi::externModuleAccessExpression *conceptName) {
5778 yoi::indexT currentModIndex = conceptName->getTerms().size() > 1 ? -1 : currentModuleIndex;
5779 for (yoi::indexT i = 0; i < conceptName->getTerms().size() - 1; i += 1) {
5780 auto term = conceptName->getTerms()[i];
5781 yoi_assert(!term->hasTemplateArg(), term->getLine(), term->getColumn(), "template arguments is not allowed except in the last term");
5782 yoi_assert(moduleContext->getCompilerContext()->getImportedModule(currentModIndex)->moduleImports.contains(term->id->node.strVal), term->getLine(), term->getColumn(), "module not found");
5783 currentModIndex = moduleContext->getCompilerContext()->getImportedModule(currentModIndex)->moduleImports[term->id->node.strVal];
5784 }
5785 auto name = conceptName->getTerms().back()->id->node.strVal;
5786 yoi_assert(moduleContext->getCompilerContext()->getImportedModule(currentModIndex)->concepts.contains(name), conceptName->getLine(), conceptName->getColumn(), "concept not found");
5787
5788 return {
5789 moduleContext->getCompilerContext()->getImportedModule(currentModIndex)->concepts[name],
5790 conceptName->getTerms().back()->arg
5791 };
5792 }
5793
5794 void visitor::checkConceptSatisfaction(yoi::externModuleAccessExpression *stmt) {
5795 auto [conceptDef, parsedTemplateArg] = parseConceptName(stmt);
5796
5798
5799 for (auto &i : parsedTemplateArg->spec) {
5800 args.push_back(managedPtr(parseTypeSpec(i->spec)));
5801 }
5802
5803 setupTemporaryConceptEvaluationEnvironment(currentModuleIndex, conceptDef->name, args);
5804
5805 for (auto constraint : conceptDef->def->conceptBlock) {
5806 evaluateConstraint(constraint, {
5808 stmt->getLine(),
5809 stmt->getColumn()
5810 });
5811 }
5812
5813 ejectTemporaryConceptEvaluationEnvironment();
5814 }
5815
5816 void visitor::checkConceptSatisfaction(yoi::externModuleAccessExpression *stmt,
5817 const yoi::wstr &paramName,
5818 const std::shared_ptr<IRValueType> &args) {
5820 t.addTemplateArgument(paramName, args);
5822 checkConceptSatisfaction(stmt);
5824 }
5825} // namespace yoi
#define HOSHI_COMPILER_CTX_GLOB_ID_CONST
yoi::indexT getColumn()
Definition ast.cpp:1042
yoi::indexT getLine()
Definition ast.cpp:1046
void pushLoopContext(yoi::indexT breakTarget, yoi::indexT continueTarget)
Definition IR.cpp:1526
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:1166
void continueOp()
Definition IR.cpp:1496
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:1209
void popOp()
Definition IR.cpp:1191
void yieldOp(bool yieldNone=false)
Definition IR.cpp:1705
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:1347
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:1491
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:1687
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:1187
void newArrayOp(const std::shared_ptr< IRValueType > &elementType, const yoi::vec< yoi::indexT > &dimensions, yoi::indexT onstackElementCount)
Definition IR.cpp:1108
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:1694
void typeIdOp(const std::shared_ptr< IRValueType > &type)
Definition IR.cpp:1224
void invokeImportedOp(yoi::indexT libIndex, yoi::indexT funcIndex, yoi::indexT funcArgsCount, const std::shared_ptr< IRValueType > &returnType)
Definition IR.cpp:1072
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:1171
void discardStateUntil(yoi::indexT stateIndex)
Definition IR.cpp:1458
void bindElementsOp(yoi::indexT extractElementCount, ExtractType extractType)
Definition IR.cpp:1501
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:1341
void popLoopContext()
Definition IR.cpp:1487
void commitState()
Definition IR.cpp:1446
void initializeFieldsOp(yoi::indexT parameterCount)
Definition IR.cpp:1680
void resumeOp()
Definition IR.cpp:1700
void jumpOp(yoi::indexT target)
Definition IR.cpp:286
void bindFieldsOp(yoi::indexT extractFieldCount, ExtractType extractType)
Definition IR.cpp:1513
void restoreState()
Definition IR.cpp:1176
void jumpIfOp(IR::Opcode op, yoi::indexT target)
Definition IR.cpp:292
yoi::indexT getCurrentInsertionPoint()
Definition IR.cpp:484
void restoreStateTemporarily()
Definition IR.cpp:1435
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:1532
void newDynamicArrayOp(const std::shared_ptr< IRValueType > &elementType, yoi::indexT initializerSize=0)
Definition IR.cpp:1284
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:1249
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:1204
void insert(const IR &ir)
Definition IR.cpp:506
Builder & addValue(const yoi::wstr &valueName, yoi::indexT valueIndex)
Definition IR.cpp:1580
std::shared_ptr< IREnumerationType > yield()
Definition IR.cpp:1614
Builder & setName(const yoi::wstr &name)
Definition IR.cpp:1575
yoi::indexT itemIndex
Definition IR.h:833
yoi::indexT affiliateModule
Definition IR.h:832
enum yoi::IRExternEntry::externType type
yoi::indexTable< yoi::wstr, Argument > templateArguments
Definition IR.h:545
IRTemplateBuilder & addTemplateArgument(const yoi::wstr &templateName, const std::shared_ptr< IRValueType > &templateType, const yoi::vec< externModuleAccessExpression * > &satisfyConditions={})
Definition IR.cpp:1012
Opcode
Definition IR.h:274
externModuleAccessExpression * rhs
Definition ast.hpp:440
primary * lhs
Definition ast.hpp:438
lexer::token op
Definition ast.hpp:439
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:247
yoi::vec< yoi::rExpr * > exprs
Definition ast.hpp:218
vec< inCodeBlockStmt * > & getStmts()
Definition ast.cpp:471
lexer::token name
Definition ast.hpp:1115
union yoi::conceptStmt::ConceptStmtValue value
enum yoi::conceptStmt::Kind kind
defTemplateArg * tempArgs
Definition ast.hpp:993
definitionArguments & getArgs()
Definition ast.cpp:988
codeBlock & getBlock()
Definition ast.cpp:996
definitionArguments & getArgs()
Definition ast.cpp:992
structDefInner & getInner()
Definition ast.cpp:339
identifier * id
Definition ast.hpp:723
rExpr * expr
Definition ast.hpp:615
vec< defTemplateArgSpec * > & get()
Definition ast.cpp:27
vec< defTemplateArgSpec * > spec
Definition ast.hpp:279
vec< identifierWithTypeSpec * > spec
Definition ast.hpp:307
vec< identifierWithTypeSpec * > & get()
Definition ast.cpp:43
vec< enumerationPair * > values
Definition ast.hpp:1099
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:1050
identifier * as
Definition ast.hpp:1051
yoi::vec< lexer::token > attrs
Definition ast.hpp:1049
vec< identifierWithTemplateArg * > & getTerms()
Definition ast.cpp:1004
codeBlock * block
Definition ast.hpp:881
inCodeBlockStmt * afterStmt
Definition ast.hpp:880
inCodeBlockStmt * initStmt
Definition ast.hpp:878
rExpr * cond
Definition ast.hpp:879
codeBlock * block
Definition ast.hpp:624
typeSpec & getResultType()
Definition ast.cpp:279
codeBlock & getBlock()
Definition ast.cpp:283
identifierWithDefTemplateArg * id
Definition ast.hpp:621
definitionArguments & getArgs()
Definition ast.cpp:275
identifierWithDefTemplateArg & getId()
Definition ast.cpp:271
yoi::vec< lexer::token > attrs
Definition ast.hpp:620
externModuleAccessExpression * name
Definition ast.hpp:241
unnamedDefinitionArguments * args
Definition ast.hpp:242
union yoi::globalStmt::vValue value
enum yoi::globalStmt::vKind kind
marcoDescriptor * marco
Definition ast.hpp:817
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:254
lexer::token & get()
Definition ast.cpp:12
vec< ifBlock > elifB
Definition ast.hpp:854
codeBlock * elseB
Definition ast.hpp:855
ifBlock & getIfBlock()
Definition ast.cpp:403
bool hasElseBlock() const
Definition ast.cpp:415
bool isFinalizer() const
Definition ast.cpp:1206
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:764
implInner & getInner()
Definition ast.cpp:371
externModuleAccessExpression & getStructId()
Definition ast.cpp:363
externModuleAccessExpression * structName
Definition ast.hpp:763
externModuleAccessExpression * interfaceName
Definition ast.hpp:762
lexer::token from_path
Definition ast.hpp:1057
innerMethodDecl * inner
Definition ast.hpp:1056
vKind & getKind()
Definition ast.cpp:463
marcoDescriptor * marco
Definition ast.hpp:936
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:182
typeSpec & getResultType()
Definition ast.cpp:968
definitionArguments & getArgs()
Definition ast.cpp:964
typeSpec * resultType
Definition ast.hpp:965
yoi::vec< lexer::token > attrs
Definition ast.hpp:962
identifierWithDefTemplateArg * name
Definition ast.hpp:963
definitionArguments * args
Definition ast.hpp:964
identifierWithDefTemplateArg & getName()
Definition ast.cpp:960
typeSpec & getResultType()
Definition ast.cpp:980
identifierWithTemplateArg & getName()
Definition ast.cpp:972
codeBlock & getBlock()
Definition ast.cpp:984
definitionArguments & getArgs()
Definition ast.cpp:976
yoi::vec< lexer::token > attrs
Definition ast.hpp:976
vec< interfaceDefInnerPair * > & getInner()
Definition ast.cpp:299
identifierWithDefTemplateArg * id
Definition ast.hpp:659
interfaceDefInner & getInner()
Definition ast.cpp:307
vec< rExpr * > & get()
Definition ast.cpp:39
vec< rExpr * > arg
Definition ast.hpp:300
codeBlock * block
Definition ast.hpp:701
vec< yoi::lambdaCapture * > captures
Definition ast.hpp:698
typeSpec * resultType
Definition ast.hpp:700
definitionArguments * args
Definition ast.hpp:699
rExpr * rhs
Definition ast.hpp:465
uniqueExpr * lhs
Definition ast.hpp:464
lexer::token & getOp()
Definition ast.cpp:123
bool hasRhs() const
Definition ast.cpp:135
vec< letAssignmentPair * > terms
Definition ast.hpp:795
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:236
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:399
invocationArguments * args
Definition ast.hpp:400
externModuleAccessExpression * type
Definition ast.hpp:398
lambdaExpr * lambda
Definition ast.hpp:424
enum yoi::primary::primaryKind kind
funcExpr * func
Definition ast.hpp:425
memberExpr * member
Definition ast.hpp:418
rExpr * expr
Definition ast.hpp:420
basicLiterals * literals
Definition ast.hpp:419
newExpression * newExpr
Definition ast.hpp:423
bracedInitalizerList * bracedInitalizer
Definition ast.hpp:426
typeIdExpression * typeId
Definition ast.hpp:421
dynCastExpression * dynCast
Definition ast.hpp:422
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:907
bool hasValue() const
Definition ast.cpp:459
externModuleAccessExpression * emae
Definition ast.hpp:1140
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:713
identifierWithDefTemplateArg & getId()
Definition ast.cpp:327
structDefInner & getInner()
Definition ast.cpp:331
vec< subscript * > & getSubscript()
Definition ast.cpp:1084
identifierWithTemplateArg * id
Definition ast.hpp:381
rExpr * expr
Definition ast.hpp:345
vec< templateArgSpec * > spec
Definition ast.hpp:293
vec< templateArgSpec * > & get()
Definition ast.cpp:35
yoi::identifierWithDefTemplateArg * lhs
Definition ast.hpp:223
yoi::typeSpec * rhs
Definition ast.hpp:224
typeSpec * type
Definition ast.hpp:1081
decltypeExpr * decltypeExpression
Definition ast.hpp:334
yoi::vec< uint64_t > * arraySubscript
Definition ast.hpp:336
externModuleAccessExpression * member
Definition ast.hpp:331
funcTypeSpec * func
Definition ast.hpp:332
enum yoi::typeSpec::typeSpecKind kind
lexer::token & getOp()
Definition ast.cpp:111
abstractExpr * lhs
Definition ast.hpp:452
vec< typeSpec * > types
Definition ast.hpp:1093
identifier * name
Definition ast.hpp:605
lexer::token path
Definition ast.hpp:606
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:869
rExpr * cond
Definition ast.hpp:868
rExpr * expr
Definition ast.hpp:1110
std::string wstring2string(const std::wstring &v)
Definition def.cpp:230
std::shared_ptr< T > managedPtr(const T &v)
Definition def.hpp:335
wstr::value_type wchar
Definition def.hpp:52
std::vector< t > vec
Definition def.hpp:56
yoi::wstr realpath(const std::wstring &path)
Definition def.cpp:236
thread_local yoi::wstr __current_file_path
Definition def.cpp:15
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:217
void set_current_file_path(const std::wstring &path)
Definition def.cpp:123
std::wstring wstr
Definition def.hpp:51
uint64_t indexT
Definition def.hpp:54
void panic(yoi::indexT line, yoi::indexT col, const std::string &msg)
Definition def.cpp:141
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:1649
yoi::indexT column
Definition IR.h:89
yoi::indexT line
Definition IR.h:88
Builder & setDebugInfo(const IRDebugInfo &debugInfo)
Definition IR.cpp:1213
yoi::vec< std::pair< yoi::wstr, std::shared_ptr< IRValueType > > > argumentTypes
Definition IR.h:512
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:1273
std::set< FunctionAttrs > attrs
Definition IR.h:514
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:846
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:823
enumerationDefinition * enumerationDefVal
Definition ast.hpp:830
useStmt * useStmtVal
Definition ast.hpp:820
implStmt * implStmtVal
Definition ast.hpp:824
interfaceDefStmt * interfaceDefStmtVal
Definition ast.hpp:821
letStmt * letStmtVal
Definition ast.hpp:825
conceptDefinition * conceptDefVal
Definition ast.hpp:831
funcDefStmt * funcDefStmtVal
Definition ast.hpp:826
typeAliasStmt * typeAliasStmtVal
Definition ast.hpp:829
exportDecl * exportDeclVal
Definition ast.hpp:828
structDefStmt * structDefStmtVal
Definition ast.hpp:822
importDecl * importDeclVal
Definition ast.hpp:827
forEachStmt * forEachStmtVal
Definition ast.hpp:941
returnStmt * returnStmtVal
Definition ast.hpp:942
continueStmt * continueStmtVal
Definition ast.hpp:943