static void kMethod_genCode(KonohaContext *kctx, kMethod *mtd, kBlock *bk) { DBG_P("START CODE GENERATION.."); INIT_GCSTACK(); if(ctxcode == NULL) { kmodcode->h.setup(kctx, NULL, 0); } KLIB kMethod_setFunc(kctx, mtd, MethodFunc_runVirtualMachine); DBG_ASSERT(kArray_size(ctxcode->codeList) == 0); kBasicBlock* lbINIT = new_BasicBlockLABEL(kctx); kBasicBlock* lbBEGIN = new_BasicBlockLABEL(kctx); ctxcode->lbEND = new_BasicBlockLABEL(kctx); PUSH_GCSTACK(lbINIT); PUSH_GCSTACK(lbBEGIN); PUSH_GCSTACK(ctxcode->lbEND); ctxcode->currentWorkingBlock = lbINIT; // BUILD_pushLABEL(kctx, NULL, lbBEGIN, lbEND); ASM(THCODE, _THCODE); ASM(CHKSTACK, 0); ASM_LABEL(kctx, lbBEGIN); BLOCK_asm(kctx, bk, 0); ASM_LABEL(kctx, ctxcode->lbEND); if (mtd->mn == MN_new) { ASM(NMOV, OC_(K_RTNIDX), OC_(0), CT_(mtd->typeId)); // FIXME: Type 'This' must be resolved } ASM(RET); assert(ctxcode->lbEND);/* scan-build: remove warning */ // BUILD_popLABEL(kctx); BUILD_compile(kctx, mtd, lbINIT, ctxcode->lbEND); ctxcode->lbEND = NULL; RESET_GCSTACK(); }
static kMethod *CompileClosure(KonohaContext *kctx, kNameSpace *ns, kNode *expr, KClass *envCt, kToken *typeTk, kNode **texprRef) { INIT_GCSTACK(); kParam *pa = kNode_GetParamNULL(kctx, expr, typeTk, ns); kMethodVar *mtd = (kMethodVar *) KLIB new_kMethod(kctx, _GcStack, 0, envCt->typeId, 0/*mn*/, NULL); KLIB kMethod_SetParam(kctx, mtd, pa->rtype, pa->psize, (kparamtype_t *)pa->paramtypeItems); int errorCount = KGetParserContext(kctx)->errorMessageCount; KGammaStackDecl lvarItems[32] = {}; struct KGammaLocalData newgma = {}; newgma.flag = 0; newgma.currentWorkingMethod = mtd; newgma.thisClass = envCt; newgma.localScope.varItems = lvarItems; newgma.localScope.capacity = 32; newgma.localScope.varsize = 0; newgma.localScope.allocsize = 0; kNameSpace_InitParam(kctx, ns, &newgma, pa, envCt); KPushGammaStack(ns, &newgma); *texprRef = SUGAR TypeCheckNodeByName(kctx, expr, KSymbol_BlockPattern, ns, KClass_var, TypeCheckPolicy_AllowVoid); kNode *block = SUGAR kNode_GetNode(kctx, expr, KSymbol_BlockPattern, NULL); KLIB kMethod_GenCode(kctx, mtd, block, HatedLazyCompile); KPopGammaStack(ns, &newgma); kMethod_Set(StaticError, mtd, KGetParserContext(kctx)->errorMessageCount > errorCount); RESET_GCSTACK(); return mtd; }
//## @Const method String[] String.split(RegExp regex); static KMETHOD String_split(KonohaContext *kctx, KonohaStack *sfp) { INIT_GCSTACK(); kArray *resultArray = (kArray *)KLIB new_kObject(kctx, _GcStack, KGetReturnType(sfp), 0); kArray_split(kctx, resultArray, sfp[0].asString, sfp[1].asRegExp, S_size(sfp[0].asString)); KReturnWith(resultArray, RESET_GCSTACK()); }
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; }
//## @Const method String[] String.split(RegExp regex, Int limit); static KMETHOD String_splitWithLimit(KonohaContext *kctx, KonohaStack *sfp) { INIT_GCSTACK(); size_t limit = sfp[2].intValue < 0 ? S_size(sfp[0].asString) : (size_t) sfp[2].intValue; kArray *resultArray = (kArray *)KLIB new_kObject(kctx, _GcStack, KGetReturnType(sfp), 0); kArray_split(kctx, resultArray, sfp[0].asString, sfp[1].asRegExp, limit); KReturnWith(resultArray, RESET_GCSTACK()); }
static kstatus_t MODSUGAR_loadScript(KonohaContext *kctx, const char *path, size_t len, KTraceInfo *trace) { if(KGetParserContext(kctx) == NULL) { KPARSERM->h.setupModelContext(kctx, (KRuntimeModel *)KPARSERM, 0/*lazy*/); } INIT_GCSTACK(); kpackageId_t packageId = KLIB KpackageId(kctx, "main", sizeof("main")-1, 0, _NEWID); kNameSpace *ns = new_PackageNameSpace(kctx, packageId); kstatus_t result = (kstatus_t)kNameSpace_LoadScript(kctx, ns, path, trace); RESET_GCSTACK(); return result; }
static kstatus_t MODSUGAR_loadScript(KonohaContext *kctx, const char *path, size_t len, KTraceInfo *trace) { if(GetSugarContext(kctx) == NULL) { kmodsugar->h.setupModuleContext(kctx, (KonohaModule *)kmodsugar, 0/*lazy*/); } INIT_GCSTACK(); kpackageId_t packageId = KLIB KpackageId(kctx, "main", sizeof("main")-1, 0, _NEWID); kNameSpace *ns = new_PackageNameSpace(kctx, packageId); kstatus_t result = (kstatus_t)kNameSpace_LoadScript(kctx, ns, path, trace); RESET_GCSTACK(); return result; }
//## @Native Thread Thread.create(Func f) static KMETHOD Thread_create(KonohaContext *kctx, KonohaStack *sfp) { INIT_GCSTACK(); kFunc *f = sfp[1].asFunc; KLIB kMethod_DoLazyCompilation(kctx, (f)->mtd, NULL, HatedLazyCompile); kThread *thread = (kThread *)KLIB new_kObject(kctx, _GcStack, KGetReturnType(sfp), 0); thread->rootCtx = kctx; //TODO getRootContext thread->kctx = KLIB KonohaContext_Init(kctx, kctx->platApi); KFieldSet(thread, thread->func, f); pthread_create(&(thread->thread), NULL, spawn_start, thread); RESET_GCSTACK(); // FIXME?? Not sure this is okay?? KReturn(thread); }
void MODCODE_init(KonohaContext *kctx, KonohaContextVar *ctx) { KModuleByteCode *base = (KModuleByteCode*)KCALLOC(sizeof(KModuleByteCode), 1); opcode_check(); base->h.name = "minivm"; base->h.setup = kmodcode_setup; base->h.reftrace = kmodcode_reftrace; base->h.free = kmodcode_free; KLIB Konoha_setModule(kctx, MOD_code, &base->h, 0); KDEFINE_CLASS defBasicBlock = { STRUCTNAME(BasicBlock), .init = BasicBlock_init, .free = BasicBlock_free, }; KDEFINE_CLASS defByteCode = { STRUCTNAME(ByteCode), .init = ByteCode_init, .reftrace = ByteCode_reftrace, .free = ByteCode_free, }; base->cBasicBlock = KLIB Konoha_defineClass(kctx, PackageId_sugar, PackageId_sugar, NULL, &defBasicBlock, 0); base->cByteCode = KLIB Konoha_defineClass(kctx, PackageId_sugar, PackageId_sugar, NULL, &defByteCode, 0); kmodcode_setup(kctx, &base->h, 0/*lazy*/); { INIT_GCSTACK(); kBasicBlock* ia = (kBasicBlock*)new_(BasicBlock, 0); kBasicBlock* ib = (kBasicBlock*)new_(BasicBlock, 0); PUSH_GCSTACK(ia); PUSH_GCSTACK(ib); kBasicBlock_add(ia, THCODE, _THCODE); kBasicBlock_add(ia, NCALL); // FUNCCALL kBasicBlock_add(ia, ENTER); kBasicBlock_add(ia, EXIT); kBasicBlock_add(ib, RET); // NEED TERMINATION ia->nextBlock = ib; kByteCode *kcode = new_ByteCode(kctx, ia, ib); KINITv(kmodcode->codeNull, kcode); VirtualMachineInstruction *pc = KonohaVirtualMachine_run(kctx, kctx->esp, kcode->code); CODE_ENTER = pc; CODE_ENTER = pc+1; KLIB kArray_clear(kctx, ctxcode->codeList, 0); RESET_GCSTACK(); } KonohaLibVar *l = (KonohaLibVar*)kctx->klib; l->kMethod_setFunc = kMethod_setFunc; l->kMethod_genCode = kMethod_genCode; }
//## ResultSet Connection.query(String query); static KMETHOD Connection_query(KonohaContext *kctx, KonohaStack *sfp) { INIT_GCSTACK(); KMakeTrace(trace, sfp); kConnection *conn = (kConnection *)sfp[0].asObject; const char *query = kString_text(sfp[1].asString); kResultSet *rs = (kResultSet *)KLIB new_kObject(kctx, OnStack, KGetReturnType(sfp), (uintptr_t)conn); KCursor *qcur = conn->driver->qexec(kctx, conn->db, query, rs, trace); if(qcur != NULL) { rs->qcur = qcur; rs->driver = conn->driver; } KReturnWith(rs, RESET_GCSTACK()); }
static struct KVirtualCode *MiniVM_GenerateVirtualCode(KonohaContext *kctx, kMethod *mtd, kUntypedNode *block, int option) { KVirtualCode *vcode; KBuffer wb; KBuilder builderbuf = {{0}}, *builder = &builderbuf; kNameSpace *ns = kUntypedNode_ns(block); INIT_GCSTACK(); KLIB KBuffer_Init(&(kctx->stack->cwb), &wb); builder->common.api = ns->builderApi; builder->constPools = ns->NameSpaceConstList; builder->bbBeginId = new_BasicBlockLABEL(kctx); builder->bbReturnId = new_BasicBlockLABEL(kctx); builder->bbMainId = builder->bbBeginId; builder->currentMtd = mtd; builder->Value = 0; builder->stackbase = 0; builder->InstructionSize = 0; builder->common.api = &CollectLocalVar_BuilderAPI; KLIB VisitNode(kctx, builder, block, NULL); builder->stackbase += builder->localVarSize + 1/* == this object */; builder->common.api = ns->builderApi; KLIB KArray_Init(kctx, &builder->localVar, sizeof(LocalVarInfo) * builder->stackbase); ASM(THCODE, 0, _THCODE); ASM(CHKSTACK, 0); KLIB VisitNode(kctx, builder, block, NULL); if(!Block_HasTerminatorInst(kctx, builder->bbMainId)) { MiniVMBuilder_JumpTo(kctx, builder, builder->bbReturnId); } MiniVMBuilder_setBlock(kctx, builder, builder->bbReturnId); if(mtd->mn == MN_new) { // FIXME: Type 'This' must be resolved ASM(NMOV, OC_(K_RTNIDX), OC_(0), KClass_(mtd->typeId)); } ASM(RET); vcode = CompileVirtualCode(kctx, builder, builder->bbBeginId, builder->bbReturnId); KLIB KArray_Free(kctx, &builder->localVar); RESET_GCSTACK(); KLIB KBuffer_Free(&wb); return vcode; }
static kstatus_t kNameSpace_Eval(KonohaContext *kctx, kNameSpace *ns, const char *script, kfileline_t uline, KTraceInfo *trace) { kstatus_t result; kmodsugar->h.setupModuleContext(kctx, (KonohaModule *)kmodsugar, 0/*lazy*/); INIT_GCSTACK(); { TokenSeq tokens = {ns, GetSugarContext(kctx)->preparedTokenList}; TokenSeq_Push(kctx, tokens); TokenSeq_Tokenize(kctx, &tokens, script, uline); result = TokenSeq_Eval(kctx, &tokens, trace); TokenSeq_Pop(kctx, tokens); } RESET_GCSTACK(); return result; }
static KMETHOD NameSpace_man(KonohaContext *kctx, KonohaStack *sfp) { INIT_GCSTACK(); kArray *list = kctx->stack->gcstack_OnContextConstList; size_t start = kArray_size(list); kNameSpace *ns = sfp[0].asNameSpace; KonohaClass *ct = O_ct(sfp[1].asObject); DBG_P("*** man %s", TY_t(ct->typeId)); while(ns != NULL) { copyMethodList(kctx, ct->typeId, ns->methodList_OnList, list); ns = ns->parentNULL; } copyMethodList(kctx, ct->typeId, ct->methodList_OnGlobalConstList, list); dumpMethodList(kctx, sfp, start, list); RESET_GCSTACK(); }
static kstatus_t kNameSpace_Eval(KonohaContext *kctx, kNameSpace *ns, const char *script, kfileline_t uline, KTraceInfo *trace) { kstatus_t result; KPARSERM->h.setupModelContext(kctx, (KRuntimeModel *)KPARSERM, 0/*lazy*/); INIT_GCSTACK(); { KTokenSeq tokens = {ns, KGetParserContext(kctx)->preparedTokenList}; KTokenSeq_Push(kctx, tokens); Tokenize(kctx, ns, script, uline, 0, tokens.tokenList); KTokenSeq_End(kctx, tokens); result = KLIB EvalTokenList(kctx, &tokens, trace); KTokenSeq_Pop(kctx, tokens); } RESET_GCSTACK(); return result; }
/* copied from src/parser/import/typecheck.h */ static kNode *CallTypeFunc(KonohaContext *kctx, kFunc *fo, kNode *expr, kNameSpace *ns, kObject *reqType) { INIT_GCSTACK(); BEGIN_UnusedStack(lsfp); KUnsafeFieldSet(lsfp[1].asNode, expr); KUnsafeFieldSet(lsfp[2].asNameSpace, ns); KUnsafeFieldSet(lsfp[3].asObject, reqType); CallSugarMethod(kctx, lsfp, fo, 4, UPCAST(K_NULLNODE)); END_UnusedStack(); RESET_GCSTACK(); if(kNode_IsError(expr)) return expr; if(lsfp[K_RTNIDX].asNode == K_NULLNODE) { DBG_ASSERT(expr->attrTypeId == KType_var); // untyped } DBG_ASSERT(IS_Node(lsfp[K_RTNIDX].asObject)); return (kNode *)lsfp[K_RTNIDX].asObject; }
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 kbool_t KClass_AddField(KonohaContext *kctx, KClass *ct, ktypeattr_t typeattr, ksymbol_t sym) { kuhalfword_t pos = ct->fieldsize; if(unlikely(ct->classMethodList == K_EMPTYARRAY)) { ((KClassVar *)ct)->classMethodList = new_(MethodArray, 8, OnGlobalConstList); /*FIXME WriteBarrier */ } INIT_GCSTACK(); if(pos < ct->fieldAllocSize) { KClassVar *definedClass = (KClassVar *)ct; definedClass->fieldsize += 1; definedClass->fieldItems[pos].name = sym; if(KType_Is(UnboxType, typeattr)) { definedClass->defaultNullValueVar->fieldUnboxItems[pos] = 0; definedClass->fieldItems[pos].typeAttr = typeattr; } else { kObjectVar *o = definedClass->defaultNullValueVar; KFieldSet(o, o->fieldObjectItems[pos], KLIB Knull(kctx, KClass_(typeattr))); definedClass->fieldItems[pos].typeAttr = typeattr | KTypeAttr_Boxed; } if(1/*KHalfFlag_Is(flag, kField_Getter)*/) { kMethod *mtd = new_FieldGetter(kctx, _GcStack, definedClass->typeId, sym, KTypeAttr_Unmask(typeattr), pos); KLIB kArray_Add(kctx, ct->classMethodList, mtd); } if(!KTypeAttr_Is(ReadOnly, typeattr)/*KHalfFlag_Is(flag, kField_Setter)*/) { kMethod *mtd = new_FieldSetter(kctx, _GcStack, definedClass->typeId, sym, KTypeAttr_Unmask(typeattr), pos); KLIB kArray_Add(kctx, ct->classMethodList, mtd); } } else { if(1/*KHalfFlag_Is(flag, kField_Getter)*/) { kMethod *mtd = new_PrototypeGetter(kctx, _GcStack, ct->typeId, sym, KTypeAttr_Unmask(typeattr)); KLIB kArray_Add(kctx, ct->classMethodList, mtd); } if(!KTypeAttr_Is(ReadOnly, typeattr)/*KHalfFlag_Is(flag, kField_Setter)*/) { kMethod *mtd = new_PrototypeSetter(kctx, _GcStack, ct->typeId, sym, KTypeAttr_Unmask(typeattr)); KLIB kArray_Add(kctx, ct->classMethodList, mtd); } } RESET_GCSTACK(); return true; }
static KClass *CreateEnvClass(KonohaContext *kctx, kNameSpace *ns, kToken *typeTk, KClass **EnvObjectClass) { INIT_GCSTACK(); size_t i = 0, esize = ns->genv->localScope.varsize; size_t start = 0, end = esize; KGammaStackDecl *oldenv = ns->genv->localScope.varItems; kparamtype_t *p = ALLOCA(kparamtype_t, esize); char buf[256] = {'_', '_', '_', 'E', 'N', 'V', 0}, *text = buf + 6; if(ns->genv->thisClass == KClass_NameSpace) { start = 1; end = esize - 1; } assert(end < 256); for(i = start; i <= end; i++) { p[i-1].name = oldenv[i].name; p[i-1].attrTypeId = oldenv[i].attrTypeId; *(text++) = (KType_text(p[i-1].attrTypeId))[0]; } *EnvObjectClass = KLIB kNameSpace_GetClassByFullName(kctx, ns, buf, text - buf, NULL); if(*EnvObjectClass == NULL) { *EnvObjectClass = kNameSpace_DefineClassName(kctx, ns, buf, text - buf); } KClass *ct = KLIB KClass_Generics(kctx, KClass_Func, typeTk->resolvedTypeId, end, p); if(end >= 1) { ((KClassVar *)ct)->classMethodList = new_(MethodArray, end*2, OnGlobalConstList); for(i = start; i <= end; i++) { int n = i - 1; ksymbol_t sym = p[n].name; ktypeattr_t type = KTypeAttr_Unmask(p[n].attrTypeId); kMethod *getter = new_FunctionGetter(kctx, _GcStack, ct->typeId, sym, type, n); kMethod *setter = new_FunctionSetter(kctx, _GcStack, ct->typeId, sym, type, n); KLIB kArray_Add(kctx, ct->classMethodList, getter); KLIB kArray_Add(kctx, ct->classMethodList, setter); } } RESET_GCSTACK(); return ct; }
static KVirtualCode *KonohaVirtualMachine_tryJump(KonohaContext *kctx, KonohaStack *sfp, KVirtualCode *pc) { int jmpresult; INIT_GCSTACK(); KRuntimeContextVar *base = kctx->stack; jmpbuf_i lbuf = {0}; if(base->evaljmpbuf == NULL) { base->evaljmpbuf = (jmpbuf_i *)KCalloc_UNTRACE(sizeof(jmpbuf_i), 1); } memcpy(&lbuf, base->evaljmpbuf, sizeof(jmpbuf_i)); if((jmpresult = PLATAPI setjmp_i(*base->evaljmpbuf)) == 0) { pc = MiniVM_RunVirtualMachine(kctx, sfp, pc); } else { DBG_P("Catch eval exception jmpresult=%d", jmpresult); //KSETv(sfp[exceptionIdx].e, ..); pc = NULL; } memcpy(base->evaljmpbuf, &lbuf, sizeof(jmpbuf_i)); RESET_GCSTACK(); return pc; }
/* ------------------------------------------------------------------------ */ static KMETHOD TypeCheck_Closure(KonohaContext *kctx, KonohaStack *sfp) { VAR_TypeCheck(expr, ns, reqc); kNode *texpr = K_NULLNODE; INIT_GCSTACK(); kToken *typeTk = SUGAR kNode_GetToken(kctx, expr, KSymbol_TypePattern, NULL); KClass *EnvObjectClass = NULL; KClass *envCt = CreateEnvClass(kctx, ns, typeTk, &EnvObjectClass); kMethod *mtd = CompileClosure(kctx, ns, expr, envCt, typeTk, &texpr); /* type check is OK */ if(texpr != K_NULLNODE) { /* * FunctionExpression * 0: Method * 1: EnvObject's Default Object * 2: Current LocalScope Variable * 3: ditto * 4: ... */ kNode_Type(texpr, KNode_Function, envCt->typeId); KFieldSet(expr, texpr->NodeList, new_(Array, 0, OnField)); KLIB kArray_Add(kctx, texpr->NodeList, mtd); KLIB kArray_Add(kctx, texpr->NodeList, KLIB Knull(kctx, EnvObjectClass)); size_t i = 0; struct KGammaLocalData *genv = ns->genv; if(genv->thisClass == KClass_NameSpace) { i = 1; } for(; i < genv->localScope.varsize; i++) { kNode *node = new_VariableNode(kctx, ns, KNode_Local, genv->localScope.varItems[i].attrTypeId, i); KLIB kArray_Add(kctx, texpr->NodeList, node); } } RESET_GCSTACK(); KReturn(texpr); }
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); }