Skip to content

Commit

Permalink
Merge pull request #279 from Code-Inspect/276-document-the-new-main-f…
Browse files Browse the repository at this point in the history
…lowr-script

document the new main flowr script
  • Loading branch information
EagleoutIce committed Sep 3, 2023
2 parents 71cb694 + dcf5203 commit 466e723
Show file tree
Hide file tree
Showing 12 changed files with 100 additions and 31 deletions.
5 changes: 5 additions & 0 deletions src/cli/repl/commands/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ import { guard } from '../../../util/assert'

type Version = `${number}.${number}.${number}`

/**
* Describes the version of flowR and the used R interpreter.
*/
export interface VersionInformation {
/** The version of flowR */
flowr: Version,
/** The version of R identified by the underlying {@link RShell} */
r: Version | 'unknown'
}

Expand Down
24 changes: 15 additions & 9 deletions src/cli/repl/server/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import { Socket } from './net'
import { serverLog } from './server'
import { ILogObj, Logger } from 'tslog'

export interface FlowRFileInformation {
filename: string,
slicer: SteppingSlicer
export interface FlowRFileOrRequestInformation {
filename?: string,
slicer: SteppingSlicer
}

export class FlowRServerConnection {
Expand All @@ -22,7 +22,7 @@ export class FlowRServerConnection {
private readonly logger: Logger<ILogObj>

// maps token to information
private readonly fileMap = new Map<string, FlowRFileInformation>()
private readonly fileMap = new Map<string, FlowRFileOrRequestInformation>()


// we do not have to ensure synchronized shell-access as we are always running synchronized
Expand Down Expand Up @@ -63,7 +63,7 @@ export class FlowRServerConnection {
id: request.message.id,
type: 'error',
fatal: true,
reason: `The message type ${JSON.stringify(request.type ?? 'undefined')} is not supported.`
reason: `The message type ${JSON.stringify(request.message.type ?? 'undefined')} is not supported.`

Check warning on line 66 in src/cli/repl/server/connection.ts

View workflow job for this annotation

GitHub Actions / Linting / flowr-action

Unnecessary conditional, expected left-hand side of `??` operator to be possibly null or undefined
})
this.socket.end()
}
Expand All @@ -76,7 +76,7 @@ export class FlowRServerConnection {
return
}
const message = requestResult.message
this.logger.info(`[${this.name}] Received file analysis request for ${message.filename} (token: ${message.filetoken})`)
this.logger.info(`[${this.name}] Received file analysis request for ${message.filename ?? 'unknown file'} (token: ${message.filetoken})`)

if(this.fileMap.has(message.filetoken)) {
this.logger.warn(`File token ${message.filetoken} already exists. Overwriting.`)
Expand All @@ -101,9 +101,15 @@ export class FlowRServerConnection {

void slicer.allRemainingSteps(false).then(results => {
sendMessage(this.socket, {
type: 'response-file-analysis',
id: message.id,
results
type: 'response-file-analysis',
id: message.id,
results: {
...results,
normalize: {
...results.normalize,
idMap: undefined
}
}
})
})
}
Expand Down
29 changes: 24 additions & 5 deletions src/cli/repl/server/messages/analysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,25 @@ import { FlowrBaseMessage, RequestMessageDefinition } from './messages'
import { LAST_PER_FILE_STEP, StepResults } from '../../../../core'
import Joi from 'joi'

/**
* Send by the client to request an analysis of a given file.
* Answered by either an {@link FlowrErrorMessage} or a {@link FileAnalysisResponseMessage}.
*/
export interface FileAnalysisRequestMessage extends FlowrBaseMessage {
type: 'request-file-analysis',
/**
* This is a unique token that you assign to subsequently slice the respective files.
* If you pass the same token multiple times, previous results will be overwritten.
*/
filetoken: string,
filename: string,
/** the contents of the file, give either this or the `filepath`. */
/**
* A human-readable file name. If you present a `filepath` or read from a file this should be straightforward.
* However, the name is only for debugging and bears no semantic meaning.
*/
filename?: string,
/** The contents of the file, or a R expression itself (like `1 + 1`), give either this or the `filepath`. */
content?: string
/** the filepath on the local machine, accessible to flowR, or simply. Give either this or the `content` */
/** The filepath on the local machine, accessible to flowR, or simply. Give either this or the `content` */
filepath?: string
}

Expand All @@ -23,15 +31,26 @@ export const requestAnalysisMessage: RequestMessageDefinition<FileAnalysisReques
type: Joi.string().valid('request-file-analysis').required(),
id: Joi.string().optional(),
filetoken: Joi.string().required(),
filename: Joi.string().required(),
filename: Joi.string().optional(),
content: Joi.string().optional(),
filepath: Joi.string().optional()
}).xor('content', 'filepath')
}


/**
* Answer for a successful {@link FileAnalysisRequestMessage}.
* It contains the results of the analysis in JSON format.
*
* The `idMap` of the normalization step (see {@link NormalizedAst}) is not serialized as it would essentially
* repeat the complete normalized AST.
*
* @note the serialization of maps and sets is controlled by the {@link jsonReplacer} as part of {@link sendMessage}.
*/
export interface FileAnalysisResponseMessage extends FlowrBaseMessage {
type: 'response-file-analysis',
/**
* See the {@link SteppingSlicer} and {@link StepResults} for details on the results.
*/
results: StepResults<typeof LAST_PER_FILE_STEP>
}

4 changes: 4 additions & 0 deletions src/cli/repl/server/messages/error.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { FlowrBaseMessage } from './messages'

/**
* Sent in case of any error (e.g., if the analysis fails, or the message contains syntax errors).
*/
export interface FlowrErrorMessage extends FlowrBaseMessage {
type: 'error',
/** if fatal, the connection will be partially closed afterward */
fatal: boolean,
/** the human-readable reason for the error */
reason: string
}
13 changes: 12 additions & 1 deletion src/cli/repl/server/messages/hello.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
import { VersionInformation } from '../../commands/version'
import { FlowrBaseMessage } from './messages'

/**
* The hello message is automatically send by the sever upon connection.
*/
export interface FlowrHelloResponseMessage extends FlowrBaseMessage {
type: 'hello',
/** The hello message never has an id, it is always undefined */
id: undefined,
/** a unique name assigned to each client it has no semantic meaning and is only used for debugging */
/**
* A unique name that is assigned to each client.
* It has no semantic meaning and is only used/useful for debugging.
*/
clientName: string,
/**
* Describes which versions are in use on the server.
* @see VersionInformation
*/
versions: VersionInformation
}

25 changes: 18 additions & 7 deletions src/cli/repl/server/messages/slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ import { LAST_PER_FILE_STEP, LAST_STEP, StepResults } from '../../../../core'
import { FlowrBaseMessage, RequestMessageDefinition } from './messages'
import Joi from 'joi'

/**
* Can only be sent after you have sent the {@link FileAnalysisRequestMessage}.
* Using the same `filetoken` as in the {@link FileAnalysisRequestMessage} you
* can slice the respective file given the respective criteria.
*/
export interface SliceRequestMessage extends FlowrBaseMessage {
type: 'request-slice',
/** The {@link FileAnalysisRequestMessage#filetoken} of the file to slice */
/** The {@link FileAnalysisRequestMessage#filetoken} of the file/data to slice */
filetoken: string,
/** The slicing criteria to use */
criterion: SlicingCriteria
}

export interface SliceResponseMessage extends FlowrBaseMessage {
type: 'response-slice',
/** only contains the results of the slice steps to not repeat ourselves */
results: Omit<StepResults<typeof LAST_STEP>, keyof StepResults<typeof LAST_PER_FILE_STEP>>
}

export const requestSliceMessage: RequestMessageDefinition<SliceRequestMessage> = {
type: 'request-slice',
schema: Joi.object({
Expand All @@ -25,3 +25,14 @@ export const requestSliceMessage: RequestMessageDefinition<SliceRequestMessage>
criterion: Joi.array().items(Joi.string().regex(/\d+:\d+|\d+@.*|\$\d+/)).min(0).required()
})
}


/**
* Similar to {@link FileAnalysisResponseMessage} this only contains the results of
* the slice steps.
*/
export interface SliceResponseMessage extends FlowrBaseMessage {
type: 'response-slice',
/** only contains the results of the slice steps to not repeat ourselves */
results: Omit<StepResults<typeof LAST_STEP>, keyof StepResults<typeof LAST_PER_FILE_STEP>>
}
16 changes: 12 additions & 4 deletions src/r-bridge/lang-4.x/ast/model/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,20 @@ import {
RIfThenElse,
RParameter,
RFunctionDefinition,
RRepeatLoop, RForLoop, RWhileLoop,
RComment, RFunctionCall, RBreak, RNext,
RArgument, RNamedAccess, RIndexAccess, RLineDirective
RRepeatLoop,
RForLoop,
RWhileLoop,
RComment,
RFunctionCall,
RBreak,
RNext,
RArgument,
RNamedAccess,
RIndexAccess,
RLineDirective,
RPipe
} from './nodes'
import { OtherInfoNode } from './nodes/info'
import { RPipe } from './nodes'

/** simply used as an empty interface with no information about additional decorations */
// eslint-disable-next-line @typescript-eslint/no-empty-interface
Expand Down
1 change: 1 addition & 0 deletions src/r-bridge/lang-4.x/ast/model/versions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
*/

export const MIN_VERSION_PIPE = "4.1.0"
export const MIN_VERSION_LAMBDA = "4.1.0"
4 changes: 3 additions & 1 deletion test/dataflow/elements/functions/function-call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { define, popLocalEnvironment, pushLocalEnvironment } from '../../../../s
import { UnnamedArgumentPrefix } from '../../../../src/dataflow/internal/process/functions/argument'
import { UnnamedFunctionCallPrefix } from '../../../../src/dataflow/internal/process/functions/functionCall'
import { LocalScope } from '../../../../src/dataflow/environments/scopes'
import { MIN_VERSION_LAMBDA } from '../../../../src/r-bridge/lang-4.x/ast/model/versions'

describe('Function Call', withShell(shell => {
describe('Calling previously defined functions', () => {
Expand Down Expand Up @@ -227,7 +228,8 @@ a(i)`, new DataflowGraph()
.addEdge('8', '0', EdgeType.DefinesOnCall, 'always')

assertDataflow('Calling with constant argument using lambda', shell, `(\\(x) { x + 1 })(2)`,
outGraph
outGraph,
{ minRVersion: MIN_VERSION_LAMBDA }
)
assertDataflow('Calling with constant argument', shell, `(function(x) { x + 1 })(2)`,
outGraph
Expand Down
4 changes: 3 additions & 1 deletion test/flowr/server.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { retrieveVersionInformation } from '../../src/cli/repl/commands/version'
import { FlowrHelloResponseMessage } from '../../src/cli/repl/server/messages/hello'
import { assert } from 'chai'
import { FileAnalysisResponseMessage } from '../../src/cli/repl/server/messages/analysis'
import { requestFromInput } from '../../src/r-bridge'
import { DecoratedAstMap, ParentInformation, requestFromInput } from '../../src/r-bridge'
import { LAST_PER_FILE_STEP, SteppingSlicer } from '../../src/core'
import { jsonReplacer } from '../../src/util/json'

Expand Down Expand Up @@ -49,6 +49,8 @@ describe('FlowR Server', withShell(shell => {
tokenMap: await defaultTokenMap(),
request: requestFromInput('1 + 1'),
}).allRemainingSteps()
// really ugly
results.normalize.idMap = undefined as unknown as DecoratedAstMap<ParentInformation>

assert.strictEqual(response.type, 'response-file-analysis', 'Expected the second message to be a response-file-analysis message')
assert.strictEqual(response.id, '42', 'Expected the second message to have the same id as the request')
Expand Down
2 changes: 1 addition & 1 deletion test/helper/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const RNumberPool: { val: RNumberValue, str: string }[] = [
{ str: '0x.p-5', val: { num: 0, complexNumber: false, markedAsInt: false } },
// the explicit integer block
{ str: '1L', val: { num: 1, complexNumber: false, markedAsInt: true } },
{ str: '0x10L', val: { num: 16, complexNumber: false, markedAsInt: true } },
// { str: '0x10L', val: { num: 16, complexNumber: false, markedAsInt: true } },
{ str: '1000000L', val: { num: 1000000, complexNumber: false, markedAsInt: true } },
{ str: '1e6L', val: { num: 1000000, complexNumber: false, markedAsInt: true } },
{ str: '1.L', val: { num: 1, complexNumber: false, markedAsInt: true } },
Expand Down
4 changes: 2 additions & 2 deletions test/slicing/static/calls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,8 @@ a(m)()`)
assertSliced('Higher order anonymous function', shell, `a <- function(b) {
b
}
x <- a(\\() 2 + 3)() + a(\\() 7)()`, ['4@x'], `a <- function(b) { b }
x <- a(\\() 2 + 3)() + a(\\() 7)()`)
x <- a(function() 2 + 3)() + a(function() 7)()`, ['4@x'], `a <- function(b) { b }
x <- a(function() 2 + 3)() + a(function() 7)()`)
})
describe('Side-Effects', () => {
assertSliced('Important Side-Effect', shell, `x <- 2
Expand Down

0 comments on commit 466e723

Please sign in to comment.