From 308fa8c9657209ec469392201cfa2f9f3c66c639 Mon Sep 17 00:00:00 2001 From: Cesare Ferrari Date: Thu, 7 Nov 2024 21:59:53 +0000 Subject: [PATCH] Add support for slices of slices --- modules/compiler/src/AST/cmaj_AST.h | 2 +- .../src/AST/cmaj_AST_Classes_Values.h | 11 +- .../compiler/src/AST/cmaj_AST_StringPool.h | 2 + .../CPlusPlus/cmaj_CPlusPlusGenerator.cpp | 19 ++- .../src/backends/LLVM/cmaj_LLVMGenerator.h | 26 ++++ .../compiler/src/codegen/cmaj_CodeGenerator.h | 30 ++-- .../src/codegen/cmaj_ProgramPrinter.h | 2 +- .../compiler/src/passes/cmaj_ConstantFolder.h | 2 +- .../src/passes/cmaj_StrengthReduction.h | 2 +- .../compiler/src/passes/cmaj_TypeResolver.h | 4 +- .../cmaj_ConvertComplexTypes.h | 4 +- .../cmaj_ReplaceMultidimensionalArrays.h | 2 +- .../transformations/cmaj_TransformSlices.h | 130 ++++++++++++++++++ .../transformations/cmaj_Transformations.cpp | 2 + .../src/validation/cmaj_ValidationUtilities.h | 2 +- .../compiler/src/validation/cmaj_Validator.h | 13 +- .../cmaj_test_not_yet_implemented.cmajtest | 32 ----- .../language_tests/cmaj_test_slices.cmajtest | 87 ++++++++++++ 18 files changed, 305 insertions(+), 67 deletions(-) create mode 100644 modules/compiler/src/transformations/cmaj_TransformSlices.h create mode 100644 tests/language_tests/cmaj_test_slices.cmajtest diff --git a/modules/compiler/src/AST/cmaj_AST.h b/modules/compiler/src/AST/cmaj_AST.h index 7f548063..f31702a8 100644 --- a/modules/compiler/src/AST/cmaj_AST.h +++ b/modules/compiler/src/AST/cmaj_AST.h @@ -100,7 +100,7 @@ using ref = choc::ObjectReference; X(ForwardBranch) \ X(Function) \ X(FunctionCall) \ - X(GetArraySlice) \ + X(GetArrayOrVectorSlice) \ X(GetElement) \ X(GetStructMember) \ X(Graph) \ diff --git a/modules/compiler/src/AST/cmaj_AST_Classes_Values.h b/modules/compiler/src/AST/cmaj_AST_Classes_Values.h index 52b1a56a..6fa4264c 100644 --- a/modules/compiler/src/AST/cmaj_AST_Classes_Values.h +++ b/modules/compiler/src/AST/cmaj_AST_Classes_Values.h @@ -1370,11 +1370,11 @@ struct GetElement : public ValueBase }; //============================================================================== -struct GetArraySlice : public ValueBase +struct GetArrayOrVectorSlice : public ValueBase { - GetArraySlice (const ObjectContext& c) : ValueBase (c) {} + GetArrayOrVectorSlice (const ObjectContext& c) : ValueBase (c) {} - CMAJ_AST_DECLARE_STANDARD_METHODS(GetArraySlice, 34) + CMAJ_AST_DECLARE_STANDARD_METHODS(GetArrayOrVectorSlice, 34) ptr getSourceVariable() const override { @@ -1404,6 +1404,11 @@ struct GetArraySlice : public ValueBase return result; } } + else + { + if (auto arrayType = parentType->getAsArrayType()) + return createSliceOfType (context, arrayType->getInnermostElementTypeRef()); + } } } diff --git a/modules/compiler/src/AST/cmaj_AST_StringPool.h b/modules/compiler/src/AST/cmaj_AST_StringPool.h index 1ee7e518..b64387ec 100644 --- a/modules/compiler/src/AST/cmaj_AST_StringPool.h +++ b/modules/compiler/src/AST/cmaj_AST_StringPool.h @@ -123,6 +123,8 @@ struct Strings out { stringPool.get ("out") }, value { stringPool.get ("value") }, index { stringPool.get ("index") }, + start { stringPool.get ("start") }, + end { stringPool.get ("end") }, array { stringPool.get ("array") }, run { stringPool.get ("run") }, increment { stringPool.get ("increment") }, diff --git a/modules/compiler/src/backends/CPlusPlus/cmaj_CPlusPlusGenerator.cpp b/modules/compiler/src/backends/CPlusPlus/cmaj_CPlusPlusGenerator.cpp index 8eb1366f..2b5c0029 100644 --- a/modules/compiler/src/backends/CPlusPlus/cmaj_CPlusPlusGenerator.cpp +++ b/modules/compiler/src/backends/CPlusPlus/cmaj_CPlusPlusGenerator.cpp @@ -1599,6 +1599,15 @@ struct EndpointInfo return createReaderNoParensNeeded (typeName + " { " + sourceExpression + " }"); } + ValueReader createSliceOfSlice (const AST::TypeBase& elementType, ValueReader sourceSlice, ValueReader start, ValueReader end) + { + (void) elementType; + + return createReaderNoParensNeeded (sourceSlice.getWithoutParens() + ".slice (" + + start.getWithoutParens() + ", " + + end.getWithoutParens() + ")"); + } + ValueReader createSliceFromArray (const AST::TypeBase& elementType, ValueReader sourceArray, uint32_t offset, uint32_t numElements) { @@ -2010,9 +2019,13 @@ struct Slice ElementType operator[] (IndexType index) const noexcept { return numElements == 0 ? ElementType() : elements[index]; } ElementType& operator[] (IndexType index) noexcept { return numElements == 0 ? emptyValue : elements[index]; } - Slice slice (IndexType start, IndexType end) noexcept { if (numElements == 0) return {}; return { elements + start, end }; } - Slice sliceFrom (IndexType start) noexcept { if (numElements == 0) return {}; return { elements + start, numElements - start }; } - Slice sliceUpTo (IndexType end) noexcept { if (numElements == 0) return {}; return { elements, end }; } + Slice slice (IndexType start, IndexType end) noexcept + { + if (numElements == 0) return {}; + if (start >= numElements) return {}; + + return { elements + start, std::min (static_cast (end - start), numElements - start) }; + } ElementType* elements = nullptr; SizeType numElements = 0; diff --git a/modules/compiler/src/backends/LLVM/cmaj_LLVMGenerator.h b/modules/compiler/src/backends/LLVM/cmaj_LLVMGenerator.h index 74a01dcb..9510655b 100644 --- a/modules/compiler/src/backends/LLVM/cmaj_LLVMGenerator.h +++ b/modules/compiler/src/backends/LLVM/cmaj_LLVMGenerator.h @@ -1849,6 +1849,32 @@ struct LLVMCodeGenerator return makeReader (fatPointer, AST::createSliceOfType (elementType.context, elementType)); } + ValueReader createSliceOfSlice (const AST::TypeBase& elementType, ValueReader sourceSlice, ValueReader start, ValueReader end) + { + auto sourcePtr = getPointer (sourceSlice); + + auto fatPointerType = getFatPointerType (elementType); + auto fatPointer = functionEntryBlockBuilder->CreateAlloca (fatPointerType); + + auto& b = getBlockBuilder(); + + auto dataField = b.CreateConstInBoundsGEP2_32 (fatPointerType, sourcePtr, 0, 0); + auto startIndex = b.CreateLoad (getInt32Type(), getPointer (start)); + + auto sliceLength = createBinaryOp (AST::BinaryOpTypeEnum::Enum::subtract, + AST::TypeRules::getBinaryOperatorTypes (AST::BinaryOpTypeEnum::Enum::subtract, allocator.int32Type, allocator.int32Type), + end, + start); + + auto ptr = b.CreateLoad (getLLVMType (elementType)->getPointerTo(), dataField); + auto sliceDataField = b.CreateInBoundsGEP (getLLVMType (elementType), ptr, { startIndex }); + + b.CreateStore (sliceDataField, b.CreateConstInBoundsGEP2_32 (fatPointerType, fatPointer, 0, 0)); + b.CreateStore (sliceLength.value, b.CreateConstInBoundsGEP2_32 (fatPointerType, fatPointer, 0, 1)); + + return makeReader (fatPointer, AST::createSliceOfType (elementType.context, elementType)); + } + ValueReader createGetSliceSize (ValueReader slice) { auto& b = getBlockBuilder(); diff --git a/modules/compiler/src/codegen/cmaj_CodeGenerator.h b/modules/compiler/src/codegen/cmaj_CodeGenerator.h index 77ddcabf..b417b4b0 100644 --- a/modules/compiler/src/codegen/cmaj_CodeGenerator.h +++ b/modules/compiler/src/codegen/cmaj_CodeGenerator.h @@ -355,7 +355,7 @@ struct CodeGenerator void emitAssignment (const AST::Object& target, const AST::Property& newValue) { - if (auto s = target.getAsGetArraySlice()) + if (auto s = target.getAsGetArrayOrVectorSlice()) return emitWriteToSlice (*s, AST::castToValueRef (newValue)); auto targetType = target.getAsValueBase()->getResultType(); @@ -372,7 +372,7 @@ struct CodeGenerator if (auto v = target.getAsVariableDeclaration()) return emitWriteToVariable (*v, std::move (newValue)); if (auto v = target.getAsNamedReference()) return emitAssignment (v->target, std::move (newValue), canSourceBeReadMultipleTimes); if (auto e = target.getAsGetElement()) return emitWriteToElement (*e, std::move (newValue)); - if (auto s = target.getAsGetArraySlice()) return emitWriteToSlice (*s, std::move (newValue), false, canSourceBeReadMultipleTimes); + if (auto s = target.getAsGetArrayOrVectorSlice()) return emitWriteToSlice (*s, std::move (newValue), false, canSourceBeReadMultipleTimes); if (auto m = target.getAsGetStructMember()) return emitWriteToStructMember (*m, std::move (newValue)); } @@ -439,7 +439,7 @@ struct CodeGenerator return v.isCompileTimeConstant() || v.isVariableReference(); } - void emitWriteToSlice (const AST::GetArraySlice& slice, ValueReader newValue, + void emitWriteToSlice (const AST::GetArrayOrVectorSlice& slice, ValueReader newValue, bool valueIsElement, bool canSourceBeReadMultipleTimes) { auto parentSize = slice.getParentSize(); @@ -467,7 +467,7 @@ struct CodeGenerator }); } - void emitWriteToSlice (const AST::GetArraySlice& slice, const AST::ValueBase& newValue) + void emitWriteToSlice (const AST::GetArrayOrVectorSlice& slice, const AST::ValueBase& newValue) { if (auto v = newValue.getAsConstantAggregate()) { @@ -696,7 +696,7 @@ struct CodeGenerator if (auto v = value.getAsVariableDeclaration()) return builder.createVariableReader (*v); if (auto v = value.getAsNamedReference()) return createValueReader (v->target); if (auto e = value.getAsGetElement()) return createElementReader (*e); - if (auto s = value.getAsGetArraySlice()) return createSliceReader (*s); + if (auto s = value.getAsGetArrayOrVectorSlice()) return createSliceReader (*s); if (auto m = value.getAsGetStructMember()) return createStructMemberReader (*m); if (auto m = value.getAsValueMetaFunction()) return createValueMetaFunction (*m); if (auto p = value.getAsPreOrPostIncOrDec()) return createPreOrPostIncOrDec (AST::castToValueRef (p->target), p->isIncrement, p->isPost); @@ -753,7 +753,7 @@ struct CodeGenerator } else { - CMAJ_ASSERT (isConst || value.getAsGetArraySlice() != nullptr); + CMAJ_ASSERT (isConst || value.getAsGetArrayOrVectorSlice() != nullptr); } auto& v = AST::castToValueRef (value); @@ -1171,7 +1171,7 @@ struct CodeGenerator ValueReader createSliceFromValue (const AST::TypeBase& elementType, const AST::ArrayType& sourceType, const AST::ValueBase& value) { - if (auto slice = value.getAsGetArraySlice()) + if (auto slice = value.getAsGetArrayOrVectorSlice()) { auto& parentArray = AST::castToValueRef (slice->parent); auto& parentArrayType = *parentArray.getResultType(); @@ -1362,9 +1362,23 @@ struct CodeGenerator m.member.get(), structType.indexOfMember (m.member.get())); } - ValueReader createSliceReader (const AST::GetArraySlice& slice) + ValueReader createSliceReader (const AST::GetArrayOrVectorSlice& slice) { auto parentSize = slice.getParentSize(); + + if (! parentSize.has_value()) + { + auto& parentArray = AST::castToValueRef (slice.parent); + auto& parentArrayType = *parentArray.getResultType(); + auto elementType = parentArrayType.getArrayOrVectorElementType(); + + // Slice of Slice + return builder.createSliceOfSlice (*elementType, + createValueReader (parentArray), + createValueReader (slice.start), + createValueReader (slice.end)); + } + CMAJ_ASSERT (parentSize.has_value()); auto sliceSize = slice.getSliceSize(); CMAJ_ASSERT (sliceSize.has_value()); diff --git a/modules/compiler/src/codegen/cmaj_ProgramPrinter.h b/modules/compiler/src/codegen/cmaj_ProgramPrinter.h index d6986c5d..e50c9c69 100644 --- a/modules/compiler/src/codegen/cmaj_ProgramPrinter.h +++ b/modules/compiler/src/codegen/cmaj_ProgramPrinter.h @@ -1082,7 +1082,7 @@ struct ProgramPrinter : public SourceCodeFormattingHelper .addPunctuation ("]"); } - if (auto slice = e.getAsGetArraySlice()) + if (auto slice = e.getAsGetArrayOrVectorSlice()) return formatExpression (slice->parent).addParensIfNeeded() .add (formatRangePair (slice->start, slice->end)); diff --git a/modules/compiler/src/passes/cmaj_ConstantFolder.h b/modules/compiler/src/passes/cmaj_ConstantFolder.h index 7e29c051..93ad17e3 100644 --- a/modules/compiler/src/passes/cmaj_ConstantFolder.h +++ b/modules/compiler/src/passes/cmaj_ConstantFolder.h @@ -110,7 +110,7 @@ struct ConstantFolder : public PassAvoidingGenericFunctionsAndModules void visit (AST::BinaryOperator& o) override { super::visit (o); fold (o); } void visit (AST::TernaryOperator& o) override { super::visit (o); fold (o); } void visit (AST::GetElement& o) override { super::visit (o); fold (o.indexes); fold (o); } - void visit (AST::GetArraySlice& o) override { super::visit (o); fold (o.start); fold (o.end); fold (o); } + void visit (AST::GetArrayOrVectorSlice& o) override { super::visit (o); fold (o.start); fold (o.end); fold (o); } void visit (AST::GetStructMember& o) override { super::visit (o); fold (o); } void visit (AST::FunctionCall& o) override { super::visit (o); fold (o); } void visit (AST::VectorType& o) override { super::visit (o); fold (o.numElements); } diff --git a/modules/compiler/src/passes/cmaj_StrengthReduction.h b/modules/compiler/src/passes/cmaj_StrengthReduction.h index 44adfff4..57fa8da6 100644 --- a/modules/compiler/src/passes/cmaj_StrengthReduction.h +++ b/modules/compiler/src/passes/cmaj_StrengthReduction.h @@ -29,7 +29,7 @@ struct StrengthReduction : public PassAvoidingGenericFunctionsAndModules CMAJ_DO_NOT_VISIT_CONSTANTS - void visit (AST::GetArraySlice& o) override + void visit (AST::GetArrayOrVectorSlice& o) override { super::visit (o); diff --git a/modules/compiler/src/passes/cmaj_TypeResolver.h b/modules/compiler/src/passes/cmaj_TypeResolver.h index 53832897..8c610841 100644 --- a/modules/compiler/src/passes/cmaj_TypeResolver.h +++ b/modules/compiler/src/passes/cmaj_TypeResolver.h @@ -48,7 +48,7 @@ struct TypeResolver : public PassAvoidingGenericFunctionsAndModules if (term.isRange) { - auto& getSlice = replaceWithNewObject (b); + auto& getSlice = replaceWithNewObject (b); getSlice.parent.referTo (*v); if (term.startIndex != nullptr) getSlice.start.referTo (term.startIndex); @@ -129,7 +129,7 @@ struct TypeResolver : public PassAvoidingGenericFunctionsAndModules if (term.isRange) { - auto& getSlice = replaceWithNewObject (b); + auto& getSlice = replaceWithNewObject (b); getSlice.parent.referTo (parent); if (term.startIndex != nullptr) getSlice.start.referTo (term.startIndex); diff --git a/modules/compiler/src/transformations/cmaj_ConvertComplexTypes.h b/modules/compiler/src/transformations/cmaj_ConvertComplexTypes.h index 913d00eb..6107df2e 100644 --- a/modules/compiler/src/transformations/cmaj_ConvertComplexTypes.h +++ b/modules/compiler/src/transformations/cmaj_ConvertComplexTypes.h @@ -353,7 +353,7 @@ inline void convertComplexTypes (AST::Program& program) } } - void visit (AST::GetArraySlice& s) override + void visit (AST::GetArrayOrVectorSlice& s) override { super::visit (s); @@ -422,7 +422,7 @@ inline void convertComplexTypes (AST::Program& program) size_t indexOffset = 0; - if (auto arraySlice = AST::castTo (firstArg)) + if (auto arraySlice = AST::castTo (firstArg)) { if (auto startPos = AST::castTo (arraySlice->start)) { diff --git a/modules/compiler/src/transformations/cmaj_ReplaceMultidimensionalArrays.h b/modules/compiler/src/transformations/cmaj_ReplaceMultidimensionalArrays.h index 88311e0a..7474ab21 100644 --- a/modules/compiler/src/transformations/cmaj_ReplaceMultidimensionalArrays.h +++ b/modules/compiler/src/transformations/cmaj_ReplaceMultidimensionalArrays.h @@ -111,7 +111,7 @@ static inline void replaceMultidimensionalArrays (AST::Program& program) auto& end = AST::foldToConstantIfPossible (AST::createAdd (context, flattenedOffset, *size)); - auto& slice = g.context.allocate(); + auto& slice = g.context.allocate(); slice.parent.referTo (g.parent.getObjectRef()); slice.start.setChildObject (flattenedOffset); slice.end.setChildObject (end); diff --git a/modules/compiler/src/transformations/cmaj_TransformSlices.h b/modules/compiler/src/transformations/cmaj_TransformSlices.h new file mode 100644 index 00000000..ee0818fc --- /dev/null +++ b/modules/compiler/src/transformations/cmaj_TransformSlices.h @@ -0,0 +1,130 @@ +// +// ,ad888ba, 88 +// d8"' "8b +// d8 88,dba,,adba, ,aPP8A.A8 88 The Cmajor Toolkit +// Y8, 88 88 88 88 88 88 +// Y8a. .a8P 88 88 88 88, ,88 88 (C)2024 Cmajor Software Ltd +// '"Y888Y"' 88 88 88 '"8bbP"Y8 88 https://cmajor.dev +// ,88 +// 888P" +// +// The Cmajor project is subject to commercial or open-source licensing. +// You may use it under the terms of the GPLv3 (see www.gnu.org/licenses), or +// visit https://cmajor.dev to learn about our commercial licence options. +// +// CMAJOR IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER +// EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE +// DISCLAIMED. + +namespace cmaj::transformations +{ + +//============================================================================== +static inline void transformSlices (AST::Program& program) +{ + struct TransformSlices : public AST::NonParameterisedObjectVisitor + { + using super = AST::NonParameterisedObjectVisitor; + using super::visit; + + TransformSlices (AST::Namespace& root) + : super (root.context.allocator), rootNamespace (root), + intrinsicsNamespace (*findIntrinsicsNamespaceFromRoot (root)) + {} + + CMAJ_DO_NOT_VISIT_CONSTANTS + + void visit (AST::GetArrayOrVectorSlice& g) override + { + super::visit (g); + + if (auto parentValue = AST::castToValue (g.parent)) + { + auto& parentType = *parentValue->getResultType(); + + if (parentType.isSlice()) + { + if (choc::text::startsWith (g.findParentFunction()->getName(), getSliceOfSliceFunctionName())) + return; // need to avoid modifying our generated functions + + auto& readFn = getOrCreateSliceOfSliceFunction (parentType); + + auto& start = (g.start != nullptr) ? g.start.get() : allocator.createConstantInt32 (0); + auto& end = (g.end != nullptr) ? g.end.get() : allocator.createConstantInt32 (0); + + g.replaceWith (AST::createFunctionCall (g, readFn, g.parent, start, end)); + } + } + } + + AST::Function& getOrCreateSliceOfSliceFunction (const AST::TypeBase& sliceType) + { + CMAJ_ASSERT (sliceType.isSlice()); + auto& elementType = *sliceType.getArrayOrVectorElementType(); + + AST::SignatureBuilder sig; + sig << getSliceOfSliceFunctionName() << elementType; + auto name = intrinsicsNamespace.getStringPool().get (sig.toString (30)); + + if (auto f = intrinsicsNamespace.findFunction (name, 3)) + return *f; + + auto& f = AST::createFunctionInModule (intrinsicsNamespace, sliceType, name); + auto parentSliceParam = AST::addFunctionParameter (f, sliceType, f.getStrings().array); + auto startIndexParam = AST::addFunctionParameter (f, allocator.int32Type, f.getStrings().start); + auto endIndexParam = AST::addFunctionParameter (f, allocator.int32Type, f.getStrings().end); + + auto& mainBlock = *f.getMainBlock(); + + auto& sliceSize = mainBlock.allocateChild(); + sliceSize.op = AST::ValueMetaFunctionTypeEnum::Enum::size; + sliceSize.arguments.addReference (parentSliceParam); + + auto& setSizeToZero = mainBlock.allocateChild(); + setSizeToZero.addStatement (AST::createAssignment (mainBlock.context, startIndexParam, allocator.createConstantInt32 (0))); + setSizeToZero.addStatement (AST::createAssignment (mainBlock.context, endIndexParam, allocator.createConstantInt32 (0))); + + mainBlock.addStatement (AST::createIfStatement (mainBlock.context, + AST::createBinaryOp (mainBlock, + AST::BinaryOpTypeEnum::Enum::greaterThanOrEqual, + startIndexParam, + sliceSize), + setSizeToZero)); + + auto& setEndToSize = mainBlock.allocateChild(); + setEndToSize.addStatement (AST::createAssignment (mainBlock.context, endIndexParam, sliceSize)); + + mainBlock.addStatement (AST::createIfStatement (mainBlock.context, + AST::createBinaryOp (mainBlock, + AST::BinaryOpTypeEnum::Enum::logicalOr, + AST::createBinaryOp (mainBlock, + AST::BinaryOpTypeEnum::Enum::equals, + endIndexParam, + allocator.createConstantInt32 (0)), + AST::createBinaryOp (mainBlock, + AST::BinaryOpTypeEnum::Enum::greaterThan, + endIndexParam, + sliceSize)), + setEndToSize)); + + auto& resultSlice = mainBlock.allocateChild(); + resultSlice.parent.referTo (parentSliceParam); + resultSlice.start.referTo (startIndexParam); + resultSlice.end.referTo (endIndexParam); + + AST::addReturnStatement (mainBlock, resultSlice); + + CMAJ_ASSERT (intrinsicsNamespace.findFunction (name, 3) == f); + return f; + } + + static constexpr std::string_view getSliceOfSliceFunctionName() { return "_createSliceOfSlice"; } + + AST::Namespace& rootNamespace; + AST::Namespace& intrinsicsNamespace; + }; + + TransformSlices (program.rootNamespace).visitObject (program.rootNamespace); +} + +} diff --git a/modules/compiler/src/transformations/cmaj_Transformations.cpp b/modules/compiler/src/transformations/cmaj_Transformations.cpp index 3ed8a768..aa6ec214 100644 --- a/modules/compiler/src/transformations/cmaj_Transformations.cpp +++ b/modules/compiler/src/transformations/cmaj_Transformations.cpp @@ -57,6 +57,7 @@ #include "cmaj_AddFallbackIntrinsics.h" #include "cmaj_ReplaceMultidimensionalArrays.h" #include "cmaj_ConvertLargeConstants.h" +#include "cmaj_TransformSlices.h" namespace cmaj::transformations { @@ -142,6 +143,7 @@ void prepareForCodeGen (AST::Program& program, convertComplexTypes (program); addFallbackIntrinsics (program, engineSupportsIntrinsic); canonicaliseLoopsAndBlocks (program); + transformSlices (program); replaceWrapTypesAndLoopCounters (program); replaceMultidimensionalArrays (program); convertUnwrittenVariablesToConst (program); diff --git a/modules/compiler/src/validation/cmaj_ValidationUtilities.h b/modules/compiler/src/validation/cmaj_ValidationUtilities.h index e5ce7d31..132ea035 100644 --- a/modules/compiler/src/validation/cmaj_ValidationUtilities.h +++ b/modules/compiler/src/validation/cmaj_ValidationUtilities.h @@ -1139,7 +1139,7 @@ struct OutOfScopeSourcesForValue return addSource (value); } - if (auto gs = value.getAsGetArraySlice()) + if (auto gs = value.getAsGetArrayOrVectorSlice()) return addSources (AST::castToValueRef (gs->parent)); if (auto gm = value.getAsGetStructMember()) diff --git a/modules/compiler/src/validation/cmaj_Validator.h b/modules/compiler/src/validation/cmaj_Validator.h index 76a94f5f..80f28b28 100644 --- a/modules/compiler/src/validation/cmaj_Validator.h +++ b/modules/compiler/src/validation/cmaj_Validator.h @@ -64,7 +64,7 @@ namespace cmaj::validation visitedMainProcessor = true; } - void visit (AST::GetArraySlice& s) override + void visit (AST::GetArrayOrVectorSlice& s) override { super::visit (s); @@ -74,12 +74,6 @@ namespace cmaj::validation if (auto graphNode = AST::castToSkippingReferences (s.parent)) throwError (graphNode, Errors::unimplementedFeature ("Slices of graph nodes")); - auto& object = getAsValueOrThrowError (s.parent); - auto& objectType = getResultTypeOfValueOrThrowError (object).skipConstAndRefModifiers(); - - if (objectType.isSlice()) - throwError (s, Errors::unimplementedFeature ("Slices of slices")); - if (auto startValue = AST::castToValue (s.start)) if (! startValue->isCompileTimeConstant()) throwError (startValue, Errors::unimplementedFeature ("Dynamic slice indexes")); @@ -796,7 +790,7 @@ namespace cmaj::validation } } - void visit (AST::GetArraySlice& s) override + void visit (AST::GetArrayOrVectorSlice& s) override { super::visit (s); @@ -832,9 +826,6 @@ namespace cmaj::validation end = endConst->getAsInt64(); } - if (objectType.isSlice()) - throwError (s, Errors::unimplementedFeature ("Slices of slices")); - auto& elementType = *objectType.getArrayOrVectorElementType(); if (! (elementType.isPrimitive() || elementType.isVector())) diff --git a/tests/language_tests/cmaj_test_not_yet_implemented.cmajtest b/tests/language_tests/cmaj_test_not_yet_implemented.cmajtest index 67b16ae7..766195a2 100644 --- a/tests/language_tests/cmaj_test_not_yet_implemented.cmajtest +++ b/tests/language_tests/cmaj_test_not_yet_implemented.cmajtest @@ -98,38 +98,6 @@ void f (int i) let b = array[i:]; } -## expectError ("4:46: error: Language feature not yet implemented: Slices of slices!") - -const int[10] data = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10); -int[] getSlice() { return data; } -int[] getSliceOfSlice() { return getSlice()[2:]; } - -bool testSliceOfSlice() -{ - var s = getSliceOfSlice(); - s[3] = 10; - return s[2] == 5 && s[3] == 10; -} - -## expectError ("16:21: error: Language feature not yet implemented: Slices of slices!") - -processor test [[ main ]] -{ - output event int results; - external float[] data [[ squarewave, rate: 1000, frequency: 10, numFrames: 1000 ]]; - - void main() - { - results <- (test() ? 1 : 0); - advance(); - loop { results <- -1; advance(); } - } - - bool test() - { - return data[1:3] == float[3] (1.0f, 1.0f, 1.0f); - } -} ## expectError ("2:22: error: Language feature not yet implemented: Writing to the console from a free function!") diff --git a/tests/language_tests/cmaj_test_slices.cmajtest b/tests/language_tests/cmaj_test_slices.cmajtest new file mode 100644 index 00000000..dc9f2660 --- /dev/null +++ b/tests/language_tests/cmaj_test_slices.cmajtest @@ -0,0 +1,87 @@ +// +// ,ad888ba, 88 +// d8"' "8b +// d8 88,dba,,adba, ,aPP8A.A8 88 (C)2024 Cmajor Software Ltd +// Y8, 88 88 88 88 88 88 +// Y8a. .a8P 88 88 88 88, ,88 88 https://cmajor.dev +// '"Y888Y"' 88 88 88 '"8bbP"Y8 88 +// ,88 +// 888P" +// +// This code may be used under either a GPLv3 or commercial +// license: see LICENSE.md for more details. + + +## testFunction() + +bool sliceOfSlice() +{ + int[10] f = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + + return getElement2 (f[2:7], 2) == 6 && + getElement3 (f[2:7], 2) == 4; +} + +int getElement3 (int[] i, int n) +{ + return getElement (i[2:4], n); +} + +int getElement2 (int[] i, int n) +{ + return getElement (i[2:], n); +} + +int getElement (int[] i, int n) +{ + return i[n]; +} + + +## testConsole ("3:2,3,4,2 2:3,4,3,4 2:2,3,2,3") + +processor Test [[ main ]] +{ + output stream float out; + + void printElement (int[] i) + { + console <- i.size <- ":" <- i[0] <- "," <- i[1] <- "," <- i[2] <- "," <- i[3]; + } + + void printElement2 (int[] i) + { + printElement (i[1:]); + } + + void printElement3 (int[] i) + { + printElement (i[:2]); + } + + int[10] f = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + + void main() + { + printElement (f[2:5]); + console <- " "; + printElement2 (f[2:5]); + console <- " "; + printElement3 (f[2:5]); + + advance(); + } +} + + +## testFunction() + +const int[10] data = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10); +int[] getSlice() { return data; } +int[] getSliceOfSlice() { return getSlice()[2:]; } + +bool testSliceOfSlice() +{ + var s = getSliceOfSlice(); + return s[2] == 5 && s[3] == 6; +}