static KMETHOD TypeCheck_Getter(KonohaContext *kctx, KonohaStack *sfp) { VAR_TypeCheck2(stmt, expr, ns, reqc); kToken *fieldToken = expr->NodeList->TokenItems[0]; ksymbol_t fn = fieldToken->symbol; kNode *self = KLIB TypeCheckNodeAt(kctx, expr, 1, ns, KClass_INFER, 0); if(self != K_NULLNODE) { kMethod *mtd = KLIB kNameSpace_GetGetterMethodNULL(kctx, ns, KClass_(self->typeAttr), fn); if(mtd != NULL) { KFieldSet(expr->NodeList, expr->NodeList->MethodItems[0], mtd); KReturn(KLIB TypeCheckMethodParam(kctx, mtd, expr, ns, reqc)); } else { // dynamic field o.name => o.get(name) kparamtype_t p[1] = {{KType_Symbol}}; kparamId_t paramdom = KLIB Kparamdom(kctx, 1, p); mtd = KLIB kNameSpace_GetMethodBySignatureNULL(kctx, ns, KClass_(self->typeAttr), KMethodNameAttr_Getter, paramdom, 1, p); if(mtd != NULL) { KFieldSet(expr->NodeList, expr->NodeList->MethodItems[0], mtd); KLIB kArray_Add(kctx, expr->NodeList, new_UnboxConstNode(kctx, ns, KType_Symbol, KSymbol_Unmask(fn))); KReturn(KLIB TypeCheckMethodParam(kctx, mtd, expr, ns, reqc)); } } KLIB MessageNode(kctx, stmt, fieldToken, ns, ErrTag, "undefined field: %s", kString_text(fieldToken->text)); } }
//## Node Node.TypeCheckNodeAt(int pos, Object type, int policy); static KMETHOD Node_TypeCheckNodeAt(KonohaContext *kctx, KonohaStack *sfp) { kNode *node = sfp[0].asNode; size_t pos = sfp[1].intValue; KClass *type = kObject_class(sfp[2].asObject); int policy = sfp[3].intValue; KReturn(SUGAR TypeCheckNodeAt(kctx, node, pos, kNode_ns(node), type, policy)); }
static KMETHOD TypeCheck_as(KonohaContext *kctx, KonohaStack *sfp) { VAR_TypeCheck2(stmt, expr, ns, reqc); kNode *targetNode = SUGAR TypeCheckNodeAt(kctx, expr, 2, ns, KClass_INFER, 0); kNode *selfNode = SUGAR TypeCheckNodeAt(kctx, expr, 1, ns, KClass_(targetNode->attrTypeId), TypeCheckPolicy_NoCheck); if(selfNode != K_NULLNODE && targetNode != K_NULLNODE) { KClass *selfClass = KClass_(selfNode->attrTypeId), *targetClass = KClass_(targetNode->attrTypeId); if(selfClass->typeId == targetClass->typeId || selfClass->isSubType(kctx, selfClass, targetClass)) { KReturn(selfNode); } if(selfClass->isSubType(kctx, targetClass, selfClass)) { kNameSpace *ns = kNode_ns(stmt); kMethod *mtd = KLIB kNameSpace_GetMethodByParamSizeNULL(kctx, ns, KClass_Object, KMethodName_("as"), 0, KMethodMatch_CamelStyle); DBG_ASSERT(mtd != NULL); KReturn(SUGAR TypeCheckMethodParam(kctx, mtd, expr, ns, targetClass)); } KReturn(SUGAR MessageNode(kctx, selfNode, NULL, ns, ErrTag, "unable to downcast: %s as %s", KType_text(selfNode->attrTypeId), KType_text(targetNode->attrTypeId))); } }
static KMETHOD TypeCheck_InstanceOf(KonohaContext *kctx, KonohaStack *sfp) { VAR_TypeCheck2(stmt, expr, ns, reqc); /* selfNode and targetNode allow void type * e.g. "'a' instanceof void" */ kNode *selfNode = SUGAR TypeCheckNodeAt(kctx, expr, 1, ns, KClass_INFER, TypeCheckPolicy_AllowVoid); kNode *targetNode = SUGAR TypeCheckNodeAt(kctx, expr, 2, ns, KClass_INFER, TypeCheckPolicy_AllowVoid); if(selfNode != K_NULLNODE && targetNode != K_NULLNODE) { KClass *selfClass = KClass_(selfNode->attrTypeId), *targetClass = KClass_(targetNode->attrTypeId); if(KClass_Is(Final, selfClass)) { kbool_t staticSubType = (selfClass == targetClass || selfClass->isSubType(kctx, selfClass, targetClass)); KReturn(SUGAR kNode_SetUnboxConst(kctx, expr, KType_Boolean, staticSubType)); } kNameSpace *ns = kNode_ns(stmt); kMethod *mtd = KLIB kNameSpace_GetMethodByParamSizeNULL(kctx, ns, KClass_Object, KMethodName_("instanceof"), 1, KMethodMatch_NoOption); DBG_ASSERT(mtd != NULL); kNode *classValue = SUGAR kNode_SetConst(kctx, expr->NodeList->NodeVarItems[2], NULL, KLIB Knull(kctx, targetClass)); KFieldSet(expr->NodeList, expr->NodeList->NodeItems[2], classValue); KReturn(SUGAR TypeCheckMethodParam(kctx, mtd, expr, ns, KClass_Boolean)); } }
static KMETHOD TypeCheck_to(KonohaContext *kctx, KonohaStack *sfp) { VAR_TypeCheck2(stmt, expr, ns, reqc); kNode *targetNode = SUGAR TypeCheckNodeAt(kctx, expr, 2, ns, KClass_INFER, 0); kNode *selfNode = SUGAR TypeCheckNodeAt(kctx, expr, 1, ns, KClass_(targetNode->attrTypeId), TypeCheckPolicy_NoCheck); if(selfNode != K_NULLNODE && targetNode != K_NULLNODE) { KClass *selfClass = KClass_(selfNode->attrTypeId), *targetClass = KClass_(targetNode->attrTypeId); if(selfNode->attrTypeId == targetNode->attrTypeId || selfClass->isSubType(kctx, selfClass, targetClass)) { SUGAR MessageNode(kctx, selfNode, NULL, ns, InfoTag, "no need: %s to %s", KType_text(selfNode->attrTypeId), KType_text(targetNode->attrTypeId)); KReturn(selfNode); } kNameSpace *ns = kNode_ns(stmt); kMethod *mtd = KLIB kNameSpace_GetCoercionMethodNULL(kctx, ns, selfClass, targetClass); if(mtd == NULL) { mtd = KLIB kNameSpace_GetMethodByParamSizeNULL(kctx, ns, selfClass, KMethodName_("to"), 0, KMethodMatch_CamelStyle); DBG_ASSERT(mtd != NULL); // because Object.to is found. if(mtd->typeId != selfClass->typeId) { KReturn(SUGAR MessageNode(kctx, selfNode, NULL, ns, ErrTag, "undefined coercion: %s to %s", KClass_text(selfClass), KClass_text(targetClass))); } } KReturn(SUGAR TypeCheckMethodParam(kctx, mtd, expr, ns, targetClass)); } }
static KMETHOD TypeCheck_UntypedAssign(KonohaContext *kctx, KonohaStack *sfp) { VAR_TypeCheck2(stmt, expr, ns, reqc); kNodeVar *leftHandNode = (kNodeVar *)kNode_At(expr, 1); if(kNode_isSymbolTerm(leftHandNode)) { kNode *texpr = KLIB TypeVariableNULL(kctx, leftHandNode, ns, KClass_INFER); if(texpr == NULL) { kNode *rightHandNode = KLIB TypeCheckNodeAt(kctx, expr, 2, ns, KClass_INFER, 0); if(rightHandNode != K_NULLNODE) { DeclVariable(kctx, stmt, ns, rightHandNode->typeAttr, leftHandNode); } } else { KFieldSet(expr->NodeList, expr->NodeList->NodeItems[1], texpr); } } }
static KMETHOD TypeCheck_Defined(KonohaContext *kctx, KonohaStack *sfp) { VAR_TypeCheck2(stmt, expr, ns, reqc); size_t i; kbool_t isDefined = true; KParserContext *sugarContext = KGetParserContext(kctx); int popIsBlockingErrorMessage = sugarContext->isBlockedErrorMessage; sugarContext->isBlockedErrorMessage = true; for(i = 1; i < kArray_size(expr->NodeList); i++) { kNode *typedNode = SUGAR TypeCheckNodeAt(kctx, expr, i, ns, KClass_INFER, TypeCheckPolicy_AllowVoid); if(kNode_IsError(typedNode)) { isDefined = false; break; } } sugarContext->isBlockedErrorMessage = popIsBlockingErrorMessage; KReturn(SUGAR kNode_SetUnboxConst(kctx, expr, KType_Boolean, isDefined)); }
static kbool_t kNode_AddClassField(KonohaContext *kctx, kNode *stmt, kNameSpace *ns, KClassVar *definedClass, ktypeattr_t ty, kNode *expr) { if(expr->syn->keyword == KSymbol_LET) { // String name = "naruto"; kNode *lexpr = kNode_At(expr, 1); if(kNode_IsTerm(lexpr)) { kString *name = lexpr->TermToken->text; ksymbol_t symbol = KAsciiSymbol(kString_text(name), kString_size(name), KSymbol_NewId); kNode *vexpr = SUGAR TypeCheckNodeAt(kctx, expr, 2, ns, KClass_(ty), 0); if(vexpr == K_NULLNODE) return false; if(vexpr->node == KNode_Const) { KLIB KClass_AddField(kctx, definedClass, ty, symbol); KClass_SetClassFieldObjectValue(kctx, definedClass, symbol, vexpr->ObjectConstValue); } else if(vexpr->node == KNode_UnboxConst) { KLIB KClass_AddField(kctx, definedClass, ty, symbol); KClass_SetClassFieldUnboxValue(kctx, definedClass, symbol, vexpr->unboxConstValue); } else if(vexpr->node == KNode_Null) { KLIB KClass_AddField(kctx, definedClass, ty, symbol); } else { SUGAR MessageNode(kctx, stmt, lexpr->TermToken, ns, ErrTag, "field initial value must be const: %s", kString_text(name)); return false; } return true; } } else if(expr->syn->keyword == KSymbol_COMMA) { // String (firstName = naruto, lastName) size_t i; for(i = 1; i < kNode_GetNodeListSize(kctx, expr); i++) { if(!kNode_AddClassField(kctx, stmt, ns, definedClass, ty, kNode_At(expr, i))) return false; } return true; } else if(kNode_IsTerm(expr)) { // String name kString *name = expr->TermToken->text; ksymbol_t symbol = KAsciiSymbol(kString_text(name), kString_size(name), KSymbol_NewId); KLIB KClass_AddField(kctx, definedClass, ty, symbol); return true; } SUGAR MessageNode(kctx, stmt, NULL, ns, ErrTag, "field name is expected"); return false; }