Skip to content

Commit 0c2d3d4

Browse files
author
TheDevConnor
committed
Updated the lsp for proper code completion and added a string_add function to the std. As well as made the lsp find the correct path for the std files
1 parent 12f714d commit 0c2d3d4

5 files changed

Lines changed: 159 additions & 19 deletions

File tree

src/helper/help.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
/** Enable debug logs for arena allocator (comment to disable) */
2929
#define DEBUG_ARENA_ALLOC 1
3030

31-
#define Luma_Compiler_version "v0.1.3"
31+
#define Luma_Compiler_version "v0.1.4"
3232

3333
/** Error codes returned by the compiler */
3434
typedef enum {

src/lsp/lsp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ bool lsp_document_analyze(LSPDocument *doc, LSPServer *server,
237237
// MODULE & IMPORT RESOLUTION
238238
// ============================================================================
239239

240+
void scan_std_library(LSPServer *server);
240241
void extract_imports(LSPDocument *doc, ArenaAllocator *arena);
241242
void resolve_imports(LSPServer *server, LSPDocument *doc, BuildConfig *config,
242243
GrowableArray *imported_modules);

src/lsp/lsp_features.c

Lines changed: 87 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -51,58 +51,128 @@ LSPCompletionItem *lsp_completion(LSPDocument *doc, LSPPosition position,
5151
GrowableArray completions;
5252
growable_array_init(&completions, arena, 32, sizeof(LSPCompletionItem));
5353

54-
// Add keyword snippets
5554
const struct {
5655
const char *label;
5756
const char *snippet;
5857
const char *detail;
5958
} keywords[] = {
60-
{"const fn",
61-
"const ${1:name} -> fn (${2:params}) ${3:Type} {\\n\\t$0\\n}",
59+
// Function declarations
60+
{"const fn", "const ${1:name} -> fn (${2:params}) ${3:Type} {\n\t$0\n}",
6261
"Function declaration"},
6362
{"pub const fn",
64-
"pub const ${1:name} -> fn (${2:params}) ${3:Type} {\\n\\t$0\\n}",
63+
"pub const ${1:name} -> fn (${2:params}) ${3:Type} {\n\t$0\n}",
6564
"Public function"},
6665

66+
// Generic functions
67+
{"const fn<T>",
68+
"const ${1:name} = fn<${2:T}>(${3:params}) ${4:Type} {\n\t$0\n}",
69+
"Generic function"},
70+
{"pub const fn<T>",
71+
"pub const ${1:name} = fn<${2:T}>(${3:params}) ${4:Type} {\n\t$0\n}",
72+
"Public generic function"},
73+
74+
// Type declarations
6775
{"const struct",
68-
"const ${1:Name} -> struct {\\n\\t${2:field}: ${3:Type}$0,\\n};",
76+
"const ${1:Name} -> struct {\n\t${2:field}: ${3:Type}$0,\n};",
6977
"Struct definition"},
70-
{"const enum", "const ${1:Name} -> enum {\\n\\t${2:Variant}$0,\\n};",
78+
{"const struct<T>",
79+
"const ${1:Name} -> struct<${2:T}> {\n\t${3:field}: ${4:Type}$0,\n};",
80+
"Generic struct"},
81+
{"const enum", "const ${1:Name} -> enum {\n\t${2:Variant}$0,\n};",
7182
"Enum definition"},
7283
{"const var", "const ${1:name}: ${2:Type} = ${3:value};$0",
7384
"Top-level constant"},
7485

75-
{"if", "if ${1:condition} {\\n\\t$0\\n}", "If statement"},
76-
{"if else", "if ${1:condition} {\\n\\t${2}\\n} else {\\n\\t$0\\n}",
86+
// Control flow - if/elif/else
87+
{"if", "if (${1:condition}) {\n\t$0\n}", "If statement"},
88+
{"if else", "if (${1:condition}) {\n\t${2}\n} else {\n\t$0\n}",
7789
"If-else statement"},
90+
{"elif", "elif (${1:condition}) {\n\t$0\n}", "Elif clause"},
7891

79-
{"loop", "loop {\\n\\t$0\\n}", "Infinite loop"},
92+
// Loop patterns
93+
{"loop", "loop {\n\t$0\n}", "Infinite loop"},
94+
{"loop while", "loop (${1:condition}) {\n\t$0\n}", "While-style loop"},
8095
{"loop for",
81-
"loop [${1:i}: int = 0](${1:i} < ${2:10}) : (++${1:i}) {\\n\\t$0\\n}",
96+
"loop [${1:i}: int = 0](${1:i} < ${2:10}) : (++${1:i}) {\n\t$0\n}",
8297
"For-style loop"},
98+
{"loop for multi",
99+
"loop [${1:i}: int = 0, ${2:j}: int = 0](${1:i} < ${3:10}) : (++${1:i}) "
100+
"{\n\t$0\n}",
101+
"Multi-variable for loop"},
83102

84-
{"switch", "switch (${1:value}) {\\n\\t${2:case} => ${3:result};$0\\n}",
103+
// Switch patterns
104+
{"switch", "switch (${1:value}) {\n\t${2:case} -> ${3:result};$0\n}",
85105
"Switch statement"},
106+
{"switch default",
107+
"switch (${1:value}) {\n\t${2:case} -> ${3:result};\n\t_ -> "
108+
"${4:default};$0\n}",
109+
"Switch with default case"},
86110

111+
// Variable declaration
87112
{"let", "let ${1:name}: ${2:Type} = ${3:value};$0",
88113
"Variable declaration"},
89114

90-
{"defer", "defer free(${1:ptr});$0", "Defer statement"},
91-
{"defer block", "defer {\\n\\t${1:cleanup()};\\n\\t$0\\n}",
92-
"Defer block"},
115+
// Defer patterns
116+
{"defer block", "defer {\n\t${1:cleanup()};$0\n}", "Defer block"},
93117

94-
{"@module", "@module \\\"${1:name}\\\"$0", "Module declaration"},
95-
{"@use", "@use \\\"${1:module}\\\" as ${2:alias}$0", "Import module"},
118+
// Module system
119+
{"@module", "@module \"${1:name}\"$0", "Module declaration"},
120+
{"@use", "@use \"${1:module}\" as ${2:alias}$0", "Import module"},
96121

122+
// Flow control
97123
{"return", "return ${1:value};$0", "Return statement"},
98124
{"break", "break;$0", "Break statement"},
99125
{"continue", "continue;$0", "Continue statement"},
100126

101-
{"main", "const main -> fn () int {\\n\\t$0\\n\\treturn 0;\\n};",
127+
// Common functions
128+
{"main", "const main -> fn () int {\n\t$0\n\treturn 0;\n};",
102129
"Main function"},
103130
{"outputln", "outputln(${1:message});$0", "Output with newline"},
131+
{"output", "output(${1:message});$0", "Output without newline"},
132+
133+
// Built-in functions
134+
{"input", "input<${1:Type}>(\"${2:prompt}\")$0", "Read typed input"},
135+
{"system", "system(\"${1:command}\");$0", "Execute system command"},
136+
137+
// Type operations
104138
{"cast", "cast<${1:Type}>(${2:value})$0", "Type cast"},
105139
{"sizeof", "sizeof<${1:Type}>$0", "Size of type"},
140+
141+
// Memory operations
142+
{"alloc", "cast<${1:*Type}>(alloc(${2:size} * sizeof<${3:Type}>))$0",
143+
"Allocate memory"},
144+
{"alloc defer",
145+
"let ${1:ptr}: ${2:*Type} = cast<${2:*Type}>(alloc(${3:size} * "
146+
"sizeof<${4:Type}>));\ndefer free(${1:ptr});$0",
147+
"Allocate with defer cleanup"},
148+
149+
// Struct patterns
150+
{"struct method", "${1:name} -> fn (${2:params}) ${3:Type} {\n\t$0\n}",
151+
"Struct method"},
152+
{"struct pub", "pub:\n\t${1:field}: ${2:Type},$0",
153+
"Public struct fields"},
154+
{"struct priv", "priv:\n\t${1:field}: ${2:Type},$0",
155+
"Private struct fields"},
156+
157+
// Array patterns
158+
{"array", "[${1:Type}; ${2:size}]$0", "Array type"},
159+
{"array init", "let ${1:arr}: [${2:Type}; ${3:size}] = [${4:values}];$0",
160+
"Array initialization"},
161+
162+
// Pointer patterns
163+
{"pointer", "*${1:Type}$0", "Pointer type"},
164+
{"address of", "&${1:variable}$0", "Address-of operator"},
165+
{"dereference", "*${1:pointer}$0", "Dereference pointer"},
166+
167+
// Function attributes
168+
{"#returns_ownership",
169+
"#returns_ownership\nconst ${1:name} -> fn (${2:params}) ${3:*Type} "
170+
"{\n\t$0\n}",
171+
"Function returns owned pointer"},
172+
{"#takes_ownership",
173+
"#takes_ownership\nconst ${1:name} -> fn (${2:ptr}: ${3:*Type}) void "
174+
"{\n\t$0\n}",
175+
"Function takes ownership"},
106176
};
107177

108178
for (size_t i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {

src/lsp/lsp_module.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#include "lsp.h"
1010

11+
#define LUMA_STD_PATH "/usr/local/lib/luma/std"
12+
1113
// Extract @module declaration from file content
1214
const char *extract_module_name(const char *content, ArenaAllocator *arena) {
1315
if (!content)
@@ -217,15 +219,40 @@ void build_module_registry(LSPServer *server, const char *workspace_uri) {
217219
arena_destroy(&temp_arena);
218220
}
219221

220-
// Look up module in registry
221222
const char *lookup_module(LSPServer *server, const char *module_name) {
223+
// First check workspace registry
222224
for (size_t i = 0; i < server->module_registry.count; i++) {
223225
if (strcmp(server->module_registry.entries[i].module_name, module_name) ==
224226
0) {
225227
return server->module_registry.entries[i].file_uri;
226228
}
227229
}
228230

231+
// If not found, check standard library
232+
ArenaAllocator temp_arena;
233+
arena_allocator_init(&temp_arena, 4096);
234+
235+
// Build path to std lib module
236+
size_t path_len = strlen(LUMA_STD_PATH) + strlen(module_name) + 10;
237+
char *std_path = arena_alloc(&temp_arena, path_len, 1);
238+
snprintf(std_path, path_len, "%s/%s.lx", LUMA_STD_PATH, module_name);
239+
240+
// Check if file exists
241+
FILE *test = fopen(std_path, "r");
242+
if (test) {
243+
fclose(test);
244+
const char *uri = lsp_path_to_uri(std_path, server->arena);
245+
arena_destroy(&temp_arena);
246+
247+
fprintf(stderr, "[LSP] Found module '%s' in std lib: %s\n", module_name,
248+
uri);
249+
return uri;
250+
}
251+
252+
arena_destroy(&temp_arena);
253+
254+
fprintf(stderr, "[LSP] Module '%s' not found in workspace or std lib\n",
255+
module_name);
229256
return NULL;
230257
}
231258

std/string.lx

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,3 +218,45 @@ pub const atio -> fn (value: *byte) int {
218218
}
219219
return num;
220220
}
221+
222+
pub const string_add -> fn (num1: *byte, num2: *byte) *byte {
223+
let len1: int = strlen(num1);
224+
let len2: int = strlen(num2);
225+
let max_len: int = 0;
226+
if (len1 > len2) max_len = len1; else max_len = len2;
227+
228+
// Result can be at most max_len + 1 digits
229+
let result: *byte = cast<*byte>(alloc(max_len + 2));
230+
let carry: int = 0;
231+
let result_idx: int = 0;
232+
233+
let i1: int = len1 - 1;
234+
let i2: int = len2 - 1;
235+
236+
// Add digits from right to left
237+
loop (i1 >= 0 || i2 >= 0 || carry > 0) {
238+
let digit1: int = 0;
239+
let digit2: int = 0;
240+
241+
if (i1 >= 0) digit1 = (cast<int>(num1[i1]) - 48); else digit1 = 0;
242+
if (i2 >= 0) digit2 = (cast<int>(num2[i2]) - 48); else digit2 = 0;
243+
244+
245+
let sum: int = digit1 + digit2 + carry;
246+
carry = sum / 10;
247+
result[result_idx++] = cast<byte>((sum % 10) + 48);
248+
249+
i1--;
250+
i2--;
251+
}
252+
253+
// Reverse the result
254+
loop [i: int = 0](i < result_idx / 2) : (++i) {
255+
let temp: byte = result[i];
256+
result[i] = result[result_idx - 1 - i];
257+
result[result_idx - 1 - i] = temp;
258+
}
259+
260+
result[result_idx] = '\0';
261+
return result;
262+
}

0 commit comments

Comments
 (0)