1793 lines
73 KiB
C#
1793 lines
73 KiB
C#
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using System.Text;
|
|
using Nub.Lang.Frontend.Lexing;
|
|
using Nub.Lang.Frontend.Parsing;
|
|
using Nub.Lang.Frontend.Parsing.Definitions;
|
|
using Nub.Lang.Frontend.Parsing.Expressions;
|
|
using Nub.Lang.Frontend.Parsing.Statements;
|
|
using Nub.Lang.Frontend.Typing;
|
|
|
|
namespace Nub.Lang.Frontend.Generation;
|
|
|
|
public class Generator
|
|
{
|
|
private const string OutOfBoundsMessage = "Index is out of bounds\\n";
|
|
|
|
private List<SourceFile> _sourceFiles = [];
|
|
private StringBuilder _builder = new();
|
|
private Dictionary<string, string> _variables = [];
|
|
private List<string> _strings = [];
|
|
private Stack<string> _breakLabels = [];
|
|
private Stack<string> _continueLabels = [];
|
|
private int _variableIndex;
|
|
private int _labelIndex;
|
|
private bool _codeIsReachable = true;
|
|
private Dictionary<IFuncSignature, string> _funcNames = [];
|
|
|
|
public string Generate(List<SourceFile> sourceFiles)
|
|
{
|
|
_sourceFiles = sourceFiles;
|
|
_builder = new StringBuilder();
|
|
_variables = new Dictionary<string, string>();
|
|
_strings = [];
|
|
_funcNames = [];
|
|
_breakLabels = [];
|
|
_continueLabels = [];
|
|
_variableIndex = 0;
|
|
_labelIndex = 0;
|
|
_codeIsReachable = true;
|
|
|
|
foreach (var structDef in _sourceFiles.SelectMany(f => f.Definitions).OfType<StructDefinitionNode>())
|
|
{
|
|
GenerateStructDefinition(structDef);
|
|
_builder.AppendLine();
|
|
}
|
|
|
|
foreach (var funcSignature in _sourceFiles.SelectMany(f => f.Definitions).OfType<IFuncSignature>())
|
|
{
|
|
switch (funcSignature)
|
|
{
|
|
case ExternFuncDefinitionNode externFuncDefinitionNode:
|
|
_funcNames[funcSignature] = "$" + externFuncDefinitionNode.CallName;
|
|
break;
|
|
case LocalFuncDefinitionNode localFuncDefinitionNode:
|
|
if (localFuncDefinitionNode.Exported)
|
|
{
|
|
_funcNames[funcSignature] = "$" + localFuncDefinitionNode.Name;
|
|
}
|
|
else
|
|
{
|
|
_funcNames[funcSignature] = "$" + localFuncDefinitionNode.Namespace + "_" + localFuncDefinitionNode.Name;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException(nameof(funcSignature));
|
|
}
|
|
}
|
|
|
|
foreach (var funcDef in _sourceFiles.SelectMany(f => f.Definitions).OfType<LocalFuncDefinitionNode>())
|
|
{
|
|
GenerateFuncDefinition(funcDef);
|
|
_builder.AppendLine();
|
|
}
|
|
|
|
_builder.AppendLine($"data $oob_message = {{ b \"{OutOfBoundsMessage}\" }}");
|
|
|
|
for (var i = 0; i < _strings.Count; i++)
|
|
{
|
|
var str = _strings[i];
|
|
_builder.AppendLine($"data $string{i + 1} = {{ b \"{str}\", b 0 }}");
|
|
}
|
|
|
|
return _builder.ToString();
|
|
}
|
|
|
|
private enum TypeContext
|
|
{
|
|
FuncDef,
|
|
FuncCall,
|
|
}
|
|
|
|
private static string QBEType(NubType type, TypeContext context)
|
|
{
|
|
return context switch
|
|
{
|
|
TypeContext.FuncDef => type switch
|
|
{
|
|
NubArrayType => "l",
|
|
NubPointerType => "l",
|
|
NubPrimitiveType primitiveType => primitiveType.Kind switch
|
|
{
|
|
PrimitiveTypeKind.I64 => "l",
|
|
PrimitiveTypeKind.I32 => "w",
|
|
PrimitiveTypeKind.I16 => "sh",
|
|
PrimitiveTypeKind.I8 => "sb",
|
|
PrimitiveTypeKind.U64 => "l",
|
|
PrimitiveTypeKind.U32 => "w",
|
|
PrimitiveTypeKind.U16 => "uh",
|
|
PrimitiveTypeKind.U8 => "ub",
|
|
PrimitiveTypeKind.F64 => "d",
|
|
PrimitiveTypeKind.F32 => "s",
|
|
PrimitiveTypeKind.Bool => "w",
|
|
PrimitiveTypeKind.Any => throw new NotSupportedException("any type cannot be used in function definitions"),
|
|
_ => throw new ArgumentOutOfRangeException()
|
|
},
|
|
NubStructType structType => $":{structType.Namespace}_{structType.Name}",
|
|
NubFixedArrayType => "l",
|
|
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
|
},
|
|
TypeContext.FuncCall => type switch
|
|
{
|
|
NubArrayType => "l",
|
|
NubPointerType => "l",
|
|
NubPrimitiveType pointerType => pointerType.Kind switch
|
|
{
|
|
PrimitiveTypeKind.I64 => "l",
|
|
PrimitiveTypeKind.I32 => "w",
|
|
PrimitiveTypeKind.I16 => "sh",
|
|
PrimitiveTypeKind.I8 => "sb",
|
|
PrimitiveTypeKind.U64 => "l",
|
|
PrimitiveTypeKind.U32 => "w",
|
|
PrimitiveTypeKind.U16 => "uh",
|
|
PrimitiveTypeKind.U8 => "ub",
|
|
PrimitiveTypeKind.F64 => "d",
|
|
PrimitiveTypeKind.F32 => "s",
|
|
PrimitiveTypeKind.Bool => "w",
|
|
PrimitiveTypeKind.Any => "l",
|
|
_ => throw new ArgumentOutOfRangeException()
|
|
},
|
|
NubStructType structType => $":{structType.Namespace}_{structType.Name}",
|
|
NubFixedArrayType => "l",
|
|
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
|
},
|
|
_ => throw new ArgumentOutOfRangeException(nameof(context), context, null)
|
|
};
|
|
}
|
|
|
|
private static string QBEStore(NubType type)
|
|
{
|
|
return $"store{type switch
|
|
{
|
|
NubArrayType => "l",
|
|
NubPointerType => "l",
|
|
NubPrimitiveType primitiveType => primitiveType.Kind switch
|
|
{
|
|
PrimitiveTypeKind.I64 => "l",
|
|
PrimitiveTypeKind.I32 => "w",
|
|
PrimitiveTypeKind.I16 => "h",
|
|
PrimitiveTypeKind.I8 => "b",
|
|
PrimitiveTypeKind.U64 => "l",
|
|
PrimitiveTypeKind.U32 => "w",
|
|
PrimitiveTypeKind.U16 => "h",
|
|
PrimitiveTypeKind.U8 => "b",
|
|
PrimitiveTypeKind.F64 => "d",
|
|
PrimitiveTypeKind.F32 => "s",
|
|
PrimitiveTypeKind.Bool => "w",
|
|
PrimitiveTypeKind.Any => throw new NotSupportedException("any type cannot be used in store instructions"),
|
|
_ => throw new ArgumentOutOfRangeException()
|
|
},
|
|
NubStructType => "l",
|
|
NubFixedArrayType => "l",
|
|
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
|
}}";
|
|
}
|
|
|
|
private static string QBELoad(NubType type)
|
|
{
|
|
return $"load{type switch
|
|
{
|
|
NubArrayType => "l",
|
|
NubPointerType => "l",
|
|
NubPrimitiveType primitiveType => primitiveType.Kind switch
|
|
{
|
|
PrimitiveTypeKind.I64 => "l",
|
|
PrimitiveTypeKind.I32 => "w",
|
|
PrimitiveTypeKind.I16 => "sh",
|
|
PrimitiveTypeKind.I8 => "sb",
|
|
PrimitiveTypeKind.U64 => "l",
|
|
PrimitiveTypeKind.U32 => "w",
|
|
PrimitiveTypeKind.U16 => "uh",
|
|
PrimitiveTypeKind.U8 => "ub",
|
|
PrimitiveTypeKind.F64 => "d",
|
|
PrimitiveTypeKind.F32 => "s",
|
|
PrimitiveTypeKind.Bool => "w",
|
|
PrimitiveTypeKind.Any => throw new NotSupportedException("any type cannot be used in load instructions"),
|
|
_ => throw new ArgumentOutOfRangeException()
|
|
},
|
|
NubStructType => "l",
|
|
NubFixedArrayType => "l",
|
|
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
|
}}";
|
|
}
|
|
|
|
private static string QBEAssign(NubType type)
|
|
{
|
|
return $"={type switch
|
|
{
|
|
NubArrayType => "l",
|
|
NubPointerType => "l",
|
|
NubPrimitiveType primitiveType => primitiveType.Kind switch
|
|
{
|
|
PrimitiveTypeKind.I64 => "l",
|
|
PrimitiveTypeKind.I32 => "w",
|
|
PrimitiveTypeKind.I16 => "w",
|
|
PrimitiveTypeKind.I8 => "w",
|
|
PrimitiveTypeKind.U64 => "l",
|
|
PrimitiveTypeKind.U32 => "w",
|
|
PrimitiveTypeKind.U16 => "w",
|
|
PrimitiveTypeKind.U8 => "w",
|
|
PrimitiveTypeKind.F64 => "d",
|
|
PrimitiveTypeKind.F32 => "s",
|
|
PrimitiveTypeKind.Bool => "w",
|
|
PrimitiveTypeKind.Any => throw new NotSupportedException("any type cannot be used in variables"),
|
|
_ => throw new ArgumentOutOfRangeException()
|
|
},
|
|
NubStructType => "l",
|
|
NubFixedArrayType => "l",
|
|
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
|
}}";
|
|
}
|
|
|
|
private int SizeOf(NubType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case NubPrimitiveType primitiveType:
|
|
{
|
|
switch (primitiveType.Kind)
|
|
{
|
|
case PrimitiveTypeKind.I64:
|
|
case PrimitiveTypeKind.U64:
|
|
case PrimitiveTypeKind.Any:
|
|
return 8;
|
|
case PrimitiveTypeKind.I32:
|
|
case PrimitiveTypeKind.U32:
|
|
return 4;
|
|
case PrimitiveTypeKind.I16:
|
|
case PrimitiveTypeKind.U16:
|
|
return 2;
|
|
case PrimitiveTypeKind.I8:
|
|
case PrimitiveTypeKind.U8:
|
|
case PrimitiveTypeKind.Bool:
|
|
return 1;
|
|
case PrimitiveTypeKind.F64:
|
|
return 8;
|
|
case PrimitiveTypeKind.F32:
|
|
return 4;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
}
|
|
case NubStructType nubStructType:
|
|
{
|
|
var definition = LookupStructDefinition(nubStructType.Namespace, nubStructType.Name);
|
|
return definition.Fields.Sum(f => SizeOf(f.Type));
|
|
}
|
|
case NubPointerType:
|
|
case NubArrayType:
|
|
{
|
|
return 8;
|
|
}
|
|
case NubFixedArrayType nubFixedArrayType:
|
|
{
|
|
return SizeOf(nubFixedArrayType.ElementType) * nubFixedArrayType.Capacity;
|
|
}
|
|
default:
|
|
{
|
|
throw new UnreachableException();
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool IsLargeType(NubType type)
|
|
{
|
|
return type switch
|
|
{
|
|
NubArrayType => false,
|
|
NubPointerType => false,
|
|
NubPrimitiveType => false,
|
|
NubStructType => true,
|
|
NubFixedArrayType => true,
|
|
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
|
};
|
|
}
|
|
|
|
private void GenerateFuncDefinition(LocalFuncDefinitionNode node)
|
|
{
|
|
_variables.Clear();
|
|
|
|
if (node.Exported)
|
|
{
|
|
_builder.Append("export ");
|
|
}
|
|
|
|
_builder.Append("function ");
|
|
if (node.ReturnType.HasValue)
|
|
{
|
|
_builder.Append($"{QBEType(node.ReturnType.Value, TypeContext.FuncDef)} ");
|
|
}
|
|
else if (!node.ReturnType.HasValue && node.Name == "main")
|
|
{
|
|
_builder.Append("l ");
|
|
}
|
|
|
|
_builder.Append(_funcNames[node]);
|
|
|
|
var parameterStrings = node.Parameters.Select(parameter => parameter.Variadic ? "..." : $"{QBEType(parameter.Type, TypeContext.FuncDef)} %{parameter.Name}");
|
|
|
|
_builder.AppendLine($"({string.Join(", ", parameterStrings)}) {{");
|
|
_builder.AppendLine("@start");
|
|
|
|
foreach (var parameter in node.Parameters)
|
|
{
|
|
var parameterName = parameter.Name;
|
|
|
|
switch (QBEType(parameter.Type, TypeContext.FuncDef))
|
|
{
|
|
case "sb":
|
|
parameterName = GenVarName();
|
|
_builder.AppendLine($" {parameterName} =w extsb %{parameter.Name}");
|
|
break;
|
|
case "ub":
|
|
parameterName = GenVarName();
|
|
_builder.AppendLine($" {parameterName} =w extub %{parameter.Name}");
|
|
break;
|
|
case "sh":
|
|
parameterName = GenVarName();
|
|
_builder.AppendLine($" {parameterName} =w extsh %{parameter.Name}");
|
|
break;
|
|
case "uh":
|
|
parameterName = GenVarName();
|
|
_builder.AppendLine($" {parameterName} =w extuh %{parameter.Name}");
|
|
break;
|
|
}
|
|
|
|
if (IsLargeType(parameter.Type))
|
|
{
|
|
_variables[parameter.Name] = parameterName;
|
|
}
|
|
else
|
|
{
|
|
var pointerName = GenVarName();
|
|
_builder.AppendLine($" {pointerName} =l alloc8 {SizeOf(parameter.Type)}");
|
|
_builder.AppendLine($" {QBEStore(parameter.Type)} %{parameterName}, {pointerName}");
|
|
|
|
_variables[parameter.Name] = pointerName;
|
|
}
|
|
}
|
|
|
|
_builder.AppendLine();
|
|
|
|
GenerateBlock(node.Body);
|
|
|
|
if (node.Body.Statements.LastOrDefault() is not ReturnNode)
|
|
{
|
|
if (!node.ReturnType.HasValue && node.Name == "main")
|
|
{
|
|
_builder.AppendLine();
|
|
_builder.AppendLine(" # Implicit return for main");
|
|
_builder.AppendLine(" ret 0");
|
|
}
|
|
else if (!node.ReturnType.HasValue)
|
|
{
|
|
_builder.AppendLine();
|
|
_builder.AppendLine(" # Implicit return");
|
|
_builder.AppendLine(" ret");
|
|
}
|
|
}
|
|
|
|
_builder.AppendLine("}");
|
|
}
|
|
|
|
private void GenerateStructDefinition(StructDefinitionNode structDefinition)
|
|
{
|
|
_builder.Append($"type :{structDefinition.Namespace}_{structDefinition.Name} = {{ ");
|
|
foreach (var structDefinitionField in structDefinition.Fields)
|
|
{
|
|
var fieldDefinition = GenerateFieldType(structDefinitionField.Type);
|
|
_builder.Append(fieldDefinition + ", ");
|
|
}
|
|
_builder.AppendLine("}");
|
|
}
|
|
|
|
private string GenerateFieldType(NubType type)
|
|
{
|
|
return type switch
|
|
{
|
|
NubArrayType => "l",
|
|
NubPointerType => "l",
|
|
NubPrimitiveType primitiveType => primitiveType.Kind switch
|
|
{
|
|
PrimitiveTypeKind.I64 => "l",
|
|
PrimitiveTypeKind.I32 => "w",
|
|
PrimitiveTypeKind.I16 => "h",
|
|
PrimitiveTypeKind.I8 => "b",
|
|
PrimitiveTypeKind.U64 => "l",
|
|
PrimitiveTypeKind.U32 => "w",
|
|
PrimitiveTypeKind.U16 => "h",
|
|
PrimitiveTypeKind.U8 => "b",
|
|
PrimitiveTypeKind.F64 => "d",
|
|
PrimitiveTypeKind.F32 => "s",
|
|
PrimitiveTypeKind.Bool => "w",
|
|
PrimitiveTypeKind.Any => throw new NotSupportedException("any type cannot be used in structs"),
|
|
_ => throw new ArgumentOutOfRangeException()
|
|
},
|
|
NubStructType structType => $":{structType.Namespace}_{structType.Name}",
|
|
NubFixedArrayType fixedArrayType => $"b {SizeOf(fixedArrayType)}",
|
|
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
|
};
|
|
}
|
|
|
|
private void GenerateStatement(StatementNode statement)
|
|
{
|
|
switch (statement)
|
|
{
|
|
case ArrayIndexAssignmentNode arrayIndexAssignment:
|
|
GenerateArrayIndexAssignment(arrayIndexAssignment);
|
|
break;
|
|
case BreakNode:
|
|
GenerateBreak();
|
|
break;
|
|
case ContinueNode:
|
|
GenerateContinue();
|
|
break;
|
|
case DereferenceAssignmentNode dereferenceAssignment:
|
|
GenerateDereferenceAssignment(dereferenceAssignment);
|
|
break;
|
|
case IfNode ifStatement:
|
|
GenerateIf(ifStatement);
|
|
break;
|
|
case MemberAssignmentNode memberAssignment:
|
|
GenerateMemberAssignment(memberAssignment);
|
|
break;
|
|
case ReturnNode @return:
|
|
GenerateReturn(@return);
|
|
break;
|
|
case StatementExpressionNode statementExpression:
|
|
GenerateExpression(statementExpression.Expression);
|
|
break;
|
|
case VariableAssignmentNode variableAssignment:
|
|
GenerateVariableAssignment(variableAssignment);
|
|
break;
|
|
case VariableDeclarationNode variableDeclaration:
|
|
GenerateVariableDeclaration(variableDeclaration);
|
|
break;
|
|
case WhileNode whileStatement:
|
|
GenerateWhile(whileStatement);
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException(nameof(statement));
|
|
}
|
|
}
|
|
|
|
private void GenerateArrayIndexAssignment(ArrayIndexAssignmentNode arrayIndexAssignment)
|
|
{
|
|
var array = GenerateExpression(arrayIndexAssignment.ArrayIndexAccess.Array);
|
|
var index = GenerateExpression(arrayIndexAssignment.ArrayIndexAccess.Index);
|
|
GenerateArrayBoundsCheck(array, index);
|
|
var value = GenerateExpression(arrayIndexAssignment.Value);
|
|
|
|
switch (arrayIndexAssignment.ArrayIndexAccess.Array.Type)
|
|
{
|
|
case NubArrayType arrayType:
|
|
{
|
|
var startName = GenVarName();
|
|
_builder.AppendLine($" {startName} =l add {array}, 8");
|
|
|
|
var adjustedIndex = GenVarName();
|
|
_builder.AppendLine($" {adjustedIndex} =l mul {index}, {SizeOf(arrayType.ElementType)}");
|
|
|
|
var offsetName = GenVarName();
|
|
_builder.AppendLine($" {offsetName} =l add {startName}, {adjustedIndex}");
|
|
|
|
if (IsLargeType(arrayType.ElementType))
|
|
{
|
|
_builder.AppendLine($" blit {value}, {offsetName}, {SizeOf(arrayType.ElementType)}");
|
|
}
|
|
else
|
|
{
|
|
_builder.AppendLine($" {QBEStore(arrayType.ElementType)} {value}, {offsetName}");
|
|
}
|
|
break;
|
|
}
|
|
case NubFixedArrayType fixedArrayType:
|
|
{
|
|
var startName = GenVarName();
|
|
_builder.AppendLine($" {startName} =l add {array}, 8");
|
|
|
|
var adjustedIndex = GenVarName();
|
|
_builder.AppendLine($" {adjustedIndex} =l mul {index}, {SizeOf(fixedArrayType.ElementType)}");
|
|
|
|
var offsetName = GenVarName();
|
|
_builder.AppendLine($" {offsetName} =l add {startName}, {adjustedIndex}");
|
|
|
|
if (IsLargeType(fixedArrayType.ElementType))
|
|
{
|
|
_builder.AppendLine($" blit {value}, {offsetName}, {SizeOf(fixedArrayType.ElementType)}");
|
|
}
|
|
else
|
|
{
|
|
_builder.AppendLine($" {QBEStore(fixedArrayType.ElementType)} {value}, {offsetName}");
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
throw new UnreachableException();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void GenerateBlock(BlockNode block)
|
|
{
|
|
foreach (var statement in block.Statements.Where(_ => _codeIsReachable))
|
|
{
|
|
GenerateStatement(statement);
|
|
}
|
|
|
|
_codeIsReachable = true;
|
|
}
|
|
|
|
private void GenerateBreak()
|
|
{
|
|
_builder.AppendLine($" jmp {_breakLabels.Peek()}");
|
|
_codeIsReachable = false;
|
|
}
|
|
|
|
private void GenerateContinue()
|
|
{
|
|
_builder.AppendLine($" jmp {_continueLabels.Peek()}");
|
|
_codeIsReachable = false;
|
|
}
|
|
|
|
private void GenerateDereferenceAssignment(DereferenceAssignmentNode dereferenceAssignment)
|
|
{
|
|
var location = GenerateExpression(dereferenceAssignment.Dereference.Expression);
|
|
var value = GenerateExpression(dereferenceAssignment.Value);
|
|
|
|
if (IsLargeType(dereferenceAssignment.Value.Type))
|
|
{
|
|
_builder.AppendLine($" blit {value}, {location}, {SizeOf(dereferenceAssignment.Value.Type)}");
|
|
}
|
|
else
|
|
{
|
|
_builder.AppendLine($" {QBEStore(dereferenceAssignment.Value.Type)} {value}, {location}");
|
|
}
|
|
}
|
|
|
|
private void GenerateIf(IfNode ifStatement)
|
|
{
|
|
var trueLabel = GenLabelName();
|
|
var falseLabel = GenLabelName();
|
|
var endLabel = GenLabelName();
|
|
|
|
var result = GenerateExpression(ifStatement.Condition);
|
|
_builder.AppendLine($" jnz {result}, {trueLabel}, {falseLabel}");
|
|
_builder.AppendLine(trueLabel);
|
|
GenerateBlock(ifStatement.Body);
|
|
_builder.AppendLine($" jmp {endLabel}");
|
|
_builder.AppendLine(falseLabel);
|
|
if (ifStatement.Else.HasValue)
|
|
{
|
|
ifStatement.Else.Value.Match
|
|
(
|
|
GenerateIf,
|
|
GenerateBlock
|
|
);
|
|
}
|
|
|
|
_builder.AppendLine(endLabel);
|
|
}
|
|
|
|
private void GenerateMemberAssignment(MemberAssignmentNode memberAssignment)
|
|
{
|
|
var structType = memberAssignment.MemberAccess.Expression.Type as NubStructType;
|
|
Debug.Assert(structType != null);
|
|
|
|
var structDefinition = LookupStructDefinition(structType.Namespace, structType.Name);
|
|
var offset = LookupMemberOffset(structDefinition, memberAssignment.MemberAccess.Member);
|
|
|
|
var item = GenerateExpression(memberAssignment.MemberAccess.Expression);
|
|
var offsetName = GenVarName();
|
|
|
|
_builder.AppendLine($" {offsetName} =l add {item}, {offset}");
|
|
|
|
var value = GenerateExpression(memberAssignment.Value);
|
|
|
|
if (IsLargeType(memberAssignment.Value.Type))
|
|
{
|
|
_builder.AppendLine($" blit {value}, {offsetName}, {SizeOf(memberAssignment.Value.Type)}");
|
|
}
|
|
else
|
|
{
|
|
_builder.AppendLine($" {QBEStore(memberAssignment.Value.Type)} {value}, {offsetName}");
|
|
}
|
|
}
|
|
|
|
private void GenerateReturn(ReturnNode @return)
|
|
{
|
|
if (@return.Value.HasValue)
|
|
{
|
|
var result = GenerateExpression(@return.Value.Value);
|
|
_builder.AppendLine($" ret {result}");
|
|
}
|
|
else
|
|
{
|
|
_builder.AppendLine(" ret");
|
|
}
|
|
}
|
|
|
|
private void GenerateVariableAssignment(VariableAssignmentNode variableAssignment)
|
|
{
|
|
var result = GenerateExpression(variableAssignment.Value);
|
|
_builder.AppendLine($" storel {result}, {_variables[variableAssignment.Identifier.Identifier]}");
|
|
}
|
|
|
|
private void GenerateVariableDeclaration(VariableDeclarationNode variableDeclaration)
|
|
{
|
|
var type = variableDeclaration.ExplicitType.Value ?? variableDeclaration.Value.Value?.Type!;
|
|
|
|
string pointerName;
|
|
|
|
if (variableDeclaration.Value.HasValue)
|
|
{
|
|
var result = GenerateExpression(variableDeclaration.Value.Value);
|
|
if (IsLargeType(type))
|
|
{
|
|
pointerName = result;
|
|
}
|
|
else
|
|
{
|
|
pointerName = GenVarName();
|
|
_builder.AppendLine($" {pointerName} =l alloc8 {SizeOf(type)}");
|
|
_builder.AppendLine($" {QBEStore(type)} {result}, {pointerName}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pointerName = GenVarName();
|
|
_builder.AppendLine($" {pointerName} =l alloc8 {SizeOf(type)}");
|
|
if (IsLargeType(type))
|
|
{
|
|
_builder.AppendLine($" call $nub_memset(l {pointerName}, ub 0, l {SizeOf(type)})");
|
|
}
|
|
else
|
|
{
|
|
_builder.AppendLine($" {QBEStore(type)} 0, {pointerName}");
|
|
}
|
|
}
|
|
|
|
_variables[variableDeclaration.Name] = pointerName;
|
|
}
|
|
|
|
private void GenerateWhile(WhileNode whileStatement)
|
|
{
|
|
var conditionLabel = GenLabelName();
|
|
var iterationLabel = GenLabelName();
|
|
var endLabel = GenLabelName();
|
|
|
|
_breakLabels.Push(endLabel);
|
|
_continueLabels.Push(conditionLabel);
|
|
|
|
_builder.AppendLine($" jmp {conditionLabel}");
|
|
_builder.AppendLine(iterationLabel);
|
|
GenerateBlock(whileStatement.Body);
|
|
_builder.AppendLine(conditionLabel);
|
|
var result = GenerateExpression(whileStatement.Condition);
|
|
_builder.AppendLine($" jnz {result}, {iterationLabel}, {endLabel}");
|
|
_builder.AppendLine(endLabel);
|
|
|
|
_continueLabels.Pop();
|
|
_breakLabels.Pop();
|
|
}
|
|
|
|
private string GenerateExpression(ExpressionNode expression)
|
|
{
|
|
return expression switch
|
|
{
|
|
AddressOfNode addressOf => GenerateAddressOf(addressOf),
|
|
ArrayIndexAccessNode arrayIndex => GenerateArrayIndex(arrayIndex),
|
|
ArrayInitializerNode arrayInitializer => GenerateArrayInitializer(arrayInitializer),
|
|
BinaryExpressionNode binaryExpression => GenerateBinaryExpression(binaryExpression),
|
|
// CastNode cast => GenerateCast(cast),
|
|
DereferenceNode dereference => GenerateDereference(dereference),
|
|
FixedArrayInitializerNode fixedArrayInitializer => GenerateFixedArrayInitializer(fixedArrayInitializer),
|
|
FuncCallNode funcCallExpression => GenerateFuncCall(funcCallExpression),
|
|
IdentifierNode identifier => GenerateIdentifier(identifier),
|
|
LiteralNode literal => GenerateLiteral(literal),
|
|
StructInitializerNode structInitializer => GenerateStructInitializer(structInitializer),
|
|
UnaryExpressionNode unaryExpression => GenerateUnaryExpression(unaryExpression),
|
|
MemberAccessNode memberAccess => GenerateMemberAccess(memberAccess),
|
|
_ => throw new ArgumentOutOfRangeException(nameof(expression))
|
|
};
|
|
}
|
|
|
|
private string GenerateArrayIndex(ArrayIndexAccessNode arrayIndexAccess)
|
|
{
|
|
var array = GenerateExpression(arrayIndexAccess.Array);
|
|
var index = GenerateExpression(arrayIndexAccess.Index);
|
|
GenerateArrayBoundsCheck(array, index);
|
|
|
|
switch (arrayIndexAccess.Array.Type)
|
|
{
|
|
case NubArrayType arrayType:
|
|
{
|
|
var firstItemPointerName = GenVarName();
|
|
_builder.AppendLine($" {firstItemPointerName} =l add {array}, 8");
|
|
var offsetPointerName = GenVarName();
|
|
_builder.AppendLine($" {offsetPointerName} =l mul {index}, {SizeOf(arrayType.ElementType)}");
|
|
var resultPointerName = GenVarName();
|
|
_builder.AppendLine($" {resultPointerName} =l add {firstItemPointerName}, {offsetPointerName}");
|
|
|
|
if (IsLargeType(arrayType.ElementType))
|
|
{
|
|
return resultPointerName;
|
|
}
|
|
else
|
|
{
|
|
var outputName = GenVarName();
|
|
_builder.AppendLine($" {outputName} {QBEAssign(arrayType.ElementType)} {QBELoad(arrayType.ElementType)} {resultPointerName}");
|
|
return outputName;
|
|
}
|
|
}
|
|
case NubFixedArrayType fixedArrayType:
|
|
{
|
|
var firstItemPointerName = GenVarName();
|
|
_builder.AppendLine($" {firstItemPointerName} =l add {array}, 8");
|
|
var offsetPointerName = GenVarName();
|
|
_builder.AppendLine($" {offsetPointerName} =l mul {index}, {SizeOf(fixedArrayType.ElementType)}");
|
|
var resultPointerName = GenVarName();
|
|
_builder.AppendLine($" {resultPointerName} =l add {firstItemPointerName}, {offsetPointerName}");
|
|
|
|
if (IsLargeType(fixedArrayType.ElementType))
|
|
{
|
|
return resultPointerName;
|
|
}
|
|
else
|
|
{
|
|
var outputName = GenVarName();
|
|
_builder.AppendLine($" {outputName} {QBEAssign(fixedArrayType.ElementType)} {QBELoad(fixedArrayType.ElementType)} {resultPointerName}");
|
|
return outputName;
|
|
}
|
|
}
|
|
default:
|
|
{
|
|
throw new UnreachableException();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void GenerateArrayBoundsCheck(string array, string index)
|
|
{
|
|
var countName = GenVarName();
|
|
_builder.AppendLine($" {countName} =l loadl {array}");
|
|
|
|
var isNegativeName = GenVarName();
|
|
_builder.AppendLine($" {isNegativeName} =w csltl {index}, 0");
|
|
|
|
var isOobName = GenVarName();
|
|
_builder.AppendLine($" {isOobName} =w csgel {index}, {countName}");
|
|
|
|
var anyOobName = GenVarName();
|
|
_builder.AppendLine($" {anyOobName} =w or {isNegativeName}, {isOobName}");
|
|
|
|
var oobLabel = GenLabelName();
|
|
var notOobLabel = GenLabelName();
|
|
_builder.AppendLine($" jnz {anyOobName}, {oobLabel}, {notOobLabel}");
|
|
|
|
_builder.AppendLine(oobLabel);
|
|
_builder.AppendLine($" call $nub_panic(l $oob_message, l {OutOfBoundsMessage.Length})");
|
|
|
|
_builder.AppendLine(notOobLabel);
|
|
}
|
|
|
|
private string GenerateArrayInitializer(ArrayInitializerNode arrayInitializer)
|
|
{
|
|
var capacity = GenerateExpression(arrayInitializer.Capacity);
|
|
var capacityInBytes = GenVarName();
|
|
_builder.AppendLine($" {capacityInBytes} =l mul {capacity}, {SizeOf(arrayInitializer.ElementType)}");
|
|
var totalArraySize = GenVarName();
|
|
_builder.AppendLine($" {totalArraySize} =l add {capacityInBytes}, 8");
|
|
var outputName = GenVarName();
|
|
_builder.AppendLine($" {outputName} =l alloc8 {totalArraySize}");
|
|
_builder.AppendLine($" storel {capacity}, {outputName}");
|
|
|
|
var dataPtr = GenVarName();
|
|
_builder.AppendLine($" {dataPtr} =l add {outputName}, 8");
|
|
_builder.AppendLine($" call $nub_memset(l {dataPtr}, w 0, l {capacityInBytes})");
|
|
|
|
return outputName;
|
|
}
|
|
|
|
private string GenerateDereference(DereferenceNode dereference)
|
|
{
|
|
var result = GenerateExpression(dereference.Expression);
|
|
var outputName = GenVarName();
|
|
_builder.AppendLine($" {outputName} {QBEAssign(dereference.Type)} {QBELoad(dereference.Type)} {result}");
|
|
return outputName;
|
|
}
|
|
|
|
private string GenerateAddressOf(AddressOfNode addressOf)
|
|
{
|
|
var result = GenerateExpression(addressOf.Expression);
|
|
var outputName = GenVarName();
|
|
switch (addressOf.Expression.Type)
|
|
{
|
|
case NubPointerType:
|
|
case NubStructType:
|
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.I64 }:
|
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.F64 }:
|
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.U64 }:
|
|
_builder.AppendLine($" {outputName} =l alloc8 8");
|
|
_builder.AppendLine($" storel {result}, {outputName}");
|
|
return outputName;
|
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.I32 }:
|
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.U32 }:
|
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.I16 }:
|
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.U16 }:
|
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.I8 }:
|
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.U8 }:
|
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.F32 }:
|
|
_builder.AppendLine($" {outputName} =l alloc8 4");
|
|
_builder.AppendLine($" storew {result}, {outputName}");
|
|
return outputName;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
}
|
|
|
|
private string GenerateBinaryExpression(BinaryExpressionNode binaryExpression)
|
|
{
|
|
var left = GenerateExpression(binaryExpression.Left);
|
|
var right = GenerateExpression(binaryExpression.Right);
|
|
var outputName = GenVarName();
|
|
|
|
switch (binaryExpression.Operator)
|
|
{
|
|
case BinaryExpressionOperator.Equal:
|
|
{
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64))
|
|
{
|
|
_builder.AppendLine($" {outputName} =w ceql {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32))
|
|
{
|
|
_builder.AppendLine($" {outputName} =w ceqw {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
// if (binaryExpression.Left.Type.Equals(NubPrimitiveType.String))
|
|
// {
|
|
// _builder.AppendLine($" {outputName} =w call $nub_strcmp(l {left}, l {right})");
|
|
// return outputName;
|
|
// }
|
|
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.Bool))
|
|
{
|
|
_builder.AppendLine($" {outputName} =w ceqw {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case BinaryExpressionOperator.NotEqual:
|
|
{
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64))
|
|
{
|
|
_builder.AppendLine($" {outputName} =w cnel {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32))
|
|
{
|
|
_builder.AppendLine($" {outputName} =w cnew {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
// if (binaryExpression.Left.Type.Equals(NubPrimitiveType.String))
|
|
// {
|
|
// _builder.AppendLine($" {outputName} =w call $nub_strcmp(l {left}, l {right})");
|
|
// _builder.AppendLine($" {outputName} =w xor {outputName}, 1");
|
|
// return outputName;
|
|
// }
|
|
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.Bool))
|
|
{
|
|
_builder.AppendLine($" {outputName} =w cnew {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case BinaryExpressionOperator.GreaterThan:
|
|
{
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64))
|
|
{
|
|
_builder.AppendLine($" {outputName} =w csgtl {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32))
|
|
{
|
|
_builder.AppendLine($" {outputName} =w csgtw {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.Bool))
|
|
{
|
|
_builder.AppendLine($" {outputName} =w csgtw {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case BinaryExpressionOperator.GreaterThanOrEqual:
|
|
{
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64))
|
|
{
|
|
_builder.AppendLine($" {outputName} =w csgel {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32))
|
|
{
|
|
_builder.AppendLine($" {outputName} =w csgew {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.Bool))
|
|
{
|
|
_builder.AppendLine($" {outputName} =w csgew {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case BinaryExpressionOperator.LessThan:
|
|
{
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64))
|
|
{
|
|
_builder.AppendLine($" {outputName} =w csltl {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32))
|
|
{
|
|
_builder.AppendLine($" {outputName} =w csltw {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.Bool))
|
|
{
|
|
_builder.AppendLine($" {outputName} =w csltw {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case BinaryExpressionOperator.LessThanOrEqual:
|
|
{
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64))
|
|
{
|
|
_builder.AppendLine($" {outputName} =w cslel {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32))
|
|
{
|
|
_builder.AppendLine($" {outputName} =w cslew {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.Bool))
|
|
{
|
|
_builder.AppendLine($" {outputName} =w cslew {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case BinaryExpressionOperator.Plus:
|
|
{
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64))
|
|
{
|
|
_builder.AppendLine($" {outputName} =l add {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32))
|
|
{
|
|
_builder.AppendLine($" {outputName} =w add {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case BinaryExpressionOperator.Minus:
|
|
{
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64))
|
|
{
|
|
_builder.AppendLine($" {outputName} =l sub {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32))
|
|
{
|
|
_builder.AppendLine($" {outputName} =w sub {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case BinaryExpressionOperator.Multiply:
|
|
{
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64))
|
|
{
|
|
_builder.AppendLine($" {outputName} =l mul {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32))
|
|
{
|
|
_builder.AppendLine($" {outputName} =w mul {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case BinaryExpressionOperator.Divide:
|
|
{
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64))
|
|
{
|
|
_builder.AppendLine($" {outputName} =l div {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32))
|
|
{
|
|
_builder.AppendLine($" {outputName} =w div {left}, {right}");
|
|
return outputName;
|
|
}
|
|
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
}
|
|
|
|
throw new NotSupportedException($"Binary operator {binaryExpression.Operator} for types {binaryExpression.Left.Type} and {binaryExpression.Right.Type} not supported");
|
|
}
|
|
|
|
// private string GenerateCast(CastNode cast)
|
|
// {
|
|
// var input = GenerateExpression(cast.Expression);
|
|
// var outputType = cast.TargetType;
|
|
// var inputType = cast.Expression.Type;
|
|
//
|
|
// if (inputType.Equals(outputType))
|
|
// {
|
|
// return input;
|
|
// }
|
|
//
|
|
// if (outputType is not NubPrimitiveType primitiveOutputType || inputType is not NubPrimitiveType primitiveInputType)
|
|
// {
|
|
// throw new NotSupportedException("Casting is only supported for primitive types");
|
|
// }
|
|
//
|
|
// var outputName = GenVarName();
|
|
//
|
|
// switch (primitiveInputType.Kind)
|
|
// {
|
|
// case PrimitiveTypeKind.I64:
|
|
// switch (primitiveOutputType.Kind)
|
|
// {
|
|
// case PrimitiveTypeKind.I64:
|
|
// case PrimitiveTypeKind.U64:
|
|
// case PrimitiveTypeKind.I32:
|
|
// case PrimitiveTypeKind.U32:
|
|
// case PrimitiveTypeKind.I16:
|
|
// case PrimitiveTypeKind.U16:
|
|
// case PrimitiveTypeKind.I8:
|
|
// case PrimitiveTypeKind.Any:
|
|
// case PrimitiveTypeKind.U8:
|
|
// return input;
|
|
// case PrimitiveTypeKind.F64:
|
|
// _builder.AppendLine($" {outputName} =d sltof {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.F32:
|
|
// _builder.AppendLine($" {outputName} =s sltof {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.String:
|
|
// _builder.AppendLine($" {outputName} =l call $nub_i64_to_string(l {input})");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.Bool:
|
|
// default:
|
|
// throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported");
|
|
// }
|
|
// case PrimitiveTypeKind.I32:
|
|
// switch (primitiveOutputType.Kind)
|
|
// {
|
|
// case PrimitiveTypeKind.I64:
|
|
// case PrimitiveTypeKind.U64:
|
|
// _builder.AppendLine($" {outputName} =l extsw {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.I32:
|
|
// case PrimitiveTypeKind.U32:
|
|
// case PrimitiveTypeKind.I16:
|
|
// case PrimitiveTypeKind.U16:
|
|
// case PrimitiveTypeKind.I8:
|
|
// case PrimitiveTypeKind.U8:
|
|
// return input;
|
|
// case PrimitiveTypeKind.F64:
|
|
// var extName = GenVarName();
|
|
// _builder.AppendLine($" {extName} =l extsw {input}");
|
|
// _builder.AppendLine($" {outputName} =d sltof {extName}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.F32:
|
|
// _builder.AppendLine($" {outputName} =s swtof {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.String:
|
|
// _builder.AppendLine($" {outputName} =l call $nub_i32_to_string(w {input})");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.Any:
|
|
// var extAnyName = GenVarName();
|
|
// _builder.AppendLine($" {extAnyName} =l extsw {input}");
|
|
// return extAnyName;
|
|
// case PrimitiveTypeKind.Bool:
|
|
// default:
|
|
// throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported");
|
|
// }
|
|
// case PrimitiveTypeKind.I16:
|
|
// switch (primitiveOutputType.Kind)
|
|
// {
|
|
// case PrimitiveTypeKind.I64:
|
|
// case PrimitiveTypeKind.U64:
|
|
// _builder.AppendLine($" {outputName} =l extsh {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.I32:
|
|
// case PrimitiveTypeKind.U32:
|
|
// _builder.AppendLine($" {outputName} =w extsh {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.I16:
|
|
// case PrimitiveTypeKind.U16:
|
|
// case PrimitiveTypeKind.I8:
|
|
// case PrimitiveTypeKind.U8:
|
|
// return input;
|
|
// case PrimitiveTypeKind.F64:
|
|
// {
|
|
// var extName = GenVarName();
|
|
// _builder.AppendLine($" {extName} =l extsh {input}");
|
|
// _builder.AppendLine($" {outputName} =d sltof {extName}");
|
|
// return outputName;
|
|
// }
|
|
// case PrimitiveTypeKind.F32:
|
|
// {
|
|
// var extName = GenVarName();
|
|
// _builder.AppendLine($" {extName} =w extsh {input}");
|
|
// _builder.AppendLine($" {outputName} =s swtof {extName}");
|
|
// return outputName;
|
|
// }
|
|
// case PrimitiveTypeKind.String:
|
|
// {
|
|
// var extName = GenVarName();
|
|
// _builder.AppendLine($" {extName} =w extsh {input}");
|
|
// _builder.AppendLine($" {outputName} =l call $nub_i32_to_string(w {extName})");
|
|
// return outputName;
|
|
// }
|
|
// case PrimitiveTypeKind.Any:
|
|
// {
|
|
// var extName = GenVarName();
|
|
// _builder.AppendLine($" {extName} =l extsh {input}");
|
|
// return extName;
|
|
// }
|
|
// case PrimitiveTypeKind.Bool:
|
|
// default:
|
|
// throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported");
|
|
// }
|
|
// case PrimitiveTypeKind.I8:
|
|
// switch (primitiveOutputType.Kind)
|
|
// {
|
|
// case PrimitiveTypeKind.I64:
|
|
// case PrimitiveTypeKind.U64:
|
|
// _builder.AppendLine($" {outputName} =l extsb {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.I32:
|
|
// case PrimitiveTypeKind.U32:
|
|
// case PrimitiveTypeKind.I16:
|
|
// case PrimitiveTypeKind.U16:
|
|
// _builder.AppendLine($" {outputName} =w extsb {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.I8:
|
|
// case PrimitiveTypeKind.U8:
|
|
// return input;
|
|
// case PrimitiveTypeKind.F64:
|
|
// {
|
|
// var extName = GenVarName();
|
|
// _builder.AppendLine($" {extName} =l extsb {input}");
|
|
// _builder.AppendLine($" {outputName} =d sltof {extName}");
|
|
// return outputName;
|
|
// }
|
|
// case PrimitiveTypeKind.F32:
|
|
// {
|
|
// var extName = GenVarName();
|
|
// _builder.AppendLine($" {extName} =w extsb {input}");
|
|
// _builder.AppendLine($" {outputName} =s swtof {extName}");
|
|
// return outputName;
|
|
// }
|
|
// case PrimitiveTypeKind.String:
|
|
// {
|
|
// var extName = GenVarName();
|
|
// _builder.AppendLine($" {extName} =w extsb {input}");
|
|
// _builder.AppendLine($" {outputName} =l call $nub_i32_to_string(w {extName})");
|
|
// return outputName;
|
|
// }
|
|
// case PrimitiveTypeKind.Any:
|
|
// {
|
|
// var extName = GenVarName();
|
|
// _builder.AppendLine($" {extName} =l extsb {input}");
|
|
// return extName;
|
|
// }
|
|
// case PrimitiveTypeKind.Bool:
|
|
// default:
|
|
// throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported");
|
|
// }
|
|
// case PrimitiveTypeKind.U64:
|
|
// switch (primitiveOutputType.Kind)
|
|
// {
|
|
// case PrimitiveTypeKind.I64:
|
|
// case PrimitiveTypeKind.U64:
|
|
// case PrimitiveTypeKind.I32:
|
|
// case PrimitiveTypeKind.U32:
|
|
// case PrimitiveTypeKind.I16:
|
|
// case PrimitiveTypeKind.U16:
|
|
// case PrimitiveTypeKind.I8:
|
|
// case PrimitiveTypeKind.U8:
|
|
// return input;
|
|
// case PrimitiveTypeKind.F64:
|
|
// _builder.AppendLine($" {outputName} =d ultof {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.F32:
|
|
// _builder.AppendLine($" {outputName} =s ultof {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.String:
|
|
// _builder.AppendLine($" {outputName} =l call $nub_u64_to_string(l {input})");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.Any:
|
|
// return input;
|
|
// case PrimitiveTypeKind.Bool:
|
|
// default:
|
|
// throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported");
|
|
// }
|
|
// case PrimitiveTypeKind.U32:
|
|
// switch (primitiveOutputType.Kind)
|
|
// {
|
|
// case PrimitiveTypeKind.I64:
|
|
// case PrimitiveTypeKind.U64:
|
|
// _builder.AppendLine($" {outputName} =l extuw {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.I32:
|
|
// case PrimitiveTypeKind.U32:
|
|
// case PrimitiveTypeKind.I16:
|
|
// case PrimitiveTypeKind.U16:
|
|
// case PrimitiveTypeKind.I8:
|
|
// case PrimitiveTypeKind.U8:
|
|
// return input;
|
|
// case PrimitiveTypeKind.F64:
|
|
// var extName = GenVarName();
|
|
// _builder.AppendLine($" {extName} =l extuw {input}");
|
|
// _builder.AppendLine($" {outputName} =d ultof {extName}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.F32:
|
|
// _builder.AppendLine($" {outputName} =s uwtof {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.String:
|
|
// _builder.AppendLine($" {outputName} =l call $nub_u32_to_string(w {input})");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.Any:
|
|
// var extAnyName = GenVarName();
|
|
// _builder.AppendLine($" {extAnyName} =l extuw {input}");
|
|
// return extAnyName;
|
|
// case PrimitiveTypeKind.Bool:
|
|
// default:
|
|
// throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported");
|
|
// }
|
|
// case PrimitiveTypeKind.U16:
|
|
// switch (primitiveOutputType.Kind)
|
|
// {
|
|
// case PrimitiveTypeKind.I64:
|
|
// case PrimitiveTypeKind.U64:
|
|
// _builder.AppendLine($" {outputName} =l extuh {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.I32:
|
|
// case PrimitiveTypeKind.U32:
|
|
// _builder.AppendLine($" {outputName} =w extuh {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.I16:
|
|
// case PrimitiveTypeKind.U16:
|
|
// case PrimitiveTypeKind.I8:
|
|
// case PrimitiveTypeKind.U8:
|
|
// return input;
|
|
// case PrimitiveTypeKind.F64:
|
|
// {
|
|
// var extName = GenVarName();
|
|
// _builder.AppendLine($" {extName} =l extuh {input}");
|
|
// _builder.AppendLine($" {outputName} =d ultof {extName}");
|
|
// return outputName;
|
|
// }
|
|
// case PrimitiveTypeKind.F32:
|
|
// {
|
|
// var extName = GenVarName();
|
|
// _builder.AppendLine($" {extName} =w extuh {input}");
|
|
// _builder.AppendLine($" {outputName} =s uwtof {extName}");
|
|
// return outputName;
|
|
// }
|
|
// case PrimitiveTypeKind.String:
|
|
// {
|
|
// var extName = GenVarName();
|
|
// _builder.AppendLine($" {extName} =w extuh {input}");
|
|
// _builder.AppendLine($" {outputName} =l call $nub_u32_to_string(w {extName})");
|
|
// return outputName;
|
|
// }
|
|
// case PrimitiveTypeKind.Any:
|
|
// {
|
|
// var extName = GenVarName();
|
|
// _builder.AppendLine($" {extName} =l extuh {input}");
|
|
// return extName;
|
|
// }
|
|
// case PrimitiveTypeKind.Bool:
|
|
// default:
|
|
// throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported");
|
|
// }
|
|
// case PrimitiveTypeKind.U8:
|
|
// switch (primitiveOutputType.Kind)
|
|
// {
|
|
// case PrimitiveTypeKind.I64:
|
|
// case PrimitiveTypeKind.U64:
|
|
// _builder.AppendLine($" {outputName} =l extub {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.I32:
|
|
// case PrimitiveTypeKind.U32:
|
|
// case PrimitiveTypeKind.I16:
|
|
// case PrimitiveTypeKind.U16:
|
|
// _builder.AppendLine($" {outputName} =w extub {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.I8:
|
|
// case PrimitiveTypeKind.U8:
|
|
// return input;
|
|
// case PrimitiveTypeKind.F64:
|
|
// {
|
|
// var extName = GenVarName();
|
|
// _builder.AppendLine($" {extName} =l extub {input}");
|
|
// _builder.AppendLine($" {outputName} =d ultof {extName}");
|
|
// return outputName;
|
|
// }
|
|
// case PrimitiveTypeKind.F32:
|
|
// {
|
|
// var extName = GenVarName();
|
|
// _builder.AppendLine($" {extName} =w extub {input}");
|
|
// _builder.AppendLine($" {outputName} =s uwtof {extName}");
|
|
// return outputName;
|
|
// }
|
|
// case PrimitiveTypeKind.String:
|
|
// {
|
|
// var extName = GenVarName();
|
|
// _builder.AppendLine($" {extName} =w extub {input}");
|
|
// _builder.AppendLine($" {outputName} =l call $nub_u32_to_string(w {extName})");
|
|
// return outputName;
|
|
// }
|
|
// case PrimitiveTypeKind.Any:
|
|
// {
|
|
// var extName = GenVarName();
|
|
// _builder.AppendLine($" {extName} =l extub {input}");
|
|
// return extName;
|
|
// }
|
|
// case PrimitiveTypeKind.Bool:
|
|
// default:
|
|
// throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported");
|
|
// }
|
|
// case PrimitiveTypeKind.F64:
|
|
// switch (primitiveOutputType.Kind)
|
|
// {
|
|
// case PrimitiveTypeKind.F64:
|
|
// case PrimitiveTypeKind.Any:
|
|
// return input;
|
|
// case PrimitiveTypeKind.F32:
|
|
// _builder.AppendLine($" {outputName} =s dtos {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.I64:
|
|
// _builder.AppendLine($" {outputName} =l dtosi {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.I32:
|
|
// case PrimitiveTypeKind.I16:
|
|
// case PrimitiveTypeKind.I8:
|
|
// _builder.AppendLine($" {outputName} =w dtosi {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.U64:
|
|
// _builder.AppendLine($" {outputName} =l dtoui {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.U32:
|
|
// case PrimitiveTypeKind.U16:
|
|
// case PrimitiveTypeKind.U8:
|
|
// _builder.AppendLine($" {outputName} =w dtoui {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.String:
|
|
// _builder.AppendLine($" {outputName} =l call $nub_f64_to_string(d {input})");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.Bool:
|
|
// default:
|
|
// throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported");
|
|
// }
|
|
// case PrimitiveTypeKind.F32:
|
|
// switch (primitiveOutputType.Kind)
|
|
// {
|
|
// case PrimitiveTypeKind.F64:
|
|
// _builder.AppendLine($" {outputName} =d stod {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.F32:
|
|
// return input;
|
|
// case PrimitiveTypeKind.I64:
|
|
// _builder.AppendLine($" {outputName} =l stosi {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.I32:
|
|
// case PrimitiveTypeKind.I16:
|
|
// case PrimitiveTypeKind.I8:
|
|
// _builder.AppendLine($" {outputName} =w stosi {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.U64:
|
|
// _builder.AppendLine($" {outputName} =l stoui {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.U32:
|
|
// case PrimitiveTypeKind.U16:
|
|
// case PrimitiveTypeKind.U8:
|
|
// _builder.AppendLine($" {outputName} =w stoui {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.String:
|
|
// _builder.AppendLine($" {outputName} =l call $nub_f32_to_string(s {input})");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.Any:
|
|
// throw new NotImplementedException();
|
|
// case PrimitiveTypeKind.Bool:
|
|
// default:
|
|
// throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported");
|
|
// }
|
|
// case PrimitiveTypeKind.Bool:
|
|
// switch (primitiveOutputType.Kind)
|
|
// {
|
|
// case PrimitiveTypeKind.Bool:
|
|
// return input;
|
|
// case PrimitiveTypeKind.Any:
|
|
// _builder.AppendLine($" {outputName} =l extsw {input}");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.String:
|
|
// _builder.AppendLine($" {outputName} =l call $nub_bool_to_string(s {input})");
|
|
// return outputName;
|
|
// case PrimitiveTypeKind.I64:
|
|
// case PrimitiveTypeKind.I32:
|
|
// case PrimitiveTypeKind.I16:
|
|
// case PrimitiveTypeKind.I8:
|
|
// case PrimitiveTypeKind.U64:
|
|
// case PrimitiveTypeKind.U32:
|
|
// case PrimitiveTypeKind.U16:
|
|
// case PrimitiveTypeKind.U8:
|
|
// case PrimitiveTypeKind.F64:
|
|
// case PrimitiveTypeKind.F32:
|
|
// default:
|
|
// throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported");
|
|
// }
|
|
// case PrimitiveTypeKind.String:
|
|
// switch (primitiveOutputType.Kind)
|
|
// {
|
|
// case PrimitiveTypeKind.String:
|
|
// case PrimitiveTypeKind.Any:
|
|
// return input;
|
|
// case PrimitiveTypeKind.I64:
|
|
// case PrimitiveTypeKind.I32:
|
|
// case PrimitiveTypeKind.I16:
|
|
// case PrimitiveTypeKind.I8:
|
|
// case PrimitiveTypeKind.U64:
|
|
// case PrimitiveTypeKind.U32:
|
|
// case PrimitiveTypeKind.U16:
|
|
// case PrimitiveTypeKind.U8:
|
|
// case PrimitiveTypeKind.F64:
|
|
// case PrimitiveTypeKind.F32:
|
|
// case PrimitiveTypeKind.Bool:
|
|
// default:
|
|
// throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported");
|
|
// }
|
|
// case PrimitiveTypeKind.Any:
|
|
// return input;
|
|
// default:
|
|
// throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported");
|
|
// }
|
|
// }
|
|
|
|
private string GenerateIdentifier(IdentifierNode identifier)
|
|
{
|
|
var variable = _variables[identifier.Identifier];
|
|
if (IsLargeType(identifier.Type))
|
|
{
|
|
return variable;
|
|
}
|
|
else
|
|
{
|
|
var outputName = GenVarName();
|
|
_builder.AppendLine($" {outputName} {QBEAssign(identifier.Type)} {QBELoad(identifier.Type)} {variable}");
|
|
return outputName;
|
|
}
|
|
}
|
|
|
|
private string GenerateLiteral(LiteralNode literal)
|
|
{
|
|
if (literal.Type.IsInteger)
|
|
{
|
|
switch (literal.Kind)
|
|
{
|
|
case LiteralKind.Integer:
|
|
return literal.Literal;
|
|
case LiteralKind.Float:
|
|
return literal.Literal.Split(".").First();
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
}
|
|
|
|
if (literal.Type.IsFloat64)
|
|
{
|
|
var value = double.Parse(literal.Literal, CultureInfo.InvariantCulture);
|
|
var bits = BitConverter.DoubleToInt64Bits(value);
|
|
return bits.ToString();
|
|
}
|
|
|
|
if (literal.Type.IsFloat32)
|
|
{
|
|
var value = float.Parse(literal.Literal, CultureInfo.InvariantCulture);
|
|
var bits = BitConverter.SingleToInt32Bits(value);
|
|
return bits.ToString();
|
|
}
|
|
|
|
switch (literal.Kind)
|
|
{
|
|
case LiteralKind.String:
|
|
_strings.Add(literal.Literal);
|
|
return $"$string{_strings.Count}";
|
|
case LiteralKind.Bool:
|
|
return bool.Parse(literal.Literal) ? "1" : "0";
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
}
|
|
|
|
private string GenerateStructInitializer(StructInitializerNode structInitializer)
|
|
{
|
|
var structDefinition = LookupStructDefinition(structInitializer.StructType.Namespace, structInitializer.StructType.Name);
|
|
|
|
var structVar = GenVarName();
|
|
var size = structDefinition.Fields.Sum(x => SizeOf(x.Type));
|
|
_builder.AppendLine($" {structVar} =l alloc8 {size}");
|
|
|
|
foreach (var field in structDefinition.Fields)
|
|
{
|
|
var offset = LookupMemberOffset(structDefinition, field.Name);
|
|
|
|
if (structInitializer.Initializers.TryGetValue(field.Name, out var fieldValue))
|
|
{
|
|
var var = GenerateExpression(fieldValue);
|
|
var offsetName = GenVarName();
|
|
_builder.AppendLine($" {offsetName} =l add {structVar}, {offset}");
|
|
|
|
if (IsLargeType(field.Type))
|
|
{
|
|
_builder.AppendLine($" blit {var}, {offsetName}, {SizeOf(field.Type)}");
|
|
}
|
|
else
|
|
{
|
|
_builder.AppendLine($" {QBEStore(field.Type)} {var}, {offsetName}");
|
|
}
|
|
}
|
|
else if (field.Value.HasValue)
|
|
{
|
|
var var = GenerateExpression(field.Value.Value);
|
|
var offsetName = GenVarName();
|
|
_builder.AppendLine($" {offsetName} =l add {structVar}, {offset}");
|
|
|
|
if (IsLargeType(field.Type))
|
|
{
|
|
_builder.AppendLine($" blit {var}, {offsetName}, {SizeOf(field.Type)}");
|
|
}
|
|
else
|
|
{
|
|
_builder.AppendLine($" {QBEStore(field.Type)} {var}, {offsetName}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Debug.Assert(false);
|
|
}
|
|
}
|
|
|
|
return structVar;
|
|
}
|
|
|
|
private string GenerateUnaryExpression(UnaryExpressionNode unaryExpression)
|
|
{
|
|
var operand = GenerateExpression(unaryExpression.Operand);
|
|
var outputName = GenVarName();
|
|
|
|
switch (unaryExpression.Operator)
|
|
{
|
|
case UnaryExpressionOperator.Negate:
|
|
{
|
|
switch (unaryExpression.Operand.Type)
|
|
{
|
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.I64 }:
|
|
_builder.AppendLine($" {outputName} =l neg {operand}");
|
|
return outputName;
|
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.I32 or PrimitiveTypeKind.I16 or PrimitiveTypeKind.I8 }:
|
|
_builder.AppendLine($" {outputName} =w neg {operand}");
|
|
return outputName;
|
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.F64 }:
|
|
_builder.AppendLine($" {outputName} =d neg {operand}");
|
|
return outputName;
|
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.F32 }:
|
|
_builder.AppendLine($" {outputName} =s neg {operand}");
|
|
return outputName;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case UnaryExpressionOperator.Invert:
|
|
{
|
|
switch (unaryExpression.Operand.Type)
|
|
{
|
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.Bool }:
|
|
_builder.AppendLine($" {outputName} =w xor {operand}, 1");
|
|
return outputName;
|
|
}
|
|
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
}
|
|
|
|
throw new NotSupportedException($"Unary operator {unaryExpression.Operator} for type {unaryExpression.Operand.Type} not supported");
|
|
}
|
|
|
|
private string GenerateMemberAccess(MemberAccessNode memberAccess)
|
|
{
|
|
var item = GenerateExpression(memberAccess.Expression);
|
|
|
|
switch (memberAccess.Expression.Type)
|
|
{
|
|
case NubArrayType:
|
|
{
|
|
if (memberAccess.Member == "count")
|
|
{
|
|
var outputName = GenVarName();
|
|
_builder.AppendLine($" {outputName} =l loadl {item}");
|
|
return outputName;
|
|
}
|
|
|
|
throw new ArgumentOutOfRangeException(nameof(memberAccess.Member));
|
|
}
|
|
case NubStructType structType:
|
|
{
|
|
var structDefinition = LookupStructDefinition(structType.Namespace, structType.Name);
|
|
var offset = LookupMemberOffset(structDefinition, memberAccess.Member);
|
|
|
|
var offsetName = GenVarName();
|
|
_builder.AppendLine($" {offsetName} =l add {item}, {offset}");
|
|
|
|
if (IsLargeType(memberAccess.Type))
|
|
{
|
|
return offsetName;
|
|
}
|
|
else
|
|
{
|
|
var outputName = GenVarName();
|
|
_builder.AppendLine($" {outputName} {QBEAssign(memberAccess.Type)} {QBELoad(memberAccess.Type)} {offsetName}");
|
|
|
|
return outputName;
|
|
}
|
|
}
|
|
default:
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(memberAccess.Expression.Type));
|
|
}
|
|
}
|
|
}
|
|
|
|
private string GenerateFixedArrayInitializer(FixedArrayInitializerNode fixedArrayInitializer)
|
|
{
|
|
var capacityInBytes = SizeOf(fixedArrayInitializer.Type);
|
|
var outputName = GenVarName();
|
|
_builder.AppendLine($" {outputName} =l alloc8 {capacityInBytes + 8}");
|
|
_builder.AppendLine($" storel {fixedArrayInitializer.Capacity}, {outputName}");
|
|
|
|
var dataPtr = GenVarName();
|
|
_builder.AppendLine($" {dataPtr} =l add {outputName}, 8");
|
|
_builder.AppendLine($" call $nub_memset(l {dataPtr}, w 0, l {capacityInBytes})");
|
|
|
|
return outputName;
|
|
}
|
|
|
|
private string GenerateFuncCall(FuncCallNode funcCall)
|
|
{
|
|
var funcDefinition = LookupFuncSignature(funcCall.Namespace, funcCall.Name);
|
|
if (funcDefinition == null)
|
|
{
|
|
throw new Exception($"Unknown function {funcCall}");
|
|
}
|
|
|
|
var parameterStrings = new List<string>();
|
|
|
|
for (var i = 0; i < funcCall.Parameters.Count; i++)
|
|
{
|
|
if (i < funcDefinition.Parameters.Count && funcDefinition.Parameters[i].Variadic)
|
|
{
|
|
parameterStrings.Add("...");
|
|
}
|
|
|
|
var parameter = funcCall.Parameters[i];
|
|
var result = GenerateExpression(parameter);
|
|
|
|
var qbeParameterType = QBEType(parameter.Type, TypeContext.FuncCall);
|
|
parameterStrings.Add($"{qbeParameterType} {result}");
|
|
}
|
|
|
|
var funcName = _funcNames[funcDefinition];
|
|
|
|
if (funcDefinition.ReturnType.HasValue)
|
|
{
|
|
var outputName = GenVarName();
|
|
_builder.AppendLine($" {outputName} {QBEAssign(funcCall.Type)} call {funcName}({string.Join(", ", parameterStrings)})");
|
|
return outputName;
|
|
}
|
|
else
|
|
{
|
|
_builder.AppendLine($" call {funcName}({string.Join(", ", parameterStrings)})");
|
|
return "this should never show up!";
|
|
}
|
|
}
|
|
|
|
private string GenVarName()
|
|
{
|
|
return $"%v{++_variableIndex}";
|
|
}
|
|
|
|
private string GenLabelName()
|
|
{
|
|
return $"@l{++_labelIndex}";
|
|
}
|
|
|
|
private IFuncSignature LookupFuncSignature(string @namespace, string name)
|
|
{
|
|
return _sourceFiles
|
|
.Where(f => f.Namespace == @namespace)
|
|
.SelectMany(f => f.Definitions)
|
|
.OfType<IFuncSignature>()
|
|
.Single(f => f.Name == name);
|
|
}
|
|
|
|
private StructDefinitionNode LookupStructDefinition(string @namespace, string name)
|
|
{
|
|
return _sourceFiles
|
|
.Where(f => f.Namespace == @namespace)
|
|
.SelectMany(f => f.Definitions)
|
|
.OfType<StructDefinitionNode>()
|
|
.Single(s => s.Name == name);
|
|
}
|
|
|
|
private int LookupMemberOffset(StructDefinitionNode structDefinition, string member)
|
|
{
|
|
return structDefinition.Fields.TakeWhile(f => f.Name != member).Sum(f => SizeOf(f.Type));
|
|
}
|
|
} |