From 6b90f4fff9e5cbfd908db2545d2efcd45ea604a9 Mon Sep 17 00:00:00 2001 From: arakov Date: Thu, 28 Mar 2024 13:27:50 +0100 Subject: [PATCH] refactoring compiler code to enable unit tests --- doc/todo.txt | 2 + elenasrc3/elc/cliconst.h | 2 +- elenasrc3/elc/compiler.cpp | 14678 +++++++++++++++++------------------ elenasrc3/elc/compiler.h | 284 +- 4 files changed, 7468 insertions(+), 7498 deletions(-) diff --git a/doc/todo.txt b/doc/todo.txt index f9d3edbc8..539fe756a 100644 --- a/doc/todo.txt +++ b/doc/todo.txt @@ -18,6 +18,8 @@ In development: - #617 - #637 : all bt tests -------------------------------------- + - part of code can be turned into static ones + - serialize / deserialize tree : syntax tree - serialize / deserialize tree : build tree diff --git a/elenasrc3/elc/cliconst.h b/elenasrc3/elc/cliconst.h index 39f18565d..056b779c7 100644 --- a/elenasrc3/elc/cliconst.h +++ b/elenasrc3/elc/cliconst.h @@ -13,7 +13,7 @@ namespace elena_lang { - #define ELC_REVISION_NUMBER 0x0245 + #define ELC_REVISION_NUMBER 0x0246 #if defined _M_IX86 || _M_X64 diff --git a/elenasrc3/elc/compiler.cpp b/elenasrc3/elc/compiler.cpp index 7dd8e1ad3..c70777c1c 100644 --- a/elenasrc3/elc/compiler.cpp +++ b/elenasrc3/elc/compiler.cpp @@ -4312,125 +4312,6 @@ inline void copyArray(BuildTreeWriter& writer, int size) writer.closeNode(); } -ObjectInfo Compiler :: boxRefArgumentInPlace(WriterContext& context, ObjectInfo info, ref_t targetRef) -{ - ref_t typeRef = targetRef; - if (!typeRef) - typeRef = retrieveStrongType(*context.scope, info); - - ObjectInfo tempLocal = declareTempLocal(*context.scope, typeRef); - tempLocal.mode = TargetMode::RefUnboxingRequired; - - info.kind = ObjectKind::Local; - compileAssigningOp(context, tempLocal, info); - - tempLocal.kind = ObjectKind::LocalReference; - - return tempLocal; -} - -ObjectInfo Compiler :: boxArgumentInPlace(WriterContext& context, ObjectInfo info, ref_t targetRef) -{ - bool condBoxing = info.mode == TargetMode::Conditional && _withConditionalBoxing; - ref_t typeRef = targetRef; - if (!typeRef) - typeRef = retrieveStrongType(*context.scope, info); - - ObjectInfo tempLocal = {}; - if (hasToBePresaved(info)) { - info = saveToTempLocal(*context.writer, *context.scope, info); - } - tempLocal = declareTempLocal(*context.scope, typeRef); - - ClassInfo argInfo; - _logic->defineClassInfo(*context.scope->moduleScope, argInfo, typeRef, false, true); - - ObjectInfo lenLocal = {}; - bool isBinaryArray = _logic->isEmbeddableArray(argInfo); - if (isBinaryArray) { - int elementSize = -(int)argInfo.size; - - // get the length - lenLocal = declareTempLocal(*context.scope, V_INT32, false); - - writeObjectInfo(context, info); - context.writer->appendNode(BuildKey::SavingInStack, 0); - context.writer->newNode(BuildKey::BinaryArraySOp, LEN_OPERATOR_ID); - context.writer->appendNode(BuildKey::Index, lenLocal.argument); - context.writer->appendNode(BuildKey::Size, elementSize); - context.writer->closeNode(); - - // allocate the object - writeObjectInfo(context, lenLocal); - context.writer->appendNode(BuildKey::SavingInStack, 0); - - context.writer->newNode(BuildKey::NewArrayOp, typeRef); - context.writer->appendNode(BuildKey::Size, argInfo.size); - context.writer->closeNode(); - - context.writer->appendNode(BuildKey::Assigning, tempLocal.argument); - - writeObjectInfo(context, info); - context.writer->appendNode(BuildKey::SavingInStack, 0); - - context.writer->appendNode(BuildKey::LoadingIndex, lenLocal.reference); - - writeObjectInfo(context, tempLocal); - - copyArray(*context.writer, elementSize); - } - else if (_logic->isDynamic(argInfo)) { - // get the length - lenLocal = declareTempLocal(*context.scope, V_INT32, false); - - writeObjectInfo(context, info); - context.writer->appendNode(BuildKey::SavingInStack, 0); - context.writer->newNode(BuildKey::ObjArraySOp, LEN_OPERATOR_ID); - context.writer->appendNode(BuildKey::Index, lenLocal.argument); - context.writer->closeNode(); - - // allocate the object - writeObjectInfo(context, lenLocal); - context.writer->appendNode(BuildKey::SavingInStack, 0); - - context.writer->newNode(BuildKey::NewArrayOp, typeRef); - context.writer->closeNode(); - - context.writer->appendNode(BuildKey::Assigning, tempLocal.argument); - - writeObjectInfo(context, info); - context.writer->appendNode(BuildKey::SavingInStack, 0); - - context.writer->appendNode(BuildKey::LoadingIndex, lenLocal.reference); - - writeObjectInfo(context, tempLocal); - - copyArray(*context.writer, 0); - } - else { - writeObjectInfo(context, info); - - if (condBoxing) - context.writer->newNode(BuildKey::StackCondOp, IF_OPERATOR_ID); - - context.writer->appendNode(BuildKey::SavingInStack, 0); - - createObject(*context.writer, argInfo, typeRef); - - copyObjectToAcc(*context.writer, argInfo, tempLocal.reference); - - if (condBoxing) - context.writer->closeNode(); - - context.writer->appendNode(BuildKey::Assigning, tempLocal.argument); - } - - if (!_logic->isReadOnly(argInfo)) - tempLocal.mode = condBoxing ? TargetMode::ConditionalUnboxingRequired : TargetMode::UnboxingRequired; - - return tempLocal; -} - inline bool isBoxingRequired(ObjectInfo info, bool allowByRefParam) { switch (info.kind) { @@ -4473,673 +4354,647 @@ int Compiler :: defineFieldSize(Scope& scope, ObjectInfo info) return size; } -ObjectInfo Compiler :: boxPtrLocally(WriterContext& context, ObjectInfo info) +ref_t Compiler :: retrieveStrongType(Scope& scope, ObjectInfo info) { - ObjectInfo tempLocal = declareTempLocal(*context.scope, info.typeInfo.typeRef, false); - - writeObjectInfo(context, info); - context.writer->appendNode(BuildKey::SavingInStack, 0); - - writeObjectInfo(context, tempLocal); - - context.writer->appendNode(BuildKey::SetImmediateField); - - return tempLocal; + if (info.typeInfo.isPrimitive()) { + if (info.typeInfo.typeRef == V_AUTO) { + return info.typeInfo.typeRef; + } + else return resolvePrimitiveType(scope, info.typeInfo, false); + } + else return info.typeInfo.typeRef; } -ObjectInfo Compiler :: boxLocally(WriterContext& context, ObjectInfo info, bool stackSafe) +ref_t Compiler :: retrieveType(Scope& scope, ObjectInfo info) { - // allocating temporal variable - ObjectInfo tempLocal = {}; - bool fixedArray = false; - int fixedSize = 0; - if ((info.typeInfo.isPrimitive() && _logic->isPrimitiveArrRef(info.typeInfo.typeRef)) - || _logic->isEmbeddableArray(*context.scope->moduleScope, info.typeInfo.typeRef)) - { - fixedSize = defineFieldSize(*context.scope, info); - - tempLocal = declareTempStructure(*context.scope, { fixedSize }); - tempLocal.typeInfo = info.typeInfo; - - fixedArray = true; - } - else tempLocal = declareTempLocal(*context.scope, info.typeInfo.typeRef, false); - - if (stackSafe) { - tempLocal.mode = TargetMode::LocalUnboxingRequired; - - context.scope->tempLocals.add({ info.kind, info.reference }, tempLocal); + if (info.typeInfo.isPrimitive() && info.typeInfo.elementRef) { + return retrieveStrongType(scope, info); } + else return info.typeInfo.typeRef; +} - writeObjectInfo(context, tempLocal); - context.writer->appendNode(BuildKey::SavingInStack, 0); +ref_t Compiler :: resolvePrimitiveType(Scope& scope, TypeInfo typeInfo, bool declarationMode) +{ + NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - writeObjectInfo(context, context.scope->mapSelf()); + return resolvePrimitiveType(*scope.moduleScope, *nsScope->nsName, typeInfo, declarationMode); +} - switch (info.kind) { - case ObjectKind::FieldAddress: - case ObjectKind::ReadOnlyField: - context.writer->newNode(BuildKey::CopyingAccField, info.reference); - break; - case ObjectKind::StaticConstField: - context.writer->appendNode(BuildKey::ClassOp, CLASS_OPERATOR_ID); - context.writer->appendNode(BuildKey::Field, info.reference); - context.writer->newNode(BuildKey::CopyingAccField, 0); - break; - case ObjectKind::ClassStaticConstField: - context.writer->appendNode(BuildKey::Field, info.reference); - context.writer->newNode(BuildKey::CopyingAccField, 0); - break; +ref_t Compiler :: resolvePrimitiveType(ModuleScopeBase& moduleScope, ustr_t ns, TypeInfo typeInfo, + bool declarationMode) +{ + switch (typeInfo.typeRef) { + case V_UINT8: + return moduleScope.buildins.uint8Reference; + case V_INT8: + return moduleScope.buildins.int8Reference; + case V_INT16: + return moduleScope.buildins.shortReference; + case V_UINT16: + return moduleScope.buildins.ushortReference; + case V_INT32: + return moduleScope.buildins.intReference; + case V_INT64: + return moduleScope.buildins.longReference; + case V_FLOAT64: + return moduleScope.buildins.realReference; + case V_UINT32: + return moduleScope.buildins.uintReference; + case V_STRING: + return moduleScope.buildins.literalReference; + case V_WIDESTRING: + return moduleScope.buildins.wideReference; + case V_MESSAGE: + return moduleScope.buildins.messageReference; + case V_MESSAGENAME: + return moduleScope.buildins.messageNameReference; + case V_EXTMESSAGE64: + case V_EXTMESSAGE128: + return moduleScope.buildins.extMessageReference; + case V_FLAG: + return moduleScope.branchingInfo.typeRef; + case V_WRAPPER: + return resolveWrapperTemplate(moduleScope, ns, typeInfo.elementRef, declarationMode); + case V_INT8ARRAY: + case V_INT16ARRAY: + case V_INT32ARRAY: + case V_BINARYARRAY: + return resolveArrayTemplate(moduleScope, ns, typeInfo.elementRef, declarationMode); + case V_NULLABLE: + return resolveNullableTemplate(moduleScope, ns, typeInfo.elementRef, declarationMode); + case V_NIL: + return moduleScope.buildins.superReference; + case V_ARGARRAY: + return resolveArgArrayTemplate(moduleScope, ns, typeInfo.elementRef, declarationMode); + case V_OBJARRAY: + return resolveArrayTemplate(moduleScope, ns, typeInfo.elementRef, declarationMode); + case V_PTR32: + case V_PTR64: + return moduleScope.buildins.pointerReference; default: - context.writer->appendNode(BuildKey::Field, info.reference); - context.writer->newNode(BuildKey::CopyingAccField, 0); - break; + return 0; } - - context.writer->appendNode(BuildKey::Size, tempLocal.extra); - context.writer->closeNode(); - - if (!stackSafe) { - ObjectInfo dynamicTempLocal = {}; - if (fixedArray) { - ref_t typeRef = info.typeInfo.isPrimitive() - ? resolvePrimitiveType(*context.scope, info.typeInfo, false) : info.typeInfo.typeRef; +} - dynamicTempLocal = declareTempLocal(*context.scope, typeRef, true); +void Compiler :: declareSymbolAttributes(SymbolScope& scope, SyntaxNode node, bool identifierDeclarationMode) +{ + bool constant = false; + SyntaxNode current = node.firstChild(); + while (current != SyntaxKey::None) { + switch (current.key) { + case SyntaxKey::Attribute: + if (!_logic->validateSymbolAttribute(current.arg.value, scope.visibility, constant, scope.isStatic)) { + current.setArgumentValue(0); // HOTFIX : to prevent duplicate warnings + scope.raiseWarning(WARNING_LEVEL_1, wrnInvalidHint, current); + } + break; + case SyntaxKey::Type: + case SyntaxKey::ArrayType: + case SyntaxKey::TemplateType: + if (!identifierDeclarationMode) + scope.info.typeRef = resolveStrongTypeAttribute(scope, current, true, false); + break; + default: + break; + } - context.writer->newNode(BuildKey::CreatingStruct, fixedSize); - context.writer->appendNode(BuildKey::Type, typeRef); - context.writer->closeNode(); + current = current.nextNode(); + } - context.writer->appendNode(BuildKey::Assigning, dynamicTempLocal.argument); + if (scope.visibility == Visibility::Public) { + scope.info.loadableInRuntime = true; + } - writeObjectInfo(context, tempLocal); - context.writer->appendNode(BuildKey::SavingInStack, 0); - writeObjectInfo(context, dynamicTempLocal); + if (constant && !identifierDeclarationMode) { + scope.info.symbolType = SymbolType::Constant; - context.writer->newNode(BuildKey::CopyingToAcc, tempLocal.reference); - context.writer->appendNode(BuildKey::Size, fixedSize); - context.writer->closeNode(); + Interpreter interpreter(scope.moduleScope, _logic); + ObjectInfo operand = evalExpression(interpreter, scope, node.findChild(SyntaxKey::GetExpression).firstChild(), true); + if (operand.kind == ObjectKind::IntLiteral) { + NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); + nsScope->defineIntConstant(scope.reference, operand.extra); + } + } +} - dynamicTempLocal.mode = TargetMode::UnboxingRequired; +void Compiler :: declareClassAttributes(ClassScope& scope, SyntaxNode node, ref_t& flags) +{ + SyntaxNode current = node.firstChild(); + while (current != SyntaxKey::None) { + switch (current.key) { + case SyntaxKey::Attribute: + if (!_logic->validateClassAttribute(current.arg.value, flags, scope.visibility)) { + current.setArgumentValue(0); // HOTFIX : to prevent duplicate warnings + scope.raiseWarning(WARNING_LEVEL_1, wrnInvalidHint, current); + } + break; + case SyntaxKey::Type: + scope.raiseError(errInvalidSyntax, current); + break; + default: + break; } - else dynamicTempLocal = boxArgument(context, tempLocal, false, true, false); - context.scope->tempLocals.add({ info.kind, info.reference }, dynamicTempLocal); + current = current.nextNode(); + } - return dynamicTempLocal; + // handle the abstract flag + if (test(scope.info.header.flags, elAbstract)) { + if (!test(flags, elAbstract)) { + scope.abstractBasedMode = true; + scope.info.header.flags &= ~elAbstract; + } + else scope.abstractMode = true; } - else return tempLocal; + else scope.abstractMode = test(flags, elAbstract); } -ObjectInfo Compiler :: boxArgumentLocally(WriterContext& context, ObjectInfo info, - bool stackSafe, bool forced) +inline bool isMethodKind(ref_t hint) { - switch (info.kind) { - case ObjectKind::Field: - case ObjectKind::Outer: - case ObjectKind::OuterField: - if (forced) { - return boxLocally(context, info, stackSafe); - } - return info; - case ObjectKind::ReadOnlyFieldAddress: - case ObjectKind::FieldAddress: - if (info.argument == 0 && !forced) { - ObjectInfo retVal = context.scope->mapSelf(); - // HOTFIX : no conditional boxing in this case - if (retVal.mode == TargetMode::Conditional) - retVal.mode = TargetMode::None; - - retVal.typeInfo = info.typeInfo; + return (hint & (ref_t)MethodHint::Mask) != 0; +} - return retVal; - } - else return boxLocally(context, info, stackSafe); - case ObjectKind::StaticConstField: - case ObjectKind::ClassStaticConstField: - if (info.mode == TargetMode::BoxingPtr) { - return boxPtrLocally(context, info); - } - else return info; - default: - return info; +void Compiler :: declareArgumentAttributes(MethodScope& scope, SyntaxNode node, TypeInfo& typeInfo, + bool declarationMode) +{ + SyntaxNode current = node.firstChild(); + TypeAttributes attributes = { false, false, false }; + while (current != SyntaxKey::None) { + switch (current.key) { + case SyntaxKey::Type: + // if it is a type attribute + typeInfo = resolveTypeAttribute(scope, current, attributes, declarationMode, false); + break; + case SyntaxKey::TemplateType: + // if it is a template type attribute + typeInfo = resolveTypeAttribute(scope, current, attributes, declarationMode, false); + break; + case SyntaxKey::ArrayType: + case SyntaxKey::NullableType: + // if it is a type attribute + typeInfo = resolveTypeScope(scope, current, attributes, declarationMode, false); + break; + case SyntaxKey::Attribute: + if (!_logic->validateArgumentAttribute(current.arg.reference, attributes)) + scope.raiseWarning(WARNING_LEVEL_1, wrnInvalidHint, current); + break; + default: + break; + } + + current = current.nextNode(); + } + if (attributes.byRefOne) { + typeInfo.elementRef = typeInfo.typeRef; + typeInfo.typeRef = V_WRAPPER; + } + else if (attributes.variadicOne) { + if (typeInfo.typeRef != V_ARGARRAY) + scope.raiseError(errInvalidOperation, node); } } -ObjectInfo Compiler :: boxVariadicArgument(WriterContext& context, ObjectInfo info) +ref_t Compiler :: declareMultiType(Scope& scope, SyntaxNode& current, ref_t elementRef) { - NamespaceScope* nsScope = Scope::getScope(*context.scope, Scope::ScopeLevel::Namespace); + bool eol = false; + ArgumentsInfo items; + items.add({ ObjectKind::Class, { elementRef }, 0 }); - ref_t elementRef = info.typeInfo.elementRef; - if (!elementRef) - elementRef = context.scope->moduleScope->buildins.superReference; + while (current != SyntaxKey::None) { + if (current == SyntaxKey::Type) { + items.add({ ObjectKind::Class, { resolveStrongTypeAttribute(scope, current, true, false) }, 0 }); + } + else break; - ref_t typeRef = resolveArgArrayTemplate(*context.scope->moduleScope, *nsScope->nsName, elementRef, false); + current = current.nextNode(); + } - ObjectInfo destLocal = declareTempLocal(*context.scope, typeRef); - ObjectInfo lenLocal = declareTempLocal(*context.scope, context.scope->moduleScope->buildins.intReference, false); + return resolveTupleClass(scope, current, items); +} - // get length - writeObjectInfo(context, info); - context.writer->appendNode(BuildKey::SavingInStack); - context.writer->newNode(BuildKey::VArgSOp, LEN_OPERATOR_ID); - context.writer->appendNode(BuildKey::Index, lenLocal.argument); - context.writer->closeNode(); +inline ref_t resloveWeakSelfReference(ModuleScopeBase* moduleScope, ref_t weakRef, ref_t classRef) +{ + ref_t resolvedRef = moduleScope->resolveWeakTemplateReferenceID(weakRef); - // create a dynamic array - writeObjectInfo(context, lenLocal); - context.writer->appendNode(BuildKey::SavingInStack); - context.writer->appendNode(BuildKey::NewArrayOp, typeRef); - compileAssigningOp(context, destLocal, { ObjectKind::Object, { typeRef }, 0 }); + // HOTFIX : if it is a weak reference to the class - use the strong one + if (resolvedRef == classRef) { + return classRef; + } + else return weakRef; +} - // copy the content - // index len - // src:sp[0] - // dst:acc - context.writer->appendNode(BuildKey::LoadingIndex, lenLocal.argument); - writeObjectInfo(context, info); - context.writer->appendNode(BuildKey::SavingInStack); - writeObjectInfo(context, destLocal); - context.writer->appendNode(BuildKey::CopyingArr); +void Compiler :: declareMethodAttributes(MethodScope& scope, SyntaxNode node, bool exensionMode, bool templateBased) +{ + if (exensionMode) + scope.info.hints |= (ref_t)MethodHint::Extension; - if (info.typeInfo.typeRef && info.typeInfo.typeRef != typeRef) { - // if the conversion is required - ObjectInfo convInfo = convertObject(*context.writer, *context.scope, {}, destLocal, - info.typeInfo.typeRef, false, false); + SyntaxNode current = node.firstChild(); + bool explicitMode = false; + while (current != SyntaxKey::None) { + switch (current.key) { + case SyntaxKey::Attribute: + { + ref_t value = current.arg.reference; + + ref_t hint = 0; + if (_logic->validateMethodAttribute(value, hint, explicitMode)) { + if (isMethodKind(hint) && isMethodKind(scope.info.hints)) { + // a method kind can be set only once + scope.raiseError(errInvalidHint, node); + } + else scope.info.hints |= hint; + } + else { + current.setArgumentReference(0); - compileAssigningOp(context, destLocal, convInfo); + scope.raiseWarning(WARNING_LEVEL_1, wrnInvalidHint, node); + } + break; + } + case SyntaxKey::Type: + case SyntaxKey::ArrayType: + case SyntaxKey::TemplateType: + // if it is a type attribute + if (scope.info.outputRef) { + scope.info.outputRef = declareMultiType(scope, current, scope.info.outputRef); - destLocal.typeInfo = convInfo.typeInfo; + continue; + } + else scope.info.outputRef = resolveStrongTypeAttribute(scope, current, true, false); + if (templateBased) + scope.info.outputRef = resloveWeakSelfReference(scope.moduleScope, scope.info.outputRef, scope.getClassRef()); + + break; + case SyntaxKey::Name: + { + // resolving implicit method attributes + ref_t attr = scope.moduleScope->attributes.get(current.firstChild(SyntaxKey::TerminalMask).identifier()); + ref_t hint = (ref_t)MethodHint::None; + if (_logic->validateImplicitMethodAttribute(attr, hint)) { + scope.info.hints |= hint; + current.setKey(SyntaxKey::Attribute); + current.setArgumentReference(attr); + } + break; + } + default: + break; + } + + current = current.nextNode(); } +} - return destLocal; +void Compiler :: declareTemplateAttributes(TemplateScope& scope, SyntaxNode node, IdentifierString& postfix) +{ + SyntaxNode current = node.firstChild(); + while (current != SyntaxKey::None) { + switch (current.key) { + case SyntaxKey::Attribute: + if (!_logic->validateTemplateAttribute(current.arg.value, scope.visibility, scope.type)) + { + current.setArgumentValue(0); // HOTFIX : to prevent duplicate warnings + scope.raiseWarning(WARNING_LEVEL_1, wrnInvalidHint, current); + } + break; + case SyntaxKey::Type: + scope.raiseError(errInvalidSyntax, current); + break; + case SyntaxKey::Postfix: + postfix.append(':'); + postfix.append(current.firstChild(SyntaxKey::TerminalMask).identifier()); + break; + default: + break; + } + + current = current.nextNode(); + } } -ObjectInfo Compiler :: boxArgument(WriterContext& context, ObjectInfo info, - bool stackSafe, bool boxInPlace, bool allowingRefArg, ref_t targetRef) +void Compiler :: registerTemplateSignature(TemplateScope& scope, SyntaxNode node, IdentifierString& signature) { - ObjectInfo retVal = { ObjectKind::Unknown }; + signature.append(TEMPLATE_PREFIX_NS); - info = boxArgumentLocally(context, info, stackSafe, false); + size_t signIndex = signature.length(); - if (!stackSafe && isBoxingRequired(info, allowingRefArg)) { - ObjectKey key = { info.kind, info.reference }; + IdentifierString templateName(node.firstChild(SyntaxKey::TerminalMask).identifier()); + int paramCounter = SyntaxTree::countChild(node, SyntaxKey::TemplateArg); - if (!boxInPlace) - retVal = context.scope->tempLocals.get(key); + templateName.append('#'); + templateName.appendInt(paramCounter); - if (retVal.kind == ObjectKind::Unknown) { - retVal = boxArgumentInPlace(context, info, targetRef); + NamespaceScope* ns = Scope::getScope(scope, Scope::ScopeLevel::Namespace); + ref_t ref = ns->resolveImplicitIdentifier(*templateName, false, true); + if (!ref) + scope.raiseError(errUnknownClass, node); - if (!boxInPlace) - context.scope->tempLocals.add(key, retVal); - } - } - else if (info.kind == ObjectKind::RefLocal) { - ObjectKey key = { info.kind, info.reference }; + ustr_t refName = scope.module->resolveReference(ref); + if (isWeakReference(refName)) + signature.append(scope.module->name()); - if (!boxInPlace) - retVal = context.scope->tempLocals.get(key); + signature.append(refName); - if (retVal.kind == ObjectKind::Unknown) { - if (!allowingRefArg) { - info.kind = ObjectKind::Local; + SyntaxNode current = node.firstChild(); + while (current != SyntaxKey::None) { + if (current == SyntaxKey::TemplateArg) { + SyntaxNode argNode = current.firstChild(); - retVal = boxArgumentInPlace(context, info, targetRef); - } - else retVal = boxRefArgumentInPlace(context, info, targetRef); + if (argNode == SyntaxKey::Type) { + signature.append('&'); + ref_t classRef = resolveStrongTypeAttribute(scope, argNode, false, false); + if (!classRef) + scope.raiseError(errUnknownClass, current); - if (!boxInPlace) - context.scope->tempLocals.add(key, retVal); + ustr_t className = scope.module->resolveReference(classRef); + if (isWeakReference(className)) + signature.append(scope.module->name()); + + signature.append(className); + } + else if (argNode == SyntaxKey::TemplateArgParameter) { + signature.append('&'); + signature.append('{'); + signature.appendInt(argNode.arg.value); + signature.append('}'); + } + else assert(false); } + + current = current.nextNode(); } - else if (info.kind == ObjectKind::VArgParam && !stackSafe) { - retVal = boxVariadicArgument(context, info); - } - else retVal = info; - return retVal; + signature.replaceAll('\'', '@', signIndex); } -void Compiler :: writeObjectInfo(WriterContext& context, ObjectInfo info) +void Compiler :: registerExtensionTemplateMethod(TemplateScope& scope, SyntaxNode& node) { - switch (info.kind) { - case ObjectKind::IntLiteral: - context.writer->newNode(BuildKey::IntLiteral, info.reference); - context.writer->appendNode(BuildKey::Value, info.extra); - context.writer->closeNode(); - break; - case ObjectKind::Float64Literal: - context.writer->appendNode(BuildKey::RealLiteral, info.reference); - break; - case ObjectKind::LongLiteral: - context.writer->appendNode(BuildKey::LongLiteral, info.reference); - break; - case ObjectKind::StringLiteral: - context.writer->appendNode(BuildKey::StringLiteral, info.reference); - break; - case ObjectKind::WideStringLiteral: - context.writer->appendNode(BuildKey::WideStringLiteral, info.reference); - break; - case ObjectKind::CharacterLiteral: - context.writer->appendNode(BuildKey::CharLiteral, info.reference); - break; - case ObjectKind::MssgLiteral: - context.writer->appendNode(BuildKey::MssgLiteral, info.reference); - break; - case ObjectKind::MssgNameLiteral: - context.writer->appendNode(BuildKey::MssgNameLiteral, info.reference); - break; - case ObjectKind::ExtMssgLiteral: - context.writer->appendNode(BuildKey::ExtMssgLiteral, info.reference); - break; - //case ObjectKind::MetaDictionary: - // writer.appendNode(BuildKey::MetaDictionary, info.reference); - // break; - //case ObjectKind::MetaArray: - // writer.appendNode(BuildKey::MetaArray, info.reference); - // break; - case ObjectKind::Nil: - context.writer->appendNode(BuildKey::NilReference, 0); - break; - case ObjectKind::Terminator: - context.writer->appendNode(BuildKey::TerminatorReference, 0); - break; - case ObjectKind::Symbol: - context.writer->appendNode(BuildKey::SymbolCall, info.reference); - break; - case ObjectKind::Extension: - case ObjectKind::Class: - case ObjectKind::ClassSelf: - case ObjectKind::Singleton: - case ObjectKind::ConstantRole: - context.writer->appendNode(BuildKey::ClassReference, info.reference); - break; - case ObjectKind::Constant: - context.writer->appendNode(BuildKey::ConstantReference, info.reference); - break; - case ObjectKind::ConstArray: - context.writer->appendNode(BuildKey::ConstArrayReference, info.reference); - break; - case ObjectKind::Param: - case ObjectKind::SelfLocal: - case ObjectKind::SuperLocal: - case ObjectKind::ReadOnlySelfLocal: - case ObjectKind::Local: - case ObjectKind::TempLocal: - case ObjectKind::ParamAddress: - case ObjectKind::ParamReference: - case ObjectKind::SelfBoxableLocal: - case ObjectKind::ByRefParamAddress: - case ObjectKind::ConstructorSelf: - context.writer->appendNode(BuildKey::Local, info.reference); - break; - case ObjectKind::LocalField: - context.writer->appendNode(BuildKey::Local, info.reference); - context.writer->appendNode(BuildKey::Field, info.extra); - break; - case ObjectKind::VArgParam: - context.writer->appendNode(BuildKey::LocalReference, info.reference); - break; - case ObjectKind::LocalReference: - context.writer->appendNode(BuildKey::LocalReference, info.reference); - break; - case ObjectKind::LocalAddress: - case ObjectKind::TempLocalAddress: - context.writer->appendNode(BuildKey::LocalAddress, info.reference); - break; - case ObjectKind::ReadOnlyField: - case ObjectKind::Field: - case ObjectKind::Outer: - case ObjectKind::OuterSelf: - writeObjectInfo(context, context.scope->mapSelf()); - context.writer->appendNode(BuildKey::Field, info.reference); - break; - case ObjectKind::OuterField: - writeObjectInfo(context, context.scope->mapSelf()); - context.writer->appendNode(BuildKey::Field, info.reference); - context.writer->appendNode(BuildKey::Field, info.extra); - break; - case ObjectKind::StaticConstField: - writeObjectInfo(context, context.scope->mapSelf()); - context.writer->appendNode(BuildKey::ClassOp, CLASS_OPERATOR_ID); - context.writer->appendNode(BuildKey::Field, info.reference); - break; - case ObjectKind::ClassStaticConstField: - writeObjectInfo(context, context.scope->mapSelf()); - context.writer->appendNode(BuildKey::Field, info.reference); - break; - case ObjectKind::StaticField: - context.writer->appendNode(BuildKey::StaticVar, info.reference); - break; - case ObjectKind::ByRefParam: - writeObjectInfo(context, { ObjectKind::Param, info.typeInfo, info.reference }); - context.writer->appendNode(BuildKey::Field); - break; - case ObjectKind::ClassConstant: - if (info.reference == INVALID_REF) - throw InternalError(errFatalError); - - context.writer->appendNode(BuildKey::ConstantReference, info.reference); - break; - case ObjectKind::Object: - break; - default: - context.scope->raiseError(errInvalidOperation, context.node); - break; + IdentifierString messageName; + pos_t argCount = 1; + ref_t flags = 0; + IdentifierString signaturePattern; + ustr_t extensionName = scope.module->resolveReference(scope.reference); + if (isWeakReference(extensionName)) { + signaturePattern.append(scope.module->name()); } -} + signaturePattern.append(extensionName); + signaturePattern.append('.'); -ref_t Compiler :: retrieveStrongType(Scope& scope, ObjectInfo info) -{ - if (info.typeInfo.isPrimitive()) { - if (info.typeInfo.typeRef == V_AUTO) { - return info.typeInfo.typeRef; + SyntaxNode current = node.firstChild(); + while (current != SyntaxKey::None) { + if (current == SyntaxKey::Name) { + messageName.copy(current.firstChild(SyntaxKey::TerminalMask).identifier()); } - else return resolvePrimitiveType(scope, info.typeInfo, false); - } - else return info.typeInfo.typeRef; -} + else if (current == SyntaxKey::Parameter) { + argCount++; + signaturePattern.append('/'); + SyntaxNode typeAttr = current.findChild(SyntaxKey::Type, SyntaxKey::ArrayType, SyntaxKey::TemplateArgParameter, SyntaxKey::TemplateType); + if (typeAttr == SyntaxKey::TemplateArgParameter) { + signaturePattern.append('{'); + signaturePattern.appendInt(typeAttr.arg.value); + signaturePattern.append('}'); + } + else if (typeAttr == SyntaxKey::TemplateType) { + registerTemplateSignature(scope, typeAttr, signaturePattern); + } + else if (typeAttr != SyntaxKey::None) { + ref_t classRef = resolveStrongTypeAttribute(scope, typeAttr, true, false); -ref_t Compiler :: retrieveType(Scope& scope, ObjectInfo info) -{ - if (info.typeInfo.isPrimitive() && info.typeInfo.elementRef) { - return retrieveStrongType(scope, info); - } - else return info.typeInfo.typeRef; -} + ustr_t className = scope.module->resolveReference(classRef); + if (isWeakReference(className)) + signaturePattern.append(scope.module->name()); -ref_t Compiler :: resolvePrimitiveType(Scope& scope, TypeInfo typeInfo, bool declarationMode) -{ - NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); + signaturePattern.append(className); + } + else scope.raiseError(/*errNotApplicable*/errInvalidOperation, current); + } + current = current.nextNode(); + } - return resolvePrimitiveType(*scope.moduleScope, *nsScope->nsName, typeInfo, declarationMode); -} + mssg_t messageRef = encodeMessage(scope.module->mapAction(*messageName, 0, false), argCount, flags); -ref_t Compiler :: resolvePrimitiveType(ModuleScopeBase& moduleScope, ustr_t ns, TypeInfo typeInfo, - bool declarationMode) -{ - switch (typeInfo.typeRef) { - case V_UINT8: - return moduleScope.buildins.uint8Reference; - case V_INT8: - return moduleScope.buildins.int8Reference; - case V_INT16: - return moduleScope.buildins.shortReference; - case V_UINT16: - return moduleScope.buildins.ushortReference; - case V_INT32: - return moduleScope.buildins.intReference; - case V_INT64: - return moduleScope.buildins.longReference; - case V_FLOAT64: - return moduleScope.buildins.realReference; - case V_UINT32: - return moduleScope.buildins.uintReference; - case V_STRING: - return moduleScope.buildins.literalReference; - case V_WIDESTRING: - return moduleScope.buildins.wideReference; - case V_MESSAGE: - return moduleScope.buildins.messageReference; - case V_MESSAGENAME: - return moduleScope.buildins.messageNameReference; - case V_EXTMESSAGE64: - case V_EXTMESSAGE128: - return moduleScope.buildins.extMessageReference; - case V_FLAG: - return moduleScope.branchingInfo.typeRef; - case V_WRAPPER: - return resolveWrapperTemplate(moduleScope, ns, typeInfo.elementRef, declarationMode); - case V_INT8ARRAY: - case V_INT16ARRAY: - case V_INT32ARRAY: - case V_BINARYARRAY: - return resolveArrayTemplate(moduleScope, ns, typeInfo.elementRef, declarationMode); - case V_NULLABLE: - return resolveNullableTemplate(moduleScope, ns, typeInfo.elementRef, declarationMode); - case V_NIL: - return moduleScope.buildins.superReference; - case V_ARGARRAY: - return resolveArgArrayTemplate(moduleScope, ns, typeInfo.elementRef, declarationMode); - case V_OBJARRAY: - return resolveArrayTemplate(moduleScope, ns, typeInfo.elementRef, declarationMode); - case V_PTR32: - case V_PTR64: - return moduleScope.buildins.pointerReference; - default: - return 0; - } + addExtensionTemplateMessage(scope, messageRef, *signaturePattern, false); } -void Compiler :: declareSymbolAttributes(SymbolScope& scope, SyntaxNode node, bool identifierDeclarationMode) +void Compiler :: registerExtensionTemplate(TemplateScope& scope, SyntaxNode& node) { - bool constant = false; SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { - switch (current.key) { - case SyntaxKey::Attribute: - if (!_logic->validateSymbolAttribute(current.arg.value, scope.visibility, constant, scope.isStatic)) { - current.setArgumentValue(0); // HOTFIX : to prevent duplicate warnings - scope.raiseWarning(WARNING_LEVEL_1, wrnInvalidHint, current); - } - break; - case SyntaxKey::Type: - case SyntaxKey::ArrayType: - case SyntaxKey::TemplateType: - if (!identifierDeclarationMode) - scope.info.typeRef = resolveStrongTypeAttribute(scope, current, true, false); - break; - default: - break; + while (current != SyntaxKey::None) { + if (current == SyntaxKey::Method) { + registerExtensionTemplateMethod(scope, current); } - current = current.nextNode(); } +} - if (scope.visibility == Visibility::Public) { - scope.info.loadableInRuntime = true; - } - - if (constant && !identifierDeclarationMode) { - scope.info.symbolType = SymbolType::Constant; +void Compiler :: saveTemplate(TemplateScope& scope, SyntaxNode& node) +{ + MemoryBase* target = scope.module->mapSection(scope.reference | mskSyntaxTreeRef, false); - Interpreter interpreter(scope.moduleScope, _logic); - ObjectInfo operand = evalExpression(interpreter, scope, node.findChild(SyntaxKey::GetExpression).firstChild(), true); - if (operand.kind == ObjectKind::IntLiteral) { - NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - nsScope->defineIntConstant(scope.reference, operand.extra); - } + if (node == SyntaxKey::ExtensionTemplate) { + registerExtensionTemplate(scope, node); } + + SyntaxTree::saveNode(node, target); } -void Compiler :: declareClassAttributes(ClassScope& scope, SyntaxNode node, ref_t& flags) +void Compiler :: saveNamespaceInfo(SyntaxNode node, NamespaceScope* nsScope, bool outerMost) { - SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { - switch (current.key) { - case SyntaxKey::Attribute: - if (!_logic->validateClassAttribute(current.arg.value, flags, scope.visibility)) { - current.setArgumentValue(0); // HOTFIX : to prevent duplicate warnings - scope.raiseWarning(WARNING_LEVEL_1, wrnInvalidHint, current); - } - break; - case SyntaxKey::Type: - scope.raiseError(errInvalidSyntax, current); - break; - default: - break; - } + if (outerMost) + node.appendChild(SyntaxKey::SourcePath, *nsScope->sourcePath); - current = current.nextNode(); + IdentifierString nsFullName(nsScope->module->name()); + if (nsScope->nsName.length() > 0) { + nsFullName.append("'"); + nsFullName.append(*nsScope->nsName); } + node.appendChild(SyntaxKey::Import) + .appendChild(SyntaxKey::Name) + .appendChild(SyntaxKey::reference, *nsFullName); - // handle the abstract flag - if (test(scope.info.header.flags, elAbstract)) { - if (!test(flags, elAbstract)) { - scope.abstractBasedMode = true; - scope.info.header.flags &= ~elAbstract; - } - else scope.abstractMode = true; + for (auto it = nsScope->importedNs.start(); !it.eof(); ++it) { + node.appendChild(SyntaxKey::Import) + .appendChild(SyntaxKey::Name) + .appendChild(SyntaxKey::reference, *it); } - else scope.abstractMode = test(flags, elAbstract); -} -inline bool isMethodKind(ref_t hint) -{ - return (hint & (ref_t)MethodHint::Mask) != 0; + if (nsScope->parent) + saveNamespaceInfo(node, (NamespaceScope*)nsScope->parent, false); } -void Compiler :: declareArgumentAttributes(MethodScope& scope, SyntaxNode node, TypeInfo& typeInfo, - bool declarationMode) +void Compiler :: declareTemplate(TemplateScope& scope, SyntaxNode& node) { - SyntaxNode current = node.firstChild(); - TypeAttributes attributes = { false, false, false }; - while (current != SyntaxKey::None) { - switch (current.key) { - case SyntaxKey::Type: - // if it is a type attribute - typeInfo = resolveTypeAttribute(scope, current, attributes, declarationMode, false); - break; - case SyntaxKey::TemplateType: - // if it is a template type attribute - typeInfo = resolveTypeAttribute(scope, current, attributes, declarationMode, false); - break; - case SyntaxKey::ArrayType: - case SyntaxKey::NullableType: - // if it is a type attribute - typeInfo = resolveTypeScope(scope, current, attributes, declarationMode, false); - break; - case SyntaxKey::Attribute: - if (!_logic->validateArgumentAttribute(current.arg.reference, attributes)) - scope.raiseWarning(WARNING_LEVEL_1, wrnInvalidHint, current); - break; - default: - break; - } + switch (scope.type) { + case TemplateType::Class: + case TemplateType::InlineProperty: + { + // COMPILER MAGIC : inject imported namespaces & source path + NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - current = current.nextNode(); - } - if (attributes.byRefOne) { - typeInfo.elementRef = typeInfo.typeRef; - typeInfo.typeRef = V_WRAPPER; - } - else if (attributes.variadicOne) { - if (typeInfo.typeRef != V_ARGARRAY) - scope.raiseError(errInvalidOperation, node); + saveNamespaceInfo(node, nsScope, true); + break; + } + case TemplateType::Inline: + case TemplateType::Statement: + break; + default: + scope.raiseError(errInvalidSyntax, node); + break; } + + saveTemplate(scope, node); + + node.setKey(SyntaxKey::Idle); } -ref_t Compiler :: declareMultiType(Scope& scope, SyntaxNode& current, ref_t elementRef) +void Compiler :: declareTemplateCode(TemplateScope& scope, SyntaxNode& node) { - bool eol = false; - ArgumentsInfo items; - items.add({ ObjectKind::Class, { elementRef }, 0 }); + IdentifierString prefix; + IdentifierString postfix; + declareTemplateAttributes(scope, node, postfix); + if (scope.type == TemplateType::None) + scope.type = TemplateType::Statement; - while (current != SyntaxKey::None) { - if (current == SyntaxKey::Type) { - items.add({ ObjectKind::Class, { resolveStrongTypeAttribute(scope, current, true, false) }, 0 }); - } - else break; + int argCount = SyntaxTree::countChild(node, SyntaxKey::TemplateArg); + int paramCount = SyntaxTree::countChild(node, SyntaxKey::Parameter); - current = current.nextNode(); + switch (scope.type) { + case TemplateType::Inline: + prefix.append(INLINE_PREFIX); + if (argCount > 0) + scope.raiseError(errInvalidSyntax, node); + break; + case TemplateType::Statement: + postfix.append('#'); + postfix.appendInt(argCount); + break; + default: + break; } - return resolveTupleClass(scope, current, items); -} + postfix.append('#'); + postfix.appendInt(paramCount); -inline ref_t resloveWeakSelfReference(ModuleScopeBase* moduleScope, ref_t weakRef, ref_t classRef) -{ - ref_t resolvedRef = moduleScope->resolveWeakTemplateReferenceID(weakRef); + SyntaxNode name = node.findChild(SyntaxKey::Name); + if (name.nextNode() == SyntaxKey::ComplexName) { + SyntaxNode secondName = name.nextNode(); + size_t index = 0; + while (secondName == SyntaxKey::ComplexName) { + postfix.insert(secondName.firstChild().identifier(), index); + postfix.insert(":", index); - // HOTFIX : if it is a weak reference to the class - use the strong one - if (resolvedRef == classRef) { - return classRef; + index += secondName.firstChild().identifier().length() + 1; + + secondName = secondName.nextNode(); + } } - else return weakRef; + + scope.reference = mapNewTerminal(scope, *prefix, name, *postfix, scope.visibility); + if (scope.module->mapSection(scope.reference | mskSyntaxTreeRef, true)) + scope.raiseError(errDuplicatedDictionary, name.firstChild(SyntaxKey::TerminalMask)); + + declareMetaInfo(scope, node); + declareTemplate(scope, node); } -void Compiler :: declareMethodAttributes(MethodScope& scope, SyntaxNode node, bool exensionMode, bool templateBased) +void Compiler :: declareTemplateClass(TemplateScope& scope, SyntaxNode& node) { - if (exensionMode) - scope.info.hints |= (ref_t)MethodHint::Extension; + scope.type = TemplateType::Class; - SyntaxNode current = node.firstChild(); - bool explicitMode = false; - while (current != SyntaxKey::None) { - switch (current.key) { - case SyntaxKey::Attribute: - { - ref_t value = current.arg.reference; + IdentifierString postfix; + declareTemplateAttributes(scope, node, postfix); - ref_t hint = 0; - if (_logic->validateMethodAttribute(value, hint, explicitMode)) { - if (isMethodKind(hint) && isMethodKind(scope.info.hints)) { - // a method kind can be set only once - scope.raiseError(errInvalidHint, node); - } - else scope.info.hints |= hint; - } - else { - current.setArgumentReference(0); + int argCount = SyntaxTree::countChild(node, SyntaxKey::TemplateArg); + postfix.append('#'); + postfix.appendInt(argCount); - scope.raiseWarning(WARNING_LEVEL_1, wrnInvalidHint, node); - } - break; - } - case SyntaxKey::Type: - case SyntaxKey::ArrayType: - case SyntaxKey::TemplateType: - // if it is a type attribute - if (scope.info.outputRef) { - scope.info.outputRef = declareMultiType(scope, current, scope.info.outputRef); + if (SyntaxTree::ifChildExists(node, SyntaxKey::Attribute, V_WEAK)) + postfix.append(WEAK_POSTFIX); - continue; - } - else scope.info.outputRef = resolveStrongTypeAttribute(scope, current, true, false); - if (templateBased) - scope.info.outputRef = resloveWeakSelfReference(scope.moduleScope, scope.info.outputRef, scope.getClassRef()); + IdentifierString prefix; + switch (scope.type) { + case TemplateType::InlineProperty: + prefix.append(INLINE_PROPERTY_PREFIX); + break; + default: + break; + } - break; - case SyntaxKey::Name: - { - // resolving implicit method attributes - ref_t attr = scope.moduleScope->attributes.get(current.firstChild(SyntaxKey::TerminalMask).identifier()); - ref_t hint = (ref_t)MethodHint::None; - if (_logic->validateImplicitMethodAttribute(attr, hint)) { - scope.info.hints |= hint; - current.setKey(SyntaxKey::Attribute); - current.setArgumentReference(attr); - } - break; + SyntaxNode name = node.findChild(SyntaxKey::Name); + scope.reference = mapNewTerminal(scope, *prefix, name, *postfix, scope.visibility); + if (scope.module->mapSection(scope.reference | mskSyntaxTreeRef, true)) + scope.raiseError(errDuplicatedDictionary, name.firstChild(SyntaxKey::TerminalMask)); + + declareTemplate(scope, node); +} + +void Compiler :: declareDictionaryAttributes(Scope& scope, SyntaxNode node, TypeInfo& typeInfo, bool& superMode) +{ + SyntaxNode current = node.firstChild(); + while (current != SyntaxKey::None) { + if (current == SyntaxKey::Attribute) { + if (!_logic->validateDictionaryAttribute(current.arg.value, typeInfo, superMode)) { + current.setArgumentValue(0); // HOTFIX : to prevent duplicate warnings + scope.raiseWarning(WARNING_LEVEL_1, wrnInvalidHint, current); } - default: - break; + } + else if (current == SyntaxKey::Type) { + TypeAttributes typeAttributes = {}; + TypeInfo dictTypeInfo = resolveTypeAttribute(scope, current, typeAttributes, true, false); + if (!typeAttributes.isNonempty() && _logic->isCompatible(*scope.moduleScope, dictTypeInfo, { V_STRING }, true)) { + typeInfo.typeRef = V_DICTIONARY; + typeInfo.elementRef = V_STRING; + } + else scope.raiseError(errInvalidHint, current); } current = current.nextNode(); } } -void Compiler :: declareTemplateAttributes(TemplateScope& scope, SyntaxNode node, IdentifierString& postfix) +void Compiler :: declareExpressionAttributes(Scope& scope, SyntaxNode node, TypeInfo& typeInfo, ExpressionAttributes& mode) { SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { + while (current != SyntaxKey::None) { switch (current.key) { case SyntaxKey::Attribute: - if (!_logic->validateTemplateAttribute(current.arg.value, scope.visibility, scope.type)) - { - current.setArgumentValue(0); // HOTFIX : to prevent duplicate warnings - scope.raiseWarning(WARNING_LEVEL_1, wrnInvalidHint, current); - } + if (!_logic->validateExpressionAttribute(current.arg.reference, mode)) + scope.raiseError(errInvalidHint, current); + + if (current.arg.reference == V_AUTO) + typeInfo = { V_AUTO }; + break; case SyntaxKey::Type: - scope.raiseError(errInvalidSyntax, current); + case SyntaxKey::TemplateType: + case SyntaxKey::ArrayType: + case SyntaxKey::NullableType: + if (!EAttrs::test(mode.attrs, EAttr::NoTypeAllowed)) { + TypeAttributes attributes = {}; + typeInfo = resolveTypeAttribute(scope, current, attributes, false, false); + + if (attributes.mssgNameLiteral) { + mode |= ExpressionAttribute::MssgNameLiteral; + } + else if (attributes.newOp) { + mode |= ExpressionAttribute::NewOp; + } + else if (attributes.typecastOne) { + mode |= ExpressionAttribute::CastOp; + } + else { + if (!attributes.variableOne) { + if (attributes.isNonempty()) + scope.raiseError(errInvalidHint, current); + } + mode |= ExpressionAttribute::NewVariable; + } + } + else scope.raiseError(errInvalidHint, current); break; - case SyntaxKey::Postfix: - postfix.append(':'); - postfix.append(current.firstChild(SyntaxKey::TerminalMask).identifier()); + case SyntaxKey::Dimension: + typeInfo.elementRef = typeInfo.typeRef; + typeInfo.typeRef = V_OBJARRAY; break; default: break; @@ -5149,5030 +5004,4630 @@ void Compiler :: declareTemplateAttributes(TemplateScope& scope, SyntaxNode node } } -void Compiler :: registerTemplateSignature(TemplateScope& scope, SyntaxNode node, IdentifierString& signature) +void Compiler :: addExtensionMessage(Scope& scope, mssg_t message, ref_t extRef, mssg_t strongMessage, bool internalOne) { - signature.append(TEMPLATE_PREFIX_NS); - - size_t signIndex = signature.length(); + NamespaceScope* ns = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - IdentifierString templateName(node.firstChild(SyntaxKey::TerminalMask).identifier()); - int paramCounter = SyntaxTree::countChild(node, SyntaxKey::TemplateArg); - - templateName.append('#'); - templateName.appendInt(paramCounter); + if (ns->outerExtensionList != nullptr) { + // COMPILER MAGIC : if it is template extension compilation + ns->outerExtensionList->add(message, { extRef, strongMessage }); + } + else { + IdentifierString sectionName(internalOne ? PRIVATE_PREFIX_NS : "'"); + if (!ns->nsName.empty()) { + sectionName.append(*ns->nsName); + sectionName.append('\''); + } + sectionName.append(EXTENSION_SECTION); - NamespaceScope* ns = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - ref_t ref = ns->resolveImplicitIdentifier(*templateName, false, true); - if (!ref) - scope.raiseError(errUnknownClass, node); + MemoryBase* section = scope.module->mapSection( + scope.module->mapReference(*sectionName, false) | mskMetaExtensionRef, false); - ustr_t refName = scope.module->resolveReference(ref); - if (isWeakReference(refName)) - signature.append(scope.module->name()); + _logic->writeExtMessageEntry(section, extRef, message, strongMessage); - signature.append(refName); + ns->declaredExtensions.add(message, { extRef, strongMessage }); + } - SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { - if (current == SyntaxKey::TemplateArg) { - SyntaxNode argNode = current.firstChild(); + ns->addExtension(message, extRef, strongMessage); +} - if (argNode == SyntaxKey::Type) { - signature.append('&'); - ref_t classRef = resolveStrongTypeAttribute(scope, argNode, false, false); - if (!classRef) - scope.raiseError(errUnknownClass, current); +void Compiler :: addExtensionTemplateMessage(Scope& scope, mssg_t message, ustr_t pattern, bool internalOne) +{ + NamespaceScope* ns = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - ustr_t className = scope.module->resolveReference(classRef); - if (isWeakReference(className)) - signature.append(scope.module->name()); + IdentifierString sectionName(internalOne ? PRIVATE_PREFIX_NS : "'"); + if (!ns->nsName.empty()) { + sectionName.append(*ns->nsName); + sectionName.append('\''); + } + sectionName.append(EXTENSION_SECTION); - signature.append(className); - } - else if (argNode == SyntaxKey::TemplateArgParameter) { - signature.append('&'); - signature.append('{'); - signature.appendInt(argNode.arg.value); - signature.append('}'); - } - else assert(false); - } + MemoryBase* section = scope.module->mapSection( + scope.module->mapReference(*sectionName, false) | mskMetaExtensionRef, false); - current = current.nextNode(); - } + _logic->writeExtMessageEntry(section, message, pattern); - signature.replaceAll('\'', '@', signIndex); + ns->extensionTemplates.add(message, pattern.clone()); } -void Compiler :: registerExtensionTemplateMethod(TemplateScope& scope, SyntaxNode& node) +void Compiler :: declareExtension(ClassScope& scope, mssg_t message, bool internalOne) { - IdentifierString messageName; - pos_t argCount = 1; - ref_t flags = 0; - IdentifierString signaturePattern; - ustr_t extensionName = scope.module->resolveReference(scope.reference); - if (isWeakReference(extensionName)) { - signaturePattern.append(scope.module->name()); - } - signaturePattern.append(extensionName); - signaturePattern.append('.'); - - SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { - if (current == SyntaxKey::Name) { - messageName.copy(current.firstChild(SyntaxKey::TerminalMask).identifier()); - } - else if (current == SyntaxKey::Parameter) { - argCount++; - signaturePattern.append('/'); - SyntaxNode typeAttr = current.findChild(SyntaxKey::Type, SyntaxKey::ArrayType, SyntaxKey::TemplateArgParameter, SyntaxKey::TemplateType); - if (typeAttr == SyntaxKey::TemplateArgParameter) { - signaturePattern.append('{'); - signaturePattern.appendInt(typeAttr.arg.value); - signaturePattern.append('}'); - } - else if (typeAttr == SyntaxKey::TemplateType) { - registerTemplateSignature(scope, typeAttr, signaturePattern); - } - else if (typeAttr != SyntaxKey::None) { - ref_t classRef = resolveStrongTypeAttribute(scope, typeAttr, true, false); - - ustr_t className = scope.module->resolveReference(classRef); - if (isWeakReference(className)) - signaturePattern.append(scope.module->name()); + mssg_t extensionMessage = 0; - signaturePattern.append(className); - } - else scope.raiseError(/*errNotApplicable*/errInvalidOperation, current); - } - current = current.nextNode(); + // get generic message + ref_t signRef = 0; + ustr_t actionName = scope.module->resolveAction(getAction(message), signRef); + if (signRef) { + extensionMessage = overwriteAction(message, scope.module->mapAction(actionName, 0, false)); } + else extensionMessage = message; - mssg_t messageRef = encodeMessage(scope.module->mapAction(*messageName, 0, false), argCount, flags); + // exclude function flag + extensionMessage = extensionMessage & ~FUNCTION_MESSAGE; - addExtensionTemplateMessage(scope, messageRef, *signaturePattern, false); + addExtensionMessage(scope, extensionMessage, scope.reference, message, internalOne); } -void Compiler :: registerExtensionTemplate(TemplateScope& scope, SyntaxNode& node) +void Compiler :: validateType(Scope& scope, ref_t typeRef, SyntaxNode node, bool ignoreUndeclared, bool allowRole) { - SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { - if (current == SyntaxKey::Method) { - registerExtensionTemplateMethod(scope, current); + if (!typeRef) { + switch (node.key) { + case SyntaxKey::string: + scope.raiseError(errInvalidSyntax, node); + break; + default: + scope.raiseError(errUnknownClass, node); + break; } - current = current.nextNode(); } + + if (!_logic->isValidType(*scope.moduleScope, typeRef, ignoreUndeclared, allowRole)) + scope.raiseError(errInvalidType, node); } -void Compiler :: saveTemplate(TemplateScope& scope, SyntaxNode& node) +ref_t Compiler :: resolveTypeIdentifier(Scope& scope, ustr_t identifier, SyntaxKey type, + bool declarationMode, bool allowRole) { - MemoryBase* target = scope.module->mapSection(scope.reference | mskSyntaxTreeRef, false); + ObjectInfo identInfo; - if (node == SyntaxKey::ExtensionTemplate) { - registerExtensionTemplate(scope, node); + NamespaceScope* ns = Scope::getScope(scope, Scope::ScopeLevel::Namespace); + + if (type == SyntaxKey::reference && isWeakReference(identifier)) { + identInfo = ns->mapWeakReference(identifier, false); + } + else if (type == SyntaxKey::globalreference) { + identInfo = ns->mapGlobal(identifier, EAttr::None); } + else identInfo = ns->mapIdentifier(identifier, type == SyntaxKey::reference, EAttr::None); - SyntaxTree::saveNode(node, target); + switch (identInfo.kind) { + case ObjectKind::Class: + case ObjectKind::ClassSelf: + return identInfo.reference; + case ObjectKind::Symbol: + if (declarationMode) + return identInfo.reference; + case ObjectKind::Extension: + if (allowRole) + return identInfo.reference; + default: + return 0; + } } -void Compiler :: saveNamespaceInfo(SyntaxNode node, NamespaceScope* nsScope, bool outerMost) +ref_t Compiler :: mapTemplateType(Scope& scope, SyntaxNode terminal, pos_t paramCounter) { - if (outerMost) - node.appendChild(SyntaxKey::SourcePath, *nsScope->sourcePath); - - IdentifierString nsFullName(nsScope->module->name()); - if (nsScope->nsName.length() > 0) { - nsFullName.append("'"); - nsFullName.append(*nsScope->nsName); - } - node.appendChild(SyntaxKey::Import) - .appendChild(SyntaxKey::Name) - .appendChild(SyntaxKey::reference, *nsFullName); - - for (auto it = nsScope->importedNs.start(); !it.eof(); ++it) { - node.appendChild(SyntaxKey::Import) - .appendChild(SyntaxKey::Name) - .appendChild(SyntaxKey::reference, *it); - } + IdentifierString templateName; + templateName.append(terminal.identifier()); + templateName.append('#'); + templateName.appendInt(paramCounter); - if (nsScope->parent) - saveNamespaceInfo(node, (NamespaceScope*)nsScope->parent, false); + // NOTE : check it in declararion mode - we need only reference + return resolveTypeIdentifier(scope, *templateName, terminal.key, true, false); } -void Compiler :: declareTemplate(TemplateScope& scope, SyntaxNode& node) +void Compiler :: declareTemplateAttributes(Scope& scope, SyntaxNode node, + TemplateTypeList& parameters, TypeAttributes& attributes, bool declarationMode, bool objectMode) { - switch (scope.type) { - case TemplateType::Class: - case TemplateType::InlineProperty: - { - // COMPILER MAGIC : inject imported namespaces & source path - NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); + SyntaxNode current = objectMode ? node.nextNode() : node.firstChild(); + while (current != SyntaxKey::None) { + switch (current.key) { + case SyntaxKey::Attribute: + if (!_logic->validateTypeScopeAttribute(current.arg.reference, attributes)) + scope.raiseWarning(WARNING_LEVEL_1, wrnInvalidHint, current); + break; + case SyntaxKey::TemplateArg: + case SyntaxKey::Type: + case SyntaxKey::TemplateType: + { + ref_t typeRef = resolveStrongTypeAttribute(scope, current, declarationMode, attributes.mssgNameLiteral); + parameters.add(typeRef); - saveNamespaceInfo(node, nsScope, true); - break; + break; + } + default: + break; } - case TemplateType::Inline: - case TemplateType::Statement: - break; - default: - scope.raiseError(errInvalidSyntax, node); - break; + + current = current.nextNode(); } +} - saveTemplate(scope, node); +ref_t Compiler :: defineArrayType(Scope& scope, ref_t elementRef, bool declarationMode) +{ + ref_t retVal = _logic->definePrimitiveArray(*scope.moduleScope, elementRef, + _logic->isEmbeddable(*scope.moduleScope, elementRef)); - node.setKey(SyntaxKey::Idle); + if (!retVal && declarationMode) + retVal = V_OBJARRAY; + + return retVal; } -void Compiler :: declareTemplateCode(TemplateScope& scope, SyntaxNode& node) +ObjectInfo Compiler :: defineArrayType(Scope& scope, ObjectInfo info, bool declarationMode) { - IdentifierString prefix; - IdentifierString postfix; - declareTemplateAttributes(scope, node, postfix); - if (scope.type == TemplateType::None) - scope.type = TemplateType::Statement; + ref_t elementRef = info.typeInfo.typeRef; + ref_t arrayRef = defineArrayType(scope, elementRef, declarationMode); - int argCount = SyntaxTree::countChild(node, SyntaxKey::TemplateArg); - int paramCount = SyntaxTree::countChild(node, SyntaxKey::Parameter); + info.typeInfo.typeRef = arrayRef; + info.typeInfo.elementRef = elementRef; - switch (scope.type) { - case TemplateType::Inline: - prefix.append(INLINE_PREFIX); - if (argCount > 0) - scope.raiseError(errInvalidSyntax, node); - break; - case TemplateType::Statement: - postfix.append('#'); - postfix.appendInt(argCount); - break; - default: - break; - } + if (info.mode == TargetMode::Creating) + info.mode = TargetMode::CreatingArray; - postfix.append('#'); - postfix.appendInt(paramCount); + return info; +} - SyntaxNode name = node.findChild(SyntaxKey::Name); - if (name.nextNode() == SyntaxKey::ComplexName) { - SyntaxNode secondName = name.nextNode(); - size_t index = 0; - while (secondName == SyntaxKey::ComplexName) { - postfix.insert(secondName.firstChild().identifier(), index); - postfix.insert(":", index); +ref_t Compiler :: resolveTypeTemplate(Scope& scope, SyntaxNode node, + TypeAttributes& attributes, bool declarationMode, bool objectMode) +{ + TemplateTypeList typeList; + declareTemplateAttributes(scope, node, typeList, attributes, declarationMode, objectMode); - index += secondName.firstChild().identifier().length() + 1; + SyntaxNode terminalNode = node != SyntaxKey::TemplateType ? node : node.firstChild(SyntaxKey::TerminalMask); + if (attributes.mssgNameLiteral) { + if (typeList.count() != 1) + scope.raiseError(errInvalidOperation, node); - secondName = secondName.nextNode(); - } + return typeList.get(0); } + else { + // HOTFIX : generate a temporal template to pass the type + SyntaxTree dummyTree; + List parameters({}); + declareTemplateParameters(scope.module, typeList, dummyTree, parameters); - scope.reference = mapNewTerminal(scope, *prefix, name, *postfix, scope.visibility); - if (scope.module->mapSection(scope.reference | mskSyntaxTreeRef, true)) - scope.raiseError(errDuplicatedDictionary, name.firstChild(SyntaxKey::TerminalMask)); + ref_t templateRef = mapTemplateType(scope, terminalNode, parameters.count()); + if (!templateRef) + scope.raiseError(errUnknownClass, terminalNode); - declareMetaInfo(scope, node); - declareTemplate(scope, node); + NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); + + return _templateProcessor->generateClassTemplate(*scope.moduleScope, *nsScope->nsName, + templateRef, parameters, declarationMode, nullptr); + } } -void Compiler :: declareTemplateClass(TemplateScope& scope, SyntaxNode& node) +ref_t Compiler :: resolveTemplate(ModuleScopeBase& moduleScope, ustr_t ns, ref_t templateRef, + ref_t elementRef, bool declarationMode) { - scope.type = TemplateType::Class; + if (isPrimitiveRef(elementRef)) + elementRef = resolvePrimitiveType(moduleScope, ns, { elementRef }); - IdentifierString postfix; - declareTemplateAttributes(scope, node, postfix); + TemplateTypeList typeList; + typeList.add(elementRef); - int argCount = SyntaxTree::countChild(node, SyntaxKey::TemplateArg); - postfix.append('#'); - postfix.appendInt(argCount); + // HOTFIX : generate a temporal template to pass the type + SyntaxTree dummyTree; + List parameters({}); + declareTemplateParameters(moduleScope.module, typeList, dummyTree, parameters); - if (SyntaxTree::ifChildExists(node, SyntaxKey::Attribute, V_WEAK)) - postfix.append(WEAK_POSTFIX); + return _templateProcessor->generateClassTemplate(moduleScope, ns, + templateRef, parameters, declarationMode, nullptr); +} - IdentifierString prefix; - switch (scope.type) { - case TemplateType::InlineProperty: - prefix.append(INLINE_PROPERTY_PREFIX); - break; - default: - break; +ref_t Compiler :: resolveClosure(Scope& scope, mssg_t closureMessage, ref_t outputRef) +{ + ref_t signRef = 0; + scope.module->resolveAction(getAction(closureMessage), signRef); + + int paramCount = getArgCount(closureMessage); + + IdentifierString closureName(scope.module->resolveReference(scope.moduleScope->buildins.closureTemplateReference)); + if (signRef == 0) { + if (paramCount > 0) { + closureName.appendInt(paramCount); + } + + if (isWeakReference(*closureName)) { + return scope.module->mapReference(*closureName, true); + } + else return scope.moduleScope->mapFullReference(*closureName, true); } + else { + ref_t signatures[ARG_COUNT]; + size_t signLen = scope.module->resolveSignature(signRef, signatures); - SyntaxNode name = node.findChild(SyntaxKey::Name); - scope.reference = mapNewTerminal(scope, *prefix, name, *postfix, scope.visibility); - if (scope.module->mapSection(scope.reference | mskSyntaxTreeRef, true)) - scope.raiseError(errDuplicatedDictionary, name.firstChild(SyntaxKey::TerminalMask)); + List parameters({}); - declareTemplate(scope, node); -} + // HOTFIX : generate a temporal template to pass the type + SyntaxTree dummyTree; + SyntaxTreeWriter dummyWriter(dummyTree); + dummyWriter.newNode(SyntaxKey::Root); -void Compiler :: declareDictionaryAttributes(Scope& scope, SyntaxNode node, TypeInfo& typeInfo, bool& superMode) -{ - SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { - if (current == SyntaxKey::Attribute) { - if (!_logic->validateDictionaryAttribute(current.arg.value, typeInfo, superMode)) { - current.setArgumentValue(0); // HOTFIX : to prevent duplicate warnings - scope.raiseWarning(WARNING_LEVEL_1, wrnInvalidHint, current); + for (size_t i = 0; i < signLen; i++) { + dummyWriter.newNode(SyntaxKey::TemplateArg, signatures[i]); + dummyWriter.newNode(SyntaxKey::Type); + + ustr_t referenceName = scope.moduleScope->module->resolveReference(signatures[i]); + if (isWeakReference(referenceName)) { + dummyWriter.appendNode(SyntaxKey::reference, referenceName); } + else dummyWriter.appendNode(SyntaxKey::globalreference, referenceName); + + dummyWriter.closeNode(); + dummyWriter.closeNode(); } - else if (current == SyntaxKey::Type) { - TypeAttributes typeAttributes = {}; - TypeInfo dictTypeInfo = resolveTypeAttribute(scope, current, typeAttributes, true, false); - if (!typeAttributes.isNonempty() && _logic->isCompatible(*scope.moduleScope, dictTypeInfo, { V_STRING }, true)) { - typeInfo.typeRef = V_DICTIONARY; - typeInfo.elementRef = V_STRING; + + if (outputRef) { + dummyWriter.newNode(SyntaxKey::TemplateArg, outputRef); + dummyWriter.newNode(SyntaxKey::Type); + + ustr_t referenceName = scope.moduleScope->module->resolveReference(outputRef); + if (isWeakReference(referenceName)) { + dummyWriter.appendNode(SyntaxKey::reference, referenceName); } - else scope.raiseError(errInvalidHint, current); + else dummyWriter.appendNode(SyntaxKey::globalreference, referenceName); + + dummyWriter.closeNode(); + dummyWriter.closeNode(); } - current = current.nextNode(); + dummyWriter.closeNode(); + + SyntaxNode current = dummyTree.readRoot().firstChild(); + while (current == SyntaxKey::TemplateArg) { + parameters.add(current); + + current = current.nextNode(); + } + + closureName.append('#'); + closureName.appendInt(paramCount + 1); + + ref_t templateReference = 0; + if (isWeakReference(*closureName)) { + templateReference = scope.module->mapReference(*closureName, true); + } + else templateReference = scope.moduleScope->mapFullReference(*closureName, true); + + NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); + + return _templateProcessor->generateClassTemplate(*scope.moduleScope, *nsScope->nsName, + templateReference, parameters, false, nullptr); } } -void Compiler :: declareExpressionAttributes(Scope& scope, SyntaxNode node, TypeInfo& typeInfo, ExpressionAttributes& mode) +ref_t Compiler :: resolveWrapperTemplate(ModuleScopeBase& moduleScope, ustr_t ns, ref_t elementRef, bool declarationMode) +{ + if (!elementRef) + elementRef = moduleScope.buildins.superReference; + + return resolveTemplate(moduleScope, ns, moduleScope.buildins.wrapperTemplateReference, elementRef, declarationMode); +} + +ref_t Compiler :: resolveArrayTemplate(ModuleScopeBase& moduleScope, ustr_t ns, ref_t elementRef, bool declarationMode) +{ + return resolveTemplate(moduleScope, ns, moduleScope.buildins.arrayTemplateReference, elementRef, declarationMode); +} + +ref_t Compiler :: resolveNullableTemplate(ModuleScopeBase& moduleScope, ustr_t ns, ref_t elementRef, bool declarationMode) { + return resolveTemplate(moduleScope, ns, moduleScope.buildins.nullableTemplateReference, elementRef, declarationMode); +} + +ref_t Compiler :: resolveArgArrayTemplate(ModuleScopeBase& moduleScope, ustr_t ns, ref_t elementRef, bool declarationMode) +{ + return resolveTemplate(moduleScope, ns, moduleScope.buildins.argArrayTemplateReference, elementRef, declarationMode); +} + +TypeInfo Compiler :: resolveTypeScope(Scope& scope, SyntaxNode node, TypeAttributes& attributes, + bool declarationMode, bool allowRole) +{ + ref_t elementRef = 0; + SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { + while (current != SyntaxKey::None) { switch (current.key) { case SyntaxKey::Attribute: - if (!_logic->validateExpressionAttribute(current.arg.reference, mode)) - scope.raiseError(errInvalidHint, current); - - if (current.arg.reference == V_AUTO) - typeInfo = { V_AUTO }; - + if (!_logic->validateTypeScopeAttribute(current.arg.reference, attributes)) + scope.raiseWarning(WARNING_LEVEL_1, wrnInvalidHint, current); break; case SyntaxKey::Type: - case SyntaxKey::TemplateType: + elementRef = resolveStrongTypeAttribute(scope, current, declarationMode, false); + break; + case SyntaxKey::identifier: + case SyntaxKey::reference: + elementRef = resolveTypeIdentifier(scope, current.identifier(), node.key, declarationMode, allowRole); + break; case SyntaxKey::ArrayType: case SyntaxKey::NullableType: - if (!EAttrs::test(mode.attrs, EAttr::NoTypeAllowed)) { - TypeAttributes attributes = {}; - typeInfo = resolveTypeAttribute(scope, current, attributes, false, false); - - if (attributes.mssgNameLiteral) { - mode |= ExpressionAttribute::MssgNameLiteral; - } - else if (attributes.newOp) { - mode |= ExpressionAttribute::NewOp; - } - else if (attributes.typecastOne) { - mode |= ExpressionAttribute::CastOp; - } - else { - if (!attributes.variableOne) { - if (attributes.isNonempty()) - scope.raiseError(errInvalidHint, current); - } - mode |= ExpressionAttribute::NewVariable; - } - } - else scope.raiseError(errInvalidHint, current); - break; - case SyntaxKey::Dimension: - typeInfo.elementRef = typeInfo.typeRef; - typeInfo.typeRef = V_OBJARRAY; + elementRef = resolvePrimitiveType(scope, resolveTypeAttribute(scope, current, attributes, declarationMode, allowRole), declarationMode); break; default: + assert(false); break; } current = current.nextNode(); } -} - -void Compiler :: addExtensionMessage(Scope& scope, mssg_t message, ref_t extRef, mssg_t strongMessage, bool internalOne) -{ - NamespaceScope* ns = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - if (ns->outerExtensionList != nullptr) { - // COMPILER MAGIC : if it is template extension compilation - ns->outerExtensionList->add(message, { extRef, strongMessage }); - } - else { - IdentifierString sectionName(internalOne ? PRIVATE_PREFIX_NS : "'"); - if (!ns->nsName.empty()) { - sectionName.append(*ns->nsName); - sectionName.append('\''); + if (node == SyntaxKey::ArrayType) { + if (attributes.variadicOne) { + return { V_ARGARRAY, elementRef }; } - sectionName.append(EXTENSION_SECTION); - - MemoryBase* section = scope.module->mapSection( - scope.module->mapReference(*sectionName, false) | mskMetaExtensionRef, false); - - _logic->writeExtMessageEntry(section, extRef, message, strongMessage); - - ns->declaredExtensions.add(message, { extRef, strongMessage }); + else return { defineArrayType(scope, elementRef, declarationMode), elementRef }; } - - ns->addExtension(message, extRef, strongMessage); -} - -void Compiler :: addExtensionTemplateMessage(Scope& scope, mssg_t message, ustr_t pattern, bool internalOne) -{ - NamespaceScope* ns = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - - IdentifierString sectionName(internalOne ? PRIVATE_PREFIX_NS : "'"); - if (!ns->nsName.empty()) { - sectionName.append(*ns->nsName); - sectionName.append('\''); + else if (node == SyntaxKey::NullableType) { + return { resolvePrimitiveType(scope, { V_NULLABLE, elementRef }, declarationMode) }; } - sectionName.append(EXTENSION_SECTION); - - MemoryBase* section = scope.module->mapSection( - scope.module->mapReference(*sectionName, false) | mskMetaExtensionRef, false); - - _logic->writeExtMessageEntry(section, message, pattern); - - ns->extensionTemplates.add(message, pattern.clone()); + else return {}; } -void Compiler :: declareExtension(ClassScope& scope, mssg_t message, bool internalOne) +TypeInfo Compiler :: resolveTypeAttribute(Scope& scope, SyntaxNode node, TypeAttributes& attributes, + bool declarationMode, bool allowRole) { - mssg_t extensionMessage = 0; + TypeInfo typeInfo = {}; + switch (node.key) { + case SyntaxKey::TemplateArg: + typeInfo = resolveTypeAttribute(scope, node.firstChild(), attributes, declarationMode, allowRole); + break; + case SyntaxKey::Type: + { + if (node.arg.reference) + return { node.arg.reference }; - // get generic message - ref_t signRef = 0; - ustr_t actionName = scope.module->resolveAction(getAction(message), signRef); - if (signRef) { - extensionMessage = overwriteAction(message, scope.module->mapAction(actionName, 0, false)); + SyntaxNode current = node.firstChild(); + if (current == SyntaxKey::Type || current == SyntaxKey::ArrayType || current == SyntaxKey::NullableType) { + // !! should be refactored + typeInfo = resolveTypeAttribute(scope, current, attributes, declarationMode, allowRole); + } + else if (current == SyntaxKey::TemplateType) { + typeInfo.typeRef = resolveTypeTemplate(scope, current, attributes, declarationMode); + } + else if (SyntaxTree::test(current.key, SyntaxKey::TerminalMask)) { + if (current.nextNode() == SyntaxKey::TemplateArg) { + // !! should be refactored : TemplateType should be used instead + typeInfo.typeRef = resolveTypeTemplate(scope, current, attributes, declarationMode); + } + else typeInfo.typeRef = resolveTypeIdentifier(scope, current.identifier(), current.key, declarationMode, allowRole); + } + else assert(false); + break; + } + case SyntaxKey::TemplateType: + typeInfo.typeRef = resolveTypeTemplate(scope, node, attributes, declarationMode); + break; + case SyntaxKey::ArrayType: + { + typeInfo = resolveTypeScope(scope, node, attributes, declarationMode, allowRole); + + if (attributes.variadicOne) + scope.raiseError(errInvalidOperation, node); + break; + } + case SyntaxKey::NullableType: + typeInfo = resolveTypeScope(scope, node, attributes, declarationMode, allowRole); + break; + default: + if (SyntaxTree::test(node.key, SyntaxKey::TerminalMask)) { + typeInfo.typeRef = resolveTypeIdentifier(scope, node.identifier(), node.key, declarationMode, allowRole); + } + else assert(false); + break; } - else extensionMessage = message; - // exclude function flag - extensionMessage = extensionMessage & ~FUNCTION_MESSAGE; + validateType(scope, typeInfo.typeRef, node, declarationMode, allowRole || attributes.mssgNameLiteral); - addExtensionMessage(scope, extensionMessage, scope.reference, message, internalOne); + return typeInfo; } -void Compiler :: validateType(Scope& scope, ref_t typeRef, SyntaxNode node, bool ignoreUndeclared, bool allowRole) +ref_t Compiler :: resolveStrongTypeAttribute(Scope& scope, SyntaxNode node, bool declarationMode, bool allowRole) { - if (!typeRef) { - switch (node.key) { - case SyntaxKey::string: - scope.raiseError(errInvalidSyntax, node); - break; - default: - scope.raiseError(errUnknownClass, node); - break; - } - } + TypeAttributes typeAttributes = {}; + TypeInfo typeInfo = resolveTypeAttribute(scope, node, typeAttributes, declarationMode, allowRole); + if (typeAttributes.isNonempty()) + scope.raiseError(errInvalidOperation, node); - if (!_logic->isValidType(*scope.moduleScope, typeRef, ignoreUndeclared, allowRole)) - scope.raiseError(errInvalidType, node); + if (isPrimitiveRef(typeInfo.typeRef)) { + return resolvePrimitiveType(scope, typeInfo, declarationMode); + } + else return typeInfo.typeRef; } -ref_t Compiler :: resolveTypeIdentifier(Scope& scope, ustr_t identifier, SyntaxKey type, - bool declarationMode, bool allowRole) +int Compiler :: resolveSize(Scope& scope, SyntaxNode node) { - ObjectInfo identInfo; + Interpreter interpreter(scope.moduleScope, _logic); - NamespaceScope* ns = Scope::getScope(scope, Scope::ScopeLevel::Namespace); + ObjectInfo retVal = evalObject(interpreter, scope, node); - if (type == SyntaxKey::reference && isWeakReference(identifier)) { - identInfo = ns->mapWeakReference(identifier, false); - } - else if (type == SyntaxKey::globalreference) { - identInfo = ns->mapGlobal(identifier, EAttr::None); + if (retVal.kind == ObjectKind::IntLiteral) { + return retVal.extra; } - else identInfo = ns->mapIdentifier(identifier, type == SyntaxKey::reference, EAttr::None); + else { + scope.raiseError(errInvalidSyntax, node); - switch (identInfo.kind) { - case ObjectKind::Class: - case ObjectKind::ClassSelf: - return identInfo.reference; - case ObjectKind::Symbol: - if (declarationMode) - return identInfo.reference; - case ObjectKind::Extension: - if (allowRole) - return identInfo.reference; - default: - return 0; + return 0; } } -ref_t Compiler :: mapTemplateType(Scope& scope, SyntaxNode terminal, pos_t paramCounter) -{ - IdentifierString templateName; - templateName.append(terminal.identifier()); - templateName.append('#'); - templateName.appendInt(paramCounter); - - // NOTE : check it in declararion mode - we need only reference - return resolveTypeIdentifier(scope, *templateName, terminal.key, true, false); -} - -void Compiler :: declareTemplateAttributes(Scope& scope, SyntaxNode node, - TemplateTypeList& parameters, TypeAttributes& attributes, bool declarationMode, bool objectMode) +void Compiler :: readFieldAttributes(ClassScope& scope, SyntaxNode node, FieldAttributes& attrs, bool declarationMode) { - SyntaxNode current = objectMode ? node.nextNode() : node.firstChild(); + SyntaxNode current = node.firstChild(); while (current != SyntaxKey::None) { switch (current.key) { + case SyntaxKey::Autogenerated: + attrs.autogenerated = true; + break; case SyntaxKey::Attribute: - if (!_logic->validateTypeScopeAttribute(current.arg.reference, attributes)) - scope.raiseWarning(WARNING_LEVEL_1, wrnInvalidHint, current); + if (!_logic->validateFieldAttribute(current.arg.reference, attrs)) + scope.raiseError(errInvalidHint, current); break; - case SyntaxKey::TemplateArg: case SyntaxKey::Type: case SyntaxKey::TemplateType: - { - ref_t typeRef = resolveStrongTypeAttribute(scope, current, declarationMode, attributes.mssgNameLiteral); - parameters.add(typeRef); + if (!attrs.typeInfo.typeRef) { + TypeAttributes typeAttributes = {}; + attrs.typeInfo = resolveTypeAttribute(scope, current, typeAttributes, declarationMode, false); + if (typeAttributes.isNonempty()) + scope.raiseError(errInvalidHint, current); + } + else scope.raiseError(errInvalidHint, current); break; - } - default: + case SyntaxKey::Dimension: + if (!attrs.size && attrs.typeInfo.typeRef && !attrs.inlineArray) { + if (current.arg.value) { + attrs.size = current.arg.value; + } + else attrs.size = resolveSize(scope, current.firstChild(SyntaxKey::TerminalMask)); + attrs.fieldArray = true; + } + else scope.raiseError(errInvalidHint, current); break; - } - - current = current.nextNode(); - } -} - -ref_t Compiler :: defineArrayType(Scope& scope, ref_t elementRef, bool declarationMode) -{ - ref_t retVal = _logic->definePrimitiveArray(*scope.moduleScope, elementRef, - _logic->isEmbeddable(*scope.moduleScope, elementRef)); + case SyntaxKey::ArrayType: + if (!attrs.size) { + attrs.size = -1; - if (!retVal && declarationMode) - retVal = V_OBJARRAY; + readFieldAttributes(scope, current, attrs, declarationMode); - return retVal; -} + if (attrs.typeInfo.isPrimitive()) + attrs.typeInfo = { resolvePrimitiveType(scope, attrs.typeInfo, declarationMode) }; -ObjectInfo Compiler :: defineArrayType(Scope& scope, ObjectInfo info, bool declarationMode) -{ - ref_t elementRef = info.typeInfo.typeRef; - ref_t arrayRef = defineArrayType(scope, elementRef, declarationMode); + if (!declarationMode) { + NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - info.typeInfo.typeRef = arrayRef; - info.typeInfo.elementRef = elementRef; + resolveArrayTemplate(*scope.moduleScope, *nsScope->nsName, + attrs.typeInfo.typeRef, declarationMode); + } + } + else if (attrs.size == -1) { + // if it is a nested array + NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - if (info.mode == TargetMode::Creating) - info.mode = TargetMode::CreatingArray; + readFieldAttributes(scope, current, attrs, declarationMode); + attrs.typeInfo = { resolveArrayTemplate(*scope.moduleScope, *nsScope->nsName, + attrs.typeInfo.typeRef, declarationMode) }; + } + else scope.raiseError(errInvalidHint, current); + break; + default: + break; + } - return info; + current = current.nextNode(); + } } -ref_t Compiler :: resolveTypeTemplate(Scope& scope, SyntaxNode node, - TypeAttributes& attributes, bool declarationMode, bool objectMode) +void Compiler :: declareFieldAttributes(ClassScope& scope, SyntaxNode node, FieldAttributes& attrs) { - TemplateTypeList typeList; - declareTemplateAttributes(scope, node, typeList, attributes, declarationMode, objectMode); + readFieldAttributes(scope, node, attrs, true); - SyntaxNode terminalNode = node != SyntaxKey::TemplateType ? node : node.firstChild(SyntaxKey::TerminalMask); - if (attributes.mssgNameLiteral) { - if (typeList.count() != 1) - scope.raiseError(errInvalidOperation, node); + //HOTFIX : recognize raw data + if (attrs.typeInfo.isPrimitive()) { + bool valid = true; + switch (attrs.typeInfo.typeRef) { + case V_INTBINARY: + switch (attrs.size) { + case 1: + attrs.typeInfo.typeRef = V_INT8; + attrs.fieldArray = false; + break; + case 2: + attrs.typeInfo.typeRef = V_INT16; + attrs.fieldArray = false; + break; + case 4: + attrs.typeInfo.typeRef = V_INT32; + attrs.fieldArray = false; + break; + case 8: + attrs.typeInfo.typeRef = V_INT64; + attrs.fieldArray = false; + break; + default: + valid = false; + break; + } + break; + case V_UINTBINARY: + switch (attrs.size) { + case 1: + attrs.typeInfo.typeRef = V_UINT8; + attrs.fieldArray = false; + break; + case 2: + attrs.typeInfo.typeRef = V_UINT16; + attrs.fieldArray = false; + break; + case 4: + attrs.typeInfo.typeRef = V_UINT32; + attrs.fieldArray = false; + break; + default: + valid = false; + break; + } + break; + case V_WORDBINARY: + switch (attrs.size) { + case 4: + attrs.typeInfo.typeRef = V_WORD32; + attrs.fieldArray = false; + break; + case 8: + attrs.typeInfo.typeRef = V_WORD64; + attrs.fieldArray = false; + break; + default: + valid = false; + break; + } + break; + case V_EXTMESSAGE: + switch (scope.moduleScope->ptrSize) { + case 4: + attrs.typeInfo.typeRef = V_EXTMESSAGE64; + attrs.size = 8; + attrs.fieldArray = false; + break; + case 8: + attrs.typeInfo.typeRef = V_EXTMESSAGE128; + attrs.size = 16; + attrs.fieldArray = false; + break; + default: + valid = false; + break; + } + break; + case V_MSSGBINARY: + switch (attrs.size) { + case 4: + attrs.typeInfo.typeRef = V_MESSAGE; + attrs.fieldArray = false; + break; + default: + valid = false; + break; + } + break; + case V_SUBJBINARY: + switch (attrs.size) { + case 4: + attrs.typeInfo.typeRef = V_MESSAGENAME; + attrs.fieldArray = false; + break; + default: + valid = false; + break; + } + break; + case V_FLOATBINARY: + switch (attrs.size) { + case 8: + attrs.typeInfo.typeRef = V_FLOAT64; + attrs.fieldArray = false; + break; + default: + valid = false; + break; + } + break; + case V_POINTER: + switch (attrs.size) { + case 4: + attrs.typeInfo.typeRef = V_PTR32; + attrs.fieldArray = false; + break; + case 8: + attrs.typeInfo.typeRef = V_PTR64; + attrs.fieldArray = false; + break; + case 0: + attrs.fieldArray = false; + attrs.size = scope.moduleScope->ptrSize; + if (attrs.size == 4) { + attrs.typeInfo.typeRef = V_PTR32; + } + else if (attrs.size == 8) { + attrs.typeInfo.typeRef = V_PTR64; + } + else assert(false); + break; + default: + valid = false; + break; + } + break; + default: + valid = false; + break; + } - return typeList.get(0); + if (!valid) + scope.raiseError(errInvalidHint, node.findChild(SyntaxKey::Name)); } - else { - // HOTFIX : generate a temporal template to pass the type - SyntaxTree dummyTree; - List parameters({}); - declareTemplateParameters(scope.module, typeList, dummyTree, parameters); +} - ref_t templateRef = mapTemplateType(scope, terminalNode, parameters.count()); - if (!templateRef) - scope.raiseError(errUnknownClass, terminalNode); +inline int newLocalAddr(int disp, int allocated) +{ + return -disp - allocated; +} - NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); +int Compiler :: allocateLocalAddress(Scope& scope, int size, bool binaryArray) +{ + int retVal = 0; - return _templateProcessor->generateClassTemplate(*scope.moduleScope, *nsScope->nsName, - templateRef, parameters, declarationMode, nullptr); + CodeScope* codeScope = Scope::getScope(scope, Scope::ScopeLevel::Code); + if (codeScope != nullptr) { + if (binaryArray) + codeScope->allocLocalAddress(4); + + retVal = codeScope->allocLocalAddress(size); + } + else { + SymbolScope* symbolScope = Scope::getScope(scope, Scope::ScopeLevel::Symbol); + assert(symbolScope != nullptr); + + if (binaryArray) + symbolScope->allocLocalAddress(4); + + retVal = symbolScope->allocLocalAddress(size); } + + return newLocalAddr(sizeof(intptr_t), retVal); } -ref_t Compiler :: resolveTemplate(ModuleScopeBase& moduleScope, ustr_t ns, ref_t templateRef, - ref_t elementRef, bool declarationMode) +int Compiler :: resolveArraySize(Scope& scope, SyntaxNode node) { - if (isPrimitiveRef(elementRef)) - elementRef = resolvePrimitiveType(moduleScope, ns, { elementRef }); + Interpreter interpreter(scope.moduleScope, _logic); + ObjectInfo retVal = evalExpression(interpreter, scope, node); + switch (retVal.kind) { + case ObjectKind::IntLiteral: + return retVal.extra; + break; + default: + scope.raiseError(errInvalidOperation, node); + return 0; + } +} - TemplateTypeList typeList; - typeList.add(elementRef); +bool Compiler :: declareYieldVariable(Scope& scope, ustr_t name, TypeInfo typeInfo) +{ + ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); - // HOTFIX : generate a temporal template to pass the type - SyntaxTree dummyTree; - List parameters({}); - declareTemplateParameters(moduleScope.module, typeList, dummyTree, parameters); + FieldAttributes attrs = { typeInfo }; - return _templateProcessor->generateClassTemplate(moduleScope, ns, - templateRef, parameters, declarationMode, nullptr); + // NOTE : should return false to indicate that it is not a variable + return !generateClassField(*classScope, attrs, name, 0, typeInfo, false); } -ref_t Compiler :: resolveClosure(Scope& scope, mssg_t closureMessage, ref_t outputRef) +bool Compiler :: declareVariable(Scope& scope, SyntaxNode terminal, TypeInfo typeInfo, bool ignoreDuplicate) { - ref_t signRef = 0; - scope.module->resolveAction(getAction(closureMessage), signRef); + int size = 0; + if (terminal == SyntaxKey::IndexerOperation) { + // COMPILER MAGIC : if it is a fixed-sized array + size = resolveArraySize(scope, terminal.firstChild(SyntaxKey::ScopeMask)); - int paramCount = getArgCount(closureMessage); + terminal = terminal.findChild(SyntaxKey::Object).findChild(SyntaxKey::identifier); + } - IdentifierString closureName(scope.module->resolveReference(scope.moduleScope->buildins.closureTemplateReference)); - if (signRef == 0) { - if (paramCount > 0) { - closureName.appendInt(paramCount); - } + ExprScope* exprScope = Scope::getScope(scope, Scope::ScopeLevel::Expr); + CodeScope* codeScope = Scope::getScope(scope, Scope::ScopeLevel::Code); + MethodScope* methodScope = Scope::getScope(scope, Scope::ScopeLevel::Method); + if (codeScope == nullptr) { + scope.raiseError(errInvalidOperation, terminal); + return false; // the code will never be reached + } - if (isWeakReference(*closureName)) { - return scope.module->mapReference(*closureName, true); + IdentifierString identifier(terminal.identifier()); + if (ignoreDuplicate) { + auto var = codeScope->mapIdentifier(*identifier, false, EAttr::None); + switch (var.kind) { + case ObjectKind::Local: + case ObjectKind::LocalAddress: + // exit if the variable with this names does exist + return false; + default: + break; } - else return scope.moduleScope->mapFullReference(*closureName, true); } - else { - ref_t signatures[ARG_COUNT]; - size_t signLen = scope.module->resolveSignature(signRef, signatures); - - List parameters({}); - // HOTFIX : generate a temporal template to pass the type - SyntaxTree dummyTree; - SyntaxTreeWriter dummyWriter(dummyTree); - dummyWriter.newNode(SyntaxKey::Root); - - for (size_t i = 0; i < signLen; i++) { - dummyWriter.newNode(SyntaxKey::TemplateArg, signatures[i]); - dummyWriter.newNode(SyntaxKey::Type); - - ustr_t referenceName = scope.moduleScope->module->resolveReference(signatures[i]); - if (isWeakReference(referenceName)) { - dummyWriter.appendNode(SyntaxKey::reference, referenceName); - } - else dummyWriter.appendNode(SyntaxKey::globalreference, referenceName); + ObjectInfo variable; + variable.typeInfo = typeInfo; + variable.kind = ObjectKind::Local; - dummyWriter.closeNode(); - dummyWriter.closeNode(); + if (size != 0 && variable.typeInfo.typeRef != 0) { + if (!variable.typeInfo.isPrimitive()) { + // if it is a primitive array + variable.typeInfo.elementRef = variable.typeInfo.typeRef; + variable.typeInfo.typeRef = _logic->definePrimitiveArray(*scope.moduleScope, variable.typeInfo.elementRef, true); } + else scope.raiseError(errInvalidHint, terminal); + } + else if (_logic->isPrimitiveArrRef(variable.typeInfo.typeRef)) { + // if it is an array reference + variable.typeInfo.typeRef = resolvePrimitiveType(scope, variable.typeInfo, false); + variable.typeInfo.elementRef = 0; + } - if (outputRef) { - dummyWriter.newNode(SyntaxKey::TemplateArg, outputRef); - dummyWriter.newNode(SyntaxKey::Type); + ClassInfo localInfo; + //bool binaryArray = false; + if (!_logic->defineClassInfo(*scope.moduleScope, localInfo, variable.typeInfo.typeRef)) + scope.raiseError(errUnknownVariableType, terminal); - ustr_t referenceName = scope.moduleScope->module->resolveReference(outputRef); - if (isWeakReference(referenceName)) { - dummyWriter.appendNode(SyntaxKey::reference, referenceName); - } - else dummyWriter.appendNode(SyntaxKey::globalreference, referenceName); + if (variable.typeInfo.typeRef == V_BINARYARRAY) + // HOTFIX : recognize binary array actual size + localInfo.size *= _logic->defineStructSize(*scope.moduleScope, variable.typeInfo.elementRef).size; - dummyWriter.closeNode(); - dummyWriter.closeNode(); - } + if (_logic->isEmbeddableArray(localInfo) && size != 0) { + //binaryArray = true; + size = size * (-((int)localInfo.size)); - dummyWriter.closeNode(); + variable.reference = allocateLocalAddress(*codeScope, size, true); + } + else if (_logic->isEmbeddableStruct(localInfo) && size == 0) { + size = align(_logic->defineStructSize(localInfo).size, + scope.moduleScope->rawStackAlingment); - SyntaxNode current = dummyTree.readRoot().firstChild(); - while (current == SyntaxKey::TemplateArg) { - parameters.add(current); + variable.reference = allocateLocalAddress(*codeScope, size, false); + } + else if (size != 0) { + scope.raiseError(errInvalidOperation, terminal); + } + else if (methodScope && methodScope->isYieldable()) { + // NOTE : yieildable method is a special case when the referece variable is declared as a special class field + return declareYieldVariable(scope, *identifier, typeInfo); + } + else variable.reference = codeScope->newLocal(); - current = current.nextNode(); - } + if (exprScope) + exprScope->syncStack(); - closureName.append('#'); - closureName.appendInt(paramCount + 1); + if (!codeScope->locals.exist(*identifier)) { + codeScope->mapNewLocal(*identifier, variable.reference, variable.typeInfo, + size, true); + } + else scope.raiseError(errDuplicatedLocal, terminal); - ref_t templateReference = 0; - if (isWeakReference(*closureName)) { - templateReference = scope.module->mapReference(*closureName, true); + if (_trackingUnassigned) { + if (size > 0) { + codeScope->localNodes.add(-(int)variable.reference, terminal); } - else templateReference = scope.moduleScope->mapFullReference(*closureName, true); - - NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - - return _templateProcessor->generateClassTemplate(*scope.moduleScope, *nsScope->nsName, - templateReference, parameters, false, nullptr); + else codeScope->localNodes.add((int)variable.reference, terminal); } + + return true; } -ref_t Compiler :: resolveWrapperTemplate(ModuleScopeBase& moduleScope, ustr_t ns, ref_t elementRef, bool declarationMode) +inline ref_t mapClassConst(ModuleScopeBase* moduleScope, ref_t reference) { - if (!elementRef) - elementRef = moduleScope.buildins.superReference; + IdentifierString name(moduleScope->module->resolveReference(reference)); + name.append(STATICFIELD_POSTFIX); - return resolveTemplate(moduleScope, ns, moduleScope.buildins.wrapperTemplateReference, elementRef, declarationMode); + return moduleScope->mapAnonymous(*name + 1); } -ref_t Compiler :: resolveArrayTemplate(ModuleScopeBase& moduleScope, ustr_t ns, ref_t elementRef, bool declarationMode) +inline bool isInherited(ModuleBase* module, ref_t reference, ref_t staticRef) { - return resolveTemplate(moduleScope, ns, moduleScope.buildins.arrayTemplateReference, elementRef, declarationMode); -} + ustr_t name = module->resolveReference(reference); + ustr_t statName = module->resolveReference(staticRef); + size_t len = getlength(name); -ref_t Compiler :: resolveNullableTemplate(ModuleScopeBase& moduleScope, ustr_t ns, ref_t elementRef, bool declarationMode) -{ - return resolveTemplate(moduleScope, ns, moduleScope.buildins.nullableTemplateReference, elementRef, declarationMode); + if (statName[len] == '#' && statName.compare(name, len)) { + return true; + } + else return false; } -ref_t Compiler :: resolveArgArrayTemplate(ModuleScopeBase& moduleScope, ustr_t ns, ref_t elementRef, bool declarationMode) +bool Compiler :: evalAccumClassConstant(ustr_t constName, ClassScope& scope, SyntaxNode node, ObjectInfo& constInfo) { - return resolveTemplate(moduleScope, ns, moduleScope.buildins.argArrayTemplateReference, elementRef, declarationMode); -} + auto it = scope.info.statics.getIt(constName); + assert(!it.eof()); -TypeInfo Compiler :: resolveTypeScope(Scope& scope, SyntaxNode node, TypeAttributes& attributes, - bool declarationMode, bool allowRole) -{ - ref_t elementRef = 0; + ref_t collectionTypeRef = retrieveStrongType(scope, constInfo); + ClassInfo collectionInfo; + if (!_logic->defineClassInfo(*scope.moduleScope, collectionInfo, collectionTypeRef, false, true)) + return false; - SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { - switch (current.key) { - case SyntaxKey::Attribute: - if (!_logic->validateTypeScopeAttribute(current.arg.reference, attributes)) - scope.raiseWarning(WARNING_LEVEL_1, wrnInvalidHint, current); - break; - case SyntaxKey::Type: - elementRef = resolveStrongTypeAttribute(scope, current, declarationMode, false); - break; - case SyntaxKey::identifier: - case SyntaxKey::reference: - elementRef = resolveTypeIdentifier(scope, current.identifier(), node.key, declarationMode, allowRole); - break; - case SyntaxKey::ArrayType: - case SyntaxKey::NullableType: - elementRef = resolvePrimitiveType(scope, resolveTypeAttribute(scope, current, attributes, declarationMode, allowRole), declarationMode); - break; - default: - assert(false); - break; - } + if (!test(collectionInfo.header.flags, elDynamicRole)) + scope.raiseError(errInvalidOperation, node); - current = current.nextNode(); - } + bool byValue = _logic->isEmbeddableArray(*scope.moduleScope, collectionTypeRef); - if (node == SyntaxKey::ArrayType) { - if (attributes.variadicOne) { - return { V_ARGARRAY, elementRef }; + Interpreter interpreter(scope.moduleScope, _logic); + + bool newOne = true; + if (constInfo.reference != INVALID_REF) { + // HOTFIX : inherit accumulating attribute list + ClassInfo parentInfo; + scope.moduleScope->loadClassInfo(parentInfo, scope.info.header.parentRef); + ref_t targtListRef = (*it).valueRef & ~mskAnyRef; + ref_t parentListRef = parentInfo.statics.get(constName).valueRef & ~mskAnyRef; + + if (parentListRef != INVALID_REF && !isInherited(scope.module, scope.reference, targtListRef)) { + constInfo.reference = mapClassConst(scope.moduleScope, scope.reference); + + // inherit the parent list + interpreter.copyConstCollection(parentListRef, constInfo.reference, byValue); } - else return { defineArrayType(scope, elementRef, declarationMode), elementRef }; + else constInfo.reference = (*it).valueRef & ~mskAnyRef; + + newOne = false; } - else if (node == SyntaxKey::NullableType) { - return { resolvePrimitiveType(scope, { V_NULLABLE, elementRef }, declarationMode) }; + else constInfo.reference = mapClassConst(scope.moduleScope, scope.reference); + + auto fieldInfo = *(collectionInfo.fields.start()); + ref_t elementTypeRef = retrieveStrongType(scope, { ObjectKind::Object, { fieldInfo.typeInfo.elementRef }, 0 }); + + ObjectInfo value = evalExpression(interpreter, scope, node); + if (value.kind == ObjectKind::Symbol && value.reference == scope.reference) { + // HOTFIX : recognize the class + value = { ObjectKind::Class, { scope.info.header.classRef }, scope.reference }; } - else return {}; -} -TypeInfo Compiler :: resolveTypeAttribute(Scope& scope, SyntaxNode node, TypeAttributes& attributes, - bool declarationMode, bool allowRole) -{ - TypeInfo typeInfo = {}; - switch (node.key) { - case SyntaxKey::TemplateArg: - typeInfo = resolveTypeAttribute(scope, node.firstChild(), attributes, declarationMode, allowRole); - break; - case SyntaxKey::Type: - { - if (node.arg.reference) - return { node.arg.reference }; + ArgumentsInfo arguments; + arguments.add(value); - SyntaxNode current = node.firstChild(); - if (current == SyntaxKey::Type || current == SyntaxKey::ArrayType || current == SyntaxKey::NullableType) { - // !! should be refactored - typeInfo = resolveTypeAttribute(scope, current, attributes, declarationMode, allowRole); - } - else if (current == SyntaxKey::TemplateType) { - typeInfo.typeRef = resolveTypeTemplate(scope, current, attributes, declarationMode); - } - else if (SyntaxTree::test(current.key, SyntaxKey::TerminalMask)) { - if (current.nextNode() == SyntaxKey::TemplateArg) { - // !! should be refactored : TemplateType should be used instead - typeInfo.typeRef = resolveTypeTemplate(scope, current, attributes, declarationMode); - } - else typeInfo.typeRef = resolveTypeIdentifier(scope, current.identifier(), current.key, declarationMode, allowRole); - } - else assert(false); - break; - } - case SyntaxKey::TemplateType: - typeInfo.typeRef = resolveTypeTemplate(scope, node, attributes, declarationMode); - break; - case SyntaxKey::ArrayType: - { - typeInfo = resolveTypeScope(scope, node, attributes, declarationMode, allowRole); + interpreter.createConstCollection(constInfo.reference, newOne ? collectionTypeRef : 0, arguments, byValue); - if (attributes.variadicOne) - scope.raiseError(errInvalidOperation, node); - break; - } - case SyntaxKey::NullableType: - typeInfo = resolveTypeScope(scope, node, attributes, declarationMode, allowRole); - break; - default: - if (SyntaxTree::test(node.key, SyntaxKey::TerminalMask)) { - typeInfo.typeRef = resolveTypeIdentifier(scope, node.identifier(), node.key, declarationMode, allowRole); - } - else assert(false); - break; - } + (*it).valueRef = constInfo.reference | (byValue ? mskConstant : mskConstArray); + if (!(*it).offset) { + scope.info.header.staticSize++; - validateType(scope, typeInfo.typeRef, node, declarationMode, allowRole || attributes.mssgNameLiteral); + (*it).offset = -((int)scope.info.header.staticSize); + } - return typeInfo; + return true; } -ref_t Compiler :: resolveStrongTypeAttribute(Scope& scope, SyntaxNode node, bool declarationMode, bool allowRole) +bool Compiler :: evalClassConstant(ustr_t constName, ClassScope& scope, SyntaxNode node, ObjectInfo& constInfo) { - TypeAttributes typeAttributes = {}; - TypeInfo typeInfo = resolveTypeAttribute(scope, node, typeAttributes, declarationMode, allowRole); - if (typeAttributes.isNonempty()) - scope.raiseError(errInvalidOperation, node); + Interpreter interpreter(scope.moduleScope, _logic); + MetaScope metaScope(&scope, Scope::ScopeLevel::Class); - if (isPrimitiveRef(typeInfo.typeRef)) { - return resolvePrimitiveType(scope, typeInfo, declarationMode); + auto it = scope.info.statics.getIt(constName); + assert(!it.eof()); + + ObjectInfo retVal = evalExpression(interpreter, metaScope, node, false, false); + bool setIndex = false; + switch (retVal.kind) { + case ObjectKind::SelfName: + constInfo.typeInfo = { V_STRING }; + constInfo.reference = mskNameLiteralRef; + setIndex = true; + break; + case ObjectKind::SelfPackage: + constInfo.typeInfo = { }; + constInfo.reference = mskPackageRef; + setIndex = true; + break; + case ObjectKind::StringLiteral: + case ObjectKind::WideStringLiteral: + case ObjectKind::IntLiteral: + case ObjectKind::Float64Literal: + constInfo.typeInfo = retVal.typeInfo; + constInfo.reference = generateConstant(scope, retVal, 0); + break; + default: + return false; } - else return typeInfo.typeRef; + + (*it).valueRef = constInfo.reference; + if (setIndex && !(*it).offset) { + scope.info.header.staticSize++; + + (*it).offset = -((int)scope.info.header.staticSize); + } + + return true; } -int Compiler :: resolveSize(Scope& scope, SyntaxNode node) +void Compiler :: recreateFieldType(ClassScope& scope, SyntaxNode node, ustr_t fieldName) { - Interpreter interpreter(scope.moduleScope, _logic); + SyntaxNode current = node.firstChild(); + while (current != SyntaxKey::None) { + if (current.key == SyntaxKey::Field) { + ustr_t name = current.findChild(SyntaxKey::Name).firstChild(SyntaxKey::TerminalMask).identifier(); - ObjectInfo retVal = evalObject(interpreter, scope, node); + if (name.compare(fieldName)) { + FieldAttributes attrs = {}; + readFieldAttributes(scope, current, attrs, false); - if (retVal.kind == ObjectKind::IntLiteral) { - return retVal.extra; - } - else { - scope.raiseError(errInvalidSyntax, node); + break; + } + } - return 0; + current = current.nextNode(); } } -void Compiler :: readFieldAttributes(ClassScope& scope, SyntaxNode node, FieldAttributes& attrs, bool declarationMode) +bool Compiler :: evalInitializers(ClassScope& scope, SyntaxNode node) { + bool found = false; + bool evalulated = true; + SyntaxNode current = node.firstChild(); while (current != SyntaxKey::None) { - switch (current.key) { - case SyntaxKey::Autogenerated: - attrs.autogenerated = true; - break; - case SyntaxKey::Attribute: - if (!_logic->validateFieldAttribute(current.arg.reference, attrs)) - scope.raiseError(errInvalidHint, current); - break; - case SyntaxKey::Type: - case SyntaxKey::TemplateType: - if (!attrs.typeInfo.typeRef) { - TypeAttributes typeAttributes = {}; + if (current == SyntaxKey::AssignOperation) { + found = true; + SyntaxNode lnode = current.findChild(SyntaxKey::Object, SyntaxKey::YieldContext); + if (lnode == SyntaxKey::YieldContext) { + return false; + } + else { + ObjectInfo target = mapObject(scope, lnode, EAttr::None); + switch (target.kind) { + case ObjectKind::Field: + evalulated = false; + break; + case ObjectKind::ClassConstant: + if (target.reference == INVALID_REF) { + ustr_t fieldName = lnode.firstChild(SyntaxKey::TerminalMask).identifier(); - attrs.typeInfo = resolveTypeAttribute(scope, current, typeAttributes, declarationMode, false); - if (typeAttributes.isNonempty()) - scope.raiseError(errInvalidHint, current); + if (evalClassConstant(fieldName, + scope, current.firstChild(SyntaxKey::ScopeMask), target)) + { + current.setKey(SyntaxKey::Idle); + } + else scope.raiseError(errInvalidOperation, current); + } + break; + case ObjectKind::StaticField: + if (!current.arg.reference) { + current.setArgumentReference(compileStaticAssigning(scope, current)); + } + break; + default: + evalulated = false; + break; } - else scope.raiseError(errInvalidHint, current); - break; - case SyntaxKey::Dimension: - if (!attrs.size && attrs.typeInfo.typeRef && !attrs.inlineArray) { - if (current.arg.value) { - attrs.size = current.arg.value; + } + } + else if (current == SyntaxKey::AddAssignOperation) { + SyntaxNode lnode = current.findChild(SyntaxKey::Object); + ObjectInfo target = mapObject(scope, lnode, EAttr::None); + switch (target.kind) { + case ObjectKind::ClassConstant: + case ObjectKind::StaticConstField: + if (evalAccumClassConstant(lnode.firstChild(SyntaxKey::TerminalMask).identifier(), + scope, current.firstChild(SyntaxKey::ScopeMask), target)) + { + current.setKey(SyntaxKey::Idle); } - else attrs.size = resolveSize(scope, current.firstChild(SyntaxKey::TerminalMask)); - attrs.fieldArray = true; - } - else scope.raiseError(errInvalidHint, current); - break; - case SyntaxKey::ArrayType: - if (!attrs.size) { - attrs.size = -1; + else { + // HOTFIX : try to create the field property + recreateFieldType(scope, node, lnode.firstChild(SyntaxKey::TerminalMask).identifier()); + if (evalAccumClassConstant(lnode.firstChild(SyntaxKey::TerminalMask).identifier(), + scope, current.firstChild(SyntaxKey::ScopeMask), target)) + { + current.setKey(SyntaxKey::Idle); + } + else scope.raiseError(errInvalidOperation, current); + } + break; + default: + evalulated = false; + break; + } + } + current = current.nextNode(); + } - readFieldAttributes(scope, current, attrs, declarationMode); + return !found || evalulated; +} - if (attrs.typeInfo.isPrimitive()) - attrs.typeInfo = { resolvePrimitiveType(scope, attrs.typeInfo, declarationMode) }; +ObjectInfo Compiler :: mapClassSymbol(Scope& scope, ref_t classRef) +{ + if (classRef) { + ObjectInfo retVal = { ObjectKind::Class }; + retVal.reference = classRef; - if (!declarationMode) { - NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); + ref_t classClassRef = scope.moduleScope->cachedClassReferences.get(classRef); + if (!classClassRef) { + ClassInfo info; + scope.moduleScope->loadClassInfo(info, classRef, true); - resolveArrayTemplate(*scope.moduleScope, *nsScope->nsName, - attrs.typeInfo.typeRef, declarationMode); - } - } - else if (attrs.size == -1) { - // if it is a nested array - NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); + classClassRef = info.header.classRef; - readFieldAttributes(scope, current, attrs, declarationMode); - attrs.typeInfo = { resolveArrayTemplate(*scope.moduleScope, *nsScope->nsName, - attrs.typeInfo.typeRef, declarationMode) }; - } - else scope.raiseError(errInvalidHint, current); - break; - default: - break; + scope.moduleScope->cachedClassReferences.add(classRef, classClassRef); } - current = current.nextNode(); + retVal.typeInfo = { classClassRef }; + + ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); + if (classScope != nullptr && (classScope->reference == retVal.typeInfo.typeRef)) + { + retVal.kind = ObjectKind::ClassSelf; + } + + return retVal; } + else return {}; } -void Compiler :: declareFieldAttributes(ClassScope& scope, SyntaxNode node, FieldAttributes& attrs) +ExternalInfo Compiler :: mapExternal(Scope& scope, SyntaxNode node) { - readFieldAttributes(scope, node, attrs, true); + SyntaxNode objNode = node.parentNode(); - //HOTFIX : recognize raw data - if (attrs.typeInfo.isPrimitive()) { - bool valid = true; - switch (attrs.typeInfo.typeRef) { - case V_INTBINARY: - switch (attrs.size) { - case 1: - attrs.typeInfo.typeRef = V_INT8; - attrs.fieldArray = false; - break; - case 2: - attrs.typeInfo.typeRef = V_INT16; - attrs.fieldArray = false; - break; - case 4: - attrs.typeInfo.typeRef = V_INT32; - attrs.fieldArray = false; - break; - case 8: - attrs.typeInfo.typeRef = V_INT64; - attrs.fieldArray = false; - break; - default: - valid = false; - break; - } - break; - case V_UINTBINARY: - switch (attrs.size) { - case 1: - attrs.typeInfo.typeRef = V_UINT8; - attrs.fieldArray = false; - break; - case 2: - attrs.typeInfo.typeRef = V_UINT16; - attrs.fieldArray = false; - break; - case 4: - attrs.typeInfo.typeRef = V_UINT32; - attrs.fieldArray = false; - break; - default: - valid = false; - break; - } - break; - case V_WORDBINARY: - switch (attrs.size) { - case 4: - attrs.typeInfo.typeRef = V_WORD32; - attrs.fieldArray = false; - break; - case 8: - attrs.typeInfo.typeRef = V_WORD64; - attrs.fieldArray = false; - break; - default: - valid = false; - break; - } - break; - case V_EXTMESSAGE: - switch (scope.moduleScope->ptrSize) { - case 4: - attrs.typeInfo.typeRef = V_EXTMESSAGE64; - attrs.size = 8; - attrs.fieldArray = false; - break; - case 8: - attrs.typeInfo.typeRef = V_EXTMESSAGE128; - attrs.size = 16; - attrs.fieldArray = false; - break; - default: - valid = false; - break; - } - break; - case V_MSSGBINARY: - switch (attrs.size) { - case 4: - attrs.typeInfo.typeRef = V_MESSAGE; - attrs.fieldArray = false; - break; - default: - valid = false; - break; - } - break; - case V_SUBJBINARY: - switch (attrs.size) { - case 4: - attrs.typeInfo.typeRef = V_MESSAGENAME; - attrs.fieldArray = false; - break; - default: - valid = false; - break; - } - break; - case V_FLOATBINARY: - switch (attrs.size) { - case 8: - attrs.typeInfo.typeRef = V_FLOAT64; - attrs.fieldArray = false; - break; - default: - valid = false; - break; - } - break; - case V_POINTER: - switch (attrs.size) { - case 4: - attrs.typeInfo.typeRef = V_PTR32; - attrs.fieldArray = false; - break; - case 8: - attrs.typeInfo.typeRef = V_PTR64; - attrs.fieldArray = false; - break; - case 0: - attrs.fieldArray = false; - attrs.size = scope.moduleScope->ptrSize; - if (attrs.size == 4) { - attrs.typeInfo.typeRef = V_PTR32; - } - else if (attrs.size == 8) { - attrs.typeInfo.typeRef = V_PTR64; - } - else assert(false); - break; - default: - valid = false; - break; - } - break; - default: - valid = false; - break; - } + ustr_t dllAlias = node.identifier(); + ustr_t functionName = SyntaxTree::gotoNode(objNode, SyntaxKey::Message).firstChild(SyntaxKey::TerminalMask).identifier(); - if (!valid) - scope.raiseError(errInvalidHint, node.findChild(SyntaxKey::Name)); + if (functionName.empty()) { + functionName = dllAlias; + dllAlias = RT_FORWARD; } -} -inline int newLocalAddr(int disp, int allocated) -{ - return -disp - allocated; + return scope.moduleScope->mapExternal(dllAlias, functionName); } -int Compiler :: allocateLocalAddress(Scope& scope, int size, bool binaryArray) +ref_t Compiler :: compileStaticAssigning(ClassScope& scope, SyntaxNode node) { - int retVal = 0; - - CodeScope* codeScope = Scope::getScope(scope, Scope::ScopeLevel::Code); - if (codeScope != nullptr) { - if (binaryArray) - codeScope->allocLocalAddress(4); + ref_t actionRef = 0; - retVal = codeScope->allocLocalAddress(size); + SyntaxNode rootNode = node.parentNode(); + while (rootNode != SyntaxKey::Class) { + rootNode = rootNode.parentNode(); } - else { - SymbolScope* symbolScope = Scope::getScope(scope, Scope::ScopeLevel::Symbol); - assert(symbolScope != nullptr); - if (binaryArray) - symbolScope->allocLocalAddress(4); + SyntaxNode staticInitializer = rootNode.firstChild(SyntaxKey::StaticInitializerMethod); + if (staticInitializer == SyntaxKey::None) { + IdentifierString sectionName(scope.module->resolveReference(scope.reference)); + sectionName.append(INITIALIZER_SECTION); - retVal = symbolScope->allocLocalAddress(size); + actionRef = scope.moduleScope->mapAnonymous(*sectionName); + + staticInitializer = rootNode.appendChild(SyntaxKey::StaticInitializerMethod, actionRef); + + scope.addAttribute(ClassAttribute::Initializer, actionRef); } + else actionRef = staticInitializer.arg.reference; - return newLocalAddr(sizeof(intptr_t), retVal); + SyntaxTreeWriter writer(staticInitializer); + SyntaxTree::copyNode(writer, node, true); + + return actionRef; } -int Compiler :: resolveArraySize(Scope& scope, SyntaxNode node) +mssg_t Compiler :: resolveOperatorMessage(ModuleScopeBase* scope, int operatorId) { - Interpreter interpreter(scope.moduleScope, _logic); - ObjectInfo retVal = evalExpression(interpreter, scope, node); - switch (retVal.kind) { - case ObjectKind::IntLiteral: - return retVal.extra; - break; + switch (operatorId) { + case INDEX_OPERATOR_ID: + return scope->buildins.refer_message; + case ADD_OPERATOR_ID: + return scope->buildins.add_message; + case SUB_OPERATOR_ID: + return scope->buildins.sub_message; + case MUL_OPERATOR_ID: + return scope->buildins.mul_message; + case DIV_OPERATOR_ID: + return scope->buildins.div_message; + case BAND_OPERATOR_ID: + return scope->buildins.band_message; + case BOR_OPERATOR_ID: + return scope->buildins.bor_message; + case BXOR_OPERATOR_ID: + return scope->buildins.bxor_message; + case IF_OPERATOR_ID: + return scope->buildins.if_message; + case IF_ELSE_OPERATOR_ID: + return overwriteArgCount(scope->buildins.if_message, 3); + case EQUAL_OPERATOR_ID: + return scope->buildins.equal_message; + case NOTEQUAL_OPERATOR_ID: + return scope->buildins.notequal_message; + case LESS_OPERATOR_ID: + return scope->buildins.less_message; + case GREATER_OPERATOR_ID: + return scope->buildins.greater_message; + case NOT_OPERATOR_ID: + return scope->buildins.not_message; + case NOTLESS_OPERATOR_ID: + return scope->buildins.notless_message; + case NOTGREATER_OPERATOR_ID: + return scope->buildins.notgreater_message; + case NEGATE_OPERATOR_ID: + return scope->buildins.negate_message; + case VALUE_OPERATOR_ID: + return scope->buildins.value_message; + case SET_INDEXER_OPERATOR_ID: + return scope->buildins.set_refer_message; + case AND_OPERATOR_ID: + return scope->buildins.and_message; + case OR_OPERATOR_ID: + return scope->buildins.or_message; + case XOR_OPERATOR_ID: + return scope->buildins.xor_message; + case SHL_OPERATOR_ID: + return scope->buildins.shl_message; + case SHR_OPERATOR_ID: + return scope->buildins.shr_message; + case BNOT_OPERATOR_ID: + return scope->buildins.bnot_message; default: - scope.raiseError(errInvalidOperation, node); - return 0; + throw InternalError(errFatalError); } } -bool Compiler :: declareYieldVariable(Scope& scope, ustr_t name, TypeInfo typeInfo) +inline bool isPrimitiveArray(ref_t typeRef) { - ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); - - FieldAttributes attrs = { typeInfo }; - - // NOTE : should return false to indicate that it is not a variable - return !generateClassField(*classScope, attrs, name, 0, typeInfo, false); + switch (typeRef) { + case V_BINARYARRAY: + case V_OBJARRAY: + case V_INT32ARRAY: + return true; + default: + return false; + } } -bool Compiler :: declareVariable(Scope& scope, SyntaxNode terminal, TypeInfo typeInfo, bool ignoreDuplicate) +inline bool DoesOperationSupportConvertableIntLiteral(int operatorId) { - int size = 0; - if (terminal == SyntaxKey::IndexerOperation) { - // COMPILER MAGIC : if it is a fixed-sized array - size = resolveArraySize(scope, terminal.firstChild(SyntaxKey::ScopeMask)); - - terminal = terminal.findChild(SyntaxKey::Object).findChild(SyntaxKey::identifier); + switch (operatorId) { + case ADD_OPERATOR_ID: + case SUB_OPERATOR_ID: + case LESS_OPERATOR_ID: + case EQUAL_OPERATOR_ID: + case NOTEQUAL_OPERATOR_ID: + case ELSE_OPERATOR_ID: + case MUL_OPERATOR_ID: + case DIV_OPERATOR_ID: + case NOTLESS_OPERATOR_ID: + case GREATER_OPERATOR_ID: + case NOTGREATER_OPERATOR_ID: + case BAND_OPERATOR_ID: + case BOR_OPERATOR_ID: + case BXOR_OPERATOR_ID: + case BNOT_OPERATOR_ID: + case AND_OPERATOR_ID: + case OR_OPERATOR_ID: + case XOR_OPERATOR_ID: + case ADD_ASSIGN_OPERATOR_ID: + case SUB_ASSIGN_OPERATOR_ID: + case MUL_ASSIGN_OPERATOR_ID: + case DIV_ASSIGN_OPERATOR_ID: + case SET_INDEXER_OPERATOR_ID: + return true; + default: + return false; } +} - ExprScope* exprScope = Scope::getScope(scope, Scope::ScopeLevel::Expr); - CodeScope* codeScope = Scope::getScope(scope, Scope::ScopeLevel::Code); - MethodScope* methodScope = Scope::getScope(scope, Scope::ScopeLevel::Method); - if (codeScope == nullptr) { - scope.raiseError(errInvalidOperation, terminal); - return false; // the code will never be reached - } - - IdentifierString identifier(terminal.identifier()); - if (ignoreDuplicate) { - auto var = codeScope->mapIdentifier(*identifier, false, EAttr::None); - switch (var.kind) { - case ObjectKind::Local: - case ObjectKind::LocalAddress: - // exit if the variable with this names does exist - return false; - default: - break; - } - } +mssg_t Compiler :: mapMessage(Scope& scope, SyntaxNode current, bool propertyMode, + bool extensionMode, bool probeMode) +{ + ref_t flags = propertyMode ? PROPERTY_MESSAGE : 0; + if (extensionMode) + flags |= FUNCTION_MESSAGE; - ObjectInfo variable; - variable.typeInfo = typeInfo; - variable.kind = ObjectKind::Local; + IdentifierString messageStr; - if (size != 0 && variable.typeInfo.typeRef != 0) { - if (!variable.typeInfo.isPrimitive()) { - // if it is a primitive array - variable.typeInfo.elementRef = variable.typeInfo.typeRef; - variable.typeInfo.typeRef = _logic->definePrimitiveArray(*scope.moduleScope, variable.typeInfo.elementRef, true); - } - else scope.raiseError(errInvalidHint, terminal); - } - else if (_logic->isPrimitiveArrRef(variable.typeInfo.typeRef)) { - // if it is an array reference - variable.typeInfo.typeRef = resolvePrimitiveType(scope, variable.typeInfo, false); - variable.typeInfo.elementRef = 0; - } + if (current == SyntaxKey::Message) { + SyntaxNode terminal = current.firstChild(SyntaxKey::TerminalMask); - ClassInfo localInfo; - //bool binaryArray = false; - if (!_logic->defineClassInfo(*scope.moduleScope, localInfo, variable.typeInfo.typeRef)) - scope.raiseError(errUnknownVariableType, terminal); + messageStr.copy(terminal.identifier()); - if (variable.typeInfo.typeRef == V_BINARYARRAY) - // HOTFIX : recognize binary array actual size - localInfo.size *= _logic->defineStructSize(*scope.moduleScope, variable.typeInfo.elementRef).size; + current = current.nextNode(); + } - if (_logic->isEmbeddableArray(localInfo) && size != 0) { - //binaryArray = true; - size = size * (-((int)localInfo.size)); + pos_t argCount = 1; + while (current != SyntaxKey::None) { + argCount++; - variable.reference = allocateLocalAddress(*codeScope, size, true); + current = current.nextNode(SyntaxKey::ScopeMask); } - else if (_logic->isEmbeddableStruct(localInfo) && size == 0) { - size = align(_logic->defineStructSize(localInfo).size, - scope.moduleScope->rawStackAlingment); - variable.reference = allocateLocalAddress(*codeScope, size, false); - } - else if (size != 0) { - scope.raiseError(errInvalidOperation, terminal); - } - else if (methodScope && methodScope->isYieldable()) { - // NOTE : yieildable method is a special case when the referece variable is declared as a special class field - return declareYieldVariable(scope, *identifier, typeInfo); + if (argCount >= ARG_COUNT) { + flags |= VARIADIC_MESSAGE; + argCount = 2; } - else variable.reference = codeScope->newLocal(); - - if (exprScope) - exprScope->syncStack(); - if (!codeScope->locals.exist(*identifier)) { - codeScope->mapNewLocal(*identifier, variable.reference, variable.typeInfo, - size, true); - } - else scope.raiseError(errDuplicatedLocal, terminal); + if (messageStr.empty()) { + flags |= FUNCTION_MESSAGE; - if (_trackingUnassigned) { - if (size > 0) { - codeScope->localNodes.add(-(int)variable.reference, terminal); - } - else codeScope->localNodes.add((int)variable.reference, terminal); + // if it is an implicit message + messageStr.copy(probeMode ? TRY_INVOKE_MESSAGE : INVOKE_MESSAGE); } - return true; -} + if (test(flags, FUNCTION_MESSAGE)) + // exclude the target from the arg counter for the function + argCount--; -inline ref_t mapClassConst(ModuleScopeBase* moduleScope, ref_t reference) -{ - IdentifierString name(moduleScope->module->resolveReference(reference)); - name.append(STATICFIELD_POSTFIX); + ref_t actionRef = scope.module->mapAction(*messageStr, 0, false); - return moduleScope->mapAnonymous(*name + 1); + return encodeMessage(actionRef, argCount, flags); } -inline bool isInherited(ModuleBase* module, ref_t reference, ref_t staticRef) +ref_t targetResolver(void* param, mssg_t mssg) { - ustr_t name = module->resolveReference(reference); - ustr_t statName = module->resolveReference(staticRef); - size_t len = getlength(name); - - if (statName[len] == '#' && statName.compare(name, len)) { - return true; - } - else return false; + return ((ResolvedMap*)param)->get(mssg); } -bool Compiler :: evalAccumClassConstant(ustr_t constName, ClassScope& scope, SyntaxNode node, ObjectInfo& constInfo) +ref_t Compiler :: compileExtensionDispatcher(BuildTreeWriter& writer, NamespaceScope& scope, mssg_t genericMessage, + ref_t outputRef) { - auto it = scope.info.statics.getIt(constName); - assert(!it.eof()); - - ref_t collectionTypeRef = retrieveStrongType(scope, constInfo); - ClassInfo collectionInfo; - if (!_logic->defineClassInfo(*scope.moduleScope, collectionInfo, collectionTypeRef, false, true)) - return false; - - if (!test(collectionInfo.header.flags, elDynamicRole)) - scope.raiseError(errInvalidOperation, node); - - bool byValue = _logic->isEmbeddableArray(*scope.moduleScope, collectionTypeRef); - - Interpreter interpreter(scope.moduleScope, _logic); + ref_t extRef = scope.moduleScope->mapAnonymous(); + ClassScope classScope(&scope, extRef, Visibility::Private); + declareClassParent(classScope.info.header.parentRef, classScope, {}); + classScope.extensionDispatcher = true; + classScope.info.header.classRef = classScope.reference; + classScope.extensionClassRef = scope.moduleScope->buildins.superReference; + generateClassFlags(classScope, elExtension | elSealed); - bool newOne = true; - if (constInfo.reference != INVALID_REF) { - // HOTFIX : inherit accumulating attribute list - ClassInfo parentInfo; - scope.moduleScope->loadClassInfo(parentInfo, scope.info.header.parentRef); - ref_t targtListRef = (*it).valueRef & ~mskAnyRef; - ref_t parentListRef = parentInfo.statics.get(constName).valueRef & ~mskAnyRef; + // create a new overload list + ClassInfo::MethodMap methods({}); + ResolvedMap targets(0); + for(auto it = scope.extensions.getIt(genericMessage); !it.eof(); it = scope.extensions.nextIt(genericMessage, it)) { + auto extInfo = *it; - if (parentListRef != INVALID_REF && !isInherited(scope.module, scope.reference, targtListRef)) { - constInfo.reference = mapClassConst(scope.moduleScope, scope.reference); + methods.add(extInfo.value2, { false, 0, 0, genericMessage | FUNCTION_MESSAGE, 0 }); + targets.add(extInfo.value2, extInfo.value1); + } - // inherit the parent list - interpreter.copyConstCollection(parentListRef, constInfo.reference, byValue); - } - else constInfo.reference = (*it).valueRef & ~mskAnyRef; + _logic->injectMethodOverloadList(this, *scope.moduleScope, + classScope.info.header.flags, genericMessage | FUNCTION_MESSAGE, methods, + classScope.info.attributes, &targets, targetResolver, ClassAttribute::OverloadList); - newOne = false; - } - else constInfo.reference = mapClassConst(scope.moduleScope, scope.reference); + SyntaxTree classTree; + SyntaxTreeWriter classWriter(classTree); - auto fieldInfo = *(collectionInfo.fields.start()); - ref_t elementTypeRef = retrieveStrongType(scope, { ObjectKind::Object, { fieldInfo.typeInfo.elementRef }, 0 }); + // build the class tree + classWriter.newNode(SyntaxKey::Root); + classWriter.newNode(SyntaxKey::Class, extRef); - ObjectInfo value = evalExpression(interpreter, scope, node); - if (value.kind == ObjectKind::Symbol && value.reference == scope.reference) { - // HOTFIX : recognize the class - value = { ObjectKind::Class, { scope.info.header.classRef }, scope.reference }; - } + SyntaxNode classNode = classWriter.CurrentNode(); + injectVirtualMultimethod(classNode, SyntaxKey::Method, genericMessage | FUNCTION_MESSAGE, genericMessage, + 0, outputRef, Visibility::Public, true); - ArgumentsInfo arguments; - arguments.add(value); + classWriter.closeNode(); + classWriter.closeNode(); - interpreter.createConstCollection(constInfo.reference, newOne ? collectionTypeRef : 0, arguments, byValue); + generateMethodDeclaration(classScope, classNode.findChild(SyntaxKey::Method), false, false); + classScope.save(); - (*it).valueRef = constInfo.reference | (byValue ? mskConstant : mskConstArray); - if (!(*it).offset) { - scope.info.header.staticSize++; + BuildNode node = writer.CurrentNode(); + while (node != BuildKey::Root) + node = node.parentNode(); - (*it).offset = -((int)scope.info.header.staticSize); - } + BuildTreeWriter nestedWriter(node); + nestedWriter.newNode(BuildKey::Class, extRef); + compileVMT(nestedWriter, classScope, classNode); + nestedWriter.closeNode(); - return true; + return extRef; } -bool Compiler :: evalClassConstant(ustr_t constName, ClassScope& scope, SyntaxNode node, ObjectInfo& constInfo) +ref_t Compiler :: mapExtension(BuildTreeWriter& writer, Scope& scope, mssg_t& message, ref_t& implicitSignatureRef, + ObjectInfo object, int& stackSafeAttr) { - Interpreter interpreter(scope.moduleScope, _logic); - MetaScope metaScope(&scope, Scope::ScopeLevel::Class); - - auto it = scope.info.statics.getIt(constName); - assert(!it.eof()); + NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - ObjectInfo retVal = evalExpression(interpreter, metaScope, node, false, false); - bool setIndex = false; - switch (retVal.kind) { - case ObjectKind::SelfName: - constInfo.typeInfo = { V_STRING }; - constInfo.reference = mskNameLiteralRef; - setIndex = true; - break; - case ObjectKind::SelfPackage: - constInfo.typeInfo = { }; - constInfo.reference = mskPackageRef; - setIndex = true; - break; - case ObjectKind::StringLiteral: - case ObjectKind::WideStringLiteral: - case ObjectKind::IntLiteral: - case ObjectKind::Float64Literal: - constInfo.typeInfo = retVal.typeInfo; - constInfo.reference = generateConstant(scope, retVal, 0); - break; - default: - return false; + ref_t objectRef = retrieveStrongType(scope, object); + if (objectRef == 0) { + objectRef = scope.moduleScope->buildins.superReference; } - (*it).valueRef = constInfo.reference; - if (setIndex && !(*it).offset) { - scope.info.header.staticSize++; - - (*it).offset = -((int)scope.info.header.staticSize); + if (implicitSignatureRef) { + // auto generate extension template for strong-typed signature + for (auto it = nsScope->extensionTemplates.getIt(message); !it.eof(); it = nsScope->extensionTemplates.nextIt(message, it)) { + _logic->resolveExtensionTemplate(*scope.moduleScope, this, *it, + implicitSignatureRef, *nsScope->nsName, nsScope->outerExtensionList ? nsScope->outerExtensionList : &nsScope->extensions); + } } - return true; -} - -void Compiler :: recreateFieldType(ClassScope& scope, SyntaxNode node, ustr_t fieldName) -{ - SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { - if (current.key == SyntaxKey::Field) { - ustr_t name = current.findChild(SyntaxKey::Name).firstChild(SyntaxKey::TerminalMask).identifier(); + // check extensions + auto it = nsScope->extensions.getIt(message); + if (!it.eof()) { + // generate an extension signature + ref_t signatures[ARG_COUNT] = {}; + size_t signatureLen = scope.module->resolveSignature(implicitSignatureRef, signatures); + for (size_t i = signatureLen; i > 0; i--) + signatures[i] = signatures[i - 1]; - if (name.compare(fieldName)) { - FieldAttributes attrs = {}; - readFieldAttributes(scope, current, attrs, false); + signatures[0] = objectRef; + signatureLen++; - break; - } + size_t argCount = getArgCount(message); + while (signatureLen < argCount) { + signatures[signatureLen] = scope.moduleScope->buildins.superReference; + signatureLen++; } - current = current.nextNode(); - } -} + scope.module->mapSignature(signatures, signatureLen, false); + mssg_t resolvedMessage = 0; + ref_t resolvedExtRef = 0; + int resolvedStackSafeAttr = 0; + int counter = 0; + while (!it.eof()) { + auto extInfo = *it; + ref_t targetRef = nsScope->resolveExtensionTarget(extInfo.value1); + int extStackAttr = 0; + if (_logic->isMessageCompatibleWithSignature(*scope.moduleScope, targetRef, extInfo.value2, + signatures, signatureLen, extStackAttr)) + { + if (!resolvedMessage) { + resolvedMessage = extInfo.value2; + resolvedExtRef = extInfo.value1; + resolvedStackSafeAttr = extStackAttr; + } + else if (_logic->isSignatureCompatible(*scope.moduleScope, resolvedMessage, extInfo.value2)) { + //NOTE : if the extension is more precise than the previous resolved one - use the new one + resolvedMessage = extInfo.value2; + resolvedExtRef = extInfo.value1; + } + else if (!_logic->isSignatureCompatible(*scope.moduleScope, extInfo.value2, resolvedMessage)) { + // if they are incompatible - use dynamic resolving + resolvedMessage = 0; + break; + } + } + counter++; -bool Compiler :: evalInitializers(ClassScope& scope, SyntaxNode node) -{ - bool found = false; - bool evalulated = true; + it = nsScope->extensions.nextIt(message, it); + } - SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { - if (current == SyntaxKey::AssignOperation) { - found = true; - SyntaxNode lnode = current.findChild(SyntaxKey::Object, SyntaxKey::YieldContext); - if (lnode == SyntaxKey::YieldContext) { - return false; + if (resolvedMessage) { + if (counter > 1 && (implicitSignatureRef == 0 && getArgCount(message) > 1)) { + // HOTFIX : does not resolve an ambigous extension for a weak message + // excluding messages without arguments } else { - ObjectInfo target = mapObject(scope, lnode, EAttr::None); - switch (target.kind) { - case ObjectKind::Field: - evalulated = false; - break; - case ObjectKind::ClassConstant: - if (target.reference == INVALID_REF) { - ustr_t fieldName = lnode.firstChild(SyntaxKey::TerminalMask).identifier(); + // if we are lucky - use the resolved one + message = resolvedMessage; + stackSafeAttr = resolvedStackSafeAttr; - if (evalClassConstant(fieldName, - scope, current.firstChild(SyntaxKey::ScopeMask), target)) - { - current.setKey(SyntaxKey::Idle); - } - else scope.raiseError(errInvalidOperation, current); - } - break; - case ObjectKind::StaticField: - if (!current.arg.reference) { - current.setArgumentReference(compileStaticAssigning(scope, current)); - } - break; - default: - evalulated = false; - break; - } + return resolvedExtRef; } } - else if (current == SyntaxKey::AddAssignOperation) { - SyntaxNode lnode = current.findChild(SyntaxKey::Object); - ObjectInfo target = mapObject(scope, lnode, EAttr::None); - switch (target.kind) { - case ObjectKind::ClassConstant: - case ObjectKind::StaticConstField: - if (evalAccumClassConstant(lnode.firstChild(SyntaxKey::TerminalMask).identifier(), - scope, current.firstChild(SyntaxKey::ScopeMask), target)) - { - current.setKey(SyntaxKey::Idle); - } - else { - // HOTFIX : try to create the field property - recreateFieldType(scope, node, lnode.firstChild(SyntaxKey::TerminalMask).identifier()); - if (evalAccumClassConstant(lnode.firstChild(SyntaxKey::TerminalMask).identifier(), - scope, current.firstChild(SyntaxKey::ScopeMask), target)) - { - current.setKey(SyntaxKey::Idle); - } - else scope.raiseError(errInvalidOperation, current); - } - break; - default: - evalulated = false; - break; - } + + // bad luck - we have to generate run-time extension dispatcher + implicitSignatureRef = 0; + ref_t extRef = nsScope->extensionDispatchers.get(message); + if (extRef == INVALID_REF) { + extRef = compileExtensionDispatcher(writer, *nsScope, message, 0); + + nsScope->extensionDispatchers.add(message, extRef); } - current = current.nextNode(); + + message |= FUNCTION_MESSAGE; + + return extRef; } - return !found || evalulated; + return 0; } -ObjectInfo Compiler :: mapClassSymbol(Scope& scope, ref_t classRef) +mssg_t Compiler :: resolveVariadicMessage(Scope& scope, mssg_t message) { - if (classRef) { - ObjectInfo retVal = { ObjectKind::Class }; - retVal.reference = classRef; - - ref_t classClassRef = scope.moduleScope->cachedClassReferences.get(classRef); - if (!classClassRef) { - ClassInfo info; - scope.moduleScope->loadClassInfo(info, classRef, true); - - classClassRef = info.header.classRef; + pos_t argCount = 0; + ref_t actionRef = 0, flags = 0, dummy = 0; + decodeMessage(message, actionRef, argCount, flags); - scope.moduleScope->cachedClassReferences.add(classRef, classClassRef); - } + ustr_t actionName = scope.module->resolveAction(actionRef, dummy); - retVal.typeInfo = { classClassRef }; + int argMultuCount = test(message, FUNCTION_MESSAGE) ? 1 : 2; - ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); - if (classScope != nullptr && (classScope->reference == retVal.typeInfo.typeRef)) - { - retVal.kind = ObjectKind::ClassSelf; - } + return encodeMessage(scope.module->mapAction(actionName, 0, false), argMultuCount, flags | VARIADIC_MESSAGE); +} - return retVal; +inline SyntaxNode findMessageNode(SyntaxNode node) +{ + if (node == SyntaxKey::ResendDispatch) { + node = node.findChild(SyntaxKey::MessageOperation); } - else return {}; + return node.findChild(SyntaxKey::Message); } -ExternalInfo Compiler :: mapExternal(Scope& scope, SyntaxNode node) +void Compiler :: addBreakpoint(BuildTreeWriter& writer, SyntaxNode node, BuildKey bpKey) { - SyntaxNode objNode = node.parentNode(); - - ustr_t dllAlias = node.identifier(); - ustr_t functionName = SyntaxTree::gotoNode(objNode, SyntaxKey::Message).firstChild(SyntaxKey::TerminalMask).identifier(); + SyntaxNode terminal = node.firstChild(SyntaxKey::TerminalMask); - if (functionName.empty()) { - functionName = dllAlias; - dllAlias = RT_FORWARD; + SyntaxNode row = terminal.findChild(SyntaxKey::Row); + SyntaxNode col = terminal.findChild(SyntaxKey::Column); + if (row != SyntaxKey::None) { + writer.newNode(bpKey); + writer.appendNode(BuildKey::Row, row.arg.value); + writer.appendNode(BuildKey::Column, col.arg.value); + writer.closeNode(); } - - return scope.moduleScope->mapExternal(dllAlias, functionName); } -ref_t Compiler :: compileStaticAssigning(ClassScope& scope, SyntaxNode node) +bool invalidObjectMode(ObjectInfo info) { - ref_t actionRef = 0; - - SyntaxNode rootNode = node.parentNode(); - while (rootNode != SyntaxKey::Class) { - rootNode = rootNode.parentNode(); + switch (info.mode) { + case TargetMode::None: + case TargetMode::Conditional: + case TargetMode::Weak: + return false; + default: + return true; } +} - SyntaxNode staticInitializer = rootNode.firstChild(SyntaxKey::StaticInitializerMethod); - if (staticInitializer == SyntaxKey::None) { - IdentifierString sectionName(scope.module->resolveReference(scope.reference)); - sectionName.append(INITIALIZER_SECTION); - - actionRef = scope.moduleScope->mapAnonymous(*sectionName); - - staticInitializer = rootNode.appendChild(SyntaxKey::StaticInitializerMethod, actionRef); - - scope.addAttribute(ClassAttribute::Initializer, actionRef); +inline bool isConditionalOp(SyntaxKey key) +{ + switch (key) { + case SyntaxKey::EqualOperation: + case SyntaxKey::NotEqualOperation: + case SyntaxKey::LessOperation: + case SyntaxKey::NotLessOperation: + case SyntaxKey::GreaterOperation: + case SyntaxKey::NotGreaterOperation: + return true; + default: + return false; } - else actionRef = staticInitializer.arg.reference; +} - SyntaxTreeWriter writer(staticInitializer); - SyntaxTree::copyNode(writer, node, true); +inline bool isSimpleNode(SyntaxNode node) +{ + SyntaxNode current = node.firstChild(); - return actionRef; + if (current == SyntaxKey::Expression && current.nextNode() == SyntaxKey::None) { + return isSimpleNode(current); + } + else if (current == SyntaxKey::Object && current.nextNode() == SyntaxKey::None) { + return true; + } + return false; } -ObjectInfo Compiler :: compileExternalOp(WriterContext& context, ref_t externalRef, - bool stdCall, ArgumentsInfo& arguments, ref_t expectedRef) +inline SyntaxNode skipNestedExpression(SyntaxNode node) { - pos_t count = arguments.count_pos(); - - context.writer->appendNode(BuildKey::Allocating, - align(count, context.scope->moduleScope->stackAlingment)); + if (node == SyntaxKey::Expression) { + SyntaxNode current = node.firstChild(); + while (current == SyntaxKey::Expression) { + node = current; + current = current.firstChild(); + } - TypeInfo retType = { V_INT32 }; - ref_t intArgType = 0; - BuildKey intArgOp = BuildKey::None; - switch (context.scope->moduleScope->ptrSize) { - case 4: - intArgType = V_INT32; - intArgOp = BuildKey::SavingNInStack; - break; - case 8: - retType = { V_INT64 }; - intArgType = V_INT64; - intArgOp = BuildKey::SavingLInStack; - break; - default: - assert(false); - break; + return node; } + return node; +} - for (pos_t i = count; i > 0; i--) { - ObjectInfo arg = boxArgumentLocally(context, arguments[i - 1], true, false); +ObjectInfo Compiler :: mapStringConstant(Scope& scope, SyntaxNode node) +{ + return { ObjectKind::StringLiteral, { V_STRING }, scope.module->mapConstant(node.identifier()) }; +} - writeObjectInfo(context, arg); - switch (arg.kind) { - case ObjectKind::IntLiteral: - context.writer->appendNode(BuildKey::SavingNInStack, i - 1); - break; - default: - if (_logic->isCompatible(*context.scope->moduleScope, { intArgType }, - arg.typeInfo, true)) - { - context.writer->appendNode(intArgOp, i - 1); - } - // NOTE : it is a duplicate for 32 bit target, but is required for 64 bit one - else if (_logic->isCompatible(*context.scope->moduleScope, { V_INT32 }, - arg.typeInfo, true)) - { - context.writer->appendNode(BuildKey::SavingNInStack, i - 1); - } - else context.writer->appendNode(BuildKey::SavingInStack, i - 1); // !! temporally - passing dynamic references to the exteranl routines should not be allowed - break; - } - } +ObjectInfo Compiler :: mapWideStringConstant(Scope& scope, SyntaxNode node) +{ + return { ObjectKind::WideStringLiteral, { V_WIDESTRING }, scope.module->mapConstant(node.identifier()) }; +} - context.writer->newNode(BuildKey::ExtCallOp, externalRef); +ObjectInfo Compiler :: mapCharacterConstant(Scope& scope, SyntaxNode node) +{ + return { ObjectKind::CharacterLiteral, { V_WORD32 }, scope.module->mapConstant(node.identifier()) }; +} - BuildNode opNode = context.writer->CurrentNode(); +ObjectInfo Compiler :: mapConstant(Scope& scope, SyntaxNode node) +{ + return { ObjectKind::ConstantLiteral, { V_WORD32 }, scope.module->mapConstant(node.identifier()) }; +} - context.writer->appendNode(BuildKey::Count, count); +ObjectInfo Compiler :: mapIntConstant(Scope& scope, SyntaxNode node, int radix) +{ + int integer = StrConvertor::toInt(node.identifier(), radix); + if (errno == ERANGE) + scope.raiseError(errInvalidIntNumber, node); - context.writer->closeNode(); + return { ObjectKind::IntLiteral, { V_INT32 }, ::mapIntConstant(scope.moduleScope, integer), integer }; +} - if (!stdCall) - context.writer->appendNode(BuildKey::Freeing, align(count, - context.scope->moduleScope->stackAlingment)); +ObjectInfo Compiler :: mapUIntConstant(Scope& scope, SyntaxNode node, int radix) +{ + int integer = StrConvertor::toUInt(node.identifier(), radix); + if (errno == ERANGE) + scope.raiseError(errInvalidIntNumber, node); - if (_logic->isCompatible(*context.scope->moduleScope, retType, { expectedRef }, true)) { - retType = { expectedRef }; - } - else if (retType.typeRef == V_INT64 && - _logic->isCompatible(*context.scope->moduleScope, { V_INT32 }, { expectedRef }, true)) - { - // HOTFIX 64bit : allow to convert the external operation to int32 - retType = { expectedRef }; - } - else if (retType.typeRef == V_INT32 && - _logic->isCompatible(*context.scope->moduleScope, { V_INT64 }, { expectedRef }, true)) - { - retType = { expectedRef }; + return { ObjectKind::IntLiteral, { V_INT32 }, ::mapUIntConstant(scope, integer), integer }; +} - // HOTFIX : special case - returning long in 32 bit mode - opNode.appendChild(BuildKey::LongMode); - } - else if (_logic->isCompatible(*context.scope->moduleScope, { V_FLOAT64 }, { expectedRef }, true)) { - retType = { expectedRef }; +ObjectInfo Compiler :: mapLongConstant(Scope& scope, SyntaxNode node, int radix) +{ + long long integer = 0; - return { ObjectKind::FloatExtern, retType, 0 }; + ustr_t val = node.identifier(); + if (val.endsWith("l")) { + String tmp(val); + tmp.truncate(tmp.length() - 1); + + integer = StrConvertor::toLong(tmp.str(), radix); } + else integer = StrConvertor::toLong(node.identifier(), radix); - return { ObjectKind::Extern, retType, 0 }; + if (errno == ERANGE) + scope.raiseError(errInvalidIntNumber, node); + + return { ObjectKind::LongLiteral, { V_INT64 }, ::mapLongConstant(scope, integer)}; } -mssg_t Compiler :: resolveOperatorMessage(ModuleScopeBase* scope, int operatorId) +inline bool defineFloat64Constant(ustr_t val, ModuleBase* module, ObjectInfo& retVal) { - switch (operatorId) { - case INDEX_OPERATOR_ID: - return scope->buildins.refer_message; - case ADD_OPERATOR_ID: - return scope->buildins.add_message; - case SUB_OPERATOR_ID: - return scope->buildins.sub_message; - case MUL_OPERATOR_ID: - return scope->buildins.mul_message; - case DIV_OPERATOR_ID: - return scope->buildins.div_message; - case BAND_OPERATOR_ID: - return scope->buildins.band_message; - case BOR_OPERATOR_ID: - return scope->buildins.bor_message; - case BXOR_OPERATOR_ID: - return scope->buildins.bxor_message; - case IF_OPERATOR_ID: - return scope->buildins.if_message; - case IF_ELSE_OPERATOR_ID: - return overwriteArgCount(scope->buildins.if_message, 3); - case EQUAL_OPERATOR_ID: - return scope->buildins.equal_message; - case NOTEQUAL_OPERATOR_ID: - return scope->buildins.notequal_message; - case LESS_OPERATOR_ID: - return scope->buildins.less_message; - case GREATER_OPERATOR_ID: - return scope->buildins.greater_message; - case NOT_OPERATOR_ID: - return scope->buildins.not_message; - case NOTLESS_OPERATOR_ID: - return scope->buildins.notless_message; - case NOTGREATER_OPERATOR_ID: - return scope->buildins.notgreater_message; - case NEGATE_OPERATOR_ID: - return scope->buildins.negate_message; - case VALUE_OPERATOR_ID: - return scope->buildins.value_message; - case SET_INDEXER_OPERATOR_ID: - return scope->buildins.set_refer_message; - case AND_OPERATOR_ID: - return scope->buildins.and_message; - case OR_OPERATOR_ID: - return scope->buildins.or_message; - case XOR_OPERATOR_ID: - return scope->buildins.xor_message; - case SHL_OPERATOR_ID: - return scope->buildins.shl_message; - case SHR_OPERATOR_ID: - return scope->buildins.shr_message; - case BNOT_OPERATOR_ID: - return scope->buildins.bnot_message; - default: - throw InternalError(errFatalError); + double real = 0; + + if (val.endsWith("r")) { + String tmp(val); + tmp.truncate(tmp.length() - 1); + + real = StrConvertor::toDouble(tmp.str()); } + else real = StrConvertor::toDouble(val); + if (errno == ERANGE) + return false; + + retVal = { ObjectKind::Float64Literal, { V_FLOAT64 }, ::mapFloat64Const(module, real) }; + + return true; } -ObjectInfo Compiler :: declareTempStructure(ExprScope& scope, SizeInfo sizeInfo) +ObjectInfo Compiler :: mapFloat64Constant(Scope& scope, SyntaxNode node) { - if (sizeInfo.size <= 0) - return {}; - - ObjectInfo retVal = { ObjectKind::TempLocalAddress }; - retVal.reference = allocateLocalAddress(scope, sizeInfo.size, false); - retVal.extra = sizeInfo.size; + ObjectInfo retVal = {}; - scope.syncStack(); + if (!defineFloat64Constant(node.identifier(), scope.module, retVal)) { + scope.raiseError(errInvalidIntNumber, node); + } return retVal; } -ObjectInfo Compiler :: allocateResult(ExprScope& scope, ref_t resultRef) +ObjectInfo Compiler :: mapMessageConstant(Scope& scope, SyntaxNode node, ref_t actionRef) { - SizeInfo info = _logic->defineStructSize(*scope.moduleScope, resultRef); - if (info.size > 0) { - ObjectInfo retVal = declareTempStructure(scope, info); - retVal.typeInfo.typeRef = resultRef; + pos_t argCount = 0; - return retVal; + Interpreter interpreter(scope.moduleScope, _logic); + ObjectInfo retVal = evalExpression(interpreter, scope, node.findChild(SyntaxKey::Expression)); + switch (retVal.kind) { + case ObjectKind::IntLiteral: + argCount = retVal.extra; + break; + default: + scope.raiseError(errCannotEval, node); + break; } - else throw InternalError(errFatalError); - return {}; // NOTE : should never be reached + mssg_t message = encodeMessage(actionRef, argCount, 0); + IdentifierString messageName; + ByteCodeUtil::resolveMessageName(messageName, scope.module, message); + + ref_t constRef = scope.module->mapConstant(*messageName); + return { ObjectKind::MssgLiteral, { V_MESSAGE }, constRef }; } -ObjectInfo Compiler :: compileWeakOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, ref_t* arguments, pos_t argLen, - ObjectInfo& loperand, ArgumentsInfo& messageArguments, mssg_t message, ref_t expectedRef, ArgumentsInfo* updatedOuterArgs) + +ObjectInfo Compiler :: mapExtMessageConstant(Scope& scope, SyntaxNode node, ref_t actionRef, ref_t extension) { - ObjectInfo retVal = {}; + pos_t argCount = 0; - // resolving a message signature (excluding a target) - bool weakSignature = false; - for (pos_t i = 1; i < argLen; i++) { - if (!arguments[i]) { - weakSignature = true; + Interpreter interpreter(scope.moduleScope, _logic); + ObjectInfo retVal = evalExpression(interpreter, scope, node.findChild(SyntaxKey::Expression)); + switch (retVal.kind) { + case ObjectKind::IntLiteral: + argCount = retVal.extra; + break; + default: + scope.raiseError(errCannotEval, node); break; - } - else if (isPrimitiveRef(arguments[i])) { - arguments[i - 1] = resolvePrimitiveType(scope, { arguments[i] }, false); - } - else arguments[i - 1] = arguments[i]; } - ref_t signRef = (!weakSignature && argLen > 1) ? scope.module->mapSignature(arguments, argLen - 1, false) : 0; + mssg_t message = encodeMessage(actionRef, argCount, 0); + IdentifierString messageName; + ByteCodeUtil::resolveMessageName(messageName, scope.module, message); - auto byRefResolution = resolveByRefHandler(writer, loperand, scope, expectedRef, message, signRef, true); - if (byRefResolution.resolved) { - ObjectInfo tempRetVal = declareTempLocal(scope, expectedRef, false); + size_t index = (*messageName).find('['); + assert(index != NOTFOUND_POS); // !! temporal - addByRefRetVal(messageArguments, tempRetVal); - // adding mark for optimization routine - if (tempRetVal.kind == ObjectKind::TempLocalAddress) - writer.appendNode(BuildKey::ByRefOpMark, tempRetVal.argument); + ustr_t extRefName = scope.moduleScope->resolveFullName(extension); + messageName.insert(">", index); + messageName.insert(extRefName, index); + if (isWeakReference(extRefName)) { + messageName.insert(scope.module->name(), index); + } + messageName.insert("<", index); - compileMessageOperation(writer, scope, node, loperand, byRefResolution, - signRef, messageArguments, EAttr::None, updatedOuterArgs); + ref_t constRef = scope.module->mapConstant(*messageName); - retVal = tempRetVal; + ref_t constType = V_EXTMESSAGE64; + switch (scope.moduleScope->ptrSize) { + case 4: + constType = V_EXTMESSAGE64; + break; + case 8: + constType = V_EXTMESSAGE128; + break; + default: + break; } - else retVal = compileMessageOperation(writer, scope, node, loperand, { message }, - signRef, messageArguments, EAttr::NoExtension, updatedOuterArgs); - return retVal; + return { ObjectKind::ExtMssgLiteral, { constType, extension }, constRef }; } -inline bool isPrimitiveArray(ref_t typeRef) +ObjectInfo Compiler :: defineTerminalInfo(Scope& scope, SyntaxNode node, TypeInfo declaredTypeInfo, bool variableMode, + bool forwardMode, bool refOp, bool mssgOp, bool memberMode, bool& invalid, ExpressionAttribute attrs) { - switch (typeRef) { - case V_BINARYARRAY: - case V_OBJARRAY: - case V_INT32ARRAY: - return true; - default: - return false; - } -} - -inline bool DoesOperationSupportConvertableIntLiteral(int operatorId) -{ - switch (operatorId) { - case ADD_OPERATOR_ID: - case SUB_OPERATOR_ID: - case LESS_OPERATOR_ID: - case EQUAL_OPERATOR_ID: - case NOTEQUAL_OPERATOR_ID: - case ELSE_OPERATOR_ID: - case MUL_OPERATOR_ID: - case DIV_OPERATOR_ID: - case NOTLESS_OPERATOR_ID: - case GREATER_OPERATOR_ID: - case NOTGREATER_OPERATOR_ID: - case BAND_OPERATOR_ID: - case BOR_OPERATOR_ID: - case BXOR_OPERATOR_ID: - case BNOT_OPERATOR_ID: - case AND_OPERATOR_ID: - case OR_OPERATOR_ID: - case XOR_OPERATOR_ID: - case ADD_ASSIGN_OPERATOR_ID: - case SUB_ASSIGN_OPERATOR_ID: - case MUL_ASSIGN_OPERATOR_ID: - case DIV_ASSIGN_OPERATOR_ID: - case SET_INDEXER_OPERATOR_ID: - return true; - default: - return false; - } -} - -void Compiler :: convertIntLiteralForOperation(ExprScope& scope, SyntaxNode node, int operatorId, ArgumentsInfo& messageArguments) -{ - if (!DoesOperationSupportConvertableIntLiteral(operatorId)) - return; + ObjectInfo retVal = {}; + bool ignoreDuplicates = EAttrs::testAndExclude(attrs, ExpressionAttribute::IgnoreDuplicate); + bool invalidForNonIdentifier = forwardMode || variableMode || refOp || mssgOp || memberMode; - ObjectInfo literal = {}; - ref_t loperandRef = messageArguments[0].typeInfo.typeRef; - switch (loperandRef) { - case V_INT16ARRAY: - literal = convertIntLiteral(scope, node, messageArguments[1], V_INT16, true); - break; - case V_INT8ARRAY: - literal = convertIntLiteral(scope, node, messageArguments[1], V_INT8, true); - break; - case V_BINARYARRAY: - literal = convertIntLiteral(scope, node, messageArguments[1], _logic->retrievePrimitiveType(*scope.moduleScope, messageArguments[0].typeInfo.elementRef), true); - break; - default: + switch (node.key) { + case SyntaxKey::TemplateType: { - literal = convertIntLiteral(scope, node, messageArguments[1], _logic->retrievePrimitiveType(*scope.moduleScope, loperandRef), true); + TypeAttributes typeAttributes = {}; + TypeInfo typeInfo = resolveTypeAttribute(scope, node, typeAttributes, false, false); + retVal = { ObjectKind::Class, typeInfo, 0u }; + retVal = mapClassSymbol(scope, retrieveStrongType(scope, retVal)); break; - } - } + } + case SyntaxKey::globalreference: + invalid = variableMode; + retVal = scope.mapGlobal(node.identifier()); + break; + case SyntaxKey::identifier: + case SyntaxKey::reference: + if (variableMode) { + invalid = forwardMode; - if (literal.kind != ObjectKind::Unknown) - messageArguments[1] = literal; -} + if (declareVariable(scope, node, declaredTypeInfo, ignoreDuplicates)) { + retVal = scope.mapIdentifier(node.identifier(), node.key == SyntaxKey::reference, + attrs | ExpressionAttribute::Local); -ObjectInfo Compiler :: compileOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, ArgumentsInfo& messageArguments, - int operatorId, ref_t expectedRef, ArgumentsInfo* updatedOuterArgs) -{ - if (messageArguments.count() > 1 && messageArguments[1].kind == ObjectKind::IntLiteral) { - // try to typecast int literal if possible - convertIntLiteralForOperation(scope, node, operatorId, messageArguments); - } + if (_trackingUnassigned && refOp) { + scope.markAsAssigned(retVal); + } + } + else retVal = scope.mapIdentifier(node.identifier(), node.key == SyntaxKey::reference, attrs); + } + else if (forwardMode) { + IdentifierString forwardName(FORWARD_PREFIX_NS, node.identifier()); - WriterContext context = { &writer, &scope, node }; + retVal = scope.mapIdentifier(*forwardName, true, attrs); + } + else if (memberMode) { + retVal = scope.mapMember(node.identifier()); + } + else retVal = scope.mapIdentifier(node.identifier(), node.key == SyntaxKey::reference, attrs); - ObjectInfo loperand = messageArguments[0]; + if (refOp) { + switch (retVal.kind) { + case ObjectKind::LocalAddress: + retVal.typeInfo = { V_WRAPPER, retVal.typeInfo.typeRef }; + break; + case ObjectKind::ParamAddress: + retVal.typeInfo = { V_WRAPPER, retVal.typeInfo.typeRef }; + break; + case ObjectKind::Local: + retVal.kind = ObjectKind::RefLocal; + retVal.typeInfo = { V_WRAPPER, retVal.typeInfo.typeRef }; + break; + case ObjectKind::ByRefParam: + // allowing to pass by ref parameter directly + retVal.kind = ObjectKind::ParamReference; + retVal.typeInfo = { V_WRAPPER, retVal.typeInfo.typeRef }; + break; + case ObjectKind::ByRefParamAddress: + // allowing to pass by ref parameter directly + retVal.kind = ObjectKind::ParamAddress; + retVal.typeInfo = { V_WRAPPER, retVal.typeInfo.typeRef }; + //retVal.mode = TargetMode::UnboxingRequired; + break; + default: + invalid = true; + break; + } + } + break; + case SyntaxKey::string: + invalid = invalidForNonIdentifier; - pos_t argLen = 1; - ref_t arguments[3] = {}; - arguments[0] = loperand.typeInfo.typeRef; - if (messageArguments.count() > 1) { - arguments[argLen++] = retrieveType(scope, messageArguments[1]); - } - if (messageArguments.count() > 2) { - arguments[argLen++] = retrieveType(scope, messageArguments[2]); - } + retVal = mapStringConstant(scope, node); + break; + case SyntaxKey::wide: + invalid = invalidForNonIdentifier; - if (operatorId == SET_INDEXER_OPERATOR_ID) { - if (isPrimitiveArray(arguments[0]) && _logic->isCompatible(*scope.moduleScope, { arguments[1] }, { loperand.typeInfo.elementRef }, false)) - // HOTFIX : for the generic binary array, recognize the element type - arguments[1] = V_ELEMENT; - } + retVal = mapWideStringConstant(scope, node); + break; + case SyntaxKey::character: + invalid = invalidForNonIdentifier; - ref_t outputRef = 0; - bool needToAlloc = false; - BuildKey op = _logic->resolveOp(*scope.moduleScope, operatorId, arguments, argLen, outputRef); + retVal = mapCharacterConstant(scope, node); + break; + case SyntaxKey::integer: + invalid = invalidForNonIdentifier; - ObjectInfo retVal = {}; - if (op != BuildKey::None) { - ObjectInfo roperand = {}; - ObjectInfo ioperand = {}; + retVal = mapIntConstant(scope, node, 10); + break; + case SyntaxKey::hexinteger: + invalid = invalidForNonIdentifier; - if (messageArguments.count() > 1) - roperand = messageArguments[1]; - if (messageArguments.count() > 2) - ioperand = messageArguments[2]; + retVal = mapUIntConstant(scope, node, 16); + break; + case SyntaxKey::longinteger: + invalid = invalidForNonIdentifier; - if (outputRef == V_ELEMENT) { - outputRef = loperand.typeInfo.elementRef; - } + retVal = mapLongConstant(scope, node, 10); + break; + case SyntaxKey::real: + invalid = invalidForNonIdentifier; - if (op == BuildKey::NilCondOp) { - // NOTE : the nil operation need only one (not nil) operand - if (loperand.typeInfo.typeRef == V_NIL) { - loperand = roperand; - } + retVal = mapFloat64Constant(scope, node); + break; + case SyntaxKey::constant: + invalid = invalidForNonIdentifier; - roperand = {}; - } - else if (op != BuildKey::ObjArrayOp && outputRef && _logic->isEmbeddable(*scope.moduleScope, outputRef)) - needToAlloc = true; + retVal = mapConstant(scope, node); + break; + default: + // to make compiler happy + invalid = true; + break; + } - if (needToAlloc) { - retVal = allocateResult(scope, outputRef); - } - else retVal = { ObjectKind::Object, { outputRef }, 0 }; + if (EAttrs::test(attrs, EAttr::Weak)) { + assert(retVal.mode == TargetMode::None); + retVal.mode = TargetMode::Weak; + } - // box argument locally if required - loperand = boxArgumentLocally(context, loperand, true, false); - roperand = boxArgumentLocally(context, roperand, true, false); + return retVal; +} - writeObjectInfo(context, loperand); - writer.appendNode(BuildKey::SavingInStack, 0); +ObjectInfo Compiler :: mapTerminal(Scope& scope, SyntaxNode node, TypeInfo declaredTypeInfo, EAttr attrs) +{ + bool forwardMode = EAttrs::testAndExclude(attrs, ExpressionAttribute::Forward); + bool variableMode = EAttrs::testAndExclude(attrs, ExpressionAttribute::NewVariable); + bool externalOp = EAttrs::testAndExclude(attrs, ExpressionAttribute::Extern); + bool newOp = EAttrs::testAndExclude(attrs, ExpressionAttribute::NewOp); + bool castOp = EAttrs::testAndExclude(attrs, ExpressionAttribute::CastOp); + bool refOp = EAttrs::testAndExclude(attrs, ExpressionAttribute::RefOp); + bool mssgOp = EAttrs::testAndExclude(attrs, ExpressionAttribute::MssgNameLiteral); + bool probeMode = EAttrs::testAndExclude(attrs, ExpressionAttribute::ProbeMode); + bool memberMode = EAttrs::testAndExclude(attrs, ExpressionAttribute::Member); - if (roperand.kind != ObjectKind::Unknown) { - writeObjectInfo(context, roperand); - writer.appendNode(BuildKey::SavingInStack, 1); + ObjectInfo retVal; + bool invalid = false; + if (externalOp) { + auto externalInfo = mapExternal(scope, node); + switch (externalInfo.type) { + case ExternalType::WinApi: + return { ObjectKind::Extern, {}, externalInfo.reference, 0, TargetMode::WinApi }; + default: + return { ObjectKind::Extern, {}, externalInfo.reference, 0, TargetMode::External }; } - - if (ioperand.kind != ObjectKind::Unknown) - writeObjectInfo(context, ioperand); - - writer.newNode(op, operatorId); - - // check if the operation requires an extra arguments - if (needToAlloc) { - writer.appendNode(BuildKey::Index, retVal.argument); + } + else if (newOp || castOp) { + if (node.key == SyntaxKey::identifier && EAttrs::testAndExclude(attrs, ExpressionAttribute::RetrievingType)) { + auto varInfo = scope.mapIdentifier(node.identifier(), false, attrs); + if (varInfo.kind != ObjectKind::Unknown) { + retVal = { ObjectKind::Class, varInfo.typeInfo, 0u, newOp ? TargetMode::Creating : TargetMode::Casting }; + } + else return varInfo; } + else { + switch (node.key) { + case SyntaxKey::TemplateType: + case SyntaxKey::ArrayType: + case SyntaxKey::Type: + case SyntaxKey::identifier: + case SyntaxKey::reference: + { + TypeAttributes typeAttributes = {}; + TypeInfo typeInfo = resolveTypeAttribute(scope, node, typeAttributes, false, false); - switch (op) { - case BuildKey::BinaryArraySOp: - case BuildKey::BinaryArrayOp: - writer.appendNode(BuildKey::Size, _logic->defineStructSize(*scope.moduleScope, loperand.typeInfo.elementRef).size); - break; - case BuildKey::BoolSOp: - case BuildKey::IntCondOp: - case BuildKey::UIntCondOp: - case BuildKey::ByteCondOp: - case BuildKey::UByteCondOp: - case BuildKey::ShortCondOp: - case BuildKey::LongCondOp: - case BuildKey::LongIntCondOp: - case BuildKey::RealCondOp: - case BuildKey::NilCondOp: - writer.appendNode(BuildKey::TrueConst, scope.moduleScope->branchingInfo.trueRef); - writer.appendNode(BuildKey::FalseConst, scope.moduleScope->branchingInfo.falseRef); + retVal = { ObjectKind::Class, typeInfo, 0u, newOp ? TargetMode::Creating : TargetMode::Casting }; + if (CompilerLogic::isPrimitiveArrRef(retVal.typeInfo.typeRef) && newOp) + retVal.mode = TargetMode::CreatingArray; + break; + } + default: + invalid = true; + break; + } + } + } + else if (mssgOp) { + switch (node.key) { + case SyntaxKey::identifier: + { + retVal = { ObjectKind::MssgNameLiteral, { V_MESSAGENAME }, + scope.module->mapAction(node.identifier(), 0, false) }; break; + } default: + invalid = true; break; } + } + else retVal = defineTerminalInfo(scope, node, declaredTypeInfo, variableMode, forwardMode, + refOp, mssgOp, memberMode, invalid, attrs); - writer.closeNode(); + if (invalid) + scope.raiseError(errInvalidOperation, node); - retVal = unboxArguments(context, retVal, updatedOuterArgs); + if (probeMode) + retVal.mode = TargetMode::Probe; - scope.reserveArgs(argLen); + return retVal; +} + +inline SyntaxNode retrieveTerminalOrType(SyntaxNode node) +{ + if (test((unsigned int)node.key, (unsigned int)SyntaxKey::TerminalMask)) + return node; + + SyntaxNode current = node.firstChild(); + SyntaxNode last = {}; + while (current != SyntaxKey::None) { + if (test((unsigned int)current.key, (unsigned int)SyntaxKey::TerminalMask)) { + last = current; + } + else if (current == SyntaxKey::ArrayType || current == SyntaxKey::Type || current == SyntaxKey::TemplateType) { + last = current; + } + + current = current.nextNode(); } - else { - mssg_t message = resolveOperatorMessage(scope.moduleScope, operatorId); - if (messageArguments.count() > 2) { - overwriteArgCount(message, 3); - // HOTFIX : index argument should be the second one - ObjectInfo tmp = messageArguments[1]; - messageArguments[1] = messageArguments[2]; - messageArguments[2] = tmp; + return last; +} - ref_t tmpRef = arguments[1]; - if (tmpRef == V_ELEMENT) - tmpRef = loperand.typeInfo.elementRef; +ObjectInfo Compiler :: mapObject(Scope& scope, SyntaxNode node, EAttrs mode) +{ + SyntaxNode terminalNode = retrieveTerminalOrType(node); - arguments[1] = arguments[2]; - arguments[2] = tmpRef; + TypeInfo declaredTypeInfo = {}; + declareExpressionAttributes(scope, node, declaredTypeInfo, mode); + if (mode.test(EAttr::Lookahead)) { + if (mode.test(EAttr::NewVariable)) { + return { ObjectKind::NewVariable, declaredTypeInfo, 0, 0 }; } + else if (mode.test(EAttr::MssgNameLiteral)) { + if (declaredTypeInfo.typeRef) { + SyntaxNode actionTerminal = terminalNode.findChild(SyntaxKey::identifier); + if (actionTerminal != SyntaxKey::None) { + return { ObjectKind::ExtMssgLiteral, { V_MESSAGE, declaredTypeInfo.typeRef }, + scope.module->mapAction(actionTerminal.identifier(), 0, false) }; + } + } + else return { ObjectKind::MssgLiteral, { V_MESSAGE }, + scope.module->mapAction(terminalNode.identifier(), 0, false) }; + } + return {}; + } - retVal = compileWeakOperation(writer, scope, node, arguments, argLen, loperand, - messageArguments, message, expectedRef, updatedOuterArgs); + if (terminalNode.nextNode() == SyntaxKey::TemplateArg && !EAttrs::test(mode.attrs, ExpressionAttribute::NewOp)) { + scope.raiseError(errInvalidSyntax, node); } + ObjectInfo retVal = mapTerminal(scope, terminalNode, declaredTypeInfo, mode.attrs); + return retVal; } -ObjectInfo Compiler :: compileOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, SyntaxNode rnode, - int operatorId, ref_t expectedRef) +inline bool isNormalConstant(ObjectInfo info) { - if (_evaluateOp) { - Interpreter interpreter(scope.moduleScope, _logic); - ObjectInfo evalRetVal = evalExpression(interpreter, scope, node.parentNode(), true); - if (evalRetVal.kind != ObjectKind::Unknown) - return evalRetVal; + switch (info.kind) { + case ObjectKind::StringLiteral: + return true; + default: + return false; } +} - ObjectInfo retVal; - ArgumentsInfo updatedOuterArgs; - - SyntaxNode lnode = node; - SyntaxNode inode; +ObjectInfo Compiler :: convertIntLiteral(ExprScope& scope, SyntaxNode node, ObjectInfo source, ref_t targetRef, bool ignoreError) +{ + bool invalid = false; + switch (targetRef) { + case V_UINT8: + invalid = source.extra < 0 || source.extra > 255; + break; + case V_INT8: + invalid = source.extra < INT8_MIN || source.extra > INT8_MAX; + break; + case V_INT16: + invalid = source.extra < INT16_MIN || source.extra > INT16_MAX; + break; + case V_UINT16: + invalid = source.extra < 0 || source.extra > 65535; + break; + case V_INT64: + source.kind = ObjectKind::LongLiteral; + break; + case V_FLOAT64: + source.kind = ObjectKind::Float64Literal; + source.reference = mapFloat64Const(scope.module, source.extra); + break; + default: + invalid = true; + break; + } + + if (invalid) { + if (!ignoreError) + scope.raiseError(errInvalidOperation, node); - if (operatorId == SET_INDEXER_OPERATOR_ID) { - lnode = node.firstChild(); - inode = lnode.nextNode(); + return {}; } - BuildKey op = BuildKey::None; - ObjectInfo loperand = compileExpression(writer, scope, lnode, 0, - EAttr::Parameter | EAttr::RetValExpected | EAttr::LookaheadExprMode, &updatedOuterArgs); - ObjectInfo roperand = {}; - ObjectInfo ioperand = {}; + source.typeInfo = { targetRef }; - ArgumentsInfo arguments; - arguments.add(loperand); + return source; +} - // HOTFIX : typecast the right-hand expression if required - if (rnode != SyntaxKey::None) { - ref_t rTargetRef = 0; - if (operatorId == SET_OPERATOR_ID) - rTargetRef = retrieveType(scope, loperand); +ref_t Compiler :: mapConstantReference(Scope& ownerScope) +{ + ref_t nestedRef = 0; + SymbolScope* owner = Scope::getScope(ownerScope, Scope::ScopeLevel::Symbol); + if (owner) { + nestedRef = owner->reference; + } - roperand = compileExpression(writer, scope, rnode, rTargetRef, - EAttr::Parameter | EAttr::RetValExpected | EAttr::LookaheadExprMode, &updatedOuterArgs); + if (!nestedRef) + nestedRef = ownerScope.moduleScope->mapAnonymous(); - arguments.add(roperand); - } + return nestedRef; +} - if (inode != SyntaxKey::None) { - arguments.add(compileExpression(writer, scope, inode, 0, - EAttr::Parameter | EAttr::RetValExpected | EAttr::LookaheadExprMode, &updatedOuterArgs)); - } +inline ref_t retrieveTypeRef(ModuleScopeBase& scope, ref_t reference) +{ + IdentifierString name(scope.module->resolveReference(reference)); + if ((*name).endsWith(CLASSCLASS_POSTFIX)) + name.truncate(name.length() - getlength(CLASSCLASS_POSTFIX)); - return compileOperation(writer, scope, node, arguments, operatorId, expectedRef, &updatedOuterArgs); + return scope.module->mapReference(*name); } -mssg_t Compiler :: mapMessage(Scope& scope, SyntaxNode current, bool propertyMode, - bool extensionMode, bool probeMode) +ref_t Compiler :: resolveTupleClass(Scope& scope, SyntaxNode node, ArgumentsInfo& items) { - ref_t flags = propertyMode ? PROPERTY_MESSAGE : 0; - if (extensionMode) - flags |= FUNCTION_MESSAGE; + IdentifierString tupleName(scope.module->resolveReference(scope.moduleScope->buildins.tupleTemplateReference)); - IdentifierString messageStr; + List parameters({}); - if (current == SyntaxKey::Message) { - SyntaxNode terminal = current.firstChild(SyntaxKey::TerminalMask); + // HOTFIX : generate a temporal template to pass the type + SyntaxTree dummyTree; + SyntaxTreeWriter dummyWriter(dummyTree); + dummyWriter.newNode(SyntaxKey::Root); - messageStr.copy(terminal.identifier()); + for (size_t i = 0; i < items.count(); i++) { + ref_t typeRef = retrieveStrongType(scope, items[i]); + if (!typeRef) + typeRef = scope.moduleScope->buildins.superReference; - current = current.nextNode(); - } + dummyWriter.newNode(SyntaxKey::TemplateArg, typeRef); + dummyWriter.newNode(SyntaxKey::Type); - pos_t argCount = 1; - while (current != SyntaxKey::None) { - argCount++; + ustr_t referenceName = scope.moduleScope->module->resolveReference(typeRef); + if (isWeakReference(referenceName)) { + dummyWriter.appendNode(SyntaxKey::reference, referenceName); + } + else dummyWriter.appendNode(SyntaxKey::globalreference, referenceName); - current = current.nextNode(SyntaxKey::ScopeMask); + dummyWriter.closeNode(); + dummyWriter.closeNode(); } - if (argCount >= ARG_COUNT) { - flags |= VARIADIC_MESSAGE; - argCount = 2; + dummyWriter.closeNode(); + + SyntaxNode current = dummyTree.readRoot().firstChild(); + while (current == SyntaxKey::TemplateArg) { + parameters.add(current); + + current = current.nextNode(); } - if (messageStr.empty()) { - flags |= FUNCTION_MESSAGE; + tupleName.append('#'); + tupleName.appendInt(items.count_int()); - // if it is an implicit message - messageStr.copy(probeMode ? TRY_INVOKE_MESSAGE : INVOKE_MESSAGE); + ref_t templateReference = 0; + if (isWeakReference(*tupleName)) { + templateReference = scope.module->mapReference(*tupleName, true); } + else templateReference = scope.moduleScope->mapFullReference(*tupleName, true); - if (test(flags, FUNCTION_MESSAGE)) - // exclude the target from the arg counter for the function - argCount--; + if (!templateReference) + scope.raiseError(errInvalidOperation, node); - ref_t actionRef = scope.module->mapAction(*messageStr, 0, false); + NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - return encodeMessage(actionRef, argCount, flags); + return _templateProcessor->generateClassTemplate(*scope.moduleScope, *nsScope->nsName, + templateReference, parameters, false, nullptr); } -ref_t targetResolver(void* param, mssg_t mssg) +inline bool checkTerminalCoords(SyntaxNode node) { - return ((ResolvedMap*)param)->get(mssg); + SyntaxNode terminal = node.firstChild(SyntaxKey::TerminalMask); + + return terminal.existChild(SyntaxKey::Row); } -ref_t Compiler :: compileExtensionDispatcher(BuildTreeWriter& writer, NamespaceScope& scope, mssg_t genericMessage, - ref_t outputRef) +inline SyntaxNode findObjectNode(SyntaxNode node) { - ref_t extRef = scope.moduleScope->mapAnonymous(); - ClassScope classScope(&scope, extRef, Visibility::Private); - declareClassParent(classScope.info.header.parentRef, classScope, {}); - classScope.extensionDispatcher = true; - classScope.info.header.classRef = classScope.reference; - classScope.extensionClassRef = scope.moduleScope->buildins.superReference; - generateClassFlags(classScope, elExtension | elSealed); + if (node == SyntaxKey::CodeBlock) { + // HOTFIX : to prevent double breakpoint + return {}; + } + SyntaxNode current = node.firstChild(); + while (current != SyntaxKey::None) { + switch (current.key) { + case SyntaxKey::Object: + if (checkTerminalCoords(current)) + return current; + break; + default: + { + SyntaxNode objectNode = findObjectNode(current); + if (objectNode != SyntaxKey::None) + return objectNode; - // create a new overload list - ClassInfo::MethodMap methods({}); - ResolvedMap targets(0); - for(auto it = scope.extensions.getIt(genericMessage); !it.eof(); it = scope.extensions.nextIt(genericMessage, it)) { - auto extInfo = *it; + break; + } + } - methods.add(extInfo.value2, { false, 0, 0, genericMessage | FUNCTION_MESSAGE, 0 }); - targets.add(extInfo.value2, extInfo.value1); + current = current.nextNode(); } - _logic->injectMethodOverloadList(this, *scope.moduleScope, - classScope.info.header.flags, genericMessage | FUNCTION_MESSAGE, methods, - classScope.info.attributes, &targets, targetResolver, ClassAttribute::OverloadList); - - SyntaxTree classTree; - SyntaxTreeWriter classWriter(classTree); + return {}; +} - // build the class tree - classWriter.newNode(SyntaxKey::Root); - classWriter.newNode(SyntaxKey::Class, extRef); +ObjectInfo Compiler :: compileRetExpression(BuildTreeWriter& writer, CodeScope& codeScope, SyntaxNode node, EAttr mode) +{ + Expression expression(this, codeScope, writer); - SyntaxNode classNode = classWriter.CurrentNode(); - injectVirtualMultimethod(classNode, SyntaxKey::Method, genericMessage | FUNCTION_MESSAGE, genericMessage, - 0, outputRef, Visibility::Public, true); + bool autoMode = false; + ref_t outputRef = 0; + if (codeScope.isByRefHandler()) { + ObjectInfo byRefTarget = codeScope.mapByRefReturnArg(); - classWriter.closeNode(); - classWriter.closeNode(); + outputRef = byRefTarget.typeInfo.typeRef; + } + else outputRef = codeScope.getOutputRef(); - generateMethodDeclaration(classScope, classNode.findChild(SyntaxKey::Method), false, false); - classScope.save(); + if (outputRef == V_AUTO) { + autoMode = true; + outputRef = 0; + } - BuildNode node = writer.CurrentNode(); - while (node != BuildKey::Root) - node = node.parentNode(); + ObjectInfo retVal = expression.compileReturning(node, mode, outputRef); - BuildTreeWriter nestedWriter(node); - nestedWriter.newNode(BuildKey::Class, extRef); - compileVMT(nestedWriter, classScope, classNode); - nestedWriter.closeNode(); + codeScope.withRetStatement = true; - return extRef; + return retVal; } -ref_t Compiler :: compileMessageArguments(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode current, - ArgumentsInfo& arguments, ref_t expectedSignRef, EAttr mode, ArgumentsInfo* updatedOuterArgs, bool& variadicArgList) +ObjectInfo Compiler :: compileRootExpression(BuildTreeWriter& writer, CodeScope& codeScope, SyntaxNode node, EAttr mode) { - EAttr paramMode = EAttr::Parameter | EAttr::RetValExpected; - if (EAttrs::testAndExclude(mode, EAttr::NoPrimitives)) - paramMode = paramMode | EAttr::NoPrimitives; - - // compile the message argument list - ref_t signatures[ARG_COUNT] = { 0 }; - ref_t signatureLen = 0; - ref_t superReference = scope.moduleScope->buildins.superReference; - - if (expectedSignRef) - scope.module->resolveSignature(expectedSignRef, signatures); + Expression expression(this, codeScope, writer); - while (current != SyntaxKey::None) { - if (current == SyntaxKey::Expression) { - // try to recognize the message signature - // NOTE : signatures[signatureLen] contains expected parameter type if expectedSignRef is provided - auto argInfo = compileExpression(writer, scope, current, signatures[signatureLen], - paramMode, updatedOuterArgs); + return expression.compileRoot(node, mode); +} - if (argInfo.mode == TargetMode::UnboxingVarArgument) { - if (argInfo.typeInfo.elementRef) { - signatures[signatureLen++] = argInfo.typeInfo.elementRef; - } - else signatures[signatureLen++] = scope.moduleScope->buildins.superReference; +void Compiler :: saveFrameAttributes(BuildTreeWriter& writer, Scope& scope, pos_t reserved, pos_t reservedN) +{ + reserved = align(reserved, scope.moduleScope->stackAlingment); + reservedN = align(reservedN, scope.moduleScope->rawStackAlingment); - if (!variadicArgList) { - variadicArgList = true; - } - else scope.raiseError(errInvalidOperation, current); - } - else { - ref_t argRef = retrieveStrongType(scope, argInfo); - if (signatureLen >= ARG_COUNT) { - signatureLen++; - } - else if (argRef) { - signatures[signatureLen++] = argRef; - } - else signatures[signatureLen++] = superReference; - } - arguments.add(argInfo); - } + if (reserved) + writer.appendNode(BuildKey::Reserved, reserved); - current = current.nextNode(); - } + if (reservedN > 0) + writer.appendNode(BuildKey::ReservedN, reservedN); +} - if (signatureLen > 0 && signatureLen <= ARG_COUNT) { - bool anonymous = true; - for (ref_t i = 0; i < signatureLen; i++) { - if (signatures[i] != superReference) { - anonymous = false; +bool Compiler :: compileSymbolConstant(SymbolScope& scope, ObjectInfo retVal) +{ + ref_t constRef = generateConstant(scope, retVal, scope.reference, false); + if (constRef) { + switch (retVal.kind) { + case ObjectKind::Singleton: + scope.info.symbolType = SymbolType::Singleton; + scope.info.valueRef = retVal.reference; + scope.info.typeRef = retrieveStrongType(scope, retVal); + break; + case ObjectKind::StringLiteral: + case ObjectKind::WideStringLiteral: + case ObjectKind::Float64Literal: + scope.info.symbolType = SymbolType::Constant; + scope.info.valueRef = constRef; + scope.info.typeRef = retrieveStrongType(scope, retVal); + break; + case ObjectKind::IntLiteral: + scope.info.symbolType = SymbolType::Constant; + scope.info.valueRef = constRef; + scope.info.typeRef = retrieveStrongType(scope, retVal); + break; + case ObjectKind::Constant: + scope.info.symbolType = SymbolType::Constant; + scope.info.valueRef = retVal.reference; + scope.info.typeRef = retrieveStrongType(scope, retVal); + break; + case ObjectKind::ConstArray: + scope.info.symbolType = SymbolType::ConstantArray; + scope.info.valueRef = retVal.reference; + scope.info.typeRef = retrieveStrongType(scope, retVal); + break; + default: + assert(false); break; - } } - if (!anonymous) - return scope.module->mapSignature(signatures, signatureLen, false); - } - return 0; + return true; + } + else return false; } -ref_t Compiler :: mapExtension(BuildTreeWriter& writer, Scope& scope, mssg_t& message, ref_t& implicitSignatureRef, - ObjectInfo object, int& stackSafeAttr) +void Compiler :: compileSymbol(BuildTreeWriter& writer, SymbolScope& scope, SyntaxNode node) { - NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); + scope.load(); - ref_t objectRef = retrieveStrongType(scope, object); - if (objectRef == 0) { - objectRef = scope.moduleScope->buildins.superReference; - } + writer.newNode(BuildKey::Symbol, node.arg.reference); - if (implicitSignatureRef) { - // auto generate extension template for strong-typed signature - for (auto it = nsScope->extensionTemplates.getIt(message); !it.eof(); it = nsScope->extensionTemplates.nextIt(message, it)) { - _logic->resolveExtensionTemplate(*scope.moduleScope, this, *it, - implicitSignatureRef, *nsScope->nsName, nsScope->outerExtensionList ? nsScope->outerExtensionList : &nsScope->extensions); - } - } + NamespaceScope* ns = Scope::getScope(scope, Scope::ScopeLevel::Namespace); + writer.appendNode(BuildKey::Path, *ns->sourcePath); - // check extensions - auto it = nsScope->extensions.getIt(message); - if (!it.eof()) { - // generate an extension signature - ref_t signatures[ARG_COUNT] = {}; - size_t signatureLen = scope.module->resolveSignature(implicitSignatureRef, signatures); - for (size_t i = signatureLen; i > 0; i--) - signatures[i] = signatures[i - 1]; + writer.newNode(BuildKey::Tape); + if (scope.isStatic) + writer.appendNode(BuildKey::OpenStatic, node.arg.reference); - signatures[0] = objectRef; - signatureLen++; + writer.appendNode(BuildKey::OpenFrame); - size_t argCount = getArgCount(message); - while (signatureLen < argCount) { - signatures[signatureLen] = scope.moduleScope->buildins.superReference; - signatureLen++; - } + SyntaxNode bodyNode = node.findChild(SyntaxKey::GetExpression); - scope.module->mapSignature(signatures, signatureLen, false); - mssg_t resolvedMessage = 0; - ref_t resolvedExtRef = 0; - int resolvedStackSafeAttr = 0; - int counter = 0; - while (!it.eof()) { - auto extInfo = *it; - ref_t targetRef = nsScope->resolveExtensionTarget(extInfo.value1); - int extStackAttr = 0; - if (_logic->isMessageCompatibleWithSignature(*scope.moduleScope, targetRef, extInfo.value2, - signatures, signatureLen, extStackAttr)) - { - if (!resolvedMessage) { - resolvedMessage = extInfo.value2; - resolvedExtRef = extInfo.value1; - resolvedStackSafeAttr = extStackAttr; - } - else if (_logic->isSignatureCompatible(*scope.moduleScope, resolvedMessage, extInfo.value2)) { - //NOTE : if the extension is more precise than the previous resolved one - use the new one - resolvedMessage = extInfo.value2; - resolvedExtRef = extInfo.value1; - } - else if (!_logic->isSignatureCompatible(*scope.moduleScope, extInfo.value2, resolvedMessage)) { - // if they are incompatible - use dynamic resolving - resolvedMessage = 0; - break; - } - } - counter++; + EAttr mode = ExpressionAttribute::RootSymbol; + if (scope.info.symbolType == SymbolType::Constant) + mode = mode | ExpressionAttribute::ConstantExpr; - it = nsScope->extensions.nextIt(message, it); - } + Expression expression(this, scope, writer); + ObjectInfo retVal = expression.compileSymbolRoot(bodyNode, mode); - if (resolvedMessage) { - if (counter > 1 && (implicitSignatureRef == 0 && getArgCount(message) > 1)) { - // HOTFIX : does not resolve an ambigous extension for a weak message - // excluding messages without arguments - } - else { - // if we are lucky - use the resolved one - message = resolvedMessage; - stackSafeAttr = resolvedStackSafeAttr; - - return resolvedExtRef; - } - } + writer.appendNode(BuildKey::CloseFrame); - // bad luck - we have to generate run-time extension dispatcher - implicitSignatureRef = 0; - ref_t extRef = nsScope->extensionDispatchers.get(message); - if (extRef == INVALID_REF) { - extRef = compileExtensionDispatcher(writer, *nsScope, message, 0); + if (scope.isStatic) + writer.appendNode(BuildKey::CloseStatic, node.arg.reference); - nsScope->extensionDispatchers.add(message, extRef); - } + writer.appendNode(BuildKey::Exit); - message |= FUNCTION_MESSAGE; + writer.closeNode(); + saveFrameAttributes(writer, scope, scope.reserved1 + scope.reservedArgs, scope.reserved2); + writer.closeNode(); - return extRef; + // create constant if required + if (scope.info.symbolType == SymbolType::Constant) { + if (!compileSymbolConstant(scope, retVal)) + scope.raiseError(errInvalidOperation, node); } - return 0; -} - -mssg_t Compiler :: resolveVariadicMessage(Scope& scope, mssg_t message) -{ - pos_t argCount = 0; - ref_t actionRef = 0, flags = 0, dummy = 0; - decodeMessage(message, actionRef, argCount, flags); - - ustr_t actionName = scope.module->resolveAction(actionRef, dummy); - - int argMultuCount = test(message, FUNCTION_MESSAGE) ? 1 : 2; + if (_logic->isLessAccessible(*scope.moduleScope, scope.visibility, scope.info.typeRef)) + scope.raiseWarning(WARNING_LEVEL_1, wrnLessAccessible, node); - return encodeMessage(scope.module->mapAction(actionName, 0, false), argMultuCount, flags | VARIADIC_MESSAGE); + scope.save(); } -Compiler::MessageResolution Compiler :: resolveMessageAtCompileTime(BuildTreeWriter& writer, ObjectInfo target, ExprScope& scope, - mssg_t weakMessage, ref_t implicitSignatureRef, bool ignoreExtensions, bool ignoreVariadics) +void Compiler :: compileClassSymbol(BuildTreeWriter& writer, ClassScope& scope) { - MessageResolution resolution = {}; - - if (target.mode == TargetMode::Weak) - return { weakMessage }; - - ref_t targetRef = retrieveStrongType(scope, target); + writer.newNode(BuildKey::Symbol, scope.reference); - // try to resolve the message as is - int resolvedStackSafeAttr = 0; - resolution.message = _logic->resolveMultimethod(*scope.moduleScope, weakMessage, targetRef, - implicitSignatureRef, resolvedStackSafeAttr, isSelfCall(target)); - if (resolution.message != 0) { - resolution.resolved = true; - resolution.stackSafeAttr = resolvedStackSafeAttr; + writer.newNode(BuildKey::Tape); + writer.appendNode(BuildKey::OpenFrame); + ObjectInfo retVal(ObjectKind::Class, { scope.info.header.classRef }, scope.reference, 0); - // if the object handles the compile-time resolved message - use it - return resolution; - } + Expression expression(this, scope, writer); + expression.writeObjectInfo(retVal); + writer.appendNode(BuildKey::CloseFrame); + writer.appendNode(BuildKey::Exit); + writer.closeNode(); - // check if the object handles the variadic message - if (targetRef && !ignoreVariadics) { - resolvedStackSafeAttr = 0; - resolution.message = _logic->resolveMultimethod(*scope.moduleScope, - resolveVariadicMessage(scope, weakMessage), - targetRef, implicitSignatureRef, resolvedStackSafeAttr, isSelfCall(target)); + writer.closeNode(); - if (resolution.message != 0) { - resolution.resolved = true; - resolution.stackSafeAttr = resolvedStackSafeAttr; + if (scope.info.attributes.exist({ 0, ClassAttribute::RuntimeLoadable })) { + SymbolInfo symbolInfo = {}; + symbolInfo.loadableInRuntime = true; - // if the object handles the compile-time resolved variadic message - use it - return resolution; - } + // save class meta data + MemoryWriter metaWriter(scope.module->mapSection(scope.reference | mskMetaSymbolInfoRef, false), 0); + symbolInfo.save(&metaWriter); } +} - if (!ignoreExtensions) { - // check the existing extensions if allowed - // if the object handles the weak message - do not use extensions - CheckMethodResult dummy = {}; - if(_logic->resolveCallType(*scope.moduleScope, targetRef, weakMessage, dummy)) { - resolution.message = weakMessage; - - return resolution; - } - - resolvedStackSafeAttr = 0; - resolution.message = weakMessage; - ref_t extensionRef = mapExtension(writer, scope, resolution.message, implicitSignatureRef, - target, resolvedStackSafeAttr); - if (extensionRef != 0) { - // if there is an extension to handle the compile-time resolved message - use it - resolution.resolved = true; - resolution.extensionRef = extensionRef; - resolution.stackSafeAttr = resolvedStackSafeAttr; - - return resolution; - } +void Compiler :: beginMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode node, BuildKey scopeKey, bool withDebugInfo) +{ + writer.newNode(scopeKey, scope.message); - // HOTFIX : do not check variadic message for the properties - if ((weakMessage & PREFIX_MESSAGE_MASK) == PROPERTY_MESSAGE) - return { weakMessage }; + if (withDebugInfo) { + SyntaxNode pathNode = node.findChild(SyntaxKey::SourcePath); + if (pathNode != SyntaxKey::None) + writer.appendNode(BuildKey::Path, pathNode.identifier()); - // check if the extension handles the variadic message - mssg_t variadicMessage = resolveVariadicMessage(scope, weakMessage); + writer.newNode(BuildKey::Tape); - resolvedStackSafeAttr = 0; - extensionRef = mapExtension(writer, scope, variadicMessage, implicitSignatureRef, - target, resolvedStackSafeAttr); - if (extensionRef != 0) { - // if there is an extension to handle the compile-time resolved message - use it - resolution.resolved = true; - resolution.stackSafeAttr = resolvedStackSafeAttr; - resolution.message = variadicMessage; - resolution.extensionRef = extensionRef; + writeMethodDebugInfo(writer, scope); + writeMessageInfo(writer, scope); - return resolution; - } } - - // otherwise - use the weak message - return { weakMessage }; + else writer.newNode(BuildKey::Tape); } -void Compiler :: unboxArgumentLocaly(WriterContext& context, ObjectInfo temp, ObjectKey key) +void Compiler :: endMethod(BuildTreeWriter& writer, MethodScope& scope) { - if ((temp.typeInfo.isPrimitive() && _logic->isPrimitiveArrRef(temp.typeInfo.typeRef)) - || _logic->isEmbeddableArray(*context.scope->moduleScope, temp.typeInfo.typeRef)) - { - int size = defineFieldSize(*context.scope, { key.value1, temp.typeInfo, key.value2 }); + writer.appendNode(BuildKey::Exit); + writer.closeNode(); - compileAssigningOp(context, { key.value1, temp.typeInfo, key.value2, size }, temp); - } - else compileAssigningOp(context, { key.value1, temp.typeInfo, key.value2 }, temp); + saveFrameAttributes(writer, scope, scope.reserved1 + scope.reservedArgs, scope.reserved2); + + writer.closeNode(); } -void Compiler :: unboxOuterArgs(WriterContext& context, ArgumentsInfo* updatedOuterArgs) +void Compiler :: injectVariableInfo(BuildNode node, CodeScope& codeScope) { - // first argument is a closure - ObjectInfo closure; + for (auto it = codeScope.locals.start(); !it.eof(); ++it) { + auto localInfo = *it; + bool embeddableArray = false; + if (localInfo.typeInfo.typeRef) { + ref_t typeRef = localInfo.typeInfo.typeRef; - for (pos_t i = 0; i != updatedOuterArgs->count_pos(); i++) { - ObjectInfo info = (*updatedOuterArgs)[i]; - if (info.kind == ObjectKind::ClosureInfo) { - closure = (*updatedOuterArgs)[++i]; - closure.kind = ObjectKind::LocalField; + if (localInfo.typeInfo.isPrimitive() && localInfo.typeInfo.elementRef) + typeRef = resolvePrimitiveType(codeScope, localInfo.typeInfo, false); + + embeddableArray = _logic->isEmbeddableArray(*codeScope.moduleScope, typeRef); + if (embeddableArray && localInfo.size > 0) { + node.appendChild(BuildKey::BinaryArray, localInfo.offset) + .appendChild(BuildKey::Size, localInfo.size); + } } - else if (info.kind == ObjectKind::MemberInfo) { - ObjectInfo source = (*updatedOuterArgs)[++i]; - if (source.kind == ObjectKind::Local) { - closure.extra = info.reference; - compileAssigningOp(context, source, closure); + if (localInfo.size > 0) { + if (embeddableArray) { + if (_logic->isCompatible(*codeScope.moduleScope, + { V_INT8 }, { localInfo.typeInfo.elementRef }, false)) + { + BuildNode varNode = node.appendChild(BuildKey::ByteArrayAddress, it.key()); + varNode.appendChild(BuildKey::Index, localInfo.offset); + } + else if (_logic->isCompatible(*codeScope.moduleScope, + { V_UINT8 }, { localInfo.typeInfo.elementRef }, false)) + { + BuildNode varNode = node.appendChild(BuildKey::ByteArrayAddress, it.key()); + varNode.appendChild(BuildKey::Index, localInfo.offset); + } + else if (_logic->isCompatible(*codeScope.moduleScope, + { V_INT16 }, { localInfo.typeInfo.elementRef }, false)) + { + BuildNode varNode = node.appendChild(BuildKey::ShortArrayAddress, it.key()); + varNode.appendChild(BuildKey::Index, localInfo.offset); + } + else if (_logic->isCompatible(*codeScope.moduleScope, + { V_INT32 }, { localInfo.typeInfo.elementRef }, false)) + { + BuildNode varNode = node.appendChild(BuildKey::IntArrayAddress, it.key()); + varNode.appendChild(BuildKey::Index, localInfo.offset); + } } - else if (source.kind == ObjectKind::LocalAddress) { - closure.extra = info.reference; - compileAssigningOp(context, source, closure); + else if (localInfo.typeInfo.typeRef == codeScope.moduleScope->buildins.intReference) { + BuildNode varNode = node.appendChild(BuildKey::IntVariableAddress, it.key()); + varNode.appendChild(BuildKey::Index, localInfo.offset); } - else if (source.kind == ObjectKind::Outer) { - // ignore outer fields + else if (localInfo.typeInfo.typeRef == codeScope.moduleScope->buildins.uintReference) { + BuildNode varNode = node.appendChild(BuildKey::UIntVariableAddress, it.key()); + varNode.appendChild(BuildKey::Index, localInfo.offset); } - else assert(false); - } - else assert(false); - } -} - -ObjectInfo Compiler :: unboxArguments(WriterContext& context, ObjectInfo retVal, - ArgumentsInfo* updatedOuterArgs) -{ - // unbox the arguments if required - bool resultSaved = false; - for (auto it = context.scope->tempLocals.start(); !it.eof(); ++it) { - ObjectInfo temp = *it; - - if (temp.mode == TargetMode::UnboxingRequired || temp.mode == TargetMode::RefUnboxingRequired - || temp.mode == TargetMode::LocalUnboxingRequired || temp.mode == TargetMode::ConditionalUnboxingRequired) - { - if (!resultSaved && retVal.kind != ObjectKind::Unknown) { - // presave the result - ObjectInfo tempResult = declareTempLocal(*context.scope, retVal.typeInfo.typeRef, false); - compileAssigningOp(context, tempResult, retVal); - retVal = tempResult; - - resultSaved = true; + else if (localInfo.typeInfo.typeRef == codeScope.moduleScope->buildins.int8Reference) { + BuildNode varNode = node.appendChild(BuildKey::IntVariableAddress, it.key()); + varNode.appendChild(BuildKey::Index, localInfo.offset); } - - // unbox the temporal variable - auto key = it.key(); - if (temp.mode == TargetMode::LocalUnboxingRequired) { - unboxArgumentLocaly(context, temp, key); + else if (localInfo.typeInfo.typeRef == codeScope.moduleScope->buildins.uint8Reference) { + BuildNode varNode = node.appendChild(BuildKey::IntVariableAddress, it.key()); + varNode.appendChild(BuildKey::Index, localInfo.offset); } - else if (temp.mode == TargetMode::RefUnboxingRequired) { - temp.kind = ObjectKind::Local; - - compileAssigningOp(context, { ObjectKind::Local, temp.typeInfo, key.value2 }, temp); + else if (localInfo.typeInfo.typeRef == codeScope.moduleScope->buildins.shortReference) { + BuildNode varNode = node.appendChild(BuildKey::IntVariableAddress, it.key()); + varNode.appendChild(BuildKey::Index, localInfo.offset); } - else if (key.value1 == ObjectKind::RefLocal) { - writeObjectInfo(context, temp); - context.writer->appendNode(BuildKey::Field); - compileAssigningOp(context, - { ObjectKind::Local, temp.typeInfo, key.value2 }, - { ObjectKind::Object, temp.typeInfo, 0 }); + else if (localInfo.typeInfo.typeRef == codeScope.moduleScope->buildins.longReference) { + BuildNode varNode = node.appendChild(BuildKey::LongVariableAddress, it.key()); + varNode.appendChild(BuildKey::Index, localInfo.offset); } - else if (key.value1 == ObjectKind::FieldAddress) { - unboxArgumentLocaly(context, temp, key); + else if (localInfo.typeInfo.typeRef == codeScope.moduleScope->buildins.realReference) { + BuildNode varNode = node.appendChild(BuildKey::RealVariableAddress, it.key()); + varNode.appendChild(BuildKey::Index, localInfo.offset); } - else if (temp.mode == TargetMode::ConditionalUnboxingRequired) { - writeObjectInfo(context, { key.value1, temp.typeInfo, key.value2 }); - context.writer->newNode(BuildKey::StackCondOp); - compileAssigningOp(context, { key.value1, temp.typeInfo, key.value2 }, temp); - context.writer->closeNode(); + else if (_logic->isCompatible(*codeScope.moduleScope, + { V_INT32 }, { localInfo.typeInfo.typeRef }, false)) + { + BuildNode varNode = node.appendChild(BuildKey::IntVariableAddress, it.key()); + varNode.appendChild(BuildKey::Index, localInfo.offset); } - else compileAssigningOp(context, { key.value1, temp.typeInfo, key.value2 }, temp); - } - } + else { + BuildNode varNode = node.appendChild(BuildKey::VariableAddress, it.key()); + varNode.appendChild(BuildKey::Index, localInfo.offset); - if (updatedOuterArgs) { - if (updatedOuterArgs->count() > 0) { - if (!resultSaved && retVal.kind != ObjectKind::Unknown) { - // presave the result - ObjectInfo tempResult = declareTempLocal(*context.scope, retVal.typeInfo.typeRef, false); - compileAssigningOp(context, tempResult, retVal); - retVal = tempResult; + ustr_t className = codeScope.moduleScope->module->resolveReference(localInfo.typeInfo.typeRef); + if (isWeakReference(className)) { + IdentifierString fullName(codeScope.module->name()); + fullName.append(className); - resultSaved = true; + varNode.appendChild(BuildKey::ClassName, *fullName); + } + else varNode.appendChild(BuildKey::ClassName, className); } } - - unboxOuterArgs(context, updatedOuterArgs); - } - - context.scope->tempLocals.clear(); - - return retVal; + else { + BuildNode varNode = node.appendChild(BuildKey::Variable, it.key()); + varNode.appendChild(BuildKey::Index, localInfo.offset); + } + } } -void Compiler :: writeMessageArguments(WriterContext& context, ObjectInfo& target, - mssg_t message, ArgumentsInfo& arguments, ObjectInfo& lenLocal, int& stackSafeAttr, - bool targetOverridden, bool found, bool argUnboxingRequired, bool stackSafe) +ObjectInfo Compiler :: compileCode(BuildTreeWriter& writer, CodeScope& codeScope, SyntaxNode node, bool closureMode, bool noDebugInfoMode) { - if (targetOverridden) { - target = boxArgument(context, target, stackSafe, false, false); - } - - if (!found) - stackSafeAttr = 0; + ObjectInfo retVal = {}; + ObjectInfo exprRetVal = {}; - pos_t counter = arguments.count_pos(); - if (argUnboxingRequired) { - counter--; + // variable declaration node + writer.newNode(BuildKey::VariableInfo); + BuildNode variableNode = writer.CurrentNode(); + writer.closeNode(); - ObjectInfo lenLocal = declareTempLocal(*context.scope, context.scope->moduleScope->buildins.intReference, false); + EAttr mode = closureMode ? EAttr::RetValExpected : EAttr::None; + if (noDebugInfoMode) + mode = mode | EAttr::NoDebugInfo; - // get length - writeObjectInfo(context, arguments[counter]); - context.writer->appendNode(BuildKey::SavingInStack); - context.writer->newNode(BuildKey::VArgSOp, LEN_OPERATOR_ID); - context.writer->appendNode(BuildKey::Index, lenLocal.argument); - context.writer->closeNode(); + SyntaxNode current = node.firstChild(); + while (current != SyntaxKey::None) { + switch (current.key) { + case SyntaxKey::Expression: + exprRetVal = compileRootExpression(writer, codeScope, current, mode); + break; + case SyntaxKey::ReturnExpression: + exprRetVal = retVal = compileRetExpression(writer, codeScope, current, EAttr::None); + break; + case SyntaxKey::CodeBlock: + { + bool autoGenerated = current.existChild(SyntaxKey::Autogenerated); - context.writer->appendNode(BuildKey::LoadingIndex, lenLocal.argument); - context.writer->newNode(BuildKey::UnboxMessage, arguments[counter].argument); - context.writer->appendNode(BuildKey::Index, counter); - context.writer->closeNode(); - } + if (!noDebugInfoMode && autoGenerated) { + writer.appendNode(BuildKey::OpenStatement); + addBreakpoint(writer, findObjectNode(current.firstChild()), BuildKey::Breakpoint); + } - // box the arguments if required - int argMask = 1; - for (unsigned int i = 0; i < counter; i++) { - // NOTE : byref dynamic arg can be passed semi-directly (via temporal variable) if the method resolved directly - ObjectInfo arg = boxArgument(context, arguments[i], - test(stackSafeAttr, argMask), false, found); + CodeScope subScope(&codeScope); + exprRetVal = compileCode(writer, subScope, current, false, autoGenerated); + subScope.syncStack(&codeScope); - arguments[i] = arg; - argMask <<= 1; - } + if (!noDebugInfoMode && autoGenerated) + writer.appendNode(BuildKey::EndStatement); + break; + } + case SyntaxKey::EOP: + addBreakpoint(writer, current, BuildKey::EOPBreakpoint); + break; + default: + break; + } - if (isOpenArg(message) && !argUnboxingRequired) { - // NOTE : in case of unboxing variadic argument, the terminator is already copied - arguments.add({ ObjectKind::Terminator }); - counter++; + current = current.nextNode(); } - for (unsigned int i = counter; i > 0; i--) { - ObjectInfo arg = arguments[i - 1]; + injectVariableInfo(variableNode, codeScope); - writeObjectInfo(context, arg); - context.writer->appendNode(BuildKey::SavingInStack, i - 1); + if (_trackingUnassigned) { + // warn if the variable was not assigned + for (auto it = codeScope.locals.start(); !it.eof(); ++it) { + if ((*it).unassigned) { + if((*it).size > 0) { + warnOnUnassignedLocal(node, codeScope, -(*it).offset); + } + else warnOnUnassignedLocal(node, codeScope, (*it).offset); + } + } } + + // NOTE : in the closure mode the last statement is the closure result + return closureMode ? exprRetVal : retVal; } -bool Compiler :: validateShortCircle(ExprScope& scope, mssg_t message, ObjectInfo target) +void Compiler :: warnOnUnassignedLocal(SyntaxNode node, CodeScope& scope, int level) { - ref_t targetRef = 0; - switch (target.kind) { - case ObjectKind::Class: - targetRef = target.reference; - break; - case ObjectKind::ConstructorSelf: - targetRef = target.extra; - break; - default: - targetRef = target.typeInfo.typeRef; - break; - } + SyntaxNode current = scope.localNodes.get(level); - MethodScope* methodScope = Scope::getScope(scope, Scope::ScopeLevel::Method); - if (methodScope != nullptr) { - return (methodScope->message == message && methodScope->getClassRef() == targetRef); - } + if (current != SyntaxKey::None) + scope.raiseWarning(WARNING_LEVEL_3, wrnUnassignedVariable, current); +} - return false; +inline void clearYieldContext() +{ + // clearing yield context +// writer.appendNode(BuildKey::SavingStackDump); } -inline SyntaxNode findMessageNode(SyntaxNode node) +ObjectInfo Compiler :: mapConstructorTarget(MethodScope& scope) { - if (node == SyntaxKey::ResendDispatch) { - node = node.findChild(SyntaxKey::MessageOperation); + ObjectInfo classSymbol = mapClassSymbol(scope, scope.getClassRef()); + + if (!test(scope.message, FUNCTION_MESSAGE)) { + return { ObjectKind::ConstructorSelf, classSymbol.typeInfo, scope.selfLocal, classSymbol.reference }; } - return node.findChild(SyntaxKey::Message); + else return classSymbol; } -void Compiler :: showContextInfo(ExprScope& scope, mssg_t message, ref_t targetRef) +void Compiler :: compileMethodCode(BuildTreeWriter& writer, ClassScope* classScope, MethodScope& scope, CodeScope& codeScope, + SyntaxNode node, bool newFrame) { - IdentifierString messageName; - ByteCodeUtil::resolveMessageName(messageName, scope.module, message); + if (!newFrame) { + if (scope.checkHint(MethodHint::Multimethod)) { + compileMultidispatch(writer, codeScope, *classScope, node, false); + } - _errorProcessor->info(infoUnknownMessage, *messageName); + // new stack frame + writer.appendNode(BuildKey::OpenFrame); + newFrame = true; + } - ustr_t name = scope.module->resolveReference(targetRef); - if (!name.empty()) - _errorProcessor->info(infoTargetClass, name); + // stack should contains current self reference + // the original message should be restored if it is a generic method + scope.selfLocal = codeScope.newLocal(); + writer.appendNode(BuildKey::Assigning, scope.selfLocal); - MethodScope* methodScope = Scope::getScope(scope, Scope::ScopeLevel::Method); - if (methodScope != nullptr) { - messageName.clear(); - ByteCodeUtil::resolveMessageName(messageName, scope.module, methodScope->message); + if (scope.isYieldable()) { + Expression expression(this, codeScope, writer); - ustr_t name = scope.module->resolveReference(methodScope->getClassRef(false)); - if (!name.empty()) { - messageName.insert(".", 0); - messageName.insert(name, 0); - } + // reserve the place for the next step + int offset = allocateLocalAddress(codeScope, sizeof(addr_t), false); + + ObjectInfo contextField = classScope->mapField(YIELD_CONTEXT_FIELD, EAttr::None); - _errorProcessor->info(infoScopeMethod, *messageName); + expression.writeObjectInfo(contextField); + writer.appendNode(BuildKey::LoadingStackDump); + writer.appendNode(BuildKey::YieldDispatch, offset); + } + if (scope.isGeneric()) { + scope.messageLocalAddress = allocateLocalAddress(codeScope, sizeof(mssg_t), false); + writer.appendNode(BuildKey::SavingIndex, scope.messageLocalAddress); } -} -ObjectInfo Compiler :: compileMessageOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, ObjectInfo target, - MessageResolution resolution, ref_t implicitSignatureRef, ArgumentsInfo& arguments, ExpressionAttributes mode, ArgumentsInfo* updatedOuterArgs) -{ - bool argUnboxingRequired = EAttrs::testAndExclude(mode.attrs, EAttr::WithVariadicArg); - bool checkShortCircle = EAttrs::testAndExclude(mode.attrs, EAttr::CheckShortCircle); - bool allowPrivateCall = EAttrs::testAndExclude(mode.attrs, EAttr::AllowPrivateCall); + ObjectInfo retVal = { }; - ObjectInfo retVal(ObjectKind::Object); + SyntaxNode bodyNode = node.firstChild(SyntaxKey::ScopeMask); + switch (bodyNode.key) { + case SyntaxKey::CodeBlock: + retVal = compileCode(writer, codeScope, bodyNode, scope.closureMode); + break; + case SyntaxKey::ReturnExpression: + if (scope.isYieldable()) { + clearYieldContext(); + } + retVal = compileRetExpression(writer, codeScope, bodyNode, EAttr::None); + break; + case SyntaxKey::ResendDispatch: + retVal = compileResendCode(writer, codeScope, + scope.constructorMode ? mapConstructorTarget(scope) : scope.mapSelf(), + bodyNode); - BuildKey operation = BuildKey::CallOp; - if (!resolution.resolved) { - resolution = resolveMessageAtCompileTime(writer, target, scope, resolution.message, - implicitSignatureRef, - EAttrs::testAndExclude(mode.attrs, EAttr::NoExtension), false); - } + if (codeScope.isByRefHandler() && retVal.kind != ObjectKind::Unknown) { + Expression expression(this, codeScope, writer); - if (resolution.extensionRef) { - // if extension was found - make it a operation target - target = { ObjectKind::ConstantRole, { resolution.extensionRef }, resolution.extensionRef }; - } + expression.compileAssigning(node, codeScope.mapByRefReturnArg(), retVal); + } + else if (scope.info.outputRef != 0 && !scope.constructorMode){ + Expression expression(this, codeScope, writer); - bool functionMode = test(resolution.message, FUNCTION_MESSAGE); - if (functionMode/* && target.kind != ObjectKind::ConstantRole*/) { - resolution.stackSafeAttr >>= 1; + expression.compileConverting(node, retVal, scope.info.outputRef, + scope.checkHint(MethodHint::Stacksafe)); + } + break; + case SyntaxKey::Redirect: + retVal = compileRedirect(writer, codeScope, bodyNode); + break; + default: + break; } - else resolution.stackSafeAttr &= 0xFFFFFFFE; // exclude the stack safe target attribute, it should be set by compileMessage - ref_t targetRef = retrieveStrongType(scope, target); + // if the method returns itself + if (retVal.kind == ObjectKind::Unknown && !codeScope.withRetStatement) { + Expression expression(this, codeScope, writer); - CheckMethodResult result = {}; - bool found = target.mode != TargetMode::Weak - ? _logic->resolveCallType(*scope.moduleScope, targetRef, resolution.message, result) : false; - if (found) { - switch (result.visibility) { - case Visibility::Private: - if (allowPrivateCall || isSelfCall(target)) { - resolution.message = result.message; - } - else found = false; - break; - case Visibility::Protected: - if (isSelfCall(target) || target.kind == ObjectKind::SuperLocal) { - resolution.message = result.message; - } - else found = false; - break; - case Visibility::Internal: - if (scope.moduleScope->isInternalOp(targetRef)) { - resolution.message = result.message; - } - else found = false; - break; - default: - break; + // NOTE : extension should re + retVal = scope.mapSelf(!scope.isExtension); + if (codeScope.isByRefHandler()) { + expression.compileAssigning(node, codeScope.mapByRefReturnArg(), retVal); + } + else { + expression.compileConverting(node, retVal, scope.info.outputRef, + scope.checkHint(MethodHint::Stacksafe)); } } - if (found) { - retVal.typeInfo = { result.outputRef }; - switch ((MethodHint)result.kind) { - case MethodHint::Sealed: - if (result.constRef && _optMode) { - NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); + if (scope.isYieldable()) { + clearYieldContext(); + } - retVal = nsScope->defineObjectInfo(result.constRef, EAttr::None, true); + writer.appendNode(BuildKey::CloseFrame); - operation = BuildKey::None; - } - else operation = BuildKey::DirectCallOp; - // HOTFIX : do not box the variadic argument target for the direct operation - if (arguments[0].kind == ObjectKind::VArgParam) - result.stackSafe = true; - - if (checkShortCircle && validateShortCircle(scope, resolution.message, target)) { - if (_verbose) { - showContextInfo(scope, resolution.message, targetRef); - } + if (scope.checkHint(MethodHint::Constant)) { + ref_t constRef = generateConstant(scope, retVal, 0); + if (constRef) { + classScope->addRefAttribute(scope.message, ClassAttribute::ConstantMethod, constRef); - if (target.kind == ObjectKind::ConstructorSelf) { - scope.raiseError(errRedirectToItself, node); - } - else scope.raiseWarning(WARNING_LEVEL_1, wrnCallingItself, findMessageNode(node)); - } - - break; - case MethodHint::Virtual: - operation = BuildKey::SemiDirectCallOp; - break; - default: - break; - } - if (operation != BuildKey::CallOp) { - // if the method directly resolved and the target is not required to be dynamic, mark it as stacksafe - if (result.stackSafe && !functionMode) - resolution.stackSafeAttr |= 1; + classScope->save(); } + else scope.raiseError(errInvalidConstAttr, node); } - else if (targetRef) { - if (EAttrs::test(mode.attrs, EAttr::StrongResolved)) { - if (getAction(resolution.message) == getAction(scope.moduleScope->buildins.constructor_message)) { - scope.raiseError(errUnknownDefConstructor, node); - } - else scope.raiseError(errUnknownMessage, findMessageNode(node)); - } - else { - bool weakTarget = targetRef == scope.moduleScope->buildins.superReference || result.withCustomDispatcher || target.mode == TargetMode::Weak; +} - SyntaxNode messageNode = findMessageNode(node); - if (weakTarget/* || ignoreWarning*/) { - // ignore warning for super class / type-less one - } - else if (messageNode == SyntaxKey::None) { - if (_verbose) { - showContextInfo(scope, resolution.message, targetRef); - } +void Compiler :: compileYieldInitializing(BuildTreeWriter& writer, CodeScope& scope, SyntaxNode node) +{ + ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); - if (test(resolution.message, CONVERSION_MESSAGE)) { - scope.raiseWarning(WARNING_LEVEL_1, wrnUnknownTypecast, node); - } - else if (resolution.message == scope.moduleScope->buildins.refer_message) { - scope.raiseWarning(WARNING_LEVEL_1, wrnUnsupportedOperator, node); - } - else scope.raiseWarning(WARNING_LEVEL_1, wrnUnknownFunction, node); - } - else { - if (_verbose) { - IdentifierString messageName; - ByteCodeUtil::resolveMessageName(messageName, scope.module, resolution.message); + ObjectInfo contextField = classScope->mapField(YIELD_CONTEXT_FIELD, EAttr::None); - _errorProcessor->info(infoUnknownMessage, *messageName); + Expression expression(this, scope, writer); - ustr_t name = scope.module->resolveReference(targetRef); - if (!name.empty()) - _errorProcessor->info(infoTargetClass, name); - } + pos_t contextSize = classScope->getMssgAttribute(node.arg.reference, ClassAttribute::YieldContextSize); - scope.raiseWarning(WARNING_LEVEL_1, wrnUnknownMessage, messageNode); - } + writer.appendNode(BuildKey::NilReference); + writer.appendNode(BuildKey::SavingInStack); - // treat it as a weak reference - targetRef = 0; - } - } + writer.newNode(BuildKey::CreatingStruct, contextSize); + writer.appendNode(BuildKey::Type, scope.moduleScope->buildins.superReference); + writer.closeNode(); - if (target.kind == ObjectKind::SuperLocal) { - if (found) { - // parent methods are always sealed - operation = BuildKey::DirectCallOp; + writer.appendNode(BuildKey::SetImmediateField, 0); + + expression.compileAssigning(node, contextField, { ObjectKind::Object }, true); +} + +void Compiler :: compileInitializerMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode classNode) +{ + beginMethod(writer, scope, classNode, BuildKey::Method, false); + + CodeScope codeScope(&scope); + + // new stack frame + writer.appendNode(BuildKey::OpenFrame); + + // stack should contains current self reference + // the original message should be restored if it is a generic method + scope.selfLocal = codeScope.newLocal(); + writer.appendNode(BuildKey::Assigning, scope.selfLocal); + + SyntaxNode current = classNode.firstChild(); + while (current != SyntaxKey::None) { + if (current == SyntaxKey::AssignOperation) { + if (current.existChild(SyntaxKey::YieldContext)) { + compileYieldInitializing(writer, codeScope, current.findChild(SyntaxKey::YieldContext)); + } + else compileRootExpression(writer, codeScope, current, EAttr::None); } - else scope.raiseError(errInvalidOperation, node); + current = current.nextNode(); } - if (operation != BuildKey::None) { - WriterContext context = { &writer, &scope, node }; + codeScope.syncStack(&scope); - bool targetOverridden = (target != arguments[0]); - ObjectInfo lenLocal = {}; - writeMessageArguments(context, target, resolution.message, arguments, lenLocal, - resolution.stackSafeAttr, targetOverridden, found, argUnboxingRequired, result.stackSafe); + writer.appendNode(BuildKey::CloseFrame); - if (!targetOverridden) { - writer.appendNode(BuildKey::Argument, 0); - } - else writeObjectInfo(context, target); + endMethod(writer, scope); +} + +void Compiler :: compileStaticInitializerMethod(BuildTreeWriter& writer, ClassScope& scope, SyntaxNode node) +{ + BuildNode buildNode = writer.CurrentNode(); + while (buildNode != BuildKey::Root) + buildNode = buildNode.parentNode(); - writer.newNode(operation, resolution.message); + BuildTreeWriter nestedWriter(buildNode); - if (targetRef) - writer.appendNode(BuildKey::Type, targetRef); + nestedWriter.newNode(BuildKey::Symbol, node.arg.reference); - writer.closeNode(); + nestedWriter.newNode(BuildKey::Tape); + nestedWriter.appendNode(BuildKey::OpenFrame); - retVal = unboxArguments(context, retVal, updatedOuterArgs); + SyntaxNode current = node.firstChild(); + while (current != SyntaxKey::None) { + if (current == SyntaxKey::AssignOperation) { + Expression expression(this, scope, nestedWriter); - if (argUnboxingRequired) { - writer.appendNode(BuildKey::LoadingIndex, lenLocal.argument); - writer.appendNode(BuildKey::FreeVarStack); + expression.compileRoot(current, EAttr::None); } + current = current.nextNode(); } - scope.reserveArgs(arguments.count_pos()); + nestedWriter.appendNode(BuildKey::CloseFrame); + nestedWriter.appendNode(BuildKey::Exit); - return retVal; + nestedWriter.closeNode(); + nestedWriter.closeNode(); } -void Compiler :: addBreakpoint(BuildTreeWriter& writer, SyntaxNode node, BuildKey bpKey) +void Compiler :: compileAbstractMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode node, bool abstractMode) { - SyntaxNode terminal = node.firstChild(SyntaxKey::TerminalMask); - - SyntaxNode row = terminal.findChild(SyntaxKey::Row); - SyntaxNode col = terminal.findChild(SyntaxKey::Column); - if (row != SyntaxKey::None) { - writer.newNode(bpKey); - writer.appendNode(BuildKey::Row, row.arg.value); - writer.appendNode(BuildKey::Column, col.arg.value); - writer.closeNode(); + SyntaxNode current = node.firstChild(SyntaxKey::MemberMask); + if (current.key == SyntaxKey::WithoutBody) { + // NOTE : abstract method should not have a body + if (!abstractMode) + scope.raiseError(errNotAbstractClass, node); } + else scope.raiseError(errAbstractMethodCode, node); + + writer.newNode(BuildKey::AbstractMethod, scope.message); + writer.closeNode(); } -ObjectInfo Compiler :: compileNewArrayOp(WriterContext& context, - ObjectInfo source, ref_t targetRef, ArgumentsInfo& arguments) +void Compiler :: compileMultidispatch(BuildTreeWriter& writer, CodeScope& scope, ClassScope& classScope, + SyntaxNode node, bool implicitMode) { - ref_t sourceRef = retrieveStrongType(*context.scope, source); + mssg_t message = scope.getMessageID(); - //if (!targetRef) - // targetRef = resolvePrimitiveReference(scope, source.type, source.element, false); + BuildKey op = BuildKey::DispatchingOp; + ref_t opRef = classScope.info.attributes.get({ message, ClassAttribute::OverloadList }); + if (!opRef) + scope.raiseError(errIllegalOperation, node); - ref_t argumentRefs[ARG_COUNT] = {}; - pos_t argLen = 0; - for (pos_t i = 0; i < arguments.count(); i++) { - argumentRefs[argLen++] = retrieveStrongType(*context.scope, arguments[i]); + if (test(classScope.info.header.flags, elSealed) || test(message, STATIC_MESSAGE)) { + op = BuildKey::SealedDispatchingOp; } - BuildKey operationKey = _logic->resolveNewOp(*context.scope->moduleScope, sourceRef, argumentRefs, argLen); - if (operationKey == BuildKey::NewArrayOp) { - auto sizeInfo = _logic->defineStructSize(*context.scope->moduleScope, sourceRef); + writer.newNode(op, opRef); + writer.appendNode(BuildKey::Message, message); + writer.closeNode(); - if (targetRef) { - NamespaceScope* nsScope = Scope::getScope(*context.scope, Scope::ScopeLevel::Namespace); + if (implicitMode) { + // if it is an implicit mode (auto generated multi-method) + if (classScope.extensionDispatcher) { + writer.appendNode(BuildKey::Argument, 0); - auto conversionRoutine = _logic->retrieveConversionRoutine(this, *context.scope->moduleScope, *nsScope->nsName, - targetRef, source.typeInfo); - if (conversionRoutine.result == ConversionResult::BoxingRequired) { - source.typeInfo = { targetRef }; - } - else source.typeInfo = { sourceRef }; + writer.newNode(BuildKey::RedirectOp, node.arg.reference); + writer.closeNode(); } - else source.typeInfo = { sourceRef }; - - assert(arguments.count() == 1); // !! temporally - only one argument is supported - - writeObjectInfo(context, arguments[0]); - context.writer->appendNode(BuildKey::SavingInStack, 0); - - assert(!source.typeInfo.isPrimitive()); - - context.writer->newNode(operationKey, source.typeInfo.typeRef); - - if (sizeInfo.size < 0) - context.writer->appendNode(BuildKey::Size, sizeInfo.size); - - context.writer->closeNode(); + else if (node.arg.reference) { + // if it is a special case of the multimethod - conversion dispatcher + // the argument should be typecasted + if (getArgCount(message) == 1 && getAction(message) == getAction(scope.moduleScope->buildins.constructor_message)) { + writer.appendNode(BuildKey::Argument); + } - // fill the array - if (!sizeInfo.size) { - context.writer->appendNode(BuildKey::FillOp); + writer.appendNode(BuildKey::RedirectOp, node.arg.reference); } + else { + SyntaxNode targetNode = node.findChild(SyntaxKey::Target); + assert(targetNode != SyntaxKey::None); - return { ObjectKind::Object, source.typeInfo, 0 }; + writer.newNode(BuildKey::StrongRedirectOp, message); + writer.appendNode(BuildKey::Type, targetNode.arg.reference); + writer.closeNode(); + } } - - context.scope->raiseError(errInvalidOperation, context.node); - - return {}; // !! temporal } -ObjectInfo Compiler :: compileNativeConversion(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, ObjectInfo source, ref_t operationKey) +ObjectInfo Compiler :: compileRedirect(BuildTreeWriter& writer, CodeScope& codeScope, SyntaxNode node) { - ObjectInfo retVal = {}; - WriterContext context = { &writer, &scope, node }; - - source = boxArgumentLocally(context, source, false, false); - - switch (operationKey) { - case INT8_32_CONVERSION: - retVal = allocateResult(scope, resolvePrimitiveType(scope, { V_INT32 }, false)); - - writeObjectInfo(context, retVal); - writer.appendNode(BuildKey::SavingInStack, 0); - - writeObjectInfo(context, source); - - writer.appendNode(BuildKey::ConversionOp, operationKey); - break; - case INT16_32_CONVERSION: - retVal = allocateResult(scope, resolvePrimitiveType(scope, { V_INT32 }, false)); + Expression expression(this, codeScope, writer); + ArgumentsInfo arguments; + ArgumentsInfo updatedOuterArgs; - writeObjectInfo(context, retVal); - writer.appendNode(BuildKey::SavingInStack, 0); + ObjectInfo target = expression.compile(node.firstChild(), 0, EAttr::Parameter, &updatedOuterArgs); - writeObjectInfo(context, source); + mssg_t messageRef = codeScope.getMessageID(); - writer.appendNode(BuildKey::ConversionOp, operationKey); - break; - case INT32_64_CONVERSION: - retVal = allocateResult(scope, resolvePrimitiveType(scope, { V_INT64 }, false) ); + if (!test(messageRef, FUNCTION_MESSAGE)) + arguments.add(target); - writeObjectInfo(context, retVal); - writer.appendNode(BuildKey::SavingInStack, 0); + MethodScope* methodScope = Scope::getScope(codeScope, Scope::ScopeLevel::Method); - writeObjectInfo(context, source); + for (auto it = methodScope->parameters.start(); !it.eof(); ++it) { + arguments.add(methodScope->mapParameter(it.key(), EAttr::None)); + } - writer.appendNode(BuildKey::ConversionOp, operationKey); - break; - case INT32_FLOAT64_CONVERSION: - retVal = allocateResult(scope, resolvePrimitiveType(scope, { V_FLOAT64 }, false)); + ref_t signRef = getSignature(codeScope.module, messageRef); - writeObjectInfo(context, retVal); - writer.appendNode(BuildKey::SavingInStack, 0); + MessageResolution resolution = { true, messageRef }; + _logic->setSignatureStacksafe(*codeScope.moduleScope, signRef, resolution.stackSafeAttr); - writeObjectInfo(context, source); + ObjectInfo retVal = expression.compileMessageOperation({}, target, resolution, + signRef, arguments, EAttr::None, & updatedOuterArgs); - writer.appendNode(BuildKey::ConversionOp, operationKey); - break; - default: - scope.raiseError(errInvalidOperation, node); - break; - } + expression.scope.syncStack(); return retVal; } -ObjectInfo Compiler :: compileNewOp(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, ObjectInfo source, - ref_t signRef, ArgumentsInfo& arguments) +ObjectInfo Compiler :: compileResendCode(BuildTreeWriter& writer, CodeScope& codeScope, ObjectInfo source, SyntaxNode node) { - mssg_t messageRef = 0; - if (source.kind == ObjectKind::ConstantLiteral) { - IdentifierString valueStr(scope.module->resolveConstant(source.reference)); - IdentifierString postfix; + ObjectInfo retVal = {}; - postfix.append(valueStr[valueStr.length() - 1]); - valueStr.truncate(valueStr.length() - 1); + if (!node.arg.reference) { + bool propertyMode = node.firstChild().key == SyntaxKey::PropertyOperation; - arguments.add({ ObjectKind::StringLiteral, - { scope.moduleScope->buildins.literalReference }, scope.module->mapConstant(*valueStr) }); + SyntaxNode current = node.firstChild().firstChild(); + bool superMode = false; + while (current == SyntaxKey::Attribute) { + if (!_logic->validateResendAttribute(current.arg.reference, superMode)) { + codeScope.raiseWarning(WARNING_LEVEL_1, wrnInvalidHint, current); + } + current = current.nextNode(); + } - postfix.append(CONSTRUCTOR_MESSAGE); + ObjectInfo target = source; + if (superMode) { + switch (source.kind) { + case ObjectKind::SelfLocal: + source.kind = ObjectKind::SuperLocal; + target = source; + break; + case ObjectKind::ConstructorSelf: + case ObjectKind::Class: + case ObjectKind::ClassSelf: + { + // NOTE : for the constructor redirect - use the class parent as a target (still keeping the original class + // as a parameter) + ClassInfo classInfo; + if (_logic->defineClassInfo(*codeScope.moduleScope, classInfo, + source.kind == ObjectKind::ConstructorSelf ? source.extra : source.reference, + true)) + { + ObjectInfo temp = mapClassSymbol(codeScope, classInfo.header.parentRef); + if (source.kind == ObjectKind::ConstructorSelf) { + target.typeInfo = temp.typeInfo; + target.extra = temp.reference; + } + else target = temp; + } + else codeScope.raiseError(errInvalidOperation, node); + break; + } + default: + codeScope.raiseError(errInvalidOperation, node); + break; + } + } - ref_t signRef = scope.module->mapSignature(&scope.moduleScope->buildins.literalReference, 1, false); - mssg_t conversionMssg = encodeMessage(scope.module->mapAction(*postfix, signRef, false), 1, FUNCTION_MESSAGE); + Expression expression(this, codeScope, writer); + ArgumentsInfo arguments; + ArgumentsInfo updatedOuterArgs; - NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - auto constInfo = nsScope->extensions.get(conversionMssg); - if (constInfo.value1) { - messageRef = constInfo.value2; - source = mapClassSymbol(scope, constInfo.value1); - } - else scope.raiseError(errInvalidOperation, node); - } - else messageRef = overwriteArgCount(scope.moduleScope->buildins.constructor_message, arguments.count_pos()); + mssg_t messageRef = mapMessage(codeScope, current, propertyMode, codeScope.isExtension(), false); - ObjectInfo retVal = compileMessageOperation( - writer, scope, node, source, messageRef, signRef, arguments, EAttr::StrongResolved | EAttr::NoExtension, nullptr); + mssg_t resolvedMessage = _logic->resolveSingleDispatch(*codeScope.moduleScope, + retrieveType(codeScope, source), messageRef); - if (arguments.count_pos() < 2 && (source.kind == ObjectKind::Class || source.kind == ObjectKind::ClassSelf)) { - pos_t argCount = arguments.count_pos() + 1; - ref_t signature[2] = { source.reference, 0}; - if (argCount == 2) - signature[1] = retrieveStrongType(scope, arguments[0]); + ref_t expectedSignRef = 0; + if (resolvedMessage) + codeScope.module->resolveAction(getAction(resolvedMessage), expectedSignRef); - mssg_t inplaceMessage = encodeMessage( - scope.module->mapAction(CONSTRUCTOR_MESSAGE, - scope.module->mapSignature(signature, argCount, false), false), argCount, STATIC_MESSAGE); + if (!test(messageRef, FUNCTION_MESSAGE)) + arguments.add(source); - CheckMethodResult result = {}; - if (_logic->resolveCallType(*scope.moduleScope, - retrieveStrongType(scope, source), inplaceMessage, result)) - { - writer.appendNode(BuildKey::InplaceCall, result.message); + bool withVariadicArg = false; + ref_t implicitSignatureRef = expression.compileMessageArguments(current, arguments, expectedSignRef, + EAttr::NoPrimitives, &updatedOuterArgs, withVariadicArg); + + EAttr opMode = EAttr::CheckShortCircle; + if (withVariadicArg) { + messageRef |= VARIADIC_MESSAGE; + + opMode = opMode | EAttr::WithVariadicArg; } + + retVal = expression.compileMessageOperation(node, target, messageRef, + implicitSignatureRef, arguments, opMode, &updatedOuterArgs); + + expression.scope.syncStack(); } + else assert(false); - // HOTFIX : to use weak reference for the created class - retVal.typeInfo = { source.reference }; + SyntaxNode current = node.nextNode(); + if (current == SyntaxKey::CodeBlock) { + MethodScope* methodScope = Scope::getScope(codeScope, Scope::ScopeLevel::Method); + if (methodScope->constructorMode) { + // HOTFIX : overwrite self variable for the redirect constructor code + + // stack should contains current self reference + // the original message should be restored if it is a generic method + writer.appendNode(BuildKey::Assigning, methodScope->selfLocal); + } + + retVal = compileCode(writer, codeScope, current, methodScope->closureMode); + } return retVal; } -bool invalidObjectMode(ObjectInfo info) +void Compiler :: compileDispatchCode(BuildTreeWriter& writer, CodeScope& codeScope, SyntaxNode node) { - switch (info.mode) { - case TargetMode::None: - case TargetMode::Conditional: - case TargetMode::Weak: - return false; - default: - return true; - } + ClassScope* classScope = Scope::getScope(codeScope, Scope::ScopeLevel::Class); + + compileMultidispatch(writer, codeScope, *classScope, node, true); } -ObjectInfo Compiler :: compilePropertyOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, - ref_t expectedRef, ExpressionAttribute attrs) +void Compiler :: compileConstructorDispatchCode(BuildTreeWriter& writer, CodeScope& codeScope, + ClassScope& classClassScope, SyntaxNode node) { - ObjectInfo retVal = { }; - ArgumentsInfo arguments; - ArgumentsInfo outerArgsToUpdate; - - SyntaxNode current = node.firstChild(); - ObjectInfo source = compileObject(writer, scope, current, EAttr::Parameter, &outerArgsToUpdate); - if (invalidObjectMode(source)) - scope.raiseError(errInvalidOperation, node); + compileMultidispatch(writer, codeScope, classClassScope, node, true); +} - arguments.add(source); +void Compiler :: compileDirectResendCode(BuildTreeWriter& writer, CodeScope& codeScope, SyntaxNode node) +{ + mssg_t dispatchMessage = node.arg.reference; - // NOTE : the operation target shouldn't be a primtive type - source = validateObject(writer, scope, node, source, 0, true, true, false); + SyntaxNode targetNode = node.findChild(SyntaxKey::Target); + ref_t disptachTarget = targetNode.arg.reference; + if (!disptachTarget) + assert(false); - current = current.nextNode(); - mssg_t messageRef = mapMessage(scope, current, true, - source.kind == ObjectKind::Extension, false); + writer.newNode(BuildKey::StrongRedirectOp, dispatchMessage); + writer.appendNode(BuildKey::Type, disptachTarget); + writer.closeNode(); +} - mssg_t resolvedMessage = _logic->resolveSingleDispatch(*scope.moduleScope, - retrieveType(scope, source), messageRef); +void Compiler :: compileDispatchProberCode(BuildTreeWriter& writer, CodeScope& scope, SyntaxNode node) +{ + ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); - bool variadicArgList = false; - ref_t expectedSignRef = 0; - if (resolvedMessage) - scope.module->resolveAction(getAction(resolvedMessage), expectedSignRef); + mssg_t message = scope.getMessageID(); + mssg_t dispatchMessage = node.arg.reference; - ref_t implicitSignatureRef = compileMessageArguments(writer, scope, current, arguments, expectedSignRef, EAttr::NoPrimitives, - &outerArgsToUpdate, variadicArgList); - EAttr opMode = EAttr::None; - if (variadicArgList) { - // HOTFIX : set variadic flag if required - messageRef |= VARIADIC_MESSAGE; + BuildKey op = BuildKey::DispatchingOp; + ref_t opRef = classScope->info.attributes.get({ dispatchMessage, ClassAttribute::OverloadList }); + if (!opRef) + scope.raiseError(errIllegalOperation, node); - opMode = EAttr::WithVariadicArg; + if (test(classScope->info.header.flags, elSealed) || test(dispatchMessage, STATIC_MESSAGE)) { + op = BuildKey::SealedDispatchingOp; } - auto byRefResolution = resolveByRefHandler(writer, source, scope, expectedRef, - messageRef, implicitSignatureRef, EAttrs::test(attrs, EAttr::NoExtension)); - if (byRefResolution.resolved) { - ObjectInfo tempRetVal = declareTempLocal(scope, expectedRef, false); - - addByRefRetVal(arguments, tempRetVal); - if (tempRetVal.kind == ObjectKind::TempLocalAddress) - writer.appendNode(BuildKey::ByRefOpMark, tempRetVal.argument); - - compileMessageOperation(writer, scope, node, source, byRefResolution, - implicitSignatureRef, arguments, opMode, &outerArgsToUpdate); + writer.newNode(op, opRef); + writer.appendNode(BuildKey::Message, dispatchMessage); + writer.closeNode(); - retVal = tempRetVal; + SyntaxNode targetNode = node.findChild(SyntaxKey::Target); + if (targetNode != SyntaxKey::None) { + writer.newNode(BuildKey::StrongRedirectOp, message); + writer.appendNode(BuildKey::Type, targetNode.arg.reference); + writer.closeNode(); } - else retVal = compileMessageOperation(writer, scope, node, source, { messageRef }, - implicitSignatureRef, arguments, opMode, &outerArgsToUpdate); + else { + writer.appendNode(BuildKey::AccSwapping, 1); - return retVal; + // get feedback arg + writer.appendNode(BuildKey::RedirectOp, overwriteArgCount(scope.moduleScope->buildins.invoke_message, 2)); + } } -Compiler::MessageResolution Compiler :: resolveByRefHandler(BuildTreeWriter& writer, ObjectInfo source, ExprScope& scope, ref_t expectedRef, - mssg_t weakMessage, ref_t& signatureRef, bool noExtensions) +mssg_t Compiler :: declareInplaceConstructorHandler(MethodScope& invokerScope, ClassScope& classClassScope) { - if (source.mode == TargetMode::Weak) - return {}; - - ref_t targetRef = retrieveStrongType(scope, source); + ClassScope* classScope = Scope::getScope(invokerScope, Scope::ScopeLevel::Class); - pos_t argCount = 0; - ref_t actionRef = 0, flags = 0; - decodeMessage(weakMessage, actionRef, argCount, flags); + ref_t actionRef, flags; + pos_t argCount; + decodeMessage(invokerScope.message, actionRef, argCount, flags); - // HOTFIX : ignore variadic message - if ((flags & PREFIX_MESSAGE_MASK) == VARIADIC_MESSAGE) - return {}; + flags &= ~FUNCTION_MESSAGE; - if (expectedRef != 0 && targetRef != 0) { - // try to resolve the weak message - MessageResolution resolution = resolveMessageAtCompileTime(writer, source, scope, weakMessage, - signatureRef, noExtensions, true); + ref_t signRef = 0; + ustr_t actionName = invokerScope.module->resolveAction(actionRef, signRef); + ref_t signArgs[ARG_COUNT]; + size_t signLen = invokerScope.module->resolveSignature(signRef, signArgs); - if (resolution.resolved || argCount == 1) { - ref_t resolvedFlags = resolution.resolved ? getFlags(resolution.message) : flags; + // insert a struct variable + for (size_t i = signLen; i > 0; i--) + signArgs[i] = signArgs[i - 1]; - // check if there is a byref handler for the resolved message or the message has no arguments - ref_t resolvedSignRef = 0; - ustr_t actionName = scope.module->resolveAction(getAction(resolution.message), resolvedSignRef); + signArgs[0] = classScope->reference; + signLen++; - ref_t byRefType = retrieveStrongType(scope, { ObjectKind::Object, { V_WRAPPER, expectedRef }, 0 }); - ref_t byRefSignature = _logic->defineByRefSignature(*scope.moduleScope, resolvedSignRef, byRefType); + mssg_t inplaceMessage = encodeMessage( + invokerScope.module->mapAction( + actionName, invokerScope.module->mapSignature(signArgs, signLen, false), false), argCount + 1, flags | STATIC_MESSAGE); - ref_t byRefMessage = encodeMessage(scope.module->mapAction(actionName, byRefSignature, false), argCount + 1, resolvedFlags); + if (MethodScope::checkHint(invokerScope.info, MethodHint::Protected)) { + mssg_t publicInplaceMessage = encodeMessage( + invokerScope.module->mapAction( + CONSTRUCTOR_MESSAGE, invokerScope.module->mapSignature(signArgs, signLen, false), false), argCount + 1, flags | STATIC_MESSAGE); - ref_t byRefTarget = resolution.extensionRef ? resolution.extensionRef : targetRef; - CheckMethodResult dummy = {}; - if (_logic->resolveCallType(*scope.moduleScope, byRefTarget, byRefMessage, dummy)) { - // NOTE : the original signature is extended with byref handler - signatureRef = _logic->defineByRefSignature(*scope.moduleScope, signatureRef, byRefType);; + classClassScope.addMssgAttribute(publicInplaceMessage, + ClassAttribute::ProtectedAlias, inplaceMessage); + } - resolution.resolved = true; - resolution.message = byRefMessage; + MethodInfo info = { }; - // NOTE : the stack safe attributes are resolved again the target signature - _logic->setSignatureStacksafe(*scope.moduleScope, byRefSignature, resolution.stackSafeAttr); + info.hints |= (ref_t)MethodHint::Private; + info.hints |= (ref_t)MethodHint::Sealed; + info.hints |= (ref_t)MethodHint::Stacksafe; - return resolution; - } - } - else if (signatureRef) { - // otherwise check if there is a byref handler if at lease a signature exists - ref_t dummySignRef = 0; - ustr_t actionName = scope.module->resolveAction(actionRef, dummySignRef); + classClassScope.info.methods.add(inplaceMessage, info); + classClassScope.save(); - ref_t byRefType = retrieveStrongType(scope, { ObjectKind::Object, { V_WRAPPER, expectedRef }, 0 }); - ref_t byRefSignature = _logic->defineByRefSignature(*scope.moduleScope, signatureRef, byRefType); + return inplaceMessage; +} - ref_t byRefMessage = encodeMessage(scope.module->mapAction(actionName, byRefSignature, false), argCount + 1, flags); +mssg_t Compiler :: compileInplaceConstructorHandler(BuildTreeWriter& writer, MethodScope& invokerScope, ClassScope& classClassScope, + SyntaxNode current, SyntaxNode methodNode, mssg_t byRefMessage) +{ + ClassScope* classScope = Scope::getScope(invokerScope, Scope::ScopeLevel::Class); - CheckMethodResult dummy = {}; - if (_logic->resolveCallType(*scope.moduleScope, targetRef, byRefMessage, dummy)) { - // NOTE : the original signature is extended with byref handler - signatureRef = _logic->defineByRefSignature(*scope.moduleScope, signatureRef, byRefType);; + MethodScope privateScope(classScope); + // copy parameters + for (auto it = invokerScope.parameters.start(); !it.eof(); ++it) { + privateScope.parameters.add(it.key(), *it); + } - resolution.resolved = true; - resolution.message = byRefMessage; + privateScope.info = classClassScope.info.methods.get(byRefMessage); - // NOTE : the stack safe attributes are resolved again the target signature - _logic->setSignatureStacksafe(*scope.moduleScope, byRefSignature, resolution.stackSafeAttr); + privateScope.message = byRefMessage | STATIC_MESSAGE; + privateScope.info.hints |= (ref_t)MethodHint::Private; + privateScope.info.hints |= (ref_t)MethodHint::Sealed; + privateScope.info.hints |= (ref_t)MethodHint::Stacksafe; - return resolution; - } - } - } + privateScope.byRefReturnMode = true; + privateScope.nestedMode = invokerScope.nestedMode; + privateScope.functionMode = false; + privateScope.isEmbeddable = _logic->isEmbeddableStruct(classScope->info); + privateScope.constructorMode = true; - return {}; -} + // NOTE self local is a first argument + privateScope.selfLocal = -1; -ObjectInfo Compiler :: compileMessageOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, - ref_t expectedRef, ExpressionAttribute attrs) -{ - ObjectInfo retVal = { }; - ArgumentsInfo arguments; - ArgumentsInfo updatedOuterArgs; + CodeScope codeScope(&privateScope); + beginMethod(writer, privateScope, methodNode, BuildKey::Method, true); + writer.appendNode(BuildKey::OpenFrame); - SyntaxNode current = node.firstChild(); - ObjectInfo source = compileObject(writer, scope, current, EAttr::Parameter, &updatedOuterArgs); - bool probeMode = source.mode == TargetMode::Probe; - switch (source.mode) { - case TargetMode::External: - case TargetMode::WinApi: - { - bool dummy = false; - compileMessageArguments(writer, scope, current, arguments, 0, EAttr::None, nullptr, dummy); - if (dummy) - scope.raiseError(errInvalidOperation, current); + if (methodNode.existChild(SyntaxKey::FillingAttr)) { + Expression expression(this, codeScope, writer); - WriterContext context = { &writer, &scope, current }; - retVal = compileExternalOp(context, source.reference, - source.mode == TargetMode::WinApi, arguments, expectedRef); - break; - } - case TargetMode::CreatingArray: - { - bool dummy = false; - compileMessageArguments(writer, scope, current, arguments, 0, EAttr::NoPrimitives, nullptr, dummy); - if (dummy) - scope.raiseError(errInvalidOperation, current); + expression.writeObjectInfo(privateScope.mapSelf()); + fillObject(writer, classScope->info, invokerScope.moduleScope->ptrSize); + } + if (classScope->info.methods.exist(invokerScope.moduleScope->buildins.init_message)) { + Expression expression(this, codeScope, writer); - WriterContext context = { &writer, &scope, current }; - retVal = compileNewArrayOp(context, source, expectedRef, arguments); - break; - } - case TargetMode::Creating: - { - bool dummy = false; - ref_t signRef = compileMessageArguments(writer, scope, current, arguments, 0, EAttr::NoPrimitives, nullptr, dummy); - if (dummy) - scope.raiseError(errInvalidOperation, current); + expression.writeObjectInfo(privateScope.mapSelf()); + + compileInlineInitializing(writer, *classScope, methodNode); + } - retVal = compileNewOp(writer, scope, node, mapClassSymbol(scope, - retrieveStrongType(scope, source)), signRef, arguments); + switch (current.key) { + case SyntaxKey::CodeBlock: + compileCode(writer, codeScope, current, false); break; - } - case TargetMode::Casting: - { - bool dummy = false; - compileMessageArguments(writer, scope, current, arguments, 0, EAttr::NoPrimitives, nullptr, dummy); - if (arguments.count() == 1 && !dummy) { - retVal = convertObject(writer, scope, current, arguments[0], retrieveStrongType(scope, source), false, true); - } - else scope.raiseError(errInvalidOperation, node); + case SyntaxKey::None: break; - } default: - { - // NOTE : the operation target shouldn't be a primtive type - source = validateObject(writer, scope, node, source, 0, true, true, false); - - current = current.nextNode(); - mssg_t messageRef = mapMessage(scope, current, false, - source.kind == ObjectKind::Extension, probeMode); + assert(false); + break; + } - if (!test(messageRef, FUNCTION_MESSAGE)) - arguments.add(source); + codeScope.syncStack(&privateScope); + writer.appendNode(BuildKey::CloseFrame); + endMethod(writer, privateScope); - mssg_t resolvedMessage = source.mode != TargetMode::Weak ? _logic->resolveSingleDispatch(*scope.moduleScope, - retrieveType(scope, source), messageRef) : 0; + return privateScope.message; +} - ref_t expectedSignRef = 0; - if (resolvedMessage) - scope.module->resolveAction(getAction(resolvedMessage), expectedSignRef); +mssg_t Compiler :: compileByRefHandler(BuildTreeWriter& writer, MethodScope& invokerScope, SyntaxNode node, mssg_t byRefHandler) +{ + ClassScope* classScope = Scope::getScope(invokerScope, Scope::ScopeLevel::Class); - bool withVariadicArg = false; - ref_t implicitSignatureRef = compileMessageArguments(writer, scope, current, arguments, expectedSignRef, EAttr::NoPrimitives, - &updatedOuterArgs, withVariadicArg); + MethodScope privateScope(classScope); + // copy parameters + for (auto it = invokerScope.parameters.start(); !it.eof(); ++it) { + privateScope.parameters.add(it.key(), *it); + } - EAttr opMode = EAttr::None; - if (withVariadicArg) { - messageRef |= VARIADIC_MESSAGE; + // add byref return arg + TypeInfo refType = { V_WRAPPER, invokerScope.info.outputRef }; + auto sizeInfo = _logic->defineStructSize(*invokerScope.moduleScope, resolvePrimitiveType(invokerScope, refType, false)); - opMode = EAttr::WithVariadicArg; - } + int offset = invokerScope.parameters.count() + 1u; + privateScope.parameters.add(RETVAL_ARG, { offset, refType, sizeInfo.size }); - auto byRefResolution = resolveByRefHandler(writer, source, scope, expectedRef, messageRef, implicitSignatureRef, - EAttrs::test(attrs, EAttr::NoExtension)); - if (byRefResolution.resolved) { - ObjectInfo tempRetVal = declareTempLocal(scope, expectedRef, false); + privateScope.message = byRefHandler | STATIC_MESSAGE; + privateScope.info.hints |= (ref_t)MethodHint::Private; + privateScope.info.hints |= (ref_t)MethodHint::Sealed; - addByRefRetVal(arguments, tempRetVal); - // adding mark for optimization routine - if (tempRetVal.kind == ObjectKind::TempLocalAddress) - writer.appendNode(BuildKey::ByRefOpMark, tempRetVal.argument); + // HOTFIX : mark it as stacksafe if required + if (_logic->isEmbeddableStruct(classScope->info)) + privateScope.info.hints |= (ref_t)MethodHint::Stacksafe; - compileMessageOperation(writer, scope, node, source, byRefResolution, - implicitSignatureRef, arguments, opMode, &updatedOuterArgs); + privateScope.byRefReturnMode = true; + privateScope.nestedMode = invokerScope.nestedMode; + privateScope.functionMode = invokerScope.functionMode; + privateScope.isEmbeddable = invokerScope.isEmbeddable; - retVal = tempRetVal; - } - else retVal = compileMessageOperation(writer, scope, node, source, messageRef, - implicitSignatureRef, arguments, opMode, &updatedOuterArgs); + classScope->info.methods.add(privateScope.message, privateScope.info); + classScope->save(); - break; - } - } + compileMethod(writer, privateScope, node); - return retVal; + return privateScope.message; } -bool Compiler :: resolveAutoType(ExprScope& scope, ObjectInfo source, ObjectInfo& target) +void Compiler::compileByRefRedirectHandler(BuildTreeWriter& writer, MethodScope& invokerScope, SyntaxNode node, + mssg_t byRefHandler) { - ref_t sourceRef = retrieveStrongType(scope, source); + ClassScope* classScope = Scope::getScope(invokerScope, Scope::ScopeLevel::Class); - if (!_logic->validateAutoType(*scope.moduleScope, sourceRef)) - return false; + MethodScope redirectScope(classScope); + // copy parameters + for (auto it = invokerScope.parameters.start(); !it.eof(); ++it) { + redirectScope.parameters.add(it.key(), *it); + } - return scope.resolveAutoType(target, source.typeInfo); -} + // add byref return arg + TypeInfo refType = { V_WRAPPER, invokerScope.info.outputRef }; + auto sizeInfo = _logic->defineStructSize(*invokerScope.moduleScope, resolvePrimitiveType(invokerScope, refType, false)); -bool Compiler :: compileAssigningOp(WriterContext& context, ObjectInfo target, ObjectInfo exprVal) -{ - BuildKey operationType = BuildKey::None; - int operand = 0; + int offset = invokerScope.parameters.count() + 1u; + redirectScope.parameters.add(RETVAL_ARG, { offset, refType, sizeInfo.size }); - int size = 0; - bool stackSafe = false; - bool fieldMode = false; - bool fieldFieldMode = false; - bool accMode = false; - bool lenRequired = false; + redirectScope.message = byRefHandler; - switch (target.kind) { - case ObjectKind::Local: - case ObjectKind::TempLocal: - context.scope->markAsAssigned(target); - operationType = BuildKey::Assigning; - operand = target.reference; - break; - case ObjectKind::ByRefParam: - operationType = BuildKey::RefParamAssigning; - operand = target.reference; - break; - case ObjectKind::SelfBoxableLocal: - case ObjectKind::ParamAddress: - accMode = true; - operationType = BuildKey::CopyingToAcc; - operand = target.reference; - size = _logic->defineStructSize(*context.scope->moduleScope, target.typeInfo.typeRef).size; - stackSafe = true; - break; - case ObjectKind::TempLocalAddress: - case ObjectKind::LocalAddress: - context.scope->markAsAssigned(target); - size = _logic->defineStructSize(*context.scope->moduleScope, target.typeInfo.typeRef).size; - if (size > 0) { - operationType = BuildKey::Copying; - operand = target.reference; - } - else { - lenRequired = true; - accMode = true; - operationType = BuildKey::CopyingArr; - size = -size; - } - stackSafe = true; - break; - case ObjectKind::Field: - context.scope->markAsAssigned(target); - operationType = BuildKey::FieldAssigning; - operand = target.reference; - fieldMode = true; - break; - case ObjectKind::OuterField: - context.scope->markAsAssigned(target); - operationType = BuildKey::FieldAssigning; - operand = target.extra; - fieldFieldMode = fieldMode = true; - break; - case ObjectKind::StaticField: - context.scope->markAsAssigned(target); - operationType = BuildKey::StaticAssigning; - operand = target.reference; - break; - case ObjectKind::FieldAddress: - context.scope->markAsAssigned(target); - fieldMode = true; - if (target.reference) { - operationType = BuildKey::CopyingToAccField; - operand = target.reference; - } - else operationType = BuildKey::CopyingToAccExact; - operand = target.reference; - size = _logic->defineStructSize(*context.scope->moduleScope, target.typeInfo.typeRef).size; - if (size < 0) { - size = target.extra; - } - stackSafe = true; + // HOTFIX : mark it as stacksafe if required + if (_logic->isEmbeddableStruct(classScope->info)) + redirectScope.info.hints |= (ref_t)MethodHint::Stacksafe; - assert(size > 0); + redirectScope.nestedMode = invokerScope.nestedMode; + redirectScope.functionMode = invokerScope.functionMode; + redirectScope.isEmbeddable = invokerScope.isEmbeddable; - break; - // NOTE : it should be the last condition - case ObjectKind::ByRefParamAddress: - { - ref_t targetRef = retrieveStrongType(*context.scope, target); - size = _logic->defineStructSize(*context.scope->moduleScope, targetRef).size; - if (size > 0) { - stackSafe = true; - operationType = BuildKey::CopyingToAcc; - operand = target.reference; - accMode = true; - } - else assert(false); // !! temporally + classScope->info.methods.add(redirectScope.message, redirectScope.info); + classScope->save(); - break; - } - case ObjectKind::Outer: - { - InlineClassScope* closure = Scope::getScope(*context.scope, Scope::ScopeLevel::Class); - if (/*!method->subCodeMode || */!closure->markAsPresaved(target)) - return false; + compileMethod(writer, redirectScope, node); +} - operationType = BuildKey::FieldAssigning; - operand = target.reference; - fieldMode = true; +void Compiler :: compileByRefHandlerInvoker(BuildTreeWriter& writer, MethodScope& methodScope, CodeScope& codeScope, mssg_t handler, ref_t targetRef) +{ + writer.appendNode(BuildKey::OpenFrame); - break; - } - default: - return false; - } + // stack should contains current self reference + // the original message should be restored if it is a generic method + methodScope.selfLocal = codeScope.newLocal(); + writer.appendNode(BuildKey::Assigning, methodScope.selfLocal); - writeObjectInfo(context, - boxArgument(context, exprVal, stackSafe, true, false)); + // calling the byref handler + Expression expression(this, codeScope, writer); + ArgumentsInfo arguments; - if (fieldMode) { - context.writer->appendNode(BuildKey::SavingInStack, 0); - writeObjectInfo(context, context.scope->mapSelf()); - if (fieldFieldMode) - context.writer->appendNode(BuildKey::Field, target.reference); + ObjectInfo tempRetVal = expression.declareTempLocal(targetRef, false); + + ObjectInfo target = methodScope.mapSelf(); + MessageResolution resolution = { true, handler }; + if (methodScope.isExtension) { + resolution.extensionRef = methodScope.getClassRef(); } - else if (accMode) { - if(lenRequired) - context.writer->appendNode(BuildKey::LoadingBinaryLen, size); + else arguments.add(target); - context.writer->appendNode(BuildKey::SavingInStack, 0); - writeObjectInfo(context, target); + for (auto it = methodScope.parameters.start(); !it.eof(); ++it) { + arguments.add(methodScope.mapParameter(it.key(), EAttr::None)); } + addByRefRetVal(arguments, tempRetVal); - context.writer->newNode(operationType, operand); - if (size != 0) { - context.writer->appendNode(BuildKey::Size, size); + ref_t signRef = getSignature(codeScope.module, handler); + _logic->setSignatureStacksafe(*codeScope.moduleScope, signRef, resolution.stackSafeAttr); - // HOTFIX : nil cannit be assigned to a struct - if (exprVal.kind == ObjectKind::Nil) - context.scope->raiseError(errInvalidOperation, context.node); - } - context.writer->closeNode(); + /*ObjectInfo retVal = */expression.compileMessageOperation({}, target, resolution, + signRef, arguments, EAttr::AllowPrivateCall, nullptr); - return true; + // return temp variable + expression.writeObjectInfo(expression.boxArgument(tempRetVal, false, true, false)); + + expression.scope.syncStack(); + + writer.appendNode(BuildKey::CloseFrame); } -ObjectInfo Compiler :: compileTupleAssigning(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node) +void Compiler :: writeMessageInfo(BuildTreeWriter& writer, MethodScope& scope) { - WriterContext context = { &writer, &scope, node }; - - ArgumentsInfo targets; - ArgumentsInfo arguments; + IdentifierString methodName; + ByteCodeUtil::resolveMessageName(methodName, scope.module, scope.message); - SyntaxNode current = node.firstChild(); - if (current == SyntaxKey::TupleCollection) { - SyntaxNode identNode = current.firstChild(); - while (identNode != SyntaxKey::None) { - SyntaxNode objNode = identNode.firstChild(); - if (objNode == SyntaxKey::Object) { - targets.add(mapObject(scope, objNode, EAttr::None)); - } - else scope.raiseError(errInvalidOperation, identNode); + writer.appendNode(BuildKey::MethodName, *methodName); +} - identNode = identNode.nextNode(); +void Compiler :: writeParameterDebugInfo(BuildTreeWriter& writer, Scope& scope, int size, TypeInfo typeInfo, + ustr_t name, int index) +{ + if (size > 0) { + if (typeInfo.typeRef == scope.moduleScope->buildins.intReference) { + writer.newNode(BuildKey::IntParameterAddress, name); + } + else if (typeInfo.typeRef == scope.moduleScope->buildins.longReference) { + writer.newNode(BuildKey::LongParameterAddress, name); + } + else if (typeInfo.typeRef == scope.moduleScope->buildins.realReference) { + writer.newNode(BuildKey::RealParameterAddress, name); } + else { + writer.newNode(BuildKey::ParameterAddress, name); - current = current.nextNode(); - } - else { - targets.add(mapObject(scope, current, EAttr::None)); - current = current.nextNode(); - while (current == SyntaxKey::SubVariable) { - ObjectInfo subVar = mapObject(scope, current, EAttr::NewVariable | EAttr::IgnoreDuplicate); - if (subVar.kind == ObjectKind::Unknown) - scope.raiseError(errUnknownObject, current); + ref_t classRef = typeInfo.typeRef; + if (isPrimitiveRef(classRef)) + classRef = resolvePrimitiveType(scope, typeInfo, true); - targets.add(subVar); + ustr_t className = scope.moduleScope->module->resolveReference(classRef); + if (isWeakReference(className)) { + IdentifierString fullName(scope.module->name()); + fullName.append(className); - current = current.nextNode(); + writer.appendNode(BuildKey::ClassName, *fullName); + } + else writer.appendNode(BuildKey::ClassName, className); + } + } + else if (size < 0) { + if (typeInfo.typeRef == V_INT16ARRAY) { + writer.newNode(BuildKey::ShortArrayParameter, name); + } + else if (typeInfo.typeRef == V_INT8ARRAY) { + writer.newNode(BuildKey::ByteArrayParameter, name); + } + else if (typeInfo.typeRef == V_INT32ARRAY) { + writer.newNode(BuildKey::IntArrayParameter, name); } + else writer.newNode(BuildKey::Parameter, name); // !! temporal } + else writer.newNode(BuildKey::Parameter, name); - ObjectInfo exprVal = compileExpression(writer, scope, current, 0, EAttr::Parameter, nullptr); - for (pos_t i = 0; i < targets.count_pos(); i++) { - arguments.clear(); - arguments.add(exprVal); - arguments.add({ ObjectKind::IntLiteral, { V_INT32 }, ::mapIntConstant(scope.moduleScope, i), i}); + writer.appendNode(BuildKey::Index, index); + writer.closeNode(); - ObjectInfo targetVar = targets[i]; +} - ref_t actionRef = scope.module->mapAction(REFER_MESSAGE, 0, false); - mssg_t getter = encodeMessage(actionRef, 2, 0); +void Compiler :: writeMethodDebugInfo(BuildTreeWriter& writer, MethodScope& scope) +{ + writer.newNode(BuildKey::ArgumentsInfo); - ObjectInfo sourceVar = compileMessageOperation(writer, scope, node, exprVal, getter, - 0, arguments, EAttr::None, nullptr); + if (!scope.functionMode) { + ref_t classRef = scope.getClassRef(); - compileAssigningOp(context, targetVar, sourceVar); + writeParameterDebugInfo(writer, scope, _logic->defineStructSize(*scope.moduleScope, classRef).size, + { classRef }, "self", -1); } - return exprVal; + int prefix = scope.functionMode ? 0 : -1; + for (auto it = scope.parameters.start(); !it.eof(); ++it) { + auto paramInfo = *it; + + writeParameterDebugInfo(writer, scope, paramInfo.size, paramInfo.typeInfo, + it.key(), prefix - paramInfo.offset); + } + + writer.closeNode(); } -ObjectInfo Compiler :: compileAssigning(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode loperand, - SyntaxNode roperand, ExpressionAttribute mode) +void Compiler :: compileMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode node) { - ObjectInfo target = mapObject(scope, loperand, mode); - if (target.kind == ObjectKind::Unknown) - scope.raiseError(errUnknownObject, loperand.lastChild(SyntaxKey::TerminalMask)); + ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); - ObjectInfo exprVal = {}; + SyntaxNode current = node.firstChild(SyntaxKey::MemberMask); - ref_t targetRef = retrieveStrongType(scope, target); - if (targetRef == V_AUTO) { - // support auto attribute - exprVal = compileExpression(writer, scope, roperand, - 0, EAttr::RetValExpected, nullptr); + CodeScope codeScope(&scope); + if (scope.info.byRefHandler && !scope.checkHint(MethodHint::InterfaceDispatcher)) { + if (current.key == SyntaxKey::Redirect) { + compileByRefRedirectHandler(writer, scope, node, scope.info.byRefHandler); + } + else { + mssg_t privateImplementation = compileByRefHandler(writer, scope, node, scope.info.byRefHandler); - if (resolveAutoType(scope, exprVal, target)) { - targetRef = retrieveStrongType(scope, exprVal); - target.typeInfo.typeRef = targetRef; + beginMethod(writer, scope, node, BuildKey::Method, false); + compileByRefHandlerInvoker(writer, scope, codeScope, privateImplementation, scope.info.outputRef); + codeScope.syncStack(&scope); + endMethod(writer, scope); + + // NOTE : normal byrefhandler has an alternative implementation + // overriding the normal routine + return; } - else scope.raiseError(errInvalidOperation, roperand.parentNode()); } - else exprVal = compileExpression(writer, scope, roperand, - targetRef, EAttr::RetValExpected, nullptr); + beginMethod(writer, scope, node, BuildKey::Method, true); - WriterContext context = { &writer, &scope, loperand }; - if (!compileAssigningOp(context, target, exprVal)) { - switch (target.kind) { - case ObjectKind::ReadOnlyField: - case ObjectKind::ReadOnlyFieldAddress: - scope.raiseError(errAssigningRealOnly, loperand.parentNode()); - break; - default: - scope.raiseError(errInvalidOperation, loperand.parentNode()); - break; - } + switch (current.key) { + case SyntaxKey::CodeBlock: + case SyntaxKey::ReturnExpression: + case SyntaxKey::ResendDispatch: + case SyntaxKey::Redirect: + compileMethodCode(writer, classScope, scope, codeScope, node, false); + break; + case SyntaxKey::DirectResend: + compileDirectResendCode(writer, codeScope, current); + break; + case SyntaxKey::Importing: + writer.appendNode(BuildKey::Import, current.arg.reference); + break; + case SyntaxKey::WithoutBody: + scope.raiseError(errNoBodyMethod, node); + break; + case SyntaxKey::RedirectDispatch: + compileDispatchCode(writer, codeScope, current); + break; + case SyntaxKey::RedirectTryDispatch: + compileDispatchProberCode(writer, codeScope, current); + break; + default: + break; } - - if (target == exprVal) - scope.raiseError(errAssigningToSelf, loperand.lastChild(SyntaxKey::TerminalMask)); - return target; + codeScope.syncStack(&scope); + endMethod(writer, scope); + + if (scope.isYieldable()) { + classScope->addMssgAttribute(scope.message, ClassAttribute::YieldContextSize, scope.reserved2); + } } -ObjectInfo Compiler :: compileIndexerOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, int operatorId, ref_t expectedRef) +bool Compiler :: isDefaultOrConversionConstructor(Scope& scope, mssg_t message, bool internalOne, bool& isProtectedDefConst) { - // HOTFIX : recognize fixed-array declaration - SyntaxNode loperand = node.firstChild(); - if (loperand == SyntaxKey::Object) { - ObjectInfo info = mapObject(scope, loperand, EAttr::Lookahead); - if (info.kind == ObjectKind::NewVariable) { - // if it is a new variable declaration - treat it like a new array - declareVariable(scope, node, info.typeInfo, false); // !! temporal - typeref should be provided or super class - - if (_trackingUnassigned) { - CodeScope* codeScope = Scope::getScope(scope, Scope::ScopeLevel::Code); - - scope.markAsAssigned(codeScope->mapLocal(loperand.firstChild(SyntaxKey::TerminalMask).identifier())); - } + ref_t actionRef = getAction(message); + if (actionRef == getAction(scope.moduleScope->buildins.constructor_message)) { + return true; + } + else if (actionRef == getAction(scope.moduleScope->buildins.protected_constructor_message)) { + isProtectedDefConst = true; - return {}; // !! temporally - } - else if (info.kind == ObjectKind::MssgLiteral) { - return mapMessageConstant(scope, node, info.reference); - } - else if (info.kind == ObjectKind::ExtMssgLiteral) { - return mapExtMessageConstant(scope, node, info.reference, info.typeInfo.elementRef); + return true; + } + else if (getArgCount(message)) { + ref_t dummy = 0; + ustr_t actionName = scope.module->resolveAction(actionRef, dummy); + if (actionName.compare(CONSTRUCTOR_MESSAGE2)) { + isProtectedDefConst = true; + return true; } + else return actionName.endsWith(CONSTRUCTOR_MESSAGE); } + else if (internalOne) { + ref_t dummy = 0; + ustr_t actionName = scope.module->resolveAction(actionRef, dummy); - return compileOperation(writer, scope, node, operatorId, expectedRef, EAttr::None); -} - -inline bool isConditionalOp(SyntaxKey key) -{ - switch (key) { - case SyntaxKey::EqualOperation: - case SyntaxKey::NotEqualOperation: - case SyntaxKey::LessOperation: - case SyntaxKey::NotLessOperation: - case SyntaxKey::GreaterOperation: - case SyntaxKey::NotGreaterOperation: - return true; - default: - return false; + return actionName.endsWith(CONSTRUCTOR_MESSAGE); } + else return false; } -ObjectInfo Compiler :: compileBoolOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, int operatorId) +// NOTE : check if init_method is declared in the current class then call it +// returns the parent class reference +void Compiler :: callInitMethod(Expression& expression, SyntaxNode node, ClassInfo& info, ref_t reference) { - SyntaxNode lnode = node.firstChild(); - SyntaxNode rnode = lnode.nextNode(); - - ObjectInfo loperand = {}; + if (!info.methods.exist(expression.scope.moduleScope->buildins.init_message)) + return; - bool condOp = isConditionalOp(lnode.key); - bool nativeOp = false; - if (!condOp) { - // If it is not a comparison operation - // we have to define if native short-circuit evaluation can be used - loperand = compileExpression(writer, scope, lnode, 0, EAttr::Parameter, nullptr); + if (info.header.parentRef != 0) { + ClassInfo classInfo; + _logic->defineClassInfo(*expression.scope.moduleScope, classInfo, info.header.parentRef); - nativeOp = _logic->isCompatible(*scope.moduleScope, - { scope.moduleScope->branchingInfo.typeRef }, loperand.typeInfo, true); + callInitMethod(expression, node, classInfo, info.header.parentRef); } - else nativeOp = true; - if (nativeOp) { - WriterContext context = { &writer, &scope, node }; + MethodInfo initInfo = info.methods.get(expression.scope.moduleScope->buildins.init_message); + if (!initInfo.inherited) { + ArgumentsInfo args; + args.add({ ObjectKind::Object, { reference }, 0 }); - writer.newNode(BuildKey::ShortCircuitOp, operatorId); + MessageResolution resolution = { true, expression.scope.moduleScope->buildins.init_message }; + _logic->setSignatureStacksafe(*expression.scope.moduleScope, 0, resolution.stackSafeAttr); - writer.appendNode(BuildKey::TrueConst, scope.moduleScope->branchingInfo.trueRef); - writer.appendNode(BuildKey::FalseConst, scope.moduleScope->branchingInfo.falseRef); + expression.compileMessageOperation(node, args[0], resolution, + 0, args, EAttr::None, nullptr); + } +} - writer.newNode(BuildKey::Tape); - if (loperand.kind == ObjectKind::Unknown) - loperand = compileExpression(writer, scope, lnode, scope.moduleScope->branchingInfo.typeRef, EAttr::None, nullptr); +void Compiler :: compileInlineInitializing(BuildTreeWriter& writer, ClassScope& classScope, SyntaxNode node) +{ + Expression expression(this, classScope, writer); - writeObjectInfo(context, loperand); - writer.closeNode(); - - writer.newNode(BuildKey::Tape); - writeObjectInfo(context, - compileExpression(writer, scope, rnode, scope.moduleScope->branchingInfo.typeRef, EAttr::None, nullptr)); - writer.closeNode(); - - writer.closeNode(); + callInitMethod(expression, node, classScope.info, classScope.reference); +} - return { ObjectKind::Object, { scope.moduleScope->branchingInfo.typeRef }, 0 }; +void Compiler :: compileDefConvConstructorCode(BuildTreeWriter& writer, MethodScope& scope, + SyntaxNode node, bool& newFrame) +{ + if (!newFrame) { + // new stack frame + writer.appendNode(BuildKey::OpenFrame); + newFrame = true; } - else { - // bad luck - we have to implement weak short-circuit evaluation - // using lazy expression - SyntaxTree tempTree; - SyntaxTreeWriter treeWriter(tempTree); - treeWriter.newNode(SyntaxKey::LazyOperation); - SyntaxTree::copyNode(treeWriter, rnode, true); - treeWriter.closeNode(); - - ObjectInfo roperand = compileClosure(writer, scope, tempTree.readRoot(), EAttr::Parameter, nullptr); - ref_t arguments[2] = - { - retrieveType(scope, loperand), - retrieveType(scope, roperand) - }; - ArgumentsInfo messageArguments; - messageArguments.add(loperand); - messageArguments.add(roperand); + ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); - mssg_t message = resolveOperatorMessage(scope.moduleScope, operatorId); + if (test(classScope->info.header.flags, elDynamicRole)) + throw InternalError(errFatalError); - return compileWeakOperation(writer, scope, node, arguments, 2, loperand, - messageArguments, message, 0, nullptr); - } + createObject(writer, classScope->info, classScope->reference); } -ObjectInfo Compiler :: compileAssignOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, - int operatorId, ref_t expectedRef) +void Compiler :: compileInplaceDefConstructorCode(BuildTreeWriter& writer, SyntaxNode current, SyntaxNode methodNode, + MethodScope& scope, CodeScope& codeScope, ClassScope& classClassScope, ref_t classFlags, bool newFrame) { - WriterContext context = { &writer, &scope, node }; + mssg_t privateHandler = declareInplaceConstructorHandler(scope, classClassScope); - SyntaxNode lnode = node.firstChild(); - SyntaxNode rnode = lnode.nextNode(); + ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); - ArgumentsInfo updatedOuterArgs; - ObjectInfo loperand = compileExpression(writer, scope, lnode, 0, EAttr::Parameter, &updatedOuterArgs); - ObjectInfo roperand = {}; - - size_t argLen = 1; - ref_t arguments[2] = {}; - arguments[0] = loperand.typeInfo.typeRef; + // calling the byref handler + Expression expression(this, codeScope, writer); + ArgumentsInfo arguments; - if (rnode != SyntaxKey::None) { - roperand = compileExpression(writer, scope, rnode, 0, EAttr::Parameter, &updatedOuterArgs); - arguments[1] = roperand.typeInfo.typeRef; - argLen++; - } + scope.selfLocal = codeScope.newLocal(); + writer.appendNode(BuildKey::Assigning, scope.selfLocal); - ref_t dummy = 0; - BuildKey op = _logic->resolveOp(*scope.moduleScope, operatorId, arguments, argLen, dummy); - if (op != BuildKey::None) { - // box argument locally if required - loperand = boxArgumentLocally(context, loperand, true, true); + ObjectInfo target = mapClassSymbol(scope, classScope->reference); + MessageResolution resolution = { true, privateHandler }; - if (roperand.kind != ObjectKind::Unknown) { - roperand = boxArgumentLocally(context, roperand, true, false); + arguments.add(scope.mapSelf()); + for (auto it = scope.parameters.start(); !it.eof(); ++it) { + arguments.add(scope.mapParameter(it.key(), EAttr::None)); + } - writeObjectInfo(context, roperand); - writer.appendNode(BuildKey::SavingInStack, 0); - } + ref_t signRef = getSignature(scope.module, privateHandler); + _logic->setSignatureStacksafe(*scope.moduleScope, signRef, resolution.stackSafeAttr); - writer.newNode(op, operatorId); - writer.appendNode(BuildKey::Index, loperand.argument); - writer.closeNode(); + expression.compileMessageOperation({}, target, resolution, + signRef, arguments, EAttr::AllowPrivateCall, nullptr); - unboxArguments(context, {}, &updatedOuterArgs); + // return the created object + expression.writeObjectInfo(scope.mapSelf(), current); - scope.reserveArgs(2); - } - else { - switch (operatorId) { - case ADD_ASSIGN_OPERATOR_ID: - operatorId = ADD_OPERATOR_ID; - break; - case SUB_ASSIGN_OPERATOR_ID: - operatorId = SUB_OPERATOR_ID; - break; - case MUL_ASSIGN_OPERATOR_ID: - operatorId = MUL_OPERATOR_ID; - break; - case DIV_ASSIGN_OPERATOR_ID: - operatorId = DIV_OPERATOR_ID; - break; - default: - break; - } + expression.scope.syncStack(); + writer.appendNode(BuildKey::CloseFrame); - mssg_t message = resolveOperatorMessage(scope.moduleScope, operatorId); - ArgumentsInfo messageArguments; - messageArguments.add(loperand); + codeScope.syncStack(&scope); + endMethod(writer, scope); - if (roperand.kind != ObjectKind::Unknown) - messageArguments.add(roperand); + compileInplaceConstructorHandler(writer, scope, classClassScope, + current, methodNode, privateHandler); +} - ObjectInfo opVal = compileWeakOperation(writer, scope, node, arguments, 2, loperand, - messageArguments, message, expectedRef, &updatedOuterArgs); +void Compiler :: compileConstructorCode(BuildTreeWriter& writer, SyntaxNode node, SyntaxNode current, MethodScope& scope, + CodeScope& codeScope, ClassScope& classClassScope, bool isDefConvConstructor, ref_t classFlags, bool newFrame) +{ + if (isDefConvConstructor) { + // if it is a default / conversion (unnamed) constructor + // call field initializers if available for default constructor + ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); - if(!compileAssigningOp(context, loperand, opVal)) - scope.raiseError(errInvalidOperation, node); - } + if (node.existChild(SyntaxKey::FillingAttr)) + fillObject(writer, classScope->info, scope.moduleScope->ptrSize); - return loperand; -} + if (classScope->info.methods.exist(scope.moduleScope->buildins.init_message)) { + compileInlineInitializing(writer, *classScope, node); + } + } -ObjectInfo Compiler :: compileSpecialOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, int operatorId, ref_t expectedRef) -{ - ObjectInfo retVal = {}; - switch (operatorId) { - case BREAK_OPERATOR_ID: - writer.appendNode(BuildKey::BreakOp); + switch (current.key) { + case SyntaxKey::CodeBlock: + case SyntaxKey::ResendDispatch: + compileMethodCode(writer, &classClassScope, scope, codeScope, node, newFrame); break; - case CONTINUE_OPERATOR_ID: - writer.appendNode(BuildKey::ContinueOp); + case SyntaxKey::ReturnExpression: + compileRetExpression(writer, codeScope, current, EAttr::DynamicObject); + writer.appendNode(BuildKey::CloseFrame); break; - default: - assert(false); + case SyntaxKey::DirectResend: + compileDirectResendCode(writer, codeScope, current); break; + case SyntaxKey::None: + if (isDefConvConstructor && !test(classFlags, elDynamicRole)) { + writer.appendNode(BuildKey::CloseFrame); + break; + } + default: + throw InternalError(errFatalError); } - - return retVal; } -inline bool isSimpleNode(SyntaxNode node) +void Compiler :: compileConstructor(BuildTreeWriter& writer, MethodScope& scope, + ClassScope& classClassScope, SyntaxNode node, bool abstractMode) { - SyntaxNode current = node.firstChild(); + bool isProtectedDefConst = false; + bool isDefConvConstructor = isDefaultOrConversionConstructor(scope, scope.message, scope.checkHint(MethodHint::Internal), isProtectedDefConst); - if (current == SyntaxKey::Expression && current.nextNode() == SyntaxKey::None) { - return isSimpleNode(current); + mssg_t defConstrMssg = scope.moduleScope->buildins.constructor_message; + mssg_t protectedDefConstructor = classClassScope.getMssgAttribute(defConstrMssg, ClassAttribute::ProtectedAlias); + if (protectedDefConstructor) { + // if protected default constructor is declared - use it + defConstrMssg = protectedDefConstructor; + isProtectedDefConst = true; } - else if (current == SyntaxKey::Object && current.nextNode() == SyntaxKey::None) { - return true; + else if (classClassScope.info.methods.exist(defConstrMssg | STATIC_MESSAGE)) { + // if private default constructor is declared - use it + defConstrMssg = defConstrMssg | STATIC_MESSAGE; } - return false; -} -ObjectInfo Compiler :: compileOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, int operatorId, ref_t expectedRef, - ExpressionAttribute mode) -{ - SyntaxNode loperand = node.firstChild(); - SyntaxNode roperand = loperand.nextNode(); + // NOTE : special case - abstract class with a protected constructor + bool protectedAbstractMode = scope.isProtected() && abstractMode; - if (operatorId == SET_OPERATOR_ID){ - // assign operation is a special case - if (loperand == SyntaxKey::IndexerOperation) { - return compileOperation(writer, scope, loperand, roperand, SET_INDEXER_OPERATOR_ID, expectedRef); - } - else if (loperand == SyntaxKey::Expression) { - if (!isSimpleNode(loperand)) - scope.raiseError(errInvalidOperation, loperand); + beginMethod(writer, scope, node, BuildKey::Method, true); - return compileAssigning(writer, scope, loperand.firstChild(), roperand, mode); - } - else return compileAssigning(writer, scope, loperand, roperand, mode); + CodeScope codeScope(&scope); + ref_t classFlags = codeScope.getClassFlags(); + SyntaxNode current = node.firstChild(SyntaxKey::MemberMask); + bool retExpr = current == SyntaxKey::ReturnExpression; + + bool newFrame = false; + if (current == SyntaxKey::ResendDispatch || current == SyntaxKey::RedirectDispatch || current == SyntaxKey::DirectResend) { + // do not create a frame for resend operation + // the object should not be created, because of redirecting + isDefConvConstructor = false; } - else return compileOperation(writer, scope, loperand, roperand, operatorId, expectedRef); -} + else if (isDefConvConstructor && !test(classFlags, elDynamicRole)) { + // new stack frame + writer.appendNode(BuildKey::OpenFrame); + newFrame = true; -inline SyntaxNode skipNestedExpression(SyntaxNode node) -{ - if (node == SyntaxKey::Expression) { - SyntaxNode current = node.firstChild(); - while (current == SyntaxKey::Expression) { - node = current; - current = current.firstChild(); + if (retExpr) { + // the object should not be created for returning expression + isDefConvConstructor = false; } - return node; } - return node; -} - -ObjectInfo Compiler :: compileSubCode(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, - ExpressionAttribute mode, bool withoutNewScope) -{ - bool retValExpected = EAttrs::testAndExclude(mode, EAttr::RetValExpected); - bool withoutDebugInfo = EAttrs::testAndExclude(mode, EAttr::NoDebugInfo); + else if (retExpr) { + // new stack frame + writer.appendNode(BuildKey::OpenFrame); + newFrame = true; + } + else if (!test(classFlags, elDynamicRole) + && (classClassScope.info.methods.exist(defConstrMssg) || protectedAbstractMode)) + { + if (scope.checkHint(MethodHint::Multimethod)) { + // NOTE : the dispatch statement must be before the default constructor call + // to avoid the doublicate allocating + compileMultidispatch(writer, codeScope, classClassScope, node, false); + } - scope.syncStack(); + // new stack frame + writer.appendNode(BuildKey::OpenFrame); + newFrame = true; - CodeScope* parentCodeScope = Scope::getScope(scope, Scope::ScopeLevel::Code); - ObjectInfo retVal = {}; - if (!withoutNewScope) { - CodeScope codeScope(parentCodeScope); - retVal = compileCode(writer, codeScope, node, retValExpected, withoutDebugInfo); + if (!retExpr) { + // NOTE : the named constructor should be polymorphic, depending on the message target + writer.appendNode(BuildKey::Local, -1); + //writer.appendNode(BuildKey::ClassReference, scope.getClassRef()); - codeScope.syncStack(parentCodeScope); + writer.newNode(BuildKey::CallOp, defConstrMssg); + writer.appendNode(BuildKey::Index, 1); // built-in constructor entry should be the second entry in VMT + writer.closeNode(); + } } - else retVal = compileCode(writer, *parentCodeScope, node, retValExpected); + // if it is a dynamic object implicit constructor call is not possible + else scope.raiseError(errIllegalConstructor, node); - if (!retValExpected) { - retVal = { ObjectKind::Object }; + if (current == SyntaxKey::RedirectDispatch) { + compileConstructorDispatchCode(writer, codeScope, classClassScope, current); } + else { + bool inPlaceConstructor = false; + if (isDefConvConstructor && !test(classFlags, elDynamicRole)) { + // if it is a default / conversion (unnamed) constructor + // it should create the object + compileDefConvConstructorCode(writer, scope, node, newFrame); - return retVal; -} - -ObjectInfo Compiler :: compileBranchingOperands(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode rnode, - SyntaxNode r2node, bool retValExpected, bool withoutDebugInfo) -{ - CodeScope* codeScope = Scope::getScope(scope, Scope::ScopeLevel::Code); - - writer.newNode(BuildKey::Tape); - - ObjectInfo subRetCode = {}; - bool oldWithRet = codeScope->withRetStatement; - if (rnode == SyntaxKey::ClosureBlock || rnode == SyntaxKey::SwitchCode) { - EAttr mode = retValExpected ? EAttr::RetValExpected : EAttr::None; - if (withoutDebugInfo) - mode = mode | EAttr::NoDebugInfo; + if (getArgCount(scope.message) < 2 && test(classFlags, elStructureRole)) + inPlaceConstructor = true; + } - codeScope->withRetStatement = false; + if (inPlaceConstructor) { + compileInplaceDefConstructorCode(writer, current, node, scope, codeScope, + classClassScope, classFlags, newFrame); - subRetCode = compileSubCode(writer, scope, rnode.firstChild(), mode); + // NOTE : the procedure closes the scope itself + return; + } + else compileConstructorCode(writer, node, current, scope, codeScope, + classClassScope, isDefConvConstructor, classFlags, newFrame); } - else subRetCode = compileExpression(writer, scope, rnode, 0, EAttr::None, nullptr); - WriterContext context = { &writer, &scope, rnode }; - if (retValExpected) { - writeObjectInfo(context, subRetCode); - } - writer.closeNode(); + codeScope.syncStack(&scope); - TypeInfo retType = {}; - if (r2node != SyntaxKey::None) { - // NOTE : it should immediately follow if-block - writer.newNode(BuildKey::Tape); - ObjectInfo elseSubRetCode = {}; - if (r2node == SyntaxKey::ClosureBlock) { - bool withRet = codeScope->withRetStatement; - codeScope->withRetStatement = false; + endMethod(writer, scope); +} - EAttr mode = retValExpected ? EAttr::RetValExpected : EAttr::None; - if (withoutDebugInfo) - mode = mode | EAttr::NoDebugInfo; +void Compiler :: initializeMethod(ClassScope& scope, MethodScope& methodScope, SyntaxNode current) +{ + methodScope.message = current.arg.reference; + methodScope.info = scope.info.methods.get(methodScope.message); + methodScope.functionMode = test(methodScope.message, FUNCTION_MESSAGE); + methodScope.isEmbeddable = methodScope.checkHint(MethodHint::Stacksafe); + methodScope.isExtension = methodScope.checkHint(MethodHint::Extension); + methodScope.targetSelfMode = methodScope.checkHint(MethodHint::TargetSelf); + methodScope.nestedMode = scope.getScope(Scope::ScopeLevel::OwnerClass) != &scope; - elseSubRetCode = compileSubCode(writer, scope, r2node.firstChild(), mode); + declareVMTMessage(methodScope, current, false, false); - if (!withRet || !codeScope->withRetStatement) { - codeScope->withRetStatement = oldWithRet; - } - } - else elseSubRetCode = compileExpression(writer, scope, r2node, 0, EAttr::None, nullptr); + if (methodScope.info.outputRef) { + SyntaxNode typeNode = current.findChild(SyntaxKey::Type, SyntaxKey::ArrayType, SyntaxKey::TemplateType); + if (typeNode != SyntaxKey::None) { + resolveStrongTypeAttribute(scope, typeNode, false, false); - if (retValExpected) { - context.node = r2node; + //TypeAttributes typeAttributes = {}; + //resolveTypeAttribute(scope, typeNode, typeAttributes, false, false); + //if (typeAttributes.isNonempty()) + // scope.raiseError(errInvalidOperation, typeNode); + } + else validateType(scope, methodScope.info.outputRef, current, false, false); - writeObjectInfo(context, elseSubRetCode); + if (methodScope.checkHint(MethodHint::VirtualReturn)) { + TypeInfo refType = { V_WRAPPER, methodScope.info.outputRef }; - if (subRetCode.typeInfo == elseSubRetCode.typeInfo) - retType = subRetCode.typeInfo; - } - writer.closeNode(); - } - else codeScope->withRetStatement = oldWithRet; + SizeInfo sizeInfo = {}; + // add byref return arg + if (_logic->isEmbeddable(*scope.moduleScope, methodScope.info.outputRef)) { + sizeInfo = _logic->defineStructSize(*scope.moduleScope, + resolvePrimitiveType(scope, refType, false)); + } - writer.closeNode(); + int offset = methodScope.parameters.count() + 1u; + methodScope.parameters.add(RETVAL_ARG, { offset, refType, sizeInfo.size }); - ObjectInfo retVal = {}; - if (retValExpected) { - retVal = { ObjectKind::Object, retType, 0 }; + methodScope.byRefReturnMode = true; + } } - - return retVal; } -ObjectInfo Compiler :: compileBranchingOperation(WriterContext& context, ObjectInfo loperand, SyntaxNode rnode, - SyntaxNode r2node, int operatorId, ArgumentsInfo* updatedOuterArgs, bool retValExpected, bool withoutDebugInfo) +void Compiler :: compileRedirectDispatcher(BuildTreeWriter& writer, MethodScope& scope, CodeScope& codeScope, SyntaxNode node, + bool withGenerics) { - ObjectInfo retVal = {}; - BuildKey op = BuildKey::None; - - ObjectInfo roperand = {}; - ObjectInfo roperand2 = {}; - if (rnode.existChild(SyntaxKey::ClosureBlock)) { - rnode = rnode.findChild(SyntaxKey::ClosureBlock); - - roperand = { ObjectKind::Closure, { V_CLOSURE }, 0 }; - } - else if (rnode == SyntaxKey::SwitchCode) { - roperand = { ObjectKind::Closure, { V_CLOSURE }, 0 }; - } - else roperand = { ObjectKind::Object, { V_OBJECT }, 0 }; - - if (r2node.existChild(SyntaxKey::ClosureBlock)) { - r2node = r2node.findChild(SyntaxKey::ClosureBlock); - - roperand2 = { ObjectKind::Closure, { V_CLOSURE }, 0 }; + writer.appendNode(BuildKey::DispatchingOp); + if (withGenerics) { + writer.newNode(BuildKey::GenericDispatchingOp); + writer.appendNode(BuildKey::Message, + encodeMessage(scope.module->mapAction(GENERIC_PREFIX, 0, false), 0, 0)); + writer.closeNode(); } - else if (r2node != SyntaxKey::None) - roperand2 = { ObjectKind::Object, { V_OBJECT }, 0 }; - size_t argLen = 2; - ref_t arguments[3] = {}; - arguments[0] = retrieveType(*context.scope, loperand); - arguments[1] = retrieveType(*context.scope, roperand); + // new stack frame + writer.appendNode(BuildKey::OpenFrame); - if (r2node != SyntaxKey::None) { - argLen++; - arguments[2] = retrieveType(*context.scope, roperand2); - } + // stack should contains current self reference + // the original message should be restored if it is a generic method + scope.selfLocal = codeScope.newLocal(); + writer.appendNode(BuildKey::Assigning, scope.selfLocal); - ref_t outputRef = 0; - op = _logic->resolveOp(*context.scope->moduleScope, operatorId, arguments, argLen, outputRef); + Expression expression(this, codeScope, writer); - if (op != BuildKey::None) { - writeObjectInfo(context, loperand); + ObjectInfo mssgVar = expression.declareTempStructure({ sizeof(mssg_t)}); + writer.appendNode(BuildKey::SavingIndex, mssgVar.reference); - context.writer->newNode(op, operatorId); - context.writer->appendNode(BuildKey::Const, context.scope->moduleScope->branchingInfo.trueRef); + ObjectInfo retVal = { }; - retVal = compileBranchingOperands(*context.writer, *context.scope, rnode, r2node, retValExpected, withoutDebugInfo); + SyntaxNode bodyNode = node.firstChild(SyntaxKey::ScopeMask); + switch (bodyNode.key) { + case SyntaxKey::Expression: + retVal = expression.compile(bodyNode, 0, EAttr::None, nullptr); + break; + default: + scope.raiseError(errInvalidOperation, node); + break; } - else { - mssg_t message = 0; - if (rnode != SyntaxKey::ClosureBlock && r2node != SyntaxKey::None) { - message = context.scope->moduleScope->buildins.iif_message; - - roperand = compileExpression(*context.writer, *context.scope, rnode, 0, EAttr::Parameter, updatedOuterArgs); - roperand2 = compileExpression(*context.writer, *context.scope, r2node, 0, EAttr::Parameter, updatedOuterArgs); - } - else { - message = resolveOperatorMessage(context.scope->moduleScope, operatorId); - - roperand = compileClosure(*context.writer, *context.scope, rnode, EAttr::None, updatedOuterArgs); - roperand2 = compileClosure(*context.writer, *context.scope, r2node, EAttr::None, updatedOuterArgs); - } - ArgumentsInfo messageArguments; - messageArguments.add(loperand); - messageArguments.add(roperand); - if (r2node != SyntaxKey::None) { - messageArguments.add(roperand2); - } + retVal = expression.boxArgument(retVal, false, true, false); - ref_t signRef = context.scope->module->mapSignature(arguments, argLen, false); + expression.writeObjectInfo(retVal); - retVal = compileMessageOperation(*context.writer, *context.scope, context.node, - loperand, message, signRef, messageArguments, EAttr::NoExtension, updatedOuterArgs); - } + writer.appendNode(BuildKey::LoadingIndex, mssgVar.reference); - // HOTFIX : to compenstate the closed statement above - context.writer->appendNode(BuildKey::OpenStatement); + expression.scope.syncStack(); - return retVal; + writer.appendNode(BuildKey::CloseFrame, -1); + writer.appendNode(BuildKey::RedirectOp); } -ObjectInfo Compiler :: compileBranchingOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, - int operatorId, bool retValExpected, bool withoutDebugInfo) +inline bool hasVariadicFunctionDispatcher(Compiler::ClassScope* classScope, bool& mixedDispatcher) { - SyntaxNode lnode = node.firstChild(); - SyntaxNode rnode = /*skipNestedExpression(*/lnode.nextNode()/*)*/; - SyntaxNode r2node = {}; - if (operatorId == IF_ELSE_OPERATOR_ID) - r2node = rnode.nextNode(); - - ArgumentsInfo updatedOuterArgs; - - ObjectInfo loperand = compileExpression(writer, scope, lnode, 0, EAttr::Parameter, &updatedOuterArgs); + bool normalVariadic = false; + bool functionVariadic = false; + for (auto it = classScope->info.methods.start(); !it.eof(); ++it) { + mssg_t m = it.key(); - if (!withoutDebugInfo) { - // HOTFIX : to allow correct step over the branching statement - writer.appendNode(BuildKey::EndStatement); - writer.appendNode(BuildKey::VirtualBreakoint); + if ((m & PREFIX_MESSAGE_MASK) == VARIADIC_MESSAGE) { + if (test(m, FUNCTION_MESSAGE)) { + functionVariadic = true; + } + else normalVariadic = true; + } } - WriterContext context = { &writer, &scope, node }; - auto retVal = compileBranchingOperation(context, loperand, rnode, r2node, operatorId, &updatedOuterArgs, retValExpected, withoutDebugInfo); - - if (!withoutDebugInfo) - writer.appendNode(BuildKey::OpenStatement); // HOTFIX : to match the closing statement + if (functionVariadic) { + if (normalVariadic) + mixedDispatcher = true; - return retVal; + return true; + } + else return false; } -ObjectInfo Compiler :: compileMessageOperationR(BuildTreeWriter& writer, ExprScope& scope, ObjectInfo target, - SyntaxNode messageNode, bool propertyMode) +void Compiler :: compileDispatcherMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode node, + bool withGenerics, bool withOpenArgGenerics) { - ArgumentsInfo arguments; - ArgumentsInfo updatedOuterArgs; - - switch (target.mode) { - case TargetMode::Casting: - { - bool dummy = false; - compileMessageArguments(writer, scope, messageNode, arguments, 0, EAttr::NoPrimitives, &updatedOuterArgs, dummy); - if (arguments.count() == 1 && !dummy) { - return convertObject(writer, scope, messageNode, arguments[0], retrieveStrongType(scope, target), false, true); - } - else scope.raiseError(errInvalidOperation, messageNode); - break; - } - default: - { - // NOTE : the operation target shouldn't be a primitive type - ObjectInfo source = validateObject(writer, scope, messageNode, target, 0, true, true, false); - - mssg_t messageRef = mapMessage(scope, messageNode, propertyMode, false, false); + CodeScope codeScope(&scope); - mssg_t resolvedMessage = _logic->resolveSingleDispatch(*scope.moduleScope, - retrieveType(scope, source), messageRef); + beginMethod(writer, scope, node, BuildKey::Method, false); - ref_t expectedSignRef = 0; - if (resolvedMessage) - scope.module->resolveAction(getAction(resolvedMessage), expectedSignRef); + if (node != SyntaxKey::None) { + // if it is an explicit dispatcher + SyntaxNode current = node.firstChild(SyntaxKey::MemberMask); + switch (current.key) { + case SyntaxKey::Importing: + writer.appendNode(BuildKey::Import, current.arg.reference); + break; + case SyntaxKey::Redirect: + compileRedirectDispatcher(writer, scope, codeScope, current, withGenerics); + break; + default: + scope.raiseError(errInvalidOperation, node); + break; + } + } + else { + // if it is an implicit dispatcher + if (withGenerics) { + ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); - if (!test(messageRef, FUNCTION_MESSAGE)) { - arguments.add(source); - } + // !! temporally + if (withOpenArgGenerics) + scope.raiseError(errInvalidOperation, node); - bool withVariadicArg = false; - ref_t implicitSignatureRef = compileMessageArguments(writer, scope, messageNode, arguments, expectedSignRef, - EAttr::NoPrimitives, &updatedOuterArgs, withVariadicArg); + writer.appendNode(BuildKey::DispatchingOp); + writer.newNode(BuildKey::GenericDispatchingOp); + writer.appendNode(BuildKey::Message, + encodeMessage(scope.module->mapAction(GENERIC_PREFIX, 0, false), 0, 0)); + writer.closeNode(); - EAttr opMode = EAttr::None; - if (withVariadicArg) { - messageRef |= VARIADIC_MESSAGE; + writer.newNode(BuildKey::StrongRedirectOp, scope.moduleScope->buildins.dispatch_message); + writer.appendNode(BuildKey::Type, classScope->info.header.parentRef); + writer.closeNode(); + } + // if it is open arg generic without redirect statement + else if (withOpenArgGenerics) { + Expression expression(this, codeScope, writer); - opMode = EAttr::WithVariadicArg; - } + ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); - return compileMessageOperation(writer, scope, messageNode, source, messageRef, - implicitSignatureRef, arguments, opMode, &updatedOuterArgs); + ref_t mask = VARIADIC_MESSAGE; + bool mixedDispatcher = false; + bool variadicFunction = hasVariadicFunctionDispatcher(classScope, mixedDispatcher); + if (variadicFunction) { - break; + mask |= FUNCTION_MESSAGE; } - } - return {}; -} + // HOTFIX : an extension is a special case of a variadic function and a target should be included + pos_t argCount = (!scope.isExtension && variadicFunction) ? 1 : 2; -ObjectInfo Compiler :: compileAltOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node) -{ - ObjectInfo ehLocal = declareTempStructure(scope, { (int)scope.moduleScope->ehTableEntrySize, false }); - - ObjectInfo target = {}; - SyntaxNode current = node.firstChild(); - if (current == SyntaxKey::MessageOperation || current == SyntaxKey::PropertyOperation) { - SyntaxNode objNode = current.firstChild(); + writer.appendNode(BuildKey::DispatchingOp); + // open frame + writer.appendNode(BuildKey::OpenFrame); + // save the target + ObjectInfo tempTarget = expression.saveToTempLocal({ ObjectKind::Object }); + // save incoming message + scope.messageLocalAddress = allocateLocalAddress(codeScope, sizeof(mssg_t), false); + writer.appendNode(BuildKey::SavingIndex, scope.messageLocalAddress); + // unbox argument list + writer.appendNode(BuildKey::LoadArgCount, 1); + writer.appendNode(BuildKey::UnboxMessage, -1); - target = compileObject(writer, scope, objNode, EAttr::Parameter, nullptr); + // change incoming message to variadic multi-method + writer.newNode(BuildKey::LoadingSubject, + encodeMessage(getAction(scope.moduleScope->buildins.dispatch_message), argCount, mask)); + writer.appendNode(BuildKey::Index, scope.messageLocalAddress); + if (mixedDispatcher) + writer.appendNode(BuildKey::Special, -1); + writer.closeNode(); - writer.newNode(BuildKey::AltOp, ehLocal.argument); + // select the target + expression.writeObjectInfo(tempTarget, node); - writer.newNode(BuildKey::Tape); - compileMessageOperationR(writer, scope, target, objNode.nextNode(), current == SyntaxKey::PropertyOperation); - writer.closeNode(); - } - else scope.raiseError(errInvalidOperation, node); + // call the message + writer.newNode(BuildKey::StrongResendOp, scope.moduleScope->buildins.dispatch_message); + writer.appendNode(BuildKey::Type, classScope->info.header.parentRef); + writer.closeNode(); - writer.newNode(BuildKey::Tape); - SyntaxNode altNode = current.nextNode().firstChild(); + // close frame + writer.appendNode(BuildKey::CloseFrame); - if (target.mode == TargetMode::Casting) { - // HOTFIX : for the cast, the argument is a target - target = compileExpression(writer, scope, current.findChild(SyntaxKey::Expression), - 0, EAttr::Parameter, nullptr); + expression.scope.syncStack(); + } } - compileMessageOperationR(writer, scope, target, altNode.firstChild(), false); - - writer.closeNode(); - - writer.closeNode(); - - return { ObjectKind::Object }; + codeScope.syncStack(&scope); + endMethod(writer, scope); } -ObjectInfo Compiler :: compileIsNilOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node) +void Compiler :: compileCustomDispatcher(BuildTreeWriter& writer, ClassScope& scope) { - WriterContext context = { &writer, &scope, node }; + MethodScope methodScope(&scope); + methodScope.message = scope.moduleScope->buildins.dispatch_message; - ObjectInfo ehLocal = declareTempStructure(scope, { (int)scope.moduleScope->ehTableEntrySize, false }); + auto methodIt = scope.info.methods.getIt(methodScope.message); + if (!methodIt.eof()) { + methodScope.info = *methodIt; - ObjectInfo loperand = {}; - SyntaxNode current = node.firstChild(); + methodScope.info.inherited = false; - if (current == SyntaxKey::MessageOperation || current == SyntaxKey::PropertyOperation) { - SyntaxNode objNode = current.firstChild(); + *methodIt = methodScope.info; + } + else { + methodScope.info.hints |= (ref_t)MethodHint::Dispatcher; + scope.info.methods.add(methodScope.message, methodScope.info); + } - loperand = compileObject(writer, scope, objNode, EAttr::Parameter, nullptr); + scope.info.header.flags |= elWithCustomDispatcher; - writer.newNode(BuildKey::AltOp, ehLocal.argument); + compileDispatcherMethod(writer, methodScope, {}, + test(scope.info.header.flags, elWithGenerics), + test(scope.info.header.flags, elWithVariadics)); - writer.newNode(BuildKey::Tape); - compileMessageOperationR(writer, scope, loperand, objNode.nextNode(), - current == SyntaxKey::PropertyOperation); - writer.closeNode(); + // overwrite the class info if required + scope.save(); +} - writer.newNode(BuildKey::Tape); - writer.appendNode(BuildKey::NilReference, 0); - writer.closeNode(); +void Compiler :: compileVMT(BuildTreeWriter& writer, ClassScope& scope, SyntaxNode node, + bool exclusiveMode, bool ignoreAutoMultimethod) +{ + SyntaxNode current = node.firstChild(); + while (current != SyntaxKey::None) { + switch (current.key) { + case SyntaxKey::Method: + { + if (exclusiveMode + && (ignoreAutoMultimethod == SyntaxTree::ifChildExists(current, SyntaxKey::Autogenerated, -1))) + { + current = current.nextNode(); + continue; + } - writer.closeNode(); + MethodScope methodScope(&scope); + initializeMethod(scope, methodScope, current); - loperand = saveToTempLocal(writer, scope, { ObjectKind::Object }); - } - else if (current == SyntaxKey::Object) { - loperand = compileObject(writer, scope, current, EAttr::Parameter, nullptr); - } - else scope.raiseError(errInvalidOperation, node); +#ifdef FULL_OUTOUT_INFO + IdentifierString messageName; + ByteCodeUtil::resolveMessageName(messageName, scope.module, methodScope.message); - SyntaxNode altNode = current.nextNode(); - ObjectInfo roperand = compileExpression(writer, scope, altNode, 0, EAttr::Parameter, nullptr); + // !! temporal + if (messageName.compare("static:getItem<'IntNumber,'Object>[3]")) + methodScope.message |= 0; - writeObjectInfo(context, roperand); - writer.appendNode(BuildKey::SavingInStack); - writeObjectInfo(context, loperand); - writer.appendNode(BuildKey::NilOp, ISNIL_OPERATOR_ID); + _errorProcessor->info(infoCurrentMethod, *messageName); +#endif // FULL_OUTOUT_INFO - return { ObjectKind::Object }; + // if it is a dispatch handler + if (methodScope.message == scope.moduleScope->buildins.dispatch_message) { + compileDispatcherMethod(writer, methodScope, current, + test(scope.info.header.flags, elWithGenerics), + test(scope.info.header.flags, elWithVariadics)); + } + // if it is an abstract one + else if (methodScope.checkHint(MethodHint::Abstract)) { + compileAbstractMethod(writer, methodScope, current, scope.abstractMode); + } + // if it is an initializer + else if (methodScope.checkHint(MethodHint::Initializer)) { + compileInitializerMethod(writer, methodScope, node); + } + // if it is a normal method + else compileMethod(writer, methodScope, current); + break; + } + case SyntaxKey::Constructor: + if (_logic->isRole(scope.info)) { + scope.raiseError(errIllegalConstructor, node); + } + break; + case SyntaxKey::StaticMethod: + if (_logic->isRole(scope.info)) { + scope.raiseError(errIllegalStaticMethod, node); + } + break; + case SyntaxKey::StaticInitializerMethod: + compileStaticInitializerMethod(writer, scope, current); + break; + default: + break; + } + + current = current.nextNode(); + } + // if the VMT conatains newly defined generic / variadic handlers, overrides default one + if (testany(scope.info.header.flags, elWithGenerics | elWithVariadics) + && scope.info.methods.get(scope.moduleScope->buildins.dispatch_message).inherited) + { + compileCustomDispatcher(writer, scope); + } } -ObjectInfo Compiler :: compileFinalOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node) +void Compiler :: compileClassVMT(BuildTreeWriter& writer, ClassScope& classClassScope, ClassScope& scope, SyntaxNode node) { - ObjectInfo ehLocal = declareTempStructure(scope, { (int)scope.moduleScope->ehTableEntrySize, false }); + SyntaxNode current = node.firstChild(); + // first pass - compile constructors + while (current != SyntaxKey::None) { + switch (current.key) { + case SyntaxKey::Constructor: + { + MethodScope methodScope(&scope); + initializeMethod(classClassScope, methodScope, current); + methodScope.constructorMode = true; - int index1 = scope.newTempLocal(); + #ifdef FULL_OUTOUT_INFO + IdentifierString messageName; + ByteCodeUtil::resolveMessageName(messageName, scope.module, methodScope.message); - SyntaxNode finallyNode = node.findChild(SyntaxKey::FinallyBlock).firstChild(); - SyntaxNode opNode = node.firstChild(); - if (opNode.existChild(SyntaxKey::ClosureBlock)) - opNode = opNode.findChild(SyntaxKey::ClosureBlock); + _errorProcessor->info(infoCurrentMethod, *messageName); + #endif // FULL_OUTOUT_INFO - writer.newNode(BuildKey::FinalOp, ehLocal.argument); - writer.appendNode(BuildKey::Index, index1); + compileConstructor(writer, methodScope, classClassScope, current, scope.isAbstract()); + break; + } + default: + break; + } + current = current.nextNode(); + } - writer.newNode(BuildKey::Tape); - compileExpression(writer, scope, opNode, 0, EAttr::None, nullptr); - writer.closeNode(); + // second pass - compile static methods + current = node.firstChild(); + while (current != SyntaxKey::None) { + switch (current.key) { + case SyntaxKey::StaticMethod: + { + MethodScope methodScope(&classClassScope); + initializeMethod(classClassScope, methodScope, current); - if (finallyNode.existChild(SyntaxKey::ClosureBlock)) - finallyNode = finallyNode.findChild(SyntaxKey::ClosureBlock); +#ifdef FULL_OUTOUT_INFO + IdentifierString messageName; + ByteCodeUtil::resolveMessageName(messageName, scope.module, methodScope.message); - writer.newNode(BuildKey::Tape); - compileExpression(writer, scope, finallyNode, 0, EAttr::None, nullptr); - writer.closeNode(); + _errorProcessor->info(infoCurrentMethod, *messageName); +#endif // FULL_OUTOUT_INFO - writer.closeNode(); + compileMethod(writer, methodScope, current); - return {}; + break; + } + default: + break; + } + current = current.nextNode(); + } + + // if the VMT conatains newly defined generic / variadic handlers, overrides default one + if (testany(classClassScope.info.header.flags, elWithGenerics | elWithVariadics) + && classClassScope.info.methods.get(scope.moduleScope->buildins.dispatch_message).inherited) + { + compileCustomDispatcher(writer, classClassScope); + } } -ObjectInfo Compiler :: compileCatchOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node) +void Compiler :: compileExpressionMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode node) { - ObjectInfo ehLocal = declareTempStructure(scope, { (int)scope.moduleScope->ehTableEntrySize, false }); - - SyntaxNode catchNode = node.findChild(SyntaxKey::CatchDispatch); - SyntaxNode finallyNode = node.findChild(SyntaxKey::FinallyBlock).firstChild(); - SyntaxNode opNode = node.firstChild(); - if (opNode.existChild(SyntaxKey::ClosureBlock)) - opNode = opNode.findChild(SyntaxKey::ClosureBlock); + beginMethod(writer, scope, node, BuildKey::Method, false); - writer.newNode(BuildKey::CatchOp, ehLocal.argument); + CodeScope codeScope(&scope); - writer.newNode(BuildKey::Tape); - compileExpression(writer, scope, opNode, 0, EAttr::None, nullptr); - writer.closeNode(); + // new stack frame + writer.appendNode(BuildKey::OpenFrame); - writer.newNode(BuildKey::Tape); - compileMessageOperationR(writer, scope, { ObjectKind::Object }, - catchNode.firstChild().firstChild(), false); - writer.closeNode(); + // stack should contains current self reference + // the original message should be restored if it is a generic method + scope.selfLocal = codeScope.newLocal(); + writer.appendNode(BuildKey::Assigning, scope.selfLocal); - if (finallyNode != SyntaxKey::None) { - if (finallyNode.existChild(SyntaxKey::ClosureBlock)) - finallyNode = finallyNode.findChild(SyntaxKey::ClosureBlock); + compileRetExpression(writer, codeScope, node, EAttr::None); - writer.newNode(BuildKey::Tape); - compileExpression(writer, scope, finallyNode, 0, EAttr::None, nullptr); - writer.closeNode(); - } + writer.appendNode(BuildKey::CloseFrame); - writer.closeNode(); + codeScope.syncStack(&scope); - return { ObjectKind::Object }; + endMethod(writer, scope); } -ObjectInfo Compiler :: mapStringConstant(Scope& scope, SyntaxNode node) +void Compiler :: compileClosureMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode node) { - return { ObjectKind::StringLiteral, { V_STRING }, scope.module->mapConstant(node.identifier()) }; -} + ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); -ObjectInfo Compiler :: mapWideStringConstant(Scope& scope, SyntaxNode node) -{ - return { ObjectKind::WideStringLiteral, { V_WIDESTRING }, scope.module->mapConstant(node.identifier()) }; -} + beginMethod(writer, scope, node, BuildKey::Method, false); -ObjectInfo Compiler :: mapCharacterConstant(Scope& scope, SyntaxNode node) -{ - return { ObjectKind::CharacterLiteral, { V_WORD32 }, scope.module->mapConstant(node.identifier()) }; -} + CodeScope codeScope(&scope); -ObjectInfo Compiler :: mapConstant(Scope& scope, SyntaxNode node) -{ - return { ObjectKind::ConstantLiteral, { V_WORD32 }, scope.module->mapConstant(node.identifier()) }; -} + SyntaxNode current = node.firstChild(SyntaxKey::MemberMask); + switch (current.key) { + case SyntaxKey::CodeBlock: + case SyntaxKey::ReturnExpression: + compileMethodCode(writer, classScope, scope, codeScope, node, false); + break; + default: + break; + } -ObjectInfo Compiler :: mapIntConstant(Scope& scope, SyntaxNode node, int radix) -{ - int integer = StrConvertor::toInt(node.identifier(), radix); - if (errno == ERANGE) - scope.raiseError(errInvalidIntNumber, node); + codeScope.syncStack(&scope); - return { ObjectKind::IntLiteral, { V_INT32 }, ::mapIntConstant(scope.moduleScope, integer), integer }; + endMethod(writer, scope); } -ObjectInfo Compiler :: mapUIntConstant(Scope& scope, SyntaxNode node, int radix) +void Compiler :: compileClosureClass(BuildTreeWriter& writer, ClassScope& scope, SyntaxNode node) { - int integer = StrConvertor::toUInt(node.identifier(), radix); - if (errno == ERANGE) - scope.raiseError(errInvalidIntNumber, node); + bool lazyExpression = node == SyntaxKey::LazyOperation; + ref_t parentRef = scope.info.header.parentRef; - return { ObjectKind::IntLiteral, { V_INT32 }, ::mapUIntConstant(scope, integer), integer }; -} + writer.newNode(BuildKey::Class, scope.reference); -ObjectInfo Compiler :: mapLongConstant(Scope& scope, SyntaxNode node, int radix) -{ - long long integer = 0; + NamespaceScope* ns = Scope::getScope(scope, Scope::ScopeLevel::Namespace); + writer.appendNode(BuildKey::Path, *ns->sourcePath); - ustr_t val = node.identifier(); - if (val.endsWith("l")) { - String tmp(val); - tmp.truncate(tmp.length() - 1); + MethodScope methodScope(&scope); + declareClosureMessage(methodScope, node); - integer = StrConvertor::toLong(tmp.str(), radix); + methodScope.functionMode = true; + + mssg_t multiMethod = /*!lazyExpression && */defineMultimethod(scope, methodScope.message, false); + if (multiMethod) { + methodScope.info.multiMethod = multiMethod; + methodScope.info.outputRef = V_AUTO; } - else integer = StrConvertor::toLong(node.identifier(), radix); - if (errno == ERANGE) - scope.raiseError(errInvalidIntNumber, node); + if (lazyExpression) { + compileExpressionMethod(writer, methodScope, node); + } + else { + compileClosureMethod(writer, methodScope, node); - return { ObjectKind::LongLiteral, { V_INT64 }, ::mapLongConstant(scope, integer)}; -} + // HOTFIX : inject an output type if required or used super class + if (methodScope.info.outputRef == V_AUTO) { + methodScope.info.outputRef = scope.moduleScope->buildins.superReference; + } + } -inline bool defineFloat64Constant(ustr_t val, ModuleBase* module, ObjectInfo& retVal) -{ - double real = 0; + if (!lazyExpression) { + ref_t closureRef = resolveClosure(scope, methodScope.message, methodScope.info.outputRef); + if (closureRef) { + parentRef = closureRef; + } + else throw InternalError(errClosureError); + } + else parentRef = scope.moduleScope->buildins.lazyExpressionReference; - if (val.endsWith("r")) { - String tmp(val); - tmp.truncate(tmp.length() - 1); + declareClassParent(parentRef, scope, node); + generateClassFlags(scope, elNestedClass | elSealed); - real = StrConvertor::toDouble(tmp.str()); + // handle the abstract flag + if (test(scope.info.header.flags, elAbstract)) { + scope.abstractBasedMode = true; + scope.info.header.flags &= ~elAbstract; } - else real = StrConvertor::toDouble(val); - if (errno == ERANGE) - return false; - retVal = { ObjectKind::Float64Literal, { V_FLOAT64 }, ::mapFloat64Const(module, real) }; + auto m_it = scope.info.methods.getIt(methodScope.message); + if (!m_it.eof()) { + (*m_it).inherited = true; + (*m_it).hints &= ~(ref_t)MethodHint::Abstract; + } + else scope.info.methods.add(methodScope.message, methodScope.info); - return true; -} + if (multiMethod) { + SyntaxTree classTree; + SyntaxTreeWriter classWriter(classTree); -ObjectInfo Compiler :: mapFloat64Constant(Scope& scope, SyntaxNode node) -{ - ObjectInfo retVal = {}; + // build the class tree + classWriter.newNode(SyntaxKey::Root); + classWriter.newNode(SyntaxKey::Class, scope.reference); - if (!defineFloat64Constant(node.identifier(), scope.module, retVal)) { - scope.raiseError(errInvalidIntNumber, node); + SyntaxNode classNode = classWriter.CurrentNode(); + injectVirtualMultimethod(classNode, SyntaxKey::Method, *scope.moduleScope, scope.reference, scope.info, multiMethod); + + classWriter.closeNode(); + classWriter.closeNode(); + + SyntaxNode current = classNode.firstChild(); + while (current != SyntaxKey::None) { + generateMethodDeclaration(scope, current, false, false); + + current = current.nextNode(); + } + + _logic->injectOverloadList(this, *scope.moduleScope, scope.info, scope.reference); + + compileVMT(writer, scope, classNode); } - return retVal; + // set flags once again + // NOTE : it should be called after the code compilation to take into consideration outer fields + _logic->tweakClassFlags(*scope.moduleScope, scope.reference, scope.info, scope.isClassClass()); + + writer.closeNode(); + + scope.save(); } -ObjectInfo Compiler :: mapMessageConstant(Scope& scope, SyntaxNode node, ref_t actionRef) +bool isEmbeddableDispatcher(ModuleScopeBase* moduleScope, SyntaxNode current) { - pos_t argCount = 0; + SyntaxNode attr = current.firstChild(); + bool embeddable = false; + bool implicit = true; + while (attr != SyntaxKey::None) { + if (attr == SyntaxKey::Attribute) { + switch (attr.arg.reference) { + case V_EMBEDDABLE: + embeddable = true; + break; + case V_METHOD: + case V_CONSTRUCTOR: + case V_DISPATCHER: + implicit = false; + break; + } + } + else if (attr == SyntaxKey::Name && embeddable && implicit) { + if (moduleScope->attributes.get(attr.firstChild(SyntaxKey::TerminalMask).identifier()) == V_DISPATCHER) { + return true; + } + else break; + } - Interpreter interpreter(scope.moduleScope, _logic); - ObjectInfo retVal = evalExpression(interpreter, scope, node.findChild(SyntaxKey::Expression)); - switch (retVal.kind) { - case ObjectKind::IntLiteral: - argCount = retVal.extra; - break; - default: - scope.raiseError(errCannotEval, node); - break; + attr = attr.nextNode(); } - mssg_t message = encodeMessage(actionRef, argCount, 0); - IdentifierString messageName; - ByteCodeUtil::resolveMessageName(messageName, scope.module, message); - - ref_t constRef = scope.module->mapConstant(*messageName); - return { ObjectKind::MssgLiteral, { V_MESSAGE }, constRef }; + return false; } - -ObjectInfo Compiler :: mapExtMessageConstant(Scope& scope, SyntaxNode node, ref_t actionRef, ref_t extension) +void Compiler :: injectInterfaceDispatch(Scope& scope, SyntaxNode node, ref_t parentRef) { - pos_t argCount = 0; + SyntaxNode current = node.firstChild(); + while (current != SyntaxKey::None) { + if (current == SyntaxKey::Method && current.existChild(SyntaxKey::Redirect)) { + if (isEmbeddableDispatcher(scope.moduleScope, current)) { + SyntaxNode exprNode = current.findChild(SyntaxKey::Redirect).findChild(SyntaxKey::Expression); + SyntaxNode objNode = exprNode.firstChild(); + if (objNode.nextNode() != SyntaxKey::None) + scope.raiseError(errInvalidSyntax, node); + SyntaxNode terminalNode = objNode.firstChild(); - Interpreter interpreter(scope.moduleScope, _logic); - ObjectInfo retVal = evalExpression(interpreter, scope, node.findChild(SyntaxKey::Expression)); - switch (retVal.kind) { - case ObjectKind::IntLiteral: - argCount = retVal.extra; - break; - default: - scope.raiseError(errCannotEval, node); - break; - } + IdentifierString arg(terminalNode.identifier()); - mssg_t message = encodeMessage(actionRef, argCount, 0); - IdentifierString messageName; - ByteCodeUtil::resolveMessageName(messageName, scope.module, message); + VirtualMethods virtualMethods; + _logic->generateVirtualDispatchMethod(*scope.moduleScope, parentRef, virtualMethods); - size_t index = (*messageName).find('['); - assert(index != NOTFOUND_POS); // !! temporal + for (pos_t i = 0; i < virtualMethods.count_pos(); i++) { + auto methInfo = virtualMethods.get(i); - ustr_t extRefName = scope.moduleScope->resolveFullName(extension); - messageName.insert(">", index); - messageName.insert(extRefName, index); - if (isWeakReference(extRefName)) { - messageName.insert(scope.module->name(), index); - } - messageName.insert("<", index); + injectVirtualDispatchMethod(scope, node, methInfo.value1, methInfo.value2, terminalNode.key, *arg); + } - ref_t constRef = scope.module->mapConstant(*messageName); + // interface class should no have a custom dispatcher + current.setKey(SyntaxKey::Idle); - ref_t constType = V_EXTMESSAGE64; - switch (scope.moduleScope->ptrSize) { - case 4: - constType = V_EXTMESSAGE64; - break; - case 8: - constType = V_EXTMESSAGE128; - break; - default: - break; - } + return; + } + } - return { ObjectKind::ExtMssgLiteral, { constType, extension }, constRef }; + current = current.nextNode(); + } } -ObjectInfo Compiler :: defineTerminalInfo(Scope& scope, SyntaxNode node, TypeInfo declaredTypeInfo, bool variableMode, - bool forwardMode, bool refOp, bool mssgOp, bool memberMode, bool& invalid, ExpressionAttribute attrs) +void Compiler :: compileNestedClass(BuildTreeWriter& writer, ClassScope& scope, SyntaxNode node, ref_t parentRef) { - ObjectInfo retVal = {}; - bool ignoreDuplicates = EAttrs::testAndExclude(attrs, ExpressionAttribute::IgnoreDuplicate); - bool invalidForNonIdentifier = forwardMode || variableMode || refOp || mssgOp || memberMode; + NamespaceScope* ns = Scope::getScope(scope, Scope::ScopeLevel::Namespace); + scope.info.header.flags |= elNestedClass; - switch (node.key) { - case SyntaxKey::TemplateType: - { - TypeAttributes typeAttributes = {}; - TypeInfo typeInfo = resolveTypeAttribute(scope, node, typeAttributes, false, false); - retVal = { ObjectKind::Class, typeInfo, 0u }; - - retVal = mapClassSymbol(scope, retrieveStrongType(scope, retVal)); - break; + bool virtualClass = true; + // NOTE : check if it is in-place initialization + SyntaxNode current = node.firstChild(); + while (current != SyntaxKey::None) { + switch (current.key) { + case SyntaxKey::Field: + case SyntaxKey::Method: + virtualClass = false; + break; + default: + break; } - case SyntaxKey::globalreference: - invalid = variableMode; - retVal = scope.mapGlobal(node.identifier()); - break; - case SyntaxKey::identifier: - case SyntaxKey::reference: - if (variableMode) { - invalid = forwardMode; - - if (declareVariable(scope, node, declaredTypeInfo, ignoreDuplicates)) { - retVal = scope.mapIdentifier(node.identifier(), node.key == SyntaxKey::reference, - attrs | ExpressionAttribute::Local); - - if (_trackingUnassigned && refOp) { - scope.markAsAssigned(retVal); - } - } - else retVal = scope.mapIdentifier(node.identifier(), node.key == SyntaxKey::reference, attrs); - } - else if (forwardMode) { - IdentifierString forwardName(FORWARD_PREFIX_NS, node.identifier()); - - retVal = scope.mapIdentifier(*forwardName, true, attrs); - } - else if (memberMode) { - retVal = scope.mapMember(node.identifier()); - } - else retVal = scope.mapIdentifier(node.identifier(), node.key == SyntaxKey::reference, attrs); - if (refOp) { - switch (retVal.kind) { - case ObjectKind::LocalAddress: - retVal.typeInfo = { V_WRAPPER, retVal.typeInfo.typeRef }; - break; - case ObjectKind::ParamAddress: - retVal.typeInfo = { V_WRAPPER, retVal.typeInfo.typeRef }; - break; - case ObjectKind::Local: - retVal.kind = ObjectKind::RefLocal; - retVal.typeInfo = { V_WRAPPER, retVal.typeInfo.typeRef }; - break; - case ObjectKind::ByRefParam: - // allowing to pass by ref parameter directly - retVal.kind = ObjectKind::ParamReference; - retVal.typeInfo = { V_WRAPPER, retVal.typeInfo.typeRef }; - break; - case ObjectKind::ByRefParamAddress: - // allowing to pass by ref parameter directly - retVal.kind = ObjectKind::ParamAddress; - retVal.typeInfo = { V_WRAPPER, retVal.typeInfo.typeRef }; - //retVal.mode = TargetMode::UnboxingRequired; - break; - default: - invalid = true; - break; - } - } - break; - case SyntaxKey::string: - invalid = invalidForNonIdentifier; + current = current.nextNode(); + } - retVal = mapStringConstant(scope, node); - break; - case SyntaxKey::wide: - invalid = invalidForNonIdentifier; + if (virtualClass) + scope.info.header.flags |= elVirtualVMT; - retVal = mapWideStringConstant(scope, node); - break; - case SyntaxKey::character: - invalid = invalidForNonIdentifier; + declareClassParent(parentRef, scope, node); - retVal = mapCharacterConstant(scope, node); - break; - case SyntaxKey::integer: - invalid = invalidForNonIdentifier; + ref_t dummy = 0; + declareClassAttributes(scope, {}, dummy); - retVal = mapIntConstant(scope, node, 10); - break; - case SyntaxKey::hexinteger: - invalid = invalidForNonIdentifier; + if (scope.abstractBasedMode && test(scope.info.header.flags, elClosed | elNoCustomDispatcher)) + { + // COMPILER MAGIC : inject interface implementation if dispatch method available + injectInterfaceDispatch(scope, node, scope.info.header.parentRef); + } - retVal = mapUIntConstant(scope, node, 16); - break; - case SyntaxKey::longinteger: - invalid = invalidForNonIdentifier; + bool withConstructors = false; + bool withDefaultConstructor = false; + bool yieldMethodNotAllowed = true; + declareVMT(scope, node, withConstructors, withDefaultConstructor, yieldMethodNotAllowed, true, false); + if (withConstructors) + scope.raiseError(errIllegalConstructor, node); - retVal = mapLongConstant(scope, node, 10); - break; - case SyntaxKey::real: - invalid = invalidForNonIdentifier; + generateClassDeclaration(scope, node, elNestedClass | elSealed); - retVal = mapFloat64Constant(scope, node); - break; - case SyntaxKey::constant: - invalid = invalidForNonIdentifier; + scope.save(); - retVal = mapConstant(scope, node); - break; - default: - // to make compiler happy - invalid = true; - break; - } + BuildNode buildNode = writer.CurrentNode(); + while (buildNode != BuildKey::Root) + buildNode = buildNode.parentNode(); - if (EAttrs::test(attrs, EAttr::Weak)) { - assert(retVal.mode == TargetMode::None); - retVal.mode = TargetMode::Weak; - } + BuildTreeWriter nestedWriter(buildNode); - return retVal; -} + nestedWriter.newNode(BuildKey::Class, scope.reference); -ObjectInfo Compiler :: mapTerminal(Scope& scope, SyntaxNode node, TypeInfo declaredTypeInfo, EAttr attrs) -{ - bool forwardMode = EAttrs::testAndExclude(attrs, ExpressionAttribute::Forward); - bool variableMode = EAttrs::testAndExclude(attrs, ExpressionAttribute::NewVariable); - bool externalOp = EAttrs::testAndExclude(attrs, ExpressionAttribute::Extern); - bool newOp = EAttrs::testAndExclude(attrs, ExpressionAttribute::NewOp); - bool castOp = EAttrs::testAndExclude(attrs, ExpressionAttribute::CastOp); - bool refOp = EAttrs::testAndExclude(attrs, ExpressionAttribute::RefOp); - bool mssgOp = EAttrs::testAndExclude(attrs, ExpressionAttribute::MssgNameLiteral); - bool probeMode = EAttrs::testAndExclude(attrs, ExpressionAttribute::ProbeMode); - bool memberMode = EAttrs::testAndExclude(attrs, ExpressionAttribute::Member); + nestedWriter.appendNode(BuildKey::Path, *ns->sourcePath); - ObjectInfo retVal; - bool invalid = false; - if (externalOp) { - auto externalInfo = mapExternal(scope, node); - switch (externalInfo.type) { - case ExternalType::WinApi: - return { ObjectKind::Extern, {}, externalInfo.reference, 0, TargetMode::WinApi }; - default: - return { ObjectKind::Extern, {}, externalInfo.reference, 0, TargetMode::External }; - } - } - else if (newOp || castOp) { - if (node.key == SyntaxKey::identifier && EAttrs::testAndExclude(attrs, ExpressionAttribute::RetrievingType)) { - auto varInfo = scope.mapIdentifier(node.identifier(), false, attrs); - if (varInfo.kind != ObjectKind::Unknown) { - retVal = { ObjectKind::Class, varInfo.typeInfo, 0u, newOp ? TargetMode::Creating : TargetMode::Casting }; - } - else return varInfo; - } - else { - switch (node.key) { - case SyntaxKey::TemplateType: - case SyntaxKey::ArrayType: - case SyntaxKey::Type: - case SyntaxKey::identifier: - case SyntaxKey::reference: - { - TypeAttributes typeAttributes = {}; - TypeInfo typeInfo = resolveTypeAttribute(scope, node, typeAttributes, false, false); + compileVMT(nestedWriter, scope, node, true, true); - retVal = { ObjectKind::Class, typeInfo, 0u, newOp ? TargetMode::Creating : TargetMode::Casting }; - if (CompilerLogic::isPrimitiveArrRef(retVal.typeInfo.typeRef) && newOp) - retVal.mode = TargetMode::CreatingArray; - break; - } - default: - invalid = true; - break; - } - } - } - else if (mssgOp) { - switch (node.key) { - case SyntaxKey::identifier: - { - retVal = { ObjectKind::MssgNameLiteral, { V_MESSAGENAME }, - scope.module->mapAction(node.identifier(), 0, false) }; - break; - } - default: - invalid = true; - break; - } - } - else retVal = defineTerminalInfo(scope, node, declaredTypeInfo, variableMode, forwardMode, - refOp, mssgOp, memberMode, invalid, attrs); + // set flags once again + // NOTE : it should be called after the code compilation to take into consideration outer fields + _logic->tweakClassFlags(*scope.moduleScope, scope.reference, scope.info, scope.isClassClass()); - if (invalid) - scope.raiseError(errInvalidOperation, node); + // NOTE : compile once again only auto generated methods + compileVMT(nestedWriter, scope, node, true, false); - if (probeMode) - retVal.mode = TargetMode::Probe; + nestedWriter.closeNode(); - return retVal; + scope.save(); } -inline SyntaxNode retrieveTerminalOrType(SyntaxNode node) +void Compiler :: validateClassFields(ClassScope& scope, SyntaxNode node) { - if (test((unsigned int)node.key, (unsigned int)SyntaxKey::TerminalMask)) - return node; - SyntaxNode current = node.firstChild(); - SyntaxNode last = {}; while (current != SyntaxKey::None) { - if (test((unsigned int)current.key, (unsigned int)SyntaxKey::TerminalMask)) { - last = current; - } - else if (current == SyntaxKey::ArrayType || current == SyntaxKey::Type || current == SyntaxKey::TemplateType) { - last = current; + if (current == SyntaxKey::Field) { + FieldAttributes attrs = {}; + readFieldAttributes(scope, current, attrs, false); + + if (attrs.isConstant) { + ustr_t name = current.findChild(SyntaxKey::Name).firstChild(SyntaxKey::TerminalMask).identifier(); + + auto fieldInfo = scope.info.statics.get(name); + if (fieldInfo.valueRef == INVALID_REF) + scope.raiseError(errNoInitializer, current.findChild(SyntaxKey::Name)); + } } current = current.nextNode(); } - - return last; } -ObjectInfo Compiler :: mapObject(Scope& scope, SyntaxNode node, EAttrs mode) +void Compiler :: compileClass(BuildTreeWriter& writer, ClassScope& scope, SyntaxNode node) { - SyntaxNode terminalNode = retrieveTerminalOrType(node); +#ifdef FULL_OUTOUT_INFO + // info + ustr_t name = scope.module->resolveReference(scope.reference); + _errorProcessor->info(infoCurrentClass, name); +#endif // FULL_OUTOUT_INFO - TypeInfo declaredTypeInfo = {}; - declareExpressionAttributes(scope, node, declaredTypeInfo, mode); - if (mode.test(EAttr::Lookahead)) { - if (mode.test(EAttr::NewVariable)) { - return { ObjectKind::NewVariable, declaredTypeInfo, 0, 0 }; - } - else if (mode.test(EAttr::MssgNameLiteral)) { - if (declaredTypeInfo.typeRef) { - SyntaxNode actionTerminal = terminalNode.findChild(SyntaxKey::identifier); - if (actionTerminal != SyntaxKey::None) { - return { ObjectKind::ExtMssgLiteral, { V_MESSAGE, declaredTypeInfo.typeRef }, - scope.module->mapAction(actionTerminal.identifier(), 0, false) }; - } - } - else return { ObjectKind::MssgLiteral, { V_MESSAGE }, - scope.module->mapAction(terminalNode.identifier(), 0, false) }; - } - return {}; - } + NamespaceScope* ns = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - if (terminalNode.nextNode() == SyntaxKey::TemplateArg && !EAttrs::test(mode.attrs, ExpressionAttribute::NewOp)) { - scope.raiseError(errInvalidSyntax, node); + // validate field types + if (scope.info.fields.count() > 0 || scope.info.statics.count() > 0) { + validateClassFields(scope, node); } - ObjectInfo retVal = mapTerminal(scope, terminalNode, declaredTypeInfo, mode.attrs); - - return retVal; -} + writer.newNode(BuildKey::Class, scope.reference); + writer.appendNode(BuildKey::Path, *ns->sourcePath); -ObjectInfo Compiler :: declareTempLocal(ExprScope& scope, ref_t typeRef, bool dynamicOnly) -{ - SizeInfo sizeInfo = {}; - if (!dynamicOnly) { - sizeInfo = _logic->defineStructSize(*scope.moduleScope, typeRef); - } - if (sizeInfo.size > 0) { - ObjectInfo tempStruct = declareTempStructure(scope, sizeInfo); - tempStruct.typeInfo = { typeRef }; + compileVMT(writer, scope, node); + writer.closeNode(); - return tempStruct; - } - else { - int tempLocal = scope.newTempLocal(); - return { ObjectKind::TempLocal, { typeRef }, (ref_t)tempLocal }; - } + scope.save(); + // compile explicit symbol + compileClassSymbol(writer, scope); } -ObjectInfo Compiler :: saveToTempLocal(BuildTreeWriter& writer, ExprScope& scope, ObjectInfo object) +void Compiler :: compileClassClass(BuildTreeWriter& writer, ClassScope& classClassScope, ClassScope& scope, + SyntaxNode node) { - if (object.kind == ObjectKind::Extern) { - auto sizeInfo = _logic->defineStructSize(*scope.moduleScope, object.typeInfo.typeRef); - int tempLocal = allocateLocalAddress(scope, sizeInfo.size, false); - - if (sizeInfo.size == 8) { - writer.appendNode(BuildKey::SavingLongIndex, tempLocal); - } - else writer.appendNode(BuildKey::SavingIndex, tempLocal); - - return { ObjectKind::TempLocalAddress, object.typeInfo, (ref_t)tempLocal }; - } - else if (object.kind == ObjectKind::FloatExtern) { - auto sizeInfo = _logic->defineStructSize(*scope.moduleScope, object.typeInfo.typeRef); - int tempLocal = allocateLocalAddress(scope, sizeInfo.size, false); - - writer.appendNode(BuildKey::SavingFloatIndex, tempLocal); +#ifdef FULL_OUTOUT_INFO + // info + ustr_t name = scope.module->resolveReference(scope.reference); + _errorProcessor->info(infoCurrentClass, name); +#endif // FULL_OUTOUT_INFO - return { ObjectKind::TempLocalAddress, object.typeInfo, (ref_t)tempLocal }; - } - else { - WriterContext context = { &writer, &scope, {} }; + NamespaceScope* ns = Scope::getScope(classClassScope, Scope::ScopeLevel::Namespace); - int tempLocal = scope.newTempLocal(); - writeObjectInfo(context, object); - writer.appendNode(BuildKey::Assigning, tempLocal); + writer.newNode(BuildKey::Class, classClassScope.reference); + writer.appendNode(BuildKey::Path, *ns->sourcePath); - return { ObjectKind::TempLocal, object.typeInfo, (ref_t)tempLocal }; - } + compileClassVMT(writer, classClassScope, scope, node); + writer.closeNode(); } -ObjectInfo Compiler :: compileObject(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, - ExpressionAttribute mode, ArgumentsInfo* updatedOuterArgs) +void Compiler :: compileNamespace(BuildTreeWriter& writer, NamespaceScope& ns, SyntaxNode node) { - if (node == SyntaxKey::Object) { - ObjectInfo retVal = mapObject(scope, node, mode); - switch (retVal.kind) { - case ObjectKind::ConstantLiteral: + SyntaxNode current = node.firstChild(); + while (current != SyntaxKey::None) { + switch (current.key) { + case SyntaxKey::SourcePath: + ns.sourcePath.copy(current.identifier()); + break; + case SyntaxKey::Namespace: { - ArgumentsInfo arguments; - ref_t typeRef = scope.moduleScope->buildins.literalReference; - ref_t signRef = scope.module->mapSignature(&typeRef, 1, false); + NamespaceScope namespaceScope(&ns); + declareNamespace(namespaceScope, current, false, false); + copyParentNamespaceExtensions(ns, namespaceScope); - return compileNewOp(writer, scope, node, retVal, signRef, arguments); + compileNamespace(writer, namespaceScope, current); + break; } - case ObjectKind::Unknown: - scope.raiseError(errUnknownObject, node.lastChild(SyntaxKey::TerminalMask)); + case SyntaxKey::Symbol: + { + SymbolScope symbolScope(&ns, current.arg.reference, ns.defaultVisibility); + symbolScope.isStatic = SyntaxTree::ifChildExists(current, SyntaxKey::Attribute, V_STATIC); + symbolScope.visibility = ns.moduleScope->retrieveVisibility(symbolScope.reference); + + compileSymbol(writer, symbolScope, current); + break; + } + case SyntaxKey::Class: + { + ClassScope classScope(&ns, current.arg.reference, ns.defaultVisibility); + ns.moduleScope->loadClassInfo(classScope.info, current.arg.reference, false); + classScope.abstractMode = test(classScope.info.header.flags, elAbstract); + if (test(classScope.info.header.flags, elExtension)) + classScope.extensionClassRef = classScope.getAttribute(ClassAttribute::ExtensionRef); + + compileClass(writer, classScope, current); + + // compile class class if it available + if (classScope.info.header.classRef != classScope.reference && classScope.info.header.classRef != 0) { + ClassClassScope classClassScope(&ns, classScope.info.header.classRef, classScope.visibility, &classScope.info); + ns.moduleScope->loadClassInfo(classClassScope.info, classClassScope.reference, false); + + compileClassClass(writer, classClassScope, classScope, current); + } break; + } default: + // to make compiler happy break; } - return retVal; + current = current.nextNode(); } - else return compileExpression(writer, scope, node, 0, mode, updatedOuterArgs); } -ObjectInfo Compiler :: typecastObject(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, ObjectInfo source, ref_t targetRef) +inline ref_t safeMapReference(ModuleScopeBase* moduleScope, ForwardResolverBase* forwardResolver, ustr_t forward) { - if (targetRef == scope.moduleScope->buildins.superReference) - return source; - - ustr_t refName2 = scope.module->resolveReference(targetRef); - - ref_t signRef = scope.module->mapSignature(&targetRef, 1, false); - ref_t actionRef = scope.module->mapAction(CAST_MESSAGE, signRef, false); - - mssg_t typecastMssg = encodeMessage(actionRef, 1, CONVERSION_MESSAGE); - - ArgumentsInfo arguments; - arguments.add(source); - - ObjectInfo retVal = compileMessageOperation(writer, scope, node, source, typecastMssg, - 0, arguments, EAttr::None, nullptr); - // NOTE : typecasting message is guaranteed to return the instance of the target type - retVal.typeInfo = { targetRef }; - - return retVal; + ustr_t resolved = forwardResolver->resolveForward(forward); + if (!resolved.empty()) { + if (moduleScope->isStandardOne()) { + return moduleScope->module->mapReference(resolved + getlength(STANDARD_MODULE)); + } + else return moduleScope->importReference(moduleScope->module, resolved); + } + else return 0; } -inline bool isNormalConstant(ObjectInfo info) +inline ref_t safeMapWeakReference(ModuleScopeBase* moduleScope, ForwardResolverBase* forwardResolver, ustr_t forward) { - switch (info.kind) { - case ObjectKind::StringLiteral: - return true; - default: - return false; + ustr_t resolved = forwardResolver->resolveForward(forward); + if (!emptystr(resolved)) { + // HOTFIX : for the standard module the references should be mapped forcefully + if (moduleScope->isStandardOne()) { + return moduleScope->module->mapReference(resolved + getlength(STANDARD_MODULE), false); + } + else return moduleScope->module->mapReference(resolved, false); } + else return 0; } -ObjectInfo Compiler :: convertIntLiteral(ExprScope& scope, SyntaxNode node, ObjectInfo source, ref_t targetRef, bool ignoreError) +inline void addPackageItem(SyntaxTreeWriter& writer, ModuleBase* module, ustr_t str) { - bool invalid = false; - switch (targetRef) { - case V_UINT8: - invalid = source.extra < 0 || source.extra > 255; - break; - case V_INT8: - invalid = source.extra < INT8_MIN || source.extra > INT8_MAX; - break; - case V_INT16: - invalid = source.extra < INT16_MIN || source.extra > INT16_MAX; - break; - case V_UINT16: - invalid = source.extra < 0 || source.extra > 65535; - break; - case V_INT64: - source.kind = ObjectKind::LongLiteral; - break; - case V_FLOAT64: - source.kind = ObjectKind::Float64Literal; - source.reference = mapFloat64Const(scope.module, source.extra); - break; - default: - invalid = true; - break; + writer.newNode(SyntaxKey::Expression); + writer.newNode(SyntaxKey::Object); + if (emptystr(str)) { + writer.appendNode(SyntaxKey::string, ""); } - - if (invalid) { - if (!ignoreError) - scope.raiseError(errInvalidOperation, node); + else writer.appendNode(SyntaxKey::string, str); + writer.closeNode(); + writer.closeNode(); +} - return {}; - } +void Compiler :: createPackageInfo(ModuleScopeBase* moduleScope, ManifestInfo& manifestInfo) +{ + ReferenceName sectionName("", PACKAGE_SECTION); + ref_t packageRef = moduleScope->module->mapReference(*sectionName); - source.typeInfo = { targetRef }; + SyntaxTree tempTree; + SyntaxTreeWriter tempWriter(tempTree); - return source; -} + tempWriter.newNode(SyntaxKey::PrimitiveCollection, packageRef); -ObjectInfo Compiler :: convertObject(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, ObjectInfo source, - ref_t targetRef, bool dynamicRequired, bool withoutBoxing) -{ - WriterContext context = { &writer, &scope, node }; - if (!_logic->isCompatible(*scope.moduleScope, { targetRef }, source.typeInfo, false)) { - if (source.kind == ObjectKind::Default) { - if (_logic->isEmbeddable(*context.scope->moduleScope, targetRef)) { - ObjectInfo classSymbol = mapClassSymbol(*context.scope, targetRef); + // namespace + addPackageItem(tempWriter, moduleScope->module, moduleScope->module->name()); - ArgumentsInfo arguments; + // package name + addPackageItem(tempWriter, moduleScope->module, manifestInfo.maninfestName); - CheckMethodResult dummy = {}; - if (_logic->resolveCallType(*scope.moduleScope, classSymbol.typeInfo.typeRef, scope.moduleScope->buildins.constructor_message, dummy) - && (dummy.visibility == Visibility::Public || (dummy.visibility == Visibility::Protected && isSelfCall(classSymbol)))) - { - return compileNewOp(*context.writer, *context.scope, context.node, - classSymbol, 0, arguments); - } - else { - // BAD LUCK : Default property should be returned - arguments.add(classSymbol); + // package version + addPackageItem(tempWriter, moduleScope->module, manifestInfo.maninfestVersion); - return compileWeakOperation(writer, scope, node, nullptr, 0, classSymbol, - arguments, scope.moduleScope->buildins.default_message, targetRef, nullptr); + // package author + addPackageItem(tempWriter, moduleScope->module, manifestInfo.maninfestAuthor); - } - } - else return { ObjectKind::Nil, { V_NIL } }; - } + tempWriter.closeNode(); - if (source.typeInfo.typeRef == V_WRAPPER) { - // unbox wrapper for the conversion - source.typeInfo = { source.typeInfo.elementRef }; - } - NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - - auto conversionRoutine = _logic->retrieveConversionRoutine(this, *scope.moduleScope, *nsScope->nsName, - targetRef, source.typeInfo); - if (!withoutBoxing && conversionRoutine.result == ConversionResult::BoxingRequired) { - // if it is implcitily compatible - switch (source.kind) { - case ObjectKind::TempLocalAddress: - case ObjectKind::LocalAddress: - case ObjectKind::IntLiteral: - case ObjectKind::MssgLiteral: - case ObjectKind::CharacterLiteral: - case ObjectKind::RefLocal: - case ObjectKind::ParamReference: - source.typeInfo.typeRef = targetRef; - break; - case ObjectKind::SelfBoxableLocal: - case ObjectKind::ParamAddress: - if (source.mode == TargetMode::Conditional && source.typeInfo.typeRef != targetRef) { - source.mode = TargetMode::None; - source.typeInfo.typeRef = targetRef; - - return source; - } - else source.typeInfo.typeRef = targetRef; - break; - default: - if (source.kind == ObjectKind::SelfLocal && source.mode == TargetMode::ArrayContent) { - source.typeInfo.typeRef = targetRef; - source.kind = ObjectKind::SelfBoxableLocal; - } - else return boxArgument(context, source, false, true, false, targetRef); - } - } - else if (conversionRoutine.result == ConversionResult::VariadicBoxingRequired) { - switch (source.kind) { - case ObjectKind::VArgParam: - source.typeInfo.typeRef = targetRef; - break; - default: - assert(false); - break; - } - - } - else if (conversionRoutine.result == ConversionResult::Conversion) { - if (!dynamicRequired && source.kind == ObjectKind::IntLiteral && _logic->isNumericType(*scope.moduleScope, targetRef)) { - // HOTFIX : convert int literal in place - source = convertIntLiteral(scope, node, source, targetRef); - } - else { - ArgumentsInfo arguments; - arguments.add(source); - ref_t typeRef = retrieveStrongType(scope, source); - ref_t signRef = scope.module->mapSignature(&typeRef, 1, false); - - return compileNewOp(writer, scope, node, mapClassSymbol(scope, targetRef), - signRef, arguments); - } - } - else if (conversionRoutine.result == ConversionResult::DynamicConversion) { - ArgumentsInfo arguments; - arguments.add(source); - - return compileNewOp(writer, scope, node, mapClassSymbol(scope, targetRef), - 0, arguments); - } - else if (conversionRoutine.result == ConversionResult::NativeConversion) { - if (source.kind == ObjectKind::IntLiteral && _logic->isNumericType(*scope.moduleScope, targetRef)) { - // HOTFIX : convert int literal in place - source = convertIntLiteral(scope, node, source, targetRef); - } - else source = compileNativeConversion(writer, scope, node, source, conversionRoutine.operationKey); - } - else source = typecastObject(writer, scope, node, source, targetRef); - } - - return source; + Interpreter interpreter(moduleScope, _logic); + MetaScope scope(nullptr, Scope::ScopeLevel::Namespace); + scope.module = moduleScope->module; + scope.moduleScope = moduleScope; + evalCollection(interpreter, scope, tempTree.readRoot(), true, false); } -ObjectInfo Compiler :: compileNestedExpression(BuildTreeWriter& writer, InlineClassScope& scope, ExprScope& ownerScope, - EAttr mode, ArgumentsInfo* updatedOuterArgs) +void Compiler :: prepare(ModuleScopeBase* moduleScope, ForwardResolverBase* forwardResolver, + ManifestInfo& manifestInfo) { - bool paramMode = EAttrs::test(mode, EAttr::Parameter); - ref_t nestedRef = scope.reference; - if (test(scope.info.header.flags, elVirtualVMT)) - nestedRef = scope.info.header.parentRef; - - if (test(scope.info.header.flags, elStateless)) { - ObjectInfo retVal = { ObjectKind::Singleton, { nestedRef }, nestedRef }; - - return retVal; - } - else { - WriterContext context = { &writer, &ownerScope, {} }; - - ObjectInfo retVal = { ObjectKind::Object, { nestedRef }, 0 }; - - ArgumentsInfo list; - // first pass : box an argument if required - for (auto it = scope.outers.start(); !it.eof(); ++it) { - ObjectInfo arg = (*it).outerObject; - - arg = boxArgument(context, arg, false, false, false); - switch (arg.kind) { - case ObjectKind::Field: - case ObjectKind::ReadOnlyField: - case ObjectKind::Outer: - case ObjectKind::OuterField: - case ObjectKind::OuterSelf: - arg = saveToTempLocal(writer, ownerScope, arg); - break; - default: - break; - } - - list.add(arg); - } - - writer.newNode(BuildKey::CreatingClass, scope.info.fields.count()); - writer.appendNode(BuildKey::Type, nestedRef); - writer.closeNode(); - - if (scope.outers.count() != scope.info.fields.count()) { - if (scope.info.fields.count() != 0) { - writer.appendNode(BuildKey::FillOp, scope.info.fields.count()); - } - } - - // second pass : fill members - int argIndex = 0; - int preservedClosure = 0; - for (auto it = scope.outers.start(); !it.eof(); ++it) { - ObjectInfo source = (*it).outerObject; - ObjectInfo arg = list[argIndex]; - - auto fieldInfo = scope.info.fields.get(it.key()); + _trackingUnassigned = (_errorProcessor->getWarningLevel() == WarningLevel::Level3); - switch (arg.kind) { - case ObjectKind::SelfLocal: - case ObjectKind::Local: - case ObjectKind::TempLocal: - case ObjectKind::Param: - writer.appendNode(BuildKey::AssignLocalToStack, arg.reference); - writer.appendNode(BuildKey::SetImmediateField, fieldInfo.offset); - break; - default: - // NOTE : should neve be hit - assert(false); - break; - } + loadMetaData(moduleScope, forwardResolver, PREDEFINED_MAP); + loadMetaData(moduleScope, forwardResolver, ATTRIBUTES_MAP); + loadMetaData(moduleScope, forwardResolver, OPERATION_MAP); + loadMetaData(moduleScope, forwardResolver, ALIASES_MAP); - if (updatedOuterArgs && (*it).updated) { - if (!preservedClosure) { - updatedOuterArgs->add({ ObjectKind::ClosureInfo }); - // reserve place for the closure - preservedClosure = updatedOuterArgs->count_pos(); - updatedOuterArgs->add({ }); - } + // cache the frequently used references + moduleScope->buildins.superReference = safeMapReference(moduleScope, forwardResolver, SUPER_FORWARD); + moduleScope->buildins.nilValueReference = safeMapReference(moduleScope, forwardResolver, NILVALUE_FORWARD); + moduleScope->buildins.intReference = safeMapReference(moduleScope, forwardResolver, INTLITERAL_FORWARD); + moduleScope->buildins.longReference = safeMapReference(moduleScope, forwardResolver, LONGLITERAL_FORWARD); + moduleScope->buildins.realReference = safeMapReference(moduleScope, forwardResolver, REALLITERAL_FORWARD); + moduleScope->buildins.shortReference = safeMapReference(moduleScope, forwardResolver, INT16LITERAL_FORWARD); + moduleScope->buildins.ushortReference = safeMapReference(moduleScope, forwardResolver, UINT16LITERAL_FORWARD); + moduleScope->buildins.int8Reference = safeMapReference(moduleScope, forwardResolver, INT8LITERAL_FORWARD); + moduleScope->buildins.uint8Reference = safeMapReference(moduleScope, forwardResolver, UINT8LITERAL_FORWARD); + moduleScope->buildins.literalReference = safeMapReference(moduleScope, forwardResolver, LITERAL_FORWARD); + moduleScope->buildins.wideReference = safeMapReference(moduleScope, forwardResolver, WIDELITERAL_FORWARD); + moduleScope->buildins.messageReference = safeMapReference(moduleScope, forwardResolver, MESSAGE_FORWARD); + moduleScope->buildins.messageNameReference = safeMapReference(moduleScope, forwardResolver, MESSAGE_NAME_FORWARD); + moduleScope->buildins.extMessageReference = safeMapReference(moduleScope, forwardResolver, EXT_MESSAGE_FORWARD); + moduleScope->buildins.wrapperTemplateReference = safeMapReference(moduleScope, forwardResolver, WRAPPER_FORWARD); + moduleScope->buildins.arrayTemplateReference = safeMapReference(moduleScope, forwardResolver, ARRAY_FORWARD); + moduleScope->buildins.argArrayTemplateReference = safeMapReference(moduleScope, forwardResolver, VARIADIC_ARRAY_FORWARD); + moduleScope->buildins.nullableTemplateReference = safeMapReference(moduleScope, forwardResolver, NULLABLE_FORWARD); - updatedOuterArgs->add({ ObjectKind::MemberInfo, (*it).reference }); - updatedOuterArgs->add(source); - } + moduleScope->buildins.closureTemplateReference = safeMapWeakReference(moduleScope, forwardResolver, CLOSURE_FORWARD); + moduleScope->buildins.tupleTemplateReference = safeMapWeakReference(moduleScope, forwardResolver, TUPLE_FORWARD); + moduleScope->buildins.lazyExpressionReference = safeMapWeakReference(moduleScope, forwardResolver, LAZY_FORWARD); + moduleScope->buildins.uintReference = safeMapReference(moduleScope, forwardResolver, UINT_FORWARD); + moduleScope->buildins.pointerReference = safeMapReference(moduleScope, forwardResolver, PTR_FORWARD); - argIndex++; - } + moduleScope->branchingInfo.typeRef = safeMapReference(moduleScope, forwardResolver, BOOL_FORWARD); + moduleScope->branchingInfo.trueRef = safeMapReference(moduleScope, forwardResolver, TRUE_FORWARD); + moduleScope->branchingInfo.falseRef = safeMapReference(moduleScope, forwardResolver, FALSE_FORWARD); - // call init handler if is available - if (scope.info.methods.exist(scope.moduleScope->buildins.init_message)) { - compileInlineInitializing(writer, scope, {}); - } + // cache the frequently used messages + moduleScope->buildins.dispatch_message = encodeMessage( + moduleScope->module->mapAction(DISPATCH_MESSAGE, 0, false), 1, 0); + moduleScope->buildins.constructor_message = + encodeMessage(moduleScope->module->mapAction(CONSTRUCTOR_MESSAGE, 0, false), + 0, FUNCTION_MESSAGE); + moduleScope->buildins.protected_constructor_message = + encodeMessage(moduleScope->module->mapAction(CONSTRUCTOR_MESSAGE2, 0, false), + 0, FUNCTION_MESSAGE); + moduleScope->buildins.init_message = + encodeMessage(moduleScope->module->mapAction(INIT_MESSAGE, 0, false), + 1, STATIC_MESSAGE); + moduleScope->buildins.invoke_message = encodeMessage( + moduleScope->module->mapAction(INVOKE_MESSAGE, 0, false), 1, FUNCTION_MESSAGE); + moduleScope->buildins.add_message = + encodeMessage(moduleScope->module->mapAction(ADD_MESSAGE, 0, false), + 2, 0); + moduleScope->buildins.sub_message = + encodeMessage(moduleScope->module->mapAction(SUB_MESSAGE, 0, false), + 2, 0); + moduleScope->buildins.mul_message = + encodeMessage(moduleScope->module->mapAction(MUL_MESSAGE, 0, false), + 2, 0); + moduleScope->buildins.div_message = + encodeMessage(moduleScope->module->mapAction(DIV_MESSAGE, 0, false), + 2, 0); + moduleScope->buildins.band_message = + encodeMessage(moduleScope->module->mapAction(BAND_MESSAGE, 0, false), + 2, 0); + moduleScope->buildins.bor_message = + encodeMessage(moduleScope->module->mapAction(BOR_MESSAGE, 0, false), + 2, 0); + moduleScope->buildins.shl_message = + encodeMessage(moduleScope->module->mapAction(SHL_MESSAGE, 0, false), + 2, 0); + moduleScope->buildins.shr_message = + encodeMessage(moduleScope->module->mapAction(SHR_MESSAGE, 0, false), + 2, 0); + moduleScope->buildins.bxor_message = + encodeMessage(moduleScope->module->mapAction(BXOR_MESSAGE, 0, false), + 2, 0); + moduleScope->buildins.and_message = + encodeMessage(moduleScope->module->mapAction(AND_MESSAGE, 0, false), + 2, 0); + moduleScope->buildins.or_message = + encodeMessage(moduleScope->module->mapAction(OR_MESSAGE, 0, false), + 2, 0); + moduleScope->buildins.xor_message = + encodeMessage(moduleScope->module->mapAction(XOR_MESSAGE, 0, false), + 2, 0); + moduleScope->buildins.refer_message = + encodeMessage(moduleScope->module->mapAction(REFER_MESSAGE, 0, false), + 2, 0); + moduleScope->buildins.set_refer_message = + encodeMessage(moduleScope->module->mapAction(SET_REFER_MESSAGE, 0, false), + 3, 0); + moduleScope->buildins.if_message = + encodeMessage(moduleScope->module->mapAction(IF_MESSAGE, 0, false), + 2, 0); + moduleScope->buildins.iif_message = + encodeMessage(moduleScope->module->mapAction(IIF_MESSAGE, 0, false), + 3, 0); + moduleScope->buildins.equal_message = + encodeMessage(moduleScope->module->mapAction(EQUAL_MESSAGE, 0, false), + 2, 0); + moduleScope->buildins.not_message = + encodeMessage(moduleScope->module->mapAction(NOT_MESSAGE, 0, false), + 1, PROPERTY_MESSAGE); + moduleScope->buildins.negate_message = + encodeMessage(moduleScope->module->mapAction(NEGATE_MESSAGE, 0, false), + 1, PROPERTY_MESSAGE); + moduleScope->buildins.value_message = + encodeMessage(moduleScope->module->mapAction(VALUE_MESSAGE, 0, false), + 1, PROPERTY_MESSAGE); + moduleScope->buildins.default_message = + encodeMessage(moduleScope->module->mapAction(DEFAULT_MESSAGE, 0, false), + 1, PROPERTY_MESSAGE); + moduleScope->buildins.bnot_message = + encodeMessage(moduleScope->module->mapAction(BNOT_MESSAGE, 0, false), + 1, PROPERTY_MESSAGE); + moduleScope->buildins.notequal_message = + encodeMessage(moduleScope->module->mapAction(NOTEQUAL_MESSAGE, 0, false), + 2, 0); + moduleScope->buildins.less_message = + encodeMessage(moduleScope->module->mapAction(LESS_MESSAGE, 0, false), + 2, 0); + moduleScope->buildins.notless_message = + encodeMessage(moduleScope->module->mapAction(NOTLESS_MESSAGE, 0, false), + 2, 0); + moduleScope->buildins.greater_message = + encodeMessage(moduleScope->module->mapAction(GREATER_MESSAGE, 0, false), + 2, 0); + moduleScope->buildins.notgreater_message = + encodeMessage(moduleScope->module->mapAction(NOTGREATER_MESSAGE, 0, false), + 2, 0); - if (paramMode || preservedClosure) { - retVal = saveToTempLocal(writer, ownerScope, retVal); + // cache self variable + moduleScope->selfVar.copy(moduleScope->predefined.retrieve("@self", V_SELF_VAR, + [](ref_t reference, ustr_t key, ref_t current) + { + return current == reference; + })); + moduleScope->declVar.copy(moduleScope->predefined.retrieve("@decl", V_DECL_VAR, + [](ref_t reference, ustr_t key, ref_t current) + { + return current == reference; + })); + moduleScope->superVar.copy(moduleScope->predefined.retrieve("@super", V_SUPER_VAR, + [](ref_t reference, ustr_t key, ref_t current) + { + return current == reference; + })); + moduleScope->receivedVar.copy(moduleScope->predefined.retrieve("@received", V_RECEIVED_VAR, + [](ref_t reference, ustr_t key, ref_t current) + { + return current == reference; + })); - if (preservedClosure) - (*updatedOuterArgs)[preservedClosure] = retVal; - } + createPackageInfo(moduleScope, manifestInfo); - return retVal; - } + if (!moduleScope->tapeOptMode) + moduleScope->tapeOptMode = _tapeOptMode; } -ref_t Compiler :: mapConstantReference(Scope& ownerScope) +void Compiler :: validateScope(ModuleScopeBase* moduleScope) { - ref_t nestedRef = 0; - SymbolScope* owner = Scope::getScope(ownerScope, Scope::ScopeLevel::Symbol); - if (owner) { - nestedRef = owner->reference; - } - - if (!nestedRef) - nestedRef = ownerScope.moduleScope->mapAnonymous(); - - return nestedRef; + if (moduleScope->buildins.superReference == 0) + _errorProcessor->raiseInternalError(errNotDefinedBaseClass); } -inline ref_t retrieveTypeRef(ModuleScopeBase& scope, ref_t reference) +void Compiler :: validateSuperClass(ClassScope& scope, SyntaxNode node) { - IdentifierString name(scope.module->resolveReference(reference)); - if ((*name).endsWith(CLASSCLASS_POSTFIX)) - name.truncate(name.length() - getlength(CLASSCLASS_POSTFIX)); - - return scope.module->mapReference(*name); + if (!scope.info.methods.exist(scope.moduleScope->buildins.dispatch_message)) + scope.raiseError(errNoDispatcher, node); } -ref_t Compiler :: mapNested(ExprScope& ownerScope, ExpressionAttribute mode) +void Compiler :: declareModuleIdentifiers(ModuleScopeBase* moduleScope, SyntaxNode node, ExtensionMap* outerExtensionList) { - ref_t nestedRef = 0; - if (EAttrs::testAndExclude(mode, EAttr::RootSymbol)) { - SymbolScope* owner = Scope::getScope(ownerScope, Scope::ScopeLevel::Symbol); - if (owner) - nestedRef = owner->reference; - } - else if (EAttrs::testAndExclude(mode, EAttr::Root)) { - MethodScope* ownerMeth = Scope::getScope(ownerScope, Scope::ScopeLevel::Method); - if (ownerMeth && ownerMeth->checkHint(MethodHint::Constant)) { - ref_t dummyRef = 0; - // HOTFIX : recognize property constant - - IdentifierString name(ownerScope.module->resolveReference(ownerScope.getClassRef())); - if ((*name).endsWith(CLASSCLASS_POSTFIX)) - name.truncate(name.length() - getlength(CLASSCLASS_POSTFIX)); + SyntaxNode current = node.firstChild(); + while (current != SyntaxKey::None) { + if (current == SyntaxKey::Namespace) { + NamespaceScope ns(moduleScope, _errorProcessor, _logic, outerExtensionList); - name.append('#'); - name.append(ownerScope.module->resolveAction(getAction(ownerMeth->message), dummyRef)); + // declare namespace + declareNamespace(ns, current, true, true); + ns.moduleScope->newNamespace(*ns.nsName); - nestedRef = ownerMeth->module->mapReference(*name); + // declare all module members - map symbol identifiers + declareMemberIdentifiers(ns, current); } - } - - if (!nestedRef) - nestedRef = ownerScope.moduleScope->mapAnonymous(); - - return nestedRef; -} - -ObjectInfo Compiler :: compileClosure(BuildTreeWriter& writer, ExprScope& ownerScope, SyntaxNode node, ExpressionAttribute mode, - ArgumentsInfo* updatedOuterArgs) -{ - ref_t nestedRef = mapNested(ownerScope, mode); - InlineClassScope scope(&ownerScope, nestedRef); - - BuildNode buildNode = writer.CurrentNode(); - while (buildNode != BuildKey::Root) - buildNode = buildNode.parentNode(); - - BuildTreeWriter nestedWriter(buildNode); - compileClosureClass(nestedWriter, scope, node); - - return compileNestedExpression(writer, scope, ownerScope, mode, updatedOuterArgs); -} - -ObjectInfo Compiler :: compileNested(BuildTreeWriter& writer, ExprScope& ownerScope, SyntaxNode node, ExpressionAttribute mode, - ArgumentsInfo* updatedOuterArgs) -{ - TypeInfo parentInfo = { ownerScope.moduleScope->buildins.superReference }; - EAttrs nestedMode = { EAttr::NestedDecl }; - declareExpressionAttributes(ownerScope, node, parentInfo, nestedMode); - - //// allow only new and type attrobutes - //if (nestedMode.attrs != EAttr::None && !EAttrs::test(nestedMode.attrs, EAttr::NewOp) && !EAttrs::test(nestedMode.attrs, EAttr::NewVariable)) - // ownerScope.raiseError(errInvalidOperation, node); - - ref_t nestedRef = mapNested(ownerScope, mode); - InlineClassScope scope(&ownerScope, nestedRef); - - compileNestedClass(writer, scope, node, parentInfo.typeRef); - - return compileNestedExpression(writer, scope, ownerScope, mode, updatedOuterArgs); -} - -ObjectInfo Compiler :: compileLoopExpression(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, - ExpressionAttribute mode) -{ - ObjectInfo retVal = { ObjectKind::Object }; - - writer.newNode(BuildKey::LoopOp); - - compileExpression(writer, scope, node, 0, mode, nullptr); - - writer.appendNode(BuildKey::VirtualBreakoint); - - writer.closeNode(); - return retVal; + current = current.nextNode(); + } } -ObjectInfo Compiler :: compileExternExpression(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, - ExpressionAttribute mode) +void Compiler :: declareModule(ModuleScopeBase* moduleScope, SyntaxNode node, ExtensionMap* outerExtensionList) { - writer.newNode(BuildKey::ExternOp); + SyntaxNode current = node.firstChild(); + while (current != SyntaxKey::None) { + if (current == SyntaxKey::Namespace) { + NamespaceScope ns(moduleScope, _errorProcessor, _logic, outerExtensionList); - compileExpression(writer, scope, node, 0, mode, nullptr); + // declare namespace + declareNamespace(ns, current, false, true); - writer.closeNode(); + // declare all module members - map symbol identifiers + declareMembers(ns, current); + } - return { }; + current = current.nextNode(); + } } -ObjectInfo Compiler :: validateObject(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, - ObjectInfo retVal, ref_t targetRef, bool noPrimitives, bool paramMode, bool dynamicRequired) +void Compiler :: declare(ModuleScopeBase* moduleScope, SyntaxTree& input, ExtensionMap* outerExtensionList) { - if (!targetRef && retVal.typeInfo.isPrimitive() && noPrimitives) { - targetRef = retrieveStrongType(scope, retVal); - } + if (moduleScope->withValidation()) + validateScope(moduleScope); - if ((paramMode || targetRef) && hasToBePresaved(retVal)) { - retVal = saveToTempLocal(writer, scope, retVal); - } - if (targetRef) { - retVal = convertObject(writer, scope, node, retVal, targetRef, dynamicRequired, false); - if (paramMode && hasToBePresaved(retVal)) - retVal = saveToTempLocal(writer, scope, retVal); - } + SyntaxNode root = input.readRoot(); + // declare all member identifiers + declareModuleIdentifiers(moduleScope, root, outerExtensionList); - return retVal; + // declare all members + declareModule(moduleScope, root, outerExtensionList); } -void Compiler :: compileSwitchOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node) +void Compiler :: compile(ModuleScopeBase* moduleScope, SyntaxTree& input, BuildTree& output, ExtensionMap* outerExtensionList) { - Interpreter interpreter(scope.moduleScope, _logic); - ArgumentsInfo arguments; + BuildTreeWriter writer(output); + writer.newNode(BuildKey::Root); + SyntaxNode node = input.readRoot(); SyntaxNode current = node.firstChild(); - - ObjectInfo loperand = compileObject(writer, scope, current, EAttr::Parameter, nullptr); - - writer.newNode(BuildKey::Switching); - - current = current.nextNode(); while (current != SyntaxKey::None) { - switch (current.key) { - case SyntaxKey::SwitchOption: - { - WriterContext context = { &writer, &scope, {} }; - SyntaxNode optionNode = current.firstChild(); - - writer.newNode(BuildKey::SwitchOption); + if (current == SyntaxKey::Namespace) { + NamespaceScope ns(moduleScope, _errorProcessor, _logic, outerExtensionList); + declareNamespace(ns, current); - int operator_id = EQUAL_OPERATOR_ID; - ObjectInfo value = evalExpression(interpreter, scope, optionNode); - arguments.clear(); - arguments.add(loperand); - arguments.add(value); - ObjectInfo retVal = compileOperation(writer, scope, node, arguments, operator_id, 0, nullptr); - compileBranchingOperation(context, retVal, optionNode.nextNode(), {}, IF_OPERATOR_ID, nullptr, false, false); + compileNamespace(writer, ns, current); - writer.closeNode(); - break; - } - case SyntaxKey::SwitchLastOption: - writer.newNode(BuildKey::ElseOption); - compileSubCode(writer, scope, current.firstChild(), EAttr::None); - writer.closeNode(); - break; - default: - assert(false); - break; + _presenter->showProgress(); } current = current.nextNode(); @@ -10181,3641 +9636,4140 @@ void Compiler :: compileSwitchOperation(BuildTreeWriter& writer, ExprScope& scop writer.closeNode(); } -ref_t Compiler :: resolveTupleClass(Scope& scope, SyntaxNode node, ArgumentsInfo& items) +inline SyntaxNode newVirtualMultimethod(SyntaxNode classNode, SyntaxKey methodType, mssg_t message, Visibility visibility, bool isExtension) { - IdentifierString tupleName(scope.module->resolveReference(scope.moduleScope->buildins.tupleTemplateReference)); + ref_t hints = (ref_t)MethodHint::Multimethod | (methodType == SyntaxKey::StaticMethod ? (ref_t)MethodHint::Sealed : (ref_t)MethodHint::Normal); - List parameters({}); + switch (visibility) { + case Visibility::Protected: + hints |= (ref_t)MethodHint::Protected; + break; + case Visibility::Internal: + hints |= (ref_t)MethodHint::Internal; + break; + default: + break; + } - // HOTFIX : generate a temporal template to pass the type - SyntaxTree dummyTree; - SyntaxTreeWriter dummyWriter(dummyTree); - dummyWriter.newNode(SyntaxKey::Root); + if (isExtension) + hints |= (ref_t)MethodHint::Extension; - for (size_t i = 0; i < items.count(); i++) { - ref_t typeRef = retrieveStrongType(scope, items[i]); - if (!typeRef) - typeRef = scope.moduleScope->buildins.superReference; + SyntaxNode methodNode = classNode.appendChild(methodType, message); + methodNode.appendChild(SyntaxKey::Hints, hints); - dummyWriter.newNode(SyntaxKey::TemplateArg, typeRef); - dummyWriter.newNode(SyntaxKey::Type); + return methodNode; +} - ustr_t referenceName = scope.moduleScope->module->resolveReference(typeRef); - if (isWeakReference(referenceName)) { - dummyWriter.appendNode(SyntaxKey::reference, referenceName); - } - else dummyWriter.appendNode(SyntaxKey::globalreference, referenceName); +inline SyntaxNode newVirtualMethod(SyntaxNode classNode, SyntaxKey methodType, mssg_t message, Visibility visibility, bool abstractOne) +{ + ref_t hints = methodType == SyntaxKey::StaticMethod ? (ref_t)MethodHint::Sealed : (ref_t)MethodHint::Normal; + if (abstractOne) + hints |= (ref_t)MethodHint::Abstract; - dummyWriter.closeNode(); - dummyWriter.closeNode(); + switch (visibility) { + case Visibility::Protected: + hints |= (ref_t)MethodHint::Protected; + break; + case Visibility::Internal: + hints |= (ref_t)MethodHint::Internal; + break; + default: + break; } - dummyWriter.closeNode(); - - SyntaxNode current = dummyTree.readRoot().firstChild(); - while (current == SyntaxKey::TemplateArg) { - parameters.add(current); + SyntaxNode methodNode = classNode.appendChild(methodType, message); + methodNode.appendChild(SyntaxKey::Hints, hints); - current = current.nextNode(); - } + return methodNode; +} - tupleName.append('#'); - tupleName.appendInt(items.count_int()); +void Compiler :: injectVirtualEmbeddableWrapper(SyntaxNode classNode, SyntaxKey methodType, ModuleScopeBase& scope, + ref_t targetRef, ClassInfo& info, mssg_t message, bool abstractOne) +{ + MethodInfo methodInfo = {}; - ref_t templateReference = 0; - if (isWeakReference(*tupleName)) { - templateReference = scope.module->mapReference(*tupleName, true); - } - else templateReference = scope.moduleScope->mapFullReference(*tupleName, true); + auto m_it = info.methods.getIt(message); + bool found = !m_it.eof(); + if (found) + methodInfo = *m_it; - if (!templateReference) - scope.raiseError(errInvalidOperation, node); + if (!found || methodInfo.inherited) { + Visibility visibility = Visibility::Public; + if (MethodScope::checkHint(methodInfo, MethodHint::Internal)) { + visibility = Visibility::Internal; + } + else if (MethodScope::checkHint(methodInfo, MethodHint::Protected)) { + visibility = Visibility::Protected; + } + else if (MethodScope::checkHint(methodInfo, MethodHint::Private)) { + visibility = Visibility::Private; + } - NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); + SyntaxNode methodNode = newVirtualMethod(classNode, methodType, message, visibility, abstractOne); + methodNode.appendChild(SyntaxKey::Autogenerated, -1); // -1 indicates autogenerated method - return _templateProcessor->generateClassTemplate(*scope.moduleScope, *nsScope->nsName, - templateReference, parameters, false, nullptr); + if (!abstractOne) { + mssg_t resendMessage = message | STATIC_MESSAGE; + + SyntaxNode resendOp = methodNode.appendChild(SyntaxKey::DirectResend, resendMessage); + resendOp.appendChild(SyntaxKey::Target, targetRef); + } + else methodNode.appendChild(SyntaxKey::WithoutBody); + } } -ObjectInfo Compiler :: compileTupleCollectiom(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, ref_t targetRef) +inline bool isSingleDispatch(SyntaxNode node, SyntaxKey methodType, mssg_t message, mssg_t& targetMessage) { - WriterContext context = { &writer, &scope, node }; + // !! currently constructor is not supporting single dispatch operation + if (methodType == SyntaxKey::Constructor) + return false; - ArgumentsInfo arguments; - EAttr paramMode = EAttr::Parameter; + mssg_t foundMessage = 0; SyntaxNode current = node.firstChild(); while (current != SyntaxKey::None) { - if (current == SyntaxKey::Expression) { - auto argInfo = compileExpression(writer, scope, current, 0, - paramMode, nullptr); - - arguments.add(argInfo); + if (current == methodType) { + mssg_t multiMethod = current.findChild(SyntaxKey::Multimethod).arg.reference; + if (multiMethod == message) { + if (foundMessage) { + return false; + } + else foundMessage = current.arg.reference; + } } current = current.nextNode(); } - ref_t tupleRef = resolveTupleClass(scope, node, arguments); - - if (_logic->isTemplateCompatible(*scope.moduleScope, targetRef, tupleRef, true)) - tupleRef = targetRef; - - writer.newNode(BuildKey::CreatingClass, arguments.count_pos()); - writer.appendNode(BuildKey::Type, tupleRef); - writer.closeNode(); + if (foundMessage) { + targetMessage = foundMessage; - for (size_t i = 0; i < arguments.count(); i++) { - writer.appendNode(BuildKey::SavingInStack, 0); - writeObjectInfo(context, arguments[i]); - writer.appendNode(BuildKey::AccSwapping); - writer.appendNode(BuildKey::FieldAssigning, (pos_t)i); + return true; } - - return { ObjectKind::Object, { tupleRef }, 0 }; + else return false; } -ObjectInfo Compiler :: compileCollection(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, ExpressionAttribute mode) +bool Compiler :: injectVirtualStrongTypedMultimethod(SyntaxNode classNode, SyntaxKey methodType, ModuleScopeBase& scope, + mssg_t message, mssg_t resendMessage, ref_t outputRef, Visibility visibility, bool isExtension) { - WriterContext context = { &writer, &scope, node }; - - bool constOne = EAttrs::testAndExclude(mode, EAttr::ConstantExpr); - - SyntaxNode current = node.firstChild(); + ref_t actionRef = getAction(resendMessage); + ref_t signRef = 0; + ustr_t actionName = scope.module->resolveAction(actionRef, signRef); - ObjectInfo typeInfo = compileObject(writer, scope, node.firstChild(), EAttr::NestedDecl, nullptr); - if (typeInfo.kind != ObjectKind::Class) - scope.raiseError(errInvalidOperation, node); + ref_t signArgs[ARG_COUNT]; + size_t signLen = scope.module->resolveSignature(signRef, signArgs); + // HOTFIX : make sure it has at least one strong-typed argument + bool strongOne = false; + for (size_t i = 0; i < signLen; i++) { + if (signArgs[i] != scope.buildins.superReference) { + strongOne = true; + break; + } + } - ref_t collectionTypeRef = retrieveStrongType(scope, typeInfo); + // HOTFIX : the weak argument list should not be type-casted + // to avoid dispatching to the same method + if (!strongOne) + return false; - ClassInfo collectionInfo; - _logic->defineClassInfo(*scope.moduleScope, collectionInfo, collectionTypeRef, false, true); + SyntaxNode methodNode = newVirtualMultimethod(classNode, methodType, message, visibility, isExtension); + methodNode.appendChild(SyntaxKey::Autogenerated, -1); // -1 indicates autogenerated multi-method - if (!test(collectionInfo.header.flags, elDynamicRole)) - scope.raiseError(errInvalidOperation, node); + if (outputRef) + methodNode.appendChild(SyntaxKey::OutputType, outputRef); - if (constOne && node.arg.reference) { - bool byValue = _logic->isEmbeddableArray(*scope.moduleScope, collectionTypeRef); + SyntaxNode resendExpr = methodNode.appendChild(SyntaxKey::ResendDispatch); + SyntaxNode operationNode = resendExpr.appendChild(((resendMessage & PREFIX_MESSAGE_MASK) == PROPERTY_MESSAGE) ? SyntaxKey::PropertyOperation : SyntaxKey::MessageOperation); - return { byValue ? ObjectKind::Constant : ObjectKind::ConstArray, { collectionTypeRef }, node.arg.reference }; - } + if (!actionName.compare(INVOKE_MESSAGE)) + operationNode.appendChild(SyntaxKey::Message).appendChild(SyntaxKey::identifier, actionName); - auto fieldInfo = *(collectionInfo.fields.start()); - ref_t elementTypeRef = retrieveStrongType(scope, { ObjectKind::Object, { fieldInfo.typeInfo.elementRef }, 0 }); + String arg; + for (size_t i = 0; i < signLen; i++) { + arg.copy("$"); + arg.appendInt((int)i); - auto sizeInfo = _logic->defineStructSize(collectionInfo); - ArgumentsInfo arguments; - EAttr paramMode = EAttr::Parameter; - while (current != SyntaxKey::None) { - if (current == SyntaxKey::Expression) { - auto argInfo = compileExpression(writer, scope, current, elementTypeRef, - paramMode, nullptr); - //ref_t argRef = retrieveStrongType(scope, argInfo); - //if (signatureLen >= ARG_COUNT) { - // signatureLen++; - //} - //else if (argRef) { - // signatures[signatureLen++] = argRef; - //} - //else signatures[signatureLen++] = superReference; + SyntaxNode param = methodNode.appendChild(SyntaxKey::Parameter); + SyntaxNode nameParam = param.appendChild(SyntaxKey::Name); + nameParam.appendChild(SyntaxKey::identifier, arg.str()); - arguments.add(argInfo); + if (signArgs[i] != scope.buildins.superReference) { + SyntaxNode castNode = operationNode.appendChild(SyntaxKey::Expression).appendChild(SyntaxKey::MessageOperation); + SyntaxNode castObject = castNode.appendChild(SyntaxKey::Object); + castObject.appendChild(SyntaxKey::Attribute, V_CONVERSION); + castObject.appendChild(SyntaxKey::Type, signArgs[i]); + castNode.appendChild(SyntaxKey::Message); + castNode.appendChild(SyntaxKey::Expression).appendChild(SyntaxKey::Object).appendChild(SyntaxKey::identifier, arg.str()); } - - current = current.nextNode(); + else operationNode.appendChild(SyntaxKey::Expression).appendChild(SyntaxKey::Object).appendChild(SyntaxKey::identifier, arg.str()); } - bool structMode = false; - if (sizeInfo.size < 0) { - structMode = true; - writer.newNode(BuildKey::CreatingStruct, arguments.count_pos() * -sizeInfo.size); - } - else if (sizeInfo.size == 0) { - WriterContext context = { &writer, &scope, {} }; + return true; +} - // box the collection items - for (size_t i = 0; i < arguments.count(); i++) { - arguments[i] = boxArgument(context, arguments[i], false, true, false); - } +void Compiler :: injectVirtualMultimethod(SyntaxNode classNode, SyntaxKey methodType, ModuleScopeBase& scope, + ref_t targetRef, ClassInfo& info, mssg_t message, bool inherited, ref_t outputRef, Visibility visibility) +{ + bool isExtension = test(info.header.flags, elExtension); - writer.newNode(BuildKey::CreatingClass, arguments.count_pos()); - } - else scope.raiseError(errInvalidOperation, node); - writer.appendNode(BuildKey::Type, collectionTypeRef); - writer.closeNode(); + mssg_t resendMessage = message; + ref_t resendTarget = 0; - if (structMode) { - writer.appendNode(BuildKey::SavingInStack, 0); + ref_t actionRef, flags; + pos_t argCount; + decodeMessage(message, actionRef, argCount, flags); - for (size_t i = 0; i < arguments.count(); i++) { - writeObjectInfo(context, arguments[i]); - writer.newNode(BuildKey::CopyingItem, -sizeInfo.size); - writer.appendNode(BuildKey::Index, (pos_t)i); - writer.closeNode(); - } + info.attributes.exclude({ message, ClassAttribute::SingleDispatch }); - writer.appendNode(BuildKey::Argument, 0); + // try to resolve an argument list in run-time if it is only a single dispatch and argument list is not weak + // !! temporally do not support variadic arguments + if (isSingleDispatch(classNode, methodType, message, resendMessage) && ((message & PREFIX_MESSAGE_MASK) != VARIADIC_MESSAGE) && + injectVirtualStrongTypedMultimethod(classNode, methodType, scope, message, resendMessage, + outputRef, visibility, isExtension)) + { + // mark the message as a signle dispatcher if the class is sealed / closed / class class + // and default multi-method was not explicitly declared + if (testany(info.header.flags, elClosed | elClassClass) && !inherited) + info.attributes.add({ message, ClassAttribute::SingleDispatch }, resendMessage); } else { - for (size_t i = 0; i < arguments.count(); i++) { - writer.appendNode(BuildKey::SavingInStack, 0); - writeObjectInfo(context, arguments[i]); - writer.appendNode(BuildKey::AccSwapping); - writer.appendNode(BuildKey::FieldAssigning, (pos_t)i); + if (inherited) { + // if virtual multi-method handler is overridden + // redirect to the parent one + resendTarget = info.header.parentRef; } - } - - return { ObjectKind::Object, { collectionTypeRef }, 0 }; -} - -void Compiler :: compileYieldOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node) -{ - WriterContext context = { &writer, &scope, node }; - - CodeScope* codeScope = Scope::getScope(scope, Scope::ScopeLevel::Code); - MethodScope* methodScope = Scope::getScope(scope, Scope::ScopeLevel::Method); - ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); + else if (methodType == SyntaxKey::Constructor && actionRef == getAction(scope.buildins.constructor_message) && argCount == 1) { + // conversion constructor multi-method is a special case + // instead of redirecting to the most generic handler + // it should try to typecast the argument - if (!methodScope->isYieldable()) - scope.raiseError(errInvalidOperation, node); + ref_t typeRef = retrieveTypeRef(scope, targetRef); - ObjectInfo contextField = classScope->mapField(YIELD_CONTEXT_FIELD, EAttr::None); + ref_t signRef = scope.module->mapSignature(&typeRef, 1, false); + ref_t actionRef = scope.module->mapAction(CAST_MESSAGE, signRef, false); + resendMessage = encodeMessage(actionRef, 1, CONVERSION_MESSAGE); + } + else { + ref_t dummy = 0; + ustr_t actionName = scope.module->resolveAction(actionRef, dummy); - writer.newNode(BuildKey::YieldingOp, -scope.moduleScope->ptrSize); - writer.newNode(BuildKey::Tape); + ref_t signatureLen = 0; + ref_t signatures[ARG_COUNT] = {}; - writeObjectInfo(context, contextField); - writer.appendNode(BuildKey::SavingStackDump); + pos_t firstArg = test(flags, FUNCTION_MESSAGE) ? 0 : 1; + for (pos_t i = firstArg; i < argCount; i++) { + signatures[signatureLen++] = scope.buildins.superReference; + } + ref_t signRef = scope.module->mapAction(actionName, + scope.module->mapSignature(signatures, signatureLen, false), false); - compileRetExpression(writer, *codeScope, node, EAttr::None); + resendMessage = encodeMessage(signRef, argCount, flags); + } - writer.closeNode(); - writer.closeNode(); + injectVirtualMultimethod(classNode, methodType, message, resendMessage, resendTarget, + outputRef, visibility, isExtension); + } } -ObjectInfo Compiler :: compileLookAheadExpression(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, - ref_t targetRef, ExpressionAttribute mode) +void Compiler :: injectVirtualMultimethod(SyntaxNode classNode, SyntaxKey methodType, mssg_t message, + mssg_t resendMessage, ref_t resendTarget, ref_t outputRef, Visibility visibility, bool isExtension) { - BuildNode lastNode = writer.CurrentNode().lastChild(); + SyntaxNode methodNode = newVirtualMultimethod(classNode, methodType, message, visibility, isExtension); + methodNode.appendChild(SyntaxKey::Autogenerated, -1); // -1 indicates autogenerated multi-method - ObjectInfo retVal; + if (outputRef) + methodNode.appendChild(SyntaxKey::OutputType, outputRef); - switch (node.key) { - case SyntaxKey::MessageOperation: - retVal = compileMessageOperation(writer, scope, node, targetRef, mode); - break; - case SyntaxKey::PropertyOperation: - retVal = compilePropertyOperation(writer, scope, node, targetRef, mode); - break; - default: - assert(false); - break; + if (message == resendMessage) { + SyntaxNode dispatchOp = methodNode.appendChild(SyntaxKey::RedirectDispatch); + if (resendTarget) + dispatchOp.appendChild(SyntaxKey::Target, resendTarget); } + else methodNode.appendChild(SyntaxKey::RedirectDispatch, resendMessage); +} - if (!targetRef && _logic->isEmbeddable(*scope.moduleScope, retVal.typeInfo.typeRef)) { - targetRef = retVal.typeInfo.typeRef; - // bad luck, we must rollback the changes and compile again - lastNode = lastNode.nextNode(); - while (lastNode != BuildKey::None) { - lastNode.setKey(BuildKey::Idle); +void Compiler :: injectVirtualTryDispatch(SyntaxNode classNode, SyntaxKey methodType, + mssg_t message, mssg_t dispatchMessage, ref_t originalTarget) +{ + SyntaxNode methodNode = newVirtualMethod(classNode, methodType, message, Visibility::Public, false); + methodNode.appendChild(SyntaxKey::Autogenerated, -1); // -1 indicates autogenerated method - lastNode = lastNode.nextNode(); - } + SyntaxNode dispatchOp = methodNode.appendChild(SyntaxKey::RedirectTryDispatch, dispatchMessage); + if (originalTarget) + dispatchOp.appendChild(SyntaxKey::Target, originalTarget); +} - switch (node.key) { - case SyntaxKey::MessageOperation: - retVal = compileMessageOperation(writer, scope, node, targetRef, mode); - break; - case SyntaxKey::PropertyOperation: - retVal = compilePropertyOperation(writer, scope, node, targetRef, mode); - break; - default: - assert(false); - break; - } +void Compiler :: injectVirtualTryDispatch(SyntaxNode classNode, SyntaxKey methodType, ClassInfo& info, + mssg_t message, mssg_t dispatchMessage, bool inherited) +{ + ref_t originalTarget = 0; + if (inherited) { + // if virtual multi-method handler is overridden + // redirect to the parent one + originalTarget = info.header.parentRef; } - return retVal; + injectVirtualTryDispatch(classNode, methodType, message, dispatchMessage, originalTarget); } -ObjectInfo Compiler :: compileExpression(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, - ref_t targetRef, ExpressionAttribute mode, ArgumentsInfo* updatedOuterArgs) +void Compiler :: injectInitializer(SyntaxNode classNode, SyntaxKey methodType, mssg_t message) { - bool paramMode = EAttrs::testAndExclude(mode, EAttr::Parameter); - bool noPrimitives = EAttrs::testAndExclude(mode, EAttr::NoPrimitives); - bool dynamicRequired = EAttrs::testAndExclude(mode, EAttr::DynamicObject); - bool lookaheadMode = EAttrs::testAndExclude(mode, EAttr::LookaheadExprMode) && _lookaheadOptMode; + SyntaxNode methodNode = classNode.appendChild(methodType, message); + methodNode.appendChild(SyntaxKey::Hints, (ref_t)MethodHint::Initializer); + methodNode.appendChild(SyntaxKey::Autogenerated); - ObjectInfo retVal; + methodNode.appendChild(SyntaxKey::FieldInitializer); // NOTE : it is a place holder +} - SyntaxNode current = node == SyntaxKey::Expression ? node.firstChild() : node; - switch (current.key) { - case SyntaxKey::MessageOperation: - if (lookaheadMode) { - retVal = compileLookAheadExpression(writer, scope, current, targetRef, mode); - } - else retVal = compileMessageOperation(writer, scope, current, targetRef, mode); - break; - case SyntaxKey::PropertyOperation: - if (lookaheadMode) { - retVal = compileLookAheadExpression(writer, scope, current, targetRef, mode); - } - else retVal = compilePropertyOperation(writer, scope, current, targetRef, mode); - break; - case SyntaxKey::AssignOperation: - case SyntaxKey::AddOperation: - case SyntaxKey::SubOperation: - case SyntaxKey::MulOperation: - case SyntaxKey::DivOperation: - case SyntaxKey::LenOperation: - case SyntaxKey::LessOperation: - case SyntaxKey::GreaterOperation: - case SyntaxKey::NameOperation: - case SyntaxKey::EqualOperation: - case SyntaxKey::NotOperation: - case SyntaxKey::NotEqualOperation: - case SyntaxKey::NotLessOperation: - case SyntaxKey::NotGreaterOperation: - case SyntaxKey::NestedExpression: - case SyntaxKey::ValueOperation: - case SyntaxKey::BAndOperation: - case SyntaxKey::BOrOperation: - case SyntaxKey::BXorOperation: - case SyntaxKey::BNotOperation: - case SyntaxKey::ShlOperation: - case SyntaxKey::ShrOperation: - case SyntaxKey::NegateOperation: - retVal = compileOperation(writer, scope, current, (int)current.key - OPERATOR_MAKS, targetRef, mode); - break; - case SyntaxKey::BreakOperation: - case SyntaxKey::ContinueOperation: - retVal = compileSpecialOperation(writer, scope, current, (int)current.key - OPERATOR_MAKS, targetRef); - break; - case SyntaxKey::YieldOperation: - compileYieldOperation(writer, scope, current); - break; - case SyntaxKey::AddAssignOperation: - case SyntaxKey::SubAssignOperation: - case SyntaxKey::MulAssignOperation: - case SyntaxKey::DivAssignOperation: - case SyntaxKey::IncOperation: - case SyntaxKey::DecOperation: - retVal = compileAssignOperation(writer, scope, current, (int)current.key - OPERATOR_MAKS, targetRef); - break; - case SyntaxKey::AndOperation: - case SyntaxKey::OrOperation: - retVal = compileBoolOperation(writer, scope, current, (int)current.key - OPERATOR_MAKS); - if (targetRef) - typecastObject(writer, scope, current, retVal, targetRef); +void Compiler :: injectStrongRedirectMethod(SyntaxNode classNode, SyntaxKey methodType, ref_t reference, mssg_t message, mssg_t redirectMessage, ref_t outputRef) +{ + SyntaxNode methodNode = classNode.appendChild(methodType, message); + methodNode.appendChild(SyntaxKey::OutputType, outputRef); - break; - case SyntaxKey::IndexerOperation: - retVal = compileIndexerOperation(writer, scope, current, (int)current.key - OPERATOR_MAKS, targetRef); - break; - case SyntaxKey::IfOperation: - case SyntaxKey::IfNotOperation: - case SyntaxKey::IfElseOperation: - retVal = compileBranchingOperation(writer, scope, current, (int)current.key - OPERATOR_MAKS, - EAttrs::test(mode, EAttr::RetValExpected), EAttrs::test(mode, EAttr::NoDebugInfo)); - break; - case SyntaxKey::BranchOperation: - // HOTFIX : used for script based code - retVal = compileBranchingOperation(writer, scope, current, - (current.firstChild().nextNode().nextNode() != SyntaxKey::None ? IF_ELSE_OPERATOR_ID : IF_OPERATOR_ID), - EAttrs::test(mode, EAttr::RetValExpected), false); - break; - case SyntaxKey::LoopOperation: - retVal = compileLoopExpression(writer, scope, current.firstChild(), mode); - break; - case SyntaxKey::ExternOperation: - retVal = compileExternExpression(writer, scope, current.firstChild(), mode); - break; - case SyntaxKey::CatchOperation: - retVal = compileCatchOperation(writer, scope, current); - break; - case SyntaxKey::FinalOperation: - retVal = compileFinalOperation(writer, scope, current); - break; - case SyntaxKey::AltOperation: - retVal = compileAltOperation(writer, scope, current); - break; - case SyntaxKey::IsNilOperation: - retVal = compileIsNilOperation(writer, scope, current); - break; - case SyntaxKey::ReturnExpression: - retVal = compileExpression(writer, scope, current.firstChild(), 0, mode, updatedOuterArgs); - break; - case SyntaxKey::Expression: - retVal = compileExpression(writer, scope, current, 0, mode, updatedOuterArgs); - break; - case SyntaxKey::Object: - retVal = compileObject(writer, scope, current, mode, updatedOuterArgs); - break; - case SyntaxKey::NestedBlock: - retVal = compileNested(writer, scope, current, mode, updatedOuterArgs); - break; - case SyntaxKey::ClosureBlock: - retVal = compileClosure(writer, scope, current, mode, updatedOuterArgs); - break; - case SyntaxKey::LazyOperation: - retVal = compileClosure(writer, scope, current, mode, updatedOuterArgs); - break; - case SyntaxKey::CodeBlock: - retVal = compileSubCode(writer, scope, current, mode, true); - break; - case SyntaxKey::SwitchOperation: - compileSwitchOperation(writer, scope, current); - break; - case SyntaxKey::CollectionExpression: - retVal = compileCollection(writer, scope, current, mode); - break; - case SyntaxKey::Type: - case SyntaxKey::ReferOperation: - scope.raiseError(errInvalidOperation, node); - break; - case SyntaxKey::Attribute: - { - EAttrs exprAttr = mode; - if (!_logic->validateExpressionAttribute(current.arg.reference, exprAttr)) - scope.raiseError(errInvalidHint, current);; + SyntaxNode resendNode = methodNode.appendChild(SyntaxKey::DirectResend, redirectMessage); + resendNode.appendChild(SyntaxKey::Target, reference); +} - return compileExpression(writer, scope, current.nextNode(), targetRef, exprAttr.attrs, updatedOuterArgs); - break; - } - case SyntaxKey::TupleCollection: - retVal = compileTupleCollectiom(writer, scope, current, targetRef); - break; - case SyntaxKey::TupleAssignOperation: - retVal = compileTupleAssigning(writer, scope, current); - break; - case SyntaxKey::None: - assert(false); - break; - default: - retVal = compileObject(writer, scope, node, mode, updatedOuterArgs); - break; - } +void Compiler :: injectDefaultConstructor(ClassScope& scope, SyntaxNode node, + bool protectedOne, bool withClearOption) +{ + mssg_t message = protectedOne ? scope.moduleScope->buildins.protected_constructor_message + : scope.moduleScope->buildins.constructor_message; + MethodHint hints = (MethodHint)((ref_t)MethodHint::Constructor | (ref_t)MethodHint::Normal); + if (protectedOne) + hints = (ref_t)hints | MethodHint::Protected; - retVal = validateObject(writer, scope, node, retVal, targetRef, - noPrimitives, paramMode, dynamicRequired); + SyntaxNode methodNode = node.appendChild(SyntaxKey::Constructor, message); + methodNode.appendChild(SyntaxKey::Autogenerated); + methodNode.appendChild(SyntaxKey::Hints, (ref_t)hints); + methodNode.appendChild(SyntaxKey::OutputType, scope.reference); - return retVal; + if (withClearOption) + methodNode.appendChild(SyntaxKey::FillingAttr); } -inline bool checkTerminalCoords(SyntaxNode node) +void Compiler :: injectVirtualReturningMethod(ModuleScopeBase* scope, SyntaxNode classNode, + mssg_t message, ustr_t retVar, ref_t classRef) { - SyntaxNode terminal = node.firstChild(SyntaxKey::TerminalMask); + SyntaxNode methNode = classNode.appendChild(SyntaxKey::Method, message); + methNode.appendChild(SyntaxKey::Autogenerated, -1); // -1 indicates autogenerated method + methNode.appendChild(SyntaxKey::Hints, (ref_t)MethodHint::Sealed | (ref_t)MethodHint::Conversion); - return terminal.existChild(SyntaxKey::Row); + if (classRef) { + methNode.appendChild(SyntaxKey::OutputType, classRef); + } + + SyntaxNode exprNode = methNode.appendChild(SyntaxKey::ReturnExpression).appendChild(SyntaxKey::Expression); + //exprNode.appendNode(lxAttribute, V_NODEBUGINFO); + exprNode.appendChild(SyntaxKey::Object).appendChild(SyntaxKey::identifier, retVar); } -inline SyntaxNode findObjectNode(SyntaxNode node) +void Compiler :: generateOverloadListMember(ModuleScopeBase& scope, ref_t listRef, ref_t classRef, + mssg_t messageRef, MethodHint type) { - if (node == SyntaxKey::CodeBlock) { - // HOTFIX : to prevent double breakpoint - return {}; - } - SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { - switch (current.key) { - case SyntaxKey::Object: - if (checkTerminalCoords(current)) - return current; + MemoryWriter metaWriter(scope.module->mapSection(listRef | mskConstArray, false)); + if (metaWriter.position() == 0) { + metaWriter.writeDReference(0, messageRef); + switch (type) { + case MethodHint::Sealed: + metaWriter.writeDReference(classRef | mskVMTMethodAddress, messageRef); + break; + case MethodHint::Virtual: + metaWriter.writeDReference(classRef | mskVMTMethodOffset, messageRef); break; default: - { - SyntaxNode objectNode = findObjectNode(current); - if (objectNode != SyntaxKey::None) - return objectNode; - + metaWriter.writeDWord(0); break; - } } - - current = current.nextNode(); - } - - return {}; -} - -ObjectInfo Compiler :: compileRetExpression(BuildTreeWriter& writer, CodeScope& codeScope, SyntaxNode node, EAttr mode) -{ - ExprScope scope(&codeScope); - WriterContext context = { &writer, &scope, node }; - - bool autoMode = false; - bool dynamicRequired = EAttrs::testAndExclude(mode, EAttr::DynamicObject); - ref_t outputRef = 0; - if (codeScope.isByRefHandler()) { - ObjectInfo byRefTarget = codeScope.mapByRefReturnArg(); - - outputRef = byRefTarget.typeInfo.typeRef; + metaWriter.writeDWord(0); } - else outputRef = codeScope.getOutputRef(); + else { + if (type == MethodHint::Normal) { + metaWriter.insertDWord(0, 0); + } + else metaWriter.insertDWord(0, messageRef); - if (outputRef == V_AUTO) { - autoMode = true; - outputRef = 0; + metaWriter.insertDWord(0, messageRef); + metaWriter.Memory()->addReference(0, 0); + switch (type) { + case MethodHint::Sealed: + metaWriter.Memory()->addReference(classRef | mskVMTMethodAddress, 4); + break; + case MethodHint::Virtual: + metaWriter.Memory()->addReference(classRef | mskVMTMethodOffset, 4); + break; + default: + break; + } } +} - writer.appendNode(BuildKey::OpenStatement); - addBreakpoint(writer, findObjectNode(node), BuildKey::Breakpoint); +void Compiler :: injectVirtualDispatchMethod(Scope& scope, SyntaxNode classNode, mssg_t message, ref_t outputRef, SyntaxKey key, ustr_t arg) +{ + SyntaxNode methodNode = classNode.appendChild(SyntaxKey::Method, message); + // HOTFIX : indicating virtual interface dispatcher, to ignore byref handler optimization + methodNode.appendChild(SyntaxKey::Attribute, V_INTERFACE_DISPATCHER); - ObjectInfo retVal = {}; - SyntaxNode exprNode = node.findChild(SyntaxKey::Expression, SyntaxKey::CodeBlock); - switch (exprNode.key) { - case SyntaxKey::Expression: - retVal = compileExpression(writer, scope, node.findChild(SyntaxKey::Expression), outputRef, - mode | EAttr::Root | EAttr::RetValExpected, nullptr); - break; - case SyntaxKey::CodeBlock: - retVal = compileCode(writer, codeScope, exprNode, true); - break; - default: - assert(false); - break; - } + if (outputRef) + methodNode.appendChild(SyntaxKey::Type, outputRef); - if (codeScope.isByRefHandler()) { - ObjectInfo byRefTarget = codeScope.mapByRefReturnArg(); + ref_t actionRef = getAction(message); + ref_t signRef = 0; + ustr_t actionName = scope.module->resolveAction(actionRef, signRef); - compileAssigningOp(context, byRefTarget, retVal); + if (signRef) { + ref_t signatures[ARG_COUNT]; + size_t len = scope.module->resolveSignature(signRef, signatures); - retVal = scope.mapSelf(); - } - else { - retVal = boxArgument(context, retVal, - !dynamicRequired && retVal.kind == ObjectKind::SelfBoxableLocal, true, false); + String arg; + for (size_t i = 0; i < len; i++) { + arg.copy("$"); + arg.appendInt((int)i); - if (!hasToBePresaved(retVal)) { - writeObjectInfo(context, retVal); + SyntaxNode param = methodNode.appendChild(SyntaxKey::Parameter); + param.appendChild(SyntaxKey::Type, signatures[i]); + SyntaxNode nameParam = param.appendChild(SyntaxKey::Name); + nameParam.appendChild(SyntaxKey::identifier, arg.str()); } - else if (retVal.kind == ObjectKind::Symbol) { - writeObjectInfo(context, retVal); + } + else { + pos_t len = getArgCount(message); + String arg; + for (pos_t i = 1; i < len; i++) { + arg.copy("$"); + arg.appendInt(i); - retVal = { ObjectKind::Object, retVal.typeInfo, 0 }; + SyntaxNode param = methodNode.appendChild(SyntaxKey::Parameter); + SyntaxNode nameParam = param.appendChild(SyntaxKey::Name); + nameParam.appendChild(SyntaxKey::identifier, arg.str()); } - - outputRef = retrieveStrongType(scope, retVal); - - _logic->validateAutoType(*scope.moduleScope, outputRef); - - scope.resolveAutoOutput(outputRef); } - writer.appendNode(BuildKey::EndStatement); - writer.appendNode(BuildKey::VirtualBreakoint); - - writer.appendNode(BuildKey::goingToEOP); + SyntaxNode body = methodNode.appendChild(SyntaxKey::Redirect); + body + .appendChild(SyntaxKey::Expression) + .appendChild(SyntaxKey::Object) + .appendChild(key, arg); +} - scope.syncStack(); +ref_t Compiler :: generateExtensionTemplate(ModuleScopeBase& scope, ref_t templateRef, size_t argumentLen, ref_t* arguments, + ustr_t ns, ExtensionMap* outerExtensionList) +{ + TemplateTypeList typeList; + for (size_t i = 0; i < argumentLen; i++) + typeList.add(arguments[i]); - codeScope.withRetStatement = true; + // HOTFIX : generate a temporal template to pass the type + SyntaxTree dummyTree; + List parameters({}); + declareTemplateParameters(scope.module, typeList, dummyTree, parameters); - return retVal; + return _templateProcessor->generateClassTemplate(scope, ns, + templateRef, parameters, false, outerExtensionList); } -ObjectInfo Compiler :: compileRootExpression(BuildTreeWriter& writer, CodeScope& codeScope, SyntaxNode node, EAttr mode) +inline int retrieveIndex(List& list, mssg_t multiMethod) { - bool noDebugInfo = EAttrs::test(mode, EAttr::NoDebugInfo); - - ExprScope scope(&codeScope); + return list.retrieveIndex(multiMethod, [](mssg_t arg, ref_t current) + { + return current == arg; + }); +} - if (!noDebugInfo) { - writer.appendNode(BuildKey::OpenStatement); - addBreakpoint(writer, findObjectNode(node), BuildKey::Breakpoint); +inline void saveAsPreloaded(CompilerLogic* logic, ustr_t ns, ModuleBase* module, ref_t ref, ref_t mask) +{ + IdentifierString preloadedListName; + if (!ns.empty()) { + preloadedListName.append(ns); } + else preloadedListName.append("'"); - auto retVal = compileExpression(writer, scope, node, 0, mode, nullptr); - - //if (isBoxingRequired(retVal)) { - // retVal = boxArgumentInPlace(writer, scope, retVal); - //} + preloadedListName.append(META_PREFIX); + preloadedListName.append(PRELOADED_FORWARD); - if (!noDebugInfo) - writer.appendNode(BuildKey::EndStatement); + ref_t dictionaryRef = module->mapReference(*preloadedListName); - scope.syncStack(); + MemoryBase* dictionary = module->mapSection(dictionaryRef | mskTypeListRef, false); - return retVal; + logic->writeArrayEntry(dictionary, ref | mask); } -void Compiler :: saveFrameAttributes(BuildTreeWriter& writer, Scope& scope, pos_t reserved, pos_t reservedN) +void Compiler :: declareModuleExtensionDispatcher(NamespaceScope& scope, SyntaxNode node) { - reserved = align(reserved, scope.moduleScope->stackAlingment); - reservedN = align(reservedN, scope.moduleScope->rawStackAlingment); + List genericMethods(0); + ClassInfo::MethodMap methods({}); + ResolvedMap targets(0); - if (reserved) - writer.appendNode(BuildKey::Reserved, reserved); + auto it = scope.declaredExtensions.start(); + while (!it.eof()) { + auto extInfo = *it; + mssg_t genericMessage = it.key(); - if (reservedN > 0) - writer.appendNode(BuildKey::ReservedN, reservedN); -} + ustr_t refName = scope.module->resolveReference(extInfo.value1); + if (isWeakReference(refName)) { + if (NamespaceString::compareNs(refName, *scope.nsName)) { + // if the extension is declared in the module namespace + // add it to the list to be generated -bool Compiler :: compileSymbolConstant(SymbolScope& scope, ObjectInfo retVal) -{ - ref_t constRef = generateConstant(scope, retVal, scope.reference, false); - if (constRef) { - switch (retVal.kind) { - case ObjectKind::Singleton: - scope.info.symbolType = SymbolType::Singleton; - scope.info.valueRef = retVal.reference; - scope.info.typeRef = retrieveStrongType(scope, retVal); - break; - case ObjectKind::StringLiteral: - case ObjectKind::WideStringLiteral: - case ObjectKind::Float64Literal: - scope.info.symbolType = SymbolType::Constant; - scope.info.valueRef = constRef; - scope.info.typeRef = retrieveStrongType(scope, retVal); - break; - case ObjectKind::IntLiteral: - scope.info.symbolType = SymbolType::Constant; - scope.info.valueRef = constRef; - scope.info.typeRef = retrieveStrongType(scope, retVal); - break; - case ObjectKind::Constant: - scope.info.symbolType = SymbolType::Constant; - scope.info.valueRef = retVal.reference; - scope.info.typeRef = retrieveStrongType(scope, retVal); - break; - case ObjectKind::ConstArray: - scope.info.symbolType = SymbolType::ConstantArray; - scope.info.valueRef = retVal.reference; - scope.info.typeRef = retrieveStrongType(scope, retVal); - break; - default: - assert(false); - break; + if (retrieveIndex(genericMethods, genericMessage) == -1) + genericMethods.add(genericMessage); + + methods.add(extInfo.value2, { false, 0, 0, genericMessage | FUNCTION_MESSAGE, 0 }); + targets.add(extInfo.value2, extInfo.value1); + } } - return true; + it++; } - else return false; -} -void Compiler :: compileSymbol(BuildTreeWriter& writer, SymbolScope& scope, SyntaxNode node) -{ - scope.load(); + if (genericMethods.count() > 0) { + // if there are extension methods in the namespace + ref_t extRef = scope.moduleScope->mapAnonymous(); + ClassScope classScope(&scope, extRef, Visibility::Private); + declareClassParent(classScope.info.header.parentRef, classScope, {}); + classScope.extensionDispatcher = true; + classScope.info.header.classRef = classScope.reference; + classScope.extensionClassRef = scope.moduleScope->buildins.superReference; + generateClassFlags(classScope, elExtension | elSealed | elAutoLoaded); - writer.newNode(BuildKey::Symbol, node.arg.reference); + for (auto g_it = genericMethods.start(); !g_it.eof(); ++g_it) { + mssg_t genericMessage = *g_it; - NamespaceScope* ns = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - writer.appendNode(BuildKey::Path, *ns->sourcePath); + _logic->injectMethodOverloadList(this, *scope.moduleScope, + classScope.info.header.flags, genericMessage | FUNCTION_MESSAGE, methods, + classScope.info.attributes, &targets, targetResolver, ClassAttribute::ExtOverloadList); + } - writer.newNode(BuildKey::Tape); - if (scope.isStatic) - writer.appendNode(BuildKey::OpenStatic, node.arg.reference); + classScope.save(); - writer.appendNode(BuildKey::OpenFrame); + // build the class tree + node.appendChild(SyntaxKey::Class, extRef); - SyntaxNode bodyNode = node.findChild(SyntaxKey::GetExpression); + // save as preloaded class + saveAsPreloaded(_logic, *scope.nsName, scope.module, extRef, mskVMTRef); + } +} - writer.appendNode(BuildKey::OpenStatement); - addBreakpoint(writer, findObjectNode(bodyNode), BuildKey::Breakpoint); +// --- Compiler::Expression --- - ExprScope exprScope(&scope); - EAttr mode = ExpressionAttribute::RootSymbol; - if (scope.info.symbolType == SymbolType::Constant) - mode = mode | ExpressionAttribute::ConstantExpr; +Compiler::Expression :: Expression(Compiler* compiler, CodeScope& codeScope, BuildTreeWriter& writer) + : compiler(compiler), scope(&codeScope), writer(&writer) +{ - ObjectInfo retVal = compileExpression(writer, exprScope, - bodyNode.firstChild(), 0, mode, nullptr); +} - WriterContext context = { &writer, &exprScope, node }; +Compiler::Expression::Expression(Compiler* compiler, SourceScope& symbolScope, BuildTreeWriter& writer) + : compiler(compiler), scope(&symbolScope), writer(&writer) +{ - writeObjectInfo(context, - boxArgument(context, retVal, false, true, false)); +} - writer.appendNode(BuildKey::EndStatement); +ObjectInfo Compiler::Expression :: compileSymbolRoot(SyntaxNode bodyNode, EAttr mode) +{ + writer->appendNode(BuildKey::OpenStatement); + addBreakpoint(*writer, findObjectNode(bodyNode), BuildKey::Breakpoint); - writer.appendNode(BuildKey::VirtualBreakoint); + ObjectInfo retVal = compile(bodyNode.firstChild(), 0, mode, nullptr); - exprScope.syncStack(); + writeObjectInfo(boxArgument(retVal, false, true, false)); - writer.appendNode(BuildKey::CloseFrame); + writer->appendNode(BuildKey::EndStatement); - if (scope.isStatic) - writer.appendNode(BuildKey::CloseStatic, node.arg.reference); + writer->appendNode(BuildKey::VirtualBreakoint); - writer.appendNode(BuildKey::Exit); + scope.syncStack(); - writer.closeNode(); - saveFrameAttributes(writer, scope, scope.reserved1 + scope.reservedArgs, scope.reserved2); - writer.closeNode(); + return retVal; +} - // create constant if required - if (scope.info.symbolType == SymbolType::Constant) { - if (!compileSymbolConstant(scope, retVal)) - scope.raiseError(errInvalidOperation, node); +ObjectInfo Compiler::Expression :: compileRoot(SyntaxNode node, EAttr mode) +{ + bool noDebugInfo = EAttrs::test(mode, EAttr::NoDebugInfo); + + if (!noDebugInfo) { + writer->appendNode(BuildKey::OpenStatement); + Compiler::addBreakpoint(*writer, findObjectNode(node), BuildKey::Breakpoint); } - if (_logic->isLessAccessible(*scope.moduleScope, scope.visibility, scope.info.typeRef)) - scope.raiseWarning(WARNING_LEVEL_1, wrnLessAccessible, node); + auto retVal = compile(node, 0, mode, nullptr); - scope.save(); + //if (isBoxingRequired(retVal)) { + // retVal = boxArgumentInPlace(writer, scope, retVal); + //} + + if (!noDebugInfo) + writer->appendNode(BuildKey::EndStatement); + + scope.syncStack(); + + return retVal; } -void Compiler :: compileClassSymbol(BuildTreeWriter& writer, ClassScope& scope) +ObjectInfo Compiler::Expression :: compileReturning(SyntaxNode node, EAttr mode, ref_t outputRef) { - writer.newNode(BuildKey::Symbol, scope.reference); + bool dynamicRequired = EAttrs::testAndExclude(mode, EAttr::DynamicObject); - writer.newNode(BuildKey::Tape); - writer.appendNode(BuildKey::OpenFrame); - ObjectInfo retVal(ObjectKind::Class, { scope.info.header.classRef }, scope.reference, 0); - ExprScope exprScope(&scope); - WriterContext context = { &writer, &exprScope, {} }; - writeObjectInfo(context, retVal); - writer.appendNode(BuildKey::CloseFrame); - writer.appendNode(BuildKey::Exit); - writer.closeNode(); + CodeScope* codeScope = Scope::getScope(scope, Scope::ScopeLevel::Code); + if (codeScope == nullptr) + scope.raiseError(errInvalidOperation, node); - writer.closeNode(); + writer->appendNode(BuildKey::OpenStatement); + addBreakpoint(*writer, findObjectNode(node), BuildKey::Breakpoint); - if (scope.info.attributes.exist({ 0, ClassAttribute::RuntimeLoadable })) { - SymbolInfo symbolInfo = {}; - symbolInfo.loadableInRuntime = true; + ObjectInfo retVal = {}; + SyntaxNode exprNode = node.findChild(SyntaxKey::Expression, SyntaxKey::CodeBlock); + switch (exprNode.key) { + case SyntaxKey::Expression: + retVal = compile(node.findChild(SyntaxKey::Expression), outputRef, + mode | EAttr::Root | EAttr::RetValExpected, nullptr); + break; + case SyntaxKey::CodeBlock: + retVal = compiler->compileCode(*writer, *codeScope, exprNode, true); + break; + default: + assert(false); + break; + } - // save class meta data - MemoryWriter metaWriter(scope.module->mapSection(scope.reference | mskMetaSymbolInfoRef, false), 0); - symbolInfo.save(&metaWriter); + if (codeScope->isByRefHandler()) { + ObjectInfo byRefTarget = codeScope->mapByRefReturnArg(); + + compileAssigningOp(byRefTarget, retVal); + + retVal = scope.mapSelf(); } -} + else { + retVal = boxArgument(retVal, + !dynamicRequired && retVal.kind == ObjectKind::SelfBoxableLocal, true, false); -void Compiler :: beginMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode node, BuildKey scopeKey, bool withDebugInfo) -{ - writer.newNode(scopeKey, scope.message); + if (!hasToBePresaved(retVal)) { + writeObjectInfo(retVal); + } + else if (retVal.kind == ObjectKind::Symbol) { + writeObjectInfo(retVal); - if (withDebugInfo) { - SyntaxNode pathNode = node.findChild(SyntaxKey::SourcePath); - if (pathNode != SyntaxKey::None) - writer.appendNode(BuildKey::Path, pathNode.identifier()); + retVal = { ObjectKind::Object, retVal.typeInfo, 0 }; + } - writer.newNode(BuildKey::Tape); + outputRef = compiler->retrieveStrongType(scope, retVal); - writeMethodDebugInfo(writer, scope); - writeMessageInfo(writer, scope); + compiler->_logic->validateAutoType(*scope.moduleScope, outputRef); + scope.resolveAutoOutput(outputRef); } - else writer.newNode(BuildKey::Tape); -} -void Compiler :: endMethod(BuildTreeWriter& writer, MethodScope& scope) -{ - writer.appendNode(BuildKey::Exit); - writer.closeNode(); + writer->appendNode(BuildKey::EndStatement); + writer->appendNode(BuildKey::VirtualBreakoint); - saveFrameAttributes(writer, scope, scope.reserved1 + scope.reservedArgs, scope.reserved2); + writer->appendNode(BuildKey::goingToEOP); - writer.closeNode(); + scope.syncStack(); + + return retVal; } -void Compiler :: injectVariableInfo(BuildNode node, CodeScope& codeScope) +ObjectInfo Compiler::Expression :: compile(SyntaxNode node, ref_t targetRef, EAttr mode, + ArgumentsInfo* updatedOuterArgs) { - for (auto it = codeScope.locals.start(); !it.eof(); ++it) { - auto localInfo = *it; - bool embeddableArray = false; - if (localInfo.typeInfo.typeRef) { - ref_t typeRef = localInfo.typeInfo.typeRef; + bool paramMode = EAttrs::testAndExclude(mode, EAttr::Parameter); + bool noPrimitives = EAttrs::testAndExclude(mode, EAttr::NoPrimitives); + bool dynamicRequired = EAttrs::testAndExclude(mode, EAttr::DynamicObject); + bool lookaheadMode = EAttrs::testAndExclude(mode, EAttr::LookaheadExprMode) && compiler->_lookaheadOptMode; - if (localInfo.typeInfo.isPrimitive() && localInfo.typeInfo.elementRef) - typeRef = resolvePrimitiveType(codeScope, localInfo.typeInfo, false); + ObjectInfo retVal; - embeddableArray = _logic->isEmbeddableArray(*codeScope.moduleScope, typeRef); - if (embeddableArray && localInfo.size > 0) { - node.appendChild(BuildKey::BinaryArray, localInfo.offset) - .appendChild(BuildKey::Size, localInfo.size); + SyntaxNode current = node == SyntaxKey::Expression ? node.firstChild() : node; + switch (current.key) { + case SyntaxKey::MessageOperation: + if (lookaheadMode) { + retVal = compileLookAhead(current, targetRef, mode); + } + else retVal = compileMessageOperation(current, targetRef, mode); + break; + case SyntaxKey::PropertyOperation: + if (lookaheadMode) { + retVal = compileLookAhead(current, targetRef, mode); } + else retVal = compilePropertyOperation(current, targetRef, mode); + break; + case SyntaxKey::AssignOperation: + case SyntaxKey::AddOperation: + case SyntaxKey::SubOperation: + case SyntaxKey::MulOperation: + case SyntaxKey::DivOperation: + case SyntaxKey::LenOperation: + case SyntaxKey::LessOperation: + case SyntaxKey::GreaterOperation: + case SyntaxKey::NameOperation: + case SyntaxKey::EqualOperation: + case SyntaxKey::NotOperation: + case SyntaxKey::NotEqualOperation: + case SyntaxKey::NotLessOperation: + case SyntaxKey::NotGreaterOperation: + case SyntaxKey::NestedExpression: + case SyntaxKey::ValueOperation: + case SyntaxKey::BAndOperation: + case SyntaxKey::BOrOperation: + case SyntaxKey::BXorOperation: + case SyntaxKey::BNotOperation: + case SyntaxKey::ShlOperation: + case SyntaxKey::ShrOperation: + case SyntaxKey::NegateOperation: + retVal = compileOperation(current, (int)current.key - OPERATOR_MAKS, targetRef, mode); + break; + case SyntaxKey::BreakOperation: + case SyntaxKey::ContinueOperation: + retVal = compileSpecialOperation(current, (int)current.key - OPERATOR_MAKS, targetRef); + break; + case SyntaxKey::YieldOperation: + compileYieldOperation(current); + break; + case SyntaxKey::AddAssignOperation: + case SyntaxKey::SubAssignOperation: + case SyntaxKey::MulAssignOperation: + case SyntaxKey::DivAssignOperation: + case SyntaxKey::IncOperation: + case SyntaxKey::DecOperation: + retVal = compileAssignOperation(current, (int)current.key - OPERATOR_MAKS, targetRef); + break; + case SyntaxKey::AndOperation: + case SyntaxKey::OrOperation: + retVal = compileBoolOperation(current, (int)current.key - OPERATOR_MAKS); + if (targetRef) + typecastObject(current, retVal, targetRef); + + break; + case SyntaxKey::IndexerOperation: + retVal = compileIndexerOperation(current, (int)current.key - OPERATOR_MAKS, targetRef); + break; + case SyntaxKey::IfOperation: + case SyntaxKey::IfNotOperation: + case SyntaxKey::IfElseOperation: + retVal = compileBranchingOperation(current, (int)current.key - OPERATOR_MAKS, + EAttrs::test(mode, EAttr::RetValExpected), EAttrs::test(mode, EAttr::NoDebugInfo)); + break; + case SyntaxKey::BranchOperation: + // HOTFIX : used for script based code + retVal = compileBranchingOperation(current, + (current.firstChild().nextNode().nextNode() != SyntaxKey::None ? IF_ELSE_OPERATOR_ID : IF_OPERATOR_ID), + EAttrs::test(mode, EAttr::RetValExpected), false); + break; + case SyntaxKey::LoopOperation: + retVal = compileLoop(current.firstChild(), mode); + break; + case SyntaxKey::ExternOperation: + retVal = compileExtern(current.firstChild(), mode); + break; + case SyntaxKey::CatchOperation: + retVal = compileCatchOperation(current); + break; + case SyntaxKey::FinalOperation: + retVal = compileFinalOperation(current); + break; + case SyntaxKey::AltOperation: + retVal = compileAltOperation(current); + break; + case SyntaxKey::IsNilOperation: + retVal = compileIsNilOperation(current); + break; + case SyntaxKey::ReturnExpression: + retVal = compile(current.firstChild(), 0, mode, updatedOuterArgs); + break; + case SyntaxKey::Expression: + retVal = compile(current, 0, mode, updatedOuterArgs); + break; + case SyntaxKey::Object: + retVal = compileObject(current, mode, updatedOuterArgs); + break; + case SyntaxKey::NestedBlock: + retVal = compileNested(current, mode, updatedOuterArgs); + break; + case SyntaxKey::ClosureBlock: + retVal = compileClosure(current, mode, updatedOuterArgs); + break; + case SyntaxKey::LazyOperation: + retVal = compileClosure(current, mode, updatedOuterArgs); + break; + case SyntaxKey::CodeBlock: + retVal = compileSubCode(current, mode, true); + break; + case SyntaxKey::SwitchOperation: + compileSwitchOperation(current); + break; + case SyntaxKey::CollectionExpression: + retVal = compileCollection(current, mode); + break; + case SyntaxKey::Type: + case SyntaxKey::ReferOperation: + scope.raiseError(errInvalidOperation, node); + break; + case SyntaxKey::Attribute: + { + EAttrs exprAttr = mode; + if (!compiler->_logic->validateExpressionAttribute(current.arg.reference, exprAttr)) + scope.raiseError(errInvalidHint, current);; + + return compile(current.nextNode(), targetRef, exprAttr.attrs, updatedOuterArgs); + break; } + case SyntaxKey::TupleCollection: + retVal = compileTupleCollection(current, targetRef); + break; + case SyntaxKey::TupleAssignOperation: + retVal = compileTupleAssigning(current); + break; + case SyntaxKey::None: + assert(false); + break; + default: + retVal = compileObject(node, mode, updatedOuterArgs); + break; + } - if (localInfo.size > 0) { - if (embeddableArray) { - if (_logic->isCompatible(*codeScope.moduleScope, - { V_INT8 }, { localInfo.typeInfo.elementRef }, false)) - { - BuildNode varNode = node.appendChild(BuildKey::ByteArrayAddress, it.key()); - varNode.appendChild(BuildKey::Index, localInfo.offset); - } - else if (_logic->isCompatible(*codeScope.moduleScope, - { V_UINT8 }, { localInfo.typeInfo.elementRef }, false)) - { - BuildNode varNode = node.appendChild(BuildKey::ByteArrayAddress, it.key()); - varNode.appendChild(BuildKey::Index, localInfo.offset); - } - else if (_logic->isCompatible(*codeScope.moduleScope, - { V_INT16 }, { localInfo.typeInfo.elementRef }, false)) - { - BuildNode varNode = node.appendChild(BuildKey::ShortArrayAddress, it.key()); - varNode.appendChild(BuildKey::Index, localInfo.offset); - } - else if (_logic->isCompatible(*codeScope.moduleScope, - { V_INT32 }, { localInfo.typeInfo.elementRef }, false)) - { - BuildNode varNode = node.appendChild(BuildKey::IntArrayAddress, it.key()); - varNode.appendChild(BuildKey::Index, localInfo.offset); - } - } - else if (localInfo.typeInfo.typeRef == codeScope.moduleScope->buildins.intReference) { - BuildNode varNode = node.appendChild(BuildKey::IntVariableAddress, it.key()); - varNode.appendChild(BuildKey::Index, localInfo.offset); - } - else if (localInfo.typeInfo.typeRef == codeScope.moduleScope->buildins.uintReference) { - BuildNode varNode = node.appendChild(BuildKey::UIntVariableAddress, it.key()); - varNode.appendChild(BuildKey::Index, localInfo.offset); - } - else if (localInfo.typeInfo.typeRef == codeScope.moduleScope->buildins.int8Reference) { - BuildNode varNode = node.appendChild(BuildKey::IntVariableAddress, it.key()); - varNode.appendChild(BuildKey::Index, localInfo.offset); - } - else if (localInfo.typeInfo.typeRef == codeScope.moduleScope->buildins.uint8Reference) { - BuildNode varNode = node.appendChild(BuildKey::IntVariableAddress, it.key()); - varNode.appendChild(BuildKey::Index, localInfo.offset); - } - else if (localInfo.typeInfo.typeRef == codeScope.moduleScope->buildins.shortReference) { - BuildNode varNode = node.appendChild(BuildKey::IntVariableAddress, it.key()); - varNode.appendChild(BuildKey::Index, localInfo.offset); - } - else if (localInfo.typeInfo.typeRef == codeScope.moduleScope->buildins.longReference) { - BuildNode varNode = node.appendChild(BuildKey::LongVariableAddress, it.key()); - varNode.appendChild(BuildKey::Index, localInfo.offset); - } - else if (localInfo.typeInfo.typeRef == codeScope.moduleScope->buildins.realReference) { - BuildNode varNode = node.appendChild(BuildKey::RealVariableAddress, it.key()); - varNode.appendChild(BuildKey::Index, localInfo.offset); - } - else if (_logic->isCompatible(*codeScope.moduleScope, - { V_INT32 }, { localInfo.typeInfo.typeRef }, false)) - { - BuildNode varNode = node.appendChild(BuildKey::IntVariableAddress, it.key()); - varNode.appendChild(BuildKey::Index, localInfo.offset); - } - else { - BuildNode varNode = node.appendChild(BuildKey::VariableAddress, it.key()); - varNode.appendChild(BuildKey::Index, localInfo.offset); + retVal = validateObject(node, retVal, targetRef, + noPrimitives, paramMode, dynamicRequired); - ustr_t className = codeScope.moduleScope->module->resolveReference(localInfo.typeInfo.typeRef); - if (isWeakReference(className)) { - IdentifierString fullName(codeScope.module->name()); - fullName.append(className); + return retVal; +} + +ObjectInfo Compiler::Expression :: compileObject(SyntaxNode node, ExpressionAttribute mode, ArgumentsInfo* updatedOuterArgs) +{ + if (node == SyntaxKey::Object) { + ObjectInfo retVal = compiler->mapObject(scope, node, mode); + switch (retVal.kind) { + case ObjectKind::ConstantLiteral: + { + ArgumentsInfo arguments; + ref_t typeRef = scope.moduleScope->buildins.literalReference; + ref_t signRef = scope.module->mapSignature(&typeRef, 1, false); - varNode.appendChild(BuildKey::ClassName, *fullName); - } - else varNode.appendChild(BuildKey::ClassName, className); + return compileNewOp(node, retVal, signRef, arguments); } + case ObjectKind::Unknown: + scope.raiseError(errUnknownObject, node.lastChild(SyntaxKey::TerminalMask)); + break; + default: + break; } - else { - BuildNode varNode = node.appendChild(BuildKey::Variable, it.key()); - varNode.appendChild(BuildKey::Index, localInfo.offset); - } + + return retVal; } + else return compile(node, 0, mode, updatedOuterArgs); } -ObjectInfo Compiler :: compileCode(BuildTreeWriter& writer, CodeScope& codeScope, SyntaxNode node, bool closureMode, bool noDebugInfoMode) +ObjectInfo Compiler::Expression :: compileLookAhead(SyntaxNode node, ref_t targetRef, ExpressionAttribute mode) { - ObjectInfo retVal = {}; - ObjectInfo exprRetVal = {}; - - // variable declaration node - writer.newNode(BuildKey::VariableInfo); - BuildNode variableNode = writer.CurrentNode(); - writer.closeNode(); + BuildNode lastNode = writer->CurrentNode().lastChild(); - EAttr mode = closureMode ? EAttr::RetValExpected : EAttr::None; - if (noDebugInfoMode) - mode = mode | EAttr::NoDebugInfo; + ObjectInfo retVal; - SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { - switch (current.key) { - case SyntaxKey::Expression: - exprRetVal = compileRootExpression(writer, codeScope, current, mode); - break; - case SyntaxKey::ReturnExpression: - exprRetVal = retVal = compileRetExpression(writer, codeScope, current, EAttr::None); - break; - case SyntaxKey::CodeBlock: - { - bool autoGenerated = current.existChild(SyntaxKey::Autogenerated); + switch (node.key) { + case SyntaxKey::MessageOperation: + retVal = compileMessageOperation(node, targetRef, mode); + break; + case SyntaxKey::PropertyOperation: + retVal = compilePropertyOperation(node, targetRef, mode); + break; + default: + assert(false); + break; + } - if (!noDebugInfoMode && autoGenerated) { - writer.appendNode(BuildKey::OpenStatement); - addBreakpoint(writer, findObjectNode(current.firstChild()), BuildKey::Breakpoint); - } + if (!targetRef && compiler->_logic->isEmbeddable(*scope.moduleScope, retVal.typeInfo.typeRef)) { + targetRef = retVal.typeInfo.typeRef; + // bad luck, we must rollback the changes and compile again + lastNode = lastNode.nextNode(); + while (lastNode != BuildKey::None) { + lastNode.setKey(BuildKey::Idle); - CodeScope subScope(&codeScope); - exprRetVal = compileCode(writer, subScope, current, false, autoGenerated); - subScope.syncStack(&codeScope); + lastNode = lastNode.nextNode(); + } - if (!noDebugInfoMode && autoGenerated) - writer.appendNode(BuildKey::EndStatement); + switch (node.key) { + case SyntaxKey::MessageOperation: + retVal = compileMessageOperation(node, targetRef, mode); break; - } - case SyntaxKey::EOP: - addBreakpoint(writer, current, BuildKey::EOPBreakpoint); + case SyntaxKey::PropertyOperation: + retVal = compilePropertyOperation(node, targetRef, mode); break; default: + assert(false); break; } - - current = current.nextNode(); } - injectVariableInfo(variableNode, codeScope); + return retVal; +} - if (_trackingUnassigned) { - // warn if the variable was not assigned - for (auto it = codeScope.locals.start(); !it.eof(); ++it) { - if ((*it).unassigned) { - if((*it).size > 0) { - warnOnUnassignedLocal(node, codeScope, -(*it).offset); - } - else warnOnUnassignedLocal(node, codeScope, (*it).offset); +ObjectInfo Compiler::Expression :: compileMessageOperation(SyntaxNode node, + ref_t expectedRef, ExpressionAttribute attrs) +{ + ObjectInfo retVal = { }; + ArgumentsInfo arguments; + ArgumentsInfo updatedOuterArgs; + + SyntaxNode current = node.firstChild(); + ObjectInfo source = compileObject(current, EAttr::Parameter, &updatedOuterArgs); + bool probeMode = source.mode == TargetMode::Probe; + switch (source.mode) { + case TargetMode::External: + case TargetMode::WinApi: + { + bool dummy = false; + compileMessageArguments(current, arguments, 0, EAttr::None, nullptr, dummy); + if (dummy) + scope.raiseError(errInvalidOperation, current); + + retVal = compileExternalOp(node, source.reference, + source.mode == TargetMode::WinApi, arguments, expectedRef); + break; + } + case TargetMode::CreatingArray: + { + bool dummy = false; + compileMessageArguments(current, arguments, 0, EAttr::NoPrimitives, nullptr, dummy); + if (dummy) + scope.raiseError(errInvalidOperation, current); + + retVal = compileNewArrayOp(node, source, expectedRef, arguments); + break; + } + case TargetMode::Creating: + { + bool dummy = false; + ref_t signRef = compileMessageArguments(current, arguments, 0, EAttr::NoPrimitives, nullptr, dummy); + if (dummy) + scope.raiseError(errInvalidOperation, current); + + retVal = compileNewOp(node, Compiler::mapClassSymbol(scope, + compiler->retrieveStrongType(scope, source)), signRef, arguments); + break; + } + case TargetMode::Casting: + { + bool dummy = false; + compileMessageArguments(current, arguments, 0, EAttr::NoPrimitives, nullptr, dummy); + if (arguments.count() == 1 && !dummy) { + retVal = convertObject(current, arguments[0], compiler->retrieveStrongType(scope, source), false, true); } + else scope.raiseError(errInvalidOperation, node); + break; } - } + default: + { + // NOTE : the operation target shouldn't be a primtive type + source = validateObject(node, source, 0, true, true, false); - // NOTE : in the closure mode the last statement is the closure result - return closureMode ? exprRetVal : retVal; -} + current = current.nextNode(); + mssg_t messageRef = compiler->mapMessage(scope, current, false, + source.kind == ObjectKind::Extension, probeMode); -void Compiler :: warnOnUnassignedLocal(SyntaxNode node, CodeScope& scope, int level) -{ - SyntaxNode current = scope.localNodes.get(level); + if (!test(messageRef, FUNCTION_MESSAGE)) + arguments.add(source); - if (current != SyntaxKey::None) - scope.raiseWarning(WARNING_LEVEL_3, wrnUnassignedVariable, current); -} + mssg_t resolvedMessage = source.mode != TargetMode::Weak ? compiler->_logic->resolveSingleDispatch(*scope.moduleScope, + compiler->retrieveType(scope, source), messageRef) : 0; -inline void clearYieldContext() -{ - // clearing yield context -// writer.appendNode(BuildKey::SavingStackDump); -} + ref_t expectedSignRef = 0; + if (resolvedMessage) + scope.module->resolveAction(getAction(resolvedMessage), expectedSignRef); -ObjectInfo Compiler :: mapConstructorTarget(MethodScope& scope) -{ - ObjectInfo classSymbol = mapClassSymbol(scope, scope.getClassRef()); + bool withVariadicArg = false; + ref_t implicitSignatureRef = compileMessageArguments(current, arguments, expectedSignRef, EAttr::NoPrimitives, + &updatedOuterArgs, withVariadicArg); - if (!test(scope.message, FUNCTION_MESSAGE)) { - return { ObjectKind::ConstructorSelf, classSymbol.typeInfo, scope.selfLocal, classSymbol.reference }; + EAttr opMode = EAttr::None; + if (withVariadicArg) { + messageRef |= VARIADIC_MESSAGE; + + opMode = EAttr::WithVariadicArg; + } + + auto byRefResolution = resolveByRefHandler(source, expectedRef, messageRef, implicitSignatureRef, + EAttrs::test(attrs, EAttr::NoExtension)); + if (byRefResolution.resolved) { + ObjectInfo tempRetVal = declareTempLocal(expectedRef, false); + + addByRefRetVal(arguments, tempRetVal); + // adding mark for optimization routine + if (tempRetVal.kind == ObjectKind::TempLocalAddress) + writer->appendNode(BuildKey::ByRefOpMark, tempRetVal.argument); + + compileMessageOperation(node, source, byRefResolution, + implicitSignatureRef, arguments, opMode, &updatedOuterArgs); + + retVal = tempRetVal; + } + else retVal = compileMessageOperation(node, source, messageRef, + implicitSignatureRef, arguments, opMode, &updatedOuterArgs); + + break; + } } - else return classSymbol; + + return retVal; } -void Compiler :: compileMethodCode(BuildTreeWriter& writer, ClassScope* classScope, MethodScope& scope, CodeScope& codeScope, - SyntaxNode node, bool newFrame) +ObjectInfo Compiler::Expression :: compilePropertyOperation(SyntaxNode node, ref_t expectedRef, ExpressionAttribute attrs) { - if (!newFrame) { - if (scope.checkHint(MethodHint::Multimethod)) { - compileMultidispatch(writer, codeScope, *classScope, node, false); - } + ObjectInfo retVal = { }; + ArgumentsInfo arguments; + ArgumentsInfo outerArgsToUpdate; - // new stack frame - writer.appendNode(BuildKey::OpenFrame); - newFrame = true; - } + SyntaxNode current = node.firstChild(); + ObjectInfo source = compileObject(current, EAttr::Parameter, &outerArgsToUpdate); + if (invalidObjectMode(source)) + scope.raiseError(errInvalidOperation, node); - // stack should contains current self reference - // the original message should be restored if it is a generic method - scope.selfLocal = codeScope.newLocal(); - writer.appendNode(BuildKey::Assigning, scope.selfLocal); + arguments.add(source); - if (scope.isYieldable()) { - ExprScope exprScope(&codeScope); - WriterContext context = { &writer, &exprScope, node }; + // NOTE : the operation target shouldn't be a primtive type + source = validateObject(node, source, 0, true, true, false); - // reserve the place for the next step - int offset = allocateLocalAddress(codeScope, sizeof(addr_t), false); + current = current.nextNode(); + mssg_t messageRef = compiler->mapMessage(scope, current, true, + source.kind == ObjectKind::Extension, false); - ObjectInfo contextField = classScope->mapField(YIELD_CONTEXT_FIELD, EAttr::None); + mssg_t resolvedMessage = compiler->_logic->resolveSingleDispatch(*scope.moduleScope, + compiler->retrieveType(scope, source), messageRef); - writeObjectInfo(context, contextField); - writer.appendNode(BuildKey::LoadingStackDump); - writer.appendNode(BuildKey::YieldDispatch, offset); - } - if (scope.isGeneric()) { - scope.messageLocalAddress = allocateLocalAddress(codeScope, sizeof(mssg_t), false); - writer.appendNode(BuildKey::SavingIndex, scope.messageLocalAddress); + bool variadicArgList = false; + ref_t expectedSignRef = 0; + if (resolvedMessage) + scope.module->resolveAction(getAction(resolvedMessage), expectedSignRef); + + ref_t implicitSignatureRef = compileMessageArguments(current, arguments, expectedSignRef, EAttr::NoPrimitives, + &outerArgsToUpdate, variadicArgList); + EAttr opMode = EAttr::None; + if (variadicArgList) { + // HOTFIX : set variadic flag if required + messageRef |= VARIADIC_MESSAGE; + + opMode = EAttr::WithVariadicArg; } - ObjectInfo retVal = { }; + auto byRefResolution = resolveByRefHandler(source, expectedRef, + messageRef, implicitSignatureRef, EAttrs::test(attrs, EAttr::NoExtension)); + if (byRefResolution.resolved) { + ObjectInfo tempRetVal = declareTempLocal(expectedRef, false); - SyntaxNode bodyNode = node.firstChild(SyntaxKey::ScopeMask); - switch (bodyNode.key) { - case SyntaxKey::CodeBlock: - retVal = compileCode(writer, codeScope, bodyNode, scope.closureMode); - break; - case SyntaxKey::ReturnExpression: - if (scope.isYieldable()) { - clearYieldContext(); - } - retVal = compileRetExpression(writer, codeScope, bodyNode, EAttr::None); - break; - case SyntaxKey::ResendDispatch: - retVal = compileResendCode(writer, codeScope, - scope.constructorMode ? mapConstructorTarget(scope) : scope.mapSelf(), - bodyNode); + addByRefRetVal(arguments, tempRetVal); + if (tempRetVal.kind == ObjectKind::TempLocalAddress) + writer->appendNode(BuildKey::ByRefOpMark, tempRetVal.argument); - if (codeScope.isByRefHandler() && retVal.kind != ObjectKind::Unknown) { - ExprScope exprScope(&codeScope); - WriterContext context = { &writer, &exprScope, node }; + compileMessageOperation(node, source, byRefResolution, + implicitSignatureRef, arguments, opMode, &outerArgsToUpdate); + + retVal = tempRetVal; + } + else retVal = compileMessageOperation(node, source, { messageRef }, + implicitSignatureRef, arguments, opMode, &outerArgsToUpdate); - ObjectInfo byRefVar = codeScope.mapByRefReturnArg(); + return retVal; +} - retVal = convertObject(writer, exprScope, node, retVal, - retrieveStrongType(scope, byRefVar), false, false); +ObjectInfo Compiler::Expression :: compileOperation(SyntaxNode node, int operatorId, ref_t expectedRef, ExpressionAttribute mode) +{ + SyntaxNode loperand = node.firstChild(); + SyntaxNode roperand = loperand.nextNode(); - compileAssigningOp(context, byRefVar, retVal); - } - else if (scope.info.outputRef != 0 && !scope.constructorMode){ - ExprScope exprScope(&codeScope); - WriterContext context = { &writer, &exprScope, node }; + if (operatorId == SET_OPERATOR_ID) { + // assign operation is a special case + if (loperand == SyntaxKey::IndexerOperation) { + return compileOperation(loperand, roperand, SET_INDEXER_OPERATOR_ID, expectedRef); + } + else if (loperand == SyntaxKey::Expression) { + if (!isSimpleNode(loperand)) + scope.raiseError(errInvalidOperation, loperand); - ref_t outputRef = scope.info.outputRef; - if (outputRef && outputRef != V_AUTO) { - convertObject(writer, exprScope, node, retVal, outputRef, false, false); + return compileAssigning(loperand.firstChild(), roperand, mode); + } + else return compileAssigning(loperand, roperand, mode); - exprScope.syncStack(); - } + } + else return compileOperation(loperand, roperand, operatorId, expectedRef); +} - writeObjectInfo(context, - boxArgument(context, retVal, - scope.checkHint(MethodHint::Stacksafe), true, false)); - } +ObjectInfo Compiler::Expression :: compileSpecialOperation(SyntaxNode node, int operatorId, ref_t expectedRef) +{ + ObjectInfo retVal = {}; + switch (operatorId) { + case BREAK_OPERATOR_ID: + writer->appendNode(BuildKey::BreakOp); break; - case SyntaxKey::Redirect: - retVal = compileRedirect(writer, codeScope, bodyNode); + case CONTINUE_OPERATOR_ID: + writer->appendNode(BuildKey::ContinueOp); break; default: + assert(false); break; } - // if the method returns itself - if (retVal.kind == ObjectKind::Unknown && !codeScope.withRetStatement) { - ExprScope exprScope(&codeScope); - WriterContext context = { &writer, &exprScope, node }; - - // NOTE : extension should re - retVal = scope.mapSelf(!scope.isExtension); - if (codeScope.isByRefHandler()) { - ObjectInfo byRefVar = codeScope.mapByRefReturnArg(); + return retVal; +} - retVal = convertObject(writer, exprScope, node, retVal, - retrieveStrongType(scope, byRefVar), false, false); +void Compiler::Expression :: compileYieldOperation(SyntaxNode node) +{ + CodeScope* codeScope = Scope::getScope(scope, Scope::ScopeLevel::Code); + MethodScope* methodScope = Scope::getScope(scope, Scope::ScopeLevel::Method); + ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); - compileAssigningOp(context, byRefVar, retVal); - } - else { - ref_t outputRef = scope.info.outputRef; - if (outputRef && outputRef != V_AUTO) { - convertObject(writer, exprScope, node, retVal, outputRef, false, false); + if (!methodScope->isYieldable()) + scope.raiseError(errInvalidOperation, node); - exprScope.syncStack(); - } + ObjectInfo contextField = classScope->mapField(YIELD_CONTEXT_FIELD, EAttr::None); - writeObjectInfo(context, - boxArgument(context, retVal, - scope.checkHint(MethodHint::Stacksafe), true, false)); - } - } + writer->newNode(BuildKey::YieldingOp, -scope.moduleScope->ptrSize); + writer->newNode(BuildKey::Tape); - if (scope.isYieldable()) { - clearYieldContext(); - } + writeObjectInfo(contextField, node); - writer.appendNode(BuildKey::CloseFrame); + writer->appendNode(BuildKey::SavingStackDump); - if (scope.checkHint(MethodHint::Constant)) { - ref_t constRef = generateConstant(scope, retVal, 0); - if (constRef) { - classScope->addRefAttribute(scope.message, ClassAttribute::ConstantMethod, constRef); + compiler->compileRetExpression(*writer, *codeScope, node, EAttr::None); - classScope->save(); - } - else scope.raiseError(errInvalidConstAttr, node); - } + writer->closeNode(); + writer->closeNode(); } -void Compiler :: compileYieldInitializing(BuildTreeWriter& writer, CodeScope& scope, SyntaxNode node) +ObjectInfo Compiler::Expression :: compileAssignOperation(SyntaxNode node, int operatorId, ref_t expectedRef) { - ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); + SyntaxNode lnode = node.firstChild(); + SyntaxNode rnode = lnode.nextNode(); - ObjectInfo contextField = classScope->mapField(YIELD_CONTEXT_FIELD, EAttr::None); + ArgumentsInfo updatedOuterArgs; + ObjectInfo loperand = compile(lnode, 0, EAttr::Parameter, &updatedOuterArgs); + ObjectInfo roperand = {}; - ExprScope exprScope(&scope); + size_t argLen = 1; + ref_t arguments[2] = {}; + arguments[0] = loperand.typeInfo.typeRef; - pos_t contextSize = classScope->getMssgAttribute(node.arg.reference, ClassAttribute::YieldContextSize); + if (rnode != SyntaxKey::None) { + roperand = compile(rnode, 0, EAttr::Parameter, &updatedOuterArgs); + arguments[1] = roperand.typeInfo.typeRef; + argLen++; + } - writer.appendNode(BuildKey::NilReference); - writer.appendNode(BuildKey::SavingInStack); + ref_t dummy = 0; + BuildKey op = compiler->_logic->resolveOp(*scope.moduleScope, operatorId, arguments, argLen, dummy); + if (op != BuildKey::None) { + // box argument locally if required + loperand = boxArgumentLocally(loperand, true, true); - writer.newNode(BuildKey::CreatingStruct, contextSize); - writer.appendNode(BuildKey::Type, scope.moduleScope->buildins.superReference); - writer.closeNode(); + if (roperand.kind != ObjectKind::Unknown) { + roperand = boxArgumentLocally(roperand, true, false); - writer.appendNode(BuildKey::SetImmediateField, 0); + writeObjectInfo(roperand, node); - WriterContext context = { &writer, &exprScope, node }; - compileAssigningOp(context, contextField, { ObjectKind::Object }); -} + writer->appendNode(BuildKey::SavingInStack, 0); + } -void Compiler :: compileInitializerMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode classNode) -{ - beginMethod(writer, scope, classNode, BuildKey::Method, false); + writer->newNode(op, operatorId); + writer->appendNode(BuildKey::Index, loperand.argument); + writer->closeNode(); - CodeScope codeScope(&scope); + unboxArguments({}, &updatedOuterArgs); - // new stack frame - writer.appendNode(BuildKey::OpenFrame); + scope.reserveArgs(2); + } + else { + switch (operatorId) { + case ADD_ASSIGN_OPERATOR_ID: + operatorId = ADD_OPERATOR_ID; + break; + case SUB_ASSIGN_OPERATOR_ID: + operatorId = SUB_OPERATOR_ID; + break; + case MUL_ASSIGN_OPERATOR_ID: + operatorId = MUL_OPERATOR_ID; + break; + case DIV_ASSIGN_OPERATOR_ID: + operatorId = DIV_OPERATOR_ID; + break; + default: + break; + } - // stack should contains current self reference - // the original message should be restored if it is a generic method - scope.selfLocal = codeScope.newLocal(); - writer.appendNode(BuildKey::Assigning, scope.selfLocal); + mssg_t message = Compiler::resolveOperatorMessage(scope.moduleScope, operatorId); + ArgumentsInfo messageArguments; + messageArguments.add(loperand); - SyntaxNode current = classNode.firstChild(); - while (current != SyntaxKey::None) { - if (current == SyntaxKey::AssignOperation) { - if (current.existChild(SyntaxKey::YieldContext)) { - compileYieldInitializing(writer, codeScope, current.findChild(SyntaxKey::YieldContext)); - } - else compileRootExpression(writer, codeScope, current, EAttr::None); - } - current = current.nextNode(); - } + if (roperand.kind != ObjectKind::Unknown) + messageArguments.add(roperand); - codeScope.syncStack(&scope); + ObjectInfo opVal = compileWeakOperation(node, arguments, 2, loperand, + messageArguments, message, expectedRef, &updatedOuterArgs); - writer.appendNode(BuildKey::CloseFrame); + if (!compileAssigningOp(loperand, opVal)) + scope.raiseError(errInvalidOperation, node); + } - endMethod(writer, scope); + return loperand; } -void Compiler :: compileStaticInitializerMethod(BuildTreeWriter& writer, ClassScope& scope, SyntaxNode node) +ObjectInfo Compiler::Expression :: compileBoolOperation(SyntaxNode node, int operatorId) { - BuildNode buildNode = writer.CurrentNode(); - while (buildNode != BuildKey::Root) - buildNode = buildNode.parentNode(); + SyntaxNode lnode = node.firstChild(); + SyntaxNode rnode = lnode.nextNode(); - BuildTreeWriter nestedWriter(buildNode); + ObjectInfo loperand = {}; - nestedWriter.newNode(BuildKey::Symbol, node.arg.reference); + bool condOp = isConditionalOp(lnode.key); + bool nativeOp = false; + if (!condOp) { + // If it is not a comparison operation + // we have to define if native short-circuit evaluation can be used + loperand = compile(lnode, 0, EAttr::Parameter, nullptr); - nestedWriter.newNode(BuildKey::Tape); - nestedWriter.appendNode(BuildKey::OpenFrame); + nativeOp = compiler->_logic->isCompatible(*scope.moduleScope, + { scope.moduleScope->branchingInfo.typeRef }, loperand.typeInfo, true); + } + else nativeOp = true; - SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { - if (current == SyntaxKey::AssignOperation) { - nestedWriter.appendNode(BuildKey::OpenStatement); - addBreakpoint(nestedWriter, findObjectNode(current), BuildKey::Breakpoint); + if (nativeOp) { + writer->newNode(BuildKey::ShortCircuitOp, operatorId); - ExprScope exprScope(&scope); - compileExpression(nestedWriter, exprScope, - current, 0, EAttr::None, nullptr); + writer->appendNode(BuildKey::TrueConst, scope.moduleScope->branchingInfo.trueRef); + writer->appendNode(BuildKey::FalseConst, scope.moduleScope->branchingInfo.falseRef); - nestedWriter.appendNode(BuildKey::EndStatement); + writer->newNode(BuildKey::Tape); + if (loperand.kind == ObjectKind::Unknown) + loperand = compile(lnode, scope.moduleScope->branchingInfo.typeRef, EAttr::None, nullptr); - exprScope.syncStack(); - } - current = current.nextNode(); - } + writeObjectInfo(loperand, node); - nestedWriter.appendNode(BuildKey::CloseFrame); - nestedWriter.appendNode(BuildKey::Exit); + writer->closeNode(); - nestedWriter.closeNode(); - nestedWriter.closeNode(); -} + writer->newNode(BuildKey::Tape); + writeObjectInfo(compile(rnode, scope.moduleScope->branchingInfo.typeRef, EAttr::None, nullptr), node); + writer->closeNode(); -void Compiler :: compileAbstractMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode node, bool abstractMode) -{ - SyntaxNode current = node.firstChild(SyntaxKey::MemberMask); - if (current.key == SyntaxKey::WithoutBody) { - // NOTE : abstract method should not have a body - if (!abstractMode) - scope.raiseError(errNotAbstractClass, node); + writer->closeNode(); + + return { ObjectKind::Object, { scope.moduleScope->branchingInfo.typeRef }, 0 }; } - else scope.raiseError(errAbstractMethodCode, node); + else { + // bad luck - we have to implement weak short-circuit evaluation + // using lazy expression + SyntaxTree tempTree; + SyntaxTreeWriter treeWriter(tempTree); + treeWriter.newNode(SyntaxKey::LazyOperation); + SyntaxTree::copyNode(treeWriter, rnode, true); + treeWriter.closeNode(); - writer.newNode(BuildKey::AbstractMethod, scope.message); - writer.closeNode(); + ObjectInfo roperand = compileClosure(tempTree.readRoot(), EAttr::Parameter, nullptr); + ref_t arguments[2] = + { + compiler->retrieveType(scope, loperand), + compiler->retrieveType(scope, roperand) + }; + + ArgumentsInfo messageArguments; + messageArguments.add(loperand); + messageArguments.add(roperand); + + mssg_t message = compiler->resolveOperatorMessage(scope.moduleScope, operatorId); + + return compileWeakOperation(node, arguments, 2, loperand, + messageArguments, message, 0, nullptr); + } } -void Compiler :: compileMultidispatch(BuildTreeWriter& writer, CodeScope& scope, ClassScope& classScope, - SyntaxNode node, bool implicitMode) +ObjectInfo Compiler::Expression :: typecastObject(SyntaxNode node, ObjectInfo source, ref_t targetRef) { - mssg_t message = scope.getMessageID(); + if (targetRef == scope.moduleScope->buildins.superReference) + return source; - BuildKey op = BuildKey::DispatchingOp; - ref_t opRef = classScope.info.attributes.get({ message, ClassAttribute::OverloadList }); - if (!opRef) - scope.raiseError(errIllegalOperation, node); + ustr_t refName2 = scope.module->resolveReference(targetRef); - if (test(classScope.info.header.flags, elSealed) || test(message, STATIC_MESSAGE)) { - op = BuildKey::SealedDispatchingOp; - } + ref_t signRef = scope.module->mapSignature(&targetRef, 1, false); + ref_t actionRef = scope.module->mapAction(CAST_MESSAGE, signRef, false); - writer.newNode(op, opRef); - writer.appendNode(BuildKey::Message, message); - writer.closeNode(); + mssg_t typecastMssg = encodeMessage(actionRef, 1, CONVERSION_MESSAGE); - if (implicitMode) { - // if it is an implicit mode (auto generated multi-method) - if (classScope.extensionDispatcher) { - writer.appendNode(BuildKey::Argument, 0); + ArgumentsInfo arguments; + arguments.add(source); - writer.newNode(BuildKey::RedirectOp, node.arg.reference); - writer.closeNode(); - } - else if (node.arg.reference) { - // if it is a special case of the multimethod - conversion dispatcher - // the argument should be typecasted - if (getArgCount(message) == 1 && getAction(message) == getAction(scope.moduleScope->buildins.constructor_message)) { - writer.appendNode(BuildKey::Argument); - } + ObjectInfo retVal = compileMessageOperation(node, source, typecastMssg, + 0, arguments, EAttr::None, nullptr); + // NOTE : typecasting message is guaranteed to return the instance of the target type + retVal.typeInfo = { targetRef }; - writer.appendNode(BuildKey::RedirectOp, node.arg.reference); - } - else { - SyntaxNode targetNode = node.findChild(SyntaxKey::Target); - assert(targetNode != SyntaxKey::None); + return retVal; +} + +ObjectInfo Compiler::Expression :: compileIndexerOperation(SyntaxNode node, int operatorId, ref_t expectedRef) +{ + // HOTFIX : recognize fixed-array declaration + SyntaxNode loperand = node.firstChild(); + if (loperand == SyntaxKey::Object) { + ObjectInfo info = compiler->mapObject(scope, loperand, EAttr::Lookahead); + if (info.kind == ObjectKind::NewVariable) { + // if it is a new variable declaration - treat it like a new array + compiler->declareVariable(scope, node, info.typeInfo, false); // !! temporal - typeref should be provided or super class + + if (compiler->_trackingUnassigned) { + CodeScope* codeScope = Scope::getScope(scope, Scope::ScopeLevel::Code); + + scope.markAsAssigned(codeScope->mapLocal(loperand.firstChild(SyntaxKey::TerminalMask).identifier())); + } - writer.newNode(BuildKey::StrongRedirectOp, message); - writer.appendNode(BuildKey::Type, targetNode.arg.reference); - writer.closeNode(); + return {}; // !! temporally + } + else if (info.kind == ObjectKind::MssgLiteral) { + return compiler->mapMessageConstant(scope, node, info.reference); + } + else if (info.kind == ObjectKind::ExtMssgLiteral) { + return compiler->mapExtMessageConstant(scope, node, info.reference, info.typeInfo.elementRef); } } + + return compileOperation(node, operatorId, expectedRef, EAttr::None); } -ObjectInfo Compiler :: compileRedirect(BuildTreeWriter& writer, CodeScope& codeScope, SyntaxNode node) +ObjectInfo Compiler::Expression :: compileBranchingOperation(SyntaxNode node, int operatorId, bool retValExpected, bool withoutDebugInfo) { - ExprScope scope(&codeScope); - ArgumentsInfo arguments; - ArgumentsInfo updatedOuterArgs; - - ObjectInfo target = compileExpression(writer, scope, node.firstChild(), 0, EAttr::Parameter, &updatedOuterArgs); - - mssg_t messageRef = codeScope.getMessageID(); + SyntaxNode lnode = node.firstChild(); + SyntaxNode rnode = /*skipNestedExpression(*/lnode.nextNode()/*)*/; + SyntaxNode r2node = {}; + if (operatorId == IF_ELSE_OPERATOR_ID) + r2node = rnode.nextNode(); - if (!test(messageRef, FUNCTION_MESSAGE)) - arguments.add(target); + ArgumentsInfo updatedOuterArgs; - MethodScope* methodScope = Scope::getScope(codeScope, Scope::ScopeLevel::Method); + ObjectInfo loperand = compile(lnode, 0, EAttr::Parameter, &updatedOuterArgs); - for (auto it = methodScope->parameters.start(); !it.eof(); ++it) { - arguments.add(methodScope->mapParameter(it.key(), EAttr::None)); + if (!withoutDebugInfo) { + // HOTFIX : to allow correct step over the branching statement + writer->appendNode(BuildKey::EndStatement); + writer->appendNode(BuildKey::VirtualBreakoint); } - ref_t signRef = getSignature(scope.module, messageRef); - - MessageResolution resolution = { true, messageRef }; - _logic->setSignatureStacksafe(*scope.moduleScope, signRef, resolution.stackSafeAttr); - - ObjectInfo retVal = compileMessageOperation(writer, scope, {}, target, resolution, - signRef, arguments, EAttr::None, & updatedOuterArgs); + auto retVal = compileBranchingOperation(node, loperand, rnode, r2node, operatorId, &updatedOuterArgs, + retValExpected, withoutDebugInfo); - scope.syncStack(); + if (!withoutDebugInfo) + writer->appendNode(BuildKey::OpenStatement); // HOTFIX : to match the closing statement return retVal; } -ObjectInfo Compiler :: compileResendCode(BuildTreeWriter& writer, CodeScope& codeScope, ObjectInfo source, SyntaxNode node) +ObjectInfo Compiler::Expression :: compileLoop(SyntaxNode node, ExpressionAttribute mode) { - ObjectInfo retVal = {}; + ObjectInfo retVal = { ObjectKind::Object }; - if (!node.arg.reference) { - bool propertyMode = node.firstChild().key == SyntaxKey::PropertyOperation; + writer->newNode(BuildKey::LoopOp); - SyntaxNode current = node.firstChild().firstChild(); - bool superMode = false; - while (current == SyntaxKey::Attribute) { - if (!_logic->validateResendAttribute(current.arg.reference, superMode)) { - codeScope.raiseWarning(WARNING_LEVEL_1, wrnInvalidHint, current); - } - current = current.nextNode(); - } + compile(node, 0, mode, nullptr); - ObjectInfo target = source; - if (superMode) { - switch (source.kind) { - case ObjectKind::SelfLocal: - source.kind = ObjectKind::SuperLocal; - target = source; - break; - case ObjectKind::ConstructorSelf: - case ObjectKind::Class: - case ObjectKind::ClassSelf: - { - // NOTE : for the constructor redirect - use the class parent as a target (still keeping the original class - // as a parameter) - ClassInfo classInfo; - if (_logic->defineClassInfo(*codeScope.moduleScope, classInfo, - source.kind == ObjectKind::ConstructorSelf ? source.extra : source.reference, - true)) - { - ObjectInfo temp = mapClassSymbol(codeScope, classInfo.header.parentRef); - if (source.kind == ObjectKind::ConstructorSelf) { - target.typeInfo = temp.typeInfo; - target.extra = temp.reference; - } - else target = temp; - } - else codeScope.raiseError(errInvalidOperation, node); - break; - } - default: - codeScope.raiseError(errInvalidOperation, node); - break; - } - } + writer->appendNode(BuildKey::VirtualBreakoint); - ExprScope scope(&codeScope); - ArgumentsInfo arguments; - ArgumentsInfo updatedOuterArgs; + writer->closeNode(); - mssg_t messageRef = mapMessage(scope, current, propertyMode, codeScope.isExtension(), false); + return retVal; +} - mssg_t resolvedMessage = _logic->resolveSingleDispatch(*scope.moduleScope, - retrieveType(scope, source), messageRef); +ObjectInfo Compiler::Expression :: compileExtern(SyntaxNode node, ExpressionAttribute mode) +{ + writer->newNode(BuildKey::ExternOp); - ref_t expectedSignRef = 0; - if (resolvedMessage) - scope.module->resolveAction(getAction(resolvedMessage), expectedSignRef); + compile(node, 0, mode, nullptr); - if (!test(messageRef, FUNCTION_MESSAGE)) - arguments.add(source); + writer->closeNode(); - bool withVariadicArg = false; - ref_t implicitSignatureRef = compileMessageArguments(writer, scope, current, arguments, expectedSignRef, - EAttr::NoPrimitives, &updatedOuterArgs, withVariadicArg); + return { }; +} - EAttr opMode = EAttr::CheckShortCircle; - if (withVariadicArg) { - messageRef |= VARIADIC_MESSAGE; +ObjectInfo Compiler::Expression :: compileCatchOperation(SyntaxNode node) +{ + ObjectInfo ehLocal = declareTempStructure({ (int)scope.moduleScope->ehTableEntrySize, false }); - opMode = opMode | EAttr::WithVariadicArg; - } + SyntaxNode catchNode = node.findChild(SyntaxKey::CatchDispatch); + SyntaxNode finallyNode = node.findChild(SyntaxKey::FinallyBlock).firstChild(); + SyntaxNode opNode = node.firstChild(); + if (opNode.existChild(SyntaxKey::ClosureBlock)) + opNode = opNode.findChild(SyntaxKey::ClosureBlock); - retVal = compileMessageOperation(writer, scope, node, target, messageRef, - implicitSignatureRef, arguments, opMode, &updatedOuterArgs); + writer->newNode(BuildKey::CatchOp, ehLocal.argument); - scope.syncStack(); - } - else assert(false); + writer->newNode(BuildKey::Tape); + compile(opNode, 0, EAttr::None, nullptr); + writer->closeNode(); - SyntaxNode current = node.nextNode(); - if (current == SyntaxKey::CodeBlock) { - MethodScope* methodScope = Scope::getScope(codeScope, Scope::ScopeLevel::Method); - if (methodScope->constructorMode) { - // HOTFIX : overwrite self variable for the redirect constructor code + writer->newNode(BuildKey::Tape); + compileMessageOperationR({ ObjectKind::Object }, + catchNode.firstChild().firstChild(), false); + writer->closeNode(); - // stack should contains current self reference - // the original message should be restored if it is a generic method - writer.appendNode(BuildKey::Assigning, methodScope->selfLocal); - } + if (finallyNode != SyntaxKey::None) { + if (finallyNode.existChild(SyntaxKey::ClosureBlock)) + finallyNode = finallyNode.findChild(SyntaxKey::ClosureBlock); - retVal = compileCode(writer, codeScope, current, methodScope->closureMode); + writer->newNode(BuildKey::Tape); + compile(finallyNode, 0, EAttr::None, nullptr); + writer->closeNode(); } - return retVal; + writer->closeNode(); + + return { ObjectKind::Object }; } -void Compiler :: compileDispatchCode(BuildTreeWriter& writer, CodeScope& codeScope, SyntaxNode node) +ObjectInfo Compiler::Expression :: compileFinalOperation(SyntaxNode node) { - ClassScope* classScope = Scope::getScope(codeScope, Scope::ScopeLevel::Class); + ObjectInfo ehLocal = declareTempStructure({ (int)scope.moduleScope->ehTableEntrySize, false }); - compileMultidispatch(writer, codeScope, *classScope, node, true); -} + int index1 = scope.newTempLocal(); -void Compiler :: compileConstructorDispatchCode(BuildTreeWriter& writer, CodeScope& codeScope, - ClassScope& classClassScope, SyntaxNode node) -{ - compileMultidispatch(writer, codeScope, classClassScope, node, true); -} + SyntaxNode finallyNode = node.findChild(SyntaxKey::FinallyBlock).firstChild(); + SyntaxNode opNode = node.firstChild(); + if (opNode.existChild(SyntaxKey::ClosureBlock)) + opNode = opNode.findChild(SyntaxKey::ClosureBlock); -void Compiler :: compileDirectResendCode(BuildTreeWriter& writer, CodeScope& codeScope, SyntaxNode node) -{ - mssg_t dispatchMessage = node.arg.reference; + writer->newNode(BuildKey::FinalOp, ehLocal.argument); + writer->appendNode(BuildKey::Index, index1); - SyntaxNode targetNode = node.findChild(SyntaxKey::Target); - ref_t disptachTarget = targetNode.arg.reference; - if (!disptachTarget) - assert(false); + writer->newNode(BuildKey::Tape); + compile(opNode, 0, EAttr::None, nullptr); + writer->closeNode(); - writer.newNode(BuildKey::StrongRedirectOp, dispatchMessage); - writer.appendNode(BuildKey::Type, disptachTarget); - writer.closeNode(); + if (finallyNode.existChild(SyntaxKey::ClosureBlock)) + finallyNode = finallyNode.findChild(SyntaxKey::ClosureBlock); + + writer->newNode(BuildKey::Tape); + compile(finallyNode, 0, EAttr::None, nullptr); + writer->closeNode(); + + writer->closeNode(); + + return {}; } -void Compiler :: compileDispatchProberCode(BuildTreeWriter& writer, CodeScope& scope, SyntaxNode node) +ObjectInfo Compiler::Expression :: compileAltOperation(SyntaxNode node) { - ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); + ObjectInfo ehLocal = declareTempStructure({ (int)scope.moduleScope->ehTableEntrySize, false }); - mssg_t message = scope.getMessageID(); - mssg_t dispatchMessage = node.arg.reference; + ObjectInfo target = {}; + SyntaxNode current = node.firstChild(); + if (current == SyntaxKey::MessageOperation || current == SyntaxKey::PropertyOperation) { + SyntaxNode objNode = current.firstChild(); - BuildKey op = BuildKey::DispatchingOp; - ref_t opRef = classScope->info.attributes.get({ dispatchMessage, ClassAttribute::OverloadList }); - if (!opRef) - scope.raiseError(errIllegalOperation, node); + target = compileObject(objNode, EAttr::Parameter, nullptr); - if (test(classScope->info.header.flags, elSealed) || test(dispatchMessage, STATIC_MESSAGE)) { - op = BuildKey::SealedDispatchingOp; + writer->newNode(BuildKey::AltOp, ehLocal.argument); + + writer->newNode(BuildKey::Tape); + compileMessageOperationR(target, objNode.nextNode(), current == SyntaxKey::PropertyOperation); + writer->closeNode(); } + else scope.raiseError(errInvalidOperation, node); - writer.newNode(op, opRef); - writer.appendNode(BuildKey::Message, dispatchMessage); - writer.closeNode(); + writer->newNode(BuildKey::Tape); + SyntaxNode altNode = current.nextNode().firstChild(); - SyntaxNode targetNode = node.findChild(SyntaxKey::Target); - if (targetNode != SyntaxKey::None) { - writer.newNode(BuildKey::StrongRedirectOp, message); - writer.appendNode(BuildKey::Type, targetNode.arg.reference); - writer.closeNode(); + if (target.mode == TargetMode::Casting) { + // HOTFIX : for the cast, the argument is a target + target = compile(current.findChild(SyntaxKey::Expression), + 0, EAttr::Parameter, nullptr); } - else { - writer.appendNode(BuildKey::AccSwapping, 1); - // get feedback arg - writer.appendNode(BuildKey::RedirectOp, overwriteArgCount(scope.moduleScope->buildins.invoke_message, 2)); - } + compileMessageOperationR(target, altNode.firstChild(), false); + + writer->closeNode(); + + writer->closeNode(); + + return { ObjectKind::Object }; } -mssg_t Compiler :: declareInplaceConstructorHandler(MethodScope& invokerScope, ClassScope& classClassScope) +ObjectInfo Compiler::Expression :: compileIsNilOperation(SyntaxNode node) { - ClassScope* classScope = Scope::getScope(invokerScope, Scope::ScopeLevel::Class); + ObjectInfo ehLocal = declareTempStructure({ (int)scope.moduleScope->ehTableEntrySize, false }); - ref_t actionRef, flags; - pos_t argCount; - decodeMessage(invokerScope.message, actionRef, argCount, flags); + ObjectInfo loperand = {}; + SyntaxNode current = node.firstChild(); - flags &= ~FUNCTION_MESSAGE; + if (current == SyntaxKey::MessageOperation || current == SyntaxKey::PropertyOperation) { + SyntaxNode objNode = current.firstChild(); - ref_t signRef = 0; - ustr_t actionName = invokerScope.module->resolveAction(actionRef, signRef); - ref_t signArgs[ARG_COUNT]; - size_t signLen = invokerScope.module->resolveSignature(signRef, signArgs); + loperand = compileObject(objNode, EAttr::Parameter, nullptr); - // insert a struct variable - for (size_t i = signLen; i > 0; i--) - signArgs[i] = signArgs[i - 1]; + writer->newNode(BuildKey::AltOp, ehLocal.argument); - signArgs[0] = classScope->reference; - signLen++; + writer->newNode(BuildKey::Tape); + compileMessageOperationR(loperand, objNode.nextNode(), + current == SyntaxKey::PropertyOperation); + writer->closeNode(); - mssg_t inplaceMessage = encodeMessage( - invokerScope.module->mapAction( - actionName, invokerScope.module->mapSignature(signArgs, signLen, false), false), argCount + 1, flags | STATIC_MESSAGE); + writer->newNode(BuildKey::Tape); + writer->appendNode(BuildKey::NilReference, 0); + writer->closeNode(); - if (MethodScope::checkHint(invokerScope.info, MethodHint::Protected)) { - mssg_t publicInplaceMessage = encodeMessage( - invokerScope.module->mapAction( - CONSTRUCTOR_MESSAGE, invokerScope.module->mapSignature(signArgs, signLen, false), false), argCount + 1, flags | STATIC_MESSAGE); + writer->closeNode(); - classClassScope.addMssgAttribute(publicInplaceMessage, - ClassAttribute::ProtectedAlias, inplaceMessage); + loperand = saveToTempLocal({ ObjectKind::Object }); } + else if (current == SyntaxKey::Object) { + loperand = compileObject(current, EAttr::Parameter, nullptr); + } + else scope.raiseError(errInvalidOperation, node); - MethodInfo info = { }; - - info.hints |= (ref_t)MethodHint::Private; - info.hints |= (ref_t)MethodHint::Sealed; - info.hints |= (ref_t)MethodHint::Stacksafe; + SyntaxNode altNode = current.nextNode(); + ObjectInfo roperand = compile(altNode, 0, EAttr::Parameter, nullptr); - classClassScope.info.methods.add(inplaceMessage, info); - classClassScope.save(); + writeObjectInfo(roperand, node); + writer->appendNode(BuildKey::SavingInStack); + writeObjectInfo(loperand, node); + writer->appendNode(BuildKey::NilOp, ISNIL_OPERATOR_ID); - return inplaceMessage; + return { ObjectKind::Object }; } -mssg_t Compiler :: compileInplaceConstructorHandler(BuildTreeWriter& writer, MethodScope& invokerScope, ClassScope& classClassScope, - SyntaxNode current, SyntaxNode methodNode, mssg_t byRefMessage) +ObjectInfo Compiler::Expression :: compileNested(SyntaxNode node, ExpressionAttribute mode, + ArgumentsInfo* updatedOuterArgs) { - ClassScope* classScope = Scope::getScope(invokerScope, Scope::ScopeLevel::Class); + TypeInfo parentInfo = { scope.moduleScope->buildins.superReference }; + EAttrs nestedMode = { EAttr::NestedDecl }; + compiler->declareExpressionAttributes(scope, node, parentInfo, nestedMode); - MethodScope privateScope(classScope); - // copy parameters - for (auto it = invokerScope.parameters.start(); !it.eof(); ++it) { - privateScope.parameters.add(it.key(), *it); - } + //// allow only new and type attrobutes + //if (nestedMode.attrs != EAttr::None && !EAttrs::test(nestedMode.attrs, EAttr::NewOp) && !EAttrs::test(nestedMode.attrs, EAttr::NewVariable)) + // ownerScope.raiseError(errInvalidOperation, node); - privateScope.info = classClassScope.info.methods.get(byRefMessage); + ref_t nestedRef = mapNested(mode); + InlineClassScope classScope(&scope, nestedRef); - privateScope.message = byRefMessage | STATIC_MESSAGE; - privateScope.info.hints |= (ref_t)MethodHint::Private; - privateScope.info.hints |= (ref_t)MethodHint::Sealed; - privateScope.info.hints |= (ref_t)MethodHint::Stacksafe; + compiler->compileNestedClass(*writer, classScope, node, parentInfo.typeRef); + + return compileNested(classScope, mode, updatedOuterArgs); +} + +ObjectInfo Compiler::Expression :: compileClosure(SyntaxNode node, ExpressionAttribute mode, + ArgumentsInfo* updatedOuterArgs) +{ + ref_t nestedRef = mapNested(mode); + InlineClassScope classScope(&scope, nestedRef); - privateScope.byRefReturnMode = true; - privateScope.nestedMode = invokerScope.nestedMode; - privateScope.functionMode = false; - privateScope.isEmbeddable = _logic->isEmbeddableStruct(classScope->info); - privateScope.constructorMode = true; + BuildNode buildNode = writer->CurrentNode(); + while (buildNode != BuildKey::Root) + buildNode = buildNode.parentNode(); - // NOTE self local is a first argument - privateScope.selfLocal = -1; + BuildTreeWriter nestedWriter(buildNode); + compiler->compileClosureClass(nestedWriter, classScope, node); - CodeScope codeScope(&privateScope); - beginMethod(writer, privateScope, methodNode, BuildKey::Method, true); - writer.appendNode(BuildKey::OpenFrame); + return compileNested(classScope, mode, updatedOuterArgs); +} - if (methodNode.existChild(SyntaxKey::FillingAttr)) { - ExprScope exprScope(&codeScope); - WriterContext context = { &writer, &exprScope, {} }; +ObjectInfo Compiler::Expression :: compileSubCode(SyntaxNode node, ExpressionAttribute mode, bool withoutNewScope) +{ + bool retValExpected = EAttrs::testAndExclude(mode, EAttr::RetValExpected); + bool withoutDebugInfo = EAttrs::testAndExclude(mode, EAttr::NoDebugInfo); - writeObjectInfo(context, privateScope.mapSelf()); - fillObject(writer, classScope->info, invokerScope.moduleScope->ptrSize); - } - if (classScope->info.methods.exist(invokerScope.moduleScope->buildins.init_message)) { - ExprScope exprScope(&codeScope); - WriterContext context = { &writer, &exprScope, {} }; + scope.syncStack(); - writeObjectInfo(context, privateScope.mapSelf()); + CodeScope* parentCodeScope = Scope::getScope(scope, Scope::ScopeLevel::Code); + ObjectInfo retVal = {}; + if (!withoutNewScope) { + CodeScope codeScope(parentCodeScope); + retVal = compiler->compileCode(*writer, codeScope, node, retValExpected, withoutDebugInfo); - compileInlineInitializing(writer, *classScope, methodNode); + codeScope.syncStack(parentCodeScope); } + else retVal = compiler->compileCode(*writer, *parentCodeScope, node, retValExpected); - switch (current.key) { - case SyntaxKey::CodeBlock: - compileCode(writer, codeScope, current, false); - break; - case SyntaxKey::None: - break; - default: - assert(false); - break; + if (!retValExpected) { + retVal = { ObjectKind::Object }; } - codeScope.syncStack(&privateScope); - writer.appendNode(BuildKey::CloseFrame); - endMethod(writer, privateScope); - - return privateScope.message; + return retVal; } -mssg_t Compiler :: compileByRefHandler(BuildTreeWriter& writer, MethodScope& invokerScope, SyntaxNode node, mssg_t byRefHandler) +void Compiler::Expression :: compileSwitchOperation(SyntaxNode node) { - ClassScope* classScope = Scope::getScope(invokerScope, Scope::ScopeLevel::Class); + Interpreter interpreter(scope.moduleScope, compiler->_logic); + ArgumentsInfo arguments; - MethodScope privateScope(classScope); - // copy parameters - for (auto it = invokerScope.parameters.start(); !it.eof(); ++it) { - privateScope.parameters.add(it.key(), *it); - } + SyntaxNode current = node.firstChild(); - // add byref return arg - TypeInfo refType = { V_WRAPPER, invokerScope.info.outputRef }; - auto sizeInfo = _logic->defineStructSize(*invokerScope.moduleScope, resolvePrimitiveType(invokerScope, refType, false)); + ObjectInfo loperand = compileObject(current, EAttr::Parameter, nullptr); - int offset = invokerScope.parameters.count() + 1u; - privateScope.parameters.add(RETVAL_ARG, { offset, refType, sizeInfo.size }); + writer->newNode(BuildKey::Switching); - privateScope.message = byRefHandler | STATIC_MESSAGE; - privateScope.info.hints |= (ref_t)MethodHint::Private; - privateScope.info.hints |= (ref_t)MethodHint::Sealed; + current = current.nextNode(); + while (current != SyntaxKey::None) { + switch (current.key) { + case SyntaxKey::SwitchOption: + { + SyntaxNode optionNode = current.firstChild(); - // HOTFIX : mark it as stacksafe if required - if (_logic->isEmbeddableStruct(classScope->info)) - privateScope.info.hints |= (ref_t)MethodHint::Stacksafe; + writer->newNode(BuildKey::SwitchOption); - privateScope.byRefReturnMode = true; - privateScope.nestedMode = invokerScope.nestedMode; - privateScope.functionMode = invokerScope.functionMode; - privateScope.isEmbeddable = invokerScope.isEmbeddable; + int operator_id = EQUAL_OPERATOR_ID; + ObjectInfo value = compiler->evalExpression(interpreter, scope, optionNode); + arguments.clear(); + arguments.add(loperand); + arguments.add(value); + ObjectInfo retVal = compileOperation(node, arguments, operator_id, 0, nullptr); + compileBranchingOperation(node, retVal, optionNode.nextNode(), {}, IF_OPERATOR_ID, nullptr, false, false); - classScope->info.methods.add(privateScope.message, privateScope.info); - classScope->save(); + writer->closeNode(); + break; + } + case SyntaxKey::SwitchLastOption: + writer->newNode(BuildKey::ElseOption); + compileSubCode(current.firstChild(), EAttr::None); + writer->closeNode(); + break; + default: + assert(false); + break; + } - compileMethod(writer, privateScope, node); + current = current.nextNode(); + } - return privateScope.message; + writer->closeNode(); } -void Compiler::compileByRefRedirectHandler(BuildTreeWriter& writer, MethodScope& invokerScope, SyntaxNode node, - mssg_t byRefHandler) +ObjectInfo Compiler::Expression :: compileCollection(SyntaxNode node, ExpressionAttribute mode) { - ClassScope* classScope = Scope::getScope(invokerScope, Scope::ScopeLevel::Class); - - MethodScope redirectScope(classScope); - // copy parameters - for (auto it = invokerScope.parameters.start(); !it.eof(); ++it) { - redirectScope.parameters.add(it.key(), *it); - } - - // add byref return arg - TypeInfo refType = { V_WRAPPER, invokerScope.info.outputRef }; - auto sizeInfo = _logic->defineStructSize(*invokerScope.moduleScope, resolvePrimitiveType(invokerScope, refType, false)); + bool constOne = EAttrs::testAndExclude(mode, EAttr::ConstantExpr); - int offset = invokerScope.parameters.count() + 1u; - redirectScope.parameters.add(RETVAL_ARG, { offset, refType, sizeInfo.size }); + SyntaxNode current = node.firstChild(); - redirectScope.message = byRefHandler; + ObjectInfo typeInfo = compileObject(node.firstChild(), EAttr::NestedDecl, nullptr); + if (typeInfo.kind != ObjectKind::Class) + scope.raiseError(errInvalidOperation, node); - // HOTFIX : mark it as stacksafe if required - if (_logic->isEmbeddableStruct(classScope->info)) - redirectScope.info.hints |= (ref_t)MethodHint::Stacksafe; + ref_t collectionTypeRef = compiler->retrieveStrongType(scope, typeInfo); - redirectScope.nestedMode = invokerScope.nestedMode; - redirectScope.functionMode = invokerScope.functionMode; - redirectScope.isEmbeddable = invokerScope.isEmbeddable; + ClassInfo collectionInfo; + compiler->_logic->defineClassInfo(*scope.moduleScope, collectionInfo, collectionTypeRef, false, true); - classScope->info.methods.add(redirectScope.message, redirectScope.info); - classScope->save(); + if (!test(collectionInfo.header.flags, elDynamicRole)) + scope.raiseError(errInvalidOperation, node); - compileMethod(writer, redirectScope, node); -} + if (constOne && node.arg.reference) { + bool byValue = compiler->_logic->isEmbeddableArray(*scope.moduleScope, collectionTypeRef); -void Compiler :: compileByRefHandlerInvoker(BuildTreeWriter& writer, MethodScope& methodScope, CodeScope& codeScope, mssg_t handler, ref_t targetRef) -{ - writer.appendNode(BuildKey::OpenFrame); + return { byValue ? ObjectKind::Constant : ObjectKind::ConstArray, { collectionTypeRef }, node.arg.reference }; + } - // stack should contains current self reference - // the original message should be restored if it is a generic method - methodScope.selfLocal = codeScope.newLocal(); - writer.appendNode(BuildKey::Assigning, methodScope.selfLocal); + auto fieldInfo = *(collectionInfo.fields.start()); + ref_t elementTypeRef = compiler->retrieveStrongType(scope, { ObjectKind::Object, { fieldInfo.typeInfo.elementRef }, 0 }); - // calling the byref handler - ExprScope scope(&codeScope); + auto sizeInfo = compiler->_logic->defineStructSize(collectionInfo); ArgumentsInfo arguments; + EAttr paramMode = EAttr::Parameter; + while (current != SyntaxKey::None) { + if (current == SyntaxKey::Expression) { + auto argInfo = compile(current, elementTypeRef, + paramMode, nullptr); + //ref_t argRef = retrieveStrongType(scope, argInfo); + //if (signatureLen >= ARG_COUNT) { + // signatureLen++; + //} + //else if (argRef) { + // signatures[signatureLen++] = argRef; + //} + //else signatures[signatureLen++] = superReference; - ObjectInfo tempRetVal = declareTempLocal(scope, targetRef, false); + arguments.add(argInfo); + } - ObjectInfo target = methodScope.mapSelf(); - MessageResolution resolution = { true, handler }; - if (methodScope.isExtension) { - resolution.extensionRef = methodScope.getClassRef(); + current = current.nextNode(); } - else arguments.add(target); - for (auto it = methodScope.parameters.start(); !it.eof(); ++it) { - arguments.add(methodScope.mapParameter(it.key(), EAttr::None)); + bool structMode = false; + if (sizeInfo.size < 0) { + structMode = true; + writer->newNode(BuildKey::CreatingStruct, arguments.count_pos() * -sizeInfo.size); } - addByRefRetVal(arguments, tempRetVal); + else if (sizeInfo.size == 0) { + // box the collection items + for (size_t i = 0; i < arguments.count(); i++) { + arguments[i] = boxArgument(arguments[i], false, true, false); + } - ref_t signRef = getSignature(scope.module, handler); - _logic->setSignatureStacksafe(*scope.moduleScope, signRef, resolution.stackSafeAttr); + writer->newNode(BuildKey::CreatingClass, arguments.count_pos()); + } + else scope.raiseError(errInvalidOperation, node); + writer->appendNode(BuildKey::Type, collectionTypeRef); + writer->closeNode(); - /*ObjectInfo retVal = */compileMessageOperation(writer, scope, {}, target, resolution, - signRef, arguments, EAttr::AllowPrivateCall, nullptr); + if (structMode) { + writer->appendNode(BuildKey::SavingInStack, 0); - // return temp variable - WriterContext context = { &writer, &scope, {} }; - writeObjectInfo(context, - boxArgument(context, tempRetVal, false, true, false)); + for (size_t i = 0; i < arguments.count(); i++) { + writeObjectInfo(arguments[i], node); + writer->newNode(BuildKey::CopyingItem, -sizeInfo.size); + writer->appendNode(BuildKey::Index, (pos_t)i); + writer->closeNode(); + } - scope.syncStack(); + writer->appendNode(BuildKey::Argument, 0); + } + else { + for (size_t i = 0; i < arguments.count(); i++) { + writer->appendNode(BuildKey::SavingInStack, 0); + writeObjectInfo(arguments[i], node); + writer->appendNode(BuildKey::AccSwapping); + writer->appendNode(BuildKey::FieldAssigning, (pos_t)i); + } + } - writer.appendNode(BuildKey::CloseFrame); + return { ObjectKind::Object, { collectionTypeRef }, 0 }; } -void Compiler :: writeMessageInfo(BuildTreeWriter& writer, MethodScope& scope) +ObjectInfo Compiler::Expression :: compileTupleCollection(SyntaxNode node, ref_t targetRef) { - IdentifierString methodName; - ByteCodeUtil::resolveMessageName(methodName, scope.module, scope.message); + ArgumentsInfo arguments; + EAttr paramMode = EAttr::Parameter; - writer.appendNode(BuildKey::MethodName, *methodName); -} + SyntaxNode current = node.firstChild(); + while (current != SyntaxKey::None) { + if (current == SyntaxKey::Expression) { + auto argInfo = compile(current, 0, paramMode, nullptr); -void Compiler :: writeParameterDebugInfo(BuildTreeWriter& writer, Scope& scope, int size, TypeInfo typeInfo, - ustr_t name, int index) -{ - if (size > 0) { - if (typeInfo.typeRef == scope.moduleScope->buildins.intReference) { - writer.newNode(BuildKey::IntParameterAddress, name); - } - else if (typeInfo.typeRef == scope.moduleScope->buildins.longReference) { - writer.newNode(BuildKey::LongParameterAddress, name); - } - else if (typeInfo.typeRef == scope.moduleScope->buildins.realReference) { - writer.newNode(BuildKey::RealParameterAddress, name); + arguments.add(argInfo); } - else { - writer.newNode(BuildKey::ParameterAddress, name); - ref_t classRef = typeInfo.typeRef; - if (isPrimitiveRef(classRef)) - classRef = resolvePrimitiveType(scope, typeInfo, true); + current = current.nextNode(); + } - ustr_t className = scope.moduleScope->module->resolveReference(classRef); - if (isWeakReference(className)) { - IdentifierString fullName(scope.module->name()); - fullName.append(className); + ref_t tupleRef = compiler->resolveTupleClass(scope, node, arguments); - writer.appendNode(BuildKey::ClassName, *fullName); - } - else writer.appendNode(BuildKey::ClassName, className); - } + if (compiler->_logic->isTemplateCompatible(*scope.moduleScope, targetRef, tupleRef, true)) + tupleRef = targetRef; + + writer->newNode(BuildKey::CreatingClass, arguments.count_pos()); + writer->appendNode(BuildKey::Type, tupleRef); + writer->closeNode(); + + for (size_t i = 0; i < arguments.count(); i++) { + writer->appendNode(BuildKey::SavingInStack, 0); + writeObjectInfo(arguments[i], node); + writer->appendNode(BuildKey::AccSwapping); + writer->appendNode(BuildKey::FieldAssigning, (pos_t)i); } - else if (size < 0) { - if (typeInfo.typeRef == V_INT16ARRAY) { - writer.newNode(BuildKey::ShortArrayParameter, name); - } - else if (typeInfo.typeRef == V_INT8ARRAY) { - writer.newNode(BuildKey::ByteArrayParameter, name); + + return { ObjectKind::Object, { tupleRef }, 0 }; +} + +ObjectInfo Compiler::Expression :: compileTupleAssigning(SyntaxNode node) +{ + ArgumentsInfo targets; + ArgumentsInfo arguments; + + SyntaxNode current = node.firstChild(); + if (current == SyntaxKey::TupleCollection) { + SyntaxNode identNode = current.firstChild(); + while (identNode != SyntaxKey::None) { + SyntaxNode objNode = identNode.firstChild(); + if (objNode == SyntaxKey::Object) { + targets.add(compiler->mapObject(scope, objNode, EAttr::None)); + } + else scope.raiseError(errInvalidOperation, identNode); + + identNode = identNode.nextNode(); } - else if (typeInfo.typeRef == V_INT32ARRAY) { - writer.newNode(BuildKey::IntArrayParameter, name); + + current = current.nextNode(); + } + else { + targets.add(compiler->mapObject(scope, current, EAttr::None)); + current = current.nextNode(); + while (current == SyntaxKey::SubVariable) { + ObjectInfo subVar = compiler->mapObject(scope, current, EAttr::NewVariable | EAttr::IgnoreDuplicate); + if (subVar.kind == ObjectKind::Unknown) + scope.raiseError(errUnknownObject, current); + + targets.add(subVar); + + current = current.nextNode(); } - else writer.newNode(BuildKey::Parameter, name); // !! temporal } - else writer.newNode(BuildKey::Parameter, name); - writer.appendNode(BuildKey::Index, index); - writer.closeNode(); + ObjectInfo exprVal = compile(current, 0, EAttr::Parameter, nullptr); + for (pos_t i = 0; i < targets.count_pos(); i++) { + arguments.clear(); + arguments.add(exprVal); + arguments.add({ ObjectKind::IntLiteral, { V_INT32 }, ::mapIntConstant(scope.moduleScope, i), i }); -} + ObjectInfo targetVar = targets[i]; -void Compiler :: writeMethodDebugInfo(BuildTreeWriter& writer, MethodScope& scope) -{ - writer.newNode(BuildKey::ArgumentsInfo); + ref_t actionRef = scope.module->mapAction(REFER_MESSAGE, 0, false); + mssg_t getter = encodeMessage(actionRef, 2, 0); - if (!scope.functionMode) { - ref_t classRef = scope.getClassRef(); + ObjectInfo sourceVar = compileMessageOperation(node, exprVal, getter, + 0, arguments, EAttr::None, nullptr); - writeParameterDebugInfo(writer, scope, _logic->defineStructSize(*scope.moduleScope, classRef).size, - { classRef }, "self", -1); + compileAssigningOp(targetVar, sourceVar); } - int prefix = scope.functionMode ? 0 : -1; - for (auto it = scope.parameters.start(); !it.eof(); ++it) { - auto paramInfo = *it; + return exprVal; +} - writeParameterDebugInfo(writer, scope, paramInfo.size, paramInfo.typeInfo, - it.key(), prefix - paramInfo.offset); +ObjectInfo Compiler::Expression :: validateObject(SyntaxNode node, ObjectInfo retVal, ref_t targetRef, bool noPrimitives, + bool paramMode, bool dynamicRequired) +{ + if (!targetRef && retVal.typeInfo.isPrimitive() && noPrimitives) { + targetRef = compiler->retrieveStrongType(scope, retVal); } - writer.closeNode(); + if ((paramMode || targetRef) && hasToBePresaved(retVal)) { + retVal = saveToTempLocal(retVal); + } + if (targetRef) { + retVal = convertObject(node, retVal, targetRef, dynamicRequired, false); + if (paramMode && hasToBePresaved(retVal)) + retVal = saveToTempLocal(retVal); + } + + return retVal; } -void Compiler :: compileMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode node) +ObjectInfo Compiler::Expression :: compileNewOp(SyntaxNode node, ObjectInfo source, ref_t signRef, ArgumentsInfo& arguments) { - ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); + mssg_t messageRef = 0; + if (source.kind == ObjectKind::ConstantLiteral) { + IdentifierString valueStr(scope.module->resolveConstant(source.reference)); + IdentifierString postfix; - SyntaxNode current = node.firstChild(SyntaxKey::MemberMask); + postfix.append(valueStr[valueStr.length() - 1]); + valueStr.truncate(valueStr.length() - 1); - CodeScope codeScope(&scope); - if (scope.info.byRefHandler && !scope.checkHint(MethodHint::InterfaceDispatcher)) { - if (current.key == SyntaxKey::Redirect) { - compileByRefRedirectHandler(writer, scope, node, scope.info.byRefHandler); - } - else { - mssg_t privateImplementation = compileByRefHandler(writer, scope, node, scope.info.byRefHandler); + arguments.add({ ObjectKind::StringLiteral, + { scope.moduleScope->buildins.literalReference }, scope.module->mapConstant(*valueStr) }); - beginMethod(writer, scope, node, BuildKey::Method, false); - compileByRefHandlerInvoker(writer, scope, codeScope, privateImplementation, scope.info.outputRef); - codeScope.syncStack(&scope); - endMethod(writer, scope); + postfix.append(CONSTRUCTOR_MESSAGE); - // NOTE : normal byrefhandler has an alternative implementation - // overriding the normal routine - return; + ref_t signRef = scope.module->mapSignature(&scope.moduleScope->buildins.literalReference, 1, false); + mssg_t conversionMssg = encodeMessage(scope.module->mapAction(*postfix, signRef, false), 1, FUNCTION_MESSAGE); + + NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); + auto constInfo = nsScope->extensions.get(conversionMssg); + if (constInfo.value1) { + messageRef = constInfo.value2; + source = compiler->mapClassSymbol(scope, constInfo.value1); } + else scope.raiseError(errInvalidOperation, node); } - beginMethod(writer, scope, node, BuildKey::Method, true); + else messageRef = overwriteArgCount(scope.moduleScope->buildins.constructor_message, arguments.count_pos()); - switch (current.key) { - case SyntaxKey::CodeBlock: - case SyntaxKey::ReturnExpression: - case SyntaxKey::ResendDispatch: - case SyntaxKey::Redirect: - compileMethodCode(writer, classScope, scope, codeScope, node, false); - break; - case SyntaxKey::DirectResend: - compileDirectResendCode(writer, codeScope, current); - break; - case SyntaxKey::Importing: - writer.appendNode(BuildKey::Import, current.arg.reference); - break; - case SyntaxKey::WithoutBody: - scope.raiseError(errNoBodyMethod, node); - break; - case SyntaxKey::RedirectDispatch: - compileDispatchCode(writer, codeScope, current); - break; - case SyntaxKey::RedirectTryDispatch: - compileDispatchProberCode(writer, codeScope, current); - break; - default: - break; - } + ObjectInfo retVal = compileMessageOperation(node, source, messageRef, signRef, arguments, EAttr::StrongResolved | EAttr::NoExtension, nullptr); - codeScope.syncStack(&scope); - endMethod(writer, scope); + if (arguments.count_pos() < 2 && (source.kind == ObjectKind::Class || source.kind == ObjectKind::ClassSelf)) { + pos_t argCount = arguments.count_pos() + 1; + ref_t signature[2] = { source.reference, 0 }; + if (argCount == 2) + signature[1] = compiler->retrieveStrongType(scope, arguments[0]); - if (scope.isYieldable()) { - classScope->addMssgAttribute(scope.message, ClassAttribute::YieldContextSize, scope.reserved2); + mssg_t inplaceMessage = encodeMessage( + scope.module->mapAction(CONSTRUCTOR_MESSAGE, + scope.module->mapSignature(signature, argCount, false), false), argCount, STATIC_MESSAGE); + + CheckMethodResult result = {}; + if (compiler->_logic->resolveCallType(*scope.moduleScope, + compiler->retrieveStrongType(scope, source), inplaceMessage, result)) + { + writer->appendNode(BuildKey::InplaceCall, result.message); + } } + + // HOTFIX : to use weak reference for the created class + retVal.typeInfo = { source.reference }; + + return retVal; } -bool Compiler :: isDefaultOrConversionConstructor(Scope& scope, mssg_t message, bool internalOne, bool& isProtectedDefConst) +ref_t Compiler::Expression :: compileMessageArguments(SyntaxNode current, ArgumentsInfo& arguments, ref_t expectedSignRef, EAttr mode, + ArgumentsInfo* updatedOuterArgs, bool& variadicArgList) { - ref_t actionRef = getAction(message); - if (actionRef == getAction(scope.moduleScope->buildins.constructor_message)) { - return true; - } - else if (actionRef == getAction(scope.moduleScope->buildins.protected_constructor_message)) { - isProtectedDefConst = true; + EAttr paramMode = EAttr::Parameter | EAttr::RetValExpected; + if (EAttrs::testAndExclude(mode, EAttr::NoPrimitives)) + paramMode = paramMode | EAttr::NoPrimitives; - return true; - } - else if (getArgCount(message)) { - ref_t dummy = 0; - ustr_t actionName = scope.module->resolveAction(actionRef, dummy); - if (actionName.compare(CONSTRUCTOR_MESSAGE2)) { - isProtectedDefConst = true; - return true; + // compile the message argument list + ref_t signatures[ARG_COUNT] = { 0 }; + ref_t signatureLen = 0; + ref_t superReference = scope.moduleScope->buildins.superReference; + + if (expectedSignRef) + scope.module->resolveSignature(expectedSignRef, signatures); + + while (current != SyntaxKey::None) { + if (current == SyntaxKey::Expression) { + // try to recognize the message signature + // NOTE : signatures[signatureLen] contains expected parameter type if expectedSignRef is provided + auto argInfo = compile(current, signatures[signatureLen], + paramMode, updatedOuterArgs); + + if (argInfo.mode == TargetMode::UnboxingVarArgument) { + if (argInfo.typeInfo.elementRef) { + signatures[signatureLen++] = argInfo.typeInfo.elementRef; + } + else signatures[signatureLen++] = scope.moduleScope->buildins.superReference; + + if (!variadicArgList) { + variadicArgList = true; + } + else scope.raiseError(errInvalidOperation, current); + } + else { + ref_t argRef = compiler->retrieveStrongType(scope, argInfo); + if (signatureLen >= ARG_COUNT) { + signatureLen++; + } + else if (argRef) { + signatures[signatureLen++] = argRef; + } + else signatures[signatureLen++] = superReference; + } + arguments.add(argInfo); } - else return actionName.endsWith(CONSTRUCTOR_MESSAGE); + + current = current.nextNode(); } - else if (internalOne) { - ref_t dummy = 0; - ustr_t actionName = scope.module->resolveAction(actionRef, dummy); - return actionName.endsWith(CONSTRUCTOR_MESSAGE); + if (signatureLen > 0 && signatureLen <= ARG_COUNT) { + bool anonymous = true; + for (ref_t i = 0; i < signatureLen; i++) { + if (signatures[i] != superReference) { + anonymous = false; + break; + } + } + if (!anonymous) + return scope.module->mapSignature(signatures, signatureLen, false); } - else return false; + + return 0; } -// NOTE : check if init_method is declared in the current class then call it -// returns the parent class reference -void Compiler :: callInitMethod(BuildTreeWriter& writer, SyntaxNode node, ExprScope& exprScope, ClassInfo& info, ref_t reference) +ObjectInfo Compiler::Expression :: compileExternalOp(SyntaxNode node, ref_t externalRef, + bool stdCall, ArgumentsInfo& arguments, ref_t expectedRef) { - if (!info.methods.exist(exprScope.moduleScope->buildins.init_message)) - return; + pos_t count = arguments.count_pos(); - if (info.header.parentRef != 0) { - ClassInfo classInfo; - _logic->defineClassInfo(*exprScope.moduleScope, classInfo, info.header.parentRef); + writer->appendNode(BuildKey::Allocating, + align(count, scope.moduleScope->stackAlingment)); - callInitMethod(writer, node, exprScope, classInfo, info.header.parentRef); + TypeInfo retType = { V_INT32 }; + ref_t intArgType = 0; + BuildKey intArgOp = BuildKey::None; + switch (scope.moduleScope->ptrSize) { + case 4: + intArgType = V_INT32; + intArgOp = BuildKey::SavingNInStack; + break; + case 8: + retType = { V_INT64 }; + intArgType = V_INT64; + intArgOp = BuildKey::SavingLInStack; + break; + default: + assert(false); + break; } - MethodInfo initInfo = info.methods.get(exprScope.moduleScope->buildins.init_message); - if (!initInfo.inherited) { - ArgumentsInfo args; - args.add({ ObjectKind::Object, { reference }, 0 }); - - MessageResolution resolution = { true, exprScope.moduleScope->buildins.init_message }; - _logic->setSignatureStacksafe(*exprScope.moduleScope, 0, resolution.stackSafeAttr); + for (pos_t i = count; i > 0; i--) { + ObjectInfo arg = boxArgumentLocally(arguments[i - 1], true, false); - compileMessageOperation(writer, exprScope, node, args[0], resolution, - 0, args, EAttr::None, nullptr); + writeObjectInfo(arg, node); + switch (arg.kind) { + case ObjectKind::IntLiteral: + writer->appendNode(BuildKey::SavingNInStack, i - 1); + break; + default: + if (compiler->_logic->isCompatible(*scope.moduleScope, { intArgType }, + arg.typeInfo, true)) + { + writer->appendNode(intArgOp, i - 1); + } + // NOTE : it is a duplicate for 32 bit target, but is required for 64 bit one + else if (compiler->_logic->isCompatible(*scope.moduleScope, { V_INT32 }, + arg.typeInfo, true)) + { + writer->appendNode(BuildKey::SavingNInStack, i - 1); + } + else writer->appendNode(BuildKey::SavingInStack, i - 1); // !! temporally - passing dynamic references to the exteranl routines should not be allowed + break; + } } -} -void Compiler :: compileInlineInitializing(BuildTreeWriter& writer, ClassScope& classScope, SyntaxNode node) -{ - ExprScope exprScope(&classScope); + writer->newNode(BuildKey::ExtCallOp, externalRef); - callInitMethod(writer, node, exprScope, classScope.info, classScope.reference); -} + BuildNode opNode = writer->CurrentNode(); -void Compiler :: compileDefConvConstructorCode(BuildTreeWriter& writer, MethodScope& scope, - SyntaxNode node, bool& newFrame) -{ - if (!newFrame) { - // new stack frame - writer.appendNode(BuildKey::OpenFrame); - newFrame = true; + writer->appendNode(BuildKey::Count, count); + + writer->closeNode(); + + if (!stdCall) + writer->appendNode(BuildKey::Freeing, align(count, + scope.moduleScope->stackAlingment)); + + if (compiler->_logic->isCompatible(*scope.moduleScope, retType, { expectedRef }, true)) { + retType = { expectedRef }; + } + else if (retType.typeRef == V_INT64 && + compiler->_logic->isCompatible(*scope.moduleScope, { V_INT32 }, { expectedRef }, true)) + { + // HOTFIX 64bit : allow to convert the external operation to int32 + retType = { expectedRef }; } + else if (retType.typeRef == V_INT32 && + compiler->_logic->isCompatible(*scope.moduleScope, { V_INT64 }, { expectedRef }, true)) + { + retType = { expectedRef }; - ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); + // HOTFIX : special case - returning long in 32 bit mode + opNode.appendChild(BuildKey::LongMode); + } + else if (compiler->_logic->isCompatible(*scope.moduleScope, { V_FLOAT64 }, { expectedRef }, true)) { + retType = { expectedRef }; - if (test(classScope->info.header.flags, elDynamicRole)) - throw InternalError(errFatalError); + return { ObjectKind::FloatExtern, retType, 0 }; + } - createObject(writer, classScope->info, classScope->reference); + return { ObjectKind::Extern, retType, 0 }; } -void Compiler :: compileInplaceDefConstructorCode(BuildTreeWriter& writer, SyntaxNode current, SyntaxNode methodNode, - MethodScope& scope, CodeScope& codeScope, ClassScope& classClassScope, ref_t classFlags, bool newFrame) +ObjectInfo Compiler::Expression :: compileNewArrayOp(SyntaxNode node, ObjectInfo source, ref_t targetRef, ArgumentsInfo& arguments) { - mssg_t privateHandler = declareInplaceConstructorHandler(scope, classClassScope); - - ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); - - // calling the byref handler - ExprScope exprScope(&codeScope); - ArgumentsInfo arguments; - - scope.selfLocal = codeScope.newLocal(); - writer.appendNode(BuildKey::Assigning, scope.selfLocal); + ref_t sourceRef = compiler->retrieveStrongType(scope, source); - ObjectInfo target = mapClassSymbol(scope, classScope->reference); - MessageResolution resolution = { true, privateHandler }; + //if (!targetRef) + // targetRef = resolvePrimitiveReference(scope, source.type, source.element, false); - arguments.add(scope.mapSelf()); - for (auto it = scope.parameters.start(); !it.eof(); ++it) { - arguments.add(scope.mapParameter(it.key(), EAttr::None)); + ref_t argumentRefs[ARG_COUNT] = {}; + pos_t argLen = 0; + for (pos_t i = 0; i < arguments.count(); i++) { + argumentRefs[argLen++] = compiler->retrieveStrongType(scope, arguments[i]); } - ref_t signRef = getSignature(scope.module, privateHandler); - _logic->setSignatureStacksafe(*scope.moduleScope, signRef, resolution.stackSafeAttr); + BuildKey operationKey = compiler->_logic->resolveNewOp(*scope.moduleScope, sourceRef, argumentRefs, argLen); + if (operationKey == BuildKey::NewArrayOp) { + auto sizeInfo = compiler->_logic->defineStructSize(*scope.moduleScope, sourceRef); - compileMessageOperation(writer, exprScope, {}, target, resolution, - signRef, arguments, EAttr::AllowPrivateCall, nullptr); + if (targetRef) { + NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - // return the created object - WriterContext context = { &writer, &exprScope, current }; - writeObjectInfo(context, scope.mapSelf()); + auto conversionRoutine = compiler->_logic->retrieveConversionRoutine(compiler, *scope.moduleScope, *nsScope->nsName, + targetRef, source.typeInfo); + if (conversionRoutine.result == ConversionResult::BoxingRequired) { + source.typeInfo = { targetRef }; + } + else source.typeInfo = { sourceRef }; + } + else source.typeInfo = { sourceRef }; - exprScope.syncStack(); - writer.appendNode(BuildKey::CloseFrame); + assert(arguments.count() == 1); // !! temporally - only one argument is supported - codeScope.syncStack(&scope); - endMethod(writer, scope); + writeObjectInfo(arguments[0], node); + writer->appendNode(BuildKey::SavingInStack, 0); - compileInplaceConstructorHandler(writer, scope, classClassScope, - current, methodNode, privateHandler); -} + assert(!source.typeInfo.isPrimitive()); -void Compiler :: compileConstructorCode(BuildTreeWriter& writer, SyntaxNode node, SyntaxNode current, MethodScope& scope, - CodeScope& codeScope, ClassScope& classClassScope, bool isDefConvConstructor, ref_t classFlags, bool newFrame) -{ - if (isDefConvConstructor) { - // if it is a default / conversion (unnamed) constructor - // call field initializers if available for default constructor - ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); + writer->newNode(operationKey, source.typeInfo.typeRef); - if (node.existChild(SyntaxKey::FillingAttr)) - fillObject(writer, classScope->info, scope.moduleScope->ptrSize); + if (sizeInfo.size < 0) + writer->appendNode(BuildKey::Size, sizeInfo.size); - if (classScope->info.methods.exist(scope.moduleScope->buildins.init_message)) { - compileInlineInitializing(writer, *classScope, node); + writer->closeNode(); + + // fill the array + if (!sizeInfo.size) { + writer->appendNode(BuildKey::FillOp); } - } - switch (current.key) { - case SyntaxKey::CodeBlock: - case SyntaxKey::ResendDispatch: - compileMethodCode(writer, &classClassScope, scope, codeScope, node, newFrame); - break; - case SyntaxKey::ReturnExpression: - compileRetExpression(writer, codeScope, current, EAttr::DynamicObject); - writer.appendNode(BuildKey::CloseFrame); - break; - case SyntaxKey::DirectResend: - compileDirectResendCode(writer, codeScope, current); - break; - case SyntaxKey::None: - if (isDefConvConstructor && !test(classFlags, elDynamicRole)) { - writer.appendNode(BuildKey::CloseFrame); - break; - } - default: - throw InternalError(errFatalError); + return { ObjectKind::Object, source.typeInfo, 0 }; } -} - -void Compiler :: compileConstructor(BuildTreeWriter& writer, MethodScope& scope, - ClassScope& classClassScope, SyntaxNode node, bool abstractMode) -{ - bool isProtectedDefConst = false; - bool isDefConvConstructor = isDefaultOrConversionConstructor(scope, scope.message, scope.checkHint(MethodHint::Internal), isProtectedDefConst); - mssg_t defConstrMssg = scope.moduleScope->buildins.constructor_message; - mssg_t protectedDefConstructor = classClassScope.getMssgAttribute(defConstrMssg, ClassAttribute::ProtectedAlias); - if (protectedDefConstructor) { - // if protected default constructor is declared - use it - defConstrMssg = protectedDefConstructor; - isProtectedDefConst = true; - } - else if (classClassScope.info.methods.exist(defConstrMssg | STATIC_MESSAGE)) { - // if private default constructor is declared - use it - defConstrMssg = defConstrMssg | STATIC_MESSAGE; - } + scope.raiseError(errInvalidOperation, node); - // NOTE : special case - abstract class with a protected constructor - bool protectedAbstractMode = scope.isProtected() && abstractMode; + return {}; // !! temporal +} - beginMethod(writer, scope, node, BuildKey::Method, true); +ObjectInfo Compiler::Expression :: convertObject(SyntaxNode node, ObjectInfo source, + ref_t targetRef, bool dynamicRequired, bool withoutBoxing) +{ + if (!compiler->_logic->isCompatible(*scope.moduleScope, { targetRef }, source.typeInfo, false)) { + if (source.kind == ObjectKind::Default) { + if (compiler->_logic->isEmbeddable(*scope.moduleScope, targetRef)) { + ObjectInfo classSymbol = mapClassSymbol(scope, targetRef); - CodeScope codeScope(&scope); - ref_t classFlags = codeScope.getClassFlags(); + ArgumentsInfo arguments; - SyntaxNode current = node.firstChild(SyntaxKey::MemberMask); - bool retExpr = current == SyntaxKey::ReturnExpression; + CheckMethodResult dummy = {}; + if (compiler->_logic->resolveCallType(*scope.moduleScope, classSymbol.typeInfo.typeRef, scope.moduleScope->buildins.constructor_message, dummy) + && (dummy.visibility == Visibility::Public || (dummy.visibility == Visibility::Protected && isSelfCall(classSymbol)))) + { + return compileNewOp(node, classSymbol, 0, arguments); + } + else { + // BAD LUCK : Default property should be returned + arguments.add(classSymbol); - bool newFrame = false; - if (current == SyntaxKey::ResendDispatch || current == SyntaxKey::RedirectDispatch || current == SyntaxKey::DirectResend) { - // do not create a frame for resend operation - // the object should not be created, because of redirecting - isDefConvConstructor = false; - } - else if (isDefConvConstructor && !test(classFlags, elDynamicRole)) { - // new stack frame - writer.appendNode(BuildKey::OpenFrame); - newFrame = true; + return compileWeakOperation(node, nullptr, 0, classSymbol, + arguments, scope.moduleScope->buildins.default_message, targetRef, nullptr); - if (retExpr) { - // the object should not be created for returning expression - isDefConvConstructor = false; + } + } + else return { ObjectKind::Nil, { V_NIL } }; } - } - else if (retExpr) { - // new stack frame - writer.appendNode(BuildKey::OpenFrame); - newFrame = true; - } - else if (!test(classFlags, elDynamicRole) - && (classClassScope.info.methods.exist(defConstrMssg) || protectedAbstractMode)) - { - if (scope.checkHint(MethodHint::Multimethod)) { - // NOTE : the dispatch statement must be before the default constructor call - // to avoid the doublicate allocating - compileMultidispatch(writer, codeScope, classClassScope, node, false); + if (source.typeInfo.typeRef == V_WRAPPER) { + // unbox wrapper for the conversion + source.typeInfo = { source.typeInfo.elementRef }; } + NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - // new stack frame - writer.appendNode(BuildKey::OpenFrame); - newFrame = true; - - if (!retExpr) { - // NOTE : the named constructor should be polymorphic, depending on the message target - writer.appendNode(BuildKey::Local, -1); - //writer.appendNode(BuildKey::ClassReference, scope.getClassRef()); + auto conversionRoutine = compiler->_logic->retrieveConversionRoutine(compiler, *scope.moduleScope, *nsScope->nsName, + targetRef, source.typeInfo); + if (!withoutBoxing && conversionRoutine.result == ConversionResult::BoxingRequired) { + // if it is implcitily compatible + switch (source.kind) { + case ObjectKind::TempLocalAddress: + case ObjectKind::LocalAddress: + case ObjectKind::IntLiteral: + case ObjectKind::MssgLiteral: + case ObjectKind::CharacterLiteral: + case ObjectKind::RefLocal: + case ObjectKind::ParamReference: + source.typeInfo.typeRef = targetRef; + break; + case ObjectKind::SelfBoxableLocal: + case ObjectKind::ParamAddress: + if (source.mode == TargetMode::Conditional && source.typeInfo.typeRef != targetRef) { + source.mode = TargetMode::None; + source.typeInfo.typeRef = targetRef; - writer.newNode(BuildKey::CallOp, defConstrMssg); - writer.appendNode(BuildKey::Index, 1); // built-in constructor entry should be the second entry in VMT - writer.closeNode(); + return source; + } + else source.typeInfo.typeRef = targetRef; + break; + default: + if (source.kind == ObjectKind::SelfLocal && source.mode == TargetMode::ArrayContent) { + source.typeInfo.typeRef = targetRef; + source.kind = ObjectKind::SelfBoxableLocal; + } + else return boxArgument(source, false, true, false, targetRef); + } } - } - // if it is a dynamic object implicit constructor call is not possible - else scope.raiseError(errIllegalConstructor, node); - - if (current == SyntaxKey::RedirectDispatch) { - compileConstructorDispatchCode(writer, codeScope, classClassScope, current); - } - else { - bool inPlaceConstructor = false; - if (isDefConvConstructor && !test(classFlags, elDynamicRole)) { - // if it is a default / conversion (unnamed) constructor - // it should create the object - compileDefConvConstructorCode(writer, scope, node, newFrame); + else if (conversionRoutine.result == ConversionResult::VariadicBoxingRequired) { + switch (source.kind) { + case ObjectKind::VArgParam: + source.typeInfo.typeRef = targetRef; + break; + default: + assert(false); + break; + } - if (getArgCount(scope.message) < 2 && test(classFlags, elStructureRole)) - inPlaceConstructor = true; } + else if (conversionRoutine.result == ConversionResult::Conversion) { + if (!dynamicRequired && source.kind == ObjectKind::IntLiteral && compiler->_logic->isNumericType(*scope.moduleScope, targetRef)) { + // HOTFIX : convert int literal in place + source = convertIntLiteral(scope, node, source, targetRef); + } + else { + ArgumentsInfo arguments; + arguments.add(source); + ref_t typeRef = compiler->retrieveStrongType(scope, source); + ref_t signRef = scope.module->mapSignature(&typeRef, 1, false); - if (inPlaceConstructor) { - compileInplaceDefConstructorCode(writer, current, node, scope, codeScope, - classClassScope, classFlags, newFrame); + return compileNewOp(node, mapClassSymbol(scope, targetRef), + signRef, arguments); + } + } + else if (conversionRoutine.result == ConversionResult::DynamicConversion) { + ArgumentsInfo arguments; + arguments.add(source); - // NOTE : the procedure closes the scope itself - return; + return compileNewOp(node, mapClassSymbol(scope, targetRef), + 0, arguments); + } + else if (conversionRoutine.result == ConversionResult::NativeConversion) { + if (source.kind == ObjectKind::IntLiteral && compiler->_logic->isNumericType(*scope.moduleScope, targetRef)) { + // HOTFIX : convert int literal in place + source = convertIntLiteral(scope, node, source, targetRef); + } + else source = compileNativeConversion(node, source, conversionRoutine.operationKey); } - else compileConstructorCode(writer, node, current, scope, codeScope, - classClassScope, isDefConvConstructor, classFlags, newFrame); + else source = typecastObject(node, source, targetRef); } - codeScope.syncStack(&scope); - - endMethod(writer, scope); + return source; } -void Compiler :: initializeMethod(ClassScope& scope, MethodScope& methodScope, SyntaxNode current) +Compiler::MessageResolution Compiler::Expression :: resolveByRefHandler(ObjectInfo source, ref_t expectedRef, + mssg_t weakMessage, ref_t& signatureRef, bool noExtensions) { - methodScope.message = current.arg.reference; - methodScope.info = scope.info.methods.get(methodScope.message); - methodScope.functionMode = test(methodScope.message, FUNCTION_MESSAGE); - methodScope.isEmbeddable = methodScope.checkHint(MethodHint::Stacksafe); - methodScope.isExtension = methodScope.checkHint(MethodHint::Extension); - methodScope.targetSelfMode = methodScope.checkHint(MethodHint::TargetSelf); - methodScope.nestedMode = scope.getScope(Scope::ScopeLevel::OwnerClass) != &scope; - - declareVMTMessage(methodScope, current, false, false); + if (source.mode == TargetMode::Weak) + return {}; - if (methodScope.info.outputRef) { - SyntaxNode typeNode = current.findChild(SyntaxKey::Type, SyntaxKey::ArrayType, SyntaxKey::TemplateType); - if (typeNode != SyntaxKey::None) { - resolveStrongTypeAttribute(scope, typeNode, false, false); + ref_t targetRef = compiler->retrieveStrongType(scope, source); - //TypeAttributes typeAttributes = {}; - //resolveTypeAttribute(scope, typeNode, typeAttributes, false, false); - //if (typeAttributes.isNonempty()) - // scope.raiseError(errInvalidOperation, typeNode); - } - else validateType(scope, methodScope.info.outputRef, current, false, false); + pos_t argCount = 0; + ref_t actionRef = 0, flags = 0; + decodeMessage(weakMessage, actionRef, argCount, flags); - if (methodScope.checkHint(MethodHint::VirtualReturn)) { - TypeInfo refType = { V_WRAPPER, methodScope.info.outputRef }; + // HOTFIX : ignore variadic message + if ((flags & PREFIX_MESSAGE_MASK) == VARIADIC_MESSAGE) + return {}; - SizeInfo sizeInfo = {}; - // add byref return arg - if (_logic->isEmbeddable(*scope.moduleScope, methodScope.info.outputRef)) { - sizeInfo = _logic->defineStructSize(*scope.moduleScope, - resolvePrimitiveType(scope, refType, false)); - } + if (expectedRef != 0 && targetRef != 0) { + // try to resolve the weak message + MessageResolution resolution = resolveMessageAtCompileTime(source, weakMessage, + signatureRef, noExtensions, true); - int offset = methodScope.parameters.count() + 1u; - methodScope.parameters.add(RETVAL_ARG, { offset, refType, sizeInfo.size }); + if (resolution.resolved || argCount == 1) { + ref_t resolvedFlags = resolution.resolved ? getFlags(resolution.message) : flags; - methodScope.byRefReturnMode = true; - } - } -} + // check if there is a byref handler for the resolved message or the message has no arguments + ref_t resolvedSignRef = 0; + ustr_t actionName = scope.module->resolveAction(getAction(resolution.message), resolvedSignRef); -void Compiler :: compileRedirectDispatcher(BuildTreeWriter& writer, MethodScope& scope, CodeScope& codeScope, SyntaxNode node, - bool withGenerics) -{ - writer.appendNode(BuildKey::DispatchingOp); - if (withGenerics) { - writer.newNode(BuildKey::GenericDispatchingOp); - writer.appendNode(BuildKey::Message, - encodeMessage(scope.module->mapAction(GENERIC_PREFIX, 0, false), 0, 0)); - writer.closeNode(); - } + ref_t byRefType = compiler->retrieveStrongType(scope, { ObjectKind::Object, { V_WRAPPER, expectedRef }, 0 }); + ref_t byRefSignature = compiler->_logic->defineByRefSignature(*scope.moduleScope, resolvedSignRef, byRefType); - // new stack frame - writer.appendNode(BuildKey::OpenFrame); + ref_t byRefMessage = encodeMessage(scope.module->mapAction(actionName, byRefSignature, false), argCount + 1, resolvedFlags); - // stack should contains current self reference - // the original message should be restored if it is a generic method - scope.selfLocal = codeScope.newLocal(); - writer.appendNode(BuildKey::Assigning, scope.selfLocal); + ref_t byRefTarget = resolution.extensionRef ? resolution.extensionRef : targetRef; + CheckMethodResult dummy = {}; + if (compiler->_logic->resolveCallType(*scope.moduleScope, byRefTarget, byRefMessage, dummy)) { + // NOTE : the original signature is extended with byref handler + signatureRef = compiler->_logic->defineByRefSignature(*scope.moduleScope, signatureRef, byRefType);; - ExprScope exprScope(&codeScope); + resolution.resolved = true; + resolution.message = byRefMessage; - ObjectInfo mssgVar = declareTempStructure(exprScope, { sizeof(mssg_t)}); - writer.appendNode(BuildKey::SavingIndex, mssgVar.reference); + // NOTE : the stack safe attributes are resolved again the target signature + compiler->_logic->setSignatureStacksafe(*scope.moduleScope, byRefSignature, resolution.stackSafeAttr); - ObjectInfo retVal = { }; + return resolution; + } + } + else if (signatureRef) { + // otherwise check if there is a byref handler if at lease a signature exists + ref_t dummySignRef = 0; + ustr_t actionName = scope.module->resolveAction(actionRef, dummySignRef); - SyntaxNode bodyNode = node.firstChild(SyntaxKey::ScopeMask); - switch (bodyNode.key) { - case SyntaxKey::Expression: - retVal = compileExpression(writer, exprScope, bodyNode, 0, EAttr::None, nullptr); - break; - default: - scope.raiseError(errInvalidOperation, node); - break; - } + ref_t byRefType = compiler->retrieveStrongType(scope, { ObjectKind::Object, { V_WRAPPER, expectedRef }, 0 }); + ref_t byRefSignature = compiler->_logic->defineByRefSignature(*scope.moduleScope, signatureRef, byRefType); - WriterContext context = { &writer, &exprScope, node }; + ref_t byRefMessage = encodeMessage(scope.module->mapAction(actionName, byRefSignature, false), argCount + 1, flags); - retVal = boxArgument(context, retVal, false, true, false); + CheckMethodResult dummy = {}; + if (compiler->_logic->resolveCallType(*scope.moduleScope, targetRef, byRefMessage, dummy)) { + // NOTE : the original signature is extended with byref handler + signatureRef = compiler->_logic->defineByRefSignature(*scope.moduleScope, signatureRef, byRefType);; - writeObjectInfo(context, retVal); + resolution.resolved = true; + resolution.message = byRefMessage; - writer.appendNode(BuildKey::LoadingIndex, mssgVar.reference); + // NOTE : the stack safe attributes are resolved again the target signature + compiler->_logic->setSignatureStacksafe(*scope.moduleScope, byRefSignature, resolution.stackSafeAttr); - exprScope.syncStack(); + return resolution; + } + } + } - writer.appendNode(BuildKey::CloseFrame, -1); - writer.appendNode(BuildKey::RedirectOp); + return {}; } -inline bool hasVariadicFunctionDispatcher(Compiler::ClassScope* classScope, bool& mixedDispatcher) +ObjectInfo Compiler::Expression :: declareTempLocal(ref_t typeRef, bool dynamicOnly) { - bool normalVariadic = false; - bool functionVariadic = false; - for (auto it = classScope->info.methods.start(); !it.eof(); ++it) { - mssg_t m = it.key(); - - if ((m & PREFIX_MESSAGE_MASK) == VARIADIC_MESSAGE) { - if (test(m, FUNCTION_MESSAGE)) { - functionVariadic = true; - } - else normalVariadic = true; - } + SizeInfo sizeInfo = {}; + if (!dynamicOnly) { + sizeInfo = compiler->_logic->defineStructSize(*scope.moduleScope, typeRef); } + if (sizeInfo.size > 0) { + ObjectInfo tempStruct = declareTempStructure(sizeInfo); + tempStruct.typeInfo = { typeRef }; - if (functionVariadic) { - if (normalVariadic) - mixedDispatcher = true; - - return true; + return tempStruct; + } + else { + int tempLocal = scope.newTempLocal(); + return { ObjectKind::TempLocal, { typeRef }, (ref_t)tempLocal }; } - else return false; } -void Compiler :: compileDispatcherMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode node, - bool withGenerics, bool withOpenArgGenerics) +ObjectInfo Compiler::Expression :: compileMessageOperation(SyntaxNode node, ObjectInfo target, MessageResolution resolution, ref_t implicitSignatureRef, + ArgumentsInfo& arguments, ExpressionAttributes mode, ArgumentsInfo* updatedOuterArgs) { - CodeScope codeScope(&scope); + bool argUnboxingRequired = EAttrs::testAndExclude(mode.attrs, EAttr::WithVariadicArg); + bool checkShortCircle = EAttrs::testAndExclude(mode.attrs, EAttr::CheckShortCircle); + bool allowPrivateCall = EAttrs::testAndExclude(mode.attrs, EAttr::AllowPrivateCall); - beginMethod(writer, scope, node, BuildKey::Method, false); + ObjectInfo retVal(ObjectKind::Object); - if (node != SyntaxKey::None) { - // if it is an explicit dispatcher - SyntaxNode current = node.firstChild(SyntaxKey::MemberMask); - switch (current.key) { - case SyntaxKey::Importing: - writer.appendNode(BuildKey::Import, current.arg.reference); - break; - case SyntaxKey::Redirect: - compileRedirectDispatcher(writer, scope, codeScope, current, withGenerics); - break; - default: - scope.raiseError(errInvalidOperation, node); - break; + BuildKey operation = BuildKey::CallOp; + if (!resolution.resolved) { + resolution = resolveMessageAtCompileTime(target, resolution.message, + implicitSignatureRef, + EAttrs::testAndExclude(mode.attrs, EAttr::NoExtension), false); + } + + if (resolution.extensionRef) { + // if extension was found - make it a operation target + target = { ObjectKind::ConstantRole, { resolution.extensionRef }, resolution.extensionRef }; + } + + bool functionMode = test(resolution.message, FUNCTION_MESSAGE); + if (functionMode/* && target.kind != ObjectKind::ConstantRole*/) { + resolution.stackSafeAttr >>= 1; + } + else resolution.stackSafeAttr &= 0xFFFFFFFE; // exclude the stack safe target attribute, it should be set by compileMessage + + ref_t targetRef = compiler->retrieveStrongType(scope, target); + + CheckMethodResult result = {}; + bool found = target.mode != TargetMode::Weak + ? compiler->_logic->resolveCallType(*scope.moduleScope, targetRef, resolution.message, result) : false; + if (found) { + switch (result.visibility) { + case Visibility::Private: + if (allowPrivateCall || isSelfCall(target)) { + resolution.message = result.message; + } + else found = false; + break; + case Visibility::Protected: + if (isSelfCall(target) || target.kind == ObjectKind::SuperLocal) { + resolution.message = result.message; + } + else found = false; + break; + case Visibility::Internal: + if (scope.moduleScope->isInternalOp(targetRef)) { + resolution.message = result.message; + } + else found = false; + break; + default: + break; } } - else { - // if it is an implicit dispatcher - if (withGenerics) { - ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); - // !! temporally - if (withOpenArgGenerics) - scope.raiseError(errInvalidOperation, node); + if (found) { + retVal.typeInfo = { result.outputRef }; + switch ((MethodHint)result.kind) { + case MethodHint::Sealed: + if (result.constRef && compiler->_optMode) { + NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - writer.appendNode(BuildKey::DispatchingOp); - writer.newNode(BuildKey::GenericDispatchingOp); - writer.appendNode(BuildKey::Message, - encodeMessage(scope.module->mapAction(GENERIC_PREFIX, 0, false), 0, 0)); - writer.closeNode(); + retVal = nsScope->defineObjectInfo(result.constRef, EAttr::None, true); - writer.newNode(BuildKey::StrongRedirectOp, scope.moduleScope->buildins.dispatch_message); - writer.appendNode(BuildKey::Type, classScope->info.header.parentRef); - writer.closeNode(); + operation = BuildKey::None; + } + else operation = BuildKey::DirectCallOp; + // HOTFIX : do not box the variadic argument target for the direct operation + if (arguments[0].kind == ObjectKind::VArgParam) + result.stackSafe = true; + + if (checkShortCircle && validateShortCircle(resolution.message, target)) { + if (compiler->_verbose) { + showContextInfo(resolution.message, targetRef); + } + + if (target.kind == ObjectKind::ConstructorSelf) { + scope.raiseError(errRedirectToItself, node); + } + else scope.raiseWarning(WARNING_LEVEL_1, wrnCallingItself, findMessageNode(node)); + } + + break; + case MethodHint::Virtual: + operation = BuildKey::SemiDirectCallOp; + break; + default: + break; } - // if it is open arg generic without redirect statement - else if (withOpenArgGenerics) { - ExprScope exprScope(&codeScope); + if (operation != BuildKey::CallOp) { + // if the method directly resolved and the target is not required to be dynamic, mark it as stacksafe + if (result.stackSafe && !functionMode) + resolution.stackSafeAttr |= 1; + } + } + else if (targetRef) { + if (EAttrs::test(mode.attrs, EAttr::StrongResolved)) { + if (getAction(resolution.message) == getAction(scope.moduleScope->buildins.constructor_message)) { + scope.raiseError(errUnknownDefConstructor, node); + } + else scope.raiseError(errUnknownMessage, findMessageNode(node)); + } + else { + bool weakTarget = targetRef == scope.moduleScope->buildins.superReference || result.withCustomDispatcher || target.mode == TargetMode::Weak; + + SyntaxNode messageNode = findMessageNode(node); + if (weakTarget/* || ignoreWarning*/) { + // ignore warning for super class / type-less one + } + else if (messageNode == SyntaxKey::None) { + if (compiler->_verbose) { + showContextInfo(resolution.message, targetRef); + } + + if (test(resolution.message, CONVERSION_MESSAGE)) { + scope.raiseWarning(WARNING_LEVEL_1, wrnUnknownTypecast, node); + } + else if (resolution.message == scope.moduleScope->buildins.refer_message) { + scope.raiseWarning(WARNING_LEVEL_1, wrnUnsupportedOperator, node); + } + else scope.raiseWarning(WARNING_LEVEL_1, wrnUnknownFunction, node); + } + else { + if (compiler->_verbose) { + IdentifierString messageName; + ByteCodeUtil::resolveMessageName(messageName, scope.module, resolution.message); - ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); + compiler->_errorProcessor->info(infoUnknownMessage, *messageName); - ref_t mask = VARIADIC_MESSAGE; - bool mixedDispatcher = false; - bool variadicFunction = hasVariadicFunctionDispatcher(classScope, mixedDispatcher); - if (variadicFunction) { + ustr_t name = scope.module->resolveReference(targetRef); + if (!name.empty()) + compiler->_errorProcessor->info(infoTargetClass, name); + } - mask |= FUNCTION_MESSAGE; + scope.raiseWarning(WARNING_LEVEL_1, wrnUnknownMessage, messageNode); } - // HOTFIX : an extension is a special case of a variadic function and a target should be included - pos_t argCount = (!scope.isExtension && variadicFunction) ? 1 : 2; + // treat it as a weak reference + targetRef = 0; + } + } - writer.appendNode(BuildKey::DispatchingOp); - // open frame - writer.appendNode(BuildKey::OpenFrame); - // save the target - ObjectInfo tempTarget = saveToTempLocal(writer, exprScope, { ObjectKind::Object }); - // save incoming message - scope.messageLocalAddress = allocateLocalAddress(codeScope, sizeof(mssg_t), false); - writer.appendNode(BuildKey::SavingIndex, scope.messageLocalAddress); - // unbox argument list - writer.appendNode(BuildKey::LoadArgCount, 1); - writer.appendNode(BuildKey::UnboxMessage, -1); + if (target.kind == ObjectKind::SuperLocal) { + if (found) { + // parent methods are always sealed + operation = BuildKey::DirectCallOp; + } + else scope.raiseError(errInvalidOperation, node); + } - // change incoming message to variadic multi-method - writer.newNode(BuildKey::LoadingSubject, - encodeMessage(getAction(scope.moduleScope->buildins.dispatch_message), argCount, mask)); - writer.appendNode(BuildKey::Index, scope.messageLocalAddress); - if (mixedDispatcher) - writer.appendNode(BuildKey::Special, -1); - writer.closeNode(); + if (operation != BuildKey::None) { + bool targetOverridden = (target != arguments[0]); + ObjectInfo lenLocal = {}; + writeMessageArguments(target, resolution.message, arguments, lenLocal, + resolution.stackSafeAttr, targetOverridden, found, argUnboxingRequired, result.stackSafe); - // select the target - WriterContext context = { &writer, &exprScope, node }; - writeObjectInfo(context, tempTarget); + if (!targetOverridden) { + writer->appendNode(BuildKey::Argument, 0); + } + else writeObjectInfo(target, node); - // call the message - writer.newNode(BuildKey::StrongResendOp, scope.moduleScope->buildins.dispatch_message); - writer.appendNode(BuildKey::Type, classScope->info.header.parentRef); - writer.closeNode(); + writer->newNode(operation, resolution.message); - // close frame - writer.appendNode(BuildKey::CloseFrame); + if (targetRef) + writer->appendNode(BuildKey::Type, targetRef); + + writer->closeNode(); - exprScope.syncStack(); + retVal = unboxArguments(retVal, updatedOuterArgs); + + if (argUnboxingRequired) { + writer->appendNode(BuildKey::LoadingIndex, lenLocal.argument); + writer->appendNode(BuildKey::FreeVarStack); } } - codeScope.syncStack(&scope); - endMethod(writer, scope); + scope.reserveArgs(arguments.count_pos()); + + return retVal; } -void Compiler :: compileCustomDispatcher(BuildTreeWriter& writer, ClassScope& scope) +ObjectInfo Compiler::Expression :: compileOperation(SyntaxNode node, SyntaxNode rnode, int operatorId, ref_t expectedRef) { - MethodScope methodScope(&scope); - methodScope.message = scope.moduleScope->buildins.dispatch_message; + if (compiler->_evaluateOp) { + Interpreter interpreter(scope.moduleScope, compiler->_logic); + ObjectInfo evalRetVal = compiler->evalExpression(interpreter, scope, node.parentNode(), true); + if (evalRetVal.kind != ObjectKind::Unknown) + return evalRetVal; + } - auto methodIt = scope.info.methods.getIt(methodScope.message); - if (!methodIt.eof()) { - methodScope.info = *methodIt; + ObjectInfo retVal; + ArgumentsInfo updatedOuterArgs; - methodScope.info.inherited = false; + SyntaxNode lnode = node; + SyntaxNode inode; - *methodIt = methodScope.info; - } - else { - methodScope.info.hints |= (ref_t)MethodHint::Dispatcher; - scope.info.methods.add(methodScope.message, methodScope.info); + if (operatorId == SET_INDEXER_OPERATOR_ID) { + lnode = node.firstChild(); + inode = lnode.nextNode(); } - scope.info.header.flags |= elWithCustomDispatcher; + BuildKey op = BuildKey::None; + ObjectInfo loperand = compile(lnode, 0, + EAttr::Parameter | EAttr::RetValExpected | EAttr::LookaheadExprMode, &updatedOuterArgs); + ObjectInfo roperand = {}; + ObjectInfo ioperand = {}; - compileDispatcherMethod(writer, methodScope, {}, - test(scope.info.header.flags, elWithGenerics), - test(scope.info.header.flags, elWithVariadics)); + ArgumentsInfo arguments; + arguments.add(loperand); - // overwrite the class info if required - scope.save(); + // HOTFIX : typecast the right-hand expression if required + if (rnode != SyntaxKey::None) { + ref_t rTargetRef = 0; + if (operatorId == SET_OPERATOR_ID) + rTargetRef = compiler->retrieveType(scope, loperand); + + roperand = compile(rnode, rTargetRef, + EAttr::Parameter | EAttr::RetValExpected | EAttr::LookaheadExprMode, &updatedOuterArgs); + + arguments.add(roperand); + } + + if (inode != SyntaxKey::None) { + arguments.add(compile(inode, 0, + EAttr::Parameter | EAttr::RetValExpected | EAttr::LookaheadExprMode, &updatedOuterArgs)); + } + + return compileOperation(node, arguments, operatorId, expectedRef, &updatedOuterArgs); } -void Compiler :: compileVMT(BuildTreeWriter& writer, ClassScope& scope, SyntaxNode node, - bool exclusiveMode, bool ignoreAutoMultimethod) +ObjectInfo Compiler::Expression :: compileAssigning(SyntaxNode loperand, SyntaxNode roperand, ExpressionAttribute mode) { - SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { - switch (current.key) { - case SyntaxKey::Method: - { - if (exclusiveMode - && (ignoreAutoMultimethod == SyntaxTree::ifChildExists(current, SyntaxKey::Autogenerated, -1))) - { - current = current.nextNode(); - continue; - } - - MethodScope methodScope(&scope); - initializeMethod(scope, methodScope, current); + ObjectInfo target = compiler->mapObject(scope, loperand, mode); + if (target.kind == ObjectKind::Unknown) + scope.raiseError(errUnknownObject, loperand.lastChild(SyntaxKey::TerminalMask)); -#ifdef FULL_OUTOUT_INFO - IdentifierString messageName; - ByteCodeUtil::resolveMessageName(messageName, scope.module, methodScope.message); + ObjectInfo exprVal = {}; - // !! temporal - if (messageName.compare("static:getItem<'IntNumber,'Object>[3]")) - methodScope.message |= 0; + ref_t targetRef = compiler->retrieveStrongType(scope, target); + if (targetRef == V_AUTO) { + // support auto attribute + exprVal = compile(roperand, 0, EAttr::RetValExpected, nullptr); - _errorProcessor->info(infoCurrentMethod, *messageName); -#endif // FULL_OUTOUT_INFO + if (resolveAutoType(exprVal, target)) { + targetRef = compiler->retrieveStrongType(scope, exprVal); + target.typeInfo.typeRef = targetRef; + } + else scope.raiseError(errInvalidOperation, roperand.parentNode()); + } + else exprVal = compile(roperand, targetRef, EAttr::RetValExpected, nullptr); - // if it is a dispatch handler - if (methodScope.message == scope.moduleScope->buildins.dispatch_message) { - compileDispatcherMethod(writer, methodScope, current, - test(scope.info.header.flags, elWithGenerics), - test(scope.info.header.flags, elWithVariadics)); - } - // if it is an abstract one - else if (methodScope.checkHint(MethodHint::Abstract)) { - compileAbstractMethod(writer, methodScope, current, scope.abstractMode); - } - // if it is an initializer - else if (methodScope.checkHint(MethodHint::Initializer)) { - compileInitializerMethod(writer, methodScope, node); - } - // if it is a normal method - else compileMethod(writer, methodScope, current); - break; - } - case SyntaxKey::Constructor: - if (_logic->isRole(scope.info)) { - scope.raiseError(errIllegalConstructor, node); - } - break; - case SyntaxKey::StaticMethod: - if (_logic->isRole(scope.info)) { - scope.raiseError(errIllegalStaticMethod, node); - } - break; - case SyntaxKey::StaticInitializerMethod: - compileStaticInitializerMethod(writer, scope, current); + if (!compileAssigningOp(target, exprVal)) { + switch (target.kind) { + case ObjectKind::ReadOnlyField: + case ObjectKind::ReadOnlyFieldAddress: + scope.raiseError(errAssigningRealOnly, loperand.parentNode()); break; default: + scope.raiseError(errInvalidOperation, loperand.parentNode()); break; } + } + + if (target == exprVal) + scope.raiseError(errAssigningToSelf, loperand.lastChild(SyntaxKey::TerminalMask)); + + return target; +} + +bool Compiler::Expression :: writeObjectInfo(ObjectInfo info) +{ + switch (info.kind) { + case ObjectKind::IntLiteral: + writer->newNode(BuildKey::IntLiteral, info.reference); + writer->appendNode(BuildKey::Value, info.extra); + writer->closeNode(); + break; + case ObjectKind::Float64Literal: + writer->appendNode(BuildKey::RealLiteral, info.reference); + break; + case ObjectKind::LongLiteral: + writer->appendNode(BuildKey::LongLiteral, info.reference); + break; + case ObjectKind::StringLiteral: + writer->appendNode(BuildKey::StringLiteral, info.reference); + break; + case ObjectKind::WideStringLiteral: + writer->appendNode(BuildKey::WideStringLiteral, info.reference); + break; + case ObjectKind::CharacterLiteral: + writer->appendNode(BuildKey::CharLiteral, info.reference); + break; + case ObjectKind::MssgLiteral: + writer->appendNode(BuildKey::MssgLiteral, info.reference); + break; + case ObjectKind::MssgNameLiteral: + writer->appendNode(BuildKey::MssgNameLiteral, info.reference); + break; + case ObjectKind::ExtMssgLiteral: + writer->appendNode(BuildKey::ExtMssgLiteral, info.reference); + break; + //case ObjectKind::MetaDictionary: + // writer.appendNode(BuildKey::MetaDictionary, info.reference); + // break; + //case ObjectKind::MetaArray: + // writer.appendNode(BuildKey::MetaArray, info.reference); + // break; + case ObjectKind::Nil: + writer->appendNode(BuildKey::NilReference, 0); + break; + case ObjectKind::Terminator: + writer->appendNode(BuildKey::TerminatorReference, 0); + break; + case ObjectKind::Symbol: + writer->appendNode(BuildKey::SymbolCall, info.reference); + break; + case ObjectKind::Extension: + case ObjectKind::Class: + case ObjectKind::ClassSelf: + case ObjectKind::Singleton: + case ObjectKind::ConstantRole: + writer->appendNode(BuildKey::ClassReference, info.reference); + break; + case ObjectKind::Constant: + writer->appendNode(BuildKey::ConstantReference, info.reference); + break; + case ObjectKind::ConstArray: + writer->appendNode(BuildKey::ConstArrayReference, info.reference); + break; + case ObjectKind::Param: + case ObjectKind::SelfLocal: + case ObjectKind::SuperLocal: + case ObjectKind::ReadOnlySelfLocal: + case ObjectKind::Local: + case ObjectKind::TempLocal: + case ObjectKind::ParamAddress: + case ObjectKind::ParamReference: + case ObjectKind::SelfBoxableLocal: + case ObjectKind::ByRefParamAddress: + case ObjectKind::ConstructorSelf: + writer->appendNode(BuildKey::Local, info.reference); + break; + case ObjectKind::LocalField: + writer->appendNode(BuildKey::Local, info.reference); + writer->appendNode(BuildKey::Field, info.extra); + break; + case ObjectKind::VArgParam: + writer->appendNode(BuildKey::LocalReference, info.reference); + break; + case ObjectKind::LocalReference: + writer->appendNode(BuildKey::LocalReference, info.reference); + break; + case ObjectKind::LocalAddress: + case ObjectKind::TempLocalAddress: + writer->appendNode(BuildKey::LocalAddress, info.reference); + break; + case ObjectKind::ReadOnlyField: + case ObjectKind::Field: + case ObjectKind::Outer: + case ObjectKind::OuterSelf: + writeObjectInfo(scope.mapSelf()); + writer->appendNode(BuildKey::Field, info.reference); + break; + case ObjectKind::OuterField: + writeObjectInfo(scope.mapSelf()); + writer->appendNode(BuildKey::Field, info.reference); + writer->appendNode(BuildKey::Field, info.extra); + break; + case ObjectKind::StaticConstField: + writeObjectInfo(scope.mapSelf()); + writer->appendNode(BuildKey::ClassOp, CLASS_OPERATOR_ID); + writer->appendNode(BuildKey::Field, info.reference); + break; + case ObjectKind::ClassStaticConstField: + writeObjectInfo(scope.mapSelf()); + writer->appendNode(BuildKey::Field, info.reference); + break; + case ObjectKind::StaticField: + writer->appendNode(BuildKey::StaticVar, info.reference); + break; + case ObjectKind::ByRefParam: + writeObjectInfo({ ObjectKind::Param, info.typeInfo, info.reference }); + writer->appendNode(BuildKey::Field); + break; + case ObjectKind::ClassConstant: + if (info.reference == INVALID_REF) + throw InternalError(errFatalError); - current = current.nextNode(); + writer->appendNode(BuildKey::ConstantReference, info.reference); + break; + case ObjectKind::Object: + break; + default: + return false; } - // if the VMT conatains newly defined generic / variadic handlers, overrides default one - if (testany(scope.info.header.flags, elWithGenerics | elWithVariadics) - && scope.info.methods.get(scope.moduleScope->buildins.dispatch_message).inherited) - { - compileCustomDispatcher(writer, scope); - } + return true; } -void Compiler :: compileClassVMT(BuildTreeWriter& writer, ClassScope& classClassScope, ClassScope& scope, SyntaxNode node) +ObjectInfo Compiler::Expression :: boxArgumentLocally(ObjectInfo info, + bool stackSafe, bool forced) { - SyntaxNode current = node.firstChild(); - // first pass - compile constructors - while (current != SyntaxKey::None) { - switch (current.key) { - case SyntaxKey::Constructor: - { - MethodScope methodScope(&scope); - initializeMethod(classClassScope, methodScope, current); - methodScope.constructorMode = true; - - #ifdef FULL_OUTOUT_INFO - IdentifierString messageName; - ByteCodeUtil::resolveMessageName(messageName, scope.module, methodScope.message); + switch (info.kind) { + case ObjectKind::Field: + case ObjectKind::Outer: + case ObjectKind::OuterField: + if (forced) { + return boxLocally(info, stackSafe); + } + return info; + case ObjectKind::ReadOnlyFieldAddress: + case ObjectKind::FieldAddress: + if (info.argument == 0 && !forced) { + ObjectInfo retVal = scope.mapSelf(); + // HOTFIX : no conditional boxing in this case + if (retVal.mode == TargetMode::Conditional) + retVal.mode = TargetMode::None; - _errorProcessor->info(infoCurrentMethod, *messageName); - #endif // FULL_OUTOUT_INFO + retVal.typeInfo = info.typeInfo; - compileConstructor(writer, methodScope, classClassScope, current, scope.isAbstract()); - break; + return retVal; } - default: - break; - } - current = current.nextNode(); + else return boxLocally(info, stackSafe); + case ObjectKind::StaticConstField: + case ObjectKind::ClassStaticConstField: + if (info.mode == TargetMode::BoxingPtr) { + return boxPtrLocally(info); + } + else return info; + default: + return info; } +} - // second pass - compile static methods - current = node.firstChild(); - while (current != SyntaxKey::None) { - switch (current.key) { - case SyntaxKey::StaticMethod: - { - MethodScope methodScope(&classClassScope); - initializeMethod(classClassScope, methodScope, current); +ObjectInfo Compiler::Expression :: unboxArguments(ObjectInfo retVal, ArgumentsInfo* updatedOuterArgs) +{ + // unbox the arguments if required + bool resultSaved = false; + for (auto it = scope.tempLocals.start(); !it.eof(); ++it) { + ObjectInfo temp = *it; -#ifdef FULL_OUTOUT_INFO - IdentifierString messageName; - ByteCodeUtil::resolveMessageName(messageName, scope.module, methodScope.message); + if (temp.mode == TargetMode::UnboxingRequired || temp.mode == TargetMode::RefUnboxingRequired + || temp.mode == TargetMode::LocalUnboxingRequired || temp.mode == TargetMode::ConditionalUnboxingRequired) + { + if (!resultSaved && retVal.kind != ObjectKind::Unknown) { + // presave the result + ObjectInfo tempResult = declareTempLocal(retVal.typeInfo.typeRef, false); + compileAssigningOp(tempResult, retVal); + retVal = tempResult; - _errorProcessor->info(infoCurrentMethod, *messageName); -#endif // FULL_OUTOUT_INFO + resultSaved = true; + } - compileMethod(writer, methodScope, current); + // unbox the temporal variable + auto key = it.key(); + if (temp.mode == TargetMode::LocalUnboxingRequired) { + unboxArgumentLocaly(temp, key); + } + else if (temp.mode == TargetMode::RefUnboxingRequired) { + temp.kind = ObjectKind::Local; - break; + compileAssigningOp({ ObjectKind::Local, temp.typeInfo, key.value2 }, temp); } - default: - break; + else if (key.value1 == ObjectKind::RefLocal) { + writeObjectInfo(temp); + writer->appendNode(BuildKey::Field); + compileAssigningOp( + { ObjectKind::Local, temp.typeInfo, key.value2 }, + { ObjectKind::Object, temp.typeInfo, 0 }); + } + else if (key.value1 == ObjectKind::FieldAddress) { + unboxArgumentLocaly(temp, key); + } + else if (temp.mode == TargetMode::ConditionalUnboxingRequired) { + writeObjectInfo({ key.value1, temp.typeInfo, key.value2 }); + writer->newNode(BuildKey::StackCondOp); + compileAssigningOp({ key.value1, temp.typeInfo, key.value2 }, temp); + writer->closeNode(); + } + else compileAssigningOp({ key.value1, temp.typeInfo, key.value2 }, temp); } - current = current.nextNode(); } - // if the VMT conatains newly defined generic / variadic handlers, overrides default one - if (testany(classClassScope.info.header.flags, elWithGenerics | elWithVariadics) - && classClassScope.info.methods.get(scope.moduleScope->buildins.dispatch_message).inherited) - { - compileCustomDispatcher(writer, classClassScope); + if (updatedOuterArgs) { + if (updatedOuterArgs->count() > 0) { + if (!resultSaved && retVal.kind != ObjectKind::Unknown) { + // presave the result + ObjectInfo tempResult = declareTempLocal(retVal.typeInfo.typeRef, false); + compileAssigningOp(tempResult, retVal); + retVal = tempResult; + + resultSaved = true; + } + } + + unboxOuterArgs(updatedOuterArgs); } + + scope.tempLocals.clear(); + + return retVal; } -void Compiler :: compileExpressionMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode node) +ObjectInfo Compiler::Expression :: compileWeakOperation(SyntaxNode node, ref_t* arguments, pos_t argLen, + ObjectInfo& loperand, ArgumentsInfo& messageArguments, mssg_t message, ref_t expectedRef, ArgumentsInfo* updatedOuterArgs) { - beginMethod(writer, scope, node, BuildKey::Method, false); + ObjectInfo retVal = {}; - CodeScope codeScope(&scope); + // resolving a message signature (excluding a target) + bool weakSignature = false; + for (pos_t i = 1; i < argLen; i++) { + if (!arguments[i]) { + weakSignature = true; + break; + } + else if (isPrimitiveRef(arguments[i])) { + arguments[i - 1] = compiler->resolvePrimitiveType(scope, { arguments[i] }, false); + } + else arguments[i - 1] = arguments[i]; + } - // new stack frame - writer.appendNode(BuildKey::OpenFrame); + ref_t signRef = (!weakSignature && argLen > 1) ? scope.module->mapSignature(arguments, argLen - 1, false) : 0; - // stack should contains current self reference - // the original message should be restored if it is a generic method - scope.selfLocal = codeScope.newLocal(); - writer.appendNode(BuildKey::Assigning, scope.selfLocal); + auto byRefResolution = resolveByRefHandler(loperand, expectedRef, message, signRef, true); + if (byRefResolution.resolved) { + ObjectInfo tempRetVal = declareTempLocal(expectedRef, false); - compileRetExpression(writer, codeScope, node, EAttr::None); + addByRefRetVal(messageArguments, tempRetVal); + // adding mark for optimization routine + if (tempRetVal.kind == ObjectKind::TempLocalAddress) + writer->appendNode(BuildKey::ByRefOpMark, tempRetVal.argument); - writer.appendNode(BuildKey::CloseFrame); + compileMessageOperation(node, loperand, byRefResolution, + signRef, messageArguments, EAttr::None, updatedOuterArgs); - codeScope.syncStack(&scope); + retVal = tempRetVal; + } + else retVal = compileMessageOperation(node, loperand, { message }, + signRef, messageArguments, EAttr::NoExtension, updatedOuterArgs); - endMethod(writer, scope); + return retVal; } -void Compiler :: compileClosureMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode node) +bool Compiler::Expression :: compileAssigningOp(ObjectInfo target, ObjectInfo exprVal) { - ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class); + BuildKey operationType = BuildKey::None; + int operand = 0; - beginMethod(writer, scope, node, BuildKey::Method, false); + int size = 0; + bool stackSafe = false; + bool fieldMode = false; + bool fieldFieldMode = false; + bool accMode = false; + bool lenRequired = false; + + switch (target.kind) { + case ObjectKind::Local: + case ObjectKind::TempLocal: + scope.markAsAssigned(target); + operationType = BuildKey::Assigning; + operand = target.reference; + break; + case ObjectKind::ByRefParam: + operationType = BuildKey::RefParamAssigning; + operand = target.reference; + break; + case ObjectKind::SelfBoxableLocal: + case ObjectKind::ParamAddress: + accMode = true; + operationType = BuildKey::CopyingToAcc; + operand = target.reference; + size = compiler->_logic->defineStructSize(*scope.moduleScope, target.typeInfo.typeRef).size; + stackSafe = true; + break; + case ObjectKind::TempLocalAddress: + case ObjectKind::LocalAddress: + scope.markAsAssigned(target); + size = compiler->_logic->defineStructSize(*scope.moduleScope, target.typeInfo.typeRef).size; + if (size > 0) { + operationType = BuildKey::Copying; + operand = target.reference; + } + else { + lenRequired = true; + accMode = true; + operationType = BuildKey::CopyingArr; + size = -size; + } + stackSafe = true; + break; + case ObjectKind::Field: + scope.markAsAssigned(target); + operationType = BuildKey::FieldAssigning; + operand = target.reference; + fieldMode = true; + break; + case ObjectKind::OuterField: + scope.markAsAssigned(target); + operationType = BuildKey::FieldAssigning; + operand = target.extra; + fieldFieldMode = fieldMode = true; + break; + case ObjectKind::StaticField: + scope.markAsAssigned(target); + operationType = BuildKey::StaticAssigning; + operand = target.reference; + break; + case ObjectKind::FieldAddress: + scope.markAsAssigned(target); + fieldMode = true; + if (target.reference) { + operationType = BuildKey::CopyingToAccField; + operand = target.reference; + } + else operationType = BuildKey::CopyingToAccExact; + operand = target.reference; + size = compiler->_logic->defineStructSize(*scope.moduleScope, target.typeInfo.typeRef).size; + if (size < 0) { + size = target.extra; + } + stackSafe = true; + + assert(size > 0); + + break; + // NOTE : it should be the last condition + case ObjectKind::ByRefParamAddress: + { + ref_t targetRef = compiler->retrieveStrongType(scope, target); + size = compiler->_logic->defineStructSize(*scope.moduleScope, targetRef).size; + if (size > 0) { + stackSafe = true; + operationType = BuildKey::CopyingToAcc; + operand = target.reference; + accMode = true; + } + else assert(false); // !! temporally + + break; + } + case ObjectKind::Outer: + { + InlineClassScope* closure = Scope::getScope(scope, Scope::ScopeLevel::Class); + if (/*!method->subCodeMode || */!closure->markAsPresaved(target)) + return false; - CodeScope codeScope(&scope); + operationType = BuildKey::FieldAssigning; + operand = target.reference; + fieldMode = true; - SyntaxNode current = node.firstChild(SyntaxKey::MemberMask); - switch (current.key) { - case SyntaxKey::CodeBlock: - case SyntaxKey::ReturnExpression: - compileMethodCode(writer, classScope, scope, codeScope, node, false); break; + } default: - break; + return false; } - codeScope.syncStack(&scope); + writeObjectInfo( + boxArgument(exprVal, stackSafe, true, false)); - endMethod(writer, scope); -} + if (fieldMode) { + writer->appendNode(BuildKey::SavingInStack, 0); + writeObjectInfo(scope.mapSelf()); + if (fieldFieldMode) + writer->appendNode(BuildKey::Field, target.reference); + } + else if (accMode) { + if (lenRequired) + writer->appendNode(BuildKey::LoadingBinaryLen, size); -void Compiler :: compileClosureClass(BuildTreeWriter& writer, ClassScope& scope, SyntaxNode node) -{ - bool lazyExpression = node == SyntaxKey::LazyOperation; - ref_t parentRef = scope.info.header.parentRef; + writer->appendNode(BuildKey::SavingInStack, 0); + writeObjectInfo(target); + } - writer.newNode(BuildKey::Class, scope.reference); + writer->newNode(operationType, operand); + if (size != 0) { + writer->appendNode(BuildKey::Size, size); - NamespaceScope* ns = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - writer.appendNode(BuildKey::Path, *ns->sourcePath); + // HOTFIX : nil cannit be assigned to a struct + if (exprVal.kind == ObjectKind::Nil) + return false; + } + writer->closeNode(); - MethodScope methodScope(&scope); - declareClosureMessage(methodScope, node); + return true; +} - methodScope.functionMode = true; +ObjectInfo Compiler::Expression :: compileBranchingOperation(SyntaxNode node, ObjectInfo loperand, SyntaxNode rnode, + SyntaxNode r2node, int operatorId, ArgumentsInfo* updatedOuterArgs, bool retValExpected, bool withoutDebugInfo) +{ + ObjectInfo retVal = {}; + BuildKey op = BuildKey::None; - mssg_t multiMethod = /*!lazyExpression && */defineMultimethod(scope, methodScope.message, false); - if (multiMethod) { - methodScope.info.multiMethod = multiMethod; - methodScope.info.outputRef = V_AUTO; - } + ObjectInfo roperand = {}; + ObjectInfo roperand2 = {}; + if (rnode.existChild(SyntaxKey::ClosureBlock)) { + rnode = rnode.findChild(SyntaxKey::ClosureBlock); - if (lazyExpression) { - compileExpressionMethod(writer, methodScope, node); + roperand = { ObjectKind::Closure, { V_CLOSURE }, 0 }; } - else { - compileClosureMethod(writer, methodScope, node); - - // HOTFIX : inject an output type if required or used super class - if (methodScope.info.outputRef == V_AUTO) { - methodScope.info.outputRef = scope.moduleScope->buildins.superReference; - } + else if (rnode == SyntaxKey::SwitchCode) { + roperand = { ObjectKind::Closure, { V_CLOSURE }, 0 }; } + else roperand = { ObjectKind::Object, { V_OBJECT }, 0 }; - if (!lazyExpression) { - ref_t closureRef = resolveClosure(scope, methodScope.message, methodScope.info.outputRef); - if (closureRef) { - parentRef = closureRef; - } - else throw InternalError(errClosureError); + if (r2node.existChild(SyntaxKey::ClosureBlock)) { + r2node = r2node.findChild(SyntaxKey::ClosureBlock); + + roperand2 = { ObjectKind::Closure, { V_CLOSURE }, 0 }; } - else parentRef = scope.moduleScope->buildins.lazyExpressionReference; + else if (r2node != SyntaxKey::None) + roperand2 = { ObjectKind::Object, { V_OBJECT }, 0 }; - declareClassParent(parentRef, scope, node); - generateClassFlags(scope, elNestedClass | elSealed); + size_t argLen = 2; + ref_t arguments[3] = {}; + arguments[0] = compiler->retrieveType(scope, loperand); + arguments[1] = compiler->retrieveType(scope, roperand); - // handle the abstract flag - if (test(scope.info.header.flags, elAbstract)) { - scope.abstractBasedMode = true; - scope.info.header.flags &= ~elAbstract; + if (r2node != SyntaxKey::None) { + argLen++; + arguments[2] = compiler->retrieveType(scope, roperand2); } - auto m_it = scope.info.methods.getIt(methodScope.message); - if (!m_it.eof()) { - (*m_it).inherited = true; - (*m_it).hints &= ~(ref_t)MethodHint::Abstract; - } - else scope.info.methods.add(methodScope.message, methodScope.info); + ref_t outputRef = 0; + op = compiler->_logic->resolveOp(*scope.moduleScope, operatorId, arguments, argLen, outputRef); - if (multiMethod) { - SyntaxTree classTree; - SyntaxTreeWriter classWriter(classTree); + if (op != BuildKey::None) { + writeObjectInfo(loperand); - // build the class tree - classWriter.newNode(SyntaxKey::Root); - classWriter.newNode(SyntaxKey::Class, scope.reference); + writer->newNode(op, operatorId); + writer->appendNode(BuildKey::Const, scope.moduleScope->branchingInfo.trueRef); - SyntaxNode classNode = classWriter.CurrentNode(); - injectVirtualMultimethod(classNode, SyntaxKey::Method, *scope.moduleScope, scope.reference, scope.info, multiMethod); + retVal = compileBranchingOperands(rnode, r2node, retValExpected, withoutDebugInfo); + } + else { + mssg_t message = 0; + if (rnode != SyntaxKey::ClosureBlock && r2node != SyntaxKey::None) { + message = scope.moduleScope->buildins.iif_message; - classWriter.closeNode(); - classWriter.closeNode(); + roperand = compile(rnode, 0, EAttr::Parameter, updatedOuterArgs); + roperand2 = compile(r2node, 0, EAttr::Parameter, updatedOuterArgs); + } + else { + message = compiler->resolveOperatorMessage(scope.moduleScope, operatorId); - SyntaxNode current = classNode.firstChild(); - while (current != SyntaxKey::None) { - generateMethodDeclaration(scope, current, false, false); + roperand = compileClosure(rnode, EAttr::None, updatedOuterArgs); + roperand2 = compileClosure(r2node, EAttr::None, updatedOuterArgs); + } - current = current.nextNode(); + ArgumentsInfo messageArguments; + messageArguments.add(loperand); + messageArguments.add(roperand); + if (r2node != SyntaxKey::None) { + messageArguments.add(roperand2); } - _logic->injectOverloadList(this, *scope.moduleScope, scope.info, scope.reference); + ref_t signRef = scope.module->mapSignature(arguments, argLen, false); - compileVMT(writer, scope, classNode); + retVal = compileMessageOperation(node, loperand, message, signRef, messageArguments, EAttr::NoExtension, updatedOuterArgs); } - // set flags once again - // NOTE : it should be called after the code compilation to take into consideration outer fields - _logic->tweakClassFlags(*scope.moduleScope, scope.reference, scope.info, scope.isClassClass()); - - writer.closeNode(); + // HOTFIX : to compenstate the closed statement above + writer->appendNode(BuildKey::OpenStatement); - scope.save(); + return retVal; } -bool isEmbeddableDispatcher(ModuleScopeBase* moduleScope, SyntaxNode current) +ObjectInfo Compiler::Expression :: compileBranchingOperands(SyntaxNode rnode, SyntaxNode r2node, bool retValExpected, bool withoutDebugInfo) { - SyntaxNode attr = current.firstChild(); - bool embeddable = false; - bool implicit = true; - while (attr != SyntaxKey::None) { - if (attr == SyntaxKey::Attribute) { - switch (attr.arg.reference) { - case V_EMBEDDABLE: - embeddable = true; - break; - case V_METHOD: - case V_CONSTRUCTOR: - case V_DISPATCHER: - implicit = false; - break; - } - } - else if (attr == SyntaxKey::Name && embeddable && implicit) { - if (moduleScope->attributes.get(attr.firstChild(SyntaxKey::TerminalMask).identifier()) == V_DISPATCHER) { - return true; - } - else break; - } + CodeScope* codeScope = Scope::getScope(scope, Scope::ScopeLevel::Code); - attr = attr.nextNode(); - } + writer->newNode(BuildKey::Tape); - return false; -} + ObjectInfo subRetCode = {}; + bool oldWithRet = codeScope->withRetStatement; + if (rnode == SyntaxKey::ClosureBlock || rnode == SyntaxKey::SwitchCode) { + EAttr mode = retValExpected ? EAttr::RetValExpected : EAttr::None; + if (withoutDebugInfo) + mode = mode | EAttr::NoDebugInfo; -void Compiler :: injectInterfaceDispatch(Scope& scope, SyntaxNode node, ref_t parentRef) -{ - SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { - if (current == SyntaxKey::Method && current.existChild(SyntaxKey::Redirect)) { - if (isEmbeddableDispatcher(scope.moduleScope, current)) { - SyntaxNode exprNode = current.findChild(SyntaxKey::Redirect).findChild(SyntaxKey::Expression); - SyntaxNode objNode = exprNode.firstChild(); - if (objNode.nextNode() != SyntaxKey::None) - scope.raiseError(errInvalidSyntax, node); - SyntaxNode terminalNode = objNode.firstChild(); + codeScope->withRetStatement = false; - IdentifierString arg(terminalNode.identifier()); + subRetCode = compileSubCode(rnode.firstChild(), mode); + } + else subRetCode = compile(rnode, 0, EAttr::None, nullptr); - VirtualMethods virtualMethods; - _logic->generateVirtualDispatchMethod(*scope.moduleScope, parentRef, virtualMethods); + if (retValExpected) { + writeObjectInfo(subRetCode); + } + writer->closeNode(); - for (pos_t i = 0; i < virtualMethods.count_pos(); i++) { - auto methInfo = virtualMethods.get(i); + TypeInfo retType = {}; + if (r2node != SyntaxKey::None) { + // NOTE : it should immediately follow if-block + writer->newNode(BuildKey::Tape); + ObjectInfo elseSubRetCode = {}; + if (r2node == SyntaxKey::ClosureBlock) { + bool withRet = codeScope->withRetStatement; + codeScope->withRetStatement = false; - injectVirtualDispatchMethod(scope, node, methInfo.value1, methInfo.value2, terminalNode.key, *arg); - } + EAttr mode = retValExpected ? EAttr::RetValExpected : EAttr::None; + if (withoutDebugInfo) + mode = mode | EAttr::NoDebugInfo; - // interface class should no have a custom dispatcher - current.setKey(SyntaxKey::Idle); + elseSubRetCode = compileSubCode(r2node.firstChild(), mode); - return; + if (!withRet || !codeScope->withRetStatement) { + codeScope->withRetStatement = oldWithRet; } } + else elseSubRetCode = compile(r2node, 0, EAttr::None, nullptr); - current = current.nextNode(); - } -} - -void Compiler :: compileNestedClass(BuildTreeWriter& writer, ClassScope& scope, SyntaxNode node, ref_t parentRef) -{ - NamespaceScope* ns = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - scope.info.header.flags |= elNestedClass; + if (retValExpected) { + writeObjectInfo(elseSubRetCode, r2node); - bool virtualClass = true; - // NOTE : check if it is in-place initialization - SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { - switch (current.key) { - case SyntaxKey::Field: - case SyntaxKey::Method: - virtualClass = false; - break; - default: - break; + if (subRetCode.typeInfo == elseSubRetCode.typeInfo) + retType = subRetCode.typeInfo; } - - current = current.nextNode(); + writer->closeNode(); } + else codeScope->withRetStatement = oldWithRet; - if (virtualClass) - scope.info.header.flags |= elVirtualVMT; - - declareClassParent(parentRef, scope, node); - - ref_t dummy = 0; - declareClassAttributes(scope, {}, dummy); + writer->closeNode(); - if (scope.abstractBasedMode && test(scope.info.header.flags, elClosed | elNoCustomDispatcher)) - { - // COMPILER MAGIC : inject interface implementation if dispatch method available - injectInterfaceDispatch(scope, node, scope.info.header.parentRef); + ObjectInfo retVal = {}; + if (retValExpected) { + retVal = { ObjectKind::Object, retType, 0 }; } - bool withConstructors = false; - bool withDefaultConstructor = false; - bool yieldMethodNotAllowed = true; - declareVMT(scope, node, withConstructors, withDefaultConstructor, yieldMethodNotAllowed, true, false); - if (withConstructors) - scope.raiseError(errIllegalConstructor, node); + return retVal; +} - generateClassDeclaration(scope, node, elNestedClass | elSealed); +ObjectInfo Compiler::Expression :: compileMessageOperationR(ObjectInfo target, SyntaxNode messageNode, bool propertyMode) +{ + ArgumentsInfo arguments; + ArgumentsInfo updatedOuterArgs; + + switch (target.mode) { + case TargetMode::Casting: + { + bool dummy = false; + compileMessageArguments(messageNode, arguments, 0, EAttr::NoPrimitives, &updatedOuterArgs, dummy); + if (arguments.count() == 1 && !dummy) { + return convertObject(messageNode, arguments[0], compiler->retrieveStrongType(scope, target), false, true); + } + else scope.raiseError(errInvalidOperation, messageNode); + break; + } + default: + { + // NOTE : the operation target shouldn't be a primitive type + ObjectInfo source = validateObject(messageNode, target, 0, true, true, false); - scope.save(); + mssg_t messageRef = compiler->mapMessage(scope, messageNode, propertyMode, false, false); - BuildNode buildNode = writer.CurrentNode(); - while (buildNode != BuildKey::Root) - buildNode = buildNode.parentNode(); + mssg_t resolvedMessage = compiler->_logic->resolveSingleDispatch(*scope.moduleScope, + compiler->retrieveType(scope, source), messageRef); - BuildTreeWriter nestedWriter(buildNode); + ref_t expectedSignRef = 0; + if (resolvedMessage) + scope.module->resolveAction(getAction(resolvedMessage), expectedSignRef); - nestedWriter.newNode(BuildKey::Class, scope.reference); + if (!test(messageRef, FUNCTION_MESSAGE)) { + arguments.add(source); + } - nestedWriter.appendNode(BuildKey::Path, *ns->sourcePath); + bool withVariadicArg = false; + ref_t implicitSignatureRef = compileMessageArguments(messageNode, arguments, expectedSignRef, + EAttr::NoPrimitives, &updatedOuterArgs, withVariadicArg); - compileVMT(nestedWriter, scope, node, true, true); + EAttr opMode = EAttr::None; + if (withVariadicArg) { + messageRef |= VARIADIC_MESSAGE; - // set flags once again - // NOTE : it should be called after the code compilation to take into consideration outer fields - _logic->tweakClassFlags(*scope.moduleScope, scope.reference, scope.info, scope.isClassClass()); + opMode = EAttr::WithVariadicArg; + } - // NOTE : compile once again only auto generated methods - compileVMT(nestedWriter, scope, node, true, false); + return compileMessageOperation(messageNode, source, messageRef, + implicitSignatureRef, arguments, opMode, &updatedOuterArgs); - nestedWriter.closeNode(); + break; + } + } - scope.save(); + return {}; } -void Compiler :: validateClassFields(ClassScope& scope, SyntaxNode node) +ObjectInfo Compiler::Expression :: declareTempStructure(SizeInfo sizeInfo) { - SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { - if (current == SyntaxKey::Field) { - FieldAttributes attrs = {}; - readFieldAttributes(scope, current, attrs, false); + if (sizeInfo.size <= 0) + return {}; - if (attrs.isConstant) { - ustr_t name = current.findChild(SyntaxKey::Name).firstChild(SyntaxKey::TerminalMask).identifier(); + ObjectInfo retVal = { ObjectKind::TempLocalAddress }; + retVal.reference = allocateLocalAddress(scope, sizeInfo.size, false); + retVal.extra = sizeInfo.size; - auto fieldInfo = scope.info.statics.get(name); - if (fieldInfo.valueRef == INVALID_REF) - scope.raiseError(errNoInitializer, current.findChild(SyntaxKey::Name)); - } - } + scope.syncStack(); - current = current.nextNode(); - } + return retVal; } -void Compiler :: compileClass(BuildTreeWriter& writer, ClassScope& scope, SyntaxNode node) +ObjectInfo Compiler::Expression :: saveToTempLocal(ObjectInfo object) { -#ifdef FULL_OUTOUT_INFO - // info - ustr_t name = scope.module->resolveReference(scope.reference); - _errorProcessor->info(infoCurrentClass, name); -#endif // FULL_OUTOUT_INFO + if (object.kind == ObjectKind::Extern) { + auto sizeInfo = compiler->_logic->defineStructSize(*scope.moduleScope, object.typeInfo.typeRef); + int tempLocal = allocateLocalAddress(scope, sizeInfo.size, false); - NamespaceScope* ns = Scope::getScope(scope, Scope::ScopeLevel::Namespace); + if (sizeInfo.size == 8) { + writer->appendNode(BuildKey::SavingLongIndex, tempLocal); + } + else writer->appendNode(BuildKey::SavingIndex, tempLocal); - // validate field types - if (scope.info.fields.count() > 0 || scope.info.statics.count() > 0) { - validateClassFields(scope, node); + return { ObjectKind::TempLocalAddress, object.typeInfo, (ref_t)tempLocal }; } + else if (object.kind == ObjectKind::FloatExtern) { + auto sizeInfo = compiler->_logic->defineStructSize(*scope.moduleScope, object.typeInfo.typeRef); + int tempLocal = allocateLocalAddress(scope, sizeInfo.size, false); - writer.newNode(BuildKey::Class, scope.reference); - writer.appendNode(BuildKey::Path, *ns->sourcePath); - - compileVMT(writer, scope, node); - writer.closeNode(); + writer->appendNode(BuildKey::SavingFloatIndex, tempLocal); - scope.save(); + return { ObjectKind::TempLocalAddress, object.typeInfo, (ref_t)tempLocal }; + } + else { + int tempLocal = scope.newTempLocal(); + writeObjectInfo(object); + writer->appendNode(BuildKey::Assigning, tempLocal); - // compile explicit symbol - compileClassSymbol(writer, scope); + return { ObjectKind::TempLocal, object.typeInfo, (ref_t)tempLocal }; + } } -void Compiler :: compileClassClass(BuildTreeWriter& writer, ClassScope& classClassScope, ClassScope& scope, - SyntaxNode node) +ref_t Compiler::Expression :: mapNested(ExpressionAttribute mode) { -#ifdef FULL_OUTOUT_INFO - // info - ustr_t name = scope.module->resolveReference(scope.reference); - _errorProcessor->info(infoCurrentClass, name); -#endif // FULL_OUTOUT_INFO + ref_t nestedRef = 0; + if (EAttrs::testAndExclude(mode, EAttr::RootSymbol)) { + SymbolScope* owner = Scope::getScope(scope, Scope::ScopeLevel::Symbol); + if (owner) + nestedRef = owner->reference; + } + else if (EAttrs::testAndExclude(mode, EAttr::Root)) { + MethodScope* ownerMeth = Scope::getScope(scope, Scope::ScopeLevel::Method); + if (ownerMeth && ownerMeth->checkHint(MethodHint::Constant)) { + ref_t dummyRef = 0; + // HOTFIX : recognize property constant - NamespaceScope* ns = Scope::getScope(classClassScope, Scope::ScopeLevel::Namespace); + IdentifierString name(scope.module->resolveReference(scope.getClassRef())); + if ((*name).endsWith(CLASSCLASS_POSTFIX)) + name.truncate(name.length() - getlength(CLASSCLASS_POSTFIX)); - writer.newNode(BuildKey::Class, classClassScope.reference); - writer.appendNode(BuildKey::Path, *ns->sourcePath); + name.append('#'); + name.append(scope.module->resolveAction(getAction(ownerMeth->message), dummyRef)); - compileClassVMT(writer, classClassScope, scope, node); - writer.closeNode(); + nestedRef = ownerMeth->module->mapReference(*name); + } + } + + if (!nestedRef) + nestedRef = scope.moduleScope->mapAnonymous(); + + return nestedRef; } -void Compiler :: compileNamespace(BuildTreeWriter& writer, NamespaceScope& ns, SyntaxNode node) +ObjectInfo Compiler::Expression :: compileNested(InlineClassScope& classScope, EAttr mode, ArgumentsInfo* updatedOuterArgs) { - SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { - switch (current.key) { - case SyntaxKey::SourcePath: - ns.sourcePath.copy(current.identifier()); - break; - case SyntaxKey::Namespace: - { - NamespaceScope namespaceScope(&ns); - declareNamespace(namespaceScope, current, false, false); - copyParentNamespaceExtensions(ns, namespaceScope); + bool paramMode = EAttrs::test(mode, EAttr::Parameter); + ref_t nestedRef = classScope.reference; + if (test(classScope.info.header.flags, elVirtualVMT)) + nestedRef = classScope.info.header.parentRef; - compileNamespace(writer, namespaceScope, current); - break; + if (test(classScope.info.header.flags, elStateless)) { + ObjectInfo retVal = { ObjectKind::Singleton, { nestedRef }, nestedRef }; + + return retVal; + } + else { + ObjectInfo retVal = { ObjectKind::Object, { nestedRef }, 0 }; + + ArgumentsInfo list; + // first pass : box an argument if required + for (auto it = classScope.outers.start(); !it.eof(); ++it) { + ObjectInfo arg = (*it).outerObject; + + arg = boxArgument(arg, false, false, false); + switch (arg.kind) { + case ObjectKind::Field: + case ObjectKind::ReadOnlyField: + case ObjectKind::Outer: + case ObjectKind::OuterField: + case ObjectKind::OuterSelf: + arg = saveToTempLocal(arg); + break; + default: + break; } - case SyntaxKey::Symbol: - { - SymbolScope symbolScope(&ns, current.arg.reference, ns.defaultVisibility); - symbolScope.isStatic = SyntaxTree::ifChildExists(current, SyntaxKey::Attribute, V_STATIC); - symbolScope.visibility = ns.moduleScope->retrieveVisibility(symbolScope.reference); - compileSymbol(writer, symbolScope, current); - break; + list.add(arg); + } + + writer->newNode(BuildKey::CreatingClass, classScope.info.fields.count()); + writer->appendNode(BuildKey::Type, nestedRef); + writer->closeNode(); + + if (classScope.outers.count() != classScope.info.fields.count()) { + if (classScope.info.fields.count() != 0) { + writer->appendNode(BuildKey::FillOp, classScope.info.fields.count()); } - case SyntaxKey::Class: - { - ClassScope classScope(&ns, current.arg.reference, ns.defaultVisibility); - ns.moduleScope->loadClassInfo(classScope.info, current.arg.reference, false); - classScope.abstractMode = test(classScope.info.header.flags, elAbstract); - if (test(classScope.info.header.flags, elExtension)) - classScope.extensionClassRef = classScope.getAttribute(ClassAttribute::ExtensionRef); + } - compileClass(writer, classScope, current); + // second pass : fill members + int argIndex = 0; + int preservedClosure = 0; + for (auto it = classScope.outers.start(); !it.eof(); ++it) { + ObjectInfo source = (*it).outerObject; + ObjectInfo arg = list[argIndex]; - // compile class class if it available - if (classScope.info.header.classRef != classScope.reference && classScope.info.header.classRef != 0) { - ClassClassScope classClassScope(&ns, classScope.info.header.classRef, classScope.visibility, &classScope.info); - ns.moduleScope->loadClassInfo(classClassScope.info, classClassScope.reference, false); + auto fieldInfo = classScope.info.fields.get(it.key()); - compileClassClass(writer, classClassScope, classScope, current); + switch (arg.kind) { + case ObjectKind::SelfLocal: + case ObjectKind::Local: + case ObjectKind::TempLocal: + case ObjectKind::Param: + writer->appendNode(BuildKey::AssignLocalToStack, arg.reference); + writer->appendNode(BuildKey::SetImmediateField, fieldInfo.offset); + break; + default: + // NOTE : should neve be hit + assert(false); + break; + } + + if (updatedOuterArgs && (*it).updated) { + if (!preservedClosure) { + updatedOuterArgs->add({ ObjectKind::ClosureInfo }); + // reserve place for the closure + preservedClosure = updatedOuterArgs->count_pos(); + updatedOuterArgs->add({ }); } - break; + + updatedOuterArgs->add({ ObjectKind::MemberInfo, (*it).reference }); + updatedOuterArgs->add(source); } - default: - // to make compiler happy - break; + + argIndex++; } - current = current.nextNode(); - } -} + // call init handler if is available + if (classScope.info.methods.exist(scope.moduleScope->buildins.init_message)) { + compiler->compileInlineInitializing(*writer, classScope, {}); + } -inline ref_t safeMapReference(ModuleScopeBase* moduleScope, ForwardResolverBase* forwardResolver, ustr_t forward) -{ - ustr_t resolved = forwardResolver->resolveForward(forward); - if (!resolved.empty()) { - if (moduleScope->isStandardOne()) { - return moduleScope->module->mapReference(resolved + getlength(STANDARD_MODULE)); + if (paramMode || preservedClosure) { + retVal = saveToTempLocal(retVal); + + if (preservedClosure) + (*updatedOuterArgs)[preservedClosure] = retVal; } - else return moduleScope->importReference(moduleScope->module, resolved); + + return retVal; } - else return 0; } -inline ref_t safeMapWeakReference(ModuleScopeBase* moduleScope, ForwardResolverBase* forwardResolver, ustr_t forward) +ObjectInfo Compiler::Expression :: compileOperation(SyntaxNode node, ArgumentsInfo& messageArguments, + int operatorId, ref_t expectedRef, ArgumentsInfo* updatedOuterArgs) { - ustr_t resolved = forwardResolver->resolveForward(forward); - if (!emptystr(resolved)) { - // HOTFIX : for the standard module the references should be mapped forcefully - if (moduleScope->isStandardOne()) { - return moduleScope->module->mapReference(resolved + getlength(STANDARD_MODULE), false); - } - else return moduleScope->module->mapReference(resolved, false); + if (messageArguments.count() > 1 && messageArguments[1].kind == ObjectKind::IntLiteral) { + // try to typecast int literal if possible + convertIntLiteralForOperation(node, operatorId, messageArguments); + } + + ObjectInfo loperand = messageArguments[0]; + + pos_t argLen = 1; + ref_t arguments[3] = {}; + arguments[0] = loperand.typeInfo.typeRef; + if (messageArguments.count() > 1) { + arguments[argLen++] = compiler->retrieveType(scope, messageArguments[1]); + } + if (messageArguments.count() > 2) { + arguments[argLen++] = compiler->retrieveType(scope, messageArguments[2]); } - else return 0; -} -inline void addPackageItem(SyntaxTreeWriter& writer, ModuleBase* module, ustr_t str) -{ - writer.newNode(SyntaxKey::Expression); - writer.newNode(SyntaxKey::Object); - if (emptystr(str)) { - writer.appendNode(SyntaxKey::string, ""); + if (operatorId == SET_INDEXER_OPERATOR_ID) { + if (isPrimitiveArray(arguments[0]) && compiler->_logic->isCompatible(*scope.moduleScope, { arguments[1] }, { loperand.typeInfo.elementRef }, false)) + // HOTFIX : for the generic binary array, recognize the element type + arguments[1] = V_ELEMENT; } - else writer.appendNode(SyntaxKey::string, str); - writer.closeNode(); - writer.closeNode(); -} -void Compiler :: createPackageInfo(ModuleScopeBase* moduleScope, ManifestInfo& manifestInfo) -{ - ReferenceName sectionName("", PACKAGE_SECTION); - ref_t packageRef = moduleScope->module->mapReference(*sectionName); + ref_t outputRef = 0; + bool needToAlloc = false; + BuildKey op = compiler->_logic->resolveOp(*scope.moduleScope, operatorId, arguments, argLen, outputRef); - SyntaxTree tempTree; - SyntaxTreeWriter tempWriter(tempTree); + ObjectInfo retVal = {}; + if (op != BuildKey::None) { + ObjectInfo roperand = {}; + ObjectInfo ioperand = {}; - tempWriter.newNode(SyntaxKey::PrimitiveCollection, packageRef); + if (messageArguments.count() > 1) + roperand = messageArguments[1]; + if (messageArguments.count() > 2) + ioperand = messageArguments[2]; - // namespace - addPackageItem(tempWriter, moduleScope->module, moduleScope->module->name()); + if (outputRef == V_ELEMENT) { + outputRef = loperand.typeInfo.elementRef; + } - // package name - addPackageItem(tempWriter, moduleScope->module, manifestInfo.maninfestName); + if (op == BuildKey::NilCondOp) { + // NOTE : the nil operation need only one (not nil) operand + if (loperand.typeInfo.typeRef == V_NIL) { + loperand = roperand; + } - // package version - addPackageItem(tempWriter, moduleScope->module, manifestInfo.maninfestVersion); + roperand = {}; + } + else if (op != BuildKey::ObjArrayOp && outputRef && compiler->_logic->isEmbeddable(*scope.moduleScope, outputRef)) + needToAlloc = true; - // package author - addPackageItem(tempWriter, moduleScope->module, manifestInfo.maninfestAuthor); + if (needToAlloc) { + retVal = allocateResult(outputRef); + } + else retVal = { ObjectKind::Object, { outputRef }, 0 }; - tempWriter.closeNode(); + // box argument locally if required + loperand = boxArgumentLocally(loperand, true, false); + roperand = boxArgumentLocally(roperand, true, false); - Interpreter interpreter(moduleScope, _logic); - MetaScope scope(nullptr, Scope::ScopeLevel::Namespace); - scope.module = moduleScope->module; - scope.moduleScope = moduleScope; - evalCollection(interpreter, scope, tempTree.readRoot(), true, false); -} + writeObjectInfo(loperand); + writer->appendNode(BuildKey::SavingInStack, 0); -void Compiler :: prepare(ModuleScopeBase* moduleScope, ForwardResolverBase* forwardResolver, - ManifestInfo& manifestInfo) -{ - _trackingUnassigned = (_errorProcessor->getWarningLevel() == WarningLevel::Level3); + if (roperand.kind != ObjectKind::Unknown) { + writeObjectInfo(roperand); + writer->appendNode(BuildKey::SavingInStack, 1); + } - loadMetaData(moduleScope, forwardResolver, PREDEFINED_MAP); - loadMetaData(moduleScope, forwardResolver, ATTRIBUTES_MAP); - loadMetaData(moduleScope, forwardResolver, OPERATION_MAP); - loadMetaData(moduleScope, forwardResolver, ALIASES_MAP); + if (ioperand.kind != ObjectKind::Unknown) + writeObjectInfo(ioperand); - // cache the frequently used references - moduleScope->buildins.superReference = safeMapReference(moduleScope, forwardResolver, SUPER_FORWARD); - moduleScope->buildins.nilValueReference = safeMapReference(moduleScope, forwardResolver, NILVALUE_FORWARD); - moduleScope->buildins.intReference = safeMapReference(moduleScope, forwardResolver, INTLITERAL_FORWARD); - moduleScope->buildins.longReference = safeMapReference(moduleScope, forwardResolver, LONGLITERAL_FORWARD); - moduleScope->buildins.realReference = safeMapReference(moduleScope, forwardResolver, REALLITERAL_FORWARD); - moduleScope->buildins.shortReference = safeMapReference(moduleScope, forwardResolver, INT16LITERAL_FORWARD); - moduleScope->buildins.ushortReference = safeMapReference(moduleScope, forwardResolver, UINT16LITERAL_FORWARD); - moduleScope->buildins.int8Reference = safeMapReference(moduleScope, forwardResolver, INT8LITERAL_FORWARD); - moduleScope->buildins.uint8Reference = safeMapReference(moduleScope, forwardResolver, UINT8LITERAL_FORWARD); - moduleScope->buildins.literalReference = safeMapReference(moduleScope, forwardResolver, LITERAL_FORWARD); - moduleScope->buildins.wideReference = safeMapReference(moduleScope, forwardResolver, WIDELITERAL_FORWARD); - moduleScope->buildins.messageReference = safeMapReference(moduleScope, forwardResolver, MESSAGE_FORWARD); - moduleScope->buildins.messageNameReference = safeMapReference(moduleScope, forwardResolver, MESSAGE_NAME_FORWARD); - moduleScope->buildins.extMessageReference = safeMapReference(moduleScope, forwardResolver, EXT_MESSAGE_FORWARD); - moduleScope->buildins.wrapperTemplateReference = safeMapReference(moduleScope, forwardResolver, WRAPPER_FORWARD); - moduleScope->buildins.arrayTemplateReference = safeMapReference(moduleScope, forwardResolver, ARRAY_FORWARD); - moduleScope->buildins.argArrayTemplateReference = safeMapReference(moduleScope, forwardResolver, VARIADIC_ARRAY_FORWARD); - moduleScope->buildins.nullableTemplateReference = safeMapReference(moduleScope, forwardResolver, NULLABLE_FORWARD); + writer->newNode(op, operatorId); - moduleScope->buildins.closureTemplateReference = safeMapWeakReference(moduleScope, forwardResolver, CLOSURE_FORWARD); - moduleScope->buildins.tupleTemplateReference = safeMapWeakReference(moduleScope, forwardResolver, TUPLE_FORWARD); - moduleScope->buildins.lazyExpressionReference = safeMapWeakReference(moduleScope, forwardResolver, LAZY_FORWARD); - moduleScope->buildins.uintReference = safeMapReference(moduleScope, forwardResolver, UINT_FORWARD); - moduleScope->buildins.pointerReference = safeMapReference(moduleScope, forwardResolver, PTR_FORWARD); + // check if the operation requires an extra arguments + if (needToAlloc) { + writer->appendNode(BuildKey::Index, retVal.argument); + } - moduleScope->branchingInfo.typeRef = safeMapReference(moduleScope, forwardResolver, BOOL_FORWARD); - moduleScope->branchingInfo.trueRef = safeMapReference(moduleScope, forwardResolver, TRUE_FORWARD); - moduleScope->branchingInfo.falseRef = safeMapReference(moduleScope, forwardResolver, FALSE_FORWARD); + switch (op) { + case BuildKey::BinaryArraySOp: + case BuildKey::BinaryArrayOp: + writer->appendNode(BuildKey::Size, compiler->_logic->defineStructSize(*scope.moduleScope, loperand.typeInfo.elementRef).size); + break; + case BuildKey::BoolSOp: + case BuildKey::IntCondOp: + case BuildKey::UIntCondOp: + case BuildKey::ByteCondOp: + case BuildKey::UByteCondOp: + case BuildKey::ShortCondOp: + case BuildKey::LongCondOp: + case BuildKey::LongIntCondOp: + case BuildKey::RealCondOp: + case BuildKey::NilCondOp: + writer->appendNode(BuildKey::TrueConst, scope.moduleScope->branchingInfo.trueRef); + writer->appendNode(BuildKey::FalseConst, scope.moduleScope->branchingInfo.falseRef); + break; + default: + break; + } - // cache the frequently used messages - moduleScope->buildins.dispatch_message = encodeMessage( - moduleScope->module->mapAction(DISPATCH_MESSAGE, 0, false), 1, 0); - moduleScope->buildins.constructor_message = - encodeMessage(moduleScope->module->mapAction(CONSTRUCTOR_MESSAGE, 0, false), - 0, FUNCTION_MESSAGE); - moduleScope->buildins.protected_constructor_message = - encodeMessage(moduleScope->module->mapAction(CONSTRUCTOR_MESSAGE2, 0, false), - 0, FUNCTION_MESSAGE); - moduleScope->buildins.init_message = - encodeMessage(moduleScope->module->mapAction(INIT_MESSAGE, 0, false), - 1, STATIC_MESSAGE); - moduleScope->buildins.invoke_message = encodeMessage( - moduleScope->module->mapAction(INVOKE_MESSAGE, 0, false), 1, FUNCTION_MESSAGE); - moduleScope->buildins.add_message = - encodeMessage(moduleScope->module->mapAction(ADD_MESSAGE, 0, false), - 2, 0); - moduleScope->buildins.sub_message = - encodeMessage(moduleScope->module->mapAction(SUB_MESSAGE, 0, false), - 2, 0); - moduleScope->buildins.mul_message = - encodeMessage(moduleScope->module->mapAction(MUL_MESSAGE, 0, false), - 2, 0); - moduleScope->buildins.div_message = - encodeMessage(moduleScope->module->mapAction(DIV_MESSAGE, 0, false), - 2, 0); - moduleScope->buildins.band_message = - encodeMessage(moduleScope->module->mapAction(BAND_MESSAGE, 0, false), - 2, 0); - moduleScope->buildins.bor_message = - encodeMessage(moduleScope->module->mapAction(BOR_MESSAGE, 0, false), - 2, 0); - moduleScope->buildins.shl_message = - encodeMessage(moduleScope->module->mapAction(SHL_MESSAGE, 0, false), - 2, 0); - moduleScope->buildins.shr_message = - encodeMessage(moduleScope->module->mapAction(SHR_MESSAGE, 0, false), - 2, 0); - moduleScope->buildins.bxor_message = - encodeMessage(moduleScope->module->mapAction(BXOR_MESSAGE, 0, false), - 2, 0); - moduleScope->buildins.and_message = - encodeMessage(moduleScope->module->mapAction(AND_MESSAGE, 0, false), - 2, 0); - moduleScope->buildins.or_message = - encodeMessage(moduleScope->module->mapAction(OR_MESSAGE, 0, false), - 2, 0); - moduleScope->buildins.xor_message = - encodeMessage(moduleScope->module->mapAction(XOR_MESSAGE, 0, false), - 2, 0); - moduleScope->buildins.refer_message = - encodeMessage(moduleScope->module->mapAction(REFER_MESSAGE, 0, false), - 2, 0); - moduleScope->buildins.set_refer_message = - encodeMessage(moduleScope->module->mapAction(SET_REFER_MESSAGE, 0, false), - 3, 0); - moduleScope->buildins.if_message = - encodeMessage(moduleScope->module->mapAction(IF_MESSAGE, 0, false), - 2, 0); - moduleScope->buildins.iif_message = - encodeMessage(moduleScope->module->mapAction(IIF_MESSAGE, 0, false), - 3, 0); - moduleScope->buildins.equal_message = - encodeMessage(moduleScope->module->mapAction(EQUAL_MESSAGE, 0, false), - 2, 0); - moduleScope->buildins.not_message = - encodeMessage(moduleScope->module->mapAction(NOT_MESSAGE, 0, false), - 1, PROPERTY_MESSAGE); - moduleScope->buildins.negate_message = - encodeMessage(moduleScope->module->mapAction(NEGATE_MESSAGE, 0, false), - 1, PROPERTY_MESSAGE); - moduleScope->buildins.value_message = - encodeMessage(moduleScope->module->mapAction(VALUE_MESSAGE, 0, false), - 1, PROPERTY_MESSAGE); - moduleScope->buildins.default_message = - encodeMessage(moduleScope->module->mapAction(DEFAULT_MESSAGE, 0, false), - 1, PROPERTY_MESSAGE); - moduleScope->buildins.bnot_message = - encodeMessage(moduleScope->module->mapAction(BNOT_MESSAGE, 0, false), - 1, PROPERTY_MESSAGE); - moduleScope->buildins.notequal_message = - encodeMessage(moduleScope->module->mapAction(NOTEQUAL_MESSAGE, 0, false), - 2, 0); - moduleScope->buildins.less_message = - encodeMessage(moduleScope->module->mapAction(LESS_MESSAGE, 0, false), - 2, 0); - moduleScope->buildins.notless_message = - encodeMessage(moduleScope->module->mapAction(NOTLESS_MESSAGE, 0, false), - 2, 0); - moduleScope->buildins.greater_message = - encodeMessage(moduleScope->module->mapAction(GREATER_MESSAGE, 0, false), - 2, 0); - moduleScope->buildins.notgreater_message = - encodeMessage(moduleScope->module->mapAction(NOTGREATER_MESSAGE, 0, false), - 2, 0); + writer->closeNode(); - // cache self variable - moduleScope->selfVar.copy(moduleScope->predefined.retrieve("@self", V_SELF_VAR, - [](ref_t reference, ustr_t key, ref_t current) - { - return current == reference; - })); - moduleScope->declVar.copy(moduleScope->predefined.retrieve("@decl", V_DECL_VAR, - [](ref_t reference, ustr_t key, ref_t current) - { - return current == reference; - })); - moduleScope->superVar.copy(moduleScope->predefined.retrieve("@super", V_SUPER_VAR, - [](ref_t reference, ustr_t key, ref_t current) - { - return current == reference; - })); - moduleScope->receivedVar.copy(moduleScope->predefined.retrieve("@received", V_RECEIVED_VAR, - [](ref_t reference, ustr_t key, ref_t current) - { - return current == reference; - })); + retVal = unboxArguments(retVal, updatedOuterArgs); + + scope.reserveArgs(argLen); + } + else { + mssg_t message = resolveOperatorMessage(scope.moduleScope, operatorId); + if (messageArguments.count() > 2) { + overwriteArgCount(message, 3); + + // HOTFIX : index argument should be the second one + ObjectInfo tmp = messageArguments[1]; + messageArguments[1] = messageArguments[2]; + messageArguments[2] = tmp; + + ref_t tmpRef = arguments[1]; + if (tmpRef == V_ELEMENT) + tmpRef = loperand.typeInfo.elementRef; + + arguments[1] = arguments[2]; + arguments[2] = tmpRef; + } - createPackageInfo(moduleScope, manifestInfo); + retVal = compileWeakOperation(node, arguments, argLen, loperand, + messageArguments, message, expectedRef, updatedOuterArgs); + } - if (!moduleScope->tapeOptMode) - moduleScope->tapeOptMode = _tapeOptMode; + return retVal; } -void Compiler :: validateScope(ModuleScopeBase* moduleScope) +ObjectInfo Compiler::Expression :: compileNativeConversion(SyntaxNode node, ObjectInfo source, ref_t operationKey) { - if (moduleScope->buildins.superReference == 0) - _errorProcessor->raiseInternalError(errNotDefinedBaseClass); -} + ObjectInfo retVal = {}; -void Compiler :: validateSuperClass(ClassScope& scope, SyntaxNode node) -{ - if (!scope.info.methods.exist(scope.moduleScope->buildins.dispatch_message)) - scope.raiseError(errNoDispatcher, node); -} + source = boxArgumentLocally(source, false, false); -void Compiler :: declareModuleIdentifiers(ModuleScopeBase* moduleScope, SyntaxNode node, ExtensionMap* outerExtensionList) -{ - SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { - if (current == SyntaxKey::Namespace) { - NamespaceScope ns(moduleScope, _errorProcessor, _logic, outerExtensionList); + switch (operationKey) { + case INT8_32_CONVERSION: + retVal = allocateResult(compiler->resolvePrimitiveType(scope, { V_INT32 }, false)); - // declare namespace - declareNamespace(ns, current, true, true); - ns.moduleScope->newNamespace(*ns.nsName); + writeObjectInfo(retVal); + writer->appendNode(BuildKey::SavingInStack, 0); - // declare all module members - map symbol identifiers - declareMemberIdentifiers(ns, current); - } + writeObjectInfo(source); - current = current.nextNode(); - } -} + writer->appendNode(BuildKey::ConversionOp, operationKey); + break; + case INT16_32_CONVERSION: + retVal = allocateResult(compiler->resolvePrimitiveType(scope, { V_INT32 }, false)); -void Compiler :: declareModule(ModuleScopeBase* moduleScope, SyntaxNode node, ExtensionMap* outerExtensionList) -{ - SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { - if (current == SyntaxKey::Namespace) { - NamespaceScope ns(moduleScope, _errorProcessor, _logic, outerExtensionList); + writeObjectInfo(retVal); + writer->appendNode(BuildKey::SavingInStack, 0); - // declare namespace - declareNamespace(ns, current, false, true); + writeObjectInfo(source); - // declare all module members - map symbol identifiers - declareMembers(ns, current); - } + writer->appendNode(BuildKey::ConversionOp, operationKey); + break; + case INT32_64_CONVERSION: + retVal = allocateResult(compiler->resolvePrimitiveType(scope, { V_INT64 }, false)); - current = current.nextNode(); + writeObjectInfo(retVal); + writer->appendNode(BuildKey::SavingInStack, 0); + + writeObjectInfo(source); + + writer->appendNode(BuildKey::ConversionOp, operationKey); + break; + case INT32_FLOAT64_CONVERSION: + retVal = allocateResult(compiler->resolvePrimitiveType(scope, { V_FLOAT64 }, false)); + + writeObjectInfo(retVal); + writer->appendNode(BuildKey::SavingInStack, 0); + + writeObjectInfo(source); + + writer->appendNode(BuildKey::ConversionOp, operationKey); + break; + default: + scope.raiseError(errInvalidOperation, node); + break; } + + return retVal; } -void Compiler :: declare(ModuleScopeBase* moduleScope, SyntaxTree& input, ExtensionMap* outerExtensionList) +ObjectInfo Compiler::Expression :: allocateResult(ref_t resultRef) { - if (moduleScope->withValidation()) - validateScope(moduleScope); + SizeInfo info = compiler->_logic->defineStructSize(*scope.moduleScope, resultRef); + if (info.size > 0) { + ObjectInfo retVal = declareTempStructure(info); + retVal.typeInfo.typeRef = resultRef; - SyntaxNode root = input.readRoot(); - // declare all member identifiers - declareModuleIdentifiers(moduleScope, root, outerExtensionList); + return retVal; + } + else throw InternalError(errFatalError); - // declare all members - declareModule(moduleScope, root, outerExtensionList); + return {}; // NOTE : should never be reached } -void Compiler :: compile(ModuleScopeBase* moduleScope, SyntaxTree& input, BuildTree& output, ExtensionMap* outerExtensionList) +Compiler::MessageResolution Compiler::Expression :: resolveMessageAtCompileTime(ObjectInfo target, mssg_t weakMessage, ref_t implicitSignatureRef, + bool ignoreExtensions, bool ignoreVariadics) { - BuildTreeWriter writer(output); - writer.newNode(BuildKey::Root); + MessageResolution resolution = {}; - SyntaxNode node = input.readRoot(); - SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { - if (current == SyntaxKey::Namespace) { - NamespaceScope ns(moduleScope, _errorProcessor, _logic, outerExtensionList); - declareNamespace(ns, current); + if (target.mode == TargetMode::Weak) + return { weakMessage }; - compileNamespace(writer, ns, current); + ref_t targetRef = compiler->retrieveStrongType(scope, target); - _presenter->showProgress(); + // try to resolve the message as is + int resolvedStackSafeAttr = 0; + resolution.message = compiler->_logic->resolveMultimethod(*scope.moduleScope, weakMessage, targetRef, + implicitSignatureRef, resolvedStackSafeAttr, isSelfCall(target)); + if (resolution.message != 0) { + resolution.resolved = true; + resolution.stackSafeAttr = resolvedStackSafeAttr; + + // if the object handles the compile-time resolved message - use it + return resolution; + } + + // check if the object handles the variadic message + if (targetRef && !ignoreVariadics) { + resolvedStackSafeAttr = 0; + resolution.message = compiler->_logic->resolveMultimethod(*scope.moduleScope, + resolveVariadicMessage(scope, weakMessage), + targetRef, implicitSignatureRef, resolvedStackSafeAttr, isSelfCall(target)); + + if (resolution.message != 0) { + resolution.resolved = true; + resolution.stackSafeAttr = resolvedStackSafeAttr; + + // if the object handles the compile-time resolved variadic message - use it + return resolution; } + } - current = current.nextNode(); + if (!ignoreExtensions) { + // check the existing extensions if allowed + // if the object handles the weak message - do not use extensions + CheckMethodResult dummy = {}; + if (compiler->_logic->resolveCallType(*scope.moduleScope, targetRef, weakMessage, dummy)) { + resolution.message = weakMessage; + + return resolution; + } + + resolvedStackSafeAttr = 0; + resolution.message = weakMessage; + ref_t extensionRef = compiler->mapExtension(*writer, scope, resolution.message, implicitSignatureRef, + target, resolvedStackSafeAttr); + if (extensionRef != 0) { + // if there is an extension to handle the compile-time resolved message - use it + resolution.resolved = true; + resolution.extensionRef = extensionRef; + resolution.stackSafeAttr = resolvedStackSafeAttr; + + return resolution; + } + + // HOTFIX : do not check variadic message for the properties + if ((weakMessage & PREFIX_MESSAGE_MASK) == PROPERTY_MESSAGE) + return { weakMessage }; + + // check if the extension handles the variadic message + mssg_t variadicMessage = resolveVariadicMessage(scope, weakMessage); + + resolvedStackSafeAttr = 0; + extensionRef = compiler->mapExtension(*writer, scope, variadicMessage, implicitSignatureRef, + target, resolvedStackSafeAttr); + if (extensionRef != 0) { + // if there is an extension to handle the compile-time resolved message - use it + resolution.resolved = true; + resolution.stackSafeAttr = resolvedStackSafeAttr; + resolution.message = variadicMessage; + resolution.extensionRef = extensionRef; + + return resolution; + } } - writer.closeNode(); + // otherwise - use the weak message + return { weakMessage }; } -inline SyntaxNode newVirtualMultimethod(SyntaxNode classNode, SyntaxKey methodType, mssg_t message, Visibility visibility, bool isExtension) +bool Compiler::Expression :: validateShortCircle(mssg_t message, ObjectInfo target) { - ref_t hints = (ref_t)MethodHint::Multimethod | (methodType == SyntaxKey::StaticMethod ? (ref_t)MethodHint::Sealed : (ref_t)MethodHint::Normal); - - switch (visibility) { - case Visibility::Protected: - hints |= (ref_t)MethodHint::Protected; + ref_t targetRef = 0; + switch (target.kind) { + case ObjectKind::Class: + targetRef = target.reference; break; - case Visibility::Internal: - hints |= (ref_t)MethodHint::Internal; + case ObjectKind::ConstructorSelf: + targetRef = target.extra; break; default: + targetRef = target.typeInfo.typeRef; break; } - if (isExtension) - hints |= (ref_t)MethodHint::Extension; + MethodScope* methodScope = Scope::getScope(scope, Scope::ScopeLevel::Method); + if (methodScope != nullptr) { + return (methodScope->message == message && methodScope->getClassRef() == targetRef); + } - SyntaxNode methodNode = classNode.appendChild(methodType, message); - methodNode.appendChild(SyntaxKey::Hints, hints); + return false; +} - return methodNode; +void Compiler::Expression :: showContextInfo(mssg_t message, ref_t targetRef) +{ + IdentifierString messageName; + ByteCodeUtil::resolveMessageName(messageName, scope.module, message); + + compiler->_errorProcessor->info(infoUnknownMessage, *messageName); + + ustr_t name = scope.module->resolveReference(targetRef); + if (!name.empty()) + compiler->_errorProcessor->info(infoTargetClass, name); + + MethodScope* methodScope = Scope::getScope(scope, Scope::ScopeLevel::Method); + if (methodScope != nullptr) { + messageName.clear(); + ByteCodeUtil::resolveMessageName(messageName, scope.module, methodScope->message); + + ustr_t name = scope.module->resolveReference(methodScope->getClassRef(false)); + if (!name.empty()) { + messageName.insert(".", 0); + messageName.insert(name, 0); + } + + compiler->_errorProcessor->info(infoScopeMethod, *messageName); + } } -inline SyntaxNode newVirtualMethod(SyntaxNode classNode, SyntaxKey methodType, mssg_t message, Visibility visibility, bool abstractOne) +void Compiler::Expression :: writeMessageArguments(ObjectInfo& target, + mssg_t message, ArgumentsInfo& arguments, ObjectInfo& lenLocal, int& stackSafeAttr, + bool targetOverridden, bool found, bool argUnboxingRequired, bool stackSafe) { - ref_t hints = methodType == SyntaxKey::StaticMethod ? (ref_t)MethodHint::Sealed : (ref_t)MethodHint::Normal; - if (abstractOne) - hints |= (ref_t)MethodHint::Abstract; + if (targetOverridden) { + target = boxArgument(target, stackSafe, false, false); + } - switch (visibility) { - case Visibility::Protected: - hints |= (ref_t)MethodHint::Protected; - break; - case Visibility::Internal: - hints |= (ref_t)MethodHint::Internal; - break; - default: - break; + if (!found) + stackSafeAttr = 0; + + pos_t counter = arguments.count_pos(); + if (argUnboxingRequired) { + counter--; + + ObjectInfo lenLocal = declareTempLocal(scope.moduleScope->buildins.intReference, false); + + // get length + writeObjectInfo(arguments[counter]); + writer->appendNode(BuildKey::SavingInStack); + writer->newNode(BuildKey::VArgSOp, LEN_OPERATOR_ID); + writer->appendNode(BuildKey::Index, lenLocal.argument); + writer->closeNode(); + + writer->appendNode(BuildKey::LoadingIndex, lenLocal.argument); + writer->newNode(BuildKey::UnboxMessage, arguments[counter].argument); + writer->appendNode(BuildKey::Index, counter); + writer->closeNode(); } - SyntaxNode methodNode = classNode.appendChild(methodType, message); - methodNode.appendChild(SyntaxKey::Hints, hints); + // box the arguments if required + int argMask = 1; + for (unsigned int i = 0; i < counter; i++) { + // NOTE : byref dynamic arg can be passed semi-directly (via temporal variable) if the method resolved directly + ObjectInfo arg = boxArgument(arguments[i], + test(stackSafeAttr, argMask), false, found); + + arguments[i] = arg; + argMask <<= 1; + } + + if (isOpenArg(message) && !argUnboxingRequired) { + // NOTE : in case of unboxing variadic argument, the terminator is already copied + arguments.add({ ObjectKind::Terminator }); + counter++; + } + + for (unsigned int i = counter; i > 0; i--) { + ObjectInfo arg = arguments[i - 1]; + + writeObjectInfo(arg); + writer->appendNode(BuildKey::SavingInStack, i - 1); + } +} + +bool Compiler::Expression :: resolveAutoType(ObjectInfo source, ObjectInfo& target) +{ + ref_t sourceRef = compiler->retrieveStrongType(scope, source); - return methodNode; + if (!compiler->_logic->validateAutoType(*scope.moduleScope, sourceRef)) + return false; + + return scope.resolveAutoType(target, source.typeInfo); } -void Compiler :: injectVirtualEmbeddableWrapper(SyntaxNode classNode, SyntaxKey methodType, ModuleScopeBase& scope, - ref_t targetRef, ClassInfo& info, mssg_t message, bool abstractOne) +ObjectInfo Compiler::Expression :: boxArgument(ObjectInfo info, bool stackSafe, bool boxInPlace, bool allowingRefArg, ref_t targetRef) { - MethodInfo methodInfo = {}; + ObjectInfo retVal = { ObjectKind::Unknown }; - auto m_it = info.methods.getIt(message); - bool found = !m_it.eof(); - if (found) - methodInfo = *m_it; + info = boxArgumentLocally(info, stackSafe, false); - if (!found || methodInfo.inherited) { - Visibility visibility = Visibility::Public; - if (MethodScope::checkHint(methodInfo, MethodHint::Internal)) { - visibility = Visibility::Internal; - } - else if (MethodScope::checkHint(methodInfo, MethodHint::Protected)) { - visibility = Visibility::Protected; - } - else if (MethodScope::checkHint(methodInfo, MethodHint::Private)) { - visibility = Visibility::Private; - } + if (!stackSafe && isBoxingRequired(info, allowingRefArg)) { + ObjectKey key = { info.kind, info.reference }; - SyntaxNode methodNode = newVirtualMethod(classNode, methodType, message, visibility, abstractOne); - methodNode.appendChild(SyntaxKey::Autogenerated, -1); // -1 indicates autogenerated method + if (!boxInPlace) + retVal = scope.tempLocals.get(key); - if (!abstractOne) { - mssg_t resendMessage = message | STATIC_MESSAGE; + if (retVal.kind == ObjectKind::Unknown) { + retVal = boxArgumentInPlace(info, targetRef); - SyntaxNode resendOp = methodNode.appendChild(SyntaxKey::DirectResend, resendMessage); - resendOp.appendChild(SyntaxKey::Target, targetRef); + if (!boxInPlace) + scope.tempLocals.add(key, retVal); } - else methodNode.appendChild(SyntaxKey::WithoutBody); } -} + else if (info.kind == ObjectKind::RefLocal) { + ObjectKey key = { info.kind, info.reference }; -inline bool isSingleDispatch(SyntaxNode node, SyntaxKey methodType, mssg_t message, mssg_t& targetMessage) -{ - // !! currently constructor is not supporting single dispatch operation - if (methodType == SyntaxKey::Constructor) - return false; + if (!boxInPlace) + retVal = scope.tempLocals.get(key); - mssg_t foundMessage = 0; + if (retVal.kind == ObjectKind::Unknown) { + if (!allowingRefArg) { + info.kind = ObjectKind::Local; - SyntaxNode current = node.firstChild(); - while (current != SyntaxKey::None) { - if (current == methodType) { - mssg_t multiMethod = current.findChild(SyntaxKey::Multimethod).arg.reference; - if (multiMethod == message) { - if (foundMessage) { - return false; - } - else foundMessage = current.arg.reference; + retVal = boxArgumentInPlace(info, targetRef); } - } + else retVal = boxRefArgumentInPlace(info, targetRef); - current = current.nextNode(); + if (!boxInPlace) + scope.tempLocals.add(key, retVal); + } } - - if (foundMessage) { - targetMessage = foundMessage; - - return true; + else if (info.kind == ObjectKind::VArgParam && !stackSafe) { + retVal = boxVariadicArgument(info); } - else return false; + else retVal = info; + + return retVal; } -bool Compiler :: injectVirtualStrongTypedMultimethod(SyntaxNode classNode, SyntaxKey methodType, ModuleScopeBase& scope, - mssg_t message, mssg_t resendMessage, ref_t outputRef, Visibility visibility, bool isExtension) +ObjectInfo Compiler::Expression :: boxLocally(ObjectInfo info, bool stackSafe) { - ref_t actionRef = getAction(resendMessage); - ref_t signRef = 0; - ustr_t actionName = scope.module->resolveAction(actionRef, signRef); + // allocating temporal variable + ObjectInfo tempLocal = {}; + bool fixedArray = false; + int fixedSize = 0; + if ((info.typeInfo.isPrimitive() && compiler->_logic->isPrimitiveArrRef(info.typeInfo.typeRef)) + || compiler->_logic->isEmbeddableArray(*scope.moduleScope, info.typeInfo.typeRef)) + { + fixedSize = defineFieldSize(scope, info); - ref_t signArgs[ARG_COUNT]; - size_t signLen = scope.module->resolveSignature(signRef, signArgs); - // HOTFIX : make sure it has at least one strong-typed argument - bool strongOne = false; - for (size_t i = 0; i < signLen; i++) { - if (signArgs[i] != scope.buildins.superReference) { - strongOne = true; - break; - } + tempLocal = declareTempStructure({ fixedSize }); + tempLocal.typeInfo = info.typeInfo; + + fixedArray = true; } + else tempLocal = declareTempLocal(info.typeInfo.typeRef, false); - // HOTFIX : the weak argument list should not be type-casted - // to avoid dispatching to the same method - if (!strongOne) - return false; + if (stackSafe) { + tempLocal.mode = TargetMode::LocalUnboxingRequired; - SyntaxNode methodNode = newVirtualMultimethod(classNode, methodType, message, visibility, isExtension); - methodNode.appendChild(SyntaxKey::Autogenerated, -1); // -1 indicates autogenerated multi-method + scope.tempLocals.add({ info.kind, info.reference }, tempLocal); + } - if (outputRef) - methodNode.appendChild(SyntaxKey::OutputType, outputRef); + writeObjectInfo(tempLocal); + writer->appendNode(BuildKey::SavingInStack, 0); - SyntaxNode resendExpr = methodNode.appendChild(SyntaxKey::ResendDispatch); - SyntaxNode operationNode = resendExpr.appendChild(((resendMessage & PREFIX_MESSAGE_MASK) == PROPERTY_MESSAGE) ? SyntaxKey::PropertyOperation : SyntaxKey::MessageOperation); + writeObjectInfo(scope.mapSelf()); - if (!actionName.compare(INVOKE_MESSAGE)) - operationNode.appendChild(SyntaxKey::Message).appendChild(SyntaxKey::identifier, actionName); + switch (info.kind) { + case ObjectKind::FieldAddress: + case ObjectKind::ReadOnlyField: + writer->newNode(BuildKey::CopyingAccField, info.reference); + break; + case ObjectKind::StaticConstField: + writer->appendNode(BuildKey::ClassOp, CLASS_OPERATOR_ID); + writer->appendNode(BuildKey::Field, info.reference); + writer->newNode(BuildKey::CopyingAccField, 0); + break; + case ObjectKind::ClassStaticConstField: + writer->appendNode(BuildKey::Field, info.reference); + writer->newNode(BuildKey::CopyingAccField, 0); + break; + default: + writer->appendNode(BuildKey::Field, info.reference); + writer->newNode(BuildKey::CopyingAccField, 0); + break; + } - String arg; - for (size_t i = 0; i < signLen; i++) { - arg.copy("$"); - arg.appendInt((int)i); + writer->appendNode(BuildKey::Size, tempLocal.extra); + writer->closeNode(); - SyntaxNode param = methodNode.appendChild(SyntaxKey::Parameter); - SyntaxNode nameParam = param.appendChild(SyntaxKey::Name); - nameParam.appendChild(SyntaxKey::identifier, arg.str()); + if (!stackSafe) { + ObjectInfo dynamicTempLocal = {}; + if (fixedArray) { + ref_t typeRef = info.typeInfo.isPrimitive() + ? compiler->resolvePrimitiveType(scope, info.typeInfo, false) : info.typeInfo.typeRef; - if (signArgs[i] != scope.buildins.superReference) { - SyntaxNode castNode = operationNode.appendChild(SyntaxKey::Expression).appendChild(SyntaxKey::MessageOperation); - SyntaxNode castObject = castNode.appendChild(SyntaxKey::Object); - castObject.appendChild(SyntaxKey::Attribute, V_CONVERSION); - castObject.appendChild(SyntaxKey::Type, signArgs[i]); - castNode.appendChild(SyntaxKey::Message); - castNode.appendChild(SyntaxKey::Expression).appendChild(SyntaxKey::Object).appendChild(SyntaxKey::identifier, arg.str()); - } - else operationNode.appendChild(SyntaxKey::Expression).appendChild(SyntaxKey::Object).appendChild(SyntaxKey::identifier, arg.str()); - } + dynamicTempLocal = declareTempLocal(typeRef, true); - return true; -} + writer->newNode(BuildKey::CreatingStruct, fixedSize); + writer->appendNode(BuildKey::Type, typeRef); + writer->closeNode(); -void Compiler :: injectVirtualMultimethod(SyntaxNode classNode, SyntaxKey methodType, ModuleScopeBase& scope, - ref_t targetRef, ClassInfo& info, mssg_t message, bool inherited, ref_t outputRef, Visibility visibility) -{ - bool isExtension = test(info.header.flags, elExtension); + writer->appendNode(BuildKey::Assigning, dynamicTempLocal.argument); - mssg_t resendMessage = message; - ref_t resendTarget = 0; + writeObjectInfo(tempLocal); + writer->appendNode(BuildKey::SavingInStack, 0); + writeObjectInfo(dynamicTempLocal); - ref_t actionRef, flags; - pos_t argCount; - decodeMessage(message, actionRef, argCount, flags); + writer->newNode(BuildKey::CopyingToAcc, tempLocal.reference); + writer->appendNode(BuildKey::Size, fixedSize); + writer->closeNode(); - info.attributes.exclude({ message, ClassAttribute::SingleDispatch }); + dynamicTempLocal.mode = TargetMode::UnboxingRequired; + } + else dynamicTempLocal = boxArgument(tempLocal, false, true, false); - // try to resolve an argument list in run-time if it is only a single dispatch and argument list is not weak - // !! temporally do not support variadic arguments - if (isSingleDispatch(classNode, methodType, message, resendMessage) && ((message & PREFIX_MESSAGE_MASK) != VARIADIC_MESSAGE) && - injectVirtualStrongTypedMultimethod(classNode, methodType, scope, message, resendMessage, - outputRef, visibility, isExtension)) - { - // mark the message as a signle dispatcher if the class is sealed / closed / class class - // and default multi-method was not explicitly declared - if (testany(info.header.flags, elClosed | elClassClass) && !inherited) - info.attributes.add({ message, ClassAttribute::SingleDispatch }, resendMessage); + scope.tempLocals.add({ info.kind, info.reference }, dynamicTempLocal); + + return dynamicTempLocal; } - else { - if (inherited) { - // if virtual multi-method handler is overridden - // redirect to the parent one - resendTarget = info.header.parentRef; - } - else if (methodType == SyntaxKey::Constructor && actionRef == getAction(scope.buildins.constructor_message) && argCount == 1) { - // conversion constructor multi-method is a special case - // instead of redirecting to the most generic handler - // it should try to typecast the argument + else return tempLocal; +} - ref_t typeRef = retrieveTypeRef(scope, targetRef); +ObjectInfo Compiler::Expression :: boxPtrLocally(ObjectInfo info) +{ + ObjectInfo tempLocal = declareTempLocal(info.typeInfo.typeRef, false); - ref_t signRef = scope.module->mapSignature(&typeRef, 1, false); - ref_t actionRef = scope.module->mapAction(CAST_MESSAGE, signRef, false); - resendMessage = encodeMessage(actionRef, 1, CONVERSION_MESSAGE); - } - else { - ref_t dummy = 0; - ustr_t actionName = scope.module->resolveAction(actionRef, dummy); + writeObjectInfo(info); + writer->appendNode(BuildKey::SavingInStack, 0); - ref_t signatureLen = 0; - ref_t signatures[ARG_COUNT] = {}; + writeObjectInfo(tempLocal); - pos_t firstArg = test(flags, FUNCTION_MESSAGE) ? 0 : 1; - for (pos_t i = firstArg; i < argCount; i++) { - signatures[signatureLen++] = scope.buildins.superReference; - } - ref_t signRef = scope.module->mapAction(actionName, - scope.module->mapSignature(signatures, signatureLen, false), false); + writer->appendNode(BuildKey::SetImmediateField); - resendMessage = encodeMessage(signRef, argCount, flags); - } + return tempLocal; +} - injectVirtualMultimethod(classNode, methodType, message, resendMessage, resendTarget, - outputRef, visibility, isExtension); +void Compiler::Expression :: unboxArgumentLocaly(ObjectInfo temp, ObjectKey key) +{ + if ((temp.typeInfo.isPrimitive() && compiler->_logic->isPrimitiveArrRef(temp.typeInfo.typeRef)) + || compiler->_logic->isEmbeddableArray(*scope.moduleScope, temp.typeInfo.typeRef)) + { + int size = defineFieldSize(scope, { key.value1, temp.typeInfo, key.value2 }); + + compileAssigningOp({ key.value1, temp.typeInfo, key.value2, size }, temp); } + else compileAssigningOp({ key.value1, temp.typeInfo, key.value2 }, temp); } -void Compiler :: injectVirtualMultimethod(SyntaxNode classNode, SyntaxKey methodType, mssg_t message, - mssg_t resendMessage, ref_t resendTarget, ref_t outputRef, Visibility visibility, bool isExtension) +void Compiler::Expression :: unboxOuterArgs(ArgumentsInfo* updatedOuterArgs) { - SyntaxNode methodNode = newVirtualMultimethod(classNode, methodType, message, visibility, isExtension); - methodNode.appendChild(SyntaxKey::Autogenerated, -1); // -1 indicates autogenerated multi-method + // first argument is a closure + ObjectInfo closure; - if (outputRef) - methodNode.appendChild(SyntaxKey::OutputType, outputRef); + for (pos_t i = 0; i != updatedOuterArgs->count_pos(); i++) { + ObjectInfo info = (*updatedOuterArgs)[i]; + if (info.kind == ObjectKind::ClosureInfo) { + closure = (*updatedOuterArgs)[++i]; + closure.kind = ObjectKind::LocalField; + } + else if (info.kind == ObjectKind::MemberInfo) { + ObjectInfo source = (*updatedOuterArgs)[++i]; - if (message == resendMessage) { - SyntaxNode dispatchOp = methodNode.appendChild(SyntaxKey::RedirectDispatch); - if (resendTarget) - dispatchOp.appendChild(SyntaxKey::Target, resendTarget); + if (source.kind == ObjectKind::Local) { + closure.extra = info.reference; + compileAssigningOp(source, closure); + } + else if (source.kind == ObjectKind::LocalAddress) { + closure.extra = info.reference; + compileAssigningOp(source, closure); + } + else if (source.kind == ObjectKind::Outer) { + // ignore outer fields + } + else assert(false); + } + else assert(false); } - else methodNode.appendChild(SyntaxKey::RedirectDispatch, resendMessage); } -void Compiler :: injectVirtualTryDispatch(SyntaxNode classNode, SyntaxKey methodType, - mssg_t message, mssg_t dispatchMessage, ref_t originalTarget) +void Compiler::Expression :: convertIntLiteralForOperation(SyntaxNode node, int operatorId, ArgumentsInfo& messageArguments) { - SyntaxNode methodNode = newVirtualMethod(classNode, methodType, message, Visibility::Public, false); - methodNode.appendChild(SyntaxKey::Autogenerated, -1); // -1 indicates autogenerated method + if (!DoesOperationSupportConvertableIntLiteral(operatorId)) + return; - SyntaxNode dispatchOp = methodNode.appendChild(SyntaxKey::RedirectTryDispatch, dispatchMessage); - if (originalTarget) - dispatchOp.appendChild(SyntaxKey::Target, originalTarget); -} + ObjectInfo literal = {}; + ref_t loperandRef = messageArguments[0].typeInfo.typeRef; + switch (loperandRef) { + case V_INT16ARRAY: + literal = convertIntLiteral(scope, node, messageArguments[1], V_INT16, true); + break; + case V_INT8ARRAY: + literal = convertIntLiteral(scope, node, messageArguments[1], V_INT8, true); + break; + case V_BINARYARRAY: + literal = convertIntLiteral(scope, node, messageArguments[1], + compiler->_logic->retrievePrimitiveType(*scope.moduleScope, messageArguments[0].typeInfo.elementRef), true); + break; + default: + { + literal = convertIntLiteral(scope, node, messageArguments[1], + compiler->_logic->retrievePrimitiveType(*scope.moduleScope, loperandRef), true); -void Compiler :: injectVirtualTryDispatch(SyntaxNode classNode, SyntaxKey methodType, ClassInfo& info, - mssg_t message, mssg_t dispatchMessage, bool inherited) -{ - ref_t originalTarget = 0; - if (inherited) { - // if virtual multi-method handler is overridden - // redirect to the parent one - originalTarget = info.header.parentRef; + break; + } } - injectVirtualTryDispatch(classNode, methodType, message, dispatchMessage, originalTarget); + if (literal.kind != ObjectKind::Unknown) + messageArguments[1] = literal; } -void Compiler :: injectInitializer(SyntaxNode classNode, SyntaxKey methodType, mssg_t message) +ObjectInfo Compiler::Expression :: boxArgumentInPlace(ObjectInfo info, ref_t targetRef) { - SyntaxNode methodNode = classNode.appendChild(methodType, message); - methodNode.appendChild(SyntaxKey::Hints, (ref_t)MethodHint::Initializer); - methodNode.appendChild(SyntaxKey::Autogenerated); + bool condBoxing = info.mode == TargetMode::Conditional && compiler->_withConditionalBoxing; + ref_t typeRef = targetRef; + if (!typeRef) + typeRef = compiler->retrieveStrongType(scope, info); - methodNode.appendChild(SyntaxKey::FieldInitializer); // NOTE : it is a place holder -} + ObjectInfo tempLocal = {}; + if (hasToBePresaved(info)) { + info = saveToTempLocal(info); + } + tempLocal = declareTempLocal(typeRef); -void Compiler :: injectStrongRedirectMethod(SyntaxNode classNode, SyntaxKey methodType, ref_t reference, mssg_t message, mssg_t redirectMessage, ref_t outputRef) -{ - SyntaxNode methodNode = classNode.appendChild(methodType, message); - methodNode.appendChild(SyntaxKey::OutputType, outputRef); + ClassInfo argInfo; + compiler->_logic->defineClassInfo(*scope.moduleScope, argInfo, typeRef, false, true); - SyntaxNode resendNode = methodNode.appendChild(SyntaxKey::DirectResend, redirectMessage); - resendNode.appendChild(SyntaxKey::Target, reference); -} + ObjectInfo lenLocal = {}; + bool isBinaryArray = compiler->_logic->isEmbeddableArray(argInfo); + if (isBinaryArray) { + int elementSize = -(int)argInfo.size; -void Compiler :: injectDefaultConstructor(ClassScope& scope, SyntaxNode node, - bool protectedOne, bool withClearOption) -{ - mssg_t message = protectedOne ? scope.moduleScope->buildins.protected_constructor_message - : scope.moduleScope->buildins.constructor_message; - MethodHint hints = (MethodHint)((ref_t)MethodHint::Constructor | (ref_t)MethodHint::Normal); - if (protectedOne) - hints = (ref_t)hints | MethodHint::Protected; + // get the length + lenLocal = declareTempLocal(V_INT32, false); - SyntaxNode methodNode = node.appendChild(SyntaxKey::Constructor, message); - methodNode.appendChild(SyntaxKey::Autogenerated); - methodNode.appendChild(SyntaxKey::Hints, (ref_t)hints); - methodNode.appendChild(SyntaxKey::OutputType, scope.reference); + writeObjectInfo(info); + writer->appendNode(BuildKey::SavingInStack, 0); + writer->newNode(BuildKey::BinaryArraySOp, LEN_OPERATOR_ID); + writer->appendNode(BuildKey::Index, lenLocal.argument); + writer->appendNode(BuildKey::Size, elementSize); + writer->closeNode(); - if (withClearOption) - methodNode.appendChild(SyntaxKey::FillingAttr); -} + // allocate the object + writeObjectInfo(lenLocal); + writer->appendNode(BuildKey::SavingInStack, 0); -void Compiler :: injectVirtualReturningMethod(ModuleScopeBase* scope, SyntaxNode classNode, - mssg_t message, ustr_t retVar, ref_t classRef) -{ - SyntaxNode methNode = classNode.appendChild(SyntaxKey::Method, message); - methNode.appendChild(SyntaxKey::Autogenerated, -1); // -1 indicates autogenerated method - methNode.appendChild(SyntaxKey::Hints, (ref_t)MethodHint::Sealed | (ref_t)MethodHint::Conversion); + writer->newNode(BuildKey::NewArrayOp, typeRef); + writer->appendNode(BuildKey::Size, argInfo.size); + writer->closeNode(); - if (classRef) { - methNode.appendChild(SyntaxKey::OutputType, classRef); - } + writer->appendNode(BuildKey::Assigning, tempLocal.argument); - SyntaxNode exprNode = methNode.appendChild(SyntaxKey::ReturnExpression).appendChild(SyntaxKey::Expression); - //exprNode.appendNode(lxAttribute, V_NODEBUGINFO); - exprNode.appendChild(SyntaxKey::Object).appendChild(SyntaxKey::identifier, retVar); -} + writeObjectInfo(info); + writer->appendNode(BuildKey::SavingInStack, 0); -void Compiler :: generateOverloadListMember(ModuleScopeBase& scope, ref_t listRef, ref_t classRef, - mssg_t messageRef, MethodHint type) -{ - MemoryWriter metaWriter(scope.module->mapSection(listRef | mskConstArray, false)); - if (metaWriter.position() == 0) { - metaWriter.writeDReference(0, messageRef); - switch (type) { - case MethodHint::Sealed: - metaWriter.writeDReference(classRef | mskVMTMethodAddress, messageRef); - break; - case MethodHint::Virtual: - metaWriter.writeDReference(classRef | mskVMTMethodOffset, messageRef); - break; - default: - metaWriter.writeDWord(0); - break; - } - metaWriter.writeDWord(0); - } - else { - if (type == MethodHint::Normal) { - metaWriter.insertDWord(0, 0); - } - else metaWriter.insertDWord(0, messageRef); + writer->appendNode(BuildKey::LoadingIndex, lenLocal.reference); - metaWriter.insertDWord(0, messageRef); - metaWriter.Memory()->addReference(0, 0); - switch (type) { - case MethodHint::Sealed: - metaWriter.Memory()->addReference(classRef | mskVMTMethodAddress, 4); - break; - case MethodHint::Virtual: - metaWriter.Memory()->addReference(classRef | mskVMTMethodOffset, 4); - break; - default: - break; - } + writeObjectInfo(tempLocal); + + copyArray(*writer, elementSize); } -} + else if (compiler->_logic->isDynamic(argInfo)) { + // get the length + lenLocal = declareTempLocal(V_INT32, false); -void Compiler :: injectVirtualDispatchMethod(Scope& scope, SyntaxNode classNode, mssg_t message, ref_t outputRef, SyntaxKey key, ustr_t arg) -{ - SyntaxNode methodNode = classNode.appendChild(SyntaxKey::Method, message); - // HOTFIX : indicating virtual interface dispatcher, to ignore byref handler optimization - methodNode.appendChild(SyntaxKey::Attribute, V_INTERFACE_DISPATCHER); + writeObjectInfo(info); + writer->appendNode(BuildKey::SavingInStack, 0); + writer->newNode(BuildKey::ObjArraySOp, LEN_OPERATOR_ID); + writer->appendNode(BuildKey::Index, lenLocal.argument); + writer->closeNode(); - if (outputRef) - methodNode.appendChild(SyntaxKey::Type, outputRef); + // allocate the object + writeObjectInfo(lenLocal); + writer->appendNode(BuildKey::SavingInStack, 0); - ref_t actionRef = getAction(message); - ref_t signRef = 0; - ustr_t actionName = scope.module->resolveAction(actionRef, signRef); + writer->newNode(BuildKey::NewArrayOp, typeRef); + writer->closeNode(); - if (signRef) { - ref_t signatures[ARG_COUNT]; - size_t len = scope.module->resolveSignature(signRef, signatures); + writer->appendNode(BuildKey::Assigning, tempLocal.argument); - String arg; - for (size_t i = 0; i < len; i++) { - arg.copy("$"); - arg.appendInt((int)i); + writeObjectInfo(info); + writer->appendNode(BuildKey::SavingInStack, 0); - SyntaxNode param = methodNode.appendChild(SyntaxKey::Parameter); - param.appendChild(SyntaxKey::Type, signatures[i]); - SyntaxNode nameParam = param.appendChild(SyntaxKey::Name); - nameParam.appendChild(SyntaxKey::identifier, arg.str()); - } + writer->appendNode(BuildKey::LoadingIndex, lenLocal.reference); + + writeObjectInfo(tempLocal); + + copyArray(*writer, 0); } else { - pos_t len = getArgCount(message); - String arg; - for (pos_t i = 1; i < len; i++) { - arg.copy("$"); - arg.appendInt(i); + writeObjectInfo(info); - SyntaxNode param = methodNode.appendChild(SyntaxKey::Parameter); - SyntaxNode nameParam = param.appendChild(SyntaxKey::Name); - nameParam.appendChild(SyntaxKey::identifier, arg.str()); - } - } + if (condBoxing) + writer->newNode(BuildKey::StackCondOp, IF_OPERATOR_ID); - SyntaxNode body = methodNode.appendChild(SyntaxKey::Redirect); - body - .appendChild(SyntaxKey::Expression) - .appendChild(SyntaxKey::Object) - .appendChild(key, arg); -} + writer->appendNode(BuildKey::SavingInStack, 0); -ref_t Compiler :: generateExtensionTemplate(ModuleScopeBase& scope, ref_t templateRef, size_t argumentLen, ref_t* arguments, - ustr_t ns, ExtensionMap* outerExtensionList) -{ - TemplateTypeList typeList; - for (size_t i = 0; i < argumentLen; i++) - typeList.add(arguments[i]); + createObject(*writer, argInfo, typeRef); - // HOTFIX : generate a temporal template to pass the type - SyntaxTree dummyTree; - List parameters({}); - declareTemplateParameters(scope.module, typeList, dummyTree, parameters); + copyObjectToAcc(*writer, argInfo, tempLocal.reference); - return _templateProcessor->generateClassTemplate(scope, ns, - templateRef, parameters, false, outerExtensionList); -} + if (condBoxing) + writer->closeNode(); -inline int retrieveIndex(List& list, mssg_t multiMethod) -{ - return list.retrieveIndex(multiMethod, [](mssg_t arg, ref_t current) - { - return current == arg; - }); + writer->appendNode(BuildKey::Assigning, tempLocal.argument); + } + + if (!compiler->_logic->isReadOnly(argInfo)) + tempLocal.mode = condBoxing ? TargetMode::ConditionalUnboxingRequired : TargetMode::UnboxingRequired; + + return tempLocal; } -inline void saveAsPreloaded(CompilerLogic* logic, ustr_t ns, ModuleBase* module, ref_t ref, ref_t mask) +ObjectInfo Compiler::Expression :: boxRefArgumentInPlace(ObjectInfo info, ref_t targetRef) { - IdentifierString preloadedListName; - if (!ns.empty()) { - preloadedListName.append(ns); - } - else preloadedListName.append("'"); + ref_t typeRef = targetRef; + if (!typeRef) + typeRef = compiler->retrieveStrongType(scope, info); - preloadedListName.append(META_PREFIX); - preloadedListName.append(PRELOADED_FORWARD); + ObjectInfo tempLocal = declareTempLocal(typeRef); + tempLocal.mode = TargetMode::RefUnboxingRequired; - ref_t dictionaryRef = module->mapReference(*preloadedListName); + info.kind = ObjectKind::Local; + compileAssigningOp(tempLocal, info); - MemoryBase* dictionary = module->mapSection(dictionaryRef | mskTypeListRef, false); + tempLocal.kind = ObjectKind::LocalReference; - logic->writeArrayEntry(dictionary, ref | mask); + return tempLocal; } -void Compiler :: declareModuleExtensionDispatcher(NamespaceScope& scope, SyntaxNode node) +ObjectInfo Compiler::Expression :: boxVariadicArgument(ObjectInfo info) { - List genericMethods(0); - ClassInfo::MethodMap methods({}); - ResolvedMap targets(0); + NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); - auto it = scope.declaredExtensions.start(); - while (!it.eof()) { - auto extInfo = *it; - mssg_t genericMessage = it.key(); + ref_t elementRef = info.typeInfo.elementRef; + if (!elementRef) + elementRef = scope.moduleScope->buildins.superReference; - ustr_t refName = scope.module->resolveReference(extInfo.value1); - if (isWeakReference(refName)) { - if (NamespaceString::compareNs(refName, *scope.nsName)) { - // if the extension is declared in the module namespace - // add it to the list to be generated + ref_t typeRef = compiler->resolveArgArrayTemplate(*scope.moduleScope, *nsScope->nsName, elementRef, false); - if (retrieveIndex(genericMethods, genericMessage) == -1) - genericMethods.add(genericMessage); + ObjectInfo destLocal = declareTempLocal(typeRef); + ObjectInfo lenLocal = declareTempLocal(scope.moduleScope->buildins.intReference, false); - methods.add(extInfo.value2, { false, 0, 0, genericMessage | FUNCTION_MESSAGE, 0 }); - targets.add(extInfo.value2, extInfo.value1); - } - } + // get length + writeObjectInfo(info); + writer->appendNode(BuildKey::SavingInStack); + writer->newNode(BuildKey::VArgSOp, LEN_OPERATOR_ID); + writer->appendNode(BuildKey::Index, lenLocal.argument); + writer->closeNode(); - it++; - } + // create a dynamic array + writeObjectInfo(lenLocal); + writer->appendNode(BuildKey::SavingInStack); + writer->appendNode(BuildKey::NewArrayOp, typeRef); + compileAssigningOp(destLocal, { ObjectKind::Object, { typeRef }, 0 }); - if (genericMethods.count() > 0) { - // if there are extension methods in the namespace - ref_t extRef = scope.moduleScope->mapAnonymous(); - ClassScope classScope(&scope, extRef, Visibility::Private); - declareClassParent(classScope.info.header.parentRef, classScope, {}); - classScope.extensionDispatcher = true; - classScope.info.header.classRef = classScope.reference; - classScope.extensionClassRef = scope.moduleScope->buildins.superReference; - generateClassFlags(classScope, elExtension | elSealed | elAutoLoaded); + // copy the content + // index len + // src:sp[0] + // dst:acc + writer->appendNode(BuildKey::LoadingIndex, lenLocal.argument); + writeObjectInfo(info); + writer->appendNode(BuildKey::SavingInStack); + writeObjectInfo(destLocal); + writer->appendNode(BuildKey::CopyingArr); - for (auto g_it = genericMethods.start(); !g_it.eof(); ++g_it) { - mssg_t genericMessage = *g_it; + if (info.typeInfo.typeRef && info.typeInfo.typeRef != typeRef) { + // if the conversion is required + ObjectInfo convInfo = convertObject({}, destLocal, + info.typeInfo.typeRef, false, false); - _logic->injectMethodOverloadList(this, *scope.moduleScope, - classScope.info.header.flags, genericMessage | FUNCTION_MESSAGE, methods, - classScope.info.attributes, &targets, targetResolver, ClassAttribute::ExtOverloadList); - } + compileAssigningOp(destLocal, convInfo); - classScope.save(); + destLocal.typeInfo = convInfo.typeInfo; + } - // build the class tree - node.appendChild(SyntaxKey::Class, extRef); + return destLocal; +} - // save as preloaded class - saveAsPreloaded(_logic, *scope.nsName, scope.module, extRef, mskVMTRef); +void Compiler::Expression :: compileAssigning(SyntaxNode node, ObjectInfo target, ObjectInfo source, bool noConversion) +{ + if (!noConversion) { + source = convertObject(node, source, + compiler->retrieveStrongType(scope, target), false, false); } + + compileAssigningOp(target, source); } + +void Compiler::Expression :: compileConverting(SyntaxNode node, ObjectInfo source, ref_t targetRef, bool stackSafe) +{ + if (targetRef && targetRef != V_AUTO) { + source = convertObject(node, source, targetRef, false, false); + + scope.syncStack(); + } + + writeObjectInfo(boxArgument(source, stackSafe, true, false)); +} \ No newline at end of file diff --git a/elenasrc3/elc/compiler.h b/elenasrc3/elc/compiler.h index 2ce80faea..2cd88e45c 100644 --- a/elenasrc3/elc/compiler.h +++ b/elenasrc3/elc/compiler.h @@ -1043,13 +1043,147 @@ namespace elena_lang } }; - struct WriterContext + class Expression { - BuildTreeWriter* writer; - ExprScope* scope; - SyntaxNode node; + friend class Compiler; + + Compiler* compiler; + ExprScope scope; + BuildTreeWriter* writer; + + ObjectInfo compileLookAhead(SyntaxNode node, + ref_t targetRef, ExpressionAttribute attrs); + + ObjectInfo compileMessageOperation(SyntaxNode node, ref_t targetRef, ExpressionAttribute attrs); + ObjectInfo compilePropertyOperation(SyntaxNode node, ref_t targetRef, ExpressionAttribute attrs); + + ObjectInfo compileOperation(SyntaxNode node, int operatorId, ref_t expectedRef, ExpressionAttribute mode); + ObjectInfo compileSpecialOperation(SyntaxNode node, int operatorId, ref_t expectedRef); + ObjectInfo compileAssignOperation(SyntaxNode node, int operatorId, ref_t expectedRef); + ObjectInfo compileBoolOperation(SyntaxNode node, int operatorId); + ObjectInfo compileIndexerOperation(SyntaxNode node, int operatorId, ref_t expectedRef); + ObjectInfo compileBranchingOperation(SyntaxNode node, int operatorId, bool retValExpected, bool withoutDebugInfo); + ObjectInfo compileCatchOperation(SyntaxNode node); + ObjectInfo compileFinalOperation(SyntaxNode node); + ObjectInfo compileAltOperation(SyntaxNode node); + ObjectInfo compileIsNilOperation(SyntaxNode node); + ObjectInfo compileTupleAssigning(SyntaxNode node); + + ObjectInfo compileAssigning(SyntaxNode loperand, SyntaxNode roperand, ExpressionAttribute mode); + + ObjectInfo compileMessageOperationR(ObjectInfo target, SyntaxNode node, bool propertyMode); + + ObjectInfo compileLoop(SyntaxNode node, ExpressionAttribute mode); + ObjectInfo compileExtern(SyntaxNode node, ExpressionAttribute mode); + + ObjectInfo compileNested(InlineClassScope& classCcope, ExpressionAttribute mode, ArgumentsInfo* updatedOuterArgs); + + ObjectInfo compileNested(SyntaxNode node, ExpressionAttribute mode, ArgumentsInfo* updatedOuterArgs); + ObjectInfo compileClosure(SyntaxNode node, ExpressionAttribute mode, ArgumentsInfo* updatedOuterArgs); + ObjectInfo compileWeakOperation(SyntaxNode node, ref_t* arguments, pos_t argLen, + ObjectInfo& loperand, ArgumentsInfo& messageArguments, mssg_t message, ref_t expectedRef, ArgumentsInfo* updatedOuterArgs); + + ObjectInfo compileNewOp(SyntaxNode node, ObjectInfo source, ref_t signRef, ArgumentsInfo& arguments); + + ObjectInfo typecastObject(SyntaxNode node, ObjectInfo source, ref_t targetRef); + + ObjectInfo validateObject(SyntaxNode node, ObjectInfo retVal, + ref_t targetRef, bool noPrimitives, bool paramMode, bool dynamicRequired); + + ObjectInfo compileExternalOp(SyntaxNode node, ref_t externalRef, bool stdCall, + ArgumentsInfo& arguments, ref_t expectedRef); + + ObjectInfo compileNewArrayOp(SyntaxNode node, ObjectInfo source, ref_t targetRef, ArgumentsInfo& arguments); + + ObjectInfo convertObject(SyntaxNode node, ObjectInfo source, ref_t targetRef, bool dynamicRequired, bool withoutBoxing); + + ObjectInfo compileMessageOperation(SyntaxNode node, ObjectInfo target, MessageResolution resolution, ref_t implicitSignatureRef, + ArgumentsInfo& arguments, ExpressionAttributes mode, ArgumentsInfo* updatedOuterArgs); + ObjectInfo compileOperation(SyntaxNode loperand, SyntaxNode roperand, + int operatorId, ref_t expectedRef); + ObjectInfo compileOperation(SyntaxNode node, ArgumentsInfo& messageArguments, + int operatorId, ref_t expectedRef, ArgumentsInfo* updatedOuterArgs); + + ObjectInfo compileBranchingOperation(SyntaxNode node, ObjectInfo loperand, SyntaxNode rnode, + SyntaxNode r2node, int operatorId, ArgumentsInfo* updatedOuterArgs, bool retValExpected, bool withoutDebugInfo); + + ref_t compileMessageArguments(SyntaxNode current, ArgumentsInfo& arguments, ref_t expectedSignRef, ExpressionAttribute mode, + ArgumentsInfo* updatedOuterArgs, bool& variadicArgList); + + MessageResolution resolveByRefHandler(ObjectInfo source, ref_t expectedRef, mssg_t weakMessage, ref_t& signatureRef, bool noExtensions); + MessageResolution resolveMessageAtCompileTime(ObjectInfo target, mssg_t weakMessage, ref_t implicitSignatureRef, bool ignoreExtensions, + bool ignoreVariadics); + + ObjectInfo declareTempLocal(ref_t typeRef, bool dynamicOnly = true); + ObjectInfo declareTempStructure(SizeInfo sizeInfo); + + ObjectInfo boxArgument(ObjectInfo info, bool stackSafe, bool boxInPlace, bool allowingRefArg, ref_t targetRef = 0); + ObjectInfo boxArgumentLocally(ObjectInfo info, bool stackSafe, bool forced); + ObjectInfo boxLocally(ObjectInfo info, bool stackSafe); + ObjectInfo boxPtrLocally(ObjectInfo info); + ObjectInfo boxArgumentInPlace(ObjectInfo info, ref_t targetRef = 0); + ObjectInfo boxRefArgumentInPlace(ObjectInfo info, ref_t targetRef = 0); + ObjectInfo boxVariadicArgument(ObjectInfo info); + + ObjectInfo unboxArguments(ObjectInfo retVal, ArgumentsInfo* updatedOuterArgs); + void unboxArgumentLocaly(ObjectInfo tempLocal, ObjectKey targetKey); + void unboxOuterArgs(ArgumentsInfo* updatedOuterArgs); + + ObjectInfo saveToTempLocal(ObjectInfo object); + + ObjectInfo compileBranchingOperands(SyntaxNode rnode, SyntaxNode r2node, bool retValExpected, bool withoutDebugInfo); + + ObjectInfo compileNativeConversion(SyntaxNode node, ObjectInfo source, ref_t operationKey); + + ObjectInfo allocateResult(ref_t resultRef); + + void compileYieldOperation(SyntaxNode node); + void compileSwitchOperation(SyntaxNode node); + + bool compileAssigningOp(ObjectInfo target, ObjectInfo source); + + bool validateShortCircle(mssg_t message, ObjectInfo target); + + ref_t mapNested(ExpressionAttribute mode); + + bool resolveAutoType(ObjectInfo source, ObjectInfo& target); + + void showContextInfo(mssg_t message, ref_t targetRef); + + void writeMessageArguments(ObjectInfo& target, mssg_t message, ArgumentsInfo& arguments, ObjectInfo& lenLocal, + int& stackSafeAttr, bool targetOverridden, bool found, bool argUnboxingRequired, bool stackSafe); + + void convertIntLiteralForOperation(SyntaxNode node, int operatorId, ArgumentsInfo& messageArguments); + + public: + bool writeObjectInfo(ObjectInfo info); + void writeObjectInfo(ObjectInfo info, SyntaxNode node) + { + if (!writeObjectInfo(info)) + scope.raiseError(errInvalidOperation, node); + } + + void compileAssigning(SyntaxNode node, ObjectInfo target, ObjectInfo source, bool noConversion = false); + void compileConverting(SyntaxNode node, ObjectInfo source, ref_t targetRef, bool stackSafe); + + ObjectInfo compileSymbolRoot(SyntaxNode bodyNode, ExpressionAttribute mode); + ObjectInfo compileRoot(SyntaxNode node, ExpressionAttribute mode); + ObjectInfo compileReturning(SyntaxNode node, ExpressionAttribute mode, ref_t outputRef); + + ObjectInfo compile(SyntaxNode node, ref_t targetRef, ExpressionAttribute mode, + ArgumentsInfo* updatedOuterArgs); + ObjectInfo compileObject(SyntaxNode node, ExpressionAttribute mode, ArgumentsInfo* updatedOuterArgs); + ObjectInfo compileCollection(SyntaxNode node, ExpressionAttribute mode); + ObjectInfo compileTupleCollection(SyntaxNode node, ref_t targetRef); + + ObjectInfo compileSubCode(SyntaxNode node, ExpressionAttribute mode, bool withoutNewScope = false); + + Expression(Compiler* compiler, CodeScope& codeScope, BuildTreeWriter& writer); + Expression(Compiler* compiler, SourceScope& symbolScope, BuildTreeWriter& writer); }; + friend class Expression; + private: CompilerLogic* _logic; TemplateProssesorBase* _templateProcessor; @@ -1065,8 +1199,6 @@ namespace elena_lang bool _evaluateOp; bool _verbose; - void showContextInfo(ExprScope& scope, mssg_t message, ref_t targetRef); - void loadMetaData(ModuleScopeBase* moduleScope, ForwardResolverBase* forwardResolver, ustr_t name); void importExtensions(NamespaceScope& ns, ustr_t importedNs); @@ -1082,10 +1214,9 @@ namespace elena_lang mssg_t mapMessage(Scope& scope, SyntaxNode node, bool propertyMode, bool extensionMode, bool probeMode); ExternalInfo mapExternal(Scope& scope, SyntaxNode node); - ObjectInfo mapClassSymbol(Scope& scope, ref_t classRef); + static ObjectInfo mapClassSymbol(Scope& scope, ref_t classRef); ObjectInfo mapConstructorTarget(MethodScope& scope); - ref_t mapNested(ExprScope& ownerScope, ExpressionAttribute mode); ref_t mapConstantReference(Scope& scope); ref_t mapTemplateType(Scope& scope, SyntaxNode terminal, pos_t parameterCount); @@ -1098,7 +1229,7 @@ namespace elena_lang void declareTemplateAttributes(Scope& scope, SyntaxNode node, TemplateTypeList& parameters, TypeAttributes& attributes, bool declarationMode, bool objectMode); - int defineFieldSize(Scope& scope, ObjectInfo info); + static int defineFieldSize(Scope& scope, ObjectInfo info); ObjectInfo defineArrayType(Scope& scope, ObjectInfo info, bool declarationMode); ref_t defineArrayType(Scope& scope, ref_t elementRef, bool declarationMode); @@ -1126,17 +1257,11 @@ namespace elena_lang bool declarationMode, bool allowRole); ref_t resolveStrongTypeAttribute(Scope& scope, SyntaxNode node, bool declarationMode, bool allowRole); - bool resolveAutoType(ExprScope& scope, ObjectInfo source, ObjectInfo& target); - ref_t retrieveTemplate(NamespaceScope& scope, SyntaxNode node, List& parameters, ustr_t prefix, SyntaxKey argKey, ustr_t postFix); - MessageResolution resolveByRefHandler(BuildTreeWriter& writer, ObjectInfo source, ExprScope& scope, ref_t expectedRef, - mssg_t weakMessage, ref_t& signatureRef, bool noExtensions); - MessageResolution resolveMessageAtCompileTime(BuildTreeWriter& writer, ObjectInfo target, ExprScope& scope, - mssg_t weakMessage, ref_t implicitSignatureRef, bool ignoreExtensions, bool ignoreVariadics); - mssg_t resolveOperatorMessage(ModuleScopeBase* scope, int operatorId); - mssg_t resolveVariadicMessage(Scope& scope, mssg_t message); + static mssg_t resolveOperatorMessage(ModuleScopeBase* scope, int operatorId); + static mssg_t resolveVariadicMessage(Scope& scope, mssg_t message); bool isDefaultOrConversionConstructor(Scope& scope, mssg_t message, bool internalOne, bool& isProtectedDefConst); @@ -1147,9 +1272,7 @@ namespace elena_lang void readFieldAttributes(ClassScope& scope, SyntaxNode node, FieldAttributes& attrs, bool declarationMode); - int allocateLocalAddress(Scope& scope, int size, bool binaryArray); - - ObjectInfo allocateResult(ExprScope& scope, ref_t resultRef); + static int allocateLocalAddress(Scope& scope, int size, bool binaryArray); ref_t declareMultiType(Scope& scope, SyntaxNode& node, ref_t elementRef); @@ -1207,8 +1330,6 @@ namespace elena_lang bool declareVariable(Scope& scope, SyntaxNode terminal, TypeInfo typeInfo, bool ignoreDuplicate); bool declareYieldVariable(Scope& scope, ustr_t name, TypeInfo typeInfo); - ObjectInfo declareTempStructure(ExprScope& scope, SizeInfo sizeInfo); - void declareClassParent(ref_t parentRef, ClassScope& scope, SyntaxNode node); void resolveClassPostfixes(ClassScope& scope, SyntaxNode node, bool extensionMode); @@ -1267,9 +1388,7 @@ namespace elena_lang void evalStatement(MetaScope& scope, SyntaxNode node); - void writeObjectInfo(WriterContext& context, ObjectInfo info); - - void addBreakpoint(BuildTreeWriter& writer, SyntaxNode node, BuildKey bpKey); + static void addBreakpoint(BuildTreeWriter& writer, SyntaxNode node, BuildKey bpKey); bool evalInitializers(ClassScope& scope, SyntaxNode node); bool evalClassConstant(ustr_t constName, ClassScope& scope, SyntaxNode node, ObjectInfo& constInfo); @@ -1278,102 +1397,17 @@ namespace elena_lang ref_t compileExtensionDispatcher(BuildTreeWriter& writer, NamespaceScope& scope, mssg_t genericMessage, ref_t outputRef); - ref_t compileMessageArguments(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode current, - ArgumentsInfo& arguments, ref_t expectedSignRef, ExpressionAttribute mode, ArgumentsInfo* updatedOuterArgs, bool& variadicArgList); - void writeParameterDebugInfo(BuildTreeWriter& writer, Scope& scope, int size, TypeInfo typeInfo, ustr_t name, int index); void writeMethodDebugInfo(BuildTreeWriter& writer, MethodScope& scope); void writeMessageInfo(BuildTreeWriter& writer, MethodScope& scope); void compileInlineInitializing(BuildTreeWriter& writer, ClassScope& classScope, SyntaxNode node); - - void writeMessageArguments(WriterContext& context, ObjectInfo& target, - mssg_t message, ArgumentsInfo& arguments, ObjectInfo& lenLocal, int& stackSafeAttr, - bool targetOverridden, bool found, bool argUnboxingRequired, bool stackSafe); - - bool validateShortCircle(ExprScope& scope, mssg_t message, ObjectInfo target); - - ObjectInfo boxArgumentInPlace(WriterContext& context, ObjectInfo info, ref_t targetRef = 0); - ObjectInfo boxRefArgumentInPlace(WriterContext& context, ObjectInfo info, ref_t targetRef = 0); - ObjectInfo boxArgument(WriterContext& context, ObjectInfo info, - bool stackSafe, bool boxInPlace, bool allowingRefArg, ref_t targetRef = 0); - ObjectInfo boxArgumentLocally(WriterContext& context, ObjectInfo info, bool stackSafe, bool forced); - ObjectInfo boxLocally(WriterContext& context, ObjectInfo info, bool stackSafe); - ObjectInfo boxPtrLocally(WriterContext& context, ObjectInfo info); - ObjectInfo boxVariadicArgument(WriterContext& context, ObjectInfo info); - - ObjectInfo unboxArguments(WriterContext& context, ObjectInfo retVal, ArgumentsInfo* updatedOuterArgs); - void unboxArgumentLocaly(WriterContext& context, ObjectInfo tempLocal, ObjectKey targetKey); - void unboxOuterArgs(WriterContext& context, ArgumentsInfo* updatedOuterArgs); - - ObjectInfo saveToTempLocal(BuildTreeWriter& writer, ExprScope& scope, ObjectInfo object); - ObjectInfo declareTempLocal(ExprScope& scope, ref_t typeRef, bool dynamicOnly = true); - - ObjectInfo typecastObject(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, ObjectInfo source, ref_t targetRef); - ObjectInfo convertObject(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, ObjectInfo source, - ref_t targetRef, bool dynamicRequired, bool withoutBoxing); - ObjectInfo convertIntLiteral(ExprScope& scope, SyntaxNode node, ObjectInfo source, ref_t targetRef, bool ignoreError = false); - - void convertIntLiteralForOperation(ExprScope& scope, SyntaxNode node, int operatorId, ArgumentsInfo& messageArguments); + + static ObjectInfo convertIntLiteral(ExprScope& scope, SyntaxNode node, ObjectInfo source, ref_t targetRef, bool ignoreError = false); bool compileSymbolConstant(SymbolScope& scope, ObjectInfo retVal); - ObjectInfo compileExternalOp(WriterContext& context, ref_t externalRef, bool stdCall, - ArgumentsInfo& arguments, ref_t expectedRef); - - ObjectInfo compileNewArrayOp(WriterContext& context, ObjectInfo source, - ref_t targetRef, ArgumentsInfo& arguments); - ObjectInfo compileNewOp(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, - ObjectInfo source, ref_t signRef, ArgumentsInfo& arguments); - ObjectInfo compileNativeConversion(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, ObjectInfo source, ref_t operationKey); - - ObjectInfo compileLookAheadExpression(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, - ref_t targetRef, ExpressionAttribute attrs); - - ObjectInfo compileMessageOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, ObjectInfo target, - MessageResolution resolution, ref_t implicitSignatureRef, ArgumentsInfo& arguments, ExpressionAttributes mode, ArgumentsInfo* updatedOuterArgs); - ObjectInfo compileMessageOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, - ref_t targetRef, ExpressionAttribute attrs); - ObjectInfo compilePropertyOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, - ref_t targetRef, ExpressionAttribute attrs); - - bool compileAssigningOp(WriterContext& context, ObjectInfo target, ObjectInfo source); - ObjectInfo compileAssigning(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode loperand, - SyntaxNode roperand, ExpressionAttribute mode); - - ObjectInfo compileMessageOperationR(BuildTreeWriter& writer, ExprScope& scope, ObjectInfo target, - SyntaxNode node, bool propertyMode); - - ObjectInfo compileWeakOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, ref_t* arguments, pos_t argLen, - ObjectInfo& loperand, ArgumentsInfo& messageArguments, mssg_t message, ref_t expectedRef, ArgumentsInfo* updatedOuterArgs); - - ObjectInfo compileOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, ArgumentsInfo& messageArguments, - int operatorId, ref_t expectedRef, ArgumentsInfo* updatedOuterArgs); - ObjectInfo compileOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode loperand, SyntaxNode roperand, - int operatorId, ref_t expectedRef); - ObjectInfo compileAssignOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, - int operatorId, ref_t expectedRef); - ObjectInfo compileBoolOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, int operatorId); - ObjectInfo compileIndexerOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, int operatorId, ref_t expectedRef); - ObjectInfo compileOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, int operatorId, - ref_t expectedRef, ExpressionAttribute mode); - ObjectInfo compileSpecialOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, int operatorId, ref_t expectedRef); - ObjectInfo compileBranchingOperands(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode rnode, - SyntaxNode r2node, bool retValExpected, bool withoutDebugInfo); - ObjectInfo compileBranchingOperation(WriterContext& context, ObjectInfo loperand, SyntaxNode rnode, - SyntaxNode r2node, int operatorId, ArgumentsInfo* updatedOuterArgs, bool retValExpected, bool withoutDebugInfo); - ObjectInfo compileBranchingOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, - int operatorId, bool retValExpected, bool withoutDebugInfo); - ObjectInfo compileCatchOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node); - ObjectInfo compileFinalOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node); - ObjectInfo compileAltOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node); - ObjectInfo compileIsNilOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node); - ObjectInfo compileTupleAssigning(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node); - - void compileSwitchOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node); - void compileYieldOperation(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node); - ObjectInfo defineTerminalInfo(Scope& scope, SyntaxNode node, TypeInfo declaredTypeInfo, bool variableMode, bool forwardMode, bool refOp, bool mssgOp, bool memberMode, bool& invalid, ExpressionAttribute attrs); @@ -1390,24 +1424,7 @@ namespace elena_lang ObjectInfo mapExtMessageConstant(Scope& scope, SyntaxNode node, ref_t actionRef, ref_t extension); ObjectInfo mapObject(Scope& scope, SyntaxNode node, ExpressionAttributes mode); - - ObjectInfo validateObject(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, ObjectInfo retVal, - ref_t targetRef, bool noPrimitives, bool paramMode, bool dynamicRequired); - - ObjectInfo compileNested(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, ExpressionAttribute mode, - ArgumentsInfo* updatedOuterArgs); - ObjectInfo compileClosure(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, ExpressionAttribute mode, - ArgumentsInfo* updatedOuterArgs); - ObjectInfo compileObject(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, - ExpressionAttribute mode, ArgumentsInfo* updatedOuterArgs); - ObjectInfo compileExpression(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, - ref_t targetRef, ExpressionAttribute mode, ArgumentsInfo* updatedOuterArgs); - ObjectInfo compileLoopExpression(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, - ExpressionAttribute mode); - ObjectInfo compileExternExpression(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, - ExpressionAttribute mode); - ObjectInfo compileSubCode(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, - ExpressionAttribute mode, bool withoutNewScope = false); + ObjectInfo compileRootExpression(BuildTreeWriter& writer, CodeScope& scope, SyntaxNode node, ExpressionAttribute mode); ObjectInfo compileRetExpression(BuildTreeWriter& writer, CodeScope& scope, SyntaxNode node, @@ -1468,10 +1485,7 @@ namespace elena_lang void compileClosureClass(BuildTreeWriter& writer, ClassScope& scope, SyntaxNode node); void compileVMT(BuildTreeWriter& writer, ClassScope& scope, SyntaxNode node, bool exclusiveMode = false, bool ignoreAutoMultimethod = false); - void compileClassVMT(BuildTreeWriter& writer, ClassScope& classClassScope, ClassScope& scope, SyntaxNode node); - - ObjectInfo compileCollection(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, ExpressionAttribute mode); - ObjectInfo compileTupleCollectiom(BuildTreeWriter& writer, ExprScope& scope, SyntaxNode node, ref_t targetRef); + void compileClassVMT(BuildTreeWriter& writer, ClassScope& classClassScope, ClassScope& scope, SyntaxNode node); void compileSymbol(BuildTreeWriter& writer, SymbolScope& scope, SyntaxNode node); void compileClassSymbol(BuildTreeWriter& writer, ClassScope& scope); @@ -1523,7 +1537,7 @@ namespace elena_lang void injectStrongRedirectMethod(SyntaxNode node, SyntaxKey methodType, ref_t reference, mssg_t message, mssg_t redirectMessage, ref_t outputRef); - void callInitMethod(BuildTreeWriter& writer, SyntaxNode node, ExprScope& exprScope, ClassInfo& info, ref_t reference); + void callInitMethod(Expression& expression, SyntaxNode node, ClassInfo& info, ref_t reference); void generateOverloadListMember(ModuleScopeBase& scope, ref_t listRef, ref_t classRef, mssg_t messageRef, MethodHint type) override;