Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/cx
*.c
harpy
25 changes: 25 additions & 0 deletions examples/generics6.cx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//! F1\nchar*\n
import std.io;

alias F1 = Foo<char*, int>

struct Foo<K, T> {
void bar(T val) {
if __is(F1, Foo<K, T>)
printf("F1\n");
else if __is(K, char*)
printf("char*\n");
else
printf("%s %s\n", __type(K), __type(T));
}
}

int main() {
F1 f1;
f1.bar(60);

Foo<char*, long> f2;
f2.bar(60);

return 0;
}
29 changes: 29 additions & 0 deletions examples/std/file.cx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//# 0
import std.file;
import std.path;
import std.io;

int main() {
char* testPath = "test.txt";

char* ext = Path.ext(testPath);
printf("Extension: %s\n", ext);

bool!FileError writeRes = File.writeText(testPath, "Hello Cx World!");
if !writeRes.valid {
printf("Failed to write: %d\n", writeRes.error);
return 1;
}

char*!FileError readRes = File.readText(testPath);
if !readRes.valid {
printf("Failed to read: %d\n", readRes.error);
return 1;
}

char* content = readRes.ok;
printf("File content: %s\n", content);

free(content);
return 0;
}
26 changes: 26 additions & 0 deletions examples/std/hashmap.cx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//! age: 18\nkey 'fernando' not found\nupdated age: 19\nkeys: 3\n
import std.hashmap;
import std.io;

int main() {
HashMap<int> map = HashMap<int>.new(16);
defer map.delete();

map.set("age", 18);
map.set("year", 2026);
map.set("port", 8080);

Box<int> age = map.get("age");
if !age.isEmpty()
printf("age: %d\n", age.unwrap());

Box<int> nonexistent = map.get("fernando");
if nonexistent.isEmpty()
printf("key 'fernando' not found\n");

map.set("age", 19); // overwrite
printf("updated age: %d\n", map.get("age").unwrap());
printf("keys: %d\n", map.size);

return 0;
}
5 changes: 1 addition & 4 deletions examples/std/hello.cx
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
//! Hello from Cx ;) \n
import std; // importa todos os módulos (sem subdiretórios) da stdlib
import std.io;

int main() {
printf("Hello from Cx ;) \n");
return 0;
}

int main() {
return 1;
}
6 changes: 6 additions & 0 deletions examples/ternary.cx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//# 67

/// The Main Function
int main() {
return 0 == 0 ? 67 : 69;
}
19 changes: 6 additions & 13 deletions src/backend/codegen.d
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,10 @@ private:
// writeln("right: ", tn.right.toStr());
return format("%s", tn.left.toStr() == tn.right.toStr() ? "true" : "false");

case NodeKind.TernaryExpr:
TernaryExpr tn = cast(TernaryExpr) node;
return format("%s ? %s : %s", compileExpr(tn.expr), compileExpr(tn.left), compileExpr(tn.right));

default:
return "/* invalid expr */";
}
Expand Down Expand Up @@ -763,17 +767,6 @@ private:
actualType = a;
}

string clearNameMangling(string name)
{
string buff;
for (ulong i; i < name.length; i++)
if (name[i] == '*')
buff ~= 'P';
else
buff ~= name[i];
return buff;
}

void compileFnDecl(FnDecl fn, uint ind, bool isMethod = false, string methodType = "", bool fromGeneric = false)
{
defer = []; // limpa
Expand Down Expand Up @@ -817,7 +810,7 @@ private:
if (fnErrorUnion)
{
TypeExprResult res = cast(TypeExprResult) fn.type_expr;
fnUnion = res.toString();
fnUnion = clearNameMangling(res.toString());
fnError[0] = res.ok;
fnError[1] = res.error;

Expand All @@ -827,7 +820,7 @@ private:
errorUnions[fnUnion] = true;
typedefs ~= format("typedef struct %s %s;", fnUnion, fnUnion);
unionErrors ~= format("struct %s { bool valid; union { %s ok; %s error; } val; };", fnUnion,
res.ok.toStr(), res.error.toStr());
res.ok.toString(), res.error.toStr());
}
}
bool hasReturn;
Expand Down
31 changes: 31 additions & 0 deletions src/frontend/parser/ast.d
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ enum NodeKind : ubyte
TypeNameExpr, // 1 2
IsExpr, // 1 2
TTypeExpr, // 1 2
TernaryExpr, // 1 2

IncludeHeader, // 1 2
VarDecl, // 1 2
Expand Down Expand Up @@ -1685,6 +1686,36 @@ class IsExpr : Node
}
}

class TernaryExpr : Node
{
Node expr, left, right;

this(Node expr, Node left, Node right, Position pos)
{
super(NodeKind.TernaryExpr, pos);
this.expr = expr;
this.left = left;
this.right = right;
}

override void print(uint indent)
{
iprint(indent, "TernaryExpr");
}

override TernaryExpr dup()
{
return new TernaryExpr(expr.dup(), left.dup(), right.dup(), pos);
}

override void subGeneric(string[] names, TypeExpr[] types)
{
expr.subGeneric(names, types);
left.subGeneric(names, types);
right.subGeneric(names, types);
}
}

pragma(inline, true)
private void iprint(uint indent, string s)
{
Expand Down
13 changes: 13 additions & 0 deletions src/frontend/parser/parse_expr.d
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ enum Precedence : ubyte
{
Low,
Assign, // = += -= etc
Ternary, // ?
Or, // ||
And, // &&
BitOr, // |
Expand Down Expand Up @@ -407,6 +408,14 @@ public:
return new IndexExpr(left, idx, p.getPos(left.pos, end));
}

Node parseTernaryExpr(Node expr)
{
Node left = parse();
p.consume(TokenKind.Colon, "Expected ':'");
Node right = parse();
return new TernaryExpr(expr, left, right, p.getPos(expr.pos, right.pos));
}

Node led(Node left)
{
Token tk = p.advance();
Expand Down Expand Up @@ -452,6 +461,8 @@ public:
case TokenKind.PPlus:
case TokenKind.MMinus:
return new UnaryExpr(left, tk.kind, tk.pos, true);
case TokenKind.Question:
return parseTernaryExpr(left);
default:
return left;
}
Expand All @@ -472,6 +483,8 @@ public:
case TokenKind.SHLEquals:
case TokenKind.SHREquals:
return Precedence.Assign;
case TokenKind.Question:
return Precedence.Ternary;
case TokenKind.Or:
return Precedence.Or;
case TokenKind.And:
Expand Down
3 changes: 2 additions & 1 deletion src/frontend/type_expr.d
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
module frontend.type_expr;

import frontend.lexer : Position;
import utils;

import std.format;
import std.stdio;
Expand Down Expand Up @@ -419,7 +420,7 @@ class TypeExprResult : TypeExpr

override string toStrVar(string var = "") const
{
return format("%s%s", ok.toStr(), error.toStr()) ~ (var == "" ? "" : " " ~ var);
return format("%s%s", clearNameMangling(ok.toString()), error.toString()) ~ (var == "" ? "" : " " ~ var);
}

override string toStr() const
Expand Down
7 changes: 7 additions & 0 deletions src/frontend/type_resolve.d
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,13 @@ private:
resolveExprType((cast(TypeNameExpr) n).expr, scp);
return n.type_expr;

case NodeKind.TernaryExpr:
TernaryExpr tn = cast(TernaryExpr) n;
resolveExprType(tn.expr, scp);
resolveExprType(tn.left, scp);
resolveExprType(tn.right, scp);
return tn.left.type_expr;

default:
// já vêm com type_expr setado no próprio construtor
return n.type_expr;
Expand Down
11 changes: 11 additions & 0 deletions src/utils.d
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,14 @@ string ext(string file)
{
return (file[$ - 3 .. $] != ".cx") ? file ~ ".cx" : file;
}

string clearNameMangling(string name)
{
string buff;
for (ulong i; i < name.length; i++)
if (name[i] == '*')
buff ~= 'P';
else
buff ~= name[i];
return buff;
}
19 changes: 16 additions & 3 deletions std/arena.cx
Original file line number Diff line number Diff line change
@@ -1,22 +1,33 @@
import std.lib;

struct Arena
/// A simple bump allocator. Grows by reallocating when capacity
/// is exceeded; never shrinks. Caller owns the lifetime and must
/// call `free()` when done.
struct Arena
{
char* data;
u32 size;
u32 cap;

static Arena new(u32 cap)
/// Creates a new Arena with the given initial capacity in bytes.
/// The underlying buffer is zero-initialized.
static Arena new(u32 cap)
{
char* data = calloc(1, cap);
return (Arena) {data, 0, cap};
}

/// Rounds `size` up to the next multiple of 8, ensuring
/// allocations stay aligned. Internal helper used by `alloc`.
u32 alignUp(u32 size)
{
return (size + 7) & ~7;
}

/// Allocates `size` bytes from the arena, aligned to 8 bytes.
/// Grows the underlying buffer automatically if there isn't
/// enough room left. Returns a pointer valid until `free()`
/// is called or the arena is reallocated again.
void* alloc(u32 size)
{
size = self.alignUp(size);
Expand All @@ -32,7 +43,9 @@ struct Arena
return (void*) data;
}

void free()
/// Releases the underlying buffer. After calling this, every
/// pointer previously returned by `alloc()` is invalid.
void free()
{
free(self.data);
}
Expand Down
Loading
Loading