From e76cc202b384b1f169555ec4ad4dde6872ed0038 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Fri, 15 Mar 2024 15:51:45 +0000 Subject: [PATCH] fix: don't renumber when stripping comments Also fixes int parse bug when inside brackets and int keywords --- .nvm | 1 + README.md | 9 +++++- __tests__/index.test.mjs | 2 +- cli/index.mjs | 4 +-- cli/txt2bas.mjs | 2 +- index.d.ts | 9 ++++-- index.mjs | 61 ++++++++++++++++++++-------------------- txt2bas/index.mjs | 4 +-- txt2bas/transform.mjs | 12 ++++---- 9 files changed, 57 insertions(+), 47 deletions(-) create mode 100644 .nvm diff --git a/.nvm b/.nvm new file mode 100644 index 0000000..aabe6ec --- /dev/null +++ b/.nvm @@ -0,0 +1 @@ +21 diff --git a/README.md b/README.md index bb3aec6..5dcecb3 100644 --- a/README.md +++ b/README.md @@ -64,12 +64,19 @@ Problematically using the library exposes a number of paired functions: - `file2bas(String: source, Object): Uint8Array` - results full byte array with correct format header, if `validate` is true, will throw on token errors - `bas2file(Uint8Array: source, String=3dos: format): String` - formatted BASIC text - `formatText(String: line): String` - processes the line through `line2bas` then `bas2line` to result the formatted line -- `validateTxt(String: source): Arrary[String]` - parses each line collecting and returning any token errors +- `validateTxt(String: source): Array[String]` - parses each line collecting and returning any token errors - `plus3DOSHeader` and `tapHeader` - file headers for the appropriate data formats - `codes` an object lookup from NextBASIC numerical value to text value, ie. `0xf5 = 'PRINT'` - `statements(String: source): Array[Statement]` - returns the parsed statement which include `lineNumber` and `tokens` for each line. - `renumber(String: source, Object)` - renumbers source lines and `GO TO` line number targets. +## Development + +- Currently the latest code uses node@21 (due to specific use of syntax) +- To test with another project: `npm link` +- For new features of language or validation changes, ensure a test is provided +- txt2bas also support different NextOS versions, specified through `parser-version` + ## Licence - [MIT](https://rem.mit-license.org/) diff --git a/__tests__/index.test.mjs b/__tests__/index.test.mjs index 3153ffd..f91cdb4 100644 --- a/__tests__/index.test.mjs +++ b/__tests__/index.test.mjs @@ -47,7 +47,7 @@ test('strip comments and autoline works', (t) => { const txt = file2txt(bytes); - t.is(txt, '#autostart 1\n1 PAUSE 0\n', 'matches'); + t.is(txt, '#autostart 1\n2 PAUSE 0\n', 'matches'); }); test('formatText', (t) => { diff --git a/cli/index.mjs b/cli/index.mjs index 97aefb6..1e2ad1e 100755 --- a/cli/index.mjs +++ b/cli/index.mjs @@ -1,8 +1,8 @@ import { readFileSync, writeFileSync, statSync } from 'fs'; import { dirname, resolve, basename, extname } from 'path'; -import * as cli from '../index'; +import * as cli from '../index.mjs'; import pkg from '../package.json' with { type: 'json' }; -import { LATEST } from '../parser-version'; +import { LATEST } from '../parser-version.mjs'; const { version } = pkg; diff --git a/cli/txt2bas.mjs b/cli/txt2bas.mjs index 2fd3039..98ddfb8 100644 --- a/cli/txt2bas.mjs +++ b/cli/txt2bas.mjs @@ -1,2 +1,2 @@ -import main from './index'; +import main from './index.mjs'; main('txt'); diff --git a/index.d.ts b/index.d.ts index 98750d7..2e17081 100644 --- a/index.d.ts +++ b/index.d.ts @@ -85,8 +85,13 @@ export type Expect = { value?: string; }; -import { Statement as StatementInstance } from './txt2bas/index'; -type Statement = InstanceType; +import { + Statement as StatementClass, + Autoline as AutolineClass, +} from './txt2bas/index'; + +export type Statement = InstanceType; +export type Autoline = InstanceType; export type RenumberOptions = { /** The line number to affect */ diff --git a/index.mjs b/index.mjs index 271452e..599000c 100644 --- a/index.mjs +++ b/index.mjs @@ -17,7 +17,7 @@ import * as parser from './parser-version.mjs'; export { plus3DOSHeader, tapHeader } from './headers.mjs'; export { default as codes } from './codes.mjs'; export { renumber, shift } from './renumber.mjs'; -import pkg from './package.json' with { type: 'json' }; +import pkg from './package.json' assert { type: 'json' }; export const version = pkg.version; @@ -125,7 +125,7 @@ export const tokens = ( } if (stripComments) { - statements = transform.stripComments(statements, rest.autoline); + statements = transform.stripComments(statements); } if (inlineLoad) { @@ -207,34 +207,34 @@ export const file2bas = (src, options = {}) => { return file; } - if (format === '3dos') { - if (rest.bankSplits.length === 0) { - return generateFile({ bytes, bank, directives }); - } + if (format === 'tap') { + return asTap(bytes, directives); + } - const file = generateFile({ bytes, bank, directives }); - - if (bankOutputDir) { - rest.bankSplits.forEach((bank) => { - const file = generateFile({ - bytes: bank.bytes, - bank: true, - directives: { ...directives, filename: bank.filename }, - }); - // save the bank as a file - const { join } = require('path'); - - require('fs').writeFileSync( - join(bankOutputDir, bank.filename), - Buffer.from(file) - ); + if (rest.bankSplits.length === 0) { + return generateFile({ bytes, bank, directives }); + } + + const file = generateFile({ bytes, bank, directives }); + + if (bankOutputDir) { + rest.bankSplits.forEach((bank) => { + const file = generateFile({ + bytes: bank.bytes, + bank: true, + directives: { ...directives, filename: bank.filename }, }); - } - // generate the file, but also save the actual banks as files - return file; - } else if (format === 'tap') { - return asTap(bytes, directives); + // save the bank as a file + const { join } = require('path'); + + require('fs').writeFileSync( + join(bankOutputDir, bank.filename), + Buffer.from(file) + ); + }); } + // generate the file, but also save the actual banks as files + return file; }; /** @@ -297,7 +297,7 @@ function generateFile({ bytes, bank, directives }) { * @param {object} [options] * @param {string} [options.format=3dos] format type: "3dos", "tap" * @param {boolean} [options.includeHeader=true] - * @returns {Uint8Array} + * @returns {string} */ export const file2txt = (src, options = {}) => { const { format = '3dos' } = options; @@ -306,9 +306,10 @@ export const file2txt = (src, options = {}) => { } if (options.includeHeader === false) { return bas2txtLines(new Uint8Array(src)) + '\n'; - } else if (format === '3dos') { - return bas2txt(new Uint8Array(src)) + '\n'; } else if (format === 'tap') { return tap2txt(new Uint8Array(src)) + '\n'; } + + // else format = '3dos' + return bas2txt(new Uint8Array(src)) + '\n'; }; diff --git a/txt2bas/index.mjs b/txt2bas/index.mjs index 29d2c6f..1c6301c 100644 --- a/txt2bas/index.mjs +++ b/txt2bas/index.mjs @@ -687,9 +687,7 @@ export class Statement { ) { this.in.push(INT_EXPRESSION); } - } - - if (!this.isIn(IF) && !this.isIn(INT_EXPRESSION)) { + } else if (!this.isIn(IF) && !this.isIn(INT_EXPRESSION)) { this.inIntExpression = false; } diff --git a/txt2bas/transform.mjs b/txt2bas/transform.mjs index 683b415..bd30bdd 100644 --- a/txt2bas/transform.mjs +++ b/txt2bas/transform.mjs @@ -7,7 +7,6 @@ import { opTable } from './op-table.mjs'; import * as types from './types.mjs'; -import { renumberStatements } from '../renumber.mjs'; import { basicToBytes, parseBasic } from './index.mjs'; import { bas2txtLines } from '../bas2txt.mjs'; @@ -22,6 +21,8 @@ export function inlineLoad(statements) { const { join } = require('path'); const cwd = process.cwd(); let index; + + /** @type {Statement} */ let st; const getLengthAndOffset = () => { @@ -254,10 +255,10 @@ function removeTrailingWhiteSpace(tokens) { * Remove comments from statements * * @param {Statement[]} statements - * @param {Autoline} autoline * @returns {Statement[]} */ -export function stripComments(statements, autoline) { +export function stripComments(statements) { + /** @type {Statement[]} */ const res = []; for (let i = 0; i < statements.length; i++) { const st = statements[i]; @@ -281,8 +282,5 @@ export function stripComments(statements, autoline) { } } - return renumberStatements(res, { - start: autoline.start, - step: autoline.step, - }); + return res; }