Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update lam4-frontend deps (vsce, langium, etc) #99

Merged
merged 3 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2024 SMU Centre for Computational Law
Copyright (c) 2024 Lam4 Contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ npm run build

After building:

* To see what the grammar looks like, you can **generate a railroad diagram from VSCode**, using the Langium VSCode extension.
* To print to std out and save to disk a **human-readable version of the concrete syntax** (i.e., a version without the metadata): `node ./bin/cli toMinimalAst <lam4program filename>.l4`
* To do that for a version of the concrete syntax that includes source text metadata: `node ./bin/cli toAstWithSrcMetadata <lam4program filename>.l4`
* Note that this is still more like concrete than abstract syntax --- I hope to be able to do that desugaring / simplfiying within the next 1-1.5 weeks. I'll aim to target Andres' AST for concrete evaluation, but I'll probably also experiment with another version on the side that has a few more constructs for symbolic execution.
* To **generate a VSCode extension**: `vsce package`
* To see what the surface Langium grammar looks like, you can **generate a railroad diagram from VSCode**, using the Langium VSCode extension.
* To print to std out and save to disk a **human-readable version of the surface Langium grammar syntax** (i.e., a version without the metadata): from `lam4-frontend`, do `node ./bin/cli toMinimalAst <lam4program filename>.l4`
* To do that for a version that includes source text metadata: `node ./bin/cli toAstWithSrcMetadata <lam4program filename>.l4`.
* To **generate and install a VSCode extension** at the command line (after removing previously-generated ones): `rm lam4-*.vsix; vsce package; code --install-extension lam4-*.vsix`
* To remove a VSCode extension at the command line: `code --list-extensions` to list extensions and get the name of the lam4 extension, then `code --uninstall-extension <name of the lam4 extension>`

## Noteworthy TODOs

Expand Down
9 changes: 9 additions & 0 deletions lam4-frontend/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// @ts-check

import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';

export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.recommended,
);
3,702 changes: 1,297 additions & 2,405 deletions lam4-frontend/package-lock.json

Large diffs are not rendered by default.

60 changes: 31 additions & 29 deletions lam4-frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@
"version": "0.0.1",
"license": "MIT",
"files": [
"!**/.DS_Store",
"!**/.vscode/**",
"!**/.vscode-test/**",
"!**/.gitignore",
"!**/langium-quickstart.md"
"bin",
"src",
"out",
"LICENSE"
],
"repository": {
"type": "git",
Expand All @@ -26,7 +25,7 @@
"scripts": {
"build": "tsc -b tsconfig.src.json && node esbuild.mjs",
"watch": "concurrently -n tsc,esbuild -c blue,yellow \"tsc -b tsconfig.src.json --watch\" \"node esbuild.mjs --watch\"",
"lint": "eslint src --ext ts",
"lint": "eslint src",
"langium:generate": "langium generate",
"langium:watch": "langium generate --watch",
"vscode:prepublish": "npm run esbuild-base -- --minify && npm run lint",
Expand All @@ -42,37 +41,40 @@
"test": "vitest run"
},
"dependencies": {
"@codingame/monaco-vscode-editor-service-override": "1.83.16",
"@codingame/monaco-vscode-keybindings-service-override": "1.83.16",
"@codingame/monaco-vscode-editor-service-override": "9.0.3",
"@codingame/monaco-vscode-keybindings-service-override": "9.0.3",
"chalk": "~5.3.0",
"commander": "~11.0.0",
"langium": "~3.0.0",
"monaco-editor": "npm:@codingame/monaco-editor-treemended@1.83.16",
"monaco-editor-workers": "~0.44.0",
"monaco-editor-wrapper": "~3.5.0",
"monaco-languageclient": "~7.2.0",
"ts-pattern": "^5.2.0",
"commander": "~12.1.0",
"langium": "~3.2.0",
"monaco-editor": "npm:@codingame/monaco-editor-treemended@1.85.6",
"monaco-editor-workers": "~0.45.0",
"monaco-editor-wrapper": "~5.5.3",
"monaco-languageclient": "~8.8.3",
"ts-pattern": "^5.3.1",
"tslog": "^4.9.3",
"vscode-languageclient": "~9.0.1",
"vscode-languageserver": "~9.0.1"
},
"devDependencies": {
"@types/node": "^18.0.0",
"@types/vscode": "~1.67.0",
"@typescript-eslint/eslint-plugin": "~6.4.1",
"@typescript-eslint/parser": "~6.4.1",
"concurrently": "~8.2.1",
"esbuild": "^0.19.12",
"eslint": "~8.47.0",
"langium-cli": "~3.0.0",
"typescript": "~5.1.6",
"vite": "~4.4.11",
"vitest": "~1.4.0",
"vscode": "npm:@codingame/[email protected]"
"@eslint/js": "^9.10.0",
"@types/eslint__js": "^8.42.3",
"@types/node": "^22.5.5",
"@types/vscode": "~1.93.0",
"@typescript-eslint/eslint-plugin": "~8.6.0",
"@typescript-eslint/parser": "~8.6.0",
"concurrently": "~9.0.1",
"esbuild": "^0.23.1",
"eslint": "~9.10.0",
"langium-cli": "~3.2.0",
"typescript": "~5.6.0",
"typescript-eslint": "^8.6.0",
"vite": "~5.4.6",
"vitest": "~2.1.1",
"vscode": "npm:@codingame/[email protected]"
},
"displayName": "lam4",
"engines": {
"vscode": "^1.67.0",
"vscode": "^1.93.0",
"node": ">=18.0.0"
},
"categories": [
Expand Down Expand Up @@ -116,4 +118,4 @@
"monaco-editor": "npm:@codingame/[email protected]",
"vscode": "npm:@codingame/[email protected]"
}
}
}
1 change: 0 additions & 1 deletion lam4-frontend/src/cli/generator.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { JSONString } from '../utils.js';
import type { Program } from '../language/generated/ast.js';
// import { expandToNode, joinToNode, toString } from 'langium/generate';
import chalk from 'chalk';
import * as fs from 'node:fs';
import * as path from 'node:path';
import { extractDestinationAndName } from './cli-util.js';
Expand Down
6 changes: 3 additions & 3 deletions lam4-frontend/src/language/lam4-json-serializer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {DefaultJsonSerializer, LangiumDocument, type LangiumCoreServices, type AstNode, } from "langium";
import {DefaultJsonSerializer, type LangiumCoreServices, type AstNode, } from "langium";
import type {JsonSerializeOptions} from "langium";
import {isNamedElement, NamedElement} from "./generated/ast.js";
import {NamedElement} from "./generated/ast.js";


export class WithNamedEltRefPathJsonSerializer extends DefaultJsonSerializer {
Expand All @@ -12,7 +12,7 @@ export class WithNamedEltRefPathJsonSerializer extends DefaultJsonSerializer {
override replacer(key: string, value: unknown, options: JsonSerializeOptions): unknown {
// Only need to add nodePath to NamedElements,
// since refs will be only to NamedElements
if (Object.hasOwn(value as Object, "name")) {
if (Object.hasOwn(value as object, "name")) {
// Might need to add more URI handling
(value as NamedElement & {"nodePath": string})["nodePath"] = "#" + this.astNodeLocator.getAstNodePath(value as AstNode);
}
Expand Down
4 changes: 2 additions & 2 deletions lam4-frontend/src/language/lam4-scope.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type {LangiumCoreServices} from "langium";
import { DefaultScopeComputation, AstNode, LangiumDocument, PrecomputedScopes, DefaultScopeProvider, EMPTY_SCOPE, ReferenceInfo, Scope } from "langium";
import { Logger } from "tslog";
import { SigDecl, RecordDecl, Project } from "./generated/ast.js";
import { RecordDecl, Project } from "./generated/ast.js";
import {isProjectExpr} from "./lam4-lang-utils.js";
import { getRecordAncestors, inferType, TypeEnv } from "./type-system/infer.js";
import { isRecordTTag, isSigTTag } from "./type-system/type-tags.js";
import { isRecordTTag } from "./type-system/type-tags.js";

const scopeLogger = new Logger({
name: "scoper",
Expand Down
6 changes: 4 additions & 2 deletions lam4-frontend/src/language/lam4-validator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { ValidationAcceptor, ValidationChecks } from 'langium';
import type {
// ValidationAcceptor,
ValidationChecks } from 'langium';
import type { Lam4AstType } from './generated/ast.js';
import {ToplevelElement, isNamedElement, isToplevelElement} from './generated/ast.js';
// import {ToplevelElement, isNamedElement, isToplevelElement} from './generated/ast.js';
import type { Lam4Services } from './lam4-module.js';

/**
Expand Down
33 changes: 17 additions & 16 deletions lam4-frontend/src/language/type-system/infer.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable */
/*
This is a simple bidirectional type checker modelled along the lines of
that in David Christansen's tutorial.
Expand All @@ -11,14 +12,13 @@ Status, as of Jul 8 2024:
to support a more type-safe scoping mechanism for record field access / joins.

Biggest TODOs:
* Augment Lam4 parser and type checker with support for type annotations with more structure, e.g. "(A => B) => C"
* Think about rewriting / desguaring FunDecls to a more convenient representation (esp. re param types)
* Support LET
* Support anon func
* The type inference/checking is currently only triggered from the scoper when certain constructs are present --- need to wire it up more systematically.
* Think about treating records as tuples or arrays / desugaring them into that
* Keep a bidir mapping between anme of field and pos in tuple
*
- Augment Lam4 parser and type checker with support for type annotations with more structure, e.g. "(A => B) => C"
- Think about rewriting / desguaring FunDecls to a more convenient representation (esp. re param types)
- Support LET
- Support anon func
- The type inference/checking is currently only triggered from the scoper when certain constructs are present --- need to wire it up more systematically.
- Think about treating records as tuples or arrays / desugaring them into that
- Keep a bidir mapping between anme of field and pos in tuple

Some intuition on bidirectional typechecking, for those unfamiliar with it:
-----------------------------------------------------------------------------
Expand All @@ -42,15 +42,15 @@ Some intuition on bidirectional typechecking, for those unfamiliar with it:
* https://www.reddit.com/r/ProgrammingLanguages/comments/v3z7r8/comment/ib32xpr/ points out that this does save you from having to
annotate function args when using higher order functions
*/

/* eslint-enable */

import { AstNode, Reference, isReference } from "langium";

import {
isExpr,
Expr,
Param,
SigDecl, isSigDecl, StringLiteral, BooleanLiteral, IntegerLiteral,TypeAnnot, isRelation, Relation, isBuiltinType, BuiltinType, isCustomTypeDef, CustomTypeDef, isParamTypePair, isIfThenElseExpr, isComparisonOp, isBinExpr, BinExpr, FunDecl, isFunDecl,
SigDecl, isSigDecl, StringLiteral, BooleanLiteral, IntegerLiteral,TypeAnnot, isRelation, BuiltinType, CustomTypeDef, isParamTypePair, isIfThenElseExpr, isComparisonOp, isBinExpr, BinExpr, FunDecl, isFunDecl,
isFunctionApplication,
PredicateDecl,
isPredicateDecl,
Expand All @@ -69,7 +69,7 @@ import {
isRecordDecl,
IDOrBackTickedID,
isRowType} from "../generated/ast.js";
import { TypeTag, ErrorTypeTag, StringTTag, IntegerTTag, isBooleanTTag, FunctionDeclTTag, isFunctionDeclTTag, PredicateTTag, isPredicateTTag, SigTTag, BooleanTTag, FunctionParameterTypePair, PredicateParameterTypePair, isErrorTypeTag, isSigTTag, isRelationTTag, RelationTTag, UnitTTag, isUnitTTag, FunOrPredDeclTTag, ParamlessFunctionTTag, isParamlessFunctionTTag, isRecordTTag, RecordTTag, RowTypeTTag} from "./type-tags.js";
import { TypeTag, ErrorTypeTag, StringTTag, IntegerTTag, isBooleanTTag, FunctionDeclTTag, isFunctionDeclTTag, PredicateTTag, isPredicateTTag, SigTTag, BooleanTTag, FunctionParameterTypePair, PredicateParameterTypePair, isErrorTypeTag, RelationTTag, UnitTTag, isUnitTTag, FunOrPredDeclTTag, ParamlessFunctionTTag, isParamlessFunctionTTag, isRecordTTag, RecordTTag, RowTypeTTag} from "./type-tags.js";
import type {FunctionParameterTypePairSequence} from "./type-tags.js";
import { isProjectExpr } from "../lam4-lang-utils.js";

Expand Down Expand Up @@ -187,13 +187,13 @@ function synthTypeAnnot(env: TypeEnv, annot: TypeAnnot | PrimitiveTypeAnnot | Bu
// Inductive case
} else if (annot.$type === "TypeAnnot") {
typecheckLogger.trace(`[synthTypeAnnot -- inductive]`);
let argTypes = [inferType(env, annot.left)];
const argTypes = [inferType(env, annot.left)];
let rightmost = annot.right;

while (!isBasecaseTypeAnnot(rightmost) && !isBasecaseFunctionTypeAnnot(rightmost)) {
rightmost = (rightmost as TypeAnnot).right;

let newArgType = inferType(env, (rightmost as TypeAnnot).left);
const newArgType = inferType(env, (rightmost as TypeAnnot).left);
argTypes.push(newArgType);
}

Expand Down Expand Up @@ -472,6 +472,7 @@ function checkFunType(env: TypeEnv, parameters: FunctionParameterTypePairSequenc
return check(newExtendedEnv, body, returnType);
}

/* eslint-disable */
const check = (env: TypeEnv, term: AstNode, type: TypeTag): TypeTag =>
match([term, type])
.with([P._, P.when(isErrorTypeTag)],
Expand Down Expand Up @@ -508,11 +509,11 @@ const check = (env: TypeEnv, term: AstNode, type: TypeTag): TypeTag =>
return iteChecksPass ? type : new ErrorTypeTag(ite, "Type error in if-then-else expression (a more helpful error msg is possible with more work)");
})
.otherwise(([term, type]) => {
let termType = inferType(env, term);
const termType = inferType(env, term);
return termType.sameTypeAs(type) ? type : new ErrorTypeTag(term, "Type error");
// TODO in the future: isSubtype(termType, type) ? type : new ErrorTypeTag(term, "Type error");
});

/* eslint-enable */

/* ===========================
* Utils
Expand All @@ -527,7 +528,7 @@ function getAncestors(sigOrRecord: SigOrRecordDecl): SigOrRecordDecl[] {
const toVisit: SigOrRecordDecl[] = [sigOrRecord];

while (toVisit.length > 0) {
let next: SigOrRecordDecl | undefined = toVisit.pop();
const next: SigOrRecordDecl | undefined = toVisit.pop();
if (!next) break; // TODO: temp hack cos TS can't narrow based on length out of box

if (!seen.has(next)) {
Expand Down
1 change: 0 additions & 1 deletion lam4-frontend/src/language/type-system/type-tags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
RecordDecl,
isRecordDecl,
IDOrBackTickedID,
TypeAnnot,
RowType
} from "../generated/ast.js";
import { zip } from "../../utils.js"
Expand Down
1 change: 1 addition & 0 deletions lam4-frontend/tsconfig.src.tsbuildinfo
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"root":["./src/utils.ts","./src/cli/cli-util.ts","./src/cli/generator.ts","./src/cli/main.ts","./src/extension/main.ts","./src/language/lam4-json-serializer.ts","./src/language/lam4-lang-utils.ts","./src/language/lam4-module.ts","./src/language/lam4-scope.ts","./src/language/lam4-validator.ts","./src/language/lam4-value-converter.ts","./src/language/main-browser.ts","./src/language/main.ts","./src/language/generated/ast.ts","./src/language/generated/grammar.ts","./src/language/generated/module.ts","./src/language/lsp/lam4-hover-provider.ts","./src/language/type-system/infer.ts","./src/language/type-system/type-tags.ts"],"version":"5.6.2"}