Skip to content

Commit ddff68e

Browse files
committed
feat: more nodes
1 parent 4eaa1b3 commit ddff68e

File tree

8 files changed

+205
-95
lines changed

8 files changed

+205
-95
lines changed

packages/language-server/src/codegen/function.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { SyntaxNode } from "tree-sitter";
22
import type { Code } from "../types";
33
import { generateBlock, generateExpression, generateIdentifier, generateSelf } from ".";
44
import { context } from "./context";
5-
import { generateType } from "./type";
5+
import { generateType, generateTypeParameters } from "./type";
66
import { between, generateChildren } from "./utils";
77

88
export enum FunctionKind {
@@ -17,14 +17,19 @@ export function* generateFunction(
1717
kind: FunctionKind,
1818
selfType?: SyntaxNode,
1919
): Generator<Code> {
20-
if (kind === FunctionKind.Declaration && node.namedChildren[0]?.type === "visibility_modifier") {
21-
yield `export `;
22-
}
23-
2420
if (kind !== FunctionKind.Closure) {
25-
yield `function `;
21+
if (kind === FunctionKind.Declaration) {
22+
if (node.namedChildren[0]?.type === "visibility_modifier") {
23+
yield `export `;
24+
}
25+
yield `function `;
26+
}
27+
2628
const name = node.childForFieldName("name")!;
2729
yield* generateIdentifier(name);
30+
31+
const typeParams = node.childForFieldName("type_parameters");
32+
yield* generateTypeParameters(typeParams);
2833
}
2934

3035
const parameters = node.childForFieldName("parameters")!;
@@ -77,6 +82,6 @@ function* generateParameter(node: SyntaxNode, selfType: SyntaxNode | undefined):
7782
yield pattern;
7883
yield* between(node, pattern, type);
7984
if (type) {
80-
yield type;
85+
yield* generateType(type);
8186
}
8287
}

packages/language-server/src/codegen/impl.ts

Lines changed: 46 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,73 +2,76 @@ import type { SyntaxNode } from "tree-sitter";
22
import type { Code } from "../types";
33
import { escapeCtorName } from "./escaping";
44
import { FunctionKind, generateFunction } from "./function";
5+
import { generateTypeParameters, getTypeParamPlaceholders } from "./type";
56

67
export function* generateImpl(node: SyntaxNode): Generator<
78
Code
89
> {
10+
const typeParams = node.childForFieldName("type_parameters");
911
const trait = node.childForFieldName("trait");
1012
const type = node.childForFieldName("type")!;
1113
const body = node.childForFieldName("body")!;
14+
const name = type.text; // FIXME: A::B
1215

1316
const staticMethods: SyntaxNode[] = [];
1417
const instanceMethods: SyntaxNode[] = [];
15-
1618
for (const child of body.namedChildren) {
1719
if (child.type === "function_item") {
18-
yield* generateFunction(child, FunctionKind.Implementation, type);
19-
yield "\n";
20-
21-
const name = child.childForFieldName("name")!;
2220
const isStatic = child.childForFieldName("parameters")?.namedChildren[0]?.type !== "self_parameter";
2321
if (isStatic)
24-
staticMethods.push(name);
22+
staticMethods.push(child);
2523
else
26-
instanceMethods.push(name);
24+
instanceMethods.push(child);
2725
}
2826
}
2927

30-
// TODO: declare module "..." {
28+
if (staticMethods.length > 0) {
29+
const implName = `__JSRS_impl_${node.startIndex}_static`;
30+
yield `function ${implName}`;
31+
yield* generateTypeParameters(typeParams);
32+
yield `() { return {\n`;
33+
for (const method of staticMethods) {
34+
yield* generateFunction(method, FunctionKind.Implementation, type);
35+
yield ",\n";
36+
}
37+
yield `} `;
3138

32-
const name = type.text; // FIXME: A::B
33-
if (trait) {
34-
const traitName = trait.text;
35-
if (staticMethods.length) {
36-
yield `;({ `;
37-
for (const methodName of staticMethods) {
38-
yield methodName;
39-
yield ", ";
40-
}
41-
yield `} satisfies ${escapeCtorName(traitName)})\n`;
39+
if (trait) {
40+
const traitName = trait.text;
41+
yield `satisfies ${escapeCtorName(traitName)}; }\n`;
42+
// TODO: declare module "..." {
4243
yield `interface ${escapeCtorName(name)} extends ${escapeCtorName(traitName)} {}\n`;
4344
}
44-
if (instanceMethods.length) {
45-
yield `;({ `;
46-
for (const methodName of instanceMethods) {
47-
yield methodName;
48-
yield ", ";
49-
}
50-
yield `} satisfies ${traitName})\n`;
51-
yield `interface ${name} extends ${traitName} {}\n`;
45+
else {
46+
yield "}\n";
47+
const typeParamPlaceholders = getTypeParamPlaceholders(typeParams);
48+
yield `type ${implName}_T${typeParamPlaceholders} = ReturnType<typeof ${implName}${typeParamPlaceholders}>;\n`;
49+
yield `interface ${escapeCtorName(name)} extends ${implName}_T${typeParamPlaceholders} {}\n`;
5250
}
5351
}
54-
else {
55-
if (staticMethods.length) {
56-
yield `interface ${escapeCtorName(name)} { `;
57-
for (const methodName of staticMethods) {
58-
yield methodName;
59-
yield ": typeof ";
60-
yield methodName;
61-
yield "; ";
62-
}
63-
yield "}\n";
52+
53+
if (instanceMethods.length > 0) {
54+
const implName = `__JSRS_impl_${node.startIndex}`;
55+
yield `function ${implName}`;
56+
yield* generateTypeParameters(typeParams);
57+
yield `() { return {\n`;
58+
for (const method of instanceMethods) {
59+
yield* generateFunction(method, FunctionKind.Implementation, type);
60+
yield ",\n";
61+
}
62+
yield `} `;
63+
64+
if (trait) {
65+
const traitName = trait.text;
66+
yield `satisfies ${traitName}; }\n`;
67+
// TODO: declare module "..." {
68+
yield `interface ${name} extends ${traitName} {}\n`;
6469
}
65-
yield `interface ${name} { `;
66-
for (const methodName of instanceMethods) {
67-
yield methodName;
68-
yield ": typeof ";
69-
yield methodName;
70-
yield "; ";
70+
else {
71+
yield "}\n";
72+
const typeParamPlaceholders = getTypeParamPlaceholders(typeParams);
73+
yield `type ${implName}_T${typeParamPlaceholders} = ReturnType<typeof ${implName}${typeParamPlaceholders}>;\n`;
74+
yield `interface ${name} extends ${implName}_T${typeParamPlaceholders} {}\n`;
7175
}
72-
yield "}\n";
7376
}
7477
}

packages/language-server/src/codegen/index.ts

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { context } from "./context";
66
import { generateEnum } from "./enum";
77
import { FunctionKind, generateFunction } from "./function";
88
import { generateImpl } from "./impl";
9-
import { generateMatch } from "./match";
9+
import { generateMatch, getPatternBindings } from "./match";
1010
import { generatePrelude } from "./prelude";
1111
import { generateStruct, generateStructExpression } from "./struct";
1212
import { generateUse } from "./use";
@@ -182,12 +182,7 @@ export function* generateExpression(node: SyntaxNode): Generator<Code> {
182182
}
183183

184184
function* generateArrayExpression(node: SyntaxNode): Generator<Code> {
185-
yield `[`;
186-
for (const child of node.namedChildren) {
187-
yield* generateExpression(child);
188-
yield `, `;
189-
}
190-
yield `]`;
185+
yield* generateChildren(node, generateExpression, text => text.replace("(", "[").replace(")", "]"));
191186
}
192187

193188
function* generateBinaryExpression(node: SyntaxNode): Generator<Code> {
@@ -254,12 +249,7 @@ function* generateCallExpression(node: SyntaxNode): Generator<Code> {
254249
const args = node.childForFieldName("arguments")!;
255250

256251
yield* generateExpression(func);
257-
yield `(`;
258-
for (const arg of args.namedChildren) {
259-
yield* generateExpression(arg);
260-
yield `, `;
261-
}
262-
yield `)`;
252+
yield* generateChildren(args, generateExpression);
263253
}
264254

265255
function* generateFieldExpression(node: SyntaxNode): Generator<Code> {
@@ -332,8 +322,12 @@ function* generateRangeExpression(node: SyntaxNode): Generator<Code> {
332322
yield `)`;
333323
}
334324

335-
function* generateReferenceExpression(_node: SyntaxNode): Generator<Code> {
336-
// TODO:
325+
function* generateReferenceExpression(node: SyntaxNode): Generator<Code> {
326+
const isMut = node.descendantsOfType("mutable_specifier").length > 0;
327+
const value = node.childForFieldName("value")!;
328+
yield isMut ? "__JSRS_mutRef(" : "__JSRS_ref(";
329+
yield* generateExpression(value);
330+
yield ")";
337331
}
338332

339333
function* generateReturnExpression(node: SyntaxNode): Generator<Code> {
@@ -375,6 +369,45 @@ export function* generateSelf(node: SyntaxNode): Generator<Code> {
375369
yield ["this", node.startIndex];
376370
}
377371

378-
function* generateIf(_node: SyntaxNode): Generator<Code> {
379-
// TODO:
372+
function* generateIf(node: SyntaxNode): Generator<Code> {
373+
const condition = node.childForFieldName("condition")!;
374+
const consequence = node.childForFieldName("consequence")!;
375+
const alternative = node.childForFieldName("alternative");
376+
if (condition.type === "let_condition") {
377+
const pattern = condition.childForFieldName("pattern")!;
378+
const value = condition.childForFieldName("value")!;
379+
380+
yield "if (__JSRS_any(";
381+
yield* generateExpression(value);
382+
yield "))";
383+
384+
const bindings = [...getPatternBindings(pattern)];
385+
if (bindings.length) {
386+
yield "{ const ";
387+
let isFirst = true;
388+
for (const binding of bindings) {
389+
if (!isFirst) {
390+
yield ", ";
391+
}
392+
isFirst = false;
393+
yield binding;
394+
yield "!";
395+
}
396+
yield "; "
397+
}
398+
yield* generateStatement(consequence);
399+
if (bindings.length) {
400+
yield " }";
401+
}
402+
}
403+
else {
404+
yield "if (";
405+
yield* generateExpression(condition);
406+
yield ")";
407+
yield* generateStatement(consequence);
408+
}
409+
if (alternative) {
410+
yield "else ";
411+
yield* generateStatement(alternative.namedChildren[0]);
412+
}
380413
}

packages/language-server/src/codegen/match.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,31 @@ import type { Code } from "../types";
44
export function* generateMatch(_node: SyntaxNode): Generator<Code> {
55
// TODO:
66
}
7+
8+
export function* getPatternBindings(node: SyntaxNode): Generator<Code> {
9+
switch (node.type) {
10+
case "identifier":
11+
yield node;
12+
break;
13+
case "tuple_struct_pattern":
14+
for (const child of node.namedChildren.slice(1)) {
15+
yield* getPatternBindings(child);
16+
}
17+
break;
18+
case "or_pattern": {
19+
const [left, right] = node.namedChildren;
20+
const leftBindings = getPatternBindings(left);
21+
const _rightBindings = getPatternBindings(right);
22+
// TODO: Check equality of bindings
23+
yield* leftBindings;
24+
break;
25+
}
26+
case "slice_pattern":
27+
case "tuple_pattern":
28+
for (const child of node.namedChildren) {
29+
yield* getPatternBindings(child);
30+
}
31+
break;
32+
default:
33+
}
34+
}

packages/language-server/src/codegen/type.ts

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import type { SyntaxNode } from "tree-sitter";
22
import type { Code } from "../types";
33
import { generateScopedIdentifier } from ".";
4+
import { codeFeatures } from "../utils/codeFeatures";
5+
import { generateChildren, wrapWith } from "./utils";
46

57
export function* generateTypeParameters(node: SyntaxNode | null): Generator<Code> {
6-
if (!node)
8+
if (!node?.namedChildren.length)
79
return;
810
yield "<";
911
for (const child of node.children) {
@@ -15,6 +17,15 @@ export function* generateTypeParameters(node: SyntaxNode | null): Generator<Code
1517
yield ">";
1618
}
1719

20+
export function getTypeParamPlaceholders(node: SyntaxNode | null): string {
21+
if (!node?.namedChildren.length)
22+
return "";
23+
return `<${node.namedChildren.map((param) => {
24+
// FIXME: complex param
25+
return param.text;
26+
}).join(", ")}>`;
27+
}
28+
1829
export function* generateType(node: SyntaxNode): Generator<Code> {
1930
switch (node.type) {
2031
case "type_identifier":
@@ -23,5 +34,39 @@ export function* generateType(node: SyntaxNode): Generator<Code> {
2334
case "scoped_type_identifier":
2435
yield* generateScopedIdentifier(node);
2536
break;
37+
case "generic_type":
38+
yield* generateGenericType(node);
39+
break;
40+
case "lifetime":
41+
yield* generateLifetime(node);
42+
break;
43+
case "reference_type":
44+
yield* generateReferenceType(node);
45+
break;
2646
}
2747
}
48+
49+
function* generateGenericType(node: SyntaxNode): Generator<Code> {
50+
const type = node.childForFieldName("type")!;
51+
const args = node.childForFieldName("type_arguments")!;
52+
53+
yield* generateType(type);
54+
yield* generateChildren(args, generateType);
55+
}
56+
57+
function* generateLifetime(node: SyntaxNode): Generator<Code> {
58+
yield* wrapWith(
59+
node.startIndex,
60+
node.endIndex,
61+
codeFeatures.verification,
62+
`__JSRS_lifetime_${node.namedChildren[0].text}`,
63+
);
64+
}
65+
66+
function* generateReferenceType(node: SyntaxNode): Generator<Code> {
67+
const isMut = node.descendantsOfType("mutable_specifier").length > 0;
68+
const type = node.childForFieldName("type")!;
69+
yield isMut ? "__JSRS_MutRef<" : "__JSRS_Ref<";
70+
yield* generateType(type);
71+
yield ">";
72+
}

0 commit comments

Comments
 (0)