diff --git a/src/services/code-index/processors/__tests__/parser.vb.spec.ts b/src/services/code-index/processors/__tests__/parser.vb.spec.ts index 95fd73cc9a..965df45745 100644 --- a/src/services/code-index/processors/__tests__/parser.vb.spec.ts +++ b/src/services/code-index/processors/__tests__/parser.vb.spec.ts @@ -234,12 +234,129 @@ End Namespace expect(block.type).toBe("fallback_chunk") }) }) + + it("should use fallback chunking for MQL files", async () => { + // Test with MQL4 file + const mql4Content = `//+------------------------------------------------------------------+ +//| ExpertAdvisor.mq4| +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024" +#property version "1.00" +#property strict + +// Input parameters +input double LotSize = 0.01; +input int StopLoss = 50; +input int TakeProfit = 100; +input int MagicNumber = 12345; + +// Global variables +int ticket = 0; +double lastPrice = 0; + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() +{ + Print("Expert Advisor initialized"); + lastPrice = Ask; + return(INIT_SUCCEEDED); +} + +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) +{ + Print("Expert Advisor deinitialized"); +} + +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() +{ + double currentPrice = Ask; + + if(OrdersTotal() == 0) + { + // Open a buy order + ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, 3, + Ask - StopLoss * Point, + Ask + TakeProfit * Point, + "EA Trade", MagicNumber, 0, clrGreen); + + if(ticket < 0) + { + Print("Error opening order: ", GetLastError()); + } + } + + lastPrice = currentPrice; +}` + + // Test .mq4 extension + const mq4Result = await parser.parseFile("expert.mq4", { + content: mql4Content, + fileHash: "test-hash-mq4", + }) + + expect(mq4Result.length).toBeGreaterThan(0) + mq4Result.forEach((block) => { + expect(block.type).toBe("fallback_chunk") + }) + + // Test .mq5 extension + const mq5Result = await parser.parseFile("expert.mq5", { + content: mql4Content, + fileHash: "test-hash-mq5", + }) + + expect(mq5Result.length).toBeGreaterThan(0) + mq5Result.forEach((block) => { + expect(block.type).toBe("fallback_chunk") + }) + + // Test .mqh extension (header file) + const mqhContent = `//+------------------------------------------------------------------+ +//| Common.mqh | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024" +#property version "1.00" + +// Common functions and definitions +#define MAX_ORDERS 10 +#define MIN_LOT_SIZE 0.01 + +double CalculateLotSize(double riskPercent, double stopLoss) +{ + double accountBalance = AccountBalance(); + double riskAmount = accountBalance * riskPercent / 100; + double lotSize = riskAmount / (stopLoss * MarketInfo(Symbol(), MODE_TICKVALUE)); + + return NormalizeDouble(lotSize, 2); +}` + + const mqhResult = await parser.parseFile("common.mqh", { + content: mqhContent, + fileHash: "test-hash-mqh", + }) + + expect(mqhResult.length).toBeGreaterThan(0) + mqhResult.forEach((block) => { + expect(block.type).toBe("fallback_chunk") + }) + }) }) describe("Fallback Extensions Configuration", () => { it("should correctly identify extensions that need fallback chunking", () => { // Extensions that should use fallback expect(shouldUseFallbackChunking(".vb")).toBe(true) + expect(shouldUseFallbackChunking(".mq4")).toBe(true) + expect(shouldUseFallbackChunking(".mq5")).toBe(true) + expect(shouldUseFallbackChunking(".mqh")).toBe(true) expect(shouldUseFallbackChunking(".scala")).toBe(true) expect(shouldUseFallbackChunking(".swift")).toBe(true) @@ -256,6 +373,9 @@ describe("Fallback Extensions Configuration", () => { it("should be case-insensitive", () => { expect(shouldUseFallbackChunking(".VB")).toBe(true) expect(shouldUseFallbackChunking(".Vb")).toBe(true) + expect(shouldUseFallbackChunking(".MQ4")).toBe(true) + expect(shouldUseFallbackChunking(".mQ5")).toBe(true) + expect(shouldUseFallbackChunking(".MQH")).toBe(true) expect(shouldUseFallbackChunking(".SCALA")).toBe(true) expect(shouldUseFallbackChunking(".Scala")).toBe(true) }) diff --git a/src/services/code-index/shared/supported-extensions.ts b/src/services/code-index/shared/supported-extensions.ts index 80dd7102ff..a495ab12e2 100644 --- a/src/services/code-index/shared/supported-extensions.ts +++ b/src/services/code-index/shared/supported-extensions.ts @@ -20,6 +20,9 @@ export const scannerExtensions = allExtensions */ export const fallbackExtensions = [ ".vb", // Visual Basic .NET - no dedicated WASM parser + ".mq4", // MetaQuotes Language 4 - no dedicated WASM parser + ".mq5", // MetaQuotes Language 5 - no dedicated WASM parser + ".mqh", // MetaQuotes Language Header - no dedicated WASM parser ".scala", // Scala - uses fallback chunking instead of Lua query workaround ".swift", // Swift - uses fallback chunking due to parser instability ] diff --git a/src/services/tree-sitter/index.ts b/src/services/tree-sitter/index.ts index 145ba84730..4b4a1f2b88 100644 --- a/src/services/tree-sitter/index.ts +++ b/src/services/tree-sitter/index.ts @@ -78,6 +78,10 @@ const extensions = [ "mli", // Lua "lua", + // MQL (MetaQuotes Language) + "mq4", + "mq5", + "mqh", // Scala "scala", // TOML