some new things, mostly not working or finished

This commit is contained in:
2025-11-08 18:16:10 +01:00
parent 5792bfbd9a
commit 795fb42900
30 changed files with 4789 additions and 1 deletions

2403
niacin/compiler.py Normal file

File diff suppressed because it is too large Load Diff

21
niacin/cpp/Makefile Normal file
View File

@@ -0,0 +1,21 @@
CC = gcc
CFLAGS = -Wall -Wextra -Werror -O2 -std=c99 -D_DEFAULT_SOURCE
CFLAGS += -fstack-protector-strong -D_FORTIFY_SOURCE=2
LDFLAGS = -z relro -z now
SOURCES = main.c vm_core.c
OBJECTS = $(SOURCES:.c=.o)
TARGET = popvm
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(CC) $(LDFLAGS) -o $@ $^
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f $(OBJECTS) $(TARGET)
.PHONY: all clean

76
niacin/cpp/main.c Normal file
View File

@@ -0,0 +1,76 @@
#include "vm_types.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Safe file reading
static uint8_t* read_file(const char* filename, size_t* size) {
FILE* file = fopen(filename, "rb");
if (!file) {
fprintf(stderr, "Cannot open file: %s\n", filename);
return NULL;
}
fseek(file, 0, SEEK_END);
long file_size = ftell(file);
fseek(file, 0, SEEK_SET);
if (file_size <= 0 || file_size > 10 * 1024 * 1024) { // 10MB limit
fclose(file);
fprintf(stderr, "Invalid file size\n");
return NULL;
}
uint8_t* buffer = malloc(file_size);
if (!buffer) {
fclose(file);
fprintf(stderr, "Memory allocation failed\n");
return NULL;
}
if (fread(buffer, 1, file_size, file) != (size_t)file_size) {
fclose(file);
free(buffer);
fprintf(stderr, "File read error\n");
return NULL;
}
fclose(file);
*size = file_size;
return buffer;
}
int main(int argc, char* argv[]) {
if (argc != 2) {
printf("Usage: %s <file.popclass>\n", argv[0]);
return 1;
}
size_t file_size;
uint8_t* bytecode = read_file(argv[1], &file_size);
if (!bytecode) {
return 1;
}
vm_t* vm = vm_create(bytecode, file_size);
if (!vm) {
fprintf(stderr, "Failed to create VM\n");
free(bytecode);
return 1;
}
if (!vm_validate_bytecode(vm)) {
fprintf(stderr, "Invalid bytecode file\n");
vm_destroy(vm);
free(bytecode);
return 1;
}
printf("Executing program...\n");
vm_execute(vm);
printf("Program finished\n");
vm_destroy(vm);
free(bytecode);
return 0;
}

BIN
niacin/cpp/sample.popclass Normal file

Binary file not shown.

285
niacin/cpp/vm_core.c Normal file
View File

@@ -0,0 +1,285 @@
#include "vm_types.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
// Safe memory allocation with overflow checking
static void* safe_malloc(size_t size) {
if (size == 0 || size > SIZE_MAX / 2) return NULL;
void* ptr = malloc(size);
if (!ptr) {
fprintf(stderr, "Memory allocation failed\n");
exit(EXIT_FAILURE);
}
return ptr;
}
static void* safe_realloc(void* ptr, size_t size) {
if (size == 0 || size > SIZE_MAX / 2) return NULL;
void* new_ptr = realloc(ptr, size);
if (!new_ptr) {
fprintf(stderr, "Memory reallocation failed\n");
exit(EXIT_FAILURE);
}
return new_ptr;
}
// Initialize VM with security limits
vm_t* vm_create(uint8_t* bytecode, size_t size) {
vm_t* vm = safe_malloc(sizeof(vm_t));
memset(vm, 0, sizeof(vm_t));
vm->bytecode = bytecode;
vm->bytecode_size = size;
vm->ip = 0;
vm->halted = false;
// Security limits
vm->max_stack_size = 65536;
vm->max_call_depth = 256;
vm->current_call_depth = 0;
return vm;
}
// Safe bytecode reading with bounds checking
static bool read_u8(vm_t* vm, uint8_t* result) {
if (vm->ip >= vm->bytecode_size) return false;
*result = vm->bytecode[vm->ip++];
return true;
}
static bool read_u16(vm_t* vm, uint16_t* result) {
if (vm->ip + 2 > vm->bytecode_size) return false;
memcpy(result, &vm->bytecode[vm->ip], 2);
vm->ip += 2;
return true;
}
static bool read_u32(vm_t* vm, uint32_t* result) {
if (vm->ip + 4 > vm->bytecode_size) return false;
memcpy(result, &vm->bytecode[vm->ip], 4);
vm->ip += 4;
return true;
}
static bool read_i32(vm_t* vm, int32_t* result) {
if (vm->ip + 4 > vm->bytecode_size) return false;
memcpy(result, &vm->bytecode[vm->ip], 4);
vm->ip += 4;
return true;
}
static bool read_f32(vm_t* vm, float* result) {
if (vm->ip + 4 > vm->bytecode_size) return false;
memcpy(result, &vm->bytecode[vm->ip], 4);
vm->ip += 4;
return true;
}
// Stack operations with bounds checking
static bool stack_push(frame_t* frame, value_t value) {
if (frame->stack_size >= frame->stack_capacity) {
size_t new_capacity = frame->stack_capacity * 2;
if (new_capacity == 0) new_capacity = 16;
value_t* new_stack = safe_realloc(frame->stack, new_capacity * sizeof(value_t));
if (!new_stack) return false;
frame->stack = new_stack;
frame->stack_capacity = new_capacity;
}
frame->stack[frame->stack_size++] = value;
return true;
}
static bool stack_pop(frame_t* frame, value_t* result) {
if (frame->stack_size == 0) return false;
*result = frame->stack[--frame->stack_size];
return true;
}
// Type checking and conversion
static bool type_check_binary(value_t a, value_t b, type_code_t* result_type) {
// Simple type checking - in real implementation, add proper type promotion
if (a.type == b.type) {
*result_type = a.type;
return true;
}
return false;
}
static int32_t value_to_int(value_t val) {
switch (val.type) {
case TYPE_I8: return val.data.i8;
case TYPE_U8: return val.data.u8;
case TYPE_I16: return val.data.i16;
case TYPE_U16: return val.data.u16;
case TYPE_I32: return val.data.i32;
case TYPE_U32: return (int32_t)val.data.u32;
case TYPE_BOOL: return val.data.boolean ? 1 : 0;
case TYPE_CHAR: return (int32_t)val.data.character;
default: return 0;
}
}
static float value_to_float(value_t val) {
switch (val.type) {
case TYPE_F32: return val.data.f32;
case TYPE_I32: return (float)val.data.i32;
case TYPE_U32: return (float)val.data.u32;
default: return 0.0f;
}
}
// Bytecode validation
bool vm_validate_bytecode(vm_t* vm) {
// Check magic number
if (vm->bytecode_size < 4 || memcmp(vm->bytecode, "POPC", 4) != 0) {
return false;
}
// Add more validation as needed
return true;
}
// Execute single instruction with full error checking
bool vm_execute_instruction(vm_t* vm) {
if (vm->halted || vm->ip >= vm->bytecode_size) return false;
uint8_t opcode;
if (!read_u8(vm, &opcode)) return false;
frame_t* frame = vm->current_frame;
if (!frame) return false;
switch (opcode) {
case OP_PUSH_CONST: {
uint32_t const_idx;
if (!read_u32(vm, &const_idx) || const_idx >= vm->constants_count) {
return false;
}
if (!stack_push(frame, vm->constants[const_idx])) return false;
break;
}
case OP_PUSH_INT: {
uint8_t width;
int32_t value;
if (!read_u8(vm, &width) || !read_i32(vm, &value)) return false;
value_t val = { 0 };
switch (width) {
case 8: val.type = TYPE_I8; val.data.i8 = (int8_t)value; break;
case 16: val.type = TYPE_I16; val.data.i16 = (int16_t)value; break;
case 32: val.type = TYPE_I32; val.data.i32 = value; break;
default: return false;
}
if (!stack_push(frame, val)) return false;
break;
}
case OP_ADD: {
value_t a, b;
if (!stack_pop(frame, &a) || !stack_pop(frame, &b)) return false;
type_code_t result_type;
if (!type_check_binary(a, b, &result_type)) return false;
value_t result = { 0 };
result.type = result_type;
if (result_type == TYPE_F32) {
result.data.f32 = value_to_float(b) + value_to_float(a);
}
else {
result.data.i32 = value_to_int(b) + value_to_int(a);
}
if (!stack_push(frame, result)) return false;
break;
}
case OP_CMP_EQ: {
value_t a, b;
if (!stack_pop(frame, &a) || !stack_pop(frame, &b)) return false;
value_t result = { 0 };
result.type = TYPE_BOOL;
result.data.boolean = (value_to_int(a) == value_to_int(b));
if (!stack_push(frame, result)) return false;
break;
}
case OP_JMP: {
int32_t offset;
if (!read_i32(vm, &offset)) return false;
// Check for negative jumps (security)
if (offset < 0 && (size_t)(-offset) > vm->ip) return false;
if (vm->ip + offset >= vm->bytecode_size) return false;
vm->ip += offset;
break;
}
case OP_PRINT: {
value_t val;
if (!stack_pop(frame, &val)) return false;
switch (val.type) {
case TYPE_I32: printf("%d\n", val.data.i32); break;
case TYPE_F32: printf("%f\n", val.data.f32); break;
case TYPE_BOOL: printf("%s\n", val.data.boolean ? "true" : "false"); break;
case TYPE_STR: printf("%s\n", val.data.string); break;
default: printf("<unknown>\n"); break;
}
break;
}
case OP_HALT:
vm->halted = true;
break;
default:
fprintf(stderr, "Unknown opcode: 0x%02x\n", opcode);
return false;
}
return true;
}
// Main execution loop
void vm_execute(vm_t* vm) {
while (!vm->halted && vm_execute_instruction(vm)) {
// Continue execution
}
}
// Cleanup
void vm_destroy(vm_t* vm) {
if (!vm) return;
// Free constants
for (size_t i = 0; i < vm->constants_count; i++) {
if (vm->constants[i].type == TYPE_STR && vm->constants[i].data.string) {
free(vm->constants[i].data.string);
}
}
free(vm->constants);
// Free functions
free(vm->functions);
// Free frames (simplified - in real impl, walk call stack)
if (vm->current_frame) {
free(vm->current_frame->locals);
free(vm->current_frame->stack);
free(vm->current_frame);
}
free(vm);
}

120
niacin/cpp/vm_types.h Normal file
View File

@@ -0,0 +1,120 @@
#ifndef VM_TYPES_H
#define VM_TYPES_H
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
// Type codes
typedef enum {
TYPE_I8 = 0x01,
TYPE_U8 = 0x02,
TYPE_I16 = 0x03,
TYPE_U16 = 0x04,
TYPE_I32 = 0x05,
TYPE_U32 = 0x06,
TYPE_F32 = 0x07,
TYPE_BOOL = 0x08,
TYPE_CHAR = 0x09,
TYPE_STR = 0x0A
} type_code_t;
// Opcodes
typedef enum {
OP_PUSH_CONST = 0x01,
OP_PUSH_INT = 0x02,
OP_PUSH_FLOAT = 0x03,
OP_PUSH_STR = 0x04,
OP_LOAD_LOCAL = 0x10,
OP_STORE_LOCAL = 0x11,
OP_ADD = 0x20,
OP_SUB = 0x21,
OP_MUL = 0x22,
OP_DIV = 0x23,
OP_MOD = 0x24,
OP_CMP_EQ = 0x40,
OP_CMP_NEQ = 0x41,
OP_CMP_LT = 0x42,
OP_CMP_GT = 0x43,
OP_CMP_LE = 0x44,
OP_CMP_GE = 0x45,
OP_JMP = 0x50,
OP_JMP_IF = 0x51,
OP_JMP_IF_NOT = 0x52,
OP_CALL = 0x60,
OP_RET = 0x61,
OP_DUP = 0x80,
OP_POP = 0x81,
OP_PRINT = 0x90,
OP_HALT = 0xA0
} opcode_t;
// Value union with type safety
typedef union {
int8_t i8;
uint8_t u8;
int16_t i16;
uint16_t u16;
int32_t i32;
uint32_t u32;
float f32;
bool boolean;
char character;
char* string;
} value_data_t;
typedef struct {
type_code_t type;
value_data_t data;
} value_t;
// Function definition
typedef struct {
uint32_t name_index;
uint8_t arg_count;
uint8_t local_count;
uint16_t reserved;
uint32_t code_size;
uint32_t code_offset;
} function_t;
// Call frame
typedef struct frame {
struct frame* prev;
uint32_t return_ip;
value_t* locals;
value_t* stack;
size_t stack_size;
size_t stack_capacity;
size_t locals_count;
} frame_t;
// Virtual machine state
typedef struct {
uint8_t* bytecode;
size_t bytecode_size;
uint32_t ip;
value_t* constants;
size_t constants_count;
function_t* functions;
size_t functions_count;
frame_t* current_frame;
bool halted;
// Security settings
size_t max_stack_size;
size_t max_call_depth;
size_t current_call_depth;
} vm_t;
// Function declarations
vm_t* vm_create(uint8_t* bytecode, size_t size);
bool vm_validate_bytecode(vm_t* vm);
bool vm_execute_instruction(vm_t* vm);
void vm_execute(vm_t* vm);
void vm_destroy(vm_t* vm);
#endif

16
niacin/sample.popasm Normal file
View File

@@ -0,0 +1,16 @@
; POP Class File Version 1.0
; Magic: b'POPC'
; Constant Pool
; Count: 0
; Function Table
; Count: 1
; func[0]: func_0, args=0, locals=1, code_size=15, offset=0x00000024
; Function 0
0x00000024: PUSH_INT i32 12
0x0000002a: STORE_LOCAL local[0]
0x0000002d: LOAD_LOCAL local[0]
0x00000030: PRINT
0x00000031: RET 0

BIN
niacin/sample.popclass Normal file

Binary file not shown.

4
niacin/sample.src Normal file
View File

@@ -0,0 +1,4 @@
fun main() {
u8 testint = 255;
print(testint);
}