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.
- package/README.md +18 -3
- package/jlex.js +113 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,9 +8,18 @@
|
|
|
8
8
|
## Usage
|
|
9
9
|
|
|
10
10
|
```
|
|
11
|
-
npx jlex
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
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
|
}
|