More types

This commit is contained in:
Alexander Luzgarev 2020-07-20 10:38:32 +02:00
parent 3f494cef6d
commit 3bc8ef0d7d
21 changed files with 1008 additions and 88 deletions

View File

@ -116,7 +116,7 @@ namespace Parser.Binding
TokenKind.ExpressionStatement =>
BindExpressionStatement((ExpressionStatementSyntaxNode)node),
TokenKind.ForStatement =>
BindForStatement((ForStatementSyntaxNode)node),
BindForStatement((ForStatementSyntaxNode)node)!,
TokenKind.FunctionDeclaration =>
BindFunctionDeclaration((FunctionDeclarationSyntaxNode)node),
TokenKind.IfStatement =>
@ -265,9 +265,29 @@ namespace Parser.Binding
return new ParameterSymbol(parameter.Text);
}
private BoundForStatement BindForStatement(ForStatementSyntaxNode node)
private BoundForStatement? BindForStatement(ForStatementSyntaxNode node)
{
throw new NotImplementedException();
var loopVariable = BindLoopVariable(node.Assignment.Lhs);
if (loopVariable is null)
{
return null;
}
var loopedExpression = BindExpression(node.Assignment.Rhs);
var body = BindStatement(node.Body);
return ForStatement(node, loopVariable, loopedExpression, body);
}
private BoundIdentifierNameExpression? BindLoopVariable(ExpressionSyntaxNode node)
{
if (node.Kind != TokenKind.IdentifierNameExpression)
{
_diagnostics.ReportForLoopWithoutVariable(
new TextSpan(node.Position, node.FullWidth));
return null;
}
return Identifier(node, ((IdentifierNameExpressionSyntaxNode)node).Name.Text);
}
private BoundExpressionStatement BindExpressionStatement(ExpressionStatementSyntaxNode node)
@ -342,11 +362,37 @@ namespace Parser.Binding
return Assignment(node, left, right);
}
private BoundExpression BindConversion(BoundExpression expression, TypeSymbol targetType)
{
var conversion = Conversion.Classify(expression.Type, targetType);
if (!conversion.Exists)
{
return new BoundErrorExpression(expression.Syntax);
}
if (conversion.IsIdentity)
{
return expression;
}
return Conversion(expression.Syntax, targetType, expression);
}
private BoundBinaryOperationExpression BindBinaryOperationExpression(BinaryOperationExpressionSyntaxNode node)
{
var left = BindExpression(node.Lhs);
var right = BindExpression(node.Rhs);
return BinaryOperation(node, left, node.Operation.Kind, right);
var op = BoundBinaryOperator.GetOperator(node.Operation.Kind, left.Type, right.Type);
if (op is null)
{
throw new Exception($"Unknown binary operator '{node.Operation.Kind}'.");
}
return BinaryOperation(
node,
BindConversion(left, op.Left),
op,
BindConversion(right, op.Right));
}
private BoundCellArrayElementAccessExpression BindCellArrayElementAccessExpression(CellArrayElementAccessExpressionSyntaxNode node)
@ -416,10 +462,10 @@ namespace Parser.Binding
throw new NotImplementedException();
}
private BoundNumberLiteralExpression BindNumberLiteralExpression(NumberLiteralExpressionSyntaxNode node)
private BoundNumberDoubleLiteralExpression BindNumberLiteralExpression(NumberLiteralExpressionSyntaxNode node)
{
var value = (double)node.Number.Value!;
return NumberLiteral(node, value);
return NumberDoubleLiteral(node, value);
}
private BoundExpression BindParenthesizedExpression(ParenthesizedExpressionSyntaxNode node)
@ -436,7 +482,16 @@ namespace Parser.Binding
private BoundUnaryOperationExpression BindUnaryPrefixOperationExpression(UnaryPrefixOperationExpressionSyntaxNode node)
{
var operand = BindExpression(node.Operand);
return UnaryOperation(node, node.Operation.Kind, operand);
var op = BoundUnaryOperator.GetOperator(node.Operation.Kind, operand.Type);
if (op is null)
{
throw new Exception($"Unknown binary operator '{node.Operation.Kind}'.");
}
return UnaryOperation(
node,
op,
BindConversion(operand, op.Result));
}
private BoundUnaryOperationExpression BindUnaryPostfixOperationExpression(UnaryPostfixOperationExpressionSyntaxNode node)

View File

@ -4,45 +4,164 @@ namespace Parser.Binding
{
public class BoundBinaryOperator
{
private static BoundBinaryOperator[] _operators =
private static BoundBinaryOperator[] _specificOperators =
{
new BoundBinaryOperator(TokenKind.EqualsToken, BoundBinaryOperatorKind.Equals),
new BoundBinaryOperator(TokenKind.PipePipeToken, BoundBinaryOperatorKind.PipePipe),
new BoundBinaryOperator(TokenKind.AmpersandAmpersandToken, BoundBinaryOperatorKind.AmpersandAmpersand),
new BoundBinaryOperator(TokenKind.PipeToken, BoundBinaryOperatorKind.Pipe),
new BoundBinaryOperator(TokenKind.AmpersandToken, BoundBinaryOperatorKind.Ampersand),
new BoundBinaryOperator(TokenKind.LessToken, BoundBinaryOperatorKind.Less),
new BoundBinaryOperator(TokenKind.LessOrEqualsToken, BoundBinaryOperatorKind.LessOrEquals),
new BoundBinaryOperator(TokenKind.GreaterToken, BoundBinaryOperatorKind.Greater),
new BoundBinaryOperator(TokenKind.GreaterOrEqualsToken, BoundBinaryOperatorKind.GreaterOrEquals),
new BoundBinaryOperator(TokenKind.EqualsEqualsToken, BoundBinaryOperatorKind.EqualsEquals),
new BoundBinaryOperator(TokenKind.TildeEqualsToken, BoundBinaryOperatorKind.TildeEquals),
new BoundBinaryOperator(TokenKind.ColonToken, BoundBinaryOperatorKind.Colon),
new BoundBinaryOperator(TokenKind.PlusToken, BoundBinaryOperatorKind.Plus),
new BoundBinaryOperator(TokenKind.MinusToken, BoundBinaryOperatorKind.Minus),
new BoundBinaryOperator(TokenKind.StarToken, BoundBinaryOperatorKind.Star),
new BoundBinaryOperator(TokenKind.DotStarToken, BoundBinaryOperatorKind.DotStar),
new BoundBinaryOperator(TokenKind.SlashToken, BoundBinaryOperatorKind.Slash),
new BoundBinaryOperator(TokenKind.DotSlashToken, BoundBinaryOperatorKind.DotSlash),
new BoundBinaryOperator(TokenKind.BackslashToken, BoundBinaryOperatorKind.Backslash),
new BoundBinaryOperator(TokenKind.DotBackslashToken, BoundBinaryOperatorKind.DotBackslash),
new BoundBinaryOperator(TokenKind.TildeToken, BoundBinaryOperatorKind.Tilde),
new BoundBinaryOperator(TokenKind.CaretToken, BoundBinaryOperatorKind.Caret),
new BoundBinaryOperator(TokenKind.DotCaretToken, BoundBinaryOperatorKind.DotCaret),
new BoundBinaryOperator(
TokenKind.LessToken,
BoundBinaryOperatorKind.Less,
TypeSymbol.Int,
TypeSymbol.Boolean),
new BoundBinaryOperator(
TokenKind.PlusToken,
BoundBinaryOperatorKind.Plus,
TypeSymbol.Int),
};
public BoundBinaryOperator(TokenKind syntaxKind, BoundBinaryOperatorKind kind)
private static BoundBinaryOperator[] _defaultOperators =
{
new BoundBinaryOperator(
TokenKind.EqualsToken,
BoundBinaryOperatorKind.Equals,
TypeSymbol.MObject),
new BoundBinaryOperator(
TokenKind.PipePipeToken,
BoundBinaryOperatorKind.PipePipe,
TypeSymbol.MObject),
new BoundBinaryOperator(
TokenKind.AmpersandAmpersandToken,
BoundBinaryOperatorKind.AmpersandAmpersand,
TypeSymbol.MObject),
new BoundBinaryOperator(
TokenKind.PipeToken,
BoundBinaryOperatorKind.Pipe,
TypeSymbol.MObject),
new BoundBinaryOperator(
TokenKind.AmpersandToken,
BoundBinaryOperatorKind.Ampersand,
TypeSymbol.MObject),
new BoundBinaryOperator(
TokenKind.LessToken,
BoundBinaryOperatorKind.Less,
TypeSymbol.MObject),
new BoundBinaryOperator(
TokenKind.LessOrEqualsToken,
BoundBinaryOperatorKind.LessOrEquals,
TypeSymbol.MObject),
new BoundBinaryOperator(
TokenKind.GreaterToken,
BoundBinaryOperatorKind.Greater,
TypeSymbol.MObject),
new BoundBinaryOperator(
TokenKind.GreaterOrEqualsToken,
BoundBinaryOperatorKind.GreaterOrEquals,
TypeSymbol.MObject),
new BoundBinaryOperator(
TokenKind.EqualsEqualsToken,
BoundBinaryOperatorKind.EqualsEquals,
TypeSymbol.MObject),
new BoundBinaryOperator(
TokenKind.TildeEqualsToken,
BoundBinaryOperatorKind.TildeEquals,
TypeSymbol.MObject),
new BoundBinaryOperator(
TokenKind.ColonToken,
BoundBinaryOperatorKind.Colon,
TypeSymbol.MObject),
new BoundBinaryOperator(
TokenKind.PlusToken,
BoundBinaryOperatorKind.Plus,
TypeSymbol.MObject),
new BoundBinaryOperator(
TokenKind.MinusToken,
BoundBinaryOperatorKind.Minus,
TypeSymbol.MObject),
new BoundBinaryOperator(
TokenKind.StarToken,
BoundBinaryOperatorKind.Star,
TypeSymbol.MObject),
new BoundBinaryOperator(
TokenKind.DotStarToken,
BoundBinaryOperatorKind.DotStar,
TypeSymbol.MObject),
new BoundBinaryOperator(
TokenKind.SlashToken,
BoundBinaryOperatorKind.Slash,
TypeSymbol.MObject),
new BoundBinaryOperator(
TokenKind.DotSlashToken,
BoundBinaryOperatorKind.DotSlash,
TypeSymbol.MObject),
new BoundBinaryOperator(
TokenKind.BackslashToken,
BoundBinaryOperatorKind.Backslash,
TypeSymbol.MObject),
new BoundBinaryOperator(
TokenKind.DotBackslashToken,
BoundBinaryOperatorKind.DotBackslash,
TypeSymbol.MObject),
new BoundBinaryOperator(
TokenKind.TildeToken,
BoundBinaryOperatorKind.Tilde,
TypeSymbol.MObject),
new BoundBinaryOperator(
TokenKind.CaretToken,
BoundBinaryOperatorKind.Caret,
TypeSymbol.MObject),
new BoundBinaryOperator(
TokenKind.DotCaretToken,
BoundBinaryOperatorKind.DotCaret,
TypeSymbol.MObject),
};
public BoundBinaryOperator(
TokenKind syntaxKind,
BoundBinaryOperatorKind kind,
TypeSymbol type)
{
SyntaxKind = syntaxKind;
Kind = kind;
Left = type;
Right = type;
Result = type;
}
public BoundBinaryOperator(
TokenKind syntaxKind,
BoundBinaryOperatorKind kind,
TypeSymbol operand,
TypeSymbol result)
{
SyntaxKind = syntaxKind;
Kind = kind;
Left = operand;
Right = operand;
Result = result;
}
public BoundBinaryOperator(
TokenKind syntaxKind,
BoundBinaryOperatorKind kind,
TypeSymbol left,
TypeSymbol right,
TypeSymbol result)
{
SyntaxKind = syntaxKind;
Kind = kind;
Left = left;
Right = right;
Result = result;
}
public TokenKind SyntaxKind { get; }
public BoundBinaryOperatorKind Kind { get; }
public TypeSymbol Left { get; }
public TypeSymbol Right { get; }
public TypeSymbol Result { get; }
internal static BoundBinaryOperator? GetOperator(TokenKind kind)
internal static BoundBinaryOperator? GetOperator(TokenKind kind, TypeSymbol left, TypeSymbol right)
{
return _operators.FirstOrDefault(op => op.SyntaxKind == kind);
return _specificOperators.FirstOrDefault(op => op.SyntaxKind == kind && op.Left == left && op.Right == right)
?? _defaultOperators.FirstOrDefault(op => op.SyntaxKind == kind);
}
}
}

View File

@ -25,6 +25,11 @@ namespace Parser.Binding
return new BoundBlockStatement(syntax, statements);
}
public static BoundConversionExpression Conversion(SyntaxNode syntax, TypeSymbol targetType, BoundExpression expression)
{
return new BoundConversionExpression(syntax, targetType, expression);
}
public static BoundExpressionStatement ExpressionStatement(
SyntaxNode syntax,
BoundExpression expression,
@ -43,6 +48,15 @@ namespace Parser.Binding
return new BoundIfStatement(syntax, condition, body, elseifClauses, elseClause);
}
public static BoundForStatement ForStatement(
SyntaxNode syntax,
BoundIdentifierNameExpression loopVariable,
BoundExpression loopExpression,
BoundStatement body)
{
return new BoundForStatement(syntax, loopVariable, loopExpression, body);
}
public static BoundLabelStatement LabelStatement(
SyntaxNode syntax,
BoundLabel label)
@ -61,10 +75,9 @@ namespace Parser.Binding
public static BoundBinaryOperationExpression BinaryOperation(
SyntaxNode syntax,
BoundExpression left,
TokenKind kind,
BoundBinaryOperator op,
BoundExpression right)
{
var op = BindBinaryOperator(kind);
return new BoundBinaryOperationExpression(syntax, left, op, right);
}
@ -127,11 +140,18 @@ namespace Parser.Binding
return new BoundIdentifierNameExpression(syntax, name);
}
public static BoundNumberLiteralExpression NumberLiteral(
public static BoundNumberDoubleLiteralExpression NumberDoubleLiteral(
SyntaxNode syntax,
double value)
{
return new BoundNumberLiteralExpression(syntax, value);
return new BoundNumberDoubleLiteralExpression(syntax, value);
}
public static BoundNumberIntLiteralExpression NumberIntLiteral(
SyntaxNode syntax,
int value)
{
return new BoundNumberIntLiteralExpression(syntax, value);
}
public static BoundStringLiteralExpression StringLiteral(
@ -149,25 +169,38 @@ namespace Parser.Binding
return new BoundElseifClause(syntax, condition, body);
}
public static BoundTypedVariableDeclaration TypedVariableDeclaration(
SyntaxNode syntax,
TypedVariableSymbol variable,
BoundExpression initializer)
{
return new BoundTypedVariableDeclaration(syntax, variable, initializer);
}
public static BoundTypedVariableExpression TypedVariableExpression(
SyntaxNode syntax,
TypedVariableSymbol variable)
{
return new BoundTypedVariableExpression(syntax, variable);
}
public static BoundUnaryOperationExpression UnaryOperation(
SyntaxNode syntax,
TokenKind kind,
BoundUnaryOperator op,
BoundExpression operand)
{
var op = BindUnaryOperator(kind);
return new BoundUnaryOperationExpression(syntax, op, operand);
}
private static BoundUnaryOperator BindUnaryOperator(TokenKind kind)
public static BoundExpression TypedFunctionCall(
SyntaxNode syntax,
TypedFunctionSymbol function,
ImmutableArray<BoundExpression> arguments)
{
return BoundUnaryOperator.GetOperator(kind)
?? throw new Exception($"Unexpected unary operator kind {kind}.");
}
private static BoundBinaryOperator BindBinaryOperator(TokenKind kind)
{
return BoundBinaryOperator.GetOperator(kind)
?? throw new Exception($"Unexpected binary operator kind {kind}.");
return new BoundTypedFunctionCallExpression(
syntax,
function,
arguments);
}
}
}

View File

@ -21,6 +21,7 @@
LabelStatement,
SwitchStatement,
TryCatchStatement,
TypedVariableDeclaration,
WhileStatement,
// Expressions
@ -33,8 +34,10 @@
ClassInvokationExpression,
CommandExpression,
CompoundNameExpression,
ConversionExpression,
DoubleQuotedStringLiteralExpression,
EmptyExpression,
ErrorExpression,
FunctionCallExpression,
IdentifierNameExpression,
IndirectMemberAccessExpression,
@ -44,11 +47,13 @@
NumberLiteralExpression,
ParenthesizedExpression,
StringLiteralExpression,
TypedFunctionCallExpression,
TypedVariableExpression,
UnaryOperationExpression,
UnquotedStringLiteralExpression,
// Parts
ElseIfClause,
ElseClause
ElseClause,
}
}

View File

@ -134,11 +134,24 @@ namespace Parser.Binding
public class BoundForStatement : BoundStatement
{
public BoundForStatement(SyntaxNode syntax)
public BoundForStatement(
SyntaxNode syntax,
BoundIdentifierNameExpression loopVariable,
BoundExpression loopedExpression,
BoundStatement body)
: base(syntax)
{
LoopVariable = loopVariable;
LoopedExpression = loopedExpression;
Body = body;
}
public BoundIdentifierNameExpression LoopVariable { get; }
public BoundExpression LoopedExpression { get; }
public BoundStatement Body { get; }
public override BoundNodeKind Kind => BoundNodeKind.ForStatement;
}
@ -257,6 +270,8 @@ namespace Parser.Binding
: base(syntax)
{
}
public abstract TypeSymbol Type { get; }
}
public class BoundArrayLiteralExpression : BoundExpression
@ -267,6 +282,8 @@ namespace Parser.Binding
}
public override BoundNodeKind Kind => BoundNodeKind.ArrayLiteralExpression;
public override TypeSymbol Type => throw new System.NotImplementedException();
}
public class BoundAssignmentExpression : BoundExpression
@ -282,6 +299,8 @@ namespace Parser.Binding
public BoundExpression Right { get; }
public override BoundNodeKind Kind => BoundNodeKind.AssignmentExpression;
public override TypeSymbol Type => Right.Type;
}
public class BoundBinaryOperationExpression : BoundExpression
@ -299,6 +318,8 @@ namespace Parser.Binding
public BoundExpression Right { get; }
public override BoundNodeKind Kind => BoundNodeKind.BinaryOperationExpression;
public override TypeSymbol Type => Op.Result;
}
public class BoundCellArrayElementAccessExpression : BoundExpression
@ -309,6 +330,8 @@ namespace Parser.Binding
}
public override BoundNodeKind Kind => BoundNodeKind.CellArrayElementAccessExpression;
public override TypeSymbol Type => throw new System.NotImplementedException();
}
public class BoundCellArrayLiteralExpression : BoundExpression
@ -319,6 +342,8 @@ namespace Parser.Binding
}
public override BoundNodeKind Kind => BoundNodeKind.CellArrayLiteralExpression;
public override TypeSymbol Type => throw new System.NotImplementedException();
}
public class BoundClassInvokationExpression : BoundExpression
@ -329,6 +354,8 @@ namespace Parser.Binding
}
public override BoundNodeKind Kind => BoundNodeKind.ClassInvokationExpression;
public override TypeSymbol Type => throw new System.NotImplementedException();
}
public class BoundCommandExpression : BoundExpression
@ -339,6 +366,8 @@ namespace Parser.Binding
}
public override BoundNodeKind Kind => BoundNodeKind.CommandExpression;
public override TypeSymbol Type => throw new System.NotImplementedException();
}
public class BoundCompoundNameExpression : BoundExpression
@ -349,6 +378,8 @@ namespace Parser.Binding
}
public override BoundNodeKind Kind => BoundNodeKind.CompoundNameExpression;
public override TypeSymbol Type => throw new System.NotImplementedException();
}
public class BoundDoubleQuotedStringLiteralExpression : BoundExpression
@ -359,6 +390,8 @@ namespace Parser.Binding
}
public override BoundNodeKind Kind => BoundNodeKind.DoubleQuotedStringLiteralExpression;
public override TypeSymbol Type => throw new System.NotImplementedException();
}
public class BoundEmptyExpression : BoundExpression
@ -369,6 +402,20 @@ namespace Parser.Binding
}
public override BoundNodeKind Kind => BoundNodeKind.EmptyExpression;
public override TypeSymbol Type => TypeSymbol.Null;
}
public class BoundErrorExpression : BoundExpression
{
public BoundErrorExpression(SyntaxNode syntax)
: base(syntax)
{
}
public override BoundNodeKind Kind => BoundNodeKind.ErrorExpression;
public override TypeSymbol Type => TypeSymbol.Error;
}
public class BoundFunctionCallExpression : BoundExpression
@ -383,6 +430,27 @@ namespace Parser.Binding
public BoundExpression Name { get; }
public ImmutableArray<BoundExpression> Arguments { get; }
public override BoundNodeKind Kind => BoundNodeKind.FunctionCallExpression;
public override TypeSymbol Type => throw new System.NotImplementedException();
}
public class BoundTypedFunctionCallExpression : BoundExpression
{
public BoundTypedFunctionCallExpression(
SyntaxNode syntax,
TypedFunctionSymbol function,
ImmutableArray<BoundExpression> arguments)
: base(syntax)
{
Function = function;
Arguments = arguments;
}
public TypedFunctionSymbol Function { get; }
public ImmutableArray<BoundExpression> Arguments { get; }
public override BoundNodeKind Kind => BoundNodeKind.TypedFunctionCallExpression;
public override TypeSymbol Type => Function.ReturnType;
}
public class BoundIdentifierNameExpression : BoundExpression
@ -395,6 +463,8 @@ namespace Parser.Binding
public string Name { get; }
public override BoundNodeKind Kind => BoundNodeKind.IdentifierNameExpression;
public override TypeSymbol Type => TypeSymbol.MObject;
}
public class BoundIndirectMemberAccessExpression : BoundExpression
@ -405,6 +475,8 @@ namespace Parser.Binding
}
public override BoundNodeKind Kind => BoundNodeKind.IndirectMemberAccessExpression;
public override TypeSymbol Type => throw new System.NotImplementedException();
}
public class BoundLambdaExpression : BoundExpression
@ -415,6 +487,8 @@ namespace Parser.Binding
}
public override BoundNodeKind Kind => BoundNodeKind.LambdaExpression;
public override TypeSymbol Type => throw new System.NotImplementedException();
}
public class BoundMemberAccessExpression : BoundExpression
@ -425,6 +499,8 @@ namespace Parser.Binding
}
public override BoundNodeKind Kind => BoundNodeKind.MemberAccessExpression;
public override TypeSymbol Type => throw new System.NotImplementedException();
}
public class BoundNamedFunctionHandleExpression : BoundExpression
@ -435,11 +511,13 @@ namespace Parser.Binding
}
public override BoundNodeKind Kind => BoundNodeKind.NamedFunctionHandleExpression;
public override TypeSymbol Type => throw new System.NotImplementedException();
}
public class BoundNumberLiteralExpression : BoundExpression
public class BoundNumberDoubleLiteralExpression : BoundExpression
{
public BoundNumberLiteralExpression(SyntaxNode syntax, double value)
public BoundNumberDoubleLiteralExpression(SyntaxNode syntax, double value)
: base(syntax)
{
Value = value;
@ -447,6 +525,22 @@ namespace Parser.Binding
public double Value { get; }
public override BoundNodeKind Kind => BoundNodeKind.NumberLiteralExpression;
public override TypeSymbol Type => TypeSymbol.Double;
}
public class BoundNumberIntLiteralExpression : BoundExpression
{
public BoundNumberIntLiteralExpression(SyntaxNode syntax, int value)
: base(syntax)
{
Value = value;
}
public double Value { get; }
public override BoundNodeKind Kind => BoundNodeKind.NumberLiteralExpression;
public override TypeSymbol Type => TypeSymbol.Int;
}
public class BoundStringLiteralExpression : BoundExpression
@ -459,6 +553,39 @@ namespace Parser.Binding
public string Value { get; }
public override BoundNodeKind Kind => BoundNodeKind.StringLiteralExpression;
public override TypeSymbol Type => TypeSymbol.String;
}
public class BoundTypedVariableDeclaration : BoundStatement
{
public BoundTypedVariableDeclaration(SyntaxNode syntax, TypedVariableSymbol variable, BoundExpression initializer)
: base(syntax)
{
Variable = variable;
Initializer = initializer;
}
public TypedVariableSymbol Variable { get; }
public BoundExpression Initializer { get; }
public override BoundNodeKind Kind => BoundNodeKind.TypedVariableDeclaration;
}
public class BoundTypedVariableExpression : BoundExpression
{
public BoundTypedVariableExpression(SyntaxNode syntax, TypedVariableSymbol variable)
: base(syntax)
{
Variable = variable;
}
public TypedVariableSymbol Variable { get; }
public override BoundNodeKind Kind => BoundNodeKind.TypedVariableExpression;
public override TypeSymbol Type => Variable.Type;
}
public class BoundUnaryOperationExpression : BoundExpression
@ -474,6 +601,8 @@ namespace Parser.Binding
public BoundUnaryOperator Op { get; }
public BoundExpression Operand { get; }
public override TypeSymbol Type => Op.Result;
}
public class BoundUnquotedStringLiteralExpression : BoundExpression
@ -484,6 +613,26 @@ namespace Parser.Binding
}
public override BoundNodeKind Kind => BoundNodeKind.UnquotedStringLiteralExpression;
public override TypeSymbol Type => throw new System.NotImplementedException();
}
public class BoundConversionExpression : BoundExpression
{
public BoundConversionExpression(SyntaxNode syntax, TypeSymbol targetType, BoundExpression expression)
: base(syntax)
{
TargetType = targetType;
Expression = expression;
}
public TypeSymbol TargetType { get; }
public BoundExpression Expression { get; }
public override BoundNodeKind Kind => BoundNodeKind.ConversionExpression;
public override TypeSymbol Type => TargetType;
}
public class BoundElseifClause : BoundNode

View File

@ -38,6 +38,8 @@ namespace Parser.Binding
RewriteSwitchStatement((BoundSwitchStatement)node),
BoundNodeKind.TryCatchStatement =>
RewriteTryCatchStatement((BoundTryCatchStatement)node),
BoundNodeKind.TypedVariableDeclaration =>
RewriteTypedVariableDeclaration((BoundTypedVariableDeclaration)node),
BoundNodeKind.WhileStatement =>
RewriteWhileStatement((BoundWhileStatement)node),
_ =>
@ -45,6 +47,11 @@ namespace Parser.Binding
};
}
public virtual BoundStatement RewriteTypedVariableDeclaration(BoundTypedVariableDeclaration node)
{
return node;
}
public virtual BoundStatement RewriteGotoStatement(BoundGotoStatement node)
{
return node;
@ -136,7 +143,7 @@ namespace Parser.Binding
public virtual BoundStatement RewriteForStatement(BoundForStatement node)
{
throw new NotImplementedException();
return node;
}
public virtual BoundStatement RewriteExpressionStatement(BoundExpressionStatement node)
@ -220,6 +227,8 @@ namespace Parser.Binding
RewriteCommandExpression((BoundCommandExpression)node),
BoundNodeKind.CompoundNameExpression =>
RewriteCompoundNameExpression((BoundCompoundNameExpression)node),
BoundNodeKind.ConversionExpression =>
RewriteConversionExpression((BoundConversionExpression)node),
BoundNodeKind.DoubleQuotedStringLiteralExpression =>
RewriteDoubleQuotedStringLiteralExpression((BoundDoubleQuotedStringLiteralExpression)node),
BoundNodeKind.EmptyExpression =>
@ -237,9 +246,11 @@ namespace Parser.Binding
BoundNodeKind.NamedFunctionHandleExpression =>
RewriteNamedFunctionHandleExpression((BoundNamedFunctionHandleExpression)node),
BoundNodeKind.NumberLiteralExpression =>
RewriteNumberLiteralExpression((BoundNumberLiteralExpression)node),
RewriteNumberLiteralExpression((BoundNumberDoubleLiteralExpression)node),
BoundNodeKind.StringLiteralExpression =>
RewriteStringLiteralExpression((BoundStringLiteralExpression)node),
BoundNodeKind.TypedVariableExpression =>
RewriteTypedVariableExpression((BoundTypedVariableExpression)node),
BoundNodeKind.UnaryOperationExpression =>
RewriteUnaryOperationExpression((BoundUnaryOperationExpression)node),
BoundNodeKind.UnquotedStringLiteralExpression =>
@ -249,6 +260,17 @@ namespace Parser.Binding
};
}
public virtual BoundExpression RewriteConversionExpression(BoundConversionExpression node)
{
var operand = RewriteExpression(node.Expression);
return Conversion(node.Syntax, node.TargetType, operand);
}
public virtual BoundExpression RewriteTypedVariableExpression(BoundTypedVariableExpression node)
{
return node;
}
public virtual BoundExpression RewriteUnquotedStringLiteralExpression(BoundUnquotedStringLiteralExpression node)
{
throw new NotImplementedException();
@ -265,7 +287,7 @@ namespace Parser.Binding
return node;
}
public virtual BoundExpression RewriteNumberLiteralExpression(BoundNumberLiteralExpression node)
public virtual BoundExpression RewriteNumberLiteralExpression(BoundNumberDoubleLiteralExpression node)
{
return node;
}

View File

@ -1,26 +1,42 @@
using System.Linq;
using System;
using System.Linq;
namespace Parser.Binding
{
public class BoundUnaryOperator
{
private static BoundUnaryOperator[] _operators =
private static BoundUnaryOperator[] _specificOperators = Array.Empty<BoundUnaryOperator>();
private static BoundUnaryOperator[] _defaultOperators =
{
new BoundUnaryOperator(TokenKind.MinusToken, BoundUnaryOperatorKind.Minus),
new BoundUnaryOperator(TokenKind.MinusToken, BoundUnaryOperatorKind.Minus, TypeSymbol.MObject),
};
public BoundUnaryOperator(TokenKind syntaxKind, BoundUnaryOperatorKind kind)
public BoundUnaryOperator(TokenKind syntaxKind, BoundUnaryOperatorKind kind, TypeSymbol type)
{
SyntaxKind = syntaxKind;
Kind = kind;
Operand = type;
Result = type;
}
public BoundUnaryOperator(TokenKind syntaxKind, BoundUnaryOperatorKind kind, TypeSymbol operand, TypeSymbol result)
{
SyntaxKind = syntaxKind;
Kind = kind;
Operand = operand;
Result = result;
}
public TokenKind SyntaxKind { get; }
public BoundUnaryOperatorKind Kind { get; }
public TypeSymbol Operand { get; }
public TypeSymbol Result { get; }
internal static BoundUnaryOperator? GetOperator(TokenKind kind)
internal static BoundUnaryOperator? GetOperator(TokenKind kind, TypeSymbol operand)
{
return _operators.FirstOrDefault(op => op.SyntaxKind == kind);
return _specificOperators.FirstOrDefault(op => op.SyntaxKind == kind && op.Operand == operand)
?? _defaultOperators.FirstOrDefault(op => op.SyntaxKind == kind);
}
}
}

View File

@ -0,0 +1,34 @@
namespace Parser.Binding
{
internal class Conversion
{
public static Conversion None = new Conversion(exists: false, isIdentity: false);
public static Conversion Identity = new Conversion(exists: true, isIdentity: true);
public static Conversion Implicit = new Conversion(exists: true, isIdentity: false);
private Conversion(bool exists, bool isIdentity)
{
Exists = exists;
IsIdentity = isIdentity;
}
public bool Exists { get; }
public bool IsIdentity { get; }
public static Conversion Classify(TypeSymbol from, TypeSymbol to)
{
if (from == to)
{
return Identity;
}
if (to == TypeSymbol.MObject)
{
return Implicit;
}
return None;
}
}
}

View File

@ -0,0 +1,26 @@
namespace Parser.Binding
{
public class TypeSymbol
{
public static readonly TypeSymbol Error = new TypeSymbol("error");
public static readonly TypeSymbol Null = new TypeSymbol("null");
public static readonly TypeSymbol Boolean = new TypeSymbol("bool");
public static readonly TypeSymbol Double = new TypeSymbol("double");
public static readonly TypeSymbol Int = new TypeSymbol("int");
public static readonly TypeSymbol String = new TypeSymbol("string");
public static readonly TypeSymbol MObject = new TypeSymbol("mobject");
public static readonly TypeSymbol Void = new TypeSymbol("void");
private TypeSymbol(string name)
{
Name = name;
}
public string Name { get; }
public override string ToString()
{
return Name;
}
}
}

View File

@ -0,0 +1,23 @@
using System.Collections.Immutable;
namespace Parser.Binding
{
public class TypedFunctionSymbol
{
public TypedFunctionSymbol(
string name,
ImmutableArray<TypedParameterSymbol> parameters,
TypeSymbol returnType)
{
Name = name;
Parameters = parameters;
ReturnType = returnType;
}
public string Name { get; }
public ImmutableArray<TypedParameterSymbol> Parameters { get; }
public TypeSymbol ReturnType { get; }
}
}

View File

@ -0,0 +1,14 @@
namespace Parser.Binding
{
public class TypedParameterSymbol
{
public TypedParameterSymbol(string name, TypeSymbol type)
{
Name = name;
Type = type;
}
public string Name { get; }
public TypeSymbol Type { get; }
}
}

View File

@ -0,0 +1,15 @@
namespace Parser.Binding
{
public class TypedVariableSymbol
{
public TypedVariableSymbol(string name, TypeSymbol type)
{
Name = name;
Type = type;
}
public string Name { get; }
public TypeSymbol Type { get; }
}
}

View File

@ -4,20 +4,34 @@ using Mono.Cecil.Rocks;
using Parser.Binding;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
namespace Parser.Emitting
{
public static class BuiltInFunctions
{
public static readonly TypedFunctionSymbol Disp = new TypedFunctionSymbol(
"disp",
ImmutableArray.Create(
new TypedParameterSymbol("text", TypeSymbol.MObject)),
TypeSymbol.Void);
}
public class Emitter
{
private Dictionary<string, TypeReference> _knownTypes = new Dictionary<string, TypeReference>();
private Dictionary<TypeSymbol, TypeReference> _resolvedTypes = new Dictionary<TypeSymbol, TypeReference>();
private Dictionary<string, MethodInterfaceDescription> _functions = new Dictionary<string, MethodInterfaceDescription>();
private MethodReference? _consoleWriteLineReference;
private MethodReference? _dispReference;
private MethodReference? _lenReference;
private MethodReference? _arraySliceReference;
private MethodReference? _mObjectToBool;
private MethodReference? _stringToMObject;
private MethodReference? _doubleToMObject;
private MethodReference? _intToMObject;
private MethodReference? _getItemFromDictionary;
private MethodReference? _putItemIntoDictionary;
private TypeReference? _mObjectType;
@ -30,6 +44,8 @@ namespace Parser.Emitting
private Dictionary<BoundUnaryOperatorKind, MethodReference> _unaryOperations = new Dictionary<BoundUnaryOperatorKind, MethodReference>();
private Dictionary<BoundLabel, int> _labels = new Dictionary<BoundLabel, int>();
private Dictionary<int, BoundLabel> _forwardLabelsToFix = new Dictionary<int, BoundLabel>();
private Dictionary<TypedVariableSymbol, VariableDefinition> _typedLocals = new Dictionary<TypedVariableSymbol, VariableDefinition>();
private Dictionary<TypedFunctionSymbol, MethodReference> _builtInFunctions = new Dictionary<TypedFunctionSymbol, MethodReference>();
private static TypeReference ResolveAndImportType(
string typeName,
@ -132,6 +148,7 @@ namespace Parser.Emitting
kind: ModuleKind.Console);
var builtInTypes = new[]
{
"System.Int32",
"System.Object",
"System.Void",
"System.String",
@ -139,6 +156,12 @@ namespace Parser.Emitting
"Parser.Objects.MObject"
};
var typeSymbolToKnownType = new Dictionary<TypeSymbol, string>
{
[TypeSymbol.Int] = "System.Int32",
[TypeSymbol.MObject] = "Parser.Objects.MObject",
};
// Resolve built-in types and methods.
foreach (var typeName in builtInTypes)
{
@ -146,6 +169,11 @@ namespace Parser.Emitting
_knownTypes.Add(typeName, typeReference);
}
foreach (var (typeSymbol, knownTypeName) in typeSymbolToKnownType)
{
_resolvedTypes.Add(typeSymbol, _knownTypes[knownTypeName]);
}
var objectType = _knownTypes["System.Object"];
var voidType = _knownTypes["System.Void"];
var stringType = _knownTypes["System.String"];
@ -192,6 +220,20 @@ namespace Parser.Emitting
assemblies: assemblies,
assemblyDefinition: assemblyDefinition);
_lenReference = ResolveAndImportMethod(
typeName: "Parser.MFunctions.MHelpers",
methodName: "Len",
parameterTypeNames: new[] { "Parser.Objects.MObject" },
assemblies: assemblies,
assemblyDefinition: assemblyDefinition);
_arraySliceReference = ResolveAndImportMethod(
typeName: "Parser.MFunctions.MOperations",
methodName: "ArraySlice",
parameterTypeNames: new[] { "Parser.Objects.MObject", "Parser.Objects.MObject" },
assemblies: assemblies,
assemblyDefinition: assemblyDefinition);
_mObjectToBool = ResolveAndImportMethod(
typeName: "Parser.MFunctions.MHelpers",
methodName: "ToBool",
@ -213,8 +255,16 @@ namespace Parser.Emitting
assemblies: assemblies,
assemblyDefinition: assemblyDefinition);
_intToMObject = ResolveAndImportMethod(
typeName: "Parser.Objects.MObject",
methodName: "CreateIntNumber",
parameterTypeNames: new[] { "System.Int32" },
assemblies: assemblies,
assemblyDefinition: assemblyDefinition);
var binaryOperationNames = new Dictionary<BoundBinaryOperatorKind, string>
{
[BoundBinaryOperatorKind.Colon] = "Colon",
[BoundBinaryOperatorKind.Plus] = "Plus",
[BoundBinaryOperatorKind.Minus] = "Minus",
[BoundBinaryOperatorKind.Star] = "Star",
@ -230,6 +280,10 @@ namespace Parser.Emitting
[BoundUnaryOperatorKind.Minus] = "Minus",
};
_builtInFunctions.Add(
BuiltInFunctions.Disp,
_dispReference);
foreach (var (op, opName) in binaryOperationNames)
{
_binaryOperations[op] = ResolveAndImportMethod(
@ -306,10 +360,12 @@ namespace Parser.Emitting
private void EmitFunction(LoweredFunction function, MethodDefinition methodDefinition)
{
Console.WriteLine($"Emitting function '{function.Name}'.");
var ilProcessor = methodDefinition.Body.GetILProcessor();
_labels.Clear();
_forwardLabelsToFix.Clear();
_typedLocals.Clear();
// Local #0 is the dictionary with actual local variables.
_currentLocals = new VariableDefinition(_stringMObjectDictionary);
@ -356,13 +412,16 @@ namespace Parser.Emitting
}
}
ilProcessor.Emit(OpCodes.Ret);
foreach (var (index, target) in _forwardLabelsToFix)
{
var targetIndex = _labels[target];
ilProcessor.Body.Instructions[index].Operand = ilProcessor.Body.Instructions[targetIndex];
var left = ilProcessor.Body.Instructions[index];
var right = ilProcessor.Body.Instructions[targetIndex];
left.Operand = right;
}
ilProcessor.Emit(OpCodes.Ret);
}
private void EmitBlockStatement(BoundBlockStatement block, MethodDefinition methodDefinition)
@ -431,11 +490,25 @@ namespace Parser.Emitting
case BoundNodeKind.ExpressionStatement:
EmitExpressionStatement((BoundExpressionStatement)node, ilProcessor);
break;
case BoundNodeKind.TypedVariableDeclaration:
EmitTypedVariableDeclaration((BoundTypedVariableDeclaration)node, ilProcessor);
break;
default:
throw new NotImplementedException($"Invalid statement kind '{node.Kind}'.");
};
}
private void EmitTypedVariableDeclaration(BoundTypedVariableDeclaration node, ILProcessor ilProcessor)
{
var typeReference = _resolvedTypes[node.Variable.Type];
var variableDefinition = new VariableDefinition(typeReference);
_typedLocals.Add(node.Variable, variableDefinition);
ilProcessor.Body.Variables.Add(variableDefinition);
EmitExpression(node.Initializer, ilProcessor);
ilProcessor.Emit(OpCodes.Stloc, variableDefinition);
}
private void EmitExpressionStatement(BoundExpressionStatement node, ILProcessor ilProcessor)
{
EmitExpression(node.Expression, ilProcessor);
@ -458,6 +531,9 @@ namespace Parser.Emitting
case BoundNodeKind.BinaryOperationExpression:
EmitBinaryOperationExpression((BoundBinaryOperationExpression)node, ilProcessor);
break;
case BoundNodeKind.ConversionExpression:
EmitConversionExpression((BoundConversionExpression)node, ilProcessor);
break;
case BoundNodeKind.FunctionCallExpression:
EmitFunctionCallExpression((BoundFunctionCallExpression)node, ilProcessor);
break;
@ -465,16 +541,47 @@ namespace Parser.Emitting
EmitIdentifierNameExpression((BoundIdentifierNameExpression)node, ilProcessor);
break;
case BoundNodeKind.NumberLiteralExpression:
EmitNumberLiteralExpression((BoundNumberLiteralExpression)node, ilProcessor);
EmitNumberLiteralExpression((BoundNumberDoubleLiteralExpression)node, ilProcessor);
break;
case BoundNodeKind.StringLiteralExpression:
EmitStringLiteralExpression((BoundStringLiteralExpression)node, ilProcessor);
break;
case BoundNodeKind.TypedFunctionCallExpression:
EmitTypedFunctionCallExpression((BoundTypedFunctionCallExpression)node, ilProcessor);
break;
case BoundNodeKind.TypedVariableExpression:
EmitTypedVariableExpression((BoundTypedVariableExpression)node, ilProcessor);
break;
default:
throw new NotImplementedException($"Invalid node kind '{node.Kind}'.");
}
}
private void EmitConversionExpression(BoundConversionExpression node, ILProcessor ilProcessor)
{
var fromType = node.Expression.Type;
var toType = node.TargetType;
EmitExpression(node.Expression, ilProcessor);
if ((fromType, toType) == (TypeSymbol.Double, TypeSymbol.MObject))
{
ilProcessor.Emit(OpCodes.Call, _doubleToMObject);
}
else if ((fromType, toType) == (TypeSymbol.String, TypeSymbol.MObject))
{
ilProcessor.Emit(OpCodes.Call, _stringToMObject);
}
else
{
throw new NotImplementedException($"Conversion of '{fromType}' to '{toType}' is not implemented.");
}
}
private void EmitTypedVariableExpression(BoundTypedVariableExpression node, ILProcessor ilProcessor)
{
var variableDefinition = _typedLocals[node.Variable];
ilProcessor.Emit(OpCodes.Ldloc, variableDefinition);
}
private void EmitBinaryOperationExpression(BoundBinaryOperationExpression node, ILProcessor ilProcessor)
{
var method = _binaryOperations[node.Op.Kind];
@ -485,19 +592,39 @@ namespace Parser.Emitting
private void EmitAssignmentExpression(BoundAssignmentExpression node, ILProcessor ilProcessor)
{
if (node.Left.Kind != BoundNodeKind.IdentifierNameExpression)
var leftType = node.Left.Kind switch
{
BoundNodeKind.IdentifierNameExpression => TypeSymbol.MObject,
BoundNodeKind.TypedVariableExpression => ((BoundTypedVariableExpression)node.Left).Type,
_ => throw new Exception($"Assignment to lvalue of kind {node.Left.Kind} is not supported."),
};
var rightType = node.Right.Type;
var rewrittenRight = ConvertExpression(node.Right, leftType);
if (node.Left.Kind == BoundNodeKind.IdentifierNameExpression)
{
throw new Exception("Assignment to complex lvalues is not supported.");
}
var left = ((BoundIdentifierNameExpression)node.Left);
ilProcessor.Emit(OpCodes.Ldloc_0);
ilProcessor.Emit(OpCodes.Ldstr, left.Name);
EmitExpression(node.Right, ilProcessor);
EmitExpression(rewrittenRight, ilProcessor);
ilProcessor.Emit(OpCodes.Callvirt, _putItemIntoDictionary);
ilProcessor.Emit(OpCodes.Ldloc_0);
ilProcessor.Emit(OpCodes.Ldstr, left.Name);
ilProcessor.Emit(OpCodes.Callvirt, _getItemFromDictionary);
}
else if (node.Left.Kind == BoundNodeKind.TypedVariableExpression)
{
var typedVariableExpression = (BoundTypedVariableExpression)node.Left;
EmitExpression(rewrittenRight, ilProcessor);
ilProcessor.Emit(OpCodes.Stloc, _typedLocals[typedVariableExpression.Variable]);
}
else
{
throw new Exception($"Assignment to lvalue of kind {node.Left.Kind} is not supported.");
}
}
private void EmitIdentifierNameExpression(BoundIdentifierNameExpression node, ILProcessor ilProcessor)
{
@ -506,26 +633,109 @@ namespace Parser.Emitting
ilProcessor.Emit(OpCodes.Callvirt, _getItemFromDictionary);
}
private void EmitNumberLiteralExpression(BoundNumberLiteralExpression node, ILProcessor ilProcessor)
private void EmitNumberLiteralExpression(BoundNumberDoubleLiteralExpression node, ILProcessor ilProcessor)
{
ilProcessor.Emit(OpCodes.Ldc_R8, node.Value);
ilProcessor.Emit(OpCodes.Call, _doubleToMObject);
}
private void EmitStringLiteralExpression(BoundStringLiteralExpression node, ILProcessor ilProcessor)
{
ilProcessor.Emit(OpCodes.Ldstr, node.Value);
ilProcessor.Emit(OpCodes.Call, _stringToMObject);
}
private BoundExpression? ConvertExpression(BoundExpression expression, TypeSymbol targetType)
{
var conversion = Conversion.Classify(expression.Type, targetType);
if (!conversion.Exists)
{
return null;
}
if (conversion.IsIdentity)
{
return expression;
}
else
{
return BoundNodeFactory.Conversion(expression.Syntax, targetType, expression);
}
}
private BoundExpression RewriteFunctionCall(BoundFunctionCallExpression node, TypedFunctionSymbol function)
{
var numberOfArguments = node.Arguments.Length;
if (numberOfArguments != function.Parameters.Length)
{
throw new NotImplementedException($"Function '{function.Name}' expected {function.Parameters.Length} arguments, but was called with {numberOfArguments}.");
}
var rewrittenArguments = ImmutableArray.CreateBuilder<BoundExpression>(numberOfArguments);
for (var i = 0; i < numberOfArguments; i++)
{
var argument = node.Arguments[i];
var parameter = function.Parameters[i];
var rewrittenArgument = ConvertExpression(argument, parameter.Type);
if (rewrittenArgument is null)
{
throw new NotImplementedException($"Argument number {i + 1} of function '{function.Name}' expects {parameter.Type}, but got {argument.Type}, and no conversion exists.");
}
rewrittenArguments.Add(rewrittenArgument);
}
return BoundNodeFactory.TypedFunctionCall(node.Syntax, function, rewrittenArguments.MoveToImmutable());
}
private void EmitTypedFunctionCallExpression(BoundTypedFunctionCallExpression node, ILProcessor ilProcessor)
{
var function = _builtInFunctions[node.Function];
foreach (var argument in node.Arguments)
{
EmitExpression(argument, ilProcessor);
}
ilProcessor.Emit(OpCodes.Call, function);
if (node.Function.ReturnType == TypeSymbol.Void)
{
ilProcessor.Emit(OpCodes.Ldnull);
}
else if (node.Function.ReturnType == TypeSymbol.MObject)
{
}
else
{
throw new Exception("Don't know how to cast function output.");
}
}
private void EmitFunctionCallExpression(BoundFunctionCallExpression node, ILProcessor ilProcessor)
{
if (node.Name.Kind == BoundNodeKind.IdentifierNameExpression
&& ((BoundIdentifierNameExpression)node.Name).Name == "disp")
{
var dispFunctionSymbol = BuiltInFunctions.Disp;
var rewrittenCall = RewriteFunctionCall(node, dispFunctionSymbol);
EmitExpression(rewrittenCall, ilProcessor);
//ilProcessor.Emit(OpCodes.Call, _dispReference);
//ilProcessor.Emit(OpCodes.Ldnull);
} else if (node.Name.Kind == BoundNodeKind.IdentifierNameExpression
&& ((BoundIdentifierNameExpression)node.Name).Name == "len")
{
EmitExpression(node.Arguments[0], ilProcessor);
ilProcessor.Emit(OpCodes.Call, _dispReference);
ilProcessor.Emit(OpCodes.Ldnull);
ilProcessor.Emit(OpCodes.Call, _lenReference);
}
else if (node.Name.Kind == BoundNodeKind.TypedVariableExpression)
{
if (node.Arguments.Length > 1)
{
throw new Exception("Multi-dimensional array slicing is not supported.");
}
var typedVariableExpression = (BoundTypedVariableExpression)node.Name;
EmitTypedVariableExpression(typedVariableExpression, ilProcessor);
EmitExpression(node.Arguments[0], ilProcessor);
ilProcessor.Emit(OpCodes.Call, _arraySliceReference);
}
else
{
@ -559,11 +769,11 @@ namespace Parser.Emitting
}
}
private MethodInterfaceDescription ResolveFunction(BoundExpression expression)
private MethodInterfaceDescription ResolveFunction(BoundExpression node)
{
if (expression.Kind == BoundNodeKind.IdentifierNameExpression)
if (node.Kind == BoundNodeKind.IdentifierNameExpression)
{
var name = ((BoundIdentifierNameExpression)expression).Name;
var name = ((BoundIdentifierNameExpression)node).Name;
if (_functions.TryGetValue(name, out var result))
{
return result;
@ -574,7 +784,7 @@ namespace Parser.Emitting
}
else
{
throw new NotImplementedException($"Dynamic functions calling not supported. Failed to resolve function call expression with kind '{expression.Kind}'.");
throw new NotImplementedException($"Dynamic functions calling not supported. Failed to resolve function call expression with kind '{node.Kind}'.");
}
}
}

View File

@ -251,7 +251,7 @@ namespace Parser
BoundNodeKind.NamedFunctionHandleExpression =>
EvaluateNamedFunctionHandleExpression((BoundNamedFunctionHandleExpression)node),
BoundNodeKind.NumberLiteralExpression =>
EvaluateNumberLiteralExpression((BoundNumberLiteralExpression)node),
EvaluateNumberLiteralExpression((BoundNumberDoubleLiteralExpression)node),
BoundNodeKind.StringLiteralExpression =>
EvaluateStringLiteralExpression((BoundStringLiteralExpression)node),
BoundNodeKind.UnaryOperationExpression =>
@ -420,7 +420,7 @@ namespace Parser
};
}
private MObject? EvaluateNumberLiteralExpression(BoundNumberLiteralExpression node)
private MObject? EvaluateNumberLiteralExpression(BoundNumberDoubleLiteralExpression node)
{
return MObject.CreateDoubleNumber(node.Value);
}

View File

@ -107,5 +107,10 @@ namespace Parser.Internal
{
Report(span, $"Too many inputs in the call to '{functionName}'.");
}
internal void ReportForLoopWithoutVariable(TextSpan span)
{
Report(span, $"A 'for' loop must have a loop variable.");
}
}
}

View File

@ -1,5 +1,4 @@
using Parser.Binding;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
@ -10,6 +9,7 @@ namespace Parser.Lowering
internal class Lowerer : BoundTreeRewriter
{
private int _labelNumber = 0;
private int _localVariableNumber = 0;
private Lowerer()
{
@ -21,6 +21,12 @@ namespace Parser.Lowering
return new BoundLabel(name);
}
private TypedVariableSymbol GenerateTypedLocalVariable(TypeSymbol typeSymbol)
{
var name = $"#{++_localVariableNumber}";
return new TypedVariableSymbol(name, typeSymbol);
}
public override BoundStatement RewriteIfStatement(BoundIfStatement node)
{
// if cond
@ -80,6 +86,84 @@ namespace Parser.Lowering
return RewriteBlockStatement(Block(node.Syntax, builder.ToArray()));
}
public override BoundStatement RewriteForStatement(BoundForStatement node)
{
// for i = expr
// body
// end
//
// #array = expr
// #length = len(#array)
// #index = 0
// i = #array(#index);
// LabelLoop:
// gotoFalse (#index < #length) LabelEnd
// body
// #index = #index + 1
// goto LabelLoop
// LabelEnd:
var builder = ImmutableArray.CreateBuilder<BoundStatement>();
var labelLoop = GenerateLabel();
var labelEnd = GenerateLabel();
var localArray = GenerateTypedLocalVariable(TypeSymbol.MObject);
var localLength = GenerateTypedLocalVariable(TypeSymbol.Int);
var localIndex = GenerateTypedLocalVariable(TypeSymbol.Int);
return RewriteBlockStatement(Block(
node.Syntax,
// #array = expr
TypedVariableDeclaration(node.Syntax, localArray, node.LoopedExpression),
// #length = len(#array)
TypedVariableDeclaration(
node.Syntax,
localLength,
FunctionCall(
node.Syntax,
Identifier(node.Syntax, "len"),
new[] { (BoundExpression)TypedVariableExpression(node.Syntax, localArray) }.ToImmutableArray())),
// #index = 0
TypedVariableDeclaration(node.Syntax, localIndex, NumberDoubleLiteral(node.Syntax, 0.0)),
// i = #array(#index);
ExpressionStatement(
node.Syntax,
Assignment(
node.Syntax,
node.LoopVariable,
FunctionCall(
node.Syntax,
TypedVariableExpression(node.Syntax, localArray),
new[] { (BoundExpression)TypedVariableExpression(node.Syntax, localIndex) }.ToImmutableArray())),
discardResult: true),
// LabelLoop:
LabelStatement(node.Syntax, labelLoop),
// gotoFalse (#index < #length) LabelEnd
GotoIfFalse(
node.Syntax,
BinaryOperation(
node.Syntax,
TypedVariableExpression(node.Syntax, localIndex),
BoundBinaryOperator.GetOperator(TokenKind.LessToken, TypeSymbol.Int, TypeSymbol.Int)!,
TypedVariableExpression(node.Syntax, localLength)),
labelEnd),
// body
node.Body,
// #index = #index + 1;
ExpressionStatement(
node.Syntax,
Assignment(
node.Syntax,
TypedVariableExpression(node.Syntax, localIndex),
BinaryOperation(
node.Syntax,
TypedVariableExpression(node.Syntax, localIndex),
BoundBinaryOperator.GetOperator(TokenKind.PlusToken, TypeSymbol.Int, TypeSymbol.Int)!,
NumberIntLiteral(node.Syntax, 1))),
discardResult: true),
// goto LabelLoop
Goto(node.Syntax, labelLoop),
// LabelEnd:
LabelStatement(node.Syntax, labelEnd)));
}
public static BoundBlockStatement Lower(BoundStatement statement)
{
var lowerer = new Lowerer();

View File

@ -13,6 +13,18 @@ namespace Parser.MFunctions
}
}
public static int Len(MObject? obj)
{
return obj switch
{
MDoubleMatrix m => m.RowCount * m.ColumnCount,
MDoubleNumber _ => 1,
MLogical _ => 1,
MCharArray c => c.Chars.Length,
_ => throw new System.Exception($"Unknown MObject type {obj.GetType()}"),
};
}
public static bool ToBool(MObject operand)
{
return operand switch
@ -20,6 +32,7 @@ namespace Parser.MFunctions
MDoubleNumber { Value: var value } => value != 0.0,
MLogical { Value: var value } => value,
MCharArray { Chars: var value } => value.Length > 0,
MDoubleMatrix m => m.RowCount > 0 && m.ColumnCount > 0,
_ => throw new System.Exception($"Unknown MObject type {operand.GetType()}"),
};
}

View File

@ -1,9 +1,34 @@
using Parser.Objects;
using System;
namespace Parser.MFunctions
{
public static class MOperations
{
public static MObject? Colon(MObject left, MObject right)
{
if (left is MDoubleNumber { Value: var lValue }
&& right is MDoubleNumber { Value: var rValue })
{
var array = CreateRangeMatrix(lValue, rValue);
return MObject.CreateDoubleMatrix(array);
}
return null;
}
private static double[,] CreateRangeMatrix(double lValue, double rValue)
{
var length = (int)Math.Round(rValue - lValue) + 1;
var result = new double[1, length];
for (var i = 0; i < length; i++)
{
result[0, i] = lValue + i;
}
return result;
}
public static MObject? Plus(MObject left, MObject right)
{
if (left is MDoubleNumber { Value: var lValue }
@ -101,5 +126,17 @@ namespace Parser.MFunctions
return null;
}
public static MObject? ArraySlice(MObject array, MObject range)
{
if (array is MDoubleMatrix m
&& range is MDoubleNumber { Value: var doubleIndex })
{
var index = (int)doubleIndex;
return MObject.CreateDoubleNumber(m[index]);
}
return null;
}
}
}

View File

@ -1,7 +1,50 @@
using System.Globalization;
using System.Text;
namespace Parser.Objects
{
public class MDoubleMatrix : MObject
{
private MDoubleMatrix(double[,] matrix)
{
Matrix = matrix;
}
public double[,] Matrix { get; }
public int RowCount { get; }
public int ColumnCount { get; }
public ref double this[int i, int j] => ref Matrix[i, j];
public ref double this[int i] => ref Matrix[i % RowCount, i / RowCount];
public override string ToString()
{
var sb = new StringBuilder();
for (var i = 0; i < RowCount; i++)
{
for (var j = 0; j < ColumnCount; j++)
{
if (j > 0)
{
sb.Append(' ');
}
sb.Append(Matrix[i, j]);
}
sb.AppendLine();
}
return sb.ToString();
}
public static MDoubleMatrix Create(double[,] matrix)
{
return new MDoubleMatrix(matrix);
}
}
public class MDoubleNumber : MObject
{
private MDoubleNumber(double value)

View File

@ -1,4 +1,6 @@
namespace Parser.Objects
using System;
namespace Parser.Objects
{
public abstract class MObject
{
@ -7,6 +9,16 @@
return MDoubleNumber.Create(value);
}
public static MDoubleNumber CreateIntNumber(int value)
{
return MDoubleNumber.Create(value);
}
public static MDoubleMatrix CreateDoubleMatrix(double[,] matrix)
{
return MDoubleMatrix.Create(matrix);
}
public static MCharArray CreateCharArray(char[] chars)
{
return MCharArray.Create(chars);

View File

@ -5,6 +5,11 @@ f(x);
x = 3;
f(x);
% for i = 1:10
% disp(i);
% end
function f(x)
disp('X was');
disp(x);