Compare commits
2 Commits
270be1f740
...
faf506f409
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
faf506f409 | ||
|
|
16d27c76ab |
6
TODO.txt
Normal file
6
TODO.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
Comma seperated function parameters and struct/enum mebers
|
||||||
|
Converting ^u8 to string
|
||||||
|
string formatting
|
||||||
|
string concatination
|
||||||
|
Dynamic arrays
|
||||||
|
C-style arrays
|
||||||
@@ -22,6 +22,7 @@ public class Generator
|
|||||||
private readonly string? entryPoint;
|
private readonly string? entryPoint;
|
||||||
private IndentedTextWriter writer = new();
|
private IndentedTextWriter writer = new();
|
||||||
private HashSet<NubType> referencedTypes = new();
|
private HashSet<NubType> referencedTypes = new();
|
||||||
|
private readonly Dictionary<string, string> referencedStringLiterals = new();
|
||||||
private readonly HashSet<NubType> emittedTypes = new();
|
private readonly HashSet<NubType> emittedTypes = new();
|
||||||
private readonly Stack<Scope> scopes = new();
|
private readonly Stack<Scope> scopes = new();
|
||||||
private int tmpNameIndex = 0;
|
private int tmpNameIndex = 0;
|
||||||
@@ -98,6 +99,7 @@ public class Generator
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
""");
|
""");
|
||||||
|
|
||||||
@@ -108,6 +110,22 @@ public class Generator
|
|||||||
referencedTypes.Remove(type);
|
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();
|
var header = writer.ToString();
|
||||||
|
|
||||||
return $"{header}\n{declarations}\n{implementations}";
|
return $"{header}\n{declarations}\n{implementations}";
|
||||||
@@ -122,55 +140,71 @@ public class Generator
|
|||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case NubTypeString stringType:
|
case NubTypeString:
|
||||||
{
|
{
|
||||||
writer.WriteLine($"struct {NameMangler.Mangle("core", "string", stringType)}");
|
writer.WriteLine
|
||||||
writer.WriteLine("{");
|
(
|
||||||
using (writer.Indent())
|
"""
|
||||||
{
|
#define FLAG_STRING_LITERAL 1
|
||||||
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");
|
struct nub_core_string
|
||||||
writer.WriteLine();
|
{
|
||||||
|
char *data;
|
||||||
|
size_t length;
|
||||||
|
uint32_t ref;
|
||||||
|
uint32_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
writer.WriteLine($"static inline void rc_inc({CType(NubTypeString.Instance, "string")})");
|
static inline void string_rc_inc(struct nub_core_string *string)
|
||||||
writer.WriteLine("{");
|
|
||||||
using (writer.Indent())
|
|
||||||
{
|
{
|
||||||
writer.WriteLine($"string->ref += 1;");
|
if (string->flags & FLAG_STRING_LITERAL)
|
||||||
}
|
return;
|
||||||
writer.WriteLine("}");
|
|
||||||
writer.WriteLine();
|
|
||||||
|
|
||||||
writer.WriteLine($"static inline void rc_dec({CType(NubTypeString.Instance, "string")})");
|
string->ref += 1;
|
||||||
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);");
|
|
||||||
}
|
}
|
||||||
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;
|
break;
|
||||||
}
|
}
|
||||||
@@ -460,6 +494,14 @@ public class Generator
|
|||||||
var left = EmitExpression(expression.Left);
|
var left = EmitExpression(expression.Left);
|
||||||
var right = EmitExpression(expression.Right);
|
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
|
return expression.Operation switch
|
||||||
{
|
{
|
||||||
TypedNodeExpressionBinary.Op.Add => $"({left} + {right})",
|
TypedNodeExpressionBinary.Op.Add => $"({left} + {right})",
|
||||||
@@ -496,17 +538,8 @@ public class Generator
|
|||||||
private string EmitExpressionStringLiteral(TypedNodeExpressionStringLiteral expression)
|
private string EmitExpressionStringLiteral(TypedNodeExpressionStringLiteral expression)
|
||||||
{
|
{
|
||||||
var name = TmpName();
|
var name = TmpName();
|
||||||
scopes.Peek().DeconstructableNames.Add((name, expression.Type));
|
referencedStringLiterals.Add(name, expression.Value.Value);
|
||||||
|
return $"&{name}";
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string EmitExpressionStructLiteral(TypedNodeExpressionStructLiteral expression)
|
private string EmitExpressionStructLiteral(TypedNodeExpressionStructLiteral expression)
|
||||||
@@ -599,7 +632,7 @@ public class Generator
|
|||||||
NubTypeSInt type => $"int{type.Width}_t" + (varName != null ? $" {varName}" : ""),
|
NubTypeSInt type => $"int{type.Width}_t" + (varName != null ? $" {varName}" : ""),
|
||||||
NubTypeUInt type => $"uint{type.Width}_t" + (varName != null ? $" {varName}" : ""),
|
NubTypeUInt type => $"uint{type.Width}_t" + (varName != null ? $" {varName}" : ""),
|
||||||
NubTypePointer type => CType(type.To) + (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)))})",
|
NubTypeFunc type => $"{CType(type.ReturnType)} (*{varName})({string.Join(", ", type.Parameters.Select(p => CType(p)))})",
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(node), node, null)
|
_ => throw new ArgumentOutOfRangeException(nameof(node), node, null)
|
||||||
};
|
};
|
||||||
@@ -642,7 +675,7 @@ public class Generator
|
|||||||
{
|
{
|
||||||
case NubTypeString:
|
case NubTypeString:
|
||||||
{
|
{
|
||||||
writer.WriteLine($"rc_inc({value});");
|
writer.WriteLine($"string_rc_inc({value});");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NubTypeStruct structType:
|
case NubTypeStruct structType:
|
||||||
@@ -709,7 +742,7 @@ public class Generator
|
|||||||
{
|
{
|
||||||
case NubTypeString:
|
case NubTypeString:
|
||||||
{
|
{
|
||||||
writer.WriteLine($"rc_dec({value});");
|
writer.WriteLine($"string_rc_dec({value});");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NubTypeStruct structType:
|
case NubTypeStruct structType:
|
||||||
|
|||||||
@@ -158,13 +158,13 @@ File.WriteAllText(".build/out.c", output);
|
|||||||
|
|
||||||
if (compileLib)
|
if (compileLib)
|
||||||
{
|
{
|
||||||
Process.Start("gcc", ["-Og", "-fno-builtin", "-c", "-o", ".build/out.o", ".build/out.c", .. archivePaths]).WaitForExit();
|
Process.Start("gcc", ["-Og", "-g", "-fno-builtin", "-c", "-o", ".build/out.o", ".build/out.c", .. archivePaths]).WaitForExit();
|
||||||
Process.Start("ar", ["rcs", ".build/out.a", ".build/out.o"]).WaitForExit();
|
Process.Start("ar", ["rcs", ".build/out.a", ".build/out.o"]).WaitForExit();
|
||||||
NubLib.Pack(".build/out.nublib", ".build/out.a", Manifest.Create(moduleGraph));
|
NubLib.Pack(".build/out.nublib", ".build/out.a", Manifest.Create(moduleGraph));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Process.Start("gcc", ["-Og", "-fno-builtin", "-o", ".build/out", ".build/out.c", .. archivePaths]).WaitForExit();
|
Process.Start("gcc", ["-Og", "-g", "-fno-builtin", "-o", ".build/out", ".build/out.c", .. archivePaths]).WaitForExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -255,6 +255,24 @@ public class TypeChecker
|
|||||||
switch (expression.Operation)
|
switch (expression.Operation)
|
||||||
{
|
{
|
||||||
case NodeExpressionBinary.Op.Add:
|
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.Subtract:
|
||||||
case NodeExpressionBinary.Op.Multiply:
|
case NodeExpressionBinary.Op.Multiply:
|
||||||
case NodeExpressionBinary.Op.Divide:
|
case NodeExpressionBinary.Op.Divide:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
pushd core
|
pushd core
|
||||||
dotnet run --project ../../compiler print.nub --type=lib
|
dotnet run --project ../../compiler sys.nub print.nub --type=lib
|
||||||
popd
|
popd
|
||||||
|
|
||||||
pushd program
|
pushd program
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
module core
|
module core
|
||||||
|
|
||||||
extern func puts(text: ^u8)
|
|
||||||
|
|
||||||
export func print(text: string) {
|
export func print(text: string) {
|
||||||
puts(text.ptr)
|
sys::write(0 text.ptr text.length)
|
||||||
|
}
|
||||||
|
|
||||||
|
export func println(text: string) {
|
||||||
|
print(text)
|
||||||
|
print("\n")
|
||||||
}
|
}
|
||||||
5
examples/core/sys.nub
Normal file
5
examples/core/sys.nub
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
module sys
|
||||||
|
|
||||||
|
export extern func read(fd: u32 buf: ^u8 count: u64): i64
|
||||||
|
export extern func write(fd: u32 buf: ^u8 count: u64): i64
|
||||||
|
export extern func open(fileName: ^u8 flags: i32 mode: u16): i64
|
||||||
@@ -1,25 +1,7 @@
|
|||||||
module main
|
module main
|
||||||
|
|
||||||
extern func puts(text: ^u8)
|
|
||||||
|
|
||||||
export func print(text: string) {
|
|
||||||
puts(text.ptr)
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Message {
|
|
||||||
Tell: string
|
|
||||||
}
|
|
||||||
|
|
||||||
func main(): i32 {
|
func main(): i32 {
|
||||||
let x = "test"
|
core::println("Hello, world!")
|
||||||
|
core::println("Hello" + "World")
|
||||||
let y = {
|
|
||||||
abc = x
|
|
||||||
}
|
|
||||||
|
|
||||||
let a: Message = enum Message::Tell x
|
|
||||||
|
|
||||||
core::print(x)
|
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user