Compare commits

...

2 Commits
v0.3.1 ... main

Author SHA1 Message Date
Talles Amadeu 4bb15c84dd add support to read json files 2025-12-09 15:36:06 -03:00
Talles Amadeu 31d7ac51ed add support do i++ and >= and <= 2025-12-09 14:37:28 -03:00
21 changed files with 581 additions and 13 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -11,6 +11,7 @@ void SetPropExpr::accept(ASTVisitor& visitor) { visitor.visit(*this); }
void ArrayExpr::accept(ASTVisitor& visitor) { visitor.visit(*this); } void ArrayExpr::accept(ASTVisitor& visitor) { visitor.visit(*this); }
void IndexExpr::accept(ASTVisitor& visitor) { visitor.visit(*this); } void IndexExpr::accept(ASTVisitor& visitor) { visitor.visit(*this); }
void ArrayAssignExpr::accept(ASTVisitor& visitor) { visitor.visit(*this); } void ArrayAssignExpr::accept(ASTVisitor& visitor) { visitor.visit(*this); }
void IncrementExpr::accept(ASTVisitor& visitor) { visitor.visit(*this); }
void BinaryExpr::accept(ASTVisitor& visitor) { visitor.visit(*this); } void BinaryExpr::accept(ASTVisitor& visitor) { visitor.visit(*this); }
void ReturnStmt::accept(ASTVisitor& visitor) { visitor.visit(*this); } void ReturnStmt::accept(ASTVisitor& visitor) { visitor.visit(*this); }
void VarDeclStmt::accept(ASTVisitor& visitor) { visitor.visit(*this); } void VarDeclStmt::accept(ASTVisitor& visitor) { visitor.visit(*this); }

View File

@ -108,6 +108,13 @@ public:
void accept(ASTVisitor& visitor) override; void accept(ASTVisitor& visitor) override;
}; };
class IncrementExpr : public Expr {
public:
std::unique_ptr<Expr> variable; // Can be VariableExpr, GetPropExpr, IndexExpr
IncrementExpr(std::unique_ptr<Expr> variable) : variable(std::move(variable)) {}
void accept(ASTVisitor& visitor) override;
};
class BinaryExpr : public Expr { class BinaryExpr : public Expr {
public: public:
std::unique_ptr<Expr> left; std::unique_ptr<Expr> left;
@ -239,6 +246,7 @@ public:
virtual void visit(ArrayExpr& node) = 0; virtual void visit(ArrayExpr& node) = 0;
virtual void visit(IndexExpr& node) = 0; virtual void visit(IndexExpr& node) = 0;
virtual void visit(ArrayAssignExpr& node) = 0; virtual void visit(ArrayAssignExpr& node) = 0;
virtual void visit(IncrementExpr& node) = 0;
virtual void visit(BinaryExpr& node) = 0; virtual void visit(BinaryExpr& node) = 0;
virtual void visit(ReturnStmt& node) = 0; virtual void visit(ReturnStmt& node) = 0;
virtual void visit(VarDeclStmt& node) = 0; virtual void visit(VarDeclStmt& node) = 0;

View File

@ -130,3 +130,60 @@ void ASTPrinter::visit(ClassDef& node) {
} }
std::cout << "}"; std::cout << "}";
} }
void ASTPrinter::visit(ArrayExpr& node) {
std::cout << "[";
for (size_t i = 0; i < node.elements.size(); ++i) {
node.elements[i]->accept(*this);
if (i < node.elements.size() - 1) std::cout << ", ";
}
std::cout << "]";
}
void ASTPrinter::visit(IndexExpr& node) {
node.array->accept(*this);
std::cout << "[";
node.index->accept(*this);
std::cout << "]";
}
void ASTPrinter::visit(ArrayAssignExpr& node) {
node.array->accept(*this);
std::cout << "[";
node.index->accept(*this);
std::cout << "] = ";
node.value->accept(*this);
}
void ASTPrinter::visit(IncrementExpr& node) {
node.variable->accept(*this);
std::cout << "++";
}
void ASTPrinter::visit(ForInStmt& node) {
std::cout << "for (var " << node.variableName << " in ";
node.collection->accept(*this);
std::cout << ") ";
node.body->accept(*this);
}
void ASTPrinter::visit(SwitchStmt& node) {
std::cout << "switch (";
node.condition->accept(*this);
std::cout << ") {" << std::endl;
for (const auto& c : node.cases) {
std::cout << "case ";
c.value->accept(*this);
std::cout << ": ";
c.body->accept(*this);
}
if (node.defaultCase) {
std::cout << "default: ";
node.defaultCase->accept(*this);
}
std::cout << "}";
}
void ASTPrinter::visit(BreakStmt& node) {
std::cout << "break;";
}

View File

@ -16,6 +16,10 @@ public:
void visit(NewExpr& node) override; void visit(NewExpr& node) override;
void visit(GetPropExpr& node) override; void visit(GetPropExpr& node) override;
void visit(SetPropExpr& node) override; void visit(SetPropExpr& node) override;
void visit(ArrayExpr& node) override;
void visit(IndexExpr& node) override;
void visit(ArrayAssignExpr& node) override;
void visit(IncrementExpr& node) override;
void visit(BinaryExpr& node) override; void visit(BinaryExpr& node) override;
void visit(ReturnStmt& node) override; void visit(ReturnStmt& node) override;
void visit(VarDeclStmt& node) override; void visit(VarDeclStmt& node) override;
@ -23,6 +27,9 @@ public:
void visit(IfStmt& node) override; void visit(IfStmt& node) override;
void visit(WhileStmt& node) override; void visit(WhileStmt& node) override;
void visit(ForStmt& node) override; void visit(ForStmt& node) override;
void visit(ForInStmt& node) override;
void visit(SwitchStmt& node) override;
void visit(BreakStmt& node) override;
void visit(ExpressionStmt& node) override; void visit(ExpressionStmt& node) override;
void visit(FunctionDef& node) override; void visit(FunctionDef& node) override;
void visit(ClassDef& node) override; void visit(ClassDef& node) override;

View File

@ -1,5 +1,6 @@
#include "codegen.h" #include "codegen.h"
#include <iostream> #include <iostream>
#include <typeinfo>
CodeGen::CodeGen() { CodeGen::CodeGen() {
context = std::make_unique<llvm::LLVMContext>(); context = std::make_unique<llvm::LLVMContext>();
@ -50,6 +51,31 @@ CodeGen::CodeGen() {
false false
); );
llvm::Function::Create(readCsvType, llvm::Function::ExternalLinkage, "sun_read_csv", module.get()); 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) { 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) { void CodeGen::visit(StringExpr& node) {
lastValue = builder->CreateGlobalString(node.value); lastValue = builder->CreateGlobalStringPtr(node.value);
lastClassName = "String"; // Special marker for string lastClassName = "String"; // Special marker for string
} }
@ -178,6 +204,36 @@ void CodeGen::visit(CallExpr& node) {
return; 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 // Handle "len" specially
if (node.callee == "len") { if (node.callee == "len") {
if (node.args.size() != 1) { if (node.args.size() != 1) {
@ -211,8 +267,17 @@ void CodeGen::visit(CallExpr& node) {
std::string argType = lastClassName; std::string argType = lastClassName;
if (argType == "String") { 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"); llvm::Function* printStr = module->getFunction("print_string");
builder->CreateCall(printStr, {argVal}); 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 { } else {
// Assume int // Assume int
llvm::Function* printInt = module->getFunction("print_int"); llvm::Function* printInt = module->getFunction("print_int");
@ -248,6 +313,95 @@ void CodeGen::visit(CallExpr& node) {
lastClassName = ""; lastClassName = "";
} }
void CodeGen::visit(IncrementExpr& node) {
if (auto varExpr = dynamic_cast<VariableExpr*>(node.variable.get())) {
if (namedValues.find(varExpr->name) == namedValues.end()) {
std::cerr << "Unknown variable: " << varExpr->name << std::endl;
lastValue = nullptr;
return;
}
llvm::AllocaInst* alloca = namedValues[varExpr->name];
llvm::Value* val = builder->CreateLoad(alloca->getAllocatedType(), alloca, varExpr->name.c_str());
lastValue = val; // Return old value
llvm::Value* inc = builder->CreateAdd(val, llvm::ConstantInt::get(*context, llvm::APInt(32, 1)), "inc");
builder->CreateStore(inc, alloca);
} else if (auto getProp = dynamic_cast<GetPropExpr*>(node.variable.get())) {
getProp->object->accept(*this);
llvm::Value* objectPtr = lastValue;
std::string className = lastClassName;
if (!objectPtr) return;
if (classFields.find(className) == classFields.end()) {
std::cerr << "Unknown class type: " << className << std::endl;
lastValue = nullptr;
return;
}
const auto& fields = classFields[className];
int fieldIndex = -1;
for (size_t i = 0; i < fields.size(); ++i) {
if (fields[i] == getProp->name) {
fieldIndex = i;
break;
}
}
if (fieldIndex == -1) {
std::cerr << "Unknown field: " << getProp->name << " in class " << className << std::endl;
lastValue = nullptr;
return;
}
std::vector<llvm::Value*> indices;
indices.push_back(llvm::ConstantInt::get(*context, llvm::APInt(32, 0)));
indices.push_back(llvm::ConstantInt::get(*context, llvm::APInt(32, fieldIndex)));
llvm::Type* structType = classStructs[className];
llvm::Value* fieldPtr = builder->CreateGEP(structType, objectPtr, indices, "fieldptr");
llvm::Value* val = builder->CreateLoad(llvm::Type::getInt32Ty(*context), fieldPtr, "fieldval");
lastValue = val;
llvm::Value* inc = builder->CreateAdd(val, llvm::ConstantInt::get(*context, llvm::APInt(32, 1)), "inc");
builder->CreateStore(inc, fieldPtr);
} else if (auto indexExpr = dynamic_cast<IndexExpr*>(node.variable.get())) {
indexExpr->array->accept(*this);
llvm::Value* arrPtr = lastValue;
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");
llvm::Value* valPtr = builder->CreateCall(getFn, {arrPtr, indexVal}, "elem");
// Assume IntArray for increment
llvm::Value* val = builder->CreatePtrToInt(valPtr, llvm::Type::getInt32Ty(*context), "elemInt");
lastValue = val;
llvm::Value* inc = builder->CreateAdd(val, llvm::ConstantInt::get(*context, llvm::APInt(32, 1)), "inc");
// Store back
llvm::Value* voidVal = builder->CreateIntToPtr(inc, llvm::PointerType::get(llvm::Type::getInt8Ty(*context), 0));
builder->CreateCall(setFn, {arrPtr, indexVal, voidVal});
} else {
std::cerr << "Invalid increment target." << std::endl;
lastValue = nullptr;
}
}
void CodeGen::visit(BinaryExpr& node) { void CodeGen::visit(BinaryExpr& node) {
node.left->accept(*this); node.left->accept(*this);
llvm::Value* L = lastValue; llvm::Value* L = lastValue;
@ -311,6 +465,12 @@ void CodeGen::visit(BinaryExpr& node) {
} else if (node.op == ">") { } else if (node.op == ">") {
lastValue = builder->CreateICmpSGT(L, R, "cmptmp"); lastValue = builder->CreateICmpSGT(L, R, "cmptmp");
lastValue = builder->CreateIntCast(lastValue, llvm::Type::getInt32Ty(*context), true, "booltmp"); lastValue = builder->CreateIntCast(lastValue, llvm::Type::getInt32Ty(*context), true, "booltmp");
} else if (node.op == "<=") {
lastValue = builder->CreateICmpSLE(L, R, "cmptmp");
lastValue = builder->CreateIntCast(lastValue, llvm::Type::getInt32Ty(*context), true, "booltmp");
} else if (node.op == ">=") {
lastValue = builder->CreateICmpSGE(L, R, "cmptmp");
lastValue = builder->CreateIntCast(lastValue, llvm::Type::getInt32Ty(*context), true, "booltmp");
} else if (node.op == "==") { } else if (node.op == "==") {
lastValue = builder->CreateICmpEQ(L, R, "cmptmp"); lastValue = builder->CreateICmpEQ(L, R, "cmptmp");
lastValue = builder->CreateIntCast(lastValue, llvm::Type::getInt32Ty(*context), true, "booltmp"); lastValue = builder->CreateIntCast(lastValue, llvm::Type::getInt32Ty(*context), true, "booltmp");
@ -780,8 +940,42 @@ void CodeGen::visit(IndexExpr& node) {
llvm::Value* arrPtr = lastValue; llvm::Value* arrPtr = lastValue;
std::string arrayType = lastClassName; std::string arrayType = lastClassName;
if (!arrPtr) {
std::cerr << "Error: Array evaluated to null in IndexExpr" << std::endl;
return;
}
node.index->accept(*this); node.index->accept(*this);
llvm::Value* indexVal = lastValue; 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::Function* getFn = module->getFunction("sun_array_get");
llvm::Value* valPtr = builder->CreateCall(getFn, {arrPtr, indexVal}, "elem"); llvm::Value* valPtr = builder->CreateCall(getFn, {arrPtr, indexVal}, "elem");
@ -792,6 +986,9 @@ void CodeGen::visit(IndexExpr& node) {
} else if (arrayType == "CSVArray") { } else if (arrayType == "CSVArray") {
lastValue = valPtr; // It's a void* (pointer to array) lastValue = valPtr; // It's a void* (pointer to array)
lastClassName = "StringArray"; lastClassName = "StringArray";
} else if (arrayType == "JSON") {
lastValue = valPtr;
lastClassName = "JSON";
} else { } else {
// Assume IntArray, cast back to i32 // Assume IntArray, cast back to i32
lastValue = builder->CreatePtrToInt(valPtr, llvm::Type::getInt32Ty(*context), "elemInt"); lastValue = builder->CreatePtrToInt(valPtr, llvm::Type::getInt32Ty(*context), "elemInt");

View File

@ -28,6 +28,7 @@ public:
void visit(ArrayExpr& node) override; void visit(ArrayExpr& node) override;
void visit(IndexExpr& node) override; void visit(IndexExpr& node) override;
void visit(ArrayAssignExpr& node) override; void visit(ArrayAssignExpr& node) override;
void visit(IncrementExpr& node) override;
void visit(BinaryExpr& node) override; void visit(BinaryExpr& node) override;
void visit(ReturnStmt& node) override; void visit(ReturnStmt& node) override;
void visit(VarDeclStmt& node) override; void visit(VarDeclStmt& node) override;

View File

@ -107,7 +107,12 @@ Token Lexer::scanToken() {
case '.': return makeToken(TokenType::DOT, "."); case '.': return makeToken(TokenType::DOT, ".");
case ':': return makeToken(TokenType::COLON, ":"); case ':': return makeToken(TokenType::COLON, ":");
case ';': return makeToken(TokenType::SEMICOLON, ";"); case ';': return makeToken(TokenType::SEMICOLON, ";");
case '+': return makeToken(TokenType::PLUS, "+"); case '+':
if (peek() == '+') {
advance();
return makeToken(TokenType::PLUS_PLUS, "++");
}
return makeToken(TokenType::PLUS, "+");
case '-': return makeToken(TokenType::MINUS, "-"); case '-': return makeToken(TokenType::MINUS, "-");
case '*': return makeToken(TokenType::STAR, "*"); case '*': return makeToken(TokenType::STAR, "*");
case '/': case '/':
@ -122,8 +127,18 @@ Token Lexer::scanToken() {
return makeToken(TokenType::EQUAL_EQUAL, "=="); return makeToken(TokenType::EQUAL_EQUAL, "==");
} }
return makeToken(TokenType::EQUALS, "="); return makeToken(TokenType::EQUALS, "=");
case '<': return makeToken(TokenType::LESS, "<"); case '<':
case '>': return makeToken(TokenType::GREATER, ">"); if (peek() == '=') {
advance();
return makeToken(TokenType::LESS_EQUAL, "<=");
}
return makeToken(TokenType::LESS, "<");
case '>':
if (peek() == '=') {
advance();
return makeToken(TokenType::GREATER_EQUAL, ">=");
}
return makeToken(TokenType::GREATER, ">");
case '"': return string(); case '"': return string();
default: return makeToken(TokenType::UNKNOWN, std::string(1, c)); default: return makeToken(TokenType::UNKNOWN, std::string(1, c));
} }

View File

@ -40,20 +40,63 @@ char* str_concat(char* a, char* b) {
return result; return result;
} }
// Struct Definitions
typedef struct { 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; int size;
void** data; void** data;
} Array; } 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) { void* sun_array_create(int size) {
Array* arr = (Array*)malloc(sizeof(Array)); Array* arr = (Array*)malloc(sizeof(Array));
arr->magic = 0x12345678;
arr->size = size; arr->size = size;
arr->data = (void**)calloc(size, sizeof(void*)); arr->data = (void**)calloc(size, sizeof(void*));
return (void*)arr; return (void*)arr;
} }
void sun_array_set(void* arrPtr, int index, void* value) { void sun_array_set(void* arrPtr, int index, void* value) {
if (!arrPtr) return;
Array* arr = (Array*)arrPtr; 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) { if (index >= 0 && index < arr->size) {
arr->data[index] = value; arr->data[index] = value;
} else { } else {
@ -63,21 +106,118 @@ void sun_array_set(void* arrPtr, int index, void* value) {
} }
void* sun_array_get(void* arrPtr, int index) { void* sun_array_get(void* arrPtr, int index) {
if (!arrPtr) return NULL;
Array* arr = (Array*)arrPtr; 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) { if (index >= 0 && index < arr->size) {
return arr->data[index]; return arr->data[index];
} else { } else {
printf("Error: Array index out of bounds: %d\n", index); printf("Error: Array index out of bounds: %d\n", index);
exit(1); exit(1);
} }
return NULL;
} }
int sun_array_length(void* arrPtr) { int sun_array_length(void* arrPtr) {
if (!arrPtr) return 0;
Array* arr = (Array*)arrPtr; 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; 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* sun_strdup(const char* s) {
char* d = (char*)malloc(strlen(s) + 1); char* d = (char*)malloc(strlen(s) + 1);
if (d == NULL) return NULL; if (d == NULL) return NULL;
@ -85,6 +225,122 @@ char* sun_strdup(const char* s) {
return d; 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) { void* sun_read_csv(char* filename, char* separator, char* quote) {
FILE* fp = fopen(filename, "r"); FILE* fp = fopen(filename, "r");
if (!fp) { if (!fp) {

View File

@ -366,7 +366,7 @@ std::unique_ptr<Expr> Parser::equality() {
std::unique_ptr<Expr> Parser::comparison() { std::unique_ptr<Expr> Parser::comparison() {
std::unique_ptr<Expr> expr = term(); std::unique_ptr<Expr> expr = term();
while (match(TokenType::LESS) || match(TokenType::GREATER)) { while (match(TokenType::LESS) || match(TokenType::GREATER) || match(TokenType::LESS_EQUAL) || match(TokenType::GREATER_EQUAL)) {
std::string op = previous().value; std::string op = previous().value;
std::unique_ptr<Expr> right = term(); std::unique_ptr<Expr> right = term();
expr = std::make_unique<BinaryExpr>(std::move(expr), op, std::move(right)); expr = std::make_unique<BinaryExpr>(std::move(expr), op, std::move(right));
@ -410,6 +410,8 @@ std::unique_ptr<Expr> Parser::call() {
std::unique_ptr<Expr> index = expression(); std::unique_ptr<Expr> index = expression();
consume(TokenType::RBRACKET, "Expect ']' after index."); consume(TokenType::RBRACKET, "Expect ']' after index.");
expr = std::make_unique<IndexExpr>(std::move(expr), std::move(index)); expr = std::make_unique<IndexExpr>(std::move(expr), std::move(index));
} else if (match(TokenType::PLUS_PLUS)) {
expr = std::make_unique<IncrementExpr>(std::move(expr));
} else { } else {
break; break;
} }

View File

@ -41,6 +41,9 @@ enum class TokenType {
EQUAL_EQUAL,// == EQUAL_EQUAL,// ==
LESS, // < LESS, // <
GREATER, // > GREATER, // >
LESS_EQUAL, // <=
GREATER_EQUAL, // >=
PLUS_PLUS, // ++
END_OF_FILE, END_OF_FILE,
UNKNOWN UNKNOWN
}; };

View File

@ -1,6 +1,6 @@
#ifndef SUN_VERSION_H #ifndef SUN_VERSION_H
#define SUN_VERSION_H #define SUN_VERSION_H
#define SUN_VERSION "0.3.1" #define SUN_VERSION "0.5.0"
#endif // SUN_VERSION_H #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]
}

View File

@ -1,7 +1,4 @@
function main() {
print("Counting:"); print("Counting:");
for (var i = 0; i < 5; i = i + 1) { for (var i = 0; i <= 5; i++) {
print(i); print(i);
} }
return 0;
}

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;
}