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; }
//## Node Node.message(int error, String msg); static KMETHOD Node_Message(KonohaContext *kctx, KonohaStack *sfp) { kNode *node = sfp[0].asNode; kinfotag_t level = (kinfotag_t)sfp[1].intValue; kString *msg = sfp[2].asString; KReturn(SUGAR MessageNode(kctx, node, NULL, kNode_ns(node), level, "%s", kString_text(msg))); }
//## Node Node.message(int error, Token tk, String msg); static KMETHOD NodeToken_Message(KonohaContext *kctx, KonohaStack *sfp) { kNode *stmt = sfp[0].asNode; kinfotag_t level = (kinfotag_t)sfp[1].intValue; kString *msg = sfp[3].asString; KReturn(SUGAR MessageNode(kctx, stmt, sfp[2].asToken, kNode_ns(stmt), level, "%s", kString_text(msg))); }
static void kNode_AddMethodDeclNode(KonohaContext *kctx, kNode *bk, kToken *tokenClassName, kNode *classNode) { if(bk == NULL) { return; } size_t i; kNameSpace *ns = kNode_ns(classNode); kMethod *AddMethod = KLIB kNameSpace_GetMethodByParamSizeNULL(kctx, ns, KClass_NameSpace, KMethodName_("AddMethodDecl"), 1, KMethodMatch_NoOption); for(i = 0; i < kNode_GetNodeListSize(kctx, bk); i++) { kNode *stmt = bk->NodeList->NodeItems[i]; if(stmt->syn->keyword == KSymbol_TypeDeclPattern) continue; if(stmt->syn->keyword == KSymbol_MethodDeclPattern) { KLIB kObjectProto_SetObject(kctx, stmt, KSymbol_("ClassName"), KType_Token, tokenClassName); kNodeVar *classParentBlock = kNode_GetParentNULL(classNode); if(classParentBlock == NULL) { classParentBlock = KNewNode(ns); SUGAR kNode_AddNode(kctx, classParentBlock, classNode); kNode_Type(kctx, classParentBlock, KNode_Block, KType_void); } /* Create 'NameSpace.AddMethodDecl(stmt)' */ kNode *arg0 = new_ConstNode(kctx, ns, NULL, UPCAST(ns)); kNode *arg1 = new_ConstNode(kctx, ns, NULL, UPCAST(stmt)); kNode *callNode = SUGAR new_MethodNode(kctx, ns, KClass_NameSpace, AddMethod, 2, arg0, arg1); SUGAR kNode_AddNode(kctx, classParentBlock, callNode); } else { SUGAR MessageNode(kctx, stmt, NULL, NULL, WarnTag, "%s is not available within the class clause", KSymbol_Fmt2(stmt->syn->keyword)); } } }
static struct KVirtualCode *FuelVM_GenerateVirtualCode(KonohaContext *kctx, kMethod *mtd, kNode *block, int option) { if(unlikely(AbstractMethodPtr == 0)) { AbstractMethodPtr = mtd->invokeKMethodFunc; } kNameSpace *ns = kNode_ns(block); KBuilder builderbuf = {}, *builder = &builderbuf; FuelIRBuilder Builder = {}; INIT_GCSTACK(); IRBuilder_Init(&Builder, kctx, ns); builder->builder = &Builder; builder->common.api = ns->builderApi; Block *EntryBlock = CreateBlock(BLD(builder)); IRBuilder_setBlock(BLD(builder), EntryBlock); INode *Self = SetUpArguments(kctx, &Builder, mtd); SUGAR VisitNode(kctx, builder, block, NULL); if(!Block_HasTerminatorInst(BLD(builder)->Current)) { if(mtd->mn == MN_new) { INode *Ret = CreateReturn(BLD(builder), Self); INode_setType(Ret, ConvertToTypeId(kctx, mtd->typeId)); } else { ktypeattr_t retTy = kMethod_GetReturnType(mtd)->typeId; if(retTy == KType_void) { CreateReturn(BLD(builder), 0); } else { enum TypeId Type = ConvertToTypeId(kctx, retTy); INode *Ret; if(KType_Is(UnboxType, retTy)) { SValue V; V.bits = 0; Ret = CreateConstant(BLD(builder), Type, V); } else { kObject *obj = KLIB Knull(kctx, KClass_(retTy)); Ret = CreateObject(BLD(builder), Type, (void *)obj); } Ret = CreateReturn(BLD(builder), Ret); INode_setType(Ret, Type); CreateReturn(BLD(builder), 0); } } } RESET_GCSTACK(); IMethod Mtd = {kctx, mtd, EntryBlock, ns}; BLD(builder)->Method = &Mtd; bool JITCompiled = false; union ByteCode *code = IRBuilder_Compile(BLD(builder), &Mtd, option, &JITCompiled); if(mtd->invokeKMethodFunc == FuelVM_RunVirtualMachine) { mtd->virtualCodeApi_plus1[-1]->FreeVirtualCode(kctx, mtd->vcode_start); } KLIB kMethod_SetFunc(kctx, mtd, 0); if(JITCompiled) { KLIB kMethod_SetFunc(kctx, mtd, (KMethodFunc) code); } KFieldSet(mtd, ((kMethodVar *)mtd)->CompiledNode, block); IRBuilder_Exit(&Builder); return (struct KVirtualCode *) code; }
//## Node Node.TypeCheckNode(Symbol key, Object type, int policy); static KMETHOD Node_TypeCheckNode(KonohaContext *kctx, KonohaStack *sfp) { kNode *node = sfp[0].asNode; ksymbol_t key = (ksymbol_t)sfp[1].intValue; KClass *type = kObject_class(sfp[2].asObject); int policy = sfp[3].intValue; KReturn(SUGAR TypeCheckNodeByName(kctx, node, key, kNode_ns(node), type, policy)); }
//## 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)); }
//## Node Node.ParseNewNode(Token[] tokenList, int beginIdx, int endIdx, boolean isMetaPattern); static KMETHOD Node_ParseNewNode(KonohaContext *kctx, KonohaStack *sfp) { kNode *stmt = sfp[0].asNode; kArray *tokenList = sfp[1].asArray; int beginIdx = (int)sfp[2].intValue; int endIdx = (int)sfp[3].intValue; ParseOption opt = (sfp[4].boolValue == true) ? ParseMetaPatternOption : 0; KReturn(SUGAR ParseNewNode(kctx, kNode_ns(stmt), tokenList, &beginIdx, endIdx, opt, NULL)); }
//## Node Node.newMethodNode(Object type, Symbol keyword, Node expr1); static KMETHOD Node_newMethodNode1(KonohaContext *kctx, KonohaStack *sfp) { kNameSpace *ns = kNode_ns(sfp[0].asNode); KClass *type = kObject_class(sfp[1].asObject); ksymbol_t keyword = (ksymbol_t)sfp[2].intValue; kNode *expr1 = sfp[3].asNode; kMethod *mtd = KLIB kNameSpace_GetMethodByParamSizeNULL(kctx, ns, type, keyword, 0, KMethodMatch_NoOption); if(mtd == NULL) { KReturn(KNULL(Node)); } KReturn(SUGAR new_MethodNode(kctx, ns, type, mtd, 1, expr1)); }
static kNode* kNode_ParseClassNodeNULL(KonohaContext *kctx, kNode *stmt, kToken *tokenClassName) { kNode *block = NULL; kTokenVar *blockToken = (kTokenVar *)kNode_GetObject(kctx, stmt, KSymbol_BlockPattern, NULL); if(blockToken != NULL) { kNameSpace *ns = kNode_ns(stmt); SUGAR kToken_ToBraceGroup(kctx, blockToken, ns, NULL); KTokenSeq source = {ns, RangeGroup(blockToken->GroupTokenList)}; block = SUGAR ParseNewNode(kctx, ns, source.tokenList, &source.beginIdx, source.endIdx, ParseMetaPatternOption, NULL); KLIB kObjectProto_SetObject(kctx, stmt, KSymbol_BlockPattern, KType_Node, block); } return block; }
static KMETHOD Expression_Defined(KonohaContext *kctx, KonohaStack *sfp) { VAR_Expression(expr, tokenList, beginIdx, currentIdx, endIdx); kNameSpace *ns = kNode_ns(expr); if(beginIdx == currentIdx && beginIdx + 1 < endIdx) { kTokenVar *definedToken = tokenList->TokenVarItems[beginIdx]; // defined kTokenVar *pToken = tokenList->TokenVarItems[beginIdx+1]; if(IS_Array(pToken->GroupTokenList)) { SUGAR kNode_Op(kctx, expr, definedToken, 0); FilterDefinedParam(kctx, ns, RangeGroup(pToken->GroupTokenList)); KReturn(SUGAR AppendParsedNode(kctx, expr, RangeGroup(pToken->GroupTokenList), NULL, ParseExpressionOption, "(")); } } }
static KMETHOD Expression_isNotNull(KonohaContext *kctx, KonohaStack *sfp) { VAR_Expression(stmt, tokenList, beginIdx, opIdx, endIdx); if(opIdx + 2 == endIdx) { DBG_P("checking .. x != null"); kTokenVar *tk = tokenList->TokenVarItems[opIdx+1]; if(tk->symbol == KSymbol_("null") || tk->symbol == KSymbol_("NULL")) { kNameSpace *ns = kNode_ns(stmt); tk->symbol = KSymbol_("IsNotNull"); tk->resolvedSyntaxInfo = tokenList->TokenVarItems[opIdx]->resolvedSyntaxInfo; SUGAR kNode_Op(kctx, stmt, tk, 1, SUGAR ParseNewNode(kctx, ns, tokenList, &beginIdx, opIdx, ParseExpressionOption, NULL)); KReturnUnboxValue(opIdx + 2); } } DBG_P("checking parent .. != .."); KReturnUnboxValue(-1); }
static KMETHOD PatternMatch_ForStmt(KonohaContext *kctx, KonohaStack *sfp) { VAR_PatternMatch(stmt, name, tokenList, beginIdx, endIdx); /* for(IniitExpr; CondExpr; IterateExpr) $Block */ kNameSpace *ns = kNode_ns(stmt); int i, start = beginIdx; /* InitExpression Part */ for(i = beginIdx; i < endIdx; i++) { kTokenVar *tk = tokenList->TokenVarItems[i]; if(tk->symbol == KSymbol_SEMICOLON) { if(start < i) { kNode *node = SUGAR ParseNewNode(kctx, ns, tokenList, &start, i, ParseMetaPatternOption, NULL); SUGAR kNode_AddParsedObject(kctx, stmt, KSymbol_("init"), UPCAST(node)); } start = i + 1; break; } } if(start == beginIdx) { KReturnUnboxValue(-1); } /* CondExpression Part */ for(i = start; i < endIdx; i++) { kTokenVar *tk = tokenList->TokenVarItems[i]; if(tk->symbol == KSymbol_SEMICOLON) { if(start < i) { kNode *node = SUGAR ParseNewNode(kctx, ns, tokenList, &start, i, ParseExpressionOption, NULL); KDump(node); SUGAR kNode_AddParsedObject(kctx, stmt, KSymbol_ExprPattern, UPCAST(node)); } start = i + 1; break; } } if(i == endIdx) { KReturnUnboxValue(-1); } /* IterExpression Part */ if(start < endIdx) { kNode *node = SUGAR ParseNewNode(kctx, ns, tokenList, &start, endIdx, ParseMetaPatternOption, NULL); SUGAR kNode_AddParsedObject(kctx, stmt, KSymbol_("Iterator"), UPCAST(node)); } KReturnUnboxValue(endIdx); }
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 Statement_namespace(KonohaContext *kctx, KonohaStack *sfp) { VAR_TypeCheck(stmt, ns, reqc); kstatus_t result = K_CONTINUE; kToken *tk = SUGAR kNode_GetToken(kctx, stmt, KSymbol_BlockPattern, NULL); if(tk != NULL && tk->resolvedSyntaxInfo->keyword == TokenType_LazyBlock) { INIT_GCSTACK(); kNameSpace *ns = new_(NameSpace, kNode_ns(stmt), _GcStack); KTokenSeq range = {ns, KGetParserContext(kctx)->preparedTokenList}; KTokenSeq_Push(kctx, range); SUGAR Tokenize(kctx, ns, kString_text(tk->text), tk->uline, tk->indent, range.tokenList); KTokenSeq_End(kctx, range); result = SUGAR EvalTokenList(kctx, &range, NULL/*trace*/); KTokenSeq_Pop(kctx, range); RESET_GCSTACK(); kNode_Type(kctx, stmt, KNode_Done, KType_void); } KReturnUnboxValue(result == K_CONTINUE); }
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 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_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 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 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); }
//## boolean Node.getNameSpace(); static KMETHOD Node_getNameSpace(KonohaContext *kctx, KonohaStack *sfp) { KReturn(kNode_ns(sfp[0].asNode)); }