This commit is contained in:
nub31
2026-03-10 16:37:59 +01:00
parent 1a1dc1389d
commit 83255980d7
5 changed files with 150 additions and 14 deletions

View File

@@ -232,6 +232,20 @@ static inline string *string_from_cstr(char *cstr)
return result;
}
#define da_append(xs, x) \
do \
{ \
if ((xs)->count >= (xs)->capacity) \
{ \
if ((xs)->capacity == 0) (xs)->capacity = 256; \
else (xs)->capacity *= 2; \
(xs)->items = realloc((xs)->items, (xs)->capacity*sizeof(*(xs)->items)); \
} \
\
(xs)->items[(xs)->count++] = (x); \
} \
while (0)
"""
);
@@ -406,6 +420,9 @@ static inline string *string_from_cstr(char *cstr)
case TypedNodeStatementWhile statement:
EmitStatementWhile(statement);
break;
case TypedNodeStatementFor statement:
EmitStatementFor(statement);
break;
case TypedNodeStatementMatch statement:
EmitStatementMatch(statement);
break;
@@ -514,6 +531,21 @@ static inline string *string_from_cstr(char *cstr)
writer.WriteLine("}");
}
private void EmitStatementFor(TypedNodeStatementFor statement)
{
var index = Tmp();
var array = EmitExpression(statement.Array);
writer.WriteLine($"for (size_t {index} = 0; {index} < {array}.count; ++{index})");
writer.WriteLine("{");
using (writer.Indent())
{
var arrayType = (NubTypeArray)statement.Array.Type;
writer.WriteLine($"{CType(arrayType.ElementType, statement.VariableName.Ident)} = {array}.items[{index}];");
EmitStatement(statement.Body);
}
writer.WriteLine("}");
}
private void EmitStatementMatch(TypedNodeStatementMatch statement)
{
var target = EmitExpression(statement.Target);
@@ -565,6 +597,7 @@ static inline string *string_from_cstr(char *cstr)
TypedNodeExpressionStringLiteral expression => EmitExpressionStringLiteral(expression),
TypedNodeExpressionStructLiteral expression => EmitExpressionStructLiteral(expression),
TypedNodeExpressionEnumLiteral expression => EmitExpressionEnumLiteral(expression),
TypedNodeExpressionArrayLiteral expression => EmitNodeExpressionArrayLiteral(expression),
TypedNodeExpressionStringConstructor expression => EmitExpressionStringConstructor(expression),
TypedNodeExpressionStructMemberAccess expression => EmitExpressionMemberAccess(expression),
TypedNodeExpressionStringLength expression => EmitExpressionStringLength(expression),
@@ -588,7 +621,7 @@ static inline string *string_from_cstr(char *cstr)
if (expression.Operation == TypedNodeExpressionBinary.Op.Add && expression.Left.Type is NubTypeString && expression.Right.Type is NubTypeString)
{
scopes.Peek().DeconstructableNames.Add((name, expression.Type));
writer.WriteLine($"{CType(NubTypeString.Instance, name)} = nub_core_string_concat({left}, {right});");
writer.WriteLine($"{CType(NubTypeString.Instance, name)} = string_concat({left}, {right});");
return name;
}
@@ -693,12 +726,27 @@ static inline string *string_from_cstr(char *cstr)
return name;
}
private string EmitNodeExpressionArrayLiteral(TypedNodeExpressionArrayLiteral expression)
{
var name = Tmp();
writer.WriteLine($"{CType(expression.Type, name)} = {{0}};");
foreach (var value in expression.Values)
{
var valueName = EmitExpression(value);
writer.WriteLine($"da_append(&{name}, {valueName});");
}
return name;
}
private string EmitExpressionStringConstructor(TypedNodeExpressionStringConstructor expression)
{
var name = Tmp();
scopes.Peek().DeconstructableNames.Add((name, expression.Type));
var value = EmitExpression(expression.Value);
writer.WriteLine($"{CType(expression.Type, name)} = nub_core_string_from_cstr({value});");
writer.WriteLine($"{CType(expression.Type, name)} = string_from_cstr({value});");
return name;
}

View File

@@ -263,8 +263,17 @@ public class Parser
if (TryExpectKeyword(Keyword.While))
{
var condition = ParseExpression();
var thenBlock = ParseStatement();
return new NodeStatementWhile(TokensFrom(startIndex), condition, thenBlock);
var block = ParseStatement();
return new NodeStatementWhile(TokensFrom(startIndex), condition, block);
}
if (TryExpectKeyword(Keyword.For))
{
var variableName = ExpectIdent();
ExpectKeyword(Keyword.In);
var array = ParseExpression();
var block = ParseStatement();
return new NodeStatementFor(TokensFrom(startIndex), variableName, array, block);
}
if (TryExpectKeyword(Keyword.Match))
@@ -363,6 +372,19 @@ public class Parser
var target = ParseExpression();
expr = new NodeExpressionUnary(TokensFrom(startIndex), target, NodeExpressionUnary.Op.Negate);
}
else if (TryExpectSymbol(Symbol.OpenSquare))
{
var values = new List<NodeExpression>();
while (!TryExpectSymbol(Symbol.CloseSquare))
{
var value = ParseExpression();
values.Add(value);
TryExpectSymbol(Symbol.Comma);
}
expr = new NodeExpressionArrayLiteral(TokensFrom(startIndex), values);
}
else if (TryExpectSymbol(Symbol.OpenCurly))
{
var initializers = new List<NodeExpressionStructLiteral.Initializer>();
@@ -893,6 +915,13 @@ public class NodeStatementWhile(List<Token> tokens, NodeExpression condition, No
public NodeStatement Body { get; } = body;
}
public class NodeStatementFor(List<Token> tokens, TokenIdent variableName, NodeExpression array, NodeStatement body) : NodeStatement(tokens)
{
public TokenIdent VariableName { get; } = variableName;
public NodeExpression Array { get; } = array;
public NodeStatement Body { get; } = body;
}
public class NodeStatementMatch(List<Token> tokens, NodeExpression target, List<NodeStatementMatch.Case> cases) : NodeStatement(tokens)
{
public NodeExpression Target { get; } = target;
@@ -941,6 +970,11 @@ public class NodeExpressionEnumLiteral(List<Token> tokens, NodeTypeNamed type, N
public NodeExpression? Value { get; } = value;
}
public class NodeExpressionArrayLiteral(List<Token> tokens, List<NodeExpression> values) : NodeExpression(tokens)
{
public List<NodeExpression> Values { get; } = values;
}
public class NodeExpressionStringConstructor(List<Token> tokens, NodeExpression value) : NodeExpression(tokens)
{
public NodeExpression Value { get; } = value;

View File

@@ -405,6 +405,8 @@ public class Tokenizer
"if" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.If),
"else" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Else),
"while" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.While),
"for" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.For),
"in" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.In),
"return" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Return),
"module" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Module),
"export" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Export),
@@ -557,6 +559,8 @@ public enum Keyword
If,
Else,
While,
For,
In,
Return,
Module,
Export,
@@ -627,6 +631,8 @@ public static class TokenExtensions
Keyword.If => "if",
Keyword.Else => "else",
Keyword.While => "while",
Keyword.For => "for",
Keyword.In => "in",
Keyword.Return => "return",
Keyword.Module => "module",
Keyword.Export => "export",

View File

@@ -99,6 +99,7 @@ public class TypeChecker
NodeStatementReturn statement => CheckStatementReturn(statement),
NodeStatementVariableDeclaration statement => CheckStatementVariableDeclaration(statement),
NodeStatementWhile statement => CheckStatementWhile(statement),
NodeStatementFor statement => CheckStatementFor(statement),
NodeStatementMatch statement => CheckStatementMatch(statement),
_ => throw new ArgumentOutOfRangeException(nameof(node))
};
@@ -204,6 +205,22 @@ public class TypeChecker
}
}
private TypedNodeStatementFor CheckStatementFor(NodeStatementFor statement)
{
var array = CheckExpression(statement.Array, null);
if (array.Type is not NubTypeArray arrayType)
throw BasicError($"Cannot iterate over non-array type '{array.Type}'", statement.Array);
TypedNodeStatement body;
using (EnterScope())
{
DeclareLocalIdentifier(statement.VariableName, arrayType.ElementType);
body = CheckStatement(statement.Body);
}
return new TypedNodeStatementFor(statement.Tokens, statement.VariableName, array, body);
}
private TypedNodeStatementMatch CheckStatementMatch(NodeStatementMatch statement)
{
var target = CheckExpression(statement.Target, null);
@@ -264,6 +281,7 @@ public class TypeChecker
NodeExpressionStructLiteral expression => CheckExpressionStructLiteral(expression, expectedType),
NodeExpressionEnumLiteral expression => CheckExpressionEnumLiteral(expression, expectedType),
NodeExpressionStringConstructor expression => CheckExpressionStringConstructor(expression, expectedType),
NodeExpressionArrayLiteral expression => CheckExpressionArrayLiteral(expression, expectedType),
_ => throw new ArgumentOutOfRangeException(nameof(node))
};
}
@@ -675,6 +693,31 @@ public class TypeChecker
return new TypedNodeExpressionStringConstructor(expression.Tokens, NubTypeString.Instance, value);
}
private TypedNodeExpressionArrayLiteral CheckExpressionArrayLiteral(NodeExpressionArrayLiteral expression, NubType? expectedType)
{
NubType? elementType = null;
if (expectedType is NubTypeArray arrayType)
elementType = arrayType.ElementType;
var values = new List<TypedNodeExpression>();
foreach (var value in expression.Values)
{
var checkedValue = CheckExpression(value, elementType);
elementType ??= checkedValue.Type;
if (!checkedValue.Type.IsAssignableTo(elementType))
throw BasicError($"Type '{checkedValue.Type}' is not assignable to type of element '{elementType}'", checkedValue);
values.Add(checkedValue);
}
if (elementType is null)
throw BasicError("Unable to infer type of array element", expression);
return new TypedNodeExpressionArrayLiteral(expression.Tokens, NubTypeArray.Get(elementType), values);
}
private NubType ResolveType(NodeType node)
{
return node switch
@@ -908,6 +951,13 @@ public class TypedNodeStatementWhile(List<Token> tokens, TypedNodeExpression con
public TypedNodeStatement Body { get; } = body;
}
public class TypedNodeStatementFor(List<Token> tokens, TokenIdent variableName, TypedNodeExpression array, TypedNodeStatement body) : TypedNodeStatement(tokens)
{
public TokenIdent VariableName { get; } = variableName;
public TypedNodeExpression Array { get; } = array;
public TypedNodeStatement Body { get; } = body;
}
public class TypedNodeStatementMatch(List<Token> tokens, TypedNodeExpression target, List<TypedNodeStatementMatch.Case> cases) : TypedNodeStatement(tokens)
{
public TypedNodeExpression Target { get; } = target;
@@ -962,6 +1012,11 @@ public class TypedNodeExpressionStringConstructor(List<Token> tokens, NubType ty
public TypedNodeExpression Value { get; } = value;
}
public class TypedNodeExpressionArrayLiteral(List<Token> tokens, NubType type, List<TypedNodeExpression> values) : TypedNodeExpression(tokens, type)
{
public List<TypedNodeExpression> Values { get; } = values;
}
public class TypedNodeExpressionStructMemberAccess(List<Token> tokens, NubType type, TypedNodeExpression target, TokenIdent name) : TypedNodeExpression(tokens, type)
{
public TypedNodeExpression Target { get; } = target;

View File

@@ -11,18 +11,11 @@ enum Message {
}
func main(): i32 {
let message = getMessage()
let names = ["a", "b", "c", "d"]
match message {
Quit {}
Say msg {
core::println(msg)
}
for name in names {
core::println(name)
}
return 0
}
func getMessage(): Message {
return new Message::Say("testæøå")
}