Skip to content

Commit 74c2200

Browse files
authored
Add files via upload
1 parent acbff0e commit 74c2200

4 files changed

Lines changed: 106 additions & 107 deletions

File tree

src/main/java/cod/interpreter/ExpressionEvaluator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,4 +212,4 @@ private boolean isForLoopStepEvaluation(BinaryOpNode binOp, ObjectInstance obj,
212212
DebugSystem.debug("FOR_LOOP_STEP", "Checking if binary op is for loop step: " + binOp.op);
213213
return true; // TEMPORARY: Allow all assignment operators in expressions for now
214214
}
215-
}
215+
}

src/main/java/cod/interpreter/IOHandler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ public Object readInput(String targetType) {
6767
}
6868

6969
public void output(Object value) {
70-
System.out.println(String.valueOf(value));
70+
System.out.print(String.valueOf(value)); // CHANGED: println to print
7171
}
7272

7373
public void close() {
7474
inputScanner.close();
7575
}
76-
}
76+
}

src/main/java/cod/interpreter/Interpreter.java

Lines changed: 57 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,8 @@ private void initializeImportResolver(UnitNode unit) {
9797
DebugSystem.debug("IMPORTS", "Initializing import resolver for unit: " + unit.name);
9898

9999
// UPDATED: Only pre-load imports that were already resolved during AST building
100-
// Don't try to resolve new imports here - do it lazily when needed
101100
if (unit.resolvedImports != null && !unit.resolvedImports.isEmpty()) {
102-
DebugSystem.debug(
103-
"IMPORTS",
104-
"Pre-loading " + unit.resolvedImports.size() + " resolved imports from AST");
101+
DebugSystem.debug("IMPORTS", "Pre-loading " + unit.resolvedImports.size() + " resolved imports from AST");
105102
for (Map.Entry<String, ProgramNode> entry : unit.resolvedImports.entrySet()) {
106103
String importName = entry.getKey();
107104
ProgramNode importedProgram = entry.getValue();
@@ -258,27 +255,15 @@ boolean shouldReturnEarly(
258255
return true; // All slots in current path are assigned
259256
}
260257

261-
public Object evalMethodCall(
262-
MethodCallNode call,
263-
ObjectInstance obj,
264-
Map<String, Object> locals) {
265-
DebugSystem.methodEntry("call:" + call.name, emptyParamMap());
266-
267-
// ADDED: Detailed debugging for method call
268-
DebugSystem.debug("METHOD_CALL", "=== METHOD CALL ENTERED ===");
258+
public Object evalMethodCall(MethodCallNode call, ObjectInstance obj, Map<String, Object> locals) {
259+
DebugSystem.debug("METHOD_CALL", "=== METHOD CALL DEBUG ===");
269260
DebugSystem.debug("METHOD_CALL", "call.name: " + call.name);
270261
DebugSystem.debug("METHOD_CALL", "call.qualifiedName: " + call.qualifiedName);
271262
DebugSystem.debug("METHOD_CALL", "call.slotNames: " + call.slotNames);
272-
DebugSystem.debug("METHOD_CALL", "call.arguments: " + call.arguments.size());
273-
for (int i = 0; i < call.arguments.size(); i++) {
274-
DebugSystem.debug("METHOD_CALL", " arg[" + i + "]: " + call.arguments.get(i).getClass().getSimpleName());
275-
}
276263
DebugSystem.debug("METHOD_CALL", "Current object type: " + obj.type.name);
277-
DebugSystem.debug("METHOD_CALL", "Current object fields: " + obj.fields.keySet());
278-
264+
279265
MethodNode method = null;
280266

281-
// First, try to find method in current type
282267
DebugSystem.debug("METHOD_CALL", "Searching for local method: '" + call.name + "'");
283268
for (int i = 0; i < obj.type.methods.size(); i++) {
284269
MethodNode candidate = obj.type.methods.get(i);
@@ -290,19 +275,15 @@ public Object evalMethodCall(
290275
}
291276
}
292277

293-
// If not found locally, try to resolve as imported method
294278
if (method == null) {
295279
DebugSystem.debug("METHOD_CALL", "Method not found locally, attempting import resolution");
296280

297-
// FIX: Handle cases where the method name itself might be qualified
298281
String qualifiedMethodName = call.qualifiedName;
299282

300-
// If qualifiedName is null but call.name contains dots, use call.name as qualified
301283
if (qualifiedMethodName == null && call.name.contains(".")) {
302284
qualifiedMethodName = call.name;
303285
DebugSystem.debug("IMPORTS", "Using call.name as qualified name: " + qualifiedMethodName);
304286
} else if (qualifiedMethodName == null) {
305-
// Fallback: just use the simple name
306287
qualifiedMethodName = call.name;
307288
DebugSystem.debug("IMPORTS", "Using simple name as qualified name: " + qualifiedMethodName);
308289
} else if (qualifiedMethodName != null) {
@@ -314,49 +295,34 @@ public Object evalMethodCall(
314295

315296
if (method != null) {
316297
DebugSystem.debug("IMPORTS", "Successfully resolved imported method: " + qualifiedMethodName);
317-
DebugSystem.debug("IMPORTS", "Resolved method details - name: " + method.name +
318-
", params: " + method.parameters.size() +
319-
", slots: " + method.returnSlots.size()); // This works again!
320298
} else {
321299
DebugSystem.warn("IMPORTS", "Failed to resolve imported method: " + qualifiedMethodName);
322-
323-
// Additional debugging: show what imports are available
324-
Set<String> availableImports = importResolver.getLoadedImports();
325-
DebugSystem.debug("IMPORTS", "Available loaded imports: " + availableImports);
326-
Set<String> registeredImports = importResolver.getRegisteredImports();
327-
DebugSystem.debug("IMPORTS", "Registered imports: " + registeredImports);
328-
329-
// Show what methods are available in current type for comparison
330-
DebugSystem.debug("IMPORTS", "Available local methods:");
331-
for (MethodNode m : obj.type.methods) {
332-
DebugSystem.debug("IMPORTS", " - " + m.name);
333-
}
334300
}
335301
}
336302

337303
if (method == null) {
338-
DebugSystem.error(
339-
"IMPORTS",
340-
"Method not found: "
341-
+ (call.qualifiedName != null ? call.qualifiedName : call.name));
342-
// Debug: List available methods in current type
304+
DebugSystem.error("IMPORTS", "Method not found: " +
305+
(call.qualifiedName != null ? call.qualifiedName : call.name));
306+
343307
DebugSystem.debug("METHODS", "Available methods in current type:");
344308
for (MethodNode m : obj.type.methods) {
345309
DebugSystem.debug("METHODS", " - " + m.name);
346310
}
347311

348-
// Show import status for debugging
349312
importResolver.debugImportStatus();
350313

351314
throw new RuntimeException(
352-
"Method not found: "
353-
+ (call.qualifiedName != null ? call.qualifiedName : call.name));
315+
"Method not found: " +
316+
(call.qualifiedName != null ? call.qualifiedName : call.name));
317+
}
318+
319+
if (method.isBuiltin) {
320+
return handleBuiltinMethod(method, call, obj, locals);
354321
}
355322

356323
Map<String, Object> newLocals = new HashMap<String, Object>();
357324
DebugSystem.debug("METHODS", "Evaluating " + call.arguments.size() + " arguments");
358325

359-
// Validate parameter count
360326
if (call.arguments.size() != method.parameters.size()) {
361327
throw new RuntimeException(
362328
"Parameter count mismatch for method " + method.name +
@@ -366,88 +332,86 @@ public Object evalMethodCall(
366332

367333
for (int i = 0; i < call.arguments.size(); i++) {
368334
ParamNode param = method.parameters.get(i);
369-
Object argValue =
370-
exprEvaluator.evaluate(
371-
call.arguments.get(i), obj, locals);
335+
Object argValue = exprEvaluator.evaluate(call.arguments.get(i), obj, locals);
372336
newLocals.put(param.name, argValue);
373337
DebugSystem.debug("MEMORY", "Bound parameter: " + param.name + " = " + argValue);
374338
}
375339

376-
// --- MODIFICATION: Reverted to original, efficient slot initialization ---
377340
Map<String, Object> slotValues = new HashMap<String, Object>();
378341
for (SlotNode s : method.returnSlots) {
379342
slotValues.put(s.name, null);
380343
DebugSystem.debug("SLOTS", "Initialized return slot: " + s.name);
381344
}
382-
// --- END MODIFICATION (REMOVED PRE-SCAN LOOP) ---
383-
384345

385-
// Execute method body with access to both locals AND slots
386346
Map<String, Object> previousSlots = currentSlots;
387347
currentSlots = slotValues;
388348

389-
// FIX: Only set up slot path tracking if the called method has slots
390349
Set<String> previousSlotsInPath = slotsInCurrentPath;
391-
boolean calledMethodHasSlots = !method.returnSlots.isEmpty(); // This works again
350+
boolean calledMethodHasSlots = !method.returnSlots.isEmpty();
392351
if (calledMethodHasSlots) {
393352
slotsInCurrentPath = new HashSet<>(slotValues.keySet());
394353
DebugSystem.debug("SLOTS", "Called method has " + method.returnSlots.size() + " slots");
395354
} else {
396-
slotsInCurrentPath = new HashSet<>(); // Empty for void methods
355+
slotsInCurrentPath = new HashSet<>();
397356
DebugSystem.debug("SLOTS", "Called method has no return slots");
398357
}
399358

400359
DebugSystem.debug("METHOD_CALL", "Executing method body for: " + method.name);
401360
for (StatementNode stmt : method.body) {
402-
stmtEvaluator.evalStmt(
403-
stmt, obj, newLocals, slotValues);
404-
// Check for early return in called method
361+
stmtEvaluator.evalStmt(stmt, obj, newLocals, slotValues);
405362
if (calledMethodHasSlots && shouldReturnEarly(slotValues)) {
406363
DebugSystem.debug("SLOTS", "Early return triggered in called method");
407364
break;
408365
}
409366
}
410367

411368
currentSlots = previousSlots;
412-
slotsInCurrentPath = previousSlotsInPath; // Restore previous slot path
369+
slotsInCurrentPath = previousSlotsInPath;
413370

414-
DebugSystem.methodExit("call:" + call.name, slotValues);
371+
DebugSystem.debug("METHOD_CALL", "Method call completed: " + method.name);
415372
return slotValues;
416373
}
417374

418-
private MethodNode resolveImportedMethod(String qualifiedMethodName) {
419-
DebugSystem.debug("IMPORTS", "resolveImportedMethod called with: " + qualifiedMethodName);
375+
private Object handleBuiltinMethod(MethodNode method, MethodCallNode call, ObjectInstance obj, Map<String, Object> locals) {
376+
switch (method.name) {
377+
case "outa":
378+
return handleSysOuta(call, obj, locals);
379+
default:
380+
throw new RuntimeException("Unknown builtin method: " + method.name);
381+
}
382+
}
420383

421-
try {
422-
MethodNode method = importResolver.findMethod(qualifiedMethodName);
423-
if (method != null) {
424-
DebugSystem.debug(
425-
"IMPORTS", "Successfully resolved imported method: " + qualifiedMethodName);
426-
DebugSystem.debug(
427-
"IMPORTS",
428-
"Method details - params: "
429-
+ method.parameters.size()
430-
+ ", slots: "
431-
+ method.returnSlots.size()); // This works again
432-
return method;
433-
} else {
434-
DebugSystem.warn(
435-
"IMPORTS", "Failed to resolve imported method: " + qualifiedMethodName);
436-
437-
// Debug: List available imports
438-
Set<String> loadedImports = importResolver.getLoadedImports();
439-
DebugSystem.debug("IMPORTS", "Loaded imports in resolver: " + loadedImports);
440-
return null;
441-
}
442-
} catch (Exception e) {
443-
DebugSystem.error(
444-
"IMPORTS",
445-
"Error resolving imported method "
446-
+ qualifiedMethodName
447-
+ ": "
448-
+ e.getMessage());
449-
e.printStackTrace();
384+
private Object handleSysOuta(MethodCallNode call, ObjectInstance obj, Map<String, Object> locals) {
385+
StringBuilder result = new StringBuilder();
386+
for (int i = 0; i < call.arguments.size(); i++) {
387+
Object value = exprEvaluator.evaluate(call.arguments.get(i), obj, locals);
388+
result.append(String.valueOf(value));
389+
}
390+
ioHandler.output(result.toString());
391+
return null;
392+
}
393+
394+
private MethodNode resolveImportedMethod(String qualifiedMethodName) {
395+
DebugSystem.debug("IMPORTS", "resolveImportedMethod called with: " + qualifiedMethodName);
396+
397+
try {
398+
MethodNode method = importResolver.findMethod(qualifiedMethodName);
399+
if (method != null) {
400+
DebugSystem.debug("IMPORTS", "Successfully resolved imported method: " + qualifiedMethodName);
401+
DebugSystem.debug("IMPORTS", "Method details - params: " + method.parameters.size() + ", slots: " + method.returnSlots.size());
402+
return method;
403+
} else {
404+
DebugSystem.warn("IMPORTS", "Failed to resolve imported method: " + qualifiedMethodName);
405+
406+
// Debug: List available imports
407+
Set<String> loadedImports = importResolver.getLoadedImports();
408+
DebugSystem.debug("IMPORTS", "Loaded imports in resolver: " + loadedImports);
450409
return null;
451410
}
411+
} catch (Exception e) {
412+
DebugSystem.error("IMPORTS", "Error resolving imported method " + qualifiedMethodName + ": " + e.getMessage());
413+
e.printStackTrace();
414+
return null;
452415
}
416+
}
453417
}

src/main/java/cod/interpreter/StatementEvaluator.java

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public Object evalStmt(StatementNode stmt, ObjectInstance obj, Map<String, Objec
4444

4545
// --- Enforce ~ for slots (NO CHANGE) ---
4646
if (slotValues != null && slotValues.containsKey(input.variableName)) {
47-
throw new RuntimeException("Cannot assign to slot '" + input.variableName + "' using '=' (from input). Use '~ " + input.variableName + " ...' syntax instead.");
47+
throw new RuntimeException("Cannot assign to slot '" + input.variableName + "' using '=' (from input). Use '~> " + input.variableName + " ...' syntax instead.");
4848
} else {
4949
obj.fields.put(input.variableName, inputValue);
5050
DebugSystem.fieldUpdate(input.variableName, inputValue);
@@ -135,7 +135,7 @@ public Object evalStmt(StatementNode stmt, ObjectInstance obj, Map<String, Objec
135135

136136
// --- Enforce ~ for slots (NO CHANGE) ---
137137
if (slotValues != null && slotValues.containsKey(f.name)) {
138-
throw new RuntimeException("Cannot assign to slot '" + f.name + "' using '=' (in field declaration). Use '~ " + f.name + " ...' syntax instead.");
138+
throw new RuntimeException("Cannot assign to slot '" + f.name + "' using '=' (in field declaration). Use '~> " + f.name + " ...' syntax instead.");
139139
} else {
140140
obj.fields.put(f.name, val);
141141
DebugSystem.fieldUpdate(f.name, val);
@@ -160,7 +160,7 @@ public Object evalStmt(StatementNode stmt, ObjectInstance obj, Map<String, Objec
160160

161161
// --- Enforce ~ for slots (NO CHANGE) ---
162162
if (slotValues != null && slotValues.containsKey(var.name)) {
163-
throw new RuntimeException("Cannot declare variable '" + var.name + "' because it conflicts with a return slot. Use '~ " + var.name + " ...' to assign to the slot.");
163+
throw new RuntimeException("Cannot declare variable '" + var.name + "' because it conflicts with a return slot. Use '~> " + var.name + " ...' to assign to the slot.");
164164
}
165165
// --- END ---
166166

@@ -494,7 +494,7 @@ public Object evalStmt(StatementNode stmt, ObjectInstance obj, Map<String, Objec
494494
multiAssign.assignments.size() + " values");
495495
}
496496

497-
// Count named assignments and validate
497+
// Count named assignments
498498
int namedCount = 0;
499499
List<String> assignedNames = new ArrayList<String>();
500500
for (SlotAssignmentNode assign : multiAssign.assignments) {
@@ -504,21 +504,56 @@ public Object evalStmt(StatementNode stmt, ObjectInstance obj, Map<String, Objec
504504
}
505505
}
506506

507-
// If mixed assignments, validate names match declared slots
507+
// Handle mixed assignments - validate names match declared slots
508508
if (namedCount > 0 && namedCount < multiAssign.assignments.size()) {
509-
throw new RuntimeException("Mixed named and unnamed assignments not allowed");
510-
}
511-
512-
// If all named, validate names match declared slots
513-
if (namedCount == multiAssign.assignments.size()) {
509+
// Mixed assignments - validate all named ones match declared slots
514510
for (String assignedName : assignedNames) {
515511
if (!declaredSlots.contains(assignedName)) {
516512
throw new RuntimeException("Assignment to undeclared slot: " + assignedName);
517513
}
518514
}
515+
516+
// Execute mixed assignments - named ones by name, unnamed ones by position
517+
Object lastValue = null;
518+
int unnamedIndex = 0;
519+
520+
for (SlotAssignmentNode assign : multiAssign.assignments) {
521+
Object value = exprEvaluator.evaluate(assign.value, obj, locals);
522+
523+
if (assign.slotName != null) {
524+
// Named assignment
525+
if (slotValues != null && slotValues.containsKey(assign.slotName)) {
526+
Object oldValue = slotValues.get(assign.slotName);
527+
slotValues.put(assign.slotName, value);
528+
DebugSystem.slotUpdate(assign.slotName, oldValue, value);
529+
}
530+
} else {
531+
// Unnamed assignment - assign by position
532+
if (unnamedIndex < declaredSlots.size()) {
533+
String slotName = declaredSlots.get(unnamedIndex);
534+
// Skip if this slot was already assigned by name
535+
while (unnamedIndex < declaredSlots.size() &&
536+
assignedNames.contains(declaredSlots.get(unnamedIndex))) {
537+
unnamedIndex++;
538+
}
539+
if (unnamedIndex < declaredSlots.size()) {
540+
slotName = declaredSlots.get(unnamedIndex);
541+
if (slotValues != null && slotValues.containsKey(slotName)) {
542+
Object oldValue = slotValues.get(slotName);
543+
slotValues.put(slotName, value);
544+
DebugSystem.slotUpdate(slotName, oldValue, value);
545+
}
546+
unnamedIndex++;
547+
}
548+
}
549+
}
550+
lastValue = value;
551+
}
552+
553+
return lastValue;
519554
}
520555

521-
// Execute assignments
556+
// Original logic for all-named or all-unnamed assignments
522557
Object lastValue = null;
523558
if (namedCount == 0) {
524559
// All unnamed - assign in declaration order

0 commit comments

Comments
 (0)