rename flowParser to flowAntlrParser to avoid conflict with lezer

This commit is contained in:
Ashish Jain
2025-08-19 10:24:14 +05:30
parent dc7eaa925f
commit baf491fde9
24 changed files with 7283 additions and 6841 deletions

View File

@@ -1,12 +1,12 @@
/**
* ANTLR Parser Validation Test Suite
*
*
* This comprehensive test suite validates the ANTLR parser against existing
* flowchart test cases to ensure 100% compatibility with the Jison parser.
*/
import { FlowDB } from '../flowDb.js';
import flowParserJison from './flowParser.ts';
import flowParserJison from './flowAntlrParser.js';
import flowParserANTLR from './flowParserANTLR.ts';
import { setConfig } from '../../../config.js';
@@ -30,101 +30,100 @@ function compareFlowDBs(jisonDB, antlrDB) {
edges: { jison: 0, antlr: 0, match: true },
direction: { jison: '', antlr: '', match: true },
subGraphs: { jison: 0, antlr: 0, match: true },
classes: { jison: 0, antlr: 0, match: true }
}
classes: { jison: 0, antlr: 0, match: true },
},
};
try {
// Compare vertices
const jisonVertices = jisonDB.getVertices();
const antlrVertices = antlrDB.getVertices();
comparison.summary.vertices.jison = jisonVertices.size;
comparison.summary.vertices.antlr = antlrVertices.size;
comparison.summary.vertices.match = jisonVertices.size === antlrVertices.size;
if (!comparison.summary.vertices.match) {
comparison.identical = false;
comparison.differences.push({
type: 'VERTEX_COUNT_MISMATCH',
jison: jisonVertices.size,
antlr: antlrVertices.size
antlr: antlrVertices.size,
});
}
// Compare edges
const jisonEdges = jisonDB.getEdges();
const antlrEdges = antlrDB.getEdges();
comparison.summary.edges.jison = jisonEdges.length;
comparison.summary.edges.antlr = antlrEdges.length;
comparison.summary.edges.match = jisonEdges.length === antlrEdges.length;
if (!comparison.summary.edges.match) {
comparison.identical = false;
comparison.differences.push({
type: 'EDGE_COUNT_MISMATCH',
jison: jisonEdges.length,
antlr: antlrEdges.length
antlr: antlrEdges.length,
});
}
// Compare direction
const jisonDirection = jisonDB.getDirection() || '';
const antlrDirection = antlrDB.getDirection() || '';
comparison.summary.direction.jison = jisonDirection;
comparison.summary.direction.antlr = antlrDirection;
comparison.summary.direction.match = jisonDirection === antlrDirection;
if (!comparison.summary.direction.match) {
comparison.identical = false;
comparison.differences.push({
type: 'DIRECTION_MISMATCH',
jison: jisonDirection,
antlr: antlrDirection
antlr: antlrDirection,
});
}
// Compare subgraphs
const jisonSubGraphs = jisonDB.getSubGraphs();
const antlrSubGraphs = antlrDB.getSubGraphs();
comparison.summary.subGraphs.jison = jisonSubGraphs.length;
comparison.summary.subGraphs.antlr = antlrSubGraphs.length;
comparison.summary.subGraphs.match = jisonSubGraphs.length === antlrSubGraphs.length;
if (!comparison.summary.subGraphs.match) {
comparison.identical = false;
comparison.differences.push({
type: 'SUBGRAPH_COUNT_MISMATCH',
jison: jisonSubGraphs.length,
antlr: antlrSubGraphs.length
antlr: antlrSubGraphs.length,
});
}
// Compare classes
const jisonClasses = jisonDB.getClasses();
const antlrClasses = antlrDB.getClasses();
comparison.summary.classes.jison = jisonClasses.size;
comparison.summary.classes.antlr = antlrClasses.size;
comparison.summary.classes.match = jisonClasses.size === antlrClasses.size;
if (!comparison.summary.classes.match) {
comparison.identical = false;
comparison.differences.push({
type: 'CLASS_COUNT_MISMATCH',
jison: jisonClasses.size,
antlr: antlrClasses.size
antlr: antlrClasses.size,
});
}
} catch (error) {
comparison.identical = false;
comparison.differences.push({
type: 'COMPARISON_ERROR',
error: error.message
error: error.message,
});
}
@@ -141,7 +140,7 @@ async function testSingleInput(input) {
input: input,
jison: { success: false, error: null, db: null },
antlr: { success: false, error: null, db: null },
comparison: null
comparison: null,
};
// Test Jison parser
@@ -150,9 +149,9 @@ async function testSingleInput(input) {
flowParserJison.parser.yy = jisonDB;
flowParserJison.parser.yy.clear();
flowParserJison.parser.yy.setGen('gen-2');
flowParserJison.parse(input);
result.jison.success = true;
result.jison.db = jisonDB;
} catch (error) {
@@ -165,9 +164,9 @@ async function testSingleInput(input) {
flowParserANTLR.parser.yy = antlrDB;
flowParserANTLR.parser.yy.clear();
flowParserANTLR.parser.yy.setGen('gen-2');
flowParserANTLR.parse(input);
result.antlr.success = true;
result.antlr.db = antlrDB;
} catch (error) {
@@ -183,7 +182,6 @@ async function testSingleInput(input) {
}
describe('ANTLR Parser Validation Against Jison Parser', () => {
describe('Basic Functionality Tests', () => {
const basicTests = [
'graph TD',
@@ -192,17 +190,17 @@ describe('ANTLR Parser Validation Against Jison Parser', () => {
'A-->B',
'A --> B',
'graph TD\nA-->B',
'graph TD\nA-->B\nB-->C'
'graph TD\nA-->B\nB-->C',
];
basicTests.forEach(testInput => {
basicTests.forEach((testInput) => {
it(`should parse "${testInput.replace(/\n/g, '\\n')}" identically to Jison`, async () => {
const result = await testSingleInput(testInput);
console.log(`\n📊 Test: "${testInput.replace(/\n/g, '\\n')}"`);
console.log(`Jison: ${result.jison.success ? '✅' : '❌'} ${result.jison.error || ''}`);
console.log(`ANTLR: ${result.antlr.success ? '✅' : '❌'} ${result.antlr.error || ''}`);
if (result.comparison) {
console.log(`Match: ${result.comparison.identical ? '✅ IDENTICAL' : '❌ DIFFERENT'}`);
if (!result.comparison.identical) {
@@ -213,7 +211,7 @@ describe('ANTLR Parser Validation Against Jison Parser', () => {
// Both parsers should succeed
expect(result.jison.success).toBe(true);
expect(result.antlr.success).toBe(true);
// Results should be identical
if (result.comparison) {
expect(result.comparison.identical).toBe(true);
@@ -234,24 +232,24 @@ describe('ANTLR Parser Validation Against Jison Parser', () => {
'graph TD\nA([Stadium])',
'graph TD\nA[[Subroutine]]',
'graph TD\nA[(Database)]',
'graph TD\nA(((Cloud)))'
'graph TD\nA(((Cloud)))',
];
shapeTests.forEach(testInput => {
shapeTests.forEach((testInput) => {
it(`should parse node shape "${testInput.split('\\n')[1]}" identically to Jison`, async () => {
const result = await testSingleInput(testInput);
console.log(`\n📊 Shape Test: "${testInput.replace(/\n/g, '\\n')}"`);
console.log(`Jison: ${result.jison.success ? '✅' : '❌'} ${result.jison.error || ''}`);
console.log(`ANTLR: ${result.antlr.success ? '✅' : '❌'} ${result.antlr.error || ''}`);
if (result.comparison) {
console.log(`Match: ${result.comparison.identical ? '✅ IDENTICAL' : '❌ DIFFERENT'}`);
}
// ANTLR parser should succeed (Jison may fail on some shapes)
expect(result.antlr.success).toBe(true);
// If both succeed, they should match
if (result.jison.success && result.comparison) {
expect(result.comparison.identical).toBe(true);
@@ -270,24 +268,24 @@ describe('ANTLR Parser Validation Against Jison Parser', () => {
'graph TD\nA<-->B',
'graph TD\nA<->B',
'graph TD\nA===B',
'graph TD\nA==>B'
'graph TD\nA==>B',
];
edgeTests.forEach(testInput => {
edgeTests.forEach((testInput) => {
it(`should parse edge type "${testInput.split('\\n')[1]}" identically to Jison`, async () => {
const result = await testSingleInput(testInput);
console.log(`\n📊 Edge Test: "${testInput.replace(/\n/g, '\\n')}"`);
console.log(`Jison: ${result.jison.success ? '✅' : '❌'} ${result.jison.error || ''}`);
console.log(`ANTLR: ${result.antlr.success ? '✅' : '❌'} ${result.antlr.error || ''}`);
if (result.comparison) {
console.log(`Match: ${result.comparison.identical ? '✅ IDENTICAL' : '❌ DIFFERENT'}`);
}
// ANTLR parser should succeed
expect(result.antlr.success).toBe(true);
// If both succeed, they should match
if (result.jison.success && result.comparison) {
expect(result.comparison.identical).toBe(true);
@@ -304,7 +302,7 @@ describe('ANTLR Parser Validation Against Jison Parser', () => {
B -->|No| D[Process 2]
C --> E[End]
D --> E`,
`flowchart LR
subgraph "Subgraph 1"
A --> B
@@ -313,21 +311,21 @@ describe('ANTLR Parser Validation Against Jison Parser', () => {
C --> D
end
B --> C`,
`graph TD
A --> B
style A fill:#f9f,stroke:#333,stroke-width:4px
style B fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5`
style B fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5`,
];
complexTests.forEach((testInput, index) => {
it(`should parse complex flowchart ${index + 1} identically to Jison`, async () => {
const result = await testSingleInput(testInput);
console.log(`\n📊 Complex Test ${index + 1}:`);
console.log(`Jison: ${result.jison.success ? '✅' : '❌'} ${result.jison.error || ''}`);
console.log(`ANTLR: ${result.antlr.success ? '✅' : '❌'} ${result.antlr.error || ''}`);
if (result.comparison) {
console.log(`Match: ${result.comparison.identical ? '✅ IDENTICAL' : '❌ DIFFERENT'}`);
if (!result.comparison.identical) {
@@ -337,7 +335,7 @@ describe('ANTLR Parser Validation Against Jison Parser', () => {
// ANTLR parser should succeed
expect(result.antlr.success).toBe(true);
// If both succeed, they should match
if (result.jison.success && result.comparison) {
expect(result.comparison.identical).toBe(true);
@@ -345,5 +343,4 @@ describe('ANTLR Parser Validation Against Jison Parser', () => {
});
});
});
});

View File

@@ -10,7 +10,7 @@
import { describe, it, expect } from 'vitest';
import { FlowDB } from '../flowDb.js';
import flowParserJison from './flowParser.ts';
import flowParserJison from './flowAntlrParser.js';
import { tokenizeWithANTLR } from './token-stream-comparator.js';
import { setConfig } from '../../../config.js';

View File

@@ -1,12 +1,12 @@
/**
* Comprehensive Jison vs ANTLR Performance and Validation Benchmark
*
*
* This is the definitive benchmark comparing Jison and ANTLR parsers across
* performance, reliability, and functionality metrics.
*/
import { FlowDB } from '../flowDb.js';
import flowParserJison from './flowParser.ts';
import flowParserJison from './flowAntlrParser.js';
import { tokenizeWithANTLR } from './token-stream-comparator.js';
import { LEXER_TEST_CASES, getAllTestCases } from './lexer-test-cases.js';
import { setConfig } from '../../../config.js';
@@ -23,16 +23,16 @@ async function runComprehensiveBenchmark() {
const testCases = [
// Basic functionality
'graph TD',
'graph LR',
'graph LR',
'flowchart TD',
// Simple connections
'A-->B',
'A -> B',
'graph TD\nA-->B',
'graph TD\nA-->B\nB-->C',
'graph TD\nA-->B\nB-->C\nC-->D',
// Node shapes
'graph TD\nA[Square]',
'graph TD\nA(Round)',
@@ -43,13 +43,13 @@ async function runComprehensiveBenchmark() {
'graph TD\nA([Stadium])',
'graph TD\nA[[Subroutine]]',
'graph TD\nA[(Database)]',
// Complex connections
'graph TD\nA[Square]-->B(Round)',
'graph TD\nA{Diamond}-->B((Circle))',
'graph TD\nA-->|Label|B',
'graph TD\nA-->|"Quoted Label"|B',
// Edge types
'graph TD\nA---B',
'graph TD\nA-.-B',
@@ -58,7 +58,7 @@ async function runComprehensiveBenchmark() {
'graph TD\nA<->B',
'graph TD\nA===B',
'graph TD\nA==>B',
// Complex examples
`graph TD
A[Start] --> B{Decision}
@@ -66,7 +66,7 @@ async function runComprehensiveBenchmark() {
B -->|No| D[Process 2]
C --> E[End]
D --> E`,
`flowchart LR
subgraph "Subgraph 1"
A --> B
@@ -75,18 +75,18 @@ async function runComprehensiveBenchmark() {
C --> D
end
B --> C`,
// Styling
`graph TD
A --> B
style A fill:#f9f,stroke:#333,stroke-width:4px
style B fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5`
style B fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5`,
];
const results = {
jison: { successes: 0, failures: 0, totalTime: 0, errors: [] },
antlr: { successes: 0, failures: 0, totalTime: 0, errors: [] },
testResults: []
testResults: [],
};
console.log('\n' + '='.repeat(80));
@@ -98,13 +98,13 @@ async function runComprehensiveBenchmark() {
for (let i = 0; i < testCases.length; i++) {
const testCase = testCases[i];
const displayCase = testCase.length > 60 ? testCase.substring(0, 60) + '...' : testCase;
console.log(`[${i + 1}/${testCases.length}] ${displayCase.replace(/\n/g, '\\n')}`);
const testResult = {
input: testCase,
jison: { success: false, time: 0, error: null, vertices: 0, edges: 0 },
antlr: { success: false, time: 0, error: null, tokens: 0 }
antlr: { success: false, time: 0, error: null, tokens: 0 },
};
// Test Jison parser
@@ -114,29 +114,33 @@ async function runComprehensiveBenchmark() {
flowParserJison.parser.yy = jisonDB;
flowParserJison.parser.yy.clear();
flowParserJison.parser.yy.setGen('gen-2');
flowParserJison.parse(testCase);
const jisonEnd = performance.now();
testResult.jison.success = true;
testResult.jison.time = jisonEnd - jisonStart;
testResult.jison.vertices = jisonDB.getVertices().size;
testResult.jison.edges = jisonDB.getEdges().length;
results.jison.successes++;
results.jison.totalTime += testResult.jison.time;
console.log(` Jison: ✅ ${testResult.jison.time.toFixed(2)}ms (${testResult.jison.vertices}v, ${testResult.jison.edges}e)`);
console.log(
` Jison: ✅ ${testResult.jison.time.toFixed(2)}ms (${testResult.jison.vertices}v, ${testResult.jison.edges}e)`
);
} catch (error) {
const jisonEnd = performance.now();
testResult.jison.time = jisonEnd - jisonStart;
testResult.jison.error = error.message;
results.jison.failures++;
results.jison.totalTime += testResult.jison.time;
results.jison.errors.push({ input: testCase, error: error.message });
console.log(` Jison: ❌ ${testResult.jison.time.toFixed(2)}ms (${error.message.substring(0, 50)}...)`);
console.log(
` Jison: ❌ ${testResult.jison.time.toFixed(2)}ms (${error.message.substring(0, 50)}...)`
);
}
// Test ANTLR lexer (as proxy for full parser)
@@ -144,25 +148,29 @@ async function runComprehensiveBenchmark() {
try {
const tokens = await tokenizeWithANTLR(testCase);
const antlrEnd = performance.now();
testResult.antlr.success = true;
testResult.antlr.time = antlrEnd - antlrStart;
testResult.antlr.tokens = tokens.length;
results.antlr.successes++;
results.antlr.totalTime += testResult.antlr.time;
console.log(` ANTLR: ✅ ${testResult.antlr.time.toFixed(2)}ms (${testResult.antlr.tokens} tokens)`);
console.log(
` ANTLR: ✅ ${testResult.antlr.time.toFixed(2)}ms (${testResult.antlr.tokens} tokens)`
);
} catch (error) {
const antlrEnd = performance.now();
testResult.antlr.time = antlrEnd - antlrStart;
testResult.antlr.error = error.message;
results.antlr.failures++;
results.antlr.totalTime += testResult.antlr.time;
results.antlr.errors.push({ input: testCase, error: error.message });
console.log(` ANTLR: ❌ ${testResult.antlr.time.toFixed(2)}ms (${error.message.substring(0, 50)}...)`);
console.log(
` ANTLR: ❌ ${testResult.antlr.time.toFixed(2)}ms (${error.message.substring(0, 50)}...)`
);
}
results.testResults.push(testResult);
@@ -173,29 +181,40 @@ async function runComprehensiveBenchmark() {
}
describe('Comprehensive Jison vs ANTLR Benchmark', () => {
it('should run comprehensive performance and validation benchmark', async () => {
const results = await runComprehensiveBenchmark();
// Generate comprehensive report
console.log('='.repeat(80));
console.log('FINAL BENCHMARK RESULTS');
console.log('='.repeat(80));
// Success rates
const jisonSuccessRate = (results.jison.successes / (results.jison.successes + results.jison.failures) * 100).toFixed(1);
const antlrSuccessRate = (results.antlr.successes / (results.antlr.successes + results.antlr.failures) * 100).toFixed(1);
const jisonSuccessRate = (
(results.jison.successes / (results.jison.successes + results.jison.failures)) *
100
).toFixed(1);
const antlrSuccessRate = (
(results.antlr.successes / (results.antlr.successes + results.antlr.failures)) *
100
).toFixed(1);
console.log('SUCCESS RATES:');
console.log(` Jison: ${results.jison.successes}/${results.jison.successes + results.jison.failures} (${jisonSuccessRate}%)`);
console.log(` ANTLR: ${results.antlr.successes}/${results.antlr.successes + results.antlr.failures} (${antlrSuccessRate}%)`);
console.log(
` Jison: ${results.jison.successes}/${results.jison.successes + results.jison.failures} (${jisonSuccessRate}%)`
);
console.log(
` ANTLR: ${results.antlr.successes}/${results.antlr.successes + results.antlr.failures} (${antlrSuccessRate}%)`
);
console.log('');
// Performance metrics
const jisonAvgTime = results.jison.totalTime / (results.jison.successes + results.jison.failures);
const antlrAvgTime = results.antlr.totalTime / (results.antlr.successes + results.antlr.failures);
const jisonAvgTime =
results.jison.totalTime / (results.jison.successes + results.jison.failures);
const antlrAvgTime =
results.antlr.totalTime / (results.antlr.successes + results.antlr.failures);
const performanceRatio = antlrAvgTime / jisonAvgTime;
console.log('PERFORMANCE METRICS:');
console.log(` Jison Total Time: ${results.jison.totalTime.toFixed(2)}ms`);
console.log(` ANTLR Total Time: ${results.antlr.totalTime.toFixed(2)}ms`);
@@ -203,7 +222,7 @@ describe('Comprehensive Jison vs ANTLR Benchmark', () => {
console.log(` ANTLR Avg Time: ${antlrAvgTime.toFixed(2)}ms per test`);
console.log(` Performance Ratio: ${performanceRatio.toFixed(2)}x (ANTLR vs Jison)`);
console.log('');
// Performance assessment
console.log('PERFORMANCE ASSESSMENT:');
if (performanceRatio < 1.0) {
@@ -220,7 +239,7 @@ describe('Comprehensive Jison vs ANTLR Benchmark', () => {
console.log('❌ POOR: ANTLR performance is significantly slower than Jison');
}
console.log('');
// Reliability assessment
console.log('RELIABILITY ASSESSMENT:');
if (parseFloat(antlrSuccessRate) > parseFloat(jisonSuccessRate)) {
@@ -231,48 +250,56 @@ describe('Comprehensive Jison vs ANTLR Benchmark', () => {
console.log('⚠️ LOWER: ANTLR has lower success rate than Jison');
}
console.log('');
// Error analysis
if (results.jison.errors.length > 0) {
console.log('JISON ERRORS:');
results.jison.errors.slice(0, 3).forEach((error, i) => {
console.log(` ${i + 1}. "${error.input.substring(0, 40)}..." - ${error.error.substring(0, 60)}...`);
console.log(
` ${i + 1}. "${error.input.substring(0, 40)}..." - ${error.error.substring(0, 60)}...`
);
});
if (results.jison.errors.length > 3) {
console.log(` ... and ${results.jison.errors.length - 3} more errors`);
}
console.log('');
}
if (results.antlr.errors.length > 0) {
console.log('ANTLR ERRORS:');
results.antlr.errors.slice(0, 3).forEach((error, i) => {
console.log(` ${i + 1}. "${error.input.substring(0, 40)}..." - ${error.error.substring(0, 60)}...`);
console.log(
` ${i + 1}. "${error.input.substring(0, 40)}..." - ${error.error.substring(0, 60)}...`
);
});
if (results.antlr.errors.length > 3) {
console.log(` ... and ${results.antlr.errors.length - 3} more errors`);
}
console.log('');
}
// Overall conclusion
console.log('OVERALL CONCLUSION:');
const antlrBetter = parseFloat(antlrSuccessRate) >= parseFloat(jisonSuccessRate) && performanceRatio < 3.0;
const antlrBetter =
parseFloat(antlrSuccessRate) >= parseFloat(jisonSuccessRate) && performanceRatio < 3.0;
if (antlrBetter) {
console.log('🏆 ANTLR MIGRATION RECOMMENDED: Superior or equal reliability with acceptable performance');
console.log(
'🏆 ANTLR MIGRATION RECOMMENDED: Superior or equal reliability with acceptable performance'
);
} else {
console.log('⚠️ ANTLR MIGRATION NEEDS WORK: Performance or reliability concerns identified');
}
console.log('='.repeat(80));
// Assertions for test framework
expect(results.antlr.successes).toBeGreaterThan(0);
expect(parseFloat(antlrSuccessRate)).toBeGreaterThan(80.0); // At least 80% success rate
expect(performanceRatio).toBeLessThan(10.0); // Performance should be reasonable
// Log final status
console.log(`\n🎉 BENCHMARK COMPLETE: ANTLR achieved ${antlrSuccessRate}% success rate with ${performanceRatio.toFixed(2)}x performance ratio`);
console.log(
`\n🎉 BENCHMARK COMPLETE: ANTLR achieved ${antlrSuccessRate}% success rate with ${performanceRatio.toFixed(2)}x performance ratio`
);
}, 60000); // 60 second timeout for comprehensive benchmark
});

View File

@@ -1,5 +1,5 @@
import { FlowDB } from '../flowDb.js';
import flow from './flowParser.ts';
import flow from './flowAntlrParser.js';
import { setConfig } from '../../../config.js';
setConfig({

View File

@@ -1,5 +1,5 @@
import { FlowDB } from '../flowDb.js';
import flow from './flowParser.ts';
import flow from './flowAntlrParser.js';
import { setConfig } from '../../../config.js';
import { cleanupComments } from '../../../diagram-api/comments.js';

View File

@@ -1,5 +1,5 @@
import { FlowDB } from '../flowDb.js';
import flow from './flowParser.ts';
import flow from './flowAntlrParser.js';
import { setConfig } from '../../../config.js';
setConfig({

View File

@@ -1,5 +1,5 @@
import { FlowDB } from '../flowDb.js';
import flow from './flowParser.ts';
import flow from './flowAntlrParser.js';
import { setConfig } from '../../../config.js';
setConfig({

View File

@@ -1,5 +1,5 @@
import { FlowDB } from '../flowDb.js';
import flow from './flowParser.ts';
import flow from './flowAntlrParser.js';
import { setConfig } from '../../../config.js';
setConfig({

View File

@@ -1,5 +1,5 @@
import { FlowDB } from '../flowDb.js';
import flow from './flowParser.ts';
import flow from './flowAntlrParser.js';
import { setConfig } from '../../../config.js';
import { vi } from 'vitest';
const spyOn = vi.spyOn;

View File

@@ -1,5 +1,5 @@
import { FlowDB } from '../flowDb.js';
import flow from './flowParser.ts';
import flow from './flowAntlrParser.js';
import { setConfig } from '../../../config.js';
setConfig({

View File

@@ -1,5 +1,5 @@
import { FlowDB } from '../flowDb.js';
import flow from './flowParser.ts';
import flow from './flowAntlrParser.js';
import { setConfig } from '../../../config.js';
setConfig({

View File

@@ -1,5 +1,5 @@
import { FlowDB } from '../flowDb.js';
import flow from './flowParser.ts';
import flow from './flowAntlrParser.js';
import { setConfig } from '../../../config.js';
setConfig({

View File

@@ -1,5 +1,5 @@
import { FlowDB } from '../flowDb.js';
import flow from './flowParser.ts';
import flow from './flowAntlrParser.js';
import { setConfig } from '../../../config.js';
setConfig({

View File

@@ -1,5 +1,5 @@
import { FlowDB } from '../flowDb.js';
import flow from './flowParser.ts';
import flow from './flowAntlrParser.js';
import { setConfig } from '../../../config.js';
setConfig({

View File

@@ -1,5 +1,5 @@
import { FlowDB } from '../flowDb.js';
import flow from './flowParser.ts';
import flow from './flowAntlrParser.js';
import { setConfig } from '../../../config.js';
setConfig({

View File

@@ -1,5 +1,5 @@
import { FlowDB } from '../flowDb.js';
import flow from './flowParser.ts';
import flow from './flowAntlrParser.js';
import { setConfig } from '../../../config.js';
setConfig({

View File

@@ -1,5 +1,5 @@
import { FlowDB } from '../flowDb.js';
import flow from './flowParser.ts';
import flow from './flowAntlrParser.js';
import { cleanupComments } from '../../../diagram-api/comments.js';
import { setConfig } from '../../../config.js';

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,12 @@
/**
* Phase 2 Completion Validation Test Suite
*
*
* This test suite validates that Phase 2 is complete by testing the ANTLR parser
* infrastructure and comparing it with the Jison parser performance and functionality.
*/
import { FlowDB } from '../flowDb.js';
import flowParserJison from './flowParser.ts';
import flowParserJison from './flowAntlrParser.js';
import { tokenizeWithANTLR } from './token-stream-comparator.js';
import { LEXER_TEST_CASES, getAllTestCases } from './lexer-test-cases.js';
import { setConfig } from '../../../config.js';
@@ -20,20 +20,18 @@ setConfig({
* Test ANTLR parser infrastructure components
*/
describe('Phase 2 Completion Validation', () => {
describe('ANTLR Infrastructure Validation', () => {
it('should have generated ANTLR parser files', () => {
// Test that ANTLR generation created the necessary files
expect(() => {
// These imports should work if ANTLR generation was successful
require('../generated/src/diagrams/flowchart/parser/FlowLexer.js');
}).not.toThrow();
expect(() => {
require('../generated/src/diagrams/flowchart/parser/FlowParser.js');
}).not.toThrow();
expect(() => {
require('../generated/src/diagrams/flowchart/parser/FlowVisitor.js');
}).not.toThrow();
@@ -42,26 +40,28 @@ describe('Phase 2 Completion Validation', () => {
it('should have ANTLR lexer working correctly', async () => {
// Test basic ANTLR lexer functionality
const testInput = 'graph TD\nA-->B';
const tokens = await tokenizeWithANTLR(testInput);
expect(tokens).toBeDefined();
expect(tokens.length).toBeGreaterThan(0);
expect(tokens[tokens.length - 1].type).toBe('EOF');
console.log(`✅ ANTLR Lexer: Successfully tokenized "${testInput}" into ${tokens.length} tokens`);
console.log(
`✅ ANTLR Lexer: Successfully tokenized "${testInput}" into ${tokens.length} tokens`
);
});
it('should have FlowVisitor implementation', () => {
// Test that FlowVisitor class exists and can be instantiated
const FlowVisitor = require('./FlowVisitor.ts').FlowVisitor;
const db = new FlowDB();
expect(() => {
const visitor = new FlowVisitor(db);
expect(visitor).toBeDefined();
}).not.toThrow();
console.log('✅ FlowVisitor: Successfully created visitor instance');
});
@@ -71,20 +71,19 @@ describe('Phase 2 Completion Validation', () => {
const ANTLRFlowParser = require('./ANTLRFlowParser.ts').ANTLRFlowParser;
expect(ANTLRFlowParser).toBeDefined();
}).not.toThrow();
console.log('✅ ANTLRFlowParser: Integration layer exists');
});
});
describe('Jison vs ANTLR Performance Comparison', () => {
it('should compare parsing performance between Jison and ANTLR', async () => {
const testCases = [
'graph TD',
'graph TD\nA-->B',
'graph TD\nA-->B\nB-->C',
'graph TD\nA[Square]-->B(Round)',
'graph TD\nA{Diamond}-->B((Circle))'
'graph TD\nA{Diamond}-->B((Circle))',
];
let jisonTotalTime = 0;
@@ -105,18 +104,20 @@ describe('Phase 2 Completion Validation', () => {
flowParserJison.parser.yy = jisonDB;
flowParserJison.parser.yy.clear();
flowParserJison.parser.yy.setGen('gen-2');
flowParserJison.parse(testCase);
const jisonEnd = performance.now();
const jisonTime = jisonEnd - jisonStart;
jisonTotalTime += jisonTime;
jisonSuccesses++;
console.log(` Jison: ✅ ${jisonTime.toFixed(2)}ms (${jisonDB.getVertices().size} vertices, ${jisonDB.getEdges().length} edges)`);
console.log(
` Jison: ✅ ${jisonTime.toFixed(2)}ms (${jisonDB.getVertices().size} vertices, ${jisonDB.getEdges().length} edges)`
);
} catch (error) {
const jisonEnd = performance.now();
jisonTotalTime += (jisonEnd - jisonStart);
jisonTotalTime += jisonEnd - jisonStart;
console.log(` Jison: ❌ ${error.message}`);
}
@@ -128,24 +129,28 @@ describe('Phase 2 Completion Validation', () => {
const antlrTime = antlrEnd - antlrStart;
antlrTotalTime += antlrTime;
antlrSuccesses++;
console.log(` ANTLR: ✅ ${antlrTime.toFixed(2)}ms (${tokens.length} tokens)`);
} catch (error) {
const antlrEnd = performance.now();
antlrTotalTime += (antlrEnd - antlrStart);
antlrTotalTime += antlrEnd - antlrStart;
console.log(` ANTLR: ❌ ${error.message}`);
}
}
console.log('\n' + '='.repeat(60));
console.log('PERFORMANCE SUMMARY:');
console.log(`Jison: ${jisonSuccesses}/${testCases.length} success (${jisonTotalTime.toFixed(2)}ms total, ${(jisonTotalTime/testCases.length).toFixed(2)}ms avg)`);
console.log(`ANTLR: ${antlrSuccesses}/${testCases.length} success (${antlrTotalTime.toFixed(2)}ms total, ${(antlrTotalTime/testCases.length).toFixed(2)}ms avg)`);
console.log(
`Jison: ${jisonSuccesses}/${testCases.length} success (${jisonTotalTime.toFixed(2)}ms total, ${(jisonTotalTime / testCases.length).toFixed(2)}ms avg)`
);
console.log(
`ANTLR: ${antlrSuccesses}/${testCases.length} success (${antlrTotalTime.toFixed(2)}ms total, ${(antlrTotalTime / testCases.length).toFixed(2)}ms avg)`
);
if (jisonSuccesses > 0 && antlrSuccesses > 0) {
const performanceRatio = (antlrTotalTime / jisonTotalTime);
const performanceRatio = antlrTotalTime / jisonTotalTime;
console.log(`Performance Ratio: ${performanceRatio.toFixed(2)}x (ANTLR vs Jison)`);
if (performanceRatio < 2.0) {
console.log('🚀 EXCELLENT: ANTLR performance is within 2x of Jison');
} else if (performanceRatio < 5.0) {
@@ -163,7 +168,6 @@ describe('Phase 2 Completion Validation', () => {
});
describe('Comprehensive ANTLR Lexer Validation', () => {
it('should validate ANTLR lexer against comprehensive test suite', async () => {
const allTestCases = getAllTestCases();
let successCount = 0;
@@ -172,27 +176,28 @@ describe('Phase 2 Completion Validation', () => {
console.log(`\n🔍 COMPREHENSIVE ANTLR LEXER VALIDATION`);
console.log(`Testing ${allTestCases.length} test cases...`);
for (let i = 0; i < Math.min(allTestCases.length, 20); i++) { // Test first 20 for performance
for (let i = 0; i < Math.min(allTestCases.length, 20); i++) {
// Test first 20 for performance
const testCase = allTestCases[i];
const start = performance.now();
try {
const tokens = await tokenizeWithANTLR(testCase);
const end = performance.now();
totalTime += (end - start);
totalTime += end - start;
if (tokens && tokens.length > 0 && tokens[tokens.length - 1].type === 'EOF') {
successCount++;
}
} catch (error) {
const end = performance.now();
totalTime += (end - start);
totalTime += end - start;
// Continue with other tests
}
}
const testedCount = Math.min(allTestCases.length, 20);
const successRate = (successCount / testedCount * 100).toFixed(1);
const successRate = ((successCount / testedCount) * 100).toFixed(1);
const avgTime = (totalTime / testedCount).toFixed(2);
console.log(`Results: ${successCount}/${testedCount} passed (${successRate}%)`);
@@ -202,22 +207,34 @@ describe('Phase 2 Completion Validation', () => {
// Assert good performance
expect(successCount).toBeGreaterThan(testedCount * 0.8); // At least 80% success rate
expect(parseFloat(avgTime)).toBeLessThan(10); // Less than 10ms average
console.log('✅ ANTLR lexer validation completed successfully');
});
});
describe('Phase 2 Completion Assessment', () => {
it('should confirm Phase 2 deliverables are complete', () => {
const deliverables = {
'ANTLR Grammar File': () => require('fs').existsSync('src/diagrams/flowchart/parser/Flow.g4'),
'Generated Lexer': () => require('fs').existsSync('src/diagrams/flowchart/parser/generated/src/diagrams/flowchart/parser/FlowLexer.ts'),
'Generated Parser': () => require('fs').existsSync('src/diagrams/flowchart/parser/generated/src/diagrams/flowchart/parser/FlowParser.ts'),
'Generated Visitor': () => require('fs').existsSync('src/diagrams/flowchart/parser/generated/src/diagrams/flowchart/parser/FlowVisitor.ts'),
'FlowVisitor Implementation': () => require('fs').existsSync('src/diagrams/flowchart/parser/FlowVisitor.ts'),
'ANTLRFlowParser Integration': () => require('fs').existsSync('src/diagrams/flowchart/parser/ANTLRFlowParser.ts'),
'Parser Integration Layer': () => require('fs').existsSync('src/diagrams/flowchart/parser/flowParserANTLR.ts')
'ANTLR Grammar File': () =>
require('fs').existsSync('src/diagrams/flowchart/parser/Flow.g4'),
'Generated Lexer': () =>
require('fs').existsSync(
'src/diagrams/flowchart/parser/generated/src/diagrams/flowchart/parser/FlowLexer.ts'
),
'Generated Parser': () =>
require('fs').existsSync(
'src/diagrams/flowchart/parser/generated/src/diagrams/flowchart/parser/FlowParser.ts'
),
'Generated Visitor': () =>
require('fs').existsSync(
'src/diagrams/flowchart/parser/generated/src/diagrams/flowchart/parser/FlowVisitor.ts'
),
'FlowVisitor Implementation': () =>
require('fs').existsSync('src/diagrams/flowchart/parser/FlowVisitor.ts'),
'ANTLRFlowParser Integration': () =>
require('fs').existsSync('src/diagrams/flowchart/parser/ANTLRFlowParser.ts'),
'Parser Integration Layer': () =>
require('fs').existsSync('src/diagrams/flowchart/parser/flowParserANTLR.ts'),
};
console.log('\n📋 PHASE 2 DELIVERABLES CHECKLIST:');
@@ -241,7 +258,9 @@ describe('Phase 2 Completion Validation', () => {
}
console.log('='.repeat(50));
console.log(`Completion: ${completedCount}/${totalCount} (${(completedCount/totalCount*100).toFixed(1)}%)`);
console.log(
`Completion: ${completedCount}/${totalCount} (${((completedCount / totalCount) * 100).toFixed(1)}%)`
);
if (completedCount === totalCount) {
console.log('🎉 PHASE 2 COMPLETE: All deliverables present!');
@@ -255,5 +274,4 @@ describe('Phase 2 Completion Validation', () => {
expect(completedCount).toBeGreaterThanOrEqual(totalCount * 0.8);
});
});
});

View File

@@ -7,7 +7,7 @@
import { describe, it, expect } from 'vitest';
import { FlowDB } from '../flowDb.js';
import flowParserJison from './flowParser.ts';
import flowParserJison from './flowAntlrParser.js';
import { tokenizeWithLark } from './lark-token-stream-comparator.js';
import { setConfig } from '../../../config.js';

View File

@@ -1,5 +1,5 @@
import { FlowDB } from '../flowDb.js';
import flow from './flowParser.ts';
import flow from './flowAntlrParser.js';
import { setConfig } from '../../../config.js';
setConfig({

View File

@@ -12,7 +12,7 @@
import { describe, it, expect } from 'vitest';
import { FlowDB } from '../flowDb.js';
import flowParserJison from './flowParser.ts';
import flowParserJison from './flowAntlrParser.js';
import flowParserANTLR from './flowParserANTLR.ts';
import flowParserLark from './flowParserLark.js';
import { tokenizeWithANTLR } from './token-stream-comparator.js';

View File

@@ -130,7 +130,7 @@ async function runAllTests() {
// Load Jison parser (always available)
try {
const jisonModule = await import('./src/diagrams/flowchart/parser/flowParser.ts');
const jisonModule = await import('./src/diagrams/flowchart/parser/flowAntlrParser.js');
jisonParser = jisonModule.default;
console.log('✅ Jison parser loaded');
} catch (error) {