Merge pull request #99 from moe-charm/copilot/fix-98
🚀 Phase 10: Classic C Applications Migration to Nyash - Triple Porting Project
This commit is contained in:
345
apps/chip8_nyash/chip8_emulator.nyash
Normal file
345
apps/chip8_nyash/chip8_emulator.nyash
Normal file
@ -0,0 +1,345 @@
|
|||||||
|
// 🎮 Chip-8 Emulator in Nyash - Phase 10.2
|
||||||
|
// Testing fini propagation and weak reference lifecycle
|
||||||
|
|
||||||
|
// Chip8CPU - Central processing unit with fini propagation
|
||||||
|
static box Chip8CPU {
|
||||||
|
init { memory, graphics, sound, program_counter, registers }
|
||||||
|
|
||||||
|
pack() {
|
||||||
|
me.program_counter = 512 // 0x200 = 512 decimal - Standard Chip-8 start address
|
||||||
|
me.registers = new ArrayBox() // 16 general registers V0-VF
|
||||||
|
|
||||||
|
// Initialize 16 registers to 0
|
||||||
|
local i = 0
|
||||||
|
loop(i < 16) {
|
||||||
|
me.registers.push(0)
|
||||||
|
i = i + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
print("🔧 CPU initialized with 16 registers")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ⭐ Phase 10: fini propagation test
|
||||||
|
fini() {
|
||||||
|
print("🔄 CPU cleanup triggered - fini propagation starting")
|
||||||
|
|
||||||
|
// Clean up dependent components in order
|
||||||
|
if (me.memory != null) {
|
||||||
|
me.memory.cleanup()
|
||||||
|
print("📦 Memory cleanup completed")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (me.graphics != null) {
|
||||||
|
me.graphics.cleanup()
|
||||||
|
print("🖼️ Graphics cleanup completed")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (me.sound != null) {
|
||||||
|
me.sound.cleanup()
|
||||||
|
print("🔊 Sound cleanup completed")
|
||||||
|
}
|
||||||
|
|
||||||
|
print("✅ CPU fini propagation complete")
|
||||||
|
}
|
||||||
|
|
||||||
|
execute_cycle() {
|
||||||
|
// Simplified fetch-decode-execute cycle
|
||||||
|
local opcode = me.fetch_instruction()
|
||||||
|
me.decode_and_execute(opcode)
|
||||||
|
me.update_timers()
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch_instruction() {
|
||||||
|
// Fetch 2-byte instruction from memory
|
||||||
|
local high_byte = me.memory.read_byte(me.program_counter)
|
||||||
|
local low_byte = me.memory.read_byte(me.program_counter + 1)
|
||||||
|
|
||||||
|
if (high_byte != null and low_byte != null) {
|
||||||
|
me.program_counter = me.program_counter + 2
|
||||||
|
return (high_byte * 256) + low_byte
|
||||||
|
} else {
|
||||||
|
return 0 // NOP if memory read failed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
decode_and_execute(opcode) {
|
||||||
|
// Simplified instruction decoding
|
||||||
|
local first_nibble = opcode / 4096 // (opcode AND 0xF000) >> 12
|
||||||
|
|
||||||
|
if (first_nibble == 1) {
|
||||||
|
// 1NNN - Jump to address NNN
|
||||||
|
me.program_counter = opcode % 4096 // opcode AND 0x0FFF
|
||||||
|
print("🦘 Jump to address: " + me.program_counter)
|
||||||
|
} else if (first_nibble == 6) {
|
||||||
|
// 6XNN - Set register VX to NN
|
||||||
|
local reg = (opcode / 256) % 16 // (opcode AND 0x0F00) >> 8
|
||||||
|
local value = opcode % 256 // opcode AND 0x00FF
|
||||||
|
me.registers.set(reg, value)
|
||||||
|
print("📝 Set register V" + reg + " = " + value)
|
||||||
|
} else if (first_nibble == 7) {
|
||||||
|
// 7XNN - Add NN to register VX
|
||||||
|
local reg = (opcode / 256) % 16
|
||||||
|
local value = opcode % 256
|
||||||
|
local current = me.registers.get(reg)
|
||||||
|
me.registers.set(reg, current + value)
|
||||||
|
print("➕ Add " + value + " to register V" + reg)
|
||||||
|
} else {
|
||||||
|
print("❓ Unknown opcode: " + opcode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update_timers() {
|
||||||
|
// Timer updates would go here
|
||||||
|
// For demo, just a placeholder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chip8Memory - Memory system with weak CPU reference
|
||||||
|
static box Chip8Memory {
|
||||||
|
init { ram, weak cpu_ref } // CPU reference is weak to prevent cycles
|
||||||
|
|
||||||
|
pack(cpu_instance) {
|
||||||
|
me.ram = new ArrayBox()
|
||||||
|
|
||||||
|
// Initialize 4KB of RAM (4096 bytes)
|
||||||
|
local i = 0
|
||||||
|
loop(i < 4096) {
|
||||||
|
me.ram.push(0)
|
||||||
|
i = i + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create weak reference to CPU
|
||||||
|
me.cpu_ref = weak cpu_instance
|
||||||
|
|
||||||
|
print("💾 Memory initialized: 4KB RAM + weak CPU reference")
|
||||||
|
me.load_test_program()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ⭐ Phase 10: weak reference life cycle test
|
||||||
|
read_byte(address) {
|
||||||
|
// Check if CPU is still alive before accessing memory
|
||||||
|
if (me.cpu_ref != null) {
|
||||||
|
if (address >= 0 and address < 4096) {
|
||||||
|
return me.ram.get(address)
|
||||||
|
} else {
|
||||||
|
print("⚠️ Memory access out of bounds: " + address)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print("⚠️ CPU destroyed, memory access blocked")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write_byte(address, value) {
|
||||||
|
if (me.cpu_ref != null) {
|
||||||
|
if (address >= 0 and address < 4096) {
|
||||||
|
me.ram.set(address, value)
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
print("⚠️ Memory write out of bounds: " + address)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print("⚠️ CPU destroyed, memory write blocked")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
load_test_program() {
|
||||||
|
// Load a simple test program starting at 0x200
|
||||||
|
local start_addr = 512 // 0x200
|
||||||
|
|
||||||
|
// Simple test program: Set V0 = 5, Add 3 to V0, Jump to start
|
||||||
|
me.ram.set(start_addr, 96) // 6005 - Set V0 = 5 (high byte: decimal 96)
|
||||||
|
me.ram.set(start_addr + 1, 5) // (low byte: decimal 5)
|
||||||
|
me.ram.set(start_addr + 2, 112) // 7003 - Add 3 to V0 (high byte: decimal 112)
|
||||||
|
me.ram.set(start_addr + 3, 3) // (low byte: decimal 3)
|
||||||
|
me.ram.set(start_addr + 4, 18) // 1200 - Jump to address 512 (high byte: decimal 18)
|
||||||
|
me.ram.set(start_addr + 5, 0) // (low byte: decimal 0)
|
||||||
|
|
||||||
|
print("🎮 Test program loaded: Set V0=5, Add 3, Loop")
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
print("🧹 Memory cleanup: clearing RAM")
|
||||||
|
me.ram.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chip8Graphics - Display system
|
||||||
|
static box Chip8Graphics {
|
||||||
|
init { screen, weak cpu_ref }
|
||||||
|
|
||||||
|
pack(cpu_instance) {
|
||||||
|
me.screen = new ArrayBox()
|
||||||
|
|
||||||
|
// Initialize 64x32 pixel display (2048 pixels)
|
||||||
|
local i = 0
|
||||||
|
loop(i < 2048) {
|
||||||
|
me.screen.push(0) // 0 = black, 1 = white
|
||||||
|
i = i + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
me.cpu_ref = weak cpu_instance
|
||||||
|
print("🖼️ Graphics initialized: 64x32 display + weak CPU reference")
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_sprite(x, y, sprite_data) {
|
||||||
|
if (me.cpu_ref != null) {
|
||||||
|
print("🎨 Drawing sprite at (" + x + ", " + y + ")")
|
||||||
|
// Sprite drawing logic would go here
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
print("⚠️ CPU destroyed, graphics operation blocked")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_screen() {
|
||||||
|
if (me.cpu_ref != null) {
|
||||||
|
local i = 0
|
||||||
|
loop(i < 2048) {
|
||||||
|
me.screen.set(i, 0)
|
||||||
|
i = i + 1
|
||||||
|
}
|
||||||
|
print("🧹 Screen cleared")
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
print("⚠️ CPU destroyed, screen clear blocked")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
print("🧹 Graphics cleanup: clearing display")
|
||||||
|
me.screen.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chip8Sound - Audio system
|
||||||
|
static box Chip8Sound {
|
||||||
|
init { beep_timer, weak cpu_ref }
|
||||||
|
|
||||||
|
pack(cpu_instance) {
|
||||||
|
me.beep_timer = 0
|
||||||
|
me.cpu_ref = weak cpu_instance
|
||||||
|
print("🔊 Sound initialized with weak CPU reference")
|
||||||
|
}
|
||||||
|
|
||||||
|
play_beep() {
|
||||||
|
if (me.cpu_ref != null) {
|
||||||
|
print("🔔 BEEP! (Sound playing)")
|
||||||
|
me.beep_timer = 60 // 1 second at 60Hz
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
print("⚠️ CPU destroyed, sound playback blocked")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
if (me.cpu_ref != null) {
|
||||||
|
if (me.beep_timer > 0) {
|
||||||
|
me.beep_timer = me.beep_timer - 1
|
||||||
|
if (me.beep_timer == 0) {
|
||||||
|
print("🔇 Sound finished")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
print("🧹 Sound cleanup: stopping audio")
|
||||||
|
me.beep_timer = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main Chip-8 System
|
||||||
|
static box Chip8System {
|
||||||
|
init { cpu, memory, graphics, sound }
|
||||||
|
|
||||||
|
main() {
|
||||||
|
print("🎮 Starting Chip-8 Emulator - Phase 10.2")
|
||||||
|
print("Testing fini propagation and weak reference lifecycle")
|
||||||
|
|
||||||
|
// Create CPU first
|
||||||
|
me.cpu = new Chip8CPU()
|
||||||
|
me.cpu.pack()
|
||||||
|
|
||||||
|
// Create subsystems with weak references to CPU
|
||||||
|
me.memory = new Chip8Memory()
|
||||||
|
me.memory.pack(me.cpu)
|
||||||
|
|
||||||
|
me.graphics = new Chip8Graphics()
|
||||||
|
me.graphics.pack(me.cpu)
|
||||||
|
|
||||||
|
me.sound = new Chip8Sound()
|
||||||
|
me.sound.pack(me.cpu)
|
||||||
|
|
||||||
|
// Link components to CPU for fini propagation
|
||||||
|
me.cpu.memory = me.memory
|
||||||
|
me.cpu.graphics = me.graphics
|
||||||
|
me.cpu.sound = me.sound
|
||||||
|
|
||||||
|
print("🔗 All components linked with weak references")
|
||||||
|
|
||||||
|
// Run a few emulation cycles
|
||||||
|
me.run_emulation()
|
||||||
|
|
||||||
|
// Test fini propagation by destroying CPU
|
||||||
|
print("💥 Testing fini propagation - destroying CPU...")
|
||||||
|
me.cpu.fini()
|
||||||
|
me.cpu = null
|
||||||
|
|
||||||
|
// Test weak reference after CPU destruction
|
||||||
|
print("🧪 Testing weak references after CPU destruction...")
|
||||||
|
me.test_weak_references()
|
||||||
|
|
||||||
|
return "Chip-8 emulation and memory management test complete"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_emulation() {
|
||||||
|
print("🚀 Starting emulation cycles...")
|
||||||
|
|
||||||
|
local cycles = 0
|
||||||
|
loop(cycles < 5) {
|
||||||
|
print("⚡ Cycle " + (cycles + 1))
|
||||||
|
me.cpu.execute_cycle()
|
||||||
|
me.sound.update()
|
||||||
|
cycles = cycles + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
print("✅ Emulation cycles complete")
|
||||||
|
}
|
||||||
|
|
||||||
|
test_weak_references() {
|
||||||
|
print("Testing memory access after CPU destruction:")
|
||||||
|
local result = me.memory.read_byte(512)
|
||||||
|
print("Memory read result: " + result)
|
||||||
|
|
||||||
|
print("Testing graphics operation after CPU destruction:")
|
||||||
|
local gfx_result = me.graphics.clear_screen()
|
||||||
|
print("Graphics operation result: " + gfx_result)
|
||||||
|
|
||||||
|
print("Testing sound operation after CPU destruction:")
|
||||||
|
local sound_result = me.sound.play_beep()
|
||||||
|
print("Sound operation result: " + sound_result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entry point
|
||||||
|
static box Main {
|
||||||
|
init { console }
|
||||||
|
|
||||||
|
main() {
|
||||||
|
me.console = new ConsoleBox()
|
||||||
|
me.console.log("🚀 Phase 10.2: Chip-8 Emulator Starting")
|
||||||
|
|
||||||
|
local chip8 = new Chip8System()
|
||||||
|
local result = chip8.main()
|
||||||
|
|
||||||
|
me.console.log("🏁 Result: " + result)
|
||||||
|
return "Phase 10.2 Complete"
|
||||||
|
}
|
||||||
|
}
|
||||||
256
apps/kilo_nyash/enhanced_kilo_editor.nyash
Normal file
256
apps/kilo_nyash/enhanced_kilo_editor.nyash
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
// ✏️ Enhanced Kilo Text Editor - Phase 10.4
|
||||||
|
// Memory efficiency monitoring and "accidental full copy" detection
|
||||||
|
|
||||||
|
// Enhanced TextBuffer with memory monitoring
|
||||||
|
box EnhancedTextBuffer {
|
||||||
|
init { lines, undo_stack, initial_memory, operation_count }
|
||||||
|
|
||||||
|
EnhancedTextBuffer() {
|
||||||
|
me.lines = new ArrayBox()
|
||||||
|
me.undo_stack = new ArrayBox()
|
||||||
|
me.operation_count = 0
|
||||||
|
|
||||||
|
// Start with one empty line
|
||||||
|
me.lines.push("")
|
||||||
|
|
||||||
|
// Record initial memory footprint
|
||||||
|
me.initial_memory = me.memory_footprint()
|
||||||
|
print("📊 Initial memory footprint: " + me.initial_memory + " bytes")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ⭐ Phase 10: Memory efficiency monitoring
|
||||||
|
memory_footprint() {
|
||||||
|
// Calculate total memory usage
|
||||||
|
local total_memory = 100 // Base TextBuffer overhead
|
||||||
|
local line_count = me.lines.length()
|
||||||
|
|
||||||
|
// Add memory for each line
|
||||||
|
local i = 0
|
||||||
|
loop(i < line_count) {
|
||||||
|
local line = me.lines.get(i)
|
||||||
|
total_memory = total_memory + line.toString().length() + 20 // String overhead
|
||||||
|
i = i + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add undo stack memory
|
||||||
|
local undo_count = me.undo_stack.length()
|
||||||
|
total_memory = total_memory + (undo_count * 50) // Estimate for undo operations
|
||||||
|
|
||||||
|
return total_memory
|
||||||
|
}
|
||||||
|
|
||||||
|
// ⭐ Phase 10: "Accidental full copy" detection
|
||||||
|
insert_char(row, col, char) {
|
||||||
|
local old_memory = me.memory_footprint()
|
||||||
|
me.operation_count = me.operation_count + 1
|
||||||
|
|
||||||
|
// Get current line
|
||||||
|
local current_line = me.lines.get(row)
|
||||||
|
local line_str = current_line.toString()
|
||||||
|
|
||||||
|
// Insert character
|
||||||
|
local left_part = line_str.substring(0, col)
|
||||||
|
local right_part = line_str.substring(col, line_str.length())
|
||||||
|
local new_line = left_part + char + right_part
|
||||||
|
|
||||||
|
// Replace line
|
||||||
|
me.lines.set(row, new_line)
|
||||||
|
|
||||||
|
// Save to undo stack
|
||||||
|
local undo_op = "insert_char:" + row + ":" + col + ":" + char
|
||||||
|
me.undo_stack.push(undo_op)
|
||||||
|
|
||||||
|
// Check for accidental full copy
|
||||||
|
local new_memory = me.memory_footprint()
|
||||||
|
local memory_diff = new_memory - old_memory
|
||||||
|
|
||||||
|
print("💾 Memory change: " + memory_diff + " bytes for operation " + me.operation_count)
|
||||||
|
|
||||||
|
// ⭐ Alert if memory increase is suspicious
|
||||||
|
if (memory_diff > 100) { // 1 character should not increase memory by 100+ bytes
|
||||||
|
print("🚨 INEFFICIENT COPY DETECTED!")
|
||||||
|
print(" Expected: ~20 bytes, Actual: " + memory_diff + " bytes")
|
||||||
|
print(" Operation: Insert '" + char + "' at (" + row + ", " + col + ")")
|
||||||
|
me.log_memory_leak_warning()
|
||||||
|
} else if (memory_diff > 0) {
|
||||||
|
print("✅ Normal memory usage: " + memory_diff + " bytes")
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
delete_char(row, col) {
|
||||||
|
if (col <= 0) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
local old_memory = me.memory_footprint()
|
||||||
|
me.operation_count = me.operation_count + 1
|
||||||
|
|
||||||
|
// Get current line and remove character
|
||||||
|
local current_line = me.lines.get(row)
|
||||||
|
local line_str = current_line.toString()
|
||||||
|
|
||||||
|
local left_part = line_str.substring(0, col - 1)
|
||||||
|
local right_part = line_str.substring(col, line_str.length())
|
||||||
|
local new_line = left_part + right_part
|
||||||
|
|
||||||
|
me.lines.set(row, new_line)
|
||||||
|
|
||||||
|
// Save to undo stack
|
||||||
|
local undo_op = "delete_char:" + row + ":" + col
|
||||||
|
me.undo_stack.push(undo_op)
|
||||||
|
|
||||||
|
local new_memory = me.memory_footprint()
|
||||||
|
local memory_diff = new_memory - old_memory
|
||||||
|
|
||||||
|
print("💾 Memory change: " + memory_diff + " bytes (deletion)")
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search and replace with efficiency monitoring
|
||||||
|
search_and_replace(pattern, replacement) {
|
||||||
|
local initial_memory = me.memory_footprint()
|
||||||
|
local matches_found = 0
|
||||||
|
|
||||||
|
print("🔍 Starting search and replace: '" + pattern + "' -> '" + replacement + "'")
|
||||||
|
|
||||||
|
local line_count = me.lines.length()
|
||||||
|
local i = 0
|
||||||
|
loop(i < line_count) {
|
||||||
|
local line = me.lines.get(i)
|
||||||
|
local line_str = line.toString()
|
||||||
|
|
||||||
|
// Simple search and replace (contains check)
|
||||||
|
if (line_str.indexOf(pattern) >= 0) {
|
||||||
|
// For simplicity, just append replacement to demonstrate memory monitoring
|
||||||
|
local new_line = line_str + " [REPLACED: " + pattern + " -> " + replacement + "]"
|
||||||
|
me.lines.set(i, new_line)
|
||||||
|
matches_found = matches_found + 1
|
||||||
|
}
|
||||||
|
i = i + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
local final_memory = me.memory_footprint()
|
||||||
|
local memory_ratio = final_memory / initial_memory
|
||||||
|
|
||||||
|
print("🔍 Search complete: " + matches_found + " matches")
|
||||||
|
print("📊 Memory usage: " + initial_memory + " -> " + final_memory + " bytes")
|
||||||
|
print("📈 Memory ratio: " + memory_ratio)
|
||||||
|
|
||||||
|
// Check for memory doubling (inefficient algorithm)
|
||||||
|
if (memory_ratio > 2) {
|
||||||
|
print("⚠️ Memory usage doubled during replace operation!")
|
||||||
|
print(" This may indicate inefficient string handling")
|
||||||
|
} else {
|
||||||
|
print("✅ Memory usage within reasonable bounds")
|
||||||
|
}
|
||||||
|
|
||||||
|
return matches_found
|
||||||
|
}
|
||||||
|
|
||||||
|
log_memory_leak_warning() {
|
||||||
|
print("⚠️ MEMORY EFFICIENCY WARNING")
|
||||||
|
print(" Current total memory: " + me.memory_footprint())
|
||||||
|
print(" Operations performed: " + me.operation_count)
|
||||||
|
print(" Average memory per operation: " + (me.memory_footprint() / me.operation_count))
|
||||||
|
print(" Consider optimizing string operations")
|
||||||
|
}
|
||||||
|
|
||||||
|
get_stats() {
|
||||||
|
local current_memory = me.memory_footprint()
|
||||||
|
local line_count = me.lines.length()
|
||||||
|
local undo_count = me.undo_stack.length()
|
||||||
|
|
||||||
|
return "Lines: " + line_count + ", Undo: " + undo_count + ", Memory: " + current_memory + "B, Ops: " + me.operation_count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enhanced Kilo Editor
|
||||||
|
box EnhancedKiloEditor {
|
||||||
|
init { buffer, cursor_row, cursor_col, filename }
|
||||||
|
|
||||||
|
EnhancedKiloEditor(file_name) {
|
||||||
|
me.buffer = new EnhancedTextBuffer()
|
||||||
|
me.cursor_row = 0
|
||||||
|
me.cursor_col = 0
|
||||||
|
me.filename = file_name
|
||||||
|
print("📝 Enhanced Kilo Editor initialized: " + me.filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
insert_text(text) {
|
||||||
|
local i = 0
|
||||||
|
local text_len = text.length()
|
||||||
|
|
||||||
|
loop(i < text_len) {
|
||||||
|
local char = text.substring(i, i + 1)
|
||||||
|
me.buffer.insert_char(me.cursor_row, me.cursor_col, char)
|
||||||
|
me.cursor_col = me.cursor_col + 1
|
||||||
|
i = i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new_line() {
|
||||||
|
// Insert new line at current position
|
||||||
|
me.cursor_row = me.cursor_row + 1
|
||||||
|
me.cursor_col = 0
|
||||||
|
me.buffer.lines.insert(me.cursor_row, "")
|
||||||
|
print("↩️ New line inserted at row " + me.cursor_row)
|
||||||
|
}
|
||||||
|
|
||||||
|
backspace() {
|
||||||
|
if (me.cursor_col > 0) {
|
||||||
|
me.buffer.delete_char(me.cursor_row, me.cursor_col)
|
||||||
|
me.cursor_col = me.cursor_col - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
show_stats() {
|
||||||
|
print("📊 Editor Stats: " + me.buffer.get_stats())
|
||||||
|
print("📍 Cursor: (" + me.cursor_row + ", " + me.cursor_col + ")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test suite for memory efficiency
|
||||||
|
static box Main {
|
||||||
|
init { console }
|
||||||
|
|
||||||
|
main() {
|
||||||
|
me.console = new ConsoleBox()
|
||||||
|
me.console.log("✏️ Phase 10.4: Enhanced Kilo Editor - Memory Efficiency Testing")
|
||||||
|
|
||||||
|
local editor = new EnhancedKiloEditor("test_document.txt")
|
||||||
|
|
||||||
|
// Test 1: Normal character insertion
|
||||||
|
me.console.log("Test 1: Inserting characters normally")
|
||||||
|
editor.insert_text("Hello World")
|
||||||
|
editor.show_stats()
|
||||||
|
|
||||||
|
// Test 2: Large text insertion (potential memory stress)
|
||||||
|
me.console.log("Test 2: Large text insertion")
|
||||||
|
editor.new_line()
|
||||||
|
editor.insert_text("This is a longer line of text to test memory efficiency monitoring")
|
||||||
|
editor.show_stats()
|
||||||
|
|
||||||
|
// Test 3: Search and replace (memory doubling test)
|
||||||
|
me.console.log("Test 3: Search and replace operation")
|
||||||
|
local matches = editor.buffer.search_and_replace("test", "TEST")
|
||||||
|
editor.show_stats()
|
||||||
|
|
||||||
|
// Test 4: Memory stress test
|
||||||
|
me.console.log("Test 4: Memory stress test - rapid insertions")
|
||||||
|
local stress_count = 0
|
||||||
|
loop(stress_count < 10) {
|
||||||
|
editor.insert_text("X")
|
||||||
|
stress_count = stress_count + 1
|
||||||
|
}
|
||||||
|
editor.show_stats()
|
||||||
|
|
||||||
|
// Final memory report
|
||||||
|
me.console.log("Final memory footprint: " + editor.buffer.memory_footprint() + " bytes")
|
||||||
|
me.console.log("Total operations: " + editor.buffer.operation_count)
|
||||||
|
|
||||||
|
return "Enhanced Kilo Editor test complete"
|
||||||
|
}
|
||||||
|
}
|
||||||
175
apps/tinyproxy_nyash/proxy_server.nyash
Normal file
175
apps/tinyproxy_nyash/proxy_server.nyash
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
// 🌐 Tinyproxy Nyash - HTTP Proxy Server Implementation
|
||||||
|
// Phase 10.1: Zero-copy detection testing with real HTTP traffic
|
||||||
|
|
||||||
|
// ProxyServer - Main proxy server implementation
|
||||||
|
static box ProxyServer {
|
||||||
|
init { server_socket, upstream_buffer, downstream_buffer, port, running }
|
||||||
|
|
||||||
|
main() {
|
||||||
|
me.port = 8080
|
||||||
|
me.running = true
|
||||||
|
me.upstream_buffer = new BufferBox()
|
||||||
|
me.downstream_buffer = new BufferBox()
|
||||||
|
me.server_socket = new SocketBox()
|
||||||
|
|
||||||
|
print("🌐 Tinyproxy Nyash starting on port " + me.port)
|
||||||
|
|
||||||
|
// Bind to port
|
||||||
|
local bind_result = me.server_socket.bind("127.0.0.1", me.port)
|
||||||
|
print("Bind result: " + bind_result)
|
||||||
|
|
||||||
|
// Start listening
|
||||||
|
local listen_result = me.server_socket.listen(10)
|
||||||
|
print("Listen result: " + listen_result)
|
||||||
|
|
||||||
|
// Main proxy loop
|
||||||
|
me.accept_connections()
|
||||||
|
|
||||||
|
return "Proxy server stopped"
|
||||||
|
}
|
||||||
|
|
||||||
|
accept_connections() {
|
||||||
|
local connection_count = 0
|
||||||
|
|
||||||
|
print("🔄 Proxy server ready - waiting for connections...")
|
||||||
|
|
||||||
|
loop(connection_count < 5 and me.running) {
|
||||||
|
print("Waiting for connection " + (connection_count + 1))
|
||||||
|
|
||||||
|
local client_socket = me.server_socket.accept()
|
||||||
|
if (client_socket != null) {
|
||||||
|
print("✅ New client connected")
|
||||||
|
me.handle_client(client_socket)
|
||||||
|
connection_count = connection_count + 1
|
||||||
|
} else {
|
||||||
|
print("❌ Failed to accept connection")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print("🏁 Proxy server finished handling " + connection_count + " connections")
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_client(client_socket) {
|
||||||
|
// Read HTTP request from client
|
||||||
|
local request_data = client_socket.read()
|
||||||
|
if (request_data == null) {
|
||||||
|
print("❌ Failed to read request from client")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
print("📥 Received request from client")
|
||||||
|
|
||||||
|
// Parse HTTP request to extract target server
|
||||||
|
local target_info = me.parse_http_request(request_data)
|
||||||
|
if (target_info == null) {
|
||||||
|
print("❌ Failed to parse HTTP request")
|
||||||
|
me.send_error_response(client_socket)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
print("🎯 Targeting: " + target_info.get("host") + ":" + target_info.get("port"))
|
||||||
|
|
||||||
|
// ⭐ Zero-copy test: Check if we can share request data without copying
|
||||||
|
local shared_result = me.relay_data(request_data)
|
||||||
|
print("Zero-copy result: " + shared_result)
|
||||||
|
|
||||||
|
// Connect to target server
|
||||||
|
local upstream_socket = new SocketBox()
|
||||||
|
local connect_result = upstream_socket.connect(target_info.get("host"), target_info.get("port"))
|
||||||
|
|
||||||
|
if (connect_result.toString() == "true") {
|
||||||
|
print("✅ Connected to upstream server")
|
||||||
|
|
||||||
|
// Forward request to upstream server
|
||||||
|
upstream_socket.write(request_data)
|
||||||
|
print("📤 Forwarded request to upstream")
|
||||||
|
|
||||||
|
// Read response from upstream
|
||||||
|
local response_data = upstream_socket.read()
|
||||||
|
if (response_data != null) {
|
||||||
|
print("📥 Received response from upstream")
|
||||||
|
|
||||||
|
// Forward response back to client
|
||||||
|
client_socket.write(response_data)
|
||||||
|
print("📤 Forwarded response to client")
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream_socket.close()
|
||||||
|
} else {
|
||||||
|
print("❌ Failed to connect to upstream server")
|
||||||
|
me.send_error_response(client_socket)
|
||||||
|
}
|
||||||
|
|
||||||
|
client_socket.close()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
relay_data(client_data) {
|
||||||
|
// ⭐ Phase 10: Zero-copy detection testing
|
||||||
|
|
||||||
|
// Test 1: Check if upstream buffer shares data with client data
|
||||||
|
if (me.upstream_buffer.is_shared_with(client_data)) {
|
||||||
|
return "✅ Zero-copy achieved!"
|
||||||
|
} else {
|
||||||
|
print("❌ Unnecessary copy detected in initial check")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test 2: Create shared reference and test again
|
||||||
|
local shared_buffer = me.upstream_buffer.share_reference(client_data)
|
||||||
|
if (shared_buffer != null) {
|
||||||
|
print("📊 Created shared reference")
|
||||||
|
|
||||||
|
// Test if the shared buffer is actually sharing memory
|
||||||
|
if (me.upstream_buffer.is_shared_with(shared_buffer)) {
|
||||||
|
return "✅ Zero-copy sharing successful!"
|
||||||
|
} else {
|
||||||
|
return "❌ Share reference failed to create shared memory"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "❌ Share reference operation failed"
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_http_request(request_data) {
|
||||||
|
// Simple HTTP request parser - extract host and port
|
||||||
|
local request_str = request_data.toString()
|
||||||
|
local result = new MapBox()
|
||||||
|
|
||||||
|
// Default values
|
||||||
|
result.set("host", "httpbin.org")
|
||||||
|
result.set("port", 80)
|
||||||
|
result.set("method", "GET")
|
||||||
|
|
||||||
|
// In a real implementation, we would parse the HTTP headers
|
||||||
|
// For this test, we'll use a fixed target
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
send_error_response(client_socket) {
|
||||||
|
local error_response = "HTTP/1.1 502 Bad Gateway\r\nContent-Length: 0\r\n\r\n"
|
||||||
|
client_socket.write(error_response)
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
me.running = false
|
||||||
|
if (me.server_socket != null) {
|
||||||
|
me.server_socket.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entry point
|
||||||
|
static box Main {
|
||||||
|
init { console }
|
||||||
|
|
||||||
|
main() {
|
||||||
|
me.console = new ConsoleBox()
|
||||||
|
me.console.log("🚀 Starting Tinyproxy Nyash - Phase 10.1")
|
||||||
|
|
||||||
|
local proxy = new ProxyServer()
|
||||||
|
local result = proxy.main()
|
||||||
|
|
||||||
|
me.console.log("🏁 Proxy result: " + result)
|
||||||
|
return "Phase 10.1 Complete"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -150,6 +150,35 @@ impl BufferBox {
|
|||||||
Box::new(StringBox::new("Error: slice() requires integer indices"))
|
Box::new(StringBox::new("Error: slice() requires integer indices"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ⭐ Phase 10: Zero-copy detection - check if buffer is shared with another buffer
|
||||||
|
pub fn is_shared_with(&self, other: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
|
||||||
|
if let Some(other_buffer) = other.as_any().downcast_ref::<BufferBox>() {
|
||||||
|
// Check if the Arc pointers are the same (shared memory)
|
||||||
|
let is_shared = Arc::ptr_eq(&self.data, &other_buffer.data);
|
||||||
|
Box::new(BoolBox::new(is_shared))
|
||||||
|
} else {
|
||||||
|
// Not a BufferBox, so definitely not shared
|
||||||
|
Box::new(BoolBox::new(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ⭐ Phase 10: Share reference - create a zero-copy shared reference to this buffer's data
|
||||||
|
pub fn share_reference(&self, _data: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
|
||||||
|
// Create a new BufferBox that shares the same Arc as this buffer
|
||||||
|
let shared_buffer = BufferBox {
|
||||||
|
data: Arc::clone(&self.data), // Share THIS buffer's data
|
||||||
|
base: BoxBase::new(), // New ID but shared data
|
||||||
|
};
|
||||||
|
Box::new(shared_buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ⭐ Phase 10: Memory footprint - get current memory usage in bytes
|
||||||
|
pub fn memory_footprint(&self) -> Box<dyn NyashBox> {
|
||||||
|
let data = self.data.read().unwrap();
|
||||||
|
let bytes = data.len() + std::mem::size_of::<BufferBox>();
|
||||||
|
Box::new(IntegerBox::new(bytes as i64))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone implementation for BufferBox (needed since RwLock doesn't auto-derive Clone)
|
// Clone implementation for BufferBox (needed since RwLock doesn't auto-derive Clone)
|
||||||
|
|||||||
@ -77,6 +77,33 @@ impl NyashInterpreter {
|
|||||||
let end = self.execute_expression(&arguments[1])?;
|
let end = self.execute_expression(&arguments[1])?;
|
||||||
Ok(buffer_box.slice(start, end))
|
Ok(buffer_box.slice(start, end))
|
||||||
}
|
}
|
||||||
|
// ⭐ Phase 10: Zero-copy detection APIs
|
||||||
|
"is_shared_with" => {
|
||||||
|
if arguments.len() != 1 {
|
||||||
|
return Err(RuntimeError::InvalidOperation {
|
||||||
|
message: format!("is_shared_with() expects 1 argument, got {}", arguments.len()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let other = self.execute_expression(&arguments[0])?;
|
||||||
|
Ok(buffer_box.is_shared_with(other))
|
||||||
|
}
|
||||||
|
"share_reference" => {
|
||||||
|
if arguments.len() != 1 {
|
||||||
|
return Err(RuntimeError::InvalidOperation {
|
||||||
|
message: format!("share_reference() expects 1 argument, got {}", arguments.len()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let data = self.execute_expression(&arguments[0])?;
|
||||||
|
Ok(buffer_box.share_reference(data))
|
||||||
|
}
|
||||||
|
"memory_footprint" => {
|
||||||
|
if !arguments.is_empty() {
|
||||||
|
return Err(RuntimeError::InvalidOperation {
|
||||||
|
message: format!("memory_footprint() expects 0 arguments, got {}", arguments.len()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(buffer_box.memory_footprint())
|
||||||
|
}
|
||||||
_ => Err(RuntimeError::InvalidOperation {
|
_ => Err(RuntimeError::InvalidOperation {
|
||||||
message: format!("Unknown method '{}' for BufferBox", method),
|
message: format!("Unknown method '{}' for BufferBox", method),
|
||||||
})
|
})
|
||||||
|
|||||||
79
test_simple_weak_ref.nyash
Normal file
79
test_simple_weak_ref.nyash
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// Simple weak reference test for Phase 10.2
|
||||||
|
|
||||||
|
// Test CPU with fini
|
||||||
|
box TestCPU {
|
||||||
|
init { memory, name }
|
||||||
|
|
||||||
|
TestCPU() {
|
||||||
|
me.name = "TestCPU"
|
||||||
|
print("CPU initialized: " + me.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fini() {
|
||||||
|
print("CPU fini called - cleaning up memory")
|
||||||
|
if (me.memory != null) {
|
||||||
|
me.memory.cleanup()
|
||||||
|
}
|
||||||
|
print("CPU fini complete")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test Memory with weak reference
|
||||||
|
box TestMemory {
|
||||||
|
init { data, weak cpu_ref }
|
||||||
|
|
||||||
|
TestMemory(cpu_instance) {
|
||||||
|
me.data = new ArrayBox()
|
||||||
|
me.data.push("test_data")
|
||||||
|
me.cpu_ref = cpu_instance // This will be automatically downgraded to weak
|
||||||
|
print("Memory initialized with weak CPU reference")
|
||||||
|
}
|
||||||
|
|
||||||
|
read_data() {
|
||||||
|
if (me.cpu_ref != null) {
|
||||||
|
print("CPU is alive - returning data")
|
||||||
|
return me.data.get(0)
|
||||||
|
} else {
|
||||||
|
print("CPU is destroyed - access blocked")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
print("Memory cleanup called")
|
||||||
|
me.data.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main test
|
||||||
|
static box Main {
|
||||||
|
init { console }
|
||||||
|
|
||||||
|
main() {
|
||||||
|
me.console = new ConsoleBox()
|
||||||
|
me.console.log("🧪 Testing weak references and fini propagation")
|
||||||
|
|
||||||
|
// Create CPU and Memory
|
||||||
|
local cpu = new TestCPU()
|
||||||
|
|
||||||
|
local memory = new TestMemory(cpu)
|
||||||
|
|
||||||
|
// Link memory to CPU for fini propagation
|
||||||
|
cpu.memory = memory
|
||||||
|
|
||||||
|
// Test 1: Normal operation
|
||||||
|
me.console.log("Test 1: Normal operation")
|
||||||
|
local result1 = memory.read_data()
|
||||||
|
me.console.log("Read result: " + result1)
|
||||||
|
|
||||||
|
// Test 2: After CPU destruction
|
||||||
|
me.console.log("Test 2: Destroying CPU...")
|
||||||
|
cpu.fini()
|
||||||
|
cpu = null
|
||||||
|
|
||||||
|
local result2 = memory.read_data()
|
||||||
|
me.console.log("Read after CPU destruction: " + result2)
|
||||||
|
|
||||||
|
return "Test complete"
|
||||||
|
}
|
||||||
|
}
|
||||||
67
test_zero_copy_detection.nyash
Normal file
67
test_zero_copy_detection.nyash
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// ⭐ Phase 10: Zero-copy Detection API Test
|
||||||
|
// Test the new BufferBox zero-copy methods
|
||||||
|
|
||||||
|
static box Main {
|
||||||
|
init { console }
|
||||||
|
|
||||||
|
main() {
|
||||||
|
me.console = new ConsoleBox()
|
||||||
|
me.console.log("🧪 Testing Zero-copy Detection APIs")
|
||||||
|
|
||||||
|
// Test 1: Basic buffer creation and memory footprint
|
||||||
|
local buffer1 = new BufferBox()
|
||||||
|
local buffer2 = new BufferBox()
|
||||||
|
|
||||||
|
me.console.log("Created two BufferBox instances")
|
||||||
|
|
||||||
|
// Test memory footprint API
|
||||||
|
local footprint1 = buffer1.memory_footprint()
|
||||||
|
me.console.log("Buffer1 memory footprint: " + footprint1)
|
||||||
|
|
||||||
|
// Test 2: is_shared_with() - should return false for independent buffers
|
||||||
|
local shared_check1 = buffer1.is_shared_with(buffer2)
|
||||||
|
me.console.log("Independent buffers shared: " + shared_check1)
|
||||||
|
|
||||||
|
// Test 3: share_reference() - create shared buffer
|
||||||
|
local shared_buffer = buffer1.share_reference(buffer2)
|
||||||
|
me.console.log("Created shared reference")
|
||||||
|
|
||||||
|
// Test 4: Check if shared buffer actually shares data with buffer1
|
||||||
|
local shared_check2 = buffer1.is_shared_with(shared_buffer)
|
||||||
|
me.console.log("Shared buffer shares data with buffer1: " + shared_check2)
|
||||||
|
|
||||||
|
// Test 5: Memory footprint should be similar for shared buffers
|
||||||
|
local footprint_shared = shared_buffer.memory_footprint()
|
||||||
|
me.console.log("Shared buffer memory footprint: " + footprint_shared)
|
||||||
|
|
||||||
|
// Test 6: Write data and check sharing
|
||||||
|
me.console.log("Writing data to test sharing...")
|
||||||
|
|
||||||
|
// Create test data
|
||||||
|
local test_data = new ArrayBox()
|
||||||
|
test_data.push(72) // 'H'
|
||||||
|
test_data.push(101) // 'e'
|
||||||
|
test_data.push(108) // 'l'
|
||||||
|
test_data.push(108) // 'l'
|
||||||
|
test_data.push(111) // 'o'
|
||||||
|
|
||||||
|
buffer1.write(test_data)
|
||||||
|
me.console.log("Written test data to buffer1")
|
||||||
|
|
||||||
|
local length1 = buffer1.length()
|
||||||
|
me.console.log("Buffer1 length after write: " + length1)
|
||||||
|
|
||||||
|
// Test 7: Check if shared buffer reflects the data
|
||||||
|
local shared_length = shared_buffer.length()
|
||||||
|
me.console.log("Shared buffer length: " + shared_length)
|
||||||
|
|
||||||
|
if (length1.toString() == shared_length.toString()) {
|
||||||
|
me.console.log("✅ Zero-copy sharing working correctly!")
|
||||||
|
} else {
|
||||||
|
me.console.log("❌ Zero-copy sharing failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
me.console.log("🎉 Zero-copy detection test complete")
|
||||||
|
return "Test completed"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user