This commit is contained in:
nub31
2025-07-09 20:04:06 +02:00
parent 22e7fedbe3
commit 3fd6eb4d81
10 changed files with 93 additions and 86 deletions

View File

@@ -1,57 +1,16 @@
struct Name
template<T> struct Box
{
first: cstring
last: cstring
}
struct Human
{
name: Name
age: i64
}
trait Printable
{
func print()
}
impl Printable for Human
{
func print() {
c::puts(this.name.first)
}
value: T
}
func main(args: []cstring): i64
{
let human = alloc Human
let box = alloc Box<cstring>
{
name = alloc Name {
first = "john"
last = "doe"
}
age = 23
value = "bob"
}
human.print()
print_result(12, func (num) => num == 12)
let x: cstring = "test"
let addr = x&
c::puts(addr^)
c::puts(box.value)
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" />
</ItemGroup>
<ItemGroup>
<Folder Include="Generation\" />
<Folder Include="Syntax\" />
</ItemGroup>
</Project>

View File

@@ -34,7 +34,7 @@ public abstract class NubType : IEquatable<NubType>
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);
@@ -225,10 +225,11 @@ public class NubStringType : NubComplexType
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 Name { get; } = name;
public IReadOnlyList<NubType> Parameters { get; } = parameters;
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 bool Equals(NubType? other) => other is NubCustomType custom && Namespace == custom.Namespace && Name == custom.Name;
public override int GetHashCode() => HashCode.Combine(typeof(NubCustomType), 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 && Parameters.SequenceEqual(custom.Parameters);
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

View File

@@ -34,7 +34,7 @@ public sealed class Binder
{
try
{
definitions.Add(BindTopLevel(definition));
definitions.Add(BindDefinition(definition));
}
catch (BindException e)
{
@@ -45,15 +45,15 @@ public sealed class Binder
return new BoundSyntaxTree(_syntaxTree.Namespace, definitions, diagnostics);
}
private BoundDefinition BindTopLevel(DefinitionSyntax node)
private BoundDefinition BindDefinition(DefinitionSyntax node)
{
return node switch
{
ExternFuncSyntax topLevel => BindExternFuncDefinition(topLevel),
TraitImplSyntax topLevel => BindTraitImplementation(topLevel),
TraitSyntax topLevel => BindTraitDefinition(topLevel),
LocalFuncSyntax topLevel => BindLocalFuncDefinition(topLevel),
StructSyntax topLevel => BindStruct(topLevel),
ExternFuncSyntax definition => BindExternFuncDefinition(definition),
TraitImplSyntax definition => BindTraitImplementation(definition),
TraitSyntax definition => BindTraitDefinition(definition),
LocalFuncSyntax definition => BindLocalFuncDefinition(definition),
StructSyntax definition => BindStruct(definition),
_ => throw new ArgumentOutOfRangeException(nameof(node))
};
}
@@ -403,7 +403,7 @@ public sealed class Binder
{
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];
@@ -413,7 +413,7 @@ public sealed class Binder
{
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];
@@ -428,7 +428,7 @@ public sealed class Binder
{
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];
@@ -438,7 +438,7 @@ public sealed class Binder
{
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];
@@ -462,12 +462,12 @@ public sealed class Binder
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)
{
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];
@@ -480,18 +480,18 @@ public sealed class Binder
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)
{
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);
}
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)

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 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);

View File

@@ -3,7 +3,7 @@ using NubLang.Syntax.Tokenization;
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);

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;
}
List<DefinitionSyntax> definitions = [];
var definitions = new List<DefinitionSyntax>();
var templates = new List<TemplateSyntax>();
while (Peek().HasValue)
{
var startIndex = _tokenIndex;
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)
{
@@ -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 node = keyword.Symbol switch
{
@@ -61,8 +81,8 @@ public sealed class Parser
Symbol.Trait => ParseTrait(startIndex),
Symbol.Impl => ParseImpl(startIndex),
_ => throw new ParseException(Diagnostic
.Error($"Expected 'func' or 'struct', but found '{keyword.Symbol}'")
.WithHelp("Valid definition keywords are 'func' and 'struct'")
.Error($"Expected 'extern', 'func', 'struct', 'trait' or 'impl' but found '{keyword.Symbol}'")
.WithHelp("Valid definition keywords are 'extern', 'func', 'struct', 'trait' and 'impl'")
.At(keyword)
.Build())
};
@@ -660,7 +680,17 @@ public sealed class Parser
@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)
{
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;
}
@@ -830,7 +860,7 @@ public sealed class Parser
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,
Semi,
Arrow,
Template
}

View File

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