Skip to content

Commit

Permalink
More for LOX (#32)
Browse files Browse the repository at this point in the history
- fixed some bugs
- more test cases
- validations: support for removing validations rules of removed types
- classes:
  - support methods/functions in classes
  - UniqueMethodValidation
  - implemented TopClassType
- refactorings
- unified configurations for OX and LOX
- added examples for LangDev'24 and EclipseCon'24
  • Loading branch information
JohannesMeierSE authored Nov 5, 2024
1 parent da77edb commit 857339a
Show file tree
Hide file tree
Showing 28 changed files with 889 additions and 228 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
.vscode-test/
coverage/
dist/
bin/
lib/
out/
node_modules/
*.vsix
*.tsbuildinfo
generated/
/**/generated/
8 changes: 8 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
"args": [
"--extensionDevelopmentPath=${workspaceFolder}/examples/ox",
"${workspaceFolder}/examples/ox/examples"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/examples/ox/out/**/*.js"
]
},
{
Expand All @@ -21,6 +25,10 @@
"args": [
"--extensionDevelopmentPath=${workspaceFolder}/examples/lox",
"${workspaceFolder}/examples/lox/examples"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/examples/lox/out/**/*.js"
]
},
{
Expand Down
13 changes: 0 additions & 13 deletions examples/lox/.eslintrc.json

This file was deleted.

3 changes: 0 additions & 3 deletions examples/lox/.gitignore

This file was deleted.

4 changes: 0 additions & 4 deletions examples/lox/.vscodeignore

This file was deleted.

2 changes: 1 addition & 1 deletion examples/lox/langium-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"grammar": "src/language/lox.langium",
"fileExtensions": [".lox"],
"textMate": {
"out": "syntaxes/lox.tmLanguage.json"
"out": "./syntaxes/lox.tmLanguage.json"
}
}],
"out": "src/language/generated"
Expand Down
12 changes: 7 additions & 5 deletions examples/lox/src/language/lox-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@
* terms of the MIT License, which is available in the project root.
******************************************************************************/

import { DefaultSharedCoreModuleContext, LangiumCoreServices, LangiumSharedCoreServices, Module, PartialLangiumCoreServices, createDefaultCoreModule, createDefaultSharedCoreModule, inject } from 'langium';
import { Module, PartialLangiumCoreServices, createDefaultCoreModule, inject } from 'langium';
import { DefaultSharedModuleContext, LangiumServices, LangiumSharedServices, createDefaultSharedModule } from 'langium/lsp';
import { LangiumServicesForTypirBinding, createLangiumModuleForTypirBinding, initializeLangiumTypirServices } from 'typir-langium';
import { LoxGeneratedModule, LoxGeneratedSharedModule } from './generated/module.js';
import { LoxScopeProvider } from './lox-scope.js';
import { LoxValidationRegistry, LoxValidator } from './lox-validator.js';
import { DefaultSharedModuleContext, LangiumServices, LangiumSharedServices, createDefaultSharedModule } from 'langium/lsp';
import { createLangiumModuleForTypirBinding, initializeLangiumTypirServices, LangiumServicesForTypirBinding } from 'typir-langium';
import { createLoxTypirModule } from './type-system/lox-type-checking.js';
import { registerValidationChecks } from 'langium/grammar';

/**
* Declaration of custom services - add your own service classes here.
Expand Down Expand Up @@ -54,6 +53,9 @@ export const LoxModule: Module<LoxServices, PartialLangiumCoreServices & LoxAdde
* - Langium default language-specific services
* - Services generated by langium-cli
* - Services specified in this file
* For type checking with Typir, merge two more modules:
* - Typir default services
* - custom services for LOX
*
* @param context Optional module context with the LSP connection
* @returns An object wrapping the shared services and the language-specific services
Expand All @@ -69,8 +71,8 @@ export function createLoxServices(context: DefaultSharedModuleContext): {
const Lox = inject(
createDefaultCoreModule({ shared }),
LoxGeneratedModule,
createLangiumModuleForTypirBinding(shared),
LoxModule,
createLangiumModuleForTypirBinding(shared),
createLoxTypirModule(shared),
);
shared.ServiceRegistry.register(Lox);
Expand Down
8 changes: 4 additions & 4 deletions examples/lox/src/language/lox-scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
* terms of the MIT License, which is available in the project root.
******************************************************************************/

import { DefaultScopeProvider, EMPTY_SCOPE, AstUtils, ReferenceInfo, Scope, LangiumCoreServices } from "langium";
import { Class, isClass, MemberCall } from "./generated/ast.js";
import { isClassType } from "./type-system/descriptions.js";
import { getClassChain, inferType } from "./type-system/infer.js";
import { DefaultScopeProvider, EMPTY_SCOPE, AstUtils, ReferenceInfo, Scope, LangiumCoreServices } from 'langium';
import { Class, isClass, MemberCall } from './generated/ast.js';
import { isClassType } from './type-system/descriptions.js';
import { getClassChain, inferType } from './type-system/infer.js';

export class LoxScopeProvider extends DefaultScopeProvider {

Expand Down
37 changes: 2 additions & 35 deletions examples/lox/src/language/lox-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@
* terms of the MIT License, which is available in the project root.
******************************************************************************/

import { AstNode, ValidationAcceptor, ValidationChecks, ValidationRegistry } from 'langium';
import { BinaryExpression, LoxAstType, VariableDeclaration } from './generated/ast.js';
import { ValidationAcceptor, ValidationChecks, ValidationRegistry } from 'langium';
import { LoxAstType, VariableDeclaration } from './generated/ast.js';
import type { LoxServices } from './lox-module.js';
import { TypeDescription } from './type-system/descriptions.js';
import { inferType } from './type-system/infer.js';
import { isLegalOperation } from './type-system/operator.js';

/**
* Registry for validation checks.
Expand All @@ -19,7 +16,6 @@ export class LoxValidationRegistry extends ValidationRegistry {
super(services);
const validator = services.validation.LoxValidator;
const checks: ValidationChecks<LoxAstType> = {
BinaryExpression: validator.checkBinaryOperationAllowed,
VariableDeclaration: validator.checkVariableDeclaration,
};
this.register(checks, validator);
Expand All @@ -41,33 +37,4 @@ export class LoxValidator {
}
}

checkBinaryOperationAllowed(binary: BinaryExpression, accept: ValidationAcceptor): void {
const map = this.getTypeCache();
const left = inferType(binary.left, map);
const right = inferType(binary.right, map);
if (!isLegalOperation(binary.operator, left, right)) {
// accept('error', `Cannot perform operation '${binary.operator}' on values of type '${typeToString(left)}' and '${typeToString(right)}'.`, {
// node: binary
// })
} else if (binary.operator === '=') {
// if (!isAssignable(right, left)) {
// accept('error', `Type '${typeToString(right)}' is not assignable to type '${typeToString(left)}'.`, {
// node: binary,
// property: 'right'
// })
// }
} else if (['==', '!='].includes(binary.operator)) {
// if (!isAssignable(right, left)) {
// accept('warning', `This comparison will always return '${binary.operator === '==' ? 'false' : 'true'}' as types '${typeToString(left)}' and '${typeToString(right)}' are not compatible.`, {
// node: binary,
// property: 'operator'
// });
// }
}
}

private getTypeCache(): Map<AstNode, TypeDescription> {
return new Map();
}

}
4 changes: 2 additions & 2 deletions examples/lox/src/language/type-system/assignment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/
import { isClassType, isFunctionType, isNilType, TypeDescription } from "./descriptions.js";
import { getClassChain } from "./infer.js";
import { isClassType, isFunctionType, isNilType, TypeDescription } from './descriptions.js';
import { getClassChain } from './infer.js';

export function isAssignable(from: TypeDescription, to: TypeDescription): boolean {
if (isClassType(from)) {
Expand Down
54 changes: 27 additions & 27 deletions examples/lox/src/language/type-system/descriptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
* terms of the MIT License, which is available in the project root.
******************************************************************************/

import { AstNode } from "langium";
import { BooleanLiteral, Class, NumberLiteral, StringLiteral } from "../generated/ast.js"
import { AstNode } from 'langium';
import { BooleanLiteral, Class, NumberLiteral, StringLiteral } from '../generated/ast.js';

export type TypeDescription =
| NilTypeDescription
Expand All @@ -18,83 +18,83 @@ export type TypeDescription =
| ErrorType;

export interface NilTypeDescription {
readonly $type: "nil"
readonly $type: 'nil'
}

export function createNilType(): NilTypeDescription {
return {
$type: "nil"
$type: 'nil'
};
}

export function isNilType(item: TypeDescription): item is NilTypeDescription {
return item.$type === "nil";
return item.$type === 'nil';
}

export interface VoidTypeDescription {
readonly $type: "void"
readonly $type: 'void'
}

export function createVoidType(): VoidTypeDescription {
return {
$type: "void"
}
$type: 'void'
};
}

export function isVoidType(item: TypeDescription): item is VoidTypeDescription {
return item.$type === "void";
return item.$type === 'void';
}

export interface BooleanTypeDescription {
readonly $type: "boolean"
readonly $type: 'boolean'
readonly literal?: BooleanLiteral
}

export function createBooleanType(literal?: BooleanLiteral): BooleanTypeDescription {
return {
$type: "boolean",
$type: 'boolean',
literal
};
}

export function isBooleanType(item: TypeDescription): item is BooleanTypeDescription {
return item.$type === "boolean";
return item.$type === 'boolean';
}

export interface StringTypeDescription {
readonly $type: "string"
readonly $type: 'string'
readonly literal?: StringLiteral
}

export function createStringType(literal?: StringLiteral): StringTypeDescription {
return {
$type: "string",
$type: 'string',
literal
};
}

export function isStringType(item: TypeDescription): item is StringTypeDescription {
return item.$type === "string";
return item.$type === 'string';
}

export interface NumberTypeDescription {
readonly $type: "number",
readonly $type: 'number',
readonly literal?: NumberLiteral
}

export function createNumberType(literal?: NumberLiteral): NumberTypeDescription {
return {
$type: "number",
$type: 'number',
literal
};
}

export function isNumberType(item: TypeDescription): item is NumberTypeDescription {
return item.$type === "number";
return item.$type === 'number';
}

export interface FunctionTypeDescription {
readonly $type: "function"
readonly $type: 'function'
readonly returnType: TypeDescription
readonly parameters: FunctionParameter[]
}
Expand All @@ -106,48 +106,48 @@ export interface FunctionParameter {

export function createFunctionType(returnType: TypeDescription, parameters: FunctionParameter[]): FunctionTypeDescription {
return {
$type: "function",
$type: 'function',
parameters,
returnType
};
}

export function isFunctionType(item: TypeDescription): item is FunctionTypeDescription {
return item.$type === "function";
return item.$type === 'function';
}

export interface ClassTypeDescription {
readonly $type: "class"
readonly $type: 'class'
readonly literal: Class
}

export function createClassType(literal: Class): ClassTypeDescription {
return {
$type: "class",
$type: 'class',
literal
};
}

export function isClassType(item: TypeDescription): item is ClassTypeDescription {
return item.$type === "class";
return item.$type === 'class';
}

export interface ErrorType {
readonly $type: "error"
readonly $type: 'error'
readonly source?: AstNode
readonly message: string
}

export function createErrorType(message: string, source?: AstNode): ErrorType {
return {
$type: "error",
$type: 'error',
message,
source
};
}

export function isErrorType(item: TypeDescription): item is ErrorType {
return item.$type === "error";
return item.$type === 'error';
}

export function typeToString(item: TypeDescription): string {
Expand Down
6 changes: 3 additions & 3 deletions examples/lox/src/language/type-system/infer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
* terms of the MIT License, which is available in the project root.
******************************************************************************/

import { AstNode } from "langium";
import { BinaryExpression, Class, isBinaryExpression, isBooleanLiteral, isClass, isFieldMember, isFunctionDeclaration, isMemberCall, isMethodMember, isNilLiteral, isNumberLiteral, isParameter, isPrintStatement, isReturnStatement, isStringLiteral, isTypeReference, isUnaryExpression, isVariableDeclaration, MemberCall, TypeReference } from "../generated/ast.js";
import { createBooleanType, createClassType, createErrorType, createFunctionType, createNilType, createNumberType, createStringType, createVoidType, isFunctionType, isStringType, TypeDescription } from "./descriptions.js";
import { AstNode } from 'langium';
import { BinaryExpression, Class, isBinaryExpression, isBooleanLiteral, isClass, isFieldMember, isFunctionDeclaration, isMemberCall, isMethodMember, isNilLiteral, isNumberLiteral, isParameter, isPrintStatement, isReturnStatement, isStringLiteral, isTypeReference, isUnaryExpression, isVariableDeclaration, MemberCall, TypeReference } from '../generated/ast.js';
import { createBooleanType, createClassType, createErrorType, createFunctionType, createNilType, createNumberType, createStringType, createVoidType, isFunctionType, isStringType, TypeDescription } from './descriptions.js';

export function inferType(node: AstNode | undefined, cache: Map<AstNode, TypeDescription>): TypeDescription {
let type: TypeDescription | undefined;
Expand Down
Loading

0 comments on commit 857339a

Please sign in to comment.