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";