This commit is contained in:
nub31
2025-09-16 16:02:08 +02:00
parent 46432d2f8e
commit c9e34ae7e2
8 changed files with 130 additions and 36 deletions

View File

@@ -528,6 +528,9 @@ public class QBEGenerator
case WhileNode whileStatement:
EmitWhile(whileStatement);
break;
case ForArrayNode forArray:
EmitForArray(forArray);
break;
default:
throw new ArgumentOutOfRangeException(nameof(statement));
}
@@ -615,6 +618,54 @@ public class QBEGenerator
_breakLabels.Pop();
}
// todo(nub31): Implement index ident
private void EmitForArray(ForArrayNode forArray)
{
var target = EmitExpression(forArray.Target);
var arrayStart = TmpName();
_writer.Indented($"{arrayStart} =l add {target}, 8");
var size = TmpName();
_writer.Indented($"{size} =l loadl {target}");
var count = TmpName();
_writer.Indented($"{count} =l copy 0");
var loopLabel = LabelName();
_writer.WriteLine(loopLabel);
var condition = TmpName();
_writer.Indented($"{condition} =w cultl {count}, {size}");
var continueLabel = LabelName();
var endLabel = LabelName();
_writer.Indented($"jnz {condition}, {continueLabel}, {endLabel}");
_writer.WriteLine(continueLabel);
var arrayOffset = TmpName();
_writer.Indented($"{arrayOffset} =l mul {count}, {SizeOf(forArray.ArrayType.ElementType)}");
var elementAddress = TmpName();
_writer.Indented($"{elementAddress} =l add {arrayStart}, {arrayOffset}");
if (forArray.ArrayType.ElementType is StructTypeNode)
{
_writer.Indented($"%{forArray.ElementIdent} =l copy {elementAddress}");
}
else
{
var element = EmitLoad(forArray.ArrayType.ElementType, elementAddress);
_writer.Indented($"%{forArray.ElementIdent} {QBEAssign(forArray.ArrayType.ElementType)} copy {element}");
}
EmitBlock(forArray.Body);
_writer.Indented($"{count} =l add {count}, 1");
_writer.Indented($"jmp {loopLabel}");
_writer.WriteLine(endLabel);
}
private string EmitExpression(ExpressionNode expression)
{
return expression switch
@@ -647,10 +698,12 @@ public class QBEGenerator
private string EmitVariableIdentifier(VariableIdentifierNode variableIdent)
{
var address = EmitAddressOfVariableIdent(variableIdent);
if (variableIdent.Type is StructTypeNode)
{
return address;
}
return variableIdent.Type.IsSimpleType(out _, out _)
? EmitLoad(variableIdent.Type, address)
: address;
return EmitLoad(variableIdent.Type, address);
}
private string EmitParameterFuncIdentifier(FuncParameterIdentifierNode funcParameterIdent)

View File

@@ -156,7 +156,6 @@ public sealed class Parser
BlockSyntax? body = null;
if (CurrentToken is SymbolToken { Symbol: Symbol.OpenBrace })
{
Next();
body = ParseBlock();
}
@@ -216,6 +215,8 @@ public sealed class Parser
return ParseIf();
case Symbol.While:
return ParseWhile();
case Symbol.For:
return ParseFor();
case Symbol.Let:
return ParseVariableDeclaration();
case Symbol.Break:
@@ -319,6 +320,25 @@ public sealed class Parser
return new WhileSyntax(GetTokens(startIndex), condition, body);
}
private ForSyntax ParseFor()
{
var startIndex = _tokenIndex;
ExpectSymbol(Symbol.For);
var elementIdent = ExpectIdentifier().Value;
string? indexIndent = null;
if (TryExpectSymbol(Symbol.Comma))
{
indexIndent = ExpectIdentifier().Value;
}
ExpectSymbol(Symbol.In);
var target = ParseExpression();
var body = ParseBlock();
return new ForSyntax(GetTokens(startIndex), elementIdent, indexIndent, target, body);
}
private ExpressionSyntax ParseExpression(int precedence = 0)
{
var startIndex = _tokenIndex;
@@ -595,6 +615,7 @@ public sealed class Parser
{
var startIndex = _tokenIndex;
List<StatementSyntax> statements = [];
ExpectSymbol(Symbol.OpenBrace);
while (!TryExpectSymbol(Symbol.CloseBrace))
{
try

View File

@@ -18,4 +18,6 @@ public record ContinueSyntax(IEnumerable<Token> Tokens) : StatementSyntax(Tokens
public record BreakSyntax(IEnumerable<Token> Tokens) : StatementSyntax(Tokens);
public record WhileSyntax(IEnumerable<Token> Tokens, ExpressionSyntax Condition, BlockSyntax Body) : StatementSyntax(Tokens);
public record WhileSyntax(IEnumerable<Token> Tokens, ExpressionSyntax Condition, BlockSyntax Body) : StatementSyntax(Tokens);
public record ForSyntax(IEnumerable<Token> Tokens, string ElementIdent, string? IndexIdent, ExpressionSyntax Target, BlockSyntax Body) : StatementSyntax(Tokens);

View File

@@ -68,6 +68,7 @@ public enum Symbol
Let,
Calls,
For,
In,
Extern,
Semi,
Percent,

View File

@@ -18,6 +18,7 @@ public sealed class Tokenizer
["let"] = Symbol.Let,
["calls"] = Symbol.Calls,
["for"] = Symbol.For,
["in"] = Symbol.In,
["extern"] = Symbol.Extern,
["module"] = Symbol.Module,
["export"] = Symbol.Export,

View File

@@ -16,4 +16,6 @@ public record ContinueNode : StatementNode;
public record BreakNode : StatementNode;
public record WhileNode(ExpressionNode Condition, BlockNode Body) : StatementNode;
public record WhileNode(ExpressionNode Condition, BlockNode Body) : StatementNode;
public record ForArrayNode(ArrayTypeNode ArrayType, string ElementIdent, string? IndexIdent, ExpressionNode Target, BlockNode Body) : StatementNode;

View File

@@ -14,9 +14,6 @@ public sealed class TypeChecker
private readonly Stack<Scope> _scopes = [];
private readonly Stack<TypeNode> _funcReturnTypes = [];
private readonly List<Diagnostic> _diagnostics = [];
private readonly List<StructTypeNode> _referencedStructTypes = [];
private readonly List<DefinitionNode> _definitions = [];
private Scope Scope => _scopes.Peek();
@@ -29,27 +26,27 @@ public sealed class TypeChecker
.ToDictionary();
}
public List<DefinitionNode> Definitions => _definitions;
public List<Diagnostic> Diagnostics => _diagnostics;
public List<StructTypeNode> ReferencedStructTypes => _referencedStructTypes;
public List<DefinitionNode> Definitions { get; } = [];
public List<Diagnostic> Diagnostics { get; } = [];
public List<StructTypeNode> ReferencedStructTypes { get; } = [];
public void Check()
{
_scopes.Clear();
_funcReturnTypes.Clear();
_diagnostics.Clear();
_referencedStructTypes.Clear();
_definitions.Clear();
Diagnostics.Clear();
Definitions.Clear();
ReferencedStructTypes.Clear();
foreach (var definition in _syntaxTree.Definitions)
{
try
{
_definitions.Add(CheckDefinition(definition));
Definitions.Add(CheckDefinition(definition));
}
catch (TypeCheckerException e)
{
_diagnostics.Add(e.Diagnostic);
Diagnostics.Add(e.Diagnostic);
}
}
}
@@ -143,6 +140,7 @@ public sealed class TypeChecker
StatementExpressionSyntax statement => CheckStatementExpression(statement),
VariableDeclarationSyntax statement => CheckVariableDeclaration(statement),
WhileSyntax statement => CheckWhile(statement),
ForSyntax statement => CheckFor(statement),
_ => throw new ArgumentOutOfRangeException(nameof(node))
};
}
@@ -222,6 +220,31 @@ public sealed class TypeChecker
return new WhileNode(condition, body);
}
private StatementNode CheckFor(ForSyntax statement)
{
var target = CheckExpression(statement.Target);
switch (target.Type)
{
case ArrayTypeNode arrayType:
{
var scope = Scope.SubScope();
scope.Declare(new Identifier(statement.ElementIdent, arrayType.ElementType, IdentifierKind.FunctionParameter));
if (statement.IndexIdent != null)
{
scope.Declare(new Identifier(statement.ElementIdent, new IntTypeNode(true, 64), IdentifierKind.FunctionParameter));
}
var body = CheckBlock(statement.Body, scope);
return new ForArrayNode(arrayType, statement.ElementIdent, statement.IndexIdent, target, body);
}
default:
{
throw new TypeCheckerException(Diagnostic.Error($"Type {target.Type} is not an iterable target").Build());
}
}
}
private FuncSignatureNode CheckFuncSignature(FuncSignatureSyntax statement)
{
var parameters = new List<FuncParameterNode>();
@@ -659,7 +682,7 @@ public sealed class TypeChecker
var typeField = structType.Fields.FirstOrDefault(x => x.Name == initializer.Key);
if (typeField == null)
{
_diagnostics.AddRange(Diagnostic
Diagnostics.AddRange(Diagnostic
.Error($"Struct {structType.Name} does not have a field named {initializer.Key}")
.At(initializer.Value)
.Build());
@@ -764,7 +787,7 @@ public sealed class TypeChecker
result.Functions.Add(new StructTypeFunc(function.Name, type));
}
_referencedStructTypes.Add(result);
ReferencedStructTypes.Add(result);
return result;
}

View File

@@ -2,26 +2,17 @@ module "main"
extern "puts" func puts(text: cstring)
struct Name
{
first: cstring
last: cstring
}
struct Human
{
name: Name
}
extern "main" func main(args: []cstring): i64
{
let x: Human = {
name = {
first = "oliver"
last = "stene"
}
let x = [2]cstring
x[0] = "test1"
x[1] = "test2"
for u in x
{
puts(u)
}
puts(x.name.last)
return 0
}