WIP: dev #1
@@ -22,6 +22,7 @@ public class Generator
|
||||
private readonly string? entryPoint;
|
||||
private IndentedTextWriter writer = new();
|
||||
private HashSet<NubType> referencedTypes = new();
|
||||
private readonly Dictionary<string, string> referencedStringLiterals = new();
|
||||
private readonly HashSet<NubType> emittedTypes = new();
|
||||
private readonly Stack<Scope> scopes = new();
|
||||
private int tmpNameIndex = 0;
|
||||
@@ -98,6 +99,7 @@ public class Generator
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
""");
|
||||
|
||||
@@ -108,6 +110,22 @@ public class Generator
|
||||
referencedTypes.Remove(type);
|
||||
}
|
||||
|
||||
foreach (var (name, value) in referencedStringLiterals)
|
||||
{
|
||||
writer.WriteLine
|
||||
(
|
||||
$$"""
|
||||
static struct nub_core_string {{name}} = {
|
||||
.data = "{{value}}",
|
||||
.length = {{value.Length}},
|
||||
.ref = 0,
|
||||
.flags = FLAG_STRING_LITERAL
|
||||
};
|
||||
|
||||
"""
|
||||
);
|
||||
}
|
||||
|
||||
var header = writer.ToString();
|
||||
|
||||
return $"{header}\n{declarations}\n{implementations}";
|
||||
@@ -122,55 +140,71 @@ public class Generator
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case NubTypeString stringType:
|
||||
case NubTypeString:
|
||||
{
|
||||
writer.WriteLine($"struct {NameMangler.Mangle("core", "string", stringType)}");
|
||||
writer.WriteLine("{");
|
||||
using (writer.Indent())
|
||||
{
|
||||
writer.WriteLine("char *data;");
|
||||
writer.WriteLine("size_t length;");
|
||||
writer.WriteLine("int32_t ref;");
|
||||
writer.WriteLine("uint32_t flags;");
|
||||
}
|
||||
writer.WriteLine("};");
|
||||
writer.WriteLine();
|
||||
writer.WriteLine
|
||||
(
|
||||
"""
|
||||
#define FLAG_STRING_LITERAL 1
|
||||
|
||||
writer.WriteLine("#define FLAG_STRING_LITERAL 1");
|
||||
writer.WriteLine();
|
||||
struct nub_core_string
|
||||
{
|
||||
char *data;
|
||||
size_t length;
|
||||
uint32_t ref;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
writer.WriteLine($"static inline void rc_inc({CType(NubTypeString.Instance, "string")})");
|
||||
writer.WriteLine("{");
|
||||
using (writer.Indent())
|
||||
static inline void string_rc_inc(struct nub_core_string *string)
|
||||
{
|
||||
writer.WriteLine($"string->ref += 1;");
|
||||
}
|
||||
writer.WriteLine("}");
|
||||
writer.WriteLine();
|
||||
if (string->flags & FLAG_STRING_LITERAL)
|
||||
return;
|
||||
|
||||
writer.WriteLine($"static inline void rc_dec({CType(NubTypeString.Instance, "string")})");
|
||||
writer.WriteLine("{");
|
||||
using (writer.Indent())
|
||||
{
|
||||
writer.WriteLine($"string->ref -= 1;");
|
||||
writer.WriteLine($"if (string->ref <= 0)");
|
||||
writer.WriteLine("{");
|
||||
using (writer.Indent())
|
||||
{
|
||||
writer.WriteLine($"if ((string->flags & FLAG_STRING_LITERAL) == 0)");
|
||||
writer.WriteLine("{");
|
||||
using (writer.Indent())
|
||||
{
|
||||
writer.WriteLine($"free(string->data);");
|
||||
string->ref += 1;
|
||||
}
|
||||
writer.WriteLine("}");
|
||||
writer.WriteLine($"free(string);");
|
||||
}
|
||||
writer.WriteLine("}");
|
||||
|
||||
static inline void string_rc_dec(struct nub_core_string *string)
|
||||
{
|
||||
if (string->flags & FLAG_STRING_LITERAL)
|
||||
return;
|
||||
|
||||
string->ref -= 1;
|
||||
|
||||
if (string->ref == 0)
|
||||
{
|
||||
free(string->data);
|
||||
free(string);
|
||||
}
|
||||
writer.WriteLine("}");
|
||||
writer.WriteLine();
|
||||
}
|
||||
|
||||
static inline struct nub_core_string *string_concat(struct nub_core_string *left, struct nub_core_string *right)
|
||||
{
|
||||
size_t new_length = left->length + right->length;
|
||||
struct nub_core_string *result = malloc(sizeof(struct nub_core_string));
|
||||
result->data = malloc(new_length + 1);
|
||||
memcpy(result->data, left->data, left->length);
|
||||
memcpy(result->data + left->length, right->data, right->length);
|
||||
result->data[new_length] = '\0';
|
||||
result->length = new_length;
|
||||
result->ref = 1;
|
||||
result->flags = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline struct nub_core_string *string_from_cstr(const char* cstr)
|
||||
{
|
||||
size_t len = strlen(cstr);
|
||||
struct nub_core_string *result = malloc(sizeof(struct nub_core_string));
|
||||
result->data = malloc(len + 1);
|
||||
memcpy(result->data, cstr, len + 1);
|
||||
result->length = len;
|
||||
result->ref = 1;
|
||||
result->flags = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
"""
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -460,6 +494,14 @@ public class Generator
|
||||
var left = EmitExpression(expression.Left);
|
||||
var right = EmitExpression(expression.Right);
|
||||
|
||||
if (expression.Operation == TypedNodeExpressionBinary.Op.Add && expression.Left.Type is NubTypeString && expression.Right.Type is NubTypeString)
|
||||
{
|
||||
var name = TmpName();
|
||||
scopes.Peek().DeconstructableNames.Add((name, expression.Type));
|
||||
writer.WriteLine($"{CType(NubTypeString.Instance, name)} = string_concat({left}, {right});");
|
||||
return name;
|
||||
}
|
||||
|
||||
return expression.Operation switch
|
||||
{
|
||||
TypedNodeExpressionBinary.Op.Add => $"({left} + {right})",
|
||||
@@ -496,17 +538,8 @@ public class Generator
|
||||
private string EmitExpressionStringLiteral(TypedNodeExpressionStringLiteral expression)
|
||||
{
|
||||
var name = TmpName();
|
||||
scopes.Peek().DeconstructableNames.Add((name, expression.Type));
|
||||
|
||||
var variable = CType(expression.Type, name);
|
||||
|
||||
writer.WriteLine($"{variable} = malloc(sizeof(struct {NameMangler.Mangle("core", "string", expression.Type)}));");
|
||||
writer.WriteLine($"{name}->data = \"{expression.Value.Value}\";");
|
||||
writer.WriteLine($"{name}->length = {expression.Value.Value.Length};");
|
||||
writer.WriteLine($"{name}->ref = 1;");
|
||||
writer.WriteLine($"{name}->flags = FLAG_STRING_LITERAL;");
|
||||
|
||||
return name;
|
||||
referencedStringLiterals.Add(name, expression.Value.Value);
|
||||
return $"&{name}";
|
||||
}
|
||||
|
||||
private string EmitExpressionStructLiteral(TypedNodeExpressionStructLiteral expression)
|
||||
@@ -599,7 +632,7 @@ public class Generator
|
||||
NubTypeSInt type => $"int{type.Width}_t" + (varName != null ? $" {varName}" : ""),
|
||||
NubTypeUInt type => $"uint{type.Width}_t" + (varName != null ? $" {varName}" : ""),
|
||||
NubTypePointer type => CType(type.To) + (varName != null ? $" *{varName}" : "*"),
|
||||
NubTypeString type => $"struct {NameMangler.Mangle("core", "string", type)}" + (varName != null ? $" *{varName}" : "*"),
|
||||
NubTypeString type => "struct nub_core_string" + (varName != null ? $" *{varName}" : "*"),
|
||||
NubTypeFunc type => $"{CType(type.ReturnType)} (*{varName})({string.Join(", ", type.Parameters.Select(p => CType(p)))})",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(node), node, null)
|
||||
};
|
||||
@@ -642,7 +675,7 @@ public class Generator
|
||||
{
|
||||
case NubTypeString:
|
||||
{
|
||||
writer.WriteLine($"rc_inc({value});");
|
||||
writer.WriteLine($"string_rc_inc({value});");
|
||||
break;
|
||||
}
|
||||
case NubTypeStruct structType:
|
||||
@@ -709,7 +742,7 @@ public class Generator
|
||||
{
|
||||
case NubTypeString:
|
||||
{
|
||||
writer.WriteLine($"rc_dec({value});");
|
||||
writer.WriteLine($"string_rc_dec({value});");
|
||||
break;
|
||||
}
|
||||
case NubTypeStruct structType:
|
||||
|
||||
@@ -255,6 +255,24 @@ public class TypeChecker
|
||||
switch (expression.Operation)
|
||||
{
|
||||
case NodeExpressionBinary.Op.Add:
|
||||
{
|
||||
if (left.Type is NubTypeString)
|
||||
{
|
||||
if (right.Type is not NubTypeString)
|
||||
throw BasicError("Right hand side of string concatination operator must be a string", right);
|
||||
|
||||
return new TypedNodeExpressionBinary(expression.Tokens, NubTypeString.Instance, left, CheckExpressionBinaryOperation(expression.Operation), right);
|
||||
}
|
||||
|
||||
if (left.Type is not NubTypeSInt and not NubTypeUInt)
|
||||
throw BasicError($"Unsupported type for left hand side arithmetic operation: {left.Type}", left);
|
||||
|
||||
if (right.Type is not NubTypeSInt and not NubTypeUInt)
|
||||
throw BasicError($"Unsupported type for right hand side arithmetic operation: {right.Type}", right);
|
||||
|
||||
type = left.Type;
|
||||
break;
|
||||
}
|
||||
case NodeExpressionBinary.Op.Subtract:
|
||||
case NodeExpressionBinary.Op.Multiply:
|
||||
case NodeExpressionBinary.Op.Divide:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
set -e
|
||||
|
||||
pushd core
|
||||
dotnet run --project ../../compiler sys.nub print.nub file.nub --type=lib
|
||||
dotnet run --project ../../compiler sys.nub print.nub --type=lib
|
||||
popd
|
||||
|
||||
pushd program
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
module file
|
||||
|
||||
export func read_text(path: string): ^u8 {
|
||||
let fd = sys::open(path.ptr 0 0o644)
|
||||
if fd < 0 {
|
||||
return ^u8(0) // failed to open
|
||||
}
|
||||
|
||||
let buf_size: u64 = 4096
|
||||
let buf = c::malloc(buf_size) as ^u8
|
||||
if buf == ^u8(0) {
|
||||
return ^u8(0)
|
||||
}
|
||||
|
||||
let bytes_read = sys::read(fd, buf, buf_size)
|
||||
if bytes_read < 0 {
|
||||
c::free(buf)
|
||||
return ^u8(0)
|
||||
}
|
||||
|
||||
buf[bytes_read] = 0
|
||||
|
||||
return buf
|
||||
}
|
||||
@@ -1,12 +1,7 @@
|
||||
module main
|
||||
|
||||
extern func puts(text: ^u8)
|
||||
|
||||
func main(): i32 {
|
||||
core::println("Hello, world!")
|
||||
|
||||
let file = file::read_text("file.nub")
|
||||
puts(file)
|
||||
|
||||
core::println("Hello" + "World")
|
||||
return 0
|
||||
}
|
||||
Reference in New Issue
Block a user