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); 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 = unboundFunctionStatement.Value.Block =
(BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.Value.UnboundBlock); (BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.Value.UnboundBlock);
var resultType = Scope.ReturnType;
Scope = Scope.ParentScope; Scope = Scope.ParentScope;
var variable = (FunctionVariableSymbol)Scope.Variables[unboundFunctionStatement.Key];
variable.IsBound = true;
variable.ResultType = resultType;
} }
_unboundFunctions = new Dictionary<string, UnboundFunctionExpression>(); _unboundFunctions = new Dictionary<string, UnboundFunctionExpression>();
return new BoundScript((BoundBlockStatement) bound, e.Span, Scope); return new BoundScript((BoundBlockStatement) bound, e.Span, Scope);
@ -198,6 +202,7 @@ namespace Upsilon.Binder
parameters.Add(bound); parameters.Add(bound);
} }
var returnType = Type.Unknown;
if (expression.Kind == BoundKind.VariableExpression) if (expression.Kind == BoundKind.VariableExpression)
{ {
var variableExpression =(BoundVariableExpression) expression; var variableExpression =(BoundVariableExpression) expression;
@ -216,14 +221,18 @@ namespace Upsilon.Binder
var unboundFunctionStatement = _unboundFunctions[function.Name]; var unboundFunctionStatement = _unboundFunctions[function.Name];
unboundFunctionStatement.Block = unboundFunctionStatement.Block =
(BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.UnboundBlock); (BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.UnboundBlock);
returnType = Scope.ReturnType;
Scope = Scope.ParentScope; Scope = Scope.ParentScope;
function.IsBound = true; function.IsBound = true;
function.ResultType = returnType;
_unboundFunctions.Remove(function.Name); _unboundFunctions.Remove(function.Name);
} }
returnType = function.ResultType;
} }
//TODO: validate parameters //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) private BoundExpression BindVariableExpression(VariableExpressionSyntax e)
@ -402,9 +411,10 @@ namespace Upsilon.Binder
{ {
Scope = innerScope; Scope = innerScope;
var block = BindBlockStatement(e.Block); var block = BindBlockStatement(e.Block);
var returnType = Scope.ReturnType;
Scope = Scope.ParentScope; Scope = Scope.ParentScope;
var func = new BoundFunctionExpression(parameters.ToImmutable(), (BoundBlockStatement) block, e.Span, var func = new BoundFunctionExpression(parameters.ToImmutable(), (BoundBlockStatement) block, e.Span,
innerScope); innerScope, returnType);
return func; return func;
} }
else else
@ -445,7 +455,7 @@ namespace Upsilon.Binder
if (!Scope.TryGetVariable(name, !isLocal, out var variable)) 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() CommentValue = commentData.ToArray()
}; };
@ -480,6 +490,17 @@ namespace Upsilon.Binder
private BoundStatement BindReturnStatement(ReturnStatementSyntax e) private BoundStatement BindReturnStatement(ReturnStatementSyntax e)
{ {
var expression = BindExpression(e.Expression); 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); return new BoundReturnStatement(expression, e.Span);
} }

View File

@ -11,10 +11,11 @@ namespace Upsilon.Binder
public ImmutableArray<BoundExpression> Parameters { get; } public ImmutableArray<BoundExpression> Parameters { get; }
public BoundFunctionCallExpression(BoundExpression identifier, ImmutableArray<BoundExpression> parameters, public BoundFunctionCallExpression(BoundExpression identifier, ImmutableArray<BoundExpression> parameters,
TextSpan span) : base(span) TextSpan span, Type type) : base(span)
{ {
Identifier = identifier; Identifier = identifier;
Parameters = parameters; Parameters = parameters;
Type = type;
} }
public override BoundKind Kind => BoundKind.BoundFunctionCallExpression; public override BoundKind Kind => BoundKind.BoundFunctionCallExpression;
@ -37,6 +38,6 @@ namespace Upsilon.Binder
yield return this; 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 ImmutableArray<BoundVariableSymbol> Parameters { get; }
public BoundBlockStatement Block { get; set; } public BoundBlockStatement Block { get; set; }
public BoundFunctionExpression(ImmutableArray<BoundVariableSymbol> parameters, BoundBlockStatement block, TextSpan span, public BoundFunctionExpression(ImmutableArray<BoundVariableSymbol> parameters, BoundBlockStatement block,
BoundScope scope) : base(span) TextSpan span, BoundScope scope, Type returnType) : base(span)
{ {
Parameters = parameters; Parameters = parameters;
Block = block; Block = block;
Scope = scope; Scope = scope;
ReturnType = returnType;
} }
public override BoundKind Kind => BoundKind.BoundFunctionExpression; public override BoundKind Kind => BoundKind.BoundFunctionExpression;
@ -35,5 +36,6 @@ namespace Upsilon.Binder
public override Type Type => Type.Function; public override Type Type => Type.Function;
public BoundScope Scope { get; set; } public BoundScope Scope { get; set; }
public Type ReturnType { get; }
} }
} }

View File

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

View File

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using Upsilon.BaseTypes;
using Upsilon.Parser; using Upsilon.Parser;
using Upsilon.Text; using Upsilon.Text;
@ -8,7 +9,8 @@ namespace Upsilon.Binder
public class UnboundFunctionExpression : BoundFunctionExpression public class UnboundFunctionExpression : BoundFunctionExpression
{ {
public UnboundFunctionExpression(ImmutableArray<BoundVariableSymbol> parameters, 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; UnboundBlock = unboundBlock;
} }

View File

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

View File

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