@robinpath/robinpath 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +856 -0
- package/bin/robinpath.js +374 -0
- package/dist/classes/ASTSerializer.d.ts +45 -0
- package/dist/classes/ExecutionStateTracker.d.ts +30 -0
- package/dist/classes/Executor.d.ts +193 -0
- package/dist/classes/ExpressionEvaluator.d.ts +20 -0
- package/dist/classes/Lexer.d.ts +86 -0
- package/dist/classes/Parser.d.ts +71 -0
- package/dist/classes/RobinPathThread.d.ts +146 -0
- package/dist/classes/TokenStream.d.ts +217 -0
- package/dist/classes/code-converter/ASTToCodeConverter.d.ts +178 -0
- package/dist/classes/code-converter/LineIndex.d.ts +54 -0
- package/dist/classes/code-converter/Printer.d.ts +117 -0
- package/dist/classes/code-converter/Writer.d.ts +42 -0
- package/dist/classes/code-converter/index.d.ts +8 -0
- package/dist/classes/code-converter/types.d.ts +29 -0
- package/dist/classes/exceptions.d.ts +26 -0
- package/dist/classes/index.d.ts +16 -0
- package/dist/index.d.ts +485 -0
- package/dist/index.js +13808 -0
- package/dist/modules/Array.d.ts +10 -0
- package/dist/modules/Core.d.ts +10 -0
- package/dist/modules/Dom.d.ts +10 -0
- package/dist/modules/Fetch.d.ts +6 -0
- package/dist/modules/Json.d.ts +10 -0
- package/dist/modules/Math.d.ts +10 -0
- package/dist/modules/Object.d.ts +10 -0
- package/dist/modules/Random.d.ts +6 -0
- package/dist/modules/String.d.ts +10 -0
- package/dist/modules/Test.d.ts +10 -0
- package/dist/modules/Time.d.ts +10 -0
- package/dist/parsers/ArrayLiteralParser.d.ts +17 -0
- package/dist/parsers/AssignmentParser.d.ts +37 -0
- package/dist/parsers/BracketParser.d.ts +31 -0
- package/dist/parsers/BreakParser.d.ts +15 -0
- package/dist/parsers/CellBlockParser.d.ts +11 -0
- package/dist/parsers/ChunkMarkerParser.d.ts +12 -0
- package/dist/parsers/CommandParser.d.ts +56 -0
- package/dist/parsers/CommentParser.d.ts +37 -0
- package/dist/parsers/ContinueParser.d.ts +15 -0
- package/dist/parsers/DecoratorParser.d.ts +29 -0
- package/dist/parsers/DefineParser.d.ts +18 -0
- package/dist/parsers/EventParser.d.ts +17 -0
- package/dist/parsers/ExpressionParser.d.ts +3 -0
- package/dist/parsers/FenceClassifier.d.ts +29 -0
- package/dist/parsers/ForLoopParser.d.ts +17 -0
- package/dist/parsers/IfBlockParser.d.ts +17 -0
- package/dist/parsers/ObjectLiteralParser.d.ts +17 -0
- package/dist/parsers/ParserUtils.d.ts +15 -0
- package/dist/parsers/PromptBlockParser.d.ts +10 -0
- package/dist/parsers/ReturnParser.d.ts +16 -0
- package/dist/parsers/ScopeParser.d.ts +24 -0
- package/dist/parsers/StringTemplateParser.d.ts +31 -0
- package/dist/parsers/SubexpressionParser.d.ts +33 -0
- package/dist/parsers/TogetherBlockParser.d.ts +18 -0
- package/dist/parsers/WithScopeParser.d.ts +24 -0
- package/dist/types/Ast.type.d.ts +455 -0
- package/dist/types/Environment.type.d.ts +53 -0
- package/dist/utils/args.d.ts +24 -0
- package/dist/utils/errorFormatter.d.ts +22 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/stringParsing.d.ts +41 -0
- package/dist/utils/types.d.ts +15 -0
- package/dist/utils/valueConversion.d.ts +25 -0
- package/package.json +50 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lexer class for tokenizing RobinPath code
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Token kinds for RobinPath language
|
|
6
|
+
* Using const object instead of enum for better compatibility
|
|
7
|
+
*/
|
|
8
|
+
export declare const TokenKind: {
|
|
9
|
+
readonly STRING: "STRING";
|
|
10
|
+
readonly NUMBER: "NUMBER";
|
|
11
|
+
readonly BOOLEAN: "BOOLEAN";
|
|
12
|
+
readonly NULL: "NULL";
|
|
13
|
+
readonly IDENTIFIER: "IDENTIFIER";
|
|
14
|
+
readonly VARIABLE: "VARIABLE";
|
|
15
|
+
readonly KEYWORD: "KEYWORD";
|
|
16
|
+
readonly ASSIGN: "ASSIGN";
|
|
17
|
+
readonly PLUS: "PLUS";
|
|
18
|
+
readonly MINUS: "MINUS";
|
|
19
|
+
readonly MULTIPLY: "MULTIPLY";
|
|
20
|
+
readonly DIVIDE: "DIVIDE";
|
|
21
|
+
readonly MODULO: "MODULO";
|
|
22
|
+
readonly EQ: "EQ";
|
|
23
|
+
readonly NE: "NE";
|
|
24
|
+
readonly GT: "GT";
|
|
25
|
+
readonly LT: "LT";
|
|
26
|
+
readonly GTE: "GTE";
|
|
27
|
+
readonly LTE: "LTE";
|
|
28
|
+
readonly AND: "AND";
|
|
29
|
+
readonly OR: "OR";
|
|
30
|
+
readonly NOT: "NOT";
|
|
31
|
+
readonly LPAREN: "LPAREN";
|
|
32
|
+
readonly RPAREN: "RPAREN";
|
|
33
|
+
readonly LBRACKET: "LBRACKET";
|
|
34
|
+
readonly RBRACKET: "RBRACKET";
|
|
35
|
+
readonly LBRACE: "LBRACE";
|
|
36
|
+
readonly RBRACE: "RBRACE";
|
|
37
|
+
readonly COMMA: "COMMA";
|
|
38
|
+
readonly COLON: "COLON";
|
|
39
|
+
readonly DOT: "DOT";
|
|
40
|
+
readonly DECORATOR: "DECORATOR";
|
|
41
|
+
readonly COMMENT: "COMMENT";
|
|
42
|
+
readonly NEWLINE: "NEWLINE";
|
|
43
|
+
readonly EOF: "EOF";
|
|
44
|
+
readonly SUBEXPRESSION_OPEN: "SUBEXPRESSION_OPEN";
|
|
45
|
+
};
|
|
46
|
+
export type TokenKind = typeof TokenKind[keyof typeof TokenKind];
|
|
47
|
+
/**
|
|
48
|
+
* List of RobinPath keywords
|
|
49
|
+
*/
|
|
50
|
+
export declare const KEYWORDS: Set<string>;
|
|
51
|
+
/**
|
|
52
|
+
* A single token in the source code
|
|
53
|
+
*/
|
|
54
|
+
export interface Token {
|
|
55
|
+
kind: TokenKind;
|
|
56
|
+
text: string;
|
|
57
|
+
line: number;
|
|
58
|
+
column: number;
|
|
59
|
+
value?: any;
|
|
60
|
+
isContinuation?: boolean;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Position information for error reporting
|
|
64
|
+
*/
|
|
65
|
+
export interface SourcePosition {
|
|
66
|
+
line: number;
|
|
67
|
+
column: number;
|
|
68
|
+
}
|
|
69
|
+
export declare class Lexer {
|
|
70
|
+
/**
|
|
71
|
+
* Tokenize entire source code into Token objects
|
|
72
|
+
* This is the new token-stream based approach
|
|
73
|
+
*
|
|
74
|
+
* @param source - Full source code (multi-line)
|
|
75
|
+
* @returns Array of tokens with position information
|
|
76
|
+
*/
|
|
77
|
+
static tokenizeFull(source: string): Token[];
|
|
78
|
+
/**
|
|
79
|
+
* Legacy tokenize method - kept for backward compatibility
|
|
80
|
+
* Tokenizes a single line into string tokens
|
|
81
|
+
*
|
|
82
|
+
* @param line - A single line of code
|
|
83
|
+
* @returns Array of string tokens
|
|
84
|
+
*/
|
|
85
|
+
static tokenize(line: string): string[];
|
|
86
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Statement, CodePosition, DefineFunction, OnBlock } from '../types/Ast.type';
|
|
2
|
+
import { Environment } from '../index';
|
|
3
|
+
export interface ExtractedVariable {
|
|
4
|
+
name: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
initialValue?: any;
|
|
7
|
+
codePos: CodePosition;
|
|
8
|
+
}
|
|
9
|
+
export declare class Parser {
|
|
10
|
+
private tokens;
|
|
11
|
+
private stream;
|
|
12
|
+
private source;
|
|
13
|
+
private extractedFunctions;
|
|
14
|
+
private extractedEventHandlers;
|
|
15
|
+
private extractedVariables;
|
|
16
|
+
private environment;
|
|
17
|
+
private decoratorBuffer;
|
|
18
|
+
private pendingComments;
|
|
19
|
+
/**
|
|
20
|
+
* Maximum number of iterations allowed before detecting an infinite loop
|
|
21
|
+
*/
|
|
22
|
+
static readonly MAX_STUCK_ITERATIONS = 100;
|
|
23
|
+
/**
|
|
24
|
+
* Debug mode flag - set to true to enable logging
|
|
25
|
+
* Can be controlled via VITE_DEBUG environment variable or set programmatically
|
|
26
|
+
*/
|
|
27
|
+
static debug: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Create a new Parser
|
|
30
|
+
* @param source - Full source code as a single string
|
|
31
|
+
* @param environment - Optional environment for executing parse decorators
|
|
32
|
+
*/
|
|
33
|
+
constructor(source: string, environment?: Environment | null);
|
|
34
|
+
/**
|
|
35
|
+
* Parse the source code into an AST
|
|
36
|
+
* @returns Array of statements
|
|
37
|
+
*/
|
|
38
|
+
parse(): Promise<Statement[]>;
|
|
39
|
+
/**
|
|
40
|
+
* Parse a statement from a stream with hierarchical nodeKey support
|
|
41
|
+
*/
|
|
42
|
+
private parseStatementFromStream;
|
|
43
|
+
/**
|
|
44
|
+
* Get extracted function definitions (def/enddef blocks)
|
|
45
|
+
*/
|
|
46
|
+
getExtractedFunctions(): DefineFunction[];
|
|
47
|
+
/**
|
|
48
|
+
* Get extracted event handlers (on/endon blocks)
|
|
49
|
+
*/
|
|
50
|
+
getExtractedEventHandlers(): OnBlock[];
|
|
51
|
+
/**
|
|
52
|
+
* Get extracted variables (from assignments)
|
|
53
|
+
*/
|
|
54
|
+
getExtractedVariables(): ExtractedVariable[];
|
|
55
|
+
/**
|
|
56
|
+
* Track a variable from an assignment statement
|
|
57
|
+
*/
|
|
58
|
+
private trackVariable;
|
|
59
|
+
/**
|
|
60
|
+
* Parse a single statement
|
|
61
|
+
*/
|
|
62
|
+
private parseStatement;
|
|
63
|
+
private parseCommentFromStream;
|
|
64
|
+
private attachInlineComments;
|
|
65
|
+
private countTrailingBlankLines;
|
|
66
|
+
/**
|
|
67
|
+
* Recursively assign nodeKeys to body statements
|
|
68
|
+
* This ensures all nested statements have hierarchical nodeKeys for execution tracking
|
|
69
|
+
*/
|
|
70
|
+
private assignBodyNodeKeys;
|
|
71
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { Value } from '../utils';
|
|
2
|
+
import { Environment, OnBlock, RobinPath } from '../index';
|
|
3
|
+
export declare class RobinPathThread {
|
|
4
|
+
private environment;
|
|
5
|
+
private executor;
|
|
6
|
+
readonly id: string;
|
|
7
|
+
private parent;
|
|
8
|
+
private serializer;
|
|
9
|
+
constructor(baseEnvironment: Environment, id: string, parent?: RobinPath);
|
|
10
|
+
/**
|
|
11
|
+
* Check if a script needs more input (incomplete block)
|
|
12
|
+
* Returns { needsMore: true, waitingFor: 'endif' | 'enddef' | 'endfor' | 'enddo' | 'subexpr' | 'paren' | 'object' | 'array' } if incomplete,
|
|
13
|
+
* or { needsMore: false } if complete.
|
|
14
|
+
*/
|
|
15
|
+
needsMoreInput(script: string): Promise<{
|
|
16
|
+
needsMore: boolean;
|
|
17
|
+
waitingFor?: 'endif' | 'enddef' | 'endfor' | 'enddo' | 'subexpr' | 'paren' | 'object' | 'array';
|
|
18
|
+
}>;
|
|
19
|
+
/**
|
|
20
|
+
* Execute a RobinPath script in this thread
|
|
21
|
+
*/
|
|
22
|
+
executeScript(script: string): Promise<Value>;
|
|
23
|
+
/**
|
|
24
|
+
* Execute a single line in this thread (for REPL)
|
|
25
|
+
*/
|
|
26
|
+
executeLine(line: string): Promise<Value>;
|
|
27
|
+
/**
|
|
28
|
+
* Get the last value ($) from this thread
|
|
29
|
+
*/
|
|
30
|
+
getLastValue(): Value;
|
|
31
|
+
/**
|
|
32
|
+
* Get a variable value from this thread
|
|
33
|
+
*/
|
|
34
|
+
getVariable(name: string): Value;
|
|
35
|
+
/**
|
|
36
|
+
* Set a variable value in this thread
|
|
37
|
+
*/
|
|
38
|
+
setVariable(name: string, value: Value): void;
|
|
39
|
+
/**
|
|
40
|
+
* Get all variables in this thread as a plain object
|
|
41
|
+
*/
|
|
42
|
+
getVariableState(): Record<string, Value>;
|
|
43
|
+
/**
|
|
44
|
+
* Get the current module name (set by "use" command)
|
|
45
|
+
* Returns null if no module is currently in use
|
|
46
|
+
*/
|
|
47
|
+
getCurrentModule(): string | null;
|
|
48
|
+
/**
|
|
49
|
+
* Get the parent RobinPath instance
|
|
50
|
+
*/
|
|
51
|
+
getParent(): RobinPath | null;
|
|
52
|
+
/**
|
|
53
|
+
* Get the environment for this thread (for CLI access to metadata)
|
|
54
|
+
*/
|
|
55
|
+
getEnvironment(): Environment;
|
|
56
|
+
/**
|
|
57
|
+
* Get the AST without execution state
|
|
58
|
+
* Returns a JSON-serializable AST array
|
|
59
|
+
*
|
|
60
|
+
* Note: This method only parses the script, it does not execute it.
|
|
61
|
+
*/
|
|
62
|
+
getAST(script: string): Promise<any[]>;
|
|
63
|
+
/**
|
|
64
|
+
* Get extracted function definitions (def/enddef blocks) from a script
|
|
65
|
+
* Returns a JSON-serializable array of function definitions
|
|
66
|
+
*
|
|
67
|
+
* Note: This method only parses the script, it does not execute it.
|
|
68
|
+
*/
|
|
69
|
+
getExtractedFunctions(script: string): Promise<any[]>;
|
|
70
|
+
/**
|
|
71
|
+
* Get all event handlers as a flat array
|
|
72
|
+
* @returns Array of all OnBlock handlers
|
|
73
|
+
*/
|
|
74
|
+
getAllEventHandlers(): OnBlock[];
|
|
75
|
+
/**
|
|
76
|
+
* Get event handlers as serialized AST
|
|
77
|
+
* @returns Array of serialized event handler AST nodes
|
|
78
|
+
*/
|
|
79
|
+
getEventAST(): any[];
|
|
80
|
+
/**
|
|
81
|
+
* Get the AST with execution state for the current thread
|
|
82
|
+
* Returns a JSON-serializable object with:
|
|
83
|
+
* - AST nodes with execution state ($ lastValue at each node)
|
|
84
|
+
* - Available variables (thread-local and global)
|
|
85
|
+
* - Organized for UI representation
|
|
86
|
+
*
|
|
87
|
+
* Note: This method executes the script to capture execution state at each node.
|
|
88
|
+
*/
|
|
89
|
+
getASTWithState(script: string): Promise<{
|
|
90
|
+
ast: any[];
|
|
91
|
+
variables: {
|
|
92
|
+
thread: Record<string, Value>;
|
|
93
|
+
global: Record<string, Value>;
|
|
94
|
+
};
|
|
95
|
+
lastValue: Value;
|
|
96
|
+
callStack: Array<{
|
|
97
|
+
locals: Record<string, Value>;
|
|
98
|
+
lastValue: Value;
|
|
99
|
+
}>;
|
|
100
|
+
}>;
|
|
101
|
+
/**
|
|
102
|
+
* Execute statements with state tracking
|
|
103
|
+
*/
|
|
104
|
+
private executeWithStateTracking;
|
|
105
|
+
/**
|
|
106
|
+
* Get all available commands, modules, and functions for this thread
|
|
107
|
+
* Includes thread-local user-defined functions in addition to shared builtins and modules
|
|
108
|
+
*
|
|
109
|
+
* @param context Optional syntax context to filter commands based on what's valid next
|
|
110
|
+
*/
|
|
111
|
+
getAvailableCommands(context?: {
|
|
112
|
+
inIfBlock?: boolean;
|
|
113
|
+
inDefBlock?: boolean;
|
|
114
|
+
afterIf?: boolean;
|
|
115
|
+
afterDef?: boolean;
|
|
116
|
+
afterElseif?: boolean;
|
|
117
|
+
}): {
|
|
118
|
+
native: Array<{
|
|
119
|
+
name: string;
|
|
120
|
+
type: string;
|
|
121
|
+
description: string;
|
|
122
|
+
}>;
|
|
123
|
+
builtin: Array<{
|
|
124
|
+
name: string;
|
|
125
|
+
type: string;
|
|
126
|
+
description: string;
|
|
127
|
+
}>;
|
|
128
|
+
modules: Array<{
|
|
129
|
+
name: string;
|
|
130
|
+
type: string;
|
|
131
|
+
description: string;
|
|
132
|
+
author?: string;
|
|
133
|
+
category?: string;
|
|
134
|
+
}>;
|
|
135
|
+
moduleFunctions: Array<{
|
|
136
|
+
name: string;
|
|
137
|
+
type: string;
|
|
138
|
+
description: string;
|
|
139
|
+
}>;
|
|
140
|
+
userFunctions: Array<{
|
|
141
|
+
name: string;
|
|
142
|
+
type: string;
|
|
143
|
+
description: string;
|
|
144
|
+
}>;
|
|
145
|
+
};
|
|
146
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { TokenKind, Token } from './Lexer';
|
|
2
|
+
/**
|
|
3
|
+
* Parsing context types that the TokenStream can track
|
|
4
|
+
*/
|
|
5
|
+
export declare const ParsingContext: {
|
|
6
|
+
readonly NONE: "none";
|
|
7
|
+
readonly ARRAY_LITERAL: "array_literal";
|
|
8
|
+
readonly OBJECT_LITERAL: "object_literal";
|
|
9
|
+
readonly FUNCTION_CALL: "function_call";
|
|
10
|
+
readonly SUBEXPRESSION: "subexpression";
|
|
11
|
+
readonly BLOCK: "block";
|
|
12
|
+
readonly FUNCTION_DEFINITION: "function_definition";
|
|
13
|
+
readonly STRING_LITERAL: "string_literal";
|
|
14
|
+
};
|
|
15
|
+
export type ParsingContext = typeof ParsingContext[keyof typeof ParsingContext];
|
|
16
|
+
export declare class TokenStream {
|
|
17
|
+
private tokens;
|
|
18
|
+
private position;
|
|
19
|
+
private contextStack;
|
|
20
|
+
private lastNextPosition;
|
|
21
|
+
private consecutiveNextCalls;
|
|
22
|
+
private positionHistory;
|
|
23
|
+
private operationsSinceLastAdvance;
|
|
24
|
+
private lastPositionValue;
|
|
25
|
+
/**
|
|
26
|
+
* Maximum number of consecutive next() calls allowed at the same position before throwing
|
|
27
|
+
*/
|
|
28
|
+
static readonly MAX_CONSECUTIVE_NEXT_AT_SAME_POSITION = 3;
|
|
29
|
+
/**
|
|
30
|
+
* Maximum number of operations without position advancement before detecting stuck
|
|
31
|
+
* Only counts operations that should advance (next, match, expect, etc.)
|
|
32
|
+
*/
|
|
33
|
+
static readonly MAX_OPERATIONS_WITHOUT_ADVANCE = 100;
|
|
34
|
+
/**
|
|
35
|
+
* Debug mode flag - set to true to enable logging
|
|
36
|
+
* Can be controlled via VITE_DEBUG environment variable or set programmatically
|
|
37
|
+
* Usage: TokenStream.debug = true;
|
|
38
|
+
*/
|
|
39
|
+
static debug: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Create a new TokenStream
|
|
42
|
+
* @param tokens - Array of tokens to stream
|
|
43
|
+
* @param startIndex - Optional starting index (default 0)
|
|
44
|
+
*/
|
|
45
|
+
constructor(tokens: Token[], startIndex?: number);
|
|
46
|
+
/**
|
|
47
|
+
* Create a new TokenStream starting from the given index
|
|
48
|
+
* Useful for sub-parsing operations that need to start from a specific position
|
|
49
|
+
* @param index - Starting index in the token array
|
|
50
|
+
* @returns New TokenStream instance starting at the given index
|
|
51
|
+
*/
|
|
52
|
+
cloneFrom(index: number): TokenStream;
|
|
53
|
+
/**
|
|
54
|
+
* Reset stuck detection counters (useful when manually advancing position)
|
|
55
|
+
*/
|
|
56
|
+
resetStuckDetection(): void;
|
|
57
|
+
/**
|
|
58
|
+
* Set the current position directly
|
|
59
|
+
* @param position - New position
|
|
60
|
+
*/
|
|
61
|
+
setPosition(position: number): void;
|
|
62
|
+
/**
|
|
63
|
+
* Get the current token without consuming it
|
|
64
|
+
* @returns The current token, or null if at end
|
|
65
|
+
*/
|
|
66
|
+
current(): Token | null;
|
|
67
|
+
/**
|
|
68
|
+
* Look ahead at a token without consuming it
|
|
69
|
+
* @param offset - Number of tokens to look ahead (default 0 = current token)
|
|
70
|
+
* @returns The token at the given offset, or null if beyond end
|
|
71
|
+
*/
|
|
72
|
+
peek(offset?: number): Token | null;
|
|
73
|
+
/**
|
|
74
|
+
* Consume and return the current token
|
|
75
|
+
* @returns The current token, or null if at end
|
|
76
|
+
* @throws Error if called multiple times at the same position (indicates infinite loop)
|
|
77
|
+
*/
|
|
78
|
+
next(): Token | null;
|
|
79
|
+
/**
|
|
80
|
+
* Check if the stream appears to be stuck (no position advancement)
|
|
81
|
+
* @param operation - Name of the operation being performed
|
|
82
|
+
* @throws Error if stuck condition detected
|
|
83
|
+
*/
|
|
84
|
+
private checkStuckCondition;
|
|
85
|
+
/**
|
|
86
|
+
* Check if we're at the end of the token stream
|
|
87
|
+
* @returns True if at EOF or beyond
|
|
88
|
+
*/
|
|
89
|
+
isAtEnd(): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Check if the current token matches the given kind or text, without consuming it
|
|
92
|
+
* @param kindOrText - TokenKind enum or string text to match
|
|
93
|
+
* @returns True if the current token matches
|
|
94
|
+
*/
|
|
95
|
+
check(kindOrText: TokenKind | string): boolean;
|
|
96
|
+
/**
|
|
97
|
+
* If the current token matches, consume it and return true
|
|
98
|
+
* Otherwise, return false without consuming
|
|
99
|
+
*
|
|
100
|
+
* @param kindOrText - TokenKind enum or string text to match
|
|
101
|
+
* @returns True if matched and consumed, false otherwise
|
|
102
|
+
*/
|
|
103
|
+
match(kindOrText: TokenKind | string): boolean;
|
|
104
|
+
/**
|
|
105
|
+
* Expect the current token to match, consume it, and return it
|
|
106
|
+
* If it doesn't match, throw an error
|
|
107
|
+
*
|
|
108
|
+
* @param kindOrText - TokenKind enum or string text to expect
|
|
109
|
+
* @param message - Optional custom error message
|
|
110
|
+
* @returns The consumed token
|
|
111
|
+
* @throws Error if token doesn't match
|
|
112
|
+
*/
|
|
113
|
+
expect(kindOrText: TokenKind | string, message?: string): Token;
|
|
114
|
+
/**
|
|
115
|
+
* Save the current position for potential backtracking
|
|
116
|
+
* @returns The current position index
|
|
117
|
+
*/
|
|
118
|
+
save(): number;
|
|
119
|
+
/**
|
|
120
|
+
* Restore a previously saved position (backtrack)
|
|
121
|
+
* @param pos - The position to restore to
|
|
122
|
+
*/
|
|
123
|
+
restore(pos: number): void;
|
|
124
|
+
/**
|
|
125
|
+
* Skip tokens of a specific kind (useful for skipping newlines, comments, etc.)
|
|
126
|
+
* @param kind - The TokenKind to skip
|
|
127
|
+
* @returns Number of tokens skipped
|
|
128
|
+
*/
|
|
129
|
+
skip(kind: TokenKind): number;
|
|
130
|
+
/**
|
|
131
|
+
* Skip all newline tokens
|
|
132
|
+
* @returns Number of newlines skipped
|
|
133
|
+
*/
|
|
134
|
+
skipNewlines(): number;
|
|
135
|
+
/**
|
|
136
|
+
* Consume tokens until a specific kind or text is found (exclusive)
|
|
137
|
+
* @param kindOrText - The kind or text to stop at
|
|
138
|
+
* @returns Array of consumed tokens (not including the stop token)
|
|
139
|
+
*/
|
|
140
|
+
consumeUntil(kindOrText: TokenKind | string): Token[];
|
|
141
|
+
/**
|
|
142
|
+
* Collect all tokens on the current line (until NEWLINE or EOF)
|
|
143
|
+
* @returns Array of tokens on the current line
|
|
144
|
+
*/
|
|
145
|
+
collectLine(): Token[];
|
|
146
|
+
/**
|
|
147
|
+
* Get the current position in the stream
|
|
148
|
+
* @returns Current position index
|
|
149
|
+
*/
|
|
150
|
+
getPosition(): number;
|
|
151
|
+
/**
|
|
152
|
+
* Get the total number of tokens in the stream
|
|
153
|
+
* @returns Total token count
|
|
154
|
+
*/
|
|
155
|
+
getLength(): number;
|
|
156
|
+
/**
|
|
157
|
+
* Get all remaining tokens without consuming them
|
|
158
|
+
* @returns Array of remaining tokens
|
|
159
|
+
*/
|
|
160
|
+
remaining(): Token[];
|
|
161
|
+
/**
|
|
162
|
+
* Create a sub-stream from a range of tokens
|
|
163
|
+
* Useful for parsing sub-expressions or blocks
|
|
164
|
+
*
|
|
165
|
+
* @param start - Start position (inclusive)
|
|
166
|
+
* @param end - End position (exclusive), defaults to current position
|
|
167
|
+
* @returns New TokenStream instance
|
|
168
|
+
*/
|
|
169
|
+
slice(start: number, end?: number): TokenStream;
|
|
170
|
+
/**
|
|
171
|
+
* Format current position for error messages
|
|
172
|
+
* @returns String like "line 10, column 5"
|
|
173
|
+
*/
|
|
174
|
+
formatPosition(): string;
|
|
175
|
+
/**
|
|
176
|
+
* Push a parsing context onto the context stack
|
|
177
|
+
* @param context - The parsing context to enter
|
|
178
|
+
*/
|
|
179
|
+
pushContext(context: ParsingContext): void;
|
|
180
|
+
/**
|
|
181
|
+
* Pop the most recent parsing context from the stack
|
|
182
|
+
* @returns The context that was removed, or NONE if stack was empty
|
|
183
|
+
*/
|
|
184
|
+
popContext(): ParsingContext;
|
|
185
|
+
/**
|
|
186
|
+
* Get the current parsing context (top of the stack)
|
|
187
|
+
* @returns The current parsing context, or NONE if no context is active
|
|
188
|
+
*/
|
|
189
|
+
getCurrentContext(): ParsingContext;
|
|
190
|
+
/**
|
|
191
|
+
* Check if we're currently in a specific parsing context
|
|
192
|
+
* @param context - The context to check for
|
|
193
|
+
* @returns True if we're in the given context (at any level)
|
|
194
|
+
*/
|
|
195
|
+
isInContext(context: ParsingContext): boolean;
|
|
196
|
+
/**
|
|
197
|
+
* Get all active contexts (the entire stack)
|
|
198
|
+
* @returns Array of contexts from bottom to top
|
|
199
|
+
*/
|
|
200
|
+
getContextStack(): ParsingContext[];
|
|
201
|
+
/**
|
|
202
|
+
* Clear all parsing contexts
|
|
203
|
+
*/
|
|
204
|
+
clearContexts(): void;
|
|
205
|
+
/**
|
|
206
|
+
* Create a new TokenStream with the same tokens and contexts
|
|
207
|
+
* Useful for sub-parsing that should inherit context
|
|
208
|
+
* @param startIndex - Optional starting index (defaults to current position)
|
|
209
|
+
* @returns New TokenStream instance with copied context
|
|
210
|
+
*/
|
|
211
|
+
cloneWithContext(startIndex?: number): TokenStream;
|
|
212
|
+
/**
|
|
213
|
+
* Skip whitespace (newlines) and comments
|
|
214
|
+
* Advances the stream past any consecutive newline or comment tokens
|
|
215
|
+
*/
|
|
216
|
+
skipWhitespaceAndComments(): void;
|
|
217
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { Statement, CommentWithPosition } from '../../types/Ast.type';
|
|
2
|
+
import { Writer } from './Writer';
|
|
3
|
+
import { LineIndex } from './LineIndex';
|
|
4
|
+
import { Patch, CommentLayout, PrintContext } from './types';
|
|
5
|
+
export type { CommentWithPosition, LineIndex, PrintContext };
|
|
6
|
+
export { Writer };
|
|
7
|
+
/**
|
|
8
|
+
* CommentLayout - Normalize comment ownership
|
|
9
|
+
*
|
|
10
|
+
* Decides, per statement:
|
|
11
|
+
* - leadingComments: Comment[] (non-inline)
|
|
12
|
+
* - inlineComment: Comment | null
|
|
13
|
+
* - leadingGapLines: number (blank lines between last leading comment and statement)
|
|
14
|
+
* - trailingBlankLinesAfterStandaloneComment: number (only for standalone comment nodes)
|
|
15
|
+
*/
|
|
16
|
+
export declare class CommentLayoutNormalizer {
|
|
17
|
+
/**
|
|
18
|
+
* Normalize comment layout for a statement
|
|
19
|
+
*/
|
|
20
|
+
static normalize(node: Statement, lineIndex: LineIndex): CommentLayout;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* PatchApplier - Apply patches to source code
|
|
24
|
+
*
|
|
25
|
+
* Sort patches descending (as you do now) and apply.
|
|
26
|
+
* Optional: validate overlaps and throw in dev mode.
|
|
27
|
+
*/
|
|
28
|
+
export declare class PatchApplier {
|
|
29
|
+
/**
|
|
30
|
+
* Apply patches to source code
|
|
31
|
+
* Patches are sorted descending by startOffset and applied from end to start
|
|
32
|
+
* to prevent character position shifts from affecting subsequent replacements
|
|
33
|
+
*/
|
|
34
|
+
static apply(originalScript: string, patches: Patch[]): string;
|
|
35
|
+
/**
|
|
36
|
+
* Validate that patches don't overlap
|
|
37
|
+
* @internal This method is kept for potential future use or manual invocation
|
|
38
|
+
*/
|
|
39
|
+
static validatePatches(patches: Patch[]): void;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* PatchPlanner - Collect edit operations
|
|
43
|
+
*
|
|
44
|
+
* Produces Patch[] = { startOffset, endOffset, replacement }.
|
|
45
|
+
* Responsible for "range selection" (including blank lines, inline comment removal, etc.)
|
|
46
|
+
* Must guarantee patches don't overlap (or resolve overlaps deterministically).
|
|
47
|
+
*/
|
|
48
|
+
export declare class PatchPlanner {
|
|
49
|
+
private lineIndex;
|
|
50
|
+
private patches;
|
|
51
|
+
private originalScript;
|
|
52
|
+
private originalAST;
|
|
53
|
+
/**
|
|
54
|
+
* Enable defensive validation of extracted code.
|
|
55
|
+
* When true, extracted code is validated before use and falls back to regeneration if invalid.
|
|
56
|
+
* Set via ROBINPATH_DEBUG environment variable or constructor option.
|
|
57
|
+
*/
|
|
58
|
+
private debugMode;
|
|
59
|
+
constructor(originalScript: string, options?: {
|
|
60
|
+
debugMode?: boolean;
|
|
61
|
+
});
|
|
62
|
+
/**
|
|
63
|
+
* Plan patches for all nodes in the AST
|
|
64
|
+
* This includes patches for:
|
|
65
|
+
* - Updated nodes (in modified AST)
|
|
66
|
+
* - New nodes (in modified AST but not in original)
|
|
67
|
+
* - Deleted nodes (in original AST but not in modified)
|
|
68
|
+
*/
|
|
69
|
+
planPatches(ast: Statement[]): Promise<Patch[]>;
|
|
70
|
+
/**
|
|
71
|
+
* Plan a patch for a deleted node
|
|
72
|
+
*/
|
|
73
|
+
private planPatchForDeletedNode;
|
|
74
|
+
/**
|
|
75
|
+
* Plan a patch for a single node
|
|
76
|
+
*/
|
|
77
|
+
private planPatchForNode;
|
|
78
|
+
/**
|
|
79
|
+
* Plan a patch for a new node (insertion)
|
|
80
|
+
*/
|
|
81
|
+
private planPatchForNewNode;
|
|
82
|
+
/**
|
|
83
|
+
* Plan patch for leading comments (non-overlapping case)
|
|
84
|
+
*/
|
|
85
|
+
private planPatchForLeadingComments;
|
|
86
|
+
/**
|
|
87
|
+
* Generate replacement without leading comments (for non-overlapping case)
|
|
88
|
+
*/
|
|
89
|
+
private generateReplacementWithoutLeadingComments;
|
|
90
|
+
/**
|
|
91
|
+
* Plan patch for a standalone comment node
|
|
92
|
+
*/
|
|
93
|
+
private planPatchForCommentNode;
|
|
94
|
+
/**
|
|
95
|
+
* Find the stop row for comment blank line inclusion
|
|
96
|
+
*/
|
|
97
|
+
private findStopRowForComment;
|
|
98
|
+
/**
|
|
99
|
+
* Plan patch to remove existing comments
|
|
100
|
+
*/
|
|
101
|
+
private planPatchToRemoveComments;
|
|
102
|
+
/**
|
|
103
|
+
* Compute the range for a statement region
|
|
104
|
+
*/
|
|
105
|
+
private computeStatementRange;
|
|
106
|
+
/**
|
|
107
|
+
* Generate replacement text for a node
|
|
108
|
+
*/
|
|
109
|
+
private generateReplacement;
|
|
110
|
+
/**
|
|
111
|
+
* Preserve blank lines that were included in the range after the statement
|
|
112
|
+
*/
|
|
113
|
+
private preserveBlankLinesInRange;
|
|
114
|
+
/**
|
|
115
|
+
* Extract original code from the script if the node hasn't changed
|
|
116
|
+
* Returns null if the node has changed and needs regeneration
|
|
117
|
+
*
|
|
118
|
+
* This preserves all original formatting including:
|
|
119
|
+
* - Indentation (spaces and tabs)
|
|
120
|
+
* - Spacing within statements
|
|
121
|
+
* - Blank lines
|
|
122
|
+
*/
|
|
123
|
+
private extractOriginalCode;
|
|
124
|
+
/**
|
|
125
|
+
* Validate extracted code by checking if it parses correctly and matches expected type.
|
|
126
|
+
* Used in debug mode to detect extraction corruption.
|
|
127
|
+
*/
|
|
128
|
+
private validateExtractedCode;
|
|
129
|
+
/**
|
|
130
|
+
* Find the original node that corresponds to the modified node
|
|
131
|
+
*/
|
|
132
|
+
private findOriginalNode;
|
|
133
|
+
/**
|
|
134
|
+
* Compare two nodes to see if they're equal (ignoring codePos and metadata)
|
|
135
|
+
*/
|
|
136
|
+
private nodesAreEqual;
|
|
137
|
+
/**
|
|
138
|
+
* Generate code with preserved indentation and spacing from original
|
|
139
|
+
* This is used when we must regenerate code but want to preserve formatting
|
|
140
|
+
*/
|
|
141
|
+
private generateCodeWithPreservedIndentation;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* ASTToCodeConverter - Converts AST nodes back to source code
|
|
145
|
+
*
|
|
146
|
+
* This class handles the conversion of AST (Abstract Syntax Tree) nodes
|
|
147
|
+
* back into RobinPath source code strings. It provides methods for:
|
|
148
|
+
* - Updating source code based on AST changes
|
|
149
|
+
* - Reconstructing code from individual AST nodes
|
|
150
|
+
* - Handling comments, indentation, and code positioning
|
|
151
|
+
*/
|
|
152
|
+
export declare class ASTToCodeConverter {
|
|
153
|
+
/**
|
|
154
|
+
* Validate that AST node positions are within bounds of the source code.
|
|
155
|
+
* This helps detect stale AST data from external source modifications.
|
|
156
|
+
*
|
|
157
|
+
* @param source The current source code
|
|
158
|
+
* @param ast The AST to validate
|
|
159
|
+
* @returns Object with isValid flag and optional error details
|
|
160
|
+
*/
|
|
161
|
+
private validateASTPositions;
|
|
162
|
+
/**
|
|
163
|
+
* Update source code based on AST changes
|
|
164
|
+
* Uses precise character-level positions (codePos.startRow/startCol/endRow/endCol) to update code
|
|
165
|
+
* Nested nodes are reconstructed as part of their parent's code
|
|
166
|
+
* @param originalScript The original source code
|
|
167
|
+
* @param ast The modified AST array (top-level nodes only)
|
|
168
|
+
* @returns Updated source code
|
|
169
|
+
*/
|
|
170
|
+
updateCodeFromAST(originalScript: string, ast: Statement[]): Promise<string>;
|
|
171
|
+
/**
|
|
172
|
+
* Reconstruct code string from an AST node
|
|
173
|
+
* @param node The AST node (serialized)
|
|
174
|
+
* @param indentLevel Indentation level for nested code
|
|
175
|
+
* @returns Reconstructed code string, or null if cannot be reconstructed
|
|
176
|
+
*/
|
|
177
|
+
reconstructCodeFromASTNode(node: Statement, indentLevel?: number): string | null;
|
|
178
|
+
}
|