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; }
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."); } }
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)); }