WIP: dev #1

Draft
nub31 wants to merge 103 commits from dev into master
9 changed files with 192 additions and 138 deletions
Showing only changes of commit 2b7eb56895 - Show all commits

View File

@@ -1,4 +1,3 @@
Comma seperated function parameters and struct/enum mebers
Converting ^u8 to string Converting ^u8 to string
string formatting string formatting
Dynamic arrays Dynamic arrays

View File

@@ -1,5 +1,7 @@
using System.Diagnostics; using System.Diagnostics;
using System.Security.Principal;
using System.Text; using System.Text;
using Microsoft.VisualBasic;
namespace Compiler; namespace Compiler;
@@ -260,7 +262,12 @@ public class Generator
throw new UnreachableException(); throw new UnreachableException();
foreach (var variant in enumInfo.Variants) foreach (var variant in enumInfo.Variants)
EmitTypeDefinitionIfNotEmitted(variant.Type); {
if (variant.Type is not null)
{
EmitTypeDefinitionIfNotEmitted(variant.Type);
}
}
writer.WriteLine($"struct {NameMangler.Mangle(enumType.Module, enumType.Name, enumType)}"); writer.WriteLine($"struct {NameMangler.Mangle(enumType.Module, enumType.Name, enumType)}");
writer.WriteLine("{"); writer.WriteLine("{");
@@ -273,7 +280,10 @@ public class Generator
{ {
foreach (var variant in enumInfo.Variants) foreach (var variant in enumInfo.Variants)
{ {
writer.WriteLine($"{CType(variant.Type, variant.Name)};"); if (variant.Type is not null)
{
writer.WriteLine($"{CType(variant.Type, variant.Name)};");
}
} }
} }
writer.WriteLine("};"); writer.WriteLine("};");
@@ -453,7 +463,12 @@ public class Generator
using (writer.Indent()) using (writer.Indent())
{ {
PushScope(); PushScope();
writer.WriteLine($"{CType(variantInfo.Type, @case.VariableName.Ident)} = {target}.{@case.Variant.Ident};"); if (@case.VariableName != null)
{
Debug.Assert(variantInfo.Type is not null);
writer.WriteLine($"{CType(variantInfo.Type, @case.VariableName.Ident)} = {target}.{@case.Variant.Ident};");
}
EmitStatement(@case.Body); EmitStatement(@case.Body);
PopScope(); PopScope();
writer.WriteLine("break;"); writer.WriteLine("break;");
@@ -474,7 +489,7 @@ public class Generator
TypedNodeExpressionIntLiteral expression => expression.Value.Value.ToString(), TypedNodeExpressionIntLiteral expression => expression.Value.Value.ToString(),
TypedNodeExpressionStringLiteral expression => EmitExpressionStringLiteral(expression), TypedNodeExpressionStringLiteral expression => EmitExpressionStringLiteral(expression),
TypedNodeExpressionStructLiteral expression => EmitExpressionStructLiteral(expression), TypedNodeExpressionStructLiteral expression => EmitExpressionStructLiteral(expression),
TypedNodeExpressionEnumLiteral expression => EmitExpressionEnumLiteral(expression), TypedNodeExpressionNewNamedType expression => EmitNodeExpressionNewNamedType(expression),
TypedNodeExpressionStructMemberAccess expression => EmitExpressionMemberAccess(expression), TypedNodeExpressionStructMemberAccess expression => EmitExpressionMemberAccess(expression),
TypedNodeExpressionStringLength expression => EmitExpressionStringLength(expression), TypedNodeExpressionStringLength expression => EmitExpressionStringLength(expression),
TypedNodeExpressionStringPointer expression => EmitExpressionStringPointer(expression), TypedNodeExpressionStringPointer expression => EmitExpressionStringPointer(expression),
@@ -563,25 +578,35 @@ public class Generator
return name; return name;
} }
private string EmitExpressionEnumLiteral(TypedNodeExpressionEnumLiteral expression) private string EmitNodeExpressionNewNamedType(TypedNodeExpressionNewNamedType expression)
{ {
var name = TmpName(); switch (expression.Type)
scopes.Peek().DeconstructableNames.Add((name, expression.Type)); {
case NubTypeEnumVariant enumVariantType:
{
var name = TmpName();
scopes.Peek().DeconstructableNames.Add((name, expression.Type));
var enumVariantType = (NubTypeEnumVariant)expression.Type; if (!moduleGraph.TryResolveType(enumVariantType.EnumType.Module, enumVariantType.EnumType.Name, true, out var info))
throw new UnreachableException();
if (!moduleGraph.TryResolveType(enumVariantType.EnumType.Module, enumVariantType.EnumType.Name, true, out var info)) var enumInfo = (Module.TypeInfoEnum)info;
throw new UnreachableException(); var tag = enumInfo.Variants.ToList().FindIndex(x => x.Name == enumVariantType.Variant);
var enumInfo = (Module.TypeInfoEnum)info; var value = EmitExpression(expression.Value);
var tag = enumInfo.Variants.ToList().FindIndex(x => x.Name == enumVariantType.Variant); EmitCopyConstructor(value, expression.Value.Type);
var value = EmitExpression(expression.Value); writer.WriteLine($"{CType(expression.Type, name)} = ({CType(expression.Type)}){{ .tag = {tag}, .{enumVariantType.Variant} = {value} }};");
EmitCopyConstructor(value, expression.Value.Type);
writer.WriteLine($"{CType(expression.Type, name)} = ({CType(expression.Type)}){{ .tag = {tag}, .{enumVariantType.Variant} = {value} }};"); return name;
}
return name; case NubTypeStruct structType:
{
return EmitExpression(expression.Value);
}
default:
throw new UnreachableException();
}
} }
private string EmitExpressionMemberAccess(TypedNodeExpressionStructMemberAccess expression) private string EmitExpressionMemberAccess(TypedNodeExpressionStructMemberAccess expression)
@@ -710,14 +735,17 @@ public class Generator
{ {
Module.TypeInfoEnum.Variant variant = enumInfo.Variants[i]; Module.TypeInfoEnum.Variant variant = enumInfo.Variants[i];
writer.WriteLine($"case {i}:"); if (variant.Type is not null)
writer.WriteLine("{");
using (writer.Indent())
{ {
EmitCopyConstructor($"{value}.{variant.Name}", variant.Type); writer.WriteLine($"case {i}:");
writer.WriteLine("break;"); writer.WriteLine("{");
using (writer.Indent())
{
EmitCopyConstructor($"{value}.{variant.Name}", variant.Type);
writer.WriteLine("break;");
}
writer.WriteLine("}");
} }
writer.WriteLine("}");
} }
} }
writer.WriteLine("}"); writer.WriteLine("}");
@@ -729,8 +757,9 @@ public class Generator
throw new UnreachableException(); throw new UnreachableException();
var variant = enumInfo.Variants.First(x => x.Name == enumVariantType.Variant); var variant = enumInfo.Variants.First(x => x.Name == enumVariantType.Variant);
if (variant.Type is not null)
EmitCopyConstructor($"{value}.{variant.Name}", variant.Type);
EmitCopyConstructor($"{value}.{variant.Name}", variant.Type);
break; break;
} }
} }
@@ -776,15 +805,17 @@ public class Generator
for (int i = 0; i < enumInfo.Variants.Count; i++) for (int i = 0; i < enumInfo.Variants.Count; i++)
{ {
var variant = enumInfo.Variants[i]; var variant = enumInfo.Variants[i];
if (variant.Type is not null)
writer.WriteLine($"case {i}:");
writer.WriteLine("{");
using (writer.Indent())
{ {
EmitCopyDestructor($"{value}.{variant.Name}", variant.Type); writer.WriteLine($"case {i}:");
writer.WriteLine("break;"); writer.WriteLine("{");
using (writer.Indent())
{
EmitCopyDestructor($"{value}.{variant.Name}", variant.Type);
writer.WriteLine("break;");
}
writer.WriteLine("}");
} }
writer.WriteLine("}");
} }
} }
writer.WriteLine("}"); writer.WriteLine("}");
@@ -796,8 +827,9 @@ public class Generator
throw new UnreachableException(); throw new UnreachableException();
var variant = enumInfo.Variants.First(x => x.Name == enumVariantType.Variant); var variant = enumInfo.Variants.First(x => x.Name == enumVariantType.Variant);
if (variant.Type is not null)
EmitCopyDestructor($"{value}.{variant.Name}", variant.Type);
EmitCopyDestructor($"{value}.{variant.Name}", variant.Type);
break; break;
} }
} }

View File

@@ -150,7 +150,7 @@ public class ModuleGraph
if (typeInfo is Module.TypeInfoEnum enumType) if (typeInfo is Module.TypeInfoEnum enumType)
{ {
var variants = enumDef.Variants.Select(v => new Module.TypeInfoEnum.Variant(v.Name.Ident, ResolveType(v.Type, module.Name))).ToList(); var variants = enumDef.Variants.Select(v => new Module.TypeInfoEnum.Variant(v.Name.Ident, v.Type == null ? null : ResolveType(v.Type, module.Name))).ToList();
enumType.SetVariants(variants); enumType.SetVariants(variants);
} }
} }
@@ -435,10 +435,10 @@ public class Module(string name)
this.variants = variants; this.variants = variants;
} }
public class Variant(string name, NubType type) public class Variant(string name, NubType? type)
{ {
public string Name { get; } = name; public string Name { get; } = name;
public NubType Type { get; } = type; public NubType? Type { get; } = type;
} }
} }
} }

View File

@@ -104,7 +104,7 @@ public record Manifest(Dictionary<string, Manifest.Module> Modules)
public record TypeInfoEnum(bool Exported, IReadOnlyList<TypeInfoEnum.Variant> Variants) : TypeInfo(Exported) public record TypeInfoEnum(bool Exported, IReadOnlyList<TypeInfoEnum.Variant> Variants) : TypeInfo(Exported)
{ {
public record Variant(string Name, NubType Type); public record Variant(string Name, NubType? Type);
} }
} }
} }

View File

@@ -86,17 +86,7 @@ public class Parser
throw BasicError("Invalid modifier for function", modifier.Value); throw BasicError("Invalid modifier for function", modifier.Value);
var name = ExpectIdent(); var name = ExpectIdent();
var parameters = new List<NodeDefinitionFunc.Param>(); var parameters = ParseFuncParameters();
ExpectSymbol(Symbol.OpenParen);
while (!TryExpectSymbol(Symbol.CloseParen))
{
var paramStartIndex = index;
var parameterName = ExpectIdent();
ExpectSymbol(Symbol.Colon);
var parameterType = ParseType();
parameters.Add(new NodeDefinitionFunc.Param(TokensFrom(paramStartIndex), parameterName, parameterType));
}
NodeType? returnType = null; NodeType? returnType = null;
if (TryExpectSymbol(Symbol.Colon)) if (TryExpectSymbol(Symbol.Colon))
@@ -132,6 +122,7 @@ public class Parser
var fieldName = ExpectIdent(); var fieldName = ExpectIdent();
ExpectSymbol(Symbol.Colon); ExpectSymbol(Symbol.Colon);
var fieldType = ParseType(); var fieldType = ParseType();
TryExpectSymbol(Symbol.Comma);
fields.Add(new NodeDefinitionStruct.Field(TokensFrom(fieldStartIndex), fieldName, fieldType)); fields.Add(new NodeDefinitionStruct.Field(TokensFrom(fieldStartIndex), fieldName, fieldType));
} }
@@ -154,8 +145,13 @@ public class Parser
{ {
var variantsStartIndex = index; var variantsStartIndex = index;
var variantName = ExpectIdent(); var variantName = ExpectIdent();
ExpectSymbol(Symbol.Colon);
var variantType = ParseType(); NodeType? variantType = null;
if (TryExpectSymbol(Symbol.Colon))
variantType = ParseType();
TryExpectSymbol(Symbol.Comma);
variants.Add(new NodeDefinitionEnum.Variant(TokensFrom(variantsStartIndex), variantName, variantType)); variants.Add(new NodeDefinitionEnum.Variant(TokensFrom(variantsStartIndex), variantName, variantType));
} }
@@ -180,6 +176,35 @@ public class Parser
throw BasicError("Not a valid definition", Peek()); throw BasicError("Not a valid definition", Peek());
} }
private List<NodeDefinitionFunc.Param> ParseFuncParameters()
{
var parameters = new List<NodeDefinitionFunc.Param>();
ExpectSymbol(Symbol.OpenParen);
while (true)
{
if (TryExpectSymbol(Symbol.CloseParen))
break;
var startIndex = index;
var name = ExpectIdent();
ExpectSymbol(Symbol.Colon);
var type = ParseType();
parameters.Add(new NodeDefinitionFunc.Param(TokensFrom(startIndex), name, type));
if (!TryExpectSymbol(Symbol.Comma))
{
ExpectSymbol(Symbol.CloseParen);
break;
}
}
return parameters;
}
private NodeStatement ParseStatement() private NodeStatement ParseStatement()
{ {
var startIndex = index; var startIndex = index;
@@ -251,10 +276,10 @@ public class Parser
while (!TryExpectSymbol(Symbol.CloseCurly)) while (!TryExpectSymbol(Symbol.CloseCurly))
{ {
var caseStartIndex = index; var caseStartIndex = index;
var type = ExpectIdent(); var variant = ExpectIdent();
var variableName = ExpectIdent(); TryExpectIdent(out var variableName);
var body = ParseStatement(); var body = ParseStatement();
cases.Add(new NodeStatementMatch.Case(TokensFrom(caseStartIndex), type, variableName, body)); cases.Add(new NodeStatementMatch.Case(TokensFrom(caseStartIndex), variant, variableName, body));
} }
return new NodeStatementMatch(TokensFrom(startIndex), target, cases); return new NodeStatementMatch(TokensFrom(startIndex), target, cases);
@@ -350,7 +375,7 @@ public class Parser
initializers.Add(new NodeExpressionStructLiteral.Initializer(TokensFrom(initializerStartIndex), fieldName, fieldValue)); initializers.Add(new NodeExpressionStructLiteral.Initializer(TokensFrom(initializerStartIndex), fieldName, fieldValue));
} }
expr = new NodeExpressionStructLiteral(TokensFrom(startIndex), null, initializers); expr = new NodeExpressionStructLiteral(TokensFrom(startIndex), initializers);
} }
else if (TryExpectSymbol(Symbol.Bang)) else if (TryExpectSymbol(Symbol.Bang))
{ {
@@ -380,30 +405,11 @@ public class Parser
expr = new NodeExpressionIdent(TokensFrom(startIndex), sections); expr = new NodeExpressionIdent(TokensFrom(startIndex), sections);
} }
else if (TryExpectKeyword(Keyword.Struct)) else if (TryExpectKeyword(Keyword.New))
{
var type = ParseType();
var initializers = new List<NodeExpressionStructLiteral.Initializer>();
ExpectSymbol(Symbol.OpenCurly);
while (!TryExpectSymbol(Symbol.CloseCurly))
{
var initializerStartIndex = startIndex;
var fieldName = ExpectIdent();
ExpectSymbol(Symbol.Equal);
var fieldValue = ParseExpression();
initializers.Add(new NodeExpressionStructLiteral.Initializer(TokensFrom(initializerStartIndex), fieldName, fieldValue));
}
expr = new NodeExpressionStructLiteral(TokensFrom(startIndex), type, initializers);
}
else if (TryExpectKeyword(Keyword.Enum))
{ {
var type = ParseType(); var type = ParseType();
var value = ParseExpression(); var value = ParseExpression();
return new NodeExpressionNewNamedType(TokensFrom(startIndex), type, value);
expr = new NodeExpressionEnumLiteral(TokensFrom(startIndex), type, value);
} }
else else
{ {
@@ -769,10 +775,10 @@ public class NodeDefinitionEnum(List<Token> tokens, bool exported, TokenIdent na
public TokenIdent Name { get; } = name; public TokenIdent Name { get; } = name;
public List<Variant> Variants { get; } = variants; public List<Variant> Variants { get; } = variants;
public class Variant(List<Token> tokens, TokenIdent name, NodeType type) : Node(tokens) public class Variant(List<Token> tokens, TokenIdent name, NodeType? type) : Node(tokens)
{ {
public TokenIdent Name { get; } = name; public TokenIdent Name { get; } = name;
public NodeType Type { get; } = type; public NodeType? Type { get; } = type;
} }
} }
@@ -838,10 +844,10 @@ public class NodeStatementMatch(List<Token> tokens, NodeExpression target, List<
public NodeExpression Target { get; } = target; public NodeExpression Target { get; } = target;
public List<Case> Cases { get; } = cases; public List<Case> Cases { get; } = cases;
public class Case(List<Token> tokens, TokenIdent type, TokenIdent variableName, NodeStatement body) : Node(tokens) public class Case(List<Token> tokens, TokenIdent type, TokenIdent? variableName, NodeStatement body) : Node(tokens)
{ {
public TokenIdent Variant { get; } = type; public TokenIdent Variant { get; } = type;
public TokenIdent VariableName { get; } = variableName; public TokenIdent? VariableName { get; } = variableName;
public NodeStatement Body { get; } = body; public NodeStatement Body { get; } = body;
} }
} }
@@ -863,9 +869,14 @@ public class NodeExpressionBoolLiteral(List<Token> tokens, TokenBoolLiteral valu
public TokenBoolLiteral Value { get; } = value; public TokenBoolLiteral Value { get; } = value;
} }
public class NodeExpressionStructLiteral(List<Token> tokens, NodeType? type, List<NodeExpressionStructLiteral.Initializer> initializers) : NodeExpression(tokens) public class NodeExpressionNewNamedType(List<Token> tokens, NodeType type, NodeExpression value) : NodeExpression(tokens)
{
public NodeType Type { get; } = type;
public NodeExpression Value { get; } = value;
}
public class NodeExpressionStructLiteral(List<Token> tokens, List<NodeExpressionStructLiteral.Initializer> initializers) : NodeExpression(tokens)
{ {
public NodeType? Type { get; } = type;
public List<Initializer> Initializers { get; } = initializers; public List<Initializer> Initializers { get; } = initializers;
public class Initializer(List<Token> tokens, TokenIdent name, NodeExpression value) : Node(tokens) public class Initializer(List<Token> tokens, TokenIdent name, NodeExpression value) : Node(tokens)
@@ -875,12 +886,6 @@ public class NodeExpressionStructLiteral(List<Token> tokens, NodeType? type, Lis
} }
} }
public class NodeExpressionEnumLiteral(List<Token> tokens, NodeType type, NodeExpression value) : NodeExpression(tokens)
{
public NodeType Type { get; } = type;
public NodeExpression Value { get; } = value;
}
public class NodeExpressionMemberAccess(List<Token> tokens, NodeExpression target, TokenIdent name) : NodeExpression(tokens) public class NodeExpressionMemberAccess(List<Token> tokens, NodeExpression target, TokenIdent name) : NodeExpression(tokens)
{ {
public NodeExpression Target { get; } = target; public NodeExpression Target { get; } = target;

View File

@@ -389,6 +389,7 @@ public class Tokenizer
"struct" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Struct), "struct" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Struct),
"packed" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Packed), "packed" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Packed),
"enum" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Enum), "enum" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Enum),
"new" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.New),
"match" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Match), "match" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Match),
"let" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Let), "let" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Let),
"if" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.If), "if" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.If),
@@ -538,6 +539,7 @@ public enum Keyword
Struct, Struct,
Packed, Packed,
Enum, Enum,
New,
Match, Match,
Let, Let,
If, If,
@@ -605,6 +607,7 @@ public static class TokenExtensions
Keyword.Struct => "struct", Keyword.Struct => "struct",
Keyword.Packed => "packed", Keyword.Packed => "packed",
Keyword.Enum => "enum", Keyword.Enum => "enum",
Keyword.New => "new",
Keyword.Match => "enum", Keyword.Match => "enum",
Keyword.Let => "let", Keyword.Let => "let",
Keyword.If => "if", Keyword.If => "if",

View File

@@ -208,15 +208,24 @@ public class TypeChecker
var cases = new List<TypedNodeStatementMatch.Case>(); var cases = new List<TypedNodeStatementMatch.Case>();
foreach (var @case in statement.Cases) foreach (var @case in statement.Cases)
{ {
if (!enumInfo.Variants.Any(x => x.Name == @case.Variant.Ident)) var variant = enumInfo.Variants.FirstOrDefault(x => x.Name == @case.Variant.Ident);
if (variant == null)
throw BasicError($"Enum type'{enumType}' does not have a variant named '{@case.Variant.Ident}'", @case.Variant); throw BasicError($"Enum type'{enumType}' does not have a variant named '{@case.Variant.Ident}'", @case.Variant);
uncoveredCases.Remove(@case.Variant.Ident); uncoveredCases.Remove(@case.Variant.Ident);
using (scope.EnterScope()) using (scope.EnterScope())
{ {
scope.DeclareIdentifier(@case.VariableName.Ident, NubTypeEnumVariant.Get(NubTypeEnum.Get(enumType.Module, enumType.Name), @case.Variant.Ident)); if (@case.VariableName != null)
{
if (variant.Type is null)
throw BasicError("Cannot capture variable for enum variant without type", @case.VariableName);
scope.DeclareIdentifier(@case.VariableName.Ident, variant.Type);
}
var body = CheckStatement(@case.Body); var body = CheckStatement(@case.Body);
cases.Add(new TypedNodeStatementMatch.Case(@case.Tokens, @case.Variant, @case.VariableName, body)); cases.Add(new TypedNodeStatementMatch.Case(@case.Tokens, @case.Variant, @case.VariableName, body));
} }
} }
@@ -240,7 +249,7 @@ public class TypeChecker
NodeExpressionFuncCall expression => CheckExpressionFuncCall(expression, expectedType), NodeExpressionFuncCall expression => CheckExpressionFuncCall(expression, expectedType),
NodeExpressionStringLiteral expression => CheckExpressionStringLiteral(expression, expectedType), NodeExpressionStringLiteral expression => CheckExpressionStringLiteral(expression, expectedType),
NodeExpressionStructLiteral expression => CheckExpressionStructLiteral(expression, expectedType), NodeExpressionStructLiteral expression => CheckExpressionStructLiteral(expression, expectedType),
NodeExpressionEnumLiteral expression => CheckExpressionEnumLiteral(expression, expectedType), NodeExpressionNewNamedType expression => CheckExpressionNewNamedType(expression, expectedType),
_ => throw new ArgumentOutOfRangeException(nameof(node)) _ => throw new ArgumentOutOfRangeException(nameof(node))
}; };
} }
@@ -517,35 +526,7 @@ public class TypeChecker
private TypedNodeExpressionStructLiteral CheckExpressionStructLiteral(NodeExpressionStructLiteral expression, NubType? expectedType) private TypedNodeExpressionStructLiteral CheckExpressionStructLiteral(NodeExpressionStructLiteral expression, NubType? expectedType)
{ {
if (expression.Type != null) if (expectedType is NubTypeStruct structType)
{
var type = ResolveType(expression.Type);
if (type is not NubTypeStruct structType)
throw BasicError("Type of struct literal is not a struct", expression);
if (!moduleGraph.TryResolveType(structType.Module, structType.Name, structType.Module == currentModule, out var info))
throw BasicError($"Type '{structType}' struct literal not found", expression);
if (info is not Module.TypeInfoStruct structInfo)
throw BasicError($"Type '{structType}' is not a struct", expression.Type);
var initializers = new List<TypedNodeExpressionStructLiteral.Initializer>();
foreach (var initializer in expression.Initializers)
{
var field = structInfo.Fields.FirstOrDefault(x => x.Name == initializer.Name.Ident);
if (field == null)
throw BasicError($"Field '{initializer.Name.Ident}' does not exist on struct '{structType.Module}::{structType.Name}'", initializer.Name);
var value = CheckExpression(initializer.Value, field.Type);
if (!value.Type.IsAssignableTo(field.Type))
throw BasicError($"Type of assignment ({value.Type}) does not match expected type of field '{field.Name}' ({field.Type})", initializer.Name);
initializers.Add(new TypedNodeExpressionStructLiteral.Initializer(initializer.Tokens, initializer.Name, value));
}
return new TypedNodeExpressionStructLiteral(expression.Tokens, structType, initializers);
}
else if (expectedType is NubTypeStruct structType)
{ {
if (!moduleGraph.TryResolveType(structType.Module, structType.Name, structType.Module == currentModule, out var info)) if (!moduleGraph.TryResolveType(structType.Module, structType.Name, structType.Module == currentModule, out var info))
throw BasicError($"Type '{structType}' struct literal not found", expression); throw BasicError($"Type '{structType}' struct literal not found", expression);
@@ -602,24 +583,36 @@ public class TypeChecker
} }
} }
private TypedNodeExpressionEnumLiteral CheckExpressionEnumLiteral(NodeExpressionEnumLiteral expression, NubType? expectedType) private TypedNodeExpressionNewNamedType CheckExpressionNewNamedType(NodeExpressionNewNamedType expression, NubType? expectedType)
{ {
var type = ResolveType(expression.Type); var type = ResolveType(expression.Type);
if (type is not NubTypeEnumVariant variantType) switch (type)
throw BasicError("Expected enum variant type", expression.Type); {
case NubTypeStruct structType:
{
var value = CheckExpression(expression.Value, structType);
return new TypedNodeExpressionNewNamedType(expression.Tokens, structType, value);
}
case NubTypeEnumVariant enumVariantType:
{
if (!moduleGraph.TryResolveType(enumVariantType.EnumType.Module, enumVariantType.EnumType.Name, enumVariantType.EnumType.Module == currentModule, out var info))
throw BasicError($"Type '{enumVariantType.EnumType}' not found", expression.Type);
if (!moduleGraph.TryResolveType(variantType.EnumType.Module, variantType.EnumType.Name, variantType.EnumType.Module == currentModule, out var info)) if (info is not Module.TypeInfoEnum enumInfo)
throw BasicError($"Type '{variantType.EnumType}' not found", expression.Type); throw BasicError($"Type '{enumVariantType.EnumType}' is not an enum", expression.Type);
if (info is not Module.TypeInfoEnum enumInfo) var variant = enumInfo.Variants.FirstOrDefault(x => x.Name == enumVariantType.Variant);
throw BasicError($"Type '{variantType.EnumType}' is not an enum", expression.Type); if (variant == null)
throw BasicError($"Enum type '{enumVariantType.EnumType}' does not have a variant named '{enumVariantType.Variant}'", expression.Type);
var variant = enumInfo.Variants.FirstOrDefault(x => x.Name == variantType.Variant); var value = CheckExpression(expression.Value, variant.Type);
if (variant == null) return new TypedNodeExpressionNewNamedType(expression.Tokens, enumVariantType, value);
throw BasicError($"Enum '{variantType.EnumType}' does not have a variant named '{variantType.Variant}'", expression.Type); }
default:
var value = CheckExpression(expression.Value, variant.Type); {
return new TypedNodeExpressionEnumLiteral(expression.Tokens, type, value); throw BasicError($"'{type}' is not a valid type for the new operator", expression);
}
}
} }
private NubType ResolveType(NodeType node) private NubType ResolveType(NodeType node)
@@ -860,10 +853,10 @@ public class TypedNodeStatementMatch(List<Token> tokens, TypedNodeExpression tar
public TypedNodeExpression Target { get; } = target; public TypedNodeExpression Target { get; } = target;
public List<Case> Cases { get; } = cases; public List<Case> Cases { get; } = cases;
public class Case(List<Token> tokens, TokenIdent type, TokenIdent variableName, TypedNodeStatement body) : Node(tokens) public class Case(List<Token> tokens, TokenIdent type, TokenIdent? variableName, TypedNodeStatement body) : Node(tokens)
{ {
public TokenIdent Variant { get; } = type; public TokenIdent Variant { get; } = type;
public TokenIdent VariableName { get; } = variableName; public TokenIdent? VariableName { get; } = variableName;
public TypedNodeStatement Body { get; } = body; public TypedNodeStatement Body { get; } = body;
} }
} }
@@ -899,7 +892,7 @@ public class TypedNodeExpressionStructLiteral(List<Token> tokens, NubType type,
} }
} }
public class TypedNodeExpressionEnumLiteral(List<Token> tokens, NubType type, TypedNodeExpression value) : TypedNodeExpression(tokens, type) public class TypedNodeExpressionNewNamedType(List<Token> tokens, NubType type, TypedNodeExpression value) : TypedNodeExpression(tokens, type)
{ {
public TypedNodeExpression Value { get; } = value; public TypedNodeExpression Value { get; } = value;
} }

View File

@@ -1,5 +1,5 @@
module sys module sys
export extern func read(fd: u32 buf: ^u8 count: u64): i64 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 write(fd: u32, buf: ^u8, count: u64): i64
export extern func open(fileName: ^u8 flags: i32 mode: u16): i64 export extern func open(fileName: ^u8, flags: i32, mode: u16): i64

View File

@@ -1,7 +1,29 @@
module main module main
struct Human {
name: string
age: i32
}
enum Message {
Quit
Say: string
}
func main(): i32 { func main(): i32 {
core::println("Hello, world!") core::println("Hello, world!")
core::println("Hello" + "World") core::println("Hello" + "World")
let message: Message = new Message::Say "test"
match message {
Quit {
core::println("quit")
}
Say message {
core::println(message)
}
}
return 0 return 0
} }