예제 #1
0
    private static StatementData CheckStatement_LocalVarDef(
        ref PassData passData, TypeData retType,
        ES_AstLocalVarDefinition varDef
        )
    {
        var idPool   = passData.Env.IdPool;
        var symbols  = passData.Symbols;
        var irWriter = passData.IRWriter;

        var typeUnknMut = passData.GetUnknownType(Constness.Mutable);

        var implicitType = varDef.ValueType is null;

        var varType = !implicitType?UnpackFirstConst(GetTypeRef (varDef.ValueType)) : TypeData.Null;

        var allVarsFlags = (SymbolFlags)0;

        if (varDef.UsingVar)
        {
            allVarsFlags |= SymbolFlags.UsingVar;
        }

        foreach (var variable in varDef.Variables)
        {
            var varName   = variable.Name.Text.Span;
            var varNameId = idPool.GetIdentifier(varName);

            using var exprList = new ExpressionList(null, null);
            ExpressionData  varExprData;
            ESIR_Expression?valueExpr;
            int?            valueReg;

            var varFlags = allVarsFlags;

            if (!implicitType)
            {
                if (variable.InitializationExpression is not null)
                {
                    varExprData = CheckExpression(ref passData, variable.InitializationExpression, varType);
                    EnsureCompat(ref varExprData, varType, ref passData, varExprData.Expr.NodeBounds);

                    exprList.Merge(ref varExprData.Expressions);

                    valueExpr = varExprData.Value;
                    valueReg  = varExprData.ValueRegister;
                }
                else
                {
                    varExprData = default;
                    valueExpr   = null;
                    valueReg    = null;
                }
            }
            else
            {
                Debug.Assert(variable.InitializationExpression is not null);
                varExprData = CheckExpression(ref passData, variable.InitializationExpression, typeUnknMut);

                exprList.Merge(ref varExprData.Expressions);

                varType   = varExprData.Type;
                valueExpr = varExprData.Value;
                valueReg  = varExprData.ValueRegister;

                if (varType.Type is not null && varType.Type->TypeTag == ES_TypeTag.Null)
                {
                    passData.ErrorList.Add(new (passData.Source, varExprData.Expr.NodeBounds, ES_FrontendErrors.NoImplicitNullVars));

                    varType = typeUnknMut;
                }
예제 #2
0
    private static StatementData CheckStatement(
        ref PassData passData, TypeData retType,
        ES_AstStatement stmt
        )
    {
        var idPool      = passData.Env.IdPool;
        var typeUnknMut = passData.GetUnknownType(Constness.Mutable);

        switch (stmt)
        {
        case ES_AstEmptyStatement:
            return(new StatementData {
                AlwaysReturns = false
            });

        case ES_AstLabeledStatement:
            throw new NotImplementedException("[TODO] Labels not implemented yet.");

        case ES_AstBlockStatement blockStmt:
            return(CheckStatement_Block(ref passData, retType, blockStmt));

            #region Symbol definition

        case ES_AstImportStatement importStmt:
            HandleImport(ref passData, importStmt);
            return(new StatementData {
                AlwaysReturns = false
            });

        case ES_AstTypeAlias aliasStmt:
            HandleAlias(ref passData, aliasStmt);
            return(new StatementData {
                AlwaysReturns = false
            });

        case ES_AstLocalVarDefinition varDef:
            return(CheckStatement_LocalVarDef(ref passData, retType, varDef));

            #endregion

            #region Jumps

        case ES_AstConditionalStatement condStmt:
            return(CheckStatement_Conditional(ref passData, retType, condStmt));

        case ES_AstSwitchStatement: {
            throw new NotImplementedException("[TODO] Switches not implemented yet.");

            /*var exprTypeData = CheckTypes_Expression (ref transUnit, symbols, src, switchStmt.ValueExpression, typeUnkn);
             *
             * foreach (var section in switchStmt.Sections) {
             *  foreach (var expr in section.Expressions) {
             *      if (expr is not null) {
             *          var sectionTypeData = CheckTypes_Expression (ref transUnit, symbols, src, expr, exprTypeData.Type);
             *
             *          if (!sectionTypeData.Constant) {
             *              errorList.Add (new (
             *                  src, expr.NodeBounds, ES_FrontendErrors.ConstantExprExpected
             *              ));
             *          }
             *
             *          if (!CheckTypes_MustBeCompat (exprTypeData.Type, sectionTypeData.Type, out var sectionConst)) {
             *              errorList.Add (ES_FrontendErrors.GenNoCast (
             *                  exprTypeData.Type->Name.GetNameAsTypeString (), sectionTypeData.Type->Name.GetNameAsTypeString (),
             *                  src, sectionTypeData.Expr.NodeBounds
             *              ));
             *          }
             *
             *          if (!sectionTypeData.Constant || !sectionConst) {
             *              errorList.Add (new (
             *                  src, expr.NodeBounds, ES_FrontendErrors.ConstantExprExpected
             *              ));
             *          }
             *      }
             *  }
             *
             *  ES_AstStatement? subStmt = section.StatementsBlock;
             *  while (subStmt is not null) {
             *      CheckTypes_Statement (ref transUnit, symbols, src, retType, subStmt);
             *
             *      subStmt = subStmt.Endpoint;
             *  }
             * }
             *
             * // TODO: Change Switch statements to check if they always return.
             * return new StatementData { AlwaysReturns = false };*/
        }

        case ES_AstBreakStatement breakStmt: {
            var irStmt = breakStmt.LabelName is not null
                    ? BreakStatement(idPool.GetIdentifier(breakStmt.LabelName.Value.Text.Span))
                    : BreakStatement();

            passData.IRWriter.AddStatement(irStmt);

            return(new StatementData {
                    AlwaysReturns = false,
                });
        }

        case ES_AstContinueStatement continueStmt: {
            var irStmt = continueStmt.LabelName is not null
                    ? ContinueStatement(idPool.GetIdentifier(continueStmt.LabelName.Value.Text.Span))
                    : ContinueStatement();

            passData.IRWriter.AddStatement(irStmt);

            return(new StatementData {
                    AlwaysReturns = false,
                });
        }

        case ES_AstGotoCaseStatement:
            throw new NotImplementedException("[TODO] 'goto case' not implemented yet.");

        case ES_AstReturnStatement retStmt:
            return(CheckStatement_Return(ref passData, retType, retStmt));

            #endregion

        case ES_AstLoopStatement loopStmt:
            return(CheckStatement_Loop(ref passData, retType, loopStmt));

        case ES_AstExpressionStatement exprStmt: {
            var exprData = CheckExpression(ref passData, exprStmt.Expression, typeUnknMut);
            FinishExpression(ref passData, ref exprData);

            return(new StatementData {
                    AlwaysReturns = false
                });
        }

        case ES_AstExpressionListStatement exprListStmt: {
            foreach (var expr in exprListStmt.Expressions)
            {
                var exprData = CheckExpression(ref passData, expr, passData.GetUnknownType(Constness.Mutable));
                FinishExpression(ref passData, ref exprData);
            }

            return(new StatementData {
                    AlwaysReturns = false
                });
        }

        default:
            throw new NotImplementedException("Statement type not implemented.");
        }
    }
예제 #3
0
    private static void CheckFunction(
        ref PassData passData,
        ES_TypeInfo *parentType, ES_NamespaceData?namespaceData,
        ES_AstFunctionDefinition funcDef
        )
    {
        Debug.Assert(parentType is not null || namespaceData is not null);

        var idPool   = passData.Env.IdPool;
        var symbols  = passData.Symbols;
        var irWriter = passData.IRWriter;

        var funcName = idPool.GetIdentifier(funcDef.Name.Text.Span);
        var retType  = UnpackFirstConst(GetTypeRef(funcDef.ReturnType));

        Debug.Assert(retType.Type is not null);

        ES_FunctionData *funcData;

        if (namespaceData is not null)
        {
            if (!namespaceData.Functions.TryGetValue(funcName, out var funcDataPtr))
            {
                Debug.Fail("This shouldn't ever be reached.");
            }

            funcData = funcDataPtr.Address;
        }
        else
        {
            throw new NotImplementedException("[TODO] Member functions not implemented yet.");
        }

        symbols.Push();

        irWriter.StartFunction(MangleFunctionName(ref passData, funcData), TypeNode(ref passData, retType));

        foreach (var arg in funcDef.ArgumentsList)
        {
            var argName    = idPool.GetIdentifier(arg.Name.Text.Span);
            var argValType = UnpackFirstConst(GetTypeRef(arg.ValueType));

            var flags = (SymbolFlags)0;

            var argType = arg.ArgType;
            switch (argType)
            {
            case ES_ArgumentType.Normal:
                break;

            case ES_ArgumentType.Ref:
                flags |= SymbolFlags.RefVar;
                break;

            case ES_ArgumentType.In:
                if (argValType.Constness != Constness.Mutable)
                {
                    passData.ErrorList.Add(ES_FrontendErrors.GenTypeAlreadyConst(
                                               false, argValType.Constness == Constness.Immutable,
                                               arg.Name
                                               ));
                    break;
                }

                argType    = ES_ArgumentType.Normal;
                argValType = argValType.WithConst(Constness.Const);
                break;

            case ES_ArgumentType.Out:
                throw new NotImplementedException("[TODO] Argument type not implemented yet.");

            default:
                throw new NotImplementedException("Argument type not implemented yet.");
            }

            if (argValType.IsWritable)
            {
                flags |= SymbolFlags.Writable;
            }

            var argIdx = irWriter.AddArgument(ArgumentDefinition(argType, TypeNode(ref passData, argValType)));
            if (!symbols.AddSymbol(argName, TCSymbol.NewVariable(argValType, ArgumentExpression(argIdx), flags)))
            {
                Debug.Fail("This shouldn't be reachable.");
            }

            if (arg.DefaultExpression is not null)
            {
                var argDefExpr = CheckExpression(ref passData, arg.DefaultExpression, argValType);
                EnsureCompat(ref argDefExpr, argValType, ref passData, arg.DefaultExpression.NodeBounds);
            }
        }

        // Emit the function body.
        Debug.Assert(funcDef.Statement is not null);
        Debug.Assert(funcDef.Statement.Endpoint is null);
        if (funcDef.ExpressionBody)
        {
            Debug.Assert(funcDef.Statement is ES_AstExpressionStatement);

            var exprExpType = retType.Type->TypeTag != ES_TypeTag.Void ? retType : passData.GetUnknownType(Constness.Mutable);
            var exprStmt    = (funcDef.Statement as ES_AstExpressionStatement) !;
            var exprData    = CheckExpression(ref passData, exprStmt.Expression, exprExpType);

            if (retType.Type->TypeTag != ES_TypeTag.Void)
            {
                if (!EnsureCompat(ref exprData, retType, ref passData, exprData.Expr.NodeBounds))
                {
                    passData.ErrorList.Add(new (funcDef.Name, ES_FrontendErrors.MissingReturnStatement));
                }
            }

            using var exprList = exprData.Expressions;

            foreach (var expr in exprList.Expressions)
            {
                irWriter.AddStatement(ExpressionStatement(expr));
            }

            if (retType.Type->TypeTag != ES_TypeTag.Void)
            {
                irWriter.AddStatement(ReturnStatement(exprData.Value));
            }
            else
            {
                irWriter.AddStatement(ExpressionStatement(exprData.Value));
            }

            irWriter.AddScopeRegisters(exprList.Registers);
            irWriter.AddScopeRegister(exprData.ValueRegister);
        }
        else
        {
            var stmtData = CheckStatement(ref passData, retType, funcDef.Statement);

            if (!stmtData.AlwaysReturns && retType.Type->TypeTag != ES_TypeTag.Void)
            {
                passData.ErrorList.Add(new (funcDef.Name, ES_FrontendErrors.MissingReturnStatement));
            }
        }

        symbols.Pop();

        ESIR_TraceDataAttribute    traceDataAttr;
        ESIR_FunctionDataAttribute funcDataAttr;

        if (parentType is not null)
        {
            traceDataAttr = TraceDataAttribute(
                parentType->Name.NamespaceName,
                funcName,
                parentType->Name.TypeName,
                funcDef.Name.FileName.Span.GetPooledString()
                );

            funcDataAttr = FunctionDataAttribute(funcData, parentType);
        }
        else
        {
            traceDataAttr = TraceDataAttribute(
                namespaceData.NamespaceName,
                funcName,
                funcDef.Name.FileName.Span.GetPooledString()
                );

            funcDataAttr = FunctionDataAttribute(funcData);
        }

        irWriter.EndFunction(List <ESIR_Attribute> (traceDataAttr, funcDataAttr));
    }