jlex 1.1.4 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +18 -3
  2. package/jlex.js +113 -15
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -8,9 +8,18 @@
8
8
  ## Usage
9
9
 
10
10
  ```
11
- npx jlex <package name>
12
- ```
11
+ npx jlex --help
12
+ Usage: jlex [options] <filename>
13
+
14
+ A tiny wrapper around jison-lex that allows you to use jison-lex as a standalone (flex like) processor.
13
15
 
16
+ Options:
17
+ -V, --version output the version number
18
+ -o, --output <fileName> Output file name
19
+ -v, --verbose Enable verbose output
20
+ -h, --help display help for command
21
+ See https://github.com/ULL-ESIT-PL/jlex/blob/main/README.md for more help
22
+ ```
14
23
 
15
24
  ## Example
16
25
 
@@ -32,7 +41,13 @@ comment [/][*](.|[\r\n])*?[*][/]
32
41
  Compile it with:
33
42
 
34
43
  ```
35
- npx jlex examples/example.l
44
+ ➜ jlex git:(main) ./jlex.js examples/example.l -v -o examples/example.js
45
+ 📖 Reading lexer grammar from: examples/example.l
46
+ 📝 Generated 11340 characters of lexer code
47
+ 🔄 Applied transformation pattern: /var\s+lexer\s*=/
48
+ 📝 Writing file: examples/example.js
49
+ ✅ Successfully processed examples/example.l → examples/example.js
50
+ 📊 Output size: 11.1KB
36
51
  ```
37
52
 
38
53
  This produces a Common.JS module `examples/example.js` you can use with a simple `require` like in the file [main.js](examples/main.js) below:
package/jlex.js CHANGED
@@ -1,35 +1,133 @@
1
1
  #!/usr/bin/env node
2
2
  // replace example by the name of the generated module
3
3
  const fs = require("fs");
4
- const { execSync } = require('child_process');
4
+ const jisonLex = require('jison-lex');
5
+
5
6
  const { Command } = require('commander')
6
7
  const packageJson = require('./package.json')
7
8
  const path = require('path');
8
9
  const program = new Command();
9
10
 
10
11
  program
11
- .version(packageJson.version)
12
- .description('A tiny wrapper around jison-lex that allows you to use jison-lex as a standalone (flex like) processor.')
13
- .addHelpText('after', `See https://github.com/ULL-ESIT-PL/jlex/blob/main/README.md for more help`)
14
- .option("-o <fileName>", "Output file name")
15
- .usage("[options] <filename>");
12
+ .version(packageJson.version)
13
+ .description('A tiny wrapper around jison-lex that allows you to use jison-lex as a standalone (flex like) processor.')
14
+ .addHelpText('after', `See https://github.com/ULL-ESIT-PL/jlex/blob/main/README.md for more help`)
15
+ .option("-o, --output <fileName>", "Output file name")
16
+ .option("-v, --verbose", "Enable verbose output")
17
+ .usage("[options] <filename>");
16
18
 
17
19
  program.parse(process.argv);
18
20
  const options = program.opts();
19
21
 
22
+ // Logging helper
23
+ function log(message, isVerbose = false) {
24
+ if (!isVerbose || options.verbose) {
25
+ console.log(message);
26
+ }
27
+ }
28
+
29
+ function logError(message) {
30
+ console.error(`❌ Error: ${message}`);
31
+ }
32
+
33
+ function logSuccess(message) {
34
+ console.log(`✅ ${message}`);
35
+ }
36
+
37
+ if (program.args.length === 0) {
38
+ logError("No input file specified");
39
+ program.help();
40
+ process.exit(1);
41
+ }
20
42
  const fileName = program.args[0];
21
43
 
22
- const {dir,name } = path.parse(fileName); // { dir, base, ext, name }
23
- const outputFileName = options.o || path.join(dir, `${name}.js`);
24
- const outputParse = path.parse(outputFileName);
44
+ // Validate input file extension
45
+ if (!/[.](l|lex|flex)$/.test(fileName)) {
46
+ console.warn(`⚠️ Warning: Expected .l or .lex extension for lexer file, got: ${path.extname(fileName)}`);
47
+ }
48
+
49
+ const { dir, name } = path.parse(fileName);
50
+ const outputFileName = options.output || path.join(dir, `${name}.js`);
25
51
 
26
- const shellCommand = `npx jison-lex ${fileName} -o ${outputFileName}`;
27
52
  try {
28
- execSync(shellCommand, { encoding: 'utf-8' });
29
- let lexerStr = fs.readFileSync(outputFileName, "utf8").toString();
30
- let lexerModule = lexerStr.replace(new RegExp(`var ${outputParse.name} =`), `\nmodule.exports =`);
31
- console.log("Writing file:", outputFileName);
53
+ if (!fs.existsSync(fileName)) {
54
+ logError(`File '${fileName}' does not exist`);
55
+ process.exit(1);
56
+ }
57
+
58
+ const stats = fs.statSync(fileName);
59
+ if (!stats.isFile()) {
60
+ logError(`'${fileName}' is not a regular file`);
61
+ process.exit(1);
62
+ }
63
+
64
+ log(`📖 Reading lexer grammar from: ${fileName}`, true);
65
+ let lexerStr = fs.readFileSync(fileName, "utf8");
66
+
67
+ let generatedCode = jisonLex.generate(lexerStr, { moduleType: 'commonjs' });
68
+
69
+ if (!generatedCode || generatedCode.trim().length === 0) {
70
+ logError(`jison-lex failed to generate code from '${fileName}'`);
71
+ process.exit(1);
72
+ }
73
+
74
+ log(`📝 Generated ${generatedCode.length} characters of lexer code`, true);
75
+
76
+ // More robust transformation with multiple patterns
77
+ const patterns = [
78
+ /var\s+lexer\s*=/,
79
+ /let\s+lexer\s*=/,
80
+ /const\s+lexer\s*=/,
81
+ new RegExp(`var\\s+${name}\\s*=`)
82
+ ];
83
+
84
+ let lexerModule = generatedCode;
85
+ let transformApplied = false;
86
+
87
+ for (const pattern of patterns) {
88
+ if (pattern.test(generatedCode)) {
89
+ lexerModule = generatedCode.replace(pattern, `module.exports =`);
90
+ transformApplied = true;
91
+ log(`🔄 Applied transformation pattern: ${pattern}`, true);
92
+ break;
93
+ }
94
+ }
95
+
96
+ //transformApplied = false;
97
+ if (!transformApplied) {
98
+ logError(
99
+ `No standard pattern found in the generated code!.
100
+ Applied patterns: ${patterns.map(p => p.toString()).join(' or ')}.
101
+ Output may not be a valid CommonJS module.
102
+ Consider adding an issue: https://github.com/ULL-ESIT-PL/jlex/issues.
103
+ `);
104
+ }
105
+
106
+ // Ensure output directory exists
107
+ const outputDir = path.dirname(outputFileName);
108
+ if (!fs.existsSync(outputDir)) {
109
+ fs.mkdirSync(outputDir, { recursive: true });
110
+ log(`📁 Created directory: ${outputDir}`, true);
111
+ }
112
+
113
+ log(`📝 Writing file: ${outputFileName}`);
32
114
  fs.writeFileSync(outputFileName, lexerModule);
115
+
116
+ logSuccess(`Successfully processed ${fileName} → ${outputFileName}`);
117
+ log(`📊 Output size: ${(fs.statSync(outputFileName).size / 1024).toFixed(1)}KB`, true);
118
+
33
119
  } catch (error) {
34
- console.error("Error:", error.message);
120
+ if (error.message.includes('Lexical error') || error.message.includes('Parse error')) {
121
+ logError(`Invalid lexer grammar in '${fileName}': ${error.message}`);
122
+ } else if (error.code === 'EACCES') {
123
+ logError(`Permission denied accessing '${error.path}'`);
124
+ } else if (error.code === 'ENOSPC') {
125
+ logError(`No space left on device when writing '${outputFileName}'`);
126
+ } else {
127
+ logError(error.message);
128
+ if (options.verbose) {
129
+ console.error('Stack trace:', error.stack);
130
+ }
131
+ }
132
+ process.exit(1);
35
133
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jlex",
3
- "version": "1.1.4",
3
+ "version": "1.2.1",
4
4
  "description": "A wrapper around jison-lex to make it work as a standalone program like Flex",
5
5
  "keywords": [
6
6
  "jison-lex",