From 510ae41566169ab231305fad1ee43c474cfd1c9f Mon Sep 17 00:00:00 2001 From: Aleksey Rakov Date: Fri, 2 Aug 2024 09:27:57 +0200 Subject: [PATCH] Iteration29 (#677) * initial commit * [ADDED] #637 : bt optimization 4 unit test * [FIXED] single dispatcher : if an argument is nillable, it can accept nil value * [FIXED] Directory.getFiles : raising an exception if no files were found * [FIXED] var attribute is allowed to be in the method argument list * [ADDED] String interpolation --- .github/workflows/msbuild.yml | 2 +- CHANGELOG.md | 16 ++ build/aarch64/build_package_arm64.script | 2 +- build/aarch64/control | 2 +- build/amd64/build_package_amd64.script | 2 +- build/amd64/control | 2 +- build/elena_inno.iss | 2 +- build/i386/build_package_i386.script | 2 +- build/i386/control | 2 +- build/ppc64le/build_package_ppc64le.script | 2 +- build/ppc64le/control | 2 +- dat/sg/syntax60.txt | 83 ++++++++- doc/features | 6 + doc/tech/bytecode60.txt | 2 + doc/todo.txt | 28 +-- elenasrc3/common/common.h | 30 +++ elenasrc3/common/lists.h | 8 + elenasrc3/elc/clicommon.h | 26 ++- elenasrc3/elc/cliconst.h | 2 +- elenasrc3/elc/compiler.cpp | 207 +++++++++++++++------ elenasrc3/elc/compiler.h | 18 +- elenasrc3/elc/compilerlogic.cpp | 18 +- elenasrc3/elc/compilerlogic.h | 3 +- elenasrc3/elc/compiling.cpp | 3 +- elenasrc3/elc/derivation.cpp | 4 + elenasrc3/elc/parser.cpp | 3 + elenasrc3/elc/parser.h | 6 +- elenasrc3/elc/source.cpp | 93 ++++++++- elenasrc3/elc/source.h | 8 +- elenasrc3/elc/windows/ntlinker.cpp | 2 +- elenasrc3/elena-tests/bt_optimization.cpp | 18 ++ elenasrc3/elena-tests/bt_optimization.h | 7 + elenasrc3/elena-tests/bt_tests.cpp | 5 + elenasrc3/elena-tests/compiler_tests.cpp | 5 + elenasrc3/elena-tests/declaration.cpp | 3 +- elenasrc3/engine/bcwriter.cpp | 7 + elenasrc3/engine/bcwriter.h | 1 + elenasrc3/engine/elena.h | 195 ------------------- elenasrc3/engine/elenaconst.h | 4 +- elenasrc3/engine/jitcompiler.cpp | 5 +- elenasrc3/engine/langcommon.h | 199 ++++++++++++++++++++ elenasrc3/engine/syntaxtree.h | 4 + elenasrc3/engine/textparser.h | 3 + elenasrc3/ldbg/ldbg_session.cpp | 8 +- elenasrc3/ldbg/ldbg_session.h | 1 + elenasrc3/ldbg/windows/ldbg.cpp | 10 + elenasrc3/tools/asmc/asmconst.h | 2 +- elenasrc3/tools/asmc/bcassembler.cpp | 1 + elenasrc3/tools/ecv/ecviewer.cpp | 1 - elenasrc3/tools/ecv/ecviewer.h | 1 + elenasrc3/tools/ecv/windows/ecv.cpp | 3 - elenasrc3/tools/ldoc/ldoc.h | 1 + elenasrc3/tools/sg/sg.cpp | 17 +- elenasrc3/tools/sg/sgconst.h | 4 +- recompile60.bat | 21 +++ src60/core/system.core_routines.esm | 64 +++++++ src60/extensions/formatter.l | 2 +- src60/system/io/win_getfiles.l | 14 +- src60/system/pointers.l | 1 + src60/system/primitives.l | 5 +- src60/system/strings.l | 35 ++++ tests60/sandbox/sandbox.l | 80 +++++++- tests60/system_tests/basic.l | 60 ++++++ 63 files changed, 1021 insertions(+), 352 deletions(-) diff --git a/.github/workflows/msbuild.yml b/.github/workflows/msbuild.yml index d9c6b9ce5..1b16320f1 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.2 + BUILD_TAG: 6.2.3 permissions: contents: read diff --git a/CHANGELOG.md b/CHANGELOG.md index 31fc67612..39f5454c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,20 +5,36 @@ - [ADDED] #265 : Support enumeration list - [ADDED] self attribute - [ADDED] new operator $size + - [ADDED] text blocks + - [ADDED] method reference - &myMethod + - [FIXED] single dispatcher : if an argument is nillable, it can accept nil value + - [ADDED] String interpolation - ELC - [FIXED] private constructor must be called directly - [FIXED] accessing static fields inside a structure - [FIXED] ppc64le : decoratorTest() + - [FIXED] #667 : Boxing the symbol expression + - [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 - VM + - [FIXED] GC_ALLOC routine for vm mode - RT +- SM + - [ADDED] CF : alternative output + - API - [ADDED] reusing PermVectorTable after windows are closed + - [ADDED] xforms60 script + - [FIXED] external calls to be excluded from managed stack frames + - [FIXED] Directory.getFiles : raising an exception if no files were found - SAMPLES + - [ADDED] xforms example - Tools - [ADDED] #658 : new project LDBG - ELENA Debugger Adapter diff --git a/build/aarch64/build_package_arm64.script b/build/aarch64/build_package_arm64.script index 4c5bb3f2f..22e50bb81 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.2.aarch64-linux +RELEASE=elena-6.2.3.aarch64-linux mkdir -p /usr/share/elena mkdir -p /etc/elena/ diff --git a/build/aarch64/control b/build/aarch64/control index 981c56c1d..4724d00d5 100644 --- a/build/aarch64/control +++ b/build/aarch64/control @@ -1,5 +1,5 @@ Package: elena-lang -Version: 6.2.2 +Version: 6.2.3 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 fbd661d86..eb0387e0d 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.2.amd64-linux +RELEASE=elena-6.2.3.amd64-linux mkdir -p /usr/share/elena mkdir -p /etc/elena/ diff --git a/build/amd64/control b/build/amd64/control index 036bf08f1..a8c6cdb32 100644 --- a/build/amd64/control +++ b/build/amd64/control @@ -1,5 +1,5 @@ Package: elena-lang -Version: 6.2.2 +Version: 6.2.3 Architecture: amd64 Maintainer: Alex Rakov Depends: libc6 (>= 2.1) diff --git a/build/elena_inno.iss b/build/elena_inno.iss index 986c53eb0..42afc8118 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.2 +AppVersion=6.2.3 ;AppVerName=ELENA Programming Language 6.2.0 AppPublisher=Alexey Rakov AppPublisherURL=http://github.com/ELENA-LANG/elena-lang diff --git a/build/i386/build_package_i386.script b/build/i386/build_package_i386.script index 106121dd2..74e0924cd 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.2.i386-linux +RELEASE=elena-6.2.3.i386-linux mkdir -p /usr/share/elena mkdir -p /etc/elena/ diff --git a/build/i386/control b/build/i386/control index e8c376c78..bbb12a2ec 100644 --- a/build/i386/control +++ b/build/i386/control @@ -1,5 +1,5 @@ Package: elena-lang -Version: 6.2.2 +Version: 6.2.3 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 4f2d42cfe..10c8c0a2b 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.2.ppc64le-linux +RELEASE=elena-6.2.3.ppc64le-linux mkdir -p /usr/share/elena mkdir -p /etc/elena/ diff --git a/build/ppc64le/control b/build/ppc64le/control index fe9f2a23e..0e0690ba1 100644 --- a/build/ppc64le/control +++ b/build/ppc64le/control @@ -1,5 +1,5 @@ Package: elena-lang -Version: 6.2.2 +Version: 6.2.3 Architecture: ppc64le Maintainer: Alex Rakov Depends: libc6 (>= 2.1) diff --git a/dat/sg/syntax60.txt b/dat/sg/syntax60.txt index e57f3f0c2..a4df34ce0 100644 --- a/dat/sg/syntax60.txt +++ b/dat/sg/syntax60.txt @@ -11,7 +11,7 @@ __define wide 12300; __define constant 12301; __define long 12302; __define real 12303; -__define nullable 12304; +__define interpolate 12304; __define DECLARATION 5120; __define BLOCK 7184; @@ -101,8 +101,10 @@ __define L3_SINGLE_EXPRESSION 6298; __define NESTED_ROOT_EXPRESSION 6299; __define OPERATION_TEMPLATE 6300; __define LT_EXPRESSION 6301; +__define INTERPOL_EXPRESSION 6302; __define KEY_VALUE_EXPRESSION 6305; __define CLOSURE_OPERATION 6306; +__define INTERPOLATE_EXPR 6307; __define SWITCH_OPTION 6353; __define SWITCH_LAST_OPTION 6354; __define SWITCH_CODE 6355; @@ -535,6 +537,7 @@ EXPRESSION ::= } | { reference | global } ^OBJECT L2_OP* L3_OP* L4_OP* L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? | { string | integer | hexinteger | long | real | constant | character | wide } ^OBJECT L_F + | interpolate { INTERPOL_EXPRESSION interpolate }+ ^INTERPOLATE_EXPR | "!" EXPRESSION ^NOT_OPERATION | "*" SINGLE_EXPRESSION ^VALUE_OPERATION L2_OP* L3_OP* L4_OP* L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? | "&" SINGLE_EXPRESSION ^CLOSURE_OPERATION L2_OP* L3_OP* L4_OP* L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? @@ -560,6 +563,84 @@ EXPRESSION ::= } | "$lazy" EXPRESSION ^LAZY_OPERATION; +INTERPOL_EXPRESSION ::= + identifier { + identifier+ { + { DYNAMIC_DIMENSION ^ARRAY_TYPE }+ { + BRACKET ^OBJECT FUNCTION_R L3_OP* L4_OP* L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? + | "{" ^OBJECT COLLECTION "}" ^ COLLECTION_EXPRESSION L3_OP* L4_OP* L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? + } + | SBRACKET ^OBJECT INDEXER_R + | BRACKET ^OBJECT FUNCTION_R + | DOT ^OBJECT MESSAGE ^PROPERTY_OPERATION + | L4_OOP L4_OP* L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? + | L5_OOP L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? + | L6_OOP L7_OP* L8_OP? L9_OP? + | L7_OOP L7_OP* L8_OP? L9_OP? + | IF ^OBJECT IF_R + | ELSE ^OBJECT ELSE_R + | L9_OOP + | LESS ^OBJECT TEMPLATE_ARG { "," TEMPLATE_ARG }* ">" ^TEMPLATE_TYPE { + "{" NESTED_EXPRESSION ^NESTED OL_F + | { DYNAMIC_DIMENSION ^ARRAY_TYPE }+ ^OBJECT BRACKET FUNCTION_R L3_OP* L4_OP* L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? + | SBRACKET ^OBJECT INDEXER_R OL_F + | BRACKET ^OBJECT FUNCTION_R OL_F + | L3_OOP L3_OP* L4_OP* L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? + | L4_OOP L4_OP* L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? + | L5_OOP L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? + | L6_OOP L7_OP* L8_OP? L9_OP? + | L7_OOP L7_OP* L8_OP? L9_OP? + | L8_OOP + | L9_OOP + } + | eps ^OBJECT + } + | reference { + SBRACKET ^OBJECT INDEXER_R + | L2_OOP L3_OP* L4_OP* L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? + | L3_OOP L3_OP* L4_OP* L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? + | L4_OOP L4_OP* L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? + | L5_OOP L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? + | L6_OOP L7_OP* L8_OP? L9_OP? + | L7_OOP L7_OP* L8_OP? L9_OP? + | L8_OOP + | L9_OOP + | eps ^OBJECT + } + | { DYNAMIC_DIMENSION ^ARRAY_TYPE }+ { + BRACKET FUNCTION_R L3_OP* L4_OP* L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? + | "{" ^OBJECT COLLECTION "}" ^ COLLECTION_EXPRESSION L3_OP* L4_OP* L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? + } + | SBRACKET ^OBJECT INDEXER_R + | BRACKET ^OBJECT FUNCTION_R + | DOT ^OBJECT MESSAGE ^PROPERTY_OPERATION + | IF_DOT ^OBJECT MESSAGE? CALL_R ^IF_OPERATION ^OPERATION_TEMPLATE ^EXPRESSION OL_F + | ELSE_DOT ^OBJECT MESSAGE? CALL_R ^ELSE_OPERATION ^OPERATION_TEMPLATE ^EXPRESSION OL_F + | ALT_DOT ^OBJECT MESSAGE? CALL_R ^ALT_OPERATION ^OPERATION_TEMPLATE ^EXPRESSION OL_F + | L4_OOP L4_OP* L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? + | L5_OOP L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? + | L6_OOP L7_OP* L8_OP? L9_OP? + | LESS ^OBJECT L6_EXPRESSION ^LESS_OPERATION L7_OP* L8_OP? L9_OP? + | L7_OOP L7_OP* L8_OP? L9_OP? + | ELSE ^OBJECT ELSE_R + | L9_OOP + | { integer | hexinteger | long | real } ^OBJECT L_F + | eps ^OBJECT + } + | { reference | global } ^OBJECT L2_OP* L3_OP* L4_OP* L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? + | { integer | hexinteger | long | real } ^OBJECT L_F + | BRACKET SUB_EXPRESSION { + L2_OP+ L3_OP* L4_OP* L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? + | L3_OP+ L4_OP* L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? + | L4_OP+ L5_OP* L6_OP? L7_OP* L8_OP? L9_OP? + | L5_OP+ L6_OP? L7_OP* L8_OP? L9_OP? + | L6_OP L7_OP* L8_OP? L9_OP? + | L7_OP+ L8_OP? L9_OP? + | L8_OP + | L9_OP + | eps + }; + SUB_EXPRESSION ::= identifier { identifier+ { diff --git a/doc/features b/doc/features index ab75bb922..c13bd0250 100644 --- a/doc/features +++ b/doc/features @@ -84,3 +84,9 @@ public program() { myFunction() } + +---------------------------------------------------------------------------- + String interpolation +---------------------------------------------------------------------------- + + var s := var s := $"a_{ 1 }_b_{ 2 }_c"; diff --git a/doc/tech/bytecode60.txt b/doc/tech/bytecode60.txt index 1815b656e..b69e2e972 100644 --- a/doc/tech/bytecode60.txt +++ b/doc/tech/bytecode60.txt @@ -198,6 +198,8 @@ ELENA byte codes (or ecodes) lload dp:disp - long:index := dp[disp] + lload sp:i - long:index := sp[i] + load fp:i - index := fp[i] load dp:disp - index := dp[disp] diff --git a/doc/todo.txt b/doc/todo.txt index e76ab32bd..b004f9a17 100644 --- a/doc/todo.txt +++ b/doc/todo.txt @@ -5,36 +5,22 @@ In development: [development] ### EPIC: elena 6.3 ### - === Iteration 28 (23.07) === - -------------------------------------- - - #637 - -------------------------------------- - - aarch64 : fix interfaceImplTests, decoratorTest - - === Iteration 29 === + === Iteration 30 (16.8) === -------------------------------------- dev: - upndown (connector) - - web server - weather forecast (project setup) + - async programming gen: - - nested call must not stop / start vm, + - lpad maint: - - elena : nested classes should not be loadable at runtime - - constructor - single dispatcher; passing nil to single dispatcher (both normal / constructor) port: - - #658 : create simplest debug adapter; connect with it from VSCode + - #658 : vscode extension (debug adapter) prom: posting weekly -------------------------------------- + - lpad : generate a code based on a record + - User-defined string literals -------------------------------------- - - === Iteration 30 === - -------------------------------------- - dev: - gen: - maint: - port: - prom: - -------------------------------------- + - #658 : connect with ldbg from VSCode -------------------------------------- ### EPIC: elena 6.4 ### diff --git a/elenasrc3/common/common.h b/elenasrc3/common/common.h index 281ed5660..1ed33d50d 100644 --- a/elenasrc3/common/common.h +++ b/elenasrc3/common/common.h @@ -14,6 +14,36 @@ #include #include +#if defined(_MSC_VER) +#define DISABLE_WARNING_PUSH __pragma(warning( push )) +#define DISABLE_WARNING_POP __pragma(warning( pop )) +#define DISABLE_WARNING(warningNumber) __pragma(warning( disable : warningNumber )) + +#define DISABLE_WARNING_UNREFERENCED_FORMAL_PARAMETER DISABLE_WARNING(4100) +#define DISABLE_WARNING_UNREFERENCED_FUNCTION DISABLE_WARNING(4505) +#define DISABLE_WARNING_UNINITIALIZED_FIELD DISABLE_WARNING(26495) +// other warnings you want to deactivate... + +#elif defined(__GNUC__) || defined(__clang__) +#define DO_PRAGMA(X) _Pragma(#X) +#define DISABLE_WARNING_PUSH DO_PRAGMA(GCC diagnostic push) +#define DISABLE_WARNING_POP DO_PRAGMA(GCC diagnostic pop) +#define DISABLE_WARNING(warningName) DO_PRAGMA(GCC diagnostic ignored #warningName) + +#define DISABLE_WARNING_UNREFERENCED_FORMAL_PARAMETER DISABLE_WARNING(-Wunused-parameter) +#define DISABLE_WARNING_UNREFERENCED_FUNCTION DISABLE_WARNING(-Wunused-function) +#define DISABLE_WARNING_UNINITIALIZED_FIELD DISABLE_WARNING(-Wunused-function) +// other warnings you want to deactivate... + +#else +#define DISABLE_WARNING_PUSH +#define DISABLE_WARNING_POP +#define DISABLE_WARNING_UNREFERENCED_FORMAL_PARAMETER +#define DISABLE_WARNING_UNREFERENCED_FUNCTION +// other warnings you want to deactivate... + +#endif + namespace elena_lang { diff --git a/elenasrc3/common/lists.h b/elenasrc3/common/lists.h index 484c90823..5a995c7fc 100644 --- a/elenasrc3/common/lists.h +++ b/elenasrc3/common/lists.h @@ -718,6 +718,8 @@ namespace elena_lang int count_int() const { return (int)_list.count(); } + short count_short() const { return (short)_list.count(); } + Iterator start() { return _list.start(); @@ -3201,11 +3203,17 @@ namespace elena_lang _allocatedSize = _length = 0; } +DISABLE_WARNING_PUSH +DISABLE_WARNING_UNINITIALIZED_FIELD + CachedList() { _allocated = nullptr; _allocatedSize = _length = 0; } + +DISABLE_WARNING_POP + ~CachedList() { freeobj(_allocated); diff --git a/elenasrc3/elc/clicommon.h b/elenasrc3/elc/clicommon.h index 6f66f17ed..b2c5c8d77 100644 --- a/elenasrc3/elc/clicommon.h +++ b/elenasrc3/elc/clicommon.h @@ -416,8 +416,9 @@ enum class ExpressionAttribute : pos64_t RetrievingType = 0x00010000000, RetValExpected = 0x00020000000, CheckShortCircle = 0x00040000000, - LookaheadExprMode = 0x00080000000, + LookaheadExprMode = 0x00080000000, Class = 0x00100000000, + Nillable = 0x00200000000, OutRefOp = 0x01000000000, WithVariadicArgCast = 0x02008000000, DistributedForward = 0x04000000000, @@ -764,8 +765,27 @@ enum class VirtualType : int AbstractEmbeddableWrapper }; -typedef Pair VirtualMethod; -typedef List VirtualMethodList; +struct VirtualMethod +{ + mssg_t message; + VirtualType type; + int nillableArgs; + + VirtualMethod() + { + message = 0; + type = VirtualType::None; + nillableArgs = 0; + } + VirtualMethod(mssg_t message, VirtualType type, int nillableArgs) + { + this->message = message; + this->type = type; + this->nillableArgs = nillableArgs; + } +}; + +typedef List VirtualMethodList; } diff --git a/elenasrc3/elc/cliconst.h b/elenasrc3/elc/cliconst.h index 98bdf3947..8cb3ffffd 100644 --- a/elenasrc3/elc/cliconst.h +++ b/elenasrc3/elc/cliconst.h @@ -13,7 +13,7 @@ namespace elena_lang { - #define ELC_REVISION_NUMBER 0x0028 + #define ELC_REVISION_NUMBER 0x002B #if defined _M_IX86 || _M_X64 diff --git a/elenasrc3/elc/compiler.cpp b/elenasrc3/elc/compiler.cpp index 12da4405c..5c8085648 100644 --- a/elenasrc3/elc/compiler.cpp +++ b/elenasrc3/elc/compiler.cpp @@ -2597,6 +2597,8 @@ void Compiler :: generateMethodAttributes(ClassScope& scope, SyntaxNode node, if (byRefMethod) methodInfo.byRefHandler = byRefMethod; + methodInfo.nillableArgs = node.findChild(SyntaxKey::NillableInfo).arg.reference; + // check duplicates with different visibility scope if (MethodScope::checkHint(methodInfo, MethodHint::Private)) { checkMethodDuplicates(scope, node, message, message & ~STATIC_MESSAGE, false, false); @@ -2770,8 +2772,8 @@ inline mssg_t retrieveMethod(VirtualMethodList& implicitMultimethods, mssg_t mul { return implicitMultimethods.retrieve(multiMethod, [](mssg_t arg, VirtualMethod current) { - return current.value1 == arg; - }).value1; + return current.message == arg; + }).message; } mssg_t Compiler :: defineMultimethod(Scope& scope, mssg_t messageRef, bool extensionMode) @@ -2845,7 +2847,7 @@ inline TypeInfo mapOutputType(MethodInfo info) } void Compiler :: injectVirtualMultimethod(SyntaxNode classNode, SyntaxKey methodType, Scope& scope, - ref_t targetRef, ClassInfo& info, mssg_t multiMethod) + ref_t targetRef, ClassInfo& info, mssg_t multiMethod, int nillableArgs) { MethodInfo methodInfo = {}; @@ -2872,7 +2874,7 @@ void Compiler :: injectVirtualMultimethod(SyntaxNode classNode, SyntaxKey method inherited = false; injectVirtualMultimethod(classNode, methodType, scope, targetRef, info, multiMethod, inherited, - mapOutputType(methodInfo), visibility); + mapOutputType(methodInfo), visibility, nillableArgs); // COMPILER MAGIC : injecting try-multi-method dispather if (_logic->isTryDispatchAllowed(*scope.moduleScope, multiMethod)) { @@ -2890,15 +2892,15 @@ void Compiler :: injectVirtualMethods(SyntaxNode classNode, SyntaxKey methodType // generate implicit mutli methods for (auto it = implicitMultimethods.start(); !it.eof(); ++it) { auto methodInfo = *it; - switch (methodInfo.value2) { + switch (methodInfo.type) { case VirtualType::Multimethod: - injectVirtualMultimethod(classNode, methodType, scope, targetRef, info, methodInfo.value1); + injectVirtualMultimethod(classNode, methodType, scope, targetRef, info, methodInfo.message, methodInfo.nillableArgs); break; case VirtualType::EmbeddableWrapper: - injectVirtualEmbeddableWrapper(classNode, methodType, targetRef, info, methodInfo.value1, false); + injectVirtualEmbeddableWrapper(classNode, methodType, targetRef, info, methodInfo.message, false); break; case VirtualType::AbstractEmbeddableWrapper: - injectVirtualEmbeddableWrapper(classNode, methodType, targetRef, info, methodInfo.value1, true); + injectVirtualEmbeddableWrapper(classNode, methodType, targetRef, info, methodInfo.message, true); break; default: break; @@ -2996,7 +2998,7 @@ void Compiler :: generateMethodDeclarations(ClassScope& scope, SyntaxNode node, current.appendChild(SyntaxKey::Multimethod, multiMethod); if (retrieveMethod(implicitMultimethods, multiMethod) == 0) { - implicitMultimethods.add({ multiMethod, VirtualType::Multimethod }); + implicitMultimethods.add({ multiMethod, VirtualType::Multimethod, current.findChild(SyntaxKey::NillableInfo).arg.value}); thirdPassRequired = true; } } @@ -3016,9 +3018,9 @@ void Compiler :: generateMethodDeclarations(ClassScope& scope, SyntaxNode node, && retrieveMethod(implicitMultimethods, byRefMethod) == 0) { if (SyntaxTree::ifChildExists(current, SyntaxKey::Attribute, V_ABSTRACT)) { - implicitMultimethods.add({ byRefMethod, VirtualType::AbstractEmbeddableWrapper }); + implicitMultimethods.add({ byRefMethod, VirtualType::AbstractEmbeddableWrapper, 0 }); } - else implicitMultimethods.add({ byRefMethod, VirtualType::EmbeddableWrapper }); + else implicitMultimethods.add({ byRefMethod, VirtualType::EmbeddableWrapper, 0 }); thirdPassRequired = true; } } @@ -3577,7 +3579,7 @@ void Compiler :: declareMethodMetaInfo(MethodScope& scope, SyntaxNode node) void Compiler :: declareParameter(MethodScope& scope, SyntaxNode current, bool withoutWeakMessages, bool declarationMode, bool& variadicMode, bool& weakSignature, bool& noSignature, - pos_t& paramCount, ref_t* signature, size_t& signatureLen) + pos_t& paramCount, ref_t* signature, size_t& signatureLen, bool& nillable) { int index = 1 + scope.parameters.count(); @@ -3624,6 +3626,8 @@ void Compiler :: declareParameter(MethodScope& scope, SyntaxNode current, bool w scope.parameters.add(terminal, Parameter(index, paramTypeInfo, sizeInfo.size, paramTypeInfo.typeRef == V_OUTWRAPPER)); + + nillable |= paramTypeInfo.nillable; } void Compiler :: declareVMTMessage(MethodScope& scope, SyntaxNode node, bool withoutWeakMessages, bool declarationMode) @@ -3666,21 +3670,33 @@ void Compiler :: declareVMTMessage(MethodScope& scope, SyntaxNode node, bool wit flags |= FUNCTION_MESSAGE; } + int nillableArgs = 0; + int argMask = 1; bool mixinFunction = false; bool noSignature = true; // NOTE : is similar to weakSignature except if withoutWeakMessages=true // if method has an argument list SyntaxNode current = node.findChild(SyntaxKey::Parameter); while (current != SyntaxKey::None) { if (current == SyntaxKey::Parameter) { + bool nillable = false; declareParameter(scope, current, withoutWeakMessages, declarationMode, variadicMode, weakSignature, noSignature, - paramCount, signature, signatureLen); + paramCount, signature, signatureLen, nillable); + + if (nillable) + { + nillableArgs |= argMask; + } } else break; current = current.nextNode(); + argMask <<= 1; } + if (nillableArgs) + scope.info.nillableArgs = nillableArgs; + // if the signature consists only of generic parameters - ignore it if (weakSignature) signatureLen = 0; @@ -3712,21 +3728,23 @@ void Compiler :: declareVMTMessage(MethodScope& scope, SyntaxNode node, bool wit unnamedMessage = false; } - else if (paramCount == 1 && !unnamedMessage && signature[0] == scope.moduleScope->buildins.literalReference) { + else if (variadicMode&& paramCount == 1 && unnamedMessage && signature[0] == scope.moduleScope->buildins.superReference) { constantConversion = true; + unnamedMessage = false; + actionStr.copy("$"); actionStr.append(CONSTRUCTOR_MESSAGE); flags |= FUNCTION_MESSAGE; scope.info.hints |= (ref_t)MethodHint::Constructor; + scope.info.hints |= (ref_t)MethodHint::Interpolator; } - //else if (paramCount == 1 && unnamedMessage && weakSignature && scope.checkHint(MethodHint::Nullable)) { - // ref_t voidSignRef = scope.module->mapSignature(&scope.moduleScope->buildins.nilValueReference, 1, false); - // actionRef = scope.module->mapAction(CONSTRUCTOR_MESSAGE, voidSignRef, false); - - // flags |= FUNCTION_MESSAGE; + else if (paramCount == 1 && !unnamedMessage && signature[0] == scope.moduleScope->buildins.literalReference) { + constantConversion = true; - // unnamedMessage = false; - //} + actionStr.append(CONSTRUCTOR_MESSAGE); + flags |= FUNCTION_MESSAGE; + scope.info.hints |= (ref_t)MethodHint::Constructor; + } else scope.raiseError(errIllegalMethod, node); } else if (scope.checkHint(MethodHint::Constructor) && unnamedMessage) { @@ -3855,9 +3873,10 @@ ref_t Compiler :: declareClosureParameters(MethodScope& methodScope, SyntaxNode ref_t signatures[ARG_COUNT]; size_t signatureLen = 0; while (argNode == SyntaxKey::Parameter) { + bool dummy = false; declareParameter(methodScope, argNode, false, false, variadicMode, weakSingature, noSignature, - paramCount, signatures, signatureLen); + paramCount, signatures, signatureLen, dummy); if (variadicMode) flags |= VARIADIC_MESSAGE; @@ -3917,6 +3936,9 @@ void Compiler :: declareMethod(MethodScope& methodScope, SyntaxNode node, bool a addTypeInfo(methodScope, node, SyntaxKey::OutputInfo, mapOutputType(methodScope.info)); } + if (methodScope.info.nillableArgs) + node.appendChild(SyntaxKey::NillableInfo, methodScope.info.nillableArgs); + if (methodScope.info.hints) node.appendChild(SyntaxKey::Hints, methodScope.info.hints); @@ -4641,7 +4663,7 @@ void Compiler :: declareArgumentAttributes(MethodScope& scope, SyntaxNode node, bool declarationMode) { SyntaxNode current = node.firstChild(); - TypeAttributes attributes = { false, false, false }; + TypeAttributes attributes = { }; while (current != SyntaxKey::None) { switch (current.key) { case SyntaxKey::Type: @@ -4652,8 +4674,8 @@ void Compiler :: declareArgumentAttributes(MethodScope& scope, SyntaxNode node, // if it is a template type attribute typeInfo = resolveTypeAttribute(scope, current, attributes, declarationMode, false); break; - case SyntaxKey::ArrayType: case SyntaxKey::NullableType: + case SyntaxKey::ArrayType: // if it is a type attribute typeInfo = resolveTypeScope(scope, current, attributes, declarationMode, false); break; @@ -5528,8 +5550,8 @@ TypeInfo Compiler :: resolveTypeScope(Scope& scope, SyntaxNode node, TypeAttribu case SyntaxKey::reference: elementRef = resolveTypeIdentifier(scope, current.identifier(), node.key, declarationMode, allowRole); break; - case SyntaxKey::ArrayType: case SyntaxKey::NullableType: + case SyntaxKey::ArrayType: elementRef = resolvePrimitiveType(*scope.moduleScope, resolveTypeAttribute(scope, current, attributes, declarationMode, allowRole), declarationMode); break; @@ -6473,7 +6495,7 @@ ref_t Compiler :: compileExtensionDispatcher(BuildTreeWriter& writer, NamespaceS for(auto it = scope.extensions.getIt(genericMessage); !it.eof(); it = scope.extensions.nextIt(genericMessage, it)) { auto extInfo = *it; - methods.add(extInfo.value2, { false, 0, 0, genericMessage | FUNCTION_MESSAGE, 0 }); + methods.add(extInfo.value2, { false, 0, 0, genericMessage | FUNCTION_MESSAGE, 0, 0 }); targets.add(extInfo.value2, extInfo.value1); } @@ -6942,6 +6964,7 @@ ObjectInfo Compiler :: defineTerminalInfo(Scope& scope, SyntaxNode node, TypeInf } break; case SyntaxKey::string: + case SyntaxKey::interpolate: invalid = invalidForNonIdentifier; retVal = mapStringConstant(scope, node); @@ -7972,7 +7995,7 @@ ObjectInfo Compiler :: compileRedirect(BuildTreeWriter& writer, CodeScope& codeS signRef, arguments, EAttr::None, &updatedOuterArgs); if (outputRef) { - expression.convertObject(node, expression.saveToTempLocal(retVal), outputRef, true, false); + expression.convertObject(node, expression.saveToTempLocal(retVal), outputRef, true, false, false); } expression.scope.syncStack(); @@ -8036,8 +8059,9 @@ ObjectInfo Compiler :: compileResendCode(BuildTreeWriter& writer, CodeScope& cod mssg_t messageRef = mapMessage(codeScope, current, propertyMode, codeScope.isExtension(), false); + int resolvedNillableArgs = 0; mssg_t resolvedMessage = _logic->resolveSingleDispatch(*codeScope.moduleScope, - retrieveType(codeScope, source), messageRef); + retrieveType(codeScope, source), messageRef, resolvedNillableArgs); ref_t expectedSignRef = 0; if (resolvedMessage) @@ -8048,7 +8072,7 @@ ObjectInfo Compiler :: compileResendCode(BuildTreeWriter& writer, CodeScope& cod Expression::ArgumentListType argListType = Expression::ArgumentListType::Normal; ref_t implicitSignatureRef = expression.compileMessageArguments(current, arguments, expectedSignRef, - EAttr::NoPrimitives, &updatedOuterArgs, argListType); + EAttr::NoPrimitives, &updatedOuterArgs, argListType, resolvedNillableArgs); EAttr opMode = EAttr::CheckShortCircle; if (argListType == Expression::ArgumentListType::VariadicArgList || argListType == Expression::ArgumentListType::VariadicArgListWithTypecasting) { @@ -8735,7 +8759,7 @@ void Compiler :: compileConstructor(BuildTreeWriter& writer, MethodScope& scope, // the object should not be created, because of redirecting isDefConvConstructor = false; } - else if (isDefConvConstructor && !test(classFlags, elDynamicRole)) { + else if (isDefConvConstructor && (!test(classFlags, elDynamicRole) || scope.checkHint(MethodHint::Interpolator))) { // new stack frame writer.appendNode(BuildKey::OpenFrame); newFrame = true; @@ -9194,7 +9218,7 @@ void Compiler :: compileClosureClass(BuildTreeWriter& writer, ClassScope& scope, classWriter.newNode(SyntaxKey::Class, scope.reference); SyntaxNode classNode = classWriter.CurrentNode(); - injectVirtualMultimethod(classNode, SyntaxKey::Method, scope, scope.reference, scope.info, multiMethod); + injectVirtualMultimethod(classNode, SyntaxKey::Method, scope, scope.reference, scope.info, multiMethod, 0); classWriter.closeNode(); classWriter.closeNode(); @@ -10055,7 +10079,7 @@ inline bool isSingleDispatch(SyntaxNode node, SyntaxKey methodType, mssg_t messa } bool Compiler :: injectVirtualStrongTypedMultimethod(SyntaxNode classNode, SyntaxKey methodType, Scope& scope, - mssg_t message, mssg_t resendMessage, TypeInfo outputInfo, Visibility visibility, bool isExtension) + mssg_t message, mssg_t resendMessage, TypeInfo outputInfo, Visibility visibility, bool isExtension, int nillableArgs) { bool variadicOne = (getFlags(resendMessage) & PREFIX_MESSAGE_MASK) == VARIADIC_MESSAGE; @@ -10095,6 +10119,8 @@ bool Compiler :: injectVirtualStrongTypedMultimethod(SyntaxNode classNode, Synta String arg; for (size_t i = 0; i < len; i++) { + bool isNillable = test(nillableArgs, 1 << i); + arg.copy("$"); arg.appendInt((int)i); @@ -10108,7 +10134,14 @@ bool Compiler :: injectVirtualStrongTypedMultimethod(SyntaxNode classNode, Synta castObject.appendChild(SyntaxKey::Attribute, V_CONVERSION); castObject.appendChild(SyntaxKey::Type, signArgs[i]); castNode.appendChild(SyntaxKey::Message); - castNode.appendChild(SyntaxKey::Expression).appendChild(SyntaxKey::Object).appendChild(SyntaxKey::identifier, arg.str()); + if (isNillable) { + SyntaxNode isNilOp = castNode.appendChild(SyntaxKey::Expression).appendChild(SyntaxKey::IsNilOperation); + isNilOp.appendChild(SyntaxKey::Object).appendChild(SyntaxKey::identifier, arg.str()); + SyntaxNode nilObject = isNilOp.appendChild(SyntaxKey::Expression).appendChild(SyntaxKey::Object); + nilObject.appendChild(SyntaxKey::Attribute, V_FORWARD); + nilObject.appendChild(SyntaxKey::identifier, NILVALUE_FORWARD); + } + else castNode.appendChild(SyntaxKey::Expression).appendChild(SyntaxKey::Object).appendChild(SyntaxKey::identifier, arg.str()); } else operationNode.appendChild(SyntaxKey::Expression).appendChild(SyntaxKey::Object).appendChild(SyntaxKey::identifier, arg.str()); } @@ -10143,7 +10176,8 @@ bool Compiler :: injectVirtualStrongTypedMultimethod(SyntaxNode classNode, Synta } void Compiler :: injectVirtualMultimethod(SyntaxNode classNode, SyntaxKey methodType, Scope& scope, - ref_t targetRef, ClassInfo& info, mssg_t message, bool inherited, TypeInfo outputInfo, Visibility visibility) + ref_t targetRef, ClassInfo& info, mssg_t message, bool inherited, TypeInfo outputInfo, + Visibility visibility, int nillableArgs) { bool isExtension = test(info.header.flags, elExtension); @@ -10160,7 +10194,7 @@ void Compiler :: injectVirtualMultimethod(SyntaxNode classNode, SyntaxKey method // !! temporally do not support variadic arguments if (isSingleDispatch(classNode, methodType, message, resendMessage) && injectVirtualStrongTypedMultimethod(classNode, methodType, scope, message, resendMessage, - outputInfo, visibility, isExtension)) + outputInfo, visibility, isExtension, nillableArgs)) { // mark the message as a signle dispatcher if the class is sealed / closed / class class // and default multi-method was not explicitly declared @@ -10485,7 +10519,7 @@ void Compiler :: declareModuleExtensionDispatcher(NamespaceScope& scope, SyntaxN if (retrieveIndex(genericMethods, genericMessage) == -1) genericMethods.add(genericMessage); - methods.add(extInfo.value2, { false, 0, 0, genericMessage | FUNCTION_MESSAGE, 0 }); + methods.add(extInfo.value2, { false, 0, 0, genericMessage | FUNCTION_MESSAGE, 0, 0 }); targets.add(extInfo.value2, extInfo.value1); } } @@ -11208,6 +11242,7 @@ ObjectInfo Compiler::Expression :: compile(SyntaxNode node, ref_t targetRef, EAt bool noPrimitives = EAttrs::testAndExclude(mode, EAttr::NoPrimitives); bool dynamicRequired = EAttrs::testAndExclude(mode, EAttr::DynamicObject); bool lookaheadMode = EAttrs::testAndExclude(mode, EAttr::LookaheadExprMode) && compiler->_lookaheadOptMode; + bool nillableArg = EAttrs::test(mode, EAttr::Nillable); ObjectInfo retVal; @@ -11273,7 +11308,7 @@ ObjectInfo Compiler::Expression :: compile(SyntaxNode node, ref_t targetRef, EAt case SyntaxKey::OrOperation: retVal = compileBoolOperation(current, (int)current.key - OPERATOR_MAKS); if (targetRef) - typecastObject(current, retVal, targetRef); + typecastObject(current, retVal, targetRef, EAttrs::test(mode, EAttr::Nillable)); break; case SyntaxKey::IndexerOperation: @@ -11361,6 +11396,9 @@ ObjectInfo Compiler::Expression :: compile(SyntaxNode node, ref_t targetRef, EAt case SyntaxKey::ClosureOperation: retVal = compileClosureOperation(current); break; + case SyntaxKey::Interpolation: + retVal = compileInterpolation(current); + break; case SyntaxKey::None: assert(false); break; @@ -11370,11 +11408,44 @@ ObjectInfo Compiler::Expression :: compile(SyntaxNode node, ref_t targetRef, EAt } retVal = validateObject(node, retVal, targetRef, - noPrimitives, paramMode, dynamicRequired); + noPrimitives, paramMode, dynamicRequired, nillableArg); return retVal; } +ObjectInfo Compiler::Expression :: compileInterpolation(SyntaxNode node) +{ + ArgumentsInfo arguments; + SyntaxNode current = node.firstChild(); + while (current != SyntaxKey::None) { + ObjectInfo arg = {}; + if (current == SyntaxKey::interpolate) { + arg = compiler->mapTerminal(scope, current, {}, EAttr::None); + } + else arg = compile(current, 0, EAttr::None, nullptr); + + arguments.add(arg); + + current = current.nextNode(); + } + + ref_t typeRef = scope.moduleScope->buildins.superReference; + ref_t signRef = scope.module->mapSignature(&typeRef, 1, false); + mssg_t conversionMssg = encodeMessage(scope.module->mapAction("$#constructor", signRef, false), 1, FUNCTION_MESSAGE | VARIADIC_MESSAGE); + + ObjectInfo source = {}; + mssg_t messageRef = 0; + NamespaceScope* nsScope = Scope::getScope(scope, Scope::ScopeLevel::Namespace); + auto constInfo = nsScope->extensions.get(conversionMssg); + if (constInfo.value1) { + messageRef = constInfo.value2; + source = compiler->mapClassSymbol(scope, constInfo.value1); + } + else scope.raiseError(errInvalidOperation, node); + + return compileMessageOperation(node, source, messageRef, 0, arguments, EAttr::StrongResolved | EAttr::NoExtension, nullptr); +} + ObjectInfo Compiler::Expression :: compileObject(SyntaxNode node, ExpressionAttribute mode, ArgumentsInfo* updatedOuterArgs) { if (node == SyntaxKey::Object) { @@ -11456,16 +11527,17 @@ ObjectInfo Compiler::Expression :: compileMessageOperationR(SyntaxNode node, Syn arguments.add(source); mssg_t resolvedMessage = 0; + int resolvedNillableArgs = 0; EAttr paramMode = EAttr::NoPrimitives; if (source.mode != TargetMode::Weak) { resolvedMessage = compiler->_logic->resolveSingleDispatch(*scope.moduleScope, - compiler->retrieveType(scope, source), messageRef); + compiler->retrieveType(scope, source), messageRef, resolvedNillableArgs); if (!resolvedMessage && !ignoreVariadics) { ref_t variadicMssg = resolveVariadicMessage(scope, messageRef); resolvedMessage = compiler->_logic->resolveSingleDispatch(*scope.moduleScope, - compiler->retrieveType(scope, source), variadicMssg); + compiler->retrieveType(scope, source), variadicMssg, resolvedNillableArgs); if (resolvedMessage) { messageRef = variadicMssg; paramMode = paramMode | EAttr::WithVariadicArg; @@ -11479,7 +11551,7 @@ ObjectInfo Compiler::Expression :: compileMessageOperationR(SyntaxNode node, Syn ArgumentListType argListType = ArgumentListType::Normal; ref_t implicitSignatureRef = compileMessageArguments(messageNode, arguments, expectedSignRef, paramMode, - updatedOuterArgs, argListType); + updatedOuterArgs, argListType, resolvedNillableArgs); EAttr opMode = EAttr::None; if (argListType == ArgumentListType::VariadicArgList || argListType == ArgumentListType::VariadicArgListWithTypecasting) { @@ -11570,7 +11642,7 @@ ObjectInfo Compiler::Expression :: compileMessageOperation(SyntaxNode node, case TargetMode::External: case TargetMode::WinApi: { - compileMessageArguments(current, arguments, 0, EAttr::None, nullptr, argListType); + compileMessageArguments(current, arguments, 0, EAttr::None, nullptr, argListType, 0); if (argListType != ArgumentListType::Normal) scope.raiseError(errInvalidOperation, current); @@ -11580,7 +11652,7 @@ ObjectInfo Compiler::Expression :: compileMessageOperation(SyntaxNode node, } case TargetMode::CreatingArray: { - compileMessageArguments(current, arguments, 0, EAttr::NoPrimitives, nullptr, argListType); + compileMessageArguments(current, arguments, 0, EAttr::NoPrimitives, nullptr, argListType, 0); if (argListType != ArgumentListType::Normal) scope.raiseError(errInvalidOperation, current); @@ -11589,7 +11661,7 @@ ObjectInfo Compiler::Expression :: compileMessageOperation(SyntaxNode node, } case TargetMode::Creating: { - ref_t signRef = compileMessageArguments(current, arguments, 0, EAttr::NoPrimitives, nullptr, argListType); + ref_t signRef = compileMessageArguments(current, arguments, 0, EAttr::NoPrimitives, nullptr, argListType, 0); if (argListType != ArgumentListType::Normal) scope.raiseError(errInvalidOperation, current); @@ -11605,7 +11677,7 @@ ObjectInfo Compiler::Expression :: compileMessageOperation(SyntaxNode node, default: { // NOTE : the operation target shouldn't be a primtive type - source = validateObject(node, source, 0, true, true, false); + source = validateObject(node, source, 0, true, true, false, false); current = current.nextNode(); @@ -11631,7 +11703,7 @@ ObjectInfo Compiler::Expression :: compilePropertyOperation(SyntaxNode node, ref scope.raiseError(errInvalidOperation, node); // NOTE : the operation target shouldn't be a primtive type - source = validateObject(node, source, 0, true, true, false); + source = validateObject(node, source, 0, true, true, false, false); current = current.nextNode(); @@ -11920,13 +11992,25 @@ inline mssg_t mapTypecasting(ModuleBase* module, ref_t targetRef) return encodeMessage(actionRef, 1, CONVERSION_MESSAGE); } -ObjectInfo Compiler::Expression :: typecastObject(SyntaxNode node, ObjectInfo source, ref_t targetRef) +ObjectInfo Compiler::Expression :: typecastObject(SyntaxNode node, ObjectInfo source, ref_t targetRef, bool nillable) { if (targetRef == scope.moduleScope->buildins.superReference) return source; mssg_t typecastMssg = mapTypecasting(scope.module, targetRef); + // if it is a weak argument + if (nillable && !isBoxingRequired(source, false)) { + if (!source.typeInfo.typeRef || source.typeInfo.typeRef == scope.moduleScope->buildins.superReference || source.typeInfo.nillable) { + IdentifierString nilForward(FORWARD_PREFIX_NS, NILVALUE_FORWARD); + writeObjectInfo(scope.mapGlobal(*nilForward)); + writer->appendNode(BuildKey::SavingInStack); + writeObjectInfo(source, node); + writer->appendNode(BuildKey::NilOp, ISNIL_OPERATOR_ID); + source = saveToTempLocal({ ObjectKind::Object }); + } + } + ArgumentsInfo arguments; arguments.add(source); @@ -12255,7 +12339,7 @@ ObjectInfo Compiler::Expression :: compileSubCode(SyntaxNode node, ExpressionAtt codeScope.syncStack(parentCodeScope); } - else retVal = compiler->compileCode(*writer, *parentCodeScope, node, retValExpected); + else retVal = compiler->compileCode(*writer, *parentCodeScope, node, retValExpected, withoutDebugInfo); if (!retValExpected) { retVal = { ObjectKind::Object }; @@ -12561,7 +12645,7 @@ ObjectInfo Compiler::Expression :: compileTupleAssigning(SyntaxNode node) } ObjectInfo Compiler::Expression :: validateObject(SyntaxNode node, ObjectInfo retVal, ref_t targetRef, bool noPrimitives, - bool paramMode, bool dynamicRequired) + bool paramMode, bool dynamicRequired, bool nillable) { if (!targetRef && retVal.typeInfo.isPrimitive() && noPrimitives) { targetRef = compiler->resolveStrongType(scope, retVal.typeInfo); @@ -12578,7 +12662,7 @@ ObjectInfo Compiler::Expression :: validateObject(SyntaxNode node, ObjectInfo re return retVal; } - retVal = convertObject(node, retVal, targetRef, dynamicRequired, false); + retVal = convertObject(node, retVal, targetRef, dynamicRequired, false, nillable); if (paramMode && hasToBePresaved(retVal)) retVal = saveToTempLocal(retVal); } @@ -12641,7 +12725,7 @@ ObjectInfo Compiler::Expression :: compileNewOp(SyntaxNode node, ObjectInfo sour } ref_t Compiler::Expression :: compileMessageArguments(SyntaxNode current, ArgumentsInfo& arguments, ref_t expectedSignRef, EAttr mode, - ArgumentsInfo* updatedOuterArgs, ArgumentListType& argListType) + ArgumentsInfo* updatedOuterArgs, ArgumentListType& argListType, int nillableArgs) { bool variadicArg = EAttrs::testAndExclude(mode, EAttr::WithVariadicArg); @@ -12658,17 +12742,19 @@ ref_t Compiler::Expression :: compileMessageArguments(SyntaxNode current, Argume if (expectedSignRef) signatureMaxLength = scope.module->resolveSignature(expectedSignRef, signatures); + int argMask = 1; while (current != SyntaxKey::None) { if (current == SyntaxKey::Expression) { if (variadicArg && signatureLen == signatureMaxLength && signatureLen > 0) { // for variadic last argument - stay at the same position signatureLen--; + argMask >>= 1; } // try to recognize the message signature // NOTE : signatures[signatureLen] contains expected parameter type if expectedSignRef is provided auto argInfo = compile(current, signatures[signatureLen], - paramMode, updatedOuterArgs); + paramMode | (test(nillableArgs, argMask) ? EAttr::Nillable : EAttr::None), updatedOuterArgs); if ((argInfo.mode == TargetMode::UnboxingVarArgument || argInfo.mode == TargetMode::UnboxingAndTypecastingVarArgument) && signatureLen < ARG_COUNT) { if (argInfo.typeInfo.elementRef) { @@ -12694,6 +12780,7 @@ ref_t Compiler::Expression :: compileMessageArguments(SyntaxNode current, Argume else signatures[signatureLen++] = superReference; } arguments.add(argInfo); + argMask <<= 1; } current = current.nextNode(); @@ -12870,7 +12957,7 @@ ObjectInfo Compiler::Expression :: compileNewArrayOp(SyntaxNode node, ObjectInfo } ObjectInfo Compiler::Expression :: convertObject(SyntaxNode node, ObjectInfo source, - ref_t targetRef, bool dynamicRequired, bool withoutBoxing) + ref_t targetRef, bool dynamicRequired, bool withoutBoxing, bool nillable) { if (!compiler->_logic->isCompatible(*scope.moduleScope, { targetRef }, source.typeInfo, false)) { if (source.kind == ObjectKind::Default) { @@ -12981,7 +13068,7 @@ ObjectInfo Compiler::Expression :: convertObject(SyntaxNode node, ObjectInfo sou return source; } - else source = typecastObject(node, source, targetRef); + else source = typecastObject(node, source, targetRef, nillable); } return source; @@ -14030,7 +14117,7 @@ ObjectInfo Compiler::Expression :: compileMessageOperationR(ObjectInfo target, S case TargetMode::Casting: { ArgumentListType argListType = ArgumentListType::Normal; - compileMessageArguments(messageNode, arguments, 0, EAttr::NoPrimitives, nullptr, argListType); + compileMessageArguments(messageNode, arguments, 0, EAttr::NoPrimitives, nullptr, argListType, 0); if (arguments.count() == 1) { ref_t targetRef = compiler->resolveStrongType(scope, target.typeInfo); @@ -14040,7 +14127,7 @@ ObjectInfo Compiler::Expression :: compileMessageOperationR(ObjectInfo target, S return arguments[0]; } - else return convertObject(messageNode, arguments[0], targetRef, false, true); + else return convertObject(messageNode, arguments[0], targetRef, false, true, false); } else scope.raiseError(errInvalidOperation, messageNode); break; @@ -14050,7 +14137,7 @@ ObjectInfo Compiler::Expression :: compileMessageOperationR(ObjectInfo target, S ArgumentsInfo updatedOuterArgs; // NOTE : the operation target shouldn't be a primitive type - ObjectInfo source = validateObject(messageNode, target, 0, true, true, false); + ObjectInfo source = validateObject(messageNode, target, 0, true, true, false, false); return compileMessageOperationR(messageNode, messageNode, source, arguments, &updatedOuterArgs, 0, propertyMode, false, false, EAttr::None); @@ -15049,7 +15136,7 @@ ObjectInfo Compiler::Expression :: boxVariadicArgument(ObjectInfo info) if (info.typeInfo.typeRef && info.typeInfo.typeRef != typeRef) { // if the conversion is required ObjectInfo convInfo = convertObject({}, destLocal, - info.typeInfo.typeRef, false, false); + info.typeInfo.typeRef, false, false, false); compileAssigningOp(destLocal, convInfo, dummy); @@ -15063,7 +15150,7 @@ void Compiler::Expression :: compileAssigning(SyntaxNode node, ObjectInfo target { if (!noConversion) { source = convertObject(node, source, - compiler->resolveStrongType(scope, target.typeInfo), false, false); + compiler->resolveStrongType(scope, target.typeInfo), false, false, false); } bool nillableOp = false; @@ -15077,7 +15164,7 @@ void Compiler::Expression :: compileAssigning(SyntaxNode node, ObjectInfo target void Compiler::Expression :: compileConverting(SyntaxNode node, ObjectInfo source, ref_t targetRef, bool stackSafe) { if (targetRef && targetRef != V_AUTO) { - source = convertObject(node, source, targetRef, false, false); + source = convertObject(node, source, targetRef, false, false, false); scope.syncStack(); } diff --git a/elenasrc3/elc/compiler.h b/elenasrc3/elc/compiler.h index e2960e74f..a6dd2646e 100644 --- a/elenasrc3/elc/compiler.h +++ b/elenasrc3/elc/compiler.h @@ -1256,17 +1256,18 @@ namespace elena_lang ObjectInfo compileNewOp(SyntaxNode node, ObjectInfo source, ref_t signRef, ArgumentsInfo& arguments); - ObjectInfo typecastObject(SyntaxNode node, ObjectInfo source, ref_t targetRef); + ObjectInfo typecastObject(SyntaxNode node, ObjectInfo source, ref_t targetRef, bool nillable); ObjectInfo validateObject(SyntaxNode node, ObjectInfo retVal, - ref_t targetRef, bool noPrimitives, bool paramMode, bool dynamicRequired); + ref_t targetRef, bool noPrimitives, bool paramMode, bool dynamicRequired, bool nillable); ObjectInfo compileExternalOp(SyntaxNode node, ref_t externalRef, bool stdCall, ArgumentsInfo& arguments, ref_t expectedRef); ObjectInfo compileNewArrayOp(SyntaxNode node, ObjectInfo source, ref_t targetRef, ArgumentsInfo& arguments); - ObjectInfo convertObject(SyntaxNode node, ObjectInfo source, ref_t targetRef, bool dynamicRequired, bool withoutBoxing); + ObjectInfo convertObject(SyntaxNode node, ObjectInfo source, ref_t targetRef, bool dynamicRequired, + bool withoutBoxing, bool nillable); ObjectInfo compileMessageOperation(SyntaxNode node, ObjectInfo target, MessageResolution resolution, ref_t implicitSignatureRef, ArgumentsInfo& arguments, ExpressionAttributes mode, ArgumentsInfo* updatedOuterArgs); @@ -1279,7 +1280,7 @@ namespace elena_lang SyntaxNode r2node, int operatorId, ArgumentsInfo* updatedOuterArgs, bool retValExpected, bool withoutDebugInfo); ref_t compileMessageArguments(SyntaxNode current, ArgumentsInfo& arguments, ref_t expectedSignRef, ExpressionAttribute mode, - ArgumentsInfo* updatedOuterArgs, ArgumentListType& argListType); + ArgumentsInfo* updatedOuterArgs, ArgumentListType& argListType, int nillableArgs); MessageResolution resolveByRefHandler(ObjectInfo source, ref_t expectedRef, mssg_t weakMessage, ref_t& signatureRef, bool noExtensions); MessageResolution resolveMessageAtCompileTime(ObjectInfo target, mssg_t weakMessage, ref_t implicitSignatureRef, bool ignoreExtensions, @@ -1349,6 +1350,7 @@ namespace elena_lang ObjectInfo compileTupleCollection(SyntaxNode node, ref_t targetRef); ObjectInfo compileKeyValue(SyntaxNode node, ExpressionAttribute mode); ObjectInfo compileClosureOperation(SyntaxNode node); + ObjectInfo compileInterpolation(SyntaxNode node); ObjectInfo compileSubCode(SyntaxNode node, ExpressionAttribute mode, bool withoutNewScope = false); @@ -1538,7 +1540,7 @@ namespace elena_lang void declareParameter(MethodScope& scope, SyntaxNode node, bool withoutWeakMessages, bool declarationMode, bool& variadicMode, bool& weakSignature, bool& noSignature, - pos_t& paramCount, ref_t* signature, size_t& signatureLen); + pos_t& paramCount, ref_t* signature, size_t& signatureLen, bool& nillable); ref_t declareClosureParameters(MethodScope& methodScope, SyntaxNode argNode); @@ -1703,7 +1705,7 @@ namespace elena_lang void injectVirtualCode(SyntaxNode classNode, ClassScope& scope, bool interfaceBased); void injectVirtualMultimethod(SyntaxNode classNode, SyntaxKey methodType, Scope& scope, - ref_t targetRef, ClassInfo& info, mssg_t multiMethod); + ref_t targetRef, ClassInfo& info, mssg_t multiMethod, int nillableArgs); void injectVirtualEmbeddableWrapper(SyntaxNode classNode, SyntaxKey methodType, ref_t targetRef, ClassInfo& info, mssg_t multiMethod, bool abstractOne); @@ -1713,12 +1715,12 @@ namespace elena_lang void injectInitializer(SyntaxNode classNode, SyntaxKey methodType, mssg_t message); bool injectVirtualStrongTypedMultimethod(SyntaxNode classNode, SyntaxKey methodType, Scope& scope, - mssg_t message, mssg_t resendMessage, TypeInfo outputInfo, Visibility visibility, bool isExtension); + mssg_t message, mssg_t resendMessage, TypeInfo outputInfo, Visibility visibility, bool isExtension, int nillableArgs); bool injectVirtualStrongTypedVariadicMultimethod(SyntaxNode classNode, SyntaxKey methodType, ModuleScopeBase& scope, mssg_t message, mssg_t resendMessage, ref_t outputRef, Visibility visibility, bool isExtension); void injectVirtualMultimethod(SyntaxNode classNode, SyntaxKey methodType, Scope& scope, - ref_t targetRef, ClassInfo& classInfo, mssg_t message, bool inherited, TypeInfo outputInfo, Visibility visibility); + ref_t targetRef, ClassInfo& classInfo, mssg_t message, bool inherited, TypeInfo outputInfo, Visibility visibility, int nillableArgs); void injectVirtualMultimethod(SyntaxNode classNode, SyntaxKey methodType, Scope& scope, mssg_t message, mssg_t resendMessage, ref_t resendTarget, TypeInfo outputInfo, Visibility visibility, bool isExtension); diff --git a/elenasrc3/elc/compilerlogic.cpp b/elenasrc3/elc/compilerlogic.cpp index c550b5056..7a0bb22c2 100644 --- a/elenasrc3/elc/compilerlogic.cpp +++ b/elenasrc3/elc/compilerlogic.cpp @@ -1108,6 +1108,8 @@ bool CompilerLogic :: validateArgumentAttribute(ref_t attrValue, TypeAttributes& case V_VARIADIC: attributes.variadicOne = true; return true; + case V_VARIABLE: + return true; default: return false; } @@ -2349,6 +2351,7 @@ bool CompilerLogic :: checkMethod(ClassInfo& info, mssg_t message, CheckMethodRe } result.stackSafe = test(methodInfo.hints, (ref_t)MethodHint::Stacksafe); + result.nillableArgs = methodInfo.nillableArgs; if (test(methodInfo.hints, (ref_t)MethodHint::Constant)) { result.constRef = info.attributes.get({ message, ClassAttribute::ConstantMethod }); @@ -2439,7 +2442,7 @@ bool CompilerLogic :: isNeedVerification(ClassInfo& info, VirtualMethodList& imp for (auto it = implicitMultimethods.start(); !it.eof(); it++) { auto vm = *it; - mssg_t message = vm.value1; + mssg_t message = vm.message; auto methodInfo = info.methods.get(message); ref_t outputRef = methodInfo.outputRef; @@ -2577,20 +2580,25 @@ void CompilerLogic :: generateVirtualDispatchMethod(ModuleScopeBase& scope, ref_ methods.add({ mssg, methodInfo.outputRef }); } } - } -mssg_t CompilerLogic :: resolveSingleDispatch(ModuleScopeBase& scope, ref_t reference, ref_t weakMessage) +mssg_t CompilerLogic :: resolveSingleDispatch(ModuleScopeBase& scope, ref_t reference, ref_t weakMessage, int& nillableArgs) { if (!reference) return 0; ClassInfo info; if (defineClassInfo(scope, info, reference)) { - return info.attributes.get({ weakMessage, ClassAttribute::SingleDispatch }); + mssg_t dispatcher = info.attributes.get({ weakMessage, ClassAttribute::SingleDispatch }); + if (dispatcher) { + CheckMethodResult result; + if (checkMethod(info, dispatcher, result)) + nillableArgs = result.nillableArgs; + } + + return dispatcher; } else return 0; - } inline size_t readSignatureMember(ustr_t signature, size_t index) diff --git a/elenasrc3/elc/compilerlogic.h b/elenasrc3/elc/compilerlogic.h index ce123253a..a5144924b 100644 --- a/elenasrc3/elc/compilerlogic.h +++ b/elenasrc3/elc/compilerlogic.h @@ -24,6 +24,7 @@ namespace elena_lang bool stackSafe; bool withVariadicDispatcher; bool withCustomDispatcher; + int nillableArgs; }; struct TypeAttributes @@ -195,7 +196,7 @@ namespace elena_lang bool resolveCallType(ModuleScopeBase& scope, ref_t classRef, mssg_t message, CheckMethodResult& result); - mssg_t resolveSingleDispatch(ModuleScopeBase& scope, ref_t reference, ref_t weakMessage); + mssg_t resolveSingleDispatch(ModuleScopeBase& scope, ref_t reference, ref_t weakMessage, int& nillableArgs); void injectOverloadList(CompilerBase* compiler, ModuleScopeBase& scope, ClassInfo& info, ref_t classRef); void injectMethodOverloadList(CompilerBase* compiler, ModuleScopeBase& scope, ref_t flags, diff --git a/elenasrc3/elc/compiling.cpp b/elenasrc3/elc/compiling.cpp index 821712e11..2504b7865 100644 --- a/elenasrc3/elc/compiling.cpp +++ b/elenasrc3/elc/compiling.cpp @@ -353,7 +353,8 @@ CompilingProcess :: CompilingProcess(PathString& appPath, path_t exeExtension, SyntaxTree::toParseKey(SyntaxKey::hexinteger), SyntaxTree::toParseKey(SyntaxKey::longinteger), SyntaxTree::toParseKey(SyntaxKey::real), - SyntaxTree::toParseKey(SyntaxKey::constant)); + SyntaxTree::toParseKey(SyntaxKey::constant), + SyntaxTree::toParseKey(SyntaxKey::interpolate)); _parser = new Parser(&syntax, terminals, _presenter); _compiler = new Compiler( diff --git a/elenasrc3/elc/derivation.cpp b/elenasrc3/elc/derivation.cpp index 438b1b44e..8950b3786 100644 --- a/elenasrc3/elc/derivation.cpp +++ b/elenasrc3/elc/derivation.cpp @@ -650,6 +650,9 @@ void SyntaxTreeBuilder :: flushExpressionMember(SyntaxTreeWriter& writer, Scope& case SyntaxKey::NullableType: flushNullable(writer, scope, current); break; + case SyntaxKey::interpolate: + flushNode(writer, scope, current); + break; case SyntaxKey::Idle: break; default: @@ -1828,6 +1831,7 @@ void SyntaxTreeBuilder :: appendTerminal(parse_key_t key, ustr_t value, LineInfo switch (syntaxKey) { case SyntaxKey::string: + case SyntaxKey::interpolate: { QuoteString quote(value, value.length_pos()); diff --git a/elenasrc3/elc/parser.cpp b/elenasrc3/elc/parser.cpp index 8107a3763..ce0c28920 100644 --- a/elenasrc3/elc/parser.cpp +++ b/elenasrc3/elc/parser.cpp @@ -43,7 +43,10 @@ parse_key_t Parser :: resolveTerminal(SourceInfo& info) return _terminalKeys.globalreference; case dfaQuote: case dfaQuoteCode: + case dfaAltQuote: return _terminalKeys.string; + case dfaStartInterpol: + return _terminalKeys.interpolate; case dfaWideQuote: return _terminalKeys.wide; case dfaEOF: diff --git a/elenasrc3/elc/parser.h b/elenasrc3/elc/parser.h index 6db4aaee4..a1f1a15c0 100644 --- a/elenasrc3/elc/parser.h +++ b/elenasrc3/elc/parser.h @@ -47,6 +47,7 @@ namespace elena_lang parse_key_t integer, hexinteger; parse_key_t longinteger, real; parse_key_t customnumber; + parse_key_t interpolate; TerminalMap() { @@ -58,6 +59,7 @@ namespace elena_lang this->integer = this->hexinteger = 0; this->longinteger = this->real = 0; this->customnumber = 0; + this->interpolate = 0; } TerminalMap(parse_key_t eof, parse_key_t identifier, @@ -70,7 +72,8 @@ namespace elena_lang parse_key_t hexinteger, parse_key_t longinteger, parse_key_t real, - parse_key_t customnumber) + parse_key_t customnumber, + parse_key_t interpolate) { this->eof = eof; this->identifier = identifier; @@ -84,6 +87,7 @@ namespace elena_lang this->longinteger = longinteger; this->real = real; this->customnumber = customnumber; + this->interpolate = interpolate; } }; diff --git a/elenasrc3/elc/source.cpp b/elenasrc3/elc/source.cpp index 870a0a4b4..ad0dfe876 100644 --- a/elenasrc3/elc/source.cpp +++ b/elenasrc3/elc/source.cpp @@ -3,7 +3,7 @@ // // This file contains ELENA Source Reader class implementation. // -// (C)2021-2023, by Aleksey Rakov +// (C)2021-2024, by Aleksey Rakov //--------------------------------------------------------------------------- #include "elena.h" @@ -12,7 +12,7 @@ using namespace elena_lang; -const char* source_dfa[37] = +const char* source_dfa[40] = { ".????????BB??B??????????????????BdFIRCDLDQDbDVQHEEEEEEEEEEDDDDYc`CCCCCCCCCCCCCCCCCCCCCCCCCCDeQDC?CCCCCCCCCCCCCCCCCCCCCCCCCCDDDDC", "*********BB*********************B***********************************************************************************************", @@ -31,7 +31,7 @@ const char* source_dfa[37] = "?OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "?OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOBOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASSSSSSSSSSAAAAAAARRRRRRRRRRRRRRRRRRRRRRRRRRAAAAAARRRRRRRRRRRRRRRRRRRRRRRRRRAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfAAAAAAAAAAAAASSSSSSSSSSAAAAAAARRRRRRRRRRRRRRRRRRRRRRRRRRAAAAAARRRRRRRRRRRRRRRRRRRRRRRRRRAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFATAAAAAAAAAAASSSSSSSSSSAAAAAAASSSSSSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASAAAAAAAAAAAAAAAAAAAAAAA", "????????????????????????????????????????????????UUUUUUUUUU??????????????????????????????????????????????????????????????????????", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAGAAAAAAAAAAAUUUUUUUUUUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -50,15 +50,18 @@ const char* source_dfa[37] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "ffffffffffffffffffffffffffffffffffhffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffgffff", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" }; // --- SourceReader --- SourceReader::SourceReader(int tabSize, UStrReader* reader) - : TextParser(source_dfa, tabSize, reader), _operatorMode(false) + : TextParser(source_dfa, tabSize, reader), _operatorMode(false), _interpolating(false), _bracketLevel(0) { - + _startState = dfaStart; } ustr_t SourceReader :: copyToken(char* token, size_t length) @@ -87,11 +90,46 @@ ustr_t SourceReader :: copyQuote(char* token, size_t length, List& dynamicStrings) +{ + pos_t start = _startPosition; + if (_line[start] == '$' || _line[start] == '{') + start++; + + size_t tokenLen = _position - start; + if (_line[start] != '"') + tokenLen++; + + if (tokenLen > length) { + char* str = StrFactory::allocate(tokenLen + 1, DEFAULT_STR); + ::copyInterpolQuote(str, _line, start, tokenLen); + + dynamicStrings.add(str); + + return str; + } + else return ::copyInterpolQuote(token, _line, start, tokenLen); +} + SourceInfo SourceReader :: read(char* line, size_t length, List& dynamicStrings) { SourceInfo info; - char terminalState = TextParser::read(dfaStart, info.state, info.lineInfo); + char terminalState = TextParser::read(_startState, info.state, info.lineInfo); switch (terminalState) { case dfaError: throw InvalidChar(info.lineInfo, _line[_position]); @@ -110,12 +148,47 @@ SourceInfo SourceReader :: read(char* line, size_t length, List& break; } - if (IsQuoteToken(info.state)) { - info.symbol = copyQuote(line, length, dynamicStrings); + switch (info.state) { + case dfaQuote: + case dfaWideQuote: + case dfaCharacter: + info.symbol = copyQuote(line, length, dynamicStrings); + break; + case dfaAltQuote:; + _startState = dfaStart; + + info.symbol = copyInterpolQuote(line, length, dynamicStrings); + info.state = dfaStartInterpol; + break; + case dfaStartInterpol: + _interpolating = true; + _bracketLevel = 1; + _startState = dfaStart; + + info.symbol = copyInterpolQuote(line, length, dynamicStrings); + break; + default: + info.symbol = copyToken(line, length); + break; } - else info.symbol = copyToken(line, length); _operatorMode = IsOperator(info.state); + if (_operatorMode && _interpolating) { + ustr_t op(line); + + if (op.compare("{")) { + _bracketLevel++; + } + else if (op.compare("}")) { + _bracketLevel--; + if (!_bracketLevel) { + _startState = dfaNextInterpol; + _interpolating = false; + + info = read(line, length, dynamicStrings); + } + } + } return info; } diff --git a/elenasrc3/elc/source.h b/elenasrc3/elc/source.h index 8b109e212..d0d766e5a 100644 --- a/elenasrc3/elc/source.h +++ b/elenasrc3/elc/source.h @@ -33,10 +33,14 @@ namespace elena_lang // --- SourceReader --- class SourceReader : protected TextParser { + char _startState; bool _operatorMode; + bool _interpolating; + int _bracketLevel; ustr_t copyToken(char* token, size_t length); ustr_t copyQuote(char* token, size_t length, List& dynamicStrings); + ustr_t copyInterpolQuote(char* token, size_t length, List& dynamicStrings); bool IsOperator(char state) { @@ -44,10 +48,6 @@ namespace elena_lang || state == dfaGrOperator || state == dfaIncOperator || state == dfaIfOperator || state == dfaElseOperator || state == dfaAltOpOperator); } - bool IsQuoteToken(char state) - { - return (state == dfaQuote || state == dfaWideQuote || state == dfaCharacter); - } void resolveSignAmbiguity(SourceInfo& info) { diff --git a/elenasrc3/elc/windows/ntlinker.cpp b/elenasrc3/elc/windows/ntlinker.cpp index 4e347e873..606858524 100644 --- a/elenasrc3/elc/windows/ntlinker.cpp +++ b/elenasrc3/elc/windows/ntlinker.cpp @@ -42,7 +42,7 @@ void WinNtLinker :: writeExecutableHeader(WinNtExecutableImage& image, FileWrite IMAGE_FILE_HEADER header = {}; header.Characteristics = image.characteristics; - header.NumberOfSections = image.imageSections.headers.count(); + header.NumberOfSections = image.imageSections.headers.count_short(); header.TimeDateStamp = (int)time(nullptr); header.PointerToSymbolTable = 0; header.NumberOfSymbols = 0; diff --git a/elenasrc3/elena-tests/bt_optimization.cpp b/elenasrc3/elena-tests/bt_optimization.cpp index 42bd8c6c0..ae071e9bb 100644 --- a/elenasrc3/elena-tests/bt_optimization.cpp +++ b/elenasrc3/elena-tests/bt_optimization.cpp @@ -28,6 +28,7 @@ constexpr auto SyntaxTree1_3 = "expression(assign_operation(object(type(identifi constexpr auto Declaration2 = "namespace (class ( nameattr (identifier \"Object\" ())) class (attribute -2147467263 () attribute -2147475455 () attribute -2147479550 () nameattr (identifier \"IntNumber\" ()) field (attribute -2147475454 () attribute -2147481597 () nameattr (identifier \"_value\" ())dimension (integer \"4\" ()))) class ( attribute -2147471359 () nameattr (identifier \"IntNumberReference\" ()) field (attribute -2147475454 () type (identifier \"IntNumber\" ()) nameattr (identifier \"_value\" ())) ))"; constexpr auto SyntaxTree2 = "expression (assign_operation (object (type (identifier \"IntNumber\" ()) identifier \"n\" ()) expression (object (integer \"2\"))))"; +constexpr auto SyntaxTree4 = "expression ( code( expression (assign_operation (object (type (identifier \"IntNumber\" ())identifier \"n\" ())expression (object (integer \"3\" ()))))expression (assign_operation (object (type (identifier \"IntNumber\" ())identifier \"r\" ())expression (add_operation (object (identifier \"n\" ())expression (object (integer \"2\" ()))))))))"; constexpr auto Struct_Declaration1 = "namespace (class ( nameattr (identifier \"Object\" ())) class (attribute -2147479550 () nameattr (identifier \"IntNumber\" ()) field (attribute -2147475454 () attribute -2147481597 () nameattr ( identifier \"_value\" ()) dimension ( integer \"4\" ()))) class (attribute -2147479550 () nameattr (identifier \"ByteNumber\" ()) field (attribute -2147475454 () attribute -2147481596 () nameattr (identifier \"_value\" ()) dimension (integer \"1\" ())))class (attribute -2147479550 () nameattr 60 (identifier \"ShortNumber\" ()) field (attribute -2147475454 () attribute -2147481597 ()nameattr ( identifier \"_value\" ()) dimension ( integer \"2\" ()))) class (attribute -2147479550 ()nameattr (identifier \"LongNumber\" ())field (attribute -2147475454 () attribute -2147481597 () nameattr ( identifier \"_value\" ()) dimension (integer \"8\" ()))) class (attribute -2147479550 () nameattr (identifier \"Aligned\" ())field (type (identifier \"byte\" ())nameattr (identifier \"b\" ()) ) field (type (identifier \"short\" ())nameattr (identifier \"w\" ())) field (type (identifier \"byte\" ())nameattr (identifier \"b2\" ())) field (type (identifier \"int\" ())nameattr (identifier \"n\" ())) field (type (identifier \"byte\" ())nameattr (identifier \"b3\" ()))field (type (identifier \"long\" ()) nameattr (identifier \"l\" ()))))"; constexpr auto Struct_Declaration2 = "namespace (class ( nameattr (identifier \"Object\" ())) class (attribute -2147479550 () nameattr (identifier \"IntNumber\" ()) field (attribute -2147475454 () attribute -2147481597 () nameattr ( identifier \"_value\" ()) dimension ( integer \"4\" ()))) class (attribute -2147479550 () nameattr (identifier \"ByteNumber\" ()) field (attribute -2147475454 () attribute -2147481596 () nameattr (identifier \"_value\" ()) dimension (integer \"1\" ())))class (attribute -2147479550 () nameattr 60 (identifier \"ShortNumber\" ()) field (attribute -2147475454 () attribute -2147481597 ()nameattr ( identifier \"_value\" ()) dimension ( integer \"2\" ()))) class (attribute -2147479550 ()nameattr (identifier \"LongNumber\" ())field (attribute -2147475454 () attribute -2147481597 () nameattr ( identifier \"_value\" ()) dimension (integer \"8\" ()))) class (attribute -2147479508 () nameattr (identifier \"Aligned\" ())field (type (identifier \"byte\" ())nameattr (identifier \"b\" ()) ) field (type (identifier \"short\" ())nameattr (identifier \"w\" ())) field (type (identifier \"byte\" ())nameattr (identifier \"b2\" ())) field (type (identifier \"int\" ())nameattr (identifier \"n\" ())) field (type (identifier \"byte\" ())nameattr (identifier \"b3\" ()))field (type (identifier \"long\" ()) nameattr (identifier \"l\" ()))))"; @@ -54,10 +55,12 @@ constexpr auto S2_Scenario1 = "class (attribute -2147479546 ()nameattr (identifi constexpr auto BuildTree1_1 = "byrefmark -8 () local_address -8 () saving_stack 1 () class_reference 4 () saving_stack () argument () direct_call_op 2050 (type 4 ()) local_address -8 () copying -4 (size 4 ())"; constexpr auto BuildTree1_2 = "byrefmark -8 () local_address -8 () saving_stack 1 () class_reference 4 () saving_stack () argument () direct_call_op 2242 (type 4 ()) local_address -8 () copying -4 (size 4 ())"; constexpr auto BuildTree2 = "int_literal 2 (value 2 ()) copying -4 ( size 4 ())"; +constexpr auto BuildTree4 = "int_literal 2 (value 3 ())copying -4 (size 4 ())local_address -4 ()saving_stack ()int_literal 3 (value 2 ())saving_stack 1 ()intop 4 (index -12 ())local_address -12 ()copying -8 (size 4 ())"; constexpr auto OptimizedBuildTree1_1 = "local_address -4 () saving_stack 1 () class_reference 4 () saving_stack () argument () direct_call_op 2050 (type 4 ()) local_address -4 ()"; constexpr auto OptimizedBuildTree1_2 = "local_address -4 () saving_stack 1 () class_reference 4 () saving_stack () argument () direct_call_op 2242 (type 4 ()) local_address -4 ()"; constexpr auto OptimizedBuildTree2 = "saving_int - 4 (size 4 ()value 2 ())"; +constexpr auto OptimizedBuildTree4 = "saving_int -4 (size 4 ()value 3 ())local_address -4 ()copying -8 (size 4 ())addingint -8 (value 2 ())"; constexpr auto BuildTree_VariadicSingleDispatch_1 = "tape(sealed_dispatching 256 (message 3202 ()) open_frame() assigning 1 () local_reference -2 () saving_stack() varg_sop 6 (index -4 ()) unbox_call_message -2 (index 1 () length -4 () temp_var -8 () message 1089 ()) local 1 () saving_stack() argument() direct_call_op 3202 (type 5 ()) loading_index() free_varstack() close_frame() exit()) reserved 3 ()reserved_n 8 ())"; constexpr auto BuildTree_VariadicSingleDispatch_2 = "tape(open_frame() assigning 1 () class_reference 2 () direct_call_op 544 (type 10 ()) assigning 2 () class_reference 8 () direct_call_op 544 (type 14 ()) assigning 3 () local 2 () saving_stack() argument() call_op 1089 () assigning 4 () local 3 () saving_stack() argument() call_op 1089 () assigning 5 () terminator() saving_stack 3 () local 5 () saving_stack 2 () local 4 () saving_stack 1 () class_reference 5 () saving_stack() argument() direct_call_op 3202 (type 5 ()) local 1 () close_frame() exit()) reserved 9 ()"; @@ -79,10 +82,12 @@ constexpr auto ComplexStructSize = 16; constexpr auto BuildTree1_1 = "byrefmark -24 () local_address -24 () saving_stack 1 () class_reference 4 () saving_stack () argument () direct_call_op 2050 (type 4 ()) local_address -24 () copying -8 (size 4 ())"; constexpr auto BuildTree1_2 = "byrefmark -24 () local_address -24 () saving_stack 1 () class_reference 4 () saving_stack () argument () direct_call_op 2242 (type 4 ()) local_address -24 () copying -8 (size 4 ())"; constexpr auto BuildTree2 = "int_literal 2 (value 2 ()) copying -8 ( size 4 ())"; +constexpr auto BuildTree4 = "int_literal 2 (value 3 ())copying -8 (size 4 ())local_address -8 ()saving_stack ()int_literal 3 (value 2 ())saving_stack 1 ()intop 4 (index -40 ())local_address -40 ()copying -24 (size 4 ())"; constexpr auto OptimizedBuildTree1_1 = "local_address -8 () saving_stack 1 () class_reference 4 () saving_stack () argument () direct_call_op 2050 (type 4 ()) local_address -8 ()"; constexpr auto OptimizedBuildTree1_2 = "local_address -8 () saving_stack 1 () class_reference 4 () saving_stack () argument () direct_call_op 2242 (type 4 ()) local_address -8 ()"; constexpr auto OptimizedBuildTree2 = "saving_int - 8 (size 4 ()value 2 ())"; +constexpr auto OptimizedBuildTree4 = "saving_int -8 (size 4 ()value 3 ())local_address -8 ()copying -24 (size 4 ())addingint -24 (value 2 ())"; constexpr auto BuildTree_VariadicSingleDispatch_1 = "tape(sealed_dispatching 256 (message 3202 ()) open_frame() assigning 1 () local_reference -2 () saving_stack() varg_sop 6 (index -8 ()) unbox_call_message -2 (index 1 () length -8 () temp_var -24 () message 1089 ()) local 1 () saving_stack() argument() direct_call_op 3202 (type 5 ()) loading_index() free_varstack() close_frame() exit()) reserved 4 ()reserved_n 32 ())"; constexpr auto BuildTree_VariadicSingleDispatch_2 = "tape(open_frame() assigning 1 () class_reference 2 () direct_call_op 544 (type 10 ()) assigning 2 () class_reference 8 () direct_call_op 544 (type 14 ()) assigning 3 () local 2 () saving_stack() argument() call_op 1089 () assigning 4 () local 3 () saving_stack() argument() call_op 1089 () assigning 5 () terminator() saving_stack 3 () local 5 () saving_stack 2 () local 4 () saving_stack 1 () class_reference 5 () saving_stack() argument() direct_call_op 3202 (type 5 ()) local 1 () close_frame() exit()) reserved 10 ()"; @@ -294,6 +299,19 @@ void BTOptimization2 :: SetUp() BuildTreeSerializer::load(OptimizedBuildTree2, afterOptimization); } +// --- BTOptimization4 --- + +void BTOptimization4 :: SetUp() +{ + BTOptimization::SetUp(); + + SyntaxTreeSerializer::load(Declaration2, declarationNode); + SyntaxTreeSerializer::load(SyntaxTree4, exprNode); + + BuildTreeSerializer::load(BuildTree4, beforeOptimization); + BuildTreeSerializer::load(OptimizedBuildTree4, afterOptimization); +} + // --- StructAlignment --- void StructAlignment :: SetUp() diff --git a/elenasrc3/elena-tests/bt_optimization.h b/elenasrc3/elena-tests/bt_optimization.h index c25302645..027e85330 100644 --- a/elenasrc3/elena-tests/bt_optimization.h +++ b/elenasrc3/elena-tests/bt_optimization.h @@ -90,6 +90,13 @@ namespace elena_lang void SetUp() override; }; + // Optimization #4 (intOpWithConsts) : "int r := n + 2" => direct op with consts + class BTOptimization4 : public BTOptimization + { + protected: + void SetUp() override; + }; + // --- StructAlignment --- class StructAlignment : public StructTest { diff --git a/elenasrc3/elena-tests/bt_tests.cpp b/elenasrc3/elena-tests/bt_tests.cpp index 464b8404c..fa4bd608e 100644 --- a/elenasrc3/elena-tests/bt_tests.cpp +++ b/elenasrc3/elena-tests/bt_tests.cpp @@ -19,6 +19,11 @@ TEST_F(BTOptimization1_3, BuildTapeTest) } TEST_F(BTOptimization2, BuildTapeTest) +{ + runBTTest(); +} + +TEST_F(BTOptimization4, BuildTapeTest) { runBTTest(); } \ No newline at end of file diff --git a/elenasrc3/elena-tests/compiler_tests.cpp b/elenasrc3/elena-tests/compiler_tests.cpp index 5e80a9866..41c2566db 100644 --- a/elenasrc3/elena-tests/compiler_tests.cpp +++ b/elenasrc3/elena-tests/compiler_tests.cpp @@ -26,6 +26,11 @@ TEST_F(BTOptimization2, CompilerTest) runCompilerTest(false); } +TEST_F(BTOptimization4, CompilerTest) +{ + runCompilerTest(false); +} + TEST_F(StructAlignment, CompilerTest) { runTest(); diff --git a/elenasrc3/elena-tests/declaration.cpp b/elenasrc3/elena-tests/declaration.cpp index d7b8eedc0..3ca48d338 100644 --- a/elenasrc3/elena-tests/declaration.cpp +++ b/elenasrc3/elena-tests/declaration.cpp @@ -47,7 +47,8 @@ void DeclarationFixture :: runTest() SyntaxTree::toParseKey(SyntaxKey::hexinteger), SyntaxTree::toParseKey(SyntaxKey::longinteger), SyntaxTree::toParseKey(SyntaxKey::real), - SyntaxTree::toParseKey(SyntaxKey::constant)); + SyntaxTree::toParseKey(SyntaxKey::constant), + SyntaxTree::toParseKey(SyntaxKey::interpolate)); PathString appPath; getAppPath(appPath); diff --git a/elenasrc3/engine/bcwriter.cpp b/elenasrc3/engine/bcwriter.cpp index 671d082d1..ed9751cb8 100644 --- a/elenasrc3/engine/bcwriter.cpp +++ b/elenasrc3/engine/bcwriter.cpp @@ -16,6 +16,13 @@ using namespace elena_lang; typedef ByteCodeWriter::TapeScope TapeScope; +//inline void storeNode(BuildNode node) +//{ +// DynamicUStr target; +// +// BuildTreeSerializer::save(node, target); +//} + //inline void testNodes(BuildNode node) //{ // BuildNode current = node.firstChild(); diff --git a/elenasrc3/engine/bcwriter.h b/elenasrc3/engine/bcwriter.h index a38ee17d7..189d6e24b 100644 --- a/elenasrc3/engine/bcwriter.h +++ b/elenasrc3/engine/bcwriter.h @@ -11,6 +11,7 @@ #include "buildtree.h" #include "bytecode.h" +#include "langcommon.h" namespace elena_lang { diff --git a/elenasrc3/engine/elena.h b/elenasrc3/engine/elena.h index 4a84faa74..f00cc013e 100644 --- a/elenasrc3/engine/elena.h +++ b/elenasrc3/engine/elena.h @@ -1108,33 +1108,6 @@ namespace elena_lang ref_t valueRef; }; - // --- MethodInfo --- - struct MethodInfo - { - bool inherited; - ref_t hints; - ref_t outputRef; - mssg_t multiMethod; - mssg_t byRefHandler; - - MethodInfo() - { - inherited = false; - hints = 0; - outputRef = 0; - multiMethod = 0; - byRefHandler = 0; - } - MethodInfo(bool inherited, ref_t hints, ref_t outputRef, mssg_t multiMethod, mssg_t byRefHandler) : - inherited(inherited), - hints(hints), - outputRef(outputRef), - multiMethod(multiMethod), - byRefHandler(byRefHandler) - { - } - }; - // --- ClassHeader --- struct ClassHeader { @@ -1201,174 +1174,6 @@ namespace elena_lang }; #pragma pack(pop) - // --- SymbolInfo --- - enum class SymbolType : int - { - Symbol = 0, - Singleton, - Constant, - ConstantArray, - }; - - struct SymbolInfo - { - SymbolType symbolType; - ref_t valueRef; - ref_t typeRef; - bool loadableInRuntime; - - SymbolInfo() - { - symbolType = SymbolType::Symbol; - valueRef = typeRef = 0; - loadableInRuntime = false; - } - SymbolInfo(SymbolType symbolType, ref_t valueRef, ref_t typeRef, bool loadableInRuntime) - { - this->symbolType = symbolType; - this->valueRef = valueRef; - this->typeRef = typeRef; - this->loadableInRuntime = loadableInRuntime; - } - - void load(StreamReader* reader) - { - symbolType = (SymbolType)reader->getDWord(); - valueRef = reader->getRef(); - typeRef = reader->getRef(); - loadableInRuntime = reader->getBool(); - } - - void save(StreamWriter* writer) - { - writer->writeDWord((unsigned int)symbolType); - writer->writeRef(valueRef); - writer->writeRef(typeRef); - writer->writeBool(loadableInRuntime); - } - }; - - // --- ClassInfo --- - struct ClassInfo - { - typedef MemoryMap MethodMap; - typedef MemoryMap FieldMap; - typedef MemoryMap StaticFieldMap; - - ClassHeader header; - pos_t size; // Object size - MethodMap methods; - FieldMap fields; - StaticFieldMap statics; - ClassAttributes attributes; - - static void loadStaticFields(StreamReader* reader, StaticFieldMap& statics) - { - pos_t statCount = reader->getPos(); - for (pos_t i = 0; i < statCount; i++) { - IdentifierString fieldName; - reader->readString(fieldName); - StaticFieldInfo fieldInfo; - reader->read(&fieldInfo, sizeof(fieldInfo)); - - statics.add(*fieldName, fieldInfo); - } - } - - static void saveStaticFields(StreamWriter* writer, StaticFieldMap& statics) - { - writer->writePos(statics.count()); - statics.forEach(writer, [](StreamWriter* writer, ustr_t name, StaticFieldInfo info) - { - writer->writeString(name); - writer->write(&info, sizeof(info)); - }); - } - - void save(StreamWriter* writer, bool headerAndSizeOnly = false) - { - writer->write(&header, sizeof(ClassHeader)); - writer->writeDWord(size); - if (!headerAndSizeOnly) { - writer->writePos(fields.count()); - fields.forEach(writer, [](StreamWriter* writer, ustr_t name, FieldInfo info) - { - writer->writeString(name); - writer->write(&info, sizeof(info)); - }); - - writer->writePos(methods.count()); - methods.forEach(writer, [](StreamWriter* writer, mssg_t message, MethodInfo info) - { - writer->writeDWord(message); - writer->write(&info, sizeof(info)); - }); - - writer->writePos(attributes.count()); - attributes.forEach(writer, [](StreamWriter* writer, ClassAttributeKey key, ref_t reference) - { - writer->write(&key, sizeof(key)); - writer->writeRef(reference); - }); - - saveStaticFields(writer, statics); - } - } - - void load(StreamReader* reader, bool headerAndSizeOnly = false, bool fieldsOnly = false) - { - reader->read(&header, sizeof(ClassHeader)); - size = reader->getDWord(); - if (!headerAndSizeOnly) { - pos_t fieldCount = reader->getPos(); - for (pos_t i = 0; i < fieldCount; i++) { - IdentifierString fieldName; - reader->readString(fieldName); - FieldInfo fieldInfo; - reader->read(&fieldInfo, sizeof(fieldInfo)); - - fields.add(*fieldName, fieldInfo); - } - - if (!fieldsOnly) { - pos_t methodsCount = reader->getPos(); - for (pos_t i = 0; i < methodsCount; i++) { - mssg_t message = reader->getDWord(); - MethodInfo methodInfo; - reader->read(&methodInfo, sizeof(MethodInfo)); - - methods.add(message, methodInfo); - } - pos_t attrCount = reader->getPos(); - for (pos_t i = 0; i < attrCount; i++) { - ClassAttributeKey key; - reader->read(&key, sizeof(key)); - - ref_t reference = reader->getRef(); - - attributes.add(key, reference); - } - - loadStaticFields(reader, statics); - } - } - } - - ClassInfo() : - header({}), - size(0), - methods({}), - fields({ -1 }), - statics({ -1 }), - attributes(0) - { - //header.staticSize = 0; - //header.parentRef = header.classRef = 0; - //header.flags = 0; - //header.count = size = 0; - } - }; - // --- ExceptionBase --- class ExceptionBase {}; diff --git a/elenasrc3/engine/elenaconst.h b/elenasrc3/engine/elenaconst.h index f1ba2fec9..1d5faed3e 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 2 + #define ENGINE_MINOR_VERSION 3 constexpr auto LINE_LEN = 0x1000; // the maximal source line length constexpr auto IDENTIFIER_LEN = 0x0300; // the maximal identifier length @@ -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.0612"; // the module version + constexpr auto MODULE_SIGNATURE = "ELENA.0620"; // the module version constexpr auto DEBUG_MODULE_SIGNATURE = "ED.06"; // --- ELENA core module names --- diff --git a/elenasrc3/engine/jitcompiler.cpp b/elenasrc3/engine/jitcompiler.cpp index c4f102cb6..2398f698e 100644 --- a/elenasrc3/engine/jitcompiler.cpp +++ b/elenasrc3/engine/jitcompiler.cpp @@ -90,7 +90,7 @@ constexpr ref_t coreFunctions[coreFunctionNumber] = }; // preloaded bc commands -constexpr size_t bcCommandNumber = 175; +constexpr size_t bcCommandNumber = 176; constexpr ByteCode bcCommands[bcCommandNumber] = { ByteCode::MovEnv, ByteCode::SetR, ByteCode::SetDP, ByteCode::CloseN, ByteCode::AllocI, @@ -127,7 +127,8 @@ constexpr ByteCode bcCommands[bcCommandNumber] = ByteCode::FISub,ByteCode::FIMul,ByteCode::FIDiv, ByteCode::SNop, ByteCode::TstStck, ByteCode::Shl, ByteCode::Shr, ByteCode::XLabelDPR, ByteCode::TryLock, ByteCode::FreeLock, ByteCode::XQuit, ByteCode::ExtCloseN, ByteCode::XCmpSI, ByteCode::LoadSI, ByteCode::XFSave, - ByteCode::XSaveN, ByteCode::XSaveDispN, ByteCode::XStoreFIR, ByteCode::LNeg, ByteCode::Parent + ByteCode::XSaveN, ByteCode::XSaveDispN, ByteCode::XStoreFIR, ByteCode::LNeg, ByteCode::Parent, + ByteCode::LLoadSI }; void elena_lang :: writeCoreReference(JITCompilerScope* scope, ref_t reference, diff --git a/elenasrc3/engine/langcommon.h b/elenasrc3/engine/langcommon.h index 74f23653f..94427dce5 100644 --- a/elenasrc3/engine/langcommon.h +++ b/elenasrc3/engine/langcommon.h @@ -32,6 +32,7 @@ namespace elena_lang Virtual = 0x00000005, Dispatcher = 0x00000007, + Interpolator = 0x00000020, Nillable = 0x00000040, Function = 0x00000080, Generic = 0x00000100, @@ -59,6 +60,204 @@ namespace elena_lang Yieldable = 0x80000000, }; + // --- MethodInfo --- + struct MethodInfo + { + bool inherited; + ref_t hints; + ref_t outputRef; + mssg_t multiMethod; + mssg_t byRefHandler; + int nillableArgs; + + MethodInfo() + { + inherited = false; + hints = 0; + outputRef = 0; + multiMethod = 0; + byRefHandler = 0; + nillableArgs = 0; + } + MethodInfo(bool inherited, ref_t hints, ref_t outputRef, mssg_t multiMethod, mssg_t byRefHandler, int nillableArgs) : + inherited(inherited), + hints(hints), + outputRef(outputRef), + multiMethod(multiMethod), + byRefHandler(byRefHandler), + nillableArgs(nillableArgs) + { + } + }; + + // --- SymbolInfo --- + enum class SymbolType : int + { + Symbol = 0, + Singleton, + Constant, + ConstantArray, + }; + + struct SymbolInfo + { + SymbolType symbolType; + ref_t valueRef; + ref_t typeRef; + bool loadableInRuntime; + + SymbolInfo() + { + symbolType = SymbolType::Symbol; + valueRef = typeRef = 0; + loadableInRuntime = false; + } + SymbolInfo(SymbolType symbolType, ref_t valueRef, ref_t typeRef, bool loadableInRuntime) + { + this->symbolType = symbolType; + this->valueRef = valueRef; + this->typeRef = typeRef; + this->loadableInRuntime = loadableInRuntime; + } + + void load(StreamReader* reader) + { + symbolType = (SymbolType)reader->getDWord(); + valueRef = reader->getRef(); + typeRef = reader->getRef(); + loadableInRuntime = reader->getBool(); + } + + void save(StreamWriter* writer) + { + writer->writeDWord((unsigned int)symbolType); + writer->writeRef(valueRef); + writer->writeRef(typeRef); + writer->writeBool(loadableInRuntime); + } + }; + + // --- ClassInfo --- + struct ClassInfo + { + typedef MemoryMap MethodMap; + typedef MemoryMap FieldMap; + typedef MemoryMap StaticFieldMap; + + ClassHeader header; + pos_t size; // Object size + MethodMap methods; + FieldMap fields; + StaticFieldMap statics; + ClassAttributes attributes; + + static void loadStaticFields(StreamReader* reader, StaticFieldMap& statics) + { + pos_t statCount = reader->getPos(); + for (pos_t i = 0; i < statCount; i++) { + IdentifierString fieldName; + reader->readString(fieldName); + StaticFieldInfo fieldInfo; + reader->read(&fieldInfo, sizeof(fieldInfo)); + + statics.add(*fieldName, fieldInfo); + } + } + + static void saveStaticFields(StreamWriter* writer, StaticFieldMap& statics) + { + writer->writePos(statics.count()); + statics.forEach(writer, [](StreamWriter* writer, ustr_t name, StaticFieldInfo info) + { + writer->writeString(name); + writer->write(&info, sizeof(info)); + }); + } + + void save(StreamWriter* writer, bool headerAndSizeOnly = false) + { + writer->write(&header, sizeof(ClassHeader)); + writer->writeDWord(size); + if (!headerAndSizeOnly) { + writer->writePos(fields.count()); + fields.forEach(writer, [](StreamWriter* writer, ustr_t name, FieldInfo info) + { + writer->writeString(name); + writer->write(&info, sizeof(info)); + }); + + writer->writePos(methods.count()); + methods.forEach(writer, [](StreamWriter* writer, mssg_t message, MethodInfo info) + { + writer->writeDWord(message); + writer->write(&info, sizeof(info)); + }); + + writer->writePos(attributes.count()); + attributes.forEach(writer, [](StreamWriter* writer, ClassAttributeKey key, ref_t reference) + { + writer->write(&key, sizeof(key)); + writer->writeRef(reference); + }); + + saveStaticFields(writer, statics); + } + } + + void load(StreamReader* reader, bool headerAndSizeOnly = false, bool fieldsOnly = false) + { + reader->read(&header, sizeof(ClassHeader)); + size = reader->getDWord(); + if (!headerAndSizeOnly) { + pos_t fieldCount = reader->getPos(); + for (pos_t i = 0; i < fieldCount; i++) { + IdentifierString fieldName; + reader->readString(fieldName); + FieldInfo fieldInfo; + reader->read(&fieldInfo, sizeof(fieldInfo)); + + fields.add(*fieldName, fieldInfo); + } + + if (!fieldsOnly) { + pos_t methodsCount = reader->getPos(); + for (pos_t i = 0; i < methodsCount; i++) { + mssg_t message = reader->getDWord(); + MethodInfo methodInfo; + reader->read(&methodInfo, sizeof(MethodInfo)); + + methods.add(message, methodInfo); + } + pos_t attrCount = reader->getPos(); + for (pos_t i = 0; i < attrCount; i++) { + ClassAttributeKey key; + reader->read(&key, sizeof(key)); + + ref_t reference = reader->getRef(); + + attributes.add(key, reference); + } + + loadStaticFields(reader, statics); + } + } + } + + ClassInfo() : + header({}), + size(0), + methods({}), + fields({ -1 }), + statics({ -1 }), + attributes(0) + { + //header.staticSize = 0; + //header.parentRef = header.classRef = 0; + //header.flags = 0; + //header.count = size = 0; + } + }; + // === ELENA Error codes === constexpr auto errInvalidSyntax = 4; constexpr auto errCBrExpectedSyntax = 9; diff --git a/elenasrc3/engine/syntaxtree.h b/elenasrc3/engine/syntaxtree.h index e8ee04818..61a6f703a 100644 --- a/elenasrc3/engine/syntaxtree.h +++ b/elenasrc3/engine/syntaxtree.h @@ -39,6 +39,7 @@ namespace elena_lang constant = 0x00300D, longinteger = 0x00300E, real = 0x00300F, + interpolate = 0x003010, // NOTE : low word should be unique for every key Declaration = 0x001400, @@ -146,9 +147,11 @@ namespace elena_lang NestedRootExpression = 0x00189B, TemplateOperation = 0x00189C, LTExpression = 0x00189D, + InterpolExpression = 0x00189E, TemplateExpression = 0x0018A0, KeyValueExpression = 0x0018A1, ClosureOperation = 0x0018A2, + Interpolation = 0x0018A3, FieldInitializer = 0x0018B0, Message = 0x0010C0, MessageOperation = 0x0018C1, @@ -205,6 +208,7 @@ namespace elena_lang ProxyDispatcher = 0x000112, EnumNameArgParameter = 0x000113, EnumArgParameter = 0x000114, + NillableInfo = 0x000115, Column = 0x000201, Row = 0x000202, diff --git a/elenasrc3/engine/textparser.h b/elenasrc3/engine/textparser.h index fd7b51ef7..5f21b9b4a 100644 --- a/elenasrc3/engine/textparser.h +++ b/elenasrc3/engine/textparser.h @@ -40,6 +40,9 @@ namespace elena_lang constexpr char dfaIfOperator = 'c'; constexpr char dfaElseOperator = 'd'; constexpr char dfaAltOpOperator = 'e'; + constexpr char dfaStartInterpol = 'g'; + constexpr char dfaNextInterpol = 'f'; + constexpr char dfaAltQuote = 'h'; constexpr char dfaPrivate = 'N'; constexpr char dfaLong = '?'; diff --git a/elenasrc3/ldbg/ldbg_session.cpp b/elenasrc3/ldbg/ldbg_session.cpp index 615e0adc1..91ca8a3ba 100644 --- a/elenasrc3/ldbg/ldbg_session.cpp +++ b/elenasrc3/ldbg/ldbg_session.cpp @@ -26,4 +26,10 @@ DPASessionWrapper :: ~DPASessionWrapper() void DPASessionWrapper :: prepare() { _session = new dpa::Session(); -} \ No newline at end of file +} + +void DPASessionWrapper :: run() +{ + // Wait for the ConfigurationDone request to be made. + +} diff --git a/elenasrc3/ldbg/ldbg_session.h b/elenasrc3/ldbg/ldbg_session.h index 2ee7e0fe2..c4df827a7 100644 --- a/elenasrc3/ldbg/ldbg_session.h +++ b/elenasrc3/ldbg/ldbg_session.h @@ -19,6 +19,7 @@ namespace elena_lang public: void prepare(); + void run(); DPASessionWrapper(); virtual ~DPASessionWrapper(); diff --git a/elenasrc3/ldbg/windows/ldbg.cpp b/elenasrc3/ldbg/windows/ldbg.cpp index 1f1338861..65b102626 100644 --- a/elenasrc3/ldbg/windows/ldbg.cpp +++ b/elenasrc3/ldbg/windows/ldbg.cpp @@ -8,14 +8,24 @@ //--------------------------------------------------------------------------- #include "ldbg_session.h" +#include "common.h" using namespace elena_lang; int main() { + printf("Starting\n"); + + int n = 0; + while (true) + { + n++; + } + DPASessionWrapper session; session.prepare(); + session.run(); return 0; } \ No newline at end of file diff --git a/elenasrc3/tools/asmc/asmconst.h b/elenasrc3/tools/asmc/asmconst.h index c86574918..43c246a3b 100644 --- a/elenasrc3/tools/asmc/asmconst.h +++ b/elenasrc3/tools/asmc/asmconst.h @@ -12,7 +12,7 @@ namespace elena_lang { - #define ASM_REVISION_NUMBER 0x0002 + #define ASM_REVISION_NUMBER 0x0003 constexpr auto N_ARGUMENT1 = "__n_1"; constexpr auto N_ARGUMENT2 = "__n_2"; diff --git a/elenasrc3/tools/asmc/bcassembler.cpp b/elenasrc3/tools/asmc/bcassembler.cpp index c5abc0dc3..a53f67748 100644 --- a/elenasrc3/tools/asmc/bcassembler.cpp +++ b/elenasrc3/tools/asmc/bcassembler.cpp @@ -1045,6 +1045,7 @@ bool ByteCodeAssembler :: compileByteCode(ScriptToken& tokenInfo, MemoryWriter& case ByteCode::SaveSI: case ByteCode::LoadSI: case ByteCode::LSaveSI: + case ByteCode::LLoadSI: return compileOpStackI(tokenInfo, writer, opCommand, true); case ByteCode::SaveDP: case ByteCode::LSaveDP: diff --git a/elenasrc3/tools/ecv/ecviewer.cpp b/elenasrc3/tools/ecv/ecviewer.cpp index d75059819..1e2fbab14 100644 --- a/elenasrc3/tools/ecv/ecviewer.cpp +++ b/elenasrc3/tools/ecv/ecviewer.cpp @@ -9,7 +9,6 @@ #include "ecviewer.h" #include "ecvconst.h" #include "module.h" -#include "langcommon.h" using namespace elena_lang; diff --git a/elenasrc3/tools/ecv/ecviewer.h b/elenasrc3/tools/ecv/ecviewer.h index 871615677..0b935394b 100644 --- a/elenasrc3/tools/ecv/ecviewer.h +++ b/elenasrc3/tools/ecv/ecviewer.h @@ -12,6 +12,7 @@ #include "elena.h" #include "bytecode.h" #include "libman.h" +#include "langcommon.h" namespace elena_lang { diff --git a/elenasrc3/tools/ecv/windows/ecv.cpp b/elenasrc3/tools/ecv/windows/ecv.cpp index dc5e7e8c2..798514735 100644 --- a/elenasrc3/tools/ecv/windows/ecv.cpp +++ b/elenasrc3/tools/ecv/windows/ecv.cpp @@ -15,9 +15,6 @@ using namespace elena_lang; -constexpr auto PLATFORM_CATEGORY = "configuration/platform"; -constexpr auto LIB_PATH = "project/libpath"; - #ifdef _M_IX86 constexpr auto PLATFORM_KEY = "Win_x86"; diff --git a/elenasrc3/tools/ldoc/ldoc.h b/elenasrc3/tools/ldoc/ldoc.h index dcad273f3..68128074b 100644 --- a/elenasrc3/tools/ldoc/ldoc.h +++ b/elenasrc3/tools/ldoc/ldoc.h @@ -11,6 +11,7 @@ #include "elena.h" #include "libman.h" +#include "langcommon.h" namespace elena_lang { diff --git a/elenasrc3/tools/sg/sg.cpp b/elenasrc3/tools/sg/sg.cpp index 0704d9cfa..f9481b3ad 100644 --- a/elenasrc3/tools/sg/sg.cpp +++ b/elenasrc3/tools/sg/sg.cpp @@ -25,6 +25,7 @@ constexpr auto DEFAULT_ENCODING = FileEncoding::UTF8; #endif typedef Tree SyntaxTempTree; +typedef Map Coordinates; parse_key_t lastKey = 0; @@ -115,7 +116,7 @@ parse_key_t registerEpsRule(ParserTable& table, parse_key_t key) return eps_key; } -void registerBrackets(ParserTable& table, parse_key_t* rule, size_t& rule_len, size_t start) +void registerBrackets(ParserTable& table, parse_key_t* rule, size_t& rule_len, size_t start, Coordinates& coordinates, int row) { parse_key_t bracket_key = rule[start]; if (!bracket_key) { @@ -130,6 +131,8 @@ void registerBrackets(ParserTable& table, parse_key_t* rule, size_t& rule_len, s bracket_key = registerSymbol(table, *ruleName, lastKey + 1, false); + coordinates.add(*ruleName, row); + rule[start] = bracket_key; } @@ -175,6 +178,8 @@ int main(int argc, char* argv[]) return -1; } + Coordinates coordiantes(-1); + ParserTable table; table.registerNonterminal(pkStart, "START"); table.registerNonterminal(pkEps, "eps"); @@ -246,7 +251,7 @@ int main(int argc, char* argv[]) } else if (token.compare("|")) { if (bracketIndexes.count() > 0) { - registerBrackets(table, rule, rule_len, bracketIndexes.peek()); + registerBrackets(table, rule, rule_len, bracketIndexes.peek(), coordiantes, token.lineInfo.row); } else if (rule_len != 1) { table.registerRule(rule, rule_len); @@ -260,7 +265,7 @@ int main(int argc, char* argv[]) bracketIndexes.push(rule_len - 1); } else if (token.compare("}")) { - registerBrackets(table, rule, rule_len, bracketIndexes.pop()); + registerBrackets(table, rule, rule_len, bracketIndexes.pop(), coordiantes, token.lineInfo.row); } else rule[rule_len++] = registerSymbol(table, *token.token, lastKey + 1, false); } @@ -269,10 +274,10 @@ int main(int argc, char* argv[]) auto ambigous = table.generate(); if (ambigous.value1) { - ustr_t terminal = table.resolveKey(ambigous.value2); - ustr_t nonterminal = table.resolveKey(ambigous.value1); + ustr_t nonterminal = table.resolveKey(ambigous.value2); + ustr_t terminal = table.resolveKey(ambigous.value1); - printf(SG_AMBIGUOUS, terminal.str(), nonterminal.str()); + printf(SG_AMBIGUOUS, nonterminal.str(), terminal.str(), coordiantes.get(nonterminal.str())); return -1; } diff --git a/elenasrc3/tools/sg/sgconst.h b/elenasrc3/tools/sg/sgconst.h index 79d6b054c..b68e2889d 100644 --- a/elenasrc3/tools/sg/sgconst.h +++ b/elenasrc3/tools/sg/sgconst.h @@ -12,7 +12,7 @@ namespace elena_lang { - #define SG_REVISION_NUMBER 0x0001 + #define SG_REVISION_NUMBER 0x0002 constexpr auto SG_GREETING = "ELENA command line syntax generator %d.%d.%d (C)2005-2024 by Aleksey Rakov\n"; @@ -21,7 +21,7 @@ namespace elena_lang constexpr auto SG_FATAL = "a fatal error\n"; constexpr auto SG_FILENOTEXIST = "error:file not found\n"; constexpr auto SG_INVALID_RULE = "error(%d:%d) : invalid rule structure\n"; - constexpr auto SG_AMBIGUOUS = "error:ambiguous rule %s for '%s' terminal\n"; + constexpr auto SG_AMBIGUOUS = "error:ambiguous rule %s for '%s' (%d) terminal\n"; } diff --git a/recompile60.bat b/recompile60.bat index 7a565b3a4..e17ef34e2 100644 --- a/recompile60.bat +++ b/recompile60.bat @@ -17,6 +17,21 @@ REM /m:2 is used to build using parallel compilation "%InstallDir%\MSBuild\Current\Bin\MSBuild.exe" elenasrc3\elenasrc3.sln /p:configuration=release /p:Platform="x86" /m:2 IF NOT %ERRORLEVEL%==0 GOTO CompilerError +ECHO Generating data files required for tests +ECHO ---------------------------------------- +bin\sg-cli dat\sg\syntax60.txt +@echo off +if %ERRORLEVEL% EQU -1 GOTO SGDataGenError +@echo on + +move dat\sg\syntax60.dat bin + +bin\og-cli -s dat\og\bt_rules60.txt +@echo off +if %ERRORLEVEL% EQU -1 GOTO BTDataGenError +@echo on +move dat\og\bt_rules60.dat bin + bin\elena-tests.exe IF NOT %ERRORLEVEL%==0 GOTO CompilerError @@ -51,3 +66,9 @@ goto:eof :CompilerError echo The MSBuild returns error %ERRORLEVEL% goto:eof +:SGDataGenError +echo The syntax data file cannnot be generated +goto:eof +:BTDataGenError +echo The build tape rule data file cannnot be generated +goto:eof diff --git a/src60/core/system.core_routines.esm b/src60/core/system.core_routines.esm index 9a2631589..9736bd2ef 100644 --- a/src60/core/system.core_routines.esm +++ b/src60/core/system.core_routines.esm @@ -1213,6 +1213,31 @@ procedure __ptrCopyTo (self, arr, len) end +procedure __ptrCopySubTo (self, arr, index, len) + + xflush sp:0 + xflush sp:1 + + open (2),[],[tmp] + + peek fp:self + get i:0 + store sp:0 + $load sp:0 + $save dp:tmp + peek fp:index + load + xadd dp:tmp + $save sp:0 + peek fp:len + load + peek fp:arr + dcopy 1 + + close [] + +end + procedure __copySubStr (self, dest, index, len, sour) xflush sp:0 @@ -1252,6 +1277,45 @@ labNext: end +procedure __copySubStr2 (self, dest, index, len, sour) + + xflush sp:0 + xflush sp:1 + + open (2),[],[i1,i2,tmp] + + peek fp:index + load + save dp:i2 + nsave dp:i1, 0 + + peek fp:dest + store sp:1 + + peek fp:sour + store sp:0 + +labNext: + set dp:tmp + load dp:i1 + bread + xswap sp:1 + load dp:i2 + write 1 + xswap sp:1 + + nadd dp:i1, 1 + nadd dp:i2, 1 + + peek fp:len + load + xcmp dp:i1 + jne labNext + + close [] + +end + procedure __copySubWStr (self, dest, index, len, sour) xflush sp:0 diff --git a/src60/extensions/formatter.l b/src60/extensions/formatter.l index 4a8dea9a6..da074f45d 100644 --- a/src60/extensions/formatter.l +++ b/src60/extensions/formatter.l @@ -35,7 +35,7 @@ singleton helper public extension stringFormatterOp : String { - interpolate(params object[] args) + string interpolate(params object[] args) { auto buffer := new TextBuilder(); diff --git a/src60/system/io/win_getfiles.l b/src60/system/io/win_getfiles.l index fad28170a..269d50960 100644 --- a/src60/system/io/win_getfiles.l +++ b/src60/system/io/win_getfiles.l @@ -4,6 +4,7 @@ namespace io import system'collections; const int INVALID_HANDLE_VALUE = -1; + const int ERROR_FILE_NOT_FOUND = 2; const int ERROR_NO_MORE_FILES = 012h; struct FILETIME @@ -78,7 +79,10 @@ namespace io open := false; int err := extern KERNEL32.GetLastError(); - IOException.new("FindFirstFile - " + err.toPrintable()).raise() + if (err != ERROR_FILE_NOT_FOUND) + { + IOException.new("FindFirstFile - " + err.toPrintable()).raise() + } } else { @@ -131,7 +135,10 @@ namespace io if (INVALID_HANDLE_VALUE == hFind) { int err := extern KERNEL32.GetLastError(); - IOException.new("FindFirstFile - " + err.toPrintable()).raise(); + if (err != ERROR_FILE_NOT_FOUND) + { + IOException.new("FindFirstFile - " + err.toPrintable()).raise(); + }; b := false; }; @@ -177,7 +184,8 @@ namespace io if (INVALID_HANDLE_VALUE == hFind) { int err := extern KERNEL32.GetLastError(); - IOException.new("FindFirstFile - " + err.toPrintable()).raise(); + if (err != ERROR_FILE_NOT_FOUND) + IOException.new("FindFirstFile - " + err.toPrintable()).raise(); b := false; }; diff --git a/src60/system/pointers.l b/src60/system/pointers.l index de4febe5a..f03332fbc 100644 --- a/src60/system/pointers.l +++ b/src60/system/pointers.l @@ -94,6 +94,7 @@ public sealed const struct UnsafePointer } copyTo(byte[] target, int len) : external(system'core_routines'__ptrCopyTo); + copyTo(byte[] target, int index, int len) : external(system'core_routines'__ptrCopySubTo); } // --- CallStack --- diff --git a/src60/system/primitives.l b/src60/system/primitives.l index 9d786e401..36f55ac93 100644 --- a/src60/system/primitives.l +++ b/src60/system/primitives.l @@ -277,9 +277,10 @@ internal singleton PrimitiveRealOperations } } -internal singleton PrimitiveStringOperations +/*internal*/public singleton PrimitiveStringOperations { - copy(byte[] dest, int index, int size, string sour) : external(system'core_routines'__copySubStr); + copy(byte[] dest, int srcIndex, int size, string sour) : external(system'core_routines'__copySubStr); + copyTo(byte[] dest, int dstIndex, int size, string sour) : external(system'core_routines'__copySubStr2); int indexOf(string s, string subs, int index, int length) { diff --git a/src60/system/strings.l b/src60/system/strings.l index f6a14e1bb..1a8841a4d 100644 --- a/src60/system/strings.l +++ b/src60/system/strings.l @@ -790,6 +790,41 @@ public const struct String : BaseValue, string toPrintable() = self; + string cast(params object[] args) + { + byte buffer[1024]; + + int len := args.Length; + int bufLen := 0; + + string retVal := nil; + for(int i := 0; i < len; i++) { + string arg := args[i].toPrintable(); + int argLen := arg.Length; + + if (argLen > 1024 - bufLen) { + string tempStr := String.fromByteArray(0, bufLen, buffer); + + if (retVal == nil) { + retVal := tempStr; + } + else retVal := retVal + tempStr; + + bufLen := 0; + }; + PrimitiveStringOperations.copyTo(buffer, bufLen, argLen, arg); + bufLen += argLen; + }; + + string tempStr := String.fromByteArray(0, bufLen, buffer); + if (retVal == nil) { + retVal := tempStr; + } + else retVal := retVal + tempStr; + + ^ retVal; + } + wide cast() { int i := 0; diff --git a/tests60/sandbox/sandbox.l b/tests60/sandbox/sandbox.l index 2a54ee4c2..21f279e08 100644 --- a/tests60/sandbox/sandbox.l +++ b/tests60/sandbox/sandbox.l @@ -1,11 +1,81 @@ import extensions; -import system'routines; -A; +sealed struct OctalNumber +{ + 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); + + OctalNumber divide(OctalNumber n) + = OctalNumber.frac(self, n); +} public program() { - Reference refA := nil; + var n := 7o; + var m := 2o; + console.printLine(n,"+",m,"=",n + m); - "abc".forEach::(ch){ console.writeLine(ch)}; -} \ No newline at end of file + 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); +} diff --git a/tests60/system_tests/basic.l b/tests60/system_tests/basic.l index 884b83223..cdb70f475 100644 --- a/tests60/system_tests/basic.l +++ b/tests60/system_tests/basic.l @@ -2016,3 +2016,63 @@ public enumTest() : testCase() console.write("."); } + +// --- passingNilArg --- + +NilArgB; + +NilArgA +{ + NilArgB b; + + constructor new(NilArgB? b) + { + this b := b + } +} + +NilArgC +{ + NilArgB b; + + constructor new(NilArgB b) + { + this b := b + } +} + +singleton NilArgTester +{ + runWeak() + { + var b := nil; + var t := class T; + var a := t.new(b); + } + runStrong() + { + var b := nil; + var a := class T.new(b); + } +} + +public passingNilArg() : testCase() +{ + NilArgTester.runWeak(); + console.write("."); + NilArgTester.runStrong(); + console.write("."); + + Assert.ifFailed({ NilArgTester.runWeak() }); + console.write("."); + Assert.ifFailed({ NilArgTester.runStrong() }); + console.write("."); +} + +public stringInterpolation() : testCase() +{ + var s := $"a_{ 1 }_b_{ 2 }_c"; + + Assert.ifEqual(s,"a_1_b_2_c"); + console.write("."); +}