Bind return type from a function to a variable

This commit is contained in:
Deukhoofd 2018-11-28 12:54:18 +01:00
parent dbc7b4eb4f
commit 71397f5db2
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
8 changed files with 70 additions and 12 deletions

View File

@ -42,5 +42,33 @@ namespace Upsilon.BaseTypes
}
return new GenericUserData(o);
}
public static Type GetLuaType(object o)
{
if (o is ScriptType t)
{
return t.Type;
}
switch (o)
{
case bool _:
return Type.Boolean;
case int _:
return Type.Number;
case long _:
return Type.Number;
case float _:
return Type.Number;
case double _:
return Type.Number;
case string _:
return Type.String;
case null:
return Type.Nil;
default:
return Type.UserData;
}
}
}
}

View File

@ -50,7 +50,11 @@ namespace Upsilon.Binder
}
unboundFunctionStatement.Value.Block =
(BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.Value.UnboundBlock);
var resultType = Scope.ReturnType;
Scope = Scope.ParentScope;
var variable = (FunctionVariableSymbol)Scope.Variables[unboundFunctionStatement.Key];
variable.IsBound = true;
variable.ResultType = resultType;
}
_unboundFunctions = new Dictionary<string, UnboundFunctionExpression>();
return new BoundScript((BoundBlockStatement) bound, e.Span, Scope);
@ -198,6 +202,7 @@ namespace Upsilon.Binder
parameters.Add(bound);
}
var returnType = Type.Unknown;
if (expression.Kind == BoundKind.VariableExpression)
{
var variableExpression =(BoundVariableExpression) expression;
@ -216,14 +221,18 @@ namespace Upsilon.Binder
var unboundFunctionStatement = _unboundFunctions[function.Name];
unboundFunctionStatement.Block =
(BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.UnboundBlock);
returnType = Scope.ReturnType;
Scope = Scope.ParentScope;
function.IsBound = true;
function.ResultType = returnType;
_unboundFunctions.Remove(function.Name);
}
returnType = function.ResultType;
}
//TODO: validate parameters
return new BoundFunctionCallExpression(expression, parameters.ToImmutable(), e.Span);
return new BoundFunctionCallExpression(expression, parameters.ToImmutable(), e.Span, returnType);
}
private BoundExpression BindVariableExpression(VariableExpressionSyntax e)
@ -402,9 +411,10 @@ namespace Upsilon.Binder
{
Scope = innerScope;
var block = BindBlockStatement(e.Block);
var returnType = Scope.ReturnType;
Scope = Scope.ParentScope;
var func = new BoundFunctionExpression(parameters.ToImmutable(), (BoundBlockStatement) block, e.Span,
innerScope);
innerScope, returnType);
return func;
}
else
@ -445,7 +455,7 @@ namespace Upsilon.Binder
if (!Scope.TryGetVariable(name, !isLocal, out var variable))
{
var functionVariable = new FunctionVariableSymbol(name, Type.Function, isLocal, parameters.ToImmutable())
var functionVariable = new FunctionVariableSymbol(name, isLocal, parameters.ToImmutable(), func.ReturnType)
{
CommentValue = commentData.ToArray()
};
@ -480,6 +490,17 @@ namespace Upsilon.Binder
private BoundStatement BindReturnStatement(ReturnStatementSyntax e)
{
var expression = BindExpression(e.Expression);
if (expression.Type != Type.Unknown && expression.Type != Type.Unknown &&
Scope.ReturnType != Type.Unknown && Scope.ReturnType != Type.Nil)
{
if (expression.Type != Scope.ReturnType)
{
_diagnostics.LogError($"Can't return type '{expression.Type}' from this scope, earlier in the" +
$" scope a return type of '{Scope.ReturnType}' is defined.", e.Span);
}
}
if (expression.Type != Type.Unknown && expression.Type != Type.Nil)
Scope.ReturnType = expression.Type;
return new BoundReturnStatement(expression, e.Span);
}

View File

@ -11,10 +11,11 @@ namespace Upsilon.Binder
public ImmutableArray<BoundExpression> Parameters { get; }
public BoundFunctionCallExpression(BoundExpression identifier, ImmutableArray<BoundExpression> parameters,
TextSpan span) : base(span)
TextSpan span, Type type) : base(span)
{
Identifier = identifier;
Parameters = parameters;
Type = type;
}
public override BoundKind Kind => BoundKind.BoundFunctionCallExpression;
@ -37,6 +38,6 @@ namespace Upsilon.Binder
yield return this;
}
public override Type Type => Type.Unknown;
public override Type Type { get; }
}
}

View File

@ -10,12 +10,13 @@ namespace Upsilon.Binder
public ImmutableArray<BoundVariableSymbol> Parameters { get; }
public BoundBlockStatement Block { get; set; }
public BoundFunctionExpression(ImmutableArray<BoundVariableSymbol> parameters, BoundBlockStatement block, TextSpan span,
BoundScope scope) : base(span)
public BoundFunctionExpression(ImmutableArray<BoundVariableSymbol> parameters, BoundBlockStatement block,
TextSpan span, BoundScope scope, Type returnType) : base(span)
{
Parameters = parameters;
Block = block;
Scope = scope;
ReturnType = returnType;
}
public override BoundKind Kind => BoundKind.BoundFunctionExpression;
@ -35,5 +36,6 @@ namespace Upsilon.Binder
public override Type Type => Type.Function;
public BoundScope Scope { get; set; }
public Type ReturnType { get; }
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Type = Upsilon.BaseTypes.Type;
namespace Upsilon.Binder
{
@ -8,6 +9,7 @@ namespace Upsilon.Binder
public readonly BoundScope ParentScope;
public BoundScope ReadOnlyScope { get; private set; }
public readonly Dictionary<string, VariableSymbol> Variables;
public Type ReturnType { get; set; } = Type.Nil;
public BoundScope(BoundScope parentScope)
{

View File

@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using Upsilon.BaseTypes;
using Upsilon.Parser;
using Upsilon.Text;
@ -8,7 +9,8 @@ namespace Upsilon.Binder
public class UnboundFunctionExpression : BoundFunctionExpression
{
public UnboundFunctionExpression(ImmutableArray<BoundVariableSymbol> parameters,
BlockStatementSyntax unboundBlock, TextSpan span, BoundScope scope) : base(parameters, null, span, scope)
BlockStatementSyntax unboundBlock, TextSpan span, BoundScope scope)
: base(parameters, null, span, scope, Type.Unknown)
{
UnboundBlock = unboundBlock;
}

View File

@ -23,12 +23,14 @@ namespace Upsilon.Binder
public class FunctionVariableSymbol : VariableSymbol
{
public ImmutableArray<VariableSymbol> Parameters { get; }
public Type ResultType { get; internal set; }
public bool IsBound { get; set; }
public FunctionVariableSymbol(string name, Type type, bool local, ImmutableArray<VariableSymbol> parameters)
: base(name, type, local)
public FunctionVariableSymbol(string name, bool local, ImmutableArray<VariableSymbol> parameters, Type resultType)
: base(name, Type.Function, local)
{
Parameters = parameters;
ResultType = resultType;
}
}

View File

@ -46,8 +46,8 @@ namespace Upsilon.StandardLibraries
var boundScope =
new BoundScope(
scope.Variables.ToDictionary(x => x.Key,
x => (VariableSymbol) new FunctionVariableSymbol(x.Key, x.Value.Type, false,
ImmutableArray<VariableSymbol>.Empty) {IsBound = true}),
x => (VariableSymbol) new FunctionVariableSymbol(x.Key, false,
ImmutableArray<VariableSymbol>.Empty, x.Value.Type) {IsBound = true}),
null);
return (scope, boundScope);
}