Compare commits
2 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
4bb15c84dd | |
|
|
31d7ac51ed |
BIN
build/ast.o
BIN
build/ast.o
Binary file not shown.
Binary file not shown.
BIN
build/codegen.o
BIN
build/codegen.o
Binary file not shown.
BIN
build/lexer.o
BIN
build/lexer.o
Binary file not shown.
BIN
build/main.o
BIN
build/main.o
Binary file not shown.
BIN
build/parser.o
BIN
build/parser.o
Binary file not shown.
|
|
@ -11,6 +11,7 @@ void SetPropExpr::accept(ASTVisitor& visitor) { visitor.visit(*this); }
|
|||
void ArrayExpr::accept(ASTVisitor& visitor) { visitor.visit(*this); }
|
||||
void IndexExpr::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 ReturnStmt::accept(ASTVisitor& visitor) { visitor.visit(*this); }
|
||||
void VarDeclStmt::accept(ASTVisitor& visitor) { visitor.visit(*this); }
|
||||
|
|
|
|||
|
|
@ -108,6 +108,13 @@ public:
|
|||
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 {
|
||||
public:
|
||||
std::unique_ptr<Expr> left;
|
||||
|
|
@ -239,6 +246,7 @@ public:
|
|||
virtual void visit(ArrayExpr& node) = 0;
|
||||
virtual void visit(IndexExpr& node) = 0;
|
||||
virtual void visit(ArrayAssignExpr& node) = 0;
|
||||
virtual void visit(IncrementExpr& node) = 0;
|
||||
virtual void visit(BinaryExpr& node) = 0;
|
||||
virtual void visit(ReturnStmt& node) = 0;
|
||||
virtual void visit(VarDeclStmt& node) = 0;
|
||||
|
|
|
|||
|
|
@ -130,3 +130,60 @@ void ASTPrinter::visit(ClassDef& node) {
|
|||
}
|
||||
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;";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@ public:
|
|||
void visit(NewExpr& node) override;
|
||||
void visit(GetPropExpr& 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(ReturnStmt& node) override;
|
||||
void visit(VarDeclStmt& node) override;
|
||||
|
|
@ -23,6 +27,9 @@ public:
|
|||
void visit(IfStmt& node) override;
|
||||
void visit(WhileStmt& 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(FunctionDef& node) override;
|
||||
void visit(ClassDef& node) override;
|
||||
|
|
|
|||
199
src/codegen.cpp
199
src/codegen.cpp
|
|
@ -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");
|
||||
|
|
@ -248,6 +313,95 @@ void CodeGen::visit(CallExpr& node) {
|
|||
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) {
|
||||
node.left->accept(*this);
|
||||
llvm::Value* L = lastValue;
|
||||
|
|
@ -311,6 +465,12 @@ void CodeGen::visit(BinaryExpr& node) {
|
|||
} else if (node.op == ">") {
|
||||
lastValue = builder->CreateICmpSGT(L, R, "cmptmp");
|
||||
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 == "==") {
|
||||
lastValue = builder->CreateICmpEQ(L, R, "cmptmp");
|
||||
lastValue = builder->CreateIntCast(lastValue, llvm::Type::getInt32Ty(*context), true, "booltmp");
|
||||
|
|
@ -780,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");
|
||||
|
|
@ -792,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");
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ public:
|
|||
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(ReturnStmt& node) override;
|
||||
void visit(VarDeclStmt& node) override;
|
||||
|
|
|
|||
|
|
@ -107,7 +107,12 @@ Token Lexer::scanToken() {
|
|||
case '.': return makeToken(TokenType::DOT, ".");
|
||||
case ':': return makeToken(TokenType::COLON, ":");
|
||||
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::STAR, "*");
|
||||
case '/':
|
||||
|
|
@ -122,8 +127,18 @@ Token Lexer::scanToken() {
|
|||
return makeToken(TokenType::EQUAL_EQUAL, "==");
|
||||
}
|
||||
return makeToken(TokenType::EQUALS, "=");
|
||||
case '<': return makeToken(TokenType::LESS, "<");
|
||||
case '>': return makeToken(TokenType::GREATER, ">");
|
||||
case '<':
|
||||
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();
|
||||
default: return makeToken(TokenType::UNKNOWN, std::string(1, c));
|
||||
}
|
||||
|
|
|
|||
258
src/main.cpp
258
src/main.cpp
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -366,7 +366,7 @@ std::unique_ptr<Expr> Parser::equality() {
|
|||
std::unique_ptr<Expr> Parser::comparison() {
|
||||
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::unique_ptr<Expr> right = term();
|
||||
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();
|
||||
consume(TokenType::RBRACKET, "Expect ']' after 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 {
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@ enum class TokenType {
|
|||
EQUAL_EQUAL,// ==
|
||||
LESS, // <
|
||||
GREATER, // >
|
||||
LESS_EQUAL, // <=
|
||||
GREATER_EQUAL, // >=
|
||||
PLUS_PLUS, // ++
|
||||
END_OF_FILE,
|
||||
UNKNOWN
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#ifndef SUN_VERSION_H
|
||||
#define SUN_VERSION_H
|
||||
|
||||
#define SUN_VERSION "0.3.1"
|
||||
#define SUN_VERSION "0.5.0"
|
||||
|
||||
#endif // SUN_VERSION_H
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "SunLang",
|
||||
"version": 1,
|
||||
"features": ["csv", "json"],
|
||||
"nested": {
|
||||
"key": "value"
|
||||
},
|
||||
"list": [10, 20, 30]
|
||||
}
|
||||
|
|
@ -1,7 +1,4 @@
|
|||
function main() {
|
||||
print("Counting:");
|
||||
for (var i = 0; i < 5; i = i + 1) {
|
||||
print(i);
|
||||
}
|
||||
return 0;
|
||||
print("Counting:");
|
||||
for (var i = 0; i <= 5; i++) {
|
||||
print(i);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
Loading…
Reference in New Issue