Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
alamarche committed Dec 2, 2023
2 parents 5081d65 + d465dc2 commit 57acb50
Show file tree
Hide file tree
Showing 18 changed files with 711 additions and 322 deletions.
121 changes: 121 additions & 0 deletions Langium_Notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Langium Notes

## Scope
A scope describes what targe elements are visible from a specific cross-reference context.
```typescript
**/**
* A scope describes what target elements are visible from a specific cross-reference context.
*/**
export interface Scope {

/**
* Find a target element matching the given name. If no element is found, `undefined` is returned.
* If multiple matching elements are present, the selection of the returned element should be done
* according to the semantics of your language. Usually it is the element that is most closely defined.
*
* @param name Name of the cross-reference target as it appears in the source text.
*/
getElement(name: string): AstNodeDescription | undefined;

/**
* Create a stream of all elements in the scope. This is used to compute completion proposals to be
* shown in the editor.
*/
getAllElements(): Stream<AstNodeDescription>;

}
```

StreamScope is the default implementation of the Scope interface - provides an outerScope that contains the next level of elements scoped if the target element isn't found in the current stream:

```typescript
/**
* The default scope implementation is based on a `Stream`. It has an optional _outer scope_ describing
* the next level of elements, which are queried when a target element is not found in the stream provided
* to this scope.
*/
export class StreamScope implements Scope {
readonly elements: Stream<AstNodeDescription>;
readonly outerScope?: Scope;
readonly caseInsensitive?: boolean;

constructor(elements: Stream<AstNodeDescription>, outerScope?: Scope, options?: ScopeOptions) {
this.elements = elements;
this.outerScope = outerScope;
this.caseInsensitive = options?.caseInsensitive;
}

getAllElements(): Stream<AstNodeDescription> {
if (this.outerScope) {
return this.elements.concat(this.outerScope.getAllElements());
} else {
return this.elements;
}
}

getElement(name: string): AstNodeDescription | undefined {
const local = this.caseInsensitive
? this.elements.find(e => e.name.toLowerCase() === name.toLowerCase())
: this.elements.find(e => e.name === name);
if (local) {
return local;
}
if (this.outerScope) {
return this.outerScope.getElement(name);
}
return undefined;
}
}
```
StreamScope objects are only used (by default) in the ScopeProvider service.
## ScopeProvider (Service)
A language-specific (i.e. varies between different defined languages) service for describing the elements visible in a specific cross-reference context (which element you're typing within).
* Basically determines whether a given reference
* Default Langium implementation is DefaultScopeProvider - automatically provided to the program if you don't provide your own. Uses `StreamScope` objects
* Default impl follows traditional variable namespacing. (e.g. inner-most nested objects can access toward the root, but cannot access its siblings and their nested objects)

## ScopeComputation (Service)
Language-specific service for precomputing global **AND** local scopes. The service methods are executed as the first and second phase in the `DocumentBuilder` (see [Document Lifecycle | Langium](https://langium.org/docs/document-lifecycle/)).
```typescript
/**
* Language-specific service for precomputing global and local scopes. The service methods are executed
* as the first and second phase in the `DocumentBuilder`.
*/
export interface ScopeComputation {

/**
* Creates descriptions of all AST nodes that shall be exported into the _global_ scope from the given
* document. These descriptions are gathered by the `IndexManager` and stored in the global index so
* they can be referenced from other documents.
*
* _Note:_ You should not resolve any cross-references in this service method. Cross-reference resolution
* depends on the scope computation phase to be completed (`computeScope` method), which runs after the
* initial indexing where this method is used.
*
* @param document The document from which to gather exported AST nodes.
* @param cancelToken Indicates when to cancel the current operation.
* @throws `OperationCanceled` if a user action occurs during execution
*/
computeExports(document: LangiumDocument, cancelToken?: CancellationToken): Promise<AstNodeDescription[]>;

/**
* Precomputes the _local_ scopes for a document, which are necessary for the default way of
* resolving references to symbols in the same document. The result is a multimap assigning a
* set of AST node descriptions to every level of the AST. These data are used by the `ScopeProvider`
* service to determine which target nodes are visible in the context of a specific cross-reference.
*
* _Note:_ You should not resolve any cross-references in this service method. Cross-reference
* resolution depends on the scope computation phase to be completed.
*
* @param document The document in which to compute scopes.
* @param cancelToken Indicates when to cancel the current operation.
* @throws `OperationCanceled` if a user action occurs during execution
*/
computeLocalScopes(document: LangiumDocument, cancelToken?: CancellationToken): Promise<PrecomputedScopes>;

}
```
ScopeComputation can be used to:
* Customize which elements can be cross-referenced globally and with what names (which element you are referencing from)
* e.g. in ReqSpec

Expand Down
2 changes: 2 additions & 0 deletions examples/categories.reqspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cat Regulatory : "Regulatory requirement"
cat NonRegulatory : "Non-regulatory requirement"
49 changes: 9 additions & 40 deletions examples/test1.reqspec → examples/goals.reqspec
Original file line number Diff line number Diff line change
@@ -1,21 +1,6 @@
cat Rofl : "Derp"
cat Lmao : "Herp"

developer Kevin {
name "Kevin Roger"
role "Systems Engineer"
}

developer Chief {
name "Chief Yankee"
role "Software Engineer"
}

stakeholder AppsDev {
desc "Applications Development"
email "[email protected]"
phone "(204)412-1293"
}

goal Goal0 : "Goal to be evolved"

Expand All @@ -32,17 +17,7 @@ goal Goal2 : "Another goal" {
rationale "Needs to produce sufficient power to be usable in heavy-duty trucking hybrids"
}

req Requirement0 : "This is a test req" {
desc "Lol"
id a2c5ab31-60b4-46b0-92fc-512c8001cd0b
see goal Goal1
cat Lmao, Rofl
}

req Requirement1 : "This is another test requirement" {
cat Lmao
mitigates Fire
}

goal set GoalSet1 : "This is the first goal set" {
desc "Derp"
Expand All @@ -51,14 +26,17 @@ goal set GoalSet1 : "This is the first goal set" {
refs goals Goal0, Goal1
}

req set ReqSet1 : "This is the first req set" {
desc "woooo!"
req ReqBelongingToSet : "A req instantiated within a set!"
references req Requirement0
see goal Goal1
issues "No issues whatsoever"
goal Derp : "Derpcity" {
id 159a00f8-0607-463c-84e6-dadb8e925cd2
cat Regulatory
desc "description"
rationale "rationale"
see goal Goal2
stakeholder AppsDev
}



goal doc SystemGoals : "System Goals Document" {
desc "These are the goals that the system should aspire to"
req UniqueRequirementWeForgot : "We can **~~define this inside the document~~** if we want" {
Expand All @@ -68,15 +46,6 @@ goal doc SystemGoals : "System Goals Document" {
ref goals Goal0
}

hazard Fire : "Generic fire with chance to spread"

comp MyFirstComponent : "First component!" {
ref func BlowAir
ref hazard Fire
}

func BlowAir : "Generic function that can be referenced"

goal TestGoal : "Yet another test" {
id f176d53e-e9f3-4de3-a99e-b95bad6ffb7d
cat Lmao
Expand Down
31 changes: 31 additions & 0 deletions examples/people.reqspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
developer SoftwareDeveloper {
id 3e8ff79d-35a5-4572-9aea-f1d710b3f6c1
name "Dev McDeverson"
title "Chief Developer"
role "Technical Project Lead"
email "[email protected]"
}

stakeholder MainCustomer {
id 82427bd9-7a6a-46a6-990d-104a6ba9b18a
name "Custer McCustomerson"
title "Project customer"
role "Drives customer needs"
email "[email protected]"
}

developer Kevin {
name "Kevin Roger"
role "Systems Engineer"
}

developer Chief {
name "Chief Yankee"
role "Software Engineer"
}

stakeholder AppsDev {
desc "Applications Development"
email "[email protected]"
phone "(204)412-1293"
}
8 changes: 8 additions & 0 deletions examples/physarch.reqspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
hazard Fire : "Generic fire with chance to spread"

comp MyFirstComponent : "First component!" {
ref func BlowAir
ref hazard Fire
}

func BlowAir : "Generic function that can be referenced"
Empty file added examples/requirements.reqspec
Empty file.
10 changes: 10 additions & 0 deletions examples/test1.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.. req:: This is a test req
:id: Requirement0
:tags: Lmao, Rofl
:referencedGoals: Goal1

.. req:: This is another test requirement
:id: Requirement1
:tags: Lmao
:mitigates: Fire

5 changes: 5 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest/presets/default-esm',
testEnvironment: 'node',
};
Loading

0 comments on commit 57acb50

Please sign in to comment.