Skip to content

Commit bc6730f

Browse files
author
dutchie031
committed
Fixed keywords and end blocks
1 parent 1dafe67 commit bc6730f

2 files changed

Lines changed: 266 additions & 25 deletions

File tree

compiler/src/CodeBlocks.ts

Lines changed: 172 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,22 @@ export enum BlockType {
2020
File
2121
}
2222

23-
const keywords = ['if', 'while', 'for', 'do', 'return', 'function', 'require', 'end'];
23+
const keywords = ['if', 'while', 'for', 'do', 'return', 'function', 'require', 'end', 'local', 'else', 'elseif'];
2424
function isKeyWord(word: string): boolean {
2525
return keywords.includes(word);
2626
}
2727

28+
function isIdentifierCharacter(char: string): boolean {
29+
return /[A-Za-z0-9_]/.test(char);
30+
}
31+
32+
/**
33+
* Trims trailing spaces and tabs, but preserves newlines
34+
*/
35+
function trimEndPreserveNewlines(str: string): string {
36+
return str.replace(/[ \t]+$/gm, '');
37+
}
38+
2839
export abstract class CodeBlock {
2940
protected childBlocks: CodeBlock[] = [];
3041
private parentBlock?: CodeBlock;
@@ -66,7 +77,11 @@ export abstract class CodeBlock {
6677

6778
while (leftCursor < fileContent.length) {
6879
const currentChar: string = fileContent[leftCursor];
69-
currentWord += currentChar;
80+
if (isIdentifierCharacter(currentChar)) {
81+
currentWord += currentChar;
82+
} else {
83+
currentWord = '';
84+
}
7085
currentBlockString += currentChar;
7186
const nextChar = leftCursor < fileContent.length - 1 ? fileContent[leftCursor + 1] : '';
7287

@@ -121,8 +136,8 @@ export abstract class CodeBlock {
121136
// }
122137
else if (currentChar === "\n") {
123138
// Process line
124-
currentBlockString = currentBlockString.trimEnd(); // Remove trailing whitespace
125-
currentBlockString += '\n'; // Add the newline back for the line block
139+
currentBlockString = trimEndPreserveNewlines(currentBlockString); // Remove trailing spaces/tabs
140+
//currentBlockString += '\n'; // Add the newline back for the line block
126141
if (currentBlockString !== '') {
127142
const lineBlock = new CodeTextBlock(lineCounter, currentBlockString, currentBlock);
128143
currentBlock.childBlocks.push(lineBlock);
@@ -131,8 +146,8 @@ export abstract class CodeBlock {
131146
}
132147
}
133148
else if (currentChar === ")" && currentBlock.blockType === BlockType.Require) {
134-
currentBlockString = currentBlockString.trimEnd(); // Remove trailing whitespace
135-
currentBlockString += '\n'; // Add the newline back for the line block as it will be skipped otherwise
149+
currentBlockString = trimEndPreserveNewlines(currentBlockString); // Remove trailing spaces/tabs
150+
//currentBlockString += '\n'; // Add the newline back for the line block as it will be skipped otherwise
136151
const lineBlock = new CodeTextBlock(lineCounter, currentBlockString, currentBlock);
137152
currentBlock.childBlocks.push(lineBlock);
138153
currentBlockString = '';
@@ -142,8 +157,8 @@ export abstract class CodeBlock {
142157
//Table blocks
143158
else if (currentChar === "{") {
144159
// Only create LineBlock if there's content before the brace
145-
if (currentBlockString.trimEnd() !== '' && currentBlockString.trimEnd() !== '{') {
146-
const currentLineBlock = new CodeTextBlock(lineCounter, currentBlockString.slice(0, -1).trimEnd(), currentBlock);
160+
if (trimEndPreserveNewlines(currentBlockString) !== '' && trimEndPreserveNewlines(currentBlockString) !== '{') {
161+
const currentLineBlock = new CodeTextBlock(lineCounter, trimEndPreserveNewlines(currentBlockString.slice(0, -1)), currentBlock);
147162
currentBlock.childBlocks.push(currentLineBlock);
148163
}
149164

@@ -174,8 +189,7 @@ export abstract class CodeBlock {
174189
}
175190

176191
if (char === '\n') {
177-
let block = currentBlockString.trimEnd();
178-
block += '\n';
192+
let block = trimEndPreserveNewlines(currentBlockString);
179193
const lineBlock = new CodeTextBlock(lineCounter, block, currentBlock);
180194
currentBlock.childBlocks.push(lineBlock);
181195
currentBlockString = '';
@@ -194,11 +208,13 @@ export abstract class CodeBlock {
194208
if (tempCursor < fileContent.length && fileContent[tempCursor] === '\n') {
195209
currentBlockString += '\n';
196210
lineCounter++;
197-
} else {
198-
leftCursor = tempCursor - 1; // Set leftCursor to the last character before the newline or non-whitespace character
211+
} else if (tempCursor > leftCursor) {
212+
// We found whitespace but no newline, so position cursor at last whitespace
213+
leftCursor = tempCursor - 1;
199214
}
215+
// else: no whitespace after table, leave leftCursor where it is
200216

201-
if (currentBlockString !== '') {
217+
if (trimEndPreserveNewlines(currentBlockString) !== '') {
202218
const lineBlock = new CodeTextBlock(lineCounter, currentBlockString, currentBlock);
203219
currentBlock.childBlocks.push(lineBlock);
204220
currentBlockString = '';
@@ -208,10 +224,22 @@ export abstract class CodeBlock {
208224
currentWord = ''; // Reset word accumulator after table block
209225
continue; // Skip the leftCursor++ at the end of the loop since we already incremented it
210226
}
211-
else if (nextChar.trim() === '' || nextChar === '(') {
227+
else if (currentWord !== '' && !isIdentifierCharacter(nextChar)) {
212228
// End of a word, check for keywords
213229
const trimmedWord = currentWord.trim();
230+
231+
232+
if (currentBlock.blockType === BlockType.Return && isKeyWord(trimmedWord) && trimmedWord !== 'return') {
233+
// We're in a ReturnBlock and hit a keyword at the statement boundary
234+
// Extract return params and exit the block
235+
(currentBlock as ReturnBlock).extractReturnParams();
236+
currentBlock = currentBlock.getParentBlock()!;
237+
// Don't clear currentBlockString - let normal flow handle the newline finalization
238+
// Continue to process this keyword normally
239+
}
240+
214241
let blockToAdd: CodeBlock | null = null;
242+
215243
if (trimmedWord === 'if') {
216244
blockToAdd = new IfBlock(lineCounter, currentBlock);
217245
}
@@ -222,20 +250,39 @@ export abstract class CodeBlock {
222250
blockToAdd = new ForBlock(lineCounter, currentBlock);
223251
}
224252
else if (trimmedWord === 'do') {
225-
blockToAdd = new DoBlock(lineCounter, currentBlock);
253+
const isForOrWhile = currentBlock.blockType === BlockType.While || currentBlock.blockType === BlockType.For;
254+
if(isForOrWhile && (currentBlock as WhileBlock | ForBlock).passedDoStatement == false) {
255+
// If we're in a While or For block and we've not yet passed a 'do' statement, mark it as passed and don't create a new block
256+
(currentBlock as WhileBlock | ForBlock).passedDoStatement = true;
257+
} else {
258+
blockToAdd = new DoBlock(lineCounter, currentBlock);
259+
}
226260
}
227261
else if (trimmedWord === 'return') {
228-
const line = new CodeTextBlock(lineCounter, currentBlockString.trimEnd().slice(0, -trimmedWord.length), currentBlock);
229-
currentBlock.childBlocks.push(line);
230-
currentBlockString = 'return';
262+
// Add any text before 'return' to parent block, but preserve newlines
263+
const beforeReturn = currentBlockString.slice(0, -trimmedWord.length);
264+
if (beforeReturn.trim()) {
265+
const line = new CodeTextBlock(lineCounter, beforeReturn, currentBlock);
266+
currentBlock.childBlocks.push(line);
267+
}
231268
blockToAdd = new ReturnBlock(lineCounter, currentBlock);
269+
// Start the return block content with 'return' keyword
270+
currentBlockString = trimmedWord;
232271
}
233272
else if (trimmedWord === 'function') {
234273
blockToAdd = new FunctionBlock(lineCounter, currentBlock);
235274
}
236275
else if (trimmedWord === 'require') {
276+
const beforeRequire = currentBlockString.slice(0, -trimmedWord.length);
277+
if (beforeRequire.trim()) {
278+
const line = new CodeTextBlock(lineCounter, beforeRequire, currentBlock);
279+
currentBlock.childBlocks.push(line);
280+
}
281+
237282
blockToAdd = new RequireBlock(lineCounter, currentBlock, leftCursor - currentWord.length, leftCursor);
238-
} else if (trimmedWord === 'end') {
283+
currentBlockString = trimmedWord; // Start the require block content with 'require' keyword
284+
}
285+
else if (trimmedWord === 'end') {
239286
const parent = currentBlock.getParentBlock();
240287
if (!parent) {
241288
onError?.({
@@ -257,6 +304,14 @@ export abstract class CodeBlock {
257304
}
258305
leftCursor++;
259306
}
307+
// Handle case where file ends while in a ReturnBlock
308+
if (currentBlock.blockType === BlockType.Return) {
309+
if (trimEndPreserveNewlines(currentBlockString) !== '') {
310+
const lineBlock = new CodeTextBlock(lineCounter, currentBlockString, currentBlock);
311+
currentBlock.childBlocks.push(lineBlock);
312+
}
313+
(currentBlock as ReturnBlock).extractReturnParams();
314+
}
260315
return file;
261316
}
262317
}
@@ -289,6 +344,8 @@ export class IfBlock extends CodeBlock {
289344

290345
export class WhileBlock extends CodeBlock {
291346

347+
public passedDoStatement: boolean = false;
348+
292349
constructor(sourceLineNumber: number, parent: CodeBlock) {
293350
super(sourceLineNumber, BlockType.While, parent);
294351
}
@@ -304,6 +361,8 @@ export class WhileBlock extends CodeBlock {
304361

305362
export class ForBlock extends CodeBlock {
306363

364+
public passedDoStatement: boolean = false;
365+
307366
constructor(sourceLineNumber: number, parent: CodeBlock) {
308367
super(sourceLineNumber, BlockType.For, parent);
309368
}
@@ -350,6 +409,8 @@ export class DoBlock extends CodeBlock {
350409

351410
export class ReturnBlock extends CodeBlock {
352411

412+
public readonly returnParams: string[] = [];
413+
353414
constructor(sourceLineNumber: number, parent: CodeBlock) {
354415
super(sourceLineNumber, BlockType.Return, parent);
355416
}
@@ -361,6 +422,98 @@ export class ReturnBlock extends CodeBlock {
361422
}
362423
return lines;
363424
}
425+
426+
/**
427+
* Extracts return parameters from the return statement.
428+
* Splits by commas while respecting nesting of {} and ().
429+
* Populates the returnParams array.
430+
*/
431+
extractReturnParams(): void {
432+
// Reconstruct the return content from all children
433+
let content = this.childBlocks
434+
.map(child => {
435+
if (child instanceof CodeTextBlock) {
436+
return child.toLines()[0];
437+
} else if (child instanceof TableBlock) {
438+
// For tables, use their full content
439+
return child.toLines().join('');
440+
} else {
441+
// For other block types, use their full content
442+
return child.toLines().join('');
443+
}
444+
})
445+
.join('')
446+
.trim();
447+
448+
if (!content) {
449+
this.returnParams.length = 0;
450+
return;
451+
}
452+
453+
content = content.replace(/^return\s+/, '').trim(); // Remove the 'return' keyword if present
454+
455+
// Split by commas while respecting nesting
456+
const params: string[] = [];
457+
let currentParam = '';
458+
let braceDepth = 0;
459+
let parenDepth = 0;
460+
461+
for (let i = 0; i < content.length; i++) {
462+
const char = content[i];
463+
const nextChar = i < content.length - 1 ? content[i + 1] : '';
464+
465+
// Skip strings to avoid counting delimiters inside them
466+
if (char === '"' || char === "'") {
467+
const quoteType = char;
468+
currentParam += char;
469+
i++;
470+
while (i < content.length && content[i] !== quoteType) {
471+
if (content[i] === '\\' && i + 1 < content.length) {
472+
currentParam += content[i];
473+
i++;
474+
currentParam += content[i];
475+
} else {
476+
currentParam += content[i];
477+
}
478+
i++;
479+
}
480+
if (i < content.length) {
481+
currentParam += content[i];
482+
}
483+
continue;
484+
}
485+
486+
// Track nesting depth
487+
if (char === '{') {
488+
braceDepth++;
489+
} else if (char === '}') {
490+
braceDepth--;
491+
} else if (char === '(') {
492+
parenDepth++;
493+
} else if (char === ')') {
494+
parenDepth--;
495+
} else if (char === ',' && braceDepth === 0 && parenDepth === 0) {
496+
// This is a param separator
497+
const param = currentParam.trim();
498+
if (param) {
499+
params.push(param);
500+
}
501+
currentParam = '';
502+
continue;
503+
}
504+
505+
currentParam += char;
506+
}
507+
508+
// Add the last parameter
509+
const lastParam = currentParam.trim();
510+
if (lastParam) {
511+
params.push(lastParam);
512+
}
513+
514+
this.returnParams.length = 0;
515+
this.returnParams.push(...params);
516+
}
364517
}
365518

366519
export class TableBlock extends CodeBlock {

0 commit comments

Comments
 (0)