From bd8bc74bd5fcedb364326b6952dcb8deef6103b7 Mon Sep 17 00:00:00 2001 From: Lucian Radu Teodorescu Date: Sun, 21 Apr 2019 20:43:51 +0300 Subject: [PATCH 1/6] Add 'bitcopiable' modifier Datatypes with this modifier will not be returned by taking a sret ptr parameter --- SparrowImplicitLib/std/ptr.spr | 2 +- src/SparrowFrontend/Helpers/SprTypeTraits.cpp | 9 ++ src/SparrowFrontend/Helpers/SprTypeTraits.h | 5 + src/SparrowFrontend/Mods.cpp | 24 ++- src/SparrowFrontend/Mods.h | 1 + src/SparrowFrontend/Nodes/Decl.cpp | 19 ++- src/SparrowFrontend/Nodes/SprProperties.h | 1 + tests/Basic/datatype/bitcopiable.spr | 148 ++++++++++++++++++ tests/tests.in | 1 + 9 files changed, 197 insertions(+), 13 deletions(-) create mode 100644 tests/Basic/datatype/bitcopiable.spr diff --git a/SparrowImplicitLib/std/ptr.spr b/SparrowImplicitLib/std/ptr.spr index 07ca960c..dd1b52d2 100644 --- a/SparrowImplicitLib/std/ptr.spr +++ b/SparrowImplicitLib/std/ptr.spr @@ -2,7 +2,7 @@ module std.ptr import newDelete(delete) -[initCtor] +[initCtor, bitcopiable] datatype Ptr(type: Type) using ValueType = type diff --git a/src/SparrowFrontend/Helpers/SprTypeTraits.cpp b/src/SparrowFrontend/Helpers/SprTypeTraits.cpp index 7c36b438..d6cbe901 100644 --- a/src/SparrowFrontend/Helpers/SprTypeTraits.cpp +++ b/src/SparrowFrontend/Helpers/SprTypeTraits.cpp @@ -316,3 +316,12 @@ Type SprFrontend::changeRefCount(Type type, int numRef, const Location& loc) { REP_INTERNAL(loc, "Cannot change reference count for type %1%") % type; return type; } + +bool SprFrontend::isBitCopiable(Type type) { + if (!type.hasStorage()) + return false; + // TODO: Remove this + if (Feather_isBasicNumericType(type)) + return true; + return type.referredNode() && type.referredNode().hasProperty(propBitCopiable); +} diff --git a/src/SparrowFrontend/Helpers/SprTypeTraits.h b/src/SparrowFrontend/Helpers/SprTypeTraits.h index 31cf442a..d69c03d7 100644 --- a/src/SparrowFrontend/Helpers/SprTypeTraits.h +++ b/src/SparrowFrontend/Helpers/SprTypeTraits.h @@ -42,4 +42,9 @@ bool isConceptType(Type t, int& numRefs); /// Creates a new type from the original type, with the specified reference count Type changeRefCount(Type type, int numRef, const Location& loc = Location()); + +//! Checks if the given type is bitcopiable +//! This returns true for native types and for references +bool isBitCopiable(Type type); + } // namespace SprFrontend \ No newline at end of file diff --git a/src/SparrowFrontend/Mods.cpp b/src/SparrowFrontend/Mods.cpp index 3df64441..3fc72772 100644 --- a/src/SparrowFrontend/Mods.cpp +++ b/src/SparrowFrontend/Mods.cpp @@ -37,7 +37,7 @@ void ModAutoCt_beforeSetContext(Nest_Modifier*, Node* node) { } void ModCtGeneric_beforeComputeType(Nest_Modifier*, Node* node) { - /// Check to apply only to classes or functions + /// Check to apply only to functions if (node->nodeKind != nkSparrowDeclSprFunction) { REP_ERROR(node->location, "ctGeneric modifier can be applied only to functions (applied to %1%)") % @@ -74,20 +74,20 @@ void ModConvert_beforeComputeType(Nest_Modifier*, Node* node) { } void ModNoDefault_beforeComputeType(Nest_Modifier*, Node* node) { - /// Check to apply only to classes or functions + /// Check to apply only to datatypes or functions if (node->nodeKind != nkSparrowDeclSprFunction && node->nodeKind != nkSparrowDeclSprDatatype) REP_INTERNAL(node->location, - "noDefault modifier can be applied only to classes or methods (applied to %1%)") % + "noDefault modifier can be applied only to datatypes or functions (applied to %1%)") % Nest_nodeKindName(node); Nest_setPropertyInt(node, propNoDefault, 1); } void ModInitCtor_beforeComputeType(Nest_Modifier*, Node* node) { - /// Check to apply only to classes + /// Check to apply only to datatypes if (node->nodeKind != nkSparrowDeclSprDatatype) { REP_ERROR(node->location, - "initCtor modifier can be applied only to classes (applied to %1%)") % + "initCtor modifier can be applied only to datatypes (applied to %1%)") % Nest_nodeKindName(node); return; } @@ -95,6 +95,18 @@ void ModInitCtor_beforeComputeType(Nest_Modifier*, Node* node) { Nest_setPropertyInt(node, propGenerateInitCtor, 1); } +void ModBitCopiable_beforeComputeType(Nest_Modifier*, Node* node) { + /// Check to apply only to datatypes + if (node->nodeKind != nkSparrowDeclSprDatatype) { + REP_ERROR(node->location, + "bitcopiable modifier can be applied only to datatypes (applied to %1%)") % + Nest_nodeKindName(node); + return; + } + + Nest_setPropertyInt(node, propBitCopiable, 1); +} + void ModMacro_beforeComputeType(Nest_Modifier*, Node* node) { /// Check to apply only to functions if (node->nodeKind != nkSparrowDeclSprFunction) { @@ -127,6 +139,7 @@ Nest_Modifier _ctGenericMod = {modTypeBeforeComputeType, &ModCtGeneric_beforeCom Nest_Modifier _convertMod = {modTypeBeforeComputeType, &ModConvert_beforeComputeType}; Nest_Modifier _noDefaultMod = {modTypeBeforeComputeType, &ModNoDefault_beforeComputeType}; Nest_Modifier _initCtorMod = {modTypeBeforeComputeType, ModInitCtor_beforeComputeType}; +Nest_Modifier _bitCopiableMod = {modTypeBeforeComputeType, &ModBitCopiable_beforeComputeType}; Nest_Modifier _macroMod = {modTypeBeforeComputeType, &ModMacro_beforeComputeType}; Nest_Modifier _noInlineMod = {modTypeBeforeComputeType, &ModNoInline_beforeComputeType}; @@ -140,6 +153,7 @@ Nest_Modifier* SprFe_getCtGenericMod() { return &_ctGenericMod; } Nest_Modifier* SprFe_getConvertMod() { return &_convertMod; } Nest_Modifier* SprFe_getNoDefaultMod() { return &_noDefaultMod; } Nest_Modifier* SprFe_getInitCtorMod() { return &_initCtorMod; } +Nest_Modifier* SprFe_getBitCopiableMod() { return &_bitCopiableMod; } Nest_Modifier* SprFe_getMacroMod() { return &_macroMod; } Nest_Modifier* SprFe_getNoInlineMod() { return &_noInlineMod; } diff --git a/src/SparrowFrontend/Mods.h b/src/SparrowFrontend/Mods.h index 45e40a92..c05363ac 100644 --- a/src/SparrowFrontend/Mods.h +++ b/src/SparrowFrontend/Mods.h @@ -15,6 +15,7 @@ Nest_Modifier* SprFe_getNativeMod(StringRef name); Nest_Modifier* SprFe_getConvertMod(); Nest_Modifier* SprFe_getNoDefaultMod(); Nest_Modifier* SprFe_getInitCtorMod(); +Nest_Modifier* SprFe_getBitCopiableMod(); Nest_Modifier* SprFe_getMacroMod(); Nest_Modifier* SprFe_getNoInlineMod(); diff --git a/src/SparrowFrontend/Nodes/Decl.cpp b/src/SparrowFrontend/Nodes/Decl.cpp index 8bd4be76..ba7eb4f3 100644 --- a/src/SparrowFrontend/Nodes/Decl.cpp +++ b/src/SparrowFrontend/Nodes/Decl.cpp @@ -85,6 +85,8 @@ void applyModifier(NodeHandle base, NodeHandle modNode) { mod = SprFe_getNoDefaultMod(); else if (name == "initCtor") mod = SprFe_getInitCtorMod(); + else if (name == "bitcopiable") + mod = SprFe_getBitCopiableMod(); else if (name == "macro") mod = SprFe_getMacroMod(); else if (name == "noInline") @@ -633,9 +635,10 @@ Type DataTypeDecl::computeTypeImpl(DataTypeDecl node) { // Copy the "convert", "native" and "description" properties to the resulting class if (node.hasProperty(propConvert)) resultingStruct.setProperty(propConvert, 1); - if (nativeName) { + if (nativeName) resultingStruct.setProperty(propNativeName, nativeName); - } + if (node.hasProperty(propBitCopiable)) + resultingStruct.setProperty(propBitCopiable, 1); auto description = node.getPropertyString(propDescription); if (description) resultingStruct.setProperty(propDescription, *description); @@ -883,11 +886,13 @@ Type SprFunctionDecl::computeTypeImpl(SprFunctionDecl node) { REP_INTERNAL(loc, "Cannot compute the function resulting type"); resType = resType.changeMode(thisEvalMode, loc); - // If the result is a non-reference class, not basic numeric, and our function is not native, - // add result parameter; otherwise, normal result - bool nativeAbi = nativeName && nativeName != "$funptr"; - if (!nativeAbi && resType.hasStorage() && resType.numReferences() == 0 && - !Feather_isBasicNumericType(resType)) { + // If the result is a non-reference, non bitcopiable datatype, not basic numeric, + // and our function is not native, add result parameter; otherwise, normal result + bool preserveRetAbi = !resType.hasStorage(); + preserveRetAbi = preserveRetAbi || resType.numReferences() > 0; + preserveRetAbi = preserveRetAbi || isBitCopiable(resType); + preserveRetAbi = preserveRetAbi || (nativeName && nativeName != "$funptr"); + if (!preserveRetAbi) { ASSERT(returnType); const Location& retLoc = returnType.location(); auto resParam = Feather::VarDecl::create(retLoc, StringRef("_result"), diff --git a/src/SparrowFrontend/Nodes/SprProperties.h b/src/SparrowFrontend/Nodes/SprProperties.h index 8ca81972..9e967716 100644 --- a/src/SparrowFrontend/Nodes/SprProperties.h +++ b/src/SparrowFrontend/Nodes/SprProperties.h @@ -20,4 +20,5 @@ constexpr const char* propSprGivenType = "spr.givenType"; constexpr const char* propSprLiteralType = "spr.literalType"; constexpr const char* propSprLiteralData = "spr.literalData"; constexpr const char* propSprOperation = "spr.operation"; +constexpr const char* propBitCopiable = "spr.bitcopiable"; } // namespace SprFrontend diff --git a/tests/Basic/datatype/bitcopiable.spr b/tests/Basic/datatype/bitcopiable.spr new file mode 100644 index 00000000..0e8ac2c2 --- /dev/null +++ b/tests/Basic/datatype/bitcopiable.spr @@ -0,0 +1,148 @@ +//!! -t "../SparrowImplicitLib.spr" -fno-main +// -dump-assembly + +// Test purpose: checks that certain types are bitcopiable, meaning they do not need copy ctors when +// passed as arguments or returned from functions + +injectBackendCode(" +%struct.IntPtr = type { i32* } + +declare i8* @malloc(i64) nounwind +declare void @free(i8*) nounwind + +define void @storeVal(i32*, i32) nounwind +{ + %3 = alloca %struct.IntPtr, align 8 + %4 = alloca i32, align 4 + %5 = getelementptr inbounds %struct.IntPtr, %struct.IntPtr* %3, i32 0, i32 0 + store i32* %0, i32** %5, align 8 + store i32 %1, i32* %4, align 4 + %6 = load i32, i32* %4, align 4 + %7 = getelementptr inbounds %struct.IntPtr, %struct.IntPtr* %3, i32 0, i32 0 + %8 = load i32*, i32** %7, align 8 + store i32 %6, i32* %8, align 4 + ret void +} + +define i32 @loadVal(i32*) nounwind +{ + %2 = alloca %struct.IntPtr, align 8 + %3 = getelementptr inbounds %struct.IntPtr, %struct.IntPtr* %2, i32 0, i32 0 + store i32* %0, i32** %3, align 8 + %4 = getelementptr inbounds %struct.IntPtr, %struct.IntPtr* %2, i32 0, i32 0 + %5 = load i32*, i32** %4, align 8 + %6 = load i32, i32* %5, align 4 + ret i32 %6 +} +define i32* @allocIntPtr() nounwind +{ + %1 = alloca %struct.IntPtr, align 8 + %2 = call i8* @malloc(i64 4) #6 + %3 = bitcast i8* %2 to i32* + %4 = getelementptr inbounds %struct.IntPtr, %struct.IntPtr* %1, i32 0, i32 0 + store i32* %3, i32** %4, align 8 + %5 = getelementptr inbounds %struct.IntPtr, %struct.IntPtr* %1, i32 0, i32 0 + %6 = load i32*, i32** %5, align 8 + ret i32* %6 +} +define void @freeIntPtr(i32*) nounwind +{ + %2 = alloca %struct.IntPtr, align 8 + %3 = getelementptr inbounds %struct.IntPtr, %struct.IntPtr* %2, i32 0, i32 0 + store i32* %0, i32** %3, align 8 + %4 = getelementptr inbounds %struct.IntPtr, %struct.IntPtr* %2, i32 0, i32 0 + %5 = load i32*, i32** %4, align 8 + %6 = bitcast i32* %5 to i8* + call void @free(i8* %6) + ret void +} +") + +[bitcopiable] +datatype IntPtr + ptr: @Int + +[native("storeVal")] fun storeVal(p: IntPtr, val: Int) +[native("loadVal")] fun loadVal(p: IntPtr): Int +[native("allocIntPtr")] fun allocIntPtr(): IntPtr +[native("freeIntPtr")] fun freeIntPtr(p: IntPtr) + +fun storeVal1(p: IntPtr, val: Int) + p.ptr = val +fun loadVal1(p: IntPtr): Int + return p.ptr +fun allocIntPtr1(): IntPtr + var p: IntPtr + p.ptr := reinterpretCast(@Int, malloc(sizeOf(Int))) + return p +fun freeIntPtr1(p: IntPtr) + free(reinterpretCast(@Byte, p.ptr)) + +package _Impl0 + datatype FunctionPtr0(resT: Type) + using arity = 0 + using ResT = resT + _funPtr: @Byte + + [native("$funptr")] fun _doCall(this: @FunctionPtr0): ResT + fun ()(this: @FunctionPtr0): ResT = this._doCall() + +using FunctionPtr = _Impl0.FunctionPtr0 + +[native("test")] fun test(n: Int) + var p1 = allocIntPtr() + var p2 = allocIntPtr() + + storeVal(p1, 17) + storeVal(p2, 19) + writeLn(loadVal(p1)) + writeLn(loadVal(p2)) + freeIntPtr(p1) + freeIntPtr(p2) + + writeLn('---') + + p1 = allocIntPtr1() + p2 = allocIntPtr1() + storeVal1(p1, 23) + storeVal1(p2, 29) + writeLn(loadVal1(p1)) + writeLn(loadVal1(p2)) + freeIntPtr1(p1) + freeIntPtr1(p2) + + writeLn('---') + if typeOf(\allocIntPtr) != typeOf(\allocIntPtr1) + writeLn('FAILURE') + + var allocFunPtr: typeOf(\allocIntPtr) = \allocIntPtr1 + p1 = allocFunPtr() + p2 = allocFunPtr() + storeVal(p1, 31) + storeVal(p2, 37) + writeLn(loadVal(p1)) + writeLn(loadVal(p2)) + freeIntPtr(p1) + freeIntPtr(p2) + + allocFunPtr = \allocIntPtr + p1 = allocFunPtr() + p2 = allocFunPtr() + storeVal(p1, 41) + storeVal(p2, 43) + writeLn(loadVal(p1)) + writeLn(loadVal(p2)) + freeIntPtr(p1) + freeIntPtr(p2) +/*<<>>*/ diff --git a/tests/tests.in b/tests/tests.in index 19265de9..b9ebbd74 100644 --- a/tests/tests.in +++ b/tests/tests.in @@ -140,6 +140,7 @@ Basic/datatype/storage.spr: Basic features - datatype - storage Basic/datatype/interaction.spr: Basic features - datatype - various interaction patterns Basic/datatype/generic.spr: Basic features - datatype - basic generics test Basic/datatype/initCtor.spr: Basic features - datatype - initCtor +Basic/datatype/bitcopiable.spr: Basic features - datatype - bitcopiable Basic/exp/dotOper.spr: Basic features - expressions - dot operator Imports/ImportTwice.spr: Import twice the same file From 332e58ec91e872215574b006c455a0c0a845be1f Mon Sep 17 00:00:00 2001 From: Lucian Radu Teodorescu Date: Sun, 21 Apr 2019 21:16:17 +0300 Subject: [PATCH 2/6] Make basic types bitcopiable The logic now checks for bitcopiable instead of native types. Remove Feather_isBasicNumericType() --- SparrowImplicitLib/sprCore/basicDecls.spr | 37 ++++++++++--------- src/Feather/Utils/FeatherUtils.h | 3 -- src/Feather/src/Utils/FeatherUtils.cpp | 11 ------ src/SparrowFrontend/Helpers/SprTypeTraits.cpp | 5 +-- tests/Basic/SparrowImplicitLib.spr | 37 ++++++++++--------- 5 files changed, 39 insertions(+), 54 deletions(-) diff --git a/SparrowImplicitLib/sprCore/basicDecls.spr b/SparrowImplicitLib/sprCore/basicDecls.spr index 6c0dd94b..b437111a 100644 --- a/SparrowImplicitLib/sprCore/basicDecls.spr +++ b/SparrowImplicitLib/sprCore/basicDecls.spr @@ -3,7 +3,7 @@ /// Most basic types [ct] - [native("Type"), noDefault] + [bitcopiable, native("Type"), noDefault] datatype Type {} [ct, protected] @@ -14,22 +14,22 @@ [noDefault] datatype Uninitialized {} - [native("Null")] datatype Null {} - - [native("i1")] datatype Bool {} - [native("i8")] datatype Byte {} - [convert, native("u8")] datatype UByte {} - [convert, native("i16")] datatype Short {} - [convert, native("u16")] datatype UShort {} - [convert, native("i32")] datatype Int {} - [convert, native("u32")] datatype UInt {} - [convert, native("i64")] datatype Long {} - [convert, native("u64")] datatype ULong {} - [convert, native("u64")] datatype SizeType {} - [convert, native("i64")] datatype DiffType {} - [convert, native("float")] datatype Float {} - [convert, native("double")] datatype Double {} - [native("i8")] datatype Char {} + [bitcopiable, native("Null")] datatype Null {} + + [bitcopiable, native("i1")] datatype Bool {} + [bitcopiable, native("i8")] datatype Byte {} + [bitcopiable, convert, native("u8")] datatype UByte {} + [bitcopiable, convert, native("i16")] datatype Short {} + [bitcopiable, convert, native("u16")] datatype UShort {} + [bitcopiable, convert, native("i32")] datatype Int {} + [bitcopiable, convert, native("u32")] datatype UInt {} + [bitcopiable, convert, native("i64")] datatype Long {} + [bitcopiable, convert, native("u64")] datatype ULong {} + [bitcopiable, convert, native("u64")] datatype SizeType {} + [bitcopiable, convert, native("i64")] datatype DiffType {} + [bitcopiable, convert, native("float")] datatype Float {} + [bitcopiable, convert, native("double")] datatype Double {} + [bitcopiable, native("i8")] datatype Char {} [protected] fun ctor(this: Uninitialized) {} @@ -625,7 +625,7 @@ using oper_assoc_:= = -1 /// /// String class that DOES NOT have ownership of the characters; it simply refers to another string -[native("StringRef")] +[bitcopiable, native("StringRef")] datatype StringRef using RetType = @Char @@ -740,6 +740,7 @@ fun construct() /// Type used to represent an untyped pointer +[bitcopiable] datatype UntypedPtr = @Byte [autoCt] diff --git a/src/Feather/Utils/FeatherUtils.h b/src/Feather/Utils/FeatherUtils.h index d85db5f5..f8210e07 100644 --- a/src/Feather/Utils/FeatherUtils.h +++ b/src/Feather/Utils/FeatherUtils.h @@ -129,9 +129,6 @@ int Feather_isCt(Nest_Node* node); /// Tests if the given node has a "Testable" type int Feather_isTestable(Nest_Node* node); -/// Checks if the given type is a basic numeric type (bool, integral, floating point, char) -int Feather_isBasicNumericType(Nest_TypeRef type); - //! Combines two modes together. //! If one of the modes is modeCt, the result will be modeCt //! If one of the given modes is unspecified, we return the other one diff --git a/src/Feather/src/Utils/FeatherUtils.cpp b/src/Feather/src/Utils/FeatherUtils.cpp index 2261cfe0..1d4c9e30 100644 --- a/src/Feather/src/Utils/FeatherUtils.cpp +++ b/src/Feather/src/Utils/FeatherUtils.cpp @@ -38,17 +38,6 @@ int _isTestable(Type type) { int Feather_isTestable(Node* node) { return _isTestable(node->type); } -int Feather_isBasicNumericType(Nest::TypeRef type) { - if (!type || !type->hasStorage) - return false; - StringRef nativeName = Feather_nativeName(type); - return !nativeName.empty() && - (nativeName == "i1" || nativeName == "u1" || nativeName == "i8" || nativeName == "u8" || - nativeName == "i16" || nativeName == "u16" || nativeName == "i32" || - nativeName == "u32" || nativeName == "i64" || nativeName == "u64" || - nativeName == "float" || nativeName == "double"); -} - EvalMode Feather_combineMode(EvalMode mode1, EvalMode mode2) { if (mode1 == modeCt || mode2 == modeCt) return modeCt; diff --git a/src/SparrowFrontend/Helpers/SprTypeTraits.cpp b/src/SparrowFrontend/Helpers/SprTypeTraits.cpp index d6cbe901..d2a2696b 100644 --- a/src/SparrowFrontend/Helpers/SprTypeTraits.cpp +++ b/src/SparrowFrontend/Helpers/SprTypeTraits.cpp @@ -252,7 +252,7 @@ Node* SprFrontend::convertCtToRt(Node* node) { if (t.numReferences() > 0) REP_ERROR_RET(nullptr, loc, "Cannot convert references from CT to RT (%1%)") % t; - if (Feather_isBasicNumericType(t) || Type(t).changeMode(modeRt, NOLOC) == StdDef::typeStringRef) + if (isBitCopiable(t)) return Nest_ctEval(node); else return checkDataTypeCtToRtConversion(node); @@ -320,8 +320,5 @@ Type SprFrontend::changeRefCount(Type type, int numRef, const Location& loc) { bool SprFrontend::isBitCopiable(Type type) { if (!type.hasStorage()) return false; - // TODO: Remove this - if (Feather_isBasicNumericType(type)) - return true; return type.referredNode() && type.referredNode().hasProperty(propBitCopiable); } diff --git a/tests/Basic/SparrowImplicitLib.spr b/tests/Basic/SparrowImplicitLib.spr index c2357b10..2ebd0f96 100644 --- a/tests/Basic/SparrowImplicitLib.spr +++ b/tests/Basic/SparrowImplicitLib.spr @@ -818,7 +818,7 @@ define void @_Type_copy_ctor(i8** %$this, i8* %other) ); [ct] - [native("Type"), noDefault] + [bitcopiable, native("Type"), noDefault] datatype Type {} [ct, protected] @@ -829,22 +829,22 @@ define void @_Type_copy_ctor(i8** %$this, i8* %other) [noDefault] datatype Uninitialized {} - [native("Null")] datatype Null {} - - [native("i1")] datatype Bool {} - [native("i8")] datatype Byte {} - [convert, native("u8")] datatype UByte {} - [convert, native("i16")] datatype Short {} - [convert, native("u16")] datatype UShort {} - [convert, native("i32")] datatype Int {} - [convert, native("u32")] datatype UInt {} - [convert, native("i64")] datatype Long {} - [convert, native("u64")] datatype ULong {} - [convert, native("u64")] datatype SizeType {} - [convert, native("i64")] datatype DiffType {} - [convert, native("float")] datatype Float {} - [convert, native("double")] datatype Double {} - [native("i8")] datatype Char {} + [bitcopiable, native("Null")] datatype Null {} + + [bitcopiable, native("i1")] datatype Bool {} + [bitcopiable, native("i8")] datatype Byte {} + [bitcopiable, convert, native("u8")] datatype UByte {} + [bitcopiable, convert, native("i16")] datatype Short {} + [bitcopiable, convert, native("u16")] datatype UShort {} + [bitcopiable, convert, native("i32")] datatype Int {} + [bitcopiable, convert, native("u32")] datatype UInt {} + [bitcopiable, convert, native("i64")] datatype Long {} + [bitcopiable, convert, native("u64")] datatype ULong {} + [bitcopiable, convert, native("u64")] datatype SizeType {} + [bitcopiable, convert, native("i64")] datatype DiffType {} + [bitcopiable, convert, native("float")] datatype Float {} + [bitcopiable, convert, native("double")] datatype Double {} + [bitcopiable, native("i8")] datatype Char {} [protected] fun ctor(this: Uninitialized) {} @@ -1072,7 +1072,7 @@ define void @_Type_copy_ctor(i8** %$this, i8* %other) -[noDefault, native("StringRef")] +[noDefault, bitcopiable, native("StringRef")] datatype StringRef begin: @Byte; end: @Byte; @@ -1424,6 +1424,7 @@ using oper_assoc_:= = -1; [native("atoi")] fun _atoi(str: @Char): Int +[bitcopiable] datatype _CStr { cstr: @Char; } [initCtor] datatype _CStrPtr { ptr: @_CStr; } From 00167b78674533f50b80dfa1bddfab97ca81a5af Mon Sep 17 00:00:00 2001 From: Lucian Radu Teodorescu Date: Sun, 21 Apr 2019 21:32:40 +0300 Subject: [PATCH 3/6] Add test to prove bitcopiable doesn't call copy ctor for returned types --- tests/Basic/datatype/bitcopiable.spr | 30 +++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/tests/Basic/datatype/bitcopiable.spr b/tests/Basic/datatype/bitcopiable.spr index 0e8ac2c2..27a3d678 100644 --- a/tests/Basic/datatype/bitcopiable.spr +++ b/tests/Basic/datatype/bitcopiable.spr @@ -89,7 +89,7 @@ package _Impl0 using FunctionPtr = _Impl0.FunctionPtr0 -[native("test")] fun test(n: Int) +fun testBinCompat var p1 = allocIntPtr() var p2 = allocIntPtr() @@ -134,6 +134,31 @@ using FunctionPtr = _Impl0.FunctionPtr0 writeLn(loadVal(p2)) freeIntPtr(p1) freeIntPtr(p2) + +[bitcopiable] +datatype Printer + +fun ctor(this: Printer) + writeLn('Printer.ctor') +fun ctor(this, other: Printer) + writeLn('Printer.copy ctor') +fun dtor(this, other: Printer) + writeLn('Printer.copy ctor') + +fun creator = Printer() // should not call copy ctor + +fun takingAsParam(x: Printer) + ; + // currently calls copy ctor + +fun printerTest + var obj = creator() + takingAsParam(obj) + +[native("test")] fun test(n: Int) + testBinCompat + writeLn('------') + printerTest /*<<>>*/ From 8647cd8707cc35f57e81d83cb729a68041f571a6 Mon Sep 17 00:00:00 2001 From: Lucian Radu Teodorescu Date: Tue, 23 Apr 2019 00:08:41 +0300 Subject: [PATCH 4/6] Add method to query if a type is bitcopiable Add test to this feature. Make Vector use memcpy if copying bitcopiable types. --- SparrowImplicitLib/sprCore/basicDecls.spr | 1 + SparrowImplicitLib/std/vector.spr | 11 +-- .../Helpers/Impl/Intrinsics.cpp | 9 +++ tests/Basic/datatype/queryBitcopiable.spr | 68 +++++++++++++++++++ tests/StdLib/VectorTest.spr | 41 ++++++++++- tests/tests.in | 1 + 6 files changed, 126 insertions(+), 5 deletions(-) create mode 100644 tests/Basic/datatype/queryBitcopiable.spr diff --git a/SparrowImplicitLib/sprCore/basicDecls.spr b/SparrowImplicitLib/sprCore/basicDecls.spr index b437111a..4ce2a3f4 100644 --- a/SparrowImplicitLib/sprCore/basicDecls.spr +++ b/SparrowImplicitLib/sprCore/basicDecls.spr @@ -768,6 +768,7 @@ package TypeOp [native("$typeNumRef")] fun numRef(t: Type): Int [native("$typeChangeMode")] fun changeMode(t: Type, mode: Int): Type [native("$typeChangeRefCount")] fun changeRefCount(t: Type, numRef: Int): Type + [native("$typeIsBitcopiable")] fun isBitcopiable(t: Type): Bool [ctGeneric] fun isRef(t: Type) = 0>>*/ diff --git a/tests/StdLib/VectorTest.spr b/tests/StdLib/VectorTest.spr index 245a5624..66e9a49a 100644 --- a/tests/StdLib/VectorTest.spr +++ b/tests/StdLib/VectorTest.spr @@ -2,7 +2,7 @@ import std.vector(Vector); import std.contiguousMemoryRange(ContiguousMemoryRange); import std.rawPtr(RawPtr, allocRawPtr); -import std.ranges(.., rangeSize, repeat, skip, take); +import std.ranges(.., rangeSize, repeat, skip, take, map); import std.algorithms(equal); import std.tuple; import check; @@ -35,6 +35,23 @@ fun sprMain return true; }) ~ "vector's copy constructor"; + forAll(DataVec arbitrary) check (fun (vec: DataVec): Bool { + copyCtorCnt = 0 + + var vec2: DataVec = vec + + if vec2.isEmpty != vec.isEmpty + return false + if vec2.size != vec.size + return false + for i = 0..vec.size + if vec2(i) != vec(i) + return false + if copyCtorCnt != 0 + return false; + return true + }) ~ "vector's copy constructor (Data); no copy ctor"; + forAll(SizeType) check (fun sz: Bool { var vec: Vec = sz; if ( vec.size != sz ) return false; @@ -338,3 +355,25 @@ fun arbitrary(t: Type): InsertRangeTestData Gen if t == InsertRangeTestData { })); } +using DataVec = Data Vector + +[initCtor, bitcopiable] +datatype Data + x: Int + +fun >>(this: @Data, os: @OutStream) + os << 'Data(' << x << ')\n' + + +fun ctor(this: @Data, other: Data) + copyCtorCnt++ + +var copyCtorCnt = 0 + +fun arbitrary(t: Type): DataVec Gen if t == DataVec + return mkGen(DataVec, \generateDataVec) + +fun generateDataVec(sizeHint: UInt): DataVec + return DataVec(generateVec(sizeHint).all map (fun x = Data(x))) + + diff --git a/tests/tests.in b/tests/tests.in index b9ebbd74..05cd0914 100644 --- a/tests/tests.in +++ b/tests/tests.in @@ -141,6 +141,7 @@ Basic/datatype/interaction.spr: Basic features - datatype - various inte Basic/datatype/generic.spr: Basic features - datatype - basic generics test Basic/datatype/initCtor.spr: Basic features - datatype - initCtor Basic/datatype/bitcopiable.spr: Basic features - datatype - bitcopiable +Basic/datatype/queryBitcopiable.spr: Basic features - datatype - query bitcopiable Basic/exp/dotOper.spr: Basic features - expressions - dot operator Imports/ImportTwice.spr: Import twice the same file From 2088839fc1aee40c7827dcc68028743f4630302c Mon Sep 17 00:00:00 2001 From: Lucian Radu Teodorescu Date: Fri, 26 Apr 2019 12:52:51 +0300 Subject: [PATCH 5/6] Add support for 'autoBitcopiable' An autoBitcopiable datatype will be bitcopiable if all the inner types are bitcopiable. --- SparrowImplicitLib/std/tuple.spr | 18 ++++----- src/SparrowFrontend/Mods.cpp | 14 +++++++ src/SparrowFrontend/Mods.h | 1 + src/SparrowFrontend/Nodes/Decl.cpp | 13 ++++++ src/SparrowFrontend/Nodes/SprProperties.h | 1 + tests/Basic/datatype/autoBitcopiable.spr | 49 +++++++++++++++++++++++ tests/tests.in | 1 + 7 files changed, 88 insertions(+), 9 deletions(-) create mode 100644 tests/Basic/datatype/autoBitcopiable.spr diff --git a/SparrowImplicitLib/std/tuple.spr b/SparrowImplicitLib/std/tuple.spr index be2f19fe..ceaf4145 100644 --- a/SparrowImplicitLib/std/tuple.spr +++ b/SparrowImplicitLib/std/tuple.spr @@ -8,25 +8,25 @@ concept TupleType(x) if ( using oper_precedence_~ = oper_precedence_* -[initCtor] datatype Tuple(t1, t2: Type) +[initCtor, autoBitcopiable] datatype Tuple(t1, t2: Type) using arity = 2 v1: t1 v2: t2 -[initCtor] datatype Tuple(t1, t2, t3: Type) +[initCtor, autoBitcopiable] datatype Tuple(t1, t2, t3: Type) using arity = 3 v1: t1 v2: t2 v3: t3 -[initCtor] datatype Tuple(t1, t2, t3, t4: Type) +[initCtor, autoBitcopiable] datatype Tuple(t1, t2, t3, t4: Type) using arity = 4 v1: t1 v2: t2 v3: t3 v4: t4 -[initCtor] datatype Tuple(t1, t2, t3, t4, t5: Type) +[initCtor, autoBitcopiable] datatype Tuple(t1, t2, t3, t4, t5: Type) using arity = 5 v1: t1 v2: t2 @@ -34,7 +34,7 @@ using oper_precedence_~ = oper_precedence_* v4: t4 v5: t5 -[initCtor] datatype Tuple(t1, t2, t3, t4, t5, t6: Type) +[initCtor, autoBitcopiable] datatype Tuple(t1, t2, t3, t4, t5, t6: Type) using arity = 6 v1: t1 v2: t2 @@ -43,7 +43,7 @@ using oper_precedence_~ = oper_precedence_* v5: t5 v6: t6 -[initCtor] datatype Tuple(t1, t2, t3, t4, t5, t6, t7: Type) +[initCtor, autoBitcopiable] datatype Tuple(t1, t2, t3, t4, t5, t6, t7: Type) using arity = 7 v1: t1 v2: t2 @@ -53,7 +53,7 @@ using oper_precedence_~ = oper_precedence_* v6: t6 v7: t7 -[initCtor] datatype Tuple(t1, t2, t3, t4, t5, t6, t7, t8: Type) +[initCtor, autoBitcopiable] datatype Tuple(t1, t2, t3, t4, t5, t6, t7, t8: Type) using arity = 8 v1: t1 v2: t2 @@ -64,7 +64,7 @@ using oper_precedence_~ = oper_precedence_* v7: t7 v8: t8 -[initCtor] datatype Tuple(t1, t2, t3, t4, t5, t6, t7, t8, t9: Type) +[initCtor, autoBitcopiable] datatype Tuple(t1, t2, t3, t4, t5, t6, t7, t8, t9: Type) using arity = 9 v1: t1 v2: t2 @@ -76,7 +76,7 @@ using oper_precedence_~ = oper_precedence_* v8: t8 v9: t9 -[initCtor] datatype Tuple(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10: Type) +[initCtor, autoBitcopiable] datatype Tuple(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10: Type) using arity = 10 v1: t1 v2: t2 diff --git a/src/SparrowFrontend/Mods.cpp b/src/SparrowFrontend/Mods.cpp index 3fc72772..d2ad6f72 100644 --- a/src/SparrowFrontend/Mods.cpp +++ b/src/SparrowFrontend/Mods.cpp @@ -107,6 +107,18 @@ void ModBitCopiable_beforeComputeType(Nest_Modifier*, Node* node) { Nest_setPropertyInt(node, propBitCopiable, 1); } +void ModAutoBitCopiable_beforeComputeType(Nest_Modifier*, Node* node) { + /// Check to apply only to datatypes + if (node->nodeKind != nkSparrowDeclSprDatatype) { + REP_ERROR(node->location, + "autoBitcopiable modifier can be applied only to datatypes (applied to %1%)") % + Nest_nodeKindName(node); + return; + } + + Nest_setPropertyInt(node, propAutoBitCopiable, 1); +} + void ModMacro_beforeComputeType(Nest_Modifier*, Node* node) { /// Check to apply only to functions if (node->nodeKind != nkSparrowDeclSprFunction) { @@ -140,6 +152,7 @@ Nest_Modifier _convertMod = {modTypeBeforeComputeType, &ModConvert_beforeCompute Nest_Modifier _noDefaultMod = {modTypeBeforeComputeType, &ModNoDefault_beforeComputeType}; Nest_Modifier _initCtorMod = {modTypeBeforeComputeType, ModInitCtor_beforeComputeType}; Nest_Modifier _bitCopiableMod = {modTypeBeforeComputeType, &ModBitCopiable_beforeComputeType}; +Nest_Modifier _autoBitCopiableMod = {modTypeBeforeComputeType, &ModAutoBitCopiable_beforeComputeType}; Nest_Modifier _macroMod = {modTypeBeforeComputeType, &ModMacro_beforeComputeType}; Nest_Modifier _noInlineMod = {modTypeBeforeComputeType, &ModNoInline_beforeComputeType}; @@ -154,6 +167,7 @@ Nest_Modifier* SprFe_getConvertMod() { return &_convertMod; } Nest_Modifier* SprFe_getNoDefaultMod() { return &_noDefaultMod; } Nest_Modifier* SprFe_getInitCtorMod() { return &_initCtorMod; } Nest_Modifier* SprFe_getBitCopiableMod() { return &_bitCopiableMod; } +Nest_Modifier* SprFe_getAutoBitCopiableMod() { return &_autoBitCopiableMod; } Nest_Modifier* SprFe_getMacroMod() { return &_macroMod; } Nest_Modifier* SprFe_getNoInlineMod() { return &_noInlineMod; } diff --git a/src/SparrowFrontend/Mods.h b/src/SparrowFrontend/Mods.h index c05363ac..763fe340 100644 --- a/src/SparrowFrontend/Mods.h +++ b/src/SparrowFrontend/Mods.h @@ -16,6 +16,7 @@ Nest_Modifier* SprFe_getConvertMod(); Nest_Modifier* SprFe_getNoDefaultMod(); Nest_Modifier* SprFe_getInitCtorMod(); Nest_Modifier* SprFe_getBitCopiableMod(); +Nest_Modifier* SprFe_getAutoBitCopiableMod(); Nest_Modifier* SprFe_getMacroMod(); Nest_Modifier* SprFe_getNoInlineMod(); diff --git a/src/SparrowFrontend/Nodes/Decl.cpp b/src/SparrowFrontend/Nodes/Decl.cpp index ba7eb4f3..f58b8d78 100644 --- a/src/SparrowFrontend/Nodes/Decl.cpp +++ b/src/SparrowFrontend/Nodes/Decl.cpp @@ -87,6 +87,8 @@ void applyModifier(NodeHandle base, NodeHandle modNode) { mod = SprFe_getInitCtorMod(); else if (name == "bitcopiable") mod = SprFe_getBitCopiableMod(); + else if (name == "autoBitcopiable") + mod = SprFe_getAutoBitCopiableMod(); else if (name == "macro") mod = SprFe_getMacroMod(); else if (name == "noInline") @@ -661,6 +663,17 @@ Type DataTypeDecl::computeTypeImpl(DataTypeDecl node) { NodeVector fields = getFields(node.childrenContext()->currentSymTab); resultingStruct.addChildren(all(fields)); + // Check for autoBitcopiable + if ( node.hasProperty(propAutoBitCopiable)) { + bool allAreBitcopiable = true; + for (auto f : fields) { + ASSERT(f->type); + allAreBitcopiable = allAreBitcopiable && isBitCopiable(f->type); + } + if (allAreBitcopiable) + resultingStruct.setProperty(propBitCopiable, 1); + } + // Check all the members if (body) { body.computeType(); // Ignore local errors diff --git a/src/SparrowFrontend/Nodes/SprProperties.h b/src/SparrowFrontend/Nodes/SprProperties.h index 9e967716..3ceea572 100644 --- a/src/SparrowFrontend/Nodes/SprProperties.h +++ b/src/SparrowFrontend/Nodes/SprProperties.h @@ -21,4 +21,5 @@ constexpr const char* propSprLiteralType = "spr.literalType"; constexpr const char* propSprLiteralData = "spr.literalData"; constexpr const char* propSprOperation = "spr.operation"; constexpr const char* propBitCopiable = "spr.bitcopiable"; +constexpr const char* propAutoBitCopiable = "spr.autoBitcopiable"; } // namespace SprFrontend diff --git a/tests/Basic/datatype/autoBitcopiable.spr b/tests/Basic/datatype/autoBitcopiable.spr new file mode 100644 index 00000000..8c5a5be6 --- /dev/null +++ b/tests/Basic/datatype/autoBitcopiable.spr @@ -0,0 +1,49 @@ +//!! -t "../SparrowImplicitLib.spr" -fno-main +// -dump-assembly + +// Test purpose: checks 'autoBitcopiable' modifier works as expected + +[ct, native("$typeDescription")] fun description(t: Type): StringRef +[ct, native("$typeIsBitcopiable")] fun isBitcopiable(t: Type): Bool + +[initCtor] +datatype Data1 + x: Int + +[initCtor, bitcopiable] +datatype Data2 + x: Int + +[initCtor, autoBitcopiable] +datatype Pair(t1, t2: Type) + v1: t1 + v2: t2 + +fun printBitcopiable(t: Type) + write(description(t)) + [ct] if isBitcopiable(t) + writeLn(': bitcopiable') + else + writeLn(': regular') + +[native("test")] fun test(n: Int) + printBitcopiable(Data1) + printBitcopiable(Data2) + printBitcopiable(Pair(Data1, Data1)) + printBitcopiable(Pair(Data1, Data2)) + printBitcopiable(Pair(Data2, Data1)) + printBitcopiable(Pair(Data2, Data2)) + printBitcopiable(Int) + printBitcopiable(StringRef) + printBitcopiable(Pair(Int, StringRef)) +/*<<>>*/ diff --git a/tests/tests.in b/tests/tests.in index 05cd0914..836c624b 100644 --- a/tests/tests.in +++ b/tests/tests.in @@ -142,6 +142,7 @@ Basic/datatype/generic.spr: Basic features - datatype - basic generi Basic/datatype/initCtor.spr: Basic features - datatype - initCtor Basic/datatype/bitcopiable.spr: Basic features - datatype - bitcopiable Basic/datatype/queryBitcopiable.spr: Basic features - datatype - query bitcopiable +Basic/datatype/autoBitcopiable.spr: Basic features - datatype - auto bitcopiable Basic/exp/dotOper.spr: Basic features - expressions - dot operator Imports/ImportTwice.spr: Import twice the same file From 4696c197c5d50d4b52f36dac513920b246d17e23 Mon Sep 17 00:00:00 2001 From: Lucian Radu Teodorescu Date: Fri, 26 Apr 2019 16:11:39 +0300 Subject: [PATCH 6/6] Add documentation for modifiers --- docs/conf.py | 3 +- docs/lang/modifiers.rst | 253 ++++++++++++++++++++++++++++++++++++++++ docs/lang/operators.rst | 1 + docs/langFeatures.rst | 1 + 4 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 docs/lang/modifiers.rst diff --git a/docs/conf.py b/docs/conf.py index 95027342..086cc055 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -39,7 +39,8 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.pngmath' + 'sphinx.ext.imgmath', + 'sphinx.ext.autosectionlabel' ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/lang/modifiers.rst b/docs/lang/modifiers.rst new file mode 100644 index 00000000..50e577ec --- /dev/null +++ b/docs/lang/modifiers.rst @@ -0,0 +1,253 @@ +.. highlight:: sparrow + +Modifiers +========= + +Modifiers allow changing the semantic of Sparrow constructs. + +Example: +:: + + [initCtor] + datatype MyType + a: Int + b: Bool + + var x = MyType(13, true) + +The ``initCtor`` is a modifier that makes the ``MyType`` datatype to have an initialization constructor for the two variables. + +Syntax +------ + +.. code-block:: ebnf + + Mods = '[' Expr { ',' Expr } ']' ; + + Stmts = { Stmt } ; + Stmt = [Mods] ImportLine + | [Mods] UsingDecl + | [Mods] PackageDecl + | [Mods] DatatypeDecl + | [Mods] ConceptDecl + | [Mods] VarDecl + | [Mods] FunDecl + | [Mods] ExprStmt + | [Mods] BlockStmt + | [Mods] IfStmt + | [Mods] ForStmt + | [Mods] WhileStmt + | [Mods] BreakStmt + | [Mods] ContinueStmt + | [Mods] ReturnStmt + ; + +Predefined modifiers +-------------------- + +``public`` modifier +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Applies to + all declarations + +Semantics + Marks the declaration as being public. A public declaration can be accessed from any module. + +See + :ref:`Access modes` + +``protected`` modifier +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Applies to + all declarations + +Semantics + Marks the declaration as being protected. A protected declaration can be accessed from any module, but it will not be considered in `using` clauses without explicit names. + +See + :ref:`Access modes` + + +``private`` modifier +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Applies to + all declarations + +Semantics + Marks the declaration as being private. A private declaration can be accessed only from the current module. + +See + :ref:`Access modes` + + +``ct`` modifier +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Applies to + all declarations, `if` statements, `while` statements, `for` statements + +Semantics + Marks the declaration or statement to be executed at compile-time. A `ct` declaration will not have a runtime counterpart. A `ct` statement will be executed at compile-time; used in specializing code or code generation. + + Examples: + :: + + [ct] fun addRef(t: Type): Type // function is available only at compile-time + + [ct] + if sizeOf(t) <= sizeOf(Int) + var storage: Int + else + var storage: Long + // Depending on the size of 't', this will create different 'storage' variables + + [ct] + for x = 1..5 + doStuff(ctEval(x)) + // Will generate the following code: + // doStuff(1) + // doStuff(2) + // doStuff(3) + // doStuff(4) + + +``rt`` modifier +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Applies to + all declarations + +Semantics + Ensures the declaration has meaning both at run-time and at compile-time. The default behavior. Can be used in ``[ct]`` environments to go back to default ``[rt]`` environments + + +``autoCt`` modifier +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Applies to + functions + +Semantics + If the function is called with only with compile-time arguments, the function will be compile-time; otherwise it will be run-time. + + Example: + :: + + [autoCt] fun printVals(x, y: Int) + cout << x << ' ' << y << '\n' + + var six = 6 + var seven = 7 + + printVals(6, 7) // prints '6 7' at compile-time + printVals(six, 7) // prints '6 7' at run-time + printVals(six, seven) // prints '6 7' at run-time + +``ctGeneric`` modifier +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Applies to + functions + +Semantics + Marks the function as being both a compile-time function and a generic function. + + A regular function (non-``[ct]``) that has compile-time parameters will be a generic; it can change the semantics of its body based on the compile-time parameters, and has run-time presence. On the other hand, a function marked as ``[ct]`` is not a generic; it doesn't have any run-time presence and it cannot change the semantics of its body based on the parameters. + + A ``[ctGeneric]`` function is a combination of both: it's a compile-time function (no run-time presence) but has a different code generated for each set of parameters. + +``convert`` modifier +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Applies to + ``ctor`` functions and datatypes + +Semantics + Used to indicate that a datatype can be implicitly converted from other types through constructors marked as ``[convert]``. To convert a value from a type ``A`` to a type ``B`` implicitly, the following conditions must be met: + + * the ``B`` datatype must be declared as ``[convert]`` + * ``B`` needs to have a constructor marked as ``[convert]`` that can construct a ``B`` from values of type ``A`` + + +``noDefault`` modifier +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Applies to + datatypes, ``ctor`` and ``dtor`` functions + +Semantics + When applied to datatypes, it tells the compiler not to generate default functions for the datatype. When applied to constructors and desructors, it tells the compiler not to try to inject constructor/destructor calls for the members of the datatype. + +``initCtor`` modifier +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Applies to + datatypes + +Semantics + It instructs the compiler to generate an extra constructor to initialize all the members of the datatype. + + When generating the initialized constructor, the following are applied: + + * the initialization constructor will have a parameter for each field of the datatype + * the order of parameters in the initialization constructor will be the same as the oder in which the corresponding fields are declared in the datatype + * if the field of the datatype has an initializer, the corresponding parameters will have the same initializer + +``bitcopiable`` modifier +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Applies to + datatypes + +Semantics + It instructs the compiler that the given datatype can be safely copied bitwise (i.e., with ``memcpy``). The copy constructor will be elided whenever possible. + + Also, functions returning *bitcopiable* will not take the location in which the resulting value needs to be placed by (hidden) reference. + + For example, a ``Vector`` applied to a *bitcopiable* type can avoid calling the copy constructor + of the elements whenever resizing the data. + + The basic numeric types are all *bitcopiable*. + +``autoBitcopiable`` modifier +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Applies to + datatypes + +Semantics + Instructs the compiler to detect whether the datatype can be bitcopiable or not. A datatype with ``[autoBitcopiable]`` modifier applied will become *bitcopiable* if all the fields are also *bitcopiable*; if at least one of the fields is not *bitcopiable* then the datatype will not be *bitcopiable*. + + It is used for datatypes like ``Tuple`` to automatically become *bitcopiable* base on the field types. + +``macro`` modifier +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Applies to + functions + +Semantics + When making calls to the function, it will pass the raw AST (abstract syntax tree) nodes to the functions, without even compiling them. Used for manipulating the source code. + + Example: ``assert`` uses macros to extract the variables out of the given condition, to be able to print them whenever the assertion fails. + +``noInline`` modifier +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Applies to + functions + +Semantics + Prevents the compiler from inlining the function. + +``native`` modifier +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Applies to + functions, datatypes + +Form + ``native(`` *stringLiteral* ``)`` + +Semantics + Assigns the specified name to the given function/datatype. It does not apply any name mangling rules when generating the assembly name. + + Native datatypes are used to map types defined in the standard library onto machine types. I.e., ``[native("i32")] datatype Int`` is mapping the type ``Int`` to a signed 32-bit machine type. + + Functions that are declared native would not change their return type (non-*bitcopiable* return types are typically transformed into hidden pointer parameters). + + Typically used when interacting with other libraries. + + +User-defined modifiers +---------------------- + +TODO: not yet implemented diff --git a/docs/lang/operators.rst b/docs/lang/operators.rst index c04d5236..62d4b701 100644 --- a/docs/lang/operators.rst +++ b/docs/lang/operators.rst @@ -244,6 +244,7 @@ The compiler uses a special ``.`` operator to ease the access for some datatypes If the dot operator would not be present, then the last 4 lines would not be valid anymore. The user would have been supposed to write: :: + p.get().x = 30 // UGLIER p.get().print // UGLIER p.get print // UGLIER diff --git a/docs/langFeatures.rst b/docs/langFeatures.rst index 1947446e..c04cb7e1 100644 --- a/docs/langFeatures.rst +++ b/docs/langFeatures.rst @@ -10,5 +10,6 @@ Language features lang/generics lang/basicExpressions lang/operators + lang/modifiers This section is still under development.