This commit is contained in:
nub31
2025-07-09 20:04:06 +02:00
parent 60088757c3
commit e8f6c483bb
10 changed files with 93 additions and 86 deletions

View File

@@ -1,57 +1,16 @@
struct Name template<T> struct Box
{ {
first: cstring value: T
last: cstring
}
struct Human
{
name: Name
age: i64
}
trait Printable
{
func print()
}
impl Printable for Human
{
func print() {
c::puts(this.name.first)
}
} }
func main(args: []cstring): i64 func main(args: []cstring): i64
{ {
let human = alloc Human let box = alloc Box<cstring>
{ {
name = alloc Name { value = "bob"
first = "john"
last = "doe"
}
age = 23
} }
human.print() c::puts(box.value)
print_result(12, func (num) => num == 12)
let x: cstring = "test"
let addr = x&
c::puts(addr^)
return 0 return 0
} }
func print_result(num: u64, delegate: func(u64): bool) {
if (delegate(num))
{
c::puts("true")
}
else
{
c::puts("false")
}
}

View File

@@ -11,9 +11,4 @@
<ProjectReference Include="..\NubLang.Common\NubLang.Common.csproj" /> <ProjectReference Include="..\NubLang.Common\NubLang.Common.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Generation\" />
<Folder Include="Syntax\" />
</ItemGroup>
</Project> </Project>

View File

@@ -34,7 +34,7 @@ public abstract class NubType : IEquatable<NubType>
return false; return false;
} }
throw new ArgumentException($"Type {this} is not a simple type, not a compex type"); throw new ArgumentException($"Type {this} is not a simple type nor a compex type");
} }
public abstract int Size(BoundDefinitionTable definitionTable); public abstract int Size(BoundDefinitionTable definitionTable);
@@ -225,10 +225,11 @@ public class NubStringType : NubComplexType
public override int GetHashCode() => HashCode.Combine(typeof(NubStringType)); public override int GetHashCode() => HashCode.Combine(typeof(NubStringType));
} }
public class NubCustomType(string @namespace, string name) : NubComplexType public class NubCustomType(string @namespace, string name, IReadOnlyList<NubType> parameters) : NubComplexType
{ {
public string Namespace { get; } = @namespace; public string Namespace { get; } = @namespace;
public string Name { get; } = name; public string Name { get; } = name;
public IReadOnlyList<NubType> Parameters { get; } = parameters;
public CustomTypeKind Kind(BoundDefinitionTable definitionTable) public CustomTypeKind Kind(BoundDefinitionTable definitionTable)
{ {
@@ -288,9 +289,22 @@ public class NubCustomType(string @namespace, string name) : NubComplexType
} }
} }
public override string ToString() => $"{Namespace}::{Name}"; public override string ToString() => $"{Namespace}::{Name}{(Parameters.Any() ? $"<{string.Join(",", Parameters)}>" : "")}";
public override bool Equals(NubType? other) => other is NubCustomType custom && Namespace == custom.Namespace && Name == custom.Name; public override bool Equals(NubType? other) => other is NubCustomType custom && Namespace == custom.Namespace && Name == custom.Name && Parameters.SequenceEqual(custom.Parameters);
public override int GetHashCode() => HashCode.Combine(typeof(NubCustomType), Namespace, Name);
public override int GetHashCode()
{
var hash = new HashCode();
hash.Add(typeof(NubFuncType));
hash.Add(Namespace);
hash.Add(Name);
foreach (var param in Parameters)
{
hash.Add(param);
}
return hash.ToHashCode();
}
} }
public enum CustomTypeKind public enum CustomTypeKind

View File

@@ -34,7 +34,7 @@ public sealed class Binder
{ {
try try
{ {
definitions.Add(BindTopLevel(definition)); definitions.Add(BindDefinition(definition));
} }
catch (BindException e) catch (BindException e)
{ {
@@ -45,15 +45,15 @@ public sealed class Binder
return new BoundSyntaxTree(_syntaxTree.Namespace, definitions, diagnostics); return new BoundSyntaxTree(_syntaxTree.Namespace, definitions, diagnostics);
} }
private BoundDefinition BindTopLevel(DefinitionSyntax node) private BoundDefinition BindDefinition(DefinitionSyntax node)
{ {
return node switch return node switch
{ {
ExternFuncSyntax topLevel => BindExternFuncDefinition(topLevel), ExternFuncSyntax definition => BindExternFuncDefinition(definition),
TraitImplSyntax topLevel => BindTraitImplementation(topLevel), TraitImplSyntax definition => BindTraitImplementation(definition),
TraitSyntax topLevel => BindTraitDefinition(topLevel), TraitSyntax definition => BindTraitDefinition(definition),
LocalFuncSyntax topLevel => BindLocalFuncDefinition(topLevel), LocalFuncSyntax definition => BindLocalFuncDefinition(definition),
StructSyntax topLevel => BindStruct(topLevel), StructSyntax definition => BindStruct(definition),
_ => throw new ArgumentOutOfRangeException(nameof(node)) _ => throw new ArgumentOutOfRangeException(nameof(node))
}; };
} }
@@ -403,7 +403,7 @@ public sealed class Binder
{ {
if (traits.Length > 1) if (traits.Length > 1)
{ {
throw new BindException(Diagnostic.Error($"Trait {customType.Namespace}::{customType.Name} has multiple definitions").Build()); throw new BindException(Diagnostic.Error($"Trait {customType} has multiple definitions").Build());
} }
var trait = traits[0]; var trait = traits[0];
@@ -413,7 +413,7 @@ public sealed class Binder
{ {
if (traits.Length > 1) if (traits.Length > 1)
{ {
throw new BindException(Diagnostic.Error($"Trait {trait.Namespace}::{trait.Name} has multiple functions with the name {expression.Member}").Build()); throw new BindException(Diagnostic.Error($"Trait {customType} has multiple functions with the name {expression.Member}").Build());
} }
var traitFunc = traitFuncs[0]; var traitFunc = traitFuncs[0];
@@ -428,7 +428,7 @@ public sealed class Binder
{ {
if (structs.Length > 1) if (structs.Length > 1)
{ {
throw new BindException(Diagnostic.Error($"Struct {customType.Namespace}::{customType.Name} has multiple definitions").Build()); throw new BindException(Diagnostic.Error($"Struct {customType} has multiple definitions").Build());
} }
var @struct = structs[0]; var @struct = structs[0];
@@ -438,7 +438,7 @@ public sealed class Binder
{ {
if (fields.Length > 1) if (fields.Length > 1)
{ {
throw new BindException(Diagnostic.Error($"Struct {@struct.Namespace}::{@struct.Name} has multiple fields with the name {expression.Member}").Build()); throw new BindException(Diagnostic.Error($"Struct {customType} has multiple fields with the name {expression.Member}").Build());
} }
var field = fields[0]; var field = fields[0];
@@ -462,12 +462,12 @@ public sealed class Binder
if (structs.Length == 0) if (structs.Length == 0)
{ {
throw new BindException(Diagnostic.Error($"Struct {structType.Namespace}::{structType.Name} is not defined").Build()); throw new BindException(Diagnostic.Error($"Struct {structType} is not defined").Build());
} }
if (structs.Length > 1) if (structs.Length > 1)
{ {
throw new BindException(Diagnostic.Error($"Struct {structType.Namespace}::{structType.Name} has multiple definitions").Build()); throw new BindException(Diagnostic.Error($"Struct {structType} has multiple definitions").Build());
} }
var @struct = structs[0]; var @struct = structs[0];
@@ -480,18 +480,18 @@ public sealed class Binder
if (fields.Length == 0) if (fields.Length == 0)
{ {
throw new BindException(Diagnostic.Error($"Struct {@struct.Namespace}::{@struct.Name} does not have a field with the name {field}").Build()); throw new BindException(Diagnostic.Error($"Struct {structType} does not have a field with the name {field}").Build());
} }
if (fields.Length > 1) if (fields.Length > 1)
{ {
throw new BindException(Diagnostic.Error($"Struct {@struct.Namespace}::{@struct.Name} has multiple fields with the name {field}").Build()); throw new BindException(Diagnostic.Error($"Struct {structType} has multiple fields with the name {field}").Build());
} }
initializers[field] = BindExpression(initializer, fields[0].Type); initializers[field] = BindExpression(initializer, fields[0].Type);
} }
return new BoundStructInitializer(expression.Tokens, structType, new NubCustomType(@struct.Namespace, @struct.Name), initializers); return new BoundStructInitializer(expression.Tokens, structType, initializers);
} }
private BoundUnaryExpression BindUnaryExpression(UnaryExpressionSyntax expression) private BoundUnaryExpression BindUnaryExpression(UnaryExpressionSyntax expression)

View File

@@ -52,6 +52,6 @@ public record BoundTraitImplFuncAccess(IReadOnlyList<Token> Tokens, NubType Type
public record BoundTraitFuncAccess(IReadOnlyList<Token> Tokens, NubType Type, NubCustomType TraitType, BoundExpression Target, string FuncName) : BoundExpression(Tokens, Type); public record BoundTraitFuncAccess(IReadOnlyList<Token> Tokens, NubType Type, NubCustomType TraitType, BoundExpression Target, string FuncName) : BoundExpression(Tokens, Type);
public record BoundStructInitializer(IReadOnlyList<Token> Tokens, NubType Type, NubCustomType StructType, Dictionary<string, BoundExpression> Initializers) : BoundExpression(Tokens, Type); public record BoundStructInitializer(IReadOnlyList<Token> Tokens, NubCustomType StructType, Dictionary<string, BoundExpression> Initializers) : BoundExpression(Tokens, StructType);
public record BoundDereference(IReadOnlyList<Token> Tokens, NubType Type, BoundExpression Expression) : BoundExpression(Tokens, Type); public record BoundDereference(IReadOnlyList<Token> Tokens, NubType Type, BoundExpression Expression) : BoundExpression(Tokens, Type);

View File

@@ -3,7 +3,7 @@ using NubLang.Syntax.Tokenization;
namespace NubLang.Syntax.Parsing.Node; namespace NubLang.Syntax.Parsing.Node;
public record SyntaxTree(string Namespace, IReadOnlyList<DefinitionSyntax> Definitions, IReadOnlyList<Diagnostic> Diagnostics); public record SyntaxTree(string Namespace, IReadOnlyList<DefinitionSyntax> Definitions, IReadOnlyList<TemplateSyntax> Templates, IReadOnlyList<Diagnostic> Diagnostics);
public abstract record SyntaxNode(IReadOnlyList<Token> Tokens); public abstract record SyntaxNode(IReadOnlyList<Token> Tokens);

View File

@@ -0,0 +1,7 @@
using NubLang.Syntax.Tokenization;
namespace NubLang.Syntax.Parsing.Node;
public abstract record TemplateSyntax(IReadOnlyList<Token> Tokens, string Namespace, IReadOnlyList<string> TemplateParameters) : SyntaxNode(Tokens);
public record StructTemplateSyntax(IReadOnlyList<Token> Tokens, string Namespace, IReadOnlyList<string> TemplateParameters, StructSyntax Struct) : TemplateSyntax(Tokens, Namespace, TemplateParameters);

View File

@@ -30,13 +30,35 @@ public sealed class Parser
_namespace = ExpectIdentifier().Value; _namespace = ExpectIdentifier().Value;
} }
List<DefinitionSyntax> definitions = []; var definitions = new List<DefinitionSyntax>();
var templates = new List<TemplateSyntax>();
while (Peek().HasValue) while (Peek().HasValue)
{ {
var startIndex = _tokenIndex;
try try
{ {
definitions.Add(ParseDefinition()); if (TryExpectSymbol(Symbol.Template))
{
var templateArguments = new List<string>();
ExpectSymbol(Symbol.LessThan);
while (!TryExpectSymbol(Symbol.GreaterThan))
{
templateArguments.Add(ExpectIdentifier().Value);
}
ExpectSymbol(Symbol.Struct);
var definition = ParseStruct(_tokenIndex);
templates.Add(new StructTemplateSyntax(GetTokens(startIndex), _namespace, templateArguments, definition));
}
else
{
var definition = ParseDefinition(startIndex);
definitions.Add(definition);
}
} }
catch (ParseException ex) catch (ParseException ex)
{ {
@@ -45,13 +67,11 @@ public sealed class Parser
} }
} }
return new SyntaxTree(_namespace, definitions, _diagnostics); return new SyntaxTree(_namespace, definitions, templates, _diagnostics);
} }
private DefinitionSyntax ParseDefinition() private DefinitionSyntax ParseDefinition(int startIndex)
{ {
var startIndex = _tokenIndex;
var keyword = ExpectSymbol(); var keyword = ExpectSymbol();
var node = keyword.Symbol switch var node = keyword.Symbol switch
{ {
@@ -61,8 +81,8 @@ public sealed class Parser
Symbol.Trait => ParseTrait(startIndex), Symbol.Trait => ParseTrait(startIndex),
Symbol.Impl => ParseImpl(startIndex), Symbol.Impl => ParseImpl(startIndex),
_ => throw new ParseException(Diagnostic _ => throw new ParseException(Diagnostic
.Error($"Expected 'func' or 'struct', but found '{keyword.Symbol}'") .Error($"Expected 'extern', 'func', 'struct', 'trait' or 'impl' but found '{keyword.Symbol}'")
.WithHelp("Valid definition keywords are 'func' and 'struct'") .WithHelp("Valid definition keywords are 'extern', 'func', 'struct', 'trait' and 'impl'")
.At(keyword) .At(keyword)
.Build()) .Build())
}; };
@@ -660,7 +680,17 @@ public sealed class Parser
@namespace = ExpectIdentifier().Value; @namespace = ExpectIdentifier().Value;
} }
return new NubCustomType(@namespace, name.Value); var parameters = new List<NubType>();
if (TryExpectSymbol(Symbol.LessThan))
{
while (!TryExpectSymbol(Symbol.GreaterThan))
{
parameters.Add(ParseType());
}
}
return new NubCustomType(@namespace, name.Value, parameters);
} }
} }
@@ -803,7 +833,7 @@ public sealed class Parser
while (Peek().HasValue) while (Peek().HasValue)
{ {
var token = Peek().Value; var token = Peek().Value;
if (token is SymbolToken { Symbol: Symbol.Extern or Symbol.Func or Symbol.Struct or Symbol.Trait or Symbol.Impl }) if (token is SymbolToken { Symbol: Symbol.Extern or Symbol.Func or Symbol.Struct or Symbol.Trait or Symbol.Impl or Symbol.Template })
{ {
break; break;
} }
@@ -830,7 +860,7 @@ public sealed class Parser
private List<Token> GetTokens(int startIndex) private List<Token> GetTokens(int startIndex)
{ {
return _tokens.Skip(startIndex).Take(Math.Min(_tokenIndex, _tokens.Count() - 1) - startIndex).ToList(); return _tokens.Skip(startIndex).Take(Math.Min(_tokenIndex, _tokens.Count - 1) - startIndex).ToList();
} }
} }

View File

@@ -73,4 +73,5 @@ public enum Symbol
Extern, Extern,
Semi, Semi,
Arrow, Arrow,
Template
} }

View File

@@ -22,7 +22,8 @@ public sealed class Tokenizer
["trait"] = Symbol.Trait, ["trait"] = Symbol.Trait,
["impl"] = Symbol.Impl, ["impl"] = Symbol.Impl,
["for"] = Symbol.For, ["for"] = Symbol.For,
["extern"] = Symbol.Extern ["extern"] = Symbol.Extern,
["template"] = Symbol.Template,
}; };
private static readonly Dictionary<char[], Symbol> Chians = new() private static readonly Dictionary<char[], Symbol> Chians = new()