Exemple #1
0
        private IEnumerable <QOperand> Emit_ConstValue(QOperand currentTask)
        {
            // node stringLiteral | boolLiteral | numberLiteral
            var node = currentTask.ObjectNode;

            switch (node.ChildNodes[0].Term.Name)
            {
            case NUMBER_LITERAL:
                ValueStack.Push(new QOperand(currentTask.CurrentBlock, node.ChildNodes[0].Token.Value));
                break;

            case STRING_LITERAL:
                ValueStack.Push(new QOperand(currentTask.CurrentBlock, node.ChildNodes[0].Token.ValueString));
                break;

            case BOOL_LITERAL:
                ValueStack.Push(new QOperand(currentTask.CurrentBlock, node.ChildNodes[0].Token.ValueString == "true"));
                break;

            default:
                throw new Exception("Unknown or unhandled type inside constexpr node");
            }

            yield break;
        }
Exemple #2
0
        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);
        }
Exemple #3
0
        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);
        }
Exemple #4
0
        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]));
        }
Exemple #5
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);
        }
Exemple #6
0
        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;
        }
Exemple #7
0
 private void PushValue(QOperand op)
 {
     ValueStack.Push(op);
 }
Exemple #8
0
 private void PushTask(QOperand op)
 {
     TaskStack.Push(op);
 }