Added Required logic if not found, and added better update logic

This commit is contained in:
2026-09-19 22:07:07 +02:00
parent 45c988c989
commit dcd1bf25e7
14 changed files with 661 additions and 735 deletions
+42 -21
View File
@@ -1,6 +1,6 @@
import * as fs from 'fs';
import * as path from 'path';
import { CompilationError } from './CompilationError';
import { CompilationError, CompilationErrorType } from './CompilationError';
/*
Block types.
@@ -10,7 +10,7 @@ import { CompilationError } from './CompilationError';
export enum BlockType {
CodeTextBlock,
Function,
If,
If,
While,
For,
Do,
@@ -68,10 +68,21 @@ export abstract class CodeBlock {
const fileContent = fs.readFileSync(luaFilePath, 'utf-8');
let leftCursor = 0;
let lineCursor = 0;
let lineCounter = 0;
const file: LuaFile = new LuaFile();
let currentBlock: CodeBlock = file;
function advanceCursor(number: number = 1) {
leftCursor += number;
lineCursor += number;
}
function newLine() {
lineCounter++;
lineCursor = 0;
}
let currentWord = '';
let currentBlockString = '';
@@ -85,10 +96,6 @@ export abstract class CodeBlock {
currentBlockString += currentChar;
const nextChar = leftCursor < fileContent.length - 1 ? fileContent[leftCursor + 1] : '';
if (currentChar === '\n') {
lineCounter++;
}
if (currentChar === '-' && nextChar === '-') {
currentBlockString = currentBlockString.slice(0, -1); // Remove the '-' from the block string
const nextNextChar = leftCursor < fileContent.length - 2 ? fileContent[leftCursor + 2] : '';
@@ -97,19 +104,20 @@ export abstract class CodeBlock {
leftCursor += 3; // Skip the --[
while (leftCursor < fileContent.length && !(fileContent[leftCursor] === ']' && fileContent[leftCursor + 1] === ']')) {
if (fileContent[leftCursor] === '\n') {
lineCounter++;
newLine();
}
leftCursor++;
advanceCursor()
}
leftCursor += 2; // Skip the closing ]]
advanceCursor(2); // Skip the closing ]]
} else {
// Comment line, skip to end of line
while (leftCursor < fileContent.length && fileContent[leftCursor] !== '\n') {
leftCursor++;
advanceCursor();
}
if (fileContent[leftCursor] === '\n') {
lineCounter++;
newLine();
}
advanceCursor();
}
currentWord = '';
continue;
@@ -117,14 +125,14 @@ export abstract class CodeBlock {
else if (currentChar === '"' || currentChar === "'") {
// String literal, skip to closing quote
const quoteType = currentChar;
leftCursor++;
advanceCursor();
while (leftCursor < fileContent.length && fileContent[leftCursor] !== quoteType) {
// Add string but don't process it for keywords
currentBlockString += fileContent[leftCursor];
leftCursor++;
advanceCursor();
}
currentBlockString += quoteType; // Add the closing quote
leftCursor++; // Skip the closing quote
advanceCursor(); // Skip the closing quote
currentWord = '';
continue;
}
@@ -144,6 +152,9 @@ export abstract class CodeBlock {
currentBlockString = '';
currentWord = '';
}
newLine();
advanceCursor();
continue;
}
else if (currentChar === ")" && currentBlock.blockType === BlockType.Require) {
currentBlockString = trimEndPreserveNewlines(currentBlockString); // Remove trailing spaces/tabs
@@ -152,6 +163,9 @@ export abstract class CodeBlock {
currentBlock.childBlocks.push(lineBlock);
currentBlockString = '';
// Update charEnd to include the closing parenthesis
(currentBlock as RequireBlock).charEnd = lineCursor + 1;
currentBlock = currentBlock.getParentBlock()!;
}
//Table blocks
@@ -178,7 +192,7 @@ export abstract class CodeBlock {
currentBlock = tableBlock;
let braceCounter = 1;
leftCursor++;
advanceCursor();
while (leftCursor < fileContent.length && braceCounter > 0) {
const char = fileContent[leftCursor];
currentBlockString += char;
@@ -194,23 +208,29 @@ export abstract class CodeBlock {
currentBlock.childBlocks.push(lineBlock);
currentBlockString = '';
lineCounter++;
lineCursor = 0;
}
leftCursor++;
advanceCursor();
}
// Find newline or other character
let tempCursor = leftCursor;
let tempLineCursor = lineCursor;
while (tempCursor < fileContent.length && fileContent[tempCursor] !== '\n' && fileContent[tempCursor].trim() === '') {
currentBlockString += fileContent[tempCursor];
tempCursor++;
tempLineCursor++;
}
if (tempCursor < fileContent.length && fileContent[tempCursor] === '\n') {
currentBlockString += '\n';
lineCounter++;
lineCursor = 0;
leftCursor = tempCursor + 1;
} else if (tempCursor > leftCursor) {
// We found whitespace but no newline, so position cursor at last whitespace
leftCursor = tempCursor - 1;
leftCursor = tempCursor;
lineCursor = tempLineCursor;
}
// else: no whitespace after table, leave leftCursor where it is
@@ -279,7 +299,7 @@ export abstract class CodeBlock {
currentBlock.childBlocks.push(line);
}
blockToAdd = new RequireBlock(lineCounter, currentBlock, leftCursor - currentWord.length, leftCursor);
blockToAdd = new RequireBlock(lineCounter, currentBlock, Math.max(0, lineCursor - trimmedWord.length), lineCursor);
currentBlockString = trimmedWord; // Start the require block content with 'require' keyword
}
else if (trimmedWord === 'end') {
@@ -288,7 +308,8 @@ export abstract class CodeBlock {
onError?.({
filePath: luaFilePath,
line: fileContent.substring(0, leftCursor).split('\n').length - 1,
message: "Unexpected 'end' without matching block start"
message: "Unexpected 'end' without matching block start",
type: CompilationErrorType.Syntax
});
} else {
currentBlock = parent;
@@ -302,7 +323,7 @@ export abstract class CodeBlock {
currentWord = '';
}
leftCursor++;
advanceCursor();
}
// Handle case where file ends while in a ReturnBlock
if (currentBlock.blockType === BlockType.Return) {
@@ -548,7 +569,7 @@ export class FunctionBlock extends CodeBlock {
export class RequireBlock extends CodeBlock {
constructor(sourceLineNumber: number, parent: CodeBlock, public readonly charStart?: number, public readonly charEnd?: number) {
constructor(sourceLineNumber: number, parent: CodeBlock, public readonly charStart?: number, public charEnd?: number) {
super(sourceLineNumber, BlockType.Require, parent);
}
+10
View File
@@ -6,4 +6,14 @@ export interface CompilationError {
charStart?: number;
charEnd?: number;
message: string;
type: CompilationErrorType;
metaData?: Map<string, any>;
}
export enum CompilationErrorType {
Syntax = "Syntax",
Semantic = "Semantic",
Runtime = "Runtime",
DependencyCircular = "DependencyCircular",
DependencyNotFound = "DependencyNotFound"
}
+12 -4
View File
@@ -1,7 +1,7 @@
import * as fs from 'fs';
import * as path from 'path';
import { LuaFile, BlockType, CodeBlock, RequireBlock, ReturnBlock, FunctionBlock, TableBlock } from './CodeBlocks';
import { CompilationError } from './CompilationError';
import { CompilationError, CompilationErrorType } from './CompilationError';
export interface ScriptCompilerOptions {
sourcePath: string,
@@ -70,7 +70,8 @@ export class ScriptCompiler {
this.options.onError?.({
filePath: fullPath,
line: 0,
message: `Duplicate file key detected: ${key}. This can happen if two files have different capitalization. Lua is case sensitive, but the compiler treats file keys as case insensitive.`
message: `Duplicate file key detected: ${key}. This can happen if two files have different capitalization. Lua is case sensitive, but the compiler treats file keys as case insensitive.`,
type: CompilationErrorType.Semantic
});
continue;
}
@@ -305,7 +306,8 @@ class Writer {
this.onError({
filePath: file.fullPath,
line: 0,
message: `Circular dependency detected: ${cycle.map(x => x.split('.').pop()).join(' -> ')}`
message: `Circular dependency detected: ${cycle.map(x => x.split('.').pop()).join(' -> ')}`,
type: CompilationErrorType.DependencyCircular
});
}
return true;
@@ -348,7 +350,13 @@ class Writer {
line: dep.requiredAtLine,
charStart: dep.charStart,
charEnd: dep.charEnd,
message: `Missing dependency: ${dep.fileKey}`
message: `Missing dependency: ${dep.fileKey}`,
type: CompilationErrorType.DependencyNotFound,
metaData: new Map(
[
["dependency", dep.fileKey],
]
)
});
}
}