cleaned up
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
package index
|
package index
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/marte-dev/marte-dev-tools/internal/parser"
|
"github.com/marte-dev/marte-dev-tools/internal/parser"
|
||||||
@@ -31,8 +33,8 @@ type ProjectNode struct {
|
|||||||
type Fragment struct {
|
type Fragment struct {
|
||||||
File string
|
File string
|
||||||
Definitions []parser.Definition
|
Definitions []parser.Definition
|
||||||
IsObject bool
|
IsObject bool
|
||||||
ObjectPos parser.Position
|
ObjectPos parser.Position
|
||||||
Doc string // Documentation for this fragment (if object)
|
Doc string // Documentation for this fragment (if object)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +85,7 @@ func (pt *ProjectTree) removeFileFromNode(node *ProjectNode, file string) {
|
|||||||
node.Doc += frag.Doc
|
node.Doc += frag.Doc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-aggregate metadata
|
// Re-aggregate metadata
|
||||||
node.Metadata = make(map[string]string)
|
node.Metadata = make(map[string]string)
|
||||||
pt.rebuildMetadata(node)
|
pt.rebuildMetadata(node)
|
||||||
@@ -114,7 +116,7 @@ func (pt *ProjectTree) extractFieldMetadata(node *ProjectNode, f *parser.Field)
|
|||||||
case *parser.IntValue:
|
case *parser.IntValue:
|
||||||
val = v.Raw
|
val = v.Raw
|
||||||
}
|
}
|
||||||
|
|
||||||
if val == "" {
|
if val == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -126,7 +128,7 @@ func (pt *ProjectTree) extractFieldMetadata(node *ProjectNode, f *parser.Field)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pt *ProjectTree) AddFile(file string, config *parser.Configuration) {
|
func (pt *ProjectTree) AddFile(file string, config *parser.Configuration) {
|
||||||
pt.RemoveFile(file)
|
pt.RemoveFile(file)
|
||||||
|
|
||||||
node := pt.Root
|
node := pt.Root
|
||||||
if config.Package != nil {
|
if config.Package != nil {
|
||||||
@@ -139,7 +141,7 @@ func (pt *ProjectTree) AddFile(file string, config *parser.Configuration) {
|
|||||||
if _, ok := node.Children[part]; !ok {
|
if _, ok := node.Children[part]; !ok {
|
||||||
node.Children[part] = &ProjectNode{
|
node.Children[part] = &ProjectNode{
|
||||||
Name: part,
|
Name: part,
|
||||||
RealName: part,
|
RealName: part,
|
||||||
Children: make(map[string]*ProjectNode),
|
Children: make(map[string]*ProjectNode),
|
||||||
Parent: node,
|
Parent: node,
|
||||||
Metadata: make(map[string]string),
|
Metadata: make(map[string]string),
|
||||||
@@ -153,10 +155,10 @@ func (pt *ProjectTree) AddFile(file string, config *parser.Configuration) {
|
|||||||
File: file,
|
File: file,
|
||||||
IsObject: false,
|
IsObject: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, def := range config.Definitions {
|
for _, def := range config.Definitions {
|
||||||
doc := pt.findDoc(config.Comments, def.Pos())
|
doc := pt.findDoc(config.Comments, def.Pos())
|
||||||
|
|
||||||
switch d := def.(type) {
|
switch d := def.(type) {
|
||||||
case *parser.Field:
|
case *parser.Field:
|
||||||
fileFragment.Definitions = append(fileFragment.Definitions, d)
|
fileFragment.Definitions = append(fileFragment.Definitions, d)
|
||||||
@@ -177,18 +179,18 @@ func (pt *ProjectTree) AddFile(file string, config *parser.Configuration) {
|
|||||||
if child.RealName == norm && d.Name != norm {
|
if child.RealName == norm && d.Name != norm {
|
||||||
child.RealName = d.Name
|
child.RealName = d.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
if doc != "" {
|
if doc != "" {
|
||||||
if child.Doc != "" {
|
if child.Doc != "" {
|
||||||
child.Doc += "\n\n"
|
child.Doc += "\n\n"
|
||||||
}
|
}
|
||||||
child.Doc += doc
|
child.Doc += doc
|
||||||
}
|
}
|
||||||
|
|
||||||
pt.addObjectFragment(child, file, d, doc, config.Comments)
|
pt.addObjectFragment(child, file, d, doc, config.Comments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(fileFragment.Definitions) > 0 {
|
if len(fileFragment.Definitions) > 0 {
|
||||||
node.Fragments = append(node.Fragments, fileFragment)
|
node.Fragments = append(node.Fragments, fileFragment)
|
||||||
}
|
}
|
||||||
@@ -196,15 +198,15 @@ func (pt *ProjectTree) AddFile(file string, config *parser.Configuration) {
|
|||||||
|
|
||||||
func (pt *ProjectTree) addObjectFragment(node *ProjectNode, file string, obj *parser.ObjectNode, doc string, comments []parser.Comment) {
|
func (pt *ProjectTree) addObjectFragment(node *ProjectNode, file string, obj *parser.ObjectNode, doc string, comments []parser.Comment) {
|
||||||
frag := &Fragment{
|
frag := &Fragment{
|
||||||
File: file,
|
File: file,
|
||||||
IsObject: true,
|
IsObject: true,
|
||||||
ObjectPos: obj.Position,
|
ObjectPos: obj.Position,
|
||||||
Doc: doc,
|
Doc: doc,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, def := range obj.Subnode.Definitions {
|
for _, def := range obj.Subnode.Definitions {
|
||||||
subDoc := pt.findDoc(comments, def.Pos())
|
subDoc := pt.findDoc(comments, def.Pos())
|
||||||
|
|
||||||
switch d := def.(type) {
|
switch d := def.(type) {
|
||||||
case *parser.Field:
|
case *parser.Field:
|
||||||
frag.Definitions = append(frag.Definitions, d)
|
frag.Definitions = append(frag.Definitions, d)
|
||||||
@@ -225,18 +227,18 @@ func (pt *ProjectTree) addObjectFragment(node *ProjectNode, file string, obj *pa
|
|||||||
if child.RealName == norm && d.Name != norm {
|
if child.RealName == norm && d.Name != norm {
|
||||||
child.RealName = d.Name
|
child.RealName = d.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
if subDoc != "" {
|
if subDoc != "" {
|
||||||
if child.Doc != "" {
|
if child.Doc != "" {
|
||||||
child.Doc += "\n\n"
|
child.Doc += "\n\n"
|
||||||
}
|
}
|
||||||
child.Doc += subDoc
|
child.Doc += subDoc
|
||||||
}
|
}
|
||||||
|
|
||||||
pt.addObjectFragment(child, file, d, subDoc, comments)
|
pt.addObjectFragment(child, file, d, subDoc, comments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node.Fragments = append(node.Fragments, frag)
|
node.Fragments = append(node.Fragments, frag)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,7 +246,7 @@ func (pt *ProjectTree) findDoc(comments []parser.Comment, pos parser.Position) s
|
|||||||
var docBuilder strings.Builder
|
var docBuilder strings.Builder
|
||||||
targetLine := pos.Line - 1
|
targetLine := pos.Line - 1
|
||||||
var docIndices []int
|
var docIndices []int
|
||||||
|
|
||||||
for i := len(comments) - 1; i >= 0; i-- {
|
for i := len(comments) - 1; i >= 0; i-- {
|
||||||
c := comments[i]
|
c := comments[i]
|
||||||
if c.Position.Line > pos.Line {
|
if c.Position.Line > pos.Line {
|
||||||
@@ -253,7 +255,7 @@ func (pt *ProjectTree) findDoc(comments []parser.Comment, pos parser.Position) s
|
|||||||
if c.Position.Line == pos.Line {
|
if c.Position.Line == pos.Line {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Position.Line == targetLine {
|
if c.Position.Line == targetLine {
|
||||||
if c.Doc {
|
if c.Doc {
|
||||||
docIndices = append(docIndices, i)
|
docIndices = append(docIndices, i)
|
||||||
@@ -265,7 +267,7 @@ func (pt *ProjectTree) findDoc(comments []parser.Comment, pos parser.Position) s
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := len(docIndices) - 1; i >= 0; i-- {
|
for i := len(docIndices) - 1; i >= 0; i-- {
|
||||||
txt := strings.TrimPrefix(comments[docIndices[i]].Text, "//#")
|
txt := strings.TrimPrefix(comments[docIndices[i]].Text, "//#")
|
||||||
txt = strings.TrimSpace(txt)
|
txt = strings.TrimSpace(txt)
|
||||||
@@ -274,7 +276,7 @@ func (pt *ProjectTree) findDoc(comments []parser.Comment, pos parser.Position) s
|
|||||||
}
|
}
|
||||||
docBuilder.WriteString(txt)
|
docBuilder.WriteString(txt)
|
||||||
}
|
}
|
||||||
|
|
||||||
return docBuilder.String()
|
return docBuilder.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,7 +321,9 @@ type QueryResult struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pt *ProjectTree) Query(file string, line, col int) *QueryResult {
|
func (pt *ProjectTree) Query(file string, line, col int) *QueryResult {
|
||||||
|
fmt.Fprintf(os.Stderr, "File: %s:%d:%d\n", file, line, col)
|
||||||
for i := range pt.References {
|
for i := range pt.References {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s\n", pt.Root.Name)
|
||||||
ref := &pt.References[i]
|
ref := &pt.References[i]
|
||||||
if ref.File == file {
|
if ref.File == file {
|
||||||
if line == ref.Position.Line && col >= ref.Position.Column && col < ref.Position.Column+len(ref.Name) {
|
if line == ref.Position.Line && col >= ref.Position.Column && col < ref.Position.Column+len(ref.Name) {
|
||||||
@@ -339,7 +343,7 @@ func (pt *ProjectTree) queryNode(node *ProjectNode, file string, line, col int)
|
|||||||
return &QueryResult{Node: node}
|
return &QueryResult{Node: node}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, def := range frag.Definitions {
|
for _, def := range frag.Definitions {
|
||||||
if f, ok := def.(*parser.Field); ok {
|
if f, ok := def.(*parser.Field); ok {
|
||||||
if line == f.Position.Line && col >= f.Position.Column && col < f.Position.Column+len(f.Name) {
|
if line == f.Position.Line && col >= f.Position.Column && col < f.Position.Column+len(f.Name) {
|
||||||
@@ -349,7 +353,7 @@ func (pt *ProjectTree) queryNode(node *ProjectNode, file string, line, col int)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, child := range node.Children {
|
for _, child := range node.Children {
|
||||||
if res := pt.queryNode(child, file, line, col); res != nil {
|
if res := pt.queryNode(child, file, line, col); res != nil {
|
||||||
return res
|
return res
|
||||||
|
|||||||
@@ -148,9 +148,16 @@ func handleMessage(msg *JsonRpcMessage) {
|
|||||||
case "textDocument/hover":
|
case "textDocument/hover":
|
||||||
var params HoverParams
|
var params HoverParams
|
||||||
if err := json.Unmarshal(msg.Params, ¶ms); err == nil {
|
if err := json.Unmarshal(msg.Params, ¶ms); err == nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Hover: %s:%d\n", params.TextDocument.URI, params.Position.Line)
|
||||||
res := handleHover(params)
|
res := handleHover(params)
|
||||||
|
if res != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Res: %v\n", res.Contents)
|
||||||
|
} else {
|
||||||
|
fmt.Fprint(os.Stderr, "Res: NIL\n")
|
||||||
|
}
|
||||||
respond(msg.ID, res)
|
respond(msg.ID, res)
|
||||||
} else {
|
} else {
|
||||||
|
fmt.Fprint(os.Stderr, "not recovered hover parameters\n")
|
||||||
respond(msg.ID, nil)
|
respond(msg.ID, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,6 +198,7 @@ func handleHover(params HoverParams) *Hover {
|
|||||||
|
|
||||||
res := tree.Query(path, line, col)
|
res := tree.Query(path, line, col)
|
||||||
if res == nil {
|
if res == nil {
|
||||||
|
fmt.Fprint(os.Stderr, "No object/node/reference found\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
135
specification.md
135
specification.md
@@ -10,6 +10,7 @@
|
|||||||
## CLI Commands
|
## CLI Commands
|
||||||
|
|
||||||
The executable should support the following subcommands:
|
The executable should support the following subcommands:
|
||||||
|
|
||||||
- `lsp`: Starts the Language Server Protocol server.
|
- `lsp`: Starts the Language Server Protocol server.
|
||||||
- `build`: Merges files with the same base namespace into a single output.
|
- `build`: Merges files with the same base namespace into a single output.
|
||||||
- `check`: Runs diagnostics and validations on the configuration files.
|
- `check`: Runs diagnostics and validations on the configuration files.
|
||||||
@@ -18,12 +19,13 @@ The executable should support the following subcommands:
|
|||||||
## LSP Features
|
## LSP Features
|
||||||
|
|
||||||
The LSP server should provide the following capabilities:
|
The LSP server should provide the following capabilities:
|
||||||
|
|
||||||
- **Diagnostics**: Report syntax errors and validation issues.
|
- **Diagnostics**: Report syntax errors and validation issues.
|
||||||
- **Hover Documentation**:
|
- **Hover Documentation**:
|
||||||
- **Objects**: Display `CLASS::Name` and any associated docstrings.
|
- **Objects**: Display `CLASS::Name` and any associated docstrings.
|
||||||
- **Signals**: Display `DataSource.Name TYPE (SIZE) [IN/OUT/INOUT]` along with docstrings.
|
- **Signals**: Display `DataSource.Name TYPE (SIZE) [IN/OUT/INOUT]` along with docstrings.
|
||||||
- **GAMs**: Show the list of States where the GAM is referenced.
|
- **GAMs**: Show the list of States where the GAM is referenced.
|
||||||
- **Referenced Signals**: Show the list of GAMs where the signal is referenced.
|
- **Referenced Signals**: Show the list of GAMs where the signal is referenced.
|
||||||
- **Go to Definition**: Jump to the definition of a reference, supporting navigation across any file in the current project.
|
- **Go to Definition**: Jump to the definition of a reference, supporting navigation across any file in the current project.
|
||||||
- **Go to References**: Find usages of a node or field, supporting navigation across any file in the current project.
|
- **Go to References**: Find usages of a node or field, supporting navigation across any file in the current project.
|
||||||
- **Code Completion**: Autocomplete fields, values, and references.
|
- **Code Completion**: Autocomplete fields, values, and references.
|
||||||
@@ -34,14 +36,14 @@ The LSP server should provide the following capabilities:
|
|||||||
- **File Extension**: `.marte`
|
- **File Extension**: `.marte`
|
||||||
- **Project Structure**: Files can be distributed across sub-folders.
|
- **Project Structure**: Files can be distributed across sub-folders.
|
||||||
- **Namespaces**: The `#package` macro defines the namespace for the file.
|
- **Namespaces**: The `#package` macro defines the namespace for the file.
|
||||||
- **Semantic**: `#package PROJECT.NODE` implies that all definitions within the file are treated as children/fields of the node `NODE`.
|
- **Semantic**: `#package PROJECT.NODE` implies that all definitions within the file are treated as children/fields of the node `NODE`.
|
||||||
- **URI Symbols**: The symbols `+` and `$` used for object nodes are **not** written in the URI of the `#package` macro (e.g., use `PROJECT.NODE` even if the node is defined as `+NODE`).
|
- **URI Symbols**: The symbols `+` and `$` used for object nodes are **not** written in the URI of the `#package` macro (e.g., use `PROJECT.NODE` even if the node is defined as `+NODE`).
|
||||||
- **Build Process**:
|
- **Build Process**:
|
||||||
- The build tool merges all files sharing the same base namespace.
|
- The build tool merges all files sharing the same base namespace.
|
||||||
- **Multi-File Nodes**: Nodes can be defined across multiple files. The build tool and validator must merge these definitions before processing.
|
- **Multi-File Nodes**: Nodes can be defined across multiple files. The build tool and validator must merge these definitions before processing.
|
||||||
- **Merging Order**: For objects defined across multiple files, the **first file** to be considered is the one containing the `Class` field definition.
|
- **Merging Order**: For objects defined across multiple files, the **first file** to be considered is the one containing the `Class` field definition.
|
||||||
- **Field Order**: Within a single file, the relative order of defined fields must be maintained.
|
- **Field Order**: Within a single file, the relative order of defined fields must be maintained.
|
||||||
- The LSP indexes only files belonging to the same project/namespace scope.
|
- The LSP indexes only files belonging to the same project/namespace scope.
|
||||||
- **Output**: The output format is the same as the input configuration but without the `#package` macro.
|
- **Output**: The output format is the same as the input configuration but without the `#package` macro.
|
||||||
|
|
||||||
## MARTe Configuration Language
|
## MARTe Configuration Language
|
||||||
@@ -73,7 +75,7 @@ The LSP server should provide the following capabilities:
|
|||||||
### Semantics
|
### Semantics
|
||||||
|
|
||||||
- **Nodes (`+` / `$`)**: The prefixes `+` and `$` indicate that the node represents an object.
|
- **Nodes (`+` / `$`)**: The prefixes `+` and `$` indicate that the node represents an object.
|
||||||
- **Constraint**: These nodes *must* contain a field named `Class` within their subnode definition.
|
- **Constraint**: These nodes _must_ contain a field named `Class` within their subnode definition.
|
||||||
- **Signals**: Signals are considered nodes but **not** objects. They do not require a `Class` field.
|
- **Signals**: Signals are considered nodes but **not** objects. They do not require a `Class` field.
|
||||||
- **Pragmas (`//!`)**: Used to suppress specific diagnostics. The developer can use these to explain why a rule is being ignored.
|
- **Pragmas (`//!`)**: Used to suppress specific diagnostics. The developer can use these to explain why a rule is being ignored.
|
||||||
- **Structure**: A configuration is composed by one or more definitions.
|
- **Structure**: A configuration is composed by one or more definitions.
|
||||||
@@ -81,47 +83,49 @@ The LSP server should provide the following capabilities:
|
|||||||
### Core MARTe Classes
|
### Core MARTe Classes
|
||||||
|
|
||||||
MARTe configurations typically involve several main categories of objects:
|
MARTe configurations typically involve several main categories of objects:
|
||||||
|
|
||||||
- **State Machine (`StateMachine`)**: Defines state machines and transition logic.
|
- **State Machine (`StateMachine`)**: Defines state machines and transition logic.
|
||||||
- **Real-Time Application (`RealTimeApplication`)**: Defines a real-time application, including its data sources, functions, states, and scheduler.
|
- **Real-Time Application (`RealTimeApplication`)**: Defines a real-time application, including its data sources, functions, states, and scheduler.
|
||||||
- **Data Source**: Multiple classes used to define input and/or output signal sources.
|
- **Data Source**: Multiple classes used to define input and/or output signal sources.
|
||||||
- **GAM (Generic Application Module)**: Multiple classes used to process signals.
|
- **GAM (Generic Application Module)**: Multiple classes used to process signals.
|
||||||
- **Constraint**: A GAM node must contain at least one `InputSignals` sub-node, one `OutputSignals` sub-node, or both.
|
- **Constraint**: A GAM node must contain at least one `InputSignals` sub-node, one `OutputSignals` sub-node, or both.
|
||||||
|
|
||||||
### Signals and Data Flow
|
### Signals and Data Flow
|
||||||
|
|
||||||
- **Signal Definition**:
|
- **Signal Definition**:
|
||||||
- **Explicit**: Signals defined within the `DataSource` definition.
|
- **Explicit**: Signals defined within the `DataSource` definition.
|
||||||
- **Implicit**: Signals defined only within a `GAM`, which are then automatically managed.
|
- **Implicit**: Signals defined only within a `GAM`, which are then automatically managed.
|
||||||
- **Requirements**:
|
- **Requirements**:
|
||||||
- All signal definitions **must** include a `Type` field with a valid value.
|
- All signal definitions **must** include a `Type` field with a valid value.
|
||||||
- **Size Information**: Signals can optionally include `NumberOfDimensions` and `NumberOfElements` fields. If not explicitly defined, these default to `1`.
|
- **Size Information**: Signals can optionally include `NumberOfDimensions` and `NumberOfElements` fields. If not explicitly defined, these default to `1`.
|
||||||
- **Extensibility**: Signal definitions can include additional fields as required by the specific application context.
|
- **Extensibility**: Signal definitions can include additional fields as required by the specific application context.
|
||||||
- **Signal Reference Syntax**:
|
- **Signal Reference Syntax**:
|
||||||
- Signals are referenced or defined in `InputSignals` or `OutputSignals` sub-nodes using one of the following formats:
|
- Signals are referenced or defined in `InputSignals` or `OutputSignals` sub-nodes using one of the following formats:
|
||||||
1. **Direct Reference**:
|
1. **Direct Reference**:
|
||||||
```
|
```
|
||||||
SIGNAL_NAME = {
|
SIGNAL_NAME = {
|
||||||
DataSource = SIGNAL_DATASOURCE
|
DataSource = SIGNAL_DATASOURCE
|
||||||
// Other fields if necessary
|
// Other fields if necessary
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
2. **Aliased Reference**:
|
2. **Aliased Reference**:
|
||||||
```
|
```
|
||||||
NAME = {
|
NAME = {
|
||||||
Alias = SIGNAL_NAME
|
Alias = SIGNAL_NAME
|
||||||
DataSource = SIGNAL_DATASOURCE
|
DataSource = SIGNAL_DATASOURCE
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
- **Implicit Definition Constraint**: If a signal is implicitly defined within a GAM, the `Type` field **must** be present in the reference block to define the signal's properties.
|
- **Implicit Definition Constraint**: If a signal is implicitly defined within a GAM, the `Type` field **must** be present in the reference block to define the signal's properties.
|
||||||
- **Directionality**: DataSources and their signals are directional:
|
- **Directionality**: DataSources and their signals are directional:
|
||||||
- `Input`: Only providing data.
|
- `Input`: Only providing data.
|
||||||
- `Output`: Only receiving data.
|
- `Output`: Only receiving data.
|
||||||
- `Inout`: Bidirectional data flow.
|
- `Inout`: Bidirectional data flow.
|
||||||
|
|
||||||
### Object Indexing & References
|
### Object Indexing & References
|
||||||
|
|
||||||
The tool must build an index of the configuration to support LSP features and validations:
|
The tool must build an index of the configuration to support LSP features and validations:
|
||||||
|
|
||||||
- **GAMs**: Referenced in `$APPLICATION.States.$STATE_NAME.Threads.$THREAD_NAME.Functions` (where `$APPLICATION` is a `RealTimeApplication` node).
|
- **GAMs**: Referenced in `$APPLICATION.States.$STATE_NAME.Threads.$THREAD_NAME.Functions` (where `$APPLICATION` is a `RealTimeApplication` node).
|
||||||
- **Signals**: Referenced within the `InputSignals` and `OutputSignals` sub-nodes of a GAM.
|
- **Signals**: Referenced within the `InputSignals` and `OutputSignals` sub-nodes of a GAM.
|
||||||
- **DataSources**: Referenced within the `DataSource` field of a signal reference/definition.
|
- **DataSources**: Referenced within the `DataSource` field of a signal reference/definition.
|
||||||
@@ -131,29 +135,30 @@ The tool must build an index of the configuration to support LSP features and va
|
|||||||
|
|
||||||
- **Consistency**: The `lsp`, `check`, and `build` commands **must share the same validation engine** to ensure consistent results across all tools.
|
- **Consistency**: The `lsp`, `check`, and `build` commands **must share the same validation engine** to ensure consistent results across all tools.
|
||||||
- **Class Validation**:
|
- **Class Validation**:
|
||||||
- For each known `Class`, the validator checks:
|
- For each known `Class`, the validator checks:
|
||||||
- **Mandatory Fields**: Verification that all required fields are present.
|
- **Mandatory Fields**: Verification that all required fields are present.
|
||||||
- **Field Types**: Verification that values assigned to fields match the expected types (e.g., `int`, `string`, `bool`).
|
- **Field Types**: Verification that values assigned to fields match the expected types (e.g., `int`, `string`, `bool`).
|
||||||
- **Field Order**: Verification that specific fields appear in a prescribed order when required by the class definition.
|
- **Field Order**: Verification that specific fields appear in a prescribed order when required by the class definition.
|
||||||
- **Conditional Fields**: Validation of fields whose presence or value depends on the values of other fields within the same node or context.
|
- **Conditional Fields**: Validation of fields whose presence or value depends on the values of other fields within the same node or context.
|
||||||
- **Schema Definition**:
|
- **Schema Definition**:
|
||||||
- Class validation rules must be defined in a separate schema file.
|
- Class validation rules must be defined in a separate schema file.
|
||||||
- **Project-Specific Classes**: Developers can define their own project-specific classes and corresponding validation rules, expanding the validation capabilities for their specific needs.
|
- **Project-Specific Classes**: Developers can define their own project-specific classes and corresponding validation rules, expanding the validation capabilities for their specific needs.
|
||||||
- **Duplicate Fields**:
|
- **Duplicate Fields**:
|
||||||
- **Constraint**: A field must not be defined more than once within the same object/node scope.
|
- **Constraint**: A field must not be defined more than once within the same object/node scope.
|
||||||
- **Multi-File Consideration**: Validation must account for nodes being defined across multiple files (merged) when checking for duplicates.
|
- **Multi-File Consideration**: Validation must account for nodes being defined across multiple files (merged) when checking for duplicates.
|
||||||
|
|
||||||
### Formatting Rules
|
### Formatting Rules
|
||||||
|
|
||||||
The `fmt` command must format the code according to the following rules:
|
The `fmt` command must format the code according to the following rules:
|
||||||
|
|
||||||
- **Indentation**: 2 spaces per indentation level.
|
- **Indentation**: 2 spaces per indentation level.
|
||||||
- **Assignment**: 1 space before and after the `=` operator (e.g., `Field = Value`).
|
- **Assignment**: 1 space before and after the `=` operator (e.g., `Field = Value`).
|
||||||
- **Comments**:
|
- **Comments**:
|
||||||
- 1 space after `//`, `//#`, or `//!`.
|
- 1 space after `//`, `//#`, or `//!`.
|
||||||
- Comments should "stick" to the next definition (no empty lines between the comment and the code it documents).
|
- Comments should "stick" to the next definition (no empty lines between the comment and the code it documents).
|
||||||
- **Placement**:
|
- **Placement**:
|
||||||
- Comments can be placed inline after a definition (e.g., `field = value // comment`).
|
- Comments can be placed inline after a definition (e.g., `field = value // comment`).
|
||||||
- Comments can be placed after a subnode opening bracket (e.g., `node = { // comment`) or after an object definition.
|
- Comments can be placed after a subnode opening bracket (e.g., `node = { // comment`) or after an object definition.
|
||||||
- **Arrays**: 1 space after the opening bracket `{` and 1 space before the closing bracket `}` (e.g., `{ 1 2 3 }`).
|
- **Arrays**: 1 space after the opening bracket `{` and 1 space before the closing bracket `}` (e.g., `{ 1 2 3 }`).
|
||||||
- **Strings**: Quoted strings must preserve their quotes during formatting.
|
- **Strings**: Quoted strings must preserve their quotes during formatting.
|
||||||
|
|
||||||
@@ -162,15 +167,15 @@ The `fmt` command must format the code according to the following rules:
|
|||||||
The LSP and `check` command should report the following:
|
The LSP and `check` command should report the following:
|
||||||
|
|
||||||
- **Warnings**:
|
- **Warnings**:
|
||||||
- **Unused GAM**: A GAM is defined but not referenced in any thread or scheduler.
|
- **Unused GAM**: A GAM is defined but not referenced in any thread or scheduler.
|
||||||
- **Unused Signal**: A signal is explicitly defined in a `DataSource` but never referenced in any `GAM`.
|
- **Unused Signal**: A signal is explicitly defined in a `DataSource` but never referenced in any `GAM`.
|
||||||
- **Implicitly Defined Signal**: A signal is defined only within a `GAM` and not in its parent `DataSource`.
|
- **Implicitly Defined Signal**: A signal is defined only within a `GAM` and not in its parent `DataSource`.
|
||||||
|
|
||||||
- **Errors**:
|
- **Errors**:
|
||||||
- **Type Inconsistency**: A signal is referenced with a type different from its definition.
|
- **Type Inconsistency**: A signal is referenced with a type different from its definition.
|
||||||
- **Size Inconsistency**: A signal is referenced with a size (dimensions/elements) different from its definition.
|
- **Size Inconsistency**: A signal is referenced with a size (dimensions/elements) different from its definition.
|
||||||
- **Duplicate Field Definition**: A field is defined multiple times within the same node scope (including across multiple files).
|
- **Duplicate Field Definition**: A field is defined multiple times within the same node scope (including across multiple files).
|
||||||
- **Validation Errors**:
|
- **Validation Errors**:
|
||||||
- Missing mandatory fields.
|
- Missing mandatory fields.
|
||||||
- Field type mismatches.
|
- Field type mismatches.
|
||||||
- Grammar errors (e.g., missing closing brackets).
|
- Grammar errors (e.g., missing closing brackets).
|
||||||
|
|||||||
@@ -8,4 +8,4 @@
|
|||||||
// Sticky comment
|
// Sticky comment
|
||||||
Field = 123
|
Field = 123
|
||||||
Array = {1 2 3}
|
Array = {1 2 3}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user