More types
This commit is contained in:
parent
3f494cef6d
commit
3bc8ef0d7d
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
34
Parser/Binding/Conversion.cs
Normal file
34
Parser/Binding/Conversion.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
26
Parser/Binding/TypeSymbol.cs
Normal file
26
Parser/Binding/TypeSymbol.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
23
Parser/Binding/TypedFunctionSymbol.cs
Normal file
23
Parser/Binding/TypedFunctionSymbol.cs
Normal 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; }
|
||||
}
|
||||
}
|
14
Parser/Binding/TypedParameterSymbol.cs
Normal file
14
Parser/Binding/TypedParameterSymbol.cs
Normal 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; }
|
||||
}
|
||||
}
|
15
Parser/Binding/TypedVariableSymbol.cs
Normal file
15
Parser/Binding/TypedVariableSymbol.cs
Normal 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; }
|
||||
}
|
||||
}
|
@ -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}'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
@ -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()}"),
|
||||
};
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user