Added Required logic if not found, and added better update logic
This commit is contained in:
+42
-21
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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],
|
||||
]
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user