Add literal conversion based on context at compile time
This commit is contained in:
@@ -1,5 +1,17 @@
|
|||||||
namespace main
|
namespace main
|
||||||
|
|
||||||
export func main(args: []^string) {
|
struct Human {
|
||||||
sys::call(60, 0)
|
age: ^u64
|
||||||
|
}
|
||||||
|
|
||||||
|
export func main(args: []^string) {
|
||||||
|
let x = [3]f64
|
||||||
|
|
||||||
|
x[0] = 1
|
||||||
|
x[1.2] = 2
|
||||||
|
x[2] = 3
|
||||||
|
|
||||||
|
c::printf("%d\n", x[0])
|
||||||
|
c::printf("%d\n", x[1])
|
||||||
|
c::printf("%d\n", x[2])
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -171,12 +171,6 @@ public class Lexer
|
|||||||
buffer += next;
|
buffer += next;
|
||||||
Next();
|
Next();
|
||||||
}
|
}
|
||||||
else if (next == 'f')
|
|
||||||
{
|
|
||||||
isFloat = true;
|
|
||||||
Next();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -20,37 +20,6 @@ public interface IFuncSignature
|
|||||||
public List<FuncParameter> Parameters { get; }
|
public List<FuncParameter> Parameters { get; }
|
||||||
public Optional<NubType> ReturnType { get; }
|
public Optional<NubType> ReturnType { get; }
|
||||||
|
|
||||||
public bool SignatureMatches(string name, List<NubType> parameters)
|
|
||||||
{
|
|
||||||
if (Name != name) return false;
|
|
||||||
if (Parameters.Count == 0 && parameters.Count == 0) return true;
|
|
||||||
if (Parameters.Count > parameters.Count) return false;
|
|
||||||
|
|
||||||
for (var i = 0; i < parameters.Count; i++)
|
|
||||||
{
|
|
||||||
if (i >= Parameters.Count)
|
|
||||||
{
|
|
||||||
if (Parameters.Count > 0 && Parameters[^1].Variadic)
|
|
||||||
{
|
|
||||||
if (!NubType.IsCompatibleWith(parameters[i], Parameters[^1].Type))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!NubType.IsCompatibleWith(parameters[i], Parameters[i].Type))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}";
|
public string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
using Nub.Lang.Frontend.Lexing;
|
// using Nub.Lang.Frontend.Lexing;
|
||||||
using Nub.Lang.Frontend.Typing;
|
// using Nub.Lang.Frontend.Typing;
|
||||||
|
//
|
||||||
namespace Nub.Lang.Frontend.Parsing.Expressions;
|
// namespace Nub.Lang.Frontend.Parsing.Expressions;
|
||||||
|
//
|
||||||
public class CastNode(IReadOnlyList<Token> tokens, NubType targetType, ExpressionNode expression) : ExpressionNode(tokens)
|
// public class CastNode(IReadOnlyList<Token> tokens, NubType targetType, ExpressionNode expression) : ExpressionNode(tokens)
|
||||||
{
|
// {
|
||||||
public NubType TargetType { get; } = targetType;
|
// public NubType TargetType { get; } = targetType;
|
||||||
public ExpressionNode Expression { get; } = expression;
|
// public ExpressionNode Expression { get; } = expression;
|
||||||
}
|
// }
|
||||||
@@ -8,5 +8,5 @@ public class FuncCallNode(IReadOnlyList<Token> tokens, string @namespace, string
|
|||||||
public string Name { get; } = name;
|
public string Name { get; } = name;
|
||||||
public List<ExpressionNode> Parameters { get; } = parameters;
|
public List<ExpressionNode> Parameters { get; } = parameters;
|
||||||
|
|
||||||
public override string ToString() => $"{Name}()";
|
public override string ToString() => $"{Name}::{Name}()";
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using Nub.Lang.Frontend.Lexing;
|
using Nub.Lang.Frontend.Lexing;
|
||||||
using Nub.Lang.Frontend.Typing;
|
|
||||||
|
|
||||||
namespace Nub.Lang.Frontend.Parsing.Expressions;
|
namespace Nub.Lang.Frontend.Parsing.Expressions;
|
||||||
|
|
||||||
|
|||||||
@@ -499,16 +499,16 @@ public class Parser
|
|||||||
expr = expression;
|
expr = expression;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Symbol.LessThan:
|
// case Symbol.LessThan:
|
||||||
{
|
// {
|
||||||
var type = ParseType();
|
// var type = ParseType();
|
||||||
ExpectSymbol(Symbol.GreaterThan);
|
// ExpectSymbol(Symbol.GreaterThan);
|
||||||
ExpectSymbol(Symbol.OpenParen);
|
// ExpectSymbol(Symbol.OpenParen);
|
||||||
var expressionToCast = ParseExpression();
|
// var expressionToCast = ParseExpression();
|
||||||
ExpectSymbol(Symbol.CloseParen);
|
// ExpectSymbol(Symbol.CloseParen);
|
||||||
expr = new CastNode(GetTokensForNode(startIndex), type, expressionToCast);
|
// expr = new CastNode(GetTokensForNode(startIndex), type, expressionToCast);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
case Symbol.Ampersand:
|
case Symbol.Ampersand:
|
||||||
{
|
{
|
||||||
var expression = ParsePrimaryExpression();
|
var expression = ParsePrimaryExpression();
|
||||||
|
|||||||
@@ -24,6 +24,30 @@ public abstract class NubType
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsInteger => this is NubPrimitiveType
|
||||||
|
{
|
||||||
|
Kind: PrimitiveTypeKind.I8
|
||||||
|
or PrimitiveTypeKind.I16
|
||||||
|
or PrimitiveTypeKind.I32
|
||||||
|
or PrimitiveTypeKind.I64
|
||||||
|
or PrimitiveTypeKind.U8
|
||||||
|
or PrimitiveTypeKind.U16
|
||||||
|
or PrimitiveTypeKind.U32
|
||||||
|
or PrimitiveTypeKind.U64
|
||||||
|
};
|
||||||
|
|
||||||
|
public bool IsFloat32 => this is NubPrimitiveType
|
||||||
|
{
|
||||||
|
Kind: PrimitiveTypeKind.F32
|
||||||
|
};
|
||||||
|
|
||||||
|
public bool IsFloat64 => this is NubPrimitiveType
|
||||||
|
{
|
||||||
|
Kind: PrimitiveTypeKind.F64
|
||||||
|
};
|
||||||
|
|
||||||
|
public bool IsNumber => IsFloat32 || IsFloat64 || IsInteger;
|
||||||
|
|
||||||
public abstract override bool Equals(object? obj);
|
public abstract override bool Equals(object? obj);
|
||||||
public abstract override int GetHashCode();
|
public abstract override int GetHashCode();
|
||||||
public abstract override string ToString();
|
public abstract override string ToString();
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ public class TypeChecker
|
|||||||
|
|
||||||
if (field.Value.HasValue)
|
if (field.Value.HasValue)
|
||||||
{
|
{
|
||||||
var fieldType = TypeCheckExpression(field.Value.Value);
|
var fieldType = TypeCheckExpression(field.Value.Value, field.Type);
|
||||||
if (fieldType != null && !fieldType.Equals(field.Type))
|
if (fieldType != null && !fieldType.Equals(field.Type))
|
||||||
{
|
{
|
||||||
ReportError("Default field initializer does not match the defined type", field.Value.Value);
|
ReportError("Default field initializer does not match the defined type", field.Value.Value);
|
||||||
@@ -153,7 +153,7 @@ public class TypeChecker
|
|||||||
{
|
{
|
||||||
var memberType = TypeCheckExpression(memberAssignment.MemberAccess);
|
var memberType = TypeCheckExpression(memberAssignment.MemberAccess);
|
||||||
if (memberType == null) return;
|
if (memberType == null) return;
|
||||||
var valueType = TypeCheckExpression(memberAssignment.Value);
|
var valueType = TypeCheckExpression(memberAssignment.Value, memberType);
|
||||||
if (valueType == null) return;
|
if (valueType == null) return;
|
||||||
|
|
||||||
if (!NubType.IsCompatibleWith(memberType, valueType))
|
if (!NubType.IsCompatibleWith(memberType, valueType))
|
||||||
@@ -166,7 +166,7 @@ public class TypeChecker
|
|||||||
{
|
{
|
||||||
var itemType = TypeCheckExpression(arrayIndexAssignment.ArrayIndexAccess);
|
var itemType = TypeCheckExpression(arrayIndexAssignment.ArrayIndexAccess);
|
||||||
if (itemType == null) return;
|
if (itemType == null) return;
|
||||||
var valueType = TypeCheckExpression(arrayIndexAssignment.Value);
|
var valueType = TypeCheckExpression(arrayIndexAssignment.Value, itemType);
|
||||||
if (valueType == null) return;
|
if (valueType == null) return;
|
||||||
|
|
||||||
if (!NubType.IsCompatibleWith(itemType, valueType))
|
if (!NubType.IsCompatibleWith(itemType, valueType))
|
||||||
@@ -177,19 +177,18 @@ public class TypeChecker
|
|||||||
|
|
||||||
private void TypeCheckVariableAssignment(VariableAssignmentNode variableAssignment)
|
private void TypeCheckVariableAssignment(VariableAssignmentNode variableAssignment)
|
||||||
{
|
{
|
||||||
var valueType = TypeCheckExpression(variableAssignment.Value);
|
if (!_variables.TryGetValue(variableAssignment.Identifier.Identifier, out var variable))
|
||||||
if (valueType == null) return;
|
|
||||||
|
|
||||||
if (!_variables.TryGetValue(variableAssignment.Identifier.Identifier, out var existingVariable))
|
|
||||||
{
|
{
|
||||||
ReportError($"Variable '{variableAssignment.Identifier}' is not declared", variableAssignment);
|
ReportError($"Variable '{variableAssignment.Identifier}' is not declared", variableAssignment);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!NubType.IsCompatibleWith(variableAssignment.Value.Type, existingVariable))
|
var valueType = TypeCheckExpression(variableAssignment.Value, variable);
|
||||||
|
if (valueType == null) return;
|
||||||
|
|
||||||
|
if (!NubType.IsCompatibleWith(variableAssignment.Value.Type, variable))
|
||||||
{
|
{
|
||||||
ReportError($"Cannot assign expression of type '{variableAssignment.Value.Type}' to variable '{variableAssignment.Identifier}' with type '{existingVariable}'",
|
ReportError($"Cannot assign expression of type '{variableAssignment.Value.Type}' to variable '{variableAssignment.Identifier}' with type '{variable}'", variableAssignment);
|
||||||
variableAssignment);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,14 +196,14 @@ public class TypeChecker
|
|||||||
{
|
{
|
||||||
NubType? type = null;
|
NubType? type = null;
|
||||||
|
|
||||||
if (_variables.TryGetValue(variableDeclaration.Name, out var existingVariable))
|
if (_variables.TryGetValue(variableDeclaration.Name, out var variable))
|
||||||
{
|
{
|
||||||
ReportError($"Cannot redeclare variable '{existingVariable}'", variableDeclaration);
|
ReportError($"Cannot redeclare variable '{variable}'", variableDeclaration);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (variableDeclaration.Value.HasValue)
|
if (variableDeclaration.Value.HasValue)
|
||||||
{
|
{
|
||||||
var valueType = TypeCheckExpression(variableDeclaration.Value.Value);
|
var valueType = TypeCheckExpression(variableDeclaration.Value.Value, variableDeclaration.ExplicitType.Value);
|
||||||
if (valueType == null) return;
|
if (valueType == null) return;
|
||||||
type = valueType;
|
type = valueType;
|
||||||
}
|
}
|
||||||
@@ -254,31 +253,21 @@ public class TypeChecker
|
|||||||
|
|
||||||
private NubType? TypeCheckFuncCall(FuncCallNode funcCall, Node node)
|
private NubType? TypeCheckFuncCall(FuncCallNode funcCall, Node node)
|
||||||
{
|
{
|
||||||
List<NubType> parameterTypes = [];
|
var funcDefinition = LookupFuncSignature(funcCall.Namespace, funcCall.Name);
|
||||||
foreach (var funcCallParameter in funcCall.Parameters)
|
|
||||||
{
|
|
||||||
var parameterType = TypeCheckExpression(funcCallParameter);
|
|
||||||
if (parameterType == null) return null;
|
|
||||||
parameterTypes.Add(parameterType);
|
|
||||||
}
|
|
||||||
|
|
||||||
var funcDefinition = LookupFuncSignature(funcCall.Namespace, funcCall.Name, parameterTypes);
|
|
||||||
if (funcDefinition == null)
|
if (funcDefinition == null)
|
||||||
{
|
{
|
||||||
ReportError($"Function '{funcCall.Name}' is not defined", node);
|
ReportError($"Function '{funcCall}' is not defined", node);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (funcDefinition.Parameters.Take(funcDefinition.Parameters.Count - 1).Any(x => x.Variadic))
|
if (funcDefinition.Parameters.Take(funcDefinition.Parameters.Count - 1).Any(x => x.Variadic))
|
||||||
{
|
{
|
||||||
ReportError($"Function '{funcCall.Name}' has multiple variadic parameters", node);
|
ReportError($"Function '{funcCall}' has multiple variadic parameters", node);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < funcCall.Parameters.Count; i++)
|
for (var i = 0; i < funcCall.Parameters.Count; i++)
|
||||||
{
|
{
|
||||||
var argType = funcCall.Parameters[i].Type;
|
|
||||||
|
|
||||||
NubType paramType;
|
NubType paramType;
|
||||||
if (i < funcDefinition.Parameters.Count)
|
if (i < funcDefinition.Parameters.Count)
|
||||||
{
|
{
|
||||||
@@ -290,13 +279,16 @@ public class TypeChecker
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ReportError($"Function '{funcCall.Name}' does not take {funcCall.Parameters.Count} parameters", node);
|
ReportError($"Function '{funcCall}' does not take {funcCall.Parameters.Count} parameters", node);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var argType = TypeCheckExpression(funcCall.Parameters[i], paramType);
|
||||||
|
if (argType == null) return null;
|
||||||
|
|
||||||
if (!NubType.IsCompatibleWith(argType, paramType))
|
if (!NubType.IsCompatibleWith(argType, paramType))
|
||||||
{
|
{
|
||||||
ReportError($"Parameter {i + 1} of function '{funcCall.Name}' expects type '{paramType}', but got '{argType}'", funcCall.Parameters[i]);
|
ReportError($"Parameter {i + 1} of function '{funcCall}' expects type '{paramType}', but got '{argType}'", funcCall.Parameters[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,7 +297,7 @@ public class TypeChecker
|
|||||||
|
|
||||||
private void TypeCheckIf(IfNode ifNode)
|
private void TypeCheckIf(IfNode ifNode)
|
||||||
{
|
{
|
||||||
var conditionType = TypeCheckExpression(ifNode.Condition);
|
var conditionType = TypeCheckExpression(ifNode.Condition, NubPrimitiveType.Bool);
|
||||||
if (conditionType != null && !conditionType.Equals(NubPrimitiveType.Bool))
|
if (conditionType != null && !conditionType.Equals(NubPrimitiveType.Bool))
|
||||||
{
|
{
|
||||||
ReportError($"If condition must be a boolean expression, got '{conditionType}'", ifNode.Condition);
|
ReportError($"If condition must be a boolean expression, got '{conditionType}'", ifNode.Condition);
|
||||||
@@ -322,7 +314,7 @@ public class TypeChecker
|
|||||||
|
|
||||||
private void TypeCheckWhile(WhileNode whileNode)
|
private void TypeCheckWhile(WhileNode whileNode)
|
||||||
{
|
{
|
||||||
var conditionType = TypeCheckExpression(whileNode.Condition);
|
var conditionType = TypeCheckExpression(whileNode.Condition, NubPrimitiveType.Bool);
|
||||||
if (conditionType != null && !conditionType.Equals(NubPrimitiveType.Bool))
|
if (conditionType != null && !conditionType.Equals(NubPrimitiveType.Bool))
|
||||||
{
|
{
|
||||||
ReportError($"While condition must be a boolean expression, got '{conditionType}'", whileNode.Condition);
|
ReportError($"While condition must be a boolean expression, got '{conditionType}'", whileNode.Condition);
|
||||||
@@ -337,7 +329,7 @@ public class TypeChecker
|
|||||||
|
|
||||||
if (returnNode.Value.HasValue)
|
if (returnNode.Value.HasValue)
|
||||||
{
|
{
|
||||||
var returnType = TypeCheckExpression(returnNode.Value.Value);
|
var returnType = TypeCheckExpression(returnNode.Value.Value, _currentFunctionReturnType);
|
||||||
if (returnType == null) return;
|
if (returnType == null) return;
|
||||||
|
|
||||||
if (_currentFunctionReturnType == null)
|
if (_currentFunctionReturnType == null)
|
||||||
@@ -361,7 +353,7 @@ public class TypeChecker
|
|||||||
{
|
{
|
||||||
var dereferenceType = TypeCheckExpression(dereferenceAssignment.Dereference);
|
var dereferenceType = TypeCheckExpression(dereferenceAssignment.Dereference);
|
||||||
if (dereferenceType == null) return;
|
if (dereferenceType == null) return;
|
||||||
var valueType = TypeCheckExpression(dereferenceAssignment.Value);
|
var valueType = TypeCheckExpression(dereferenceAssignment.Value, dereferenceType);
|
||||||
if (valueType == null) return;
|
if (valueType == null) return;
|
||||||
|
|
||||||
if (!NubType.IsCompatibleWith(dereferenceType, valueType))
|
if (!NubType.IsCompatibleWith(dereferenceType, valueType))
|
||||||
@@ -370,17 +362,17 @@ public class TypeChecker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private NubType? TypeCheckExpression(ExpressionNode expression)
|
private NubType? TypeCheckExpression(ExpressionNode expression, NubType? expectedType = null)
|
||||||
{
|
{
|
||||||
var resultType = expression switch
|
var resultType = expression switch
|
||||||
{
|
{
|
||||||
AddressOfNode addressOf => TypeCheckAddressOf(addressOf),
|
AddressOfNode addressOf => TypeCheckAddressOf(addressOf),
|
||||||
ArrayIndexAccessNode arrayIndex => TypeCheckArrayIndex(arrayIndex),
|
ArrayIndexAccessNode arrayIndex => TypeCheckArrayIndex(arrayIndex),
|
||||||
ArrayInitializerNode arrayInitializer => TypeCheckArrayInitializer(arrayInitializer),
|
ArrayInitializerNode arrayInitializer => TypeCheckArrayInitializer(arrayInitializer),
|
||||||
LiteralNode literal => TypeCheckLiteral(literal),
|
LiteralNode literal => TypeCheckLiteral(literal, expectedType),
|
||||||
IdentifierNode identifier => TypeCheckIdentifier(identifier),
|
IdentifierNode identifier => TypeCheckIdentifier(identifier),
|
||||||
BinaryExpressionNode binaryExpr => TypeCheckBinaryExpression(binaryExpr),
|
BinaryExpressionNode binaryExpr => TypeCheckBinaryExpression(binaryExpr),
|
||||||
CastNode cast => TypeCheckCast(cast),
|
// CastNode cast => TypeCheckCast(cast),
|
||||||
DereferenceNode dereference => TypeCheckDereference(dereference),
|
DereferenceNode dereference => TypeCheckDereference(dereference),
|
||||||
FixedArrayInitializerNode fixedArray => TypeCheckFixedInitializerArray(fixedArray),
|
FixedArrayInitializerNode fixedArray => TypeCheckFixedInitializerArray(fixedArray),
|
||||||
FuncCallNode funcCallExpr => TypeCheckFuncCall(funcCallExpr, funcCallExpr),
|
FuncCallNode funcCallExpr => TypeCheckFuncCall(funcCallExpr, funcCallExpr),
|
||||||
@@ -398,15 +390,34 @@ public class TypeChecker
|
|||||||
return resultType;
|
return resultType;
|
||||||
}
|
}
|
||||||
|
|
||||||
private NubType TypeCheckLiteral(LiteralNode literal)
|
private NubType? TypeCheckLiteral(LiteralNode literal, NubType? expectedType = null)
|
||||||
{
|
{
|
||||||
|
if (expectedType != null)
|
||||||
|
{
|
||||||
|
if (expectedType.IsNumber && literal.Kind is not LiteralKind.Integer and not LiteralKind.Float)
|
||||||
|
{
|
||||||
|
ReportError("Expression expects a numeric literal", literal);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expectedType.IsInteger && literal.Kind == LiteralKind.Float)
|
||||||
|
{
|
||||||
|
if (literal.Kind == LiteralKind.Float)
|
||||||
|
{
|
||||||
|
ReportWarning("Possible loss of precision when using float in integer context", literal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return expectedType;
|
||||||
|
}
|
||||||
|
|
||||||
return literal.Kind switch
|
return literal.Kind switch
|
||||||
{
|
{
|
||||||
LiteralKind.Integer => NubPrimitiveType.I64,
|
LiteralKind.Integer => NubPrimitiveType.I64,
|
||||||
LiteralKind.Float => NubPrimitiveType.F64,
|
LiteralKind.Float => NubPrimitiveType.F64,
|
||||||
LiteralKind.String => NubPrimitiveType.String,
|
LiteralKind.String => NubPrimitiveType.String,
|
||||||
LiteralKind.Bool => NubPrimitiveType.Bool,
|
LiteralKind.Bool => NubPrimitiveType.Bool,
|
||||||
_ => throw new UnreachableException()
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,10 +425,10 @@ public class TypeChecker
|
|||||||
{
|
{
|
||||||
var expressionType = TypeCheckExpression(arrayIndexAccess.Array);
|
var expressionType = TypeCheckExpression(arrayIndexAccess.Array);
|
||||||
if (expressionType == null) return null;
|
if (expressionType == null) return null;
|
||||||
var indexType = TypeCheckExpression(arrayIndexAccess.Index);
|
var indexType = TypeCheckExpression(arrayIndexAccess.Index, NubPrimitiveType.U64);
|
||||||
if (indexType != null && !IsInteger(indexType))
|
if (indexType is { IsInteger: false })
|
||||||
{
|
{
|
||||||
ReportError("Array index type must be an integer", arrayIndexAccess.Index);
|
ReportError("Array index type must be a number", arrayIndexAccess.Index);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expressionType is NubArrayType arrayType)
|
if (expressionType is NubArrayType arrayType)
|
||||||
@@ -436,8 +447,8 @@ public class TypeChecker
|
|||||||
|
|
||||||
private NubType TypeCheckArrayInitializer(ArrayInitializerNode arrayInitializer)
|
private NubType TypeCheckArrayInitializer(ArrayInitializerNode arrayInitializer)
|
||||||
{
|
{
|
||||||
var capacityType = TypeCheckExpression(arrayInitializer.Capacity);
|
var capacityType = TypeCheckExpression(arrayInitializer.Capacity, NubPrimitiveType.U64);
|
||||||
if (capacityType != null && !IsInteger(capacityType))
|
if (capacityType is { IsInteger: false })
|
||||||
{
|
{
|
||||||
ReportError("Array capacity type must be an integer", arrayInitializer.Capacity);
|
ReportError("Array capacity type must be an integer", arrayInitializer.Capacity);
|
||||||
}
|
}
|
||||||
@@ -516,12 +527,12 @@ public class TypeChecker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private NubType? TypeCheckCast(CastNode cast)
|
// private NubType? TypeCheckCast(CastNode cast)
|
||||||
{
|
// {
|
||||||
TypeCheckExpression(cast.Expression);
|
// TypeCheckExpression(cast.Expression, cast.TargetType);
|
||||||
// TODO: Check if castable
|
// // TODO: Check if castable
|
||||||
return cast.TargetType;
|
// return cast.TargetType;
|
||||||
}
|
// }
|
||||||
|
|
||||||
private NubType? TypeCheckStructInitializer(StructInitializerNode structInit)
|
private NubType? TypeCheckStructInitializer(StructInitializerNode structInit)
|
||||||
{
|
{
|
||||||
@@ -543,7 +554,7 @@ public class TypeChecker
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var initializerType = TypeCheckExpression(initializer.Value);
|
var initializerType = TypeCheckExpression(initializer.Value, definitionField.Type);
|
||||||
if (initializerType != null && !NubType.IsCompatibleWith(initializerType, definitionField.Type))
|
if (initializerType != null && !NubType.IsCompatibleWith(initializerType, definitionField.Type))
|
||||||
{
|
{
|
||||||
ReportError($"Cannot initialize field '{initializer.Key}' of type '{definitionField.Type}' with expression of type '{initializerType}'", initializer.Value);
|
ReportError($"Cannot initialize field '{initializer.Key}' of type '{definitionField.Type}' with expression of type '{initializerType}'", initializer.Value);
|
||||||
@@ -654,6 +665,12 @@ public class TypeChecker
|
|||||||
_diagnostics.Add(diagnostic);
|
_diagnostics.Add(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ReportWarning(string message, Node node)
|
||||||
|
{
|
||||||
|
var diagnostic = Diagnostic.Warning(message).At(node).Build();
|
||||||
|
_diagnostics.Add(diagnostic);
|
||||||
|
}
|
||||||
|
|
||||||
private static bool IsNumeric(NubType type)
|
private static bool IsNumeric(NubType type)
|
||||||
{
|
{
|
||||||
if (type is not NubPrimitiveType primitiveType)
|
if (type is not NubPrimitiveType primitiveType)
|
||||||
@@ -679,36 +696,13 @@ public class TypeChecker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsInteger(NubType type)
|
private IFuncSignature? LookupFuncSignature(string @namespace, string name)
|
||||||
{
|
|
||||||
if (type is not NubPrimitiveType primitiveType)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (primitiveType.Kind)
|
|
||||||
{
|
|
||||||
case PrimitiveTypeKind.I8:
|
|
||||||
case PrimitiveTypeKind.I16:
|
|
||||||
case PrimitiveTypeKind.I32:
|
|
||||||
case PrimitiveTypeKind.I64:
|
|
||||||
case PrimitiveTypeKind.U8:
|
|
||||||
case PrimitiveTypeKind.U16:
|
|
||||||
case PrimitiveTypeKind.U32:
|
|
||||||
case PrimitiveTypeKind.U64:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IFuncSignature? LookupFuncSignature(string @namespace, string name, List<NubType> parameters)
|
|
||||||
{
|
{
|
||||||
return _sourceFiles
|
return _sourceFiles
|
||||||
.Where(f => f.Namespace == @namespace)
|
.Where(f => f.Namespace == @namespace)
|
||||||
.SelectMany(f => f.Definitions)
|
.SelectMany(f => f.Definitions)
|
||||||
.OfType<IFuncSignature>()
|
.OfType<IFuncSignature>()
|
||||||
.FirstOrDefault(f => f.SignatureMatches(name, parameters));
|
.FirstOrDefault(f => f.Name == name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private StructDefinitionNode? LookupStructDefinition(string @namespace, string name)
|
private StructDefinitionNode? LookupStructDefinition(string @namespace, string name)
|
||||||
@@ -717,6 +711,6 @@ public class TypeChecker
|
|||||||
.Where(f => f.Namespace == @namespace)
|
.Where(f => f.Namespace == @namespace)
|
||||||
.SelectMany(f => f.Definitions)
|
.SelectMany(f => f.Definitions)
|
||||||
.OfType<StructDefinitionNode>()
|
.OfType<StructDefinitionNode>()
|
||||||
.FirstOrDefault(d => d.Name == name);
|
.SingleOrDefault(d => d.Name == name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user