8000 lambda: support golang · brpapa/recursion-tree-visualizer@4bd42ca · GitHub
[go: up one dir, main page]

Skip to content

Commit 4bd42ca

Browse files
committed
lambda: support golang
1 parent d28e074 commit 4bd42ca

File tree

16 files changed

+1004
-494
lines changed

16 files changed

+1004
-494
lines changed

packages/lambda/src/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ require('dotenv').config()
44

55
export const environment = String(process.env.NODE_ENV) || 'production'
66
export const supportedLanguages: SupportedLanguages[] = ['node', 'python']
7+
78
export const DEFAULT_TIMEOUT_MS = 5000
89
export const DEFAULT_MAX_RECURSIVE_CALLS = 256
910
export const DEFAULT_TMP_DIR_PATH = '/tmp'

packages/lambda/src/errors/child-process.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { SupportedLanguages } from '../types'
12
import { Error } from './common'
23

34
export enum ChildProcessError {
@@ -7,16 +8,31 @@ export enum ChildProcessError {
78
}
89

910
export const runtimeError = (
11+
lang: SupportedLanguages,
1012
stderr: string
1113
): Error<ChildProcessError.RuntimeError> => {
12-
const matched = stderr.match(/([a-zA-Z]*(Error|Exception):\s[^\n]+)/gm)
13-
if (matched === null) throw new Error(`Fail to parse the following stderr:\n${stderr}`)
14+
15+
const errorMessage = ((): string => {
16+
if (lang === 'python' || lang === 'node') {
17+
const matched1st = /([a-zA-Z]*(Error|Exception):\s[^\n]+)/gm.exec(stderr)
18+
if (matched1st !== null && matched1st?.length >= 1)
19+
return matched1st[1]
20+
}
21+
if (lang === 'golang') {
22+
const matched2nd = /panic:\s([^\n]+)/gm.exec(stderr)
23+
if (matched2nd !== null && matched2nd.length >= 1)
24+
return `Error: ${matched2nd[1]}`
1425

15-
const errorMessage = matched[0]
26+
const matched3rd = /# command-line-arguments\n.*.go:\d+:\d+:\s([^\n]+)/gm.exec(stderr)
27+
if (matched3rd !== null && matched3rd.length >= 1)
28+
return `Error: ${matched3rd[1]}`
29+
}
30+
throw new Error(`Fail to parse the stderr:\n${stderr}`)
31+
})()
1632

1733
return {
1834
type: ChildProcessError.RuntimeError,
19-
reason: `Your code outputs the following ${errorMessage}`,
35+
reason: `Your code outputs the ${errorMessage}`,
2036
}
2137
}
2238

packages/lambda/src/runner/index.ts

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
import { flow } from 'fp-ts/function'
2-
import { toFullSourceCode } from './steps/source-code'
3-
import { toRecursionTree } from './steps/recursion-tree'
4-
import { toUserCode } from './steps/user-code'
5-
import { toTreeViewer } from './steps/tree-viewer'
2+
import { toSourceCode } from './steps/source-code'
3+
import { toInitialTree } from './steps/initial-tree'
4+
import { toFinalTree } from './steps/final-tree'
65
import { FunctionData, SupportedLanguages } from '../types'
76
import {
87
DEFAULT_MAX_RECURSIVE_CALLS,
98
DEFAULT_TIMEOUT_MS,
109
DEFAULT_TMP_DIR_PATH,
1110
DEFAULT_TMP_FILE_MAX_SIZE_BYTES,
1211
} from '../config'
13-
import { toRawTree } from './steps/raw-tree'
12+
import { toIntermediateTree } from './steps/intermediate-tree'
1413

1514
/** Pipeline to input FuncionData and output TreeViewerData. */
1615
export default function buildRunner(
@@ -32,17 +31,16 @@ export default function buildRunner(
3231
options?.tmpFileMaxSizeBytes || DEFAULT_TMP_FILE_MAX_SIZE_BYTES
3332

3433
return flow(
35-
(fnData: FunctionData) => toUserCode(fnData, lang, memoize),
36-
(userCode) => toFullSourceCode(userCode, lang, maxRecursiveCalls),
37-
(fullSourceCode) =>
38-
toRecursionTree(
39-
fullSourceCode,
34+
(fnData: FunctionData) => toSourceCode(fnData, lang, maxRecursiveCalls, memoize),
35+
(sourceCode) =>
36+
toInitialTree(
37+
sourceCode,
4038
lang,
4139
timeoutMs,
4240
4D24 tmpDirPath,
4341
tmpFileMaxSizeBytes
4442
),
45-
(recursionTree) => recursionTree.then((r) => r.onSuccess(toRawTree)),
46-
(rawTree) => rawTree.then((r) => r.onSuccess(toTreeViewer))
43+
(tree) => tree.then((t) => t.onSuccess(toIntermediateTree)),
44+
(tree) => tree.then((t) => t.onSuccess(toFinalTree))
4745
)
4846
}

packages/lambda/src/runner/steps/tree-viewer.ts renamed to packages/lambda/src/runner/steps/final-tree.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import {
2-
EdgesData, Point, RawTree, TreeViewer,
2+
EdgesData, Point, IntermediateTree, FinalTree,
33
Vertices, VerticesData
44
} from '../../types'
55
import { objectMap } from '../../utils/object-map'
66

77
/** Traverse tree to adjust coords, populate logs, times, verticesData and edgesData */
8-
export function toTreeViewer(rawTree: RawTree): TreeViewer {
8+
export function toFinalTree(rawTree: IntermediateTree): FinalTree {
99
const logs: string[] = []
1010
const edgesData = initialEdgesData(rawTree.tree.vertices)
1111
const verticesData = initialVerticesData(

packages/lambda/src/runner/steps/recursion-tree.ts renamed to packages/lambda/src/runner/steps/initial-tree.ts

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
exceededSourceCodeSizeLimitError,
1515
TreeError,
1616
} from '../../errors/tree'
17-
import { RecursionTree, SupportedLanguages } from '../../types'
17+
import { InitialTree, SupportedLanguages } from '../../types'
1818
import { Either, error, success } from '../../utils/either'
1919
import { validateChildProcessStdout } from '../../validations/stdout'
2020

@@ -23,7 +23,7 @@ const exec = util.promisify(childProcess.exec)
2323
const ENCODING: BufferEncoding = 'utf-8'
2424

2525
/** Starts a child process that evaluate the source code content and return the recursion tree. */
26-
export async function toRecursionTree(
26+
export async function toInitialTree(
2727
sourceCode: string,
2828
lang: SupportedLanguages,
2929
childProcessTimeoutMs: number,
@@ -39,7 +39,7 @@ export async function toRecursionTree(
3939
| TreeError.ExceededRecursiveCallsLimit
4040
| TreeError.ExceededSourceCodeSizeLimit
4141
>,
42-
RecursionTree
42+
InitialTree
4343
>
4444
> {
4545
const declare = buildDeclare(lang)
@@ -61,7 +61,7 @@ export async function toRecursionTree(
6161

6262
const tmpFileName = `${crypto
6363
.randomBytes(16)
64-
.toString('hex')}${declare.ext()}`
64+
.toString('hex')}.${declare.ext()}`
6565
const tmpFileFullPath = `${tmpFolderPath}/${tmpFileName}`
6666

6767
// escrever código fonte
@@ -82,15 +82,8 @@ export async function toRecursionTree(
8282
const { stdout: rawStdout } = await exec(declare.command(tmpFileFullPath), {
8383
timeout: childProcessTimeoutMs,
8484
})
85-
// console.log(rawStdout)
8685

87-
const validatedStdout = validateChildProcessStdout(rawStdout)
88-
if (validatedStdout.isError())
89-
throw new Error(
90-
`Fail to deserialize the \`rawStdout\` object:\n${validatedStdout.value}`
91-
)
92-
93-
const stdout = validatedStdout.value
86+
const stdout = validateChildProcessStdout(rawStdout)
9487
if (stdout.errorValue !== null)
9588
return error(exceededRecursiveCallsLimitError(stdout.errorValue))
9689

@@ -106,10 +99,7 @@ export async function toRecursionTree(
10699
return success(recursionTree)
107100
} catch (err) {
108101
if (err?.killed) return error(timeoutError(childProcessTimeoutMs))
109-
if (err?.stderr) {
110-
// console.log(err.stderr)
111-
return error(runtimeError(err.stderr as string))
112-
}
102+
if (err?.stderr) return error(runtimeError(lang, err.stderr as string))
113103
throw err
114104
} finally {
115105
fs.rmSync(tmpFileFullPath)
@@ -123,16 +113,20 @@ const buildDeclare = (lang: SupportedLanguages) => ({
123113
return `node "${path}"`
124114
case 'python':
125115
return `python3 "${path}"`
116+
case 'golang':
117+
return `go run "${path}"`
126118
default:
127119
throw new Error(`Unexpected lang, got ${lang}`)
128120
}
129121
},
130122
ext: () => {
131123
switch (lang) {
132124
case 'node':
133-
return '.js'
125+
return 'js'
134126
case 'python':
135-
return '.py'
127+
return 'py'
128+
case 'golang':
129+
return 'go'
136130
default:
137131
throw new Error(`Unexpected lang, got ${lang}`)
138132
}

packages/lambda/src/runner/steps/raw-tree.ts renamed to packages/lambda/src/runner/steps/intermediate-tree.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Point, RawTree, RecursionTree, Vertices } from '../../types'
1+
import { Point, IntermediateTree, InitialTree, Vertices } from '../../types'
22

33
type TreeNode = {
44
/** Must be >= 0 */
@@ -13,7 +13,7 @@ type TreeNode = {
1313
}
1414

1515
/** A partir da recursion tree, determina a melhores coordenadas (x,y) de cada vértice usando o Reingold-Tilford's algorithm */
16-
export function toRawTree(recursionTree: RecursionTree): RawTree {
16+
export function toIntermediateTree(recursionTree: InitialTree): IntermediateTree {
1717
const rawCoords: Record<number, Point> = {} // rawCoords[u]: coordenada do vértice u
1818
const rawBottomRight: Point = [0, 0]
1919
const rootId = 0

0 commit comments

Comments
 (0)
0