foreach
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user