private IEnumerable <QOperand> Emit_IConst(QOperand currentTask) { // node {const} {variableQualifier} {constExpr} var node = currentTask.ObjectNode; // Yield<Storage>: Variable name and type specifier, which should push the result to the stack yield return(new QOperand(currentTask.CurrentBlock, node.ChildNodes[1])); QVariable variable = ValueStack.Pop().ObjectValue as QVariable; if (variable is null) { throw new InvalidOperationException($"Stack expected to be retrieving a QVariable, but instead retrieved '{variable.GetType()}'"); } // Yield<Value>: Const operand value yield return(new QOperand(currentTask.CurrentBlock, node.ChildNodes[2])); object value = ValueStack.Pop().ObjectValue; variable.SetValue(value); // Register the variable with the environment Env.PutReadonly(variable); }
public static QVariable AllocConst(string typename, QObj environment, string contextName, string rootContext) { var type = environment.LocateType(typename); var variable = new QVariable(type, true); QContextEntry context = new QContextEntry(variable, contextName, rootContext); environment.PutContext(context.FullContext, context); return(variable); }
private IEnumerable <QOperand> Emit_ILet(QOperand currentTask) { // node {let} {variableQualifier} var node = currentTask.ObjectNode; // Yield<Storage>: Variable name and type specifier, which should push the result to the stack yield return(new QOperand(currentTask.CurrentBlock, node.ChildNodes[1])); QVariable variable = ValueStack.Pop().ObjectValue as QVariable; variable.IsConst = false; // Push storage into the current scope currentTask.CurrentBlock.AddScopedParameter(variable); }
private IEnumerable <QOperand> Emit_NamedBlock(QOperand currentTask) { // node {name} {paramsList} {codeBlock} var node = currentTask.ObjectNode; // Build context information string functionName = node.ChildNodes[0].Token.ValueString; string newContext = $"{currentTask.CurrentBlock.Context}.{functionName}"; // Create a new export QCodeBlock exportBlock = new QCodeBlock(newContext); QContextEntry contextEntry = new QContextEntry(exportBlock, functionName, currentTask.CurrentBlock.Context); Env.PutContext(newContext, contextEntry); // collect the parameter references foreach (var pnode in node.ChildNodes[1].ChildNodes) { yield return(new QOperand(exportBlock, pnode)); } // populate a params array var numParams = node.ChildNodes[1].ChildNodes.Count; QVariable[] parameters = new QVariable[numParams]; for (int i = parameters.Length - 1; i > -1; i--) { parameters[i] = ValueStack.Pop().ObjectValue as QVariable; if (parameters[i] is null) { throw new InvalidCastException($"Failed to create a qvariable from a parameter index {i}"); } } // Put params in the target export context exportBlock.SetParameters(parameters); // Link the export block into the current context so it is emitted currentTask.CurrentBlock.Add(exportBlock); // function.codeblock.directives yield return(new QOperand(exportBlock, node.ChildNodes[2].ChildNodes[0])); }
private IEnumerable <QOperand> Emit_IExtern(QOperand currentTask) { // node {extern} {variableQualifier} var node = currentTask.ObjectNode; // Yield<Storage>: Variable name and type specifier, which should push the result to the stack yield return(new QOperand(currentTask.CurrentBlock, node.ChildNodes[1])); QVariable variable = ValueStack.Pop().ObjectValue as QVariable; // Externs are simply context registered with no value. // These values must be validated though. Variables with size >= 8 that are not pointers will be rejected if (!variable.TypeInfo.IsReferenceType && variable.TypeInfo.Size > sizeof(ulong)) { throw new InvalidDataException("Externs must be a reference type, or of size less than 8."); } // Register the variable as an external with the environment Env.PutExtern(variable); }
private IEnumerable <QOperand> Emit_VarQualifier(QOperand currentTask) { // node {identifier} {typeAccessor}? var node = currentTask.ObjectNode; // Variable name string var_name = node.ChildNodes[0].Token.ValueString; string typeName = "qword"; if (node.ChildNodes.Count > 1) { typeName = node.ChildNodes[1].ChildNodes[0].Token.ValueString; } // Allocate a constant and push it to the stack. This is the default action for variables. The type of variable can be changed by the compiler to fit its needs. // This default readonly behavior will help to prevent invalid assignments to constant variables. var variable = QVariable.AllocConst(typeName, Env, currentTask.CurrentBlock.Context, var_name); ValueStack.Push(new QOperand(currentTask.CurrentBlock, variable)); yield break; }
public void AddScopedParameter(QVariable variable) { ScopedVariables.Add(variable); }
public void PutExtern(QVariable variable) { ExternCache.Add(variable); }
public void PutReadonly(QVariable variable) { ReadOnlyData.Add(variable); }