add support to read json files

This commit is contained in:
Talles Amadeu 2025-12-09 15:36:06 -03:00
parent 31d7ac51ed
commit 4bb15c84dd
8 changed files with 393 additions and 3 deletions

Binary file not shown.

Binary file not shown.

View File

@ -1,5 +1,6 @@
#include "codegen.h"
#include <iostream>
#include <typeinfo>
CodeGen::CodeGen() {
context = std::make_unique<llvm::LLVMContext>();
@ -50,6 +51,31 @@ CodeGen::CodeGen() {
false
);
llvm::Function::Create(readCsvType, llvm::Function::ExternalLinkage, "sun_read_csv", module.get());
// void* sun_read_json(char* filename)
llvm::FunctionType* readJsonType = llvm::FunctionType::get(
llvm::PointerType::get(llvm::Type::getInt8Ty(*context), 0),
{
llvm::PointerType::get(llvm::Type::getInt8Ty(*context), 0) // filename
},
false
);
llvm::Function::Create(readJsonType, llvm::Function::ExternalLinkage, "sun_read_json", module.get());
// void sun_print_json(void* val)
llvm::FunctionType* printJsonType = llvm::FunctionType::get(llvm::Type::getVoidTy(*context), {llvm::PointerType::get(llvm::Type::getInt8Ty(*context), 0)}, false);
llvm::Function::Create(printJsonType, llvm::Function::ExternalLinkage, "sun_print_json", module.get());
// void* sun_map_get(void* map, char* key)
llvm::FunctionType* mapGetType = llvm::FunctionType::get(
llvm::PointerType::get(llvm::Type::getInt8Ty(*context), 0),
{
llvm::PointerType::get(llvm::Type::getInt8Ty(*context), 0), // map
llvm::PointerType::get(llvm::Type::getInt8Ty(*context), 0) // key
},
false
);
llvm::Function::Create(mapGetType, llvm::Function::ExternalLinkage, "sun_map_get", module.get());
}
llvm::AllocaInst* CodeGen::createEntryBlockAlloca(llvm::Function* theFunction, const std::string& varName, llvm::Type* type) {
@ -98,7 +124,7 @@ void CodeGen::visit(NumberExpr& node) {
}
void CodeGen::visit(StringExpr& node) {
lastValue = builder->CreateGlobalString(node.value);
lastValue = builder->CreateGlobalStringPtr(node.value);
lastClassName = "String"; // Special marker for string
}
@ -178,6 +204,36 @@ void CodeGen::visit(CallExpr& node) {
return;
}
// Handle "readjson" specially
if (node.callee == "readjson") {
if (node.args.size() != 1) {
std::cerr << "readjson() takes exactly 1 argument." << std::endl;
lastValue = nullptr;
return;
}
node.args[0]->accept(*this);
llvm::Value* filenameVal = lastValue;
if (filenameVal->getType() != llvm::PointerType::get(llvm::Type::getInt8Ty(*context), 0)) {
filenameVal = builder->CreateBitCast(filenameVal, llvm::PointerType::get(llvm::Type::getInt8Ty(*context), 0));
}
llvm::Function* readJsonFn = module->getFunction("sun_read_json");
if (!readJsonFn) {
std::cerr << "Error: sun_read_json function not found in module!" << std::endl;
lastValue = nullptr;
return;
}
lastValue = builder->CreateCall(readJsonFn, {filenameVal}, "json_data");
if (!lastValue) {
std::cerr << "Error: CreateCall for sun_read_json returned null!" << std::endl;
return;
}
lastClassName = "JSON"; // Special marker
return;
}
// Handle "len" specially
if (node.callee == "len") {
if (node.args.size() != 1) {
@ -211,8 +267,17 @@ void CodeGen::visit(CallExpr& node) {
std::string argType = lastClassName;
if (argType == "String") {
if (argVal->getType() != llvm::PointerType::get(llvm::Type::getInt8Ty(*context), 0)) {
argVal = builder->CreateBitCast(argVal, llvm::PointerType::get(llvm::Type::getInt8Ty(*context), 0));
}
llvm::Function* printStr = module->getFunction("print_string");
builder->CreateCall(printStr, {argVal});
} else if (argType == "JSON") {
if (argVal->getType() != llvm::PointerType::get(llvm::Type::getInt8Ty(*context), 0)) {
argVal = builder->CreateBitCast(argVal, llvm::PointerType::get(llvm::Type::getInt8Ty(*context), 0));
}
llvm::Function* printJson = module->getFunction("sun_print_json");
builder->CreateCall(printJson, {argVal});
} else {
// Assume int
llvm::Function* printInt = module->getFunction("print_int");
@ -309,6 +374,14 @@ void CodeGen::visit(IncrementExpr& node) {
indexExpr->index->accept(*this);
llvm::Value* indexVal = lastValue;
std::string indexType = lastClassName;
if (indexType == "String") {
// Map increment? Not supported yet easily without sun_map_set
std::cerr << "Increment on map values not fully supported yet." << std::endl;
lastValue = nullptr;
return;
}
llvm::Function* getFn = module->getFunction("sun_array_get");
llvm::Function* setFn = module->getFunction("sun_array_set");
@ -867,8 +940,42 @@ void CodeGen::visit(IndexExpr& node) {
llvm::Value* arrPtr = lastValue;
std::string arrayType = lastClassName;
if (!arrPtr) {
std::cerr << "Error: Array evaluated to null in IndexExpr" << std::endl;
return;
}
node.index->accept(*this);
llvm::Value* indexVal = lastValue;
std::string indexType = lastClassName;
if (!indexVal) {
std::cerr << "Error: Index evaluated to null in IndexExpr" << std::endl;
return;
}
if (indexType == "String") {
// Map lookup
llvm::Function* getFn = module->getFunction("sun_map_get");
if (!getFn) {
std::cerr << "Error: sun_map_get function not found!" << std::endl;
return;
}
llvm::Value* valPtr = builder->CreateCall(getFn, {arrPtr, indexVal}, "elem");
// We don't know the return type, assume generic (void*) or int?
// If it's JSON, it could be anything.
// Let's assume it returns void* and we might need to cast it if we use it as int.
// But wait, if we use it in an expression, we expect int or string.
// If we assume int, we need PtrToInt.
// If we assume String, we keep it as Ptr.
// For now, let's assume JSON values are either Strings or Ints (casted to Ptr).
// If we don't know, we return Ptr.
lastValue = valPtr;
lastClassName = "JSON"; // Keep it generic
return;
}
llvm::Function* getFn = module->getFunction("sun_array_get");
llvm::Value* valPtr = builder->CreateCall(getFn, {arrPtr, indexVal}, "elem");
@ -879,6 +986,9 @@ void CodeGen::visit(IndexExpr& node) {
} else if (arrayType == "CSVArray") {
lastValue = valPtr; // It's a void* (pointer to array)
lastClassName = "StringArray";
} else if (arrayType == "JSON") {
lastValue = valPtr;
lastClassName = "JSON";
} else {
// Assume IntArray, cast back to i32
lastValue = builder->CreatePtrToInt(valPtr, llvm::Type::getInt32Ty(*context), "elemInt");

View File

@ -40,20 +40,63 @@ char* str_concat(char* a, char* b) {
return result;
}
// Struct Definitions
typedef struct {
int type; // 0=int, 1=string, 2=array, 3=map, 4=null
union {
int i;
char* s;
void* ptr;
} as;
} JsonValue;
typedef struct {
unsigned int magic; // 0x12345678
int size;
void** data;
} Array;
typedef struct {
char* key;
void* value;
} MapEntry;
typedef struct {
int size;
int capacity;
MapEntry* entries;
} Map;
// Forward declarations
void* sun_array_create(int size);
JsonValue* sun_json_array(void* arr);
JsonValue* sun_json_map(void* map);
JsonValue* sun_json_string(char* s);
JsonValue* sun_json_int(int i);
JsonValue* sun_json_null();
char* sun_strdup(const char* s);
// Array Functions
void* sun_array_create(int size) {
Array* arr = (Array*)malloc(sizeof(Array));
arr->magic = 0x12345678;
arr->size = size;
arr->data = (void**)calloc(size, sizeof(void*));
return (void*)arr;
}
void sun_array_set(void* arrPtr, int index, void* value) {
if (!arrPtr) return;
Array* arr = (Array*)arrPtr;
if (arr->magic != 0x12345678) {
JsonValue* v = (JsonValue*)arrPtr;
if (v->type == 2) {
arr = (Array*)v->as.ptr;
} else {
printf("Error: Not an array (set)\n");
exit(1);
}
}
if (index >= 0 && index < arr->size) {
arr->data[index] = value;
} else {
@ -63,21 +106,118 @@ void sun_array_set(void* arrPtr, int index, void* value) {
}
void* sun_array_get(void* arrPtr, int index) {
if (!arrPtr) return NULL;
Array* arr = (Array*)arrPtr;
if (arr->magic != 0x12345678) {
JsonValue* v = (JsonValue*)arrPtr;
if (v->type == 2) {
arr = (Array*)v->as.ptr;
} else {
printf("Error: Not an array (get) type=%d magic=%x\n", v->type, arr->magic);
exit(1);
}
}
if (index >= 0 && index < arr->size) {
return arr->data[index];
} else {
printf("Error: Array index out of bounds: %d\n", index);
exit(1);
}
return NULL;
}
int sun_array_length(void* arrPtr) {
if (!arrPtr) return 0;
Array* arr = (Array*)arrPtr;
if (arr->magic != 0x12345678) {
JsonValue* v = (JsonValue*)arrPtr;
if (v->type == 2) {
arr = (Array*)v->as.ptr;
} else {
printf("Error: Not an array (len)\n");
exit(1);
}
}
return arr->size;
}
// Map Functions
void* sun_map_create() {
Map* map = (Map*)malloc(sizeof(Map));
map->size = 0;
map->capacity = 8;
map->entries = (MapEntry*)malloc(sizeof(MapEntry) * map->capacity);
return (void*)map;
}
void sun_map_set(void* mapPtr, char* key, void* value) {
Map* map = (Map*)mapPtr;
for (int i = 0; i < map->size; i++) {
if (strcmp(map->entries[i].key, key) == 0) {
map->entries[i].value = value;
return;
}
}
if (map->size >= map->capacity) {
map->capacity *= 2;
map->entries = (MapEntry*)realloc(map->entries, sizeof(MapEntry) * map->capacity);
}
map->entries[map->size].key = sun_strdup(key);
map->entries[map->size].value = value;
map->size++;
}
void* sun_map_get(void* mapPtr, char* key) {
if (!mapPtr) return NULL;
JsonValue* v = (JsonValue*)mapPtr;
if (v->type == 3) {
mapPtr = v->as.ptr;
}
Map* map = (Map*)mapPtr;
for (int i = 0; i < map->size; i++) {
if (strcmp(map->entries[i].key, key) == 0) {
return map->entries[i].value;
}
}
return NULL;
}
// JSON Constructors
JsonValue* sun_json_int(int i) {
JsonValue* v = (JsonValue*)malloc(sizeof(JsonValue));
v->type = 0; v->as.i = i; return v;
}
JsonValue* sun_json_string(char* s) {
JsonValue* v = (JsonValue*)malloc(sizeof(JsonValue));
v->type = 1; v->as.s = s; return v;
}
JsonValue* sun_json_array(void* arr) {
JsonValue* v = (JsonValue*)malloc(sizeof(JsonValue));
v->type = 2; v->as.ptr = arr; return v;
}
JsonValue* sun_json_map(void* map) {
JsonValue* v = (JsonValue*)malloc(sizeof(JsonValue));
v->type = 3; v->as.ptr = map; return v;
}
JsonValue* sun_json_null() {
JsonValue* v = (JsonValue*)malloc(sizeof(JsonValue));
v->type = 4; return v;
}
void sun_print_json(void* ptr) {
if (!ptr) { printf("null\n"); return; }
JsonValue* v = (JsonValue*)ptr;
if (v->type == 0) printf("%d\n", v->as.i);
else if (v->type == 1) printf("%s\n", v->as.s);
else if (v->type == 2) printf("[Array]\n");
else if (v->type == 3) printf("[Object]\n");
else if (v->type == 4) printf("null\n");
else printf("Unknown JSON type: %d\n", v->type);
}
char* sun_strdup(const char* s) {
char* d = (char*)malloc(strlen(s) + 1);
if (d == NULL) return NULL;
@ -85,6 +225,122 @@ char* sun_strdup(const char* s) {
return d;
}
// JSON Parser
char* json_pos;
void skip_whitespace() {
while (*json_pos && (*json_pos == ' ' || *json_pos == '\t' || *json_pos == '\n' || *json_pos == '\r')) {
json_pos++;
}
}
void* parse_json_value();
char* parse_json_string() {
skip_whitespace();
if (*json_pos != '"') return NULL;
json_pos++;
char* start = json_pos;
while (*json_pos && *json_pos != '"') {
json_pos++;
}
if (*json_pos == '"') {
*json_pos = '\0';
char* str = sun_strdup(start);
*json_pos = '"';
json_pos++;
return str;
}
return NULL;
}
void* parse_json_object() {
skip_whitespace();
if (*json_pos != '{') return NULL;
json_pos++;
void* map = sun_map_create();
skip_whitespace();
if (*json_pos == '}') {
json_pos++;
return sun_json_map(map);
}
while (1) {
skip_whitespace();
char* key = parse_json_string();
skip_whitespace();
if (*json_pos != ':') { printf("Expected : in JSON object\n"); exit(1); }
json_pos++;
void* value = parse_json_value();
sun_map_set(map, key, value);
skip_whitespace();
if (*json_pos == ',') { json_pos++; continue; }
else if (*json_pos == '}') { json_pos++; break; }
else { printf("Expected , or } in JSON object\n"); exit(1); }
}
return sun_json_map(map);
}
void* parse_json_array() {
skip_whitespace();
if (*json_pos != '[') return NULL;
json_pos++;
int capacity = 8;
int size = 0;
void** temp = (void**)malloc(sizeof(void*) * capacity);
skip_whitespace();
if (*json_pos == ']') {
json_pos++;
void* arr = sun_array_create(0);
free(temp);
return sun_json_array(arr);
}
while (1) {
void* val = parse_json_value();
if (size >= capacity) {
capacity *= 2;
temp = (void**)realloc(temp, sizeof(void*) * capacity);
}
temp[size++] = val;
skip_whitespace();
if (*json_pos == ',') { json_pos++; continue; }
else if (*json_pos == ']') { json_pos++; break; }
else { printf("Expected , or ] in JSON array\n"); exit(1); }
}
void* arr = sun_array_create(size);
Array* a = (Array*)arr;
for(int i=0; i<size; i++) a->data[i] = temp[i];
free(temp);
return sun_json_array(arr);
}
void* parse_json_value() {
skip_whitespace();
if (*json_pos == '{') return parse_json_object();
if (*json_pos == '[') return parse_json_array();
if (*json_pos == '"') return sun_json_string(parse_json_string());
if ((*json_pos >= '0' && *json_pos <= '9') || *json_pos == '-') {
int val = strtol(json_pos, &json_pos, 10);
return sun_json_int(val);
}
if (strncmp(json_pos, "true", 4) == 0) { json_pos += 4; return sun_json_int(1); }
if (strncmp(json_pos, "false", 5) == 0) { json_pos += 5; return sun_json_int(0); }
if (strncmp(json_pos, "null", 4) == 0) { json_pos += 4; return sun_json_null(); }
return NULL;
}
void* sun_read_json(char* filename) {
FILE* fp = fopen(filename, "r");
if (!fp) { printf("Error: Could not open file %s\n", filename); exit(1); }
fseek(fp, 0, SEEK_END);
long length = ftell(fp);
fseek(fp, 0, SEEK_SET);
char* buffer = (char*)malloc(length + 1);
fread(buffer, 1, length, fp);
buffer[length] = '\0';
fclose(fp);
json_pos = buffer;
void* result = parse_json_value();
free(buffer);
return result;
}
void* sun_read_csv(char* filename, char* separator, char* quote) {
FILE* fp = fopen(filename, "r");
if (!fp) {

View File

@ -1,6 +1,6 @@
#ifndef SUN_VERSION_H
#define SUN_VERSION_H
#define SUN_VERSION "0.4.0"
#define SUN_VERSION "0.5.0"
#endif // SUN_VERSION_H

BIN
sun

Binary file not shown.

9
tests/test.json Normal file
View File

@ -0,0 +1,9 @@
{
"name": "SunLang",
"version": 1,
"features": ["csv", "json"],
"nested": {
"key": "value"
},
"list": [10, 20, 30]
}

15
tests/test_json.sun Normal file
View File

@ -0,0 +1,15 @@
function main() {
var data = readjson("./tests/test.json");
print(data["name"]);
print(data["version"]);
var list = data["list"];
print(list[0]);
print(list[1]);
var nested = data["nested"];
print(nested["key"]);
return 0;
}