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

Add Load and Activate Real Time Commands to SeqN #1543

Merged
merged 7 commits into from
Jan 3, 2025
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
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"dependencies": {
"@fontsource/jetbrains-mono": "^5.0.19",
"@nasa-jpl/aerie-ampcs": "^1.0.5",
"@nasa-jpl/seq-json-schema": "^1.0.20",
"@nasa-jpl/seq-json-schema": "^1.2.0",
"@nasa-jpl/stellar": "^1.1.18",
"@streamparser/json": "^0.0.17",
"@sveltejs/adapter-node": "5.0.1",
Expand Down
4 changes: 2 additions & 2 deletions src/utilities/codemirror/sequence.grammar
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ Command {
Models?
}

Activate { TimeTag activateDirective commonLoadActivate }
Activate { TimeTag? activateDirective commonLoadActivate }

Load { TimeTag loadDirective commonLoadActivate }
Load { TimeTag? loadDirective commonLoadActivate }

commonLoadActivate {
"(" SequenceName { String } ")"
Expand Down
25 changes: 25 additions & 0 deletions src/utilities/sequence-editor/from-seq-json.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -461,16 +461,38 @@ C FSW_CMD_2 10 "ENUM" # fsw cmd 2 description
description: 'immediate command',
metadata: {},
stem: 'IC',
type: 'immediate_command',
},
{
args: [],
stem: 'IC2',
type: 'immediate_command',
},
{
args: [],
description: 'noop command, no arguments',
metadata: { processor: 'VC1A' },
stem: 'NOOP',
type: 'immediate_command',
},
{
args: [
{
type: 'string',
value: 'hi',
},
],
description: 'description',
metadata: {
Key: 'Value',
},
sequence: 'seqA',
type: 'immediate_load',
},
{
description: 'description',
sequence: 'seqB',
type: 'immediate_activate',
},
],
metadata: {},
Expand All @@ -484,6 +506,9 @@ IC "1" 2 3 # immediate command
IC2
NOOP # noop command, no arguments
@METADATA "processor" "VC1A"
@LOAD("seqA") "hi" # description
@METADATA "Key" "Value"
@ACTIVATE("seqB") # description
`;
expect(sequence).toEqual(expectedSequence);
});
Expand Down
66 changes: 47 additions & 19 deletions src/utilities/sequence-editor/from-seq-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import type {
GroundBlock,
GroundEvent,
HexArgument,
ImmediateActivate,
ImmediateFswCommand,
ImmediateLoad,
Load,
Metadata,
Model,
Expand Down Expand Up @@ -205,18 +208,22 @@ export async function seqJsonToSequence(input: string | null): Promise<string> {
if (seqJson.immediate_commands) {
sequence.push(`\n`);
sequence.push(`@IMMEDIATE\n`);
for (const icmd of seqJson.immediate_commands) {
const args = seqJsonArgsToSequence(icmd.args);
const description = icmd.description ? seqJsonDescriptionToSequence(icmd.description) : '';
const metadata = icmd.metadata ? seqJsonMetadataToSequence(icmd.metadata) : '';
let immediateString = `${icmd.stem}${args}${description}`;
// add a new line if on doesn't exit at the end of the immediateString
if (!immediateString.endsWith('\n')) {
immediateString += '\n';
for (const realTimeCommand of seqJson.immediate_commands) {
switch (realTimeCommand.type) {
case 'immediate_command': {
// FSW Commands
sequence.push(commandToString(realTimeCommand));
break;
}
case 'immediate_activate':
case 'immediate_load': {
sequence.push(loadOrActivateToString(realTimeCommand));
break;
}
default: {
throw new Error(`Invalid immediate command type ${realTimeCommand.type}`);
}
}
// Add metadata data if it exists
immediateString += metadata;
sequence.push(immediateString);
}
}

Expand Down Expand Up @@ -250,14 +257,24 @@ export async function seqJsonToSequence(input: string | null): Promise<string> {
return sequence.join('');
}

function commandToString(step: Command) {
const time = seqJsonTimeToSequence(step.time);
function isCommand(step: Command | ImmediateFswCommand): step is Command {
return (step as Command).time !== undefined;
}

function commandToString(step: Command | ImmediateFswCommand): string {
const args = seqJsonArgsToSequence(step.args);
const metadata = step.metadata ? seqJsonMetadataToSequence(step.metadata) : '';
const models = step.models ? seqJsonModelsToSequence(step.models) : '';
const description = step.description ? seqJsonDescriptionToSequence(step.description) : '';

let commandString = `${time} ${step.stem}${args}${description}`;
// used for commands, ImmediateFswCommand doesn't support 'time' and 'models'
let time = '';
let models = '';
if (isCommand(step)) {
time = step.time ? `${seqJsonTimeToSequence(step.time)} ` : '';
models = step.models ? (step.models ? seqJsonModelsToSequence(step.models) : '') : '';
}

let commandString = `${time}${step.stem}${args}${description}`;
// add a new line if on doesn't exit at the end of the commandString
if (!commandString.endsWith('\n')) {
commandString += '\n';
Expand All @@ -267,16 +284,27 @@ function commandToString(step: Command) {
return commandString;
}

function loadOrActivateToString(step: Activate | Load) {
const time = seqJsonTimeToSequence(step.time);
function loadOrActivateToString(step: Activate | Load | ImmediateActivate | ImmediateLoad) {
const time = (step as Activate | Load).time ? `${seqJsonTimeToSequence((step as Activate | Load).time)} ` : '';
const args = step.args ? seqJsonArgsToSequence(step.args) : '';
const metadata = step.metadata ? seqJsonMetadataToSequence(step.metadata) : '';
const models = step.models ? seqJsonModelsToSequence(step.models) : '';
const engine = step.engine !== undefined ? `@ENGINE ${step.engine.toString(10)}\n` : '';
const epoch = step.epoch !== undefined ? `@EPOCH ${quoteEscape(step.epoch)}\n` : '';
const description = step.description ? seqJsonDescriptionToSequence(step.description) : '';
const stepType = `@${step.type === 'activate' ? 'ACTIVATE' : 'LOAD'}(${quoteEscape(step.sequence)})`;
let stepString = `${time} ${stepType}${args}${description}`;
let stepType = '';
switch (step.type) {
case 'activate':
case 'immediate_activate':
stepType = '@ACTIVATE';
break;
case 'load':
case 'immediate_load':
stepType = '@LOAD';
break;
}
stepType += `(${quoteEscape(step.sequence)})`;
let stepString = `${time}${stepType}${args}${description}`;
if (!stepString.endsWith('\n')) {
stepString += '\n';
}
Expand Down
33 changes: 19 additions & 14 deletions src/utilities/sequence-editor/sequence-completion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,8 @@ function generateHardwareCompletions(commandDictionary: CommandDictionary | null
}

function generateStepCompletion(cursor: CursorInfo): Completion[] {
// if cursor is at the LineComment/Description don't show the command completions list
if (cursor.isAtLineComment || !cursor.isBeforeHDWCommands || !cursor.isBeforeImmedOrHDWCommands) {
// if cursor is at the LineComment/Description after hardware commands don't show the command completions list
if (cursor.isAtLineComment || !cursor.isBeforeHDWCommands) {
return [];
}

Expand All @@ -397,13 +397,13 @@ function generateStepCompletion(cursor: CursorInfo): Completion[] {
view.dispatch({
changes: {
from: Math.max(0, from + (!cursor.isAfterTimeTag || cursor.isAtSymbolBefore ? -1 : 0)),
insert: `${!cursor.isAfterTimeTag ? 'C ' : ''}@GROUND_EVENT("ground_event.name")`,
insert: `${!cursor.isAfterTimeTag && cursor.isBeforeImmedOrHDWCommands ? 'C ' : ''}@ACTIVATE("activate.name")`,
to,
},
});
},
info: 'ground event command',
label: '@GROUND_EVENT',
info: 'activate command',
label: '@ACTIVATE',
section: 'Ground Commands',
type: 'function',
});
Expand All @@ -413,29 +413,34 @@ function generateStepCompletion(cursor: CursorInfo): Completion[] {
view.dispatch({
changes: {
from: Math.max(0, from + (!cursor.isAfterTimeTag || cursor.isAtSymbolBefore ? -1 : 0)),
insert: `${!cursor.isAfterTimeTag ? 'C ' : ''}@GROUND_BLOCK("ground_block.name")`,
insert: `${!cursor.isAfterTimeTag && cursor.isBeforeImmedOrHDWCommands ? 'C ' : ''}@LOAD("load.name")`,
to,
},
});
},
info: 'ground block command',
label: '@GROUND_BLOCK',
info: 'load command',
label: '@LOAD',
section: 'Ground Commands',
type: 'function',
});

// if after immediate commands don't show the command completions list below
if (!cursor.isBeforeImmedOrHDWCommands) {
return stepCompletion;
}

stepCompletion.push({
apply: (view, _completion, from: number, to: number) => {
view.dispatch({
changes: {
from: Math.max(0, from + (!cursor.isAfterTimeTag || cursor.isAtSymbolBefore ? -1 : 0)),
insert: `${!cursor.isAfterTimeTag ? 'C ' : ''}@ACTIVATE("activate.name")`,
insert: `${!cursor.isAfterTimeTag ? 'C ' : ''}@GROUND_EVENT("ground_event.name")`,
to,
},
});
},
info: 'activate command',
label: '@ACTIVATE',
info: 'ground event command',
label: '@GROUND_EVENT',
section: 'Ground Commands',
type: 'function',
});
Expand All @@ -445,13 +450,13 @@ function generateStepCompletion(cursor: CursorInfo): Completion[] {
view.dispatch({
changes: {
from: Math.max(0, from + (!cursor.isAfterTimeTag || cursor.isAtSymbolBefore ? -1 : 0)),
insert: `${!cursor.isAfterTimeTag ? 'C ' : ''}@LOAD("load.name")`,
insert: `${!cursor.isAfterTimeTag ? 'C ' : ''}@GROUND_BLOCK("ground_block.name")`,
to,
},
});
},
info: 'load command',
label: '@LOAD',
info: 'ground block command',
label: '@GROUND_BLOCK',
section: 'Ground Commands',
type: 'function',
});
Expand Down
18 changes: 16 additions & 2 deletions src/utilities/sequence-editor/sequence-linter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,11 @@ export function sequenceLinter(
if (commandsNode) {
diagnostics.push(
...commandLinter(
commandsNode.getChildren(TOKEN_COMMAND),
[
...commandsNode.getChildren(TOKEN_COMMAND),
...commandsNode.getChildren(TOKEN_LOAD), // TODO: remove in the library sequence PR because that check should validate load and activates
...commandsNode.getChildren(TOKEN_ACTIVATE), // TODO: remove in the library sequence PR because that check should validate load and activates
],
docText,
variableMap,
commandDictionary,
Expand All @@ -155,7 +159,11 @@ export function sequenceLinter(

diagnostics.push(
...immediateCommandLinter(
treeNode.getChild('ImmediateCommands')?.getChildren(TOKEN_COMMAND) || [],
[
...(treeNode.getChild('ImmediateCommands')?.getChildren(TOKEN_COMMAND) || []),
...(treeNode.getChild('ImmediateCommands')?.getChildren(TOKEN_LOAD) || []),
...(treeNode.getChild('ImmediateCommands')?.getChildren(TOKEN_ACTIVATE) || []),
],
docText,
variableMap,
commandDictionary,
Expand Down Expand Up @@ -693,6 +701,12 @@ function commandLinter(
// Get the TimeTag node for the current command
diagnostics.push(...validateTimeTags(command, text));

// TODO: remove in the library sequence PR because that check should validate
// load and activates
if (command.name === TOKEN_ACTIVATE || command.name === TOKEN_LOAD) {
continue;
}

// Validate the command and push the generated diagnostics to the array
diagnostics.push(
...validateCommand(
Expand Down
43 changes: 43 additions & 0 deletions src/utilities/sequence-editor/to-seq-json.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,49 @@ HDW_CMD`;
expect(actual).toEqual(expectedJson);
});

it('immediate command', async () => {
const seq = `@IMMEDIATE
ECHO "hello"
# activate sequences
@LOAD("seqA")
@ACTIVATE("seqB") 10 #description`;
const id = 'test';
const expectedJson = {
id: 'test',
immediate_commands: [
{
args: [
{
type: 'string',
value: 'hello',
},
],
stem: 'ECHO',
type: 'immediate_command',
},
{
args: [],
sequence: 'seqA',
type: 'immediate_load',
},
{
args: [
{
type: 'number',
value: 10,
},
],
description: 'description',
sequence: 'seqB',
type: 'immediate_activate',
},
],
metadata: {},
};
const actual = JSON.parse(await sequenceToSeqJson(SeqLanguage.parser.parse(seq), seq, commandDictionary, id));
expect(actual).toEqual(expectedJson);
});

it('multiple hardware commands', async () => {
const seq = `@HARDWARE
HDW_CMD_1
Expand Down
Loading
Loading