Skip to content

Commit

Permalink
very basic index access, tuple, rest, template literal
Browse files Browse the repository at this point in the history
  • Loading branch information
marcj committed Jun 12, 2022
1 parent c5ddd6c commit a9730b7
Show file tree
Hide file tree
Showing 18 changed files with 884 additions and 159 deletions.
6 changes: 4 additions & 2 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,18 @@ bool exists(const string &file)
int main(int argc, char *argv[]) {
// std::string cwd = "";
// if (argc > 0) cwd = argv[0];
std::string file = "/Users/marc/bude/typescript-cpp/tests/basic1.ts";
std::string file = "/Users/marc/bude/typescript-cpp/tests/generic2.ts";
if (argc > 1) file = argv[1];

// cwd.append("/");
// file = cwd + file;

auto bytecode = file + ".tsbytecode";
if (exists(bytecode)) {
auto buffer = readFile(file);
auto buffer = readFile(bytecode);
vm::VM vm;
vm.call(buffer);
vm.printErrors();
} else {
auto buffer = readFile(file);
checker::Compiler compiler;
Expand All @@ -56,6 +57,7 @@ int main(int argc, char *argv[]) {
writeFile(bytecode, bin);
vm::VM vm;
vm.call(bin);
vm.printErrors();
}
return 0;
}
2 changes: 1 addition & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ add_subdirectory(tests)
add_library(typescript utf.h utf.cpp core.h core.cpp utilities.h utilities.cpp node_test.h node_test.cpp
syntax_cursor.h syntax_cursor.cpp parser2.h parser2.cpp types.h types.cpp path.h path.cpp
factory.h factory.cpp parenthesizer.h parenthesizer.cpp scanner.h scanner.cpp
checker/vm.h checker/instructions.h checker/compiler.h checker/type_objects.h checker/utils.h checker/checks.h)
checker/vm.h checker/vm.cpp checker/instructions.h checker/compiler.h checker/type_objects.h checker/utils.h checker/checks.h)
# ${CMAKE_CURRENT_SOURCE_DIR}/../libs/tracy/TracyClient.cpp

target_link_libraries(typescript fmt)
57 changes: 36 additions & 21 deletions src/checker/checks.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,56 @@

namespace ts::vm {
/**
* Checks whether two types are assignable.
* Checks whether left extends right.
*
* `const value: left = right;`
* `left extends right ? true : false`
*/
bool isAssignable(shared<Type> left, shared<Type> right) {
if (left->kind == TypeKind::String) {
if (right->kind == TypeKind::String) return true;
if (right->kind == TypeKind::Literal) return to<TypeLiteral>(right)->type == TypeLiteralType::String;
bool isExtendable(shared<Type> &left, shared<Type> &right) {
if (right->kind == TypeKind::String) {
if (left->kind == TypeKind::String) return true;
if (left->kind == TypeKind::Literal) return to<TypeLiteral>(left)->type == TypeLiteralType::String;
}

if (left->kind == TypeKind::Number) {
if (right->kind == TypeKind::Number) return true;
if (right->kind == TypeKind::Literal) return to<TypeLiteral>(right)->type == TypeLiteralType::Number;
if (right->kind == TypeKind::Number) {
if (left->kind == TypeKind::Number) return true;
if (left->kind == TypeKind::Literal) return to<TypeLiteral>(left)->type == TypeLiteralType::Number;
}

if (left->kind == TypeKind::Literal && right->kind == TypeKind::Literal) {
return to<TypeLiteral>(left)->type == to<TypeLiteral>(right)->type &&
to<TypeLiteral>(left)->literal == to<TypeLiteral>(right)->literal;
if (left->kind == TypeKind::Literal && left->kind == TypeKind::Literal) {
return to<TypeLiteral>(left)->type == to<TypeLiteral>(left)->type &&
to<TypeLiteral>(right)->text() == to<TypeLiteral>(left)->text();
}

if (left->kind == TypeKind::Union) {
if (right->kind != TypeKind::Union) {
for (auto &&l: to<TypeUnion>(left)->types) {
if (isAssignable(l, right)) return true;
if (right->kind == TypeKind::Tuple && left->kind == TypeKind::Tuple) {
auto &rtypes = to<TypeTuple>(right)->types;
auto &ltypes = to<TypeTuple>(left)->types;
for (auto i = 0; i < rtypes.size(); i++) {
// auto rightType = indexAccess(left, { kind: TypeKind::Literal, literal: i });
// auto leftType = indexAccess(right, { kind: TypeKind::Literal, literal: i });
// if (rightType->kind == TypeKind::Infer || leftType->kind == TypeKind::Infer) continue;
// auto valid = isExtendable(leftType, rightType, extendStack);
// if (!valid) return false;
}
// inferFromTuple(right, left);

// return true;
}

if (right->kind == TypeKind::Union) {
if (left->kind != TypeKind::Union) {
for (auto &&l: to<TypeUnion>(right)->types) {
if (isExtendable(l, left)) return true;
}
return false;
} else {
//e.g.: string|number = string|boolean
const auto leftTypes = to<TypeUnion>(left)->types;
const auto rightTypes = to<TypeUnion>(right)->types;
auto rightTypes = to<TypeUnion>(right)->types;
auto leftTypes = to<TypeUnion>(left)->types;

for (auto &&r: rightTypes) {
for (auto &&r: leftTypes) {
bool valid = false;
for (auto &&l: leftTypes) {
if (isAssignable(l, r)) {
for (auto &&l: rightTypes) {
if (isExtendable(l, r)) {
valid = true;
break;
};
Expand Down
85 changes: 82 additions & 3 deletions src/checker/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ namespace ts::checker {
return address;
}

void pushStorage(const string_view &s) {
void pushStorage(string_view s) {
pushAddress(registerStorage(s));
}

Expand Down Expand Up @@ -325,6 +325,7 @@ namespace ts::checker {
for (unsigned int i = 0; i < end; i++) {
auto op = (OP) ops[i];
switch (op) {
case OP::TypeArgumentDefault:
case OP::Distribute: {
auto index = readUint32(ops, i + 1);
auto &routine = subroutines[index];
Expand Down Expand Up @@ -376,6 +377,7 @@ namespace ts::checker {
i += 4;
break;
}
case OP::TypeArgumentDefault:
case OP::Distribute: {
params += fmt::format(" &{}", readUint32(ops, i + 1));
i += 4;
Expand Down Expand Up @@ -453,11 +455,50 @@ namespace ts::checker {
break;
case types::SyntaxKind::FalseKeyword: program.pushOp(OP::False);
break;
case types::SyntaxKind::IndexedAccessType: {
const auto n = to<IndexedAccessTypeNode>(node);

handle(n->objectType, program);
handle(n->indexType, program);
program.pushOp(OP::IndexAccess);
break;
}
case types::SyntaxKind::LiteralType: {
const auto n = to<LiteralTypeNode>(node);
handle(n->literal, program);
break;
}
case types::SyntaxKind::TemplateLiteralType: {
auto t = to<TemplateLiteralTypeNode>(node);

program.pushFrame();
if (t->head->rawText && *t->head->rawText != "") {
program.pushOp(OP::StringLiteral);
program.pushStorage(*t->head->rawText);
}

for (auto &&sub: t->templateSpans->list) {
auto span = to<TemplateLiteralTypeSpan>(sub);
handle(to<TemplateLiteralTypeSpan>(span)->type, program);

if (auto a = to<TemplateMiddle>(span->literal)) {
if (a->rawText && *a->rawText != "") {
program.pushOp(OP::StringLiteral);
program.pushStorage(a->rawText ? *a->rawText : "");
}
} else if (auto a = to<TemplateTail>(span->literal)) {
if (a->rawText && *a->rawText != "") {
program.pushOp(OP::StringLiteral);
program.pushStorage(a->rawText ? *a->rawText : "");
}
}
}

program.pushOp(OP::TemplateLiteral);
program.popFrameImplicit();

break;
}
case types::SyntaxKind::UnionType: {
const auto n = to<UnionTypeNode>(node);
program.pushFrame();
Expand Down Expand Up @@ -511,8 +552,17 @@ namespace ts::checker {

if (n->typeParameters) {
for (auto &&p: n->typeParameters->list) {
auto &symbol = program.pushSymbol(to<TypeParameterDeclaration>(p)->name->escapedText, SymbolType::TypeVariable, n->pos);
auto tp = to<TypeParameterDeclaration>(p);
if (!tp) throw runtime_error("no type parameter");
auto &symbol = program.pushSymbol(tp->name->escapedText, SymbolType::TypeVariable, n->pos);
program.pushOp(instructions::TypeArgument);
if (tp->defaultType) {
program.pushSubroutine2(tp->defaultType->pos);
handle(tp->defaultType, program);
auto routine = program.popSubroutine();
program.pushOp(instructions::TypeArgumentDefault);
program.pushAddress(routine->address);
}
//todo constraints + default
}
}
Expand Down Expand Up @@ -616,14 +666,43 @@ namespace ts::checker {
handle(to<ParenthesizedTypeNode>(node)->type, program);
break;
}
case types::SyntaxKind::RestType: {
handle(to<RestTypeNode>(node)->type, program);
program.pushOp(OP::Rest);
break;
}
// case types::SyntaxKind::OptionalType: {
//
// break;
// }
//value inference
case types::SyntaxKind::ArrayLiteralExpression: {
program.pushFrame();
for (auto &&v: to<ArrayLiteralExpression>(node)->elements->list) {
handle(v, program);
program.pushOp(OP::TupleMember);
}
program.pushOp(OP::Tuple);
program.popFrameImplicit();
//todo: handle `as const`, widen if not const
break;
}
case types::SyntaxKind::TupleType: {
program.pushFrame();
auto n = to<TupleTypeNode>(node);
for (auto &&e: n->elements->list) {
if (auto tm = to<NamedTupleMember>(e)) {
// tm->
handle(tm->type, program);
if (tm->dotDotDotToken) program.pushOp(OP::Rest);
program.pushOp(OP::TupleMember);
if (tm->questionToken) program.pushOp(OP::Optional);
} else if (auto ot = to<OptionalTypeNode>(e)) {
handle(ot->type, program);
program.pushOp(OP::TupleMember);
program.pushOp(OP::Optional);
} else {
handle(e, program);
program.pushOp(OP::TupleMember);
}
}
program.pushOp(OP::Tuple);
Expand Down
26 changes: 21 additions & 5 deletions src/checker/instructions.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ namespace ts::instructions {
Null,
Undefined,


StringLiteral,
NumberLiteral,
BigIntLiteral,
Expand All @@ -39,6 +38,10 @@ namespace ts::instructions {

Tuple,
TupleMember,
TupleNamedMember, //has one parameter, the name in the storage

Optional,
Rest,

Union,
Intersection,
Expand All @@ -60,13 +63,24 @@ namespace ts::instructions {
/**
* Makes sure that in the current variable slot is a type placed if nothing was provided as parameter.
*
* For reach type argument like here `T` a TypeArgument OP is generated.
* Different to Var OP since Var does reserve an entry on the stack, whereas TypeArgument does nothing on the stack per default.
* For each type argument like here `T` a TypeArgument OP is generated.
* Different to Var OP since Var does reserve an entry on the stack,
* whereas TypeArgument ensures there is a stack entry if not already provided via call parameters..
* ```typescript
* type A<T> = T;
* ```
*/
TypeArgument,
TypeArgumentDefault, //expects an entry on the stack
TypeArgumentConstraint, //expects an entry on the stack


TemplateLiteral,

IndexAccess,
KeyOf,
Infer,
TypeOf,

/**
* Reserves a type variable on the stack, which contains a type object. Unknown as default.
Expand All @@ -87,8 +101,10 @@ namespace ts::instructions {
};
}

template <> struct fmt::formatter<ts::instructions::OP> : formatter<std::string_view> {
template <typename FormatContext> auto format(ts::instructions::OP p, FormatContext &ctx) {
template<>
struct fmt::formatter<ts::instructions::OP>: formatter<std::string_view> {
template<typename FormatContext>
auto format(ts::instructions::OP p, FormatContext &ctx) {
return formatter<string_view>::format(magic_enum::enum_name<ts::instructions::OP>(p), ctx);
}
};
Loading

0 comments on commit a9730b7

Please sign in to comment.