diff --git a/src/ast.ts b/src/ast.ts
index c18ba274..1323f7ec 100644
--- a/src/ast.ts
+++ b/src/ast.ts
@@ -46,3 +46,74 @@ export type Statement = Meta & {
export type Program = {
statements: Statement[];
};
+
+export type Span = [startIdx: number, endIdx: number];
+export type SpanMeta = { span: Span };
+
+function spanContains([start, end]: Span, offset: number) {
+ return start <= offset && end >= offset;
+}
+
+function exprByOffset(
+ ast: Expr,
+ offset: number,
+): T | undefined {
+ if (!spanContains(ast.span, offset)) {
+ return;
+ }
+
+ switch (ast.type) {
+ case "constant":
+ case "identifier":
+ return ast;
+ case "application":
+ for (const arg of ast.args) {
+ const t = exprByOffset(arg, offset);
+ if (t !== undefined) {
+ return t;
+ }
+ }
+ return exprByOffset(ast.caller, offset) ?? ast;
+
+ case "let":
+ if (spanContains(ast.binding.span, offset)) {
+ return ast.binding;
+ }
+ return (
+ exprByOffset(ast.value, offset) ?? exprByOffset(ast.body, offset) ?? ast
+ );
+
+ case "fn":
+ for (const param of ast.params) {
+ if (spanContains(param.span, offset)) {
+ return param;
+ }
+ }
+ return exprByOffset(ast.body, offset) ?? ast;
+
+ case "if":
+ return (
+ exprByOffset(ast.condition, offset) ??
+ exprByOffset(ast.then, offset) ??
+ exprByOffset(ast.else, offset) ??
+ ast
+ );
+ }
+}
+
+export function declByOffset(
+ program: Program,
+ offset: number,
+): T | undefined {
+ for (const st of program.statements) {
+ if (spanContains(st.binding.span, offset)) {
+ return st.binding;
+ }
+ const e = exprByOffset(st.value, offset);
+ if (e !== undefined) {
+ return e;
+ }
+ }
+
+ return undefined;
+}
diff --git a/src/cli/commands/lsp.ts b/src/cli/commands/lsp.ts
index 50bc2780..7de95bee 100644
--- a/src/cli/commands/lsp.ts
+++ b/src/cli/commands/lsp.ts
@@ -7,83 +7,15 @@ import {
createConnection,
} from "vscode-languageserver";
import { TextDocument } from "vscode-languageserver-textdocument";
-import { Span, SpanMeta, parse } from "../../parser";
+import { parse } from "../../parser";
import { typeErrorPPrint, typePPrint } from "../../typecheck/pretty-printer";
import { TypeMeta, typecheck } from "../../typecheck/typecheck";
import { prelude } from "../../typecheck/prelude";
-import { Expr, Program } from "../../ast";
+import { Program, SpanMeta, declByOffset } from "../../ast";
const documents = new TextDocuments(TextDocument);
const docs = new Map]>();
-function spanContains([start, end]: Span, offset: number) {
- return start <= offset && end >= offset;
-}
-
-function exprByOffset(
- ast: Expr,
- offset: number,
-): T | undefined {
- if (!spanContains(ast.span, offset)) {
- return;
- }
-
- switch (ast.type) {
- case "constant":
- case "identifier":
- return ast;
- case "application":
- for (const arg of ast.args) {
- const t = exprByOffset(arg, offset);
- if (t !== undefined) {
- return t;
- }
- }
- return exprByOffset(ast.caller, offset) ?? ast;
-
- case "let":
- if (spanContains(ast.binding.span, offset)) {
- return ast.binding;
- }
- return (
- exprByOffset(ast.value, offset) ?? exprByOffset(ast.body, offset) ?? ast
- );
-
- case "fn":
- for (const param of ast.params) {
- if (spanContains(param.span, offset)) {
- return param;
- }
- }
- return exprByOffset(ast.body, offset) ?? ast;
-
- case "if":
- return (
- exprByOffset(ast.condition, offset) ??
- exprByOffset(ast.then, offset) ??
- exprByOffset(ast.else, offset) ??
- ast
- );
- }
-}
-
-function declByOffset(
- program: Program,
- offset: number,
-): T | undefined {
- for (const st of program.statements) {
- if (spanContains(st.binding.span, offset)) {
- return st.binding;
- }
- const e = exprByOffset(st.value, offset);
- if (e !== undefined) {
- return e;
- }
- }
-
- return undefined;
-}
-
export function lspCmd() {
const connection =
// @ts-ignore
@@ -94,11 +26,6 @@ export function lspCmd() {
textDocumentSync: TextDocumentSyncKind.Incremental,
hoverProvider: true,
documentSymbolProvider: true,
- // inlayHintProvider: true,
- // codeLensProvider: {
- // resolveProvider: true,
- // },
- // documentSymbolProvider: true,
},
}));
diff --git a/src/cli/commands/typecheck.ts b/src/cli/commands/typecheck.ts
index ae96a21d..0ba1dfbc 100644
--- a/src/cli/commands/typecheck.ts
+++ b/src/cli/commands/typecheck.ts
@@ -1,8 +1,9 @@
import { readFileSync } from "fs";
-import { Span, unsafeParse } from "../../parser";
+import { unsafeParse } from "../../parser";
import { typecheck } from "../../typecheck/typecheck";
import { typeErrorPPrint } from "../../typecheck/pretty-printer";
import { prelude } from "../../typecheck/prelude";
+import { Span } from "../../ast";
const FgRed = "\x1b[31m";
const Reset = "\x1b[0m";
diff --git a/src/parser.ts b/src/parser.ts
index 20027eb1..d2577b65 100644
--- a/src/parser.ts
+++ b/src/parser.ts
@@ -1,5 +1,5 @@
import grammar from "./parser/grammar.ohm-bundle";
-import { ConstLiteral, Program, Expr, Statement } from "./ast";
+import { ConstLiteral, Program, Expr, Statement, Span, SpanMeta } from "./ast";
import type {
MatchResult,
NonterminalNode,
@@ -7,9 +7,6 @@ import type {
TerminalNode,
} from "ohm-js";
-export type Span = [startIdx: number, endIdx: number];
-export type SpanMeta = { span: Span };
-
function getSpan({ source }: OhmNode): Span {
return [source.startIdx, source.endIdx];
}
diff --git a/src/typecheck/typecheck.ts b/src/typecheck/typecheck.ts
index 7c63d073..0a1fde40 100644
--- a/src/typecheck/typecheck.ts
+++ b/src/typecheck/typecheck.ts
@@ -1,5 +1,4 @@
-import { ConstLiteral, Expr, Program, Statement } from "../ast";
-import { Span, SpanMeta } from "../parser";
+import { ConstLiteral, Expr, Program, Statement, Span, SpanMeta } from "../ast";
import { TVar, Type, unify, Context, generalize, instantiate } from "./unify";
export type UnifyErrorType = "type-mismatch" | "occurs-check";