diff --git a/README.md b/README.md new file mode 100644 index 0000000..fece62b --- /dev/null +++ b/README.md @@ -0,0 +1,50 @@ +# TypeRunner + +High-performance TypeScript compiler. + +## Goal + +- Parser +- Type checking (as CLI and as library) +- Language Server +- Interactive type debugging +- Type information in other languages +- (optional) transpiling to JavaScript +- (optional) RTTI in JavaScript + +The goal is to make TypeScript type checking as fast as possible and provide alongside with it a native TS library for other languages, so they can use TypeScript type information +without the need for a JavaScript engine for all sorts of use cases like JSON-Schema replacement, ORM DSL, encoding information (like Protocol Buffers schema) and more. + +The goal is not to be a drop-in replacement for the entire official TypeScript compiler (tsc). TypeScript just supports so much that is not always necessary. +We focus on the more strict TS part which means TypeRunner won't support JSDoc and a lot of compiler options. + +## Status + +The source code in the initial version is really only a proof of concept. It consists of roughly 30k LoC and shows very promising results. +The approach is a TS-to-bytecode compiler and then run the bytecode in a custom virtual machine. +The data show that this approach can lead to a hundred- to several-thousand-fold improvement in speed. + +-- todo show data as graphs, maybe even make auto-generated -- + +![TypeRunner Debugger](./docs/typerunner-debugger.png) + +Once the project gets funding through the community, the development will continue. + +## Development + +TypeRunner is written in modern C++ with cmake, doctest, imgui, tracy, fmt. To work on this project first clone the repository: + +```sh +$ git clone git@github.com:marcj/TypeRunner.git +$ cd TypeRunner +``` + +then make sure cmake and a C++ compiler is installed. We use LLVM toolchain per default. To build the project run the usual cmake command: + +```sh +$ mkdir build +$ cd build +$ cmake .. +``` + +Now you find in the build folder some binaries you can execute. \ No newline at end of file diff --git a/docs/typerunner-debugger.png b/docs/typerunner-debugger.png new file mode 100644 index 0000000..239942c Binary files /dev/null and b/docs/typerunner-debugger.png differ diff --git a/main.cpp b/main.cpp index 0d481b4..102fc92 100644 --- a/main.cpp +++ b/main.cpp @@ -41,7 +41,7 @@ void compileAndRun(const string &code, const string &file, const string &fileNam int main(int argc, char *argv[]) { ZoneScoped; - std::string file = "/Users/marc/bude/typescript-cpp/tests/basic1.ts"; + std::string file = "/Users/marc/bude/TypeRunner/tests/basic1.ts"; auto cwd = std::filesystem::current_path(); if (argc > 1) { diff --git a/package.json b/package.json index 35c4fe0..445c849 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,11 @@ { - "name": "typescript-cpp", - "version": "1.0.0", + "name": "typerunner", + "version": "0.0.1", "description": "", "main": "index.js", + "files": [ + "README.md" + ], "directories": { "test": "tests" }, @@ -11,15 +14,14 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/marcj/typescript-cpp.git" + "url": "git+https://github.com/marcj/TypeRunner.git" }, "author": "", - "license": "ISC", "bugs": { - "url": "https://github.com/marcj/typescript-cpp/issues" + "url": "https://github.com/marcj/TypeRunner/issues" }, - "homepage": "https://github.com/marcj/typescript-cpp#readme", - "dependencies": { + "homepage": "https://github.com/marcj/TypeRunner#readme", + "devDependencies": { "ts-node": "^10.9.1", "typescript": "^4.7.4" } diff --git a/src/checker/check2.h b/src/checker/check2.h index 9e67f51..d671fec 100644 --- a/src/checker/check2.h +++ b/src/checker/check2.h @@ -2,7 +2,7 @@ #include "./types2.h" -namespace ts::vm2 { +namespace tr::vm2 { namespace check { struct Check { @@ -29,6 +29,37 @@ namespace ts::vm2 { return true; } + case TypeKind::Function: { + switch (left->kind) { + case TypeKind::Function: { + auto leftFirst = (TypeRef *) left->type; + auto leftSecond = (TypeRef *) leftFirst->next; + auto leftReturnType = leftSecond->type; + + auto rightFirst = (TypeRef *) right->type; + auto rightSecond = (TypeRef *) rightFirst->next; + auto rightReturnType = rightSecond->type; + + auto leftCurrent = leftSecond->next; + auto rightCurrent = rightSecond->next; + while (leftCurrent) { + if (!rightCurrent) return false; + + auto leftParameter = leftCurrent->type; + auto rightParameter = rightCurrent->type; + + if (!extends(leftParameter, rightParameter)) return false; + + leftCurrent = leftCurrent->next; + rightCurrent = rightCurrent->next; + } + + return extends(leftReturnType, rightReturnType); + } + } + return false; + break; + } case TypeKind::Tuple: { switch (left->kind) { case TypeKind::Tuple: { diff --git a/src/checker/checks.h b/src/checker/checks.h index 8a8f4ca..6b75b2b 100644 --- a/src/checker/checks.h +++ b/src/checker/checks.h @@ -3,7 +3,7 @@ #include "./types.h" #include "../core.h" -namespace ts::vm { +namespace tr::vm { static auto emptyString = HashString(""); HashString &getName(const shared &member) { diff --git a/src/checker/compiler.h b/src/checker/compiler.h index e421376..8c2495f 100644 --- a/src/checker/compiler.h +++ b/src/checker/compiler.h @@ -8,7 +8,7 @@ #include "./utils.h" #include "../node_test.h" -namespace ts::checker { +namespace tr::checker { using std::string; using std::function; @@ -67,6 +67,14 @@ namespace ts::checker { sharedOpt routine = nullptr; }; + struct FoundSymbol { + Symbol *symbol = nullptr; + unsigned int offset; + + explicit FoundSymbol(): symbol(nullptr), offset(0) {} + explicit FoundSymbol(Symbol *symbol, unsigned int offset): symbol(symbol), offset(offset) {} + }; + //aka Branch struct Section { //instruction pointer start and end @@ -490,18 +498,20 @@ namespace ts::checker { return activeSubroutines.back(); } - Symbol *findSymbol(const string_view &identifier) { + FoundSymbol findSymbol(const string_view &identifier) { + unsigned int offset = 0; for (auto subroutine = activeSubroutines.rbegin(); subroutine != activeSubroutines.rend(); ++subroutine) { - auto symbols = (*subroutine)->symbols; + auto &symbols = (*subroutine)->symbols; //we go in reverse to fetch the closest for (auto it = symbols.rbegin(); it != symbols.rend(); ++it) { if (it->active && it->name == identifier) { - return &*it; + return FoundSymbol(&(*it), offset); } } + offset++; } - return nullptr; + return FoundSymbol(); } /** @@ -542,8 +552,10 @@ namespace ts::checker { vm::writeUint16(main->ops, main->ops.size(), (unsigned int) code); } - void pushSymbolAddress(Symbol &symbol) { - vm::writeUint16(currentSubroutine()->ops, currentSubroutine()->ops.size(), symbol.index); + void pushSymbolAddress(FoundSymbol &foundSymbol) { + if (!foundSymbol.symbol) throw std::runtime_error("FoundSymbol without symbol"); + pushUint16(foundSymbol.offset); + pushUint16(foundSymbol.symbol->index); } void pushSourceMap(const shared &node) { @@ -649,7 +661,7 @@ namespace ts::checker { symbol.pos = node->pos; symbol.end = node->end; if (type == SymbolType::TypeVariable) subroutine->slots++; - subroutine->symbols.push_back(std::move(symbol)); + subroutine->symbols.push_back(symbol); return subroutine->symbols.back(); } @@ -771,7 +783,7 @@ namespace ts::checker { program.popSubroutine(); //main - return std::move(program); + return program; } void pushName(sharedOpt name, Program &program) { @@ -798,6 +810,10 @@ namespace ts::checker { type = a->type; parameters = a->parameters; typeParameters = a->typeParameters; + } else if (auto a = to(node)) { + type = a->type; + parameters = a->parameters; + typeParameters = a->typeParameters; } else if (auto a = to(node)) { body = a->body; type = a->type; @@ -815,6 +831,7 @@ namespace ts::checker { handle(body, program); program.pushOp(OP::Loads); program.pushUint16(0); + program.pushUint16(0); program.pushOp(OP::UnwrapInferBody); program.popSubroutine(); } @@ -865,9 +882,7 @@ namespace ts::checker { handle(param, program); } - if (withName) { - pushName(withName, program); - } + pushName(withName, program); program.pushOp(op, reinterpret_pointer_cast(node)); program.pushUint16(size); program.popSubroutine(); @@ -886,9 +901,7 @@ namespace ts::checker { handle(param, program); } - if (withName) { - pushName(withName, program); - } + pushName(withName, program); program.pushOp(op, reinterpret_pointer_cast(node)); program.pushUint16(size); } @@ -1017,16 +1030,16 @@ namespace ts::checker { // program.pushOp(OP::Number); const auto n = to(node); const auto name = to(n->typeName)->escapedText; - auto symbol = program.findSymbol(name); - if (!symbol) { + auto foundSymbol = program.findSymbol(name); + if (!foundSymbol.symbol) { program.pushOp(OP::Never, n->typeName); program.pushError(ErrorCode::CannotFind, n->typeName); } else { - if (symbol->type == SymbolType::TypeArgument || symbol->type == SymbolType::TypeVariable) { + if (foundSymbol.symbol->type == SymbolType::TypeArgument || foundSymbol.symbol->type == SymbolType::TypeVariable) { program.pushOp(OP::Loads, n->typeName); - program.pushSymbolAddress(*symbol); - if (symbol->type == SymbolType::TypeArgument) { - program.registerTypeArgumentUsage(symbol); + program.pushSymbolAddress(foundSymbol); + if (foundSymbol.symbol->type == SymbolType::TypeArgument) { + program.registerTypeArgumentUsage(foundSymbol.symbol); } } else { if (n->typeArguments) { @@ -1035,10 +1048,10 @@ namespace ts::checker { } } program.pushOp(OP::Call, n->typeName); - if (!symbol->routine) { + if (!foundSymbol.symbol->routine) { throw runtime_error("Reference is not a reference to a existing routine."); } - program.pushAddress(symbol->routine->index); + program.pushAddress(foundSymbol.symbol->routine->index); if (n->typeArguments) { program.pushUint16(n->typeArguments->length()); } else { @@ -1133,16 +1146,21 @@ namespace ts::checker { break; } + case SyntaxKind::FunctionType: { + const auto n = to(node); + pushFunction(OP::Function, n, program, n->name); + break; + } case SyntaxKind::Identifier: { const auto n = to(node); - auto symbol = program.findSymbol(n->escapedText); - if (!symbol) { + auto foundSymbol = program.findSymbol(n->escapedText); + if (!foundSymbol.symbol) { program.pushOp(OP::Never, n); program.pushError(ErrorCode::CannotFind, n); } else { - if (symbol->type == SymbolType::TypeArgument || symbol->type == SymbolType::TypeVariable) { + if (foundSymbol.symbol->type == SymbolType::TypeArgument || foundSymbol.symbol->type == SymbolType::TypeVariable) { program.pushOp(OP::Loads, node); - program.pushSymbolAddress(*symbol); + program.pushSymbolAddress(foundSymbol); } else { if (n->typeArguments) { for (auto &&p: n->typeArguments->list) { @@ -1150,10 +1168,10 @@ namespace ts::checker { } } program.pushOp(OP::Call, node); - if (!symbol->routine) { + if (!foundSymbol.symbol->routine) { throw runtime_error("Reference is not a reference to a existing routine."); } - program.pushAddress(symbol->routine->index); + program.pushAddress(foundSymbol.symbol->routine->index); if (n->typeArguments) { program.pushUint16(n->typeArguments->length()); } else { @@ -1271,8 +1289,18 @@ namespace ts::checker { } case SyntaxKind::NewExpression: { const auto n = to(node); + auto typeArgumentsCount = n->typeArguments ? n->typeArguments->length() : 0; + if (n->typeArguments) { + for (auto &&sub: n->typeArguments->list) handle(sub, program); + } + handle(n->expression, program); + if (n->typeArguments) { + program.pushOp(OP::Instantiate, node); + program.pushUint16(typeArgumentsCount); + } + auto argumentsCount = n->arguments ? n->arguments->length() : 0; if (n->arguments) for (auto &&sub: n->arguments->list) handle(sub, program); @@ -1368,7 +1396,7 @@ namespace ts::checker { program.pushOp(OP::Distribute); distributeJumpIp = program.ip(); - program.pushSymbolAddress(symbol); + program.pushUint16(symbol.index); program.pushAddress(0); } @@ -1482,19 +1510,36 @@ namespace ts::checker { program.blockTailCall(); if (n->typeParameters) { + auto subroutineIndex = program.pushSubroutineNameLess(); + program.blockTailCall(); for (auto &&p: n->typeParameters->list) { handle(p, program); } - } - program.pushSlots(); - unsigned int size = 0; - for (auto &&member: n->members->list) { - size++; - handle(member, program); + program.pushSlots(); + + unsigned int size = 0; + for (auto &&member: n->members->list) { + size++; + handle(member, program); + } + program.pushOp(OP::Class, node); + program.pushUint16(size); + program.popSubroutine(); + + program.pushOp(OP::ClassRef, reinterpret_pointer_cast(node)); + program.pushAddress(subroutineIndex); + } else { + program.pushSlots(); + + unsigned int size = 0; + for (auto &&member: n->members->list) { + size++; + handle(member, program); + } + program.pushOp(OP::Class, node); + program.pushUint16(size); } - program.pushOp(OP::Class, node); - program.pushUint16(size); program.popSubroutine(); } break; @@ -1549,16 +1594,16 @@ namespace ts::checker { case SyntaxKind::EqualsToken: { if (n->left->kind == SyntaxKind::Identifier) { const auto name = to(n->left)->escapedText; - auto symbol = program.findSymbol(name); - if (!symbol) { + auto foundSymbol = program.findSymbol(name); + if (!foundSymbol.symbol) { program.pushOp(OP::Never, n->left); program.pushError(ErrorCode::CannotFind, n->left); } else { - if (!symbol->routine) throw runtime_error("Symbol has no routine"); + if (!foundSymbol.symbol->routine) throw runtime_error("Symbol has no routine"); handle(n->right, program); program.pushOp(OP::Set, n->operatorToken); - program.pushAddress(symbol->routine->index); + program.pushAddress(foundSymbol.symbol->routine->index); } } else { throw runtime_error("BinaryExpression left only Identifier implemented"); diff --git a/src/checker/debug.h b/src/checker/debug.h index 933eb2d..0ab7445 100644 --- a/src/checker/debug.h +++ b/src/checker/debug.h @@ -5,9 +5,9 @@ #include "../core.h" #include "./utils.h" -namespace ts::checker { +namespace tr::checker { using std::string_view; - using ts::instructions::OP; + using tr::instructions::OP; struct PrintSubroutineOp { string text; @@ -151,11 +151,13 @@ namespace ts::checker { vm::eatParams(op, &i); break; } + case OP::ClassRef: case OP::FunctionRef: { params += fmt::format(" &{}", vm::readUint32(bin, i + 1)); vm::eatParams(op, &i); break; } + case OP::New: case OP::Instantiate: { params += fmt::format(" {}", vm::readUint16(bin, i + 1)); vm::eatParams(op, &i); @@ -178,12 +180,16 @@ namespace ts::checker { case OP::TemplateLiteral: case OP::Class: case OP::ObjectLiteral: - case OP::Slots: - case OP::Loads: { + case OP::Slots: { params += fmt::format(" {}", vm::readUint16(bin, i + 1)); vm::eatParams(op, &i); break; } + case OP::Loads: { + params += fmt::format(" {} {}", vm::readUint16(bin, i + 1), vm::readUint16(bin, i + 3)); + vm::eatParams(op, &i); + break; + } case OP::Parameter: case OP::NumberLiteral: case OP::BigIntLiteral: diff --git a/src/checker/instructions.h b/src/checker/instructions.h index cedb969..9844c2f 100644 --- a/src/checker/instructions.h +++ b/src/checker/instructions.h @@ -2,7 +2,7 @@ #include "../enum.h" -namespace ts::instructions { +namespace tr::instructions { enum OP { Noop, Jump, //arbitrary jump, used at the beginning to jump over storage-data (storage-data's addresses are constant) @@ -33,6 +33,7 @@ namespace ts::instructions { Function, FunctionRef, //one parameter, the index of the subroutine of the function that needs to be instantiated + ClassRef, Method, MethodSignature, @@ -157,17 +158,17 @@ namespace ts::instructions { template<> -struct fmt::formatter: formatter { +struct fmt::formatter: formatter { template - auto format(ts::instructions::OP p, FormatContext &ctx) { - return formatter::format(magic_enum::enum_name(p), ctx); + auto format(tr::instructions::OP p, FormatContext &ctx) { + return formatter::format(magic_enum::enum_name(p), ctx); } }; template<> -struct fmt::formatter: formatter { +struct fmt::formatter: formatter { template - auto format(ts::instructions::ErrorCode p, FormatContext &ctx) { - return formatter::format(magic_enum::enum_name(p), ctx); + auto format(tr::instructions::ErrorCode p, FormatContext &ctx) { + return formatter::format(magic_enum::enum_name(p), ctx); } }; diff --git a/src/checker/module2.h b/src/checker/module2.h index ac74f7b..c1d15ac 100644 --- a/src/checker/module2.h +++ b/src/checker/module2.h @@ -7,20 +7,21 @@ #include "./instructions.h" #include "../utf.h" -namespace ts::vm2 { +namespace tr::vm2 { using std::string; using std::string_view; - using ts::instructions::OP; - using ts::utf::eatWhitespace; + using tr::instructions::OP; + using tr::utf::eatWhitespace; struct ModuleSubroutine { string_view name; + bool main = false; unsigned int address; unsigned int flags; bool exported = false; Type *result = nullptr; Type *narrowed = nullptr; //when control flow analysis sets a new value - ModuleSubroutine(string_view name, unsigned int address, unsigned int flags): name(name), address(address), flags(flags) {} + ModuleSubroutine(string_view name, unsigned int address, unsigned int flags, bool main): name(name), address(address), flags(flags), main(main) {} }; struct FoundSourceMap { @@ -163,6 +164,7 @@ namespace ts::vm2 { inline void parseHeader(shared &module) { auto &bin = module->bin; auto end = bin.size(); + bool main = true; for (unsigned int i = 0; i < end; i++) { const auto op = (OP) bin[i]; switch (op) { @@ -183,7 +185,8 @@ namespace ts::vm2 { unsigned int address = vm::readUint32(bin, i + 5); unsigned int flags = vm::readUint32(bin, i + 5 + 4); vm::eatParams(op, &i); - module->subroutines.push_back(ModuleSubroutine(name, address, flags)); + module->subroutines.push_back(ModuleSubroutine(name, address, flags, main)); + main = false; break; } case OP::Main: { diff --git a/src/checker/types.h b/src/checker/types.h index f18927b..1f3b9b4 100644 --- a/src/checker/types.h +++ b/src/checker/types.h @@ -12,17 +12,17 @@ #include #include -namespace ts::checker { +namespace tr::checker { } -namespace ts::vm { +namespace tr::vm { using std::string_view; using std::array; using std::to_string; using std::make_shared; using std::reference_wrapper; - using ts::utf::eatWhitespace; - using namespace ts::checker; + using tr::utf::eatWhitespace; + using namespace tr::checker; struct HashString { uint64_t hash; @@ -312,7 +312,7 @@ namespace ts::vm { shared type; sharedOpt initializer = nullptr; bool optional = false; - TypeParameter(const string_view &name, const shared &type): name(name), type(type) {} + TypeParameter(const string_view &name, const shared &type): name(name), type(type) {} }; struct TypeFunction: BrandKind { @@ -529,9 +529,9 @@ namespace ts::vm { } template<> -struct fmt::formatter: formatter { +struct fmt::formatter: formatter { template - auto format(ts::vm::TypeKind p, FormatContext &ctx) { + auto format(tr::vm::TypeKind p, FormatContext &ctx) { return formatter::format(magic_enum::enum_name(p), ctx); } }; diff --git a/src/checker/types2.h b/src/checker/types2.h index 19ac1a8..a3d0aec 100644 --- a/src/checker/types2.h +++ b/src/checker/types2.h @@ -7,7 +7,7 @@ #include "../enum.h" #include "../hash.h" -namespace ts::vm2 { +namespace tr::vm2 { using std::string; using std::string_view; @@ -29,6 +29,7 @@ namespace ts::vm2 { Property, PropertySignature, Class, + ClassRef, ClassInstance, ObjectLiteral, Union, @@ -250,7 +251,7 @@ namespace ts::vm2 { inline Type *findChild(Type *type, uint64_t hash) { if (type->children.empty()) { - auto current = (TypeRef *)type->type; + auto current = (TypeRef *) type->type; while (current) { if (current->type->hash == hash) return current->type; current = current->next; @@ -270,7 +271,7 @@ namespace ts::vm2 { inline void forEachChild(Type *type, const std::function &callback) { if (type->type) { auto stop = false; - auto current = (TypeRef *)type->type; + auto current = (TypeRef *) type->type; while (!stop && current) { callback(current->type, stop); current = current->next; @@ -351,9 +352,9 @@ namespace ts::vm2 { break; } case TypeKind::PropertySignature: { - stringifyType(((TypeRef*)type->type)->type, r); + stringifyType(((TypeRef *) type->type)->type, r); r += ": "; - stringifyType(((TypeRef*)type->type)->next->type, r); + stringifyType(((TypeRef *) type->type)->next->type, r); break; } case TypeKind::ObjectLiteral: { @@ -397,7 +398,10 @@ namespace ts::vm2 { break; } case TypeKind::Parameter: { - stringifyType((Type *) type->type, r); + auto parameterType = (Type *) type->type; + r += type->text; + r += ": "; + stringifyType(parameterType, r); break; } case TypeKind::Tuple: { @@ -446,6 +450,24 @@ namespace ts::vm2 { r += "`"; break; } + case TypeKind::Function: { + auto first = (TypeRef *) type->type; + auto nameType = first->type; + auto second = (TypeRef *) first->next; + auto returnType = second->type; + + r += "("; + auto current = (TypeRef *) second->next; + while (current) { + stringifyType(current->type, r); + current = current->next; + if (current) r += ", "; + } + r += ") => ("; + stringifyType(returnType, r); + r += ")"; + break; + } case TypeKind::Literal: { if (type->flag & TypeFlag::StringLiteral) { r += "\""; @@ -534,9 +556,9 @@ namespace ts::vm2 { } template<> -struct fmt::formatter: formatter { +struct fmt::formatter: formatter { template - auto format(ts::vm2::TypeKind p, FormatContext &ctx) { + auto format(tr::vm2::TypeKind p, FormatContext &ctx) { return formatter::format(magic_enum::enum_name(p), ctx); } }; diff --git a/src/checker/utils.h b/src/checker/utils.h index e6cc0b1..2c0d06a 100644 --- a/src/checker/utils.h +++ b/src/checker/utils.h @@ -5,7 +5,7 @@ #include #include "./instructions.h" -namespace ts::vm { +namespace tr::vm { using std::vector; using std::string_view; @@ -62,7 +62,7 @@ namespace ts::vm { return string_view(reinterpret_cast(bin.data() + offset + 2), size); } - using ts::instructions::OP; + using tr::instructions::OP; inline void eatParams(OP op, unsigned int *i) { switch (op) { case OP::TailCall: @@ -98,10 +98,12 @@ namespace ts::vm { *i += 4; break; } + case OP::ClassRef: case OP::FunctionRef: { *i += 4; break; } + case OP::New: case OP::Instantiate: { *i += 2; break; @@ -123,7 +125,7 @@ namespace ts::vm { break; } case OP::Loads: { - *i += 2; + *i += 4; break; } case OP::Parameter: diff --git a/src/checker/vm.cpp b/src/checker/vm.cpp index 745124b..70c5ecb 100644 --- a/src/checker/vm.cpp +++ b/src/checker/vm.cpp @@ -1,6 +1,6 @@ #include "./vm.h" -namespace ts::vm { +namespace tr::vm { shared stringToNum(VM &vm) { } } \ No newline at end of file diff --git a/src/checker/vm.h b/src/checker/vm.h index 2d6c67f..c129275 100644 --- a/src/checker/vm.h +++ b/src/checker/vm.h @@ -15,8 +15,8 @@ #include #include -namespace ts::vm { - using namespace ts::checker; +namespace tr::vm { + using namespace tr::checker; using std::string_view; using std::span; using std::vector; diff --git a/src/checker/vm2.cpp b/src/checker/vm2.cpp index 95e3114..72669eb 100644 --- a/src/checker/vm2.cpp +++ b/src/checker/vm2.cpp @@ -4,11 +4,15 @@ #include "./vm2_utils.h" #include "Tracy.hpp" -namespace ts::vm2 { +namespace tr::vm2 { void prepare(shared &module) { parseHeader(module); + subroutine = activeSubroutines.reset(); subroutine->module = module.get(); - subroutine->ip = module->subroutines[0].address; //first is main + //first is main + subroutine->subroutine = &module->subroutines[0]; + subroutine->ip = module->subroutines[0].address; + subroutine->initialSp = sp; subroutine->depth = 0; } @@ -290,7 +294,7 @@ namespace ts::vm2 { /** * Unuse all cached types of subroutines and make them available for GC. */ - void clear(shared &module) { + void clear(shared &module) { for (auto &&subroutine: module->subroutines) { if (subroutine.result) drop(subroutine.result); if (subroutine.narrowed) drop(subroutine.narrowed); @@ -407,6 +411,7 @@ namespace ts::vm2 { } inline ActiveSubroutine *pushSubroutine(ModuleSubroutine *routine, unsigned int arguments) { + if (!routine) throw std::runtime_error("no routine given"); auto nextSubroutine = activeSubroutines.push(); //&activeSubroutines[++activeSubroutineIdx]; //important to reset necessary stuff, since we reuse nextSubroutine->ip = routine->address; @@ -825,7 +830,9 @@ namespace ts::vm2 { //auto frameName = new string_view(fmt::format("[{}] {}", subroutine->ip, (OP) bin[subroutine->ip])); //ZoneName(frameName->begin(), frameName->size()); - switch ((OP) bin[subroutine->ip]) { + auto ip = subroutine->ip; + auto op = (OP) bin[subroutine->ip]; + switch (op) { case OP::Halt: { // subroutine = activeSubroutines.reset(); // frame = frames.reset(); @@ -892,11 +899,22 @@ namespace ts::vm2 { stack[sp++] = type; break; } + case OP::ClassRef: { + const auto address = subroutine->parseUint32(); + auto type = allocate(TypeKind::ClassRef, hash::const_hash("class")); + type->size = address; + stack[sp++] = type; + break; + } case OP::Instantiate: { const auto arguments = subroutine->parseUint16(); auto ref = pop(); //FunctionRef/Class switch (ref->kind) { + case TypeKind::ClassRef: { + call(ref->size, arguments); + break; + } case TypeKind::FunctionRef: { call(ref->size, arguments); break; @@ -917,6 +935,7 @@ namespace ts::vm2 { break; } case TypeKind::Class: { + //todo: convert to ClassInstance. Do we really have to copy all TypeRef? //push() } } @@ -1002,7 +1021,7 @@ namespace ts::vm2 { case OP::Assign: { auto rvalue = pop(); auto lvalue = pop(); - //debug("assign {} = {}", stringify(rvalue), stringify(lvalue)); + debug("assign {} = {}", stringify(rvalue), stringify(lvalue)); if (!extends(lvalue, rvalue)) { // auto error = stack.errorMessage(); // error.ip = ip; @@ -1020,7 +1039,8 @@ namespace ts::vm2 { } case OP::Return: { if (subroutine->isMain()) { - subroutine = activeSubroutines.reset(); + activeSubroutines.reset(); + subroutine = nullptr; return; } @@ -1099,7 +1119,8 @@ namespace ts::vm2 { case OP::CheckBody: { const auto address = subroutine->parseUint32(); auto expectedType = stack[sp - 1]; - report("Nope"); + //todo implement + //report("Nope"); break; } case OP::InferBody: { @@ -1237,14 +1258,13 @@ namespace ts::vm2 { break; } case OP::Loads: { + const auto frameOffset = subroutine->parseUint16(); const auto varIndex = subroutine->parseUint16(); - push(stack[subroutine->initialSp + varIndex]); - //debug("Loads {}:{} -> {}", frameOffset, varIndex, stringify(stack[index])); - //if (frameOffset == 0) { - // push(stack[subroutine->initialSp + varIndex]); - //} else { - // push(stack[frames.at(frames.i - frameOffset)->initialSp + varIndex]); - //} + if (frameOffset == 0) { + push(stack[subroutine->initialSp + varIndex]); + } else { + push(stack[activeSubroutines.at(activeSubroutines.index() - frameOffset)->initialSp + varIndex]); + } break; } case OP::Slots: { @@ -1693,6 +1713,20 @@ namespace ts::vm2 { debug("[{}] OP {} not handled!", subroutine->ip, (OP) bin[subroutine->ip]); } } + + if (stepper) { + if (op == instructions::TypeArgument) { + subroutine->variableIPs.push_back(ip); + } + subroutine->ip++; +//// debug("Routine {} (ended={})", subroutine->depth, subroutine->ip == subroutine->end); +// if (subroutine->ip == subroutine->end) { +// //subroutine is done +// subroutine = subroutine->previous; +// } + //process() needs to be executed for each step + return; + } subroutine->ip++; } } diff --git a/src/checker/vm2.h b/src/checker/vm2.h index dcdee49..42d303c 100644 --- a/src/checker/vm2.h +++ b/src/checker/vm2.h @@ -14,7 +14,7 @@ #include "./module2.h" #include "./instructions.h" -namespace ts::vm2 { +namespace tr::vm2 { using instructions::OP; using std::string_view; @@ -62,7 +62,7 @@ namespace ts::vm2 { }; enum SubroutineFlag: uint16_t { - InferBody = 1 << 0, + InferBody = 1<<0, }; /** @@ -78,6 +78,7 @@ namespace ts::vm2 { //the amount of registered variable slots on the stack. will be subtracted when doing popFrame() //type arguments of type functions and variables like for mapped types unsigned int variables = 0; + vector variableIPs; //only used when stepper is active uint16_t typeArguments = 0; /** @see SubroutineFlag */ @@ -93,6 +94,10 @@ namespace ts::vm2 { return sp - initialSp; } + OP op() { + return (OP) module->bin[ip]; + } + std::span pop(unsigned int size) { sp -= size; return {stack.data() + sp, size}; @@ -104,7 +109,7 @@ namespace ts::vm2 { } bool isMain() { - return !subroutine; + return subroutine->main; } int32_t parseInt32() { @@ -121,14 +126,27 @@ namespace ts::vm2 { }; template - struct StackPool { + class StackPool { + private: std::array values; unsigned int i; - + public: T *at(unsigned int pos) { return &values[pos]; } + T *front() { + return &values[i]; + } + + unsigned int index() { + return i; + } + + unsigned int size() { + return i + 1; + } + T *reset() { i = 0; return &values[0]; @@ -150,15 +168,17 @@ namespace ts::vm2 { }; constexpr auto stackSize = 1024; + //aka frames inline StackPool activeSubroutines; inline StackPool loops; + inline bool stepper = false; inline ActiveSubroutine *subroutine = nullptr; void process(); - void clear(shared &module); - void prepare(shared &module); + void clear(shared &module); + void prepare(shared &module); void drop(Type *type); void drop(std::span *types); void gc(std::span *types); @@ -184,7 +204,6 @@ namespace ts::vm2 { poolRefs.clear(); sp = 0; - subroutine = activeSubroutines.reset(); loops.reset(); prepare(module); diff --git a/src/checker/vm3.h b/src/checker/vm3.h index c220aa5..ef8cb07 100644 --- a/src/checker/vm3.h +++ b/src/checker/vm3.h @@ -1,4 +1,4 @@ -namespace ts::vm3 { +namespace tr::vm3 { // struct Type2 { // string_view typeName; @@ -59,7 +59,7 @@ namespace ts::vm3 { //// Main //// }; // -// void jump(shared &module) { +// void jump(shared &module) { // //https://christopherschwaab.wordpress.com/2018/04/13/generating-a-threaded-arm-interpreter-with-templates/ // // We're using the GNU C, labels-as-values extension here. // void *prog[] = {&&PUSH, (void*)6, @@ -92,7 +92,7 @@ namespace ts::vm3 { // return; // } // -// void run(shared &module) { +// void run(shared &module) { // program[0] = Noop; // program[1] = Jump; // program[2] = Halt; @@ -107,7 +107,7 @@ namespace ts::vm3 { // (*program[*ip])(); // } // -// void naive(shared &module) { +// void naive(shared &module) { // prepare(module); // auto end = module->bin.size(); // auto &bin = module->bin; @@ -152,7 +152,7 @@ namespace ts::vm3 { // break; // } // case OP::Jump: { -// ip = ts::checker::readUint32(bin, 1) - 1; //minus 1 because for's i++ +// ip = tr::checker::readUint32(bin, 1) - 1; //minus 1 because for's i++ // break; // } // } @@ -278,7 +278,7 @@ namespace ts::vm3 { //// int result = func(); // } // -// void jit(shared &module) { +// void jit(shared &module) { //// a64::Compiler c; //// c.add(Jump); // @@ -334,7 +334,7 @@ namespace ts::vm3 { //// break; //// } //// case OP::Jump: { -//// ip = ts::checker::readUint32(bin, 1) - 1; //minus 1 because for's i++ +//// ip = tr::checker::readUint32(bin, 1) - 1; //minus 1 because for's i++ //// break; //// } //// } diff --git a/src/core.cpp b/src/core.cpp index 4c5f8d9..cb65e46 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -1,6 +1,6 @@ #include "core.h" -namespace ts::Debug { +namespace tr::Debug { void asserts(bool v, std::string text) { if (!v) throw std::runtime_error("assert: " + text); } @@ -10,7 +10,7 @@ namespace ts::Debug { } } -namespace ts { +namespace tr { string substr(const string &str, int start, optional len) { if (start <= 0 && len && len < 0) return ""; if (!len || *len < 0 || len > str.size()) *len = str.size(); diff --git a/src/core.h b/src/core.h index a211afc..f9acffc 100644 --- a/src/core.h +++ b/src/core.h @@ -15,12 +15,12 @@ #define CALLBACK(name) [this](auto ...a) { return name(a...); } -namespace ts::Debug { +namespace tr::Debug { void asserts(bool v, std::string text = ""); void fail(std::string text = ""); } -namespace ts { +namespace tr { using std::string; using std::vector; using std::function; @@ -218,6 +218,7 @@ namespace ts { template inline optional set(unordered_map &m, K key, T v) { // m.insert_or_assign(key, v); + throw std::runtime_error("not implemented"); std::cout << "set map: " << key << ", " << v << "\n"; // m.insert({key, v}); // m[key] = v; diff --git a/src/diagnostic_messages.h b/src/diagnostic_messages.h index 0aa58ba..439b789 100644 --- a/src/diagnostic_messages.h +++ b/src/diagnostic_messages.h @@ -5,7 +5,7 @@ #include #include -namespace ts { +namespace tr { using types::DiagnosticMessage; using types::DiagnosticCategory; diff --git a/src/factory.cpp b/src/factory.cpp index 3b463fa..87b9385 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -1,8 +1,8 @@ #include "factory.h" #include -namespace ts { - int Factory::propagatePropertyNameFlagsOfChild(shared &node, int transformFlags) { +namespace tr { + int Factory::propagatePropertyNameFlagsOfChild(shared &node, int transformFlags) { return transformFlags | (node->transformFlags & (int) TransformFlags::PropertyNamePropagatingFlags); } diff --git a/src/factory.h b/src/factory.h index 510378e..94744a5 100644 --- a/src/factory.h +++ b/src/factory.h @@ -9,7 +9,7 @@ #include "node_test.h" #include "parenthesizer.h" -namespace ts { +namespace tr { struct Parenthesizer; diff --git a/src/fs.h b/src/fs.h index 2653318..2f5432b 100644 --- a/src/fs.h +++ b/src/fs.h @@ -24,8 +24,7 @@ inline void fileWrite(const string &file, const string_view &content) { t << content; } -inline bool fileExists(const string &file) -{ +inline bool fileExists(const string &file) { std::ifstream infile(file); return infile.good(); } \ No newline at end of file diff --git a/src/gui/app.h b/src/gui/app.h index e17d596..6ae86e5 100644 --- a/src/gui/app.h +++ b/src/gui/app.h @@ -13,7 +13,7 @@ using namespace std; -namespace ts::gui { +namespace tr::gui { class App { public: int displayWidth = 20; diff --git a/src/gui/debugger_main.cpp b/src/gui/debugger_main.cpp index 65f713c..95a3ebd 100644 --- a/src/gui/debugger_main.cpp +++ b/src/gui/debugger_main.cpp @@ -5,7 +5,7 @@ #include "./app.h" #include "../parser2.h" #include "../checker/compiler.h" -#include "../checker/vm.h" +#include "../checker/vm2.h" #include "../checker/debug.h" #include "../fs.h" #include "TextEditor.h" @@ -13,8 +13,8 @@ using std::string; using std::span; -using namespace ts; -using namespace ts::gui; +using namespace tr; +using namespace tr::gui; typedef std::chrono::duration took; @@ -26,7 +26,7 @@ struct ExecutionData { }; int main() { - guiApp.title = "Typhoon"; + guiApp.title = "TypeRunner"; guiAppInit(); string fileName = "app.ts"; @@ -68,7 +68,7 @@ const v3: NoNumber = 34; auto fontMonoSmall = ImGui::GetIO().Fonts->AddFontFromFileTTF("/System/Library/Fonts/SFNSMono.ttf", 26.0); checker::DebugBinResult debugBinResult; - auto module = make_shared(); + auto module = make_shared(); ExecutionData lastExecution; @@ -84,10 +84,10 @@ const v3: NoNumber = 34; { checker::Compiler compiler; Parser parser; - auto result = parser.parseSourceFile(fileName, code, ts::types::ScriptTarget::Latest, false, ScriptKind::TS, {}); + auto result = parser.parseSourceFile(fileName, code, tr::types::ScriptTarget::Latest, false, ScriptKind::TS, {}); auto program = compiler.compileSourceFile(result); auto bin = program.build(); - module = make_shared(std::move(bin), fileName, code); + module = make_shared(std::move(bin), fileName, code); debugBinResult = checker::parseBin(module->bin); extractErrors(); } @@ -100,35 +100,34 @@ const v3: NoNumber = 34; auto start = std::chrono::high_resolution_clock::now(); shared result; - for (auto i = 0; i < iterations; i++) { - result = parser.parseSourceFile(fileName, code, ts::types::ScriptTarget::Latest, false, ScriptKind::TS, {}); + for (auto i = 0; i(std::move(bin), fileName, code); + module = make_shared(std::move(bin), fileName, code); debugBinResult = checker::parseBin(module->bin); start = std::chrono::high_resolution_clock::now(); - for (auto i = 0; i < iterations; i++) { + for (auto i = 0; iclear(); - vm::VM vm; //we need to keep Modules alive - vm.run(module); + vm2::run(module); } lastExecution.checkTime = (std::chrono::high_resolution_clock::now() - start) / iterations; @@ -138,14 +137,13 @@ const v3: NoNumber = 34; editor.inlineErrorHover = [](ImVec2 &start, ImVec2 &end, TextEditor::InlineError &inlineError) { ImGui::BeginTooltip(); - vm::DiagnosticMessage *message = (vm::DiagnosticMessage *) inlineError.data; + vm2::DiagnosticMessage *message = (vm2::DiagnosticMessage *) inlineError.data; ImGui::TextUnformatted(message->message.c_str()); ImGui::EndTooltip(); }; auto debugActive = false; auto debugEnded = false; - vm::VM debugVM; runProgram(); guiAppRender([&] { @@ -226,14 +224,14 @@ const v3: NoNumber = 34; ImGui::TableHeadersRow(); #ifdef TS_PROFILE - for (unsigned int type = 0; type < vm::profiler.data.typeCount; type++) { - auto count = vm::profiler.data.instantiations[type]; + for (unsigned int type = 0; type < vm2::profiler.data.typeCount; type++) { + auto count = vm2::profiler.data.instantiations[type]; if (!count) continue; ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Text(string(magic_enum::enum_name((vm::TypeKind)type)).c_str()); + ImGui::Text(string(magic_enum::enum_name((vm2::TypeKind)type)).c_str()); ImGui::TableNextColumn(); ImGui::Text("%lld", count); @@ -250,18 +248,18 @@ const v3: NoNumber = 34; ImGui::TableHeadersRow(); #ifdef TS_PROFILE - for (unsigned int left = 0; left < vm::profiler.data.typeCount; left++) { - for (unsigned int right = 0; right < vm::profiler.data.typeCount; right++) { - auto count = vm::profiler.data.comparisons[left][right]; + for (unsigned int left = 0; left < vm2::profiler.data.typeCount; left++) { + for (unsigned int right = 0; right < vm2::profiler.data.typeCount; right++) { + auto count = vm2::profiler.data.comparisons[left][right]; if (!count) continue; ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Text(string(magic_enum::enum_name((vm::TypeKind)left)).c_str()); + ImGui::Text(string(magic_enum::enum_name((vm2::TypeKind)left)).c_str()); ImGui::TableNextColumn(); - ImGui::Text(string(magic_enum::enum_name((vm::TypeKind)right)).c_str()); + ImGui::Text(string(magic_enum::enum_name((vm2::TypeKind)right)).c_str()); ImGui::TableNextColumn(); ImGui::Text("%lld", count); } @@ -270,7 +268,6 @@ const v3: NoNumber = 34; ImGui::EndTable(); - ImGui::PopFont(); // // ImGui::SameLine(); @@ -322,34 +319,32 @@ const v3: NoNumber = 34; if (ImGui::Begin("Virtual Machine", nullptr)) { if ((!debugActive || debugEnded) && ImGui::Button("Debug")) { if (!debugActive || debugEnded) { - debugVM = vm::VM(); module->clear(); debugActive = true; debugEnded = false; editor.SetReadOnly(true); - debugVM.stepper = true; - debugVM.prepare(module); + vm2::stepper = true; + vm2::prepare(module); } } - static vm::Frame *selectedFrame = nullptr; + static vm2::ActiveSubroutine *selectedSubroutine = nullptr; if (debugActive) { if (debugEnded) { ImGui::Text("Program exited"); } else { if (ImGui::Button("Next")) { - static vm::FoundSourceMap lastMap; - selectedFrame = nullptr; + static vm2::FoundSourceMap lastMap; while (true) { - debugVM.process(); - if (!debugVM.subroutine) { + vm2::process(); + if (!vm2::subroutine) { debugEnded = true; editor.SetReadOnly(false); editor.highlights.clear(); break; } else { - auto map = module->findNormalizedMap(debugVM.subroutine->ip); + auto map = module->findNormalizedMap(vm2::subroutine->ip); if (!map.found()) continue; //another step please if (map.pos == lastMap.pos && map.end == lastMap.end) continue; //another step please lastMap = map; @@ -366,7 +361,6 @@ const v3: NoNumber = 34; editor.SetReadOnly(false); debugActive = false; debugEnded = true; - debugVM = vm::VM(); runProgram(); } @@ -375,43 +369,38 @@ const v3: NoNumber = 34; } } - if (debugVM.subroutine) { - - vector frames; -// auto current = debugVM.frame; -// while (current) { -// frames.push_back(current); -// current = current->previous; -// } - ImGui::Text("Stack (%d/%d)", frames.size(), debugVM.stack.size()); + if (vm2::subroutine) { + ImGui::Text("Stack (%d), OP=%s (%d)", vm2::sp, string(magic_enum::enum_name(vm2::subroutine->op())).c_str(), vm2::subroutine->ip); static auto showNonVariables = false; - if (!selectedFrame) selectedFrame = frames.front(); + if (!selectedSubroutine) selectedSubroutine = vm2::activeSubroutines.front(); ImGui::Checkbox("Show all stack entries", &showNonVariables); ImGui::PushItemWidth(120); if (ImGui::BeginListBox("###listbox")) { - auto i = 0; string_view lastName = "main"; - for (auto it = frames.rbegin(); it != frames.rend(); it++) { - auto frame = (*it); + for (int i = 0; isubroutine->name.empty()) { -// lastName = frame->subroutine->name; -// } - if (ImGui::Selectable((string(lastName)).c_str(), selectedFrame == frame)) { - selectedFrame = frame; + if (!frame->subroutine) { + break; + } + if (!frame->subroutine->name.empty()) { + lastName = frame->subroutine->name; + } + if (ImGui::Selectable((string(lastName)).c_str(), selectedSubroutine == frame)) { + selectedSubroutine = frame; } ImGui::SameLine(); ImGui::TextColored(grey, to_string(showNonVariables ? frame->size() : frame->variables).c_str()); // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) - if (selectedFrame == frame) ImGui::SetItemDefaultFocus(); - i++; + if (selectedSubroutine == frame) ImGui::SetItemDefaultFocus(); ImGui::PopID(); } ImGui::EndListBox(); @@ -419,27 +408,39 @@ const v3: NoNumber = 34; ImGui::PopItemWidth(); - if (selectedFrame) { + if (selectedSubroutine) { ImGui::SameLine(); ImGui::BeginGroup(); - auto start = selectedFrame->initialSp; // + frame->variables; - span> frameStack{debugVM.stack.data() + start, selectedFrame->sp - start}; - - for (unsigned int i = 0; i < frameStack.size(); i++) { - auto type = frameStack[i]; - if (i >= selectedFrame->variables && !showNonVariables) continue; + auto start = selectedSubroutine->initialSp; // + frame->variables; + auto end = vm2::sp; + auto subroutinesEnd = vm2::activeSubroutines.size(); + for (int i = 0; iinitialSp; + break; + } + } - ImGui::Text(" "); - ImGui::SameLine(); - if (i < selectedFrame->variables) { -// auto ip = selectedFrame->variableIPs[i]; -// auto identifier = module->findIdentifier(ip); -// ImGui::Text(identifier.c_str()); -// ImGui::SameLine(); + if (end > start) { + span frameStack{vm2::stack.data() + start, end - start}; + + for (unsigned int i = 0; i=selectedSubroutine->variables && !showNonVariables) continue; + + ImGui::Text(" "); + ImGui::SameLine(); + if (ivariables) { + auto ip = selectedSubroutine->variableIPs[i]; + auto identifier = module->findIdentifier(ip); + ImGui::Text(identifier.c_str()); + ImGui::SameLine(); + } + auto stype = vm2::stringify(type); + if (stype.size()>20) stype = stype.substr(0, 20) + "..."; + ImGui::TextColored(grey, stype.c_str()); } - auto stype = vm::stringify(type); - if (stype.size() > 20) stype = stype.substr(0, 20) + "..."; - ImGui::TextColored(grey, stype.c_str()); } ImGui::EndGroup(); } @@ -499,7 +500,7 @@ const v3: NoNumber = 34; for (auto &&op: s.operations) { ImGui::TextColored(grey, to_string(op.address).c_str()); ImGui::SameLine(); - if (debugVM.subroutine && debugVM.subroutine->ip == op.address) { + if (vm2::subroutine && vm2::subroutine->ip == op.address) { ImGui::TextColored(yellow, op.text.c_str()); } else { ImGui::Text(op.text.c_str()); @@ -528,7 +529,7 @@ const v3: NoNumber = 34; ImGui::Text("%d", m.bytecodePos); ImGui::TableNextColumn(); - ImGui::Text(string(magic_enum::enum_name(m.op)).c_str()); + ImGui::Text(string(magic_enum::enum_name(m.op)).c_str()); ImGui::TableNextColumn(); ImGui::Text((to_string(m.sourcePos) + ":" + to_string(m.sourceEnd)).c_str()); diff --git a/src/hash.h b/src/hash.h index a20249e..f725ddb 100644 --- a/src/hash.h +++ b/src/hash.h @@ -4,7 +4,7 @@ #include #include -namespace ts::hash { +namespace tr::hash { //https://github.com/ekpyron/xxhashct struct xxh64 { diff --git a/src/node_test.cpp b/src/node_test.cpp index 9b36750..36f0268 100644 --- a/src/node_test.cpp +++ b/src/node_test.cpp @@ -1,7 +1,7 @@ #include "node_test.h" #include -namespace ts { +namespace tr { /** * Gets flags that control emit behavior of a node. */ diff --git a/src/node_test.h b/src/node_test.h index 96e33e6..c74dcb8 100644 --- a/src/node_test.h +++ b/src/node_test.h @@ -2,7 +2,7 @@ #include "types.h" -namespace ts { +namespace tr { // Literals using types::ModifierFlags; diff --git a/src/parenthesizer.cpp b/src/parenthesizer.cpp index f7df102..a77955c 100644 --- a/src/parenthesizer.cpp +++ b/src/parenthesizer.cpp @@ -5,7 +5,7 @@ #include "parenthesizer.h" #include "factory.h" -namespace ts { +namespace tr { template shared sameMap(const sharedOpt &array, const function(shared, int)> &callback) { diff --git a/src/parenthesizer.h b/src/parenthesizer.h index e52b703..b1215c8 100644 --- a/src/parenthesizer.h +++ b/src/parenthesizer.h @@ -6,8 +6,8 @@ #include "scanner.h" #include "node_test.h" -namespace ts { - using namespace ts::types; +namespace tr { + using namespace tr::types; struct Factory; diff --git a/src/parser2.cpp b/src/parser2.cpp index 22f4e73..48bf870 100644 --- a/src/parser2.cpp +++ b/src/parser2.cpp @@ -1,7 +1,7 @@ #include "parser2.h" -namespace ts { +namespace tr { SyntaxKind Parser::token() { return currentToken; } diff --git a/src/parser2.h b/src/parser2.h index ae3e74e..c922f8c 100644 --- a/src/parser2.h +++ b/src/parser2.h @@ -18,10 +18,10 @@ #include "diagnostic_messages.h" #include -using namespace ts::types; -using namespace ts::hash; +using namespace tr::types; +using namespace tr::hash; -namespace ts { +namespace tr { using std::string; using std::vector; using std::function; @@ -1473,7 +1473,7 @@ namespace ts { } // Otherwise, if this isn't a well-known keyword-like identifier, give the generic fallback message. - string expressionText = ts::isIdentifier(node) ? idText(node) : ""; + string expressionText = tr::isIdentifier(node) ? idText(node) : ""; if (expressionText == "" || !isIdentifierText(expressionText, languageVersion)) { parseErrorAtCurrentToken(Diagnostics::_0_expected(), tokenToString(SyntaxKind::SemicolonToken)); return; @@ -7085,7 +7085,7 @@ namespace ts { shared node; auto hasParen = token() == SyntaxKind::OpenParenToken; auto expression = allowInAnd>(CALLBACK(parseExpression)); - if (ts::isIdentifier(expression) && parseOptional(SyntaxKind::ColonToken)) { + if (tr::isIdentifier(expression) && parseOptional(SyntaxKind::ColonToken)) { node = factory.createLabeledStatement(expression, parseStatement()); } else { if (!tryParseSemicolon()) { diff --git a/src/path.cpp b/src/path.cpp index b8f221c..ddee996 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -2,12 +2,12 @@ #include "path.h" -namespace ts { +namespace tr { using std::string; using std::replace; using std::regex; - using ts::utf::charCodeAt; - using ts::utf::CharacterCodes; + using tr::utf::charCodeAt; + using tr::utf::CharacterCodes; bool fileExtensionIs(const string &path, const string &extension) { return path.size() > extension.size() && endsWith(path, extension); diff --git a/src/path.h b/src/path.h index 3832b89..2965540 100644 --- a/src/path.h +++ b/src/path.h @@ -5,11 +5,11 @@ #include "core.h" #include "utf.h" -namespace ts { +namespace tr { using std::string; using std::replace; using std::regex; - using ts::utf::CharCode; + using tr::utf::CharCode; constexpr static auto directorySeparator = "/"; constexpr static auto altDirectorySeparator = "\\"; diff --git a/src/scanner.cpp b/src/scanner.cpp index 780a48a..d62de1c 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -7,14 +7,14 @@ #include "diagnostic_messages.h" #include -using namespace ts; +using namespace tr; using namespace std; -namespace ts { - using ts::utf::charCodeAt; - using ts::utf::CharacterCodes; - using ts::utf::fromCharCode; - using namespace ts::hash; +namespace tr { + using tr::utf::charCodeAt; + using tr::utf::CharacterCodes; + using tr::utf::fromCharCode; + using namespace tr::hash; bool isShebangTrivia(const string &text, int pos) { // Shebangs check must only be done at the start of the file diff --git a/src/scanner.h b/src/scanner.h index 677a13f..55e0bff 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -8,10 +8,10 @@ #include "utf.h" #include "hash.h" -namespace ts { - using namespace ts::types; +namespace tr { + using namespace tr::types; using namespace std; - using ts::utf::CharCode; + using tr::utf::CharCode; struct ScanNumber { SyntaxKind type; diff --git a/src/string.h b/src/string.h index f98b113..e6a1ae1 100644 --- a/src/string.h +++ b/src/string.h @@ -3,7 +3,7 @@ * do not need std::string with all its features, it's enough if we either have a string_view (reference) * to the SourceFile::text, or have a static string wrapper around const char *. */ -namespace ts { +namespace tr { struct simple_string { const char *text; diff --git a/src/syntax_cursor.cpp b/src/syntax_cursor.cpp index eacb603..b234f9f 100644 --- a/src/syntax_cursor.cpp +++ b/src/syntax_cursor.cpp @@ -1,6 +1,6 @@ #include "syntax_cursor.h" -using namespace ts; +using namespace tr; Node SyntaxCursor::currentNode(int position) { // Only compute the current node if the position is different than the last time diff --git a/src/syntax_cursor.h b/src/syntax_cursor.h index 1caa3ad..20517f8 100644 --- a/src/syntax_cursor.h +++ b/src/syntax_cursor.h @@ -5,7 +5,7 @@ using namespace std; -namespace ts { +namespace tr { enum InvalidPosition { Value = -1 diff --git a/src/tests/test_bench.cpp b/src/tests/test_bench.cpp index e9da1e5..cbdb722 100644 --- a/src/tests/test_bench.cpp +++ b/src/tests/test_bench.cpp @@ -9,7 +9,7 @@ #include "../checker/compiler.h" #include "../checker/debug.h" -using namespace ts; +using namespace tr; using std::string; using std::make_shared; using std::string_view; @@ -217,10 +217,10 @@ TEST(bench, hashing) { string s = "foo188"; bench("hash from view", 100, [&] { - ts::hash::runtime_hash(s); + tr::hash::runtime_hash(s); }); bench("hash from string", 100, [&] { - ts::hash::runtime_hash(s); + tr::hash::runtime_hash(s); }); } diff --git a/src/tests/test_checker.cpp b/src/tests/test_checker.cpp index bc4fe99..b4d17ba 100644 --- a/src/tests/test_checker.cpp +++ b/src/tests/test_checker.cpp @@ -6,7 +6,7 @@ #include "../checker/debug.h" #include "../utils.h" -using namespace ts; +using namespace tr; TEST(checker, program) { checker::Program program; @@ -120,7 +120,7 @@ TEST(checker, assign) { v = 123; //Assign to 123, change to number )"; - auto result = parser.parseSourceFile("app.ts", code, ts::types::ScriptTarget::Latest, false, ScriptKind::TS, {}); + auto result = parser.parseSourceFile("app.ts", code, tr::types::ScriptTarget::Latest, false, ScriptKind::TS, {}); checker::Compiler compiler; @@ -153,7 +153,7 @@ TEST(checker, stackFrame) { } )"; - auto result = parser.parseSourceFile("app.ts", code, ts::types::ScriptTarget::Latest, false, ScriptKind::TS, {}); + auto result = parser.parseSourceFile("app.ts", code, tr::types::ScriptTarget::Latest, false, ScriptKind::TS, {}); debug("done"); } @@ -297,6 +297,6 @@ TEST(checker, basic2) { print(i); )"; - auto result = parser.parseSourceFile("app.ts", code, ts::types::ScriptTarget::Latest, false, ScriptKind::TS, {}); + auto result = parser.parseSourceFile("app.ts", code, tr::types::ScriptTarget::Latest, false, ScriptKind::TS, {}); debug("done"); } diff --git a/src/tests/test_core.cpp b/src/tests/test_core.cpp index dc4ed7b..4b67bc7 100644 --- a/src/tests/test_core.cpp +++ b/src/tests/test_core.cpp @@ -11,7 +11,7 @@ #include "../factory.h" using namespace std; -using namespace ts; +using namespace tr; TEST(core, regexp) { std::regex regex("^///?\\s*@(ts-expect-error|ts-ignore)"); diff --git a/src/tests/test_hash.cpp b/src/tests/test_hash.cpp index c7b1406..f5fba22 100644 --- a/src/tests/test_hash.cpp +++ b/src/tests/test_hash.cpp @@ -3,7 +3,7 @@ #include "../hash.h" using namespace std; -using namespace ts::hash; +using namespace tr::hash; TEST(hash, hash) { string_view sv = "foo188"; diff --git a/src/tests/test_mem.cpp b/src/tests/test_mem.cpp index e355db3..7d54d2d 100644 --- a/src/tests/test_mem.cpp +++ b/src/tests/test_mem.cpp @@ -5,7 +5,7 @@ #include #include -using namespace ts; +using namespace tr; TEST(mem, unint) { std::vector bin; diff --git a/src/tests/test_newtypes.cpp b/src/tests/test_newtypes.cpp index b229270..9cdd705 100644 --- a/src/tests/test_newtypes.cpp +++ b/src/tests/test_newtypes.cpp @@ -5,7 +5,7 @@ #include "../core.h" using namespace std; -using namespace ts; +using namespace tr; enum class SyntaxKind { Unknown, diff --git a/src/tests/test_parser.cpp b/src/tests/test_parser.cpp index 3bcdc7a..6b56225 100644 --- a/src/tests/test_parser.cpp +++ b/src/tests/test_parser.cpp @@ -4,7 +4,7 @@ #include "../parser2.h" #include -using namespace ts; +using namespace tr; TEST(parser, single) { Parser parser; @@ -22,7 +22,7 @@ SemicolonToken EndOfFileToken */ - auto result = parser.parseSourceFile("app.ts", code, ts::types::ScriptTarget::Latest, false, ScriptKind::TS, {}); + auto result = parser.parseSourceFile("app.ts", code, tr::types::ScriptTarget::Latest, false, ScriptKind::TS, {}); debug("done"); } @@ -37,8 +37,8 @@ TEST(parser, bench) { usleep(100'000); bench(1, [&]{ - auto result = parser.parseSourceFile("app.ts", code, ts::types::ScriptTarget::Latest, false, ScriptKind::TS, {}); -// auto sourceFile = parser.createSourceFile("app.ts", ts::types::ScriptTarget::Latest, ScriptKind::TS, false, make_shared(), make_shared(), 0, [](auto s) {}); + auto result = parser.parseSourceFile("app.ts", code, tr::types::ScriptTarget::Latest, false, ScriptKind::TS, {}); +// auto sourceFile = parser.createSourceFile("app.ts", tr::types::ScriptTarget::Latest, ScriptKind::TS, false, make_shared(), make_shared(), 0, [](auto s) {}); }); fmt::print("parse {} bytes ", code.size()); @@ -74,8 +74,8 @@ const thisWorks: RedundantBigAssUnion[] = ["hello", 123] usleep(100'000); bench(1, [&]{ - auto result = parser.parseSourceFile("app.ts", code, ts::types::ScriptTarget::Latest, false, ScriptKind::TS, {}); -// auto sourceFile = parser.createSourceFile("app.ts", ts::types::ScriptTarget::Latest, ScriptKind::TS, false, make_shared(), make_shared(), 0, [](auto s) {}); + auto result = parser.parseSourceFile("app.ts", code, tr::types::ScriptTarget::Latest, false, ScriptKind::TS, {}); +// auto sourceFile = parser.createSourceFile("app.ts", tr::types::ScriptTarget::Latest, ScriptKind::TS, false, make_shared(), make_shared(), 0, [](auto s) {}); }); fmt::print("parse {} bytes ", code.size()); diff --git a/src/tests/test_pool_array.cpp b/src/tests/test_pool_array.cpp index 7e8a13a..91e99bc 100644 --- a/src/tests/test_pool_array.cpp +++ b/src/tests/test_pool_array.cpp @@ -14,7 +14,7 @@ struct Item { }; TEST_CASE("basic") { - ts::debug("std::span = {}", sizeof(std::span)); + tr::debug("std::span = {}", sizeof(std::span)); } TEST_CASE("block creation") { diff --git a/src/tests/test_scanner.cpp b/src/tests/test_scanner.cpp index c2dc382..55000b2 100644 --- a/src/tests/test_scanner.cpp +++ b/src/tests/test_scanner.cpp @@ -3,7 +3,7 @@ #include #include "../scanner.h" -using namespace ts; +using namespace tr; TEST(scanner, basisc) { @@ -14,10 +14,10 @@ TEST(scanner, basisc) { for (i = 0; i <10000; i++) { scanner.setText("const i = 123"); // scanner.setOnError([this](auto ...a) { scanError(a...); }); - scanner.setScriptTarget(ts::types::ScriptTarget::Latest); - scanner.setLanguageVariant(ts::types::LanguageVariant::Standard); + scanner.setScriptTarget(tr::types::ScriptTarget::Latest); + scanner.setLanguageVariant(tr::types::LanguageVariant::Standard); - while (scanner.scan() != ts::types::SyntaxKind::EndOfFileToken) { + while (scanner.scan() != tr::types::SyntaxKind::EndOfFileToken) { } diff --git a/src/tests/test_vm2.cpp b/src/tests/test_vm2.cpp index 9411d64..cb46f46 100644 --- a/src/tests/test_vm2.cpp +++ b/src/tests/test_vm2.cpp @@ -8,8 +8,8 @@ #include "../checker/vm2.h" #include "./utils.h" -using namespace ts; -using namespace ts::vm2; +using namespace tr; +using namespace tr::vm2; using std::string; using std::string_view; @@ -40,12 +40,12 @@ TEST_CASE("vm2Base1") { const v1: string = "abc"; const v2: number = 123; )"; - auto module = std::make_shared(ts::compile(code), "app.ts", ""); + auto module = std::make_shared(tr::compile(code), "app.ts", ""); run(module); REQUIRE(module->errors.size() == 0); - ts::vm2::gcStackAndFlush(); + tr::vm2::gcStackAndFlush(); //only v1, v2 - REQUIRE(ts::vm2::pool.active == 2); + REQUIRE(tr::vm2::pool.active == 2); testBench(code, 0); } @@ -84,14 +84,14 @@ const v1: a = 'yes'; const v2: a = true; const v3: a = false; )"; - auto module = std::make_shared(ts::compile(code), "app.ts", code); + auto module = std::make_shared(tr::compile(code), "app.ts", code); run(module); module->printErrors(); REQUIRE(module->errors.size() == 1); - ts::vm2::gcStackAndFlush(); + tr::vm2::gcStackAndFlush(); //only v1, v2, v3 plus for each 4 because union + (true | string | number) - REQUIRE(ts::vm2::pool.active == 3 * 4); + REQUIRE(tr::vm2::pool.active == 3 * 4); testBench(code, 1); } @@ -103,14 +103,14 @@ const v1: a = 'no'; const v2: a = 'yes'; const v3: a = 'nope'; )"; - auto module = std::make_shared(ts::compile(code), "app.ts", code); + auto module = std::make_shared(tr::compile(code), "app.ts", code); run(module); module->printErrors(); REQUIRE(module->errors.size() == 1); //only v1, v2, v3 subroutine cached value should live - ts::vm2::gcStackAndFlush(); - REQUIRE(ts::vm2::pool.active == 3); + tr::vm2::gcStackAndFlush(); + REQUIRE(tr::vm2::pool.active == 3); testBench(code, 1); } @@ -124,7 +124,7 @@ const v3: a = true; const v4: a = 'yes'; const v5: a = 'nope'; )"; - auto module = std::make_shared(ts::compile(code), "app.ts", code); + auto module = std::make_shared(tr::compile(code), "app.ts", code); run(module); module->printErrors(); @@ -149,21 +149,21 @@ type a = b; const var1: a = false; )"; - auto module = std::make_shared(ts::compile(code), "app.ts", code); + auto module = std::make_shared(tr::compile(code), "app.ts", code); run(module); module->printErrors(); REQUIRE(module->errors.size() == 1); - ts::vm2::gcFlush(); + tr::vm2::gcFlush(); //only var1 cached value should live - REQUIRE(ts::vm2::pool.active == 1); + REQUIRE(tr::vm2::pool.active == 1); - ts::vm2::clear(module); - ts::vm2::gcStackAndFlush(); - REQUIRE(ts::vm2::pool.active == 0); + tr::vm2::clear(module); + tr::vm2::gcStackAndFlush(); + REQUIRE(tr::vm2::pool.active == 0); - ts::bench("first", 1000, [&] { -// ts::vm2::clear(module); + tr::bench("first", 1000, [&] { +// tr::vm2::clear(module); module->clear(); //no vm2::clear necessary sine run() resets the type pool anyways run(module); @@ -171,7 +171,7 @@ const var1: a = false; } TEST_CASE("gcUnion") { - ts::checker::Program program; + tr::checker::Program program; for (auto i = 0; i<10; i++) { program.pushOp(OP::StringLiteral); program.pushStorage("a" + to_string(i)); @@ -183,12 +183,12 @@ TEST_CASE("gcUnion") { auto module = std::make_shared(program.build(), "app.ts", ""); run(module); REQUIRE(module->errors.size() == 0); - ts::vm2::gcStackAndFlush(); - REQUIRE(ts::vm2::pool.active == 0); + tr::vm2::gcStackAndFlush(); + REQUIRE(tr::vm2::pool.active == 0); } TEST_CASE("gcTuple") { - ts::checker::Program program; + tr::checker::Program program; for (auto i = 0; i<10; i++) { program.pushOp(OP::String); program.pushOp(OP::TupleMember); @@ -200,12 +200,12 @@ TEST_CASE("gcTuple") { auto module = std::make_shared(program.build(), "app.ts", ""); run(module); REQUIRE(module->errors.size() == 0); - ts::vm2::gcStackAndFlush(); - REQUIRE(ts::vm2::pool.active == 0); + tr::vm2::gcStackAndFlush(); + REQUIRE(tr::vm2::pool.active == 0); } TEST_CASE("gcObject") { - ts::checker::Program program; + tr::checker::Program program; for (auto i = 0; i<10; i++) { program.pushOp(OP::StringLiteral); program.pushStorage("foo1"); @@ -220,8 +220,8 @@ TEST_CASE("gcObject") { auto module = std::make_shared(program.build(), "app.ts", ""); run(module); REQUIRE(module->errors.size() == 0); - ts::vm2::gcStackAndFlush(); - REQUIRE(ts::vm2::pool.active == 0); + tr::vm2::gcStackAndFlush(); + REQUIRE(tr::vm2::pool.active == 0); } TEST_CASE("vm2TemplateLiteral1") { @@ -230,7 +230,7 @@ type L = `${string}`; const var1: L = 'abc'; const var2: L = 22; )"; - ts::testBench(code, 1); + tr::testBench(code, 1); } TEST_CASE("vm2TemplateLiteral2") { @@ -239,7 +239,7 @@ type L = `${34}`; const var1: L = '34'; const var2: L = 34; )"; - ts::testBench(code, 1); + tr::testBench(code, 1); } TEST_CASE("vm2TemplateLiteral3") { @@ -249,7 +249,7 @@ const var1: L = 'abc'; const var2: L = 'bbc'; )"; //not implemented yet - ts::testBench(code, 1); + tr::testBench(code, 1); } TEST_CASE("vm2TemplateLiteralSize") { @@ -259,7 +259,7 @@ type L = `${A['length']}`; const var1: L = "1"; const var2: L = "10"; )"; - ts::testBench(code, 1); + tr::testBench(code, 1); } TEST_CASE("vm2TemplateLiteralSizeGc") { @@ -268,9 +268,9 @@ type A = [1]; type L = `${A['length']}`; const var1: L = "1"; )"; - ts::test(code, 0); - ts::vm2::gcFlush(); - REQUIRE(ts::vm2::pool.active == 4); //A|var1 (literal+tupleMember+tuple) + L (literal) + tr::test(code, 0); + tr::vm2::gcFlush(); + REQUIRE(tr::vm2::pool.active == 4); //A|var1 (literal+tupleMember+tuple) + L (literal) } TEST_CASE("vm2TupleMerge") { @@ -282,8 +282,8 @@ const var2: L = [1, 2]; // Error const var3: A = [1, 2]; )"; test(code, 1); - debug("active {}", ts::vm2::pool.active); - ts::test(code, 1); + debug("active {}", tr::vm2::pool.active); + tr::test(code, 1); } TEST_CASE("vm2Tuple2") { @@ -292,8 +292,8 @@ type A = [1, 2]; const var1: A = [1, 2]; )"; test(code, 0); - ts::vm2::gcFlush(); - REQUIRE(ts::vm2::pool.active == 1 + (2 + 2)); + tr::vm2::gcFlush(); + REQUIRE(tr::vm2::pool.active == 1 + (2 + 2)); } TEST_CASE("vm2Tuple3") { @@ -303,8 +303,8 @@ type A = [...T, 2]; const var1: A = [1, 2]; )"; auto module = test(code, 0); - ts::vm2::gcFlush(); - REQUIRE(ts::vm2::pool.active == (1 + 2) + (1 + 2)); //[1], [1, 2], where "1" in second tuple is shared with first "1" in [1] + tr::vm2::gcFlush(); + REQUIRE(tr::vm2::pool.active == (1 + 2) + (1 + 2)); //[1], [1, 2], where "1" in second tuple is shared with first "1" in [1] testBench(code); } @@ -315,8 +315,8 @@ type A = [T, 2]; const var1: A = [1, 2]; )"; auto module = test(code, 0); - ts::vm2::gcFlush(); - REQUIRE(ts::vm2::pool.active == (1 + 2 + 2)); //$1, [$1, 2] + tr::vm2::gcFlush(); + REQUIRE(tr::vm2::pool.active == (1 + 2 + 2)); //$1, [$1, 2] } TEST_CASE("vm2Tuple31") { @@ -326,8 +326,8 @@ type A = [...B, 2]; const var1: A = [1, 2]; )"; test(code, 0); - ts::vm2::gcFlush(); - REQUIRE(ts::vm2::pool.active == (1 + 2) + (1 + 2)); //[1], [1, 2], where "1" in second tuple is shared with first "1" in [1] + tr::vm2::gcFlush(); + REQUIRE(tr::vm2::pool.active == (1 + 2) + (1 + 2)); //[1], [1, 2], where "1" in second tuple is shared with first "1" in [1] } TEST_CASE("vm2Tuple32") { @@ -336,8 +336,8 @@ type A = [...B, 2]; const var1: A<[1]> = [1, 2]; )"; test(code, 0); - ts::vm2::gcFlush(); - REQUIRE(ts::vm2::pool.active == (1 + 2 + 2)); //[1, 2] + tr::vm2::gcFlush(); + REQUIRE(tr::vm2::pool.active == (1 + 2 + 2)); //[1, 2] } TEST_CASE("vm2Tuple33") { @@ -346,8 +346,8 @@ type A = [...B, 2]; const var1: A<[]> = [2]; )"; test(code, 0); - ts::vm2::gcFlush(); - REQUIRE(ts::vm2::pool.active == (1 + 2)); // [2] + tr::vm2::gcFlush(); + REQUIRE(tr::vm2::pool.active == (1 + 2)); // [2] } TEST_CASE("vm2Fn1") { @@ -356,9 +356,9 @@ type F = T; const var1: F = 'abc'; )"; test(code, 0); - //REQUIRE(ts::vm2::pool.active == 2); - ts::vm2::gcFlush(); - REQUIRE(ts::vm2::pool.active == 1); + //REQUIRE(tr::vm2::pool.active == 2); + tr::vm2::gcFlush(); + REQUIRE(tr::vm2::pool.active == 1); } TEST_CASE("vm2Fn2") { @@ -368,9 +368,9 @@ const var1: F = 'abc'; )"; //todo extends not added yet test(code, 0); - //REQUIRE(ts::vm2::pool.active == 3); - ts::vm2::gcFlush(); - REQUIRE(ts::vm2::pool.active == 1); + //REQUIRE(tr::vm2::pool.active == 3); + tr::vm2::gcFlush(); + REQUIRE(tr::vm2::pool.active == 1); } TEST_CASE("vm2Fn3") { @@ -379,9 +379,9 @@ type F = T; const var1: F = 'abc'; )"; test(code, 0); - //REQUIRE(ts::vm2::pool.active == 2); - ts::vm2::gcFlush(); - REQUIRE(ts::vm2::pool.active == 1); + //REQUIRE(tr::vm2::pool.active == 2); + tr::vm2::gcFlush(); + REQUIRE(tr::vm2::pool.active == 1); } TEST_CASE("vm2Fn4") { @@ -390,8 +390,8 @@ type F1 = [0]; const var1: F1 = [0]; )"; test(code, 0); - ts::vm2::gcStackAndFlush(); - REQUIRE(ts::vm2::pool.active == 3); //[0] + tr::vm2::gcStackAndFlush(); + REQUIRE(tr::vm2::pool.active == 3); //[0] } TEST_CASE("vm2Fn4_1") { @@ -400,8 +400,8 @@ type F1 = [0]; const var1: F1 = [0]; )"; test(code, 0); - ts::vm2::gcFlush(); - REQUIRE(ts::vm2::pool.active == 3); //[0] + tr::vm2::gcFlush(); + REQUIRE(tr::vm2::pool.active == 3); //[0] } TEST_CASE("vm2Fn4_2") { @@ -410,8 +410,8 @@ type F1 = [...T, 0]; const var1: F1<[]> = [0]; )"; test(code, 0); - ts::vm2::gcFlush(); - REQUIRE(ts::vm2::pool.active == 3); //[0] + tr::vm2::gcFlush(); + REQUIRE(tr::vm2::pool.active == 3); //[0] } TEST_CASE("vm2Fn5") { @@ -420,8 +420,8 @@ type F1 = T extends any ? [...T, 0] : never; const var1: F1<[]> = [0]; )"; test(code, 0); - ts::vm2::gcFlush(); - REQUIRE(ts::vm2::pool.active == 3); //[0] + tr::vm2::gcFlush(); + REQUIRE(tr::vm2::pool.active == 3); //[0] } TEST_CASE("vm2Fn7") { @@ -432,9 +432,9 @@ const var1: F1 = [0]; const var2: T = []; )"; test(code, 0); - ts::vm2::gcFlush(); + tr::vm2::gcFlush(); //a new tuple is generated, but the same amount of active elements is active - REQUIRE(ts::vm2::pool.active == 1 + 3); //[] + [0] + REQUIRE(tr::vm2::pool.active == 1 + 3); //[] + [0] } TEST_CASE("vm2FnArg") { @@ -445,12 +445,12 @@ const var1: F1<[]> = [0]; const var2: F2<[]> = [0]; )"; test(code, 0); - ts::vm2::gcFlush(); + tr::vm2::gcFlush(); //The idea is that for F1<[]> the [] is refCount=0, and for each argument in `type F1<>` the refCount is increased // and dropped at the end (::Return). This makes sure that [] in F1<[]> does not get stolen in F1. // To support stealing in tail calls, the drop (and frame cleanup) happens before the next function is called. - REQUIRE(ts::vm2::pool.active == 3 + 3); //two tuples + REQUIRE(tr::vm2::pool.active == 3 + 3); //two tuples } TEST_CASE("vm2FnTailCall") { @@ -460,8 +460,8 @@ type F2 = F1; const var1: F1<[]> = [0]; )"; test(code, 0); - ts::vm2::gcFlush(); - REQUIRE(ts::vm2::pool.active == 3); + tr::vm2::gcFlush(); + REQUIRE(tr::vm2::pool.active == 3); } TEST_CASE("vm2FnTailCallConditional1") { @@ -526,12 +526,12 @@ type F2 = T2 extends any ? T2 extends any ? F1 : 1 : 2; const var1: F2<[]> = [0]; )"; test(code, 0); - ts::vm2::gcFlush(); - REQUIRE(ts::vm2::pool.active == 3); + tr::vm2::gcFlush(); + REQUIRE(tr::vm2::pool.active == 3); } TEST_CASE("vm2BenchOverhead") { - ts::bench("nothing", 1000, [&] { + tr::bench("nothing", 1000, [&] { }); } @@ -665,8 +665,8 @@ TEST_CASE("class2") { return 0; } } - const now: number = new MyDate.now(); - const now2: string = new MyDate.now(); + const now: number = new MyDate().now(); + const now2: string = new MyDate().now(); )"; test(code, 1); testBench(code, 1); @@ -679,15 +679,36 @@ TEST_CASE("class3") { return 0; } } - const now: number = new MyDate.now(); - const now2: string = new MyDate.now(); + const now: number = new MyDate().now(); + const now2: string = new MyDate().now(); )"; test(code, 1); testBench(code, 1); } -//todo: instance class from value arguments. does this work for functions already? +//todo: requires handling Constructor, ThisKeyword, ThisType +// this['item'] relies on `item`, since we can't enforce the order in compile time, we convert all properties/methods to subroutines and call them however they are referenced, +// and detect circular dependencies in the runtime. +// How do we pass `this`? As first TypeArgument, or in a Slot? +// `this` could change, e.g. `new (MyDate & {now: () => string})` +// https://www.typescriptlang.org/play?#code/FAMwrgdgxgLglgewgAggCgJQC5VgLYBGApgE7IDewy1yJRMYJKADANzAC+wwUANgIYBnQcgCyATwAi-GEQpUaEBAHdMOCPmJlKNXbXqMW7XVwXUYCNchgALOCIBkFJauzJBMEnAgBzDvL0aOgYmazsRIWR+CHFjGlNdAHpEsPtkKCQAN1IYEVs5YMNrcQAHOQso5AATIhBSOirkJDk4GDNkAgErACUDJgAVUqIAHlt7AG0AchdJgF0APgDA-RCjdq5TZOKyyuQAXjEpGTknchccTH3Fjy9fLi2MiA9q4-3UImVD6Vl2HiRnghvCAfL7HTAAOgsmF+j2e51whFIbwI4Jc0O4sJgqBUACZ1JokQcUZ1+NCgA TEST_CASE("class4") { + string code = R"( + class MyDate { + constructor(public item: T) {} + now(): this['item'] { + return this.item; + } + } + const now: number = new MyDate(123).now(); + const now2: string = new MyDate('123').now(); +)"; + test(code, 1); + testBench(code, 1); +} + +//todo: instance class from value arguments. does this work for functions already? +TEST_CASE("class41") { string code = R"( class MyDate { constructor(public item: T) {} @@ -702,6 +723,43 @@ TEST_CASE("class4") { testBench(code, 1); } +TEST_CASE("class5") { + string code = R"( + class Data { + constructor(public item: T) {} + } + + class MyDate extends Data { + now(): this['item'] { + return this.item; + } + } + const now: number = new MyDate('123').now(); + const now2: string = new MyDate('123').now(); +)"; + test(code, 1); + testBench(code, 1); +} + +TEST_CASE("class6") { + string code = R"( + class Data { + constructor(public item: T) {} + } + + class MyDate extends Data { + public item: number; + now(): this['item'] { + return this.item; + } + } + const now: number = new MyDate(123).now(); + const now2: string = new MyDate('123').now(); +)"; + test(code, 1); + testBench(code, 1); +} + TEST_CASE("vm2Cartesian") { { vm2::CartesianProduct cartesian; diff --git a/src/tests/test_vm2_closure.cpp b/src/tests/test_vm2_closure.cpp new file mode 100644 index 0000000..6c53d5f --- /dev/null +++ b/src/tests/test_vm2_closure.cpp @@ -0,0 +1,66 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include +#include + +#include "../core.h" +#include "../hash.h" +#include "../checker/compiler.h" +#include "../checker/vm2.h" +#include "./utils.h" + +using namespace tr; +using namespace tr::vm2; + +TEST_CASE("closure1") { + string code = R"( +function test() { + function b(): T { + return {} as any; + } + + return b; +} + +const b: () => string = test(); +const c: string = b(); +const d: number = b(); +)"; + test(code, 1); + //testBench(code, 1); +} + +//todo: this breaks since we do not capture T and generate a FunctionRef since b is generic and needs to be instantiated. +// FunctionRef needs to capture T and acts as closure. That's the solution right? +TEST_CASE("closure2") { + string code = R"( +function test() { + function b(v: K): K | T { + return {} as any; + } + + return b; +} + +const b = test(); +const c: string | number = b(3); +const d: string = b('3'); +)"; + test(code, 1); + //testBench(code, 1); +} + +TEST_CASE("closure3") { + string code = R"( +function test() { + function b(k: K): K & T { + return {} as any; + } + + return b; +} + +const b = test(); +)"; + test(code, 0); + //testBench(code, 1); +} \ No newline at end of file diff --git a/src/tests/test_vm2_union.cpp b/src/tests/test_vm2_union.cpp index 814822c..7dea5a8 100644 --- a/src/tests/test_vm2_union.cpp +++ b/src/tests/test_vm2_union.cpp @@ -8,14 +8,14 @@ #include "../checker/vm2.h" #include "./utils.h" -using namespace ts; -using namespace ts::vm2; +using namespace tr; +using namespace tr::vm2; using std::string; using std::string_view; TEST_CASE("bigUnion") { - ts::checker::Program program; + tr::checker::Program program; auto foos = 300; @@ -55,14 +55,14 @@ TEST_CASE("bigUnion") { module->printErrors(); REQUIRE(module->errors.size() == 0); - debug("pool.active = {}", ts::vm2::pool.active); - debug("poolRef.active = {}", ts::vm2::poolRef.active); - ts::vm2::clear(module); - ts::vm2::gcStackAndFlush(); - REQUIRE(ts::vm2::pool.active == 0); - REQUIRE(ts::vm2::poolRef.active == 0); + debug("pool.active = {}", tr::vm2::pool.active); + debug("poolRef.active = {}", tr::vm2::poolRef.active); + tr::vm2::clear(module); + tr::vm2::gcStackAndFlush(); + REQUIRE(tr::vm2::pool.active == 0); + REQUIRE(tr::vm2::poolRef.active == 0); - ts::bench("first", 1000, [&] { + tr::bench("first", 1000, [&] { module->clear(); run(module); }); diff --git a/src/tests/utils.h b/src/tests/utils.h index b6fdb4d..d6ac9e6 100644 --- a/src/tests/utils.h +++ b/src/tests/utils.h @@ -4,7 +4,7 @@ #include "../checker/vm2.h" #include "Tracy.hpp" -namespace ts { +namespace tr { std::string compile(std::string code, bool print = true) { Parser parser; auto result = parser.parseSourceFile("app.ts", code, ScriptTarget::Latest, false, ScriptKind::TS, {}); diff --git a/src/types.cpp b/src/types.cpp index 215ffb5..4de4ee3 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1,7 +1,7 @@ #include "types.h" -namespace ts { +namespace tr { // types::SyntaxKind BaseUnion::kind() { // return node->kind; // } diff --git a/src/types.h b/src/types.h index 9ec3979..3fcf070 100644 --- a/src/types.h +++ b/src/types.h @@ -14,11 +14,11 @@ #include #include -namespace ts { +namespace tr { struct SourceFile; } -namespace ts::types { +namespace tr::types { using namespace std; struct CompilerOptions; @@ -1070,14 +1070,14 @@ namespace ts::types { } template<> -struct fmt::formatter: formatter { +struct fmt::formatter: formatter { template - auto format(ts::types::SyntaxKind p, FormatContext &ctx) { + auto format(tr::types::SyntaxKind p, FormatContext &ctx) { return formatter::format(magic_enum::enum_name(p), ctx); } }; -namespace ts { +namespace tr { using namespace std; using types::SyntaxKind; diff --git a/src/utf.cpp b/src/utf.cpp index 5cca110..85ae6b5 100644 --- a/src/utf.cpp +++ b/src/utf.cpp @@ -4,7 +4,7 @@ * Note that an arbitrary `charCodeAt(text, position+1)` does not work since the current code point might be longer than one byte. * We probably should introduction `int position, int offset` so that `charCodeAt(text, position, 1)` returns the correct unicode code point. */ -ts::utf::CharCode ts::utf::charCodeAt(const std::string &text, int position, int *size) { +tr::utf::CharCode tr::utf::charCodeAt(const std::string &text, int position, int *size) { //from - https://stackoverflow.com/a/40054802/979328 int length = 1; int first = text[position]; @@ -34,7 +34,7 @@ ts::utf::CharCode ts::utf::charCodeAt(const std::string &text, int position, int return {-1, position}; } -std::string ts::utf::fromCharCode(int cp) { +std::string tr::utf::fromCharCode(int cp) { char c[5] = {0x00, 0x00, 0x00, 0x00, 0x00}; if (cp <= 0x7F) { c[0] = cp; } else if (cp <= 0x7FF) { diff --git a/src/utf.h b/src/utf.h index 8b29232..6885a00 100644 --- a/src/utf.h +++ b/src/utf.h @@ -5,7 +5,7 @@ #include #include -namespace ts::utf { +namespace tr::utf { enum CharacterCodes { nullCharacter = 0, maxAsciiCharacter = 0x7F, diff --git a/src/utilities.cpp b/src/utilities.cpp index 37d8feb..c2dae50 100644 --- a/src/utilities.cpp +++ b/src/utilities.cpp @@ -6,8 +6,8 @@ #include "hash.h" #include -namespace ts { - using namespace ts::hash; +namespace tr { + using namespace tr::hash; LanguageVariant getLanguageVariant(ScriptKind scriptKind) { // .tsx and .jsx files are treated as jsx language variant. diff --git a/src/utilities.h b/src/utilities.h index 68f09b0..f803e7a 100644 --- a/src/utilities.h +++ b/src/utilities.h @@ -11,18 +11,18 @@ #include "scanner.h" #include "hash.h" -namespace ts { - using namespace ts::types; +namespace tr { + using namespace tr::types; using std::vector; using std::string; using std::optional; - using ts::types::ScriptKind; - using ts::types::SyntaxKind; - using ts::types::Extension; - using ts::types::LanguageVariant; - using ts::utf::charCodeAt; - using ts::utf::CharCode; - using ts::utf::CharacterCodes; + using tr::types::ScriptKind; + using tr::types::SyntaxKind; + using tr::types::Extension; + using tr::types::LanguageVariant; + using tr::utf::charCodeAt; + using tr::utf::CharCode; + using tr::utf::CharacterCodes; using types::DiagnosticMessage; using types::DiagnosticCategory; using types::DiagnosticWithDetachedLocation; diff --git a/tests/generic2.ts b/tests/generic2.ts index 85a700e..10f05f8 100644 --- a/tests/generic2.ts +++ b/tests/generic2.ts @@ -1,2 +1,2 @@ type StringToNum = `${A['length']}` extends T ? A['length'] : StringToNum; -const var1: StringToNum<'999'> = 999; +const var1: StringToNum<'999'> = 999; \ No newline at end of file