for in syntax
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ public enum Symbol
|
|||||||
If,
|
If,
|
||||||
Else,
|
Else,
|
||||||
While,
|
While,
|
||||||
|
For,
|
||||||
|
In,
|
||||||
Break,
|
Break,
|
||||||
Continue,
|
Continue,
|
||||||
Return,
|
Return,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user