Variable declarations seperate from assignment
This commit is contained in:
@@ -3,9 +3,9 @@ namespace main
|
||||
/// # Documentation
|
||||
/// ## Documentation subtitle
|
||||
export func main(args: []string) {
|
||||
i = 0
|
||||
let i: i64
|
||||
|
||||
x = math::add(1, 1)
|
||||
let x = math::add(1, 1)
|
||||
|
||||
c::printf("%d\n", args.count)
|
||||
|
||||
|
||||
@@ -296,8 +296,6 @@ public class Generator
|
||||
_builder.AppendLine($"({string.Join(", ", parameterStrings)}) {{");
|
||||
_builder.AppendLine("@start");
|
||||
|
||||
_builder.AppendLine(" # Variable allocation");
|
||||
|
||||
foreach (var parameter in node.Parameters)
|
||||
{
|
||||
var parameterName = parameter.Name;
|
||||
@@ -334,9 +332,6 @@ public class Generator
|
||||
};
|
||||
}
|
||||
|
||||
_builder.AppendLine(" # End variable allocation");
|
||||
_builder.AppendLine();
|
||||
|
||||
GenerateBlock(node.Body);
|
||||
|
||||
if (node.Body.Statements.LastOrDefault() is not ReturnNode)
|
||||
@@ -386,6 +381,9 @@ public class Generator
|
||||
case VariableAssignmentNode variableAssignment:
|
||||
GenerateVariableAssignment(variableAssignment);
|
||||
break;
|
||||
case VariableDeclarationNode variableDeclaration:
|
||||
GenerateVariableDeclaration(variableDeclaration);
|
||||
break;
|
||||
case WhileNode whileStatement:
|
||||
GenerateWhile(whileStatement);
|
||||
break;
|
||||
@@ -505,24 +503,33 @@ public class Generator
|
||||
private void GenerateVariableAssignment(VariableAssignmentNode variableAssignment)
|
||||
{
|
||||
var result = GenerateExpression(variableAssignment.Value);
|
||||
_builder.AppendLine($" storel {result}, {_variables[variableAssignment.Name].Pointer}");
|
||||
}
|
||||
|
||||
if (_variables.TryGetValue(variableAssignment.Name, out var existingVariable))
|
||||
private void GenerateVariableDeclaration(VariableDeclarationNode variableDeclaration)
|
||||
{
|
||||
_builder.AppendLine($" storel {result}, {existingVariable.Pointer}");
|
||||
var pointerName = GenVarName();
|
||||
|
||||
var type = variableDeclaration.ExplicitType.Value ?? variableDeclaration.Value.Value?.Type!;
|
||||
|
||||
_builder.AppendLine($" %{pointerName} ={SQT(type)} alloc8 {QbeTypeSize(type)}");
|
||||
|
||||
if (variableDeclaration.Value.HasValue)
|
||||
{
|
||||
var result = GenerateExpression(variableDeclaration.Value.Value);
|
||||
_builder.AppendLine($" storel {result}, %{pointerName}");
|
||||
}
|
||||
else
|
||||
{
|
||||
var pointerName = GenVarName();
|
||||
_builder.AppendLine($" %{pointerName} ={SQT(variableAssignment.Value.Type)} alloc8 {QbeTypeSize(variableAssignment.Value.Type)}");
|
||||
_builder.AppendLine($" storel {result}, %{pointerName}");
|
||||
_builder.AppendLine($" storel 0, %{pointerName}");
|
||||
}
|
||||
|
||||
_variables[variableAssignment.Name] = new Variable
|
||||
_variables[variableDeclaration.Name] = new Variable
|
||||
{
|
||||
Pointer = $"%{pointerName}",
|
||||
Type = variableAssignment.Value.Type
|
||||
Type = type
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateWhile(WhileNode whileStatement)
|
||||
{
|
||||
|
||||
@@ -17,6 +17,7 @@ public class Lexer
|
||||
["return"] = Symbol.Return,
|
||||
["new"] = Symbol.New,
|
||||
["struct"] = Symbol.Struct,
|
||||
["let"] = Symbol.Let,
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, Modifier> Modifiers = new()
|
||||
|
||||
@@ -44,4 +44,5 @@ public enum Symbol
|
||||
Ampersand,
|
||||
DoubleColon,
|
||||
Namespace,
|
||||
Let
|
||||
}
|
||||
@@ -192,11 +192,12 @@ public class Parser
|
||||
Symbol.Return => ParseReturn(startIndex),
|
||||
Symbol.If => ParseIf(startIndex),
|
||||
Symbol.While => ParseWhile(startIndex),
|
||||
Symbol.Let => ParseVariableDeclaration(startIndex),
|
||||
Symbol.Break => new BreakNode(GetTokensForNode(startIndex)),
|
||||
Symbol.Continue => new ContinueNode(GetTokensForNode(startIndex)),
|
||||
_ => throw new ParseException(Diagnostic
|
||||
.Error($"Unexpected symbol '{symbol.Symbol}' at start of statement")
|
||||
.WithHelp("Expected identifier, 'return', 'if', 'while', 'break', or 'continue'")
|
||||
.WithHelp("Expected identifier, 'let', 'return', 'if', 'while', 'break', or 'continue'")
|
||||
.At(symbol)
|
||||
.Build())
|
||||
};
|
||||
@@ -258,14 +259,7 @@ public class Parser
|
||||
case Symbol.Assign:
|
||||
{
|
||||
var value = ParseExpression();
|
||||
return new VariableAssignmentNode(GetTokensForNode(startIndex), identifier.Value, Optional<NubType>.Empty(), value);
|
||||
}
|
||||
case Symbol.Colon:
|
||||
{
|
||||
var type = ParseType();
|
||||
ExpectSymbol(Symbol.Assign);
|
||||
var value = ParseExpression();
|
||||
return new VariableAssignmentNode(GetTokensForNode(startIndex), identifier.Value, type, value);
|
||||
return new VariableAssignmentNode(GetTokensForNode(startIndex), identifier.Value, value);
|
||||
}
|
||||
default:
|
||||
{
|
||||
@@ -278,6 +272,24 @@ public class Parser
|
||||
}
|
||||
}
|
||||
|
||||
private VariableDeclarationNode ParseVariableDeclaration(int startIndex)
|
||||
{
|
||||
var name = ExpectIdentifier().Value;
|
||||
var type = Optional<NubType>.Empty();
|
||||
if (TryExpectSymbol(Symbol.Colon))
|
||||
{
|
||||
type = ParseType();
|
||||
}
|
||||
|
||||
var value = Optional<ExpressionNode>.Empty();
|
||||
if (TryExpectSymbol(Symbol.Assign))
|
||||
{
|
||||
value = ParseExpression();
|
||||
}
|
||||
|
||||
return new VariableDeclarationNode(GetTokensForNode(startIndex), name, type, value);
|
||||
}
|
||||
|
||||
private ReturnNode ParseReturn(int startIndex)
|
||||
{
|
||||
var value = Optional<ExpressionNode>.Empty();
|
||||
|
||||
@@ -3,9 +3,8 @@ using Nub.Lang.Frontend.Typing;
|
||||
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class VariableAssignmentNode(IReadOnlyList<Token> tokens, string name, Optional<NubType> explicitType, ExpressionNode value) : StatementNode(tokens)
|
||||
public class VariableAssignmentNode(IReadOnlyList<Token> tokens, string name, ExpressionNode value) : StatementNode(tokens)
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public Optional<NubType> ExplicitType { get; } = explicitType;
|
||||
public ExpressionNode Value { get; } = value;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using Nub.Lang.Frontend.Lexing;
|
||||
using Nub.Lang.Frontend.Typing;
|
||||
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class VariableDeclarationNode(IReadOnlyList<Token> tokens, string name, Optional<NubType> explicitType, Optional<ExpressionNode> value) : StatementNode(tokens)
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public Optional<NubType> ExplicitType { get; } = explicitType;
|
||||
public Optional<ExpressionNode> Value { get; } = value;
|
||||
}
|
||||
@@ -108,8 +108,11 @@ public class TypeChecker
|
||||
{
|
||||
switch (statement)
|
||||
{
|
||||
case VariableAssignmentNode varAssign:
|
||||
TypeCheckVariableAssignment(varAssign);
|
||||
case VariableAssignmentNode variableAssignment:
|
||||
TypeCheckVariableAssignment(variableAssignment);
|
||||
break;
|
||||
case VariableDeclarationNode variableDeclaration:
|
||||
TypeCheckVariableVariableDeclaration(variableDeclaration);
|
||||
break;
|
||||
case FuncCallStatementNode funcCall:
|
||||
TypeCheckFuncCall(funcCall.FuncCall, funcCall);
|
||||
@@ -132,45 +135,59 @@ public class TypeChecker
|
||||
}
|
||||
}
|
||||
|
||||
private void TypeCheckVariableAssignment(VariableAssignmentNode varAssign)
|
||||
private void TypeCheckVariableAssignment(VariableAssignmentNode variableAssignment)
|
||||
{
|
||||
var valueType = TypeCheckExpression(varAssign.Value);
|
||||
var valueType = TypeCheckExpression(variableAssignment.Value);
|
||||
if (valueType == null) return;
|
||||
|
||||
if (_variables.TryGetValue(varAssign.Name, out var existingVariable))
|
||||
if (!_variables.TryGetValue(variableAssignment.Name, out var existingVariable))
|
||||
{
|
||||
if (varAssign.ExplicitType.HasValue)
|
||||
{
|
||||
if (!NubType.IsCompatibleWith(existingVariable, varAssign.ExplicitType.Value))
|
||||
{
|
||||
ReportError($"Explicit type '{varAssign.ExplicitType.Value}' on variable '{varAssign.Name}' is not compatible with declared type '{existingVariable}'", varAssign);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!NubType.IsCompatibleWith(valueType, existingVariable))
|
||||
{
|
||||
ReportError($"Cannot assign expression of type '{valueType}' to variable '{varAssign.Name}' of type '{existingVariable}'", varAssign);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (varAssign.ExplicitType.HasValue)
|
||||
{
|
||||
var explicitType = varAssign.ExplicitType.Value;
|
||||
if (!NubType.IsCompatibleWith(valueType, explicitType))
|
||||
{
|
||||
ReportError($"Cannot assign expression of type '{valueType}' to variable '{varAssign.Name}' of type '{explicitType}'", varAssign);
|
||||
ReportError($"Variable '{variableAssignment.Name}' is not declared", variableAssignment);
|
||||
return;
|
||||
}
|
||||
|
||||
_variables[varAssign.Name] = explicitType;
|
||||
}
|
||||
else
|
||||
if (!NubType.IsCompatibleWith(variableAssignment.Value.Type, existingVariable))
|
||||
{
|
||||
_variables[varAssign.Name] = valueType;
|
||||
ReportError($"Cannot assign expression of type '{variableAssignment.Value.Type}' to variable '{variableAssignment.Name}' with type '{existingVariable}'", variableAssignment);
|
||||
}
|
||||
}
|
||||
|
||||
private void TypeCheckVariableVariableDeclaration(VariableDeclarationNode variableDeclaration)
|
||||
{
|
||||
NubType? type = null;
|
||||
|
||||
if (_variables.TryGetValue(variableDeclaration.Name, out var existingVariable))
|
||||
{
|
||||
ReportError($"Cannot redeclare variable '{existingVariable}'", variableDeclaration);
|
||||
}
|
||||
|
||||
if (variableDeclaration.Value.HasValue)
|
||||
{
|
||||
var valueType = TypeCheckExpression(variableDeclaration.Value.Value);
|
||||
if (valueType == null) return;
|
||||
type = valueType;
|
||||
}
|
||||
|
||||
if (variableDeclaration.ExplicitType.HasValue)
|
||||
{
|
||||
type = variableDeclaration.ExplicitType.Value;
|
||||
}
|
||||
|
||||
if (variableDeclaration.ExplicitType.HasValue && variableDeclaration.Value.HasValue)
|
||||
{
|
||||
if (!NubType.IsCompatibleWith(variableDeclaration.ExplicitType.Value, variableDeclaration.Value.Value.Type))
|
||||
{
|
||||
ReportError($"Cannot assign expression of type '{variableDeclaration.Value.Value.Type}' to variable '{variableDeclaration.Name}' with type '{variableDeclaration.ExplicitType.Value}'", variableDeclaration);
|
||||
}
|
||||
}
|
||||
|
||||
if (type == null)
|
||||
{
|
||||
ReportError($"Cannot implicitly get type of variable '{variableDeclaration.Name}'", variableDeclaration);
|
||||
return;
|
||||
}
|
||||
|
||||
_variables[variableDeclaration.Name] = type;
|
||||
}
|
||||
|
||||
private NubType? TypeCheckDereference(DereferenceNode dereference)
|
||||
|
||||
Reference in New Issue
Block a user