static kbool_t FuelVM_VisitAssignNode(KonohaContext *kctx, KBuilder *builder, kNode *expr, void *thunk) { /* * [LetExpr] := lhs = rhs * expr->NodeList = [NULL, lhs, rhs] **/ kNode *left = kNode_At(expr, 1); kNode *right = kNode_At(expr, 2); INode *Node; FuelIRBuilder *flbuilder = BLD(builder); if(left->node == KNode_Local) { enum TypeId type = ConvertToTypeId(kctx, left->attrTypeId); if((Node = IRBuilder_FindLocalVarByHash(flbuilder, type, left->index)) == 0) { Node = CreateLocal(flbuilder, type); IField_setHash((IField *) Node, left->index); } SUGAR VisitNode(kctx, builder, right, thunk); INode *RHS = FuelVM_getExpression(builder); //if(RHS->Type != Node->Type) { // INode_setType(Node, RHS->Type); //} CreateUpdate(flbuilder, Node, RHS); } //else if(left->node == TEXPR_STACKTOP) { // enum TypeId type = ConvertToTypeId(kctx, left->attrTypeId); // uintptr_t Hash = (uintptr_t) left; // if((Node = IRBuilder_FindLocalVarByHash(flbuilder, type, Hash)) == 0) { // Node = CreateLocal(flbuilder, type); // IField_setHash((IField *) Node, Hash); // ARRAY_add(INodePtr, &BLD(builder)->Stack, Node); // } // SUGAR VisitNode(kctx, builder, right, thunk); // INode *RHS = FuelVM_getExpression(builder); // if(RHS->Type != Node->Type) // INode_setType(Node, RHS->Type); // CreateUpdate(BLD(builder), Node, RHS); //} else{ assert(left->node == KNode_Field); SUGAR VisitNode(kctx, builder, right, thunk); kshort_t index = (kshort_t)left->index; kshort_t xindex = (kshort_t)(left->index >> (sizeof(kshort_t)*8)); INode *Left; if((Left = IRBuilder_FindLocalVarByHash(BLD(builder), TYPE_Object, index)) == 0) { Left = CreateLocal(BLD(builder), TYPE_Object); IField_setHash((IField *) Left, index); } enum TypeId type = ConvertToTypeId(kctx, left->attrTypeId); Node = CreateField(BLD(builder), FieldScope, type, Left, xindex); SUGAR VisitNode(kctx, builder, right, thunk); CreateUpdate(BLD(builder), Node, FuelVM_getExpression(builder)); } builder->Value = Node; return true; }
static kbool_t KBuilder_VisitMethodCallNode(KonohaContext *kctx, KBuilder *builder, kNode *expr, void *thunk) { kshort_t a = AssignStack(thunk), espidx = expr->stackbase, thisidx = espidx + K_CALLDELTA; DBG_ASSERT(a <= espidx); kMethod *mtd = CallNode_getMethod(expr); DBG_ASSERT(IS_Method(mtd)); int i, s = kMethod_Is(Static, mtd) ? 2 : 1; int argc = CallNode_getArgCount(expr); for (i = s; i < argc + 2; i++) { intptr_t a = thisidx + i - 1; kNode *paramNode = kNode_At(expr, i); if(!kNode_IsValue(paramNode) && paramNode->stackbase != a) { DBG_P("a=%d, stackbase=%d", a, paramNode->stackbase); DBG_ASSERT(paramNode->stackbase == a); } SUGAR VisitNode(kctx, builder, paramNode, &a); } if(kMethod_Is(Final, mtd) || !kMethod_Is(Virtual, mtd)) { ASM(NSET, NC_(thisidx-1), (intptr_t)mtd, KClass_Method); if(kMethod_Is(Virtual, mtd)) { // set namespace to enable method lookups ASM(NSET, OC_(thisidx-2), (intptr_t)kNode_ns(expr), KClass_NameSpace); } } else { ASM(NSET, OC_(thisidx-2), (intptr_t)kNode_ns(expr), KClass_NameSpace); ASM(LOOKUP, SFP_(thisidx), kNode_ns(expr), mtd); } int esp_ = SFP_(espidx + argc + K_CALLDELTA + 1); ASM(CALL, builder->common.uline, SFP_(thisidx), esp_, KLIB Knull(kctx, KClass_(expr->attrTypeId))); ReAssignNonValueNode(kctx, builder, a, expr); return true; }
static INode *FetchINode(KonohaContext *kctx, KBuilder *builder, kNode *expr, unsigned idx, ktypeattr_t reqTy, void *thunk) { kNode *exprN = kNode_At(expr, idx); SUGAR VisitNode(kctx, builder, exprN, thunk); INode *Node = FuelVM_getExpression(builder); assert(Node->Type != TYPE_void); return Node; }
static void CreateCond(KonohaContext *kctx, KBuilder *builder, kNode *expr, enum ConditionalOp Op, void *thunk) { kNode *LHS = kNode_At(expr, 1); kNode *RHS = kNode_At(expr, 2); Block *HeadBB = CreateBlock(BLD(builder)); Block *ThenBB = CreateBlock(BLD(builder)); Block *MergeBB = CreateBlock(BLD(builder)); /* [CondExpr] * LogicalAnd case * | goto Head * Head | let bval = LHS * | if(bval) { goto Then } else { goto Merge } * Then | bval = RHS * | goto Merge * Merge | ... */ INode *Node; IRBuilder_JumpTo(BLD(builder), HeadBB); { /* Head */ IRBuilder_setBlock(BLD(builder), HeadBB); Node = CreateLocal(BLD(builder), TYPE_boolean); SUGAR VisitNode(kctx, builder, LHS, thunk); INode *Left = FuelVM_getExpression(builder); CreateUpdate(BLD(builder), Node, Left); if(Op == LogicalAnd) { CreateBranch(BLD(builder), Left, ThenBB, MergeBB); } else { CreateBranch(BLD(builder), Left, MergeBB, ThenBB); } } { /* Then */ IRBuilder_setBlock(BLD(builder), ThenBB); SUGAR VisitNode(kctx, builder, RHS, thunk); INode *Right = FuelVM_getExpression(builder); CreateUpdate(BLD(builder), Node, Right); IRBuilder_JumpTo(BLD(builder), MergeBB); } IRBuilder_setBlock(BLD(builder), MergeBB); builder->Value = Node; }
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; }
static KMETHOD Expression_LispOperator(KonohaContext *kctx, KonohaStack *sfp) { VAR_Expression(expr, tokenList, beginIdx, currentIdx, endIdx); kNameSpace *ns = kNode_ns(expr); if(beginIdx == currentIdx && beginIdx + 1 < endIdx) { kTokenVar *opToken = tokenList->TokenVarItems[beginIdx]; kNode_Type(kctx, expr, KNode_Block, KType_var); int i = beginIdx + 1; SUGAR kNode_Op(kctx, expr, opToken, 0); while(i < endIdx) { int orig = i; kNode *node = SUGAR ParseNewNode(kctx, ns, tokenList, &i, i+1, ParseExpressionOption, "("); SUGAR kNode_AddNode(kctx, expr, node); assert(i != orig); } int size = kNode_GetNodeListSize(kctx, expr); if(size == 1) { /* case (+) */ assert(0 && "(+) is not supported"); } else if(size == 2) { /* case (+ 1) */ KReturnUnboxValue(endIdx); } /* (+ 1 2 3 4) => (+ (+ (+ 1 2) 3 ) 4) */ kNode *leftNode = kNode_At(expr, 1), *rightNode; for(i = 2; i < size-1; i++) { kNode *node = KNewNode(ns); rightNode = kNode_At(expr, i); SUGAR kNode_Op(kctx, node, opToken, 2, leftNode, rightNode); leftNode = node; } rightNode = kNode_At(expr, i); KLIB kArray_Clear(kctx, expr->NodeList, 1); KLIB kArray_Add(kctx, expr->NodeList, leftNode); KLIB kArray_Add(kctx, expr->NodeList, rightNode); KDump(expr); KReturnUnboxValue(endIdx); } }
static kbool_t KBuilder_VisitAssignNode(KonohaContext *kctx, KBuilder *builder, kNode *expr, void *thunk) { kNode *leftHandNode = kNode_At(expr, 1); kNode *rightHandNode = kNode_At(expr, 2); //DBG_P("LET (%s) a=%d, shift=%d, espidx=%d", KType_text(expr->attrTypeId), a, shift, espidx); if(kNode_node(leftHandNode) == KNode_Local) { kshort_t a = AssignStack(thunk); SUGAR VisitNode(kctx, builder, rightHandNode, &(leftHandNode->index)); if(expr->attrTypeId != KType_void && a != leftHandNode->index) { AsmMOV(kctx, builder, a, KClass_(leftHandNode->attrTypeId), leftHandNode->index); } } else if(kNode_node(leftHandNode) == KNode_Field) { intptr_t espidx = expr->stackbase; SUGAR VisitNode(kctx, builder, rightHandNode, &espidx); kshort_t index = (kshort_t)leftHandNode->index; kshort_t xindex = (kshort_t)(leftHandNode->index >> (sizeof(kshort_t)*8)); KClass *lhsClass = KClass_(leftHandNode->attrTypeId), *rhClass = KClass_(rightHandNode->attrTypeId); ASM(XNMOV, OC_(index), xindex, TC_(espidx, rhClass), lhsClass); if(expr->attrTypeId != KType_void) { kshort_t a = AssignStack(thunk); ASM(NMOVx, TC_(a, rhClass), OC_(index), xindex, lhsClass); } }
static kbool_t FuelVM_VisitMethodCallNode(KonohaContext *kctx, KBuilder *builder, kNode *expr, void *thunk) { kMethod *mtd = CallNode_getMethod(expr); DBG_ASSERT(IS_Method(mtd)); enum TypeId Type = ConvertToTypeId(kctx, expr->attrTypeId); if(mtd->mn == KMethodName_("box")) { Type = ToBoxType(Type); } /* * [CallExpr] := this.method(arg1, arg2, ...) * expr->NodeList = [method, this, arg1, arg2, ...] **/ INode *Inst; if((Inst = CreateSpecialInstruction(kctx, builder, mtd, expr, thunk)) != 0) { INode_setType(Inst, Type); builder->Value = Inst; return true; } int i, s = kMethod_Is(Static, mtd) ? 2 : 1; int argc = CallExpr_getArgCount(expr); INode *Params[argc+2]; if(kMethod_Is(Static, mtd)) { kObject *obj = KLIB Knull(kctx, KClass_(mtd->typeId)); INode *Self = CreateObject(BLD(builder), mtd->typeId, (void *) obj); Params[1] = Self; } for (i = s; i < argc + 2; i++) { kNode *exprN = kNode_At(expr, i); DBG_ASSERT(IS_Node(exprN)); SUGAR VisitNode(kctx, builder, exprN, thunk); INode *Node = FuelVM_getExpression(builder); assert(Node->Type != TYPE_void); Params[i] = Node; } INode *MtdObj = CreateObject(BLD(builder), KType_Method, (void *) mtd); enum CallOp Op = (kMethod_Is(Virtual, mtd)) ? VirtualCall : DefaultCall; Params[0] = MtdObj; kNode *stmt = expr->Parent; assert(IS_Node(stmt)); Inst = CreateICall(BLD(builder), Type, Op, kNode_uline(stmt), Params, argc + 2); builder->Value = Inst; return true; }
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 kbool_t FuelVM_VisitFunctionNode(KonohaContext *kctx, KBuilder *builder, kNode *expr, void *thunk) { /* * [FunctionExpr] := new Function(method, env1, env2, ...) * expr->NodeList = [method, defObj, env1, env2, ...] **/ enum TypeId Type; kMethod *mtd = CallNode_getMethod(expr); kObject *obj = expr->NodeList->ObjectItems[1]; INode *MtdObj = CreateObject(BLD(builder), KType_Method, (void *) mtd); Type = ConvertToTypeId(kctx, kObject_class(obj)->typeId); INode *NewEnv = CreateNew(BLD(builder), 0, Type); size_t i, ParamSize = kArray_size(expr->NodeList)-2; for(i = 0; i < ParamSize; i++) { kNode *envN = kNode_At(expr, i+2); enum TypeId FieldType = ConvertToTypeId(kctx, envN->attrTypeId); INode *Node = CreateField(BLD(builder), FieldScope, FieldType, NewEnv, i); SUGAR VisitNode(kctx, builder, envN, thunk); CreateUpdate(BLD(builder), Node, FuelVM_getExpression(builder)); } Type = ConvertToTypeId(kctx, expr->attrTypeId); INode *NewFunc = CreateNew(BLD(builder), 0, Type); kNameSpace *ns = kNode_ns(expr); mtd = KLIB kNameSpace_GetMethodByParamSizeNULL(kctx, ns, KClass_Func, KMethodName_("_Create"), 2, KMethodMatch_NoOption); INode *CallMtd = CreateObject(BLD(builder), KType_Method, (void *) mtd); INode *Params[4]; Params[0] = CallMtd; Params[1] = NewFunc; Params[2] = NewEnv; Params[3] = MtdObj; builder->Value = CreateICall(BLD(builder), Type, DefaultCall, kNode_uline(expr), Params, 4); return true; }
static KMETHOD Expression_ExtendedTextLiteral(KonohaContext *kctx, KonohaStack *sfp) { VAR_Expression(expr, tokenList, beginIdx, opIdx, endIdx); kNameSpace *ns = kNode_ns(expr); kToken *tk = tokenList->TokenItems[opIdx]; INIT_GCSTACK(); kString *text = remove_escapes(kctx, tk); if(beginIdx != opIdx) { /* FIXME */ assert(0 && "FIXME"); KReturnUnboxValue(-1); } if(text == NULL) { /* text contain unsupported escape sequences */ RESET_GCSTACK(); KReturnUnboxValue(-1); } const char *str = kString_text(text); const char *end = NULL; const char *start = strstr(str, "${"); if(start == NULL) { /* text does not contain Interpolation expressions */ RESET_GCSTACK(); KReturnUnboxValue(beginIdx+1); } kSyntax *addSyntax = kSyntax_(ns, KSymbol_("+")); kTokenVar *opToken = tokenList->TokenVarItems[beginIdx]; opToken->symbol = KSymbol_("+"); opToken->text = KLIB new_kString(kctx, OnGcStack, "+", 1, 0); KFieldSet(opToken, opToken->resolvedSyntaxInfo, addSyntax); SUGAR kNode_Op(kctx, expr, opToken, 0); /* [before] "aaa${bbb}ccc" * [after] "" + "aaa" + bbb + "ccc" */ SUGAR kNode_AddNode(kctx, expr, new_ConstNode(kctx, ns, NULL, UPCAST(TS_EMPTY))); while(true) { start = strstr(str, "${"); if(start == NULL) break; if(start == strstr(str, "${}")) { str += 3; continue; } end = strchr(start, '}'); if(end == NULL) break; kNode *newexpr = ParseSource(kctx, ns, start+2, end-(start+2)); if(start - str > 0) { kNode *first = new_ConstNode(kctx, ns, NULL, UPCAST(KLIB new_kString(kctx, OnGcStack, str, (start - str), 0))); SUGAR kNode_AddNode(kctx, expr, first); } SUGAR kNode_AddNode(kctx, expr, newexpr); str = end + 1; } if((start == NULL) || (start != NULL && end == NULL)) { kNode *rest = new_ConstNode(kctx, ns, KClass_String, UPCAST(KLIB new_kString(kctx, OnGcStack, str, strlen(str), 0))); SUGAR kNode_AddNode(kctx, expr, rest); } /* (+ 1 2 3 4) => (+ (+ (+ 1 2) 3 ) 4) */ int i, size = kNode_GetNodeListSize(kctx, expr); assert(size > 2); kNode *leftNode = kNode_At(expr, 1), *rightNode; for(i = 2; i < size-1; i++) { kNode *node = KNewNode(ns); rightNode = kNode_At(expr, i); SUGAR kNode_Op(kctx, node, opToken, 2, leftNode, rightNode); leftNode = node; } rightNode = kNode_At(expr, i); KLIB kArray_Clear(kctx, expr->NodeList, 1); KLIB kArray_Add(kctx, expr->NodeList, leftNode); KLIB kArray_Add(kctx, expr->NodeList, rightNode); RESET_GCSTACK(); KReturnUnboxValue(beginIdx+1); }