Fix compiling
This commit is contained in:
parent
62713311cc
commit
c8025ff723
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Parser\Parser.csproj" />
|
<ProjectReference Include="..\Parser\Parser.csproj" />
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<LangVersion>8.0</LangVersion>
|
<LangVersion>8.0</LangVersion>
|
||||||
|
@ -13,24 +13,33 @@ namespace Parser.Binding
|
|||||||
{
|
{
|
||||||
private readonly DiagnosticsBag _diagnostics = new DiagnosticsBag();
|
private readonly DiagnosticsBag _diagnostics = new DiagnosticsBag();
|
||||||
|
|
||||||
public static BoundProgram BindProgram(SyntaxTree syntaxTree)
|
private BoundProgram? BindProgramInternal(SyntaxTree syntaxTree)
|
||||||
{
|
{
|
||||||
var binder = new Binder();
|
var boundRoot = BindRoot(syntaxTree.NullRoot);
|
||||||
var boundRoot = binder.BindRoot(syntaxTree.NullRoot);
|
|
||||||
var statements = ((BoundBlockStatement)boundRoot.File.Body).Statements;
|
var statements = ((BoundBlockStatement)boundRoot.File.Body).Statements;
|
||||||
var functionsBuilder = ImmutableDictionary.CreateBuilder<FunctionSymbol, LoweredFunction>();
|
var functionsBuilder = ImmutableDictionary.CreateBuilder<FunctionSymbol, LoweredFunction>();
|
||||||
var globalStatements = statements.Where(s => s.Kind != BoundNodeKind.FunctionDeclaration).ToArray();
|
var globalStatements = statements.Where(s => s.Kind != BoundNodeKind.FunctionDeclaration).ToArray();
|
||||||
var mainFunction = (FunctionSymbol?)null;
|
var mainFunction = (FunctionSymbol?)null;
|
||||||
var scriptFunction = (FunctionSymbol?)null;
|
var scriptFunction = (FunctionSymbol?)null;
|
||||||
|
var functions = statements.OfType<BoundFunctionDeclaration>().ToArray();
|
||||||
if (globalStatements.Length > 0)
|
if (globalStatements.Length > 0)
|
||||||
{
|
{
|
||||||
// we have to gather all bound expression statements into a "script" function.
|
// we have to gather all bound expression statements into a "Main" function.
|
||||||
scriptFunction = new FunctionSymbol("%script");
|
scriptFunction = new FunctionSymbol("Main");
|
||||||
|
foreach (var f in functions) {
|
||||||
|
if (f.Name == "Main")
|
||||||
|
{
|
||||||
|
_diagnostics.ReportMainIsNotAllowed(
|
||||||
|
new TextSpan(f.Syntax.Position, f.Syntax.FullWidth));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var body = Block(globalStatements[0].Syntax, globalStatements);
|
var body = Block(globalStatements[0].Syntax, globalStatements);
|
||||||
var loweredBody = Lowerer.Lower(body);
|
var loweredBody = Lowerer.Lower(body);
|
||||||
var declaration = new BoundFunctionDeclaration(
|
var declaration = new BoundFunctionDeclaration(
|
||||||
syntax: globalStatements[0].Syntax,
|
syntax: globalStatements[0].Syntax,
|
||||||
name: "%script",
|
name: "Main",
|
||||||
inputDescription: ImmutableArray<ParameterSymbol>.Empty,
|
inputDescription: ImmutableArray<ParameterSymbol>.Empty,
|
||||||
outputDescription: ImmutableArray<ParameterSymbol>.Empty,
|
outputDescription: ImmutableArray<ParameterSymbol>.Empty,
|
||||||
body: body);
|
body: body);
|
||||||
@ -38,7 +47,7 @@ namespace Parser.Binding
|
|||||||
functionsBuilder.Add(scriptFunction, loweredFunction);
|
functionsBuilder.Add(scriptFunction, loweredFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
var functions = statements.OfType<BoundFunctionDeclaration>().ToArray();
|
|
||||||
var first = true;
|
var first = true;
|
||||||
foreach (var function in functions)
|
foreach (var function in functions)
|
||||||
{
|
{
|
||||||
@ -55,12 +64,18 @@ namespace Parser.Binding
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new BoundProgram(
|
return new BoundProgram(
|
||||||
binder._diagnostics.ToImmutableArray(),
|
_diagnostics.ToImmutableArray(),
|
||||||
mainFunction,
|
mainFunction,
|
||||||
scriptFunction,
|
scriptFunction,
|
||||||
functionsBuilder.ToImmutable());
|
functionsBuilder.ToImmutable());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BoundProgram? BindProgram(SyntaxTree syntaxTree)
|
||||||
|
{
|
||||||
|
var binder = new Binder();
|
||||||
|
return binder.BindProgramInternal(syntaxTree);
|
||||||
|
}
|
||||||
|
|
||||||
private static LoweredFunction LowerFunction(BoundFunctionDeclaration declaration)
|
private static LoweredFunction LowerFunction(BoundFunctionDeclaration declaration)
|
||||||
{
|
{
|
||||||
var loweredBody = Lowerer.Lower(declaration.Body);
|
var loweredBody = Lowerer.Lower(declaration.Body);
|
||||||
|
@ -1,16 +1,49 @@
|
|||||||
using Mono.Cecil;
|
using Mono.Cecil;
|
||||||
using Mono.Cecil.Cil;
|
using Mono.Cecil.Cil;
|
||||||
|
using Mono.Cecil.Rocks;
|
||||||
using Parser.Binding;
|
using Parser.Binding;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Parser.Emitting
|
namespace Parser.Emitting
|
||||||
{
|
{
|
||||||
|
public class MethodInterfaceDescription
|
||||||
|
{
|
||||||
|
public MethodInterfaceDescription(ImmutableArray<ParameterSymbol> inputDescription, ImmutableArray<ParameterSymbol> outputDescription, MethodDefinition method)
|
||||||
|
{
|
||||||
|
InputDescription = inputDescription;
|
||||||
|
OutputDescription = outputDescription;
|
||||||
|
Method = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImmutableArray<ParameterSymbol> InputDescription { get; }
|
||||||
|
|
||||||
|
public ImmutableArray<ParameterSymbol> OutputDescription { get; }
|
||||||
|
|
||||||
|
public MethodDefinition Method { get; }
|
||||||
|
}
|
||||||
|
|
||||||
public class Emitter
|
public class Emitter
|
||||||
{
|
{
|
||||||
private Dictionary<string, TypeReference> _knownTypes = new Dictionary<string, TypeReference>();
|
private Dictionary<string, TypeReference> _knownTypes = new Dictionary<string, TypeReference>();
|
||||||
|
private Dictionary<string, MethodInterfaceDescription> _functions = new Dictionary<string, MethodInterfaceDescription>();
|
||||||
|
private MethodReference? _consoleWriteLineReference;
|
||||||
|
private MethodReference? _dispReference;
|
||||||
|
private MethodReference? _stringToMObject;
|
||||||
|
private MethodReference? _doubleToMObject;
|
||||||
|
private MethodReference? _getItemFromDictionary;
|
||||||
|
private MethodReference? _putItemIntoDictionary;
|
||||||
|
private TypeReference? _mObjectType;
|
||||||
|
private ArrayType? _mObjectArrayType;
|
||||||
|
private Dictionary<string, VariableDefinition> _currentOutputVariables = new Dictionary<string, VariableDefinition>();
|
||||||
|
private VariableDefinition? _currentLocals = null;
|
||||||
|
private TypeSpecification? _stringMObjectDictionary = null;
|
||||||
|
private MethodReference? _dictionaryCtorReference = null;
|
||||||
|
private Dictionary<BoundBinaryOperatorKind, MethodReference> _binaryOperations = new Dictionary<BoundBinaryOperatorKind, MethodReference>();
|
||||||
|
private Dictionary<BoundUnaryOperatorKind, MethodReference> _unaryOperations = new Dictionary<BoundUnaryOperatorKind, MethodReference>();
|
||||||
|
|
||||||
private static TypeReference ResolveAndImportType(
|
private static TypeReference ResolveAndImportType(
|
||||||
string typeName,
|
string typeName,
|
||||||
@ -114,7 +147,10 @@ namespace Parser.Emitting
|
|||||||
var builtInTypes = new[]
|
var builtInTypes = new[]
|
||||||
{
|
{
|
||||||
"System.Object",
|
"System.Object",
|
||||||
"System.Void"
|
"System.Void",
|
||||||
|
"System.String",
|
||||||
|
"System.Collections.Generic.Dictionary`2",
|
||||||
|
"Parser.Objects.MObject"
|
||||||
};
|
};
|
||||||
|
|
||||||
// Resolve built-in types and methods.
|
// Resolve built-in types and methods.
|
||||||
@ -126,14 +162,101 @@ namespace Parser.Emitting
|
|||||||
|
|
||||||
var objectType = _knownTypes["System.Object"];
|
var objectType = _knownTypes["System.Object"];
|
||||||
var voidType = _knownTypes["System.Void"];
|
var voidType = _knownTypes["System.Void"];
|
||||||
|
var stringType = _knownTypes["System.String"];
|
||||||
|
var dictionaryType = _knownTypes["System.Collections.Generic.Dictionary`2"];
|
||||||
|
_mObjectType = _knownTypes["Parser.Objects.MObject"];
|
||||||
|
_mObjectArrayType = _mObjectType.MakeArrayType();
|
||||||
|
var stringMObjectDictionary = new GenericInstanceType(dictionaryType);
|
||||||
|
stringMObjectDictionary.GenericArguments.Add(stringType);
|
||||||
|
stringMObjectDictionary.GenericArguments.Add(_mObjectType);
|
||||||
|
_stringMObjectDictionary = stringMObjectDictionary;
|
||||||
|
_dictionaryCtorReference = ResolveAndImportMethod(
|
||||||
|
typeName: "System.Collections.Generic.Dictionary`2",
|
||||||
|
methodName: ".ctor",
|
||||||
|
parameterTypeNames: Array.Empty<string>(),
|
||||||
|
assemblies: assemblies,
|
||||||
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
_dictionaryCtorReference.DeclaringType = _stringMObjectDictionary;
|
||||||
|
_getItemFromDictionary = ResolveAndImportMethod(
|
||||||
|
typeName: "System.Collections.Generic.Dictionary`2",
|
||||||
|
methodName: "get_Item",
|
||||||
|
parameterTypeNames: new[] { "TKey" },
|
||||||
|
assemblies: assemblies,
|
||||||
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
_getItemFromDictionary.DeclaringType = _stringMObjectDictionary;
|
||||||
|
_putItemIntoDictionary = ResolveAndImportMethod(
|
||||||
|
typeName: "System.Collections.Generic.Dictionary`2",
|
||||||
|
methodName: "set_Item",
|
||||||
|
parameterTypeNames: new[] { "TKey", "TValue" },
|
||||||
|
assemblies: assemblies,
|
||||||
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
_putItemIntoDictionary.DeclaringType = _stringMObjectDictionary;
|
||||||
|
|
||||||
var consoleWriteLineReference = ResolveAndImportMethod(
|
_consoleWriteLineReference = ResolveAndImportMethod(
|
||||||
typeName: "System.Console",
|
typeName: "System.Console",
|
||||||
methodName: "WriteLine",
|
methodName: "WriteLine",
|
||||||
parameterTypeNames: new[] { "System.Object" },
|
parameterTypeNames: new[] { "System.Object" },
|
||||||
assemblies: assemblies,
|
assemblies: assemblies,
|
||||||
assemblyDefinition: assemblyDefinition);
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
|
||||||
|
_dispReference = ResolveAndImportMethod(
|
||||||
|
typeName: "Parser.MFunctions.MHelpers",
|
||||||
|
methodName: "Disp",
|
||||||
|
parameterTypeNames: new[] { "Parser.Objects.MObject" },
|
||||||
|
assemblies: assemblies,
|
||||||
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
|
||||||
|
_stringToMObject = ResolveAndImportMethod(
|
||||||
|
typeName: "Parser.Objects.MObject",
|
||||||
|
methodName: "CreateCharArray",
|
||||||
|
parameterTypeNames: new[] { "System.String" },
|
||||||
|
assemblies: assemblies,
|
||||||
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
|
||||||
|
_doubleToMObject = ResolveAndImportMethod(
|
||||||
|
typeName: "Parser.Objects.MObject",
|
||||||
|
methodName: "CreateDoubleNumber",
|
||||||
|
parameterTypeNames: new[] { "System.Double" },
|
||||||
|
assemblies: assemblies,
|
||||||
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
|
||||||
|
var binaryOperationNames = new Dictionary<BoundBinaryOperatorKind, string>
|
||||||
|
{
|
||||||
|
[BoundBinaryOperatorKind.Plus] = "Plus",
|
||||||
|
[BoundBinaryOperatorKind.Minus] = "Minus",
|
||||||
|
[BoundBinaryOperatorKind.Star] = "Star",
|
||||||
|
[BoundBinaryOperatorKind.Slash] = "Slash",
|
||||||
|
[BoundBinaryOperatorKind.Greater] = "Greater",
|
||||||
|
[BoundBinaryOperatorKind.GreaterOrEquals] = "GreaterOrEquals",
|
||||||
|
[BoundBinaryOperatorKind.Less] = "Less",
|
||||||
|
[BoundBinaryOperatorKind.LessOrEquals] = "LessOrEquals",
|
||||||
|
};
|
||||||
|
|
||||||
|
var unaryOperationNames = new Dictionary<BoundUnaryOperatorKind, string>
|
||||||
|
{
|
||||||
|
[BoundUnaryOperatorKind.Minus] = "Minus",
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var (op, opName) in binaryOperationNames)
|
||||||
|
{
|
||||||
|
_binaryOperations[op] = ResolveAndImportMethod(
|
||||||
|
typeName: "Parser.MFunctions.MOperations",
|
||||||
|
methodName: opName,
|
||||||
|
parameterTypeNames: new[] { "Parser.Objects.MObject", "Parser.Objects.MObject" },
|
||||||
|
assemblies: assemblies,
|
||||||
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var (op, opName) in unaryOperationNames)
|
||||||
|
{
|
||||||
|
_unaryOperations[op] = ResolveAndImportMethod(
|
||||||
|
typeName: "Parser.MFunctions.MOperations",
|
||||||
|
methodName: opName,
|
||||||
|
parameterTypeNames: new[] { "Parser.Objects.MObject" },
|
||||||
|
assemblies: assemblies,
|
||||||
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
// Create type.
|
// Create type.
|
||||||
var typeDefinition = new TypeDefinition(
|
var typeDefinition = new TypeDefinition(
|
||||||
@namespace: "",
|
@namespace: "",
|
||||||
@ -142,20 +265,287 @@ namespace Parser.Emitting
|
|||||||
baseType: objectType);
|
baseType: objectType);
|
||||||
assemblyDefinition.MainModule.Types.Add(typeDefinition);
|
assemblyDefinition.MainModule.Types.Add(typeDefinition);
|
||||||
|
|
||||||
// Create method.
|
// Generate method definitions for all functions first.
|
||||||
var methodDefinition = new MethodDefinition(
|
foreach (var (name, body) in program.Functions)
|
||||||
name: "Main",
|
{
|
||||||
attributes: MethodAttributes.Static | MethodAttributes.Private,
|
var methodDefinition = new MethodDefinition(
|
||||||
returnType: voidType);
|
name: name.Name,
|
||||||
var ilProcessor = methodDefinition.Body.GetILProcessor();
|
attributes: MethodAttributes.Static | MethodAttributes.Private,
|
||||||
ilProcessor.Emit(OpCodes.Ldstr, "Hello world!");
|
returnType: body.OutputDescription.Length == 0 ? voidType : _mObjectArrayType);
|
||||||
ilProcessor.Emit(OpCodes.Call, consoleWriteLineReference);
|
if (body.InputDescription.Length > 0)
|
||||||
ilProcessor.Emit(OpCodes.Ret);
|
{
|
||||||
|
foreach (var inputDescription in body.InputDescription)
|
||||||
|
{
|
||||||
|
var parameter = new ParameterDefinition(
|
||||||
|
name: inputDescription.Name,
|
||||||
|
attributes: ParameterAttributes.None,
|
||||||
|
parameterType: _mObjectType);
|
||||||
|
methodDefinition.Parameters.Add(parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
typeDefinition.Methods.Add(methodDefinition);
|
_functions[name.Name] = new MethodInterfaceDescription(
|
||||||
assemblyDefinition.EntryPoint = methodDefinition;
|
inputDescription: body.InputDescription,
|
||||||
|
outputDescription: body.OutputDescription,
|
||||||
|
method: methodDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit functions.
|
||||||
|
foreach (var (name, body) in program.Functions)
|
||||||
|
{
|
||||||
|
var methodDefinition = _functions[name.Name];
|
||||||
|
EmitFunction(body, methodDefinition.Method);
|
||||||
|
typeDefinition.Methods.Add(methodDefinition.Method);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set entry point.
|
||||||
|
if (program.ScriptFunction is { } scriptFunction)
|
||||||
|
{
|
||||||
|
assemblyDefinition.EntryPoint = _functions[scriptFunction.Name].Method;
|
||||||
|
}
|
||||||
|
else if (program.MainFunction is { } mainFunction)
|
||||||
|
{
|
||||||
|
assemblyDefinition.EntryPoint = _functions[mainFunction.Name].Method;
|
||||||
|
}
|
||||||
|
|
||||||
assemblyDefinition.Write(outputFileName);
|
assemblyDefinition.Write(outputFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void EmitFunction(LoweredFunction function, MethodDefinition methodDefinition)
|
||||||
|
{
|
||||||
|
var ilProcessor = methodDefinition.Body.GetILProcessor();
|
||||||
|
|
||||||
|
// Local #0 is the dictionary with actual local variables.
|
||||||
|
_currentLocals = new VariableDefinition(_stringMObjectDictionary);
|
||||||
|
ilProcessor.Body.Variables.Add(_currentLocals);
|
||||||
|
ilProcessor.Emit(OpCodes.Newobj, _dictionaryCtorReference);
|
||||||
|
ilProcessor.Emit(OpCodes.Stloc_0);
|
||||||
|
var counter = 0;
|
||||||
|
foreach (var inputDescription in function.InputDescription)
|
||||||
|
{
|
||||||
|
var name = inputDescription.Name;
|
||||||
|
ilProcessor.Emit(OpCodes.Ldloc_0);
|
||||||
|
ilProcessor.Emit(OpCodes.Ldstr, name);
|
||||||
|
ilProcessor.Emit(OpCodes.Ldarg, methodDefinition.Parameters[counter]);
|
||||||
|
ilProcessor.Emit(OpCodes.Callvirt, _putItemIntoDictionary);
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following locals are "output variables".
|
||||||
|
_currentOutputVariables.Clear();
|
||||||
|
if (function.OutputDescription.Length > 0)
|
||||||
|
{
|
||||||
|
foreach (var outputDescription in function.OutputDescription)
|
||||||
|
{
|
||||||
|
var outputVariable = new VariableDefinition(_mObjectArrayType);
|
||||||
|
ilProcessor.Body.Variables.Add(outputVariable);
|
||||||
|
_currentOutputVariables.Add(outputDescription.Name, outputVariable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EmitBlockStatement(function.Body, methodDefinition);
|
||||||
|
|
||||||
|
// Copy output variables to the output array.
|
||||||
|
if (function.OutputDescription.Length > 0)
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Ldc_I4, function.OutputDescription.Length);
|
||||||
|
ilProcessor.Emit(OpCodes.Newarr, _mObjectType);
|
||||||
|
for (var i = 0; i < function.OutputDescription.Length; i++)
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Dup);
|
||||||
|
ilProcessor.Emit(OpCodes.Ldc_I4, i);
|
||||||
|
ilProcessor.Emit(OpCodes.Ldloc, i + 1);
|
||||||
|
ilProcessor.Emit(OpCodes.Stelem_Ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ilProcessor.Emit(OpCodes.Ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitBlockStatement(BoundBlockStatement block, MethodDefinition methodDefinition)
|
||||||
|
{
|
||||||
|
var index = 0;
|
||||||
|
while (index < block.Statements.Length)
|
||||||
|
{
|
||||||
|
var statement = block.Statements[index];
|
||||||
|
switch (statement.Kind)
|
||||||
|
{
|
||||||
|
case BoundNodeKind.GotoStatement:
|
||||||
|
throw new NotImplementedException("Gotos are not supported.");
|
||||||
|
case BoundNodeKind.ConditionalGotoStatement:
|
||||||
|
throw new NotImplementedException("Conditional gotos are not supported.");
|
||||||
|
case BoundNodeKind.LabelStatement:
|
||||||
|
throw new NotImplementedException("Labels are not supported.");
|
||||||
|
default:
|
||||||
|
EmitStatement(statement, methodDefinition);
|
||||||
|
index++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitStatement(BoundStatement node, MethodDefinition methodDefinition)
|
||||||
|
{
|
||||||
|
switch (node.Kind)
|
||||||
|
{
|
||||||
|
case BoundNodeKind.EmptyStatement:
|
||||||
|
break;
|
||||||
|
case BoundNodeKind.ExpressionStatement:
|
||||||
|
EmitExpressionStatement((BoundExpressionStatement)node, methodDefinition);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException($"Invalid statement kind '{node.Kind}'.");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitExpressionStatement(BoundExpressionStatement node, MethodDefinition methodDefinition)
|
||||||
|
{
|
||||||
|
var ilProcessor = methodDefinition.Body.GetILProcessor();
|
||||||
|
EmitExpression(node.Expression, methodDefinition);
|
||||||
|
if (node.DiscardResult)
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Pop);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Call, _dispReference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitExpression(BoundExpression node, MethodDefinition methodDefinition)
|
||||||
|
{
|
||||||
|
switch (node.Kind) {
|
||||||
|
case BoundNodeKind.AssignmentExpression:
|
||||||
|
EmitAssignmentExpression((BoundAssignmentExpression)node, methodDefinition);
|
||||||
|
break;
|
||||||
|
case BoundNodeKind.BinaryOperationExpression:
|
||||||
|
EmitBinaryOperationExpression((BoundBinaryOperationExpression)node, methodDefinition);
|
||||||
|
break;
|
||||||
|
case BoundNodeKind.FunctionCallExpression:
|
||||||
|
EmitFunctionCallExpression((BoundFunctionCallExpression)node, methodDefinition);
|
||||||
|
break;
|
||||||
|
case BoundNodeKind.IdentifierNameExpression:
|
||||||
|
EmitIdentifierNameExpression((BoundIdentifierNameExpression)node, methodDefinition);
|
||||||
|
break;
|
||||||
|
case BoundNodeKind.NumberLiteralExpression:
|
||||||
|
EmitNumberLiteralExpression((BoundNumberLiteralExpression)node, methodDefinition);
|
||||||
|
break;
|
||||||
|
case BoundNodeKind.StringLiteralExpression:
|
||||||
|
EmitStringLiteralExpression((BoundStringLiteralExpression)node, methodDefinition);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException($"Invalid node kind '{node.Kind}'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitBinaryOperationExpression(BoundBinaryOperationExpression node, MethodDefinition methodDefinition)
|
||||||
|
{
|
||||||
|
var ilProcessor = methodDefinition.Body.GetILProcessor();
|
||||||
|
var method = _binaryOperations[node.Op.Kind];
|
||||||
|
EmitExpression(node.Left, methodDefinition);
|
||||||
|
EmitExpression(node.Right, methodDefinition);
|
||||||
|
ilProcessor.Emit(OpCodes.Call, method);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitAssignmentExpression(BoundAssignmentExpression node, MethodDefinition methodDefinition)
|
||||||
|
{
|
||||||
|
var ilProcessor = methodDefinition.Body.GetILProcessor();
|
||||||
|
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, methodDefinition);
|
||||||
|
ilProcessor.Emit(OpCodes.Callvirt, _putItemIntoDictionary);
|
||||||
|
ilProcessor.Emit(OpCodes.Ldloc_0);
|
||||||
|
ilProcessor.Emit(OpCodes.Ldstr, left.Name);
|
||||||
|
ilProcessor.Emit(OpCodes.Callvirt, _getItemFromDictionary);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitIdentifierNameExpression(BoundIdentifierNameExpression node, MethodDefinition methodDefinition)
|
||||||
|
{
|
||||||
|
var ilProcessor = methodDefinition.Body.GetILProcessor();
|
||||||
|
ilProcessor.Emit(OpCodes.Ldloc_0);
|
||||||
|
ilProcessor.Emit(OpCodes.Ldstr, node.Name);
|
||||||
|
ilProcessor.Emit(OpCodes.Callvirt, _getItemFromDictionary);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitNumberLiteralExpression(BoundNumberLiteralExpression node, MethodDefinition methodDefinition)
|
||||||
|
{
|
||||||
|
var ilProcessor = methodDefinition.Body.GetILProcessor();
|
||||||
|
ilProcessor.Emit(OpCodes.Ldc_R8, node.Value);
|
||||||
|
ilProcessor.Emit(OpCodes.Call, _doubleToMObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitStringLiteralExpression(BoundStringLiteralExpression node, MethodDefinition methodDefinition)
|
||||||
|
{
|
||||||
|
var ilProcessor = methodDefinition.Body.GetILProcessor();
|
||||||
|
ilProcessor.Emit(OpCodes.Ldstr, node.Value);
|
||||||
|
ilProcessor.Emit(OpCodes.Call, _stringToMObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitFunctionCallExpression(BoundFunctionCallExpression node, MethodDefinition methodDefinition)
|
||||||
|
{
|
||||||
|
var ilProcessor = methodDefinition.Body.GetILProcessor();
|
||||||
|
if (node.Name.Kind == BoundNodeKind.IdentifierNameExpression
|
||||||
|
&& ((BoundIdentifierNameExpression)node.Name).Name == "disp")
|
||||||
|
{
|
||||||
|
EmitExpression(node.Arguments[0], methodDefinition);
|
||||||
|
ilProcessor.Emit(OpCodes.Call, _dispReference);
|
||||||
|
ilProcessor.Emit(OpCodes.Ldnull);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var function = ResolveFunction(node.Name);
|
||||||
|
for (var i = 0; i < function.InputDescription.Length; i++)
|
||||||
|
{
|
||||||
|
if (i < node.Arguments.Length)
|
||||||
|
{
|
||||||
|
EmitExpression(node.Arguments[i], methodDefinition);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Ldnull);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ilProcessor.Emit(OpCodes.Call, function.Method);
|
||||||
|
if (function.OutputDescription.Length == 0)
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Ldnull);
|
||||||
|
}
|
||||||
|
else if (function.OutputDescription.Length == 1)
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Ldc_I4_0);
|
||||||
|
ilProcessor.Emit(OpCodes.Ldelem_Ref);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotImplementedException("Functions with multiple output are not supported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodInterfaceDescription ResolveFunction(BoundExpression expression)
|
||||||
|
{
|
||||||
|
if (expression.Kind == BoundNodeKind.IdentifierNameExpression)
|
||||||
|
{
|
||||||
|
var name = ((BoundIdentifierNameExpression)expression).Name;
|
||||||
|
if (_functions.TryGetValue(name, out var result))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
throw new Exception($"Function '{name}' not found.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotImplementedException($"Dynamic functions calling not supported. Failed to resolve function call expression with kind '{expression.Kind}'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,11 @@ namespace Parser.Internal
|
|||||||
Report(span, $"Unexpected character '{c}' while parsing a number.");
|
Report(span, $"Unexpected character '{c}' while parsing a number.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void ReportMainIsNotAllowed(TextSpan span)
|
||||||
|
{
|
||||||
|
Report(span, $"Function name 'Main' is not allowed in scripts.");
|
||||||
|
}
|
||||||
|
|
||||||
internal void ReportUnexpectedEOLWhileParsingString(TextSpan span)
|
internal void ReportUnexpectedEOLWhileParsingString(TextSpan span)
|
||||||
{
|
{
|
||||||
Report(span, "Unexpected end of line while parsing a string literal.");
|
Report(span, "Unexpected end of line while parsing a string literal.");
|
||||||
|
16
Parser/MFunctions/MHelpers.cs
Normal file
16
Parser/MFunctions/MHelpers.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using Parser.Objects;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Parser.MFunctions
|
||||||
|
{
|
||||||
|
public static class MHelpers
|
||||||
|
{
|
||||||
|
public static void Disp(MObject? obj)
|
||||||
|
{
|
||||||
|
if (obj is not null)
|
||||||
|
{
|
||||||
|
Console.WriteLine(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,11 @@
|
|||||||
return MCharArray.Create(chars);
|
return MCharArray.Create(chars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MCharArray CreateCharArray(string s)
|
||||||
|
{
|
||||||
|
return MCharArray.Create(s.ToCharArray());
|
||||||
|
}
|
||||||
|
|
||||||
public static MLogical CreateLogical(bool value)
|
public static MLogical CreateLogical(bool value)
|
||||||
{
|
{
|
||||||
return MLogical.Create(value);
|
return MLogical.Create(value);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
<LangVersion>8.0</LangVersion>
|
<LangVersion>8.0</LangVersion>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<LangVersion>preview</LangVersion>
|
<LangVersion>preview</LangVersion>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Parser\Parser.csproj" />
|
<ProjectReference Include="..\Parser\Parser.csproj" />
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.7.0-3.final" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.7.0-3.final" />
|
||||||
|
@ -3,10 +3,12 @@
|
|||||||
<Target Name="CreateManifestResourceNames" />
|
<Target Name="CreateManifestResourceNames" />
|
||||||
|
|
||||||
<Target Name="CoreCompile" DependsOnTargets="$(CoreCompileDependsOn)">
|
<Target Name="CoreCompile" DependsOnTargets="$(CoreCompileDependsOn)">
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ReferencePath Remove="@(ReferencePath)"
|
<ReferencePath Remove="@(ReferencePath)"
|
||||||
Condition="'%(FileName)' != 'System.Console' AND
|
Condition="'%(FileName)' != 'System.Console' AND
|
||||||
|
'%(FileName)' != 'System.Collections' AND
|
||||||
'%(FileName)' != 'System.Runtime'" />
|
'%(FileName)' != 'System.Runtime'" />
|
||||||
|
<ReferencePath Include="$(MSBuildThisFileDirectory)\..\Parser\bin\Debug\net5.0\Parser.dll" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Message Importance="high" Text="ReferencePath: @(ReferencePath)" />
|
<Message Importance="high" Text="ReferencePath: @(ReferencePath)" />
|
||||||
<Exec Command="dotnet run --project "$(MSBuildThisFileDirectory)\..\cmc\cmc.csproj" -- @(Compile->'"%(Identity)"', ' ') /o "@(IntermediateAssembly)" @(ReferencePath->'/r "%(Identity)"', ' ')"
|
<Exec Command="dotnet run --project "$(MSBuildThisFileDirectory)\..\cmc\cmc.csproj" -- @(Compile->'"%(Identity)"', ' ') /o "@(IntermediateAssembly)" @(ReferencePath->'/r "%(Identity)"', ' ')"
|
||||||
|
@ -6,6 +6,6 @@ function f(x)
|
|||||||
disp('X was');
|
disp('X was');
|
||||||
disp(x);
|
disp(x);
|
||||||
x = x + 1;
|
x = x + 1;
|
||||||
disp('X is')
|
disp('X is');
|
||||||
disp(x);
|
disp(x);
|
||||||
end
|
end
|
@ -5,4 +5,8 @@
|
|||||||
<TargetFramework>net5.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Parser\Parser.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user