for in syntax

This commit is contained in:
nub31
2025-10-22 18:32:45 +02:00
parent 420c990731
commit 1fb88f2073
8 changed files with 172 additions and 25 deletions

View File

@@ -40,6 +40,10 @@ public record BreakNode(List<Token> Tokens) : TerminalStatementNode(Tokens);
public record WhileNode(List<Token> Tokens, ExpressionNode Condition, BlockNode Body) : StatementNode(Tokens); public record WhileNode(List<Token> Tokens, ExpressionNode Condition, BlockNode Body) : StatementNode(Tokens);
public record ForSliceNode(List<Token> Tokens, string ElementName, string? IndexName, ExpressionNode Target, BlockNode Body) : StatementNode(Tokens);
public record ForConstArrayNode(List<Token> Tokens, string ElementName, string? IndexName, ExpressionNode Target, BlockNode Body) : StatementNode(Tokens);
public record DeferNode(List<Token> Tokens, StatementNode Statement) : StatementNode(Tokens); public record DeferNode(List<Token> Tokens, StatementNode Statement) : StatementNode(Tokens);
#endregion #endregion

View File

@@ -234,6 +234,51 @@ public sealed class TypeChecker
return new WhileNode(statement.Tokens, condition, body); return new WhileNode(statement.Tokens, condition, body);
} }
private StatementNode CheckFor(ForSyntax forSyntax)
{
var target = CheckExpression(forSyntax.Target);
switch (target.Type)
{
case NubSliceType sliceType:
{
using (BeginScope())
{
Scope.DeclareVariable(new Variable(forSyntax.ElementName, sliceType.ElementType));
if (forSyntax.IndexName != null)
{
Scope.DeclareVariable(new Variable(forSyntax.IndexName, new NubIntType(false, 64)));
}
var body = CheckBlock(forSyntax.Body);
return new ForSliceNode(forSyntax.Tokens, forSyntax.ElementName, forSyntax.IndexName, target, body);
}
}
case NubConstArrayType constArrayType:
{
using (BeginScope())
{
Scope.DeclareVariable(new Variable(forSyntax.ElementName, constArrayType.ElementType));
if (forSyntax.IndexName != null)
{
Scope.DeclareVariable(new Variable(forSyntax.IndexName, new NubIntType(false, 64)));
}
var body = CheckBlock(forSyntax.Body);
return new ForConstArrayNode(forSyntax.Tokens, forSyntax.ElementName, forSyntax.IndexName, target, body);
}
}
default:
{
throw new TypeCheckerException(Diagnostic
.Error($"For statement not supported for type {target.Type}")
.At(forSyntax)
.Build());
}
}
}
private FuncPrototypeNode CheckFuncPrototype(FuncPrototypeSyntax statement) private FuncPrototypeNode CheckFuncPrototype(FuncPrototypeSyntax statement)
{ {
var parameters = new List<FuncParameterNode>(); var parameters = new List<FuncParameterNode>();
@@ -332,8 +377,8 @@ public sealed class TypeChecker
private ArrayInitializerNode CheckArrayInitializer(ArrayInitializerSyntax expression, NubType? _) private ArrayInitializerNode CheckArrayInitializer(ArrayInitializerSyntax expression, NubType? _)
{ {
var elementType = ResolveType(expression.ElementType); var elementType = ResolveType(expression.ElementType);
var type = new NubArrayType(elementType);
var capacity = CheckExpression(expression.Capacity); var capacity = CheckExpression(expression.Capacity);
var type = new NubArrayType(elementType);
return new ArrayInitializerNode(expression.Tokens, type, capacity, elementType); return new ArrayInitializerNode(expression.Tokens, type, capacity, elementType);
} }
@@ -811,6 +856,7 @@ public sealed class TypeChecker
VariableDeclarationSyntax varDeclStmt => CheckVariableDeclaration(varDeclStmt), VariableDeclarationSyntax varDeclStmt => CheckVariableDeclaration(varDeclStmt),
WhileSyntax whileStmt => CheckWhile(whileStmt), WhileSyntax whileStmt => CheckWhile(whileStmt),
DeferSyntax defer => new DeferNode(statement.Tokens, CheckStatement(defer.Statement)), DeferSyntax defer => new DeferNode(statement.Tokens, CheckStatement(defer.Statement)),
ForSyntax forSyntax => CheckFor(forSyntax),
_ => throw new ArgumentOutOfRangeException(nameof(statement)) _ => throw new ArgumentOutOfRangeException(nameof(statement))
}; };
} }

View File

@@ -95,7 +95,13 @@ public class Generator
var name = FuncName(funcNode.Module, funcNode.Name, funcNode.Prototype.ExternSymbol); var name = FuncName(funcNode.Module, funcNode.Name, funcNode.Prototype.ExternSymbol);
_writer.WriteLine($"{CType.Create(funcNode.Prototype.ReturnType, name)}({parameters})"); _writer.WriteLine($"{CType.Create(funcNode.Prototype.ReturnType, name)}({parameters})");
EmitBlock(funcNode.Body); _writer.WriteLine("{");
using (_writer.Indent())
{
EmitBlock(funcNode.Body);
}
_writer.WriteLine("}");
_writer.WriteLine(); _writer.WriteLine();
} }
@@ -111,7 +117,13 @@ public class Generator
EmitAssignment(assignmentNode); EmitAssignment(assignmentNode);
break; break;
case BlockNode blockNode: case BlockNode blockNode:
EmitBlock(blockNode); _writer.WriteLine("{");
using (_writer.Indent())
{
EmitBlock(blockNode);
}
_writer.WriteLine("{");
break; break;
case BreakNode breakNode: case BreakNode breakNode:
EmitBreak(breakNode); EmitBreak(breakNode);
@@ -122,6 +134,12 @@ public class Generator
case DeferNode deferNode: case DeferNode deferNode:
EmitDefer(deferNode); EmitDefer(deferNode);
break; break;
case ForConstArrayNode forConstArrayNode:
EmitForConstArray(forConstArrayNode);
break;
case ForSliceNode forSliceNode:
EmitForSlice(forSliceNode);
break;
case IfNode ifNode: case IfNode ifNode:
EmitIf(ifNode); EmitIf(ifNode);
break; break;
@@ -174,18 +192,64 @@ public class Generator
_deferStack.Peek().Add(deferNode); _deferStack.Peek().Add(deferNode);
} }
private void EmitForSlice(ForSliceNode forSliceNode)
{
var targetType = (NubSliceType)forSliceNode.Target.Type;
var target = EmitExpression(forSliceNode.Target);
var indexName = forSliceNode.IndexName ?? NewTmp();
_writer.WriteLine($"for (size_t {indexName} = 0; {indexName} < {target}.length; ++{indexName})");
_writer.WriteLine("{");
using (_writer.Indent())
{
_writer.WriteLine($"{CType.Create(targetType.ElementType, forSliceNode.ElementName)} = {target}.data[{indexName}];");
EmitBlock(forSliceNode.Body);
}
_writer.WriteLine("}");
}
private void EmitForConstArray(ForConstArrayNode forConstArrayNode)
{
var targetType = (NubConstArrayType)forConstArrayNode.Target.Type;
var target = EmitExpression(forConstArrayNode.Target);
var indexName = forConstArrayNode.IndexName ?? NewTmp();
_writer.WriteLine($"for (size_t {indexName} = 0; {indexName} < {targetType.Size}; ++{indexName})");
_writer.WriteLine("{");
using (_writer.Indent())
{
_writer.WriteLine($"{CType.Create(targetType.ElementType, forConstArrayNode.ElementName)} = {target}[{indexName}];");
EmitBlock(forConstArrayNode.Body);
}
_writer.WriteLine("}");
}
private void EmitIf(IfNode ifNode, bool elseIf = false) private void EmitIf(IfNode ifNode, bool elseIf = false)
{ {
var condition = EmitExpression(ifNode.Condition); var condition = EmitExpression(ifNode.Condition);
_writer.WriteLine($"{(elseIf ? "else " : "")}if ({condition})"); _writer.WriteLine($"{(elseIf ? "else " : "")}if ({condition})");
EmitBlock(ifNode.Body); _writer.WriteLine("{");
using (_writer.Indent())
{
EmitBlock(ifNode.Body);
}
_writer.WriteLine("}");
ifNode.Else?.Match ifNode.Else?.Match
( (
elseIfNode => EmitIf(elseIfNode, true), elseIfNode => EmitIf(elseIfNode, true),
elseNode => elseNode =>
{ {
_writer.WriteLine("else"); _writer.WriteLine("else");
EmitBlock(elseNode); _writer.WriteLine("{");
using (_writer.Indent())
{
EmitBlock(elseNode);
}
_writer.WriteLine("}");
} }
); );
} }
@@ -251,7 +315,13 @@ public class Generator
{ {
var condition = EmitExpression(whileNode.Condition); var condition = EmitExpression(whileNode.Condition);
_writer.WriteLine($"while ({condition})"); _writer.WriteLine($"while ({condition})");
EmitBlock(whileNode.Body); _writer.WriteLine("{");
using (_writer.Indent())
{
EmitBlock(whileNode.Body);
}
_writer.WriteLine("}");
} }
private string EmitExpression(ExpressionNode expressionNode) private string EmitExpression(ExpressionNode expressionNode)
@@ -530,25 +600,17 @@ public class Generator
private void EmitBlock(BlockNode blockNode) private void EmitBlock(BlockNode blockNode)
{ {
EmitLine(blockNode.Tokens.FirstOrDefault()); _deferStack.Push([]);
_writer.WriteLine("{");
using (_writer.Indent()) foreach (var statementNode in blockNode.Statements)
{ {
_deferStack.Push([]); EmitStatement(statementNode);
foreach (var statementNode in blockNode.Statements)
{
EmitStatement(statementNode);
}
var blockDefers = _deferStack.Pop();
for (var i = blockDefers.Count - 1; i >= 0; i--)
{
EmitStatement(blockDefers[i].Statement);
}
} }
EmitLine(blockNode.Tokens.LastOrDefault()); var blockDefers = _deferStack.Pop();
_writer.WriteLine("}"); for (var i = blockDefers.Count - 1; i >= 0; i--)
{
EmitStatement(blockDefers[i].Statement);
}
} }
} }

View File

@@ -241,6 +241,8 @@ public sealed class Parser
return ParseIf(startIndex); return ParseIf(startIndex);
case Symbol.While: case Symbol.While:
return ParseWhile(startIndex); return ParseWhile(startIndex);
case Symbol.For:
return ParseFor(startIndex);
case Symbol.Let: case Symbol.Let:
return ParseVariableDeclaration(startIndex); return ParseVariableDeclaration(startIndex);
case Symbol.Defer: case Symbol.Defer:
@@ -330,6 +332,23 @@ public sealed class Parser
return new WhileSyntax(GetTokens(startIndex), condition, body); return new WhileSyntax(GetTokens(startIndex), condition, body);
} }
private ForSyntax ParseFor(int startIndex)
{
var itemName = ExpectIdentifier().Value;
string? indexName = null;
if (TryExpectSymbol(Symbol.Comma))
{
indexName = ExpectIdentifier().Value;
}
ExpectSymbol(Symbol.In);
var target = ParseExpression();
var body = ParseBlock();
return new ForSyntax(GetTokens(startIndex), itemName, indexName, target, body);
}
private ExpressionSyntax ParseExpression(int precedence = 0) private ExpressionSyntax ParseExpression(int precedence = 0)
{ {
var startIndex = _tokenIndex; var startIndex = _tokenIndex;

View File

@@ -74,6 +74,8 @@ public record DeferSyntax(List<Token> Tokens, StatementSyntax Statement) : State
public record WhileSyntax(List<Token> Tokens, ExpressionSyntax Condition, BlockSyntax Body) : StatementSyntax(Tokens); public record WhileSyntax(List<Token> Tokens, ExpressionSyntax Condition, BlockSyntax Body) : StatementSyntax(Tokens);
public record ForSyntax(List<Token> Tokens, string ElementName, string? IndexName, ExpressionSyntax Target, BlockSyntax Body) : StatementSyntax(Tokens);
#endregion #endregion
#region Expressions #region Expressions

View File

@@ -8,6 +8,8 @@ public enum Symbol
If, If,
Else, Else,
While, While,
For,
In,
Break, Break,
Continue, Continue,
Return, Return,

View File

@@ -10,6 +10,8 @@ public sealed class Tokenizer
["if"] = Symbol.If, ["if"] = Symbol.If,
["else"] = Symbol.Else, ["else"] = Symbol.Else,
["while"] = Symbol.While, ["while"] = Symbol.While,
["for"] = Symbol.For,
["in"] = Symbol.In,
["break"] = Symbol.Break, ["break"] = Symbol.Break,
["continue"] = Symbol.Continue, ["continue"] = Symbol.Continue,
["return"] = Symbol.Return, ["return"] = Symbol.Return,

View File

@@ -2,9 +2,19 @@ module "main"
extern "puts" func puts(text: cstring) extern "puts" func puts(text: cstring)
struct Test
{
data: [23]cstring
}
extern "main" func main(argc: i64, argv: [?]cstring): i64 extern "main" func main(argc: i64, argv: [?]cstring): i64
{ {
defer puts("Bye cruel world!") let names = struct Test {}
puts("Hello world!")
for name, i in names.data
{
puts(name)
}
return 0 return 0
} }