...
This commit is contained in:
@@ -528,6 +528,9 @@ public class QBEGenerator
|
|||||||
case WhileNode whileStatement:
|
case WhileNode whileStatement:
|
||||||
EmitWhile(whileStatement);
|
EmitWhile(whileStatement);
|
||||||
break;
|
break;
|
||||||
|
case ForArrayNode forArray:
|
||||||
|
EmitForArray(forArray);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException(nameof(statement));
|
throw new ArgumentOutOfRangeException(nameof(statement));
|
||||||
}
|
}
|
||||||
@@ -615,6 +618,54 @@ public class QBEGenerator
|
|||||||
_breakLabels.Pop();
|
_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)
|
private string EmitExpression(ExpressionNode expression)
|
||||||
{
|
{
|
||||||
return expression switch
|
return expression switch
|
||||||
@@ -647,10 +698,12 @@ public class QBEGenerator
|
|||||||
private string EmitVariableIdentifier(VariableIdentifierNode variableIdent)
|
private string EmitVariableIdentifier(VariableIdentifierNode variableIdent)
|
||||||
{
|
{
|
||||||
var address = EmitAddressOfVariableIdent(variableIdent);
|
var address = EmitAddressOfVariableIdent(variableIdent);
|
||||||
|
if (variableIdent.Type is StructTypeNode)
|
||||||
|
{
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
return variableIdent.Type.IsSimpleType(out _, out _)
|
return EmitLoad(variableIdent.Type, address);
|
||||||
? EmitLoad(variableIdent.Type, address)
|
|
||||||
: address;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string EmitParameterFuncIdentifier(FuncParameterIdentifierNode funcParameterIdent)
|
private string EmitParameterFuncIdentifier(FuncParameterIdentifierNode funcParameterIdent)
|
||||||
|
|||||||
@@ -156,7 +156,6 @@ public sealed class Parser
|
|||||||
BlockSyntax? body = null;
|
BlockSyntax? body = null;
|
||||||
if (CurrentToken is SymbolToken { Symbol: Symbol.OpenBrace })
|
if (CurrentToken is SymbolToken { Symbol: Symbol.OpenBrace })
|
||||||
{
|
{
|
||||||
Next();
|
|
||||||
body = ParseBlock();
|
body = ParseBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,6 +215,8 @@ public sealed class Parser
|
|||||||
return ParseIf();
|
return ParseIf();
|
||||||
case Symbol.While:
|
case Symbol.While:
|
||||||
return ParseWhile();
|
return ParseWhile();
|
||||||
|
case Symbol.For:
|
||||||
|
return ParseFor();
|
||||||
case Symbol.Let:
|
case Symbol.Let:
|
||||||
return ParseVariableDeclaration();
|
return ParseVariableDeclaration();
|
||||||
case Symbol.Break:
|
case Symbol.Break:
|
||||||
@@ -319,6 +320,25 @@ public sealed class Parser
|
|||||||
return new WhileSyntax(GetTokens(startIndex), condition, body);
|
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)
|
private ExpressionSyntax ParseExpression(int precedence = 0)
|
||||||
{
|
{
|
||||||
var startIndex = _tokenIndex;
|
var startIndex = _tokenIndex;
|
||||||
@@ -595,6 +615,7 @@ public sealed class Parser
|
|||||||
{
|
{
|
||||||
var startIndex = _tokenIndex;
|
var startIndex = _tokenIndex;
|
||||||
List<StatementSyntax> statements = [];
|
List<StatementSyntax> statements = [];
|
||||||
|
ExpectSymbol(Symbol.OpenBrace);
|
||||||
while (!TryExpectSymbol(Symbol.CloseBrace))
|
while (!TryExpectSymbol(Symbol.CloseBrace))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -19,3 +19,5 @@ public record ContinueSyntax(IEnumerable<Token> Tokens) : StatementSyntax(Tokens
|
|||||||
public record BreakSyntax(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);
|
||||||
@@ -68,6 +68,7 @@ public enum Symbol
|
|||||||
Let,
|
Let,
|
||||||
Calls,
|
Calls,
|
||||||
For,
|
For,
|
||||||
|
In,
|
||||||
Extern,
|
Extern,
|
||||||
Semi,
|
Semi,
|
||||||
Percent,
|
Percent,
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ public sealed class Tokenizer
|
|||||||
["let"] = Symbol.Let,
|
["let"] = Symbol.Let,
|
||||||
["calls"] = Symbol.Calls,
|
["calls"] = Symbol.Calls,
|
||||||
["for"] = Symbol.For,
|
["for"] = Symbol.For,
|
||||||
|
["in"] = Symbol.In,
|
||||||
["extern"] = Symbol.Extern,
|
["extern"] = Symbol.Extern,
|
||||||
["module"] = Symbol.Module,
|
["module"] = Symbol.Module,
|
||||||
["export"] = Symbol.Export,
|
["export"] = Symbol.Export,
|
||||||
|
|||||||
@@ -17,3 +17,5 @@ public record ContinueNode : StatementNode;
|
|||||||
public record BreakNode : 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;
|
||||||
@@ -14,9 +14,6 @@ public sealed class TypeChecker
|
|||||||
|
|
||||||
private readonly Stack<Scope> _scopes = [];
|
private readonly Stack<Scope> _scopes = [];
|
||||||
private readonly Stack<TypeNode> _funcReturnTypes = [];
|
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();
|
private Scope Scope => _scopes.Peek();
|
||||||
|
|
||||||
@@ -29,27 +26,27 @@ public sealed class TypeChecker
|
|||||||
.ToDictionary();
|
.ToDictionary();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DefinitionNode> Definitions => _definitions;
|
public List<DefinitionNode> Definitions { get; } = [];
|
||||||
public List<Diagnostic> Diagnostics => _diagnostics;
|
public List<Diagnostic> Diagnostics { get; } = [];
|
||||||
public List<StructTypeNode> ReferencedStructTypes => _referencedStructTypes;
|
public List<StructTypeNode> ReferencedStructTypes { get; } = [];
|
||||||
|
|
||||||
public void Check()
|
public void Check()
|
||||||
{
|
{
|
||||||
_scopes.Clear();
|
_scopes.Clear();
|
||||||
_funcReturnTypes.Clear();
|
_funcReturnTypes.Clear();
|
||||||
_diagnostics.Clear();
|
Diagnostics.Clear();
|
||||||
_referencedStructTypes.Clear();
|
Definitions.Clear();
|
||||||
_definitions.Clear();
|
ReferencedStructTypes.Clear();
|
||||||
|
|
||||||
foreach (var definition in _syntaxTree.Definitions)
|
foreach (var definition in _syntaxTree.Definitions)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_definitions.Add(CheckDefinition(definition));
|
Definitions.Add(CheckDefinition(definition));
|
||||||
}
|
}
|
||||||
catch (TypeCheckerException e)
|
catch (TypeCheckerException e)
|
||||||
{
|
{
|
||||||
_diagnostics.Add(e.Diagnostic);
|
Diagnostics.Add(e.Diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -143,6 +140,7 @@ public sealed class TypeChecker
|
|||||||
StatementExpressionSyntax statement => CheckStatementExpression(statement),
|
StatementExpressionSyntax statement => CheckStatementExpression(statement),
|
||||||
VariableDeclarationSyntax statement => CheckVariableDeclaration(statement),
|
VariableDeclarationSyntax statement => CheckVariableDeclaration(statement),
|
||||||
WhileSyntax statement => CheckWhile(statement),
|
WhileSyntax statement => CheckWhile(statement),
|
||||||
|
ForSyntax statement => CheckFor(statement),
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(node))
|
_ => throw new ArgumentOutOfRangeException(nameof(node))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -222,6 +220,31 @@ public sealed class TypeChecker
|
|||||||
return new WhileNode(condition, body);
|
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)
|
private FuncSignatureNode CheckFuncSignature(FuncSignatureSyntax statement)
|
||||||
{
|
{
|
||||||
var parameters = new List<FuncParameterNode>();
|
var parameters = new List<FuncParameterNode>();
|
||||||
@@ -659,7 +682,7 @@ public sealed class TypeChecker
|
|||||||
var typeField = structType.Fields.FirstOrDefault(x => x.Name == initializer.Key);
|
var typeField = structType.Fields.FirstOrDefault(x => x.Name == initializer.Key);
|
||||||
if (typeField == null)
|
if (typeField == null)
|
||||||
{
|
{
|
||||||
_diagnostics.AddRange(Diagnostic
|
Diagnostics.AddRange(Diagnostic
|
||||||
.Error($"Struct {structType.Name} does not have a field named {initializer.Key}")
|
.Error($"Struct {structType.Name} does not have a field named {initializer.Key}")
|
||||||
.At(initializer.Value)
|
.At(initializer.Value)
|
||||||
.Build());
|
.Build());
|
||||||
@@ -764,7 +787,7 @@ public sealed class TypeChecker
|
|||||||
result.Functions.Add(new StructTypeFunc(function.Name, type));
|
result.Functions.Add(new StructTypeFunc(function.Name, type));
|
||||||
}
|
}
|
||||||
|
|
||||||
_referencedStructTypes.Add(result);
|
ReferencedStructTypes.Add(result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,26 +2,17 @@ module "main"
|
|||||||
|
|
||||||
extern "puts" func puts(text: cstring)
|
extern "puts" func puts(text: cstring)
|
||||||
|
|
||||||
struct Name
|
|
||||||
{
|
|
||||||
first: cstring
|
|
||||||
last: cstring
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Human
|
|
||||||
{
|
|
||||||
name: Name
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "main" func main(args: []cstring): i64
|
extern "main" func main(args: []cstring): i64
|
||||||
{
|
{
|
||||||
let x: Human = {
|
let x = [2]cstring
|
||||||
name = {
|
|
||||||
first = "oliver"
|
x[0] = "test1"
|
||||||
last = "stene"
|
x[1] = "test2"
|
||||||
}
|
|
||||||
|
for u in x
|
||||||
|
{
|
||||||
|
puts(u)
|
||||||
}
|
}
|
||||||
|
|
||||||
puts(x.name.last)
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user