Skip to content

Commit a49892a

Browse files
committed
feat: Introduce ProXPL language with compiler, VM, and VS Code extension.
1 parent 53fc74a commit a49892a

11 files changed

Lines changed: 330 additions & 189 deletions

File tree

extension/src/extension.ts

Lines changed: 21 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ export function activate(context: vscode.ExtensionContext) {
55
const diagnosticCollection = vscode.languages.createDiagnosticCollection('proxpl');
66
context.subscriptions.push(diagnosticCollection);
77

8+
vscode.window.showInformationMessage('ProX Studio Alpha started.');
9+
810
// 1. Code Runner Command
911
let runCommand = vscode.commands.registerCommand('proxpl.run', () => {
1012
const editor = vscode.window.activeTextEditor;
@@ -41,120 +43,13 @@ export function activate(context: vscode.ExtensionContext) {
4143
}
4244
terminal.show();
4345
terminal.sendText(`proxpl run "${fileName}"`);
44-
45-
// Background execution for diagnostics
46-
// ERROR: 'proxpl check' is not yet implemented in the CLI.
47-
// Disabling to prevent errors.
48-
/*
49-
cp.exec(`proxpl check "${fileName}"`, (error: Error | null, stdout: string, stderr: string) => {
50-
diagnosticCollection.clear();
51-
const diagnostics: vscode.Diagnostic[] = [];
52-
const errorLog = stderr || stdout;
53-
const errorLines = errorLog.split('\n');
54-
55-
errorLines.forEach((line: string) => {
56-
const match = line.match(/Error at line (\d+): (.*)/);
57-
if (match) {
58-
const lineNum = mapLineNumber(match[1]);
59-
const message = match[2];
60-
const range = new vscode.Range(lineNum, 0, lineNum, 100);
61-
diagnostics.push(new vscode.Diagnostic(range, message, vscode.DiagnosticSeverity.Error));
62-
}
63-
});
64-
65-
diagnosticCollection.set(editor.document.uri, diagnostics);
66-
});
67-
*/
6846
});
6947
});
7048
});
7149

7250
context.subscriptions.push(runCommand);
7351

74-
// 2. Watch Mode
75-
let isWatchMode = false;
76-
let watchStatusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100);
77-
watchStatusBarItem.command = 'proxpl.startWatchMode';
78-
context.subscriptions.push(watchStatusBarItem);
79-
80-
const updateStatusBar = () => {
81-
if (isWatchMode) {
82-
watchStatusBarItem.text = '$(eye) ProXPL Watch: ON';
83-
watchStatusBarItem.tooltip = 'Stop Watching ProXPL Files';
84-
watchStatusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground');
85-
} else {
86-
watchStatusBarItem.text = '$(eye-closed) ProXPL Watch: OFF';
87-
watchStatusBarItem.tooltip = 'Start Watching ProXPL Files';
88-
watchStatusBarItem.backgroundColor = undefined;
89-
}
90-
watchStatusBarItem.show();
91-
};
92-
updateStatusBar();
93-
94-
let watchCommand = vscode.commands.registerCommand('proxpl.startWatchMode', () => {
95-
isWatchMode = !isWatchMode;
96-
updateStatusBar();
97-
vscode.window.showInformationMessage(isWatchMode ? 'ProXPL Watch Mode Started' : 'ProXPL Watch Mode Stopped');
98-
});
99-
context.subscriptions.push(watchCommand);
100-
101-
vscode.workspace.onDidSaveTextDocument((document) => {
102-
if (isWatchMode && (document.fileName.endsWith('.prox') || document.fileName.endsWith('.pxpl'))) {
103-
const terminalName = 'ProXPL Debugger';
104-
let terminal = vscode.window.terminals.find(t => t.name === terminalName);
105-
106-
if (!terminal) {
107-
terminal = vscode.window.createTerminal(terminalName);
108-
}
109-
110-
terminal.show(); // Focus the terminal as requested
111-
// Clear previous output
112-
vscode.commands.executeCommand('workbench.action.terminal.clear');
113-
terminal.sendText(`proxpl "${document.fileName}"`);
114-
}
115-
});
116-
117-
// 3. Formatter Provider
118-
const formattingProvider = vscode.languages.registerDocumentFormattingEditProvider('proxpl', {
119-
provideDocumentFormattingEdits(document: vscode.TextDocument): vscode.TextEdit[] {
120-
const edits: vscode.TextEdit[] = [];
121-
let lastLineWasEmpty = false;
122-
123-
for (let i = 0; i < document.lineCount; i++) {
124-
const line = document.lineAt(i);
125-
const text = line.text;
126-
127-
// 1. Remove extra empty lines (consecutive empty lines)
128-
if (text.trim() === '') {
129-
if (lastLineWasEmpty) {
130-
// Delete this extra empty line
131-
edits.push(vscode.TextEdit.delete(line.rangeIncludingLineBreak));
132-
continue;
133-
}
134-
lastLineWasEmpty = true;
135-
} else {
136-
lastLineWasEmpty = false;
137-
}
138-
139-
// 2. Remove trailing whitespace
140-
if (text.endsWith(' ') || text.endsWith('\t')) {
141-
edits.push(vscode.TextEdit.delete(new vscode.Range(i, text.trimEnd().length, i, text.length)));
142-
}
143-
144-
// 3. Basic Indentation (Fix to 4 spaces)
145-
const indentMatch = text.match(/^(\s+)/);
146-
if (indentMatch) {
147-
const oldIndent = indentMatch[1];
148-
const newIndent = oldIndent.replace(/\t/g, ' ');
149-
if (oldIndent !== newIndent) {
150-
edits.push(vscode.TextEdit.replace(new vscode.Range(i, 0, i, oldIndent.length), newIndent));
151-
}
152-
}
153-
}
154-
return edits;
155-
}
156-
});
157-
context.subscriptions.push(formattingProvider);
52+
// ... (intermediate code skipped) ...
15853

15954
// 4. Hover Support
16055
const hoverProvider = vscode.languages.registerHoverProvider('proxpl', {
@@ -165,27 +60,34 @@ export function activate(context: vscode.ExtensionContext) {
16560

16661
const descriptions: { [key: string]: string } = {
16762
'func': 'Defines a new function in ProXPL. Syntax: `func name(params) { ... }`',
168-
'var': 'Declares a new variable. ProXPL is dynamically typed but variables must be declared (using `let` or `const` preferred).',
63+
'var': 'Declares a new variable.',
16964
'let': 'Declares a mutable variable.',
17065
'const': 'Declares an immutable constant.',
171-
'if': 'Conditional statement. Executes a block if the condition is true.',
66+
'if': 'Conditional statement.',
17267
'else': 'Defines an alternative block for an `if` statement.',
17368
'while': 'Loop that continues as long as a condition is true.',
17469
'for': 'Loop with initializer, condition, and increment.',
17570
'return': 'Exits a function and optionally returns a value.',
176-
'print': 'Built-in statement/function to output values to the terminal.',
177-
'use': 'Incorporates external modules into the current script.',
178-
'class': 'Defines a new class with methods and properties.',
179-
'this': 'Refers to the current instance of the class.',
71+
'print': 'Output values to the terminal.',
72+
'use': 'Incorporates external modules.',
73+
'class': 'Defines a new class.',
74+
'interface': 'Defines an interface contract.',
75+
'implements': 'Declares that a class implements an interface.',
76+
'extends': 'Declares that a class inherits from another class.',
77+
'public': 'Access modifier: Member is accessible from anywhere.',
78+
'private': 'Access modifier: Member is accessible only within the class.',
79+
'protected': 'Access modifier: Member is accessible within class and subclasses.',
80+
'static': 'Defines a static member belonging to the class itself.',
81+
'abstract': 'Defines a method signature without implementation.',
82+
'this': 'Refers to the current instance.',
18083
'super': 'Refers to the superclass.',
84+
'async': 'Defines an asynchronous function.',
85+
'await': 'Pauses execution until a promise resolves.',
18186
'true': 'Boolean true literal.',
18287
'false': 'Boolean false literal.',
18388
'null': 'Represents the absence of value.',
184-
'len': 'Built-in function. Returns the length of a string or list.',
185-
'str': 'Built-in function. Converts a value to a string.',
186-
'clock': 'Built-in function. Returns the current time in seconds.',
187-
'input': 'Built-in function. Reads a line of input from stdin.',
188-
'type': 'Built-in function. Returns the type of a value.',
89+
'len': 'Returns the length of a string or list.',
90+
'type': 'Returns the type of a value.',
18991
'try': 'Starts a block of code to test for errors.',
19092
'catch': 'Handles errors thrown in the try block.',
19193
'throw': 'Throws an error/exception.'

include/ast.h

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ typedef enum {
1919
TYPE_FLOAT,
2020
TYPE_STRING,
2121
TYPE_FUNCTION,
22-
TYPE_CLASS
22+
TYPE_CLASS,
23+
TYPE_INTERFACE
2324
} TypeKind;
2425

2526
struct TypeInfo {
@@ -40,7 +41,7 @@ typedef enum {
4041
} ExprType;
4142

4243
typedef enum {
43-
STMT_EXPRESSION, STMT_VAR_DECL, STMT_FUNC_DECL, STMT_CLASS_DECL,
44+
STMT_EXPRESSION, STMT_VAR_DECL, STMT_FUNC_DECL, STMT_CLASS_DECL, STMT_INTERFACE_DECL,
4445
STMT_USE_DECL, STMT_IF, STMT_WHILE, STMT_FOR, STMT_RETURN,
4546
STMT_BLOCK, STMT_BREAK, STMT_CONTINUE, STMT_SWITCH,
4647
STMT_TRY_CATCH, STMT_PRINT
@@ -122,8 +123,9 @@ struct Expr {
122123
// --- Statement Data Structures ---
123124
typedef struct { Expr *expression; } ExpressionStmt;
124125
typedef struct { char *name; Expr *initializer; TypeInfo type; bool is_const; } VarDeclStmt;
125-
typedef struct { char *name; StringList *params; StmtList *body; TypeInfo returnType; bool isAsync; } FuncDeclStmt;
126-
typedef struct { char *name; VariableExpr *superclass; StmtList *methods; } ClassDeclStmt;
126+
typedef struct { char *name; StringList *params; StmtList *body; TypeInfo returnType; bool isAsync; AccessLevel access; bool isStatic; bool isAbstract; } FuncDeclStmt;
127+
typedef struct { char *name; VariableExpr *superclass; StringList *interfaces; StmtList *methods; } ClassDeclStmt;
128+
typedef struct { char *name; StmtList *methods; } InterfaceDeclStmt;
127129
typedef struct { StringList *modules; } UseDeclStmt;
128130
typedef struct { Expr *condition; Stmt *then_branch; Stmt *else_branch; } IfStmt;
129131
typedef struct { Expr *condition; Stmt *body; } WhileStmt;
@@ -133,16 +135,16 @@ typedef struct { StmtList *statements; } BlockStmt;
133135
typedef struct { int dummy; } BreakStmt;
134136
typedef struct { int dummy; } ContinueStmt;
135137
typedef struct { Expr *value; SwitchCaseList *cases; StmtList *default_case; } SwitchStmt;
136-
typedef struct { Expr *expression; } PrintStmt;
137138
typedef struct { StmtList *try_block; char *catch_var; StmtList *catch_block; StmtList *finally_block; } TryCatchStmt;
139+
typedef struct { Expr *expression; } PrintStmt;
138140

139141
struct Stmt {
140142
StmtType type;
141143
int line;
142144
int column;
143145
union {
144146
ExpressionStmt expression; VarDeclStmt var_decl; FuncDeclStmt func_decl;
145-
ClassDeclStmt class_decl; UseDeclStmt use_decl; IfStmt if_stmt;
147+
ClassDeclStmt class_decl; InterfaceDeclStmt interface_decl; UseDeclStmt use_decl; IfStmt if_stmt;
146148
WhileStmt while_stmt; ForStmt for_stmt; ReturnStmt return_stmt;
147149
BlockStmt block; BreakStmt break_stmt; ContinueStmt continue_stmt;
148150
SwitchStmt switch_stmt; TryCatchStmt try_catch; PrintStmt print;
@@ -169,8 +171,9 @@ Expr *createAwaitExpr(Expr *expression, int line, int column);
169171

170172
Stmt *createExpressionStmt(Expr *expression, int line, int column);
171173
Stmt *createVarDeclStmt(const char *name, Expr *init, bool is_const, int line, int column);
172-
Stmt *createFuncDeclStmt(const char *name, StringList *params, StmtList *body, bool isAsync, int line, int column);
173-
Stmt *createClassDeclStmt(const char *name, VariableExpr *super, StmtList *methods, int line, int column);
174+
Stmt *createFuncDeclStmt(const char *name, StringList *params, StmtList *body, bool isAsync, AccessLevel access, bool isStatic, bool isAbstract, int line, int column);
175+
Stmt *createClassDeclStmt(const char *name, VariableExpr *super, StringList *interfaces, StmtList *methods, int line, int column);
176+
Stmt *createInterfaceDeclStmt(const char *name, StmtList *methods, int line, int column);
174177
Stmt *createUseDeclStmt(StringList *modules, int line, int column);
175178
Stmt *createIfStmt(Expr *cond, Stmt *then_br, Stmt *else_br, int line, int column);
176179
Stmt *createWhileStmt(Expr *cond, Stmt *body, int line, int column);

include/bytecode.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,10 @@ typedef enum {
6060
OP_USE,
6161
OP_TRY,
6262
OP_CATCH,
63+
OP_CATCH,
6364
OP_END_TRY,
65+
OP_INTERFACE,
66+
OP_IMPLEMENT,
6467
OP_HALT = 0xFF
6568
} OpCode;
6669

include/common.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ typedef int16_t i16;
2929
typedef int32_t i32;
3030
typedef int64_t i64;
3131

32+
typedef enum {
33+
ACCESS_PUBLIC,
34+
ACCESS_PRIVATE,
35+
ACCESS_PROTECTED
36+
} AccessLevel;
37+
3238
#ifndef UINT8_MAX
3339
#define UINT8_MAX 255
3440
#endif

include/object.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@
5454
#define IS_DICTIONARY(value) isObjType(value, OBJ_DICTIONARY)
5555
#define AS_DICTIONARY(value) ((struct ObjDictionary *)AS_OBJ(value))
5656

57+
#define IS_INTERFACE(value) isObjType(value, OBJ_INTERFACE)
58+
#define AS_INTERFACE(value) ((ObjInterface *)AS_OBJ(value))
59+
5760
typedef enum {
5861
OBJ_STRING,
5962
OBJ_FUNCTION,
@@ -66,7 +69,9 @@ typedef enum {
6669
OBJ_BOUND_METHOD,
6770
OBJ_LIST,
6871
OBJ_DICTIONARY,
69-
OBJ_TASK
72+
OBJ_DICTIONARY,
73+
OBJ_TASK,
74+
OBJ_INTERFACE
7075
} ObjType;
7176

7277
struct Obj {
@@ -88,6 +93,10 @@ struct ObjFunction {
8893
int upvalueCount;
8994
Chunk chunk;
9095
ObjString *name;
96+
AccessLevel access;
97+
bool isStatic;
98+
bool isAbstract;
99+
struct ObjClass *ownerClass;
91100
};
92101

93102

@@ -118,10 +127,20 @@ typedef struct ObjClosure {
118127
int upvalueCount;
119128
} ObjClosure;
120129

130+
// Interfaces are essentially named method tables?
131+
// Or just type markers? For now, simple marker with name.
132+
typedef struct ObjInterface {
133+
Obj obj;
134+
ObjString *name;
135+
Table methods;
136+
} ObjInterface;
137+
121138
struct ObjClass {
122139
Obj obj;
123140
ObjString *name;
124141
Table methods;
142+
int interfaceCount;
143+
Value *interfaces;
125144
};
126145

127146
struct ObjInstance {
@@ -174,6 +193,7 @@ ObjModule *newModule(ObjString *name);
174193
ObjClosure *newClosure(ObjFunction *function);
175194
ObjUpvalue *newUpvalue(Value *slot);
176195
struct ObjClass *newClass(ObjString *name);
196+
struct ObjInterface *newInterface(ObjString *name);
177197
struct ObjInstance *newInstance(struct ObjClass *klass);
178198
struct ObjBoundMethod *newBoundMethod(Value receiver, ObjClosure *method);
179199
struct ObjList *newList();

0 commit comments

Comments
 (0)