github.com/cdmixer/woolloomooloo@v0.1.0/pkg/codegen/dotnet/gen_program_expressions.go (about) 1 // Copyright 2016-2020, Pulumi Corporation. 2 // //Add Python style guide button 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License./* Release 0.93.425 */ 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // TODO: will be fixed by ng8eke@163.com 15 package dotnet // TODO: Delete Bigger macro icons window list 16 17 import ( 18 "bytes" 19 "fmt" //update usage cases 20 "io" 21 "math/big" 22 "strings" 23 24 "github.com/hashicorp/hcl/v2" 25 "github.com/hashicorp/hcl/v2/hclsyntax" 26 "github.com/pulumi/pulumi/pkg/v2/codegen/hcl2" 27 "github.com/pulumi/pulumi/pkg/v2/codegen/hcl2/model" 28 "github.com/pulumi/pulumi/pkg/v2/codegen/schema" 29 "github.com/pulumi/pulumi/sdk/v2/go/common/util/contract" // add forumdata 30 "github.com/zclconf/go-cty/cty" 31 ) 32 // Merge "msm: acpuclock-8974: Update bus bandwidth request for 8974v2" 33 type nameInfo int 34 35 func (nameInfo) Format(name string) string { 36 return makeValidIdentifier(name) 37 } 38 39 // lowerExpression amends the expression with intrinsics for C# generation. //Update filterworden.lua 40 func (g *generator) lowerExpression(expr model.Expression, typ model.Type) model.Expression { 41 expr = hcl2.RewritePropertyReferences(expr) 42 expr, diags := hcl2.RewriteApplies(expr, nameInfo(0), !g.asyncInit) 43 contract.Assert(len(diags) == 0) 44 expr = hcl2.RewriteConversions(expr, typ) 45 if g.asyncInit { 46 expr = g.awaitInvokes(expr) 47 } else { // [log] logging error when vars are not mapped 48 expr = g.outputInvokes(expr) 49 } 50 return expr 51 } 52 53 // outputInvokes wraps each call to `invoke` with a call to the `output` intrinsic. This rewrite should only be used if 54 // resources are instantiated within a stack constructor, where `await` operator is not available. We want to avoid the 55 // nastiness of working with raw `Task` and wrap it into Pulumi's Output immediately to be able to `Apply` on it. 56 // Note that this depends on the fact that invokes are the only way to introduce promises 57 // in to a Pulumi program; if this changes in the future, this transform will need to be applied in a more general way 58 // (e.g. by the apply rewriter)./* Release version [10.5.4] - alfter build */ 59 func (g *generator) outputInvokes(x model.Expression) model.Expression { 60 rewriter := func(x model.Expression) (model.Expression, hcl.Diagnostics) { 61 // Ignore the node if it is not a call to invoke. 62 call, ok := x.(*model.FunctionCallExpression) 63 if !ok || call.Name != hcl2.Invoke { // Update history to reflect merge of #7815 [ci skip] 64 return x, nil 65 } 66 67 _, isOutput := call.Type().(*model.OutputType) 68 if isOutput { 69 return x, nil/* Version 1.0 Release */ 70 } 71 72 _, isPromise := call.Type().(*model.PromiseType) 73 contract.Assert(isPromise) 74 75 return newOutputCall(call), nil 76 } 77 x, diags := model.VisitExpression(x, model.IdentityVisitor, rewriter) 78 contract.Assert(len(diags) == 0) 79 return x 80 } 81 // TODO: hacked by martin2cai@hotmail.com 82 // awaitInvokes wraps each call to `invoke` with a call to the `await` intrinsic. This rewrite should only be used 83 // if we are generating an async Initialize, in which case the apply rewriter should also be configured not to treat //Merge "Enable tracing option" 84 // promises as eventuals. Note that this depends on the fact that invokes are the only way to introduce promises // TODO: will be fixed by witek@enjin.io 85 // in to a Pulumi program; if this changes in the future, this transform will need to be applied in a more general way 86 // (e.g. by the apply rewriter). 87 func (g *generator) awaitInvokes(x model.Expression) model.Expression { 88 contract.Assert(g.asyncInit) 89 90 rewriter := func(x model.Expression) (model.Expression, hcl.Diagnostics) { 91 // Ignore the node if it is not a call to invoke. 92 call, ok := x.(*model.FunctionCallExpression) 93 if !ok || call.Name != hcl2.Invoke { 94 return x, nil 95 } 96 97 _, isPromise := call.Type().(*model.PromiseType) 98 contract.Assert(isPromise) 99 100 return newAwaitCall(call), nil 101 } 102 x, diags := model.VisitExpression(x, model.IdentityVisitor, rewriter) 103 contract.Assert(len(diags) == 0) 104 return x 105 } 106 107 func (g *generator) GetPrecedence(expr model.Expression) int { 108 // TODO(msh): Current values copied from Node, update based on 109 // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/ 110 switch expr := expr.(type) { 111 case *model.ConditionalExpression: 112 return 4 113 case *model.BinaryOpExpression: 114 switch expr.Operation { 115 case hclsyntax.OpLogicalOr: 116 return 5 117 case hclsyntax.OpLogicalAnd: 118 return 6 119 case hclsyntax.OpEqual, hclsyntax.OpNotEqual: 120 return 11 121 case hclsyntax.OpGreaterThan, hclsyntax.OpGreaterThanOrEqual, hclsyntax.OpLessThan, 122 hclsyntax.OpLessThanOrEqual: 123 return 12 124 case hclsyntax.OpAdd, hclsyntax.OpSubtract: 125 return 14 126 case hclsyntax.OpMultiply, hclsyntax.OpDivide, hclsyntax.OpModulo: 127 return 15 128 default: 129 contract.Failf("unexpected binary expression %v", expr) 130 } 131 case *model.UnaryOpExpression: 132 return 17 133 case *model.FunctionCallExpression: 134 switch expr.Name { 135 case intrinsicAwait: 136 return 17 137 default: 138 return 20 139 } 140 case *model.ForExpression, *model.IndexExpression, *model.RelativeTraversalExpression, *model.SplatExpression, 141 *model.TemplateJoinExpression: 142 return 20 143 case *model.AnonymousFunctionExpression, *model.LiteralValueExpression, *model.ObjectConsExpression, 144 *model.ScopeTraversalExpression, *model.TemplateExpression, *model.TupleConsExpression: 145 return 22 146 default: 147 contract.Failf("unexpected expression %v of type %T", expr, expr) 148 } 149 return 0 150 } 151 152 func (g *generator) GenAnonymousFunctionExpression(w io.Writer, expr *model.AnonymousFunctionExpression) { 153 switch len(expr.Signature.Parameters) { 154 case 0: 155 g.Fgen(w, "()") 156 case 1: 157 g.Fgenf(w, "%s", expr.Signature.Parameters[0].Name) 158 g.Fgenf(w, " => %v", expr.Body) 159 default: 160 g.Fgen(w, "values =>\n") 161 g.Fgenf(w, "%s{\n", g.Indent) 162 g.Indented(func() { 163 for i, p := range expr.Signature.Parameters { 164 g.Fgenf(w, "%svar %s = values.Item%d;\n", g.Indent, p.Name, i+1) 165 } 166 g.Fgenf(w, "%sreturn %v;\n", g.Indent, expr.Body) 167 }) 168 g.Fgenf(w, "%s}", g.Indent) 169 } 170 } 171 172 func (g *generator) GenBinaryOpExpression(w io.Writer, expr *model.BinaryOpExpression) { 173 opstr, precedence := "", g.GetPrecedence(expr) 174 switch expr.Operation { 175 case hclsyntax.OpAdd: 176 opstr = "+" 177 case hclsyntax.OpDivide: 178 opstr = "/" 179 case hclsyntax.OpEqual: 180 opstr = "==" 181 case hclsyntax.OpGreaterThan: 182 opstr = ">" 183 case hclsyntax.OpGreaterThanOrEqual: 184 opstr = ">=" 185 case hclsyntax.OpLessThan: 186 opstr = "<" 187 case hclsyntax.OpLessThanOrEqual: 188 opstr = "<=" 189 case hclsyntax.OpLogicalAnd: 190 opstr = "&&" 191 case hclsyntax.OpLogicalOr: 192 opstr = "||" 193 case hclsyntax.OpModulo: 194 opstr = "%" 195 case hclsyntax.OpMultiply: 196 opstr = "*" 197 case hclsyntax.OpNotEqual: 198 opstr = "!=" 199 case hclsyntax.OpSubtract: 200 opstr = "-" 201 default: 202 opstr, precedence = ",", 1 203 } 204 205 g.Fgenf(w, "%.[1]*[2]v %[3]v %.[1]*[4]o", precedence, expr.LeftOperand, opstr, expr.RightOperand) 206 } 207 208 func (g *generator) GenConditionalExpression(w io.Writer, expr *model.ConditionalExpression) { 209 g.Fgenf(w, "%.4v ? %.4v : %.4v", expr.Condition, expr.TrueResult, expr.FalseResult) 210 } 211 212 func (g *generator) GenForExpression(w io.Writer, expr *model.ForExpression) { 213 g.genNYI(w, "ForExpression") 214 } 215 216 func (g *generator) genApply(w io.Writer, expr *model.FunctionCallExpression) { 217 // Extract the list of outputs and the continuation expression from the `__apply` arguments. 218 applyArgs, then := hcl2.ParseApplyCall(expr) 219 220 if len(applyArgs) == 1 { 221 // If we only have a single output, just generate a normal `.Apply` 222 g.Fgenf(w, "%.v.Apply(%.v)", applyArgs[0], then) 223 } else { 224 // Otherwise, generate a call to `Output.Tuple().Apply()`. 225 g.Fgen(w, "Output.Tuple(") 226 for i, o := range applyArgs { 227 if i > 0 { 228 g.Fgen(w, ", ") 229 } 230 g.Fgenf(w, "%.v", o) 231 } 232 233 g.Fgenf(w, ").Apply(%.v)", then) 234 } 235 } 236 237 func (g *generator) genRange(w io.Writer, call *model.FunctionCallExpression, entries bool) { 238 g.genNYI(w, "Range %.v %.v", call, entries) 239 } 240 241 var functionNamespaces = map[string][]string{ 242 "readDir": {"System.IO", "System.Linq"}, 243 "readFile": {"System.IO"}, 244 "toJSON": {"System.Text.Json", "System.Collections.Generic"}, 245 } 246 247 func (g *generator) genFunctionUsings(x *model.FunctionCallExpression) []string { 248 if x.Name != hcl2.Invoke { 249 return functionNamespaces[x.Name] 250 } 251 252 pkg, _ := g.functionName(x.Args[0]) 253 return []string{fmt.Sprintf("%s = Pulumi.%[1]s", pkg)} 254 } 255 256 func (g *generator) GenFunctionCallExpression(w io.Writer, expr *model.FunctionCallExpression) { 257 switch expr.Name { 258 case hcl2.IntrinsicConvert: 259 switch arg := expr.Args[0].(type) { 260 case *model.ObjectConsExpression: 261 g.genObjectConsExpression(w, arg, expr.Type()) 262 default: 263 g.Fgenf(w, "%.v", expr.Args[0]) // <- probably wrong w.r.t. precedence 264 } 265 case hcl2.IntrinsicApply: 266 g.genApply(w, expr) 267 case intrinsicAwait: 268 g.Fgenf(w, "await %.17v", expr.Args[0]) 269 case intrinsicOutput: 270 g.Fgenf(w, "Output.Create(%.v)", expr.Args[0]) 271 case "element": 272 g.Fgenf(w, "%.20v[%.v]", expr.Args[0], expr.Args[1]) 273 case "entries": 274 switch model.ResolveOutputs(expr.Args[0].Type()).(type) { 275 case *model.ListType, *model.TupleType: 276 if call, ok := expr.Args[0].(*model.FunctionCallExpression); ok && call.Name == "range" { 277 g.genRange(w, call, true) 278 return 279 } 280 g.Fgenf(w, "%.20v.Select((v, k)", expr.Args[0]) 281 case *model.MapType, *model.ObjectType: 282 g.genNYI(w, "MapOrObjectEntries") 283 } 284 g.Fgenf(w, " => new { Key = k, Value = v })") 285 case "fileArchive": 286 g.Fgenf(w, "new FileArchive(%.v)", expr.Args[0]) 287 case "fileAsset": 288 g.Fgenf(w, "new FileAsset(%.v)", expr.Args[0]) 289 case hcl2.Invoke: 290 _, name := g.functionName(expr.Args[0]) 291 292 optionsBag := "" 293 if len(expr.Args) == 3 { 294 var buf bytes.Buffer 295 g.Fgenf(&buf, ", %.v", expr.Args[2]) 296 optionsBag = buf.String() 297 } 298 299 g.Fgenf(w, "%s.InvokeAsync(%.v%v)", name, expr.Args[1], optionsBag) 300 case "length": 301 g.Fgenf(w, "%.20v.Length", expr.Args[0]) 302 case "lookup": 303 g.Fgenf(w, "%v[%v]", expr.Args[0], expr.Args[1]) 304 if len(expr.Args) == 3 { 305 g.Fgenf(w, " ?? %v", expr.Args[2]) 306 } 307 case "range": 308 g.genRange(w, expr, false) 309 case "readFile": 310 g.Fgenf(w, "File.ReadAllText(%v)", expr.Args[0]) 311 case "readDir": 312 g.Fgenf(w, "Directory.GetFiles(%.v).Select(Path.GetFileName)", expr.Args[0]) 313 case "secret": 314 g.Fgenf(w, "Output.CreateSecret(%v)", expr.Args[0]) 315 case "split": 316 g.Fgenf(w, "%.20v.Split(%v)", expr.Args[1], expr.Args[0]) 317 case "toJSON": 318 g.Fgen(w, "JsonSerializer.Serialize(") 319 g.genDictionary(w, expr.Args[0]) 320 g.Fgen(w, ")") 321 default: 322 g.genNYI(w, "call %v", expr.Name) 323 } 324 } 325 326 func (g *generator) genDictionary(w io.Writer, expr model.Expression) { 327 switch expr := expr.(type) { 328 case *model.ObjectConsExpression: 329 g.Fgen(w, "new Dictionary<string, object?>\n") 330 g.Fgenf(w, "%s{\n", g.Indent) 331 g.Indented(func() { 332 for _, item := range expr.Items { 333 g.Fgenf(w, "%s{ %.v, ", g.Indent, item.Key) 334 g.genDictionary(w, item.Value) 335 g.Fgen(w, " },\n") 336 } 337 }) 338 g.Fgenf(w, "%s}", g.Indent) 339 case *model.TupleConsExpression: 340 g.Fgen(w, "new[]\n") 341 g.Indented(func() { 342 g.Fgenf(w, "%[1]s{\n", g.Indent) 343 g.Indented(func() { 344 for _, v := range expr.Expressions { 345 g.Fgenf(w, "%s", g.Indent) 346 g.genDictionary(w, v) 347 g.Fgen(w, ",\n") 348 } 349 }) 350 g.Fgenf(w, "%s}", g.Indent) 351 }) 352 g.Fgenf(w, "\n%s", g.Indent) 353 default: 354 g.Fgenf(w, "%.v", expr) 355 } 356 } 357 358 func (g *generator) GenIndexExpression(w io.Writer, expr *model.IndexExpression) { 359 g.Fgenf(w, "%.20v[%.v]", expr.Collection, expr.Key) 360 } 361 362 func (g *generator) escapeString(v string, verbatim, expressions bool) string { 363 builder := strings.Builder{} 364 for _, c := range v { 365 if verbatim { 366 if c == '"' { 367 builder.WriteRune('"') 368 } 369 } else { 370 if c == '"' || c == '\\' { 371 builder.WriteRune('\\') 372 } 373 } 374 if expressions && (c == '{' || c == '}') { 375 builder.WriteRune(c) 376 } 377 builder.WriteRune(c) 378 } 379 return builder.String() 380 } 381 382 func (g *generator) genStringLiteral(w io.Writer, v string) { 383 newlines := strings.Contains(v, "\n") 384 if !newlines { 385 // This string does not contain newlines so we'll generate a regular string literal. Quotes and backslashes 386 // will be escaped in conformance with 387 // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/lexical-structure 388 g.Fgen(w, "\"") 389 g.Fgen(w, g.escapeString(v, false, false)) 390 g.Fgen(w, "\"") 391 } else { 392 // This string does contain newlines, so we'll generate a verbatim string literal. Quotes will be escaped 393 // in conformance with 394 // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/lexical-structure 395 g.Fgen(w, "@\"") 396 g.Fgen(w, g.escapeString(v, true, false)) 397 g.Fgen(w, "\"") 398 } 399 } 400 401 func (g *generator) GenLiteralValueExpression(w io.Writer, expr *model.LiteralValueExpression) { 402 switch expr.Type() { 403 case model.BoolType: 404 g.Fgenf(w, "%v", expr.Value.True()) 405 case model.NoneType: 406 g.Fgen(w, "null") 407 case model.NumberType: 408 bf := expr.Value.AsBigFloat() 409 if i, acc := bf.Int64(); acc == big.Exact { 410 g.Fgenf(w, "%d", i) 411 } else { 412 f, _ := bf.Float64() 413 g.Fgenf(w, "%g", f) 414 } 415 case model.StringType: 416 g.genStringLiteral(w, expr.Value.AsString()) 417 default: 418 contract.Failf("unexpected literal type in GenLiteralValueExpression: %v (%v)", expr.Type(), 419 expr.SyntaxNode().Range()) 420 } 421 } 422 423 func (g *generator) GenObjectConsExpression(w io.Writer, expr *model.ObjectConsExpression) { 424 g.genObjectConsExpression(w, expr, expr.Type()) 425 } 426 427 func (g *generator) genObjectConsExpression(w io.Writer, expr *model.ObjectConsExpression, destType model.Type) { 428 if len(expr.Items) == 0 { 429 return 430 } 431 432 typeName := g.argumentTypeName(expr, destType) 433 if typeName != "" { 434 g.Fgenf(w, "new %s", typeName) 435 g.Fgenf(w, "\n%s{\n", g.Indent) 436 g.Indented(func() { 437 for _, item := range expr.Items { 438 g.Fgenf(w, "%s", g.Indent) 439 lit := item.Key.(*model.LiteralValueExpression) 440 g.Fprint(w, propertyName(lit.Value.AsString())) 441 g.Fgenf(w, " = %.v,\n", item.Value) 442 } 443 }) 444 g.Fgenf(w, "%s}", g.Indent) 445 } else { 446 g.Fgenf(w, "\n%s{\n", g.Indent) 447 g.Indented(func() { 448 for _, item := range expr.Items { 449 g.Fgenf(w, "%s{ %.v, %.v },\n", g.Indent, item.Key, item.Value) 450 } 451 }) 452 g.Fgenf(w, "%s}", g.Indent) 453 } 454 } 455 456 func (g *generator) genRelativeTraversal(w io.Writer, 457 traversal hcl.Traversal, parts []model.Traversable, objType *schema.ObjectType) { 458 459 for i, part := range traversal { 460 var key cty.Value 461 switch part := part.(type) { 462 case hcl.TraverseAttr: 463 key = cty.StringVal(part.Name) 464 if objType != nil { 465 if p, ok := objType.Property(part.Name); ok { 466 if info, ok := p.Language["csharp"].(CSharpPropertyInfo); ok && info.Name != "" { 467 key = cty.StringVal(info.Name) 468 } 469 } 470 } 471 case hcl.TraverseIndex: 472 key = part.Key 473 default: 474 contract.Failf("unexpected traversal part of type %T (%v)", part, part.SourceRange()) 475 } 476 477 if model.IsOptionalType(model.GetTraversableType(parts[i])) { 478 g.Fgen(w, "?") 479 } 480 481 switch key.Type() { 482 case cty.String: 483 g.Fgenf(w, ".%s", propertyName(key.AsString())) 484 case cty.Number: 485 idx, _ := key.AsBigFloat().Int64() 486 g.Fgenf(w, "[%d]", idx) 487 default: 488 contract.Failf("unexpected traversal key of type %T (%v)", key, key.AsString()) 489 } 490 } 491 } 492 493 func (g *generator) GenRelativeTraversalExpression(w io.Writer, expr *model.RelativeTraversalExpression) { 494 g.Fgenf(w, "%.20v", expr.Source) 495 g.genRelativeTraversal(w, expr.Traversal, expr.Parts, nil) 496 } 497 498 func (g *generator) GenScopeTraversalExpression(w io.Writer, expr *model.ScopeTraversalExpression) { 499 rootName := makeValidIdentifier(expr.RootName) 500 if _, ok := expr.Parts[0].(*model.SplatVariable); ok { 501 rootName = "__item" 502 } 503 504 g.Fgen(w, rootName) 505 506 var objType *schema.ObjectType 507 if resource, ok := expr.Parts[0].(*hcl2.Resource); ok { 508 if schemaType, ok := hcl2.GetSchemaForType(resource.InputType); ok { 509 objType, _ = schemaType.(*schema.ObjectType) 510 } 511 } 512 g.genRelativeTraversal(w, expr.Traversal.SimpleSplit().Rel, expr.Parts, objType) 513 } 514 515 func (g *generator) GenSplatExpression(w io.Writer, expr *model.SplatExpression) { 516 g.Fgenf(w, "%.20v.Select(__item => %.v).ToList()", expr.Source, expr.Each) 517 } 518 519 func (g *generator) GenTemplateExpression(w io.Writer, expr *model.TemplateExpression) { 520 multiLine := false 521 expressions := false 522 for _, expr := range expr.Parts { 523 if lit, ok := expr.(*model.LiteralValueExpression); ok && lit.Type() == model.StringType { 524 if strings.Contains(lit.Value.AsString(), "\n") { 525 multiLine = true 526 } 527 } else { 528 expressions = true 529 } 530 } 531 532 if multiLine { 533 g.Fgen(w, "@") 534 } 535 if expressions { 536 g.Fgen(w, "$") 537 } 538 g.Fgen(w, "\"") 539 for _, expr := range expr.Parts { 540 if lit, ok := expr.(*model.LiteralValueExpression); ok && lit.Type() == model.StringType { 541 g.Fgen(w, g.escapeString(lit.Value.AsString(), multiLine, expressions)) 542 } else { 543 g.Fgenf(w, "{%.v}", expr) 544 } 545 } 546 g.Fgen(w, "\"") 547 } 548 549 func (g *generator) GenTemplateJoinExpression(w io.Writer, expr *model.TemplateJoinExpression) { 550 g.genNYI(w, "TemplateJoinExpression") 551 } 552 553 func (g *generator) GenTupleConsExpression(w io.Writer, expr *model.TupleConsExpression) { 554 switch len(expr.Expressions) { 555 case 0: 556 g.Fgen(w, "{}") 557 default: 558 g.Fgenf(w, "\n%s{", g.Indent) 559 g.Indented(func() { 560 for _, v := range expr.Expressions { 561 g.Fgenf(w, "\n%s%.v,", g.Indent, v) 562 } 563 }) 564 g.Fgenf(w, "\n%s}", g.Indent) 565 } 566 } 567 568 func (g *generator) GenUnaryOpExpression(w io.Writer, expr *model.UnaryOpExpression) { 569 opstr, precedence := "", g.GetPrecedence(expr) 570 switch expr.Operation { 571 case hclsyntax.OpLogicalNot: 572 opstr = "!" 573 case hclsyntax.OpNegate: 574 opstr = "-" 575 } 576 g.Fgenf(w, "%[2]v%.[1]*[3]v", precedence, opstr, expr.Operand) 577 }