diff --git a/.github/workflows/msbuild.yml b/.github/workflows/msbuild.yml
index 1b16320f1..68541854d 100644
--- a/.github/workflows/msbuild.yml
+++ b/.github/workflows/msbuild.yml
@@ -20,7 +20,7 @@ env:
# https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
BUILD_CONFIGURATION: Release
- BUILD_TAG: 6.2.3
+ BUILD_TAG: 6.3.0
permissions:
contents: read
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 39f5454c3..bfb97021c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,8 @@
- [ADDED] method reference - &myMethod
- [FIXED] single dispatcher : if an argument is nillable, it can accept nil value
- [ADDED] String interpolation
+ - [REDUX] iterator method
+ - [ADDED] #496 : private fields
- ELC
- [FIXED] private constructor must be called directly
@@ -18,6 +20,7 @@
- [FIXED] only public classes can be loaded in run-time
- [ADDED] #637 : bt optimization 4 unit test
- [FIXED] var attribute is allowed to be in the method argument list
+ - [FIXED] "__typeof self" expression inside the nested class / closure
- VM
- [FIXED] GC_ALLOC routine for vm mode
diff --git a/VERSION b/VERSION
index 30bc70ba1..e7e42a4b5 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-6.2.2
\ No newline at end of file
+6.3.0
\ No newline at end of file
diff --git a/bin/templates/lib60.cfg b/bin/templates/lib60.cfg
index 2407654c8..77327bc06 100644
--- a/bin/templates/lib60.cfg
+++ b/bin/templates/lib60.cfg
@@ -51,5 +51,6 @@
system'BaseLazyExpression
system'Nullable#1
system'UnsafePointer
+ system'YieldStateEnumerator
\ No newline at end of file
diff --git a/bin/templates/lib60.config b/bin/templates/lib60.config
index 5b322a3ae..fc0e5cadc 100644
--- a/bin/templates/lib60.config
+++ b/bin/templates/lib60.config
@@ -57,5 +57,6 @@
system'UnsafePointer
meta$preloadedSymbols
meta$preloadedSymbols
+ system'YieldStateEnumerator
\ No newline at end of file
diff --git a/build/aarch64/build_package_arm64.script b/build/aarch64/build_package_arm64.script
index 22e50bb81..2960e9061 100755
--- a/build/aarch64/build_package_arm64.script
+++ b/build/aarch64/build_package_arm64.script
@@ -1,5 +1,5 @@
#!/bin/bash
-RELEASE=elena-6.2.3.aarch64-linux
+RELEASE=elena-6.3.0.aarch64-linux
mkdir -p /usr/share/elena
mkdir -p /etc/elena/
diff --git a/build/aarch64/control b/build/aarch64/control
index 4724d00d5..3da3ee69a 100644
--- a/build/aarch64/control
+++ b/build/aarch64/control
@@ -1,5 +1,5 @@
Package: elena-lang
-Version: 6.2.3
+Version: 6.3.0
Architecture: aarch64
Maintainer: Alex Rakov
Depends: libc6 (>= 2.1)
diff --git a/build/amd64/build_package_amd64.script b/build/amd64/build_package_amd64.script
index eb0387e0d..53564a43d 100755
--- a/build/amd64/build_package_amd64.script
+++ b/build/amd64/build_package_amd64.script
@@ -1,5 +1,5 @@
#!/bin/bash
-RELEASE=elena-6.2.3.amd64-linux
+RELEASE=elena-6.3.0.amd64-linux
mkdir -p /usr/share/elena
mkdir -p /etc/elena/
diff --git a/build/amd64/control b/build/amd64/control
index a8c6cdb32..ebb52c770 100644
--- a/build/amd64/control
+++ b/build/amd64/control
@@ -1,5 +1,5 @@
Package: elena-lang
-Version: 6.2.3
+Version: 6.3.0
Architecture: amd64
Maintainer: Alex Rakov
Depends: libc6 (>= 2.1)
diff --git a/build/create_package_x64.bat b/build/create_package_x64.bat
index a14ca92bb..6874fbd8f 100644
--- a/build/create_package_x64.bat
+++ b/build/create_package_x64.bat
@@ -73,6 +73,8 @@ copy %~dp0\..\bin\scripts\*.es %~dp0\x64\bin\scripts\
copy %~dp0\..\doc\license %~dp0\x64\doc\
copy %~dp0\..\doc\contributors %~dp0\x64\doc\
copy %~dp0\..\readme.md %~dp0\x64\
+copy %~dp0\..\CHANGELOG.md %~dp0\x64\
+copy %~dp0\..\VERSION %~dp0\x64\
md %~dp0\x64\src60\system
xcopy %~dp0\..\src60\system\*.l %~dp0\x64\src60\system /s
diff --git a/build/elena_inno.iss b/build/elena_inno.iss
index 42afc8118..a2b2b4b36 100644
--- a/build/elena_inno.iss
+++ b/build/elena_inno.iss
@@ -7,7 +7,7 @@
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{3CAA69D3-0F98-44B1-A73E-E864BA51D5BD}
AppName=ELENA Programming Language
-AppVersion=6.2.3
+AppVersion=6.3.0
;AppVerName=ELENA Programming Language 6.2.0
AppPublisher=Alexey Rakov
AppPublisherURL=http://github.com/ELENA-LANG/elena-lang
@@ -18,7 +18,7 @@ DefaultGroupName=ELENA Programming Language
AllowNoIcons=yes
LicenseFile=..\doc\license
InfoAfterFile=..\CHANGELOG.md
-OutputBaseFilename=elena-lang-6.2.0.x86-setup
+OutputBaseFilename=elena-lang-6.3.0.x86-win-setup
Compression=lzma
SolidCompression=yes
ChangesEnvironment=yes
diff --git a/build/i386/build_package_i386.script b/build/i386/build_package_i386.script
index 74e0924cd..1022969ac 100755
--- a/build/i386/build_package_i386.script
+++ b/build/i386/build_package_i386.script
@@ -1,5 +1,5 @@
#!/bin/bash
-RELEASE=elena-6.2.3.i386-linux
+RELEASE=elena-6.3.0.i386-linux
mkdir -p /usr/share/elena
mkdir -p /etc/elena/
diff --git a/build/i386/control b/build/i386/control
index bbb12a2ec..25d579edf 100644
--- a/build/i386/control
+++ b/build/i386/control
@@ -1,5 +1,5 @@
Package: elena-lang
-Version: 6.2.3
+Version: 6.3.0
Architecture: i386
Maintainer: Alex Rakov
Depends: libc6 (>= 2.1)
diff --git a/build/ppc64le/build_package_ppc64le.script b/build/ppc64le/build_package_ppc64le.script
index 10c8c0a2b..0a5715bb5 100755
--- a/build/ppc64le/build_package_ppc64le.script
+++ b/build/ppc64le/build_package_ppc64le.script
@@ -1,5 +1,5 @@
#!/bin/bash
-RELEASE=elena-6.2.3.ppc64le-linux
+RELEASE=elena-6.3.0.ppc64le-linux
mkdir -p /usr/share/elena
mkdir -p /etc/elena/
diff --git a/build/ppc64le/control b/build/ppc64le/control
index 0e0690ba1..6c9aeed85 100644
--- a/build/ppc64le/control
+++ b/build/ppc64le/control
@@ -1,5 +1,5 @@
Package: elena-lang
-Version: 6.2.3
+Version: 6.3.0
Architecture: ppc64le
Maintainer: Alex Rakov
Depends: libc6 (>= 2.1)
diff --git a/doc/features b/doc/features
index c13bd0250..a41d3b01c 100644
--- a/doc/features
+++ b/doc/features
@@ -90,3 +90,31 @@ public program()
----------------------------------------------------------------------------
var s := var s := $"a_{ 1 }_b_{ 2 }_c";
+
+----------------------------------------------------------------------------
+ user-defined literals
+----------------------------------------------------------------------------
+
+ import extensions;
+
+ sealed struct OctalNumber
+ {
+ int value;
+
+ int cast() = value;
+
+ constructor(int n)
+ {
+ value := n;
+ }
+
+ cast o(string s)
+ {
+ value := s.toInt(8);
+ }
+ }
+
+ public program()
+ {
+ var n := 12o;
+ }
diff --git a/doc/todo.txt b/doc/todo.txt
index b004f9a17..33e02b3e3 100644
--- a/doc/todo.txt
+++ b/doc/todo.txt
@@ -3,29 +3,58 @@ In development:
------
[development]
- ### EPIC: elena 6.3 ###
+ ### EPIC: elena 6.4 ###
- === Iteration 30 (16.8) ===
+ === Iteration 31 ===
--------------------------------------
dev:
+ - async programming (general concept, SynchronizationContext, ThreadPool, Task, AsyncLocal, ThreadStatic)
- upndown (connector)
- - async programming
+ - chat: add mutex (see dpa_queue)
+ - #496
gen:
- - lpad
+ - lpad : generate a code based on a record
maint:
+ - #679
port:
- - #658 : vscode extension (debug adapter)
+ - #658 : connect with ldbg from VSCode
prom: posting weekly
--------------------------------------
- - lpad : generate a code based on a record
- - User-defined string literals
--------------------------------------
- - #658 : connect with ldbg from VSCode
+
+ === Iteration 32 ===
+ --------------------------------------
+ dev:
+ gen:
+ maint:
+ port:
+ prom:
+ --------------------------------------
--------------------------------------
- ### EPIC: elena 6.4 ###
+ === Iteration 33 ===
+ --------------------------------------
+ dev:
+ gen:
+ maint:
+ port:
+ prom:
+ --------------------------------------
+ --------------------------------------
- === Iteration 31 ===
+ === Iteration 34 ===
+ --------------------------------------
+ dev:
+ gen:
+ maint:
+ port:
+ prom:
+ --------------------------------------
+ --------------------------------------
+
+ ### EPIC: elena 6.5 ###
+
+ === Iteration 35 ===
--------------------------------------
dev:
gen:
diff --git a/elenasrc3/common/paths.cpp b/elenasrc3/common/paths.cpp
index f22a7aaa5..b8efec428 100644
--- a/elenasrc3/common/paths.cpp
+++ b/elenasrc3/common/paths.cpp
@@ -72,6 +72,13 @@ bool PathUtil :: checkExtension(path_t path, ustr_t extension)
return PathUtil::checkExtension(path, *wExtension);
}
+void PathUtil :: makeCorrectExePath(PathString& target)
+{
+ if (!PathUtil::checkExtension(*target, "exe")) {
+ target.appendExtension("exe");
+ }
+}
+
#elif __GNUG__
#include
@@ -115,6 +122,11 @@ bool PathUtil :: removeFile(path_t path)
{
return ::remove(path.str()) != 0;;
}
+
+void PathUtil::makeCorrectExePath(PathString& target)
+{
+}
+
#endif
diff --git a/elenasrc3/common/paths.h b/elenasrc3/common/paths.h
index b1c24b9a3..3bd3a9bbc 100644
--- a/elenasrc3/common/paths.h
+++ b/elenasrc3/common/paths.h
@@ -46,6 +46,8 @@ namespace elena_lang
#endif
static void combineCanonicalized(PathString& target, path_t subpath);
+
+ static void makeCorrectExePath(PathString& target);
};
// --- PathString ---
diff --git a/elenasrc3/dpa/dpa_queue.h b/elenasrc3/dpa/dpa_queue.h
new file mode 100644
index 000000000..b0c655eda
--- /dev/null
+++ b/elenasrc3/dpa/dpa_queue.h
@@ -0,0 +1,67 @@
+//---------------------------------------------------------------------------
+// E L E N A P r o j e c t: ELENA Debugger Adapater
+//
+// This file contains the DPA queue declarations
+//
+// (C)2024, by Aleksey Rakov
+//---------------------------------------------------------------------------
+
+#ifndef DPA_QUEUE_H
+#define DPA_QUEUE_H
+
+#include
+#include
+#include
+#include
+
+namespace dpa
+{
+ // --- ContentReader ---
+ template
+ class ThreadQueue
+ {
+ bool _closed = false;
+ std::queue _queue;
+ std::condition_variable _cv;
+ std::mutex _mutex;
+
+ public:
+ void close();
+
+ void put(const T& in);
+ std::optional take();
+ };
+
+ template
+ void ThreadQueue :: close()
+ {
+ std::unique_lock lock(_mutex);
+ _closed = true;
+ _cv.notify_all();
+ }
+
+ template
+ void ThreadQueue :: put(const T& in)
+ {
+ std::unique_lock lock(_mutex);
+ auto notify = _queue.size() == 0 && !_closed;
+ _queue.push(in);
+ if (notify)
+ _cv.notify_all();
+ }
+
+ template
+ std::optional ThreadQueue :: take()
+ {
+ std::unique_lock lock(_mutex);
+ _cv.wait(lock, [&] { return _queue.size() > 0 || _closed; });
+ if (_queue.size() == 0) {
+ return std::optional();
+ }
+ auto out = std::move(_queue.front());
+ _queue.pop();
+ return std::optional(std::move(out));
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/elenasrc3/dpa/dpa_session.cpp b/elenasrc3/dpa/dpa_session.cpp
index fbab19d18..1acfdf213 100644
--- a/elenasrc3/dpa/dpa_session.cpp
+++ b/elenasrc3/dpa/dpa_session.cpp
@@ -17,5 +17,43 @@ Session :: Session()
Session :: ~Session()
{
+ _inbox.close();
+ if (_recvThread.joinable()) {
+ _recvThread.join();
+ }
+ if (_dispatchThread.joinable()) {
+ _dispatchThread.join();
+ }
+ _reader.close();
+}
+
+void Session :: connect()
+{
+ _reader = ContentReader();
+}
+
+Payload Session :: getPayload()
+{
+ return {};
+}
+
+void Session :: start(const ClosedHandler& onClose)
+{
+ _recvThread = std::thread([this/*, onClose*/] {
+ while (_reader.isOpen()) {
+ if (auto payload = getPayload()) {
+ _inbox.put(std::move(payload));
+ }
+ }
+ //if (onClose) {
+ // onClose();
+ //}
+ });
+
+ _dispatchThread = std::thread([this] {
+ while (auto payload = _inbox.take()) {
+ payload.value()();
+ }
+ });
}
\ No newline at end of file
diff --git a/elenasrc3/dpa/dpa_session.h b/elenasrc3/dpa/dpa_session.h
index 9e758287a..4c0dd35d1 100644
--- a/elenasrc3/dpa/dpa_session.h
+++ b/elenasrc3/dpa/dpa_session.h
@@ -9,12 +9,40 @@
#ifndef DPA_SESSION_H
#define DPA_SESSION_H
+#include
+#include
+
+#include "dpa_stream.h"
+#include "dpa_queue.h"
+
namespace dpa
{
+ using Payload = std::function;
+ using PayloadQueue = ThreadQueue;
+
+ using ClosedHandler = std::function;
+
+ //using RequestHandler =
+ // std::function;
+
// --- Session ---
class Session
{
+ ContentReader _reader;
+ PayloadQueue _inbox;
+
+ std::thread _recvThread;
+ std::thread _dispatchThread;
+
+ Payload getPayload();
+
public:
+ //virtual void registerHandler(const TypeInfo* typeinfo,
+ // const RequestHandler& handler);
+
+ void connect();
+ void start(const ClosedHandler& onClose = {});
+
Session();
virtual ~Session();
};
diff --git a/elenasrc3/dpa/dpa_stream.cpp b/elenasrc3/dpa/dpa_stream.cpp
new file mode 100644
index 000000000..7401e3459
--- /dev/null
+++ b/elenasrc3/dpa/dpa_stream.cpp
@@ -0,0 +1,26 @@
+//---------------------------------------------------------------------------
+// E L E N A P r o j e c t: ELENA Debugger Adapater
+//
+// This file contains the DPA I/O class implementations
+//
+// (C)2024, by Aleksey Rakov
+//---------------------------------------------------------------------------
+
+#include "dpa_stream.h"
+
+using namespace dpa;
+
+ContentReader :: ~ContentReader()
+{
+
+}
+
+bool ContentReader :: isOpen()
+{
+ return false;
+}
+
+void ContentReader :: close()
+{
+
+}
diff --git a/elenasrc3/dpa/dpa_stream.h b/elenasrc3/dpa/dpa_stream.h
new file mode 100644
index 000000000..99e7dc97f
--- /dev/null
+++ b/elenasrc3/dpa/dpa_stream.h
@@ -0,0 +1,31 @@
+//---------------------------------------------------------------------------
+// E L E N A P r o j e c t: ELENA Debugger Adapater
+//
+// This file contains the DPA I/O class declarations
+//
+// (C)2024, by Aleksey Rakov
+//---------------------------------------------------------------------------
+
+#ifndef DPA_STREAM_H
+#define DPA_STREAM_H
+
+namespace dpa
+{
+ //using RequestHandler =
+ // std::function;
+
+ // --- ContentReader ---
+ class ContentReader
+ {
+
+ public:
+ bool isOpen();
+
+ void close();
+
+ ContentReader() = default;
+ virtual ~ContentReader();
+ };
+}
+
+#endif
\ No newline at end of file
diff --git a/elenasrc3/elc/clicommon.h b/elenasrc3/elc/clicommon.h
index b2c5c8d77..7c6a785e0 100644
--- a/elenasrc3/elc/clicommon.h
+++ b/elenasrc3/elc/clicommon.h
@@ -186,6 +186,7 @@ struct BuiltinReferences
ref_t nullableTemplateReference;
ref_t argArrayTemplateReference;
ref_t closureTemplateReference, tupleTemplateReference;
+ ref_t yielditTemplateReference;
ref_t lazyExpressionReference;
ref_t pointerReference;
@@ -222,6 +223,7 @@ struct BuiltinReferences
arrayTemplateReference = argArrayTemplateReference = 0;
nullableTemplateReference = 0;
closureTemplateReference = lazyExpressionReference = tupleTemplateReference = 0;
+ yielditTemplateReference = 0;
pointerReference = 0;
dispatch_message = constructor_message = 0;
@@ -489,6 +491,7 @@ struct FieldAttributes
bool fieldArray;
bool overrideMode;
bool autogenerated;
+ bool privateOne;
};
// --- CompilerBase ---
diff --git a/elenasrc3/elc/cliconst.h b/elenasrc3/elc/cliconst.h
index 8cb3ffffd..ec5141cf2 100644
--- a/elenasrc3/elc/cliconst.h
+++ b/elenasrc3/elc/cliconst.h
@@ -13,7 +13,7 @@
namespace elena_lang
{
- #define ELC_REVISION_NUMBER 0x002B
+ #define ELC_REVISION_NUMBER 0x0030
#if defined _M_IX86 || _M_X64
diff --git a/elenasrc3/elc/compiler.cpp b/elenasrc3/elc/compiler.cpp
index 5c8085648..04335a1da 100644
--- a/elenasrc3/elc/compiler.cpp
+++ b/elenasrc3/elc/compiler.cpp
@@ -1,5 +1,4 @@
//---------------------------------------------------------------------------
-//---------------------------------------------------------------------------
// E L E N A P r o j e c t: ELENA Compiler
//
// This file contains ELENA compiler class implementation.
@@ -1190,13 +1189,14 @@ Compiler::ClassScope :: ClassScope(Scope* ns, ref_t reference, Visibility visibi
extensionClassRef = 0;
abstractMode = abstractBasedMode = false;
extensionDispatcher = false;
+ withPrivateField = false;
}
inline ObjectInfo mapClassInfoField(ClassInfo& info, ustr_t identifier, ExpressionAttribute attr, bool ignoreFields)
{
auto fieldInfo = info.fields.get(identifier);
if (!ignoreFields && fieldInfo.offset >= 0) {
- bool readOnly = (test(info.header.flags, elReadOnlyRole) || fieldInfo.readOnly)
+ bool readOnly = (test(info.header.flags, elReadOnlyRole) || FieldInfo::checkHint(fieldInfo, FieldHint::ReadOnly))
&& !EAttrs::test(attr, EAttr::InitializerScope);
if (test(info.header.flags, elStructureRole)) {
@@ -1207,7 +1207,7 @@ inline ObjectInfo mapClassInfoField(ClassInfo& info, ustr_t identifier, Expressi
fieldInfo.typeInfo, fieldInfo.offset };
}
else if (!ignoreFields && fieldInfo.offset == -2) {
- bool readOnly = (test(info.header.flags, elReadOnlyRole) || fieldInfo.readOnly)
+ bool readOnly = (test(info.header.flags, elReadOnlyRole) || FieldInfo::checkHint(fieldInfo, FieldHint::ReadOnly))
&& !EAttrs::test(attr, EAttr::InitializerScope);
return { readOnly ? ObjectKind::ReadOnlySelfLocal : ObjectKind::SelfLocal, fieldInfo.typeInfo, 1u, TargetMode::ArrayContent };
@@ -1243,7 +1243,23 @@ ObjectInfo Compiler::ClassScope :: mapField(ustr_t identifier, ExpressionAttribu
return mapClassInfoField(targetInfo, identifier, attr, true);
}
- else return mapClassInfoField(info, identifier, attr, false);
+ else {
+ if (withPrivateField) {
+ auto retVal = mapPrivateField(identifier, attr);
+ if (retVal.kind != ObjectKind::Unknown)
+ return retVal;
+ }
+
+ return mapClassInfoField(info, identifier, attr, false);
+ }
+}
+
+ObjectInfo Compiler::ClassScope :: mapPrivateField(ustr_t identifier, ExpressionAttribute attr)
+{
+ IdentifierString privateName(identifier, "$");
+ privateName.appendInt(info.inheritLevel);
+
+ return mapClassInfoField(info, *privateName, attr, false);
}
ObjectInfo Compiler::ClassScope :: mapIdentifier(ustr_t identifier, bool referenceOne, ExpressionAttribute attr)
@@ -1419,7 +1435,10 @@ ObjectInfo Compiler::MethodScope :: mapIdentifier(ustr_t identifier, bool refere
return mapSelf(false);
}
else if ((functionMode && !constructorMode) || closureMode || nestedMode) {
- return parent->mapIdentifier(OWNER_VAR, false, attr);
+ if (EAttrs::test(attr, EAttr::RetrievingType)) {
+ return mapClassSymbol(*this, getClassRef());
+ }
+ else return parent->mapIdentifier(OWNER_VAR, false, attr);
}
else return mapSelf();
}
@@ -1703,7 +1722,7 @@ Compiler::InlineClassScope::Outer Compiler::InlineClassScope :: mapSelf()
}
outers.add(*moduleScope->selfVar, ownerVar);
- mapNewField(info.fields, *moduleScope->selfVar, FieldInfo{ (int)ownerVar.reference, ownerVar.outerObject.typeInfo });
+ mapNewField(info.fields, *moduleScope->selfVar, FieldInfo{ (int)ownerVar.reference, ownerVar.outerObject.typeInfo, false, false });
}
return ownerVar;
@@ -1836,6 +1855,19 @@ bool Compiler::InlineClassScope :: markAsPresaved(ObjectInfo object)
return false;
}
+// --- Compiler::StatemachineClassScope ---
+
+Compiler::StatemachineClassScope :: StatemachineClassScope(ExprScope* owner, ref_t reference)
+ : InlineClassScope(owner, reference)
+{
+ contextSize = 0;
+}
+
+ObjectInfo Compiler::StatemachineClassScope :: mapCurrentField()
+{
+ return { ObjectKind::Field, { typeRef }, 1 };
+}
+
// --- Compiler ---
Compiler :: Compiler(
@@ -2279,7 +2311,7 @@ void Compiler :: declareDictionary(Scope& scope, SyntaxNode node, Visibility vis
}
void Compiler :: declareVMT(ClassScope& scope, SyntaxNode node, bool& withConstructors, bool& withDefaultConstructor,
- bool& yieldMethodNotAllowed, bool staticNotAllowed, bool templateBased)
+ bool yieldMethodNotAllowed, bool staticNotAllowed, bool templateBased)
{
SyntaxNode current = node.firstChild();
while (current != SyntaxKey::None) {
@@ -2312,15 +2344,8 @@ void Compiler :: declareVMT(ClassScope& scope, SyntaxNode node, bool& withConstr
}
else methodScope.message = current.arg.reference;
- if (methodScope.isYieldable()) {
- if (yieldMethodNotAllowed) {
- scope.raiseError(errIllegalMethod, current);
- }
- else yieldMethodNotAllowed = true;
- }
-
declareMethodMetaInfo(methodScope, current);
- declareMethod(methodScope, current, scope.abstractMode, staticNotAllowed);
+ declareMethod(methodScope, current, scope.abstractMode, staticNotAllowed, yieldMethodNotAllowed);
if (methodScope.checkHint(MethodHint::Constructor)) {
withConstructors = true;
@@ -2435,6 +2460,7 @@ Compiler::InheritResult Compiler :: inheritClass(ClassScope& scope, ref_t parent
scope.info.header.classRef = classClassCopy;
scope.info.header.flags |= flagCopy;
+ scope.info.inheritLevel++;
return InheritResult::irSuccessfull;
}
@@ -3198,6 +3224,7 @@ bool Compiler :: generateClassField(ClassScope& scope, FieldAttributes& attrs, u
int offset = 0;
bool embeddable = attrs.isEmbeddable;
bool readOnly = attrs.isReadonly;
+ bool privateOne = attrs.privateOne;
ref_t flags = scope.info.header.flags;
// a role / interface cannot have fields
@@ -3255,7 +3282,7 @@ bool Compiler :: generateClassField(ClassScope& scope, FieldAttributes& attrs, u
typeInfo.typeRef = _logic->definePrimitiveArray(*scope.moduleScope, typeInfo.elementRef,
test(scope.info.header.flags, elStructureRole));
- scope.info.fields.add(name, { -2, typeInfo, readOnly });
+ scope.info.fields.add(name, { -2, typeInfo, readOnly, privateOne });
}
else return false;
}
@@ -3266,9 +3293,6 @@ bool Compiler :: generateClassField(ClassScope& scope, FieldAttributes& attrs, u
// if it is a structure field
if (test(scope.info.header.flags, elStructureRole)) {
- if (test(scope.info.header.flags, elWithYieldable))
- return false;
-
if (sizeInfo.size <= 0)
return false;
@@ -3282,7 +3306,7 @@ bool Compiler :: generateClassField(ClassScope& scope, FieldAttributes& attrs, u
offset = scope.info.size;
scope.info.size += sizeInfo.size;
- scope.info.fields.add(name, { offset, typeInfo, readOnly });
+ scope.info.fields.add(name, { offset, typeInfo, readOnly, privateOne });
if (typeInfo.isPrimitive())
_logic->tweakPrimitiveClassFlags(scope.info, typeInfo.typeRef);
@@ -3295,14 +3319,14 @@ bool Compiler :: generateClassField(ClassScope& scope, FieldAttributes& attrs, u
scope.info.header.flags |= elNonStructureRole;
offset = scope.info.fields.count();
- scope.info.fields.add(name, { offset, typeInfo, readOnly });
+ scope.info.fields.add(name, { offset, typeInfo, readOnly, privateOne });
}
}
return true;
}
-void Compiler :: generateClassField(ClassScope& scope, SyntaxNode node,
+DeclResult Compiler :: checkAndGenerateClassField(ClassScope& scope, SyntaxNode node, ustr_t name,
FieldAttributes& attrs, bool singleField)
{
TypeInfo typeInfo = attrs.typeInfo;
@@ -3315,30 +3339,28 @@ void Compiler :: generateClassField(ClassScope& scope, SyntaxNode node,
else if (!test(scope.info.header.flags, elStructureRole)) {
typeInfo.typeRef = resolveArrayTemplate(*scope.moduleScope, attrs.typeInfo.typeRef, true);
}
- else scope.raiseError(errIllegalField, node);
+ else return DeclResult::Illegal;
sizeHint = 0;
}
- ustr_t name = node.findChild(SyntaxKey::Name).firstChild(SyntaxKey::TerminalMask).identifier();
if (scope.info.fields.exist(name)) {
- if (attrs.autogenerated) {
- node.setKey(SyntaxKey::Idle);
- }
- else scope.raiseError(errDuplicatedField, node);
-
- return;
+ return DeclResult::Duplicate;
}
- if (!generateClassField(scope, attrs, name, sizeHint, typeInfo, singleField))
- {
+ if (!generateClassField(scope, attrs, name, sizeHint, typeInfo, singleField)) {
if (attrs.overrideMode && checkPreviousDeclaration(node, name)) {
// override the field type if both declared in the same scope
auto it = scope.info.fields.getIt(name);
(*it).typeInfo = typeInfo;
}
- else scope.raiseError(errIllegalField, node);
+ else return DeclResult::Illegal;
}
+
+ if (attrs.privateOne)
+ scope.withPrivateField = true;
+
+ return DeclResult::Success;
}
void Compiler :: generateClassFields(ClassScope& scope, SyntaxNode node, bool singleField)
@@ -3355,7 +3377,28 @@ void Compiler :: generateClassFields(ClassScope& scope, SyntaxNode node, bool si
generateClassStaticField(scope, current, attrs);
}
else if (!isClassClassMode) {
- generateClassField(scope, current, attrs, singleField);
+ DeclResult result = DeclResult::Success;
+ if (attrs.privateOne) {
+ IdentifierString privateName(current.findChild(SyntaxKey::Name).firstChild(SyntaxKey::TerminalMask).identifier(), "$");
+ privateName.appendHex(scope.info.inheritLevel);
+
+ result = checkAndGenerateClassField(scope, current, *privateName, attrs, singleField);
+ }
+ else result = checkAndGenerateClassField(scope, current, current.findChild(SyntaxKey::Name).firstChild(SyntaxKey::TerminalMask).identifier(), attrs, singleField);
+
+ switch (result) {
+ case Duplicate:
+ if (attrs.autogenerated) {
+ current.setKey(SyntaxKey::Idle);
+ }
+ else scope.raiseError(errDuplicatedField, current);
+ break;
+ case Illegal:
+ scope.raiseError(errIllegalField, current);
+ break;
+ default:
+ break;
+ }
}
}
@@ -3905,7 +3948,17 @@ void Compiler :: declareClosureMessage(MethodScope& methodScope, SyntaxNode node
methodScope.message = declareClosureParameters(methodScope, argNode);
}
-void Compiler :: declareMethod(MethodScope& methodScope, SyntaxNode node, bool abstractMode, bool staticNotAllowed)
+void Compiler :: declareIteratorMessage(MethodScope& scope, SyntaxNode node)
+{
+ ref_t itAction = scope.module->mapAction(NEXT_MESSAGE, 0, false);
+ scope.message = encodeMessage(itAction, 1, 0);
+
+ scope.info.outputRef = scope.moduleScope->branchingInfo.typeRef;
+ scope.info.hints |= (ref_t)MethodHint::Yieldable;
+}
+
+void Compiler :: declareMethod(MethodScope& methodScope, SyntaxNode node, bool abstractMode,
+ bool staticNotAllowed, bool yieldMethodNotAllowed)
{
if (methodScope.checkHint(MethodHint::Static)) {
if (staticNotAllowed)
@@ -3942,24 +3995,9 @@ void Compiler :: declareMethod(MethodScope& methodScope, SyntaxNode node, bool a
if (methodScope.info.hints)
node.appendChild(SyntaxKey::Hints, methodScope.info.hints);
- if (methodScope.checkHint(MethodHint::Yieldable)) {
- // raise an error if the method has arguments
- if (getArgCount(methodScope.message) > 1 || (test(methodScope.message, FUNCTION_MESSAGE) && getArgCount(methodScope.message) > 0))
- methodScope.raiseError(errIllegalMethod, node);
-
- // raise an error if the class is a struct
- // only a single yield method is allowed
-
- // inject yield context assigning
- node.parentNode()
- .appendChild(SyntaxKey::AssignOperation)
- .appendChild(SyntaxKey::YieldContext, methodScope.message);
-
- // inject yield context field
- node.parentNode()
- .appendChild(SyntaxKey::Field)
- .appendChild(SyntaxKey::Name)
- .appendChild(SyntaxKey::identifier, YIELD_CONTEXT_FIELD);
+ if (methodScope.checkHint(MethodHint::Yieldable) && yieldMethodNotAllowed) {
+ // raise an error if the method must be static
+ methodScope.raiseError(errIllegalMethod, node);
}
}
@@ -5423,6 +5461,51 @@ ref_t Compiler :: resolveTemplate(ModuleScopeBase& moduleScope, ref_t templateRe
templateRef, parameters, declarationMode, nullptr);
}
+ref_t Compiler :: resolveStateMachine(Scope& scope, ref_t templateRef, ref_t elementRef)
+{
+ IdentifierString smName(scope.module->resolveReference(templateRef));
+
+ List parameters({});
+ // HOTFIX : generate a temporal template to pass the type
+ SyntaxTree dummyTree;
+ SyntaxTreeWriter dummyWriter(dummyTree);
+ dummyWriter.newNode(SyntaxKey::Root);
+
+ dummyWriter.newNode(SyntaxKey::TemplateArg, elementRef);
+ dummyWriter.newNode(SyntaxKey::Type);
+
+ ustr_t referenceName = scope.moduleScope->module->resolveReference(elementRef);
+ if (isWeakReference(referenceName)) {
+ dummyWriter.appendNode(SyntaxKey::reference, referenceName);
+ }
+ else dummyWriter.appendNode(SyntaxKey::globalreference, referenceName);
+
+ dummyWriter.closeNode();
+ dummyWriter.closeNode();
+
+ dummyWriter.closeNode();
+
+ SyntaxNode current = dummyTree.readRoot().firstChild();
+ while (current == SyntaxKey::TemplateArg) {
+ parameters.add(current);
+
+ current = current.nextNode();
+ }
+
+ smName.append("#1");
+
+ ref_t templateReference = 0;
+ if (isWeakReference(*smName)) {
+ templateReference = scope.module->mapReference(*smName, true);
+ }
+ else templateReference = scope.moduleScope->mapFullReference(*smName, true);
+
+ NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace);
+
+ return _templateProcessor->generateClassTemplate(*scope.moduleScope,
+ templateReference, parameters, false, nullptr);
+}
+
ref_t Compiler :: resolveClosure(Scope& scope, mssg_t closureMessage, ref_t outputRef)
{
ref_t signRef = 0;
@@ -6178,37 +6261,33 @@ bool Compiler :: evalInitializers(ClassScope& scope, SyntaxNode node)
while (current != SyntaxKey::None) {
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();
-
- 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));
+
+ SyntaxNode lnode = current.findChild(SyntaxKey::Object);
+ 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 (evalClassConstant(fieldName,
+ scope, current.firstChild(SyntaxKey::ScopeMask), target))
+ {
+ current.setKey(SyntaxKey::Idle);
}
- break;
- default:
- evalulated = false;
- break;
- }
+ else scope.raiseError(errInvalidOperation, current);
+ }
+ break;
+ case ObjectKind::StaticField:
+ if (!current.arg.reference) {
+ current.setArgumentReference(compileStaticAssigning(scope, current));
+ }
+ break;
+ default:
+ evalulated = false;
+ break;
}
}
else if (current == SyntaxKey::AddAssignOperation) {
@@ -6255,7 +6334,7 @@ ObjectInfo Compiler :: mapClassSymbol(Scope& scope, ref_t classRef)
ClassInfo info;
scope.moduleScope->loadClassInfo(info, classRef, true);
- classClassRef = info.header.classRef;
+ classClassRef = test(info.header.flags, elClassClass) ? classRef : info.header.classRef;
scope.moduleScope->cachedClassReferences.add(classRef, classClassRef);
}
@@ -7047,7 +7126,7 @@ ObjectInfo Compiler :: mapTerminal(Scope& scope, SyntaxNode node, TypeInfo decla
}
else if (newOp || castOp) {
if (node.key == SyntaxKey::identifier && EAttrs::testAndExclude(attrs, ExpressionAttribute::RetrievingType)) {
- auto varInfo = scope.mapIdentifier(node.identifier(), false, attrs);
+ auto varInfo = scope.mapIdentifier(node.identifier(), false, attrs | ExpressionAttribute::RetrievingType);
if (varInfo.kind != ObjectKind::Unknown) {
retVal = { ObjectKind::Class, varInfo.typeInfo, 0u, newOp ? TargetMode::Creating : TargetMode::Casting };
}
@@ -7694,12 +7773,6 @@ void Compiler :: warnOnUnassignedParameter(SyntaxNode node, Scope& scope, ustr_t
}
}
-inline void clearYieldContext()
-{
- // clearing yield context
-// writer.appendNode(BuildKey::SavingStackDump);
-}
-
ObjectInfo Compiler :: mapConstructorTarget(MethodScope& scope)
{
ObjectInfo classSymbol = mapClassSymbol(scope, scope.getClassRef());
@@ -7726,12 +7799,14 @@ void Compiler :: compileMethodCode(BuildTreeWriter& writer, ClassScope* classSco
writer.appendNode(BuildKey::Assigning, scope.selfLocal);
if (scope.isYieldable()) {
+ StatemachineClassScope* smScope = Scope::getScope(*classScope, Scope::ScopeLevel::Statemachine);
+
Expression expression(this, codeScope, writer);
// reserve the place for the next step
int offset = allocateLocalAddress(codeScope, sizeof(addr_t), false);
- ObjectInfo contextField = classScope->mapField(YIELD_CONTEXT_FIELD, EAttr::None);
+ ObjectInfo contextField = smScope->mapContextField();
expression.writeObjectInfo(contextField);
writer.appendNode(BuildKey::LoadingStackDump);
@@ -7750,9 +7825,6 @@ void Compiler :: compileMethodCode(BuildTreeWriter& writer, ClassScope* classSco
retVal = compileCode(writer, codeScope, bodyNode, scope.closureMode, !_withDebugInfo);
break;
case SyntaxKey::ReturnExpression:
- if (scope.isYieldable()) {
- clearYieldContext();
- }
retVal = compileRetExpression(writer, codeScope, bodyNode, EAttr::None);
break;
case SyntaxKey::ResendDispatch:
@@ -7791,8 +7863,13 @@ void Compiler :: compileMethodCode(BuildTreeWriter& writer, ClassScope* classSco
}
}
+ if (scope.isYieldable()) {
+ Expression expression(this, codeScope, writer);
+
+ expression.writeObjectInfo({ ObjectKind::Singleton, { scope.moduleScope->branchingInfo.typeRef }, scope.moduleScope->branchingInfo.falseRef});
+ }
// if the method returns itself
- if (retVal.kind == ObjectKind::Unknown && !codeScope.withRetStatement) {
+ else if (retVal.kind == ObjectKind::Unknown && !codeScope.withRetStatement) {
Expression expression(this, codeScope, writer);
// NOTE : extension should re
@@ -7806,10 +7883,6 @@ void Compiler :: compileMethodCode(BuildTreeWriter& writer, ClassScope* classSco
}
}
- if (scope.isYieldable()) {
- clearYieldContext();
- }
-
writer.appendNode(BuildKey::CloseFrame);
if (scope.checkHint(MethodHint::Constant)) {
@@ -7823,28 +7896,6 @@ void Compiler :: compileMethodCode(BuildTreeWriter& writer, ClassScope* classSco
}
}
-void Compiler :: compileYieldInitializing(BuildTreeWriter& writer, CodeScope& scope, SyntaxNode node)
-{
- ClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Class);
-
- ObjectInfo contextField = classScope->mapField(YIELD_CONTEXT_FIELD, EAttr::None);
-
- Expression expression(this, scope, writer);
-
- pos_t contextSize = classScope->getMssgAttribute(node.arg.reference, ClassAttribute::YieldContextSize);
-
- writer.appendNode(BuildKey::NilReference);
- writer.appendNode(BuildKey::SavingInStack);
-
- writer.newNode(BuildKey::CreatingStruct, contextSize);
- writer.appendNode(BuildKey::Type, scope.moduleScope->buildins.superReference);
- writer.closeNode();
-
- 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);
@@ -7862,10 +7913,7 @@ void Compiler :: compileInitializerMethod(BuildTreeWriter& writer, MethodScope&
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);
+ compileRootExpression(writer, codeScope, current, EAttr::None);
}
current = current.nextNode();
}
@@ -8487,6 +8535,7 @@ void Compiler :: compileMethod(BuildTreeWriter& writer, MethodScope& scope, Synt
SyntaxNode current = node.firstChild(SyntaxKey::MemberMask);
CodeScope codeScope(&scope);
+
if (scope.info.byRefHandler && !scope.checkHint(MethodHint::InterfaceDispatcher)) {
if (current.key == SyntaxKey::Redirect) {
compileByRefRedirectHandler(writer, scope, node, scope.info.byRefHandler);
@@ -8504,6 +8553,7 @@ void Compiler :: compileMethod(BuildTreeWriter& writer, MethodScope& scope, Synt
return;
}
}
+
beginMethod(writer, scope, node, BuildKey::Method, _withDebugInfo);
switch (current.key) {
@@ -8535,19 +8585,87 @@ void Compiler :: compileMethod(BuildTreeWriter& writer, MethodScope& scope, Synt
codeScope.syncStack(&scope);
endMethod(writer, scope);
- if (scope.isYieldable()) {
- classScope->addMssgAttribute(scope.message, ClassAttribute::YieldContextSize, scope.reserved2);
- }
+ if (_trackingUnassigned && current == SyntaxKey::CodeBlock)
+ checkUnassignedVariables(scope, node);
+}
- if (_trackingUnassigned && current == SyntaxKey::CodeBlock) {
- // warn if the variable was not assigned
- for (auto it = scope.parameters.start(); !it.eof(); ++it) {
- if ((*it).unassigned) {
- warnOnUnassignedParameter(node, scope, it.key());
- }
+void Compiler :: checkUnassignedVariables(MethodScope& scope, SyntaxNode node)
+{
+ // warn if the variable was not assigned
+ for (auto it = scope.parameters.start(); !it.eof(); ++it) {
+ if ((*it).unassigned) {
+ warnOnUnassignedParameter(node, scope, it.key());
}
}
+}
+
+ref_t Compiler :: resolveYieldType(Scope& scope, SyntaxNode node)
+{
+ SyntaxNode current = node.findChild(SyntaxKey::TemplateType);
+ if (current != SyntaxKey::None) {
+ auto typeInfo = resolveStrongTypeAttribute(scope, current.findChild(SyntaxKey::TemplateArg), true, false);
+
+ return typeInfo.typeRef;
+ }
+
+ return scope.moduleScope->buildins.superReference;
+}
+
+void Compiler :: compileYieldMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode node)
+{
+ CodeScope codeScope(&scope);
+ Expression expression(this, codeScope, writer);
+
+ // create yield state machine
+ ref_t nestedRef = scope.moduleScope->mapAnonymous();
+ StatemachineClassScope smScope(&expression.scope, nestedRef);
+ smScope.typeRef = resolveYieldType(scope, node);
+
+ BuildNode buildNode = writer.CurrentNode();
+ while (buildNode != BuildKey::Root)
+ buildNode = buildNode.parentNode();
+
+ BuildTreeWriter nestedWriter(buildNode);
+ compileStatemachineClass(nestedWriter, smScope, node);
+
+ beginMethod(writer, scope, node, BuildKey::Method, _withDebugInfo);
+
+ // new stack frame
+ writer.appendNode(BuildKey::OpenFrame);
+
+ ObjectInfo retVal = { ObjectKind::Object, { nestedRef }, 0 };
+
+ int preservedClosure = 0;
+ expression.compileNestedInitializing(smScope, nestedRef, preservedClosure, nullptr);
+
+ retVal = expression.saveToTempLocal(retVal);
+
+ ObjectInfo contextField = smScope.mapContextField();
+ contextField.kind = ObjectKind::LocalField;
+ contextField.extra = contextField.reference;
+ contextField.argument = retVal.argument;
+ pos_t contextSize = smScope.contextSize;
+
+ writer.appendNode(BuildKey::NilReference);
+ writer.appendNode(BuildKey::SavingInStack);
+
+ writer.newNode(BuildKey::CreatingStruct, contextSize);
+ writer.appendNode(BuildKey::Type, scope.moduleScope->buildins.superReference);
+ writer.closeNode();
+
+ writer.appendNode(BuildKey::SetImmediateField, 0);
+
+ expression.compileAssigning(node, contextField, { ObjectKind::Object }, true);
+
+ expression.compileConverting(node, retVal, scope.info.outputRef,
+ scope.checkHint(MethodHint::Stacksafe));
+
+ codeScope.syncStack(&scope);
+
+ writer.appendNode(BuildKey::CloseFrame);
+
+ endMethod(writer, scope);
}
bool Compiler :: isCompatible(Scope& scope, ObjectInfo source, ObjectInfo target, bool resolvePrimitives)
@@ -9244,6 +9362,96 @@ void Compiler :: compileClosureClass(BuildTreeWriter& writer, ClassScope& scope,
scope.save();
}
+inline void mapUninqueField(ClassInfo::FieldMap& fields, IdentifierString& name, FieldInfo info)
+{
+ size_t pos = name.length();
+ int index = 0;
+ ref_t ref = 0;
+ while (true) {
+ name[pos] = 0;
+ name.appendUInt(index++, 16);
+
+ if (!fields.exist(*name)) {
+ fields.add(*name, info);
+
+ return;
+ }
+ }
+}
+
+void Compiler :: compileIteratorMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode node)
+{
+ StatemachineClassScope* classScope = Scope::getScope(scope, Scope::ScopeLevel::Statemachine);
+
+ assert(!scope.info.byRefHandler);
+
+ beginMethod(writer, scope, node, BuildKey::Method, false);
+
+ CodeScope codeScope(&scope);
+
+ 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;
+ }
+
+ codeScope.syncStack(&scope);
+
+ endMethod(writer, scope);
+
+ classScope->contextSize = scope.reserved2;
+
+ if (_trackingUnassigned && current == SyntaxKey::CodeBlock)
+ checkUnassignedVariables(scope, node);
+}
+
+void Compiler :: compileStatemachineClass(BuildTreeWriter& writer, StatemachineClassScope& scope, SyntaxNode node)
+{
+ ref_t parentRef = resolveStateMachine(scope, scope.moduleScope->buildins.yielditTemplateReference, scope.typeRef);
+
+ declareClassParent(parentRef, scope, node);
+ generateClassFlags(scope, elNestedClass | elSealed);
+
+ scope.info.attributes.exclude({ 0, ClassAttribute::RuntimeLoadable });
+
+ writer.newNode(BuildKey::Class, scope.reference);
+
+ NamespaceScope* ns = Scope::getScope(scope, Scope::ScopeLevel::Namespace);
+ if (_withDebugInfo)
+ writer.appendNode(BuildKey::Path, *ns->sourcePath);
+
+ MethodScope methodScope(&scope);
+ declareIteratorMessage(methodScope, node);
+
+ compileIteratorMethod(writer, methodScope, node);
+
+ // handle the abstract flag
+ if (test(scope.info.header.flags, elAbstract)) {
+ scope.abstractBasedMode = true;
+ scope.info.header.flags &= ~elAbstract;
+ }
+
+ auto m_it = scope.info.methods.getIt(methodScope.message);
+ if (!m_it.eof()) {
+ (*m_it).inherited = true;
+ (*m_it).hints &= ~(ref_t)MethodHint::Abstract;
+ (*m_it).hints &= (ref_t)MethodHint::Yieldable;
+ }
+ else scope.info.methods.add(methodScope.message, methodScope.info);
+
+ // 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();
+}
+
void Compiler :: compileVMT(BuildTreeWriter& writer, ClassScope& scope, SyntaxNode node,
bool exclusiveMode, bool ignoreAutoMultimethod)
{
@@ -9325,7 +9533,10 @@ void Compiler :: compileClassVMT(BuildTreeWriter& writer, ClassScope& classClass
_errorProcessor->info(infoCurrentMethod, *messageName);
#endif // FULL_OUTOUT_INFO
- compileMethod(writer, methodScope, current);
+ if (methodScope.isYieldable()) {
+ compileYieldMethod(writer, methodScope, current);
+ }
+ else compileMethod(writer, methodScope, current);
break;
}
@@ -9733,6 +9944,7 @@ void Compiler :: prepare(ModuleScopeBase* moduleScope, ForwardResolverBase* forw
moduleScope->buildins.closureTemplateReference = safeMapWeakReference(moduleScope, forwardResolver, CLOSURE_FORWARD);
moduleScope->buildins.tupleTemplateReference = safeMapWeakReference(moduleScope, forwardResolver, TUPLE_FORWARD);
+ moduleScope->buildins.yielditTemplateReference = safeMapWeakReference(moduleScope, forwardResolver, YIELDIT_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);
@@ -10828,15 +11040,10 @@ void Compiler::Class :: declare(SyntaxNode node)
bool withConstructors = false;
bool withDefConstructor = false;
- bool yieldMethodNotAllowed = test(scope.info.header.flags, elWithYieldable) || test(declaredFlags, elStructureRole);
+ bool yieldMethodNotAllowed = !test(declaredFlags, elStateless);
compiler->declareVMT(scope, node, withConstructors, withDefConstructor,
yieldMethodNotAllowed, false, test(declaredFlags, elTemplatebased));
- if (yieldMethodNotAllowed && !test(scope.info.header.flags, elWithYieldable) && !test(declaredFlags, elStructureRole)) {
- // HOTFIX : trying to figure out if the yield method was declared inside declareVMT
- declaredFlags |= elWithYieldable;
- }
-
// NOTE : generateClassDeclaration should be called for the proper class before a class class one
// due to dynamic array implementation (auto-generated default constructor should be removed)
compiler->generateClassDeclaration(scope, node, declaredFlags);
@@ -10998,6 +11205,18 @@ void Compiler::Class :: load()
scope.abstractMode = test(scope.info.header.flags, elAbstract);
if (test(scope.info.header.flags, elExtension))
scope.extensionClassRef = scope.getAttribute(ClassAttribute::ExtensionRef);
+
+ // check if the class have private fields
+ for (auto it = scope.info.fields.start(); !it.eof(); ++it) {
+ if (FieldInfo::checkHint(*it, FieldHint::Private)) {
+ IdentifierString postfix("$");
+ postfix.appendInt(scope.info.inheritLevel);
+ if (it.key().endsWith(*postfix)) {
+ scope.withPrivateField = true;
+ break;
+ }
+ }
+ }
}
// --- Compiler::ClassClass ---
@@ -11054,6 +11273,9 @@ void Compiler::Method :: compile(BuildTreeWriter& writer, SyntaxNode current)
else if (scope.checkHint(MethodHint::Initializer)) {
compiler->compileInitializerMethod(writer, scope, current.parentNode());
}
+ else if (scope.checkHint(MethodHint::Yieldable)) {
+ compiler->compileYieldMethod(writer, scope, current);
+ }
// if it is a normal method
else compiler->compileMethod(writer, scope, current);
}
@@ -11067,9 +11289,9 @@ void Compiler::Method :: compileConstructor(BuildTreeWriter& writer, SyntaxNode
#ifdef FULL_OUTOUT_INFO
IdentifierString messageName;
- ByteCodeUtil::resolveMessageName(messageName, scope.module, methodScope.message);
+ ByteCodeUtil::resolveMessageName(messageName, scope.module, scope.message);
- _errorProcessor->info(infoCurrentMethod, *messageName);
+ compiler->_errorProcessor->info(infoCurrentMethod, *messageName);
#endif // FULL_OUTOUT_INFO
compiler->compileConstructor(writer, scope, classClassScope, current, classScope->isAbstract());
@@ -11757,21 +11979,33 @@ 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);
+ StatemachineClassScope* smScope = Scope::getScope(scope, Scope::ScopeLevel::Statemachine);
if (!methodScope->isYieldable())
scope.raiseError(errInvalidOperation, node);
- ObjectInfo contextField = classScope->mapField(YIELD_CONTEXT_FIELD, EAttr::None);
+ ObjectInfo contextField = smScope->mapContextField();
+ ObjectInfo currentField = smScope->mapCurrentField();
writer->newNode(BuildKey::YieldingOp, -scope.moduleScope->ptrSize);
writer->newNode(BuildKey::Tape);
- writeObjectInfo(contextField, node);
+ ObjectInfo retVal = compile(node.firstChild(), 0, EAttr::None, nullptr);
+
+ bool nillableOp = false;
+ if (!compileAssigningOp(currentField, retVal, nillableOp))
+ scope.raiseError(errInvalidOperation, node);
+
+ if (nillableOp)
+ scope.raiseWarning(WARNING_LEVEL_1, wrnReturningNillable, node);
+ writeObjectInfo(contextField, node);
writer->appendNode(BuildKey::SavingStackDump);
- compiler->compileRetExpression(*writer, *codeScope, node, EAttr::None);
+ // returning true
+ writeObjectInfo({ ObjectKind::Singleton, { scope.moduleScope->branchingInfo.typeRef }, scope.moduleScope->branchingInfo.trueRef });
+
+ writer->appendNode(BuildKey::goingToEOP);
writer->closeNode();
writer->closeNode();
@@ -12900,6 +13134,80 @@ ObjectInfo Compiler::Expression :: compileExternalOp(SyntaxNode node, ref_t exte
return { ObjectKind::Extern, retType, 0 };
}
+
+void Compiler::Expression :: compileNestedInitializing(InlineClassScope& classScope, ref_t nestedRef, int& preservedClosure,
+ ArgumentsInfo* updatedOuterArgs)
+{
+ 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;
+ }
+
+ 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());
+ }
+ }
+
+ // second pass : fill members
+ int argIndex = 0;
+ preservedClosure = 0;
+ for (auto it = classScope.outers.start(); !it.eof(); ++it) {
+ ObjectInfo source = (*it).outerObject;
+ ObjectInfo arg = list[argIndex];
+
+ auto fieldInfo = classScope.info.fields.get(it.key());
+
+ 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({ });
+ }
+
+ updatedOuterArgs->add({ ObjectKind::MemberInfo, (*it).reference });
+ updatedOuterArgs->add(source);
+ }
+
+ argIndex++;
+ }
+}
+
ObjectInfo Compiler::Expression :: compileNewArrayOp(SyntaxNode node, ObjectInfo source, ref_t targetRef, ArgumentsInfo& arguments)
{
ref_t sourceRef = compiler->resolveStrongType(scope, source.typeInfo);
@@ -13779,6 +14087,7 @@ bool Compiler::Expression :: compileAssigningOp(ObjectInfo target, ObjectInfo ex
bool stackSafe = false;
bool fieldMode = false;
bool fieldFieldMode = false;
+ bool localFieldMode = false;
bool accMode = false;
bool lenRequired = false;
@@ -13888,6 +14197,12 @@ bool Compiler::Expression :: compileAssigningOp(ObjectInfo target, ObjectInfo ex
break;
}
+ case ObjectKind::LocalField:
+ localFieldMode = true;
+ operationType = BuildKey::FieldAssigning;
+ operand = target.extra;
+
+ break;
default:
return false;
}
@@ -13908,6 +14223,10 @@ bool Compiler::Expression :: compileAssigningOp(ObjectInfo target, ObjectInfo ex
writer->appendNode(BuildKey::SavingInStack, 0);
writeObjectInfo(target);
}
+ else if (localFieldMode) {
+ writer->appendNode(BuildKey::SavingInStack, 0);
+ writeObjectInfo({ ObjectKind::Local, target.reference });
+ }
writer->newNode(operationType, operand);
if (size != 0) {
@@ -14237,74 +14556,8 @@ ObjectInfo Compiler::Expression :: compileNested(InlineClassScope& classScope, E
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;
- }
-
- 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());
- }
- }
-
- // 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];
-
- auto fieldInfo = classScope.info.fields.get(it.key());
-
- 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({ });
- }
-
- updatedOuterArgs->add({ ObjectKind::MemberInfo, (*it).reference });
- updatedOuterArgs->add(source);
- }
-
- argIndex++;
- }
+ compileNestedInitializing(classScope, nestedRef, preservedClosure, updatedOuterArgs);
// call init handler if is available
if (classScope.info.methods.exist(scope.moduleScope->buildins.init_message)) {
diff --git a/elenasrc3/elc/compiler.h b/elenasrc3/elc/compiler.h
index a6dd2646e..80f84f684 100644
--- a/elenasrc3/elc/compiler.h
+++ b/elenasrc3/elc/compiler.h
@@ -120,6 +120,13 @@ namespace elena_lang
Weak,
};
+ enum DeclResult : int
+ {
+ Success = 0,
+ Duplicate = 1,
+ Illegal = 2
+ };
+
struct ObjectInfo
{
ObjectKind kind;
@@ -355,6 +362,7 @@ namespace elena_lang
Symbol,
Class,
OwnerClass,
+ Statemachine,
Method,
Field,
Code,
@@ -614,6 +622,7 @@ namespace elena_lang
bool abstractMode;
bool abstractBasedMode;
bool extensionDispatcher;
+ bool withPrivateField;
Scope* getScope(ScopeLevel level) override
{
@@ -666,6 +675,7 @@ namespace elena_lang
ObjectInfo mapMember(ustr_t identifier) override;
virtual ObjectInfo mapField(ustr_t identifier, ExpressionAttribute attr);
+ ObjectInfo mapPrivateField(ustr_t identifier, ExpressionAttribute attr);
ObjectInfo mapIdentifier(ustr_t identifier, bool referenceOne, ExpressionAttribute attr) override;
@@ -1031,6 +1041,28 @@ namespace elena_lang
InlineClassScope(ExprScope* owner, ref_t reference);
};
+ struct StatemachineClassScope : InlineClassScope
+ {
+ pos_t contextSize;
+ ref_t typeRef;
+
+ ObjectInfo mapContextField()
+ {
+ return { ObjectKind::Field };
+ }
+ ObjectInfo mapCurrentField();
+
+ Scope* getScope(ScopeLevel level) override
+ {
+ if (level == ScopeLevel::Statemachine) {
+ return this;
+ }
+ else return InlineClassScope::getScope(level);
+ }
+
+ StatemachineClassScope(ExprScope* owner, ref_t reference);
+ };
+
struct MessageResolution
{
bool resolved;
@@ -1310,6 +1342,9 @@ namespace elena_lang
ObjectInfo allocateResult(ref_t resultRef);
+ void compileNestedInitializing(InlineClassScope& classScope, ref_t nestedRef, int& preservedClosure,
+ ArgumentsInfo* updatedOuterArgs);
+
void compileYieldOperation(SyntaxNode node);
void compileSwitchOperation(SyntaxNode node);
@@ -1392,6 +1427,8 @@ namespace elena_lang
void saveFrameAttributes(BuildTreeWriter& writer, Scope& scope, pos_t reserved, pos_t reservedN);
+ ref_t resolveYieldType(Scope& scope, SyntaxNode node);
+
pos_t saveMetaInfo(ModuleBase* module, ustr_t value, ustr_t postfix);
ref_t mapNewTerminal(Scope& scope, ustr_t prefix, SyntaxNode nameNode, ustr_t postfix, Visibility visibility, bool ignoreDuplicates = false);
@@ -1432,6 +1469,7 @@ namespace elena_lang
ref_t resolveTemplate(ModuleScopeBase& moduleScope, ref_t templateRef, ref_t elementRef, bool declarationMode);
ref_t resolveClosure(Scope& scope, mssg_t closureMessage, ref_t outputRef);
+ ref_t resolveStateMachine(Scope& scope, ref_t templateRef, ref_t stateRef);
ref_t resolveWrapperTemplate(ModuleScopeBase& moduleScope, ref_t elementRef, bool declarationMode);
ref_t resolveArrayTemplate(ModuleScopeBase& moduleScope, ref_t elementRef, bool declarationMode);
//ref_t resolveNullableTemplate(ModuleScopeBase& moduleScope, ustr_t ns, ref_t elementRef, bool declarationMode);
@@ -1489,7 +1527,7 @@ namespace elena_lang
Scope::ScopeLevel level, bool shareMode);
void declareVMT(ClassScope& scope, SyntaxNode node, bool& withConstructors, bool& withDefaultConstructor,
- bool& yieldMethodNotAllowed, bool staticNotAllowed, bool templateBased);
+ bool yieldMethodNotAllowed, bool staticNotAllowed, bool templateBased);
void registerTemplateSignature(TemplateScope& scope, SyntaxNode node, IdentifierString& signature);
void registerExtensionTemplateMethod(TemplateScope& scope, SyntaxNode& node);
@@ -1508,6 +1546,8 @@ namespace elena_lang
void checkMethodDuplicates(ClassScope& scope, SyntaxNode node, mssg_t message,
mssg_t publicMessage, bool protectedOne, bool internalOne);
+ void checkUnassignedVariables(MethodScope& scope, SyntaxNode node);
+
ref_t generateConstant(Scope& scope, ObjectInfo& info, ref_t reference, bool saveScope = true);
mssg_t defineOutRefMethod(ClassScope& scope, SyntaxNode node, bool isExtension);
@@ -1526,7 +1566,7 @@ namespace elena_lang
MethodInfo& methodInfo, bool abstractBased);
void generateMethodDeclaration(ClassScope& scope, SyntaxNode node, bool closed, bool hideDuplicate);
void generateMethodDeclarations(ClassScope& scope, SyntaxNode node, SyntaxKey methodKey, bool closed);
- void generateClassField(ClassScope& scope, SyntaxNode node, FieldAttributes& attrs, bool singleField);
+ DeclResult checkAndGenerateClassField(ClassScope& scope, SyntaxNode node, ustr_t name, FieldAttributes& attrs, bool singleField);
void generateClassStaticField(ClassScope& scope, SyntaxNode node, FieldAttributes& attrs);
void generateClassFields(ClassScope& scope, SyntaxNode node, bool singleField);
void generateClassDeclaration(ClassScope& scope, SyntaxNode node, ref_t declaredFlags);
@@ -1546,6 +1586,7 @@ namespace elena_lang
void declareVMTMessage(MethodScope& scope, SyntaxNode node, bool withoutWeakMessages, bool declarationMode);
void declareClosureMessage(MethodScope& scope, SyntaxNode node);
+ void declareIteratorMessage(MethodScope& scope, SyntaxNode node);
void initializeMethod(ClassScope& scope, MethodScope& methodScope, SyntaxNode current);
@@ -1553,7 +1594,8 @@ namespace elena_lang
void declareMetaInfo(Scope& scope, SyntaxNode node);
void declareMethodMetaInfo(MethodScope& scope, SyntaxNode node);
- void declareMethod(MethodScope& scope, SyntaxNode node, bool abstractMode, bool staticNotAllowed);
+ void declareMethod(MethodScope& scope, SyntaxNode node, bool abstractMode,
+ bool staticNotAllowed, bool yieldMethodNotAllowed);
void declareSymbol(SymbolScope& scope, SyntaxNode node);
@@ -1670,18 +1712,20 @@ namespace elena_lang
void compileDispatcherMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode node,
bool withGenerics, bool withOpenArgGenerics);
- void compileYieldInitializing(BuildTreeWriter& writer, CodeScope& scope, SyntaxNode node);
void compileInitializerMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode classNode);
void compileStaticInitializerMethod(BuildTreeWriter& writer, ClassScope& scope, SyntaxNode classNode);
void compileClosureMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode node);
+ void compileIteratorMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode node);
void compileExpressionMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode node);
void compileAbstractMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode node, bool abstractMode);
void compileMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode node);
+ void compileYieldMethod(BuildTreeWriter& writer, MethodScope& scope, SyntaxNode node);
void compileConstructor(BuildTreeWriter& writer, MethodScope& scope, ClassScope& classClassScope,
SyntaxNode node, bool abstractMode);
void compileCustomDispatcher(BuildTreeWriter& writer, ClassScope& scope);
void compileNestedClass(BuildTreeWriter& writer, ClassScope& scope, SyntaxNode node, ref_t parentRef);
void compileClosureClass(BuildTreeWriter& writer, ClassScope& scope, SyntaxNode node);
+ void compileStatemachineClass(BuildTreeWriter& writer, StatemachineClassScope& scope, SyntaxNode node);
void compileVMT(BuildTreeWriter& writer, ClassScope& scope, SyntaxNode node,
bool exclusiveMode = false, bool ignoreAutoMultimethod = false);
diff --git a/elenasrc3/elc/compilerlogic.cpp b/elenasrc3/elc/compilerlogic.cpp
index 7a0bb22c2..519184bd4 100644
--- a/elenasrc3/elc/compilerlogic.cpp
+++ b/elenasrc3/elc/compilerlogic.cpp
@@ -904,6 +904,9 @@ bool CompilerLogic :: validateFieldAttribute(ref_t attribute, FieldAttributes& a
case V_OVERRIDE:
attrs.overrideMode = true;
break;
+ case V_PRIVATE:
+ attrs.privateOne = true;
+ break;
default:
return false;
}
@@ -3023,7 +3026,7 @@ pos_t CompilerLogic :: definePadding(ModuleScopeBase& scope, pos_t offset, pos_t
bool CompilerLogic :: validateDispatcherType(ClassInfo& classInfo)
{
bool isProxy = classInfo.fields.count() == 1 && test(classInfo.header.flags, elWithCustomDispatcher | elNestedClass | elSealed)
- && !testany(classInfo.header.flags, elWithGenerics | elWithVariadics | elWithYieldable | elStructure);
+ && !testany(classInfo.header.flags, elWithGenerics | elWithVariadics | elStructure);
if (isProxy && (classInfo.header.flags & elDebugMask) == 0) {
classInfo.header.flags |= elProxy;
diff --git a/elenasrc3/elena-tests/bt_optimization.cpp b/elenasrc3/elena-tests/bt_optimization.cpp
index ae071e9bb..9855ae24e 100644
--- a/elenasrc3/elena-tests/bt_optimization.cpp
+++ b/elenasrc3/elena-tests/bt_optimization.cpp
@@ -130,7 +130,7 @@ void BTOptimization :: SetUp()
afterOptimization = buildTree.readRoot().appendChild(BuildKey::Tape);
}
-void BTOptimization :: runCompilerTest(bool declareOperators)
+void BTOptimization :: runBuildTest(bool declareOperators)
{
// Arrange
ModuleScopeBase* moduleScope = env.createModuleScope(true);
diff --git a/elenasrc3/elena-tests/bt_optimization.h b/elenasrc3/elena-tests/bt_optimization.h
index 027e85330..48d1b5b85 100644
--- a/elenasrc3/elena-tests/bt_optimization.h
+++ b/elenasrc3/elena-tests/bt_optimization.h
@@ -32,7 +32,7 @@ namespace elena_lang
public:
void runBTTest();
- void runCompilerTest(bool declareOperators);
+ void runBuildTest(bool declareOperators);
};
class StructTest : public testing::Test
diff --git a/elenasrc3/elena-tests/build_tests.cpp b/elenasrc3/elena-tests/build_tests.cpp
new file mode 100644
index 000000000..dec6425ae
--- /dev/null
+++ b/elenasrc3/elena-tests/build_tests.cpp
@@ -0,0 +1,83 @@
+#include "pch.h"
+// ------------------------------------------------
+#include "bt_optimization.h"
+
+#include "compiler.h"
+
+using namespace elena_lang;
+
+TEST_F(BTOptimization1_1, BuildTest)
+{
+ runBuildTest(false);
+}
+
+TEST_F(BTOptimization1_2, BuildTest)
+{
+ runBuildTest(false);
+}
+
+TEST_F(BTOptimization1_3, BuildTest)
+{
+ runBuildTest(true);
+}
+
+TEST_F(BTOptimization2, BuildTest)
+{
+ runBuildTest(false);
+}
+
+TEST_F(BTOptimization4, BuildTest)
+{
+ runBuildTest(false);
+}
+
+TEST_F(StructAlignment, BuildTest)
+{
+ runTest();
+}
+
+TEST_F(PackedStructAlignment, BuildTest)
+{
+ runTest();
+}
+
+TEST_F(VariadicRuntimeSingleDispatch, BuildTest)
+{
+ runTest();
+}
+
+TEST_F(VariadicCompiletimeSingleDispatch, BuildTest)
+{
+ runTest();
+}
+
+TEST_F(CallMethodWithoutTarget, BuildTest)
+{
+ runTest(false);
+}
+
+TEST_F(CallVariadocMethodWithoutTarget, BuildTest)
+{
+ runTest(false);
+}
+
+// Test scenario : E.load(new C(), new D()); where: class E { constructor load(params B[] args) {}}, C:B and D:B
+TEST_F(VariadicCompiletimeSingleDispatch_WithDifferentArgs, BuildTest)
+{
+ runTest();
+}
+
+TEST_F(Lambda_CallingPrivateMethod, BuildTest)
+{
+ runTest();
+}
+
+TEST_F(IntAssigningNil, BuildTest)
+{
+ runTest(true);
+}
+
+TEST_F(NillableIntAssigning, BuildTest)
+{
+ runTest(false);
+}
\ No newline at end of file
diff --git a/elenasrc3/elena-tests/compile_tests.cpp b/elenasrc3/elena-tests/compile_tests.cpp
new file mode 100644
index 000000000..3858e7c39
--- /dev/null
+++ b/elenasrc3/elena-tests/compile_tests.cpp
@@ -0,0 +1,88 @@
+#include "pch.h"
+// ------------------------------------------------
+#include "serializer.h"
+#include "bcwriter.h"
+
+#include "compile_tests.h"
+#include "scenario_consts.h"
+
+using namespace elena_lang;
+
+// ==== Tests Scenarios ===
+
+constexpr auto PrivateField_Scenario1 = "class (nameattr (identifier \"A\" ())field (attribute -2147467262 ()nameattr (identifier \"_x\" ()))method (nameattr (identifier \"setX\" ())code (expression (assign_operation (object (identifier \"_x\" ())expression (object (integer \"2\" ())))))))class (nameattr 62 (identifier \"B\" ())parent (type (identifier \"A\" ()))method (nameattr (identifier \"setParentX\" ())code (expression (assign_operation (object (identifier \"_x\" ())expression (object (integer \"2\" ())))))))";
+
+// --- CompileScenarioTest ---
+
+void CompileScenarioTest :: SetUp()
+{
+ CompileTest::SetUp();
+}
+
+void CompileScenarioTest :: runTest(ref_t targetRef, int exptectedError)
+{
+ // Arrange
+ ModuleScopeBase* moduleScope = env.createModuleScope(true);
+ moduleScope->buildins.superReference = 1;
+ moduleScope->buildins.intReference = intReference;
+ moduleScope->buildins.constructor_message =
+ encodeMessage(moduleScope->module->mapAction(CONSTRUCTOR_MESSAGE, 0, false),
+ 0, FUNCTION_MESSAGE);
+
+ moduleScope->aliases.add("int", intReference);
+
+ Compiler* compiler = env.createCompiler();
+
+ BuildTree output;
+ BuildTreeWriter writer(output);
+ Compiler::Namespace nsScope(compiler, moduleScope, TestErrorProcessor::getInstance(), nullptr, nullptr);
+
+ // Act
+ nsScope.declare(declarationNode.firstChild(), true);
+
+ Compiler::Class classHelper(nsScope, targetRef, Visibility::Public);
+ classHelper.load();
+ Compiler::Method methodHelper(classHelper);
+
+ SyntaxNode methodNode = findTargetNode(targetRef);
+ int catchedError = 0;
+ try
+ {
+ methodHelper.compile(writer, methodNode);
+ }
+ catch (TestException& ex) {
+ catchedError = ex.code;
+ }
+
+ // Assess
+ EXPECT_TRUE(exptectedError == catchedError);
+}
+
+SyntaxNode CompileScenarioTest :: findTargetNode(ref_t targetRef)
+{
+ return findClassNode(targetRef).findChild(SyntaxKey::Method);
+}
+
+SyntaxNode CompileScenarioTest :: findClassNode(ref_t targetRef)
+{
+ return SyntaxTree::gotoChild(declarationNode.firstChild(), SyntaxKey::Class, targetRef);
+}
+
+// --- CallPrivateConstructorDirectly ---
+
+void AccessPrivateField :: SetUp()
+{
+ CompileScenarioTest::SetUp();
+
+ LoadDeclarationScenario(S_DefaultNamespace_3, S_IntNumber, PrivateField_Scenario1);
+}
+
+TEST_F(AccessPrivateField, AccessPrivateFieldTest)
+{
+ runTest(3, 0);
+}
+
+TEST_F(AccessPrivateField, AccessParentPrivateFieldTest)
+{
+ runTest(4, 106);
+}
diff --git a/elenasrc3/elena-tests/compile_tests.h b/elenasrc3/elena-tests/compile_tests.h
new file mode 100644
index 000000000..b68d42f64
--- /dev/null
+++ b/elenasrc3/elena-tests/compile_tests.h
@@ -0,0 +1,36 @@
+//---------------------------------------------------------------------------
+// E L E N A P r o j e c t: ELENA Compiler
+//
+// This header contains ELENA Compile Test Fixture declarations
+// (C)2024, by Aleksey Rakov
+//---------------------------------------------------------------------------
+
+#ifndef COMPILE_TESTS_H
+#define COMPILE_TESTS_H
+
+#include "tests_common.h"
+
+namespace elena_lang
+{
+ class CompileScenarioTest : public CompileTest
+ {
+ protected:
+ ref_t intReference;
+
+ virtual SyntaxNode findTargetNode(ref_t targetRef);
+ virtual SyntaxNode findClassNode(ref_t targetRef);
+
+ void SetUp() override;
+
+ public:
+ void runTest(ref_t targetRef, int exptectedError);
+ };
+
+ class AccessPrivateField : public CompileScenarioTest
+ {
+ protected:
+ void SetUp() override;
+ };
+}
+
+#endif
diff --git a/elenasrc3/elena-tests/compiler_tests.cpp b/elenasrc3/elena-tests/compiler_tests.cpp
deleted file mode 100644
index 41c2566db..000000000
--- a/elenasrc3/elena-tests/compiler_tests.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-#include "pch.h"
-// ------------------------------------------------
-#include "bt_optimization.h"
-
-#include "compiler.h"
-
-using namespace elena_lang;
-
-TEST_F(BTOptimization1_1, CompilerTest)
-{
- runCompilerTest(false);
-}
-
-TEST_F(BTOptimization1_2, CompilerTest)
-{
- runCompilerTest(false);
-}
-
-TEST_F(BTOptimization1_3, CompilerTest)
-{
- runCompilerTest(true);
-}
-
-TEST_F(BTOptimization2, CompilerTest)
-{
- runCompilerTest(false);
-}
-
-TEST_F(BTOptimization4, CompilerTest)
-{
- runCompilerTest(false);
-}
-
-TEST_F(StructAlignment, CompilerTest)
-{
- runTest();
-}
-
-TEST_F(PackedStructAlignment, CompilerTest)
-{
- runTest();
-}
-
-TEST_F(VariadicRuntimeSingleDispatch, CompilerTest)
-{
- runTest();
-}
-
-TEST_F(VariadicCompiletimeSingleDispatch, CompilerTest)
-{
- runTest();
-}
-
-TEST_F(CallMethodWithoutTarget, CompilerTest)
-{
- runTest(false);
-}
-
-TEST_F(CallVariadocMethodWithoutTarget, CompilerTest)
-{
- runTest(false);
-}
-
-// Test scenario : E.load(new C(), new D()); where: class E { constructor load(params B[] args) {}}, C:B and D:B
-TEST_F(VariadicCompiletimeSingleDispatch_WithDifferentArgs, CompilerTest)
-{
- runTest();
-}
-
-TEST_F(Lambda_CallingPrivateMethod, CompilerTest)
-{
- runTest();
-}
-
-TEST_F(IntAssigningNil, CompilerTest)
-{
- runTest(true);
-}
-
-TEST_F(NillableIntAssigning, CompilerTest)
-{
- runTest(false);
-}
\ No newline at end of file
diff --git a/elenasrc3/elena-tests/elena-tests.vcxproj b/elenasrc3/elena-tests/elena-tests.vcxproj
index 3ce4af8c8..3dbb030e5 100644
--- a/elenasrc3/elena-tests/elena-tests.vcxproj
+++ b/elenasrc3/elena-tests/elena-tests.vcxproj
@@ -135,6 +135,7 @@
+
@@ -158,8 +159,9 @@
-
+
+
diff --git a/elenasrc3/elena-tests/tests_common.cpp b/elenasrc3/elena-tests/tests_common.cpp
index fb5df504f..e240f1c4f 100644
--- a/elenasrc3/elena-tests/tests_common.cpp
+++ b/elenasrc3/elena-tests/tests_common.cpp
@@ -403,6 +403,16 @@ void ScenarioTest::SetUp()
controlOutputNode = buildTree.readRoot().appendChild(BuildKey::Tape);
}
+// --- CompileTest ---
+
+void CompileTest :: SetUp()
+{
+ SyntaxTreeWriter writer(syntaxTree);
+ writer.appendNode(SyntaxKey::Root);
+
+ declarationNode = syntaxTree.readRoot().appendChild(SyntaxKey::Idle, 1);
+}
+
// --- MethodScenarioTest ---
void MethodScenarioTest :: runTest(bool withProtectedConstructor, bool withAttributes)
diff --git a/elenasrc3/elena-tests/tests_common.h b/elenasrc3/elena-tests/tests_common.h
index e8ca1ec8a..cfeef7ebc 100644
--- a/elenasrc3/elena-tests/tests_common.h
+++ b/elenasrc3/elena-tests/tests_common.h
@@ -234,6 +234,13 @@ namespace elena_lang
void SetUp() override;
};
+ // --- ScenarioTest ---
+ class CompileTest : public BaseFixture
+ {
+ protected:
+ void SetUp() override;
+ };
+
// --- MethodScenarioTest ---
class MethodScenarioTest : public ScenarioTest
{
diff --git a/elenasrc3/elenavm/elenavmmachine.cpp b/elenasrc3/elenavm/elenavmmachine.cpp
index 1d28c3c66..0fd65bde7 100644
--- a/elenasrc3/elenavm/elenavmmachine.cpp
+++ b/elenasrc3/elenavm/elenavmmachine.cpp
@@ -113,7 +113,7 @@ ELENAVMMachine :: ELENAVMMachine(path_t configPath, PresenterBase* presenter, Pl
}
ustr_t ELENAVMMachine::getArchitectureName() {
-#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__)
+#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) || defined(__aarch64__)
return "64-bit";
#else
return "32-bit";
diff --git a/elenasrc3/engine/bytecode.cpp b/elenasrc3/engine/bytecode.cpp
index 4fe89ba0f..abe181f55 100644
--- a/elenasrc3/engine/bytecode.cpp
+++ b/elenasrc3/engine/bytecode.cpp
@@ -313,9 +313,6 @@ void ByteCodeUtil :: generateAutoSymbol(ModuleInfoList& symbolList, ModuleBase*
pos_t sizePlaceholder = writer.position();
writer.writePos(0);
- pos_t command = 0;
- ustr_t strArg = nullptr;
-
ByteCodeUtil::write(writer, ByteCode::OpenIN, 2, 0);
// generate the preloaded list
diff --git a/elenasrc3/engine/elena.h b/elenasrc3/engine/elena.h
index d545cbeb2..81ed93fe4 100644
--- a/elenasrc3/engine/elena.h
+++ b/elenasrc3/engine/elena.h
@@ -1093,14 +1093,6 @@ namespace elena_lang
}
};
- // --- FieldInfo ---
- struct FieldInfo
- {
- int offset;
- TypeInfo typeInfo;
- bool readOnly;
- };
-
// --- StaticFieldInfo ---
struct StaticFieldInfo
{
diff --git a/elenasrc3/engine/elenaconst.h b/elenasrc3/engine/elenaconst.h
index 1d5faed3e..d60c23020 100644
--- a/elenasrc3/engine/elenaconst.h
+++ b/elenasrc3/engine/elenaconst.h
@@ -13,7 +13,7 @@ namespace elena_lang
{
// --- Common ELENA Engine constants ---
#define ENGINE_MAJOR_VERSION 6 // ELENA Engine version
- #define ENGINE_MINOR_VERSION 3
+ #define ENGINE_MINOR_VERSION 4
constexpr auto LINE_LEN = 0x1000; // the maximal source line length
constexpr auto IDENTIFIER_LEN = 0x0300; // the maximal identifier length
@@ -26,11 +26,11 @@ namespace elena_lang
constexpr auto MESSAGE_FLAG_MASK = 0x1E0u;
constexpr auto STATIC_MESSAGE = 0x100u;
- constexpr auto FUNCTION_MESSAGE = 0x020u; // indicates it is an invoke message (without target variable in the call stack)
+ constexpr auto FUNCTION_MESSAGE = 0x020u; // indicates it is an invoke message (without target variable in the call stack)
constexpr auto CONVERSION_MESSAGE = 0x040u;
constexpr auto VARIADIC_MESSAGE = 0x080u;
constexpr auto PROPERTY_MESSAGE = 0x0C0u;
- constexpr auto PREFIX_MESSAGE_MASK = 0x0C0u; // HOTFIX : is used to correctly identify VARIADIC_MESSAGE or PROPERTY_MESSAGE
+ constexpr auto PREFIX_MESSAGE_MASK = 0x0C0u; // HOTFIX : is used to correctly identify VARIADIC_MESSAGE or PROPERTY_MESSAGE
constexpr auto ARG_COUNT = 0x01Eu;
constexpr auto ARG_MASK = 0x01Fu;
@@ -38,7 +38,7 @@ namespace elena_lang
// --- ELENA Module structure constants ---
constexpr auto ELENA_SIGNITURE = "ELENA."; // the stand alone image
constexpr auto ELENA_VM_SIGNITURE = "VM.ELENA."; // the stand alone image
- constexpr auto MODULE_SIGNATURE = "ELENA.0620"; // the module version
+ constexpr auto MODULE_SIGNATURE = "ELENA.0604"; // the module version
constexpr auto DEBUG_MODULE_SIGNATURE = "ED.06";
// --- ELENA core module names ---
@@ -69,7 +69,7 @@ namespace elena_lang
constexpr auto TEMPLATE_PREFIX_NS_ENCODED = "@$auto@";
constexpr auto FORWARD_PREFIX_NS = "$forwards'";
constexpr auto AUTO_SYMBOL_PREFIX = "@autosymbol";
- constexpr auto INLINE_CLASSNAME = "$inline"; // nested class generic name
+ constexpr auto INLINE_CLASSNAME = "$inline"; // nested class generic name
constexpr auto OPERATION_MAP_KEY = "statements";
constexpr auto PREDEFINED_MAP_KEY = "defaults";
@@ -110,7 +110,8 @@ namespace elena_lang
constexpr auto MESSAGE_NAME_FORWARD = "$subject"; // the message class
constexpr auto EXT_MESSAGE_FORWARD = "$ext_message"; // the extension message class
constexpr auto CLOSURE_FORWARD = "$closure"; // the closure template class
- constexpr auto TUPLE_FORWARD = "$tuple"; // the closure template class
+ constexpr auto TUPLE_FORWARD = "$tuple"; // the tuple template class
+ constexpr auto YIELDIT_FORWARD = "$yieldit"; // the yield state machine iterator template class
constexpr auto UINT_FORWARD = "$uint"; // the uint wrapper
constexpr auto PTR_FORWARD = "$ptr"; // the ptr wrapper
constexpr auto LAZY_FORWARD = "$lazy";
@@ -149,35 +150,37 @@ namespace elena_lang
constexpr auto TRY_INVOKE_MESSAGE = "#try_invoke";
constexpr auto INIT_MESSAGE = "#init";
- constexpr auto ADD_MESSAGE = "add";
- constexpr auto SUB_MESSAGE = "subtract";
- constexpr auto MUL_MESSAGE = "multiply";
- constexpr auto DIV_MESSAGE = "divide";
- constexpr auto BAND_MESSAGE = "band";
- constexpr auto BOR_MESSAGE = "bor";
- constexpr auto BXOR_MESSAGE = "bxor";
- constexpr auto REFER_MESSAGE = "at";
- constexpr auto SET_REFER_MESSAGE = "setAt";
- constexpr auto IF_MESSAGE = "if";
- constexpr auto IIF_MESSAGE = "iif";
- constexpr auto EQUAL_MESSAGE = "equal";
- constexpr auto NOT_MESSAGE = "Inverted";
- constexpr auto NEGATE_MESSAGE = "Negative";
- constexpr auto VALUE_MESSAGE = "Value";
- constexpr auto ITEM_MESSAGE = "Value";
- constexpr auto DEFAULT_MESSAGE = "Default";
- constexpr auto BNOT_MESSAGE = "BInverted";
- constexpr auto NOTEQUAL_MESSAGE = "notequal";
- constexpr auto LESS_MESSAGE = "less";
- constexpr auto NOTLESS_MESSAGE = "notless";
- constexpr auto GREATER_MESSAGE = "greater";
- constexpr auto NOTGREATER_MESSAGE = "notgreater";
- constexpr auto AND_MESSAGE = "and";
- constexpr auto OR_MESSAGE = "or";
- constexpr auto XOR_MESSAGE = "xor";
- constexpr auto SHL_MESSAGE = "shiftLeft";
- constexpr auto SHR_MESSAGE = "shiftRight";
-
+ constexpr auto NEXT_MESSAGE = "next";
+ constexpr auto CURRENT_FIELD = "__current";
+
+ constexpr auto ADD_MESSAGE = "add";
+ constexpr auto SUB_MESSAGE = "subtract";
+ constexpr auto MUL_MESSAGE = "multiply";
+ constexpr auto DIV_MESSAGE = "divide";
+ constexpr auto BAND_MESSAGE = "band";
+ constexpr auto BOR_MESSAGE = "bor";
+ constexpr auto BXOR_MESSAGE = "bxor";
+ constexpr auto REFER_MESSAGE = "at";
+ constexpr auto SET_REFER_MESSAGE = "setAt";
+ constexpr auto IF_MESSAGE = "if";
+ constexpr auto IIF_MESSAGE = "iif";
+ constexpr auto EQUAL_MESSAGE = "equal";
+ constexpr auto NOT_MESSAGE = "Inverted";
+ constexpr auto NEGATE_MESSAGE = "Negative";
+ constexpr auto VALUE_MESSAGE = "Value";
+ constexpr auto ITEM_MESSAGE = "Value";
+ constexpr auto DEFAULT_MESSAGE = "Default";
+ constexpr auto BNOT_MESSAGE = "BInverted";
+ constexpr auto NOTEQUAL_MESSAGE = "notequal";
+ constexpr auto LESS_MESSAGE = "less";
+ constexpr auto NOTLESS_MESSAGE = "notless";
+ constexpr auto GREATER_MESSAGE = "greater";
+ constexpr auto NOTGREATER_MESSAGE = "notgreater";
+ constexpr auto AND_MESSAGE = "and";
+ constexpr auto OR_MESSAGE = "or";
+ constexpr auto XOR_MESSAGE = "xor";
+ constexpr auto SHL_MESSAGE = "shiftLeft";
+ constexpr auto SHR_MESSAGE = "shiftRight";
// --- constant string lengths ---
constexpr auto TEMPLATE_PREFIX_NS_LEN = 7;
@@ -208,7 +211,6 @@ namespace elena_lang
constexpr ref_t elMessageName = 0x01000000;
constexpr ref_t elWithGenerics = 0x02000000;
constexpr ref_t elVirtualVMT = 0x04000000;
- constexpr ref_t elWithYieldable = 0x08000000;
constexpr ref_t elGroup = 0x10000000;
constexpr ref_t elPacked = 0x20000000;
constexpr ref_t elTemplatebased = 0x40000000;
diff --git a/elenasrc3/engine/jitlinker.cpp b/elenasrc3/engine/jitlinker.cpp
index f63e13f34..856703738 100644
--- a/elenasrc3/engine/jitlinker.cpp
+++ b/elenasrc3/engine/jitlinker.cpp
@@ -805,10 +805,6 @@ addr_t JITLinker :: createVMTSection(ReferenceInfo referenceInfo, ClassSectionIn
#ifdef FULL_OUTOUT_INFO
if (referenceInfo.referenceName)
printf("linking %s\n", referenceInfo.referenceName.str());
-
- if (referenceInfo.referenceName.compare("'$inline0"))
- referenceInfo.module = referenceInfo.module;
-
#endif // FULL_OUTOUT_INFO
referenceInfo.module = sectionInfo.module;
diff --git a/elenasrc3/engine/langcommon.h b/elenasrc3/engine/langcommon.h
index 94427dce5..3355dfd62 100644
--- a/elenasrc3/engine/langcommon.h
+++ b/elenasrc3/engine/langcommon.h
@@ -137,6 +137,42 @@ namespace elena_lang
}
};
+ enum class FieldHint : ref_t
+ {
+ None = 0x00000000,
+ ReadOnly = 0x00000001,
+ Private = 0x00000002,
+ };
+
+ // --- FieldInfo ---
+ struct FieldInfo
+ {
+ int offset;
+ TypeInfo typeInfo;
+ ref_t hints;
+
+ static bool checkHint(FieldInfo& info, FieldHint hint)
+ {
+ return test(info.hints, (ref_t)hint);
+ }
+
+ FieldInfo()
+ : offset(0), typeInfo({}), hints(0)
+ {
+
+ }
+ FieldInfo(int offset, TypeInfo typeInfo)
+ : offset(offset), typeInfo(typeInfo), hints(0)
+ {
+ }
+ FieldInfo(int offset, TypeInfo typeInfo, bool readOnly, bool privateOne)
+ : offset(offset), typeInfo(typeInfo), hints(0)
+ {
+ hints |= readOnly ? (ref_t)FieldHint::ReadOnly : 0;
+ hints |= privateOne ? (ref_t)FieldHint::Private : 0;
+ }
+ };
+
// --- ClassInfo ---
struct ClassInfo
{
@@ -144,6 +180,7 @@ namespace elena_lang
typedef MemoryMap FieldMap;
typedef MemoryMap StaticFieldMap;
+ pos_t inheritLevel;
ClassHeader header;
pos_t size; // Object size
MethodMap methods;
@@ -179,6 +216,7 @@ namespace elena_lang
writer->write(&header, sizeof(ClassHeader));
writer->writeDWord(size);
if (!headerAndSizeOnly) {
+ writer->writeDWord(inheritLevel);
writer->writePos(fields.count());
fields.forEach(writer, [](StreamWriter* writer, ustr_t name, FieldInfo info)
{
@@ -209,11 +247,12 @@ namespace elena_lang
reader->read(&header, sizeof(ClassHeader));
size = reader->getDWord();
if (!headerAndSizeOnly) {
+ inheritLevel = reader->getDWord();
pos_t fieldCount = reader->getPos();
for (pos_t i = 0; i < fieldCount; i++) {
IdentifierString fieldName;
reader->readString(fieldName);
- FieldInfo fieldInfo;
+ FieldInfo fieldInfo = {};
reader->read(&fieldInfo, sizeof(fieldInfo));
fields.add(*fieldName, fieldInfo);
@@ -244,17 +283,14 @@ namespace elena_lang
}
ClassInfo() :
+ inheritLevel(0),
header({}),
size(0),
methods({}),
- fields({ -1 }),
+ fields({ -1, {} }),
statics({ -1 }),
attributes(0)
{
- //header.staticSize = 0;
- //header.parentRef = header.classRef = 0;
- //header.flags = 0;
- //header.count = size = 0;
}
};
@@ -392,6 +428,7 @@ namespace elena_lang
/// accessors:
constexpr auto V_GETACCESSOR = 0x80005001u;
constexpr auto V_SETACCESSOR = 0x80005002u;
+ constexpr auto V_YIELDABLE = 0x80005003u;
/// visibility:
constexpr auto V_PUBLIC = 0x80004001u;
@@ -403,7 +440,6 @@ namespace elena_lang
constexpr auto V_SEALED = 0x80003001u;
constexpr auto V_ABSTRACT = 0x80003002u;
constexpr auto V_CLOSED = 0x80003003u;
- constexpr auto V_YIELDABLE = 0x80003004u;
constexpr auto V_PREDEFINED = 0x80003005u;
constexpr auto V_OVERRIDE = 0x80003006u;
@@ -652,7 +688,6 @@ namespace elena_lang
constexpr auto RETVAL_ARG = "$retVal";
constexpr auto PARENT_VAR = "$parent";
constexpr auto OWNER_VAR = "$owner";
- constexpr auto YIELD_CONTEXT_FIELD = "$context";
inline ustr_t getPlatformName(PlatformType type)
{
diff --git a/elenasrc3/engine/linux/presenter.cpp b/elenasrc3/engine/linux/presenter.cpp
index 3b75bb8bf..faaacabdd 100644
--- a/elenasrc3/engine/linux/presenter.cpp
+++ b/elenasrc3/engine/linux/presenter.cpp
@@ -3,7 +3,7 @@
//
// This file contains the Windows Presenter implementation
//
-// (C)2021-2023, by Aleksey Rakov
+// (C)2021-2024, by Aleksey Rakov
//---------------------------------------------------------------------------
#include "presenter.h"
@@ -104,6 +104,16 @@ void LinuxConsolePresenter :: printLine(ustr_t msg, ustr_t arg1, ustr_t arg2, us
::printLine(msg.str(), arg1.str(), arg2.str(), arg3.str());
}
+void LinuxConsolePresenter :: printLine(ustr_t msg, int arg1, int arg2, int arg3, ustr_t arg4)
+{
+ ::printLine(msg.str(), arg1, arg2, arg3, arg4.str());
+}
+
+void LinuxConsolePresenter::printLine(ustr_t msg, ustr_t path, int col, int row, ustr_t s)
+{
+ ::printLine(msg.str(), path.str(), row, col, s.str());
+}
+
void LinuxConsolePresenter :: printLine(ustr_t msg, int arg1, int arg2, int arg3)
{
::printLine(msg.str(), arg1, arg2, arg3);
@@ -134,11 +144,6 @@ void LinuxConsolePresenter :: printLine(ustr_t msg)
::printLine(msg.str());
}
-void LinuxConsolePresenter :: printLine(ustr_t msg, ustr_t path, int col, int row, ustr_t s)
-{
- ::printLine(msg.str(), path.str(), row, col, s.str());
-}
-
void LinuxConsolePresenter::showProgress()
{
::print(".");
diff --git a/elenasrc3/engine/linux/presenter.h b/elenasrc3/engine/linux/presenter.h
index 1deab3617..060c8e4b6 100644
--- a/elenasrc3/engine/linux/presenter.h
+++ b/elenasrc3/engine/linux/presenter.h
@@ -3,7 +3,7 @@
//
// This file contains the Windows Presenter declaration
//
-// (C)2021-2023, by Aleksey Rakov
+// (C)2021-2024, by Aleksey Rakov
//---------------------------------------------------------------------------
#ifndef PRESENTER_H
@@ -18,28 +18,30 @@ namespace elena_lang
public:
void readLine(char* buffer, size_t length) override;
+ void print(ustr_t msg) override;
void print(ustr_t msg, ustr_t arg) override;
void print(ustr_t msg, ustr_t arg1, ustr_t arg2) override;
void print(ustr_t msg, ustr_t arg1, ustr_t arg2, ustr_t arg3) override;
- void print(ustr_t msg, int arg1, int arg2, int arg3) override;
- void printPath(ustr_t msg, path_t arg1, int arg2, int arg3, ustr_t arg4) override;
void print(ustr_t msg, int arg1) override;
void print(ustr_t msg, int arg1, int arg2) override;
- void printPath(ustr_t msg, path_t arg) override;
- void print(ustr_t msg) override;
+ void print(ustr_t msg, int arg1, int arg2, int arg3) override;
void print(ustr_t msg, ustr_t path, int col, int row, ustr_t s) override;
+ void printPath(ustr_t msg, path_t arg) override;
+ void printPath(ustr_t msg, path_t arg1, int arg2, int arg3, ustr_t arg4) override;
+ void printLine(ustr_t msg) override;
void printLine(ustr_t msg, ustr_t arg) override;
void printLine(ustr_t msg, ustr_t arg1, ustr_t arg2) override;
void printLine(ustr_t msg, ustr_t arg1, ustr_t arg2, ustr_t arg3) override;
- void printLine(ustr_t msg, int arg1, int arg2, int arg3) override;
- void printPathLine(ustr_t msg, path_t arg1, int arg2, int arg3, ustr_t arg4) override;
void printLine(ustr_t msg, int arg1) override;
void printLine(ustr_t msg, int arg1, int arg2) override;
- void printPathLine(ustr_t msg, path_t arg) override;
- void printLine(ustr_t msg) override;
+ void printLine(ustr_t msg, int arg1, int arg2, int arg3) override;
+ void printLine(ustr_t msg, int arg1, int arg2, int arg3, ustr_t arg4) override; //version support print
void printLine(ustr_t msg, ustr_t path, int col, int row, ustr_t s) override;
+ void printPathLine(ustr_t msg, path_t arg) override;
+ void printPathLine(ustr_t msg, path_t arg1, int arg2, int arg3, ustr_t arg4) override;
+
void showProgress() override;
void stopProgress() override;
};
diff --git a/elenasrc3/engine/rtmanager.cpp b/elenasrc3/engine/rtmanager.cpp
index cc075873c..f92d74d74 100644
--- a/elenasrc3/engine/rtmanager.cpp
+++ b/elenasrc3/engine/rtmanager.cpp
@@ -85,12 +85,9 @@ bool RTManager :: readAddressInfo(addr_t retAddress, LibraryLoaderBase& provider
}
if (found) {
- bool isClass = true;
// if symbol
if (symbol[0] == '#') {
symbol += 1;
-
- isClass = false;
}
auto moduleInfo = provider.getDebugModule({ symbol }, true);
diff --git a/elenasrc3/engine/syntaxtree.h b/elenasrc3/engine/syntaxtree.h
index 61a6f703a..dd28c23ef 100644
--- a/elenasrc3/engine/syntaxtree.h
+++ b/elenasrc3/engine/syntaxtree.h
@@ -214,7 +214,6 @@ namespace elena_lang
Row = 0x000202,
ExternalTree = 0x000301,
- YieldContext = 0x000302,
Idle = 0x000F01,
};
diff --git a/elenasrc3/engine/windows/winevents.h b/elenasrc3/engine/windows/winevents.h
new file mode 100644
index 000000000..2ceb2d07d
--- /dev/null
+++ b/elenasrc3/engine/windows/winevents.h
@@ -0,0 +1,69 @@
+//---------------------------------------------------------------------------
+// E L E N A P r o j e c t: ELENA Engine
+//
+// This file contains the Win32 event template class
+// (C)2021-2024, by Aleksey Rakov
+//---------------------------------------------------------------------------
+
+#ifndef WIN32EVENT_H
+#define WIN32EVENT_H
+
+#include
+
+namespace elena_lang
+{
+ // --- EventManager ---
+ template class EventManager
+ {
+ HANDLE _events[EventCount];
+
+ public:
+ void init(T startEvent)
+ {
+ for (T i = 0; i < EventCount; i++)
+ _events[i] = CreateEvent(nullptr, TRUE, i == startEvent ? TRUE : FALSE, nullptr);;
+ }
+
+ void setEvent(T event)
+ {
+ SetEvent(_events[event]);
+ }
+
+ void resetEvent(T event)
+ {
+ ResetEvent(_events[event]);
+ }
+
+ int waitForAnyEvent()
+ {
+ return WaitForMultipleObjects(EventCount, _events, FALSE, INFINITE);
+ }
+
+ bool waitForEvent(T event, int timeout = INFINITE)
+ {
+ return (WaitForSingleObject(_events[event], timeout) == WAIT_OBJECT_0);
+ }
+
+ void close()
+ {
+ for (T i = 0; i < EventCount; i++) {
+ if (_events[i]) {
+ CloseHandle(_events[i]);
+ _events[i] = nullptr;
+ }
+ }
+ }
+
+ EventManager()
+ {
+ for (T i = 0; i < EventCount; i++)
+ _events[i] = nullptr;
+ }
+ virtual ~EventManager()
+ {
+ close();
+ }
+ };
+}
+
+#endif
\ No newline at end of file
diff --git a/elenasrc3/ide/idecontroller.cpp b/elenasrc3/ide/idecontroller.cpp
index feb8c0cf5..c49ad0472 100644
--- a/elenasrc3/ide/idecontroller.cpp
+++ b/elenasrc3/ide/idecontroller.cpp
@@ -248,6 +248,7 @@ bool ProjectController :: startDebugger(ProjectModel& model, DebugActionResult&
if (!target.empty()) {
PathString exePath(*model.projectPath, target);
+ PathUtil::makeCorrectExePath(exePath);
// provide the whole command line including the executable path and name
PathString commandLine(exePath);
@@ -787,7 +788,6 @@ int ProjectController :: openSingleFileProject(ProjectModel& model, path_t singl
IdentifierString tmp(*name);
model.package.copy(*tmp);
model.target.copy(*tmp);
- model.target.append(".exe");
//model.profile
diff --git a/elenasrc3/ide/ideversion.h b/elenasrc3/ide/ideversion.h
index d6ac43e9e..5128be75a 100644
--- a/elenasrc3/ide/ideversion.h
+++ b/elenasrc3/ide/ideversion.h
@@ -1,2 +1,2 @@
-#define IDE_REVISION_NUMBER 12
+#define IDE_REVISION_NUMBER 14
diff --git a/elenasrc3/ide/vs/elide.vcxproj b/elenasrc3/ide/vs/elide.vcxproj
index f591cbee1..f23c48619 100644
--- a/elenasrc3/ide/vs/elide.vcxproj
+++ b/elenasrc3/ide/vs/elide.vcxproj
@@ -182,6 +182,7 @@
+
diff --git a/elenasrc3/ide/windows/win32debugprocess.cpp b/elenasrc3/ide/windows/win32debugprocess.cpp
index 517996776..5fc202bc4 100644
--- a/elenasrc3/ide/windows/win32debugprocess.cpp
+++ b/elenasrc3/ide/windows/win32debugprocess.cpp
@@ -112,46 +112,6 @@ BOOL WINAPI debugEventThread(DebugControllerBase* controller)
return TRUE;
}
-// --- DebugEventManager ---
-
-void DebugEventManager :: init()
-{
- _events[DEBUG_ACTIVE] = CreateEvent(nullptr, TRUE, TRUE, nullptr);
- _events[DEBUG_CLOSE] = CreateEvent(nullptr, TRUE, FALSE, nullptr);
- _events[DEBUG_SUSPEND] = CreateEvent(nullptr, TRUE, FALSE, nullptr);
- _events[DEBUG_RESUME] = CreateEvent(nullptr, TRUE, FALSE, nullptr);
-}
-
-void DebugEventManager :: setEvent(int event)
-{
- SetEvent(_events[event]);
-}
-
-void DebugEventManager :: resetEvent(int event)
-{
- ResetEvent(_events[event]);
-}
-
-bool DebugEventManager :: waitForEvent(int event, int timeout)
-{
- return (WaitForSingleObject(_events[event], timeout) == WAIT_OBJECT_0);
-}
-
-int DebugEventManager :: waitForAnyEvent()
-{
- return WaitForMultipleObjects(MAX_DEBUG_EVENT, _events, FALSE, INFINITE);
-}
-
-void DebugEventManager :: close()
-{
- for (int i = 0; i < MAX_DEBUG_EVENT; i++) {
- if (_events[i]) {
- CloseHandle(_events[i]);
- _events[i] = nullptr;
- }
- }
-}
-
// --- Win32ThreadContext ---
Win32ThreadContext :: Win32ThreadContext(HANDLE hProcess, HANDLE hThread)
@@ -358,7 +318,7 @@ void Win32DebugProcess::ConsoleHelper :: printText(const char* s)
{
HANDLE output_handle = GetStdHandle(STD_OUTPUT_HANDLE);
- WriteConsoleA(output_handle, s, getlength(s), 0, 0);
+ WriteConsoleA(output_handle, s, getlength_pos(s), 0, 0);
}
void Win32DebugProcess::ConsoleHelper :: waitForAnyKey()
@@ -486,7 +446,7 @@ void Win32DebugProcess :: processEnd()
}
}
-void Win32DebugProcess :: processEvent(size_t timeout)
+void Win32DebugProcess :: processEvent(DWORD timeout)
{
DEBUG_EVENT event;
diff --git a/elenasrc3/ide/windows/win32debugprocess.h b/elenasrc3/ide/windows/win32debugprocess.h
index 9ccb72000..72ed22815 100644
--- a/elenasrc3/ide/windows/win32debugprocess.h
+++ b/elenasrc3/ide/windows/win32debugprocess.h
@@ -9,33 +9,12 @@
#define WIN32DEBUGPROCESS_H
#include "idecommon.h"
-#include
+#include "windows/winevents.h"
namespace elena_lang
{
// --- DebugEventManager ---
- class DebugEventManager
- {
- HANDLE _events[MAX_DEBUG_EVENT];
-
- public:
- void init();
- void setEvent(int event);
- void resetEvent(int event);
- int waitForAnyEvent();
- bool waitForEvent(int event, int timeout);
- void close();
-
- DebugEventManager()
- {
- for (int i = 0; i < MAX_DEBUG_EVENT; i++)
- _events[i] = nullptr;
- }
- ~DebugEventManager()
- {
- close();
- }
- };
+ typedef EventManager DebugEventManager;
class Win32DebugProcess;
struct Win32BreakpointContext;
@@ -159,7 +138,7 @@ namespace elena_lang
bool startProcess(const wchar_t* exePath, const wchar_t* cmdLine, bool withPersistentConsole);
void continueProcess();
- void processEvent(size_t timeout);
+ void processEvent(DWORD timeout);
void processException(EXCEPTION_DEBUG_INFO* exception);
void processStep();
void processEnd();
@@ -167,7 +146,7 @@ namespace elena_lang
public:
void initEvents() override
{
- _events.init();
+ _events.init(DEBUG_ACTIVE);
}
void setEvent(int event) override
{
diff --git a/elenasrc3/ldbg/ldbg_common.h b/elenasrc3/ldbg/ldbg_common.h
new file mode 100644
index 000000000..ed7a820be
--- /dev/null
+++ b/elenasrc3/ldbg/ldbg_common.h
@@ -0,0 +1,28 @@
+//---------------------------------------------------------------------------
+// E L E N A P r o j e c t: ELENA command-Line Debugger Adapter
+//
+// This file contains LDBG comment declaration
+//
+// (C)2024, by Aleksey Rakov
+//---------------------------------------------------------------------------
+
+#ifndef LDBG_COMMON
+#define LDBG_COMMON
+
+#if defined(_MSC_VER)
+
+#include "windows\winevents.h"
+
+#else
+
+#endif
+
+namespace elena_lang
+{
+ constexpr auto LDBG_EVENT_COUNT = 1;
+ constexpr auto LDBF_CONFIGURED = 0;
+
+ typedef EventManager DPAEventManager;
+}
+
+#endif // LDBG_COMMON
diff --git a/elenasrc3/ldbg/ldbg_const.h b/elenasrc3/ldbg/ldbg_const.h
index eb7fd79e5..43d78ac60 100644
--- a/elenasrc3/ldbg/ldbg_const.h
+++ b/elenasrc3/ldbg/ldbg_const.h
@@ -1 +1 @@
-#define LDBG_REVISION_NUMBER 0x0001
+#define LDBG_REVISION_NUMBER 0x0002
diff --git a/elenasrc3/ldbg/ldbg_session.cpp b/elenasrc3/ldbg/ldbg_session.cpp
index 91ca8a3ba..e6877fe69 100644
--- a/elenasrc3/ldbg/ldbg_session.cpp
+++ b/elenasrc3/ldbg/ldbg_session.cpp
@@ -15,7 +15,7 @@ using namespace elena_lang;
DPASessionWrapper :: DPASessionWrapper()
{
-
+ _events.init(-1);
}
DPASessionWrapper :: ~DPASessionWrapper()
@@ -26,10 +26,26 @@ DPASessionWrapper :: ~DPASessionWrapper()
void DPASessionWrapper :: prepare()
{
_session = new dpa::Session();
+
+ // The ConfigurationDone request is made by the client once all configuration
+ // requests have been made.
+
+ //session->registerHandler([&](const dap::ConfigurationDoneRequest&) {
+ // configured.fire();
+ // return dap::ConfigurationDoneResponse();
+ // });
+
+}
+
+void DPASessionWrapper :: bind()
+{
+ _session->connect();
}
void DPASessionWrapper :: run()
{
- // Wait for the ConfigurationDone request to be made.
+ _session->start();
+ // Wait for the ConfigurationDone request to be made.
+ _events.waitForEvent(LDBF_CONFIGURED);
}
diff --git a/elenasrc3/ldbg/ldbg_session.h b/elenasrc3/ldbg/ldbg_session.h
index c4df827a7..8a8015d61 100644
--- a/elenasrc3/ldbg/ldbg_session.h
+++ b/elenasrc3/ldbg/ldbg_session.h
@@ -10,15 +10,19 @@
#define LDBG_SESSION_H
#include "dpa_session.h"
+#include "ldbg_common.h"
namespace elena_lang
{
class DPASessionWrapper
{
+ DPAEventManager _events;
+
dpa::Session* _session;
public:
void prepare();
+ void bind();
void run();
DPASessionWrapper();
diff --git a/elenasrc3/ldbg/vs/ldbg.vcxproj b/elenasrc3/ldbg/vs/ldbg.vcxproj
index 59c821d92..e953b5af0 100644
--- a/elenasrc3/ldbg/vs/ldbg.vcxproj
+++ b/elenasrc3/ldbg/vs/ldbg.vcxproj
@@ -101,6 +101,7 @@
WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
true
..\..\common;..\..\engine;..\..\dpa;..\windows;..;%(AdditionalIncludeDirectories)
+ stdcpp17
Console
@@ -119,6 +120,7 @@
WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
true
..\..\common;..\..\engine;..\..\dpa;..\windows;..;%(AdditionalIncludeDirectories)
+ stdcpp17
Console
@@ -137,6 +139,7 @@
_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
true
..\..\common;..\..\engine;..\..\dpa;..\windows;..;%(AdditionalIncludeDirectories)
+ stdcpp17
Console
@@ -155,6 +158,7 @@
NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
true
..\..\common;..\..\engine;..\..\dpa;..\windows;..;%(AdditionalIncludeDirectories)
+ stdcpp17
Console
@@ -167,14 +171,17 @@
+
+
+
+
-
diff --git a/elenasrc3/ldbg/windows/ldbg.cpp b/elenasrc3/ldbg/windows/ldbg.cpp
index 65b102626..417e692c0 100644
--- a/elenasrc3/ldbg/windows/ldbg.cpp
+++ b/elenasrc3/ldbg/windows/ldbg.cpp
@@ -25,6 +25,7 @@ int main()
DPASessionWrapper session;
session.prepare();
+ session.bind();
session.run();
return 0;
diff --git a/elenasrc3/tools/ecv/ecvconst.h b/elenasrc3/tools/ecv/ecvconst.h
index e3a8503fd..6e9c7eff3 100644
--- a/elenasrc3/tools/ecv/ecvconst.h
+++ b/elenasrc3/tools/ecv/ecvconst.h
@@ -11,7 +11,7 @@
namespace elena_lang
{
- #define ECV_REVISION_NUMBER 0x0003
+ #define ECV_REVISION_NUMBER 0x0004
constexpr auto ECV_GREETING = "ELENA command line ByteCode Viewer %d.%d.%d (C)2021-24 by Aleksey Rakov\n";
diff --git a/elenasrc3/tools/ecv/linux/ecv.cpp b/elenasrc3/tools/ecv/linux/ecv.cpp
index 5bfefe70b..8bb46ded0 100644
--- a/elenasrc3/tools/ecv/linux/ecv.cpp
+++ b/elenasrc3/tools/ecv/linux/ecv.cpp
@@ -14,9 +14,6 @@ using namespace elena_lang;
constexpr auto DEFAULT_CONFIG = "/etc/elena/templates/lib60.config";
-constexpr auto PLATFORM_CATEGORY = "configuration/platform";
-constexpr auto LIB_PATH = "project/libpath";
-
#if defined(__x86_64__)
constexpr auto PLATFORM_KEY = "Linux_AMD64";
@@ -92,7 +89,7 @@ class ConsoleHelper : public ConsoleHelperBase
int main(int argc, char* argv[])
{
- printf("ELENA command line ByteCode Viewer %d.%d.%d (C)2011-2022 by Aleksey Rakov\n", ENGINE_MAJOR_VERSION, ENGINE_MINOR_VERSION, ECV_REVISION_NUMBER);
+ printf(ECV_GREETING, ENGINE_MAJOR_VERSION, ENGINE_MINOR_VERSION, ECV_REVISION_NUMBER);
// prepare library provider
LibraryProvider provider;
diff --git a/examples60/console/matrix/matrix.prj b/examples60/console/matrix/matrix.prj
index 90f7d1cf9..17fef952c 100644
--- a/examples60/console/matrix/matrix.prj
+++ b/examples60/console/matrix/matrix.prj
@@ -1,25 +1,26 @@
-
-
- matrix
-
-
-
-
- matrix64
-
-
-
- matrix
- console
-
-
-
- matrix.l
-
-
-
- extensions'programLoop
- matrix'control
-
+
+
+ matrix
+
+
+
+
+ matrix64
+
+
+
+
+ matrix
+ console
+
+
+
+ matrix.l
+
+
+
+ extensions'programLoop
+ matrix'control
+
\ No newline at end of file
diff --git a/src60/system/attributes/attributes.l b/src60/system/attributes/attributes.l
index 47aea8bcb..213dc31c6 100644
--- a/src60/system/attributes/attributes.l
+++ b/src60/system/attributes/attributes.l
@@ -6,6 +6,7 @@
/// scope_accessors:
#let attributes["get"] := 80005001h;
#let attributes["set"] := 80005002h;
+#let attributes["yield"] := 80005003h;
/// visibility:
#let attributes["public"] := 80004001h;
@@ -17,7 +18,6 @@
#let attributes["sealed"] := 80003001h;
#let attributes["abstract"] := 80003002h;
#let attributes["closed"] := 80003003h;
-#let attributes["yieldable"] := 80003004h;
#let attributes["predefined"] := 80003005h;
#let attributes["override"] := 80003006h;
diff --git a/src60/system/inline_templates.l b/src60/system/inline_templates.l
index ad9ad18e1..f8ca3de42 100644
--- a/src60/system/inline_templates.l
+++ b/src60/system/inline_templates.l
@@ -190,4 +190,24 @@ public enumeration enum
^ false
}
-}
\ No newline at end of file
+}
+
+// --- yield state machine ---
+
+public abstract class YieldStateEnumerator : Enumerator
+{
+ private __context; // context must be the first one
+ private T __current;
+
+ get T Value()
+ = __current;
+
+ reset()
+ {
+ NotSupportedException.raise()
+ }
+
+ Enumerator cast() = new Enumerator { embeddable dispatch() => self; };
+
+ enumerable() = self;
+}
diff --git a/tests60/sandbox/sandbox.l b/tests60/sandbox/sandbox.l
index 21f279e08..b0e0cff04 100644
--- a/tests60/sandbox/sandbox.l
+++ b/tests60/sandbox/sandbox.l
@@ -1,81 +1,33 @@
import extensions;
-sealed struct OctalNumber
+singleton IteratorEnumerable : Enumerable
{
- int value;
-
- int cast() = value;
-
- constructor(int n)
- {
- value := n;
- }
-
- cast o(string s)
- {
- value := s.toInt(8);
- }
-
- internal constructor sum(OctalNumber o1, OctalNumber o2)
- {
- int n1 := o1.Value;
- int n2 := o2.Value;
-
- value := n1 + n2
- }
-
- internal constructor diff(OctalNumber o1, OctalNumber o2)
- {
- int n1 := o1.Value;
- int n2 := o2.Value;
-
- value := n1 - n2
- }
-
- internal constructor prod(OctalNumber o1, OctalNumber o2)
- {
- int n1 := o1.Value;
- int n2 := o2.Value;
-
- value := n1 * n2
- }
-
- internal constructor frac(OctalNumber o1, OctalNumber o2)
- {
- int n1 := o1.Value;
- int n2 := o2.Value;
-
- value := n1 / n2
- }
-
- int Value = value;
-
- string toPrintable()
- = value.toString(8);
-
- OctalNumber add(OctalNumber n)
- = OctalNumber.sum(self, n);
-
- OctalNumber subtract(OctalNumber n)
- = OctalNumber.diff(self, n);
-
- OctalNumber multiply(OctalNumber n)
- = OctalNumber.prod(self, n);
+ Enumerator enumerator()
+ = IteratorEnumerable.infinitEnumerator();
+
+ yield Enumerator infinitEnumerator()
+ {
+ $yield 2;
+ $yield 5;
+ $yield 7;
+ }
+}
- OctalNumber divide(OctalNumber n)
- = OctalNumber.frac(self, n);
+public iteratorMethodTest()
+{
+ auto e := IteratorEnumerable.enumerator();
+
+ Assert.ifTrue(e.next());
+ Assert.ifTrue(*e == 2);
+ Assert.ifTrue(e.next());
+ Assert.ifTrue(*e == 5);
+ Assert.ifTrue(e.next());
+ Assert.ifTrue(*e == 7);
+ Assert.ifFalse(e.next());
}
+
public program()
{
- var n := 7o;
- var m := 2o;
- console.printLine(n,"+",m,"=",n + m);
-
- n := 24o;
- m := 7o;
- console.printLine(n,"+",m,"=",n + m);
- console.printLine(n,"-",m,"=",n - m);
- console.printLine(n,"*",m,"=",n * m);
- console.printLine(n,"/",m,"=",n / m);
+ iteratorMethodTest();
}
diff --git a/tests60/system_tests/basic.l b/tests60/system_tests/basic.l
index cdb70f475..511b58284 100644
--- a/tests60/system_tests/basic.l
+++ b/tests60/system_tests/basic.l
@@ -2076,3 +2076,32 @@ public stringInterpolation() : testCase()
Assert.ifEqual(s,"a_1_b_2_c");
console.write(".");
}
+
+// --- iteratorMethodTest ---
+
+singleton IteratorEnumerable : Enumerable
+{
+ Enumerator enumerator()
+ = IteratorEnumerable.infinitEnumerator();
+
+ yield Enumerator infinitEnumerator()
+ {
+ $yield 2;
+ $yield 5;
+ $yield 7;
+ }
+}
+
+public iteratorMethodTest() : testCase()
+{
+ auto e := IteratorEnumerable.enumerator();
+
+ Assert.ifTrue(e.next());
+ Assert.ifTrue(*e == 2);
+ Assert.ifTrue(e.next());
+ Assert.ifTrue(*e == 5);
+ Assert.ifTrue(e.next());
+ Assert.ifTrue(*e == 7);
+ Assert.ifFalse(e.next());
+ console.write(".");
+}