From 41275c06c58c91aa216300f39e0557153667d965 Mon Sep 17 00:00:00 2001 From: Jason Dreyzehner Date: Wed, 21 Aug 2019 11:34:15 -0400 Subject: [PATCH] fix(compiler): allow empty programs to be compiled --- .../auth/templates/language/compile.spec.ts | 159 +++++++++++++++++- src/lib/auth/templates/language/compile.ts | 18 -- src/lib/auth/templates/language/resolve.ts | 9 +- 3 files changed, 157 insertions(+), 29 deletions(-) diff --git a/src/lib/auth/templates/language/compile.spec.ts b/src/lib/auth/templates/language/compile.spec.ts index 746a1bb9..73dbb873 100644 --- a/src/lib/auth/templates/language/compile.spec.ts +++ b/src/lib/auth/templates/language/compile.spec.ts @@ -3,7 +3,7 @@ import test from 'ava'; import { hexToBin } from '../../../utils/hex'; -import { compileScript } from './compile'; +import { compileScript, compileScriptText } from './compile'; test('compileScript: unprovided ID', t => { t.deepEqual(compileScript('test', {}, { scripts: { typo: '1' } }), { @@ -26,19 +26,160 @@ test('compileScript: unprovided ID', t => { test('compileScript: empty string', t => { t.deepEqual(compileScript('t', {}, { scripts: { t: '' } }), { - errorType: 'parse', - errors: [ + bytecode: Uint8Array.of(), + parse: { + end: { + column: 1, + line: 1, + offset: 0 + }, + name: 'Script', + start: { + column: 1, + line: 1, + offset: 0 + }, + value: [] + }, + reduce: { + bytecode: Uint8Array.of(), + range: { + endColumn: 1, + endLineNumber: 1, + startColumn: 1, + startLineNumber: 1 + }, + source: [ + { + bytecode: Uint8Array.of(), + range: { + endColumn: 1, + endLineNumber: 1, + startColumn: 1, + startLineNumber: 1 + } + } + ] + }, + resolve: [ { - error: 'Tried to compile an empty string as a script.', range: { - endColumn: 0, - endLineNumber: 0, - startColumn: 0, - startLineNumber: 0 + endColumn: 1, + endLineNumber: 1, + startColumn: 1, + startLineNumber: 1 + }, + type: 'comment', + value: '' + } + ], + success: true + }); +}); + +test('compileScriptText: empty string', t => { + t.deepEqual(compileScriptText('', {}, { scripts: {} }), { + bytecode: Uint8Array.of(), + parse: { + end: { + column: 1, + line: 1, + offset: 0 + }, + name: 'Script', + start: { + column: 1, + line: 1, + offset: 0 + }, + value: [] + }, + reduce: { + bytecode: Uint8Array.of(), + range: { + endColumn: 1, + endLineNumber: 1, + startColumn: 1, + startLineNumber: 1 + }, + source: [ + { + bytecode: Uint8Array.of(), + range: { + endColumn: 1, + endLineNumber: 1, + startColumn: 1, + startLineNumber: 1 + } } + ] + }, + resolve: [ + { + range: { + endColumn: 1, + endLineNumber: 1, + startColumn: 1, + startLineNumber: 1 + }, + type: 'comment', + value: '' } ], - success: false + success: true + }); +}); + +test('compileScriptText: empty script (script with space)', t => { + t.deepEqual(compileScript('t', {}, { scripts: { t: ' ' } }), { + bytecode: Uint8Array.of(), + parse: { + end: { + column: 5, + line: 1, + offset: 4 + }, + name: 'Script', + start: { + column: 5, + line: 1, + offset: 4 + }, + value: [] + }, + reduce: { + bytecode: Uint8Array.of(), + range: { + endColumn: 5, + endLineNumber: 1, + startColumn: 5, + startLineNumber: 1 + }, + source: [ + { + bytecode: Uint8Array.of(), + range: { + endColumn: 5, + endLineNumber: 1, + startColumn: 5, + startLineNumber: 1 + } + } + ] + }, + resolve: [ + { + range: { + endColumn: 5, + endLineNumber: 1, + startColumn: 5, + startLineNumber: 1 + }, + type: 'comment', + value: '' + } + ], + success: true }); }); diff --git a/src/lib/auth/templates/language/compile.ts b/src/lib/auth/templates/language/compile.ts index c21f3ba0..dd40295e 100644 --- a/src/lib/auth/templates/language/compile.ts +++ b/src/lib/auth/templates/language/compile.ts @@ -83,24 +83,6 @@ export const compileScriptText = < environment: CompilationEnvironment, scriptId?: string ): CompilationResult => { - // tslint:disable-next-line: no-if-statement - if (script.length === 0) { - return { - errorType: 'parse', - errors: [ - { - error: 'Tried to compile an empty string as a script.', - range: { - endColumn: 0, - endLineNumber: 0, - startColumn: 0, - startLineNumber: 0 - } - } - ], - success: false - }; - } const parseResult = parseScript(script); // tslint:disable-next-line: no-if-statement if (!parseResult.status) { diff --git a/src/lib/auth/templates/language/resolve.ts b/src/lib/auth/templates/language/resolve.ts index 28472477..345267b8 100644 --- a/src/lib/auth/templates/language/resolve.ts +++ b/src/lib/auth/templates/language/resolve.ts @@ -84,9 +84,9 @@ enum Constants { export const resolveScriptSegment = ( segment: BitAuthScriptSegment, resolveIdentifiers: IdentifierResolutionFunction -): ResolvedScript => +): ResolvedScript => { // tslint:disable-next-line: cyclomatic-complexity - segment.value.map(child => { + const resolved = segment.value.map(child => { const range = pluckRange(child); switch (child.name) { case 'Identifier': @@ -159,6 +159,11 @@ export const resolveScriptSegment = ( } }); + return resolved.length === 0 + ? [{ range: pluckRange(segment), type: 'comment' as 'comment', value: '' }] + : resolved; +}; + /** * Returns the bytecode result on success or an error message on failure. */