WIP: dev #1
@@ -23,8 +23,6 @@ public class ModuleGraph(Dictionary<string, ModuleGraph.Module> modules)
|
||||
return new Manifest(1, GetModules().Select(x => x.CreateManifestModule()).ToList());
|
||||
}
|
||||
|
||||
public record Manifest(int Version, IReadOnlyList<Module.ManifestModule> Modules);
|
||||
|
||||
public sealed class Module(string name)
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
@@ -110,7 +108,7 @@ public class ModuleGraph(Dictionary<string, ModuleGraph.Module> modules)
|
||||
|
||||
public ManifestCustomTypeInfo CreateManifestCustomTypeInfo()
|
||||
{
|
||||
return new ManifestCustomTypeInfo(Type, Exported);
|
||||
return new ManifestCustomTypeInfo(TypeMangler.Encode(Type), Exported);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,13 +120,9 @@ public class ModuleGraph(Dictionary<string, ModuleGraph.Module> modules)
|
||||
|
||||
public ManifestIdentifierInfo CreateManifestIdentifierInfo()
|
||||
{
|
||||
return new ManifestIdentifierInfo(Type, Exported);
|
||||
return new ManifestIdentifierInfo(TypeMangler.Encode(Type), Exported);
|
||||
}
|
||||
}
|
||||
|
||||
public record ManifestModule(string Name, Dictionary<string, ManifestCustomTypeInfo> CustomTypes, Dictionary<string, ManifestIdentifierInfo> Identifiers);
|
||||
public record ManifestCustomTypeInfo(NubType Type, bool Exported);
|
||||
public record ManifestIdentifierInfo(NubType Type, bool Exported);
|
||||
}
|
||||
|
||||
public class Builder
|
||||
@@ -165,12 +159,14 @@ public class ModuleGraph(Dictionary<string, ModuleGraph.Module> modules)
|
||||
|
||||
foreach (var customType in manifestModule.CustomTypes)
|
||||
{
|
||||
module.AddCustomType(customType.Key, new Module.CustomTypeInfo(customType.Value.Type, customType.Value.Exported, Module.Source.Lib));
|
||||
var decoded = TypeMangler.Decode(customType.Value.EncodedType);
|
||||
module.AddCustomType(customType.Key, new Module.CustomTypeInfo(decoded, customType.Value.Exported, Module.Source.Lib));
|
||||
}
|
||||
|
||||
foreach (var customType in manifestModule.Identifiers)
|
||||
foreach (var identifier in manifestModule.Identifiers)
|
||||
{
|
||||
module.AddIdentifier(customType.Key, new Module.IdentifierInfo(customType.Value.Type, customType.Value.Exported, Module.Source.Lib));
|
||||
var decoded = TypeMangler.Decode(identifier.Value.EncodedType);
|
||||
module.AddIdentifier(identifier.Key, new Module.IdentifierInfo(decoded, identifier.Value.Exported, Module.Source.Lib));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -274,4 +270,9 @@ public class ModuleGraph(Dictionary<string, ModuleGraph.Module> modules)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public record Manifest(int Version, IReadOnlyList<ManifestModule> Modules);
|
||||
public record ManifestModule(string Name, Dictionary<string, ManifestCustomTypeInfo> CustomTypes, Dictionary<string, ManifestIdentifierInfo> Identifiers);
|
||||
public record ManifestCustomTypeInfo(string EncodedType, bool Exported);
|
||||
public record ManifestIdentifierInfo(string EncodedType, bool Exported);
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
namespace Compiler;
|
||||
@@ -5,7 +6,6 @@ namespace Compiler;
|
||||
public abstract class NubType
|
||||
{
|
||||
public abstract override string ToString();
|
||||
public string GetSignature() => TypeMangler.Encode(this);
|
||||
}
|
||||
|
||||
public sealed class NubTypeVoid : NubType
|
||||
@@ -193,15 +193,11 @@ static class TypeMangler
|
||||
break;
|
||||
|
||||
case NubTypeUInt u:
|
||||
sb.Append("U(");
|
||||
sb.Append(u.Width);
|
||||
sb.Append(')');
|
||||
sb.Append("U(").Append(u.Width).Append(')');
|
||||
break;
|
||||
|
||||
case NubTypeSInt s:
|
||||
sb.Append("U(");
|
||||
sb.Append(s.Width);
|
||||
sb.Append(')');
|
||||
sb.Append("I(").Append(s.Width).Append(')');
|
||||
break;
|
||||
|
||||
case NubTypeString:
|
||||
@@ -215,17 +211,29 @@ static class TypeMangler
|
||||
break;
|
||||
|
||||
case NubTypeStruct st:
|
||||
sb.Append($"T({st.Module}::{st.Name})");
|
||||
sb.Append("T(");
|
||||
sb.Append(st.Module).Append("::").Append(st.Name);
|
||||
sb.Append(',').Append(st.Packed ? '1' : '0');
|
||||
sb.Append('{');
|
||||
for (int i = 0; i < st.Fields.Count; i++)
|
||||
{
|
||||
var field = st.Fields[i];
|
||||
sb.Append(field.Name).Append(':');
|
||||
Encode(field.Type, sb);
|
||||
if (i < st.Fields.Count - 1)
|
||||
sb.Append(',');
|
||||
}
|
||||
sb.Append("})");
|
||||
break;
|
||||
|
||||
case NubTypeFunc fn:
|
||||
sb.Append("F(");
|
||||
for (int i = 0; i < fn.Parameters.Count; i++)
|
||||
foreach (var parameter in fn.Parameters)
|
||||
{
|
||||
Encode(fn.Parameters[i], sb);
|
||||
sb.Append(Encode(parameter));
|
||||
sb.Append(',');
|
||||
}
|
||||
Encode(fn.ReturnType, sb);
|
||||
sb.Append(Encode(fn.ReturnType));
|
||||
sb.Append(')');
|
||||
break;
|
||||
|
||||
@@ -233,6 +241,155 @@ static class TypeMangler
|
||||
throw new NotSupportedException(type.GetType().Name);
|
||||
}
|
||||
}
|
||||
|
||||
public static NubType Decode(string encoded)
|
||||
{
|
||||
int pos = 0;
|
||||
return Parse(encoded, ref pos);
|
||||
}
|
||||
|
||||
private static NubType Parse(string s, ref int pos)
|
||||
{
|
||||
if (pos >= s.Length)
|
||||
throw new InvalidOperationException("Unexpected end of string");
|
||||
|
||||
char c = s[pos++];
|
||||
return c switch
|
||||
{
|
||||
'V' => NubTypeVoid.Instance,
|
||||
'B' => NubTypeBool.Instance,
|
||||
'S' => NubTypeString.Instance,
|
||||
'U' => ParseUInt(s, ref pos),
|
||||
'I' => ParseSInt(s, ref pos),
|
||||
'P' => ParsePointer(s, ref pos),
|
||||
'T' => ParseStruct(s, ref pos),
|
||||
'F' => ParseFunc(s, ref pos),
|
||||
_ => throw new NotSupportedException($"Unknown type code '{c}' at position {pos - 1}")
|
||||
};
|
||||
}
|
||||
|
||||
private static NubTypeUInt ParseUInt(string s, ref int pos)
|
||||
{
|
||||
ExpectChar(s, ref pos, '(');
|
||||
int width = ReadNumber(s, ref pos);
|
||||
ExpectChar(s, ref pos, ')');
|
||||
return NubTypeUInt.Get(width);
|
||||
}
|
||||
|
||||
private static NubTypeSInt ParseSInt(string s, ref int pos)
|
||||
{
|
||||
ExpectChar(s, ref pos, '(');
|
||||
int width = ReadNumber(s, ref pos);
|
||||
ExpectChar(s, ref pos, ')');
|
||||
return NubTypeSInt.Get(width);
|
||||
}
|
||||
|
||||
private static NubTypePointer ParsePointer(string s, ref int pos)
|
||||
{
|
||||
ExpectChar(s, ref pos, '(');
|
||||
var to = Parse(s, ref pos);
|
||||
ExpectChar(s, ref pos, ')');
|
||||
return NubTypePointer.Get(to);
|
||||
}
|
||||
|
||||
private static NubTypeStruct ParseStruct(string s, ref int pos)
|
||||
{
|
||||
ExpectChar(s, ref pos, '(');
|
||||
int start = pos;
|
||||
while (pos < s.Length && s[pos] != ',' && s[pos] != '{') pos++;
|
||||
var fullName = s[start..pos];
|
||||
var parts = fullName.Split("::");
|
||||
if (parts.Length != 2)
|
||||
throw new InvalidOperationException($"Invalid struct name: {fullName}");
|
||||
|
||||
string module = parts[0], name = parts[1];
|
||||
|
||||
bool packed = false;
|
||||
if (s[pos] == ',')
|
||||
{
|
||||
pos += 1;
|
||||
packed = s[pos += 1] == '1';
|
||||
}
|
||||
|
||||
var st = new NubTypeStruct(module, name, packed);
|
||||
|
||||
ExpectChar(s, ref pos, '{');
|
||||
|
||||
var fields = new List<NubTypeStruct.Field>();
|
||||
while (s[pos] != '}')
|
||||
{
|
||||
int nameStart = pos;
|
||||
while (s[pos] != ':') pos += 1;
|
||||
string fieldName = s[nameStart..pos];
|
||||
pos += 1;
|
||||
|
||||
var fieldType = Parse(s, ref pos);
|
||||
fields.Add(new NubTypeStruct.Field(fieldName, fieldType));
|
||||
|
||||
if (s[pos] == ',') pos += 1;
|
||||
}
|
||||
|
||||
ExpectChar(s, ref pos, '}');
|
||||
ExpectChar(s, ref pos, ')');
|
||||
|
||||
st.ResolveFields(fields);
|
||||
return st;
|
||||
}
|
||||
|
||||
private static NubTypeFunc ParseFunc(string s, ref int pos)
|
||||
{
|
||||
ExpectChar(s, ref pos, '(');
|
||||
var parameters = new List<NubType>();
|
||||
while (true)
|
||||
{
|
||||
if (s[pos] == ')')
|
||||
{
|
||||
pos++;
|
||||
break;
|
||||
}
|
||||
|
||||
var param = Parse(s, ref pos);
|
||||
parameters.Add(param);
|
||||
|
||||
if (s[pos] == ',')
|
||||
{
|
||||
pos += 1;
|
||||
}
|
||||
else if (s[pos] == ')')
|
||||
{
|
||||
pos += 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException($"Unexpected char '{s[pos]}' in function type at {pos}");
|
||||
}
|
||||
}
|
||||
|
||||
if (parameters.Count == 0)
|
||||
throw new InvalidOperationException("Function must have a return type");
|
||||
|
||||
var returnType = parameters[^1];
|
||||
var paramTypes = parameters.Take(parameters.Count - 1).ToList();
|
||||
|
||||
return NubTypeFunc.Get(paramTypes, returnType);
|
||||
}
|
||||
|
||||
private static void ExpectChar(string s, ref int pos, char expected)
|
||||
{
|
||||
if (pos >= s.Length || s[pos] != expected)
|
||||
throw new InvalidOperationException($"Expected '{expected}' at position {pos}");
|
||||
|
||||
pos += 1;
|
||||
}
|
||||
|
||||
private static int ReadNumber(string s, ref int pos)
|
||||
{
|
||||
int start = pos;
|
||||
while (pos < s.Length && char.IsDigit(s[pos])) pos += 1;
|
||||
if (start == pos) throw new InvalidOperationException($"Expected number at position {start}");
|
||||
return int.Parse(s[start..pos]);
|
||||
}
|
||||
}
|
||||
|
||||
static class Hashing
|
||||
|
||||
@@ -163,7 +163,7 @@ static void CleanDirectory(string dirName)
|
||||
}
|
||||
}
|
||||
|
||||
static void WriteNublib(string outputPath, string archivePath, ModuleGraph.Manifest manifest)
|
||||
static void WriteNublib(string outputPath, string archivePath, Manifest manifest)
|
||||
{
|
||||
using var fs = new FileStream(outputPath, FileMode.Create);
|
||||
using var zip = new ZipArchive(fs, ZipArchiveMode.Create);
|
||||
@@ -174,6 +174,8 @@ static void WriteNublib(string outputPath, string archivePath, ModuleGraph.Manif
|
||||
WriteIndented = true,
|
||||
});
|
||||
|
||||
File.WriteAllText(".build/manifest.json", serialized);
|
||||
|
||||
var manifestEntry = zip.CreateEntry("manifest.json");
|
||||
using (var writer = new StreamWriter(manifestEntry.Open()))
|
||||
{
|
||||
@@ -195,11 +197,11 @@ static NublibLoadResult ReadNublib(string nublibPath)
|
||||
|
||||
var manifestEntry = zip.GetEntry("manifest.json") ?? throw new FileNotFoundException("Manifest not found in nublib", "manifest.json");
|
||||
|
||||
ModuleGraph.Manifest manifest;
|
||||
Manifest manifest;
|
||||
using (var reader = new StreamReader(manifestEntry.Open()))
|
||||
{
|
||||
var json = reader.ReadToEnd();
|
||||
manifest = JsonSerializer.Deserialize<ModuleGraph.Manifest>(json) ?? throw new InvalidDataException("Failed to deserialize manifest.json");
|
||||
manifest = JsonSerializer.Deserialize<Manifest>(json) ?? throw new InvalidDataException("Failed to deserialize manifest.json");
|
||||
}
|
||||
|
||||
var archiveEntry = zip.Entries.FirstOrDefault(e => e.Name.EndsWith(".a")) ?? throw new FileNotFoundException("Archive not found in nublib", "*.a");
|
||||
@@ -214,4 +216,4 @@ static NublibLoadResult ReadNublib(string nublibPath)
|
||||
return new NublibLoadResult(manifest, tempArchivePath);
|
||||
}
|
||||
|
||||
public record NublibLoadResult(ModuleGraph.Manifest Manifest, string ArchivePath);
|
||||
public record NublibLoadResult(Manifest Manifest, string ArchivePath);
|
||||
|
||||
15
examples/math/.build/manifest.json
Normal file
15
examples/math/.build/manifest.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"version": 1,
|
||||
"modules": [
|
||||
{
|
||||
"name": "math",
|
||||
"customTypes": {},
|
||||
"identifiers": {
|
||||
"add": {
|
||||
"encodedType": "F(I(32),I(32),I(32))",
|
||||
"exported": true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
@@ -12,10 +12,10 @@ struct nub_core_string
|
||||
|
||||
|
||||
|
||||
int32_t nub_math_add_cc3fc9d68812b10d(int32_t, int32_t);
|
||||
int32_t nub_math_add_500748c2c6d70959(int32_t, int32_t);
|
||||
|
||||
|
||||
int32_t nub_math_add_cc3fc9d68812b10d(int32_t a, int32_t b)
|
||||
int32_t nub_math_add_500748c2c6d70959(int32_t a, int32_t b)
|
||||
{
|
||||
{
|
||||
return (a + b);
|
||||
|
||||
Binary file not shown.
Binary file not shown.
BIN
examples/program/.build/out
Executable file
BIN
examples/program/.build/out
Executable file
Binary file not shown.
29
examples/program/.build/out.c
Normal file
29
examples/program/.build/out.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <float.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct nub_core_string
|
||||
{
|
||||
const char *data;
|
||||
int length;
|
||||
};
|
||||
|
||||
|
||||
|
||||
extern int32_t nub_math_add_500748c2c6d70959(int32_t, int32_t);
|
||||
int32_t nub_main_main_55882df37f903935();
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return nub_main_main_55882df37f903935();
|
||||
}
|
||||
|
||||
int32_t nub_main_main_55882df37f903935()
|
||||
{
|
||||
{
|
||||
return nub_math_add_500748c2c6d70959(1, 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@ module main
|
||||
|
||||
func main(): i32
|
||||
{
|
||||
return math::add(1, 2)
|
||||
return math::add(1 2)
|
||||
}
|
||||
Reference in New Issue
Block a user